994910d7952611f057a0ffef106f78cc7c84c1da
[fceu.git] / boards / 90.c
1 /* FCE Ultra - NES/Famicom Emulator
2  *
3  * Copyright notice for this file:
4  *  Copyright (C) 2002 Xodnizel
5  *  Copyright (C) 2005 CaH4e3
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "mapinc.h"
23 //#define DEBUG90
24
25 static int is209;
26 static int is211;
27
28 static uint8 IRQMode;        // from $c001
29 static uint8 IRQPre;         // from $c004
30 static uint8 IRQPreSize;     // from $c007
31 static uint8 IRQCount;       // from $c005
32 static uint8 IRQXOR;         // Loaded from $C006
33 static uint8 IRQa;           // $c002, $c003, and $c000
34
35 static uint8 mul[2];
36 static uint8 regie;
37
38 static uint8 tkcom[4];
39 static uint8 prgb[4];
40 static uint8 chrlow[8];
41 static uint8 chrhigh[8];
42
43 static uint16 names[4];
44 static uint8 tekker;
45
46 static SFORMAT Tek_StateRegs[]={
47   {&IRQMode, 1, "IRQMODE"},
48   {&IRQPre, 1, "IRQPRE"},
49   {&IRQPreSize, 1, "IRQPRESIZE"},
50   {&IRQCount, 1, "IRQC"},
51   {&IRQXOR, 1, "IRQXOR"},
52   {&IRQa, 1, "IRQa"},
53   {mul, 2, "MUL"},
54   {&regie, 1, "REGI"},
55   {tkcom, 4, "TKCO"},
56   {prgb, 4, "PRGB"},
57   {chrlow, 4, "CHRL"},
58   {chrhigh, 8, "CHRH"},
59   {&names[0], 2|FCEUSTATE_RLSB, "NMS0"},
60   {&names[1], 2|FCEUSTATE_RLSB, "NMS1"},
61   {&names[2], 2|FCEUSTATE_RLSB, "NMS2"},
62   {&names[3], 2|FCEUSTATE_RLSB, "NMS3"},
63   {&tekker, 1, "TEKR"},
64   {0}
65 };
66
67 static void mira(void)
68 {
69   if((tkcom[0]&0x20&&is209)||is211)
70   {
71     int x;
72     if(tkcom[0]&0x40)        // Name tables are ROM-only
73     {
74       for(x=0;x<4;x++)
75          setntamem(CHRptr[0]+(((names[x])&CHRmask1[0])<<10),0,x);
76     }
77     else                        // Name tables can be RAM or ROM.
78     {
79       for(x=0;x<4;x++)
80       {
81         if((tkcom[1]&0x80)==(names[x]&0x80))        // RAM selected.
82           setntamem(NTARAM+((names[x]&0x1)<<10),1,x);
83         else
84           setntamem(CHRptr[0]+(((names[x])&CHRmask1[0])<<10),0,x);
85       }
86     }
87   }
88   else
89   {
90     switch(tkcom[1]&3)
91     {
92       case 0: setmirror(MI_V); break;
93       case 1: setmirror(MI_H); break;
94       case 2: setmirror(MI_0); break;
95       case 3: setmirror(MI_1); break;
96     }
97   }
98 }
99
100 static void tekprom(void)
101 {
102   uint32 bankmode=((tkcom[3]&6)<<5);
103   switch(tkcom[0]&7)
104   {
105     case 00: if(tkcom[0]&0x80)
106                setprg8(0x6000,(((prgb[3]<<2)+3)&0x3F)|bankmode);
107              setprg32(0x8000,0x0F|((tkcom[3]&6)<<3));
108              break;
109     case 01: if(tkcom[0]&0x80)
110                setprg8(0x6000,(((prgb[3]<<1)+1)&0x3F)|bankmode);
111              setprg16(0x8000,(prgb[1]&0x1F)|((tkcom[3]&6)<<4));
112              setprg16(0xC000,0x1F|((tkcom[3]&6)<<4));
113              break;
114     case 03: // bit reversion
115     case 02: if(tkcom[0]&0x80)
116                setprg8(0x6000,(prgb[3]&0x3F)|bankmode);
117              setprg8(0x8000,(prgb[0]&0x3F)|bankmode);
118              setprg8(0xa000,(prgb[1]&0x3F)|bankmode);
119              setprg8(0xc000,(prgb[2]&0x3F)|bankmode);
120              setprg8(0xe000,0x3F|bankmode);
121              break;
122     case 04: if(tkcom[0]&0x80)
123                setprg8(0x6000,(((prgb[3]<<2)+3)&0x3F)|bankmode);
124              setprg32(0x8000,(prgb[3]&0x0F)|((tkcom[3]&6)<<3));
125              break;
126     case 05: if(tkcom[0]&0x80)
127                setprg8(0x6000,(((prgb[3]<<1)+1)&0x3F)|bankmode);
128              setprg16(0x8000,(prgb[1]&0x1F)|((tkcom[3]&6)<<4));
129              setprg16(0xC000,(prgb[3]&0x1F)|((tkcom[3]&6)<<4));
130              break;
131     case 07: // bit reversion
132     case 06: if(tkcom[0]&0x80)
133                setprg8(0x6000,(prgb[3]&0x3F)|bankmode);
134              setprg8(0x8000,(prgb[0]&0x3F)|bankmode);
135              setprg8(0xa000,(prgb[1]&0x3F)|bankmode);
136              setprg8(0xc000,(prgb[2]&0x3F)|bankmode);
137              setprg8(0xe000,(prgb[3]&0x3F)|bankmode);
138              break;
139   }
140 }
141
142 static void tekvrom(void)
143 {
144   int x, bank=0, mask=0xFFFF;
145   if(!(tkcom[3]&0x20))
146   {
147     bank=(tkcom[3]&1)|((tkcom[3]&0x18)>>2);
148     switch (tkcom[0]&0x18)
149     {
150       case 0x00: bank<<=5; mask=0x1F; break;
151       case 0x08: bank<<=6; mask=0x3F; break;
152       case 0x10: bank<<=7; mask=0x7F; break;
153       case 0x18: bank<<=8; mask=0xFF; break;
154     }
155   }
156   switch(tkcom[0]&0x18)
157   {
158     case 0x00:      // 8KB
159          setchr8(((chrlow[0]|(chrhigh[0]<<8))&mask)|bank);
160          break;
161     case 0x08:      // 4KB
162          for(x=0;x<8;x+=4)
163             setchr4(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank);
164          break;
165     case 0x10:      // 2KB
166          for(x=0;x<8;x+=2)
167             setchr2(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank);
168          break;
169     case 0x18:      // 1KB
170          for(x=0;x<8;x++)
171             setchr1(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank);
172          break;
173   }
174 }
175
176 static DECLFW(M90TekWrite)
177 {
178   switch(A)
179   {
180     case 0x5800: mul[0]=V; break;
181     case 0x5801: mul[1]=V; break;
182     case 0x5803: regie=V; break;
183   }
184 }
185
186 static DECLFR(M90TekRead)
187 {
188   switch(A)
189   {
190     case 0x5800: return (mul[0]*mul[1]);
191     case 0x5801: return((mul[0]*mul[1])>>8);
192     case 0x5803: return (regie);
193   }
194   return(tekker);
195 }
196
197 static DECLFW(M90PRGWrite)
198 {
199   prgb[A&3]=V;
200   tekprom();
201 }
202
203 static DECLFW(M90CHRlowWrite)
204 {
205   chrlow[A&7]=V;
206   tekvrom();
207 }
208
209 static DECLFW(M90CHRhiWrite)
210 {
211   chrhigh[A&7]=V;
212   tekvrom();
213 }
214
215 static DECLFW(M90NTWrite)
216 {
217   if(A&4)
218   {
219     names[A&3]&=0x00FF;
220     names[A&3]|=V<<8;
221   }
222   else
223   {
224     names[A&3]&=0xFF00;
225     names[A&3]|=V;
226   }
227   mira();
228 }
229
230 static DECLFW(M90IRQWrite)
231 {
232   switch(A&7)
233   {
234     case 00: //FCEU_printf("%s IRQ (C000)\n",V&1?"Enable":"Disable");
235              IRQa=V&1;if(!(V&1)) X6502_IRQEnd(FCEU_IQEXT);break;
236     case 02: //FCEU_printf("Disable IRQ (C002) scanline=%d\n", scanline);
237              IRQa=0;X6502_IRQEnd(FCEU_IQEXT);break;
238     case 03: //FCEU_printf("Enable IRQ (C003) scanline=%d\n", scanline);
239              IRQa=1;break;
240     case 01: IRQMode=V;
241 /*               FCEU_printf("IRQ Count method: ");
242                switch (IRQMode&3)
243                {
244                  case 00: FCEU_printf("M2 cycles\n");break;
245                  case 01: FCEU_printf("PPU A12 toggles\n");break;
246                  case 02: FCEU_printf("PPU reads\n");break;
247                  case 03: FCEU_printf("Writes to CPU space\n");break;
248                }
249                FCEU_printf("Counter prescaler size: %s\n",(IRQMode&4)?"3 bits":"8 bits");
250                FCEU_printf("Counter prescaler size adjust: %s\n",(IRQMode&8)?"Used C007":"Normal Operation");
251                if((IRQMode>>6)==2) FCEU_printf("Counter Down\n");
252                 else if((IRQMode>>6)==1) FCEU_printf("Counter Up\n");
253                 else FCEU_printf("Counter Stopped\n");
254 */               break;
255     case 04: //FCEU_printf("Pre Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR);
256              IRQPre=V^IRQXOR;break;
257     case 05: //FCEU_printf("Main Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR);
258              IRQCount=V^IRQXOR;break;
259     case 06: //FCEU_printf("Xor Value: %d\n",V);
260              IRQXOR=V;break;
261     case 07: //if(!(IRQMode&8)) FCEU_printf("C001 is clear, no effect applied\n");
262                  // else if(V==0xFF) FCEU_printf("Prescaler is changed for 12bits\n");
263                  // else FCEU_printf("Counter Stopped\n");
264              IRQPreSize=V;break;
265   }
266 }
267
268 static DECLFW(M90ModeWrite)
269 {
270     tkcom[A&3]=V;
271     tekprom();
272     tekvrom();
273     mira();
274     
275 #ifdef DEBUG90
276   switch (A&3)
277   {
278    case 00: FCEU_printf("Main Control Register:\n");
279             FCEU_printf("  PGR Banking mode: %d\n",V&7);
280             FCEU_printf("  CHR Banking mode: %d\n",(V>>3)&3);
281             FCEU_printf("  6000-7FFF addresses mapping: %s\n",(V&0x80)?"Yes":"No");
282             FCEU_printf("  Nametable control: %s\n",(V&0x20)?"Enabled":"Disabled");
283             if(V&0x20)
284                FCEU_printf("  Nametable can be: %s\n",(V&0x40)?"ROM Only":"RAM or ROM");
285             break;
286    case 01: FCEU_printf("Mirroring mode: ");
287             switch (V&3)
288             {
289              case 0: FCEU_printf("Vertical\n");break;
290              case 1: FCEU_printf("Horizontal\n");break;
291              case 2: FCEU_printf("Nametable 0 only\n");break;
292              case 3: FCEU_printf("Nametable 1 only\n");break;
293             }
294             FCEU_printf("Mirroring flag: %s\n",(V&0x80)?"On":"Off");
295             break;
296    case 02: if((((tkcom[0])>>5)&3)==1)
297               FCEU_printf("Nametable ROM/RAM select mode: %d\n",V>>7);
298             break;
299    case 03:
300             FCEU_printf("CHR Banking mode: %s\n",(V&0x20)?"Entire CHR ROM":"256Kb Switching mode");
301             if(!(V&0x20)) FCEU_printf("256K CHR bank number: %02x\n",(V&1)|((V&0x18)>>2));
302             FCEU_printf("512K PRG bank number: %d\n",(V&6)>>1);
303             FCEU_printf("CHR Bank mirroring: %s\n",(V&0x80)?"Swapped":"Normal operate");
304   }
305 #endif
306 }
307
308 static void CCL(void)
309 {
310   if((IRQMode>>6) == 1) // Count Up
311   {
312     IRQCount++;
313     if((IRQCount == 0) && IRQa)
314     {
315       X6502_IRQBegin(FCEU_IQEXT);
316     }
317   }
318   else if((IRQMode>>6) == 2) // Count down
319   {
320     IRQCount--;
321     if((IRQCount == 0xFF) && IRQa)
322     {
323       X6502_IRQBegin(FCEU_IQEXT);
324     }
325   }
326 }
327
328 static void ClockCounter(void)
329 {
330   uint8 premask;
331
332   if(IRQMode & 0x4)
333     premask = 0x7;
334   else
335     premask = 0xFF;
336   if((IRQMode>>6) == 1) // Count up
337   {
338     IRQPre++;
339     if((IRQPre & premask) == 0) CCL();
340   }
341   else if((IRQMode>>6) == 2) // Count down
342   {
343     IRQPre--;
344     if((IRQPre & premask) == premask) CCL();
345   }
346 }
347
348 void FP_FASTAPASS(1) CPUWrap(int a)
349 {
350   int x;
351   if((IRQMode&3)==0) for(x=0;x<a;x++) ClockCounter();
352 }
353
354 static void SLWrap(void)
355 {
356   int x;
357   if((IRQMode&3)==1) for(x=0;x<8;x++) ClockCounter();
358 }
359
360 static uint32 lastread;
361 static void FP_FASTAPASS(1) M90PPU(uint32 A)
362 {
363   if((IRQMode&3)==2)
364   {
365     if(lastread!=A)
366     {
367       ClockCounter();
368       ClockCounter();
369     }
370     lastread=A;
371   }
372 //  else
373 //  {
374 //    if((!lastread)&&(A&0x1000))
375 //      ClockCounter();
376 //    lastread=A&0x1000;
377 //  }
378
379 }
380
381 static void togglie()
382 {
383   tekker>>=6;
384   if(tekker>3)
385     tekker=0;
386   else
387     tekker++;
388   tekker<<=6;
389   FCEU_printf("tekker=%04x\n",tekker);
390   memset(tkcom,0x00,sizeof(tkcom));
391   memset(prgb,0xff,sizeof(prgb));
392   tekprom();
393   tekvrom();
394 }
395
396 static void M90Restore(int version)
397 {
398   tekprom();
399   tekvrom();
400   mira();
401 }
402
403 static void M90Power(void)
404 {
405   SetWriteHandler(0x5000,0x5fff,M90TekWrite);
406   SetWriteHandler(0x8000,0x8fff,M90PRGWrite);
407   SetWriteHandler(0x9000,0x9fff,M90CHRlowWrite);
408   SetWriteHandler(0xA000,0xAfff,M90CHRhiWrite);
409   SetWriteHandler(0xB000,0xBfff,M90NTWrite);
410   SetWriteHandler(0xC000,0xCfff,M90IRQWrite);
411   SetWriteHandler(0xD000,0xDfff,M90ModeWrite);
412
413   SetReadHandler(0x5000,0x5fff,M90TekRead);
414   SetReadHandler(0x6000,0xffff,CartBR);
415
416   mul[0]=mul[1]=regie=0xFF;
417
418   memset(tkcom,0x00,sizeof(tkcom));
419   memset(prgb,0xff,sizeof(prgb));
420   memset(chrlow,0xff,sizeof(chrlow));
421   memset(chrhigh,0xff,sizeof(chrhigh));
422   memset(names,0x00,sizeof(names));
423
424   if(is211)
425     tekker=0xC0;
426   else
427     tekker=0x00;
428
429   tekprom();
430   tekvrom();
431 }
432
433
434 void Mapper90_Init(CartInfo *info)
435 {
436   is211=0;
437   is209=0;
438   info->Reset=togglie;
439   info->Power=M90Power;
440   PPU_hook=M90PPU;
441   GameHBIRQHook2=SLWrap;
442   MapIRQHook=CPUWrap;
443   GameStateRestore=M90Restore;
444   AddExState(Tek_StateRegs, ~0, 0, 0);
445 }
446
447 void Mapper209_Init(CartInfo *info)
448 {
449   is211=0;
450   is209=1;
451   info->Reset=togglie;
452   info->Power=M90Power;
453   GameHBIRQHook2=SLWrap;
454   GameStateRestore=M90Restore;
455   AddExState(Tek_StateRegs, ~0, 0, 0);
456 }
457
458 void Mapper211_Init(CartInfo *info)
459 {
460   is211=1;
461   info->Reset=togglie;
462   info->Power=M90Power;
463   GameHBIRQHook2=SLWrap;
464   GameStateRestore=M90Restore;
465   AddExState(Tek_StateRegs, ~0, 0, 0);
466 }