mirror of
https://github.com/FranLMSP/snes.git
synced 2026-08-03 08:30:01 -04:00
XCE instruction
This commit is contained in:
@@ -11,4 +11,11 @@ pub enum Flags {
|
||||
Zero(bool),
|
||||
Carry(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;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_exchange(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 2;
|
||||
}
|
||||
|
||||
pub fn increment_cycles_xba(&mut self) {
|
||||
self.registers.increment_pc(1); self.cycles += 3;
|
||||
}
|
||||
|
||||
@@ -1098,6 +1098,11 @@ impl CPU {
|
||||
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) {
|
||||
let opcode = bus.read(self.registers.get_pc_address());
|
||||
self.execute_opcode(opcode, bus);
|
||||
@@ -1452,7 +1457,7 @@ impl CPU {
|
||||
// XBA
|
||||
0xEB => self.xba(),
|
||||
// XCE
|
||||
0xFB => unimplemented!("XCE instruction not implemented yet"),
|
||||
0xFB => self.xce(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1460,6 +1465,7 @@ impl CPU {
|
||||
#[cfg(test)]
|
||||
mod cpu_instructions_tests {
|
||||
use super::*;
|
||||
use crate::common::flags::ModeFlag;
|
||||
|
||||
#[test]
|
||||
fn test_adc() {
|
||||
@@ -2883,4 +2889,15 @@ mod cpu_instructions_tests {
|
||||
assert_eq!(cpu.registers.pc, 0x0001);
|
||||
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 sp: u16, // Stack pointer
|
||||
@@ -10,7 +10,9 @@ pub struct Registers {
|
||||
pub pbr: u8, // Program bank register
|
||||
pub dbr: u8, // Data bank register
|
||||
pub pc: u16, // Program counter
|
||||
pub exposed_bit_zero: ModeFlag,
|
||||
pub emulation_mode: bool,
|
||||
pub carry: bool,
|
||||
}
|
||||
|
||||
impl Registers {
|
||||
@@ -25,7 +27,9 @@ impl Registers {
|
||||
pbr: 0,
|
||||
dbr: 0,
|
||||
pc: 0,
|
||||
exposed_bit_zero: ModeFlag::Carry,
|
||||
emulation_mode: false,
|
||||
carry: false,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,12 +50,27 @@ impl Registers {
|
||||
}
|
||||
|
||||
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) {
|
||||
self.p = self.p & 0b1111_1110;
|
||||
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 {
|
||||
@@ -166,6 +185,21 @@ impl Registers {
|
||||
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]) {
|
||||
for flag in flags {
|
||||
let flag = *flag;
|
||||
@@ -177,7 +211,7 @@ impl Registers {
|
||||
Flags::DecimalMode(v) => self.set_decimal_mode_flag(v),
|
||||
Flags::IRQDisable(v) => self.set_irq_disable_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(_) => {},
|
||||
}
|
||||
}
|
||||
@@ -287,6 +321,13 @@ mod registers_tests {
|
||||
assert!(!registers.get_carry_flag());
|
||||
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);
|
||||
assert!(registers.get_zero_flag());
|
||||
assert_eq!(registers.p, 0b0000_0010);
|
||||
@@ -359,5 +400,30 @@ mod registers_tests {
|
||||
assert!(!registers.get_zero_flag());
|
||||
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!("PC: | {:#06X}", emulator.cpu.registers.pc));
|
||||
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