Hi, so I'm learning how to do multiprecision math and stuff, and I can usually figure that out, but I just realized, I have no idea how to actually display those dword answers. I can't seem to find the answer here or on google either, so could someone please share how to do it?
You mean 32-bit numbers? It's not that complicated, but you'll have to convert the numbers into decimal. The easiest way is just to subtract the digits you want to display. For example, if you have 924,332,503, you'll start with 1,000,000,000 (the highest possible 32-bit digit). I assume you already have routines to handle 32-bit math? If not, it's not terribly complicated. So first you'll count how many times you can subtract 1 billion before getting a carry. Here it's a 0, so you'll store a 0. Next count how many times you can subtract 100 million before a carry, then 10 million, etc. You might want to add $80 (EDIT: see ASCII codes) to the value before you store it, that way you can just use _vPuts or whatever you want to display the string (make sure to put a 0 at the end).
Well to be honest, I'm confused by what you said... How do you convert a 32-bit number in hexadecimal into decimal? Lets say i had $EA18A644, how do you do that? and another thing, for doing dword rotations, asm28days says:

The code to do a rotation depends on the type of rotation wanted.
For RL-type rotation:

Code:

    LD     HL, dword+3

    RL     (HL)
    DEC    HL
    RL     (HL)
    DEC    HL
    RL     (HL)
    DEC    HL
    RL     (HL)

dword:    .DB    $B3, $90, $12, $32


But doesn't that just screw up the LSB of each byte? I thought that you should start with the LSB ($B3), and increase to the MSB ($32), so your carry contains the rotated MSB from the previous byte. could you explain how that works?
Yeah, that depends on how you're storing your numbers. If you're following the usual z80 little-endian pattern, you're right, you'd start at the left (dword, the LSB) and work your way up (inc hl) to the MSB. Their 32-bit RL seems to be for big-endian numbers.

Let's start with something a little simpler, converting a 16-bit hex number into decimal. Say we have $A644. The maximum 16-bit number only goes up into the 10s of thousands, so first we'll subtract 10,000 until we get a carry. 10,000 = $2710. So:

Code:
 $A46A   0
-$2710
------
 $7D5A   1 no carry, so repeat
-$2710
------
 $564A   2 ...
-$2710
------
 $2F3A   3 ...
-$2710
------
 $ 82A   4 ...
-$2710
------
-$1EE6   4 carry, so don't add 1
So the ten thousands digit is 4, now we repeat subtracting 1,000 ($3E8):

Code:
 $82A   0 ...
-$3E8
-----
 $442   1 no carry
-$3E8
-----
 $ 5A   2 no carry
-$3E8
-----
-$38E   2
So now we have 42,XXX. Repeat with the 100s, 10s, and 1s.

A simple code to do this might look like:

Code:
num2String:
   exx
      ld hl,table   ;where we will store the result
   exx
   ld de,-10000      ;check how many 10,000s units there are
   call dN_b2d
   ld de,-1000    ;check how many 1,000s units there are
   call dN_b2d
   ld de,-100      ;hundreds
   call dN_b2d
   ld de,-10      ;tens
   call dN_b2d
   ld de,-1      ;single digits
   call dN_b2d
   exx
   ld (hl),$FF
   ld hl,table   ;where the string is stored
   ret

dN_b2d:
   ld a,-1               ;if there is no carry the first run through, # = 0
dN_b2dloop:
   inc a               ;each iteration increase accumulator by 1
   add hl,de
   jr c,dN_b2dloop
   or a
   sbc hl,de            ;225 - 100 = 125 - 100 = 25 - 100 = -75. This adds 100 again so we can check the next digits.
   exx
      ld (hl),a
      inc hl
   exx
   ret


If you're going to work with 32-bit numbers, it'll be a little more complicated since you'll need 32-bit addition/subtraction. I've only ever bothered with 24-bit arithmetic, but 32-bit shouldn't be much different. Also, you'd start with the billions, then hundred millions, ten millions, etc. down to the ones/single digits. One billion in hex is "$3B9ACA00", so you'd subtract $3B9ACA00 from $EA18A644 until you got a carry. The 4th subtraction would give you a carry, so you would store 3.

For a 32-bit subtraction, you could try:

Code:
;h'l'hl - b'c'bc
;h'l'hl = $EA18A644
;b'c'bc = $3B9ACA00 (1,000,000,000)
ld hl,$A644 ;LSB into HL
ld bc,1000000000 & $FFFF ;LSB into BC
exx
 ld hl,$EA18 ;MSB into H'L'
 ld bc,1000000000 >> 16 ;MSB into B'C'
exx
;now subtract
or a
sbc hl,bc
exx
 sbc hl,bc
