diff --git a/src/r6502/instructions.rs b/src/r6502/instructions.rs index fb05799..a30e8d7 100644 --- a/src/r6502/instructions.rs +++ b/src/r6502/instructions.rs @@ -257,17 +257,106 @@ impl Instructions pub fn ROL(cpu: &mut R6502, bus: &mut dyn Bus) { + let old_bit_7 = (cpu.working_data & 0x80) > 0; + let carry = cpu.check_flag(Flags::C) as u16; + let result = (cpu.working_data << 1) ^ carry; + + cpu.clear_flag(Flags::C); + if old_bit_7 + { + cpu.set_flag(Flags::C); + } + cpu.clear_flag(Flags::N); + if result & 0x80 > 0 + { + cpu.set_flag(Flags::N); + } + + cpu.clear_flag(Flags::Z); + if result == 0 + { + cpu.set_flag(Flags::Z); + } + + if cpu.addr_mode == ModeID::ACM + { + cpu.a = result as u8; + } + else + { + bus.write(cpu.working_addr, result as u8); + } + } pub fn LSR(cpu: &mut R6502, bus: &mut dyn Bus) { + let old_bit_0 = (cpu.working_data & 0x01) > 0; + let carry = cpu.check_flag(Flags::C) as u16; + let result = cpu.working_data >> 1; + + cpu.clear_flag(Flags::C); + if old_bit_0 + { + cpu.set_flag(Flags::C); + } + + cpu.clear_flag(Flags::N); + if result & 0x80 > 0 + { + cpu.set_flag(Flags::N); + } + + cpu.clear_flag(Flags::Z); + if result == 0 + { + cpu.set_flag(Flags::Z); + } + if cpu.addr_mode == ModeID::ACM + { + cpu.a = result as u8; + } + else + { + bus.write(cpu.working_addr, result as u8); + } } pub fn ROR(cpu: &mut R6502, bus: &mut dyn Bus) { + let old_bit_0 = (cpu.working_data & 0x01) > 0; + let carry = cpu.check_flag(Flags::C) as u16; + let temp = carry << 7; + let result = (cpu.working_data >> 1) ^ (carry << 7); + + cpu.clear_flag(Flags::C); + if old_bit_0 + { + cpu.set_flag(Flags::C); + } + cpu.clear_flag(Flags::N); + if result & 0x80 > 0 + { + cpu.set_flag(Flags::N); + } + + cpu.clear_flag(Flags::Z); + if result == 0 + { + cpu.set_flag(Flags::Z); + } + + if cpu.addr_mode == ModeID::ACM + { + cpu.a = result as u8; + } + else + { + bus.write(cpu.working_addr, result as u8); + } } pub fn STX(cpu: &mut R6502, bus: &mut dyn Bus) diff --git a/src/tests/instructions/mod.rs b/src/tests/instructions/mod.rs index 5b9ceec..b768f41 100644 --- a/src/tests/instructions/mod.rs +++ b/src/tests/instructions/mod.rs @@ -202,4 +202,139 @@ fn ASL() assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set"); assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set"); assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set"); +} + +#[test] +fn ASL_ZP0() +{ + let mut cpu = R6502::new(); + let mut bus = RAMBus::new(); + + // program address + let addr = 0x0020 as u16; + + // Set the program counter address + bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte + bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte + + // Write the value into memory + bus.write(0x05, 0x98); + + // Program to left shift the value in the accumulator + bus.write(addr, 0x06); // ASL - Zero Page mode + bus.write(addr + 1, 0x05); // Zero Page pointer + + // Restart cpu + cpu.reset(&mut bus); + + // manually setup the cpu registers + cpu.debug_set_reg(Registers::A, 0x05); + + // Clock the cpu to run the program (Clock essentially runs one full instruction) + cpu.clock(&mut bus); + + // Is 0x30 in memory? + assert_eq!(0x30, bus.read(0x05)); + assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set"); + assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set"); + assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set"); +} + +#[test] +fn ROL() +{ + let mut cpu = R6502::new(); + let mut bus = RAMBus::new(); + + // program address + let addr = 0x0020 as u16; + + // Set the program counter address + bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte + bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte + + // Program to left shift the value in the accumulator + bus.write(addr, 0x2A); // ROL - Accumulator mode + + // Restart cpu + cpu.reset(&mut bus); + + // manually setup the cpu registers + cpu.debug_set_reg(Registers::A, 0x80); + cpu.set_flag(Flags::C); + + // Clock the cpu to run the program (Clock essentially runs one full instruction) + cpu.clock(&mut bus); + + // Is 0x01 in the A register? + assert_eq!(0x01, cpu.debug_get_reg(Registers::A)); + assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set"); + assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set"); + assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set"); +} + + +#[test] +fn LSR() +{ + let mut cpu = R6502::new(); + let mut bus = RAMBus::new(); + + // program address + let addr = 0x0020 as u16; + + // Set the program counter address + bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte + bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte + + // Program to left shift the value in the accumulator + bus.write(addr, 0x4A); // LSR - Accumulator mode + + // Restart cpu + cpu.reset(&mut bus); + + // manually setup the cpu registers + cpu.debug_set_reg(Registers::A, 0x81); + + // Clock the cpu to run the program (Clock essentially runs one full instruction) + cpu.clock(&mut bus); + + // Is 0x40 in the A register? + assert_eq!(0x40, cpu.debug_get_reg(Registers::A)); + assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set"); + assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set"); + assert_eq!(0, cpu.check_flag(Flags::N), "Negative flag should not be set"); +} + +#[test] +fn ROR() +{ + let mut cpu = R6502::new(); + let mut bus = RAMBus::new(); + + // program address + let addr = 0x0020 as u16; + + // Set the program counter address + bus.write(0xFFFC, (addr & 0x00FF) as u8); // low byte + bus.write(0xFFFD, ((addr & 0xFF00) >> 8) as u8); // high byte + + // Program to left shift the value in the accumulator + bus.write(addr, 0x6A); // ROR - Accumulator mode + + // Restart cpu + cpu.reset(&mut bus); + + // manually setup the cpu registers + cpu.debug_set_reg(Registers::A, 0x81); + cpu.set_flag(Flags::C); + + // Clock the cpu to run the program (Clock essentially runs one full instruction) + cpu.clock(&mut bus); + + // Is 0xC0 in the A register? + assert_eq!(0xC0, cpu.debug_get_reg(Registers::A)); + assert_eq!(0, cpu.check_flag(Flags::Z), "Zero flag should not be set"); + assert_eq!(1, cpu.check_flag(Flags::C), "Carry flag should be set"); + assert_eq!(1, cpu.check_flag(Flags::N), "Negative flag should be set"); } \ No newline at end of file diff --git a/todo/todo.todo b/todo/todo.todo index 9a096cb..e4929c5 100644 --- a/todo/todo.todo +++ b/todo/todo.todo @@ -41,9 +41,9 @@ Instructions: GROUP TWO: ✔ 000 ASL @done(23-11-30 17:31) - ☐ 001 ROL - ☐ 010 LSR - ☐ 011 ROR + ✔ 001 ROL @done(23-11-30 17:49) + ✔ 010 LSR @done(23-11-30 18:12) + ✔ 011 ROR @done(23-11-30 18:12) ☐ 100 STX ☐ 101 LDX ☐ 110 DEC