Skip to content

Commit

Permalink
Implement the FLASH save type
Browse files Browse the repository at this point in the history
  • Loading branch information
Hydr8gon committed Jun 6, 2023
1 parent 05ef0e2 commit cd5dd8f
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 23 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ Although still in early stages, rokuyon should be plug-and-play with any NTSC RO
* [RCP Documentation](https://dragonminded.com/n64dev/Reality%20Coprocessor.pdf) - Nice reference for a subset of RDP functionality
* [RDP Triangle Command Guide](https://docs.google.com/document/d/17ddEo61V0suXbSkKP5mY97QxgUnB-QfAjuBIsPiLWko) - Covers everything related to RDP triangles
* [N64 bilinear filter (3-point)](https://www.shadertoy.com/view/Ws2fWV) - Reference implementation of the N64's texture filter
* [dgb-n64](https://github.com/Dillonb/n64) - Provides details of the FLASH interface, since it isn't documented
* Hardware tests - I'll probably be testing things myself as I go along

### Other Links
Expand Down
38 changes: 25 additions & 13 deletions src/desktop/save_dialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,16 @@ enum SaveEvent
SELECT_0 = 1,
SELECT_1,
SELECT_2,
SELECT_3
SELECT_3,
SELECT_4
};

wxBEGIN_EVENT_TABLE(SaveDialog, wxDialog)
EVT_RADIOBUTTON(SELECT_0, SaveDialog::select0)
EVT_RADIOBUTTON(SELECT_1, SaveDialog::select1)
EVT_RADIOBUTTON(SELECT_2, SaveDialog::select2)
EVT_RADIOBUTTON(SELECT_3, SaveDialog::select3)
EVT_RADIOBUTTON(SELECT_4, SaveDialog::select4)
EVT_BUTTON(wxID_OK, SaveDialog::confirm)
wxEND_EVENT_TABLE()

Expand All @@ -41,10 +43,11 @@ uint32_t SaveDialog::selectToSize(uint32_t select)
// Convert a save selection to a size
switch (select)
{
case 1: return 0x8000; // SRAM 32KB
case 2: return 0x0200; // EEPROM 0.5KB
case 3: return 0x0800; // EEPROM 8KB
default: return 0x0000; // None
case 1: return 0x00200; // EEPROM 0.5KB
case 2: return 0x00800; // EEPROM 8KB
case 3: return 0x08000; // SRAM 32KB
case 4: return 0x20000; // FLASH 128KB
default: return 0x00000; // None
}
}

Expand All @@ -53,10 +56,11 @@ uint32_t SaveDialog::sizeToSelect(uint32_t size)
// Convert a save size to a selection
switch (size)
{
case 0x8000: return 1; // SRAM 32KB
case 0x0200: return 2; // EEPROM 0.5KB
case 0x0800: return 3; // EEPROM 8KB
default: return 0; // None
case 0x00200: return 1; // EEPROM 0.5KB
case 0x00800: return 2; // EEPROM 8KB
case 0x08000: return 3; // SRAM 32KB
case 0x20000: return 4; // FLASH 128KB
default: return 0; // None
}
}

Expand All @@ -71,13 +75,15 @@ SaveDialog::SaveDialog(std::string &lastPath): lastPath(lastPath),
// Create left and right columns for the radio buttons
wxBoxSizer *leftRadio = new wxBoxSizer(wxVERTICAL);
wxBoxSizer *rightRadio = new wxBoxSizer(wxVERTICAL);
wxRadioButton *buttons[4];
wxRadioButton *buttons[5];

// Set up radio buttons for the save types
leftRadio->Add(buttons[0] = new wxRadioButton(this, SELECT_0, "None"), 1);
leftRadio->Add(buttons[1] = new wxRadioButton(this, SELECT_1, "SRAM 32KB"), 1);
rightRadio->Add(buttons[2] = new wxRadioButton(this, SELECT_2, "EEPROM 0.5KB"), 1);
rightRadio->Add(buttons[3] = new wxRadioButton(this, SELECT_3, "EEPROM 2KB"), 1);
leftRadio->Add(buttons[1] = new wxRadioButton(this, SELECT_1, "EEPROM 0.5KB"), 1);
leftRadio->Add(buttons[2] = new wxRadioButton(this, SELECT_2, "EEPROM 2KB"), 1);
rightRadio->Add(buttons[3] = new wxRadioButton(this, SELECT_3, "SRAM 32KB"), 1);
rightRadio->Add(buttons[4] = new wxRadioButton(this, SELECT_4, "FLASH 128KB"), 1);
rightRadio->Add(new wxStaticText(this, wxID_ANY, ""), 1);

// Select the current save type by default
selection = sizeToSelect(Core::saveSize);
Expand Down Expand Up @@ -134,6 +140,12 @@ void SaveDialog::select3(wxCommandEvent &event)
selection = 3;
}

