suzukiplan / z80

Single header Z80 emulator for C++ (C++11 or later)
MIT License
54 stars 7 forks source link

CPD, CPDR, CPI, CPIR: invalid compare address #59

Closed suzukiplan closed 3 months ago

suzukiplan commented 3 months ago

CPD, CPDR, CPI, CPIR compares A with the value of the address that HL points to “after” being incremented (CPI, CPIR) or decremented (CPD, CPDR) but “before” being incremented (CPI, CPIR) or decremented (CPD, CPDR) The ZF and CF of the execution result are different from the expected values because the value of A is paired with the value of the address pointed to by the HL “before” the increment (CPI, CPIR) or decrement (CPD, CPDR).

The specific problem occurred with a certain MSX game software, which hung in the following loop procedure. (Confirmed with the micro-msx2p)

                    push      hl                            ;[5c55] e5
                    ld        a,$07                         ;[5c56] 3e 07
                    call      $453f                         ;[5c58] cd 3f 45
                    ld        bc,$0003                      ;[5c5b] 01 03 00
                    cpir                                    ;[5c5e] ed b1
                    pop       hl                            ;[5c60] e1
                    jr        nz,$5c55                      ;[5c61] 20 f2 <---- Hang-up due to zflag always in reset state (zflag is set when A==(HL) in 5c5e cpir)
                    ret                                     ;[5c63] c9

I changed the HL of cpir to preincrement in z80.hpp and confirmed that the problem no longer occurs.

suzukiplan commented 3 months ago

specification confirmed: https://userweb.alles.or.jp/chunichidenko/nd3setumeisyo/nd3_z80meirei.pdf Page.5

Screenshot from 2024-07-17 14-00-28

suzukiplan commented 3 months ago

I tried to make HL pre-increment and pre-decrement in CPI, CPIR, CPD and CPDR and zexall failed, so it may be correct as post-increment and post-decrement (current implementation).

./cpm -e zexall.cim
Z80all instruction exerciser
<adc,sbc> hl,<bc,de,hl,sp>....  OK
add hl,<bc,de,hl,sp>..........  OK
add ix,<bc,de,ix,sp>..........  OK
add iy,<bc,de,iy,sp>..........  OK
aluop a,nn....................  OK
aluop a,<b,c,d,e,h,l,(hl),a>..  OK
aluop a,<ixh,ixl,iyh,iyl>.....  OK
aluop a,(<ix,iy>+1)...........  OK
bit n,(<ix,iy>+1).............  OK
bit n,<b,c,d,e,h,l,(hl),a>....  OK
cpd<r>........................  ERROR **** crc expected:134b622d found:24944238
cpi<r>........................CPM halted at $1BAD (total: 43097726643Hz ... about 12040 seconds in Z80A)
Actual execution time: 134.403191 seconds (x89.58 times higher performance than Z80A)
make[1]: *** [Makefile:28: zexall] Error 255
make[1]: Leaving directory '/home/suzukiplan/dev/z80/test-ex'
make: *** [Makefile:6: all] Error 2
suzukiplan commented 3 months ago

We are closing this issue as we believe it may be due to an implementation bug in the game in which we detected this issue.