Is there any ASM snippet to port in ascii a 32 bit long ?
I have seen z80 ASM for 16 bit int to ascii but no 32 bit code...
Aangemeld of registreer om reacties te plaatsen
Is there any ASM snippet to port in ascii a 32 bit long ?
I have seen z80 ASM for 16 bit int to ascii but no 32 bit code...
24 bits enough?
--------------- snip -----------
; Routine for converting a 24-bit binary number to decimal
; In: E:HL = 24-bit binary number (0-16777215)
; Out: DE:HL = 8 digit decimal form (packed BCD)
; Changes: AF, BC, DE, HL & IX
; by Alwin Henseler
LD C,E
PUSH HL
POP IX ; input value in C:IX
LD HL,1
LD D,H
LD E,H ; start value corresponding with 1st 1-bit
LD B,24 ; bitnr. being processed + 1
FIND1: ADD IX,IX
RL C ; shift bit 23-0 from C:IX into carry
JR C,NEXTBIT
DJNZ FIND1 ; find highest 1-bit
; All bits 0:
RES 0,L ; least significant bit not 1 after all ..
RET
DBLLOOP: LD A,L
ADD A,A
DAA
LD L,A
LD A,H
ADC A,A
DAA
LD H,A
LD A,E
ADC A,A
DAA
LD E,A
LD A,D
ADC A,A
DAA
LD D,A ; double the value found so far
ADD IX,IX
RL C ; shift next bit from C:IX into carry
JR NC,NEXTBIT ; bit = 0 -> don't add 1 to the number
SET 0,L ; bit = 1 -> add 1 to the number
NEXTBIT: DJNZ DBLLOOP
RET
--------------- snip -----------
Straight from my time-tested toolbox
If you want bigger numbers: let me know. I also have a routine that can do up to 64 bit numbers (20 digits decimal) and produces ready-for-printing result, but it's quite a bit longer. Probably did it once just to see how easy it was to expand, or to have something that can take anything you throw at it...
hummm
I was expecting something different .... thanks anyway
Scores need only Add and Sub. Maybe it is safer to move to BCD math directly
RetroTechie
I need to convert a 32bit number from DE:HL to a string inRAM pointed by BC
can you share your code for ready for printing results?
I found this routine...
;### CLCN32 -> Converts 32Bit-Value in ASCII-String (terminated by 0)
;### Input DE,IX=32bit value, IY=destination address
;### Output IY=last char in destination string
;### Destroyed AF,BC,DE,HL,IX
clcn32t dw 1,0, 10,0, 100,0, 1000,0, 10000,0
dw #86a0,1, #4240,#f, #9680,#98, #e100,#5f5, #ca00,#3b9a
clcn32z ds 4
clcn32 ld (clcn32z),ix
ld (clcn32z+2),de
ld ix,clcn32t+36
ld b,9
ld c,0
clcn321 ld a,"0"
or a
clcn322 ld e,(ix+0):ld d,(ix+1):ld hl,(clcn32z): sbc hl,de:ld (clcn32z),hl
ld e,(ix+2):ld d,(ix+3):ld hl,(clcn32z+2):sbc hl,de:ld (clcn32z+2),hl
jr c,clcn325
inc c
inc a
jr clcn322
clcn325 ld e,(ix+0):ld d,(ix+1):ld hl,(clcn32z): add hl,de:ld (clcn32z),hl
ld e,(ix+2):ld d,(ix+3):ld hl,(clcn32z+2):adc hl,de:ld (clcn32z+2),hl
ld de,-4
add ix,de
inc c
dec c
jr z,clcn323
ld (iy+0),a
inc iy
clcn323 djnz clcn321
ld a,(clcn32z)
add "0"
ld (iy+0),a
ld (iy+1),0
ret
...but I don't know (and don't think so
), if it's optimized in any way ( I didn't really need it to be optimized up to now).
Now tested and working
; HL:DE INPUT ; BC POINTS TO OUTPUT long2ascii: ; HL = HIGH WORD PUSH DE EXX POP HL ; HL' = LOW WORD EXX LD E,C LD D,B LD BC,-1000000000/0x10000 -1 EXX LD BC,-1000000000&0xFFFF EXX CALL NUM1 LD BC,-100000000/0x10000 -1 EXX LD BC,-100000000&0xFFFF EXX CALL NUM1 LD BC,-10000000/0x10000 -1 EXX LD BC,-10000000&0xFFFF EXX CALL NUM1 LD BC,-1000000/0x10000 -1 EXX LD BC,-1000000&0xFFFF EXX CALL NUM1 LD BC,-100000/0x10000 -1 EXX LD BC,-100000&0xFFFF EXX CALL NUM1 LD BC,-10000/0x10000 -1 EXX LD BC,-10000&0xFFFF EXX CALL NUM1 LD BC,-1000/0x10000 -1 EXX LD BC,-1000&0xFFFF EXX CALL NUM1 LD BC,-100/0x10000 -1 EXX LD BC,-100&0xFFFF EXX CALL NUM1 LD BC,-10/0x10000 -1 EXX LD BC,-10&0xFFFF EXX CALL NUM1 LD BC,-1/0x10000 -1 EXX LD BC,-1&0xFFFF EXX CALL NUM1 RET NUM1: LD A,'0'-1 ; '0' IN THE TILESET NUM2: INC A EXX add HL,BC ; low word EXX ADC HL,BC ; high word jp C,NUM2 EXX SBC HL,BC ; low word EXX SBC HL,BC ; high word LD (DE),A INC DE RET












