mirror of
https://github.com/cc65/cc65.git
synced 2025-04-08 19:38:55 +00:00
Merge pull request #2567 from sidneycadot/fix-jsr
sim65: fix memory access order of the JSR instruction.
This commit is contained in:
commit
3c4d9660ed
@ -1456,13 +1456,37 @@ static void OPC_6502_1F (void)
|
||||
static void OPC_6502_20 (void)
|
||||
/* Opcode $20: JSR */
|
||||
{
|
||||
unsigned Addr;
|
||||
/* The obvious way to implement JSR for the 6502 is to (a) read the target address,
|
||||
* and then (b) push the return address minus one. Or do (b) first, then (a).
|
||||
*
|
||||
* However, there is a non-obvious case where this conflicts with the actual order
|
||||
* of operations that the 6502 does, which is:
|
||||
*
|
||||
* (a) Load the LSB of the target address.
|
||||
* (b) Push the MSB of the return address, minus one.
|
||||
* (c) Push the LSB of the return address, minus one.
|
||||
* (d) Load the MSB of the target address.
|
||||
*
|
||||
* This can make a difference in a pretty esoteric case, if the JSR target is located,
|
||||
* wholly or in part, inside the stack page (!). This won't happen in normal code
|
||||
* but it can happen in specifically constructed examples.
|
||||
*
|
||||
* To deal with this, we load the LSB and MSB of the target address separately,
|
||||
* with the pushing of the return address sandwiched in between, to mimic
|
||||
* the order of the bus operations on a real 6502.
|
||||
*/
|
||||
|
||||
unsigned AddrLo, AddrHi;
|
||||
|
||||
Cycles = 6;
|
||||
Addr = MemReadWord (Regs.PC+1);
|
||||
Regs.PC += 2;
|
||||
Regs.PC += 1;
|
||||
AddrLo = MemReadByte(Regs.PC);
|
||||
Regs.PC += 1;
|
||||
PUSH (PCH);
|
||||
PUSH (PCL);
|
||||
Regs.PC = Addr;
|
||||
AddrHi = MemReadByte(Regs.PC);
|
||||
|
||||
Regs.PC = AddrLo + (AddrHi << 8);
|
||||
|
||||
ParaVirtHooks (&Regs);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user