DEC, DEX and DEY instructions

This commit is contained in:
2022-11-26 21:51:51 -05:00
parent b1b80e0c48
commit 82f8676a39
4 changed files with 195 additions and 20 deletions
+8
View File
@@ -198,6 +198,14 @@ impl CPU {
let (bytes, cycles) = self.common_conditions(addressing_mode, &COMP_INDEX_CONDITIONS);
self.registers.increment_pc(bytes); self.cycles += cycles;
}
pub fn increment_cycles_dec(&mut self, addressing_mode: AddressingMode) {
self.increment_cycles_shift(addressing_mode);
}
pub fn increment_cycles_dec_index(&mut self) {
self.registers.increment_pc(1); self.cycles += 2;
}
}
#[cfg(test)]
+152 -20
View File
@@ -7,23 +7,57 @@ use crate::common::flags::Flags;
impl CPU {
fn get_8bit_from_address(&self, bus: &Bus, addressing_mode: AddressingMode) -> u8 {
addressing_mode.value_8bit(
bus,
self.registers.get_pc_address(),
self.registers.d,
self.registers.sp,
self.registers.x, self.registers.y
)
match addressing_mode {
AddressingMode::Accumulator => self.registers.a as u8,
_ => addressing_mode.value_8bit(
bus,
self.registers.get_pc_address(),
self.registers.d,
self.registers.sp,
self.registers.x, self.registers.y
)
}
}
fn get_16bit_from_address(&self, bus: &Bus, addressing_mode: AddressingMode) -> u16 {
addressing_mode.value_16bit(
bus,
self.registers.get_pc_address(),
self.registers.d,
self.registers.sp,
self.registers.x, self.registers.y
)
match addressing_mode {
AddressingMode::Accumulator => self.registers.a,
_ => addressing_mode.value_16bit(
bus,
self.registers.get_pc_address(),
self.registers.d,
self.registers.sp,
self.registers.x, self.registers.y
)
}
}
fn set_8bit_to_address(&mut self, bus: &mut Bus, addressing_mode: AddressingMode, value: u8) {
match addressing_mode {
AddressingMode::Accumulator => self.registers.set_low_a(value),
_ => addressing_mode.store_8bit(
bus,
self.registers.get_pc_address(),
self.registers.d,
self.registers.sp,
self.registers.x, self.registers.y,
value,
),
};
}
fn set_16bit_to_address(&mut self, bus: &mut Bus, addressing_mode: AddressingMode, value: u16) {
match addressing_mode {
AddressingMode::Accumulator => self.registers.a = value,
_ => addressing_mode.store_16bit(
bus,
self.registers.get_pc_address(),
self.registers.d,
self.registers.sp,
self.registers.x, self.registers.y,
value,
),
};
}
fn adc(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
@@ -76,6 +110,50 @@ impl CPU {
self.increment_cycles_arithmetic(addressing_mode);
}
fn do_dec<T: SnesNum>(&mut self, target: T) -> T {
let (result, affected_flags) = alu::sbc_bin(target, T::from_u32(1), false);
for flag in affected_flags {
match flag {
Flags::Negative(_) | Flags::Zero(_) => self.registers.set_flags(&[flag]),
_ => {},
}
}
result
}
fn dec(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
if self.registers.is_16bit_mode() {
let value = self.get_16bit_from_address(bus, addressing_mode);
let result = self.do_dec(value).to_u32() as u16;
self.set_16bit_to_address(bus, addressing_mode, result);
} else {
let value = self.get_8bit_from_address(bus, addressing_mode);
let result = self.do_dec(value).to_u32() as u8;
self.set_8bit_to_address(bus, addressing_mode, result);
}
self.increment_cycles_dec(addressing_mode);
}
fn dex(&mut self) {
if self.registers.is_16bit_index() {
self.registers.x = self.do_dec(self.registers.x);
} else {
let result = self.do_dec(self.registers.x).to_u32() as u8;
self.registers.set_low_x(result);
}
self.increment_cycles_dec_index();
}
fn dey(&mut self) {
if self.registers.is_16bit_index() {
self.registers.y = self.do_dec(self.registers.y);
} else {
let result = self.do_dec(self.registers.y).to_u32() as u8;
self.registers.set_low_y(result);
}
self.increment_cycles_dec_index();
}
fn do_comp<T: SnesNum>(&mut self, target: T, value: T) {
let (_, affected_flags) = alu::sbc_bin(target, value, false);
for flag in affected_flags {
@@ -142,7 +220,7 @@ impl CPU {
self.increment_cycles_bitwise(addressing_mode);
}
fn asl(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
fn asl(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
let target = match addressing_mode {
AddressingMode::Accumulator => self.registers.a,
_ => match self.registers.is_16bit_mode() {
@@ -152,11 +230,11 @@ impl CPU {
};
if self.registers.is_16bit_mode() {
let (result, affected_flags) = alu::asl(target);
self.registers.a = result;
self.set_16bit_to_address(bus, addressing_mode, result);
self.registers.set_flags(&affected_flags);
} else {
let (result, affected_flags) = alu::asl(target as u8);
self.registers.set_low_a(result);
self.set_8bit_to_address(bus, addressing_mode, result);
self.registers.set_flags(&affected_flags);
}
self.increment_cycles_shift(addressing_mode);
@@ -304,7 +382,7 @@ impl CPU {
self.increment_cycles_clear();
}
pub fn execute_opcode(&mut self, opcode: u8, bus: &Bus) {
pub fn execute_opcode(&mut self, opcode: u8, bus: &mut Bus) {
type A = AddressingMode;
type I = IndexRegister;
match opcode {
@@ -424,6 +502,16 @@ impl CPU {
0xC0 => self.cpy(bus, A::Immediate),
0xCC => self.cpy(bus, A::Absolute),
0xC4 => self.cpy(bus, A::DirectPage),
// DEC
0x3A => self.dec(bus, A::Accumulator),
0xCE => self.dec(bus, A::Absolute),
0xC6 => self.dec(bus, A::DirectPage),
0xDE => self.dec(bus, A::AbsoluteIndexed(I::X)),
0xD6 => self.dec(bus, A::DirectPageIndexed(I::X)),
// DEX
0xCA => self.dex(),
// DEY
0x88 => self.dey(),
_ => println!("Invalid opcode: {:02X}", opcode),
}
}
@@ -487,12 +575,12 @@ mod cpu_instructions_tests {
#[test]
fn test_asl() {
let mut cpu = CPU::new();
let bus = Bus::new();
let mut bus = Bus::new();
cpu.registers.a = 0b01010000_00000000;
cpu.registers.pbr = 0x00;
cpu.registers.pc = 0x0000;
cpu.registers.set_memory_select_flag(false);
cpu.asl(&bus, AddressingMode::Accumulator);
cpu.asl(&mut bus, AddressingMode::Accumulator);
assert_eq!(cpu.registers.a, 0b10100000_00000000);
assert_eq!(cpu.registers.pc, 0x01);
assert_eq!(cpu.cycles, 4);
@@ -984,4 +1072,48 @@ mod cpu_instructions_tests {
assert!(!cpu.registers.get_zero_flag());
assert!(!cpu.registers.get_overflow_flag());
}
#[test]
fn test_dec() {
let mut cpu = CPU::new();
let mut bus = Bus::new();
cpu.registers.a = 0x0001;
cpu.registers.pbr = 0x00;
cpu.registers.pc = 0x0000;
cpu.registers.set_memory_select_flag(true);
cpu.dec(&mut bus, AddressingMode::Accumulator);
assert_eq!(cpu.registers.a, 0);
assert_eq!(cpu.registers.pc, 0x01);
assert_eq!(cpu.cycles, 2);
assert!(!cpu.registers.get_negative_flag());
assert!(cpu.registers.get_zero_flag());
}
#[test]
fn test_dex() {
let mut cpu = CPU::new();
cpu.registers.x = 0x0001;
cpu.registers.pbr = 0x00;
cpu.registers.pc = 0x0000;
cpu.dex();
assert_eq!(cpu.registers.x, 0);
assert_eq!(cpu.registers.pc, 0x01);
assert_eq!(cpu.cycles, 2);
assert!(!cpu.registers.get_negative_flag());
assert!(cpu.registers.get_zero_flag());
}
#[test]
fn test_dey() {
let mut cpu = CPU::new();
cpu.registers.y = 0x0001;
cpu.registers.pbr = 0x00;
cpu.registers.pc = 0x0000;
cpu.dey();
assert_eq!(cpu.registers.y, 0);
assert_eq!(cpu.registers.pc, 0x01);
assert_eq!(cpu.cycles, 2);
assert!(!cpu.registers.get_negative_flag());
assert!(cpu.registers.get_zero_flag());
}
}
+24
View File
@@ -33,6 +33,14 @@ impl Registers {
self.a = (self.a & 0xFF00) | (val as u16);
}
pub fn set_low_x(&mut self, val: u8) {
self.x = (self.x & 0xFF00) | (val as u16);
}
pub fn set_low_y(&mut self, val: u8) {
self.y = (self.y & 0xFF00) | (val as u16);
}
pub fn get_carry_flag(&self) -> bool {
(self.p & 0b0000_0001) == 1
}
@@ -212,6 +220,22 @@ mod registers_tests {
assert_eq!(registers.a, 0xA1FF);
}
#[test]
fn test_set_low_x() {
let mut registers = Registers::new();
registers.x = 0xA1A1;
registers.set_low_x(0xFF);
assert_eq!(registers.x, 0xA1FF);
}
#[test]
fn test_set_low_y() {
let mut registers = Registers::new();
registers.y = 0xA1A1;
registers.set_low_y(0xFF);
assert_eq!(registers.y, 0xA1FF);
}
#[test]
fn test_direct_page_log() {
let mut registers = Registers::new();
+11
View File
@@ -142,6 +142,17 @@ impl AddressingMode {
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, x, y);
return (bus.read(address) as u16) | ((bus.read(address + 1) as u16) << 8);
}
pub fn store_8bit(self, bus: &mut Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16, value: u8) {
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, x, y);
bus.write(address, value);
}
pub fn store_16bit(self, bus: &mut Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16, value: u16) {
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, x, y);
bus.write(address, value as u8);
bus.write(address + 1, (value >> 8) as u8);
}
}
#[cfg(test)]