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. 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 (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 If you had a multiplication routine, maybe you could just divide by 10 and loop however many digits you wanted to check EDIT: Oops, left my test values in 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 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.

»
» 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