mirror of
https://github.com/FranLMSP/snes.git
synced 2026-08-03 08:30:01 -04:00
Refactor opcode execution and adc instruction
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
use crate::bus::Bus;
|
||||
use super::registers::Registers;
|
||||
|
||||
pub struct CPU {
|
||||
@@ -13,136 +12,4 @@ impl CPU {
|
||||
cycles: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_absolute(&self, bus: &Bus) -> u16 {
|
||||
let pc = self.registers.get_pc_address();
|
||||
(bus.read(pc + 1) as u16) | ((bus.read(pc + 2) as u16) << 8)
|
||||
}
|
||||
|
||||
pub fn get_absolute_long(&self, bus: &Bus) -> u32 {
|
||||
let pc = self.registers.get_pc_address();
|
||||
(bus.read(pc + 1) as u32) | ((bus.read(pc + 2) as u32) << 8) | ((bus.read(pc + 3) as u32) << 16)
|
||||
}
|
||||
|
||||
pub fn get_direct_page(&self, bus: &Bus) -> u8 {
|
||||
let pc = self.registers.get_pc_address();
|
||||
bus.read(pc + 1)
|
||||
}
|
||||
|
||||
pub fn get_immediate(&self, bus: &Bus) -> u16 {
|
||||
// If the "m" flag is set to 1, read only 8 bits.
|
||||
// Otherwise, read 16 bits
|
||||
let address = self.registers.get_pc_address();
|
||||
if self.registers.get_memory_select_flag() {
|
||||
return bus.read(address + 1) as u16;
|
||||
} else {
|
||||
return (bus.read(address + 1) as u16) | ((bus.read(address + 2) as u16) << 8);
|
||||
}
|
||||
}
|
||||
|
||||
fn execute_opcode(&mut self, opcode: u8, bus: &Bus) {
|
||||
match opcode {
|
||||
0x69 => self.adc_const(bus),
|
||||
0x6D => self.adc_addr(bus),
|
||||
0x6F => self.adc_long(bus),
|
||||
0x65 => self.adc_dp(bus),
|
||||
0x72 => self.adc_dp_indirect(bus),
|
||||
0x67 => self.adc_dp_indirect_long(bus),
|
||||
_ => todo!("Missing opcode implementation: {:02X}", opcode),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn tick(&mut self, bus: &Bus) {
|
||||
let address = self.registers.get_pc_address();
|
||||
let opcode = bus.read(address);
|
||||
self.execute_opcode(opcode, bus);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod cpu_tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_get_immediate() {
|
||||
let mut bus = Bus::new();
|
||||
let mut cpu = CPU::new();
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.pbr = 0x00;
|
||||
// write to WRAM
|
||||
bus.write(0x00_0001, 0x01);
|
||||
bus.write(0x00_0002, 0x02);
|
||||
assert_eq!(cpu.get_immediate(&bus), 0x0001);
|
||||
cpu.registers.set_memory_select_flag(false);
|
||||
assert_eq!(cpu.get_immediate(&bus), 0x0201);
|
||||
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
cpu.registers.pc = 0x0010;
|
||||
cpu.registers.pbr = 0x7E;
|
||||
// write to WRAM
|
||||
bus.write(0x7E_0011, 0x01);
|
||||
bus.write(0x7E_0012, 0x02);
|
||||
assert_eq!(cpu.get_immediate(&bus), 0x0001);
|
||||
cpu.registers.set_memory_select_flag(false);
|
||||
assert_eq!(cpu.get_immediate(&bus), 0x0201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_absolute() {
|
||||
let mut bus = Bus::new();
|
||||
let mut cpu = CPU::new();
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.pbr = 0x00;
|
||||
// write to WRAM
|
||||
bus.write(0x00_0001, 0x01);
|
||||
bus.write(0x00_0002, 0x02);
|
||||
assert_eq!(cpu.get_absolute(&bus), 0x0201);
|
||||
|
||||
cpu.registers.pc = 0x0010;
|
||||
cpu.registers.pbr = 0x7E;
|
||||
// write to WRAM
|
||||
bus.write(0x7E_0011, 0x01);
|
||||
bus.write(0x7E_0012, 0x02);
|
||||
assert_eq!(cpu.get_absolute(&bus), 0x0201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_absolute_long() {
|
||||
let mut bus = Bus::new();
|
||||
let mut cpu = CPU::new();
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.pbr = 0x00;
|
||||
// write to WRAM
|
||||
bus.write(0x00_0001, 0x01);
|
||||
bus.write(0x00_0002, 0x02);
|
||||
bus.write(0x00_0003, 0x03);
|
||||
assert_eq!(cpu.get_absolute_long(&bus), 0x030201);
|
||||
|
||||
cpu.registers.pc = 0x0010;
|
||||
cpu.registers.pbr = 0x7E;
|
||||
// write to WRAM
|
||||
bus.write(0x7E_0011, 0x01);
|
||||
bus.write(0x7E_0012, 0x02);
|
||||
bus.write(0x7E_0013, 0x03);
|
||||
assert_eq!(cpu.get_absolute_long(&bus), 0x030201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_get_direct_page() {
|
||||
let mut bus = Bus::new();
|
||||
let mut cpu = CPU::new();
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.pbr = 0x00;
|
||||
// write to WRAM
|
||||
bus.write(0x00_0001, 0x01);
|
||||
assert_eq!(cpu.get_direct_page(&bus), 0x01);
|
||||
|
||||
cpu.registers.pc = 0x0010;
|
||||
cpu.registers.pbr = 0x7E;
|
||||
// write to WRAM
|
||||
bus.write(0x7E_0011, 0x01);
|
||||
assert_eq!(cpu.get_direct_page(&bus), 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,192 +1,84 @@
|
||||
use super::cpu::CPU;
|
||||
use crate::bus::Bus;
|
||||
use crate::utils::addressing::{AddressingMode, IndexRegister};
|
||||
use crate::utils::alu;
|
||||
|
||||
impl CPU {
|
||||
fn adc8bcd(&mut self, value: u8) {
|
||||
let carry = self.registers.get_carry_flag();
|
||||
let a = self.registers.a as u8;
|
||||
let carry_result = match a.checked_add(value) {
|
||||
None => true,
|
||||
Some(res) => match res.checked_add(carry as u8) {
|
||||
None => true,
|
||||
Some(_) => false,
|
||||
},
|
||||
};
|
||||
let result = a
|
||||
.wrapping_add(value)
|
||||
.wrapping_add(carry as u8);
|
||||
self.registers.a = (self.registers.a & 0xFF00) | (result as u16);
|
||||
self.registers.set_carry_flag(carry_result);
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
fn adc16bcd(&mut self, value: u16) {
|
||||
let carry = self.registers.get_carry_flag();
|
||||
let carry_result = match self.registers.a.checked_add(value) {
|
||||
None => true,
|
||||
Some(res) => match res.checked_add(carry as u16) {
|
||||
None => true,
|
||||
Some(_) => false,
|
||||
},
|
||||
};
|
||||
let result = self.registers.a
|
||||
.wrapping_add(value)
|
||||
.wrapping_add(carry as u16);
|
||||
self.registers.a = result;
|
||||
self.registers.set_carry_flag(carry_result);
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
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
|
||||
)
|
||||
}
|
||||
|
||||
fn adc8(&mut self, value: u8) {
|
||||
let carry = self.registers.get_carry_flag();
|
||||
let a = self.registers.a as u8;
|
||||
let carry_result = match a.checked_add(value) {
|
||||
None => true,
|
||||
Some(res) => match res.checked_add(carry as u8) {
|
||||
None => true,
|
||||
Some(_) => false,
|
||||
},
|
||||
};
|
||||
let result = a
|
||||
.wrapping_add(value)
|
||||
.wrapping_add(carry as u8);
|
||||
self.registers.a = (self.registers.a & 0xFF00) | (result as u16);
|
||||
self.registers.set_carry_flag(carry_result);
|
||||
self.registers.set_negative_flag((result >> 7) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
|
||||
fn adc16(&mut self, value: u16) {
|
||||
let carry = self.registers.get_carry_flag();
|
||||
let carry_result = match self.registers.a.checked_add(value) {
|
||||
None => true,
|
||||
Some(res) => match res.checked_add(carry as u16) {
|
||||
None => true,
|
||||
Some(_) => false,
|
||||
},
|
||||
};
|
||||
let result = self.registers.a
|
||||
.wrapping_add(value)
|
||||
.wrapping_add(carry as u16);
|
||||
self.registers.a = result;
|
||||
self.registers.set_carry_flag(carry_result);
|
||||
self.registers.set_negative_flag((result >> 15) == 1);
|
||||
self.registers.set_zero_flag(result == 0);
|
||||
}
|
||||
|
||||
fn adc(&mut self, value: u16) {
|
||||
fn adc(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
// if the M flag is set, perform 8 bit addition.
|
||||
// Otherwise, 16 bit addition
|
||||
if self.registers.get_memory_select_flag() {
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.adc8bcd(value as u8);
|
||||
} else {
|
||||
self.adc8(value as u8);
|
||||
let carry_flag = self.registers.get_carry_flag();
|
||||
let is_decimal_mode = self.registers.get_decimal_mode_flag();
|
||||
let is_8bit = self.registers.get_memory_select_flag();
|
||||
let target = self.registers.a;
|
||||
match is_8bit {
|
||||
true => {
|
||||
let value = self.get_8bit_from_address(bus, addressing_mode);
|
||||
let (result, is_carry, is_negative, is_zero) = match is_decimal_mode {
|
||||
true => alu::adc8bcd(target as u8, value, carry_flag),
|
||||
false => alu::adc8bin(target as u8, value, carry_flag),
|
||||
};
|
||||
self.registers.a = result as u16;
|
||||
self.registers.set_carry_flag(is_carry);
|
||||
self.registers.set_negative_flag(is_negative);
|
||||
self.registers.set_zero_flag(is_zero);
|
||||
},
|
||||
false => {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
let (result, is_carry, is_negative, is_zero) = match is_decimal_mode {
|
||||
true => alu::adc16bcd(target, value, carry_flag),
|
||||
false => alu::adc16bin(target, value, carry_flag),
|
||||
};
|
||||
self.registers.a = result;
|
||||
self.registers.set_carry_flag(is_carry);
|
||||
self.registers.set_negative_flag(is_negative);
|
||||
self.registers.set_zero_flag(is_zero);
|
||||
}
|
||||
} else {
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.adc16bcd(value);
|
||||
} else {
|
||||
self.adc16(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub fn adc_const(&mut self, bus: &Bus) {
|
||||
let value = self.get_immediate(bus);
|
||||
self.registers.pc = self.registers.pc.wrapping_add(2);
|
||||
self.cycles += 2;
|
||||
if self.registers.get_memory_select_flag() {
|
||||
self.registers.pc = self.registers.pc.wrapping_add(1);
|
||||
self.cycles += 1;
|
||||
pub fn execute_opcode(&mut self, opcode: u8, bus: &Bus) {
|
||||
type A = AddressingMode;
|
||||
type I = IndexRegister;
|
||||
match opcode {
|
||||
// ADC
|
||||
0x69 => self.adc(bus, A::Immediate),
|
||||
0x6D => self.adc(bus, A::Absolute),
|
||||
0x6F => self.adc(bus, A::AbsoluteLong),
|
||||
0x65 => self.adc(bus, A::DirectPage),
|
||||
0x72 => self.adc(bus, A::DirectPageIndirect),
|
||||
0x67 => self.adc(bus, A::DirectPageIndirectLong),
|
||||
0x7D => self.adc(bus, A::AbsoluteIndexed(I::X)),
|
||||
0x7F => self.adc(bus, A::AbsoluteLongIndexed(I::X)),
|
||||
0x79 => self.adc(bus, A::AbsoluteIndexed(I::Y)),
|
||||
0x75 => self.adc(bus, A::DirectPageIndexed(I::X)),
|
||||
0x61 => self.adc(bus, A::DirectPageIndexedIndirect(I::X)),
|
||||
0x71 => self.adc(bus, A::DirectPageIndirectIndexed(I::Y)),
|
||||
0x77 => self.adc(bus, A::DirectPageIndirectLongIndexed(I::Y)),
|
||||
0x63 => self.adc(bus, A::StackRelative),
|
||||
0x73 => self.adc(bus, A::StackRelativeIndirectIndexed(I::Y)),
|
||||
_ => println!("Invalid opcode: {:02X}", opcode),
|
||||
}
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
self.adc(value);
|
||||
}
|
||||
|
||||
pub fn adc_addr(&mut self, bus: &Bus) {
|
||||
let address = ((self.registers.pbr as u32) << 16) | (self.get_absolute(bus) as u32);
|
||||
self.registers.pc = self.registers.pc.wrapping_add(3);
|
||||
self.cycles += 4;
|
||||
if self.registers.get_memory_select_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
let value = bus.read(address);
|
||||
self.adc(value as u16);
|
||||
}
|
||||
|
||||
pub fn adc_long(&mut self, bus: &Bus) {
|
||||
let address = self.get_absolute_long(bus);
|
||||
self.registers.pc = self.registers.pc.wrapping_add(4);
|
||||
self.cycles += 5;
|
||||
if self.registers.get_memory_select_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
let value = bus.read(address);
|
||||
self.adc(value as u16);
|
||||
}
|
||||
|
||||
pub fn adc_dp(&mut self, bus: &Bus) {
|
||||
let address = self.get_direct_page(bus);
|
||||
self.registers.pc = self.registers.pc.wrapping_add(2);
|
||||
self.cycles += 3;
|
||||
if self.registers.get_memory_select_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if address != 0 {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
let value = bus.read(address as u32);
|
||||
self.adc(value as u16);
|
||||
}
|
||||
|
||||
pub fn adc_dp_indirect(&mut self, bus: &Bus) {
|
||||
let pointer = self.get_direct_page(bus) as u32;
|
||||
let address = ((bus.read(pointer) as u32) << 8) | (bus.read(pointer + 1) as u32);
|
||||
self.registers.pc = self.registers.pc.wrapping_add(2);
|
||||
self.cycles += 3;
|
||||
if self.registers.get_memory_select_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if address != 0 {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
let value = bus.read(address);
|
||||
self.adc(value as u16);
|
||||
}
|
||||
|
||||
pub fn adc_dp_indirect_long(&mut self, bus: &Bus) {
|
||||
let pointer = self.get_direct_page(bus) as u32;
|
||||
let address = ((bus.read(pointer) as u32) << 16) | ((bus.read(pointer + 1) as u32) << 8) | (bus.read(pointer + 2) as u32);
|
||||
self.registers.pc = self.registers.pc.wrapping_add(2);
|
||||
self.cycles += 3;
|
||||
if self.registers.get_memory_select_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if address != 0 {
|
||||
self.cycles += 1;
|
||||
}
|
||||
if self.registers.get_decimal_mode_flag() {
|
||||
self.cycles += 1;
|
||||
}
|
||||
let value = bus.read(address);
|
||||
self.adc(value as u16);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,32 +89,14 @@ mod cpu_instructions_tests {
|
||||
#[test]
|
||||
fn test_adc() {
|
||||
let mut cpu = CPU::new();
|
||||
cpu.registers.a = 0x00;
|
||||
cpu.adc(0x40);
|
||||
let mut bus = Bus::new();
|
||||
cpu.registers.a = 0x0000;
|
||||
cpu.registers.pbr = 0x00;
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
bus.write(0x000001, 0x40);
|
||||
cpu.adc(&bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0x40);
|
||||
assert!(!cpu.registers.get_carry_flag());
|
||||
|
||||
cpu.registers.a = 0xFFFF;
|
||||
cpu.adc(0x01);
|
||||
assert_eq!(cpu.registers.a, 0x0000);
|
||||
assert!(cpu.registers.get_carry_flag());
|
||||
|
||||
cpu.registers.a = 0xFFFF;
|
||||
cpu.registers.set_carry_flag(true);
|
||||
cpu.adc(0x01);
|
||||
assert_eq!(cpu.registers.a, 0x0001);
|
||||
assert!(cpu.registers.get_carry_flag());
|
||||
|
||||
cpu.registers.a = 0xFFFD;
|
||||
cpu.registers.set_carry_flag(true);
|
||||
cpu.adc(0x01);
|
||||
assert_eq!(cpu.registers.a, 0xFFFF);
|
||||
assert!(!cpu.registers.get_carry_flag());
|
||||
|
||||
cpu.registers.a = 0x0000;
|
||||
cpu.registers.set_carry_flag(true);
|
||||
cpu.adc(0x01);
|
||||
assert_eq!(cpu.registers.a, 0x0002);
|
||||
assert!(!cpu.registers.get_carry_flag());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,6 +86,11 @@ pub fn stack_relative_indirect_indexed(bus: &Bus, pc_addr: u32, stack_pointer: u
|
||||
absolute_indexed(bus, pc_addr, stack_pointer) + (xy as u32)
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
pub enum IndexRegister {
|
||||
X, Y,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum AddressingMode {
|
||||
Immediate,
|
||||
@@ -94,18 +99,19 @@ pub enum AddressingMode {
|
||||
DirectPage,
|
||||
DirectPageIndirect,
|
||||
DirectPageIndirectLong,
|
||||
AbsoluteIndexed,
|
||||
AbsoluteLongIndexed,
|
||||
DirectPageIndexed,
|
||||
DirectPageIndexedIndirect,
|
||||
DirectPageIndirectIndexed,
|
||||
DirectPageIndirectLongIndexed,
|
||||
AbsoluteIndexed(IndexRegister),
|
||||
AbsoluteLongIndexed(IndexRegister),
|
||||
DirectPageIndexed(IndexRegister),
|
||||
DirectPageIndexedIndirect(IndexRegister),
|
||||
DirectPageIndirectIndexed(IndexRegister),
|
||||
DirectPageIndirectLongIndexed(IndexRegister),
|
||||
StackRelative,
|
||||
StackRelativeIndirectIndexed,
|
||||
StackRelativeIndirectIndexed(IndexRegister),
|
||||
}
|
||||
|
||||
impl AddressingMode {
|
||||
pub fn effective_address(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, xy: u16) -> u32 {
|
||||
pub fn effective_address(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u32 {
|
||||
use IndexRegister::X as X;
|
||||
match self {
|
||||
Self::Immediate => immediate(pc_addr),
|
||||
Self::Absolute => absolute(bus, pc_addr),
|
||||
@@ -113,24 +119,24 @@ impl AddressingMode {
|
||||
Self::DirectPage => direct_page(bus, pc_addr, direct_page_register),
|
||||
Self::DirectPageIndirect => direct_page_indirect(bus, pc_addr, direct_page_register),
|
||||
Self::DirectPageIndirectLong => direct_page_indirect_long(bus, pc_addr, direct_page_register),
|
||||
Self::AbsoluteIndexed => absolute_indexed(bus, pc_addr, xy),
|
||||
Self::AbsoluteLongIndexed => absolute_long_indexed(bus, pc_addr, xy),
|
||||
Self::DirectPageIndexed => direct_page_indexed(bus, pc_addr, direct_page_register, xy),
|
||||
Self::DirectPageIndexedIndirect => direct_page_indexed_indirect(bus, pc_addr, direct_page_register, xy),
|
||||
Self::DirectPageIndirectIndexed => direct_page_indirect_indexed(bus, pc_addr, direct_page_register, xy),
|
||||
Self::DirectPageIndirectLongIndexed => direct_page_indirect_long_indexed(bus, pc_addr, direct_page_register, xy),
|
||||
Self::AbsoluteIndexed(idx) => absolute_indexed(bus, pc_addr, if idx == X {x} else {y}),
|
||||
Self::AbsoluteLongIndexed(idx) => absolute_long_indexed(bus, pc_addr, if idx == X {x} else {y}),
|
||||
Self::DirectPageIndexed(idx) => direct_page_indexed(bus, pc_addr, direct_page_register, if idx == X {x} else {y}),
|
||||
Self::DirectPageIndexedIndirect(idx) => direct_page_indexed_indirect(bus, pc_addr, direct_page_register, if idx == X {x} else {y}),
|
||||
Self::DirectPageIndirectIndexed(idx) => direct_page_indirect_indexed(bus, pc_addr, direct_page_register, if idx == X {x} else {y}),
|
||||
Self::DirectPageIndirectLongIndexed(idx) => direct_page_indirect_long_indexed(bus, pc_addr, direct_page_register, if idx == X {x} else {y}),
|
||||
Self::StackRelative => stack_relative(bus, pc_addr, stack_pointer),
|
||||
Self::StackRelativeIndirectIndexed => stack_relative_indirect_indexed(bus, pc_addr, stack_pointer, xy),
|
||||
Self::StackRelativeIndirectIndexed(idx) => stack_relative_indirect_indexed(bus, pc_addr, stack_pointer, if idx == X {x} else {y}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value_8bit(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, xy: u16) -> u8 {
|
||||
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, xy);
|
||||
pub fn value_8bit(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u8 {
|
||||
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, x, y);
|
||||
return bus.read(address);
|
||||
}
|
||||
|
||||
pub fn value_16bit(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, xy: u16) -> u16 {
|
||||
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, xy);
|
||||
pub fn value_16bit(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u16 {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -389,7 +395,7 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, 0x20);
|
||||
bus.write(pc_addr + 2, 0x10);
|
||||
bus.write(0x001020, 0xFE);
|
||||
let val = AddressingMode::Absolute.value_8bit(&bus, pc_addr, 0x00, 0x00, 0x00);
|
||||
let val = AddressingMode::Absolute.value_8bit(&bus, pc_addr, 0x00, 0x00, 0x00, 0x00);
|
||||
assert_eq!(val, 0xFE);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
@@ -398,7 +404,7 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 2, 0x10);
|
||||
bus.write(0x001020, 0xFF);
|
||||
bus.write(0x001021, 0xEE);
|
||||
let val = AddressingMode::Absolute.value_16bit(&bus, pc_addr, 0x00, 0x00, 0x00);
|
||||
let val = AddressingMode::Absolute.value_16bit(&bus, pc_addr, 0x00, 0x00, 0x00, 0x00);
|
||||
assert_eq!(val, 0xEEFF);
|
||||
}
|
||||
}
|
||||
+32
-40
@@ -32,26 +32,15 @@ pub fn adc16bin(target: u16, value: u16, carry: bool) -> (u16, bool, bool, bool)
|
||||
|
||||
pub fn adc8bcd(target: u8, value: u8, carry: bool) -> (u8, bool, bool, bool) {
|
||||
let mut is_carry = carry;
|
||||
let mut result: u8 = 0;
|
||||
let mut operand_mask: u8 = 0x0F;
|
||||
let mut result_mask: u8 = 0x00;
|
||||
let mut carry_check: u8= 0x09;
|
||||
let mut carry_add: u8 = 0x06;
|
||||
let mut is_carry_shifts: u8 = 0;
|
||||
for _ in 0..2 {
|
||||
result = (result & result_mask)
|
||||
.wrapping_add(target & operand_mask)
|
||||
.wrapping_add(value & operand_mask)
|
||||
.wrapping_add((is_carry as u8) << is_carry_shifts);
|
||||
is_carry = result > carry_check;
|
||||
if is_carry {
|
||||
result = result.wrapping_add(carry_add);
|
||||
}
|
||||
operand_mask = operand_mask << 4;
|
||||
carry_add = carry_add << 4;
|
||||
carry_check = (carry_check << 4) | 0x0F;
|
||||
result_mask = (result_mask << 4) | 0x0F;
|
||||
is_carry_shifts += 4;
|
||||
let mut result = (target & 0xF) + (value & 0xF) + (is_carry as u8);
|
||||
is_carry = result > 9;
|
||||
if is_carry {
|
||||
result += 6;
|
||||
}
|
||||
result = (result & 0xF0) + (target & 0xF0) + (value & 0xF0) + ((is_carry as u8) << 4);
|
||||
is_carry = result > 0x9F;
|
||||
if is_carry {
|
||||
result = result.wrapping_add(0x60);
|
||||
}
|
||||
let is_negative = (result >> 7) == 1;
|
||||
let is_zero = result == 0;
|
||||
@@ -60,26 +49,29 @@ pub fn adc8bcd(target: u8, value: u8, carry: bool) -> (u8, bool, bool, bool) {
|
||||
|
||||
pub fn adc16bcd(target: u16, value: u16, carry: bool) -> (u16, bool, bool, bool) {
|
||||
let mut is_carry = carry;
|
||||
let mut result: u16 = 0;
|
||||
let mut operand_mask: u16 = 0x0F;
|
||||
let mut result_mask: u16 = 0x00;
|
||||
let mut carry_check: u16 = 0x09;
|
||||
let mut carry_add: u16 = 0x06;
|
||||
let mut is_carry_shifts: u16 = 0;
|
||||
for _ in 0..4 {
|
||||
result = (result & result_mask)
|
||||
.wrapping_add(target & operand_mask)
|
||||
.wrapping_add(value & operand_mask)
|
||||
.wrapping_add((is_carry as u16) << is_carry_shifts);
|
||||
is_carry = result > carry_check;
|
||||
if is_carry {
|
||||
result = result.wrapping_add(carry_add);
|
||||
}
|
||||
operand_mask = operand_mask << 4;
|
||||
carry_add = carry_add << 4;
|
||||
carry_check = (carry_check << 4) | 0x0F;
|
||||
result_mask = (result_mask << 4) | 0x0F;
|
||||
is_carry_shifts += 4;
|
||||
let mut result = (target & 0xF) + (value & 0xF) + (is_carry as u16);
|
||||
is_carry = false;
|
||||
if result > 9 {
|
||||
result += 6;
|
||||
is_carry = true;
|
||||
}
|
||||
result = (result & 0xF0) + (target & 0xF0) + (value & 0xF0) + ((is_carry as u16) << 4);
|
||||
is_carry = false;
|
||||
if result > 0x9F {
|
||||
result += 0x60;
|
||||
is_carry = true;
|
||||
}
|
||||
result = (result & 0xF00) + (target & 0xF00) + (value & 0xF00) + ((is_carry as u16) << 8);
|
||||
is_carry = false;
|
||||
if result > 0x9FF {
|
||||
result += 0x600;
|
||||
is_carry = true;
|
||||
}
|
||||
result = (result & 0xF000) + (target & 0xF000) + (target & 0xF000) + ((is_carry as u16) << 12);
|
||||
is_carry = false;
|
||||
if result > 0x9FFF {
|
||||
result += 0x6000;
|
||||
is_carry = true;
|
||||
}
|
||||
let is_negative = (result >> 15) == 1;
|
||||
let is_zero = result == 0;
|
||||
|
||||
Reference in New Issue
Block a user