Displaying 24, 32, 48 and 64-bit hexadecimal, signed and unsigned decimal values

hippy

Technical Support
Staff member
#1
Displaying 24, 32, 48 and 64-bit hexadecimal, signed and unsigned decimal values

While greater than 16-bit maths can be relatively straightforward with the right code, showing multi-word numbers as decimal values can be a little complicated.

These routines show how that can be done with a brute-force approach rather than by creating a complicated algorithm. This uses more program memory but keeps the principles simple and minimises the number of variables which need to be used.

The basic principle used here is to use a number of words which each hold four digits of the decimal number. Then one adds to the words values which represent each bit value of the hexadecimal number, keeping them as four digits. Overflow, when a word in the decimal number becomes larger than 9999 is easily handled.

The lower 16-bits can be handled directly which minimises the iterations needed to perform the additions to just 8 for 24-bit, 16 for 32-bit, 32 for 48-bit, but a hefty 48 for 64-bit..

Being a brute force approach there is nothing particularly complicated about the code. It handles integer numbers and two's complement signed numbers. Negation is achieved by inverting and adding one, with any overflow then handled.

Take a look at the 24-bit code first, and you should how the 32-bit and 48-bit versions are just extensions of what is used there.

You will probably notice that the values added to the decimal words halve for each bit. And that's the principle behind a traditional algorithm; set the value for the highest bit, halve it for the next bit, while looping until all bit values have been added.

It would be possible to extend the principle here to larger bit-size numbers using the same principles. It would just require more words to store the decimal value and more program memory to do the additions for the individual bits.

Memory use does increase with bit-size and the 48-bit code won't fit in an M2's memory, and the 64-bit code won't even fit in an X2. There is probably some scope for optimisation but the goal was something 'straight forward' which worked.

Apart from that; this code should work on any M2, X1 and X2 PICAXE and will also run within the PE6 simulator.

If there are any questions; please do ask. If you spot any errors or bugs; please let me know.
 

hippy

Technical Support
Staff member
#2
Code:
; *********************************************
; * 24-Bit Number Printing Routines           *
; *********************************************

;     $FFFFFF = 16777215 = 1677 7216
;
; Bit $800000 =  8388608 =  838 8608
; Bit $400000 =  4194304 =  419 4304
; Bit $200000 =  2097152 =  209 7152
; Bit $100000 =  1048576 =  104 8576
; Bit $080000 =   524288 =   52 4288
; Bit $040000 =   262144 =   26 2144
; Bit $020000 =   131072 =   13 1072
; Bit $010000 =    65536 =    6 5536
;
;     $ABCDEF = 11259375 = 1125 9375
;     $543211 =  5517841 =  551 7841

; *********************************************
; * Variables                                 *
; *********************************************

; Reserve w0, b1 and b0 for general purpose use

Symbol reserveW0 = w0  ; b1:b0

; The decimal number as two 4-digit words

Symbol dec.h     = w1  ; b3:b2 High digits
Symbol dec.l     = w2  ; b5:b4 Low digits

; The hexadecimal 24-bit number as bytes

Symbol hex.h     = b6  ; High byte
Symbol hex.m     = b7  ; Middle byte
Symbol hex.l     = b8  ; Low byte

; Decimal 4-digit display

Symbol n4        = b9  ; High digit
Symbol n3        = b10
Symbol n2        = b11
Symbol n1        = b12 ; Low digit

; *********************************************
; * Example Program                           *
; *********************************************

Test24BitNumbers:

  SerTxd( "24-bit number example", CR, LF )

  ; Set a 24-bit hexadecimal number
  ;
  ;             hex.h   hex.m   hex.l
  ;           .-------.-------.-------.
  ; $ABCDEF = |  $AB  |  $CD  |  $EF  |
  ;           `-------^-------^-------'

  hex.h = $AB       ; High byte
  hex.m = $CD       ; Middle byte
  hex.l = $EF       ; Low byte

  Gosub Show24BitNumber

  ; Now try the largest unsigned number, also -1

  hex.h = $FF       ; High word
  hex.m = $FF       ; Middle word
  hex.l = $FF       ; Low word

  Gosub Show24BitNumber

  End

; *********************************************
; * Show the 24-bit number                    *
; *********************************************

Show24BitNumber:

  SerTxd( CR, LF )

  ; Show it as a hexadecimal number
  ;
  ; $ABCDEF
  ; $FFFFFF

  SerTxd( "Hexadecimal", TAB )
  Gosub ShowAsHex24
  SerTxd( CR, LF )

  ; Show it as an unsigned decimal
  ;
  ; $ABCDEF = 11259375
  ; $FFFFFF = 16777215

  SerTxd( "Unsigned", TAB )
  Gosub ShowAsDec24
  SerTxd( CR, LF )

  ; Show it as a signed decimal
  ;
  ; $ABCDEF = -5517841
  ; $FFFFFF = -1

  SerTxd( "Signed", TAB )
  Gosub ShowAsSignedDec24
  SerTxd( CR, LF )

  Return

; *********************************************
; * 24-bit number handling routines           *
; *********************************************

#Macro AddHexBitToDec24( bVar, bMask, hAdd, lAdd )
  b0 = bVar & bMask
  If b0 <> 0 Then
    dec.h = dec.l + lAdd /  10000 + dec.h + hAdd
    dec.l = dec.l + lAdd // 10000
  End If
#EndMacro

ShowAsHex24:
  SerTxd( "$" )
  b0 = hex.h : Gosub ShowHexByteInB0
  b0 = hex.m : Gosub ShowHexByteInB0
  b0 = hex.l : Gosub ShowHexByteInB0
  Return

ShowHexByteInB0:
  b1 = b0 / $10 + "0" : If b1 > "9" Then : b1 = b1 + 7 : End If
  b0 = b0 & $0F + "0" : If b0 > "9" Then : b0 = b0 + 7 : End If
  SerTxd( b1, b0 )
  Return

ShowAsDec24:

  dec.h = hex.m * 256 + hex.l /  10000
  dec.l = hex.m * 256 + hex.l // 10000

  AddHexBitToDec24( hex.h, $80, 838,8608 )
  AddHexBitToDec24( hex.h, $40, 419,4304 )
  AddHexBitToDec24( hex.h, $20, 209,7152 )
  AddHexBitToDec24( hex.h, $10, 104,8576 )
  AddHexBitToDec24( hex.h, $08,  52,4288 )
  AddHexBitToDec24( hex.h, $04,  26,2144 )
  AddHexBitToDec24( hex.h, $02,  13,1072 )
  AddHexBitToDec24( hex.h, $01,   6,5536 )

  If dec.h = 0 Then
    SerTxd( #dec.l )
  Else
    BinToAscii dec.l, n4,n4,n3,n2,n1
    SerTxd( #dec.h, n4,n3,n2,n1 )
  End If

  Return

ShowAsSignedDec24:

  If hex.h < $80 Then
    SerTxd( "+" )
    Gosub ShowAsDec24
  Else
    SerTxd( "-" )
    Gosub NegateHex24
    Gosub ShowAsDec24
    Gosub NegateHex24
  End If
  Return

NegateHex24:  
  hex.h = hex.h ^ $FF
  hex.m = hex.m ^ $FF
  hex.l = hex.l ^ $FF + 1
  If hex.l = 0 Then
    hex.m = hex.m + 1
    If hex.m = 0 Then
      hex.h = hex.h + 1
    End If
  End If
  Return

; *********************************************
; * End of program                            *
; *********************************************
Code:
24-bit number example

Hexadecimal $ABCDEF
Unsigned    11259375
Signed      -5517841

Hexadecimal $FFFFFF
Unsigned    16777215
Signed      -1
 

hippy

Technical Support
Staff member
#3
Code:
; *********************************************
; * 32-Bit Number Printing Routines           *
; *********************************************

;     $FFFFFFFF = 4294967295 = 42 9496 7295
;
; Bit $80000000 = 2147483648 = 21 4748 3648
; Bit $40000000 = 1073741824 = 10 7374 1824
; Bit $20000000 =  536870912 =  5 3687 0912
; Bit $10000000 =  268435456 =  2 6843 5456
; Bit $08000000 =  134217728 =  1 3421 7728
; Bit $04000000 =   67108864 =    6710 8864
; Bit $02000000 =   33554432 =    3355 4432
; Bit $01000000 =   16777216 =    1677 7216
;
; Bit $00800000 =    8388608 =     838 8608
; Bit $00400000 =    4194304 =     419 4304
; Bit $00200000 =    2097152 =     209 7152
; Bit $00100000 =    1048576 =     104 8576
; Bit $00080000 =     524288 =      52 4288
; Bit $00040000 =     262144 =      26 2144
; Bit $00020000 =     131072 =      13 1072
; Bit $00010000 =      65536 =       6 5536
;
;     $89ABCDEF = 2309737967 = 23 0973 7967
;     $76543211 = 1985229329 = 19 8522 9329

; *********************************************
; * Variables                                 *
; *********************************************

; Reserve w0, b1 and b0 for general purpose use

Symbol reserveW0 = w0  ; b1:b0

; The decimal number as three 4-digit words
; Note that 'dec.h' can be a byte variable
 
Symbol dec.h     = w1  ; b3:b2   High digits
Symbol dec.m     = w2  ; b5:b4   Middle digits
Symbol dec.l     = w3  ; b7:b6   Low digits

; The hexadecimal 32-bit number as two 16-bit words

Symbol hex.h     = w4  ; b9:b8   High word
Symbol hex.l     = w5  ; b11:b10 Low word

; Decimal 4-digit display

Symbol n4        = b12 ; High digit
Symbol n3        = b13
Symbol n2        = b14
Symbol n1        = b15 ; Low digit

; *********************************************
; * Example Program                           *
; *********************************************

Test32BitNumbers:

  SerTxd( "32-bit number example", CR, LF )

  ; Set a 32-bit hexadecimal number
  ;
  ;               hex.h   hex.l
  ;             .-------.-------.
  ; $89ABCDEF = | $89AB | $CDEF |
  ;             `-------^-------'

  hex.h = $89AB     ; High word
  hex.l = $CDEF     ; Low word

  Gosub Show32BitNumber

  ; Now try the largest unsigned number, also -1

  hex.h = $FFFF     ; High word
  hex.l = $FFFF     ; Low word

  Gosub Show32BitNumber

  End

