merge mappers from FCEU-mm
[fceu.git] / boards / 164.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Xodnizel 2006 CaH4e3
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  * It seems that 162/163/164 mappers are the same mapper with just different
21  * mapper modes enabled or disabled in software or hardware, need more nanjing
22  * carts
23  */
24
25 #include "mapinc.h"
26
27 static uint8 laststrobe, trigger;
28 static uint8 reg[8];
29 static uint8 *WRAM=NULL;
30 static uint32 WRAMSIZE;
31
32 static void(*WSync)(void);
33
34 static SFORMAT StateRegs[]=
35 {
36   {&laststrobe, 1, "STB"},
37   {&trigger, 1, "TRG"},
38   {reg, 8, "REGS"},
39   {0}
40 };
41
42 /*
43 const EEPROM_interface eeprom_interface. =
44 {
45         9,                                 // address bits 9
46         8,                                 // data bits    8
47         "*110",                    // read         1 10 aaaaaaaaa
48         "*101",                    // write        1 01 aaaaaaaaa dddddddd
49 .       "*10000xxxxxxx",   // lock         1 00 00xxxxxxx
50         "*10011xxxxxxx",   // unlock       1 00 11xxxxxxx
51         1,
52         5
53 };
54
55 static const EEPROM_interface *intf;
56
57 static int serial_count = 0;
58 static u8  serial_buffer[SERIAL_BUFFER_LENGTH];
59
60 static int eeprom_data_bits;
61 static int eeprom_clock_count;
62 static int eeprom_read_address;
63 static u8  *eeprom_data;
64
65 static int latch = 0;
66 static int locked = 1;
67 static int sending = 0;
68 static int reset_line = ASSERT_LINE;
69 static int clock_line = ASSERT_LINE;
70 static int reset_delay;
71
72 void EEPROM_Init(u8 *data, u8 bit)
73 {
74         eeprom_data = data;
75         if(bit == 8)
76                 intf = &eeprom_interface_93C46_8;
77         else
78                 intf = &eeprom_interface_93C46_16;
79 }
80
81 u8 *EEPROM_GetData()
82 {
83         return eeprom_data;
84 }
85
86 static int EEPROM_command_match(const char *buf, const char *cmd, int len)
87 {
88         if ( cmd == 0 ) return 0;
89         if ( len == 0 ) return 0;
90
91         for (;len>0;)
92         {
93                 char b = *buf;
94                 char c = *cmd;
95
96                 if ((b==0) || (c==0))
97                         return (b==c);
98
99                 switch ( c )
100                 {
101                 case '0':
102                 case '1':
103                         if (b != c)     return 0;
104                 case 'X':
105                 case 'x':
106                         buf++;
107                         len--;
108                         cmd++;
109                         break;
110
111                 case '*':
112                         c = cmd[1];
113                         switch( c )
114                         {
115                         case '0':
116                         case '1':
117                                 if (b == c)     {       cmd++;                  }
118                                 else            {       buf++;  len--;  }
119                                 break;
120                         default:        return 0;
121                         }
122                 }
123         }
124         return (*cmd==0);
125 }
126
127 static void EEPROM_write(int bit)
128 {
129         if (serial_count >= SERIAL_BUFFER_LENGTH-1)
130         {
131                 return;
132         }
133
134         serial_buffer[serial_count++] = (bit ? '1' : '0');
135         serial_buffer[serial_count] = 0;
136
137         if ( (serial_count > intf->address_bits) &&
138               EEPROM_command_match((char*)serial_buffer,intf->cmd_read,(int)strlen((char*)serial_buffer)-intf->address_bits) )
139         {
140                 int i,address;
141
142                 address = 0;
143                 for (i = serial_count-intf->address_bits;i < serial_count;i++)
144                 {
145                         address <<= 1;
146                         if (serial_buffer[i] == '1') address |= 1;
147                 }
148                 if (intf->data_bits == 16)
149                         eeprom_data_bits = (eeprom_data[2*address+0] << 8) + eeprom_data[2*address+1];
150                 else
151                         eeprom_data_bits = eeprom_data[address];
152                 eeprom_read_address = address;
153                 eeprom_clock_count = 0;
154                 sending = 1;
155                 serial_count = 0;
156         }
157         else if ( (serial_count > intf->address_bits) &&
158                    EEPROM_command_match((char*)serial_buffer,intf->cmd_erase,(int)strlen((char*)serial_buffer)-intf->address_bits) )
159         {
160                 int i,address;
161
162                 address = 0;
163                 for (i = serial_count-intf->address_bits;i < serial_count;i++)
164                 {
165                         address <<= 1;
166                         if (serial_buffer[i] == '1') address |= 1;
167                 }
168
169                 if (locked == 0)
170                 {
171                         if (intf->data_bits == 16)
172                         {
173                                 eeprom_data[2*address+0] = 0x00;
174                                 eeprom_data[2*address+1] = 0x00;
175                         }
176                         else
177                                 eeprom_data[address] = 0x00;
178                 }
179                 else
180                 serial_count = 0;
181         }
182         else if ( (serial_count > (intf->address_bits + intf->data_bits)) &&
183                    EEPROM_command_match((char*)serial_buffer,intf->cmd_write,(int)strlen((char*)serial_buffer)-(intf->address_bits + intf->data_bits)) )
184         {
185                 int i,address,data;
186
187                 address = 0;
188                 for (i = serial_count-intf->data_bits-intf->address_bits;i < (serial_count-intf->data_bits);i++)
189                 {
190                         address <<= 1;
191                         if (serial_buffer[i] == '1') address |= 1;
192                 }
193                 data = 0;
194                 for (i = serial_count-intf->data_bits;i < serial_count;i++)
195                 {
196                         data <<= 1;
197                         if (serial_buffer[i] == '1') data |= 1;
198                 }
199                 if (locked == 0)
200                 {
201                         if (intf->data_bits == 16)
202                         {
203                                 eeprom_data[2*address+0] = data >> 8;
204                                 eeprom_data[2*address+1] = data & 0xff;
205                         }
206                         else
207                                 eeprom_data[address] = data;
208                 }
209                 else
210                 serial_count = 0;
211         }
212         else if ( EEPROM_command_match((char*)serial_buffer,intf->cmd_lock,(int)strlen((char*)serial_buffer)) )
213         {
214                 locked = 1;
215                 serial_count = 0;
216         }
217         else if ( EEPROM_command_match((char*)serial_buffer,intf->cmd_unlock,(int)strlen((char*)serial_buffer)) )
218         {
219                 locked = 0;
220                 serial_count = 0;
221         }
222 }
223
224 static void EEPROM_reset()
225 {
226         serial_count = 0;
227         sending = 0;
228         reset_delay = intf->reset_delay;
229 }
230
231 void EEPROM_set_cs_line(int state)
232 {
233         reset_line = state;
234
235         if (reset_line != CLEAR_LINE)
236                 EEPROM_reset();
237 }
238
239 void EEPROM_set_clock_line(int state)
240 {
241         if (state == PULSE_LINE || (clock_line == CLEAR_LINE && state != CLEAR_LINE))
242         {
243                 if (reset_line == CLEAR_LINE)
244                 {
245                         if (sending)
246                         {
247                                 if (eeprom_clock_count == intf->data_bits)
248                                 {
249                                         if(intf->enable_multi_read)
250                                         {
251                                                 eeprom_read_address = (eeprom_read_address + 1) & ((1 << intf->address_bits) - 1);
252                                                 if (intf->data_bits == 16)
253                                                         eeprom_data_bits = (eeprom_data[2*eeprom_read_address+0] << 8) + eeprom_data[2*eeprom_read_address+1];
254                                                 else
255                                                         eeprom_data_bits = eeprom_data[eeprom_read_address];
256                                                 eeprom_clock_count = 0;
257                                         }
258                                         else
259                                         {
260                                                 sending = 0;
261                                         }
262                                 }
263                                 eeprom_data_bits = (eeprom_data_bits << 1) | 1;
264                                 eeprom_clock_count++;
265                         }
266                         else
267                                 EEPROM_write(latch);
268                 }
269         }
270
271         clock_line = state;
272 }
273
274
275 void EEPROM_write_bit(int bit)
276 {
277         latch = bit;
278 }
279
280 int EEPROM_read_bit(void)
281 {
282         int res;
283
284         if (sending)
285                 res = (eeprom_data_bits >> intf->data_bits) & 1;
286         else
287         {
288                 if (reset_delay > 0)
289                 {
290                         reset_delay--;
291                         res = 0;
292                 }
293                 else
294                         res = 1;
295         }
296
297         return res;
298 }
299 */
300
301 static void Sync(void)
302 {
303   setprg8r(0x10,0x6000,0);
304   setprg32(0x8000,(reg[0]<<4)|(reg[1]&0xF));
305   setchr8(0);
306 }
307
308 static void StateRestore(int version)
309 {
310   WSync();
311 }
312
313 static DECLFR(ReadLow)
314 {
315   switch (A&0x7700)
316   {
317     case 0x5100: return reg[2]|reg[0]|reg[1]|reg[3]^0xff; break;
318     case 0x5500: if(trigger)
319                    return reg[2]|reg[1]; // Lei Dian Huang Bi Ka Qiu Chuan Shuo (NJ046) may broke other games
320                  else
321                    return 0;
322   }
323   return 4;
324 }
325
326 static void M163HB(void)
327 {
328     if(reg[1]&0x80)
329     {
330       if(scanline==239)
331       {
332         setchr4(0x0000,0);
333         setchr4(0x1000,0);
334       }
335       else if(scanline==127)
336       {
337         setchr4(0x0000,1);
338         setchr4(0x1000,1);
339       }
340 /*
341       if(scanline>=127)     // Hu Lu Jin Gang (NJ039) (Ch) [!] don't like it
342       {
343         setchr4(0x0000,1);
344         setchr4(0x1000,1);
345       }
346       else
347       {
348         setchr4(0x0000,0);
349         setchr4(0x1000,0);
350       }
351 */      
352     }
353 }
354
355 static DECLFW(Write)
356 {
357   switch (A&0x7300)
358   {
359     case 0x5100: reg[0]=V; WSync(); break;
360     case 0x5000: reg[1]=V; WSync(); break;
361     case 0x5300: reg[2]=V; break;
362     case 0x5200: reg[3]=V; WSync(); break;
363   }
364 }
365
366 static void Power(void)
367 {
368   memset(reg,0,8);
369   reg[1]=0xFF;
370   SetWriteHandler(0x5000,0x5FFF,Write);
371   SetReadHandler(0x6000,0xFFFF,CartBR);
372   SetWriteHandler(0x6000,0x7FFF,CartBW);
373   WSync();
374 }
375
376 static void Close(void)
377 {
378   if(WRAM)
379     FCEU_gfree(WRAM);
380   WRAM=NULL;
381 }
382
383 void Mapper164_Init(CartInfo *info)
384 {
385   info->Power=Power;
386   info->Close=Close;
387   WSync = Sync;
388
389   WRAMSIZE = 8192;
390   WRAM=(uint8*)FCEU_gmalloc(WRAMSIZE);
391   SetupCartPRGMapping(0x10,WRAM,WRAMSIZE,1);
392   AddExState(WRAM, WRAMSIZE, 0, "WRAM");
393
394   if(info->battery)
395   {
396     info->SaveGame[0]=WRAM;
397     info->SaveGameLen[0]=WRAMSIZE;
398   }
399
400   GameStateRestore=StateRestore;
401   AddExState(&StateRegs, ~0, 0, 0);
402 }
403
404 static DECLFW(Write2)
405 {
406   if(A==0x5101)
407   {
408     if(laststrobe&&!V)
409     {
410       trigger^=1;
411     }
412     laststrobe=V;
413   }else if(A==0x5100&&V==6) //damn thoose protected games
414     setprg32(0x8000,3);
415   else
416   switch (A&0x7300)
417   {
418     case 0x5200: reg[0]=V; WSync(); break;
419     case 0x5000: reg[1]=V; WSync(); if(!(reg[1]&0x80)&&(scanline<128)) setchr8(0); /* setchr8(0); */ break;
420     case 0x5300: reg[2]=V; break;
421     case 0x5100: reg[3]=V; WSync(); break;
422   }
423 }
424
425 static void Power2(void)
426 {
427   memset(reg,0,8);
428   laststrobe=1;
429   SetReadHandler(0x5000,0x5FFF,ReadLow);
430   SetWriteHandler(0x5000,0x5FFF,Write2);
431   SetReadHandler(0x6000,0xFFFF,CartBR);
432   SetWriteHandler(0x6000,0x7FFF,CartBW);
433   WSync();
434 }
435
436 void Mapper163_Init(CartInfo *info)
437 {
438   info->Power=Power2;
439   info->Close=Close;
440   WSync = Sync;
441   GameHBIRQHook=M163HB;
442
443   WRAMSIZE = 8192;
444   WRAM=(uint8*)FCEU_gmalloc(WRAMSIZE);
445   SetupCartPRGMapping(0x10,WRAM,WRAMSIZE,1);
446   AddExState(WRAM, WRAMSIZE, 0, "WRAM");
447
448   if(info->battery)
449   {
450     info->SaveGame[0]=WRAM;
451     info->SaveGameLen[0]=WRAMSIZE;
452   }
453   GameStateRestore=StateRestore;
454   AddExState(&StateRegs, ~0, 0, 0);
455 }
456
457 static void Sync3(void)
458 {
459   setchr8(0);
460   setprg8r(0x10,0x6000,0);
461   switch(reg[3]&7){
462     case 0:
463     case 2: setprg32(0x8000,(reg[0]&0xc)|(reg[1]&2)|((reg[2]&0xf)<<4)); break;
464     case 1:
465     case 3: setprg32(0x8000,(reg[0]&0xc)|(reg[2]&0xf)<<4); break;
466     case 4: 
467     case 6: setprg32(0x8000,(reg[0]&0xe)|((reg[1]>>1)&1)|((reg[2]&0xf)<<4)); break;
468     case 5:
469     case 7: setprg32(0x8000,(reg[0]&0xf)|((reg[2]&0xf)<<4)); break;
470   }
471 }
472
473 static DECLFW(Write3)
474 {
475 //  FCEU_printf("bs %04x %02x\n",A,V);
476   reg[(A>>8)&3]=V;
477   WSync();
478 }
479
480 static void Power3(void)
481 {
482   reg[0]=3;
483   reg[1]=0;
484   reg[2]=0;
485   reg[3]=7;
486   SetWriteHandler(0x5000,0x5FFF,Write3);
487   SetReadHandler(0x6000,0xFFFF,CartBR);
488   SetWriteHandler(0x6000,0x7FFF,CartBW);
489   WSync();
490 }
491
492 void UNLFS304_Init(CartInfo *info)
493 {
494   info->Power=Power3;
495   info->Close=Close;
496   WSync = Sync3;
497   
498   WRAMSIZE = 8192;
499   WRAM=(uint8*)FCEU_gmalloc(WRAMSIZE);
500   SetupCartPRGMapping(0x10,WRAM,WRAMSIZE,1);
501   AddExState(WRAM, WRAMSIZE, 0, "WRAM");
502
503   if(info->battery)
504   {
505     info->SaveGame[0]=WRAM;
506     info->SaveGameLen[0]=WRAMSIZE;
507   }
508   
509   GameStateRestore=StateRestore;
510   AddExState(&StateRegs, ~0, 0, 0);
511 }