perfect vsync, bugfixes
[fceu.git] / boards / 90.c
CommitLineData
d97315ac 1/* FCE Ultra - NES/Famicom Emulator
2 *
3 * Copyright notice for this file:
4 * Copyright (C) 2002 Xodnizel
e2d0dd92 5 * Copyright (C) 2005 CaH4e3
d97315ac 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"
e2d0dd92 23//#define DEBUG90
d97315ac 24
25static int is209;
e2d0dd92 26static int is211;
d97315ac 27
28static uint8 IRQMode; // from $c001
29static uint8 IRQPre; // from $c004
30static uint8 IRQPreSize; // from $c007
31static uint8 IRQCount; // from $c005
32static uint8 IRQXOR; // Loaded from $C006
33static uint8 IRQa; // $c002, $c003, and $c000
34
35static uint8 mul[2];
36static uint8 regie;
37
38static uint8 tkcom[4];
39static uint8 prgb[4];
40static uint8 chrlow[8];
41static uint8 chrhigh[8];
42
43static uint16 names[4];
44static uint8 tekker;
45
46static 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
d97315ac 67static void mira(void)
68{
e2d0dd92 69 if((tkcom[0]&0x20&&is209)||is211)
d97315ac 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 {
e2d0dd92 81 if((tkcom[1]&0x80)==(names[x]&0x80)) // RAM selected.
d97315ac 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
100static void tekprom(void)
101{
102 uint32 bankmode=((tkcom[3]&6)<<5);
e2d0dd92 103 switch(tkcom[0]&7)
d97315ac 104 {
e2d0dd92 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;
d97315ac 139 }
140}
141
142static 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
e2d0dd92 176static DECLFW(M90TekWrite)
d97315ac 177{
e2d0dd92 178 switch(A)
d97315ac 179 {
e2d0dd92 180 case 0x5800: mul[0]=V; break;
181 case 0x5801: mul[1]=V; break;
182 case 0x5803: regie=V; break;
d97315ac 183 }
e2d0dd92 184}
185
186static DECLFR(M90TekRead)
187{
188 switch(A)
d97315ac 189 {
e2d0dd92 190 case 0x5800: return (mul[0]*mul[1]);
191 case 0x5801: return((mul[0]*mul[1])>>8);
192 case 0x5803: return (regie);
d97315ac 193 }
e2d0dd92 194 return(tekker);
195}
196
197static DECLFW(M90PRGWrite)
198{
199 prgb[A&3]=V;
200 tekprom();
201}
202
203static DECLFW(M90CHRlowWrite)
204{
205 chrlow[A&7]=V;
206 tekvrom();
207}
208
209static DECLFW(M90CHRhiWrite)
210{
211 chrhigh[A&7]=V;
212 tekvrom();
213}
214
215static DECLFW(M90NTWrite)
216{
217 if(A&4)
d97315ac 218 {
e2d0dd92 219 names[A&3]&=0x00FF;
220 names[A&3]|=V<<8;
d97315ac 221 }
e2d0dd92 222 else
d97315ac 223 {
e2d0dd92 224 names[A&3]&=0xFF00;
225 names[A&3]|=V;
d97315ac 226 }
e2d0dd92 227 mira();
228}
229
230static DECLFW(M90IRQWrite)
231{
232 switch(A&7)
d97315ac 233 {
e2d0dd92 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
268static DECLFW(M90ModeWrite)
269{
d97315ac 270 tkcom[A&3]=V;
271 tekprom();
272 tekvrom();
273 mira();
e2d0dd92 274
275#ifdef DEBUG90
d97315ac 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 {
e2d0dd92 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;
d97315ac 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 }
e2d0dd92 305#endif
d97315ac 306}
307
308static void CCL(void)
309{
310 if((IRQMode>>6) == 1) // Count Up
311 {
312 IRQCount++;
313 if((IRQCount == 0) && IRQa)
e2d0dd92 314 {
d97315ac 315 X6502_IRQBegin(FCEU_IQEXT);
e2d0dd92 316 }
d97315ac 317 }
318 else if((IRQMode>>6) == 2) // Count down
319 {
320 IRQCount--;
321 if((IRQCount == 0xFF) && IRQa)
e2d0dd92 322 {
d97315ac 323 X6502_IRQBegin(FCEU_IQEXT);
e2d0dd92 324 }
d97315ac 325 }
326}
327
328static 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
e2d0dd92 348void FP_FASTAPASS(1) CPUWrap(int a)
349{
350 int x;
351 if((IRQMode&3)==0) for(x=0;x<a;x++) ClockCounter();
352}
353
d97315ac 354static void SLWrap(void)
355{
356 int x;
e2d0dd92 357 if((IRQMode&3)==1) for(x=0;x<8;x++) ClockCounter();
d97315ac 358}
359
360static uint32 lastread;
361static void FP_FASTAPASS(1) M90PPU(uint32 A)
362{
e2d0dd92 363 if((IRQMode&3)==2)
d97315ac 364 {
e2d0dd92 365 if(lastread!=A)
d97315ac 366 {
367 ClockCounter();
368 ClockCounter();
369 }
e2d0dd92 370 lastread=A;
d97315ac 371 }
e2d0dd92 372// else
373// {
374// if((!lastread)&&(A&0x1000))
375// ClockCounter();
376// lastread=A&0x1000;
377// }
378
d97315ac 379}
380
381static 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);
e2d0dd92 390 memset(tkcom,0x00,sizeof(tkcom));
d97315ac 391 memset(prgb,0xff,sizeof(prgb));
392 tekprom();
393 tekvrom();
394}
395
396static void M90Restore(int version)
397{
398 tekprom();
399 tekvrom();
400 mira();
401}
402
403static void M90Power(void)
404{
e2d0dd92 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);
d97315ac 414 SetReadHandler(0x6000,0xffff,CartBR);
415
416 mul[0]=mul[1]=regie=0xFF;
417
e2d0dd92 418 memset(tkcom,0x00,sizeof(tkcom));
d97315ac 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
e2d0dd92 424 if(is211)
425 tekker=0xC0;
426 else
427 tekker=0x00;
d97315ac 428
429 tekprom();
430 tekvrom();
431}
432
433
434void Mapper90_Init(CartInfo *info)
435{
e2d0dd92 436 is211=0;
d97315ac 437 is209=0;
438 info->Reset=togglie;
439 info->Power=M90Power;
e2d0dd92 440 PPU_hook=M90PPU;
441 GameHBIRQHook2=SLWrap;
442 MapIRQHook=CPUWrap;
d97315ac 443 GameStateRestore=M90Restore;
444 AddExState(Tek_StateRegs, ~0, 0, 0);
445}
446
447void Mapper209_Init(CartInfo *info)
448{
e2d0dd92 449 is211=0;
d97315ac 450 is209=1;
451 info->Reset=togglie;
452 info->Power=M90Power;
e2d0dd92 453 GameHBIRQHook2=SLWrap;
454 GameStateRestore=M90Restore;
455 AddExState(Tek_StateRegs, ~0, 0, 0);
456}
457
458void Mapper211_Init(CartInfo *info)
459{
460 is211=1;
461 info->Reset=togglie;
462 info->Power=M90Power;
463 GameHBIRQHook2=SLWrap;
d97315ac 464 GameStateRestore=M90Restore;
465 AddExState(Tek_StateRegs, ~0, 0, 0);
466}