Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ares/n64/mi/mi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ struct MI : Memory::RCP<MI> {
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
Expand Down
7 changes: 6 additions & 1 deletion ares/n64/rdram/rdram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,29 @@ 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);
}

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 = {};
}
}
Expand Down
64 changes: 48 additions & 16 deletions ares/n64/rdram/rdram.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,17 @@ struct RDRAM : Memory::RCP<RDRAM> {

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) {}

Expand All @@ -14,9 +25,30 @@ struct RDRAM : Memory::RCP<RDRAM> {
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<Size>(address);
}

template<u32 Size>
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<Size>(address, data);
}

template<u32 Size>
auto writeRepeat(u32 address, u64 value, u8 length) -> void {
if constexpr(Size == Byte) {
Expand All @@ -36,43 +68,43 @@ struct RDRAM : Memory::RCP<RDRAM> {
length = end - address;

if (address & 1) {
Memory::Writable::write<Byte>(address, value >> 56);
writeAutoCVG<Byte>(address, value >> 56);
value = (value << 8) | (value >> 56);
address = (address & ~0x7FF) | ((address + 1) & 0x7FF);
length -= 1;
}
if ((address & 2) && length >= 2) {
Memory::Writable::write<Half>(address, value >> 48);
writeAutoCVG<Half>(address, value >> 48);
value = (value << 16) | (value >> 48);
address = (address & ~0x7FF) | ((address + 2) & 0x7FF);
length -= 2;
}
if ((address & 4) && length >= 4) {
Memory::Writable::write<Word>(address, value >> 32);
writeAutoCVG<Word>(address, value >> 32);
value = (value << 32) | (value >> 32);
address = (address & ~0x7FF) | ((address + 4) & 0x7FF);
length -= 4;
}

while (length >= 8) {
Memory::Writable::write<Dual>(address, value);
writeAutoCVG<Dual>(address, value);
address = (address & ~0x7FF) | ((address + 8) & 0x7FF);
length -= 8;
}
if (length >= 4) {
Memory::Writable::write<Word>(address, value >> 32);
writeAutoCVG<Word>(address, value >> 32);
value <<= 32;
address += 4;
length -= 4;
}
if (length >= 2) {
Memory::Writable::write<Half>(address, value >> 48);
writeAutoCVG<Half>(address, value >> 48);
value <<= 16;
address += 2;
length -= 2;
}
if (length == 1)
Memory::Writable::write<Byte>(address, value >> 56);
writeAutoCVG<Byte>(address, value >> 56);
}

template<u32 Size>
Expand All @@ -84,22 +116,22 @@ struct RDRAM : Memory::RCP<RDRAM> {
if (unlikely(mi.initializeMode())) {
writeRepeat<Size>(address, value, mi.initializeLength()+1);
} else {
Memory::Writable::write<Size>(address, value);
writeAutoCVG<Size>(address, value);
}
}

template<u32 Size>
auto writeBurst(u32 address, u32 *value, const char *peripheral) -> void {
if (address >= size) return;
Memory::Writable::write<Word>(address | 0x00, value[0]);
Memory::Writable::write<Word>(address | 0x04, value[1]);
Memory::Writable::write<Word>(address | 0x08, value[2]);
Memory::Writable::write<Word>(address | 0x0c, value[3]);
writeAutoCVG<Word>(address | 0x00, value[0]);
writeAutoCVG<Word>(address | 0x04, value[1]);
writeAutoCVG<Word>(address | 0x08, value[2]);
writeAutoCVG<Word>(address | 0x0c, value[3]);
if (Size == ICache) {
Memory::Writable::write<Word>(address | 0x10, value[4]);
Memory::Writable::write<Word>(address | 0x14, value[5]);
Memory::Writable::write<Word>(address | 0x18, value[6]);
Memory::Writable::write<Word>(address | 0x1c, value[7]);
writeAutoCVG<Word>(address | 0x10, value[4]);
writeAutoCVG<Word>(address | 0x14, value[5]);
writeAutoCVG<Word>(address | 0x18, value[6]);
writeAutoCVG<Word>(address | 0x1c, value[7]);
}
}

Expand Down
9 changes: 8 additions & 1 deletion ares/n64/vulkan/vulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}

Expand Down Expand Up @@ -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;
Expand Down
Loading