32 bit long to ascii

Pagina 1/2
| 2

Door ARTRAG

Enlighted (6923)

afbeelding van ARTRAG

07-12-2009, 11:26

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

Van RetroTechie

Paragon (1563)

afbeelding van RetroTechie

07-12-2009, 14:37

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 Smile 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...

Van ARTRAG

Enlighted (6923)

afbeelding van ARTRAG

07-12-2009, 16:10

hummm
I was expecting something different .... thanks anyway
Scores need only Add and Sub. Maybe it is safer to move to BCD math directly

Van ARTRAG

Enlighted (6923)

afbeelding van ARTRAG

08-12-2009, 00:18

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?

Van Prodatron

Paragon (1836)

afbeelding van Prodatron

08-12-2009, 02:08

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 Wink ), if it's optimized in any way ( I didn't really need it to be optimized up to now).

Van ARTRAG

Enlighted (6923)

afbeelding van ARTRAG

08-12-2009, 19:35

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

Big smileBig smileBig smileBig smileBig smileBig smileBig smileBig smileBig smileBig smileBig smileBig smileSmile

Van RetroTechie

Paragon (1563)

afbeelding van RetroTechie

08-12-2009, 23:42

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 Tongue
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'. Smile

Van RetroTechie

Paragon (1563)

afbeelding van RetroTechie

09-12-2009, 02:52

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).

Van Prodatron

Paragon (1836)

afbeelding van Prodatron

09-12-2009, 09:49

Great stuff! Thanx for posting, RetroTechie!

Van ARTRAG

Enlighted (6923)

afbeelding van ARTRAG

09-12-2009, 23:32

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

Van RetroTechie

Paragon (1563)

afbeelding van RetroTechie

10-12-2009, 12:16

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?

Pagina 1/2
| 2