Menu

#3340 [sz80] Erroneous pop af on -tlr35902

open
None
Simulator
5
2022-03-14
2022-03-03
No

Context:
I’m debugging a regression Failure: gen/ucgbz80/gcc-torture-execute-20050502-1/gcc-torture-execute-20050502-1, which I introduced with [r13045]
I’m on [r13110]
I’ve built the regression tests for sm83. (cd next/sdcc/support/regression && make test-ucgbz80 -j8)
Working directory is next/sdcc/support/regression/gen/ucgbz80/gcc-torture-execute-20050502-1
I’m running ../../../../../sim/ucsim/z80.src/sz80 -tlr35902 ./gcc-torture-execute-20050502-1.ihx

Pasted the commands

set error non-classified off 
set error unknown_code off 
set error memory off 
set error stack off 
set hw simif xram 0xbfff 
pc 0x100
break 0x04a9
break 0x0510
break 0x05ff

Top of this is from ports/ucgbz80/uCsim.cmd
0x4a9 is where the code changed from

inc sp
inc sp

to

pop af

for throwing away arguments on the stack before returning.

0x0510 and 0x05ff are push af

0> run
Simulation started, PC=0x000100
--- Running: gen/ucgbz80/gcc-torture-execute-20050502-1/gcc-torture-execute-20050502-1
Running testTortureExecute

Stop at 0x0004a9: (104) Breakpoint
ZNHC---  Flags= 0x00   0 .  A= 0x00   0 .
00000000
BC= 0xdfbf [BC]= 00   0 .  DE= 0x0027 [DE]= 00   0 .  HL= 0x04c5 [HL]= 00   0 .
SP= 0xdfb8 [SP]= 01   1 .
0x04a9 F? f1          POP    AF
F 0x0004a9
Simulated 20613 ticks (1.864e-03 sec)
Host usage: 0.003423 sec, rate=0.544520
0> next

Stop at 0x0004aa: (109) stepped 10 ticks
ZNHC---  Flags= 0x01   1 .  A= 0x00   0 .
00000010
BC= 0xdfbf [BC]= 00   0 .  DE= 0x0027 [DE]= 00   0 .  HL= 0x04c5 [HL]= 00   0 .
SP= 0xdfba [SP]= 61  97 a
0x04aa  ? e9          JP     (HL)
F 0x0004aa

Flags get set to 0x01 which is wrong, the lower nibble is always 0.

0> run
Simulation started, PC=0x0004aa

Stop at 0x000510: (104) Breakpoint
ZNHC---  Flags= 0x01   1 .  A= 0x01   1 .
00000010
BC= 0xdfba [BC]= 61  97 a  DE= 0xdffa [DE]= b1 177 .  HL= 0xdffa [HL]= b1 177 .
SP= 0xdfba [SP]= 61  97 a
0x0510 F? f5          PUSH   AF
F 0x000510
Simulated 708 ticks (6.402e-05 sec)
Host usage: 0.000114 sec, rate=0.561748
0> next

Stop at 0x000511: (109) stepped 11 ticks
ZNHC---  Flags= 0x01   1 .  A= 0x01   1 .
00000010
BC= 0xdfba [BC]= 61  97 a  DE= 0xdffa [DE]= b1 177 .  HL= 0xdffa [HL]= b1 177 .
SP= 0xdfb8 [SP]= 01   1 .
0x0511  ? cd 32 04    CALL   #0x0432
F 0x000511
0> dump xram 0xdfb8 0xdfb9
0xdfb8                 01 01 ..
0> 

Since the lower nibble aren’t flags, they don’t change and the next push af pushes a wrong number on the stack.

xor a
inc a
push af

Is supposed to push 0x0100

This is probably also what lead to

xor a, a
rra
push af

(push 0x0000)
failing regression test.

I suppose pop af and push af should both &0xf0 the flags.

