XCE instruction

This commit is contained in:
2023-05-20 18:54:42 -05:00
parent 7b12911e4a
commit 71801857f0
5 changed files with 100 additions and 5 deletions
+7
View File
@@ -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,
}
+4
View File
@@ -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;
}
+18 -1
View File
@@ -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);
}
}
+70 -4
View File
@@ -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);
}
}