Looks like a pretty tight routine, Prodatron (if it works, that is).
Sorry for the delay... I was translating comments, then my employer called and turned my day off into a work day 
Now, onto the mother of all binary-to-printable routines:
------------ snip ------------
; Combined routine for conversion of different sized binary numbers into
; directly printable ASCII(Z)-string
; Input value in registers, number size and -related to that- registers to fill
; is selected by calling the correct entry:
;
; entry inputregister(s) decimal value 0 to:
; B2D8 A 255 (3 digits)
; B2D16 HL 65535 5 "
; B2D24 E:HL 16777215 8 "
; B2D32 DE:HL 4294967295 10 "
; B2D48 BC:DE:HL 281474976710655 15 "
; B2D64 IX:BC:DE:HL 18446744073709551615 20 "
;
; The resulting string is placed into a small buffer attached to this routine,
; this buffer needs no initialization and can be modified as desired.
; The number is aligned to the right, and leading 0's are replaced with spaces.
; On exit HL points to the first digit, (B)C = number of decimals
; This way any re-alignment / postprocessing is made easy.
; Changes: AF,BC,DE,HL,IX
; P.S. some examples below
; by Alwin Henseler
B2D8: LD H,0
LD L,A
B2D16: LD E,0
B2D24: LD D,0
B2D32: LD BC,0
B2D48: LD IX,0 ; zero all non-used bits
B2D64: LD (B2DINV),HL
LD (B2DINV+2),DE
LD (B2DINV+4),BC
LD (B2DINV+6),IX ; place full 64-bit input value in buffer
LD HL,B2DBUF
LD DE,B2DBUF+1
LD (HL)," "
B2DFILC: EQU $-1 ; address of fill-character
LD BC,18
LDIR ; fill 1st 19 bytes of buffer with spaces
LD (B2DEND-1),BC ;set BCD value to "0" & place terminating 0
LD E,1 ; no. of bytes in BCD value
LD HL,B2DINV+8 ; (address MSB input)+1
LD BC,#0909
XOR A
B2DSKP0: DEC B
JR Z,B2DSIZ ; all 0: continue with postprocessing
DEC HL
OR (HL) ; find first byte <>0
JR Z,B2DSKP0
B2DFND1: DEC C
RLA
JR NC,B2DFND1 ; determine no. of most significant 1-bit
RRA
LD D,A ; byte from binary input value
B2DLUS2: PUSH HL
PUSH BC
B2DLUS1: LD HL,B2DEND-1 ; address LSB of BCD value
LD B,E ; current length of BCD value in bytes
RL D ; highest bit from input value -> carry
B2DLUS0: LD A,(HL)
ADC A,A
DAA
LD (HL),A ; double 1 BCD byte from intermediate result
DEC HL
DJNZ B2DLUS0 ; and go on to double entire BCD value (+carry!)
JR NC,B2DNXT
INC E ; carry at MSB -> BCD value grew 1 byte larger
LD (HL),1 ; initialize new MSB of BCD value
B2DNXT: DEC C
JR NZ,B2DLUS1 ; repeat for remaining bits from 1 input byte
POP BC ; no. of remaining bytes in input value
LD C,8 ; reset bit-counter
POP HL ; pointer to byte from input value
DEC HL
LD D,(HL) ; get next group of 8 bits
DJNZ B2DLUS2 ; and repeat until last byte from input value
B2DSIZ: LD HL,B2DEND ; address of terminating 0
LD C,E ; size of BCD value in bytes
OR A
SBC HL,BC ; calculate address of MSB BCD
LD D,H
LD E,L
SBC HL,BC
EX DE,HL ; HL=address BCD value, DE=start of decimal value
LD B,C ; no. of bytes BCD
SLA C ; no. of bytes decimal (possibly 1 too high)
LD A,"0"
RLD ; shift bits 4-7 of (HL) into bit 0-3 of A
CP "0" ; (HL) was > 9h?
JR NZ,B2DEXPH ; if yes, start with recording high digit
DEC C ; correct number of decimals
INC DE ; correct start address
JR B2DEXPL ; continue with converting low digit
B2DEXP: RLD ; shift high digit (HL) into low digit of A
B2DEXPH: LD (DE),A ; record resulting ASCII-code
INC DE
B2DEXPL: RLD
LD (DE),A
INC DE
INC HL ; next BCD-byte
DJNZ B2DEXP ; and go on to convert each BCD-byte into 2 ASCII
SBC HL,BC ; return with HL pointing to 1st decimal
RET
B2DINV: DS 8 ; space for 64-bit input value (LSB first)
B2DBUF: DS 20 ; space for 20 decimal digits
B2DEND: DS 1 ; space for terminating 0
END
EXAMPLES
--------
(In these examples, it is assumed there exists a subroutine PRINT, that
prints a string (terminated by a 0-byte) starting at address [HL] )
Print 1 byte, as follows:
20
7
145 etc.
by: LD A,byte
CALL B2D8
LD HL,B2DEND-3
CALL PRINT
Print a 24-bit value, as follows:
9345
76856366
534331
by: LD E,bit23-16
LD HL,bit15-0
CALL B2D24
CALL PRINT
Print a 48-bit value, like
14984366484
49
123456789012345
3155556 etc.
by:
LD BC,bit47-32
LD DE,bit31-16
LD HL,bit15-0
CALL B2D48
LD HL,B2DEND-15
CALL PRINT
....... ETC , ETC , ETC , ...... --------------- snip -------------------
As I said: it's looonnggg. It should be straightforward to trim it down in case you only need a 32-bit conversion. But there's not much point, the routine above is reasonably efficient in avoiding unnecessary work. If you don't believe me: fire up a debugger, throw eg. a 16 bit number at it, and trace the steps it goes through. It is known working, but can't say I used it much. More like a 'nice to have in my toolbox'.
Btw. if you're using this for score-keeping in an action game, then I suggest you move to (packed?) BCD arithmetic. Almost as simple to add/subtract as binary, and conversion to ASCII is trivial (=good when you don't want to affect gameplay).
Great stuff! Thanx for posting, RetroTechie!
RetroTechie this code is pure gold
Thanks!!!
BTW, yes, i am doing the score system of an action game and I was just wandering about the cpu load....
Just in case, do you know where I can wind some tested BCD asm routines for add, sub and print of 10 digits numbers?
Actually I've never used DAA....
ps
code from this site seemd broken
http://icarus.ticalc.org/articles/z80_faq.html
as no carry is passed between digits in different bytes
Actually I've never used DAA....
DAA (Decimal Adjust Accumulator) works best with packed BCD arithmetic (2 digits 0-9 encoded in the 2 halves -nibbles- of an 8-bit number). So each byte encodes 00-99 decimal number (actually, the hex representation matches the decimal number).
When you do an addition, a nibble may go into 10-15 range (A-F hex). Now if you execute DAA immediately after that addition, it will leave that nibble alone if in 0-9 range, or subtract 10 if in 10-15 range, and pass any carry along. That is: for low nibble, pass carry to high nibble, for high nibble, pass to carry flag. IIRC it uses various flags (P/V, carry) to 'do the right thing' in various situations.
Basically you just do 8-bits add as usual, but throw in a DAA right after each add instruction (to bring temporary result back to 00-99), and you process the carry flag as usual. AFAIK this works for subtractions too. Just remember your bytes now represent 00-99 values, and you have to use A register for the actual arithmetic (DAA only works on A register).
Nicest use I ever saw, was for an insanely short 0-A hex -> "0"-"A" ASCII conversion (4 Z80 instructions!). I'll see if I can find that snippet somewhere... or maybe someone else here knows that sequence I'm referring to?
Don't you have an account yet? Become an MSX-friend and register an account!
