srctree

Johan parent a981d57c ab183c25 1416cc15
Merge pull request #395 from johnor/open-bus

Implement ppu open bus
core/src/ppu.cpp added: 81, removed: 14, total 67
@@ -124,14 +124,21 @@ Ppu::Ppu(PpuRegisters *registers, IMmu *mmu)
: registers_(registers), mmu_(mmu) {}
 
uint8_t Ppu::read_byte(uint16_t addr) {
uint8_t byte = 0;
uint8_t byte = open_bus_;
 
if (addr == kPpuStatus) {
byte = registers_->status.value();
if (addr == kPpuCtrl || addr == kPpuMask || addr == kOamAddr ||
addr == kPpuScroll || addr == kPpuAddr) {
// Return open bus value
} else if (addr == kPpuStatus) {
// Bit 0-4 contains whatever is on the bus.
byte &= 0b0001'1111u;
byte |= registers_->status.value() & 0b1110'0000u;
registers_->write_toggle = false;
open_bus_ = byte;
clear_vblank_flag();
} else if (addr == kOamData) {
byte = oam_data_[registers_->oamaddr];
open_bus_ = byte;
} else if (addr == kPpuData) {
byte = mmu_->read_byte(registers_->vram_addr.value());
if (registers_->vram_addr.value() < kFirstPaletteData) {
@@ -141,7 +148,11 @@ uint8_t Ppu::read_byte(uint16_t addr) {
} else {
read_buffer_ = mmu_->read_byte(registers_->vram_addr.value() -
static_cast<uint16_t>(0x1000));
byte &= 0b0011'1111u;
byte |= open_bus_ & 0b1100'0000u;
// Bit 6-7 contains whatever is on the bus.
}
open_bus_ = byte;
increment_vram_address();
} else {
byte = mmu_->read_byte(addr);
@@ -152,6 +163,7 @@ uint8_t Ppu::read_byte(uint16_t addr) {
 
void Ppu::write_byte(uint16_t addr, uint8_t byte) {
if (addr == kPpuCtrl) {
open_bus_ = byte;
const auto new_ctrl = PpuCtrl(byte);
// Trigger nmi if the nmi-enabled flag goes from 0 to 1 during vblank.
if (!registers_->ctrl.is_set(7u) && new_ctrl.is_set(7u) &&
@@ -162,14 +174,20 @@ void Ppu::write_byte(uint16_t addr, uint8_t byte) {
registers_->ctrl = new_ctrl;
registers_->temp_vram_addr.set_nametable(byte);
} else if (addr == kPpuMask) {
open_bus_ = byte;
registers_->mask = PpuMask(byte);
} else if (addr == kOamAddr) {
open_bus_ = byte;
registers_->oamaddr = byte;
} else if (addr == kPpuStatus) {
open_bus_ = byte;
} else if (addr == kOamData) {
open_bus_ = byte;
if (!is_rendering_active()) {
oam_data_[registers_->oamaddr++] = byte;
}
} else if (addr == kPpuScroll) {
open_bus_ = byte;
if (registers_->write_toggle) { // Second write, Y scroll
const uint16_t y_scroll = (byte >> 3u);
const auto fine_y_scroll = static_cast<uint16_t>(byte & 7u);
@@ -183,6 +201,7 @@ void Ppu::write_byte(uint16_t addr, uint8_t byte) {
registers_->write_toggle = true;
}
} else if (addr == kPpuAddr) {
open_bus_ = byte;
if (registers_->write_toggle) { // Second write, lower address byte
registers_->temp_vram_addr = PpuVram(
(registers_->temp_vram_addr.value() & 0xFF00u) | byte);
@@ -198,6 +217,7 @@ void Ppu::write_byte(uint16_t addr, uint8_t byte) {
registers_->write_toggle = true;
}
} else if (addr == kPpuData) {
open_bus_ = byte;
mmu_->write_byte(registers_->vram_addr.value(), byte);
increment_vram_address();
} else {
 
core/src/ppu.h added: 81, removed: 14, total 67
@@ -31,6 +31,7 @@ private:
std::function<void()> on_nmi_{[] {}};
 
uint8_t read_buffer_{0};
uint8_t open_bus_{0};
 
// Object Atribute Memory
constexpr static uint16_t kOamSize{256};
 
core/test/src/test_ppu.cpp added: 81, removed: 14, total 67
@@ -64,7 +64,8 @@ TEST_F(PpuTest, read_status_register_clears_write_toggle) {
 
const uint8_t status = ppu->read_byte(0x2002);
 
EXPECT_EQ(0x25, status);
// First 5 bits is whetever is on the open bus (emtpy here)
EXPECT_EQ(0x20, status);
}
 
TEST_F(PpuTest, clear_status_when_reading_status) {
@@ -399,6 +400,51 @@ TEST_F(PpuTest, increment_vram_addr_by_32_after_writing) {
EXPECT_EQ(expected, registers);
}
 
TEST_F(PpuTest, read_returns_open_bus) {
// Write something to the open bus
ppu->write_byte(0x2001, 0b1001'0110);
registers.status = PpuStatus(0b0111'1011);
 
EXPECT_EQ(0b1001'0110, ppu->read_byte(0x2000));
EXPECT_EQ(0b1001'0110, ppu->read_byte(0x2001));
 
EXPECT_EQ(0b1001'0110, ppu->read_byte(0x2003));
 
EXPECT_EQ(0b1001'0110, ppu->read_byte(0x2005));
EXPECT_EQ(0b1001'0110, ppu->read_byte(0x2006));
 
// PpuData with palette address
// Bit 6-7 from the bus, 0-5 from memory
EXPECT_CALL(mmu, read_byte(0x3F01)).WillOnce(Return(0b0011'1110));
EXPECT_CALL(mmu, read_byte(0x2F01)).WillOnce(Return(0x00));
registers.vram_addr = PpuVram(0x3F01);
EXPECT_EQ(0b1011'1110, ppu->read_byte(0x2007));
}
 
TEST_F(PpuTest, read_write_oam_data_updates_open_bus) {
// Write something to oam
registers.oamaddr = 0x12;
ppu->write_byte(0x2004, 0x54);
// Open bus should be updated
EXPECT_EQ(0x54, ppu->read_byte(0x2000));
 
// Reading from oam should also update open bus
registers.oamaddr = 0x12;
EXPECT_EQ(0x54, ppu->read_byte(0x2004));
EXPECT_EQ(0x54, ppu->read_byte(0x2000));
}
 
TEST_F(PpuTest, read_status_returns_open_bus) {
// Write something to the open bus
ppu->write_byte(0x2001, 0b1001'0110);
registers.status = PpuStatus(0b0111'1011);
 
// Status, bit 0-4 from the bus, 5-7 from the register
EXPECT_EQ(0b0111'0110, ppu->read_byte(0x2002));
// Reading will update bus
EXPECT_EQ(0b0111'0110, ppu->read_byte(0x2000));
}
 
TEST_F(PpuTest, forwards_ppudata_reads_to_mmu_) {
registers.vram_addr = PpuVram(0x4001);
EXPECT_CALL(mmu, write_byte(0x4001, 0x05)).Times(1);
@@ -426,7 +472,8 @@ TEST_F(PpuTest, read_from_palette_memory) {
 
uint8_t read_byte = ppu->read_byte(0x2007);
 
EXPECT_EQ(0x68, read_byte);
// Last two bits is whetever is on the open bus (empty here)
EXPECT_EQ(0x28, read_byte);
 
registers.vram_addr = PpuVram(0x0100);
 
 
romtest/test_rom.py added: 81, removed: 14, total 67
@@ -68,7 +68,7 @@ TESTS = [
pass_pattern="PASSED",
cycles=100000000,
failing=True,
), # FAILED #2
), # FAILED #3, decay not implemented
# CPU tests
Test(
rom="cpu_dummy_reads/cpu_dummy_reads.nes",
@@ -88,10 +88,9 @@ TESTS = [
),
Test(
rom="cpu_exec_space/test_cpu_exec_space_ppuio.nes",
pass_pattern="PASSED",
cycles=10000000,
failing=True,
), # Failed #3, ppu open bus
pass_pattern="0ASSED", # Tile indexes are not mapped to ascii for all characters.
cycles=14000000,
),
Test(
rom="cpu_timing_test6/cpu_timing_test.nes",
pass_pattern="PASSED",