mirror of
https://github.com/FranLMSP/snes.git
synced 2026-08-03 08:30:01 -04:00
fix xce, plp and cop instructions
This commit is contained in:
@@ -11,15 +11,22 @@ pub struct COP {}
|
||||
|
||||
impl CPUInstruction for COP {
|
||||
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
||||
if !registers.emulation_mode {
|
||||
push_common::do_push(registers, bus, &[registers.pbr]);
|
||||
}
|
||||
let (bytes, cycles) = cycles::increment_cycles_brk(registers.emulation_mode);
|
||||
registers.increment_pc(bytes); registers.cycles += cycles;
|
||||
push_common::do_push(registers, bus, &[(registers.pc >> 8) as u8, registers.pc as u8]);
|
||||
push_common::do_push(registers, bus, &[registers.p]);
|
||||
registers.set_irq_disable_flag(true);
|
||||
registers.pbr = 0x00;
|
||||
if registers.emulation_mode {
|
||||
let vector = (bus.read(0x00FFF4) as u16) | ((bus.read(0x00FFF5) as u16) << 8);
|
||||
registers.pc = vector;
|
||||
} else {
|
||||
let vector = (bus.read(0x00FFE4) as u16) | ((bus.read(0x00FFE5) as u16) << 8);
|
||||
registers.pc = vector;
|
||||
}
|
||||
registers.set_decimal_mode_flag(false);
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,10 @@ impl CPUInstruction for PLP {
|
||||
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
||||
let bytes = pull_common::do_pull(registers, bus, 1, true);
|
||||
registers.p = bytes[0];
|
||||
if registers.emulation_mode {
|
||||
registers.set_memory_select_flag(true);
|
||||
registers.set_index_register_select_flag(true);
|
||||
}
|
||||
let (bytes, cycles) = cycles::increment_cycles_plp();
|
||||
registers.increment_pc(bytes); registers.cycles += cycles;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,11 @@ pub fn do_pull(registers: &mut Registers, bus: &mut Bus, count: usize, alter_fla
|
||||
let mut is_zero = true;
|
||||
for _ in 0..count {
|
||||
registers.increment_sp(1);
|
||||
let byte = bus.read(registers.sp as u32);
|
||||
let mut address = registers.sp;
|
||||
if registers.emulation_mode {
|
||||
address = (registers.sp | 0x100) & 0x1FF
|
||||
}
|
||||
let byte = bus.read(address as u32);
|
||||
if byte != 0 {
|
||||
is_zero = false;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,10 @@ use crate::cpu::{registers::Registers, bus::Bus};
|
||||
|
||||
pub fn do_push(registers: &mut Registers, bus: &mut Bus, bytes: &[u8]) {
|
||||
for byte in bytes {
|
||||
let address = registers.sp as u32;
|
||||
let mut address = registers.sp as u32;
|
||||
if registers.emulation_mode {
|
||||
address = (address & 0xFF) | 0x100;
|
||||
}
|
||||
bus.write(address, *byte);
|
||||
registers.decrement_sp(1);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,12 @@ pub struct XCE {}
|
||||
|
||||
impl CPUInstruction for XCE {
|
||||
fn execute(&self, registers: &mut Registers, _bus: &mut Bus) {
|
||||
let did_mode_change = registers.emulation_mode != registers.get_carry_flag();
|
||||
registers.exchange_carry_and_emulation();
|
||||
if did_mode_change {
|
||||
registers.set_memory_select_flag(true);
|
||||
registers.set_index_register_select_flag(true);
|
||||
}
|
||||
let (bytes, cycles) = cycles::increment_cycles_exchange();
|
||||
registers.increment_pc(bytes); registers.cycles += cycles;
|
||||
}
|
||||
@@ -34,5 +39,44 @@ mod cpu_instructions_tests {
|
||||
instruction.execute(&mut registers, &mut bus);
|
||||
assert_eq!(registers.pc, 0x0001);
|
||||
assert_eq!(registers.cycles, 2);
|
||||
assert!(registers.get_memory_select_flag());
|
||||
assert!(registers.get_index_register_select_flag());
|
||||
|
||||
let mut registers = Registers::new();
|
||||
let mut bus = Bus::new();
|
||||
registers.pc = 0x0000;
|
||||
registers.emulation_mode = true;
|
||||
registers.set_carry_flag(false);
|
||||
let instruction = XCE{};
|
||||
instruction.execute(&mut registers, &mut bus);
|
||||
assert_eq!(registers.pc, 0x0001);
|
||||
assert_eq!(registers.cycles, 2);
|
||||
assert!(!registers.emulation_mode);
|
||||
assert!(registers.get_memory_select_flag());
|
||||
assert!(registers.get_index_register_select_flag());
|
||||
|
||||
let mut registers = Registers::new();
|
||||
let mut bus = Bus::new();
|
||||
registers.pc = 0x0000;
|
||||
registers.emulation_mode = false;
|
||||
registers.set_carry_flag(true);
|
||||
let instruction = XCE{};
|
||||
instruction.execute(&mut registers, &mut bus);
|
||||
assert_eq!(registers.pc, 0x0001);
|
||||
assert_eq!(registers.cycles, 2);
|
||||
assert!(registers.emulation_mode);
|
||||
assert!(registers.get_memory_select_flag());
|
||||
assert!(registers.get_index_register_select_flag());
|
||||
|
||||
let mut registers = Registers::new();
|
||||
let mut bus = Bus::new();
|
||||
registers.pc = 0x0000;
|
||||
registers.emulation_mode = true;
|
||||
registers.set_carry_flag(false);
|
||||
let instruction = XCE{};
|
||||
instruction.execute(&mut registers, &mut bus);
|
||||
assert!(registers.get_carry_flag());
|
||||
assert!(registers.get_memory_select_flag());
|
||||
assert!(registers.get_index_register_select_flag());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,34 @@ pub struct Registers {
|
||||
pub is_move_next: bool, // TODO: refactor these states with an enum
|
||||
pub cycles: usize,
|
||||
}
|
||||
/*
|
||||
P register flags
|
||||
|
||||
Emulation mode:
|
||||
NV-BDIZC
|
||||
N - Negative
|
||||
V - Overflow
|
||||
-
|
||||
B - Break Instruction
|
||||
D - Decimal Mode
|
||||
I - IRQ Disable
|
||||
Z - Zero
|
||||
C - Carry
|
||||
|
||||
Native Mode
|
||||
E - Emulation Mode
|
||||
NVMXDIZC
|
||||
|
||||
N - Negative
|
||||
V - Overflow
|
||||
M - Memory/Accumulator Select
|
||||
X - Index Register Select
|
||||
D - Decimal Mode
|
||||
I - IRQ Disable
|
||||
Z - Zero
|
||||
C - Carry
|
||||
|
||||
*/
|
||||
|
||||
impl Registers {
|
||||
pub fn new() -> Self {
|
||||
@@ -214,7 +242,11 @@ impl Registers {
|
||||
}
|
||||
|
||||
pub fn reset_rep_byte(&mut self, byte: u8) {
|
||||
self.p &= !byte;
|
||||
let mut effective_byte = byte;
|
||||
if self.emulation_mode {
|
||||
effective_byte &= 0b1100_1111;
|
||||
}
|
||||
self.p &= !effective_byte;
|
||||
}
|
||||
|
||||
pub fn set_sep_byte(&mut self, byte: u8) {
|
||||
@@ -440,6 +472,7 @@ mod registers_tests {
|
||||
#[test]
|
||||
fn test_reset_rep_byte() {
|
||||
let mut registers = Registers::new();
|
||||
registers.emulation_mode = false;
|
||||
registers.p = 0xFF;
|
||||
registers.reset_rep_byte(0b0000_0001);
|
||||
assert_eq!(registers.p, 0b1111_1110);
|
||||
|
||||
@@ -263,6 +263,16 @@ impl PPURegisters {
|
||||
0b11 => 128,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let address_translation_rotate = match (register >> 2) & 0b11 {
|
||||
0b00 => 0,
|
||||
0b01 => 8,
|
||||
0b10 => 9,
|
||||
0b11 => 10,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if address_translation_rotate > 0 {
|
||||
// TODO: implement address translation
|
||||
}
|
||||
let increment_when_lo = (register >> 7) != 1;
|
||||
let increment_when_hi = !increment_when_lo;
|
||||
let current_value = self.get_current_vram_address();
|
||||
|
||||
@@ -116,7 +116,7 @@ fn main() -> Result<()> {
|
||||
emulator.tick();
|
||||
}
|
||||
|
||||
let is_emu_mode = emulator.cpu.registers.emulation_mode;
|
||||
let is_emu_mode = emulator.cpu.registers.emulation_mode || (test.initial.e == 1);
|
||||
let is_16index = emulator.cpu.registers.is_16bit_index();
|
||||
|
||||
let emu_mode_sp = (emulator.cpu.registers.sp as usize & 0xFF) | 0x100;
|
||||
|
||||
Reference in New Issue
Block a user