exx
You should be able to use this in the little routine i gave above. I hope i haven't confused you even more, if you've still got questions please ask. Also, have you worked with the shadow registers before? (exx/ex af,af') If you're going to use the shadow registers, make sure you DI (disable interrupts) first, otherwise you'll likely get incorrect values/crash, 'cuz the interrupts make use of the shadow registers. exx swaps the values of hl, bc, and de with their shadow registers, ex af,af' swaps af with af'. Both instructions only use 4 t-states and take up 1 byte, so they're really quick and a nice way to get extra registers when you need them.
That's a great explanation, chickendude. Smile If I get around to updating ASM in 28 Days this summer, perhaps I'll ask if I can incorporate a version of that explanation (and code) into the tutorial.
That is a really good explanation! I haven't used shadow registers yet, (I'm a super noob) but the theory, and top examples make perfect sense. I just wish there was a faster way, haha. Thank you very much!
It's really not that slow, though the 32-bit routine would be quite a bit slower than the 16-bit one. But if you code your own number displaying routine (ie, instead of using _vPuts/one of the bcalls) the final code might even be faster than drawing a normal string with _vPuts. But if you want a quicker way (for example, if you're going to be drawing the high score to the screen every frame) you might want to look into storing the string directly in decimal, either using one byte per digit or using half-bytes (nibbles), ie 1553923 would be stored as:
.db 3,2,9,3,5,5,1 (or .db 1,5,5,3,9,2,3)
or:
.db $32,$93,$55,$10 (or $01,55,39,23)
Either way, it'll all happen in the blink of an eye.

@Kerm: i just hope whatever i've written is useful. The more information we can share, the better Smile (ie. do whatever you want with the code/explanations!)
Here's a 24-bit number-to-string routine:

Code:
;#######################
;#NUM2STR
;# Convert number in AHL to a string
;# input: ahl = number to display
;# output: hl = pointer to converted string
;#######################
num2str:
   ld ix,numberString   ;where we will store the result
;-10,000,000
   ld c,$67
   ld de,$6980
   call b2d         ;count how many 10,000,000s there are
;-1,000,000
   ld c,$F0
   ld de,$BDC0
   call b2d
;-100,000
   ld c,$FE
   ld de,$7960
   call b2d
;-10,000
   inc c         ;ld c,$FF
   ld de,-10000
   call b2d
;-1,000
   ld de,-1000
   call b2d
;-100
   ld de,-100
   call b2d
;-10
   ld e,-10
   call b2d
;-1
   ld e,-1
   call b2d
   ld (ix),a      ;put the terminating zero
   ld hl,numberString-1  ;where the string is stored
      inc hl
      ld a,(hl)
      cp '0'      ;if it's a 0, skip it
    jr z,$-4      ;repeat until we find a non-zero number
   or a
    jr nz,$+3      ;if all numbers are zeros, move hl back one
      dec hl      ;.. to display one zero
   ret

;#######################
;#B2D
;# Convert the units of a 24-bit binary
;#   number in AHL into decimal
;# input: ahl = number to display
;#        cde = negative value of units to check (if you
;#            want to check 10s, cde should equal -10)
;#        ix  = string pointer to store the unit
;#######################
b2d:
   ld b,-1         ;if there is no carry the first run through, # = 0
b2dLoop:
      inc b      ;each iteration increase accumulator by 1
      add hl,de
      adc a,c
    jr c,b2dLoop
   sbc hl,de      ;225 - 100 = 125 - 100 = 25 - 100 = -75. This adds 100 again so we can check the next digits.
   sbc a,c
   set 4,b
   set 5,b         ;b+$30
   ld (ix),b
   inc ix
   ret
I chose to add negative numbers, but you could just as easily subtract positive numbers. You can see how the routine's starting to get a bit larger Razz If you had a multiplication routine, maybe you could just divide by 10 and loop however many digits you wanted to check Smile

EDIT: Oops, left my test values in Razz
EDIT2: Made some small optimizations/fixes.
Another method is to divide by 10 and display the remainder and keep repeating this until your number becomes 0. The tricky part with this then becomes that each digit you extract is in reverse order! So the first digit is 1s place, second is 10s place, et cetera. If you need the string stored somewhere, though, that makes this problem very easy to get around by just storing it in reverse in memory. The nice advantage to this is that you can very easily display the number in any base that you want:

Code:

DrawNumber:
     dec c
     ret z
     inc c
     ret z
     dec ix
     ld (ix+1),0
DispNumBase32:
;Inputs:
;     C is the base (use 2 to 36)
;     DEHL is the number to display
;     IX is the end of where to store the number string
;
     ld b,32
     xor a
       add hl,hl
       rl e \ rl d
       rla
       cp c
       jr c,$+4
         inc l
         sub c
       djnz $-11
     add a,30h
     cp 3Ah
     jr c,$+4
     add a,7
     dec ix
     ld (ix),a
     ld a,h
     or l \ or d \ or e
     jr nz,DispNumBase32
     push ix
     pop hl
     bcall(_PutS)
     ret

Hopefully there are no typos and I am pretty sure there is a tricky optimisation that I left out using DAA, but I am not sure how to implement it.
Cool. I think we've got the same idea, but yours is much smaller. Mine i think is a bit faster, but i don't know that speed is generally that important in text routines Smile
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
Page 1 of 1
» All times are UTC - 5 Hours
 
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum

 

Advertisement