void SaveDialog::select4(wxCommandEvent &event)
{
// Select save type 4
selection = 4;
}

void SaveDialog::confirm(wxCommandEvent &event)
{
// Ask for confirmation before doing anything because accidents could be bad!
Expand Down
1 change: 1 addition & 0 deletions src/desktop/save_dialog.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class SaveDialog: public wxDialog
void select1(wxCommandEvent &event);
void select2(wxCommandEvent &event);
void select3(wxCommandEvent &event);
void select4(wxCommandEvent &event);
void confirm(wxCommandEvent &event);

wxDECLARE_EVENT_TABLE();
Expand Down
100 changes: 98 additions & 2 deletions src/memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,15 @@
#include "si.h"
#include "vi.h"

enum FlashState
{
FLASH_NONE = 0,
FLASH_STATUS,
FLASH_READ,
FLASH_WRITE,
FLASH_ERASE
};

struct TLBEntry
{
uint32_t entryLo0;
Expand All @@ -47,13 +56,24 @@ namespace Memory
uint8_t rdram[0x400000]; // 4MB RDRAM
uint8_t rspMem[0x2000]; // 4KB RSP DMEM + 4KB RSP IMEM
TLBEntry entries[32];

uint8_t writeBuf[0x80];
uint32_t writeOfs;
uint32_t eraseOfs;
FlashState state;

void writeFlash(uint32_t value);
}

void Memory::reset()
{
// Clear RDRAM and RSP DMEM/IMEM
memset(rdram, 0, sizeof(rdram));
// Reset memory to its initial state
memset(rdram, 0, sizeof(rdram));
memset(rspMem, 0, sizeof(rspMem));
memset(writeBuf, 0, sizeof(writeBuf));
writeOfs = 0;
eraseOfs = 0;
state = FLASH_NONE;

// Map TLB entries to inaccessible locations
for (int i = 0; i < 32; i++)
Expand Down Expand Up @@ -142,6 +162,11 @@ template <typename T> T Memory::read(uint32_t address)
// Get a pointer to data in cart SRAM, if it exists
data = &Core::save[pAddr & 0x7FFF];
}
else if (pAddr >= 0x8000000 && pAddr < 0x8020000 && state == FLASH_READ)
{
// Get a pointer to data in cart FLASH, if it's readable
data = &Core::save[address & 0x1FFFF];
}
else if (pAddr >= 0x10000000 && pAddr < 0x10000000 + std::min(Core::romSize, 0xFC00000U))
{
// Get a pointer to data in cart ROM
Expand Down Expand Up @@ -281,6 +306,11 @@ template <typename T> void Memory::write(uint32_t address, T value)
Core::writeSave((pAddr + i) & 0x7FFF, value >> ((sizeof(T) - 1 - i) * 8));
return;
}
else if (pAddr >= 0x8000000 && pAddr < 0x8000080 && state == FLASH_WRITE)
{
// Get a pointer to data in the FLASH write buffer, if it's writable
data = &writeBuf[address & 0x7F];
}
else if (pAddr >= 0x1FC007C0 && pAddr < 0x1FC00800)
{
// Get a pointer to data in PIF ROM/RAM
Expand Down Expand Up @@ -314,6 +344,11 @@ template <typename T> void Memory::write(uint32_t address, T value)
// Write a value to an RDP register
return RDP::write((pAddr & 0x1F) >> 2, value);
}
else if (pAddr == 0x8010000 && Core::saveSize == 0x20000)
{
// Write a value to the FLASH register
return writeFlash(value);
}
else
{
// Write a value to a group of registers
Expand All @@ -337,3 +372,64 @@ template <typename T> void Memory::write(uint32_t address, T value)

LOG_WARN("Unknown memory write: 0x%X\n", address);
}

void Memory::writeFlash(uint32_t value)
{
// Handle a FLASH register write based on the command byte
switch (uint8_t command = value >> 24)
{
case 0xD2: // Execute
switch (state)
{
case FLASH_WRITE:
// Copy the write buffer to a save block
for (int i = 0; i < 0x80; i++)
Core::writeSave(writeOfs + i, writeBuf[i]);
return;

case FLASH_ERASE:
// Reset the contents of a save block
for (int i = 0; i < 0x80; i++)
Core::writeSave(eraseOfs + i, 0xFF);
return;

default:
LOG_WARN("Executing FLASH in invalid state: %d\n", state);
return;
}

case 0xE1: // Status
// Change the FLASH state to status
state = FLASH_STATUS;
return;

case 0xF0: // Read
// Change the FLASH state to read
state = FLASH_READ;
return;

case 0xB4: // Write
// Change the FLASH state to write
state = FLASH_WRITE;
return;

case 0x78: // Erase
// Change the FLASH state to erase
state = FLASH_ERASE;
return;

case 0x4B: // Erase Offset
// Set the address of the save block to erase
eraseOfs = (value & 0xFFFF) << 7;
return;

case 0xA5: // Write Offset
// Set the address of the save block to write
writeOfs = (value & 0xFFFF) << 7;
return;

default:
LOG_CRIT("Unknown FLASH command: 0x%02X\n", command);
return;
}
}
1 change: 1 addition & 0 deletions src/rsp_cp2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include "rsp_cp2.h"
#include "log.h"
#include "rsp.h"

namespace RSP_CP2
{
Expand Down
19 changes: 11 additions & 8 deletions src/switch/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,15 +219,17 @@ bool saveTypeMenu()
ListItem("None"),
ListItem("EEPROM 0.5KB"),
ListItem("EEPROM 2KB"),
ListItem("SRAM 32KB")
ListItem("SRAM 32KB"),
ListItem("FLASH 128KB")
};

// Select the current save type by default
switch (Core::saveSize)
{
case 0x0200: index = 1; break; // EEPROM 0.5KB
case 0x0800: index = 2; break; // EEPROM 8KB
case 0x8000: index = 3; break; // SRAM 32KB
case 0x00200: index = 1; break; // EEPROM 0.5KB
case 0x00800: index = 2; break; // EEPROM 8KB
case 0x08000: index = 3; break; // SRAM 32KB
case 0x20000: index = 4; break; // FLASH 128KB
}

// Create the save type menu
Expand All @@ -245,10 +247,11 @@ bool saveTypeMenu()
// On confirmation, change the save type
switch (index)
{
case 0: Core::resizeSave(0x0000); break; // None
case 1: Core::resizeSave(0x0200); break; // EEPROM 0.5KB
case 2: Core::resizeSave(0x0800); break; // EEPROM 8KB
case 3: Core::resizeSave(0x8000); break; // SRAM 32KB
case 0: Core::resizeSave(0x00000); break; // None
case 1: Core::resizeSave(0x00200); break; // EEPROM 0.5KB
case 2: Core::resizeSave(0x00800); break; // EEPROM 8KB
case 3: Core::resizeSave(0x08000); break; // SRAM 32KB
case 4: Core::resizeSave(0x20000); break; // FLASH 128KB
}

// Restart the emulator
Expand Down

0 comments on commit cd5dd8f

Please sign in to comment.