floooh / chips

8-bit chip and system emulators in standalone C headers
zlib License
969 stars 73 forks source link

Q: page-cross behaviour on 6502 SHY opcode #66

Open rofl0r opened 2 years ago

rofl0r commented 2 years ago

i'm using your m6502 to verify accurateness of the 6502 emu i'm writing and encountered this cornercase in blargg NES cpu testsuite:

PC:0200 S:90 A:ff X:02 Y:01 nvTBdizc O:9c @shy $02fe, x

m6502 writes to 0x300 upon encountering this instruction, and i believe the original intent of the code (and also what i observe in visual6502 remix) is to write to 0x200 instead.

    /* SHY abs,X (undoc) */
        case (0x9C<<3)|0: _SA(c->PC++);break;
        case (0x9C<<3)|1: _SA(c->PC++);c->AD=_GD();break;
        case (0x9C<<3)|2: c->AD|=_GD()<<8;_SA((c->AD&0xFF00)|((c->AD+c->X)&0xFF));break;
        case (0x9C<<3)|3: _SA(c->AD+c->X);_SD(c->Y&(uint8_t)((_GA()>>8)+1));_WR();break;

the 3rd cycle actually does the expected page-cross wrap, and a read happens on 0x200, however AD isn't set to this address, instead the 4th cycle uses again 0x2fe and adds X again for the write (this time without page-cross wrap), resulting in a write to 0x300.

floooh commented 2 years ago

Hmm ok, I'm currently "mentally tuned out" from emulator coding so I don't quite remember why I coded it that way.

But you're right, this seems to be a bug (it definitely behaves differently than visual6502). Looks like this is a side effect of the code generation which assumes that the abs,X addressing mode works like in regular instructions, which doesn't seem to be the case here.

To my defense, I didn't care much about the undocumented instructions which are marked as "unstable", because I expected that such unstable instructions would never be useful in regular code anyway (different from the "stable" undocumented instructions which might be useful).

rofl0r commented 2 years ago

it definitely behaves differently than visual6502

indeed, it seems in visual6502 Y influences not only the value, but also the location being written to, contrary to all documentation i've encountered. it appears the page being written to is Y & X & (hibyte(addr)+1).

I didn't care much about the undocumented instructions which are marked as "unstable", because I expected that such unstable instructions would never be useful in regular code anyway

thanks, good to know. i'll let you know i f i figure out the exact algorithm matching the behaviour of visual6502.

rofl0r commented 2 years ago

ok, i figured out the behaviour that makes blargg test 6 pass, as well as being seemingly identical to visual6502 remix. so maybe the behaviour isn't that unstable after all.

my code for shy is

                        u8 data = Y & (op.pb[1]+1);
                        addr = (op.pb[0] + X)&0xff;
                        addr |= data << 8;
                        CPU_WRITE_N(&data, addr, 1);

where op.bp are the bytes immediately following the opcode, so in the above example pb[0] is 0xfe and pb[1] is 2.