6502

 avatar
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...