Skip to content

Instantly share code, notes, and snippets.

@LVMBDV
Last active April 30, 2020 17:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LVMBDV/912fd498a3c54c59e7a89f03feadb57c to your computer and use it in GitHub Desktop.
Save LVMBDV/912fd498a3c54c59e7a89f03feadb57c to your computer and use it in GitHub Desktop.
#include <SPI.h>
#include <SD.h>
#define ADDRLO_PORT PORTA
#define ADDRHI_PORT PORTC
#define DATA_PORT PORTD
#define MREQ_PIN PB0
#define WR_PIN PB1
#define RD_PIN PB2
#define WAIT_PIN PB3
#define CS_PIN PB3
const uint16_t pageSize = 0xFFFF;
const uint16_t pageSwapTriggerOffset = 0xFFFD;
const uint16_t kPages = 256;
const char rom_filename[] PROGMEM = "rom.hex";
const char log_filename[] PROGMEM = "log.txt";
const char pagefile_format[] PROGMEM = "%u.hex";
const char cpu_done_message[] PROGMEM = "cpu done\n";
const char mreq_short[] PROGMEM = "rd or wr fell short\n";
const char swap_msgformat[] PROGMEM = "swap %04x %04x\n";
const char wrote_msgformat[] PROGMEM = "wrote %02x at %04x\n";
const char read_msgformat[] PROGMEM = "read %02x at %04x\n";
bool waitForCPU;
uint16_t currentPageIndex;
uint16_t nextPageIndex;
uint16_t touchedPages[kPages / 16] = {0};
char filename[13];
char logMsg[20];
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile currentPageFile;
void log(const char *msg) {
currentPageFile.close();
currentPageFile.open(&root, log_filename, FILE_WRITE);
currentPageFile.write(msg);
currentPageFile.close();
sprintf(filename, pagefile_format, currentPageIndex);
currentPageFile.open(&root, filename, FILE_WRITE);
}
void setup() {
portMode(ADDRLO_PORT, INPUT);
portMode(ADDRHI_PORT, INPUT);
portMode(DATA_PORT, INPUT);
pinMode(MREQ_PIN, INPUT_PULLUP);
pinMode(WR_PIN, INPUT_PULLUP);
pinMode(RD_PIN, INPUT_PULLUP);
pinMode(WAIT_PIN, OUTPUT);
digitalWrite(WAIT_PIN, HIGH); // no wait
card.init(SPI_HALF_SPEED, CS_PIN);
volume.init(card);
root.openRoot(volume);
waitForCPU = false;
int romSize = currentPageFile.open(&root, rom_filename, FILE_READ) ? currentPageFile.fileSize() : 0;
currentPageFile.close();
log(romSize ? "ye rom\n" : "no rom\n");
currentPageFile.close();
currentPageFile.open(&root, "0.hex", FILE_WRITE | O_TRUNC);
currentPageFile.close();
byte currentByte;
do {
currentPageFile.open(&root, rom_filename, FILE_READ);
currentPageFile.seekSet(--romSize);
currentByte = currentPageFile.read();
currentPageFile.close();
currentPageFile.open(&root, "0.hex", FILE_WRITE);
currentPageFile.seekSet(currentPageFile.fileSize());
currentPageFile.write(currentByte);
currentPageFile.close();
} while (romSize > 0);
log("rom copied\n");
currentPageFile.open(&root, "0.hex", FILE_WRITE);
currentPageIndex = 0;
bitSet(touchedPages[0], 0);
}
void loop() {
if (!waitForCPU && !digitalRead(MREQ_PIN)) {
uint16_t address = (((uint16_t) portRead(ADDRLO_PORT)) << 8) | (portRead(ADDRHI_PORT) & 0xFE);
uint8_t data;
// wait until the cpu signals read or write along with mreq
do {
__asm__ __volatile__ ("nop\n\t");
} while (digitalRead(RD_PIN) && digitalRead(WR_PIN));
digitalWrite(WAIT_PIN, LOW); // wait while i read/write
if (!digitalRead(RD_PIN)) { // read
portMode(DATA_PORT, OUTPUT); // will output to data bus
if (address == pageSwapTriggerOffset) {
data = (nextPageIndex & 0xFF00) >> 8;
} else if (address == (pageSwapTriggerOffset + 1)) {
data = nextPageIndex & 0x00FF;
} else if (address >= currentPageFile.fileSize()) {
data = 0;
} else {
currentPageFile.seekSet(address);
data = currentPageFile.read();
}
sprintf(logMsg, read_msgformat, data, address);
log(logMsg);
portWrite(DATA_PORT, data); // output to data bus
digitalWrite(WAIT_PIN, HIGH); // stop waiting, data is ready
waitForCPU = true;
} else if (!digitalRead(WR_PIN)) { // write
data = portRead(DATA_PORT);
if (address == pageSwapTriggerOffset) { // assuming low byte is written last
nextPageIndex = (nextPageIndex & 0x00FF) | (((uint16_t) data) << 8);
sprintf(filename, pagefile_format, nextPageIndex);
int flags = bitRead(touchedPages[nextPageIndex / 16], nextPageIndex % 16) ? 0 : O_TRUNC;
currentPageFile.close();
currentPageFile.open(&root, filename, FILE_WRITE | flags);
sprintf(logMsg, swap_msgformat, currentPageIndex, nextPageIndex);
log(logMsg);
bitSet(touchedPages[nextPageIndex / 16], nextPageIndex % 16);
currentPageIndex = nextPageIndex;
} else if (address == (pageSwapTriggerOffset + 1)) {
nextPageIndex = (nextPageIndex & 0xFF00) | data;
} else {
if (address > currentPageFile.fileSize()) {
currentPageFile.seekSet(currentPageFile.fileSize());
uint16_t fillerCounter = address - currentPageFile.fileSize();
do {
currentPageFile.write('\0');
fillerCounter--;
} while (fillerCounter > 0);
}
currentPageFile.seekSet(address);
currentPageFile.write(data);
sprintf(logMsg, wrote_msgformat, data, address);
log(logMsg);
}
digitalWrite(WAIT_PIN, HIGH); // stop waiting, write is finished
} else {
log(mreq_short);
}
} else if (waitForCPU && digitalRead(MREQ_PIN)) {
log(cpu_done_message);
waitForCPU = false;
portMode(DATA_PORT, INPUT);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment