2 // Memory Track cartridge emulation
5 // (C) 2016 Underground Software
7 // The Memory Track is just a large(-ish) EEPROM, holding 128K. We emulate the
8 // Atmel part, since it seems to be easier to deal with than the AMD part. The
9 // way it works is the 68K checks in its R/W functions to see if the MT is
10 // inserted, and, if so, call the R/W functions here. It also checks to see if
11 // the ROM width was changed to 32-bit; if not, then it reads the normal ROM in
12 // the ROM space like usual.
14 // The Atmel part reads/writes a single byte into a long space. So we have to
15 // adjust for that when reading from/writing to the NVRAM.
17 // JLH = James Hammons <jlhamm@acm.org>
20 // --- ---------- -----------------------------------------------------------
21 // JLH 06/12/2016 Created this file ;-)
32 #define MEMTRACK_FILENAME "memtrack.eeprom"
33 //#define DEBUG_MEMTRACK
35 enum { MT_NONE, MT_PROD_ID, MT_RESET, MT_WRITE_ENABLE };
36 enum { MT_IDLE, MT_PHASE1, MT_PHASE2 };
38 uint8_t mtMem[0x20000];
39 uint8_t mtCommand = MT_NONE;
40 uint8_t mtState = MT_IDLE;
42 char mtFilename[MAX_PATH];
44 // Private function prototypes
45 void MTWriteFile(void);
46 void MTStateMachine(uint8_t reg, uint16_t data);
51 sprintf(mtFilename, "%s%s", vjs.EEPROMPath, MEMTRACK_FILENAME);
52 FILE * fp = fopen(mtFilename, "rb");
56 size_t ignored = fread(mtMem, 1, 0x20000, fp);
58 WriteLog("MT: Loaded NVRAM from %s\n", mtFilename);
62 WriteLog("MT: Could not open file \"%s\"!\n", mtFilename);
69 memset(mtMem, 0xFF, 0x20000);
76 WriteLog("MT: Done.\n");
80 void MTWriteFile(void)
85 FILE * fp = fopen(mtFilename, "wb");
89 fwrite(mtMem, 1, 0x20000, fp);
93 WriteLog("MT: Could not create file \"%s\"!", mtFilename);
98 // This is crappy, there doesn't seem to be a word interface to the NVRAM. But
99 // we'll keep this as a placeholder for now.
101 uint16_t MTReadWord(uint32_t addr)
103 uint32_t value = MTReadLong(addr);
105 if ((addr & 0x03) == 0)
107 else if ((addr & 0x03) == 2)
110 #ifdef DEBUG_MEMTRACK
111 WriteLog("MT: Reading word @ $%06X: $%04X\n", addr, value);
114 return (uint16_t)value;
118 uint32_t MTReadLong(uint32_t addr)
122 if (mtCommand == MT_PROD_ID)
124 if (addr == 0x800000)
126 else if (addr == 0x800004)
131 value = (uint32_t)mtMem[(addr & 0x7FFFC) >> 2];
134 // We do this because we're not sure how the real thing behaves; but it
135 // seems reasonable on its face to do it this way. :-P So we turn off write
136 // mode when reading the NVRAM.
137 if (mtCommand == MT_WRITE_ENABLE)
140 #ifdef DEBUG_MEMTRACK
141 WriteLog("MT: Reading long @ $%06X: $%08X\n", addr, value << 16);
147 void MTWriteWord(uint32_t addr, uint16_t data)
149 // We don't care about writes to long offsets + 2
150 if ((addr & 0x3) == 2)
153 #ifdef DEBUG_MEMTRACK
154 WriteLog("MT: Writing word @ $%06X: $%04X (Writing is %sabled)\n", addr, data, (mtCommand == MT_WRITE_ENABLE ? "en" : "dis"));
157 // Write to the NVRAM if it's enabled...
158 if (mtCommand == MT_WRITE_ENABLE)
160 mtMem[(addr & 0x7FFFC) >> 2] = (uint8_t)(data & 0xFF);
166 case (0x800000 + (4 * 0x5555)): // $815554
167 MTStateMachine(0, data);
169 case (0x800000 + (4 * 0x2AAA)): // $80AAA8
170 MTStateMachine(1, data);
176 void MTWriteLong(uint32_t addr, uint32_t data)
178 // Strip off lower 3 bits of the passed in address
181 MTWriteWord(addr + 0, data & 0xFFFF);
182 MTWriteWord(addr + 2, data >> 16);
186 void MTStateMachine(uint8_t reg, uint16_t data)
188 #ifdef DEBUG_MEMTRACK
189 WriteLog("MTStateMachine: reg = %u, data = $%02X, current state = %u\n", reg, data, mtState);
194 if ((reg == 0) && (data == 0xAA))
199 if ((reg == 1) && (data == 0x55))
208 if (data == 0x90) // Product ID
209 mtCommand = MT_PROD_ID;
210 else if (data == 0xF0) // Reset
212 else if (data == 0xA0) // Write enagle
213 mtCommand = MT_WRITE_ENABLE;
221 #ifdef DEBUG_MEMTRACK
222 WriteLog(" state = %u, cmd = %u\n", mtState, mtCommand);