diff --git a/README.md b/README.md index 2aae72b..8749e0d 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ - [X] ADC - [X] AND - [X] ASL -- [ ] BCC +- [X] BCC - [ ] BCS - [ ] BEQ - [ ] BIT diff --git a/src/cpu/instructions.rs b/src/cpu/instructions.rs index 22f17bc..f80d59b 100644 --- a/src/cpu/instructions.rs +++ b/src/cpu/instructions.rs @@ -6,6 +6,7 @@ use std::collections::HashMap; pub enum AddressingMode { Implicit, Accumulator, + Relative, Immediate, ZeroPage, ZeroPage_X, @@ -62,6 +63,7 @@ pub static INSTRUCTIONS: Lazy> = Lazy::new(|| { Instruction {opcode: 0x16, name: "ASL", bytes: 2, addressing_mode: AddressingMode::ZeroPage_X}, Instruction {opcode: 0x0E, name: "ASL", bytes: 3, addressing_mode: AddressingMode::Absolute}, Instruction {opcode: 0x1E, name: "ASL", bytes: 3, addressing_mode: AddressingMode::Absolute_X}, + Instruction {opcode: 0x90, name: "BCC", bytes: 2, addressing_mode: AddressingMode::Relative}, Instruction {opcode: 0x00, name: "BRK", bytes: 1, addressing_mode: AddressingMode::Implicit}, Instruction {opcode: 0xA9, name: "LDA", bytes: 2, addressing_mode: AddressingMode::Immediate}, Instruction {opcode: 0xA5, name: "LDA", bytes: 2, addressing_mode: AddressingMode::ZeroPage}, diff --git a/src/cpu/mod.rs b/src/cpu/mod.rs index 5088e05..c167983 100644 --- a/src/cpu/mod.rs +++ b/src/cpu/mod.rs @@ -1,6 +1,6 @@ mod instructions; -use std::ops::{Add, Shl}; +use std::ops::{Add, Shl, Sub}; use crate::cpu::instructions::*; @@ -127,6 +127,10 @@ impl CPU { self.status = self.status & 0b1111_1110; } + fn carry_flag_is_clear(&self) -> bool { + return self.status & 0b0000_0001 == 0; + } + fn set_overflow_flag(&mut self) { self.status = self.status | 0b0100_0000; } @@ -141,12 +145,6 @@ impl CPU { fn get_operand_address(&mut self, addressing_mode: &AddressingMode) -> u16 { match addressing_mode { - AddressingMode::Implicit => { - panic!("Cannot get operand address when the Addressing Mode is Implicit"); - } - AddressingMode::Accumulator => { - panic!("Cannot get operand address when the Addressing Mode is Accumulator"); - } AddressingMode::Immediate => self.program_counter, AddressingMode::ZeroPage => self.mem_read(self.program_counter) as u16, AddressingMode::ZeroPage_X => self @@ -188,6 +186,12 @@ impl CPU { self.mem_read_u16(indirect_address) .wrapping_add(self.register_y as u16) } + _ => { + panic!( + "Cannot get operand address when the Addressing Mode is {:?}", + addressing_mode + ); + } } } @@ -250,6 +254,17 @@ impl CPU { } } + fn bcc(&mut self) { + if self.carry_flag_is_clear() { + if self.mem_read(self.program_counter) > 0x7F { + let distance = 0xFF - self.mem_read(self.program_counter) + 1; + self.program_counter -= distance as u16; + } else { + self.program_counter += self.mem_read(self.program_counter) as u16 - 1; + } + } + } + fn lda(&mut self, addressing_mode: &AddressingMode) { let operand = self.get_operand(addressing_mode); self.register_a = operand; @@ -471,6 +486,18 @@ mod test_cpu { assert_eq!(cpu.status, expected_status); } + #[test_case(0b0000_0001, 0x8080, 0x8080, 0x06)] + #[test_case(0b0000_0000, 0xE004, 0xE009, 0x06)] + #[test_case(0b0000_0000, 0xE009, 0xE003, 0xFA)] + fn test_bcc(status: u8, program_counter: u16, expected_program_counter: u16, distance: u8) { + let mut cpu = CPU::new(); + cpu.status = status; + cpu.program_counter = program_counter; + cpu.memory[cpu.program_counter as usize] = distance; + cpu.bcc(); + assert_eq!(cpu.program_counter, expected_program_counter); + } + #[test_case(0b0000_0001, 0x5, 0x4, 0x1, 0b0000_0001)] #[test_case(0b0000_0001, 0x5, 0x5, 0x0, 0b0000_0011)] #[test_case(0b0000_0001, 0x0, 0x1, 0xFF, 0b1000_0000)]