From 1b9024373897a1c939a2af5fcef4d7f3cd9d4b1c Mon Sep 17 00:00:00 2001 From: Sam M W Date: Thu, 13 Apr 2023 10:23:55 +0100 Subject: [PATCH 01/10] implementation of RTS --- src/cpu.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index a2a0d0c..3cec77d 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -409,11 +409,13 @@ impl CPU { } (Instruction::PLA, OpInput::UseImplied) => { // Pull accumulator + self.pull_from_stack(); let val: u8 = self.pull_from_stack(); self.registers.accumulator = val as i8; } (Instruction::PLP, OpInput::UseImplied) => { // Pull status + self.pull_from_stack(); let val: u8 = self.pull_from_stack(); // The `truncate` here won't do anything because we have a // constant for the single unused flags bit. This probably @@ -443,6 +445,12 @@ impl CPU { CPU::::rotate_right_with_flags(&mut operand, &mut self.registers.status); self.memory.set_byte(addr, operand); } + (Instruction::RTS, OpInput::UseImplied) => { + self.pull_from_stack(); + let pcl: u8 = self.pull_from_stack(); + let pch: u8 = self.fetch_from_stack(); + self.registers.program_counter = (((pch as u16) << 8) | pcl as u16).wrapping_add(1); + } (Instruction::SBC, OpInput::UseImmediate(val)) => { debug!("subtract with carry immediate: {}", val); @@ -921,6 +929,12 @@ impl CPU { self.registers.stack_pointer.increment(); out } + + fn fetch_from_stack(&mut self) -> u8 { + // gets the next value on the stack but does not update the stack pointer + let addr = self.registers.stack_pointer.to_u16(); + self.memory.get_byte(addr) + } } impl core::fmt::Debug for CPU { From 18164c7abfcab0a1b3c8301ad6aab4458cf3bea8 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 15:27:51 +0100 Subject: [PATCH 02/10] implement RTI as well --- src/cpu.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index 3cec77d..399990b 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -445,6 +445,18 @@ impl CPU { CPU::::rotate_right_with_flags(&mut operand, &mut self.registers.status); self.memory.set_byte(addr, operand); } + (Instruction::RTI, OpInput::UseImplied) => { + // Pull status + self.pull_from_stack(); + let val: u8 = self.pull_from_stack(); + // The `truncate` here won't do anything because we have a + // constant for the single unused flags bit. This probably + // corresponds to the behavior of the 6502...? FIXME: verify + self.registers.status = Status::from_bits_truncate(val); + let pcl: u8 = self.pull_from_stack(); + let pch: u8 = self.fetch_from_stack(); + self.registers.program_counter = ((pch as u16) << 8) | pcl as u16; + } (Instruction::RTS, OpInput::UseImplied) => { self.pull_from_stack(); let pcl: u8 = self.pull_from_stack(); From 8e797b70fa04bfd62b01eef08dbd63764c236a02 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 16:17:51 +0100 Subject: [PATCH 03/10] implement BNE --- src/cpu.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index 399990b..a63e6c2 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -228,6 +228,11 @@ impl CPU { self.branch_if_equal(addr); } + (Instruction::BNE, OpInput::UseRelative(rel)) => { + let addr = self.registers.program_counter.wrapping_add(rel); + self.branch_if_not_equal(addr); + } + (Instruction::BIT, OpInput::UseAddress(addr)) => { let a: u8 = self.registers.accumulator as u8; let m: u8 = self.memory.get_byte(addr); @@ -850,6 +855,12 @@ impl CPU { } } + fn branch_if_not_equal(&mut self, addr: u16) { + if !self.registers.status.contains(Status::PS_ZERO) { + self.registers.program_counter = addr; + } + } + fn branch_if_minus(&mut self, addr: u16) { if self.registers.status.contains(Status::PS_NEGATIVE) { self.registers.program_counter = addr; From 239992ea6cba3a774eaf600f994e4243a2141da3 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 20:58:31 +0100 Subject: [PATCH 04/10] first stab at implementing the JSR instruction --- src/cpu.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index a63e6c2..07ee848 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -352,6 +352,13 @@ impl CPU { (Instruction::JMP, OpInput::UseAddress(addr)) => self.jump(addr), + (Instruction::JSR, OpInput::UseAddress(addr)) => { + for b in self.registers.program_counter.wrapping_sub(1).to_le_bytes() { + self.push_on_stack(b); + } + self.jump(addr); + } + (Instruction::LDA, OpInput::UseImmediate(val)) => { debug!("load A immediate: {}", val); self.load_accumulator(val as i8); From 1c31a73a2bda45001341325ef7b30700729dc44f Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 21:01:08 +0100 Subject: [PATCH 05/10] correct endianness for program counter push --- src/cpu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu.rs b/src/cpu.rs index 07ee848..c7edc21 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -353,7 +353,7 @@ impl CPU { (Instruction::JMP, OpInput::UseAddress(addr)) => self.jump(addr), (Instruction::JSR, OpInput::UseAddress(addr)) => { - for b in self.registers.program_counter.wrapping_sub(1).to_le_bytes() { + for b in self.registers.program_counter.wrapping_sub(1).to_be_bytes() { self.push_on_stack(b); } self.jump(addr); From a8d53f926d17ef3dfc42284a27474b257318d052 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 21:17:28 +0100 Subject: [PATCH 06/10] implement BRK --- src/cpu.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index c7edc21..38b0a0e 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -269,6 +269,16 @@ impl CPU { self.branch_if_positive(addr); } + (Instruction::BRK, 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); + } + (Instruction::BVC, OpInput::UseRelative(rel)) => { let addr = self.registers.program_counter.wrapping_add(rel); self.branch_if_overflow_clear(addr); From 62424070a149fbdc93b75899f530aaf97c602284 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 21:34:07 +0100 Subject: [PATCH 07/10] disable interrupts after BRK instruction --- src/cpu.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cpu.rs b/src/cpu.rs index 38b0a0e..53ef685 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -277,6 +277,7 @@ impl CPU { 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); } (Instruction::BVC, OpInput::UseRelative(rel)) => { From 26a2f51bc6d58658a47a03b700afdcc1af991b25 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 21:37:47 +0100 Subject: [PATCH 08/10] don't overshoot the stack pointer! (pla and plp) --- src/cpu.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cpu.rs b/src/cpu.rs index 53ef685..a9956bc 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -433,13 +433,13 @@ impl CPU { (Instruction::PLA, OpInput::UseImplied) => { // Pull accumulator self.pull_from_stack(); - let val: u8 = self.pull_from_stack(); + let val: u8 = self.fetch_from_stack(); self.registers.accumulator = val as i8; } (Instruction::PLP, OpInput::UseImplied) => { // Pull status self.pull_from_stack(); - let val: u8 = self.pull_from_stack(); + let val: u8 = self.fetch_from_stack(); // The `truncate` here won't do anything because we have a // constant for the single unused flags bit. This probably // corresponds to the behavior of the 6502...? FIXME: verify From f0fc9829db129e5c8932cb0ab4e28c8d308bf808 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 21:44:05 +0100 Subject: [PATCH 09/10] PLA opcode should update the flags --- src/cpu.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/cpu.rs b/src/cpu.rs index a9956bc..72f4e83 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -435,6 +435,14 @@ impl CPU { self.pull_from_stack(); let val: u8 = self.fetch_from_stack(); self.registers.accumulator = val as i8; + self.registers.status.set_with_mask( + Status::PS_ZERO | Status::PS_NEGATIVE, + Status::new(StatusArgs { + zero: val == 0, + negative: self.registers.accumulator < 0, + ..StatusArgs::none() + }), + ); } (Instruction::PLP, OpInput::UseImplied) => { // Pull status From bd1ab13dc10b418473c3f93693ad678c1b9970d9 Mon Sep 17 00:00:00 2001 From: Sam M W Date: Sat, 15 Apr 2023 21:47:17 +0100 Subject: [PATCH 10/10] point INY instruction at the correct register --- src/cpu.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cpu.rs b/src/cpu.rs index 72f4e83..2c2eb52 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -358,7 +358,7 @@ impl CPU { CPU::::increment(&mut self.registers.index_x, &mut self.registers.status); } (Instruction::INY, OpInput::UseImplied) => { - CPU::::increment(&mut self.registers.index_x, &mut self.registers.status); + CPU::::increment(&mut self.registers.index_y, &mut self.registers.status); } (Instruction::JMP, OpInput::UseAddress(addr)) => self.jump(addr),