vram writes, reads, auto increments and clear vblank nmi flag when read

This commit is contained in:
2023-07-05 23:13:14 -05:00
parent a82c554b25
commit e7a40db745
10 changed files with 302 additions and 176 deletions

View File

@@ -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),

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -30,6 +30,6 @@ impl Emulator {
}
pub fn reset(&mut self) {
self.cpu.reset_vector(&self.bus);
self.cpu.reset_vector(&mut self.bus);
}
}

View File

@@ -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> {

View File

@@ -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();

View File

@@ -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);
}
}

View File

@@ -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();

View File

@@ -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();
});
}