mirror of
https://github.com/FranLMSP/snes.git
synced 2026-01-01 07:21:35 -05:00
vram writes, reads, auto increments and clear vblank nmi flag when read
This commit is contained in:
@@ -56,14 +56,14 @@ impl Bus {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(&self, address: u32) -> u8 {
|
||||
pub fn read(&mut self, address: u32) -> u8 {
|
||||
let section = Bus::map_address(address);
|
||||
match section {
|
||||
MemoryMap::WRAM => self.read_wram(address),
|
||||
MemoryMap::PPU => self.ppu.registers.read(address as u16),
|
||||
MemoryMap::CPU => self.internal_registers.read(
|
||||
address as u16,
|
||||
&self.ppu.registers,
|
||||
&mut self.ppu.registers,
|
||||
),
|
||||
MemoryMap::Joypad => 0x00, // TODO: Placeholder
|
||||
MemoryMap::Cartridge => self.rom.read(address),
|
||||
|
||||
@@ -9,7 +9,7 @@ use crate::common::flags::Flags;
|
||||
/// arithmetic instructions in one file, transfers in another file, etc
|
||||
|
||||
impl CPU {
|
||||
fn get_effective_address(&self, bus: &Bus, addressing_mode: AddressingMode) -> u32 {
|
||||
fn get_effective_address(&self, bus: &mut Bus, addressing_mode: AddressingMode) -> u32 {
|
||||
addressing_mode.effective_address(
|
||||
bus,
|
||||
self.registers.get_pc_address(),
|
||||
@@ -19,7 +19,7 @@ impl CPU {
|
||||
)
|
||||
}
|
||||
|
||||
fn get_8bit_from_address(&self, bus: &Bus, addressing_mode: AddressingMode) -> u8 {
|
||||
fn get_8bit_from_address(&self, bus: &mut Bus, addressing_mode: AddressingMode) -> u8 {
|
||||
match addressing_mode {
|
||||
AddressingMode::Accumulator => self.registers.a as u8,
|
||||
_ => addressing_mode.value_8bit(
|
||||
@@ -32,7 +32,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn get_16bit_from_address(&self, bus: &Bus, addressing_mode: AddressingMode) -> u16 {
|
||||
fn get_16bit_from_address(&self, bus: &mut Bus, addressing_mode: AddressingMode) -> u16 {
|
||||
match addressing_mode {
|
||||
AddressingMode::Accumulator => self.registers.a,
|
||||
_ => addressing_mode.value_16bit(
|
||||
@@ -73,7 +73,7 @@ impl CPU {
|
||||
};
|
||||
}
|
||||
|
||||
fn adc(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn adc(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let carry_flag = self.registers.get_carry_flag();
|
||||
let is_decimal_mode = self.registers.get_decimal_mode_flag();
|
||||
let is_16bit = self.registers.is_16bit_mode();
|
||||
@@ -98,7 +98,7 @@ impl CPU {
|
||||
self.increment_cycles_arithmetic(addressing_mode);
|
||||
}
|
||||
|
||||
fn sbc(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn sbc(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let carry_flag = self.registers.get_carry_flag();
|
||||
let is_decimal_mode = self.registers.get_decimal_mode_flag();
|
||||
let is_16bit = self.registers.is_16bit_mode();
|
||||
@@ -221,7 +221,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn cmp(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn cmp(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let is_16bit = self.registers.is_16bit_mode();
|
||||
let target = self.registers.a;
|
||||
if is_16bit {
|
||||
@@ -234,7 +234,7 @@ impl CPU {
|
||||
self.increment_cycles_arithmetic(addressing_mode);
|
||||
}
|
||||
|
||||
fn cpx(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn cpx(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let is_16bit = self.registers.is_16bit_index();
|
||||
let target = self.registers.x;
|
||||
if is_16bit {
|
||||
@@ -247,7 +247,7 @@ impl CPU {
|
||||
self.increment_cycles_comp_index(addressing_mode);
|
||||
}
|
||||
|
||||
fn cpy(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn cpy(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let is_16bit = self.registers.is_16bit_index();
|
||||
let target = self.registers.y;
|
||||
if is_16bit {
|
||||
@@ -260,7 +260,7 @@ impl CPU {
|
||||
self.increment_cycles_comp_index(addressing_mode);
|
||||
}
|
||||
|
||||
fn and(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn and(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let target = self.registers.a;
|
||||
if self.registers.is_16bit_mode() {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
@@ -276,7 +276,7 @@ impl CPU {
|
||||
self.increment_cycles_bitwise(addressing_mode);
|
||||
}
|
||||
|
||||
fn ora(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn ora(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let target = self.registers.a;
|
||||
if self.registers.is_16bit_mode() {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
@@ -292,7 +292,7 @@ impl CPU {
|
||||
self.increment_cycles_bitwise(addressing_mode);
|
||||
}
|
||||
|
||||
fn eor(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn eor(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let target = self.registers.a;
|
||||
if self.registers.is_16bit_mode() {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
@@ -361,7 +361,7 @@ impl CPU {
|
||||
};
|
||||
}
|
||||
|
||||
fn bit(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn bit(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
if self.registers.is_16bit_mode() {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
self.do_bit(self.registers.a, value, addressing_mode);
|
||||
@@ -386,7 +386,7 @@ impl CPU {
|
||||
return page_boundary_crossed
|
||||
}
|
||||
|
||||
fn bcc(&mut self, bus: &Bus) {
|
||||
fn bcc(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if !self.registers.get_carry_flag() {
|
||||
@@ -395,7 +395,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn bcs(&mut self, bus: &Bus) {
|
||||
fn bcs(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if self.registers.get_carry_flag() {
|
||||
@@ -404,7 +404,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn beq(&mut self, bus: &Bus) {
|
||||
fn beq(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if self.registers.get_zero_flag() {
|
||||
@@ -413,7 +413,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn bne(&mut self, bus: &Bus) {
|
||||
fn bne(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if !self.registers.get_zero_flag() {
|
||||
@@ -422,7 +422,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn bmi(&mut self, bus: &Bus) {
|
||||
fn bmi(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if self.registers.get_negative_flag() {
|
||||
@@ -431,7 +431,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn bpl(&mut self, bus: &Bus) {
|
||||
fn bpl(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if !self.registers.get_negative_flag() {
|
||||
@@ -440,14 +440,14 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn bra(&mut self, bus: &Bus) {
|
||||
fn bra(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
let page_boundary_crossed = self.do_branch(nearlabel);
|
||||
self.increment_cycles_branch_taken(page_boundary_crossed);
|
||||
}
|
||||
|
||||
fn brl(&mut self, bus: &Bus) {
|
||||
fn brl(&mut self, bus: &mut Bus) {
|
||||
let label = bus.read(self.registers.get_pc_address()) as u16 |
|
||||
((bus.read(self.registers.get_pc_address() + 1) as u16) << 8);
|
||||
let is_negative = (label >> 15) != 0;
|
||||
@@ -460,7 +460,7 @@ impl CPU {
|
||||
self.increment_cycles_branch_long();
|
||||
}
|
||||
|
||||
fn bvc(&mut self, bus: &Bus) {
|
||||
fn bvc(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if !self.registers.get_overflow_flag() {
|
||||
@@ -469,7 +469,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn bvs(&mut self, bus: &Bus) {
|
||||
fn bvs(&mut self, bus: &mut Bus) {
|
||||
let nearlabel = bus.read(self.registers.get_pc_address().wrapping_add(1));
|
||||
self.increment_cycles_branch();
|
||||
if self.registers.get_overflow_flag() {
|
||||
@@ -502,7 +502,7 @@ impl CPU {
|
||||
self.increment_cycles_nop();
|
||||
}
|
||||
|
||||
fn jmp(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn jmp(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
let effective_address = self.get_effective_address(bus, addressing_mode);
|
||||
let is_long = match addressing_mode {
|
||||
AddressingMode::AbsoluteLong |
|
||||
@@ -644,7 +644,7 @@ impl CPU {
|
||||
}
|
||||
}
|
||||
|
||||
fn lda(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn lda(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
if self.registers.is_16bit_mode() {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
self.registers.a = value;
|
||||
@@ -664,7 +664,7 @@ impl CPU {
|
||||
self.increment_cycles_lda(addressing_mode);
|
||||
}
|
||||
|
||||
fn do_ld_index(&mut self, bus: &Bus, index: IndexRegister, addressing_mode: AddressingMode) {
|
||||
fn do_ld_index(&mut self, bus: &mut Bus, index: IndexRegister, addressing_mode: AddressingMode) {
|
||||
if self.registers.is_16bit_index() {
|
||||
let value = self.get_16bit_from_address(bus, addressing_mode);
|
||||
match index {
|
||||
@@ -689,15 +689,15 @@ impl CPU {
|
||||
self.increment_cycles_ld_index(addressing_mode);
|
||||
}
|
||||
|
||||
fn ldx(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn ldx(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
self.do_ld_index(bus, IndexRegister::X, addressing_mode);
|
||||
}
|
||||
|
||||
fn ldy(&mut self, bus: &Bus, addressing_mode: AddressingMode) {
|
||||
fn ldy(&mut self, bus: &mut Bus, addressing_mode: AddressingMode) {
|
||||
self.do_ld_index(bus, IndexRegister::Y, addressing_mode);
|
||||
}
|
||||
|
||||
fn do_pull(&mut self, bus: &Bus, count: usize) -> Vec<u8> {
|
||||
fn do_pull(&mut self, bus: &mut Bus, count: usize) -> Vec<u8> {
|
||||
let mut bytes = vec![];
|
||||
let mut is_zero = true;
|
||||
for _ in 0..count {
|
||||
@@ -717,7 +717,7 @@ impl CPU {
|
||||
bytes
|
||||
}
|
||||
|
||||
fn pla(&mut self, bus: &Bus) {
|
||||
fn pla(&mut self, bus: &mut Bus) {
|
||||
if self.registers.is_16bit_mode() {
|
||||
let bytes = self.do_pull(bus, 2);
|
||||
self.registers.a = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
@@ -728,24 +728,24 @@ impl CPU {
|
||||
self.increment_cycles_pla();
|
||||
}
|
||||
|
||||
fn plb(&mut self, bus: &Bus) {
|
||||
fn plb(&mut self, bus: &mut Bus) {
|
||||
self.registers.dbr = self.do_pull(bus, 1)[0];
|
||||
self.increment_cycles_plb();
|
||||
}
|
||||
|
||||
fn pld(&mut self, bus: &Bus) {
|
||||
fn pld(&mut self, bus: &mut Bus) {
|
||||
let bytes = self.do_pull(bus, 2);
|
||||
self.registers.d = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
self.increment_cycles_pld();
|
||||
}
|
||||
|
||||
fn plp(&mut self, bus: &Bus) {
|
||||
fn plp(&mut self, bus: &mut Bus) {
|
||||
let bytes = self.do_pull(bus, 1);
|
||||
self.registers.p = bytes[0];
|
||||
self.increment_cycles_plp();
|
||||
}
|
||||
|
||||
fn plx(&mut self, bus: &Bus) {
|
||||
fn plx(&mut self, bus: &mut Bus) {
|
||||
if self.registers.is_16bit_index() {
|
||||
let bytes = self.do_pull(bus, 2);
|
||||
self.registers.x = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
@@ -756,7 +756,7 @@ impl CPU {
|
||||
self.increment_cycles_pl_index();
|
||||
}
|
||||
|
||||
fn ply(&mut self, bus: &Bus) {
|
||||
fn ply(&mut self, bus: &mut Bus) {
|
||||
if self.registers.is_16bit_index() {
|
||||
let bytes = self.do_pull(bus, 2);
|
||||
self.registers.y = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
@@ -767,7 +767,7 @@ impl CPU {
|
||||
self.increment_cycles_pl_index();
|
||||
}
|
||||
|
||||
fn rep(&mut self, bus: &Bus) {
|
||||
fn rep(&mut self, bus: &mut Bus) {
|
||||
let byte = self.get_8bit_from_address(bus, AddressingMode::Immediate);
|
||||
self.registers.reset_rep_byte(byte);
|
||||
self.increment_cycles_rep();
|
||||
@@ -813,7 +813,7 @@ impl CPU {
|
||||
self.increment_cycles_shift(addressing_mode);
|
||||
}
|
||||
|
||||
fn rtl(&mut self, bus: &Bus) {
|
||||
fn rtl(&mut self, bus: &mut Bus) {
|
||||
let bytes = self.do_pull(bus, 3);
|
||||
// Low byte of PC is pulled first, then high byte and then PBR
|
||||
self.registers.pc = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
@@ -821,7 +821,7 @@ impl CPU {
|
||||
self.increment_cycles_return_subroutine();
|
||||
}
|
||||
|
||||
fn rts(&mut self, bus: &Bus) {
|
||||
fn rts(&mut self, bus: &mut Bus) {
|
||||
let bytes = self.do_pull(bus, 2);
|
||||
// Low byte of PC is pulled first, then high byte
|
||||
self.registers.pc = (bytes[0] as u16) | ((bytes[1] as u16) << 8);
|
||||
@@ -843,7 +843,7 @@ impl CPU {
|
||||
self.increment_cycles_set_flag();
|
||||
}
|
||||
|
||||
fn sep(&mut self, bus: &Bus) {
|
||||
fn sep(&mut self, bus: &mut Bus) {
|
||||
self.registers.p = self.get_8bit_from_address(bus, AddressingMode::Immediate);
|
||||
self.increment_cycles_sep();
|
||||
}
|
||||
@@ -1053,7 +1053,8 @@ impl CPU {
|
||||
};
|
||||
let source_address = ((source_bank as u32) << 16) | (x as u32);
|
||||
let dest_address = ((dest_bank as u32) << 16) | (y as u32);
|
||||
bus.write(dest_address, bus.read(source_address));
|
||||
let byte = bus.read(source_address);
|
||||
bus.write(dest_address, byte);
|
||||
self.registers.a = self.registers.a.wrapping_sub(1);
|
||||
if is_next {
|
||||
self.registers.x = self.registers.x.wrapping_add(1);
|
||||
@@ -1075,7 +1076,7 @@ impl CPU {
|
||||
self.do_move(bus, true);
|
||||
}
|
||||
|
||||
fn rti(&mut self, bus: &Bus) {
|
||||
fn rti(&mut self, bus: &mut Bus) {
|
||||
self.registers.p = self.do_pull(bus, 1)[0];
|
||||
let pc_bytes = self.do_pull(bus, 2);
|
||||
self.registers.pc = (pc_bytes[0] as u16) | ((pc_bytes[1] as u16) << 8);
|
||||
@@ -1521,7 +1522,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
bus.write(0x000001, 0x40);
|
||||
cpu.adc(&bus, AddressingMode::Immediate);
|
||||
cpu.adc(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0x40);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -1537,7 +1538,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
bus.write(0x000001, 0xF0);
|
||||
cpu.eor(&bus, AddressingMode::Immediate);
|
||||
cpu.eor(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0xFF);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -1555,7 +1556,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
bus.write(0x000001, 1);
|
||||
cpu.sbc(&bus, AddressingMode::Immediate);
|
||||
cpu.sbc(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -1574,7 +1575,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
bus.write(0x000001, 0x01);
|
||||
bus.write(0x000002, 0x01);
|
||||
cpu.and(&bus, AddressingMode::Immediate);
|
||||
cpu.and(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0x0101);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -1591,7 +1592,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
bus.write(0x000001, 0xF0);
|
||||
cpu.ora(&bus, AddressingMode::Immediate);
|
||||
cpu.ora(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0xFF);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -1649,7 +1650,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.p = 0x00;
|
||||
bus.write(0x000001, 0b0000_1111);
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.bit(&bus, AddressingMode::Immediate);
|
||||
cpu.bit(&mut bus, AddressingMode::Immediate);
|
||||
// Check that it only affects the zero flag on immediate mode
|
||||
assert_eq!(cpu.registers.a, 0b1111_0000); // Check that A is not altered
|
||||
assert_eq!(cpu.registers.p, 0b0010_0010); // Only zero flag was altered (bit 6 is memory select mode)
|
||||
@@ -1669,7 +1670,7 @@ mod cpu_instructions_tests {
|
||||
bus.write(0x000004, 0x00);
|
||||
bus.write(0x000005, 0b1100_0000);
|
||||
cpu.registers.set_16bit_mode(true);
|
||||
cpu.bit(&bus, AddressingMode::Absolute);
|
||||
cpu.bit(&mut bus, AddressingMode::Absolute);
|
||||
// Check that it only affects the zero flag on immediate mode
|
||||
assert_eq!(cpu.registers.a, 0b00110000_00000000); // Check that A is not altered
|
||||
assert_eq!(cpu.registers.p, 0b1100_0010);
|
||||
@@ -1734,7 +1735,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_carry_flag(true);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.bcc(&bus);
|
||||
cpu.bcc(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -1742,7 +1743,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_carry_flag(false);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bcc(&bus);
|
||||
cpu.bcc(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1750,7 +1751,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_carry_flag(false);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bcc(&bus);
|
||||
cpu.bcc(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1765,7 +1766,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_carry_flag(false);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.bcs(&bus);
|
||||
cpu.bcs(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -1773,7 +1774,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_carry_flag(true);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bcs(&bus);
|
||||
cpu.bcs(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1781,7 +1782,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_carry_flag(true);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bcs(&bus);
|
||||
cpu.bcs(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1796,7 +1797,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_zero_flag(false);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.beq(&bus);
|
||||
cpu.beq(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -1804,7 +1805,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_zero_flag(true);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.beq(&bus);
|
||||
cpu.beq(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1812,7 +1813,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_zero_flag(true);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.beq(&bus);
|
||||
cpu.beq(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1827,7 +1828,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_zero_flag(true);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.bne(&bus);
|
||||
cpu.bne(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -1835,7 +1836,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_zero_flag(false);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bne(&bus);
|
||||
cpu.bne(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1843,7 +1844,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_zero_flag(false);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bne(&bus);
|
||||
cpu.bne(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1858,7 +1859,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_negative_flag(false);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.bmi(&bus);
|
||||
cpu.bmi(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -1866,7 +1867,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_negative_flag(true);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bmi(&bus);
|
||||
cpu.bmi(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1874,7 +1875,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_negative_flag(true);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bmi(&bus);
|
||||
cpu.bmi(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1889,7 +1890,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_negative_flag(true);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.bpl(&bus);
|
||||
cpu.bpl(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -1897,7 +1898,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_negative_flag(false);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bpl(&bus);
|
||||
cpu.bpl(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1905,7 +1906,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_negative_flag(false);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bpl(&bus);
|
||||
cpu.bpl(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1919,14 +1920,14 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.cycles = 0;
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bra(&bus);
|
||||
cpu.bra(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
cpu.registers.pc = 0x0100;
|
||||
cpu.cycles = 0;
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bra(&bus);
|
||||
cpu.bra(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1941,7 +1942,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
bus.write(0x01, 0b00000000);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.brl(&bus);
|
||||
cpu.brl(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x04 + 0b00001111_00000000);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1949,7 +1950,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
bus.write(0xFD, 0xFF); // write -1
|
||||
bus.write(0xFE, 0xFF); // write -1
|
||||
cpu.brl(&bus);
|
||||
cpu.brl(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFF);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1964,7 +1965,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_overflow_flag(true);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.bvc(&bus);
|
||||
cpu.bvc(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -1972,7 +1973,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_overflow_flag(false);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bvc(&bus);
|
||||
cpu.bvc(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -1980,7 +1981,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_overflow_flag(false);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bvc(&bus);
|
||||
cpu.bvc(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -1995,7 +1996,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_overflow_flag(false);
|
||||
bus.write(0x02, 0b00001111);
|
||||
cpu.bvs(&bus);
|
||||
cpu.bvs(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
// branch taken
|
||||
@@ -2003,7 +2004,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_overflow_flag(true);
|
||||
bus.write(0x01, 0b00001111);
|
||||
cpu.bvs(&bus);
|
||||
cpu.bvs(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0x02 + 0b00001111);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
// test with negative nearlabel and boundary cross
|
||||
@@ -2011,7 +2012,7 @@ mod cpu_instructions_tests {
|
||||
cpu.cycles = 0;
|
||||
cpu.registers.set_overflow_flag(true);
|
||||
bus.write(0x101, 0xFB); // write -5
|
||||
cpu.bvs(&bus);
|
||||
cpu.bvs(&mut bus);
|
||||
assert_eq!(cpu.registers.pc, 0xFD);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
}
|
||||
@@ -2027,7 +2028,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_memory_select_flag(true);
|
||||
bus.write(0x000001, 1);
|
||||
cpu.cmp(&bus, AddressingMode::Immediate);
|
||||
cpu.cmp(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0x0001); // check A is not affected
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -2042,7 +2043,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
cpu.registers.set_overflow_flag(false);
|
||||
bus.write(0x000001, 0xB0);
|
||||
cpu.cmp(&bus, AddressingMode::Immediate);
|
||||
cpu.cmp(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.a, 0x0050); // check A is not affected
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -2063,7 +2064,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_16bit_index(false);
|
||||
bus.write(0x000001, 1);
|
||||
cpu.cpx(&bus, AddressingMode::Immediate);
|
||||
cpu.cpx(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.x, 0x01); // check A is not affected
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -2081,7 +2082,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.set_overflow_flag(false);
|
||||
bus.write(0x000002, 0xB0);
|
||||
bus.write(0x000001, 0x00);
|
||||
cpu.cpx(&bus, AddressingMode::Immediate);
|
||||
cpu.cpx(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.x, 0x50); // check X is not affected
|
||||
assert_eq!(cpu.registers.pc, 0x03);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
@@ -2103,7 +2104,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.set_16bit_index(false);
|
||||
bus.write(0x000001, 1);
|
||||
cpu.cpy(&bus, AddressingMode::Immediate);
|
||||
cpu.cpy(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.y, 0x01); // check A is not affected
|
||||
assert_eq!(cpu.registers.pc, 0x02);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -2119,7 +2120,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.set_overflow_flag(false);
|
||||
bus.write(0x000002, 0xB0);
|
||||
bus.write(0x000001, 0x00);
|
||||
cpu.cpy(&bus, AddressingMode::Immediate);
|
||||
cpu.cpy(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.y, 0x50); // check X is not affected
|
||||
assert_eq!(cpu.registers.pc, 0x03);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
@@ -2232,7 +2233,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
bus.write(0x000002, 0xAA);
|
||||
bus.write(0x000001, 0xBB);
|
||||
cpu.jmp(&bus, AddressingMode::Absolute);
|
||||
cpu.jmp(&mut bus, AddressingMode::Absolute);
|
||||
assert_eq!(cpu.registers.pc, 0xAABB);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
|
||||
@@ -2244,7 +2245,7 @@ mod cpu_instructions_tests {
|
||||
bus.write(0x000003, 0xAA);
|
||||
bus.write(0x000002, 0xBB);
|
||||
bus.write(0x000001, 0xCC);
|
||||
cpu.jmp(&bus, AddressingMode::AbsoluteLong);
|
||||
cpu.jmp(&mut bus, AddressingMode::AbsoluteLong);
|
||||
assert_eq!(cpu.registers.pbr, 0xAA);
|
||||
assert_eq!(cpu.registers.pc, 0xBBCC);
|
||||
assert_eq!(cpu.cycles, 4);
|
||||
@@ -2283,7 +2284,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.set_zero_flag(true);
|
||||
cpu.registers.set_16bit_mode(false);
|
||||
bus.write(0x0001, 0xFF);
|
||||
cpu.lda(&bus, AddressingMode::Immediate);
|
||||
cpu.lda(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.pc, 0x0002);
|
||||
assert_eq!(cpu.registers.a, 0x00FF);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -2302,7 +2303,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.set_zero_flag(true);
|
||||
cpu.registers.set_16bit_index(false);
|
||||
bus.write(0x0001, 0xFF);
|
||||
cpu.ldx(&bus, AddressingMode::Immediate);
|
||||
cpu.ldx(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.pc, 0x0002);
|
||||
assert_eq!(cpu.registers.x, 0x00FF);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -2321,7 +2322,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.set_zero_flag(true);
|
||||
cpu.registers.set_16bit_index(false);
|
||||
bus.write(0x0001, 0xFF);
|
||||
cpu.ldy(&bus, AddressingMode::Immediate);
|
||||
cpu.ldy(&mut bus, AddressingMode::Immediate);
|
||||
assert_eq!(cpu.registers.pc, 0x0002);
|
||||
assert_eq!(cpu.registers.y, 0x00FF);
|
||||
assert_eq!(cpu.cycles, 2);
|
||||
@@ -2719,7 +2720,7 @@ mod cpu_instructions_tests {
|
||||
cpu.registers.pc = 0x0000;
|
||||
cpu.registers.p = 0x00;
|
||||
bus.write(0x0001, 0xFF);
|
||||
cpu.sep(&bus);
|
||||
cpu.sep(&mut bus);
|
||||
assert_eq!(cpu.registers.p, 0xFF);
|
||||
assert_eq!(cpu.registers.pc, 0x0002);
|
||||
assert_eq!(cpu.cycles, 3);
|
||||
|
||||
@@ -24,7 +24,7 @@ impl InternalRegisters {
|
||||
self.registers[(address - INTERNAL_REGISTERS_ADDRESS) as usize] = value
|
||||
}
|
||||
|
||||
pub fn read(&self, address: u16, ppu_registers: &PPURegisters) -> u8 {
|
||||
pub fn read(&self, address: u16, ppu_registers: &mut PPURegisters) -> u8 {
|
||||
match address {
|
||||
RDNMI => self.read_vblank_nmi(ppu_registers),
|
||||
_ => self._read(address),
|
||||
@@ -35,10 +35,12 @@ impl InternalRegisters {
|
||||
self._write(address, value);
|
||||
}
|
||||
|
||||
fn read_vblank_nmi(&self, ppu_registers: &PPURegisters) -> u8 {
|
||||
fn read_vblank_nmi(&self, ppu_registers: &mut PPURegisters) -> u8 {
|
||||
let byte = self._read(RDNMI);
|
||||
// TODO: when this register is read, bit 7 is cleared
|
||||
(byte & 0x7F) | ((ppu_registers.is_vblanking() as u8) << 7)
|
||||
// When register is read, bit 7 is cleared
|
||||
let result = (byte & 0x7F) | ((ppu_registers.vblank_nmi as u8) << 7);
|
||||
ppu_registers.vblank_nmi = false;
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,17 +48,21 @@ impl InternalRegisters {
|
||||
#[cfg(test)]
|
||||
mod ppu_general_test {
|
||||
use super::*;
|
||||
use crate::ppu::ppu::PPU;
|
||||
|
||||
#[test]
|
||||
fn test_read_vblank_nmi() {
|
||||
let registers = InternalRegisters::new();
|
||||
let mut ppu_registers = PPURegisters::new();
|
||||
ppu_registers.h_count = 20;
|
||||
assert_eq!(registers.read_vblank_nmi(&ppu_registers), 0x00);
|
||||
ppu_registers.h_count = 300;
|
||||
assert_eq!(registers.read_vblank_nmi(&ppu_registers), 0x80);
|
||||
// TODO: reset vblank bit after read
|
||||
// ppu_registers.h_count = 300;
|
||||
// assert_eq!(registers.read_vblank_nmi(&ppu_registers), 0x00);
|
||||
let mut ppu = PPU::new();
|
||||
ppu.registers.h_count = 20;
|
||||
ppu.dot_cycle();
|
||||
assert_eq!(registers.read_vblank_nmi(&mut ppu.registers), 0x00);
|
||||
ppu.registers.h_count = 339;
|
||||
ppu.registers.v_count = 224;
|
||||
ppu.dot_cycle();
|
||||
assert_eq!(registers.read_vblank_nmi(&mut ppu.registers), 0x80);
|
||||
// vblank bit is reset after read
|
||||
ppu.dot_cycle();
|
||||
assert_eq!(registers.read_vblank_nmi(&mut ppu.registers), 0x00);
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,11 @@ impl Vector {
|
||||
}
|
||||
|
||||
impl CPU {
|
||||
fn get_vector(base_address: u32, bus: &Bus) -> u16 {
|
||||
fn get_vector(base_address: u32, bus: &mut Bus) -> u16 {
|
||||
(bus.read(base_address) as u16) | ((bus.read(base_address + 1) as u16) << 8)
|
||||
}
|
||||
|
||||
pub fn reset_vector(&mut self, bus: &Bus) {
|
||||
pub fn reset_vector(&mut self, bus: &mut Bus) {
|
||||
let base_address = Vector::Reset.get_base_address();
|
||||
let reset_vector = CPU::get_vector(base_address, bus);
|
||||
self.registers.pc = reset_vector;
|
||||
@@ -74,10 +74,10 @@ mod cpu_vectors_tests {
|
||||
#[test]
|
||||
fn test_reset_vector() {
|
||||
let mut cpu = CPU::new();
|
||||
let bus = Bus::new();
|
||||
let mut bus = Bus::new();
|
||||
cpu.is_stopped = true;
|
||||
// TODO: test that the PC register got the right vector
|
||||
cpu.reset_vector(&bus);
|
||||
cpu.reset_vector(&mut bus);
|
||||
assert_eq!(cpu.is_stopped, false);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,6 @@ impl Emulator {
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.cpu.reset_vector(&self.bus);
|
||||
self.cpu.reset_vector(&mut self.bus);
|
||||
}
|
||||
}
|
||||
@@ -28,10 +28,16 @@ impl PPU {
|
||||
if self.registers.h_count > 339 {
|
||||
self.registers.h_count = 0;
|
||||
self.registers.v_count += 1;
|
||||
if self.registers.v_count > 224 {
|
||||
self.registers.vblank_nmi = true;
|
||||
}
|
||||
if self.registers.v_count > 261 {
|
||||
self.registers.v_count = 0;
|
||||
}
|
||||
}
|
||||
if !self.registers.is_vblanking() {
|
||||
self.registers.vblank_nmi = false;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn framebuffer(&self) -> &Vec<u8> {
|
||||
|
||||
@@ -64,7 +64,8 @@ pub const TSW: u16 = 0x212F; // Window Area Sub Screen Disable (W)
|
||||
pub const RDNMI: u16 = 0x4210; // V-Blank NMI Flag
|
||||
|
||||
// PPU VRAM Access
|
||||
pub const VMAINC: u16 = 0x2115; // VRAM Address Increment
|
||||
pub const VMAIN: u16 = 0x2115; // VRAM Address Increment
|
||||
pub const VMAINC: u16 = VMAIN; // VRAM Address Increment
|
||||
|
||||
pub const VMADDL: u16 = 0x2116; // VRAM Address Low
|
||||
pub const VMADDH: u16 = 0x2117; // VRAM Address High
|
||||
@@ -139,6 +140,7 @@ pub enum Background {
|
||||
pub struct PPURegisters {
|
||||
data: [u8; 256],
|
||||
vram: [u8; 0x10000],
|
||||
pub vblank_nmi: bool,
|
||||
pub h_count: u16,
|
||||
pub v_count: u16,
|
||||
}
|
||||
@@ -148,6 +150,7 @@ impl PPURegisters {
|
||||
Self {
|
||||
data: [0x00; 256],
|
||||
vram: [0; 0x10000],
|
||||
vblank_nmi: false,
|
||||
h_count: 0,
|
||||
v_count: 0,
|
||||
}
|
||||
@@ -161,7 +164,13 @@ impl PPURegisters {
|
||||
self.data[(address as usize) - 0x2100] = value;
|
||||
}
|
||||
|
||||
pub fn read(&self, address: u16) -> u8 {
|
||||
pub fn read(&mut self, address: u16) -> u8 {
|
||||
let result = self._read(address);
|
||||
match address {
|
||||
VMDATALR => self.handle_vram_addr_auto_increment(Some(result), None),
|
||||
VMDATAHR => self.handle_vram_addr_auto_increment(None, Some(result)),
|
||||
_ => {},
|
||||
};
|
||||
self._read(address)
|
||||
}
|
||||
|
||||
@@ -191,6 +200,41 @@ impl PPURegisters {
|
||||
self.vram[effective_address as usize] = byte;
|
||||
self._write(VMDATAHR, byte);
|
||||
}
|
||||
self.handle_vram_addr_auto_increment(byte_lo, byte_hi);
|
||||
}
|
||||
|
||||
fn handle_vram_addr_auto_increment(&mut self, byte_lo: Option<u8>, byte_hi: Option<u8>) {
|
||||
let register = self._read(VMAINC);
|
||||
let amount_to_increment = match register & 0b11 {
|
||||
0b00 => 1,
|
||||
0b01 => 32,
|
||||
0b10 => 128,
|
||||
0b11 => 128,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let increment_when_lo = (register >> 7) != 1;
|
||||
let increment_when_hi = !increment_when_lo;
|
||||
let current_value = self.get_current_vram_address();
|
||||
if increment_when_lo {
|
||||
if let Some(_) = byte_lo {
|
||||
self.set_current_vram_address(current_value.wrapping_add(amount_to_increment));
|
||||
}
|
||||
}
|
||||
if increment_when_hi {
|
||||
if let Some(_) = byte_hi {
|
||||
self.set_current_vram_address(current_value.wrapping_add(amount_to_increment));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_current_vram_address(&self) -> u16 {
|
||||
((self._read(VMADDH) as u16) << 8) | (self._read(VMADDL) as u16)
|
||||
}
|
||||
|
||||
fn set_current_vram_address(&mut self, value: u16) {
|
||||
let bytes = value.to_be_bytes();
|
||||
self._write(VMADDH, bytes[0]);
|
||||
self._write(VMADDL, bytes[1]);
|
||||
}
|
||||
|
||||
/// 7 BG4 Tile Size (0=8x8, 1=16x16) ;\(BgMode0..4: variable 8x8 or 16x16)
|
||||
@@ -200,7 +244,7 @@ impl PPURegisters {
|
||||
/// 3 BG3 Priority in Mode 1 (0=Normal, 1=High)
|
||||
/// 2-0 BG Screen Mode (0..7 = see below)
|
||||
pub fn get_bg_tile_size(&self, background: Background) -> TileSize {
|
||||
let byte = self.read(BGMODE);
|
||||
let byte = self._read(BGMODE);
|
||||
let bit = match background {
|
||||
Background::Bg1 => byte >> 3 & 0b1 == 1, // Bit 4
|
||||
Background::Bg2 => byte >> 4 & 0b1 == 1, // Bit 5
|
||||
@@ -215,10 +259,10 @@ impl PPURegisters {
|
||||
|
||||
pub fn get_bg_size(&self, background: Background) -> BgSize {
|
||||
let byte = match background {
|
||||
Background::Bg1 => self.read(BG1SC),
|
||||
Background::Bg2 => self.read(BG2SC),
|
||||
Background::Bg3 => self.read(BG3SC),
|
||||
Background::Bg4 => self.read(BG4SC),
|
||||
Background::Bg1 => self._read(BG1SC),
|
||||
Background::Bg2 => self._read(BG2SC),
|
||||
Background::Bg3 => self._read(BG3SC),
|
||||
Background::Bg4 => self._read(BG4SC),
|
||||
};
|
||||
match byte & 0b11 {
|
||||
0 => BgSize::T32x32,
|
||||
@@ -230,7 +274,7 @@ impl PPURegisters {
|
||||
}
|
||||
|
||||
pub fn get_bg_modes(&self) -> (Option<BgMode>, Option<BgMode>, Option<BgMode>, Option<BgMode>) {
|
||||
let byte = self.read(BGMODE);
|
||||
let byte = self._read(BGMODE);
|
||||
match byte & 0b111 {
|
||||
0 => (
|
||||
Some(BgMode::Color2BPP),
|
||||
@@ -292,17 +336,17 @@ impl PPURegisters {
|
||||
Background::Bg4 => BG4SC,
|
||||
};
|
||||
// Most significant bit is unused
|
||||
let base_address = (self.read(register) & 0b01111111) >> 2;
|
||||
let base_address = (self._read(register) & 0b01111111) >> 2;
|
||||
let result = (base_address as u16) * 0x400;
|
||||
result
|
||||
}
|
||||
|
||||
pub fn get_bg_char_base_address(&self, background: Background) -> u16 {
|
||||
let register = match background {
|
||||
Background::Bg1 => self.read(BG12NBA),
|
||||
Background::Bg2 => self.read(BG12NBA) >> 4,
|
||||
Background::Bg3 => self.read(BG34NBA),
|
||||
Background::Bg4 => self.read(BG34NBA) >> 4,
|
||||
Background::Bg1 => self._read(BG12NBA),
|
||||
Background::Bg2 => self._read(BG12NBA) >> 4,
|
||||
Background::Bg3 => self._read(BG34NBA),
|
||||
Background::Bg4 => self._read(BG34NBA) >> 4,
|
||||
};
|
||||
// Most significant bit is unused
|
||||
((register as u16) & 0b111) * 0x1000
|
||||
@@ -437,6 +481,74 @@ mod ppu_registers_test {
|
||||
assert_eq!(registers.read(VMDATALR), 0xCD);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_auto_increment_vram_address() {
|
||||
let mut registers = PPURegisters::new();
|
||||
// Increment after writing
|
||||
registers.write(VMADDL, 0x00);
|
||||
registers.write(VMADDH, 0x00);
|
||||
|
||||
// Increment when low bit is written to
|
||||
registers.write(VMAINC, 0x00);
|
||||
|
||||
registers.write(VMDATAHW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0000);
|
||||
registers.write(VMDATALW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0001);
|
||||
|
||||
// Increment when hi bit is written to
|
||||
registers.write(VMAINC, 0b1000_0000);
|
||||
registers.write(VMDATAHW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0002);
|
||||
registers.write(VMDATALW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0002);
|
||||
|
||||
|
||||
// Increment after reading
|
||||
registers.write(VMADDL, 0x00);
|
||||
registers.write(VMADDH, 0x00);
|
||||
|
||||
// Increment when low bit is read from
|
||||
registers.write(VMAINC, 0x00);
|
||||
|
||||
registers.read(VMDATAHR);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0000);
|
||||
registers.read(VMDATALR);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0001);
|
||||
|
||||
// Increment when hi bit is read from
|
||||
registers.write(VMAINC, 0b1000_0000);
|
||||
registers.read(VMDATAHR);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0002);
|
||||
registers.read(VMDATALR);
|
||||
assert_eq!(registers.get_current_vram_address(), 0x0002);
|
||||
|
||||
// Increment amounts
|
||||
registers.write(VMAINC, 0b1000_0000);
|
||||
registers.write(VMADDL, 0x00);
|
||||
registers.write(VMADDH, 0x00);
|
||||
registers.write(VMDATAHW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 1);
|
||||
|
||||
registers.write(VMAINC, 0b1000_0001);
|
||||
registers.write(VMADDL, 0x00);
|
||||
registers.write(VMADDH, 0x00);
|
||||
registers.write(VMDATAHW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 32);
|
||||
|
||||
registers.write(VMAINC, 0b1000_0010);
|
||||
registers.write(VMADDL, 0x00);
|
||||
registers.write(VMADDH, 0x00);
|
||||
registers.write(VMDATAHW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 128);
|
||||
|
||||
registers.write(VMAINC, 0b1000_0011);
|
||||
registers.write(VMADDL, 0x00);
|
||||
registers.write(VMADDH, 0x00);
|
||||
registers.write(VMDATAHW, 0xAA);
|
||||
assert_eq!(registers.get_current_vram_address(), 128);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_vblanking() {
|
||||
let mut registers = PPURegisters::new();
|
||||
|
||||
@@ -6,28 +6,28 @@ pub fn immediate(pc_addr: u32) -> u32 {
|
||||
}
|
||||
|
||||
/// OPCODE addr
|
||||
pub fn absolute(bus: &Bus, pc_addr: u32) -> u32 {
|
||||
pub fn absolute(bus: &mut Bus, pc_addr: u32) -> u32 {
|
||||
(pc_addr & 0xFF0000) |
|
||||
(bus.read(pc_addr + 1) as u32) |
|
||||
((bus.read(pc_addr + 2) as u32) << 8)
|
||||
}
|
||||
|
||||
/// OPCODE (addr)
|
||||
pub fn absolute_indirect(bus: &Bus, pc_addr: u32) -> u32 {
|
||||
pub fn absolute_indirect(bus: &mut Bus, pc_addr: u32) -> u32 {
|
||||
let addr = absolute(bus, pc_addr);
|
||||
let dbr = pc_addr & 0xFF0000;
|
||||
dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32)
|
||||
}
|
||||
|
||||
/// OPCODE long
|
||||
pub fn absolute_long(bus: &Bus, pc_addr: u32) -> u32 {
|
||||
pub fn absolute_long(bus: &mut Bus, pc_addr: u32) -> u32 {
|
||||
(bus.read(pc_addr + 1) as u32) |
|
||||
((bus.read(pc_addr + 2) as u32) << 8) |
|
||||
((bus.read(pc_addr + 3) as u32) << 16)
|
||||
}
|
||||
|
||||
/// OPCODE (addr)
|
||||
pub fn absolute_indirect_long(bus: &Bus, pc_addr: u32) -> u32 {
|
||||
pub fn absolute_indirect_long(bus: &mut Bus, pc_addr: u32) -> u32 {
|
||||
let addr = absolute(bus, pc_addr);
|
||||
((bus.read(addr) as u32) << 16) |
|
||||
((bus.read(addr + 1) as u32) << 8) |
|
||||
@@ -35,19 +35,19 @@ pub fn absolute_indirect_long(bus: &Bus, pc_addr: u32) -> u32 {
|
||||
}
|
||||
|
||||
/// OPCODE dp
|
||||
pub fn direct_page(bus: &Bus, pc_addr: u32, direct_page_register: u16) -> u32 {
|
||||
pub fn direct_page(bus: &mut Bus, pc_addr: u32, direct_page_register: u16) -> u32 {
|
||||
(bus.read(pc_addr + 1) as u32) + direct_page_register as u32
|
||||
}
|
||||
|
||||
/// OPCODE (dp)
|
||||
pub fn direct_page_indirect(bus: &Bus, pc_addr: u32, direct_page_register: u16) -> u32 {
|
||||
pub fn direct_page_indirect(bus: &mut Bus, pc_addr: u32, direct_page_register: u16) -> u32 {
|
||||
let addr = direct_page(bus, pc_addr, direct_page_register);
|
||||
let dbr = pc_addr & 0xFF0000;
|
||||
dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32)
|
||||
}
|
||||
|
||||
/// OPCODE [dp]
|
||||
pub fn direct_page_indirect_long(bus: &Bus, pc_addr: u32, direct_page_register: u16) -> u32 {
|
||||
pub fn direct_page_indirect_long(bus: &mut Bus, pc_addr: u32, direct_page_register: u16) -> u32 {
|
||||
let addr = direct_page(bus, pc_addr, direct_page_register);
|
||||
((bus.read(addr) as u32) << 16) |
|
||||
((bus.read(addr + 1) as u32) << 8) |
|
||||
@@ -56,12 +56,12 @@ pub fn direct_page_indirect_long(bus: &Bus, pc_addr: u32, direct_page_register:
|
||||
|
||||
/// OPCODE addr,X
|
||||
/// OPCODE addr,Y
|
||||
pub fn absolute_indexed(bus: &Bus, pc_addr: u32, xy: u16) -> u32 {
|
||||
pub fn absolute_indexed(bus: &mut Bus, pc_addr: u32, xy: u16) -> u32 {
|
||||
absolute(bus, pc_addr) + (xy as u32)
|
||||
}
|
||||
|
||||
/// OPCODE (addr)
|
||||
pub fn absolute_indexed_indirect(bus: &Bus, pc_addr: u32, xy: u16) -> u32 {
|
||||
pub fn absolute_indexed_indirect(bus: &mut Bus, pc_addr: u32, xy: u16) -> u32 {
|
||||
let addr = absolute_indexed(bus, pc_addr, xy);
|
||||
let dbr = pc_addr & 0xFF0000;
|
||||
dbr | ((bus.read(addr) as u32) << 8) | (bus.read(addr + 1) as u32)
|
||||
@@ -70,42 +70,42 @@ pub fn absolute_indexed_indirect(bus: &Bus, pc_addr: u32, xy: u16) -> u32 {
|
||||
|
||||
/// OPCODE long,X
|
||||
/// OPCODE long,Y
|
||||
pub fn absolute_long_indexed(bus: &Bus, pc_addr: u32, xy: u16) -> u32 {
|
||||
pub fn absolute_long_indexed(bus: &mut Bus, pc_addr: u32, xy: u16) -> u32 {
|
||||
absolute_long(bus, pc_addr) + (xy as u32)
|
||||
}
|
||||
|
||||
/// OPCODE dp,X
|
||||
/// OPCODE dp,Y
|
||||
pub fn direct_page_indexed(bus: &Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
pub fn direct_page_indexed(bus: &mut Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
direct_page(bus, pc_addr, direct_page_register) + (xy as u32)
|
||||
}
|
||||
|
||||
/// OPCODE (dp,X)
|
||||
/// OPCODE (dp,Y)
|
||||
pub fn direct_page_indexed_indirect(bus: &Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
pub fn direct_page_indexed_indirect(bus: &mut Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
direct_page_indirect(bus, pc_addr, direct_page_register.wrapping_add(xy))
|
||||
}
|
||||
|
||||
/// OPCODE (dp),X
|
||||
/// OPCODE (dp),Y
|
||||
pub fn direct_page_indirect_indexed(bus: &Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
pub fn direct_page_indirect_indexed(bus: &mut Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
direct_page_indirect(bus, pc_addr, direct_page_register) + (xy as u32)
|
||||
}
|
||||
|
||||
/// OPCODE [dp],X
|
||||
/// OPCODE [dp],Y
|
||||
pub fn direct_page_indirect_long_indexed(bus: &Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
pub fn direct_page_indirect_long_indexed(bus: &mut Bus, pc_addr: u32, direct_page_register: u16, xy: u16) -> u32 {
|
||||
direct_page_indirect_long(bus, pc_addr, direct_page_register) + (xy as u32)
|
||||
}
|
||||
|
||||
/// OPCODE sr,S
|
||||
pub fn stack_relative(bus: &Bus, pc_addr: u32, stack_pointer: u16) -> u32 {
|
||||
pub fn stack_relative(bus: &mut Bus, pc_addr: u32, stack_pointer: u16) -> u32 {
|
||||
absolute_indexed(bus, pc_addr, stack_pointer)
|
||||
}
|
||||
|
||||
/// OPCODE (sr,S),X
|
||||
/// OPCODE (sr,S),Y
|
||||
pub fn stack_relative_indirect_indexed(bus: &Bus, pc_addr: u32, stack_pointer: u16, xy: u16) -> u32 {
|
||||
pub fn stack_relative_indirect_indexed(bus: &mut Bus, pc_addr: u32, stack_pointer: u16, xy: u16) -> u32 {
|
||||
absolute_indexed(bus, pc_addr, stack_pointer) + (xy as u32)
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ pub enum AddressingMode {
|
||||
}
|
||||
|
||||
impl AddressingMode {
|
||||
pub fn effective_address(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u32 {
|
||||
pub fn effective_address(self, bus: &mut Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u32 {
|
||||
use IndexRegister::X as X;
|
||||
// TODO: maybe use impl Immediate {pub fn effective_address} to prevent this match statement?
|
||||
match self {
|
||||
@@ -162,12 +162,12 @@ impl AddressingMode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn value_8bit(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u8 {
|
||||
pub fn value_8bit(self, bus: &mut Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u8 {
|
||||
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, x, y);
|
||||
return bus.read(address);
|
||||
}
|
||||
|
||||
pub fn value_16bit(self, bus: &Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u16 {
|
||||
pub fn value_16bit(self, bus: &mut Bus, pc_addr: u32, direct_page_register: u16, stack_pointer: u16, x: u16, y: u16) -> u16 {
|
||||
let address = self.effective_address(bus, pc_addr, direct_page_register, stack_pointer, x, y);
|
||||
return (bus.read(address) as u16) | ((bus.read(address + 1) as u16) << 8);
|
||||
}
|
||||
@@ -200,13 +200,13 @@ mod addressing_modes_tests {
|
||||
let pc_addr = 0x000000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(absolute(&bus, pc_addr), 0x000201);
|
||||
assert_eq!(absolute(&mut bus, pc_addr), 0x000201);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x7F0000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(absolute(&bus, pc_addr), 0x7F0201);
|
||||
assert_eq!(absolute(&mut bus, pc_addr), 0x7F0201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -217,21 +217,21 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, addr);
|
||||
bus.write(addr as u32, 0x02);
|
||||
bus.write((addr + 1) as u32, 0x01);
|
||||
assert_eq!(absolute_indirect(&bus, pc_addr), 0x000201);
|
||||
assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x000201);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let addr = 0x55;
|
||||
bus.write(pc_addr + 1, addr);
|
||||
bus.write(addr as u32, 0x02);
|
||||
bus.write((addr + 1) as u32, 0x01);
|
||||
assert_eq!(absolute_indirect(&bus, pc_addr), 0x7E0201);
|
||||
assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x7E0201);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let addr = 0x55;
|
||||
bus.write(pc_addr + 1, addr);
|
||||
bus.write(addr as u32, 0x02);
|
||||
bus.write((addr + 1) as u32, 0x01);
|
||||
assert_eq!(absolute_indirect(&bus, pc_addr), 0x7E0201);
|
||||
assert_eq!(absolute_indirect(&mut bus, pc_addr), 0x7E0201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -241,14 +241,14 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
bus.write(pc_addr + 3, 0x03);
|
||||
assert_eq!(absolute_long(&bus, pc_addr), 0x030201);
|
||||
assert_eq!(absolute_long(&mut bus, pc_addr), 0x030201);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x7E0010;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
bus.write(pc_addr + 3, 0x03);
|
||||
assert_eq!(absolute_long(&bus, pc_addr), 0x030201);
|
||||
assert_eq!(absolute_long(&mut bus, pc_addr), 0x030201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -260,7 +260,7 @@ mod addressing_modes_tests {
|
||||
bus.write(addr as u32, 0x03);
|
||||
bus.write((addr + 1) as u32, 0x02);
|
||||
bus.write((addr + 2) as u32, 0x01);
|
||||
assert_eq!(absolute_indirect_long(&bus, pc_addr), 0x030201);
|
||||
assert_eq!(absolute_indirect_long(&mut bus, pc_addr), 0x030201);
|
||||
}
|
||||
|
||||
|
||||
@@ -270,11 +270,11 @@ mod addressing_modes_tests {
|
||||
let pc_addr = 0x000000;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
assert_eq!(direct_page(&bus, pc_addr, 0x00), 0x000055);
|
||||
assert_eq!(direct_page(&mut bus, pc_addr, 0x00), 0x000055);
|
||||
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
assert_eq!(direct_page(&bus, pc_addr, 0x01), 0x000056);
|
||||
assert_eq!(direct_page(&mut bus, pc_addr, 0x01), 0x000056);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -285,21 +285,21 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write(dp as u32, 0x02);
|
||||
bus.write((dp + 1) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect(&bus, pc_addr, 0x00), 0x000201);
|
||||
assert_eq!(direct_page_indirect(&mut bus, pc_addr, 0x00), 0x000201);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write(dp as u32, 0x02);
|
||||
bus.write((dp + 1) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect(&bus, pc_addr, 0x00), 0x7E0201);
|
||||
assert_eq!(direct_page_indirect(&mut bus, pc_addr, 0x00), 0x7E0201);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write((dp + 1) as u32, 0x02);
|
||||
bus.write((dp + 2) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect(&bus, pc_addr, 0x01), 0x7E0201);
|
||||
assert_eq!(direct_page_indirect(&mut bus, pc_addr, 0x01), 0x7E0201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -311,7 +311,7 @@ mod addressing_modes_tests {
|
||||
bus.write(dp as u32, 0x03);
|
||||
bus.write((dp + 1) as u32, 0x02);
|
||||
bus.write((dp + 2) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect_long(&bus, pc_addr, 0x00), 0x030201);
|
||||
assert_eq!(direct_page_indirect_long(&mut bus, pc_addr, 0x00), 0x030201);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x000000;
|
||||
@@ -320,7 +320,7 @@ mod addressing_modes_tests {
|
||||
bus.write((dp + 1) as u32, 0x03);
|
||||
bus.write((dp + 2) as u32, 0x02);
|
||||
bus.write((dp + 3) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect_long(&bus, pc_addr, 0x01), 0x030201);
|
||||
assert_eq!(direct_page_indirect_long(&mut bus, pc_addr, 0x01), 0x030201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -329,13 +329,13 @@ mod addressing_modes_tests {
|
||||
let pc_addr = 0x000000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(absolute_indexed(&bus, pc_addr, 0x02), 0x000203);
|
||||
assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02), 0x000203);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x7F0000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(absolute_indexed(&bus, pc_addr, 0x02), 0x7F0203);
|
||||
assert_eq!(absolute_indexed(&mut bus, pc_addr, 0x02), 0x7F0203);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -346,7 +346,7 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, addr);
|
||||
bus.write(addr as u32, 0x02);
|
||||
bus.write((addr + 1) as u32, 0x01);
|
||||
assert_eq!(absolute_indexed_indirect(&bus, pc_addr, 0), 0x000201);
|
||||
assert_eq!(absolute_indexed_indirect(&mut bus, pc_addr, 0), 0x000201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -356,14 +356,14 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
bus.write(pc_addr + 3, 0x03);
|
||||
assert_eq!(absolute_long_indexed(&bus, pc_addr, 0x02), 0x030203);
|
||||
assert_eq!(absolute_long_indexed(&mut bus, pc_addr, 0x02), 0x030203);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x7E0010;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
bus.write(pc_addr + 3, 0x03);
|
||||
assert_eq!(absolute_long_indexed(&bus, pc_addr, 0x02), 0x030203);
|
||||
assert_eq!(absolute_long_indexed(&mut bus, pc_addr, 0x02), 0x030203);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -372,11 +372,11 @@ mod addressing_modes_tests {
|
||||
let pc_addr = 0x000000;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
assert_eq!(direct_page_indexed(&bus, pc_addr, 0x00, 0x01), 0x000056);
|
||||
assert_eq!(direct_page_indexed(&mut bus, pc_addr, 0x00, 0x01), 0x000056);
|
||||
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
assert_eq!(direct_page_indexed(&bus, pc_addr, 0x01, 0x01), 0x000057);
|
||||
assert_eq!(direct_page_indexed(&mut bus, pc_addr, 0x01, 0x01), 0x000057);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -387,21 +387,21 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write((dp + 1) as u32, 0x02);
|
||||
bus.write((dp + 2) as u32, 0x01);
|
||||
assert_eq!(direct_page_indexed_indirect(&bus, pc_addr, 0x00, 0x01), 0x000201);
|
||||
assert_eq!(direct_page_indexed_indirect(&mut bus, pc_addr, 0x00, 0x01), 0x000201);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write((dp + 1) as u32, 0x02);
|
||||
bus.write((dp + 2) as u32, 0x01);
|
||||
assert_eq!(direct_page_indexed_indirect(&bus, pc_addr, 0x00, 0x01), 0x7E0201);
|
||||
assert_eq!(direct_page_indexed_indirect(&mut bus, pc_addr, 0x00, 0x01), 0x7E0201);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write((dp + 2) as u32, 0x02);
|
||||
bus.write((dp + 3) as u32, 0x01);
|
||||
assert_eq!(direct_page_indexed_indirect(&bus, pc_addr, 0x01, 0x01), 0x7E0201);
|
||||
assert_eq!(direct_page_indexed_indirect(&mut bus, pc_addr, 0x01, 0x01), 0x7E0201);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -412,21 +412,21 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write(dp as u32, 0x02);
|
||||
bus.write((dp + 1) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect_indexed(&bus, pc_addr, 0x00, 0x01), 0x000202);
|
||||
assert_eq!(direct_page_indirect_indexed(&mut bus, pc_addr, 0x00, 0x01), 0x000202);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write(dp as u32, 0x02);
|
||||
bus.write((dp + 1) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect_indexed(&bus, pc_addr, 0x00, 0x01), 0x7E0202);
|
||||
assert_eq!(direct_page_indirect_indexed(&mut bus, pc_addr, 0x00, 0x01), 0x7E0202);
|
||||
|
||||
let pc_addr = 0x7E0010;
|
||||
let dp = 0x55;
|
||||
bus.write(pc_addr + 1, dp);
|
||||
bus.write((dp + 1) as u32, 0x02);
|
||||
bus.write((dp + 2) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect_indexed(&bus, pc_addr, 0x01, 0x01), 0x7E0202);
|
||||
assert_eq!(direct_page_indirect_indexed(&mut bus, pc_addr, 0x01, 0x01), 0x7E0202);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -438,7 +438,7 @@ mod addressing_modes_tests {
|
||||
bus.write(dp as u32, 0x03);
|
||||
bus.write((dp + 1) as u32, 0x02);
|
||||
bus.write((dp + 2) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect_long_indexed(&bus, pc_addr, 0x00, 0x02), 0x030203);
|
||||
assert_eq!(direct_page_indirect_long_indexed(&mut bus, pc_addr, 0x00, 0x02), 0x030203);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x000000;
|
||||
@@ -447,7 +447,7 @@ mod addressing_modes_tests {
|
||||
bus.write((dp + 1) as u32, 0x03);
|
||||
bus.write((dp + 2) as u32, 0x02);
|
||||
bus.write((dp + 3) as u32, 0x01);
|
||||
assert_eq!(direct_page_indirect_long_indexed(&bus, pc_addr, 0x01, 0x02), 0x030203);
|
||||
assert_eq!(direct_page_indirect_long_indexed(&mut bus, pc_addr, 0x01, 0x02), 0x030203);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -456,13 +456,13 @@ mod addressing_modes_tests {
|
||||
let pc_addr = 0x000000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(stack_relative(&bus, pc_addr, 0x02), 0x000203);
|
||||
assert_eq!(stack_relative(&mut bus, pc_addr, 0x02), 0x000203);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x7F0000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(stack_relative(&bus, pc_addr, 0x02), 0x7F0203);
|
||||
assert_eq!(stack_relative(&mut bus, pc_addr, 0x02), 0x7F0203);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -471,13 +471,13 @@ mod addressing_modes_tests {
|
||||
let pc_addr = 0x000000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(stack_relative_indirect_indexed(&bus, pc_addr, 0x02, 0x02), 0x000205);
|
||||
assert_eq!(stack_relative_indirect_indexed(&mut bus, pc_addr, 0x02, 0x02), 0x000205);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
let pc_addr = 0x7F0000;
|
||||
bus.write(pc_addr + 1, 0x01);
|
||||
bus.write(pc_addr + 2, 0x02);
|
||||
assert_eq!(stack_relative_indirect_indexed(&bus, pc_addr, 0x02, 0x02), 0x7F0205);
|
||||
assert_eq!(stack_relative_indirect_indexed(&mut bus, pc_addr, 0x02, 0x02), 0x7F0205);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -487,7 +487,7 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 1, 0x20);
|
||||
bus.write(pc_addr + 2, 0x10);
|
||||
bus.write(0x001020, 0xFE);
|
||||
let val = AddressingMode::Absolute.value_8bit(&bus, pc_addr, 0x00, 0x00, 0x00, 0x00);
|
||||
let val = AddressingMode::Absolute.value_8bit(&mut bus, pc_addr, 0x00, 0x00, 0x00, 0x00);
|
||||
assert_eq!(val, 0xFE);
|
||||
|
||||
let mut bus = Bus::new();
|
||||
@@ -496,7 +496,7 @@ mod addressing_modes_tests {
|
||||
bus.write(pc_addr + 2, 0x10);
|
||||
bus.write(0x001020, 0xFF);
|
||||
bus.write(0x001021, 0xEE);
|
||||
let val = AddressingMode::Absolute.value_16bit(&bus, pc_addr, 0x00, 0x00, 0x00, 0x00);
|
||||
let val = AddressingMode::Absolute.value_16bit(&mut bus, pc_addr, 0x00, 0x00, 0x00, 0x00);
|
||||
assert_eq!(val, 0xEEFF);
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@ pub struct CPUDisassembler {
|
||||
}
|
||||
|
||||
impl CPUDisassembler {
|
||||
pub fn get_next_instruction(emulator: &Emulator) -> String {
|
||||
// TODO FIXME: please do not mutate the emulator state to fetch upcoming instructions
|
||||
pub fn get_next_instruction(emulator: &mut Emulator) -> String {
|
||||
let opcode = emulator.bus.read(emulator.cpu.registers.get_pc_address());
|
||||
let is_cpu_16bit = emulator.cpu.registers.is_16bit_mode();
|
||||
let is_index_16bit = emulator.cpu.registers.is_16bit_index();
|
||||
|
||||
@@ -347,7 +347,7 @@ fn main() {
|
||||
.size([150.0, 200.0], Condition::FirstUseEver)
|
||||
.build(&ui, || {
|
||||
ui.text("Upcoming instruction:");
|
||||
ui.text(cpu_debug::CPUDisassembler::get_next_instruction(&emulator));
|
||||
ui.text(cpu_debug::CPUDisassembler::get_next_instruction(&mut emulator));
|
||||
ui.separator();
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user