Discussion

  • Sebastian Riedel

    Now that I think about it, I first tried to also enable that commit for z80, which broke regression tests. So it could be that z80 has similar issues, are the undocumented flags implemented for z80?

     
  • Sebastian Riedel

    Further tests indicate that

    xor a
    dec a
    push af
    pop bc
    

    malfunctions because the H flag isn’t set properly.
    push af and daa are the only instructions who use that flag.

    break 0x0222
    
     

    Last edit: Sebastian Riedel 2022-03-03
  • Sebastian Riedel

    This is a little test file for Z80. Z80 should have similar flag leakage issues, since it appears to not set the two undocumented flags.

    I took the comparison values from Emulicious.

    I get different behaviour for:

    sub a
    rra
    

    0x40 vs 0x44
    sub a resets overflow flag and sets carry flag.
    sz80 sets the P/V flag and unsets the carry flag for rra, but it’s not supposed to touch P/V.
    https://clrhome.org/table/

    xor a
    dec a
    

    0xFFBA vs 0xFF80
    0x80 would mean that there is only the sign flag set.
    Substract and half carry flag is not set, which might also break daa.
    I don’t know if sz80 or Emulicious is wrong on the half carry flag.
    And undocumented flags 5 and 3 have to be set to bits 5 and 3 of A.
    http://www.z80.info/z80sflag.htm

    xor a
    cpl
    

    0xFF7E vs 0xFF56
    Undocumented flags 5 and 3 missing.

    xor a
    and a
    

    0x0054 vs 0x0044
    According to the opcode table half carry flag always gets set by and
    The same happens for and on sm83, there half carry should also be set, but isn’t.

    Ran with sz80 -tz80 ./z80.ihx and

    set error non-classified off
    set error unknown_code off
    set error memory off
    set error stack off
    set hw simif outputs 0xff
    b 0x218
    b 0x222
    b 0x22c
    b 0x237 
    
     
  • Daniel Drotos

    Daniel Drotos - 2022-03-04

    I'm not author of z80 simulator but I'm pretty sure that undocumented flags are not handled. Are they mandatory for sdcc?

     
    • Sebastian Riedel

      I’m undecided. On the one hand it could be abused for optimizations, on the other it seems soviet clones didn’t get the undocumented flags right. But it still feels like the simulator should behave like the original Z80.
      https://www.cpushack.com/2021/01/26/the-story-of-the-soviet-z80-processor/
      Possible optimizations would be things like

      ld bc, #0x0100 ; 3B 10 cycles
      push bc
      

      to

      xor a ; 1B 4 cycles
      inc a ; 1B 4 cycles
      push af
      
       
      • Philipp Klaus Krause

        I think the best way is to implement them in the simulator, but not to use them in SDCC. Users that really want such optimizations can supply their own peephole rules in addition to the SDCC ones. Similarly to how we do not use the undocumented Z80 instructions in SDCC when targeting the Z80 (where AFAIK some of them do not work in early Zilog NMOS Z80).

         
  • Sebastian Riedel

    Fixed in [r13124].
    It seems the bitmask for pop af got implemented forpop bc.
    and now sets half carry.
    I didn’t touch the undocumented registers of z80 yet.

     

    Last edit: Sebastian Riedel 2022-03-06
  • Ragozini Arturo

    Ragozini Arturo - 2022-03-12

    the most accurate description of the z80 is here
    http://www.z80.info/zip/z80-documented.pdf
    the official zilog manual is sometimes wrong when dealing with flags

     
  • Ragozini Arturo

    Ragozini Arturo - 2022-03-13

    all instructions accessing to ixh ixl iyh iyl are safe

     
  • Daniel Drotos

    Daniel Drotos - 2022-03-14

    I'd like to ask, how z80 undocumented instructions behave on sm83?

     
    • Sebastian Riedel

      They don’t, sm83 isn’t considered being a z80 descendant.
      sm83 doesn’t have DD, FD, ED, DDCB, FDCB.
      The undocumented instructions in CB are irrelevant, because sm83 has swap there.

      sm83 is as far as I know more viewed as 8080 with some z80 extensions (CB prefix, jr, N-flag) and z80 mnemonics. And some further custom replacements/additions or things completely removed (S-flag, P-flag, exchange). They probably introduced N to get the fixed daa from z80.
      jp is different from both z80 and 8080 as it is longer when it has to jump.
      Most instruction cycles could be viewed as being rounded to the next multiple of 4, but ret and call are significantly slower than on z80 and 8080.
      But I don’t know 8080 asm, so I don’t know how much that’s really true. And it was never revealed what it was based on.

      The flags are different from both: (Auxiliary Carry and Half Carry do the same)

      8080: |S|Z|0|A|0|P|1|C|
      z80:  |S|Z|Y|H|X|P|N|C|
      sm83: |Z|N|H|C|0|0|0|0|
      

      https://gbdev.io/pandocs/CPU_Comparison_with_Z80.html

      Some extensions have similarities to zeropage instructions of 6502, which was used in Nintendo’s last console (NES). ldh (a8), a is similar to sta a8 and ld (c), a is a short version of sta 0,x

       

      Last edit: Sebastian Riedel 2022-03-14
  • Ragozini Arturo

    Ragozini Arturo - 2022-03-14

    No idea, but for sure those involving IXL,IXH,IYL,IYH cannot lead to anything very useful

     

Log in to post a comment.

MongoDB Logo MongoDB