6502
unknown
pascal
a year ago
46 kB
11
No Index
// All opcodes start with a "_3_*" cycle. The second-to-last cycle ("_1_*") fetches the next opcode. The last cycle ("_2_*") decodes the fetched opcode,
// executes the previous instruction (in case of "*_rd" / the 2-cycle "implied" / "*_PLx" addressing modes), and fetches the next byte in the opcode stream.
//
// *_rd (read): get address, read memory, set MDR, store it in Data, call Instruction in cycle 2 of the next instruction to process Data
// *_wr (write): get address, call Instruction to modify MDR, write MDR to the address
// *_rmw (read-modify-write): get address, read memory, set MDR, call Instruction to modify MDR, write MDR to the address
procedure MOS_6502.Step;
var
prev : Handler;
tmp : Cycles;
begin
{$define Inc_PC := Inc(PCW) } // making sure that there's a 16-bit wrap-around
tmp := Cycle;
Cycle := Cycles(ord(tmp) + 1);
case tmp of
// absolute (read) -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_rd: begin EA := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_rd: begin EAH := MDR; Inc_PC; MAR := EA; end; // receive address high byte, read data
_1_Absolute_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_Absolute_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// absolute (write) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_wr: begin EA := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_wr: begin EAH := MDR; Inc_PC; MAR := EA; RW := wr; Instruction; end; // receive address high byte, write data
_1_Absolute_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_Absolute_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute (read-modify-write) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_rmw: begin EA := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_rmw: begin EAH := MDR; Inc_PC; MAR := EA; end; // receive address high byte, read data
_5_Absolute_rmw: begin RW := wr; end; // write old data (CMOS: read)
_6_Absolute_rmw: begin Instruction; end; // write new data
_1_Absolute_rmw: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_Absolute_rmw: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute (JMP) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_JMP: begin EA := MDR; Inc_PC; MAR := PC; end; // receive PC low byte, fetch PC high byte
_1_Absolute_JMP: begin PCH := MDR; PCL := EA; MAR := PC; end; // receive PC high byte, fetch next opcode
_2_Absolute_JMP: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute (JSR) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_JSR: begin Data := MDR; Inc_PC; MAR := S; RW := wr; end; // receive PC low byte, internal operation "store ADL" (CMOS: pull)
_4_Absolute_JSR: begin MDR := PCH; end; // push PC high byte (PC = last byte of JSR)
_5_Absolute_JSR: begin Dec(SL); MAR := S; MDR := PCL; end; // push PC low byte (PC = last byte of JSR)
_6_Absolute_JSR: begin Inc_PC; Dec(SL); MAR := PC; RW := rd; end; // fetch PC high byte
_1_Absolute_JSR: begin PCH := MDR; PCL := Data; MAR := PC; end; // receive PC high byte, fetch next opcode
_2_Absolute_JSR: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute X indexed (read) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_X_rd: begin Data := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_X_rd: begin EAH := MDR; Inc_PC; Inc(Data, X); EAL := DataL; MAR := EA; Inc(Cycle, DataH XOR 1); end; // receive address high byte, calculate address, skip cycle if no overflow (DataH = 0)
_5_Absolute_X_rd: begin Inc(EAH); MAR := EA; end; // fix address, read data
_1_Absolute_X_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_Absolute_X_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// absolute X indexed (write) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_X_wr: begin Data := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_X_wr: begin EAH := MDR; Inc_PC; Inc(Data, X); EAL := DataL; MAR := EA; end; // receive address high byte, calculate address, read from unfinished address
_5_Absolute_X_wr: begin Inc(EAH, DataH); MAR := EA; RW := wr; Instruction; end; // fix address, write data
_1_Absolute_X_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_Absolute_X_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute X indexed (read-modify-write) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_X_rmw: begin Data := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_X_rmw: begin EAH := MDR; Inc_PC; Inc(Data, X); EAL := DataL; MAR := EA; end; // receive address high byte, calculate address, read from unfinished address
_5_Absolute_X_rmw: begin Inc(EAH, DataH); MAR := EA; end; // fix address, read data
_6_Absolute_X_rmw: begin RW := wr; end; // write old data (CMOS: read)
_7_Absolute_X_rmw: begin Instruction; end; // write new data
_1_Absolute_X_rmw: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_Absolute_X_rmw: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute Y indexed (read) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_Y_rd: begin Data := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_Y_rd: begin EAH := MDR; Inc_PC; Inc(Data, Y); EAL := DataL; MAR := EA; Inc(Cycle, DataH XOR 1); end; // receive address high byte, calculate address, skip cycle if no overflow (DataH = 0)
_5_Absolute_Y_rd: begin Inc(EAH); MAR := EA; end; // fix address, read data
_1_Absolute_Y_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_Absolute_Y_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// absolute Y indexed (write) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_Y_wr: begin Data := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_Y_wr: begin EAH := MDR; Inc_PC; Inc(Data, Y); EAL := DataL; MAR := EA; end; // receive address high byte, calculate address, read from unfinished address
_5_Absolute_Y_wr: begin Inc(EAH, DataH); MAR := EA; RW := wr; Instruction; end; // fix address, write data
_1_Absolute_Y_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_Absolute_Y_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute Y indexed (read-modify-write) (unofficial) -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_Y_rmw: begin Data := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_Y_rmw: begin EAH := MDR; Inc_PC; Inc(Data, Y); EAL := DataL; MAR := EA; end; // receive address high byte, calculate address, read from unfinished address
_5_Absolute_Y_rmw: begin Inc(EAH, DataH); MAR := EA; end; // fix address, read data
_6_Absolute_Y_rmw: begin RW := wr; end; // write old data (CMOS: read)
_7_Absolute_Y_rmw: begin Instruction; end; // write new data
_1_Absolute_Y_rmw: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_Absolute_Y_rmw: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// absolute indirect (JMP) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Absolute_Indirect_JMP: begin EA := MDR; Inc_PC; MAR := PC; end; // receive address low byte, fetch address high byte
_4_Absolute_Indirect_JMP: begin EAH := MDR; Inc_PC; MAR := EA; end; // receive address high byte, read new PCL
_5_Absolute_Indirect_JMP: begin PCL := MDR; Inc(EAL); MAR := EA; end; // receive new PCL, read new PCH (no page crossing)
_1_Absolute_Indirect_JMP: begin PCH := MDR; MAR := PC; end; // receive new PCH, fetch next opcode
_2_Absolute_Indirect_JMP: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page (read) ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_rd: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read data
_1_ZP_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_ZP_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// zero page (write) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_wr: begin EA := MDR; Inc_PC; MAR := EA; RW := wr; Instruction; end; // receive address low byte, write data
_1_ZP_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page (read-modify-write) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_rmw: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read data
_4_ZP_rmw: begin RW := wr; end; // write old data (CMOS: read)
_5_ZP_rmw: begin Instruction; end; // write new data
_1_ZP_rmw: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_rmw: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page X indexed (read) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_X_rd: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read from unfinished address
_4_ZP_X_rd: begin EA := u8(EA + X); MAR := EA; end; // calculate address, read data
_1_ZP_X_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_ZP_X_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// zero page X indexed (write) -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_X_wr: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read from unfinished address
_4_ZP_X_wr: begin EA := u8(EA + X); MAR := EA; RW := wr; Instruction; end; // calculate address, write data
_1_ZP_X_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_X_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page X indexed (read-modify-write) -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_X_rmw: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read from unfinished address
_4_ZP_X_rmw: begin EA := u8(EA + X); MAR := EA; end; // calculate address, read data
_5_ZP_X_rmw: begin RW := wr; end; // write old data (CMOS: read)
_6_ZP_X_rmw: begin Instruction; end; // write new data
_1_ZP_X_rmw: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_X_rmw: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page Y indexed (read) ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_Y_rd: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read from unfinished address
_4_ZP_Y_rd: begin EA := u8(EA + Y); MAR := EA; end; // calculate address, read data
_1_ZP_Y_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_ZP_Y_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// zero page Y indexed (write) -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_Y_wr: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read from unfinished address
_4_ZP_Y_wr: begin EA := u8(EA + Y); MAR := EA; RW := wr; Instruction; end; // calculate address, write data
_1_ZP_Y_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_Y_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page X indexed indirect (read) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_X_Indirect_rd: begin Data := MDR; Inc_PC; MAR := Data; end; // receive address low byte, read from unfinished address
_4_ZP_X_Indirect_rd: begin Data := u8(Data + X); MAR := Data; end; // calculate address, read pointer low byte
_5_ZP_X_Indirect_rd: begin EA := MDR; Inc(DataL); MAR := Data; end; // receive pointer low byte, read pointer high byte
_6_ZP_X_Indirect_rd: begin EAH := MDR; MAR := EA; end; // receive pointer high byte, read data
_1_ZP_X_Indirect_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_ZP_X_Indirect_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// zero page X indexed indirect (write) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_X_Indirect_wr: begin Data := MDR; Inc_PC; MAR := Data; end; // receive address low byte, read from unfinished address
_4_ZP_X_Indirect_wr: begin Data := u8(Data + X); MAR := Data; end; // calculate address, read pointer low byte
_5_ZP_X_Indirect_wr: begin EA := MDR; Inc(DataL); MAR := Data; end; // receive pointer low byte, read pointer high byte
_6_ZP_X_Indirect_wr: begin EAH := MDR; MAR := EA; RW := wr; Instruction; end; // receive pointer high byte, write data
_1_ZP_X_Indirect_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_X_Indirect_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page X indexed indirect (read-modify-write) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_X_Indirect_rmw: begin Data := MDR; Inc_PC; MAR := Data; end; // receive address low byte, read from unfinished address
_4_ZP_X_Indirect_rmw: begin Data := u8(Data + X); MAR := Data; end; // calculate address, read pointer low byte
_5_ZP_X_Indirect_rmw: begin EA := MDR; Inc(DataL); MAR := Data; end; // receive pointer low byte, read pointer high byte
_6_ZP_X_Indirect_rmw: begin EAH := MDR; MAR := EA; end; // receive pointer high byte, read data
_7_ZP_X_Indirect_rmw: begin RW := wr; end; // write old data (CMOS: read)
_8_ZP_X_Indirect_rmw: begin Instruction; end; // write new data
_1_ZP_X_Indirect_rmw: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_X_Indirect_rmw: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page indirect Y indexed (read) ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_Indirect_Y_rd: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read pointer low byte
_4_ZP_Indirect_Y_rd: begin Data := MDR; Inc(EAL); Inc(Data, Y); MAR := EA; end; // receive pointer low byte, read pointer high byte, calculate address
_5_ZP_Indirect_Y_rd: begin EAH := MDR; EAL := DataL; MAR := EA; Inc(Cycle, DataH XOR 1); end; // receive pointer high byte, skip cycle if no overflow (DataH = 0)
_6_ZP_Indirect_Y_rd: begin Inc(EAH); MAR := EA; end; // fix address, read data
_1_ZP_Indirect_Y_rd: begin Data := MDR; MAR := PC; end; // receive data, fetch next opcode
_2_ZP_Indirect_Y_rd: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// zero page indirect Y indexed (write) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_Indirect_Y_wr: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read pointer low byte
_4_ZP_Indirect_Y_wr: begin Data := MDR; Inc(EAL); Inc(Data, Y); MAR := EA; end; // receive pointer low byte, read pointer high byte, calculate address
_5_ZP_Indirect_Y_wr: begin EAH := MDR; EAL := DataL; MAR := EA; end; // receive pointer high byte, read from unfinished address
_6_ZP_Indirect_Y_wr: begin Inc(EAH, DataH); MAR := EA; RW := wr; Instruction; end; // fix address, write data
_1_ZP_Indirect_Y_wr: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_Indirect_Y_wr: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// zero page indirect Y indexed (read-modify-write) --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_ZP_Indirect_Y_rmw: begin EA := MDR; Inc_PC; MAR := EA; end; // receive address low byte, read pointer low byte
_4_ZP_Indirect_Y_rmw: begin Data := MDR; Inc(EAL); Inc(Data, Y); MAR := EA; end; // receive pointer low byte, read pointer high byte, calculate address
_5_ZP_Indirect_Y_rmw: begin EAH := MDR; EAL := DataL; MAR := EA; end; // receive pointer high byte, read from unfinished address
_6_ZP_Indirect_Y_rmw: begin Inc(EAH, DataH); MAR := EA; end; // fix address, read old data
_7_ZP_Indirect_Y_rmw: begin RW := wr; end; // write old data (CMOS: read)
_8_ZP_Indirect_Y_rmw: begin Instruction; end; // write new data
_1_ZP_Indirect_Y_rmw: begin MAR := PC; RW := rd; end; // fetch next opcode
_2_ZP_Indirect_Y_rmw: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// immediate -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_1_Immediate: begin Data := MDR; Inc_PC; MAR := PC; end; // receive next byte, fetch next opcode
_2_Immediate: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// implied -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_1_Implied: begin end; // don't advance PC, fetch next opcode (same byte)
_2_Implied: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// implied (PHx) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Implied_PHx: begin MAR := S; RW := wr; Instruction; end; // push accumulator/flags
_1_Implied_PHx: begin Dec(SL); MAR := PC; RW := rd; end; // fetch next opcode
_2_Implied_PHx: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// implied (PLx) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Implied_PLx: begin MAR := S; end; // internal operation
_4_Implied_PLx: begin Inc(SL); MAR := S; end; // pull data
_1_Implied_PLx: begin Data := MDR; MAR := PC; end; // save data (for PLP), fetch next opcode
_2_Implied_PLx: begin prev := Instruction; Update_IR_PC; prev; MAR := PC; end; // finish, fetch next byte
// implied (RTI) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Implied_RTI: begin MAR := S; end; // internal operation
_4_Implied_RTI: begin Inc(SL); MAR := S; end; // pull P (sets i which sets other internal variables)
_5_Implied_RTI: begin P := MDR; Inc(SL); MAR := S; end; // receive P, pull PCL
_6_Implied_RTI: begin PCL := MDR; Inc(SL); MAR := S; end; // receive PCL, pull PCH
_1_Implied_RTI: begin PCH := MDR; MAR := PC; end; // receive PCH, fetch next opcode
_2_Implied_RTI: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// implied (RTS) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Implied_RTS: begin MAR := S; end; // internal operation
_4_Implied_RTS: begin Inc(SL); MAR := S; end; // pull PCL
_5_Implied_RTS: begin PCL := MDR; Inc(SL); MAR := S; end; // receive PCL, pull PCH
_6_Implied_RTS: begin PCH := MDR; MAR := PC; end; // receive PCH, fetch from unfinished address
_1_Implied_RTS: begin Inc_PC; MAR := PC; end; // adjust PC, fetch next opcode
_2_Implied_RTS: begin Update_IR_PC; MAR := PC; end; // finish, fetch next byte
// implied (JAM) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_1_JAM: begin if (not RES) then Cycle := _1_JAM; MAR := Bits16; MDR := Bits8; end; // wait for /RESET pin = 0
_2_JAM: begin if ( RES) then Cycle := _2_JAM; MDR := Bits8; end; // wait for /RESET pin = 1, then advance to BRK ↓
// implied (BRK) -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{$define Get_Vector := begin
; if RES then EA := %1111111111111110 - Bit1 // $FFFC: RESET
else if NMI then EA := %1111111111111110 - Bit2 // $FFFA: NMI
else EA := %1111111111111110; // $FFFE: IRQ/BRK
end}
{$define BRK_RW := if (not RES) then RW := wr }
_3_Implied_BRK: begin Inc(PCW, 1 AND Interrupt_Mask); MAR := S; BRK_RW; MDR := PCH; end; // skip byte if no interrupt, push PCH (RESET: pull)
_4_Implied_BRK: begin Dec(SL); MAR := S; MDR := PCL; end; // push PCL (RESET: pull)
_5_Implied_BRK: begin Dec(SL); Get_Vector; MAR := S; MDR := P XOR b_toggle; end; // get vector and P, push P (RESET: pull)
_6_Implied_BRK: begin i := i_set; Dec(SL); MAR := EA; RW := rd; end; // mask IRQs, read new PCL
_7_Implied_BRK: begin PCL := MDR; Inc(EAL); MAR := EA; end; // receive new PCL, read new PCH
_1_Implied_BRK: begin PCH := MDR; MAR := PC; end; // receive new PCH, fetch next opcode
_2_Implied_BRK: begin NMI := False; Update_IR_PC(Bits32); MAR := PC; end; // finish, fetch next byte
// relative ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
_3_Relative: // cycle 3 of the current instruction if the branch condition is true, or cycle 1 of the next instruction
begin
Inc_PC;
// c 0 .......x $10: 00010000 n = 0 $50: 01010000 v = 0
// z 1 ......x. $30: 00110000 n <> 0 $70: 01110000 v <> 0
// i 2 .....x..
// d 3 ....x... $D0: 11010000 z = 0 $90: 10010000 c = 0
// b 4 ...x.... $F0: 11110000 z <> 0 $B0: 10110000 c <> 0
// r 5 ..x.....
// v 6 .x...... IR bits 7..6: %00 = n, %01 = v, %10 = c, %11 = z
// n 7 x....... IR bit 5: 0 = flag must be zero, 1 = flag must be nonzero
Instruction; // check condition (todo: decode directly from IR?)
if (Data <> 0) then begin
Data := u16(PC + i8(MDR)); // add signed operand to PC
PCL := DataL; // PC may be off by $0100
Cycle := _4_Relative_BranchTaken;
end;
MAR := PC; // fetch next opcode
end;
_4_Relative_BranchNotTaken: // cycle 4 of the current instruction, or cycle 2 of the next instruction
begin
Update_IR_PC; // receive and decode opcode (checking interrupts), advance PC, select new instruction cycle
MAR := PC; // fetch operand
end;
_4_Relative_BranchTaken: // cycle 4 of the current instruction, or cycle 2 of the next instruction
begin
if (PC = Data) // PC was already correct?
then Update_IR_PC(Bits32) // no interrupt check, see https://www.nesdev.org/wiki/Visual6502wiki/6502_Timing_of_Interrupt_Handling
else PC := Data; // fix PC, go to cycle 5
MAR := PC; // fetch operand if no page crossed, else fetch opcode
end;
_5_Relative_BranchTaken_PageCrossed: // cycle 5 of the current instruction, or cycle 2 of the next instruction
begin
Update_IR_PC; // with interrupt check
MAR := PC;
end;
end;
end;
procedure MOS_6502.Update_IR_PC(const Ignore_Interrupts : u32 = Bits0); // TODO: use a look-up table instead
var
is_multibyte : u32;
u : u32;
begin
// single-byte opcode pattern $x8 = %xxxx1000
// single-byte opcode pattern $xA = %xxxx1010
// common bits = %xxxx10x0
is_multibyte := is_not_zero((IR AND %00001101) XOR Bit3); // 0 = single-byte instruction, 1 = multi-byte instruction
// Interrupt_Mask: either all bits 1 (use MDR as IR, advance PC) or all bits 0 (clear IR, halt PC)
// Ignore_Interrupts: either all bits 0 (use Interrupt_Mask) or all bits 1 (ignore Interrupt_Mask)
u := Interrupt_Mask OR Ignore_Interrupts; // Ignore_Interrupts can 'overwrite' Interrupt_Mask
IR := MDR AND u; // clear IR only if an interrupt is pending and Ignore_Interrupts = Bits0
Inc(PCW, is_multibyte AND u); // halt PC only if an interrupt is pending and Ignore_Interrupts = Bits0
end;
Editor is loading...