mirror of
https://github.com/FranLMSP/snes.git
synced 2026-10-04 16:35:18 -04:00
XCE instruction
This commit is contained in:
@@ -11,4 +11,11 @@ pub enum Flags {
|
|||||||
Zero(bool),
|
Zero(bool),
|
||||||
Carry(bool),
|
Carry(bool),
|
||||||
HalfCarry(bool),
|
HalfCarry(bool),
|
||||||
|
EmulationMode(bool),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||||
|
pub enum ModeFlag {
|
||||||
|
Carry,
|
||||||
|
EmulationMode,
|
||||||
}
|
}
|
||||||
@@ -381,6 +381,10 @@ impl CPU {
|
|||||||
self.registers.increment_pc(1); self.cycles += 2;
|
self.registers.increment_pc(1); self.cycles += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increment_cycles_exchange(&mut self) {
|
||||||
|
self.registers.increment_pc(1); self.cycles += 2;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn increment_cycles_xba(&mut self) {
|
pub fn increment_cycles_xba(&mut self) {
|
||||||
self.registers.increment_pc(1); self.cycles += 3;
|
self.registers.increment_pc(1); self.cycles += 3;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1098,6 +1098,11 @@ impl CPU {
|
|||||||
self.increment_cycles_test(addressing_mode);
|
self.increment_cycles_test(addressing_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn xce(&mut self) {
|
||||||
|
self.registers.exchange_carry_and_emulation();
|
||||||
|
self.increment_cycles_exchange();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tick(&mut self, bus: &mut Bus) {
|
pub fn tick(&mut self, bus: &mut Bus) {
|
||||||
let opcode = bus.read(self.registers.get_pc_address());
|
let opcode = bus.read(self.registers.get_pc_address());
|
||||||
self.execute_opcode(opcode, bus);
|
self.execute_opcode(opcode, bus);
|
||||||
@@ -1452,7 +1457,7 @@ impl CPU {
|
|||||||
// XBA
|
// XBA
|
||||||
0xEB => self.xba(),
|
0xEB => self.xba(),
|
||||||
// XCE
|
// XCE
|
||||||
0xFB => unimplemented!("XCE instruction not implemented yet"),
|
0xFB => self.xce(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1460,6 +1465,7 @@ impl CPU {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod cpu_instructions_tests {
|
mod cpu_instructions_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use crate::common::flags::ModeFlag;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_adc() {
|
fn test_adc() {
|
||||||
@@ -2883,4 +2889,15 @@ mod cpu_instructions_tests {
|
|||||||
assert_eq!(cpu.registers.pc, 0x0001);
|
assert_eq!(cpu.registers.pc, 0x0001);
|
||||||
assert_eq!(cpu.cycles, 3);
|
assert_eq!(cpu.cycles, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_xce() {
|
||||||
|
let mut cpu = CPU::new();
|
||||||
|
cpu.registers.pc = 0x0000;
|
||||||
|
cpu.registers.exposed_bit_zero = ModeFlag::Carry;
|
||||||
|
cpu.xce();
|
||||||
|
assert_eq!(cpu.registers.exposed_bit_zero, ModeFlag::EmulationMode);
|
||||||
|
assert_eq!(cpu.registers.pc, 0x0001);
|
||||||
|
assert_eq!(cpu.cycles, 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::common::flags::Flags;
|
use crate::common::flags::{Flags, ModeFlag};
|
||||||
|
|
||||||
pub struct Registers {
|
pub struct Registers {
|
||||||
pub sp: u16, // Stack pointer
|
pub sp: u16, // Stack pointer
|
||||||
@@ -10,7 +10,9 @@ pub struct Registers {
|
|||||||
pub pbr: u8, // Program bank register
|
pub pbr: u8, // Program bank register
|
||||||
pub dbr: u8, // Data bank register
|
pub dbr: u8, // Data bank register
|
||||||
pub pc: u16, // Program counter
|
pub pc: u16, // Program counter
|
||||||
|
pub exposed_bit_zero: ModeFlag,
|
||||||
pub emulation_mode: bool,
|
pub emulation_mode: bool,
|
||||||
|
pub carry: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Registers {
|
impl Registers {
|
||||||
@@ -25,7 +27,9 @@ impl Registers {
|
|||||||
pbr: 0,
|
pbr: 0,
|
||||||
dbr: 0,
|
dbr: 0,
|
||||||
pc: 0,
|
pc: 0,
|
||||||
|
exposed_bit_zero: ModeFlag::Carry,
|
||||||
emulation_mode: false,
|
emulation_mode: false,
|
||||||
|
carry: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,12 +50,27 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_carry_flag(&self) -> bool {
|
pub fn get_carry_flag(&self) -> bool {
|
||||||
(self.p & 0b0000_0001) == 1
|
match self.exposed_bit_zero {
|
||||||
|
ModeFlag::Carry => self.carry,
|
||||||
|
ModeFlag::EmulationMode => self.emulation_mode,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_carry_flag(&mut self, val: bool) {
|
pub fn set_carry_flag(&mut self, val: bool) {
|
||||||
self.p = self.p & 0b1111_1110;
|
self.p = self.p & 0b1111_1110;
|
||||||
self.p = self.p | (val as u8);
|
self.p = self.p | (val as u8);
|
||||||
|
match self.exposed_bit_zero {
|
||||||
|
ModeFlag::Carry => self.carry = val,
|
||||||
|
ModeFlag::EmulationMode => self.emulation_mode = val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_emulation_mode_flag(&self) -> bool {
|
||||||
|
self.get_carry_flag()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_emulation_mode_flag(&mut self, val: bool) {
|
||||||
|
self.set_carry_flag(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_zero_flag(&self) -> bool {
|
pub fn get_zero_flag(&self) -> bool {
|
||||||
@@ -166,6 +185,21 @@ impl Registers {
|
|||||||
self.d as u8
|
self.d as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn exchange_carry_and_emulation(&mut self) {
|
||||||
|
match self.exposed_bit_zero {
|
||||||
|
ModeFlag::Carry => {
|
||||||
|
self.carry = self.get_carry_flag();
|
||||||
|
self.exposed_bit_zero = ModeFlag::EmulationMode;
|
||||||
|
self.set_emulation_mode_flag(self.emulation_mode);
|
||||||
|
},
|
||||||
|
ModeFlag::EmulationMode => {
|
||||||
|
self.emulation_mode = self.get_carry_flag();
|
||||||
|
self.exposed_bit_zero = ModeFlag::Carry;
|
||||||
|
self.set_carry_flag(self.carry);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_flags(&mut self, flags: &[Flags]) {
|
pub fn set_flags(&mut self, flags: &[Flags]) {
|
||||||
for flag in flags {
|
for flag in flags {
|
||||||
let flag = *flag;
|
let flag = *flag;
|
||||||
@@ -177,7 +211,7 @@ impl Registers {
|
|||||||
Flags::DecimalMode(v) => self.set_decimal_mode_flag(v),
|
Flags::DecimalMode(v) => self.set_decimal_mode_flag(v),
|
||||||
Flags::IRQDisable(v) => self.set_irq_disable_flag(v),
|
Flags::IRQDisable(v) => self.set_irq_disable_flag(v),
|
||||||
Flags::Zero(v) => self.set_zero_flag(v),
|
Flags::Zero(v) => self.set_zero_flag(v),
|
||||||
Flags::Carry(v) => self.set_carry_flag(v),
|
Flags::Carry(v) | Flags::EmulationMode(v) => self.set_carry_flag(v),
|
||||||
Flags::HalfCarry(_) => {},
|
Flags::HalfCarry(_) => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,6 +321,13 @@ mod registers_tests {
|
|||||||
assert!(!registers.get_carry_flag());
|
assert!(!registers.get_carry_flag());
|
||||||
assert_eq!(registers.p, 0b0000_0000);
|
assert_eq!(registers.p, 0b0000_0000);
|
||||||
|
|
||||||
|
registers.set_emulation_mode_flag(true);
|
||||||
|
assert!(registers.get_emulation_mode_flag());
|
||||||
|
assert_eq!(registers.p, 0b0000_0001);
|
||||||
|
registers.set_emulation_mode_flag(false);
|
||||||
|
assert!(!registers.get_emulation_mode_flag());
|
||||||
|
assert_eq!(registers.p, 0b0000_0000);
|
||||||
|
|
||||||
registers.set_zero_flag(true);
|
registers.set_zero_flag(true);
|
||||||
assert!(registers.get_zero_flag());
|
assert!(registers.get_zero_flag());
|
||||||
assert_eq!(registers.p, 0b0000_0010);
|
assert_eq!(registers.p, 0b0000_0010);
|
||||||
@@ -359,5 +400,30 @@ mod registers_tests {
|
|||||||
assert!(!registers.get_zero_flag());
|
assert!(!registers.get_zero_flag());
|
||||||
assert_eq!(registers.p, 0b1111_1100);
|
assert_eq!(registers.p, 0b1111_1100);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_exchange_carry_and_emulation() {
|
||||||
|
let mut registers = Registers::new();
|
||||||
|
registers.exposed_bit_zero = ModeFlag::Carry;
|
||||||
|
registers .set_flags(&[Flags::Carry(false)]);
|
||||||
|
registers.exposed_bit_zero = ModeFlag::EmulationMode;
|
||||||
|
registers .set_flags(&[Flags::EmulationMode(false)]);
|
||||||
|
|
||||||
|
registers.exposed_bit_zero = ModeFlag::Carry;
|
||||||
|
registers.set_carry_flag(true);
|
||||||
|
assert_eq!(registers.get_carry_flag(), true);
|
||||||
|
registers.exchange_carry_and_emulation();
|
||||||
|
assert_eq!(registers.get_carry_flag(), false);
|
||||||
|
|
||||||
|
registers.exposed_bit_zero = ModeFlag::Carry;
|
||||||
|
registers .set_flags(&[Flags::Carry(false)]);
|
||||||
|
registers.exposed_bit_zero = ModeFlag::EmulationMode;
|
||||||
|
registers .set_flags(&[Flags::EmulationMode(false)]);
|
||||||
|
|
||||||
|
registers.exposed_bit_zero = ModeFlag::EmulationMode;
|
||||||
|
registers.set_emulation_mode_flag(true);
|
||||||
|
assert_eq!(registers.get_emulation_mode_flag(), true);
|
||||||
|
registers.exchange_carry_and_emulation();
|
||||||
|
assert_eq!(registers.get_emulation_mode_flag(), false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -327,6 +327,7 @@ fn main() {
|
|||||||
ui.text(format!("DBR: | {:#04X}", emulator.cpu.registers.dbr));
|
ui.text(format!("DBR: | {:#04X}", emulator.cpu.registers.dbr));
|
||||||
ui.text(format!("PC: | {:#06X}", emulator.cpu.registers.pc));
|
ui.text(format!("PC: | {:#06X}", emulator.cpu.registers.pc));
|
||||||
ui.text(format!("EMU MODE: | {}", emulator.cpu.registers.emulation_mode));
|
ui.text(format!("EMU MODE: | {}", emulator.cpu.registers.emulation_mode));
|
||||||
|
ui.text(format!("CARRY: | {}", emulator.cpu.registers.carry));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user