From 309ad503746df0e392213f650a9ea1e15a93cc00 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Wed, 24 Apr 2024 12:13:13 +0100 Subject: [PATCH 01/12] simpler/more obvious way to select for different implementations on derivatives --- src/instruction.rs | 38 +++++++++++++------------------------- 1 file changed, 13 insertions(+), 25 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index f63dd5e..a7d7a69 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -455,24 +455,15 @@ pub struct Ricoh2a03; impl crate::Variant for Ricoh2a03 { fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> { - match opcode { - 0x61 => Some((Instruction::ADCnd, AddressingMode::IndexedIndirectX)), - 0x65 => Some((Instruction::ADCnd, AddressingMode::ZeroPage)), - 0x69 => Some((Instruction::ADCnd, AddressingMode::Immediate)), - 0x6d => Some((Instruction::ADCnd, AddressingMode::Absolute)), - 0x71 => Some((Instruction::ADCnd, AddressingMode::IndirectIndexedY)), - 0x75 => Some((Instruction::ADCnd, AddressingMode::ZeroPageX)), - 0x79 => Some((Instruction::ADCnd, AddressingMode::AbsoluteY)), - 0x7d => Some((Instruction::ADCnd, AddressingMode::AbsoluteX)), - 0xe1 => Some((Instruction::SBCnd, AddressingMode::IndexedIndirectX)), - 0xe5 => Some((Instruction::SBCnd, AddressingMode::ZeroPage)), - 0xe9 => Some((Instruction::SBCnd, AddressingMode::Immediate)), - 0xed => Some((Instruction::SBCnd, AddressingMode::Absolute)), - 0xf1 => Some((Instruction::SBCnd, AddressingMode::IndirectIndexedY)), - 0xf5 => Some((Instruction::SBCnd, AddressingMode::ZeroPageX)), - 0xf9 => Some((Instruction::SBCnd, AddressingMode::AbsoluteY)), - 0xfd => Some((Instruction::SBCnd, AddressingMode::AbsoluteX)), - _ => Nmos6502::decode(opcode), + // It's the same as on NMOS, but doesn't support decimal mode. + match Nmos6502::decode(opcode) { + Some((Instruction::ADC, addressing_mode)) => { + Some((Instruction::ADCnd, addressing_mode)) + } + Some((Instruction::SBC, addressing_mode)) => { + Some((Instruction::SBCnd, addressing_mode)) + } + something_else => something_else, } } } @@ -483,13 +474,10 @@ pub struct RevisionA; impl crate::Variant for RevisionA { fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> { - match opcode { - 0x66 => None, - 0x6a => None, - 0x6e => None, - 0x76 => None, - 0x7e => None, - _ => Nmos6502::decode(opcode), + // It's the same as on NMOS, but has no ROR instruction. + match Nmos6502::decode(opcode) { + Some((Instruction::ROR, _)) => None, + something_else => something_else, } } } From df51b077e738302d3d3d7f8daf3ae26c7e4e66e1 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Wed, 24 Apr 2024 12:16:27 +0100 Subject: [PATCH 02/12] add/implement BRA instruction for CMOS --- src/cpu.rs | 9 +++++++++ src/instruction.rs | 2 ++ 2 files changed, 11 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index 90e8dfa..b9dcc40 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -310,6 +310,11 @@ impl CPU { self.branch_if_positive(addr); } + (Instruction::BRA, OpInput::UseRelative(rel)) => { + let addr = self.registers.program_counter.wrapping_add(rel); + self.branch(addr); + } + (Instruction::BRK, OpInput::UseImplied) => { for b in self.registers.program_counter.wrapping_sub(1).to_be_bytes() { self.push_on_stack(b); @@ -1007,6 +1012,10 @@ impl CPU { } } + fn branch(&mut self, addr: u16) { + self.registers.program_counter = addr; + } + fn branch_if_positive(&mut self, addr: u16) { if !self.registers.status.contains(Status::PS_NEGATIVE) { self.registers.program_counter = addr; diff --git a/src/instruction.rs b/src/instruction.rs index a7d7a69..ede53c8 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -55,6 +55,7 @@ pub enum Instruction { BMI, // Branch if Minus............... | .. ..... PC = N BNE, // Branch if Not Equal........... | .. ..... PC = !Z BPL, // Branch if Positive............ | .. ..... PC = Z + BRA, // Unconditional BRAnch.......... | .. B.... S PC = BRK, // BReaK......................... | .. B.... S PC = BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V BVS, // Branch if oVerflow Set........ | .. ..... PC = V @@ -490,6 +491,7 @@ impl crate::Variant for Cmos6502 { // TODO: We obviously need to add the other CMOS instructions here. match opcode { 0x6c => Some((Instruction::JMP, AddressingMode::Indirect)), + 0x80 => Some((Instruction::BRA, AddressingMode::Relative)), _ => Nmos6502::decode(opcode), } } From 2c26ebb00a0a9573075d29fb6c2a009104145dff Mon Sep 17 00:00:00 2001 From: Sam M W Date: Wed, 24 Apr 2024 12:29:19 +0100 Subject: [PATCH 03/12] decode inc a and dec a on CMOS --- src/instruction.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/instruction.rs b/src/instruction.rs index ede53c8..88568ee 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -490,6 +490,8 @@ impl crate::Variant for Cmos6502 { fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> { // TODO: We obviously need to add the other CMOS instructions here. match opcode { + 0x1a => Some((Instruction::INC, AddressingMode::Accumulator)), + 0x3a => Some((Instruction::DEC, AddressingMode::Accumulator)), 0x6c => Some((Instruction::JMP, AddressingMode::Indirect)), 0x80 => Some((Instruction::BRA, AddressingMode::Relative)), _ => Nmos6502::decode(opcode), From 0f1c01ce602229eb2677651e67e33f7e868454b0 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Wed, 24 Apr 2024 14:38:29 +0100 Subject: [PATCH 04/12] implement stz --- src/cpu.rs | 3 +++ src/instruction.rs | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index b9dcc40..45fe5ed 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -580,6 +580,9 @@ impl CPU { (Instruction::STY, OpInput::UseAddress(addr)) => { self.memory.set_byte(addr, self.registers.index_y); } + (Instruction::STZ, OpInput::UseAddress(addr)) => { + self.memory.set_byte(addr, 0); + } (Instruction::TAX, OpInput::UseImplied) => { let val = self.registers.accumulator; diff --git a/src/instruction.rs b/src/instruction.rs index 88568ee..8854154 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -100,6 +100,7 @@ pub enum Instruction { STA, // STore Accumulator............. | .. ..... M = A STX, // STore X register.............. | .. ..... M = X STY, // STore Y register.............. | .. ..... M = Y + STZ, // STore Zero.................... | .. ..... M = Y TAX, // Transfer Accumulator to X..... | N. ...Z. X = A TAY, // Transfer Accumulator to Y..... | N. ...Z. Y = A TSX, // Transfer Stack pointer to X... | N. ...Z. X = S @@ -494,6 +495,10 @@ impl crate::Variant for Cmos6502 { 0x3a => Some((Instruction::DEC, AddressingMode::Accumulator)), 0x6c => Some((Instruction::JMP, AddressingMode::Indirect)), 0x80 => Some((Instruction::BRA, AddressingMode::Relative)), + 0x64 => Some((Instruction::STZ, AddressingMode::ZeroPage)), + 0x74 => Some((Instruction::STZ, AddressingMode::ZeroPageX)), + 0x9c => Some((Instruction::STZ, AddressingMode::Absolute)), + 0x9e => Some((Instruction::STZ, AddressingMode::AbsoluteX)), _ => Nmos6502::decode(opcode), } } From cfb956f6a2b0344f3ea45713325abda586751606 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 02:55:49 +0100 Subject: [PATCH 05/12] phx phy plx ply --- src/cpu.rs | 36 ++++++++++++++++++++++++++++++++++++ src/instruction.rs | 8 ++++++++ 2 files changed, 44 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index 45fe5ed..56eb4fb 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -471,11 +471,47 @@ impl CPU { let val = self.registers.accumulator; self.push_on_stack(val); } + (Instruction::PHX, OpInput::UseImplied) => { + // Push X + self.push_on_stack(self.registers.index_x); + } + (Instruction::PHY, OpInput::UseImplied) => { + // Push Y + self.push_on_stack(self.registers.index_y); + } (Instruction::PHP, OpInput::UseImplied) => { // Push status let val = self.registers.status.bits() | 0x30; self.push_on_stack(val); } + (Instruction::PLX, OpInput::UseImplied) => { + // Pull accumulator + self.pull_from_stack(); + let val: u8 = self.fetch_from_stack(); + self.registers.index_x = val; + self.registers.status.set_with_mask( + Status::PS_ZERO | Status::PS_NEGATIVE, + Status::new(StatusArgs { + zero: val == 0, + negative: self.registers.accumulator > 127, + ..StatusArgs::none() + }), + ); + } + (Instruction::PLY, OpInput::UseImplied) => { + // Pull accumulator + self.pull_from_stack(); + let val: u8 = self.fetch_from_stack(); + self.registers.index_y = val; + self.registers.status.set_with_mask( + Status::PS_ZERO | Status::PS_NEGATIVE, + Status::new(StatusArgs { + zero: val == 0, + negative: self.registers.accumulator > 127, + ..StatusArgs::none() + }), + ); + } (Instruction::PLA, OpInput::UseImplied) => { // Pull accumulator self.pull_from_stack(); diff --git a/src/instruction.rs b/src/instruction.rs index 8854154..3b97477 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -83,8 +83,12 @@ pub enum Instruction { NOP, // No OPeration.................. | .. ..... = ORA, // inclusive OR (bitwise)........ | N. ...Z. A = A | M PHA, // PusH Accumulator.............. | .. ..... S M = A + PHX, // PusH X........................ | .. ..... S M = A + PHY, // PusH Y........................ | .. ..... S M = A PHP, // PusH Processor status......... | .. ..... S M = F PLA, // PuLl Accumulator.............. | N. ...Z. A S = M (stack) + PLX, // PuLl X........................ | N. ...Z. A S = M (stack) + PLY, // PuLl Y........................ | N. ...Z. A S = M (stack) PLP, // PuLl Processor status......... | NV BDIZC S = M (stack) ROL, // ROtate Left................... | N. ...ZC A = C A rotated // or N. ...ZC M = C M rotated @@ -499,6 +503,10 @@ impl crate::Variant for Cmos6502 { 0x74 => Some((Instruction::STZ, AddressingMode::ZeroPageX)), 0x9c => Some((Instruction::STZ, AddressingMode::Absolute)), 0x9e => Some((Instruction::STZ, AddressingMode::AbsoluteX)), + 0x7a => Some((Instruction::PLY, AddressingMode::Implied)), + 0xfa => Some((Instruction::PLX, AddressingMode::Implied)), + 0x5a => Some((Instruction::PHY, AddressingMode::Implied)), + 0xda => Some((Instruction::PHX, AddressingMode::Implied)), _ => Nmos6502::decode(opcode), } } From ecf222f80b59cbee456716b340d4a45bc9b75bb1 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 11:42:37 +0100 Subject: [PATCH 06/12] BRK on CMOS clears the decimal flag --- src/cpu.rs | 12 ++++++++++++ src/instruction.rs | 2 ++ 2 files changed, 14 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index 56eb4fb..f7b1a29 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -326,6 +326,18 @@ impl CPU { self.registers.status.or(Status::PS_DISABLE_INTERRUPTS); } + (Instruction::BRKcld, OpInput::UseImplied) => { + for b in self.registers.program_counter.wrapping_sub(1).to_be_bytes() { + self.push_on_stack(b); + } + self.push_on_stack(self.registers.status.bits()); + let pcl = self.memory.get_byte(0xfffe); + let pch = self.memory.get_byte(0xffff); + self.jump(((pch as u16) << 8) | pcl as u16); + self.registers.status.or(Status::PS_DISABLE_INTERRUPTS); + self.registers.status.and(!Status::PS_DECIMAL_MODE); + } + (Instruction::BVC, OpInput::UseRelative(rel)) => { let addr = self.registers.program_counter.wrapping_add(rel); self.branch_if_overflow_clear(addr); diff --git a/src/instruction.rs b/src/instruction.rs index 3b97477..9f25291 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -57,6 +57,7 @@ pub enum Instruction { BPL, // Branch if Positive............ | .. ..... PC = Z BRA, // Unconditional BRAnch.......... | .. B.... S PC = BRK, // BReaK......................... | .. B.... S PC = + BRKcld,// BReaK, clearing decimal flag.. | .. BD... S PC = BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V BVS, // Branch if oVerflow Set........ | .. ..... PC = V CLC, // CLear Carry flag.............. | .. ....C = 0 @@ -495,6 +496,7 @@ impl crate::Variant for Cmos6502 { fn decode(opcode: u8) -> Option<(Instruction, AddressingMode)> { // TODO: We obviously need to add the other CMOS instructions here. match opcode { + 0x00 => Some((Instruction::BRKcld, AddressingMode::Implied)), 0x1a => Some((Instruction::INC, AddressingMode::Accumulator)), 0x3a => Some((Instruction::DEC, AddressingMode::Accumulator)), 0x6c => Some((Instruction::JMP, AddressingMode::Indirect)), From 6a52e0e88247547fc511a0789eaa873ab64e68b7 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 11:45:20 +0100 Subject: [PATCH 07/12] formatting --- src/instruction.rs | 72 +++++++++++++++++++++++----------------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 9f25291..86217b5 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -44,42 +44,42 @@ #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Instruction { - ADC, // ADd with Carry................ | NV ...ZC A = A + M + C - ADCnd, // ADd with Carry................ | NV ...ZC A = A + M + C - AND, // logical AND (bitwise)......... | N. ...Z. A = A && M - ASL, // Arithmetic Shift Left......... | N. ...ZC A = M << 1 - BCC, // Branch if Carry Clear......... | .. ..... PC = !C - BCS, // Branch if Carry Set........... | .. ..... PC = C - BEQ, // Branch if Equal (to zero?).... | .. ..... PC = Z - BIT, // BIT test...................... | NV ...Z. = A & M - BMI, // Branch if Minus............... | .. ..... PC = N - BNE, // Branch if Not Equal........... | .. ..... PC = !Z - BPL, // Branch if Positive............ | .. ..... PC = Z - BRA, // Unconditional BRAnch.......... | .. B.... S PC = - BRK, // BReaK......................... | .. B.... S PC = - BRKcld,// BReaK, clearing decimal flag.. | .. BD... S PC = - BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V - BVS, // Branch if oVerflow Set........ | .. ..... PC = V - CLC, // CLear Carry flag.............. | .. ....C = 0 - CLD, // Clear Decimal Mode............ | .. .D... = 0 - CLI, // Clear Interrupt Disable....... | .. ..I.. = 0 - CLV, // Clear oVerflow flag........... | .V ..... = 0 - CMP, // Compare....................... | N. ...ZC = A - M - CPX, // Compare X register............ | N. ...ZC = X - M - CPY, // Compare Y register............ | N. ...ZC = Y - M - DEC, // DECrement memory.............. | N. ...Z. M = M - 1 - DEX, // DEcrement X register.......... | N. ...Z. X = X - 1 - DEY, // DEcrement Y register.......... | N. ...Z. Y = Y - 1 - EOR, // Exclusive OR (bitwise)........ | N. ...Z. A = A ^ M - INC, // INCrement memory.............. | N. ...Z. M = M + 1 - INX, // INcrement X register.......... | N. ...Z. X = X + 1 - INY, // INcrement Y register.......... | N. ...Z. Y = Y + 1 - JMP, // JuMP.......................... | .. ..... S PC = - JSR, // Jump to SubRoutine............ | .. ..... S PC = - LDA, // LoaD Accumulator.............. | N. ...Z. A = M - LDX, // LoaD X register............... | N. ...Z. X = M - LDY, // LoaD Y register............... | N. ...Z. Y = M - LSR, // Logical Shift Right........... | N. ...ZC A = A/2 + ADC, // ADd with Carry................ | NV ...ZC A = A + M + C + ADCnd, // ADd with Carry................ | NV ...ZC A = A + M + C + AND, // logical AND (bitwise)......... | N. ...Z. A = A && M + ASL, // Arithmetic Shift Left......... | N. ...ZC A = M << 1 + BCC, // Branch if Carry Clear......... | .. ..... PC = !C + BCS, // Branch if Carry Set........... | .. ..... PC = C + BEQ, // Branch if Equal (to zero?).... | .. ..... PC = Z + BIT, // BIT test...................... | NV ...Z. = A & M + BMI, // Branch if Minus............... | .. ..... PC = N + BNE, // Branch if Not Equal........... | .. ..... PC = !Z + BPL, // Branch if Positive............ | .. ..... PC = Z + BRA, // Unconditional BRAnch.......... | .. B.... S PC = + BRK, // BReaK......................... | .. B.... S PC = + BRKcld, // BReaK, clearing decimal flag.. | .. BD... S PC = + BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V + BVS, // Branch if oVerflow Set........ | .. ..... PC = V + CLC, // CLear Carry flag.............. | .. ....C = 0 + CLD, // Clear Decimal Mode............ | .. .D... = 0 + CLI, // Clear Interrupt Disable....... | .. ..I.. = 0 + CLV, // Clear oVerflow flag........... | .V ..... = 0 + CMP, // Compare....................... | N. ...ZC = A - M + CPX, // Compare X register............ | N. ...ZC = X - M + CPY, // Compare Y register............ | N. ...ZC = Y - M + DEC, // DECrement memory.............. | N. ...Z. M = M - 1 + DEX, // DEcrement X register.......... | N. ...Z. X = X - 1 + DEY, // DEcrement Y register.......... | N. ...Z. Y = Y - 1 + EOR, // Exclusive OR (bitwise)........ | N. ...Z. A = A ^ M + INC, // INCrement memory.............. | N. ...Z. M = M + 1 + INX, // INcrement X register.......... | N. ...Z. X = X + 1 + INY, // INcrement Y register.......... | N. ...Z. Y = Y + 1 + JMP, // JuMP.......................... | .. ..... S PC = + JSR, // Jump to SubRoutine............ | .. ..... S PC = + LDA, // LoaD Accumulator.............. | N. ...Z. A = M + LDX, // LoaD X register............... | N. ...Z. X = M + LDY, // LoaD Y register............... | N. ...Z. Y = M + LSR, // Logical Shift Right........... | N. ...ZC A = A/2 // or N. ...ZC M = M/2 NOP, // No OPeration.................. | .. ..... = ORA, // inclusive OR (bitwise)........ | N. ...Z. A = A | M From d51ae3057b9596174a4d200043618d60d3dfe8c8 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 11:56:58 +0100 Subject: [PATCH 08/12] better commenting for Instruction enum --- src/instruction.rs | 279 +++++++++++++++++++++++++++++++-------------- 1 file changed, 194 insertions(+), 85 deletions(-) diff --git a/src/instruction.rs b/src/instruction.rs index 86217b5..ae8f3f1 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -25,93 +25,202 @@ // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. -// Abbreviations -// -// General -// -// M | `Memory location` -// -// Registers -// -// A | accumulator -// X | general purpose register -// Y | general purpose register -// F | processor status flags, collectively -// NV-BDIZC | processor status flags, individually -// S | stack pointer -// PC | program counter -// - #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum Instruction { - ADC, // ADd with Carry................ | NV ...ZC A = A + M + C - ADCnd, // ADd with Carry................ | NV ...ZC A = A + M + C - AND, // logical AND (bitwise)......... | N. ...Z. A = A && M - ASL, // Arithmetic Shift Left......... | N. ...ZC A = M << 1 - BCC, // Branch if Carry Clear......... | .. ..... PC = !C - BCS, // Branch if Carry Set........... | .. ..... PC = C - BEQ, // Branch if Equal (to zero?).... | .. ..... PC = Z - BIT, // BIT test...................... | NV ...Z. = A & M - BMI, // Branch if Minus............... | .. ..... PC = N - BNE, // Branch if Not Equal........... | .. ..... PC = !Z - BPL, // Branch if Positive............ | .. ..... PC = Z - BRA, // Unconditional BRAnch.......... | .. B.... S PC = - BRK, // BReaK......................... | .. B.... S PC = - BRKcld, // BReaK, clearing decimal flag.. | .. BD... S PC = - BVC, // Branch if oVerflow Clear...... | .. ..... PC = !V - BVS, // Branch if oVerflow Set........ | .. ..... PC = V - CLC, // CLear Carry flag.............. | .. ....C = 0 - CLD, // Clear Decimal Mode............ | .. .D... = 0 - CLI, // Clear Interrupt Disable....... | .. ..I.. = 0 - CLV, // Clear oVerflow flag........... | .V ..... = 0 - CMP, // Compare....................... | N. ...ZC = A - M - CPX, // Compare X register............ | N. ...ZC = X - M - CPY, // Compare Y register............ | N. ...ZC = Y - M - DEC, // DECrement memory.............. | N. ...Z. M = M - 1 - DEX, // DEcrement X register.......... | N. ...Z. X = X - 1 - DEY, // DEcrement Y register.......... | N. ...Z. Y = Y - 1 - EOR, // Exclusive OR (bitwise)........ | N. ...Z. A = A ^ M - INC, // INCrement memory.............. | N. ...Z. M = M + 1 - INX, // INcrement X register.......... | N. ...Z. X = X + 1 - INY, // INcrement Y register.......... | N. ...Z. Y = Y + 1 - JMP, // JuMP.......................... | .. ..... S PC = - JSR, // Jump to SubRoutine............ | .. ..... S PC = - LDA, // LoaD Accumulator.............. | N. ...Z. A = M - LDX, // LoaD X register............... | N. ...Z. X = M - LDY, // LoaD Y register............... | N. ...Z. Y = M - LSR, // Logical Shift Right........... | N. ...ZC A = A/2 - // or N. ...ZC M = M/2 - NOP, // No OPeration.................. | .. ..... = - ORA, // inclusive OR (bitwise)........ | N. ...Z. A = A | M - PHA, // PusH Accumulator.............. | .. ..... S M = A - PHX, // PusH X........................ | .. ..... S M = A - PHY, // PusH Y........................ | .. ..... S M = A - PHP, // PusH Processor status......... | .. ..... S M = F - PLA, // PuLl Accumulator.............. | N. ...Z. A S = M (stack) - PLX, // PuLl X........................ | N. ...Z. A S = M (stack) - PLY, // PuLl Y........................ | N. ...Z. A S = M (stack) - PLP, // PuLl Processor status......... | NV BDIZC S = M (stack) - ROL, // ROtate Left................... | N. ...ZC A = C A rotated - // or N. ...ZC M = C M rotated - ROR, // ROtate Right.................. | N. ...ZC A = C A rotated - // or N. ...ZC M = C M rotated - RTI, // ReTurn from Interrupt......... | NV BDIZC PC = M (stack) - RTS, // ReTurn from Subroutine........ | .. ..... PC = M (stack) - SBC, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C) - SBCnd, // SuBtract with Carry........... | NV ...ZC A = A-M-(1-C) - SEC, // SEt Carry flag................ | .. ....C = 1 - SED, // SEt Decimal flag.............. | .. .D... = 1 - SEI, // SEt Interrupt disable......... | .. ..I.. = 1 - STA, // STore Accumulator............. | .. ..... M = A - STX, // STore X register.............. | .. ..... M = X - STY, // STore Y register.............. | .. ..... M = Y - STZ, // STore Zero.................... | .. ..... M = Y - TAX, // Transfer Accumulator to X..... | N. ...Z. X = A - TAY, // Transfer Accumulator to Y..... | N. ...Z. Y = A - TSX, // Transfer Stack pointer to X... | N. ...Z. X = S - TXA, // Transfer X to Accumulator..... | N. ...Z. A = X - TXS, // Transfer X to Stack pointer... | .. ..... S = X - TYA, // Transfer Y to Accumulator..... | N. ...Z. A = Y + // ADd with Carry + ADC, + + // ADd with Carry. This one has now decimal mode. + ADCnd, + + // logical AND (bitwise) + AND, + + // Arithmetic Shift Left + ASL, + + // Branch if Carry Clear + BCC, + + // Branch if Carry Set + BCS, + + // Branch if Equal (to zero?) + BEQ, + + // BIT test + BIT, + + // Branch if Minus + BMI, + + // Branch if Not Equal + BNE, + + // Branch if Positive + BPL, + + // Unconditional BRAnch + BRA, + + // BReaK + BRK, + + // BReaK, clearing decimal flag + BRKcld, + + // Branch if oVerflow Clear + BVC, + + // Branch if oVerflow Set + BVS, + + // CLear Carry flag + CLC, + + // Clear Decimal Mode + CLD, + + // Clear Interrupt Disable + CLI, + + // Clear oVerflow flag + CLV, + + // Compare + CMP, + + // Compare X register + CPX, + + // Compare Y register + CPY, + + // DECrement memory + DEC, + + // DEcrement X register + DEX, + + // DEcrement Y register + DEY, + + // Exclusive OR (bitwise) + EOR, + + // INCrement memory + INC, + + // INcrement X register + INX, + + // INcrement Y register + INY, + + // JuMP + JMP, + + // Jump to SubRoutine + JSR, + + // LoaD Accumulator + LDA, + + // LoaD X register + LDX, + + // LoaD Y register + LDY, + + // Logical Shift Right + LSR, + + // No OPeration + NOP, + + // inclusive OR (bitwise) + ORA, + + // PusH Accumulator + PHA, + + // PusH X + PHX, + + // PusH Y + PHY, + + // PusH Processor status + PHP, + + // PuLl Accumulator + PLA, + + // PuLl X + PLX, + + // PuLl Y + PLY, + + // PuLl Processor status + PLP, + + // ROtate Left + ROL, + + // ROtate Right + ROR, + + // ReTurn from Interrupt + RTI, + + // ReTurn from Subroutine + RTS, + + // SuBtract with Carry + SBC, + + // SuBtract with Carry. This one has now decimal mode. + SBCnd, + + // SEt Carry flag + SEC, + + // SEt Decimal flag + SED, + + // SEt Interrupt disable + SEI, + + // STore Accumulator + STA, + + // STore X register + STX, + + // STore Y register + STY, + + // STore Zero + STZ, + + // Transfer Accumulator to X + TAX, + + // Transfer Accumulator to Y + TAY, + + // Transfer Stack pointer to X + TSX, + + // Transfer X to Accumulator + TXA, + + // Transfer X to Stack pointer + TXS, + + // Transfer Y to Accumulator + TYA, } #[derive(Copy, Clone)] From 747d620943123b0fc62892587f686d4272130efa Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 14:04:54 +0100 Subject: [PATCH 09/12] trb tsb --- src/cpu.rs | 32 ++++++++++++++++++++++++++++++++ src/instruction.rs | 10 ++++++++++ 2 files changed, 42 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index f7b1a29..ca83e11 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -640,6 +640,38 @@ impl CPU { let val = self.registers.accumulator; self.load_y_register(val); } + (Instruction::TRB, OpInput::UseAddress(addr)) => { + let val = self.memory.get_byte(addr); + + // The zero flag is set based on the result of the 'and'. + self.registers.status.set_with_mask( + Status::PS_ZERO, + Status::new(StatusArgs { + zero: 0 == (self.registers.accumulator & val), + ..StatusArgs::none() + }), + ); + + // The 1's in the accumulator set the corresponding bits in the operand + let res = self.registers.accumulator | val; + self.memory.set_byte(addr, res); + } + (Instruction::TSB, OpInput::UseAddress(addr)) => { + let val = self.memory.get_byte(addr); + + // The zero flag is set based on the result of the 'and'. + self.registers.status.set_with_mask( + Status::PS_ZERO, + Status::new(StatusArgs { + zero: 0 == (self.registers.accumulator & val), + ..StatusArgs::none() + }), + ); + + // The 1's in the accumulator clear the corresponding bits in the operand + let res = (self.registers.accumulator ^ 0xff) & val; + self.memory.set_byte(addr, res); + } (Instruction::TSX, OpInput::UseImplied) => { let StackPointer(val) = self.registers.stack_pointer; self.load_x_register(val); diff --git a/src/instruction.rs b/src/instruction.rs index ae8f3f1..9ea3cfa 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -210,6 +210,12 @@ pub enum Instruction { // Transfer Accumulator to Y TAY, + // Test and Reset Bits + TRB, + + // Test and Set Bits + TSB, + // Transfer Stack pointer to X TSX, @@ -618,6 +624,10 @@ impl crate::Variant for Cmos6502 { 0xfa => Some((Instruction::PLX, AddressingMode::Implied)), 0x5a => Some((Instruction::PHY, AddressingMode::Implied)), 0xda => Some((Instruction::PHX, AddressingMode::Implied)), + 0x04 => Some((Instruction::TSB, AddressingMode::ZeroPage)), + 0x14 => Some((Instruction::TRB, AddressingMode::ZeroPage)), + 0x0c => Some((Instruction::TSB, AddressingMode::Absolute)), + 0x1c => Some((Instruction::TRB, AddressingMode::Absolute)), _ => Nmos6502::decode(opcode), } } From 8704fd55bf38d96899e3f0bf53c991c6a469f75c Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 14:15:19 +0100 Subject: [PATCH 10/12] add the cmos addressing mode, indirect unindexed --- src/cpu.rs | 10 ++++++++++ src/instruction.rs | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index ca83e11..60c0af9 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -201,6 +201,16 @@ impl CPU { address_from_bytes(slice[0], slice[1]).wrapping_add(y.into()), ) } + AddressingMode::ZeroPageIndirect => { + // Use [u8, ..1] from instruction + // This is where the absolute (16-bit) target address is stored. + // (Output: a 16-bit address) + let start = slice[0]; + let slice = read_address(memory, u16::from(start)); + OpInput::UseAddress( + address_from_bytes(slice[0], slice[1]) + ) + } }; // Increment program counter diff --git a/src/instruction.rs b/src/instruction.rs index 9ea3cfa..89ee8b0 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -280,6 +280,9 @@ pub enum AddressingMode { // load from (address stored at constant zero page address) plus Y register, e. g. `lda ($10),Y`. IndirectIndexedY, + + // Address stored at constant zero page address + ZeroPageIndirect, } impl AddressingMode { @@ -299,6 +302,7 @@ impl AddressingMode { AddressingMode::BuggyIndirect => 2, AddressingMode::IndexedIndirectX => 1, AddressingMode::IndirectIndexedY => 1, + AddressingMode::ZeroPageIndirect => 1, } } } @@ -628,6 +632,14 @@ impl crate::Variant for Cmos6502 { 0x14 => Some((Instruction::TRB, AddressingMode::ZeroPage)), 0x0c => Some((Instruction::TSB, AddressingMode::Absolute)), 0x1c => Some((Instruction::TRB, AddressingMode::Absolute)), + 0x12 => Some((Instruction::ORA, AddressingMode::ZeroPageIndirect)), + 0x32 => Some((Instruction::AND, AddressingMode::ZeroPageIndirect)), + 0x52 => Some((Instruction::EOR, AddressingMode::ZeroPageIndirect)), + 0x72 => Some((Instruction::ADC, AddressingMode::ZeroPageIndirect)), + 0x92 => Some((Instruction::STA, AddressingMode::ZeroPageIndirect)), + 0xb2 => Some((Instruction::LDA, AddressingMode::ZeroPageIndirect)), + 0xd2 => Some((Instruction::CMP, AddressingMode::ZeroPageIndirect)), + 0xf2 => Some((Instruction::SBC, AddressingMode::ZeroPageIndirect)), _ => Nmos6502::decode(opcode), } } From b62b6c74b027b95ca99d823cba7be4b2e848ac2b Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 14:16:40 +0100 Subject: [PATCH 11/12] fmt --- src/cpu.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 60c0af9..94b059a 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -207,9 +207,7 @@ impl CPU { // (Output: a 16-bit address) let start = slice[0]; let slice = read_address(memory, u16::from(start)); - OpInput::UseAddress( - address_from_bytes(slice[0], slice[1]) - ) + OpInput::UseAddress(address_from_bytes(slice[0], slice[1])) } }; From 536abef126d2379f21cf1d7272d30a38b8a776c7 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 27 Apr 2024 14:23:28 +0100 Subject: [PATCH 12/12] add immediate BIT instruction --- src/cpu.rs | 10 ++++++++++ src/instruction.rs | 1 + 2 files changed, 11 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index 94b059a..f346200 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -282,6 +282,16 @@ impl CPU { self.branch_if_not_equal(addr); } + (Instruction::BIT, OpInput::UseImmediate(val)) => { + self.registers.status.set_with_mask( + Status::PS_ZERO, + Status::new(StatusArgs { + zero: 0 == (self.registers.accumulator & val), + ..StatusArgs::none() + }), + ); + } + (Instruction::BIT, OpInput::UseAddress(addr)) => { let a: u8 = self.registers.accumulator; let m: u8 = self.memory.get_byte(addr); diff --git a/src/instruction.rs b/src/instruction.rs index 89ee8b0..3a3c659 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -640,6 +640,7 @@ impl crate::Variant for Cmos6502 { 0xb2 => Some((Instruction::LDA, AddressingMode::ZeroPageIndirect)), 0xd2 => Some((Instruction::CMP, AddressingMode::ZeroPageIndirect)), 0xf2 => Some((Instruction::SBC, AddressingMode::ZeroPageIndirect)), + 0x89 => Some((Instruction::BIT, AddressingMode::Immediate)), _ => Nmos6502::decode(opcode), } }