~ubuntu-branches/ubuntu/lucid/fceux/lucid

« back to all changes in this revision

Viewing changes to fceu/src/boards/90.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Fabrice Coutadeur
  • Date: 2009-12-14 08:05:17 UTC
  • Revision ID: james.westby@ubuntu.com-20091214080517-abi5tj8avthfan7c
Tags: upstream-2.1.2+repack
ImportĀ upstreamĀ versionĀ 2.1.2+repack

Show diffs side-by-side

added added

removed removed

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