mapvrc.c
  1  /*
  2  ** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
  3  **
  4  **
  5  ** This program is free software; you can redistribute it and/or
  6  ** modify it under the terms of version 2 of the GNU Library General 
  7  ** Public License as published by the Free Software Foundation.
  8  **
  9  ** This program is distributed in the hope that it will be useful, 
 10  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 12  ** Library General Public License for more details.  To obtain a 
 13  ** copy of the GNU Library General Public License, write to the Free 
 14  ** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 15  **
 16  ** Any permitted reproduction of these routines, in whole or in part,
 17  ** must bear this legend.
 18  **
 19  **
 20  ** map_vrc.c
 21  **
 22  ** VRC mapper interface
 23  ** $Id: mapvrc.c,v 1.2 2001/04/27 14:37:11 neil Exp $
 24  */
 25  
 26  #include "noftypes.h"
 27  #include "nes_mmc.h"
 28  #include "nes.h"
 29  #include "log.h"
 30  
 31  #define VRC_VBANK(bank, value, high) \
 32  { \
 33     if ((high)) \
 34        highnybbles[(bank)] = (value) & 0x0F; \
 35     else \
 36        lownybbles[(bank)] = (value) & 0x0F; \
 37     mmc_bankvrom(1, (bank) << 10, (highnybbles[(bank)] << 4)+lownybbles[(bank)]); \
 38  }
 39  
 40  static struct
 41  {
 42     int counter, enabled;
 43     int latch, wait_state;
 44  } irq;
 45  
 46  static int select_c000 = 0;
 47  static uint8 lownybbles[8];
 48  static uint8 highnybbles[8];
 49  
 50  static void vrc_init(void)
 51  {
 52     irq.counter = irq.enabled = 0;
 53     irq.latch = irq.wait_state = 0;
 54  }
 55  
 56  static void map21_write(uint32 address, uint8 value)
 57  {
 58     switch (address)
 59     {
 60     case 0x8000:
 61        if (select_c000) 
 62           mmc_bankrom(8, 0xC000,value);
 63        else
 64           mmc_bankrom(8, 0x8000,value);
 65        break;
 66  
 67     case 0x9000:
 68        switch (value & 3)
 69        {
 70        case 0:
 71           ppu_mirror(0, 1, 0, 1); /* vertical */
 72           break;
 73  
 74        case 1: 
 75           ppu_mirror(0, 0, 1, 1); /* horizontal */
 76           break;
 77  
 78        case 2: 
 79           ppu_mirror(0, 0, 0, 0); 
 80           break;
 81  
 82        case 3: 
 83           ppu_mirror(1, 1, 1, 1); 
 84           break;
 85  
 86        default: 
 87           break;
 88        }
 89        break;
 90     case 0x9002: select_c000=(value&0x02)>>1; break;
 91     case 0xA000: mmc_bankrom(8, 0xA000,value); break;
 92  
 93     case 0xB000: VRC_VBANK(0,value,0); break;
 94     case 0xB002:
 95     case 0xB040: VRC_VBANK(0,value,1); break;
 96     case 0xB001:
 97     case 0xB004:
 98     case 0xB080: VRC_VBANK(1,value,0); break;
 99     case 0xB003:
100     case 0xB006:
101     case 0xB0C0: VRC_VBANK(1,value,1); break;
102     case 0xC000: VRC_VBANK(2,value,0); break;
103     case 0xC002:
104     case 0xC040: VRC_VBANK(2,value,1); break;
105     case 0xC001:
106     case 0xC004:
107     case 0xC080: VRC_VBANK(3,value,0); break;
108     case 0xC003:
109     case 0xC006:
110     case 0xC0C0: VRC_VBANK(3,value,1); break;
111     case 0xD000: VRC_VBANK(4,value,0); break;
112     case 0xD002:
113     case 0xD040: VRC_VBANK(4,value,1); break;
114     case 0xD001:
115     case 0xD004:
116     case 0xD080: VRC_VBANK(5,value,0); break;
117     case 0xD003:
118     case 0xD006:
119     case 0xD0C0: VRC_VBANK(5,value,1); break;
120     case 0xE000: VRC_VBANK(6,value,0); break;
121     case 0xE002:
122     case 0xE040: VRC_VBANK(6,value,1); break;
123     case 0xE001:
124     case 0xE004:
125     case 0xE080: VRC_VBANK(7,value,0); break;
126     case 0xE003:
127     case 0xE006:
128     case 0xE0C0: VRC_VBANK(7,value,1); break;
129  
130     case 0xF000:
131        irq.latch &= 0xF0;
132        irq.latch |= (value & 0x0F);
133        break;
134     case 0xF002:
135     case 0xF040:
136        irq.latch &= 0x0F;
137        irq.latch |= ((value & 0x0F) << 4);
138        break;
139     case 0xF004:
140     case 0xF001:
141     case 0xF080:
142        irq.enabled = (value >> 1) & 0x01;
143        irq.wait_state = value & 0x01;
144        irq.counter = irq.latch;
145        break;
146     case 0xF006:
147     case 0xF003:
148     case 0xF0C0:
149        irq.enabled = irq.wait_state;
150        break;
151  
152     default:
153  #ifdef NOFRENDO_DEBUG
154        log_printf("wrote $%02X to $%04X", value, address);
155  #endif
156        break;
157     }
158  }
159  
160  static void map22_write(uint32 address, uint8 value)
161  {
162     int reg = address >> 12;
163     
164     switch (reg)
165     {
166     case 0x8:
167        mmc_bankrom(8, 0x8000, value);
168        break;
169     
170     case 0xA:
171        mmc_bankrom(8, 0xA000, value);
172        break;
173  
174     case 0x9:
175        switch (value & 3)
176        {
177        case 0:
178           ppu_mirror(0, 1, 0, 1); /* vertical */
179           break;
180  
181        case 1: 
182           ppu_mirror(0, 0, 1, 1); /* horizontal */
183           break;
184  
185        case 2:
186           ppu_mirror(1, 1, 1, 1);
187           break;
188  
189        case 3:
190           ppu_mirror(0, 0, 0, 0);
191           break;
192        }
193        break;
194  
195     case 0xB:
196     case 0xC:
197     case 0xD:
198     case 0xE:
199        {
200           int loc = (((reg - 0xB) << 1) + (address & 1)) << 10;
201           mmc_bankvrom(1, loc, value >> 1);
202        }
203        break;
204  
205     default:
206        break;
207     }
208  }
209  
210  static void map23_write(uint32 address, uint8 value)
211  {
212     switch (address)
213     {
214     case 0x8000:
215     case 0x8FFF:
216        mmc_bankrom(8, 0x8000, value);
217        break;
218  
219     case 0xA000:
220     case 0xAFFF:
221        mmc_bankrom(8, 0xA000, value);
222        break;
223     
224     case 0x9000:
225     case 0x9004:
226     case 0x9008:
227        switch(value & 3)
228        {
229        case 0:
230           ppu_mirror(0, 1, 0, 1); /* vertical */
231           break;
232  
233        case 1: 
234           ppu_mirror(0, 0, 1, 1); /* horizontal */
235           break;
236  
237        case 2:
238           ppu_mirror(0, 0, 0, 0);
239           break;
240  
241        case 3:
242           ppu_mirror(1, 1, 1, 1);
243           break;
244        }
245        break;
246  
247     case 0xB000: VRC_VBANK(0,value,0); break;
248     case 0xB001:
249     case 0xB004: VRC_VBANK(0,value,1); break;
250     case 0xB002:
251     case 0xB008: VRC_VBANK(1,value,0); break;
252     case 0xB003:
253     case 0xB00C: VRC_VBANK(1,value,1); break;
254     case 0xC000: VRC_VBANK(2,value,0); break;
255     case 0xC001:
256     case 0xC004: VRC_VBANK(2,value,1); break;
257     case 0xC002:
258     case 0xC008: VRC_VBANK(3,value,0); break;
259     case 0xC003:
260     case 0xC00C: VRC_VBANK(3,value,1); break;
261     case 0xD000: VRC_VBANK(4,value,0); break;
262     case 0xD001:
263     case 0xD004: VRC_VBANK(4,value,1); break;
264     case 0xD002:
265     case 0xD008: VRC_VBANK(5,value,0); break;
266     case 0xD003:
267     case 0xD00C: VRC_VBANK(5,value,1); break;
268     case 0xE000: VRC_VBANK(6,value,0); break;
269     case 0xE001:
270     case 0xE004: VRC_VBANK(6,value,1); break;
271     case 0xE002:
272     case 0xE008: VRC_VBANK(7,value,0); break;
273     case 0xE003:
274     case 0xE00C: VRC_VBANK(7,value,1); break;
275  
276     case 0xF000: 
277        irq.latch &= 0xF0;
278        irq.latch |= (value & 0x0F);
279        break;
280  
281     case 0xF004: 
282        irq.latch &= 0x0F;
283        irq.latch |= ((value & 0x0F) << 4);
284        break;
285  
286     case 0xF008:
287        irq.enabled = (value >> 1) & 0x01;
288        irq.wait_state = value & 0x01;
289        irq.counter = irq.latch;
290        break;
291  
292     case 0xF00C:
293        irq.enabled = irq.wait_state;
294        break;
295  
296     default:
297  #ifdef NOFRENDO_DEBUG
298        log_printf("wrote $%02X to $%04X",value,address);
299  #endif
300        break;
301     }
302  }
303  
304  static void vrc_hblank(int vblank) 
305  {
306     UNUSED(vblank);
307  
308     if (irq.enabled)
309     {
310        if (256 == ++irq.counter)
311        {
312           irq.counter = irq.latch;
313           nes_irq();
314           //irq.enabled = false;
315           irq.enabled = irq.wait_state;
316        }
317     }
318  }
319  
320  
321  
322  static map_memwrite map21_memwrite[] =
323  {
324     { 0x8000, 0xFFFF, map21_write },
325     {     -1,     -1, NULL }
326  };
327  
328  static map_memwrite map22_memwrite[] =
329  {
330     { 0x8000, 0xFFFF, map22_write },
331     {     -1,     -1, NULL }
332  };
333  
334  static map_memwrite map23_memwrite[] =
335  {
336     { 0x8000, 0xFFFF, map23_write },
337     {     -1,     -1, NULL }
338  };
339  
340  static void map21_getstate(SnssMapperBlock *state)
341  {
342     state->extraData.mapper21.irqCounter = irq.counter;
343     state->extraData.mapper21.irqCounterEnabled = irq.enabled;
344  }
345  
346  static void map21_setstate(SnssMapperBlock *state)
347  {
348     irq.counter = state->extraData.mapper21.irqCounter;
349     irq.enabled = state->extraData.mapper21.irqCounterEnabled;
350  }
351  
352  const mapintf_t map21_intf =
353  {
354     21, /* mapper number */
355     "Konami VRC4 A", /* mapper name */
356     vrc_init, /* init routine */
357     NULL, /* vblank callback */
358     vrc_hblank, /* hblank callback */
359     map21_getstate, /* get state (snss) */
360     map21_setstate, /* set state (snss) */
361     NULL, /* memory read structure */
362     map21_memwrite, /* memory write structure */
363     NULL /* external sound device */
364  };
365  
366  const mapintf_t map22_intf =
367  {
368     22, /* mapper number */
369     "Konami VRC2 A", /* mapper name */
370     vrc_init, /* init routine */
371     NULL, /* vblank callback */
372     NULL, /* hblank callback */
373     NULL, /* get state (snss) */
374     NULL, /* set state (snss) */
375     NULL, /* memory read structure */
376     map22_memwrite, /* memory write structure */
377     NULL /* external sound device */
378  };
379  
380  const mapintf_t map23_intf =
381  {
382     23, /* mapper number */
383     "Konami VRC2 B", /* mapper name */
384     vrc_init, /* init routine */
385     NULL, /* vblank callback */
386     vrc_hblank, /* hblank callback */
387     NULL, /* get state (snss) */
388     NULL, /* set state (snss) */
389     NULL, /* memory read structure */
390     map23_memwrite, /* memory write structure */
391     NULL /* external sound device */
392  };
393  
394  const mapintf_t map25_intf =
395  {
396     25, /* mapper number */
397     "Konami VRC4 B", /* mapper name */
398     NULL, /* init routine */
399     NULL, /* vblank callback */
400     vrc_hblank, /* hblank callback */
401     NULL, /* get state (snss) */
402     NULL, /* set state (snss) */
403     NULL, /* memory read structure */
404     map21_memwrite, /* memory write structure */
405     NULL /* external sound device */
406  };
407  
408  /*
409  ** $Log: mapvrc.c,v $
410  ** Revision 1.2  2001/04/27 14:37:11  neil
411  ** wheeee
412  **
413  ** Revision 1.1  2001/04/27 12:54:40  neil
414  ** blah
415  **
416  ** Revision 1.1.1.1  2001/04/27 07:03:54  neil
417  ** initial
418  **
419  ** Revision 1.1  2000/10/24 12:19:33  matt
420  ** changed directory structure
421  **
422  ** Revision 1.10  2000/10/22 19:17:46  matt
423  ** mapper cleanups galore
424  **
425  ** Revision 1.9  2000/10/22 15:03:14  matt
426  ** simplified mirroring
427  **
428  ** Revision 1.8  2000/10/21 19:33:38  matt
429  ** many more cleanups
430  **
431  ** Revision 1.7  2000/10/10 13:58:17  matt
432  ** stroustrup squeezing his way in the door
433  **
434  ** Revision 1.6  2000/08/16 02:50:11  matt
435  ** random mapper cleanups
436  **
437  ** Revision 1.5  2000/07/15 23:52:20  matt
438  ** rounded out a bunch more mapper interfaces
439  **
440  ** Revision 1.4  2000/07/10 13:51:25  matt
441  ** using generic nes_irq() routine now
442  **
443  ** Revision 1.3  2000/07/10 05:29:03  matt
444  ** cleaned up some mirroring issues
445  **
446  ** Revision 1.2  2000/07/06 02:48:43  matt
447  ** clearly labelled structure members
448  **
449  ** Revision 1.1  2000/07/06 01:01:56  matt
450  ** initial revision
451  **
452  */