merge mappers from FCEU-mm
[fceu.git] / boards / copyfami_hwi.c
CommitLineData
43725da7 1/* FCE Ultra - NES/Famicom Emulator\r
2 *\r
3 * Copyright notice for this file:\r
4 * Copyright (C) 2011 CaH4e3\r
5 *\r
6 * This program is free software; you can redistribute it and/or modify\r
7 * it under the terms of the GNU General Public License as published by\r
8 * the Free Software Foundation; either version 2 of the License, or\r
9 * (at your option) any later version.\r
10 *\r
11 * This program is distributed in the hope that it will be useful,\r
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
14 * GNU General Public License for more details.\r
15 *\r
16 * You should have received a copy of the GNU General Public License\r
17 * along with this program; if not, write to the Free Software\r
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
19 */\r
20\r
21// *** COPY FAMICOM HARDWARE INTERFACE ***\r
22\r
23#ifdef COPYFAMI\r
24\r
25#define MESSAGE_LOG\r
26#define NO_CACHE\r
27#define NO_RAM\r
28\r
29#include "__serial.h"\r
30#include "mapinc.h"\r
31\r
32#define FNV_32_PRIME ((uint32)0x01000193)\r
33\r
34#define CHR_CACHE_SIZE (1024 * 4)\r
35#define WRAM_CACHE_SIZE (1024 / 2)\r
36#define PRG_CACHE_SIZE (1024 / 4)\r
37#define CMD_CACHE_SIZE (1024 * 128)\r
38\r
39#define CMD_MAX_SIZE (5)\r
40#define CMD_MAX_RETEST (16)\r
41#define CMD_MAX_VERIFY (16)\r
42\r
43static uint8 *WRAM = NULL;\r
44\r
45uint8 InitVector[] = {0xDE, 0xAD, 0xBE, 0xEF}; // args none, return DE AD BE EF\r
46uint8 ResetCmd[] = {0x00}; // args none, return none\r
47uint8 StateCmd[] = {0x01}; // args none, return 7 bytes status\r
48uint8 StatusCmd[] = {0x02}; // args none, return 32 bytes status\r
49uint8 LoadPlugCmd[] = {0x03, 0x00, 0x00}; // args 2b size, Nb data return none\r
50uint8 RunPlugCmd[] = {0x04}; // args none, return none\r
51uint8 RunGameCmd[] = {0x05}; // args none, return none\r
52uint8 NROMSave[] = {0x06}; // args none, return 16b + 32kb + 8kb\r
53\r
54uint8 PRGWBCmd[] = {0x08, 0x00, 0x00, 0x00}; // args 2b addr, 1b data return none\r
55uint8 PRGRBCmd[] = {0x09, 0x00, 0x00}; // args 2b addr return 1b data\r
56uint8 CHRWBCmd[] = {0x0A, 0x00, 0x00, 0x00}; // args 2b addr, 1b data return none\r
57uint8 CHRRBCmd[] = {0x0B, 0x00, 0x00}; // args 2b addr, return 1b data\r
58\r
59uint8 PRGSUMCmd[] = {0x10, 0x00, 0x00}; // args 1b addr, 1b size return (256 * N)b\r
60uint8 PRG32KSUMCmd[] = {0x10, 0x80, 0x80}; // args 1b addr, 1b size return 32kb\r
61uint8 PRG16KSUMCmd[] = {0x10, 0x00, 0x40}; // args 1b addr, 1b size return 16kb\r
62uint8 PRG8KSUMCmd[] = {0x10, 0x00, 0x20}; // args 1b addr, 1b size return 8kb\r
63uint8 PRG4KSUMCmd[] = {0x10, 0x00, 0x10}; // args 1b addr, 1b size return 4kb\r
64\r
65uint8 CHRSUMCmd[] = {0x11, 0x00, 0x00}; // args 1b addr, 1b size return (256 * N)b\r
66uint8 CHR8KSUMCmd[] = {0x11, 0x00, 0x20}; // args 1b addr, 1b size return 8kb\r
67uint8 CHR4KSUMCmd[] = {0x11, 0x00, 0x10}; // args 1b addr, 1b size return 4kb\r
68uint8 CHR2KSUMCmd[] = {0x11, 0x00, 0x08}; // args 1b addr, 1b size return 2kb\r
69uint8 CHR1KSUMCmd[] = {0x11, 0x00, 0x04}; // args 1b addr, 1b size return 1kb\r
70\r
71uint8 PRGGetCmd[] = {0x12, 0x00, 0x00}; // args 1b addr, 1b size return (256 * N)b\r
72uint8 PRG32KGetCmd[] = {0x12, 0x80, 0x80}; // args 1b addr, 1b size return 32kb\r
73uint8 PRG16KGetCmd[] = {0x12, 0x00, 0x40}; // args 1b addr, 1b size return 16kb\r
74uint8 PRG8KGetCmd[] = {0x12, 0x00, 0x20}; // args 1b addr, 1b size return 8kb\r
75uint8 PRG4KGetCmd[] = {0x12, 0x00, 0x10}; // args 1b addr, 1b size return 4kb\r
76\r
77uint8 CHRGetCmd[] = {0x13, 0x00, 0x00}; // args 1b addr, 1b size return (256 * N)b\r
78uint8 CHR8KGetCmd[] = {0x13, 0x00, 0x20}; // args 1b addr, 1b size return 8kb\r
79uint8 CHR4KGetCmd[] = {0x13, 0x00, 0x10}; // args 1b addr, 1b size return 4kb\r
80uint8 CHR2KGetCmd[] = {0x13, 0x00, 0x08}; // args 1b addr, 1b size return 2kb\r
81uint8 CHR1KGetCmd[] = {0x13, 0x00, 0x04}; // args 1b addr, 1b size return 1kb\r
82\r
83uint8 CPUTestCmd[] = {0x14, 0x00, 0x00}; // args 1b addr, 1b size return (2b + 1b) * N + 3b\r
84\r
85typedef struct {\r
86 int32 mirror;\r
87 int32 chrsum[8];\r
88 int32 prgsum[4];\r
89} SYNC_STATE;\r
90\r
91static SYNC_STATE state_cur, state_new, state_def;\r
92\r
93typedef struct {\r
94 uint8 *buf;\r
95 int32 count;\r
96} DATA_BANKS;\r
97\r
98static DATA_BANKS chr_data;\r
99static int32 chr_bank[0x10000];\r
100static DATA_BANKS prg_data;\r
101static int32 prg_bank[0x10000];\r
102\r
103typedef struct {\r
104 SYNC_STATE states[CMD_CACHE_SIZE];\r
105 int32 seqs[CMD_CACHE_SIZE][CMD_MAX_SIZE];\r
106 int32 count;\r
107} SYNC_CMDS;\r
108\r
109typedef struct {\r
110 int32 seq[CMD_MAX_SIZE];\r
111 int32 size;\r
112 int32 found;\r
113 uint32 hash;\r
114 uint16 hashf;\r
115} SYNC_CMD;\r
116\r
117static SYNC_CMD cmd;\r
118static SYNC_CMDS cmds;\r
119\r
120typedef struct {\r
121 int32 index;\r
122 int32 size;\r
123 int32 retest;\r
124 int32 verify; \r
125} CMD_CACHE;\r
126\r
127static CMD_CACHE cmd_cache[0x10000];\r
128\r
129static SFORMAT StateRegs[]=\r
130{\r
131 {state_cur.chrsum, sizeof(state_cur.chrsum), "CHRREG"},\r
132 {state_cur.prgsum, sizeof(state_cur.prgsum), "ROMREG"},\r
133 {&state_cur.mirror, sizeof(state_cur.mirror), "MIRREG"},\r
134 {0}\r
135};\r
136\r
137#define MI_U 4\r
138\r
139static char *mirror_names[5] = {"Horizontal", "Vertical", "Mirror 0", "Mirror 1", "Unknown mirror"};\r
140static int32 mirror_modes[16] = {\r
141 MI_0, MI_U, MI_U, MI_H, MI_U, MI_V, MI_U, MI_U,\r
142 MI_U, MI_U, MI_U, MI_U, MI_U, MI_U, MI_U, MI_1 };\r
143\r
144#define CHRDEF(slot) (chr_bank[state_def.chrsum[slot]])\r
145#define PRGDEF(slot) (prg_bank[state_def.prgsum[slot]])\r
146#define CHRCUR(slot) (chr_bank[state_cur.chrsum[slot]])\r
147#define PRGCUR(slot) (prg_bank[state_cur.prgsum[slot]])\r
148#define CHRNEW(slot) (chr_bank[state_new.chrsum[slot]])\r
149#define PRGNEW(slot) (prg_bank[state_new.prgsum[slot]])\r
150\r
151static void GetStatus(SYNC_STATE *state)\r
152{\r
153 uint8 resp0;\r
154 uint16 resp1, i;\r
155 SEND(StatusCmd);\r
156 GET(resp0, 1);\r
157 state->mirror = resp0;\r
158 GET(resp0, 1);\r
159 for(i=0; i<8; i++) {\r
160 GET(resp1, 2);\r
161 state->chrsum[i] = resp1;\r
162 }\r
163 for(i=0; i<4; i++) {\r
164 GET(resp1, 2);\r
165 state->prgsum[i] = resp1;\r
166 } \r
167}\r
168\r
169static int32 FetchNewCHRBank(int32 slot)\r
170{\r
171 FILE *ofile;\r
172 char name[256];\r
173 int32 bank = chr_data.count++;\r
174 CHR1KGetCmd[1] = slot << 2;\r
175 SENDGET(CHR1KGetCmd, chr_data.buf[bank * 1024], 1024);\r
176 sprintf(name,"%04x.chr",bank);\r
177 ofile=fopen(name,"wb");\r
178 fwrite((void *)&chr_data.buf[bank * 1024], 1, 1024, ofile);\r
179 fclose(ofile);\r
180 return bank;\r
181}\r
182\r
183static int32 FetchNewPRGBank(int32 slot)\r
184{\r
185 FILE *ofile;\r
186 char name[256];\r
187 int32 bank = prg_data.count++;\r
188 PRG8KGetCmd[1] = 0x80 + (slot << 5);\r
189 SENDGET(PRG8KGetCmd, prg_data.buf[bank * 8192], 8192);\r
190 sprintf(name,"%04x.prg",bank);\r
191 ofile=fopen(name,"wb");\r
192 fwrite((void *)&prg_data.buf[bank * 8192], 1, 8192, ofile);\r
193 fclose(ofile);\r
194 return bank;\r
195}\r
196\r
197static int CheckStatus(void)\r
198{\r
199 int32 i, ischanged = 0;\r
200 GetStatus(&state_new);\r
201 if(state_cur.mirror != state_new.mirror) {\r
202 state_cur.mirror = state_new.mirror;\r
203#ifdef MESSAGE_LOG\r
204 FCEU_printf(">> mirror changed to %s (%02X)\n",mirror_names[mirror_modes[state_cur.mirror]], state_cur.mirror);\r
205#endif\r
206 ischanged = 1;\r
207 } else {\r
208 state_new.mirror = -1;\r
209 }\r
210 for(i=0; i<8; i++) {\r
211 if(state_cur.chrsum[i] != state_new.chrsum[i]) {\r
212 state_cur.chrsum[i] = state_new.chrsum[i];\r
213 if(CHRCUR(i) == -1) {\r
214 CHRCUR(i) = FetchNewCHRBank(i);\r
215#ifdef MESSAGE_LOG\r
216 FCEU_printf(">> chr[%d] bank %d loaded\n", i, CHRCUR(i));\r
217#endif\r
218 }\r
219#ifdef MESSAGE_LOG\r
220 else\r
221 FCEU_printf(">> chr[%d] bank %d switched\n", i, CHRCUR(i));\r
222#endif\r
223 ischanged = 1;\r
224 } else {\r
225 state_new.chrsum[i] = -1;\r
226 }\r
227 }\r
228 for(i=0; i<4; i++) {\r
229 if(state_cur.prgsum[i] != state_new.prgsum[i]) {\r
230 state_cur.prgsum[i] = state_new.prgsum[i]; \r
231 if(PRGCUR(i) == -1) {\r
232 PRGCUR(i) = FetchNewPRGBank(i);\r
233#ifdef MESSAGE_LOG\r
234 FCEU_printf(">> prg[%d] bank %d loaded\n", i, PRGCUR(i));\r
235#endif\r
236 }\r
237#ifdef MESSAGE_LOG\r
238 else\r
239 FCEU_printf(">> prg[%d] bank %d switched\n", i, PRGCUR(i));\r
240#endif\r
241 ischanged = 1;\r
242 } else {\r
243 state_new.prgsum[i] = -1;\r
244 }\r
245 }\r
246 return ischanged;\r
247}\r
248\r
249#ifndef NO_CACHE\r
250static void ApplyStatus()\r
251{\r
252 int32 i;\r
253 if ((cmds.states[cmd.found].mirror != -1) && (cmds.states[cmd.found].mirror != state_cur.mirror)) {\r
254 state_cur.mirror = cmds.states[cmd.found].mirror;\r
255 setmirror(mirror_modes[state_cur.mirror]);\r
256#ifdef MESSAGE_LOG\r
257 FCEU_printf(">> mirror changed to %s (%02X)\n",mirror_names[mirror_modes[state_cur.mirror]], state_cur.mirror);\r
258#endif\r
259 }\r
260 for(i=0; i<8; i++) {\r
261 int32 sum = cmds.states[cmd.found].chrsum[i];\r
262 if (sum != -1) {\r
263 if (sum != state_cur.chrsum[i]) {\r
264 state_cur.chrsum[i] = sum;\r
265 setchr1r(1, i * 1024, CHRCUR(i));\r
266#ifdef MESSAGE_LOG\r
267 FCEU_printf(">> chr[%d] bank %d switched\n", i, chr_bank[sum]);\r
268#endif\r
269 }\r
270 else\r
271#ifdef MESSAGE_LOG\r
272 FCEU_printf(">> chr[%d] bank %d switched the same\n", i, chr_bank[sum]);\r
273 }\r
274#endif\r
275 }\r
276 for(i=0; i<4; i++) {\r
277 int32 sum = cmds.states[cmd.found].prgsum[i];\r
278 if (sum != -1) {\r
279 if (sum != state_cur.prgsum[i]) {\r
280 state_cur.prgsum[i] = sum;\r
281 setprg8r(2, 0x8000 + (i * 8192), PRGCUR(i));\r
282#ifdef MESSAGE_LOG\r
283 FCEU_printf(">> prg[%d] bank %d switched\n", i, prg_bank[sum]);\r
284#endif\r
285 }\r
286 else\r
287#ifdef MESSAGE_LOG\r
288 FCEU_printf(">> prg[%d] bank %d switched the same\n", i, prg_bank[sum]);\r
289 }\r
290#endif\r
291 }\r
292}\r
293\r
294static void LogCmd()\r
295{\r
296 int32 i;\r
297 FCEU_printf(">> new cmd size %d [", cmd_cache[cmd.hashf].size);\r
298 for(i=0; i<cmd_cache[cmd.hashf].size; i++)\r
299 FCEU_printf(" %06X",cmds.seqs[cmd.found][i]);\r
300 FCEU_printf(" ], switched to ("); \r
301 if (cmds.states[cmd.found].mirror != -1)\r
302 FCEU_printf(" mirror=%s",mirror_names[mirror_modes[cmds.states[cmd.found].mirror]]);\r
303 for(i=0; i<8; i++)\r
304 if (cmds.states[cmd.found].chrsum[i] != -1)\r
305 FCEU_printf(" chr%d=%02X", i, chr_bank[cmds.states[cmd.found].chrsum[i]]);\r
306 for(i=0; i<4; i++)\r
307 if (cmds.states[cmd.found].prgsum[i] != -1)\r
308 FCEU_printf(" prg%d=%02X", i, prg_bank[cmds.states[cmd.found].prgsum[i]]);\r
309 FCEU_printf(" )\n"); \r
310}\r
311#endif\r
312static void Sync()\r
313{\r
314 setchr1r(1, 0x0000, CHRCUR(0));\r
315 setchr1r(1, 0x0400, CHRCUR(1));\r
316 setchr1r(1, 0x0800, CHRCUR(2));\r
317 setchr1r(1, 0x0C00, CHRCUR(3));\r
318 setchr1r(1, 0x1000, CHRCUR(4));\r
319 setchr1r(1, 0x1400, CHRCUR(5));\r
320 setchr1r(1, 0x1800, CHRCUR(6));\r
321 setchr1r(1, 0x1C00, CHRCUR(7));\r
322#ifndef NO_RAM\r
323 setprg8r(1, 0x6000, 0);\r
324#endif\r
325 setprg8r(2, 0x8000, PRGCUR(0));\r
326 setprg8r(2, 0xA000, PRGCUR(1));\r
327 setprg8r(2, 0xC000, PRGCUR(2));\r
328 setprg8r(2, 0xE000, PRGCUR(3));\r
329 setmirror(mirror_modes[state_cur.mirror]);\r
330}\r
331#ifndef NO_CACHE\r
332static void UpdateCmd(uint32 val)\r
333{\r
334 int32 index;\r
335 if(cmd.size < CMD_MAX_SIZE) {\r
336 index = cmd.size++;\r
337 } else {\r
338