more menu work, scalers, sound
[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
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
21#include "mapinc.h"
22
23static int is209;
24
25static uint8 IRQMode; // from $c001
26static uint8 IRQPre; // from $c004
27static uint8 IRQPreSize; // from $c007
28static uint8 IRQCount; // from $c005
29static uint8 IRQXOR; // Loaded from $C006
30static uint8 IRQa; // $c002, $c003, and $c000
31
32static uint8 mul[2];
33static uint8 regie;
34
35static uint8 tkcom[4];
36static uint8 prgb[4];
37static uint8 chrlow[8];
38static uint8 chrhigh[8];
39
40static uint16 names[4];
41static uint8 tekker;
42
43static SFORMAT Tek_StateRegs[]={
44 {&IRQMode, 1, "IRQMODE"},
45 {&IRQPre, 1, "IRQPRE"},
46 {&IRQPreSize, 1, "IRQPRESIZE"},
47 {&IRQCount, 1, "IRQC"},
48 {&IRQXOR, 1, "IRQXOR"},
49 {&IRQa, 1, "IRQa"},
50 {mul, 2, "MUL"},
51 {&regie, 1, "REGI"},
52 {tkcom, 4, "TKCO"},
53 {prgb, 4, "PRGB"},
54 {chrlow, 4, "CHRL"},
55 {chrhigh, 8, "CHRH"},
56 {&names[0], 2|FCEUSTATE_RLSB, "NMS0"},
57 {&names[1], 2|FCEUSTATE_RLSB, "NMS1"},
58 {&names[2], 2|FCEUSTATE_RLSB, "NMS2"},
59 {&names[3], 2|FCEUSTATE_RLSB, "NMS3"},
60 {&tekker, 1, "TEKR"},
61 {0}
62};
63
64static DECLFR(M90Read)
65{
66 switch(A)
67 {
68 case 0x5800: return (mul[0]*mul[1]);
69 case 0x5801: return((mul[0]*mul[1])>>8);
70 case 0x5803: return (regie);
71 default: return(tekker);
72 }
73}
74
75static void mira(void)
76{
77 if(tkcom[0]&0x20 && is209)
78 {
79 int x;
80 if(tkcom[0]&0x40) // Name tables are ROM-only
81 {
82 for(x=0;x<4;x++)
83 setntamem(CHRptr[0]+(((names[x])&CHRmask1[0])<<10),0,x);
84 }
85 else // Name tables can be RAM or ROM.
86 {
87 for(x=0;x<4;x++)
88 {
89 if((tkcom[2]&0x80)==(names[x]&0x80)) // RAM selected.
90 setntamem(NTARAM+((names[x]&0x1)<<10),1,x);
91 else
92 setntamem(CHRptr[0]+(((names[x])&CHRmask1[0])<<10),0,x);
93 }
94 }
95 }
96 else
97 {
98 switch(tkcom[1]&3)
99 {
100 case 0: setmirror(MI_V); break;
101 case 1: setmirror(MI_H); break;
102 case 2: setmirror(MI_0); break;
103 case 3: setmirror(MI_1); break;
104 }
105 }
106}
107
108static void tekprom(void)
109{
110 uint32 bankmode=((tkcom[3]&6)<<5);
111 switch(tkcom[0]&3)
112 {
113 case 1: // 16 KB
114 setprg16(0x8000,(prgb[0]&0x1F)|((tkcom[3]&6)<<4));
115 setprg16(0xC000,(prgb[2]&0x1F)|((tkcom[3]&6)<<4));
116 break;
117 case 2: //2 = 8 KB ??
118 if(tkcom[0]&0x4)
119 {
120 setprg8(0x8000,(prgb[0]&0x3F)|bankmode);
121 setprg8(0xa000,(prgb[1]&0x3F)|bankmode);
122 setprg8(0xc000,(prgb[2]&0x3F)|bankmode);
123 setprg8(0xe000,(prgb[3]&0x3F)|bankmode);
124 }
125 else
126 {
127 if(tkcom[0]&0x80)
128 setprg8(0x6000,(prgb[3]&0x3F)|bankmode);
129 setprg8(0x8000,(prgb[0]&0x3F)|bankmode);
130 setprg8(0xa000,(prgb[1]&0x3F)|bankmode);
131 setprg8(0xc000,(prgb[2]&0x3F)|bankmode);
132 setprg8(0xe000,((~0)&0x3F)|bankmode);
133 }
134 break;
135 case 0:
136 case 3:
137 setprg8(0x8000,(prgb[0]&0x3F)|bankmode);
138 setprg8(0xa000,(prgb[1]&0x3F)|bankmode);
139 setprg8(0xc000,(prgb[2]&0x3F)|bankmode);
140 setprg8(0xe000,(prgb[3]&0x3F)|bankmode);
141 break;
142 }
143}
144
145static void tekvrom(void)
146{
147 int x, bank=0, mask=0xFFFF;
148 if(!(tkcom[3]&0x20))
149 {
150 bank=(tkcom[3]&1)|((tkcom[3]&0x18)>>2);
151 switch (tkcom[0]&0x18)
152 {
153 case 0x00: bank<<=5; mask=0x1F; break;
154 case 0x08: bank<<=6; mask=0x3F; break;
155 case 0x10: bank<<=7; mask=0x7F; break;
156 case 0x18: bank<<=8; mask=0xFF; break;
157 }
158 }
159 switch(tkcom[0]&0x18)
160 {
161 case 0x00: // 8KB
162 setchr8(((chrlow[0]|(chrhigh[0]<<8))&mask)|bank);
163 break;
164 case 0x08: // 4KB
165 for(x=0;x<8;x+=4)
166 setchr4(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank);
167 break;
168 case 0x10: // 2KB
169 for(x=0;x<8;x+=2)
170 setchr2(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank);
171 break;
172 case 0x18: // 1KB
173 for(x=0;x<8;x++)
174 setchr1(x<<10,((chrlow[x]|(chrhigh[x]<<8))&mask)|bank);
175 break;
176 }
177}
178
179static DECLFW(M90Write)
180{
181 if(A==0x5800) mul[0]=V;
182 else if(A==0x5801) mul[1]=V;
183 else if(A==0x5803) regie=V;
184
185 A&=0xF007;
186 if(A>=0x8000 && A<=0x8003)
187 {
188 prgb[A&3]=V;
189 tekprom();
190 }
191 else if(A>=0x9000 && A<=0x9007)
192 {
193 chrlow[A&7]=V;
194 tekvrom();
195 }
196 else if(A>=0xa000 && A<=0xa007)
197 {
198 chrhigh[A&7]=V;
199 tekvrom();
200 }
201 else if(A>=0xb000 && A<=0xb007)
202 {
203 if(A&4)
204 {
205 names[A&3]&=0x00FF;
206 names[A&3]|=V<<8;
207 }
208 else
209 {
210 names[A&3]&=0xFF00;
211 names[A&3]|=V;
212 }
213 mira();
214 }
215 else if(A>=0xd000 && A<=0xdfff)
216 {
217 tkcom[A&3]=V;
218 tekprom();
219 tekvrom();
220 mira();
221/*
222 switch (A&3)
223 {
224 case 00: FCEU_printf("Main Control Register:\n");
225 FCEU_printf(" PGR Banking mode: %d\n",V&7);
226 FCEU_printf(" CHR Banking mode: %d\n",(V>>3)&3);
227 FCEU_printf(" 6000-7FFF addresses mapping: %s\n",(V&0x80)?"Yes":"No");
228 FCEU_printf(" Nametable control: %s\n",(V&0x20)?"Enabled":"Disabled");
229 if(V&0x20)
230 FCEU_printf(" Nametable can be: %s\n",(V&0x40)?"ROM Only":"RAM or ROM");
231 break;
232 case 01: FCEU_printf("Mirroring mode: ");
233 switch (V&3)
234 {
235 case 00: FCEU_printf("Vertical\n");break;
236 case 01: FCEU_printf("Horizontal\n");break;
237 case 02: FCEU_printf("Nametable 0 only\n");break;
238 case 03: FCEU_printf("Nametable 1 only\n");break;
239 }
240 FCEU_printf("Mirroring flag: %s\n",(V&0x80)?"On":"Off");
241 break;
242 case 02: if((((tkcom[0])>>5)&3)==1)
243 FCEU_printf("Nametable ROM/RAM select mode: %d\n",V>>7);
244 break;
245 case 03:
246 FCEU_printf("CHR Banking mode: %s\n",(V&0x20)?"Entire CHR ROM":"256Kb Switching mode");
247 if(!(V&0x20)) FCEU_printf("256K CHR bank number: %02x\n",(V&1)|((V&0x18)>>2));
248 FCEU_printf("512K PRG bank number: %d\n",(V&6)>>1);
249 FCEU_printf("CHR Bank mirroring: %s\n",(V&0x80)?"Swapped":"Normal operate");
250 }
251*/
252 }
253 else switch(A)
254 {
255 case 0xc000: //FCEU_printf("%s IRQ (C000)\n",V&1?"Enable":"Disable");
256 IRQa=V&1;if(!(V&1)) X6502_IRQEnd(FCEU_IQEXT);break;
257 case 0xc002: //FCEU_printf("Disable IRQ (C002) scanline=%d\n", scanline);
258 IRQa=0;X6502_IRQEnd(FCEU_IQEXT);break;
259 case 0xc003: //FCEU_printf("Enable IRQ (C003) scanline=%d\n", scanline);
260 IRQa=1;break;
261 case 0xc001: IRQMode=V;
262/* FCEU_printf("IRQ Count method: ");
263 switch (IRQMode&3)
264 {
265 case 00: FCEU_printf("M2 cycles\n");break;
266 case 01: FCEU_printf("PPU A12 toggles\n");break;
267 case 02: FCEU_printf("PPU reads\n");break;
268 case 03: FCEU_printf("Writes to CPU space\n");break;
269 }
270 FCEU_printf("Counter prescaler size: %s\n",(IRQMode&4)?"3 bits":"8 bits");
271 FCEU_printf("Counter prescaler size adjust: %s\n",(IRQMode&8)?"Used C007":"Normal Operation");
272 if((IRQMode>>6)==2) FCEU_printf("Counter Down\n");
273 else if((IRQMode>>6)==1) FCEU_printf("Counter Up\n");
274 else FCEU_printf("Counter Stopped\n");
275*/ break;
276 case 0xc004: //FCEU_printf("Pre Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR);
277 IRQPre=V^IRQXOR;break;
278 case 0xc005: //FCEU_printf("Main Counter Loaded and Xored wiht C006: %d\n",V^IRQXOR);
279 IRQCount=V^IRQXOR;break;
280 case 0xc006: //FCEU_printf("Xor Value: %d\n",V);
281 IRQXOR=V;break;
282 case 0xc007: //if(!(IRQMode&8)) FCEU_printf("C001 is clear, no effect applied\n");
283 // else if(V==0xFF) FCEU_printf("Prescaler is changed for 12bits\n");
284 // else FCEU_printf("Counter Stopped\n");
285 IRQPreSize=V;break;
286 }
287}
288
289static void CCL(void)
290{
291 if((IRQMode>>6) == 1) // Count Up
292 {
293 IRQCount++;
294 if((IRQCount == 0) && IRQa)
295 X6502_IRQBegin(FCEU_IQEXT);
296 }
297 else if((IRQMode>>6) == 2) // Count down
298 {
299 IRQCount--;
300 if((IRQCount == 0xFF) && IRQa)
301 X6502_IRQBegin(FCEU_IQEXT);
302 }
303}
304
305static void ClockCounter(void)
306{
307 uint8 premask;
308
309 if(IRQMode & 0x4)
310 premask = 0x7;
311 else
312 premask = 0xFF;
313 if((IRQMode>>6) == 1) // Count up
314 {
315 IRQPre++;
316 if((IRQPre & premask) == 0) CCL();
317 }
318 else if((IRQMode>>6) == 2) // Count down
319 {
320 IRQPre--;
321 if((IRQPre & premask) == premask) CCL();
322 }
323}
324
325static void SLWrap(void)
326{
327 int x;
328 if((IRQMode&3)!=2) for(x=0;x<8;x++) ClockCounter();
329}
330
331static uint32 lastread;
332static void FP_FASTAPASS(1) M90PPU(uint32 A)
333{
334 if(lastread!=A)
335 {
336 lastread=A;
337 if((IRQMode&3)==2)
338 {
339 ClockCounter();
340 ClockCounter();
341 }
342 }
343}
344
345static void togglie()
346{
347 tekker>>=6;
348 if(tekker>3)
349 tekker=0;
350 else
351 tekker++;
352 tekker<<=6;
353 FCEU_printf("tekker=%04x\n",tekker);
354 memset(tkcom,0xff,sizeof(tkcom));
355 memset(prgb,0xff,sizeof(prgb));
356 tekprom();
357 tekvrom();
358}
359
360static void M90Restore(int version)
361{
362 tekprom();
363 tekvrom();
364 mira();
365}
366
367static void M90Power(void)
368{
369 SetWriteHandler(0x5000,0xffff,M90Write);
370 SetReadHandler(0x5000,0x5fff,M90Read);
371 SetReadHandler(0x6000,0xffff,CartBR);
372
373 mul[0]=mul[1]=regie=0xFF;
374
375 memset(tkcom,0xff,sizeof(tkcom));
376 memset(prgb,0xff,sizeof(prgb));
377 memset(chrlow,0xff,sizeof(chrlow));
378 memset(chrhigh,0xff,sizeof(chrhigh));
379 memset(names,0x00,sizeof(names));
380
381 tekker=0;
382
383 tekprom();
384 tekvrom();
385}
386
387
388void Mapper90_Init(CartInfo *info)
389{
390 is209=0;
391 info->Reset=togglie;
392 info->Power=M90Power;
393 PPU_hook = M90PPU;
394 GameHBIRQHook2 = SLWrap;
395 GameStateRestore=M90Restore;
396 AddExState(Tek_StateRegs, ~0, 0, 0);
397}
398
399void Mapper209_Init(CartInfo *info)
400{
401 is209=1;
402 info->Reset=togglie;
403 info->Power=M90Power;
404 PPU_hook = M90PPU;
405 GameHBIRQHook2 = SLWrap;
406 GameStateRestore=M90Restore;
407 AddExState(Tek_StateRegs, ~0, 0, 0);
408}