; *********************************************
; * Show the 32-bit number                    *
; *********************************************

Show32BitNumber:

  SerTxd( CR, LF )

  ; Show it as a hexadecimal number
  ;
  ; $89ABCDEF

  SerTxd( "Hexadecimal", TAB )
  Gosub ShowAsHex32
  SerTxd( CR, LF )

  ; Show it as an unsigned decimal
  ;
  ; $89ABCDEF = 2309737967

  SerTxd( "Unsigned", TAB )
  Gosub ShowAsDec32
  SerTxd( CR, LF )

  ; Show it as a signed decimal
  ;
  ; $89ABCDEF = -1985229329

  SerTxd( "Signed", TAB )
  Gosub ShowAsSignedDec32
  SerTxd( CR, LF )

  Return

; *********************************************
; * 32-bit number handling routines           *
; *********************************************

#Macro AddHexBitToDec32( wVar, wMask, hAdd, mAdd, lAdd )
  w0 = wVar & wMask
  If w0 <> 0 Then
    dec.m = dec.l + lAdd /  10000 + dec.m + mAdd
    dec.l = dec.l + lAdd // 10000
    dec.h = dec.m        /  10000 + dec.h + hAdd
    dec.m = dec.m        // 10000      
  End If
#EndMacro

ShowAsHex32:
  SerTxd( "$" )
  w0 = hex.h : Gosub ShowHexByteInB1
  w0 = hex.h : Gosub ShowHexByteInB0
  w0 = hex.l : Gosub ShowHexByteInB1
  w0 = hex.l : Gosub ShowHexByteInB0
  Return

ShowHexByteInB1:
  b0 = b1

ShowHexByteInB0:
  b1 = b0 / $10 + "0" : If b1 > "9" Then : b1 = b1 + 7 : End If
  b0 = b0 & $0F + "0" : If b0 > "9" Then : b0 = b0 + 7 : End If
  SerTxd( b1, b0 )
  Return

