0

I need to figure out how to make a routine for the LR35902 (the Game Boy's Z80-like CPU) that will take the contents of HL (not where it points to, the actual number stored in it) and convert it into 1 to 5 (actual values would range from 0 to 65,535, since HL is 16-bit) non-ASCII* characters using the decimal system. I have routines to print and can easily figure out a way to crop leading zeroes.

All I need is at least some pseudo-code for this function and at most an actual RGBDS LR35902 ASM routine.

*Instead of ASCII, I use my own 1-byte-per-character charmap, in which the character 0 is hexadecimal byte $17, increasing until 9, which is $20.

André Baptista
  • 490
  • 8
  • 23
Tachytaenius
  • 147
  • 8
  • can you provide a few simple examples to demonstrate what you are looking for, a few from this bit pattern to this output pattern. – old_timer Jul 29 '16 at 19:37
  • The same way you'd convert it to ASCII, which has its digits in the range $30 to $39. – Ross Ridge Jul 29 '16 at 20:11
  • @dwelch: %0000000110111010 (442) = $1B, (4) $1B, (4) $19 (2) – Tachytaenius Jul 29 '16 at 20:17
  • @RossRidge : and how's that? – Tachytaenius Jul 29 '16 at 20:18
  • 2
    then it is no different than any other base2 to base10 conversion, you have to do the base10 conversion then look up or otherwise convert each digit to your output format. – old_timer Jul 29 '16 at 20:29
  • 1
    If you ever do your own encoding again, I suggest you to push hard to have '0' encoded with 0000 in lowest 4 bits, or at least '9' having as 1111 (in your case $10-$19 or $20-$29 or at least $16-$1F). Similarly try to put 'a' again at 0000 boundary, or right after '9' (is handy when doing hex), and 'A' on +-32 index. (if you have enough special chars to fill gaps between). But then you have almost ASCII, so why not to stick to it (you don't have to have gfx data for first 32 codes, you can treat ascii as starting at 32 (space) (in gfx data). But if you need it packed so tightly, $17 is OK too. – Ped7g Jul 29 '16 at 23:57

3 Answers3

2

How do I covert seconds to base 60 (hours minutes seconds)? 1234 seconds for examaple

divide 1234 by 3600 (60^2) to get hours which is zero remainder 1234

divide remainder 1234 by 60 (60^1) to get minutes which is 20 minutes remainder 34

divide remainder 34 by 1 (60^0) to get seconds which is 34

So 1234 seconds base 10 converted to base 60 (HH:MM:SS) is 00:20:34

Doesnt matter what the bases are the conversion is the same unless one base is a power of the other base (binary to hex, hex to binary, binary to octal, octal to binary) then you can take shortcuts.

You are going from base 2 to base 10 and then after that you can use ASCII or any other representation for the base 10 digits.

This question has been asked hundreds of times here. The next question of how do I divide by 10 if your processor doesnt have a divide. Also asked and answered many times.

The conversion from digits to your display representation is on you we would need to see the whole table, since you only have 10 digits to deal with you can if nothing else just do a look up table.

old_timer
  • 69,149
  • 8
  • 89
  • 168
  • 3
    +1! :) ... and to add something. If this is for example score, or other often-to-be-displayed value (but not used in calculations often) you can consider using either BCD (special encoding, two digits per byte, natively supported by Z80 (instructions like `DAA`)) or digit-per-byte (0..9 numbers, eventually directly in the special encoding) format, instead of binary number => to make the conversion to string faster (avoiding true software div by 10^n). – Ped7g Jul 29 '16 at 23:45
1

Bonus pre-routines to convert the number HL points to or the number in A included.

This works, it's only a matter of cropping leading zeroes.

ConvertNumberHLPoint::
    ld a, [hl]
ConvertNumberA::
    ld h, 0
    ld l, a
ConvertNumberHL::
    ; Get the number in hl as text in de
    ld bc, -10000
    call .one
    ld bc, -1000
    call .one
    ld bc, -100
    call .one
    ld bc, -10
    call .one
    ld c, -1
.one
    ld a, "0"-1
.two
    inc a
    add hl, bc
    jr c, .two
    push bc;
    push af;
    ld a, b;
    cpl;
    ld b, a;
    ld a, c;
    cpl;
    ld c, a;
    inc bc;
    call c, .carry;
    pop af;
    add hl, bc;
    pop bc;
    ld [de], a
    inc de
    ret

.carry;
    dec bc;
    ret;

If there was such an opcode as sbc hl, bc on the LR35902, like there is on the Z80, it would be possible to replace the lines that end with blank comments-- ;-- with it. Instead, we backup bc and af, invert bc and increment it (two's complement,) then, for the sake of the carry function in the SBC instruction, increment it again if carry is set, then un-backup af, add hl to the two's complemented bc, and finally un-backup bc.

Tachytaenius
  • 147
  • 8
  • why don't you simply keep "old hl" around, like ld ix,hl ahead of add hl,bc, then ld hl,ix to restore it (sorry if the that CPU doesn't have ix like Z80, then you run out of regs I think... haven't done Z80 asm for 10+ years ;) ) – Ped7g Jul 30 '16 at 11:02
  • BTW, this suddenly uses ASCII? `ld a,"0"-1` ... I would expect `ld a,0x17-1` according to your question description. :) (don't have to answer me, just a curiosity) – Ped7g Jul 30 '16 at 11:07
  • But I think the `ConvertNumberA::` prologue has actually real bug. You probably want to load "a" into hl, so `ld h,0 ld l,a`. `de` points to string buffer and shouldn't be changed? – Ped7g Jul 30 '16 at 11:10
  • and you don't need to do `push af ... pop af ld [de],a` .. do the `ld [de],a` instead of `push af` immediately, then let the `a` waste, not needed any more. – Ped7g Jul 30 '16 at 11:15
  • @Ped7g, no "0" is replaced with 0 in my charmap. – Tachytaenius Jul 30 '16 at 15:20
  • @Ped7g, also, I have no IX or shadow registers or anything like that. Also, yes, `ConverNumberA` has a bug, that should be h and l not d and e. I will edit, thanks for pointing it out ;-) And I'll check out the af-stacking, too. Thanks. – Tachytaenius Jul 30 '16 at 15:22
  • Actually, no, I won't change the af-stacking, since I've actually moved it into a "universal" routine for mimicking the Z80's sbc hl, bc, with it still changing af, and as such, It still needs push af and pop af. – Tachytaenius Jul 30 '16 at 15:26
  • I did check the "LR35902" instruction set, and oh boy, that's one sad gimmick! (in joke-ish way from ZX Spectrum programmer, used to all that Z80 luxury like shadow set of registers... and ix/iy... and fast push/pop (11t/10t)). I was trying to write your code in a bit less weird way (that `neg bc` feels weird after x86 years), but I'm lacking the skill after that long time, and without online IDE to verify myself... Curiously I found online IDE for ZX Z80 (including emulator+debugger). Looks very spartan and uncomfortable, but works. :D Amazing world. – Ped7g Jul 30 '16 at 21:57
0

This routine converts the value from HL into it's ASCII representation, starting to memory location pointing by DE, in decimal form and with trailing zeroes so it will allways be 5 characters length. It was adapted from this source: http://map.grauw.nl/sources/external/z80bits.html#5.1


reg2ascdec: ld   bc,55536
            call OneDigit
            ld   bc,64536
            call OneDigit
            ld   bc,65436
            call OneDigit
            ld   c,-10
            call OneDigit
            ld   c,b
OneDigit:   ld   a,47         ;replace with $16 (for $17-$20)
DivideMe:   inc  a
            add  hl,bc
            jr   c,DivideMe
            sbc  hl,bc
            ld   (de),a
            inc  de
            ret
Ratos
  • 1
  • 1