diff --git a/ares/n64/mi/mi.hpp b/ares/n64/mi/mi.hpp index 0d11b9fedf..71e590b48e 100644 --- a/ares/n64/mi/mi.hpp +++ b/ares/n64/mi/mi.hpp @@ -30,6 +30,7 @@ struct MI : Memory::RCP { auto readWord(u32 address, Thread& thread) -> u32; auto writeWord(u32 address, u32 data, Thread& thread) -> void; auto initializeMode() -> bool { bool m = io.initializeMode; io.initializeMode = 0; return m; } + auto ebusTestMode() -> bool { return io.ebusTestMode; } auto initializeLength() -> n7 { return io.initializeLength; } //serialization.cpp diff --git a/ares/n64/rdram/rdram.cpp b/ares/n64/rdram/rdram.cpp index bcbd53130e..69d87c40f0 100644 --- a/ares/n64/rdram/rdram.cpp +++ b/ares/n64/rdram/rdram.cpp @@ -12,11 +12,14 @@ auto RDRAM::load(Node::Object parent) -> void { if(!system.expansionPak) { //4MB internal - ram.allocate(4_MiB); + ram.allocate(4_MiB); } else { //4MB internal + 4MB expansion pak ram.allocate(4_MiB + 4_MiB); } + + // parallelRDP stores hidden bits in 2-bit pairs (LSB) + ram.hiddenBits.allocate(ram.size / 2); debugger.load(node); } @@ -24,12 +27,14 @@ auto RDRAM::load(Node::Object parent) -> void { auto RDRAM::unload() -> void { debugger = {}; ram.reset(); + ram.hiddenBits.reset(); node.reset(); } auto RDRAM::power(bool reset) -> void { if(!reset) { ram.fill(); + ram.hiddenBits.fill(); for(auto& chip : chips) chip = {}; } } diff --git a/ares/n64/rdram/rdram.hpp b/ares/n64/rdram/rdram.hpp index bc048756ef..1ea1ab4646 100644 --- a/ares/n64/rdram/rdram.hpp +++ b/ares/n64/rdram/rdram.hpp @@ -5,6 +5,17 @@ struct RDRAM : Memory::RCP { struct Writable : public Memory::Writable { RDRAM& self; + Memory::Writable hiddenBits; + + void setHiddenBit(u32 address, bool isSet) + { + u32 idx = address / 2; + u32 bitPos = 1 - (address & 1); + auto bits = hiddenBits.read<1>(idx); + bits &= ~(1 << bitPos); // remove old value + bits |= (isSet << bitPos); // set new value + hiddenBits.write<1>(idx, bits); + } Writable(RDRAM& self) : self(self) {} @@ -14,9 +25,30 @@ struct RDRAM : Memory::RCP { if (unlikely(peripheral && system.homebrewMode)) { self.debugger.readWord(address, Size, peripheral); } + if (unlikely(mi.ebusTestMode())) { + u32 idx = address / 2; + auto bits0 = hiddenBits.read<1>(idx+0); + auto bits1 = hiddenBits.read<1>(idx+1); + return (bits0 << 2) | bits1; + } return Memory::Writable::read(address); } + template + auto writeAutoCVG(u32 address, u64 data) -> void { + + if constexpr (Size == 1) { // only updates the current byte + setHiddenBit(address, (address & 1) ? (data & 1) : 0); // @TODO: retest if X%2 addresses really ignored the bit + } + else if constexpr (Size == 2) { // sets both bits based on the LSB + setHiddenBit(address+0, data & 1); + setHiddenBit(address+1, data & 1); + } + // @TODO: re-test 32 bit writes + + Memory::Writable::write(address, data); + } + template auto writeRepeat(u32 address, u64 value, u8 length) -> void { if constexpr(Size == Byte) { @@ -36,43 +68,43 @@ struct RDRAM : Memory::RCP { length = end - address; if (address & 1) { - Memory::Writable::write(address, value >> 56); + writeAutoCVG(address, value >> 56); value = (value << 8) | (value >> 56); address = (address & ~0x7FF) | ((address + 1) & 0x7FF); length -= 1; } if ((address & 2) && length >= 2) { - Memory::Writable::write(address, value >> 48); + writeAutoCVG(address, value >> 48); value = (value << 16) | (value >> 48); address = (address & ~0x7FF) | ((address + 2) & 0x7FF); length -= 2; } if ((address & 4) && length >= 4) { - Memory::Writable::write(address, value >> 32); + writeAutoCVG(address, value >> 32); value = (value << 32) | (value >> 32); address = (address & ~0x7FF) | ((address + 4) & 0x7FF); length -= 4; } while (length >= 8) { - Memory::Writable::write(address, value); + writeAutoCVG(address, value); address = (address & ~0x7FF) | ((address + 8) & 0x7FF); length -= 8; } if (length >= 4) { - Memory::Writable::write(address, value >> 32); + writeAutoCVG(address, value >> 32); value <<= 32; address += 4; length -= 4; } if (length >= 2) { - Memory::Writable::write(address, value >> 48); + writeAutoCVG(address, value >> 48); value <<= 16; address += 2; length -= 2; } if (length == 1) - Memory::Writable::write(address, value >> 56); + writeAutoCVG(address, value >> 56); } template @@ -84,22 +116,22 @@ struct RDRAM : Memory::RCP { if (unlikely(mi.initializeMode())) { writeRepeat(address, value, mi.initializeLength()+1); } else { - Memory::Writable::write(address, value); + writeAutoCVG(address, value); } } template auto writeBurst(u32 address, u32 *value, const char *peripheral) -> void { if (address >= size) return; - Memory::Writable::write(address | 0x00, value[0]); - Memory::Writable::write(address | 0x04, value[1]); - Memory::Writable::write(address | 0x08, value[2]); - Memory::Writable::write(address | 0x0c, value[3]); + writeAutoCVG(address | 0x00, value[0]); + writeAutoCVG(address | 0x04, value[1]); + writeAutoCVG(address | 0x08, value[2]); + writeAutoCVG(address | 0x0c, value[3]); if (Size == ICache) { - Memory::Writable::write(address | 0x10, value[4]); - Memory::Writable::write(address | 0x14, value[5]); - Memory::Writable::write(address | 0x18, value[6]); - Memory::Writable::write(address | 0x1c, value[7]); + writeAutoCVG(address | 0x10, value[4]); + writeAutoCVG(address | 0x14, value[5]); + writeAutoCVG(address | 0x18, value[6]); + writeAutoCVG(address | 0x1c, value[7]); } } diff --git a/ares/n64/vulkan/vulkan.cpp b/ares/n64/vulkan/vulkan.cpp index 065549a539..6a495896f4 100644 --- a/ares/n64/vulkan/vulkan.cpp +++ b/ares/n64/vulkan/vulkan.cpp @@ -127,6 +127,13 @@ auto Vulkan::render() -> bool { if(::RDP::Op(code) == ::RDP::Op::SyncFull) { implementation->processor->wait_for_timeline(implementation->processor->signal_timeline()); + + // @TODO: how exactly does parallelRDP update the RDRAM values? + // this here is a hack as i read just the entire RAM and ignore some parts to make my demo work + uint8_t *hiddenBitsBuff = (uint8_t*)implementation->processor->begin_read_hidden_rdram(); + uint32_t offset = 1024*1024; // @TODO: HACK + memcpy(rdram.ram.hiddenBits.data + offset, hiddenBitsBuff + offset, implementation->processor->get_hidden_rdram_size() - offset); + rdp.syncFull(); } @@ -226,7 +233,7 @@ Vulkan::Implementation::Implementation(u8* data, u32 size) { device.set_context(context); device.init_frame_contexts(3); - ::RDP::CommandProcessorFlags flags = 0; + ::RDP::CommandProcessorFlags flags = ::RDP::COMMAND_PROCESSOR_FLAG_HOST_VISIBLE_HIDDEN_RDRAM_BIT; switch(vulkan.internalUpscale) { case 2: flags |= ::RDP::COMMAND_PROCESSOR_FLAG_UPSCALING_2X_BIT; break; case 4: flags |= ::RDP::COMMAND_PROCESSOR_FLAG_UPSCALING_4X_BIT; break;