mirror of
https://github.com/FranLMSP/snes.git
synced 2026-10-04 16:35:18 -04:00
Fix bugs with emulation mode flag
This commit is contained in:
@@ -349,6 +349,10 @@ impl CPU {
|
|||||||
self.registers.increment_pc(2); self.cycles += 3;
|
self.registers.increment_pc(2); self.cycles += 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn increment_cycles_sep(&mut self) {
|
||||||
|
self.registers.increment_pc(2); self.cycles += 3;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn increment_cycles_return_subroutine(&mut self) {
|
pub fn increment_cycles_return_subroutine(&mut self) {
|
||||||
self.cycles += 6;
|
self.cycles += 6;
|
||||||
}
|
}
|
||||||
@@ -364,10 +368,6 @@ impl CPU {
|
|||||||
self.registers.increment_pc(1); self.cycles += 2;
|
self.registers.increment_pc(1); self.cycles += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increment_cycles_sep(&mut self) {
|
|
||||||
self.registers.increment_pc(2); self.cycles += 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn increment_cycles_sta(&mut self, addressing_mode: AddressingMode) {
|
pub fn increment_cycles_sta(&mut self, addressing_mode: AddressingMode) {
|
||||||
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
let (bytes, cycles) = CPU::common_bytes_cycles_arithmetic(addressing_mode);
|
||||||
self.registers.increment_pc(bytes); self.cycles += cycles;
|
self.registers.increment_pc(bytes); self.cycles += cycles;
|
||||||
|
|||||||
@@ -672,7 +672,7 @@ impl CPU {
|
|||||||
IndexRegister::Y => self.registers.y = value,
|
IndexRegister::Y => self.registers.y = value,
|
||||||
}
|
}
|
||||||
self.registers.set_flags(&[
|
self.registers.set_flags(&[
|
||||||
Flags::Negative(value >> 7 == 1),
|
Flags::Negative(value >> 15 == 1),
|
||||||
Flags::Zero(value == 0),
|
Flags::Zero(value == 0),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
@@ -844,7 +844,8 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn sep(&mut self, bus: &mut Bus) {
|
fn sep(&mut self, bus: &mut Bus) {
|
||||||
self.registers.p = self.get_8bit_from_address(bus, AddressingMode::Immediate);
|
let byte = self.get_8bit_from_address(bus, AddressingMode::Immediate);
|
||||||
|
self.registers.set_sep_byte(byte);
|
||||||
self.increment_cycles_sep();
|
self.increment_cycles_sep();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -979,7 +980,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn txs(&mut self) {
|
fn txs(&mut self) {
|
||||||
if self.registers.is_16bit_mode() {
|
if self.registers.is_16bit_index() {
|
||||||
self.registers.sp = self.registers.x;
|
self.registers.sp = self.registers.x;
|
||||||
self.registers.set_negative_flag((self.registers.a >> 15) == 1);
|
self.registers.set_negative_flag((self.registers.a >> 15) == 1);
|
||||||
self.registers.set_zero_flag(self.registers.a == 0);
|
self.registers.set_zero_flag(self.registers.a == 0);
|
||||||
@@ -993,7 +994,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn txy(&mut self) {
|
fn txy(&mut self) {
|
||||||
if self.registers.is_16bit_mode() {
|
if self.registers.is_16bit_index() {
|
||||||
self.registers.y = self.registers.x;
|
self.registers.y = self.registers.x;
|
||||||
self.registers.set_negative_flag((self.registers.x >> 15) == 1);
|
self.registers.set_negative_flag((self.registers.x >> 15) == 1);
|
||||||
self.registers.set_zero_flag(self.registers.x == 0);
|
self.registers.set_zero_flag(self.registers.x == 0);
|
||||||
@@ -1021,7 +1022,7 @@ impl CPU {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn tyx(&mut self) {
|
fn tyx(&mut self) {
|
||||||
if self.registers.is_16bit_mode() {
|
if self.registers.is_16bit_index() {
|
||||||
self.registers.x = self.registers.y;
|
self.registers.x = self.registers.y;
|
||||||
self.registers.set_negative_flag((self.registers.y >> 15) == 1);
|
self.registers.set_negative_flag((self.registers.y >> 15) == 1);
|
||||||
self.registers.set_zero_flag(self.registers.y == 0);
|
self.registers.set_zero_flag(self.registers.y == 0);
|
||||||
@@ -1510,7 +1511,6 @@ 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() {
|
||||||
@@ -1623,7 +1623,6 @@ mod cpu_instructions_tests {
|
|||||||
let mut cpu = CPU::new();
|
let mut cpu = CPU::new();
|
||||||
let mut bus = Bus::new();
|
let mut bus = Bus::new();
|
||||||
cpu.registers.emulation_mode = false;
|
cpu.registers.emulation_mode = false;
|
||||||
cpu.registers.exposed_bit_zero = ModeFlag::Carry;
|
|
||||||
cpu.registers.a = 0b00000000_00000011;
|
cpu.registers.a = 0b00000000_00000011;
|
||||||
cpu.registers.pbr = 0x00;
|
cpu.registers.pbr = 0x00;
|
||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
@@ -2077,7 +2076,6 @@ mod cpu_instructions_tests {
|
|||||||
cpu.registers.pbr = 0x00;
|
cpu.registers.pbr = 0x00;
|
||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
cpu.registers.emulation_mode = false;
|
cpu.registers.emulation_mode = false;
|
||||||
cpu.registers.exposed_bit_zero = ModeFlag::Carry;
|
|
||||||
cpu.registers.set_16bit_index(true);
|
cpu.registers.set_16bit_index(true);
|
||||||
cpu.registers.set_overflow_flag(false);
|
cpu.registers.set_overflow_flag(false);
|
||||||
bus.write(0x000002, 0xB0);
|
bus.write(0x000002, 0xB0);
|
||||||
@@ -2098,7 +2096,6 @@ mod cpu_instructions_tests {
|
|||||||
let mut cpu = CPU::new();
|
let mut cpu = CPU::new();
|
||||||
let mut bus = Bus::new();
|
let mut bus = Bus::new();
|
||||||
cpu.registers.emulation_mode = false;
|
cpu.registers.emulation_mode = false;
|
||||||
cpu.registers.exposed_bit_zero = ModeFlag::Carry;
|
|
||||||
cpu.registers.y = 0x01;
|
cpu.registers.y = 0x01;
|
||||||
cpu.registers.pbr = 0x00;
|
cpu.registers.pbr = 0x00;
|
||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
@@ -2455,6 +2452,7 @@ mod cpu_instructions_tests {
|
|||||||
let mut cpu = CPU::new();
|
let mut cpu = CPU::new();
|
||||||
let mut bus = Bus::new();
|
let mut bus = Bus::new();
|
||||||
cpu.registers.emulation_mode = false;
|
cpu.registers.emulation_mode = false;
|
||||||
|
cpu.registers.set_16bit_index(true);
|
||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
cpu.registers.x = 0x1234;
|
cpu.registers.x = 0x1234;
|
||||||
cpu.registers.sp = 0x1FC;
|
cpu.registers.sp = 0x1FC;
|
||||||
@@ -2471,6 +2469,7 @@ mod cpu_instructions_tests {
|
|||||||
let mut cpu = CPU::new();
|
let mut cpu = CPU::new();
|
||||||
let mut bus = Bus::new();
|
let mut bus = Bus::new();
|
||||||
cpu.registers.emulation_mode = false;
|
cpu.registers.emulation_mode = false;
|
||||||
|
cpu.registers.set_16bit_index(true);
|
||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
cpu.registers.y = 0x1234;
|
cpu.registers.y = 0x1234;
|
||||||
cpu.registers.sp = 0x1FC;
|
cpu.registers.sp = 0x1FC;
|
||||||
@@ -2900,7 +2899,7 @@ mod cpu_instructions_tests {
|
|||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
cpu.registers.a = 0x0000;
|
cpu.registers.a = 0x0000;
|
||||||
cpu.registers.x = 0xF0F0;
|
cpu.registers.x = 0xF0F0;
|
||||||
cpu.registers.set_16bit_index(true);
|
cpu.registers.set_16bit_mode(true);
|
||||||
cpu.txa();
|
cpu.txa();
|
||||||
assert_eq!(cpu.registers.a, 0xF0F0);
|
assert_eq!(cpu.registers.a, 0xF0F0);
|
||||||
assert_eq!(cpu.registers.pc, 0x0001);
|
assert_eq!(cpu.registers.pc, 0x0001);
|
||||||
@@ -2942,7 +2941,7 @@ mod cpu_instructions_tests {
|
|||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
cpu.registers.a = 0x0000;
|
cpu.registers.a = 0x0000;
|
||||||
cpu.registers.y = 0xF0F0;
|
cpu.registers.y = 0xF0F0;
|
||||||
cpu.registers.set_16bit_index(true);
|
cpu.registers.set_16bit_mode(true);
|
||||||
cpu.tya();
|
cpu.tya();
|
||||||
assert_eq!(cpu.registers.a, 0xF0F0);
|
assert_eq!(cpu.registers.a, 0xF0F0);
|
||||||
assert_eq!(cpu.registers.pc, 0x0001);
|
assert_eq!(cpu.registers.pc, 0x0001);
|
||||||
@@ -2998,9 +2997,7 @@ mod cpu_instructions_tests {
|
|||||||
fn test_xce() {
|
fn test_xce() {
|
||||||
let mut cpu = CPU::new();
|
let mut cpu = CPU::new();
|
||||||
cpu.registers.pc = 0x0000;
|
cpu.registers.pc = 0x0000;
|
||||||
cpu.registers.exposed_bit_zero = ModeFlag::Carry;
|
|
||||||
cpu.xce();
|
cpu.xce();
|
||||||
assert_eq!(cpu.registers.exposed_bit_zero, ModeFlag::EmulationMode);
|
|
||||||
assert_eq!(cpu.registers.pc, 0x0001);
|
assert_eq!(cpu.registers.pc, 0x0001);
|
||||||
assert_eq!(cpu.cycles, 2);
|
assert_eq!(cpu.cycles, 2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::common::flags::{Flags, ModeFlag};
|
use crate::common::flags::Flags;
|
||||||
|
|
||||||
pub struct Registers {
|
pub struct Registers {
|
||||||
pub sp: u16, // Stack pointer
|
pub sp: u16, // Stack pointer
|
||||||
@@ -10,26 +10,22 @@ 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 {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
sp: 0x01FC,
|
sp: 0x01FF,
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0,
|
y: 0,
|
||||||
a: 0,
|
a: 0,
|
||||||
p: 0,
|
p: 0b00110100,
|
||||||
d: 0,
|
d: 0,
|
||||||
pbr: 0,
|
pbr: 0,
|
||||||
dbr: 0,
|
dbr: 0,
|
||||||
pc: 0,
|
pc: 0,
|
||||||
exposed_bit_zero: ModeFlag::EmulationMode,
|
|
||||||
emulation_mode: true,
|
emulation_mode: true,
|
||||||
carry: false,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,19 +46,12 @@ impl Registers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_carry_flag(&self) -> bool {
|
pub fn get_carry_flag(&self) -> bool {
|
||||||
match self.exposed_bit_zero {
|
(self.p & 0b0000_0001) == 1
|
||||||
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 {
|
pub fn get_emulation_mode_flag(&self) -> bool {
|
||||||
@@ -191,26 +180,10 @@ impl Registers {
|
|||||||
self.d as u8
|
self.d as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_emu_mode_flag_exposed(&self) -> bool {
|
|
||||||
match self.exposed_bit_zero {
|
|
||||||
ModeFlag::Carry => false,
|
|
||||||
ModeFlag::EmulationMode => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn exchange_carry_and_emulation(&mut self) {
|
pub fn exchange_carry_and_emulation(&mut self) {
|
||||||
match self.exposed_bit_zero {
|
let temp_carry_flag_value = self.get_carry_flag();
|
||||||
ModeFlag::Carry => {
|
self.set_carry_flag(self.emulation_mode);
|
||||||
self.carry = self.get_carry_flag();
|
self.emulation_mode = temp_carry_flag_value;
|
||||||
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]) {
|
||||||
@@ -232,11 +205,10 @@ impl Registers {
|
|||||||
|
|
||||||
pub fn reset_rep_byte(&mut self, byte: u8) {
|
pub fn reset_rep_byte(&mut self, byte: u8) {
|
||||||
self.p = self.p & !byte;
|
self.p = self.p & !byte;
|
||||||
// Avoid messing up exposed emu mode flag logic
|
}
|
||||||
let reset_carry_flag = (byte & 0x01) == 1;
|
|
||||||
if reset_carry_flag {
|
pub fn set_sep_byte(&mut self, byte: u8) {
|
||||||
self.set_carry_flag(false);
|
self.p = self.p | byte;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -437,27 +409,16 @@ mod registers_tests {
|
|||||||
fn test_exchange_carry_and_emulation() {
|
fn test_exchange_carry_and_emulation() {
|
||||||
let mut registers = Registers::new();
|
let mut registers = Registers::new();
|
||||||
registers.emulation_mode = false;
|
registers.emulation_mode = false;
|
||||||
registers.exposed_bit_zero = ModeFlag::Carry;
|
registers.set_flags(&[Flags::Carry(true)]);
|
||||||
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();
|
registers.exchange_carry_and_emulation();
|
||||||
assert_eq!(registers.get_carry_flag(), false);
|
assert_eq!(registers.get_carry_flag(), false);
|
||||||
|
assert_eq!(registers.emulation_mode, true);
|
||||||
|
|
||||||
registers.exposed_bit_zero = ModeFlag::Carry;
|
registers.emulation_mode = true;
|
||||||
registers .set_flags(&[Flags::Carry(false)]);
|
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();
|
registers.exchange_carry_and_emulation();
|
||||||
assert_eq!(registers.get_emulation_mode_flag(), false);
|
assert_eq!(registers.get_carry_flag(), true);
|
||||||
|
assert_eq!(registers.emulation_mode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -495,4 +456,20 @@ mod registers_tests {
|
|||||||
registers.reset_rep_byte(0x38);
|
registers.reset_rep_byte(0x38);
|
||||||
assert_eq!(registers.p, 0b10000110);
|
assert_eq!(registers.p, 0b10000110);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_set_rep_byte() {
|
||||||
|
let mut registers = Registers::new();
|
||||||
|
registers.p = 0xFF;
|
||||||
|
registers.set_sep_byte(0b0000_0001);
|
||||||
|
assert_eq!(registers.p, 0xFF);
|
||||||
|
|
||||||
|
registers.p = 0b10101010;
|
||||||
|
registers.set_sep_byte(0b0000_0000);
|
||||||
|
assert_eq!(registers.p, 0b10101010);
|
||||||
|
|
||||||
|
registers.p = 0b10100000;
|
||||||
|
registers.set_sep_byte(0b0000_1111);
|
||||||
|
assert_eq!(registers.p, 0b10101111);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -370,10 +370,8 @@ 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));
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
ui.text("Status flags:");
|
ui.text("Status flags:");
|
||||||
ui.text(format!(" E (exposed: {})", emulator.cpu.registers.is_emu_mode_flag_exposed()));
|
|
||||||
ui.text("NVMXDIZC");
|
ui.text("NVMXDIZC");
|
||||||
ui.text(format!("{:08b}", emulator.cpu.registers.p));
|
ui.text(format!("{:08b}", emulator.cpu.registers.p));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -71,13 +71,13 @@ fn render_background_char_2bpp(bgdebug: &mut BgDebug, registers: &PPURegisters)
|
|||||||
// 8x8 pixels, 2 bitplanes, each word (16bit) holds 8 pixels
|
// 8x8 pixels, 2 bitplanes, each word (16bit) holds 8 pixels
|
||||||
// so 1 char is 8 bytes x 2
|
// so 1 char is 8 bytes x 2
|
||||||
let char_base_vram_address = current_char * 8 * 2;
|
let char_base_vram_address = current_char * 8 * 2;
|
||||||
let vram_address = vram_base_address + (
|
let effective_vram_address = vram_base_address + (
|
||||||
char_base_vram_address + (current_char_row * 2)
|
char_base_vram_address + (current_char_row * 2)
|
||||||
);
|
);
|
||||||
let current_pixel = x + (y * width);
|
let current_pixel = x + (y * width);
|
||||||
|
|
||||||
let lsb_bitplane= vram[vram_address];
|
let lsb_bitplane= vram[effective_vram_address];
|
||||||
let msb_bitplane= vram[vram_address + 1];
|
let msb_bitplane= vram[effective_vram_address + 1];
|
||||||
let pixels = [
|
let pixels = [
|
||||||
(
|
(
|
||||||
(lsb_bitplane >> 7) |
|
(lsb_bitplane >> 7) |
|
||||||
|
|||||||
Reference in New Issue
Block a user