vhelin / wla-dx

WLA DX - Yet Another GB-Z80/Z80/Z80N/6502/65C02/65CE02/65816/68000/6800/6801/6809/8008/8080/HUC6280/SPC-700/SuperFX Multi Platform Cross Assembler Package
Other
545 stars 98 forks source link

Z80 asm jr/jp/ret/call condition codes enhancement #527

Closed sverx closed 2 years ago

sverx commented 2 years ago

Well maybe it's just me but I often find myself desiring we had more condition codes than the basic Z/NZ, C/NC etc. for JR/JP/CALL/RET Z80 asm instructions, mainly to make source code clearer.

For instance, take this very simple piece of code:

ld a,(some_var)
cp SOME_CONST
jr z,_some_label
jr nc,_some_other_label

sure we can tell what's going on here, but I still suspect if we had enhanced condition codes (actually just aliases of what we have already) the code would be clearer.

So I'm probably just asking for feedback on the idea for the moment. My take would be to add three letters condition codes such as equ (equal - alias for z) neq (not equal - alias for nz) gte (greater than or equal - alias for nc) lss/lst (or some better 3 letters code for less than - alias for c)

... and maybe even more than these might be needed, but those are the ones I would gladly use. :smiley:

vhelin commented 2 years ago

Well, such aliases are quick and easy to add, and I support anything that'll make asm coding easier :)

sverx commented 2 years ago

Thanks! Just pick some nice aliases and let's see what others suggest too - as for me, I'm not that fond of gte but lss / lst are the worst ones I think.

sverx commented 2 years ago

EQU NEQ GEQ LSS would match DOS batch scripting relational operators

not that I'm that fond of that GEQ either but we need to pick something in the end...

vhelin commented 2 years ago

As an old 68k programmer, these came into my mind:

jr z, some_label 
->
jreq some_label

jr nz, some_label 
->
jrne some_label

jr nc, some_label
->
jrge some_label

jr c, some_label
->
jrlt some_label

JP versions:

jp z, some_label 
->
jpeq some_label

jp nz, some_label 
->
jpne some_label

jp nc, some_label
->
jpge some_label

jp c, some_label
->
jplt some_label
sverx commented 2 years ago

I would still prefer to keep the instruction separated from the condition, not to mention that also RET and CALL can be conditional.

Also since the original conditions are either 1 or 2 chars long I would define the new aliases using 3 chars exclusively, and have a couple different spellings for greater-than-or-equal and for less-than.

I also thought that even pos and neg could be added as aliases of conditions p and m which where never really clear, especially the latter.

So my suggestion is still to create a set of condition aliases so that these would be all valid instructions:

ret neq

jr equ, some_label

call gte, some_label

call geq, some_label

jp lss, some_label

jp lst, some_label

jp pos, some_label

jp neg, some_label
Kroc commented 2 years ago

NB: These would also apply to GameBoy/SM83, which doesn't have P/M flags

vhelin commented 2 years ago

I'm ready to implement these, but does anyone else has something to say about this?

vhelin commented 2 years ago

@Kroc You gave a tumbs down. Why was that? Any way these could be done better?

sverx commented 2 years ago

NB: These would also apply to GameBoy/SM83, which doesn't have P/M flags

I think only the 'valid' aliases would work there? So pos and neg won't be valid on the SM83/GB as they would alias to not existing jump/call/ret conditions...

Kroc commented 2 years ago

@Kroc You gave a tumbs down. Why was that? Any way these could be done better?

Given that Z80 already has a 2 parameter structure for conditional jumps, this syntax confuses the nature of CPU flags and register values; I can't put my finger on it exactly but it feels semantically confusing. Other architectures have "jple"/"jpge" instructions so I would prefer to use that style of syntax.

sverx commented 2 years ago

@Kroc Even if I understand your concerns, I do believe that the syntax of JR,JP and CALL is

instruction [condition] label

and for RET it's

instruction [condition]

and what we would create here would simply be handy nicknames for the existing conditions, not new syntax.

vhelin commented 2 years ago

I hope I got all correct. Next I'll add these to WLA-GB as well...

sverx commented 2 years ago

I hope I got all correct. [...]

So far so good.

    ; check if bullet.damage >= enemy.HP
    ld a,(iy+enemy.HP)
    sub (ix+bullet.damage)
    jr lss,_kill_enemy            ; if HP < damage
    jr equ,_kill_enemy            ; if HP = damage
    ld (iy+enemy.HP),a
vhelin commented 2 years ago

I guess this issue has been taken care of?

sverx commented 2 years ago

I already used a few of them a couple of times now and they seem working just fine - though I didn't do any extensive tests.

But of course you can mark this issue as closed. I will let you know later if something breaks :smiley:

vhelin commented 2 years ago

I think I'll go through all the changes row by row and check that they are ok and if they are then I'll close this issue. But can you confirm that these flag changes are correct?

C -> LSS and LST, M -> NEG, NC -> GTE and GEQ, NZ -> NEQ, P -> POS, Z -> EQU

sverx commented 2 years ago

As said I've only used a few of them so far, but they seem to work just fine.

The assignments are correct for what I understand.

When doing CP x (likewise with SUB x) you'll get the flags according to the A - x operation, so:

vhelin commented 2 years ago

Double checked Z80 and GB-Z80, all seems to be good.

sverx commented 2 years ago

Good! :heart:

Of course it works with 16 bit SBC too:

  sbc hl,de                     ; check X coordinate
  jr lss,_left_of_barrier

but I still believe its main purpose is to make CP followed by a conditional jump more readable:

  cp UNINITIALIZED
  jr neq,_advance_next

Also, and maybe I should open a separate topic about it, I do believe there might be a case for two additional condition codes - but they're so rarely used that I don't know if it's even worth to bother...

The 'issue' is about the P/V flag when used as overflow. Currently the condition codes to check them (with JP and RET instructions only) are PE (parity even, flag SET) and PO (parity odd, flag RESET) even when there's no parity check involved, like with SUB or SBC.

So three letter aliases could be added to signal overflow (flag SET) and not-overflow (flag RESET). But... OVF / NOF ??? They're terrible... :thinking: