AND instructions

This commit is contained in:
2022-11-20 20:55:23 -05:00
parent 49bb3a04cc
commit f78883257a
3 changed files with 98 additions and 0 deletions
+13
View File
@@ -18,6 +18,12 @@ const ALL_CONDITIONS: [Condition; 4] = [
Condition::DecimalMode,
];
const BITWISE_CONDITIONS: [Condition; 3] = [
Condition::MemorySelectFlag,
Condition::DirectPageZero,
Condition::IndexCrossesPageBoundary,
];
impl CPU {
fn common_conditions(&mut self, addressing_mode: AddressingMode, conditions: &[Condition]) {
let mut bytes = 0;
@@ -103,6 +109,13 @@ impl CPU {
self.cycles += cycles;
self.common_conditions(addressing_mode, &ALL_CONDITIONS);
}
pub fn increment_cycles_bitwise(&mut self, addressing_mode: AddressingMode) {
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
self.registers.increment_pc(bytes);
self.cycles += cycles;
self.common_conditions(addressing_mode, &BITWISE_CONDITIONS);
}
}
#[cfg(test)]
+55
View File
@@ -92,6 +92,27 @@ impl CPU {
self.increment_cycles_arithmetic(addressing_mode);
}
fn and(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
// if the M flag is set, perform 8 bit addition.
// Otherwise, 16 bit addition
let target = self.registers.a;
if self.registers.is_16bit_mode() {
let value = self.get_16bit_from_address(bus, addressing_mode);
let (result, is_negative, is_zero) = alu::and16bit(target, value);
self.registers.a = result;
self.registers.set_negative_flag(is_negative);
self.registers.set_zero_flag(is_zero);
} else {
let value = self.get_8bit_from_address(bus, addressing_mode);
let (result, is_negative, is_zero) = alu::and8bit(target as u8, value);
self.registers.set_low_a(result);
self.registers.set_negative_flag(is_negative);
self.registers.set_zero_flag(is_zero);
}
self.increment_cycles_bitwise(addressing_mode);
}
pub fn execute_opcode(&mut self, opcode: u8, bus: &Bus) {
type A = AddressingMode;
type I = IndexRegister;
@@ -128,6 +149,22 @@ impl CPU {
0xF7 => self.sbc(bus, A::DirectPageIndirectLongIndexed(I::Y)),
0xE3 => self.sbc(bus, A::StackRelative),
0xF3 => self.sbc(bus, A::StackRelativeIndirectIndexed(I::Y)),
// AND
0x29 => self.and(bus, A::Immediate),
0x2D => self.and(bus, A::Absolute),
0x2F => self.and(bus, A::AbsoluteLong),
0x25 => self.and(bus, A::DirectPage),
0x32 => self.and(bus, A::DirectPageIndirect),
0x27 => self.and(bus, A::DirectPageIndirectLong),
0x3D => self.and(bus, A::AbsoluteIndexed(I::X)),
0x3F => self.and(bus, A::AbsoluteLongIndexed(I::X)),
0x39 => self.and(bus, A::AbsoluteIndexed(I::Y)),
0x35 => self.and(bus, A::DirectPageIndexed(I::X)),
0x21 => self.and(bus, A::DirectPageIndexedIndirect(I::X)),
0x31 => self.and(bus, A::DirectPageIndirectIndexed(I::Y)),
0x37 => self.and(bus, A::DirectPageIndirectLongIndexed(I::Y)),
0x23 => self.and(bus, A::StackRelative),
0x33 => self.and(bus, A::StackRelativeIndirectIndexed(I::Y)),
_ => println!("Invalid opcode: {:02X}", opcode),
}
}
@@ -169,4 +206,22 @@ mod cpu_instructions_tests {
assert!(!cpu.registers.get_carry_flag());
assert!(cpu.registers.get_zero_flag());
}
#[test]
fn test_and() {
let mut cpu = CPU::new();
let mut bus = Bus::new();
cpu.registers.a = 0x0101;
cpu.registers.pbr = 0x00;
cpu.registers.pc = 0x0000;
cpu.registers.set_memory_select_flag(true);
bus.write(0x000001, 0x01);
bus.write(0x000002, 0x01);
cpu.and(&bus, AddressingMode::Immediate);
assert_eq!(cpu.registers.a, 0x0101);
assert_eq!(cpu.registers.pc, 0x02);
assert_eq!(cpu.cycles, 2);
assert!(!cpu.registers.get_carry_flag());
assert!(!cpu.registers.get_zero_flag());
}
}
+30
View File
@@ -151,6 +151,20 @@ pub fn sbc16bcd(target: u16, value: u16, carry: bool) -> (u16, bool, bool, bool)
(result, is_carry, is_negative, is_zero)
}
pub fn and8bit(target: u8, value: u8) -> (u8, bool, bool) {
let result = target & value;
let is_negative = (result >> 7) == 1;
let is_zero = result == 0;
(result, is_negative, is_zero)
}
pub fn and16bit(target: u16, value: u16) -> (u16, bool, bool) {
let result = target & value;
let is_negative = (result >> 15) == 1;
let is_zero = result == 0;
(result, is_negative, is_zero)
}
#[cfg(test)]
mod alu_tests {
use super::*;
@@ -376,4 +390,20 @@ mod alu_tests {
assert_eq!(negative, true);
assert_eq!(zero, false);
}
#[test]
fn test_and8bit() {
let (result, is_negative, is_zero) = and8bit(0b0101_0101, 0b0101_0101);
assert_eq!(result, 0b0101_0101);
assert_eq!(is_negative, false);
assert_eq!(is_zero, false);
}
#[test]
fn test_and16bit() {
let (result, is_negative, is_zero) = and16bit(0b01010101_01010101, 0b01010101_01010101);
assert_eq!(result, 0b01010101_01010101);
assert_eq!(is_negative, false);
assert_eq!(is_zero, false);
}
}