ShowAsDec32:

  dec.h = 0
  dec.m = hex.l /  10000
  dec.l = hex.l // 10000

  AddHexBitToDec32( hex.h, $8000, 21,4748,3648 )
  AddHexBitToDec32( hex.h, $4000, 10,7374,1824 )
  AddHexBitToDec32( hex.h, $2000,  5,3687,0912 )
  AddHexBitToDec32( hex.h, $1000,  2,6843,5456 )
  AddHexBitToDec32( hex.h, $0800,  1,3421,7728 )
  AddHexBitToDec32( hex.h, $0400,  0,6710,8864 )
  AddHexBitToDec32( hex.h, $0200,  0,3355,4432 )
  AddHexBitToDec32( hex.h, $0100,  0,1677,7216 )

  AddHexBitToDec32( hex.h, $0080,  0, 838,8608 )
  AddHexBitToDec32( hex.h, $0040,  0, 419,4304 )
  AddHexBitToDec32( hex.h, $0020,  0, 209,7152 )
  AddHexBitToDec32( hex.h, $0010,  0, 104,8576 )
  AddHexBitToDec32( hex.h, $0008,  0,  52,4288 )
  AddHexBitToDec32( hex.h, $0004,  0,  26,2144 )
  AddHexBitToDec32( hex.h, $0002,  0,  13,1072 )
  AddHexBitToDec32( hex.h, $0001,  0,   6,5536 )

  If dec.h = 0 And dec.m = 0 Then
    SerTxd( #dec.l )
  Else
    If dec.h = 0 Then
      SerTxd( #dec.m )
    Else
      BinToAscii dec.m, n4,n4,n3,n2,n1
      SerTxd( #dec.h, n4,n3,n2,n1 )
    End If
    BinToAscii dec.l, n4,n4,n3,n2,n1
    SerTxd( n4,n3,n2,n1 )
  End If
  Return

ShowAsSignedDec32:

  If hex.h < $8000 Then
    SerTxd( "+" )
    Gosub ShowAsDec32
  Else
    SerTxd( "-" )
    Gosub NegateHex32
    Gosub ShowAsDec32
    Gosub NegateHex32
  End If
  Return

NegateHex32:  
  hex.h = hex.h ^ $FFFF
  hex.l = hex.l ^ $FFFF + 1
  If hex.l = 0 Then
    hex.h = hex.h + 1
  End If
  Return

; *********************************************
; * End of program                            *
; *********************************************
Code:
32-bit number example

Hexadecimal $89ABCDEF
Unsigned    2309737967
Signed      -1985229329

Hexadecimal $FFFFFFFF
Unsigned    4294967295
Signed      -1
 

hippy

Technical Support
Staff member
#4
Code:
; *********************************************
; * 48-Bit Number Printing Routines           *
; *********************************************

;     $FFFFFFFFFFFF = 281474976710655 = 281 4749 7671 0655
;
; Bit $800000000000 = 140737488355328 = 140 7374 8835 5328
; Bit $400000000000 =  70368744177664 =  70 3687 4417 7664
; Bit $200000000000 =  35184372088832 =  35 1843 7208 8832
; Bit $100000000000 =  17592186044416 =  17 5921 8604 4416
; Bit $080000000000 =   8796093022208 =   8 7960 9302 2208
; Bit $040000000000 =   4398046511104 =   4 3980 4651 1104
; Bit $020000000000 =   2199023255552 =   2 1990 2325 5552
; Bit $010000000000 =   1099511627776 =   1 0995 1162 7776
;
; Bit $008000000000 =    549755813888 =     5497 5581 3888
; Bit $004000000000 =    274877906944 =     2748 7790 6944
; Bit $002000000000 =    137438953472 =     1374 3895 3472
; Bit $001000000000 =     68719476736 =      687 1947 6736
; Bit $000800000000 =     34359738368 =      343 5973 8368
; Bit $000400000000 =     17179869184 =      171 7986 9184
; Bit $000200000000 =      8589934592 =       85 8993 4592
; Bit $000100000000 =      4294967296 =       42 9496 7296
;
; Bit $000080000000 =      2147483648 =       21 4748 3648
; Bit $000040000000 =      1073741824 =       10 7374 1824
; Bit $000020000000 =       536870912 =        5 3687 0912
; Bit $000010000000 =       268435456 =        2 6843 5456
; Bit $000008000000 =       134217728 =        1 3421 7728
; Bit $000004000000 =        67108864 =          6710 8864
; Bit $000002000000 =        33554432 =          3355 4432
; Bit $000001000000 =        16777216 =          1677 7216
;
; Bit $000000800000 =         8388608 =          838 8608
; Bit $000000400000 =         4194304 =          419 4304
; Bit $000000200000 =         2097152 =          209 7152
; Bit $000000100000 =         1048576 =          104 8576
; Bit $000000080000 =          524288 =           52 4288
; Bit $000000040000 =          262144 =           26 2144
; Bit $000000020000 =          131072 =           13 1072
; Bit $000000010000 =           65536 =            6 5536
;
;     $89ABCDEFEDCB = 151370987466187
;     $765432101235 = 130103989244469

; *********************************************
; * Variables                                 *
; *********************************************

; Reserve w0, b1 and b0 for general purpose use

Symbol reserveW0 = w0  ; b1:b0

; The decimal number as four 4-digit words
 
Symbol dec.x     = w1  ; b3:b2   Extra high digits
Symbol dec.h     = w2  ; b5:b4   High digits
Symbol dec.m     = w3  ; b7:b6   Middle digits
Symbol dec.l     = w4  ; b9:b8   Low digits

; The hexadecimal 48-bit number as three 16-bit words

Symbol hex.h     = w5  ; b11:b10  High word
Symbol hex.m     = w6  ; b13:b12 Middle word
Symbol hex.l     = w7  ; b15:b14 Low word

; Decimal 4-digit display

Symbol n4        = b16 ; High digit
Symbol n3        = b17
Symbol n2        = b18
Symbol n1        = b19 ; Low digit

; *********************************************
; * Example Program                           *
; *********************************************

Test48BitNumbers:

  SerTxd( "48-bit number example", CR, LF )

  ; Set a 48-bit hexadecimal number
  ;
  ;                   hex.h   hex.m   hex.l
  ;                 .-------.-------.-------.
  ; $89ABCDEFEDCB = | $89AB | $CDEF | $EDCB |
  ;                 `-------^-------^-------'

  hex.h = $89AB     ; High word
  hex.m = $CDEF     ; Middle word
  hex.l = $EDCB     ; Low word

  Gosub Show48BitNumber

  ; Now try the largest unsigned number, also -1

  hex.h = $FFFF     ; High word
  hex.m = $FFFF     ; Middle word
  hex.l = $FFFF     ; Low word

  Gosub Show48BitNumber

  End

; *********************************************
; * Show the 48-bit number                    *
; *********************************************

Show48BitNumber:

  SerTxd( CR, LF )

  ; Show it as a hexadecimal number
  ;
  ; $89ABCDEFEDCB
  ; $FFFFFFFFFFFF

  SerTxd( "Hexadecimal", TAB )
  Gosub ShowAsHex48
  SerTxd( CR, LF )

  ; Show it as an unsigned decimal
  ;
  ; $89ABCDEFEDCB = 151370987466187
  ; $FFFFFFFFFFFF = 281474976710655

  SerTxd( "Unsigned", TAB )
  Gosub ShowAsDec48
  SerTxd( CR, LF )

  ; Show it as a signed decimal
  ;
  ; $89ABCDEFEDCB = -130103989244469
  ; $FFFFFFFFFFFF = -1

  SerTxd( "Signed", TAB )
  Gosub ShowAsSignedDec48
  SerTxd( CR, LF )

  Return

; *********************************************
; * 48-bit number handling routines           *
; *********************************************

#Macro AddHexBitToDec48( wVar, wMask, xAdd, hAdd, mAdd, lAdd )
  w0 = wVar & wMask
  If w0 <> 0 Then
    dec.m = dec.l + lAdd /  10000 + dec.m + mAdd
    dec.l = dec.l + lAdd // 10000
    dec.h = dec.m        /  10000 + dec.h + hAdd
    dec.m = dec.m        // 10000      
    dec.x = dec.h        /  10000 + dec.x + xAdd
    dec.h = dec.h        // 10000      
  End If
#EndMacro

ShowAsHex48:
  SerTxd( "$" )
  w0 = hex.h : Gosub ShowHexByteInB1
  w0 = hex.h : Gosub ShowHexByteInB0
  w0 = hex.m : Gosub ShowHexByteInB1
  w0 = hex.m : Gosub ShowHexByteInB0
  w0 = hex.l : Gosub ShowHexByteInB1
  w0 = hex.l : Gosub ShowHexByteInB0
  Return

ShowHexByteInB1:
  b0 = b1

ShowHexByteInB0:
  b1 = b0 / $10 + "0" : If b1 > "9" Then : b1 = b1 + 7 : End If
  b0 = b0 & $0F + "0" : If b0 > "9" Then : b0 = b0 + 7 : End If
  SerTxd( b1, b0 )
  Return

ShowAsDec48:

  dec.x = 0
  dec.h = 0
  dec.m = hex.l /  10000
  dec.l = hex.l // 10000

  AddHexBitToDec48( hex.h, $8000, 140,7374,8835,5328 )
  AddHexBitToDec48( hex.h, $4000,  70,3687,4417,7664 )
  AddHexBitToDec48( hex.h, $2000,  35,1843,7208,8832 )
  AddHexBitToDec48( hex.h, $1000,  17,5921,8604,4416 )
  AddHexBitToDec48( hex.h, $0800,   8,7960,9302,2208 )
  AddHexBitToDec48( hex.h, $0400,   4,3980,4651,1104 )
  AddHexBitToDec48( hex.h, $0200,   2,1990,2325,5552 )
  AddHexBitToDec48( hex.h, $0100,   1,0995,1162,7776 )

  AddHexBitToDec48( hex.h, $0080,   0,5497,5581,3888 )
  AddHexBitToDec48( hex.h, $0040,   0,2748,7790,6944 )
  AddHexBitToDec48( hex.h, $0020,   0,1374,3895,3472 )
  AddHexBitToDec48( hex.h, $0010,   0, 687,1947,6736 )
  AddHexBitToDec48( hex.h, $0008,   0, 343,5973,8368 )
  AddHexBitToDec48( hex.h, $0004,   0, 171,7986,9184 )
  AddHexBitToDec48( hex.h, $0002,   0,  85,8993,4592 )
  AddHexBitToDec48( hex.h, $0001,   0,  42,9496,7296 )

  AddHexBitToDec48( hex.m, $8000,   0,  21,4748,3648 )
  AddHexBitToDec48( hex.m, $4000,   0,  10,7374,1824 )
  AddHexBitToDec48( hex.m, $2000,   0,   5,3687,0912 )
  AddHexBitToDec48( hex.m, $1000,   0,   2,6843,5456 )
  AddHexBitToDec48( hex.m, $0800,   0,   1,3421,7728 )
  AddHexBitToDec48( hex.m, $0400,   0,   0,6710,8864 )
  AddHexBitToDec48( hex.m, $0200,   0,   0,3355,4432 )
  AddHexBitToDec48( hex.m, $0100,   0,   0,1677,7216 )

  AddHexBitToDec48( hex.m, $0080,   0,   0, 838,8608 )
  AddHexBitToDec48( hex.m, $0040,   0,   0, 419,4304 )
  AddHexBitToDec48( hex.m, $0020,   0,   0, 209,7152 )
  AddHexBitToDec48( hex.m, $0010,   0,   0, 104,8576 )
  AddHexBitToDec48( hex.m, $0008,   0,   0,  52,4288 )
  AddHexBitToDec48( hex.m, $0004,   0,   0,  26,2144 )
  AddHexBitToDec48( hex.m, $0002,   0,   0,  13,1072 )
  AddHexBitToDec48( hex.m, $0001,   0,   0,   6,5536 )

  If dec.x = 0 And dec.h = 0 And dec.m = 0 Then
    SerTxd( #dec.l )
  Else
    If dec.x = 0 Then
      If dec.h = 0 Then
        SerTxd( #dec.m )
      Else
        BinToAscii dec.m, n4,n4,n3,n2,n1
        SerTxd( #dec.h, n4,n3,n2,n1 )
      End If
    Else
      BinToAscii dec.h, n4,n4,n3,n2,n1
      SerTxd( #dec.x, n4,n3,n2,n1 )
      BinToAscii dec.m, n4,n4,n3,n2,n1
      SerTxd( n4,n3,n2,n1 )
    End If
    BinToAscii dec.l, n4,n4,n3,n2,n1
    SerTxd( n4,n3,n2,n1 )
  End If
  Return

ShowAsSignedDec48:

  If hex.h < $8000 Then
    SerTxd( "+" )
    Gosub ShowAsDec48
  Else
    SerTxd( "-" )
    Gosub NegateHex48
    Gosub ShowAsDec48
    Gosub NegateHex48
  End If
  Return

NegateHex48:  
  hex.h = hex.h ^ $FFFF
  hex.m = hex.m ^ $FFFF
  hex.l = hex.l ^ $FFFF + 1
  If hex.l = 0 Then
    hex.m = hex.m + 1
    If hex.m = 0 Then
      hex.h = hex.h + 1
    End If
  End If
  Return

; *********************************************
; * End of program                            *
; *********************************************
Code:
48-bit number example

Hexadecimal $89ABCDEFEDCB
Unsigned    151370987466187
Signed      -130103989244469

Hexadecimal $FFFFFFFFFFFF
Unsigned    281474976710655
Signed      -1
 

hippy

Technical Support
Staff member
#6
With the brute-force approach under our belt we can consider turning what we have into an algorithm which, while more complicated and using more variables, does have the benefit of reducing memory usage. That allows us to create a 48-bit version which will fit within even an M2, though the 64-bit version uses more variables than the M2 provides for.

Previously the programs were all extensions of the 24-bit version. Development of the algorithmic programs here started with the 48-bit version, which was then modified for 64-bit, 32-bit and 24-bit use. It is probably best to start with the 32-bit version to get the clearest understanding of what is being done.

There are a number of things which need to be described for these algorithms -

Because we are no longer adding hard-coded values for bits in a brute-force way, we need an additional set of variables which hold the number we are adding for each bit value. These are the 'add' variables. Those are initialised to the MSB value when we start and then divided by two subsequently, which is done by a shift right. Note that a decimal 1 divided by 2 or shifted right becomes 0.5, which becomes 5000 in the lower set of four-digit words which represents our adding value.

We also need an additional set of variables to hold a temporary copy of the 'hex' value while operating on it. These are our 'tmp' variables. We left shift the 'tmp' value and check the MSB to see if a decimal value has to be added. We could have moved a bit through a bit mask to determine which bits are set but that would also require additional values, and what we have is simpler to implement and easier to follow.

The algorithm is pretty much like the brute-force approach, except rather than adding a specific value for each bit, we loop through all bits which are set, adding to the decimal value, adjusting the bit looked at and the bit value as we go. We finish when there are no more bits set.

Note that, because we can easily handle the least 16-bits separately, these lower 16-bits are not included as a 'tmp' variable, and the looping code and terminating check does not have to deal with those bits.

The handling of the various parts of the algorithm, shifting the 'tmp' value, adding and shifting the 'add' value, is all specified within macro routines to keep code memory usage lower. The number printing output routines have also been slightly modified to earlier to reduce code space.

As noted, all but the 64-bit version will run on an M2, X1 and X2 and in the PE6 simulator. The results generated should of course be identical to those from the brute force method.

Again, if there are any questions then please do ask and please let me know if you spot any bugs.
 

hippy

Technical Support
Staff member
#7
Code:
; *********************************************
; * 24-Bit Number Printing Algorithm Routines *
; *********************************************

; Bit $800000 =  8388608 =  838 8608
;
;     $ABCDEF = 11259375 = 1125 9375
;     $543211 =  5517841 =  551 7841
;     $FFFFFF = 16777215 = 1677 7216

; *********************************************
; * Variables                                 *
; *********************************************

; Reserve w0, b1 and b0 for general purpose use

Symbol reserveW0 = w0  ; b1:b0

; The decimal number as two 4-digit words

Symbol dec.h     = w1  ; b3:b2 High digits
Symbol dec.l     = w2  ; b5:b4 Low digits

; The decimal addition values for bits 
 
Symbol add.h     = w3  ; b7:b6 High digits
Symbol add.l     = w4  ; b9:b8 Low digits

; The hexadecimal 24-bit number as bytes

Symbol hex.h     = b10 ; High byte
Symbol hex.m     = b11 ; Middle byte
Symbol hex.l     = b12 ; Low byte

; Temporary storage for the hexadecimal 24-bit number
; Note tmp.m and tmp.l not needed

Symbol tmp.h     = b13 ; High byte

; Decimal 4-digit display
; Note partly reuses the temporary storage above

Symbol n4        = b13 ; High digit
Symbol n3        = b14
Symbol n2        = b15
Symbol n1        = b16 ; Low digit

; *********************************************
; * Example Program                           *
; *********************************************

Test24BitNumbers:

  SerTxd( "24-bit number algorithm example", CR, LF )

  ; Set a 24-bit hexadecimal number
  ;
  ;             hex.h   hex.m   hex.l
  ;           .-------.-------.-------.
  ; $ABCDEF = |  $AB  |  $CD  |  $EF  |
  ;           `-------^-------^-------'

  hex.h = $AB       ; High byte
  hex.m = $CD       ; Middle byte
  hex.l = $EF       ; Low byte

  Gosub Show24BitNumber

  ; Now try the largest unsigned number, also -1

  hex.h = $FF       ; High word
  hex.m = $FF       ; Middle word
  hex.l = $FF       ; Low word

  Gosub Show24BitNumber

  End

; *********************************************
; * Show the 24-bit number                    *
; *********************************************

Show24BitNumber:

  SerTxd( CR, LF )

  ; Show it as a hexadecimal number
  ;
  ; $ABCDEF
  ; $FFFFFF

  SerTxd( "Hexadecimal", TAB )
  Gosub ShowAsHex24
  SerTxd( CR, LF )

  ; Show it as an unsigned decimal
  ;
  ; $ABCDEF = 11259375
  ; $FFFFFF = 16777215

  SerTxd( "Unsigned", TAB )
  Gosub ShowAsDec24
  SerTxd( CR, LF )

  ; Show it as a signed decimal
  ;
  ; $ABCDEF = -5517841
  ; $FFFFFF = -1

  SerTxd( "Signed", TAB )
  Gosub ShowAsSignedDec24
  SerTxd( CR, LF )

  Return

; *********************************************
; * 24-bit number handling routines           *
; *********************************************

#Macro MoveHexToTmp24
  tmp.h = hex.h
#EndMacro

#Macro ShiftTmp24Left
  tmp.h = tmp.h + tmp.h
#EndMacro

#Macro SetAdd24( iniH, iniL )
  add.h = iniH
  add.l = iniL
#EndMacro

#Macro AddToDec24
  dec.h = dec.l + add.l /  10000 + dec.h + add.h
  dec.l = dec.l + add.l // 10000
#EndMacro

#Macro ShiftAdd24Right
  add.l = add.l / 2 : add.l = add.h & 1 * 5000 + add.l
  add.h = add.h / 2 
#EndMacro

ShowAsHex24:
  SerTxd( "$" )
  b0 = hex.h : Gosub ShowHexByteInB0
  b0 = hex.m : Gosub ShowHexByteInB0
  b0 = hex.l : Gosub ShowHexByteInB0
  Return

ShowHexByteInB0:
  b1 = b0 / $10 + "0" : If b1 > "9" Then : b1 = b1 + 7 : End If
  b0 = b0 & $0F + "0" : If b0 > "9" Then : b0 = b0 + 7 : End If
  SerTxd( b1, b0 )
  Return

ShowAsDec24:

  ; Move hex to tmp so we don't corrupt hex

  MoveHexToTmp24

  ; Initialise decimal total

  dec.h = hex.m * 256 + hex.l /  10000
  dec.l = hex.m * 256 + hex.l // 10000

  ; Set the addition value for MSB
  ;
  ; $800000 = 8388608 = 838 8608

  SetAdd24( 838,8608 )

  ; Add all the remaining bit values

  Do While tmp.h <> 0
    If tmp.h >= $80 Then
      AddToDec24
    End If
    ShiftAdd24Right
    ShiftTmp24Left
  Loop

  ; Print the resulting decimal digits

  If dec.h = 0 Then
    SerTxd( #dec.l )
  Else
    BinToAscii dec.l, n4,n4,n3,n2,n1
    SerTxd( #dec.h, n4,n3,n2,n1 )
  End If

  Return

ShowAsSignedDec24:

  If hex.h < $80 Then
    SerTxd( "+" )
    Gosub ShowAsDec24
  Else
    SerTxd( "-" )
    Gosub NegateHex24
    Gosub ShowAsDec24
    Gosub NegateHex24
  End If
  Return

NegateHex24:  
  hex.h = hex.h ^ $FF
  hex.m = hex.m ^ $FF
  hex.l = hex.l ^ $FF + 1
  If hex.l = 0 Then
    hex.m = hex.m + 1
    If hex.m = 0 Then
      hex.h = hex.h + 1
    End If
  End If
  Return

; *********************************************
; * End of program                            *
; *********************************************
Code:
24-bit number algorithm example

Hexadecimal $ABCDEF
Unsigned    11259375
Signed      -5517841

Hexadecimal $FFFFFF
Unsigned    16777215
Signed      -1
 

hippy

Technical Support
Staff member
#8
Code:
; *********************************************
; * 32-Bit Number Printing Algorithm Routines *
; *********************************************

; Bit $80000000 = 2147483648 = 21 4748 3648
;
;     $89ABCDEF = 2309737967 = 23 0973 7967
;     $76543211 = 1985229329 = 19 8522 9329
;     $FFFFFFFF = 4294967295 = 42 9496 7295

; *********************************************
; * Variables                                 *
; *********************************************

; Reserve w0, b1 and b0 for general purpose use

Symbol reserveW0 = w0  ; b1:b0

; The decimal number as three 4-digit words
; Note that 'dec.h' can be a byte variable
 
Symbol dec.h     = w1  ; b3:b2   High digits
Symbol dec.m     = w2  ; b5:b4   Middle digits
Symbol dec.l     = w3  ; b7:b6   Low digits

; The decimal addition values for bits 
 
Symbol add.h     = w4  ; b9:b8   High digits
Symbol add.m     = w5  ; b11:b10 Middle digits
Symbol add.l     = w6  ; b13:b12 Low digits

; The hexadecimal 32-bit number as two 16-bit words

Symbol hex.h     = w7  ; b15:b14 High word
Symbol hex.l     = w8  ; b17:b16 Low word

; Temporary storage for the hexadecimal 32-bit number
; Note tmp.l not needed

Symbol tmp.h     = w9  ; b19:b18 High word

; Decimal 4-digit display
; Note partly reuses the temporary storage above

Symbol n4        = b18 ; High digit
Symbol n3        = b19
Symbol n2        = b20
Symbol n1        = b21 ; Low digit

; *********************************************
; * Example Program                           *
; *********************************************

Test32BitNumbers:

  SerTxd( "32-bit number algorithm example", CR, LF )

  ; Set a 32-bit hexadecimal number
  ;
  ;               hex.h   hex.l
  ;             .-------.-------.
  ; $89ABCDEF = | $89AB | $CDEF |
  ;             `-------^-------'

  hex.h = $89AB     ; High word
  hex.l = $CDEF     ; Low word

  Gosub Show32BitNumber

  ; Now try the largest unsigned number, also -1

  hex.h = $FFFF     ; High word
  hex.l = $FFFF     ; Low word

  Gosub Show32BitNumber

  End

; *********************************************
; * Show the 32-bit number                    *
; *********************************************

Show32BitNumber:

  SerTxd( CR, LF )

  ; Show it as a hexadecimal number
  ;
  ; $89ABCDEF
  ; $FFFFFFFF

  SerTxd( "Hexadecimal", TAB )
  Gosub ShowAsHex32
  SerTxd( CR, LF )

  ; Show it as an unsigned decimal
  ;
  ; $89ABCDEF = 2309737967
  ; $FFFFFFFF = 4294967295

  SerTxd( "Unsigned", TAB )
  Gosub ShowAsDec32
  SerTxd( CR, LF )

  ; Show it as a signed decimal
  ;
  ; $89ABCDEF = -1985229329
  ; $FFFFFFFF = -1

  SerTxd( "Signed", TAB )
  Gosub ShowAsSignedDec32
  SerTxd( CR, LF )

  Return

; *********************************************
; * 32-bit number handling routines           *
; *********************************************

#Macro MoveHexToTmp32
  tmp.h = hex.h
#EndMacro

#Macro ShiftTmp32Left
  tmp.h = tmp.h + tmp.h
#EndMacro

#Macro SetAdd32( iniH, iniM, iniL )
  add.h = iniH
  add.m = iniM
  add.l = iniL
#EndMacro

#Macro AddToDec32
  dec.m = dec.l + add.l /  10000 + dec.m + add.m
  dec.l = dec.l + add.l // 10000
  dec.h = dec.m         /  10000 + dec.h + add.h
  dec.m = dec.m         // 10000       
#EndMacro

#Macro ShiftAdd32Right
  add.l = add.l / 2 : add.l = add.m & 1 * 5000 + add.l
  add.m = add.m / 2 : add.m = add.h & 1 * 5000 + add.m
  add.h = add.h / 2 
#EndMacro

ShowAsHex32:
  SerTxd( "$" )
  w0 = hex.h : Gosub ShowHexByteInB1
  w0 = hex.h : Gosub ShowHexByteInB0
  w0 = hex.l : Gosub ShowHexByteInB1
  w0 = hex.l : Gosub ShowHexByteInB0
  Return

ShowHexByteInB1:
  b0 = b1

ShowHexByteInB0:
  b1 = b0 / $10 + "0" : If b1 > "9" Then : b1 = b1 + 7 : End If
  b0 = b0 & $0F + "0" : If b0 > "9" Then : b0 = b0 + 7 : End If
  SerTxd( b1, b0 )
  Return

ShowAsDec32:

  ; Move hex to tmp so we don't corrupt hex

  MoveHexToTmp32

  ; Initialise decimal total

  dec.h = 0
  dec.m = hex.l /  10000
  dec.l = hex.l // 10000

  ; Set the addition value for MSB
  ;
  ; $80000000 = 2147483648 = 21 4748 3648

  SetAdd32( 21,4748,3648 )

  ; Add all the remaining bit values

  Do while tmp.h <> 0
    If tmp.h >= $8000 Then
      AddToDec32
    End If
    ShiftAdd32Right
    ShiftTmp32Left
  Loop
  
  ; Print the resulting decimal digits

  If dec.h <> 0 Then
    SerTxd( #dec.h ) : Goto ShowDigitsInM
  End If
  If dec.m <> 0 Then
    SerTxd( #dec.m ) : Goto ShowDigitsInL
  Else
    SerTxd( #dec.l )
  End If
  Return

ShowDigitsInM:
  w0 = dec.m : Gosub ShowDigitsInW0
ShowDigitsInL:
  w0 = dec.l

ShowDigitsInW0:
  BinToAscii w0, n4,n4,n3,n2,n1
  SerTxd( n4,n3,n2,n1 )
  Return

ShowAsSignedDec32:

  If hex.h < $8000 Then
    SerTxd( "+" )
    Gosub ShowAsDec32
  Else
    SerTxd( "-" )
    Gosub NegateHex32
    Gosub ShowAsDec32
    Gosub NegateHex32
  End If
  Return

NegateHex32:  
  hex.h = hex.h ^ $FFFF
  hex.l = hex.l ^ $FFFF + 1
  If hex.l = 0 Then
    hex.h = hex.h + 1
  End If
  Return

; *********************************************
; * End of program                            *
; *********************************************
Code:
32-bit number algorithm example

Hexadecimal $89ABCDEF
Unsigned    2309737967
Signed      -1985229329

Hexadecimal $FFFFFFFF
Unsigned    4294967295
Signed      -1
 

hippy

Technical Support
Staff member
#9
Code:
; *********************************************
; * 48-Bit Number Printing Algorithm Routines *
; *********************************************

; Bit $800000000000 = 140737488355328 = 140 7374 8835 5328
;
;     $89ABCDEFEDCB = 151370987466187
;     $765432101235 = 130103989244469
;     $FFFFFFFFFFFF = 281474976710655

; *********************************************
; * Variables                                 *
; *********************************************

; Reserve w0, b1 and b0 for general purpose use

Symbol reserveW0 = w0  ; b1:b0

; The decimal number as four 4-digit words
 
Symbol dec.x     = w1  ; b3:b2   Extra high digits
Symbol dec.h     = w2  ; b5:b4   High digits
Symbol dec.m     = w3  ; b7:b6   Middle digits
Symbol dec.l     = w4  ; b9:b8   Low digits

; The decimal addition values for bits 
 
Symbol add.x     = w5  ; b11:b10 Extra high digits
Symbol add.h     = w6  ; b13:b12 High digits
Symbol add.m     = w7  ; b15:b14 Middle digits
Symbol add.l     = w8  ; b17:b16 Low digits

; The hexadecimal 48-bit number as three 16-bit words

Symbol hex.h     = w9  ; b19:b18  High word
Symbol hex.m     = w10 ; b21:b20 Middle word
Symbol hex.l     = w11 ; b23:b22 Low word

; Temporary storage for the hexadecimal 48-bit number
; Note tmp.l not needed

Symbol tmp.h     = w12 ; b25:b24  High word
Symbol tmp.m     = w13 ; b27:b26 Middle word

; Decimal 4-digit display
; Note reuses the temporary storage above

Symbol n4        = b24 ; High digit
Symbol n3        = b25
Symbol n2        = b26
Symbol n1        = b27 ; Low digit

; *********************************************
; * Example Program                           *
; *********************************************

Test48BitNumbers:

  SerTxd( "48-bit number algorithm example", CR, LF )

  ; Set a 48-bit hexadecimal number
  ;
  ;                   hex.h   hex.m   hex.l
  ;                 .-------.-------.-------.
  ; $89ABCDEFEDCB = | $89AB | $CDEF | $EDCB |
  ;                 `-------^-------^-------'

  hex.h = $89AB     ; High word
  hex.m = $CDEF     ; Middle word
  hex.l = $EDCB     ; Low word

  Gosub Show48BitNumber

  ; Now try the largest unsigned number, also -1

  hex.h = $FFFF     ; High word
  hex.m = $FFFF     ; Middle word
  hex.l = $FFFF     ; Low word

  Gosub Show48BitNumber

  End

; *********************************************
; * Show the 48-bit number                    *
; *********************************************

Show48BitNumber:

  SerTxd( CR, LF )

  ; Show it as a hexadecimal number
  ;
  ; $89ABCDEFEDCB
  ; $FFFFFFFFFFFF

  SerTxd( "Hexadecimal", TAB )
  Gosub ShowAsHex48
  SerTxd( CR, LF )

  ; Show it as an unsigned decimal
  ;
  ; $89ABCDEFEDCB = 151370987466187
  ; $FFFFFFFFFFFF = 281474976710655

  SerTxd( "Unsigned", TAB )
  Gosub ShowAsDec48
  SerTxd( CR, LF )

  ; Show it as a signed decimal
  ;
  ; $89ABCDEFEDCB = -130103989244469
  ; $FFFFFFFFFFFF = -1

  SerTxd( "Signed", TAB )
  Gosub ShowAsSignedDec48
  SerTxd( CR, LF )

  Return

; *********************************************
; * 48-bit number handling routines           *
; *********************************************

#Macro MoveHexToTmp48
  tmp.h = hex.h
  tmp.m = hex.m
#EndMacro

#Macro ShiftTmp48Left
  tmp.h = tmp.m / $8000 + tmp.h + tmp.h
  tmp.m =                 tmp.m + tmp.m
#EndMacro

#Macro SetAdd48( iniX, iniH, iniM, iniL )
  add.x = iniX
  add.h = iniH
  add.m = iniM
  add.l = iniL
#EndMacro

#Macro AddToDec48
  dec.m = dec.l + add.l /  10000 + dec.m + add.m
  dec.l = dec.l + add.l // 10000
  dec.h = dec.m         /  10000 + dec.h + add.h
  dec.m = dec.m         // 10000      
  dec.x = dec.h         /  10000 + dec.x + add.x
  dec.h = dec.h         // 10000      
#EndMacro

#Macro ShiftAdd48Right
  add.l = add.l / 2 : add.l = add.m & 1 * 5000 + add.l
  add.m = add.m / 2 : add.m = add.h & 1 * 5000 + add.m
  add.h = add.h / 2 : add.h = add.x & 1 * 5000 + add.h
  add.x = add.x / 2
#EndMacro

ShowAsHex48:
  SerTxd( "$" )
  w0 = hex.h : Gosub ShowHexByteInB1
  w0 = hex.h : Gosub ShowHexByteInB0
  w0 = hex.m : Gosub ShowHexByteInB1
  w0 = hex.m : Gosub ShowHexByteInB0
  w0 = hex.l : Gosub ShowHexByteInB1
  w0 = hex.l : Gosub ShowHexByteInB0
  Return

ShowHexByteInB1:
  b0 = b1

ShowHexByteInB0:
  b1 = b0 / $10 + "0" : If b1 > "9" Then : b1 = b1 + 7 : End If
  b0 = b0 & $0F + "0" : If b0 > "9" Then : b0 = b0 + 7 : End If
  SerTxd( b1, b0 )
  Return

ShowAsDec48:

  ; Move hex to tmp so we don't corrupt hex

  MoveHexToTmp48

  ; Initialise decimal total

  dec.x = 0
  dec.h = 0
  dec.m = hex.l /  10000
  dec.l = hex.l // 10000

  ; Set the addition value for MSB
  ;
  ; $800000000000 = 140737488355328 = 140 7374 8835 5328

  SetAdd48( 140,7374,8835,5328 )

  ; Add all the remaining bit values

  Do While tmp.h <> 0 Or tmp.m <> 0
    If tmp.h >= $8000 Then
      AddToDec48
    End If
    ShiftAdd48Right
    ShiftTmp48Left
  Loop

  ; Print the resulting decimal digits

  If dec.x <> 0 Then
    SerTxd( #dec.x ) : Goto ShowDigitsInH
  End If
  If dec.h <> 0 Then
    SerTxd( #dec.h ) : Goto ShowDigitsInM
  End If
  If dec.m <> 0 Then
    SerTxd( #dec.m ) : Goto ShowDigitsInL
  Else
    SerTxd( #dec.l )
  End If
  Return

ShowDigitsInH:
  w0 = dec.h : Gosub ShowDigitsInW0
ShowDigitsInM:
  w0 = dec.m : Gosub ShowDigitsInW0
ShowDigitsInL:
  w0 = dec.l

ShowDigitsInW0:
  BinToAscii w0, n4,n4,n3,n2,n1
  SerTxd( n4,n3,n2,n1 )
  Return

ShowAsSignedDec48:

  If hex.h < $8000 Then
    SerTxd( "+" )
    Gosub ShowAsDec48
  Else
    SerTxd( "-" )
    Gosub NegateHex48
    Gosub ShowAsDec48
    Gosub NegateHex48
  End If
  Return

NegateHex48:  
  hex.h = hex.h ^ $FFFF
  hex.m = hex.m ^ $FFFF
  hex.l = hex.l ^ $FFFF + 1
  If hex.l = 0 Then
    hex.m = hex.m + 1
    If hex.m = 0 Then
      hex.h = hex.h + 1
    End If
  End If
  Return

; *********************************************
; * End of program                            *
; *********************************************
Code:
48-bit number algorithm example

Hexadecimal $89ABCDEFEDCB
Unsigned    151370987466187
Signed      -130103989244469

Hexadecimal $FFFFFFFFFFFF
Unsigned    281474976710655
Signed      -1
 

hippy

Technical Support
Staff member
#10
Code:
; *********************************************
; * 64-Bit Number Printing Algorithm Routines *
; *********************************************

; Bit $8000000000000000 =  9223372036854775808 = 922 3372 0368 5477 5808
;
;     $89ABCDEFEDCBA987 =  9920249034584074631
;     $7654321012345679 =  8526495039125476985
;     $FFFFFFFFFFFFFFFF = 18446744073709551615

; *********************************************
; * Variables                                 *
; *********************************************

; Reserve w0, b1 and b0 for general purpose use

Symbol reserveW0 = w0  ; b1:b0

; The decimal number as five 4-digit words
 
Symbol dec.u     = w1  ; b3:b2   Uppermost high digits
Symbol dec.x     = w2  ; b5:b4   Extra high digits
Symbol dec.h     = w3  ; b7:b6   High digits
Symbol dec.m     = w4  ; b9:b8   Middle digits
Symbol dec.l     = w5  ; b11:b10 Low digits

; The decimal addition values for bits 
 
Symbol add.u     = w6  ; b13:b12 Uppermost high digits
Symbol add.x     = w7  ; b15:b14 Extra high digits
Symbol add.h     = w8  ; b17:b16 High digits
Symbol add.m     = w9  ; b19:b18 Middle digits
Symbol add.l     = w10 ; b21:b20 Low digits

; The hexadecimal 64-bit number as four 16-bit words

Symbol hex.x     = w11 ; b23:b22 Extra High word
Symbol hex.h     = w12 ; b25:b24 High word
Symbol hex.m     = w13 ; b27:b26 Middle word
Symbol hex.l     = w14 ; b29:b28 Low word

; Temporary storage for the hexadecimal 64-bit number
; Note tmp.l not needed

Symbol tmp.x     = w15 ; b31:b30 High word
Symbol tmp.h     = w16 ; b33:b32 High word
Symbol tmp.m     = w17 ; b35:b34 Middle word

; Decimal 4-digit display
; Note reuses the temporary storage above

Symbol n4        = b30 ; High digit
Symbol n3        = b31
Symbol n2        = b32
Symbol n1        = b33 ; Low digit

; *********************************************
; * Example Program                           *
; *********************************************

Test48BitNumbers:

  SerTxd( "64-bit number algorithm example", CR, LF )

  ; Set a 64-bit hexadecimal number
  ;
  ;                   hex.x   hex.h   hex.m   hex.l
  ;                 .-------.-------.-------.------.
  ; $89ABCDEFEDCB = | $89AB | $CDEF | $EDCB | A987 |
  ;                 `-------^-------^-------^------'

  hex.x = $89AB     ; Extra high word
  hex.h = $CDEF     ; High word
  hex.m = $EDCB     ; Middle word
  hex.l = $A987     ; Low word

  Gosub Show64BitNumber

  ; Now try the largest unsigned number, also -1

  hex.x = $FFFF     ; Extra high word
  hex.h = $FFFF     ; High word
  hex.m = $FFFF     ; Middle word
  hex.l = $FFFF     ; Low word

  Gosub Show64BitNumber

  End

; *********************************************
; * Show the 64-bit number                    *
; *********************************************

Show64BitNumber:

  SerTxd( CR, LF )

  ; Show it as a hexadecimal number
  ;
  ; $89ABCDEFEDCBA987
  ; $FFFFFFFFFFFFFFFF

  SerTxd( "Hexadecimal", TAB )
  Gosub ShowAsHex64
  SerTxd( CR, LF )

  ; Show it as an unsigned decimal
  ;
  ; $89ABCDEFEDCBA987 =  9920249034584074631
  ; $FFFFFFFFFFFFFFFF = 18446744073709551615

  SerTxd( "Unsigned", TAB )
  Gosub ShowAsDec64
  SerTxd( CR, LF )

  ; Show it as a signed decimal
  ;
  ; $89ABCDEFEDCBA987 = -8526495039125476985
  ; $FFFFFFFFFFFFFFFF = -1

  SerTxd( "Signed", TAB )
  Gosub ShowAsSignedDec64
  SerTxd( CR, LF )

  Return

; *********************************************
; * 64-bit number handling routines           *
; *********************************************

#Macro MoveHexToTmp64
  tmp.x = hex.x
  tmp.h = hex.h
  tmp.m = hex.m
#EndMacro

#Macro ShiftTmp64Left
  tmp.x = tmp.h / $8000 + tmp.x + tmp.x
  tmp.h = tmp.m / $8000 + tmp.h + tmp.h
  tmp.m =                 tmp.m + tmp.m
#EndMacro

#Macro SetAdd64( iniU, iniX, iniH, iniM, iniL )
  add.u = iniU
  add.x = iniX
  add.h = iniH
  add.m = iniM
  add.l = iniL
#EndMacro

#Macro AddToDec64
  dec.m = dec.l + add.l /  10000 + dec.m + add.m
  dec.l = dec.l + add.l // 10000
  dec.h = dec.m         /  10000 + dec.h + add.h
  dec.m = dec.m         // 10000      
  dec.x = dec.h         /  10000 + dec.x + add.x
  dec.h = dec.h         // 10000      
  dec.u = dec.x         /  10000 + dec.u + add.u
  dec.x = dec.x         // 10000      
#EndMacro

#Macro ShiftAdd64Right
  add.l = add.l / 2 : add.l = add.m & 1 * 5000 + add.l
  add.m = add.m / 2 : add.m = add.h & 1 * 5000 + add.m
  add.h = add.h / 2 : add.h = add.x & 1 * 5000 + add.h
  add.x = add.x / 2 : add.x = add.u & 1 * 5000 + add.x
  add.u = add.u / 2
#EndMacro

ShowAsHex64:
  SerTxd( "$" )
  w0 = hex.x : Gosub ShowHexByteInB1
  w0 = hex.x : Gosub ShowHexByteInB0
  w0 = hex.h : Gosub ShowHexByteInB1
  w0 = hex.h : Gosub ShowHexByteInB0
  w0 = hex.m : Gosub ShowHexByteInB1
  w0 = hex.m : Gosub ShowHexByteInB0
  w0 = hex.l : Gosub ShowHexByteInB1
  w0 = hex.l : Gosub ShowHexByteInB0
  Return

ShowHexByteInB1:
  b0 = b1

ShowHexByteInB0:
  b1 = b0 / $10 + "0" : If b1 > "9" Then : b1 = b1 + 7 : End If
  b0 = b0 & $0F + "0" : If b0 > "9" Then : b0 = b0 + 7 : End If
  SerTxd( b1, b0 )
  Return

ShowAsDec64:

  ; Move hex to tmp so we don't corrupt hex

  MoveHexToTmp64

  ; Initialise decimal total

  dec.u = 0
  dec.x = 0
  dec.h = 0
  dec.m = hex.l /  10000
  dec.l = hex.l // 10000

  ; Set the addition value for MSB
  ;
  ; $8000000000000000 = 9223372036854775808 = 922 3372 0368 5477 5808

  SetAdd64( 922,3372,0368,5477,5808 )

  ; Add all the remaining bit values

  Do While tmp.x <> 0 Or tmp.h <> 0 Or tmp.m <> 0
    If tmp.x >= $8000 Then
      AddToDec64
    End If
    ShiftAdd64Right
    ShiftTmp64Left
  Loop

  ; Print the resulting decimal digits

  If dec.u <> 0 Then
    SerTxd( #dec.u ) : Goto ShowDigitsInX
  End If
  If dec.x <> 0 Then
    SerTxd( #dec.x ) : Goto ShowDigitsInH
  End If
  If dec.h <> 0 Then
    SerTxd( #dec.h ) : Goto ShowDigitsInM
  End If
  If dec.m <> 0 Then
    SerTxd( #dec.m ) : Goto ShowDigitsInL
  Else
    SerTxd( #dec.l )
  End If
  Return

ShowDigitsInX:
  w0 = dec.x : Gosub ShowDigitsInW0
ShowDigitsInH:
  w0 = dec.h : Gosub ShowDigitsInW0
ShowDigitsInM:
  w0 = dec.m : Gosub ShowDigitsInW0
ShowDigitsInL:
  w0 = dec.l

ShowDigitsInW0:
  BinToAscii w0, n4,n4,n3,n2,n1
  SerTxd( n4,n3,n2,n1 )
  Return

ShowAsSignedDec64:

  If hex.x < $8000 Then
    SerTxd( "+" )
    Gosub ShowAsDec64
  Else
    SerTxd( "-" )
    Gosub NegateHex64
    Gosub ShowAsDec64
    Gosub NegateHex64
  End If
  Return

NegateHex64:  
  hex.x = hex.x ^ $FFFF
  hex.h = hex.h ^ $FFFF
  hex.m = hex.m ^ $FFFF
  hex.l = hex.l ^ $FFFF + 1
  If hex.l = 0 Then
    hex.m = hex.m + 1
    If hex.m = 0 Then
      hex.h = hex.h + 1
      If hex.h = 0 Then
        hex.x = hex.x + 1
      End If
    End If
  End If
  Return

; *********************************************
; * End of program                            *
; *********************************************
Code:
64-bit number algorithm example

Hexadecimal $89ABCDEFEDCBA987
Unsigned    9920249034584074631
Signed      -8526495039125476985

Hexadecimal $FFFFFFFFFFFFFFFF
Unsigned    18446744073709551615
Signed      -1
 
Top