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 {
|
impl CPUInstruction for COP {
|
||||||
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
||||||
push_common::do_push(registers, bus, &[registers.pbr]);
|
if !registers.emulation_mode {
|
||||||
|
push_common::do_push(registers, bus, &[registers.pbr]);
|
||||||
|
}
|
||||||
let (bytes, cycles) = cycles::increment_cycles_brk(registers.emulation_mode);
|
let (bytes, cycles) = cycles::increment_cycles_brk(registers.emulation_mode);
|
||||||
registers.increment_pc(bytes); registers.cycles += cycles;
|
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.pc >> 8) as u8, registers.pc as u8]);
|
||||||
push_common::do_push(registers, bus, &[registers.p]);
|
push_common::do_push(registers, bus, &[registers.p]);
|
||||||
registers.set_irq_disable_flag(true);
|
registers.set_irq_disable_flag(true);
|
||||||
registers.pbr = 0x00;
|
registers.pbr = 0x00;
|
||||||
let vector = (bus.read(0x00FFE4) as u16) | ((bus.read(0x00FFE5) as u16) << 8);
|
if registers.emulation_mode {
|
||||||
registers.pc = vector;
|
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);
|
registers.set_decimal_mode_flag(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ impl CPUInstruction for PLP {
|
|||||||
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
fn execute(&self, registers: &mut Registers, bus: &mut Bus) {
|
||||||
let bytes = pull_common::do_pull(registers, bus, 1, true);
|
let bytes = pull_common::do_pull(registers, bus, 1, true);
|
||||||
registers.p = bytes[0];
|
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();
|
let (bytes, cycles) = cycles::increment_cycles_plp();
|
||||||
registers.increment_pc(bytes); registers.cycles += cycles;
|
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;
|
let mut is_zero = true;
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
registers.increment_sp(1);
|
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 {
|
if byte != 0 {
|
||||||
is_zero = false;
|
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]) {
|
pub fn do_push(registers: &mut Registers, bus: &mut Bus, bytes: &[u8]) {
|
||||||
for byte in bytes {
|
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);
|
bus.write(address, *byte);
|
||||||
registers.decrement_sp(1);
|
registers.decrement_sp(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,12 @@ pub struct XCE {}
|
|||||||
|
|
||||||
impl CPUInstruction for XCE {
|
impl CPUInstruction for XCE {
|
||||||
fn execute(&self, registers: &mut Registers, _bus: &mut Bus) {
|
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();
|
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();
|
let (bytes, cycles) = cycles::increment_cycles_exchange();
|
||||||
registers.increment_pc(bytes); registers.cycles += cycles;
|
registers.increment_pc(bytes); registers.cycles += cycles;
|
||||||
}
|
}
|
||||||
@@ -34,5 +39,44 @@ mod cpu_instructions_tests {
|
|||||||
instruction.execute(&mut registers, &mut bus);
|
instruction.execute(&mut registers, &mut bus);
|
||||||
assert_eq!(registers.pc, 0x0001);
|
assert_eq!(registers.pc, 0x0001);
|
||||||
assert_eq!(registers.cycles, 2);
|
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 is_move_next: bool, // TODO: refactor these states with an enum
|
||||||
pub cycles: usize,
|
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 {
|
impl Registers {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@@ -214,7 +242,11 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset_rep_byte(&mut self, byte: u8) {
|
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) {
|
pub fn set_sep_byte(&mut self, byte: u8) {
|
||||||
@@ -440,6 +472,7 @@ mod registers_tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_reset_rep_byte() {
|
fn test_reset_rep_byte() {
|
||||||
let mut registers = Registers::new();
|
let mut registers = Registers::new();
|
||||||
|
registers.emulation_mode = false;
|
||||||
registers.p = 0xFF;
|
registers.p = 0xFF;
|
||||||
registers.reset_rep_byte(0b0000_0001);
|
registers.reset_rep_byte(0b0000_0001);
|
||||||
assert_eq!(registers.p, 0b1111_1110);
|
assert_eq!(registers.p, 0b1111_1110);
|
||||||
|
|||||||
@@ -263,6 +263,16 @@ impl PPURegisters {
|
|||||||
0b11 => 128,
|
0b11 => 128,
|
||||||
_ => unreachable!(),
|
_ => 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_lo = (register >> 7) != 1;
|
||||||
let increment_when_hi = !increment_when_lo;
|
let increment_when_hi = !increment_when_lo;
|
||||||
let current_value = self.get_current_vram_address();
|
let current_value = self.get_current_vram_address();
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ fn main() -> Result<()> {
|
|||||||
emulator.tick();
|
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 is_16index = emulator.cpu.registers.is_16bit_index();
|
||||||
|
|
||||||
let emu_mode_sp = (emulator.cpu.registers.sp as usize & 0xFF) | 0x100;
|
let emu_mode_sp = (emulator.cpu.registers.sp as usize & 0xFF) | 0x100;
|
||||||
|
|||||||
Reference in New Issue
Block a user