map004.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 ** map4.c 21 ** 22 ** mapper 4 interface 23 ** $Id: map004.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 "libsnss.h" 30 31 static struct 32 { 33 int counter, latch; 34 bool enabled, reset; 35 } irq; 36 37 static uint8 reg; 38 static uint8 command; 39 static uint16 vrombase; 40 41 /* mapper 4: MMC3 */ 42 static void map4_write(uint32 address, uint8 value) 43 { 44 switch (address & 0xE001) 45 { 46 case 0x8000: 47 command = value; 48 vrombase = (command & 0x80) ? 0x1000 : 0x0000; 49 50 if (reg != (value & 0x40)) 51 { 52 if (value & 0x40) 53 mmc_bankrom(8, 0x8000, (mmc_getinfo()->rom_banks * 2) - 2); 54 else 55 mmc_bankrom(8, 0xC000, (mmc_getinfo()->rom_banks * 2) - 2); 56 } 57 reg = value & 0x40; 58 break; 59 60 case 0x8001: 61 switch (command & 0x07) 62 { 63 case 0: 64 value &= 0xFE; 65 mmc_bankvrom(1, vrombase ^ 0x0000, value); 66 mmc_bankvrom(1, vrombase ^ 0x0400, value + 1); 67 break; 68 69 case 1: 70 value &= 0xFE; 71 mmc_bankvrom(1, vrombase ^ 0x0800, value); 72 mmc_bankvrom(1, vrombase ^ 0x0C00, value + 1); 73 break; 74 75 case 2: 76 mmc_bankvrom(1, vrombase ^ 0x1000, value); 77 break; 78 79 case 3: 80 mmc_bankvrom(1, vrombase ^ 0x1400, value); 81 break; 82 83 case 4: 84 mmc_bankvrom(1, vrombase ^ 0x1800, value); 85 break; 86 87 case 5: 88 mmc_bankvrom(1, vrombase ^ 0x1C00, value); 89 break; 90 91 case 6: 92 mmc_bankrom(8, (command & 0x40) ? 0xC000 : 0x8000, value); 93 break; 94 95 case 7: 96 mmc_bankrom(8, 0xA000, value); 97 break; 98 } 99 break; 100 101 case 0xA000: 102 /* four screen mirroring crap */ 103 if (0 == (mmc_getinfo()->flags & ROM_FLAG_FOURSCREEN)) 104 { 105 if (value & 1) 106 ppu_mirror(0, 0, 1, 1); /* horizontal */ 107 else 108 ppu_mirror(0, 1, 0, 1); /* vertical */ 109 } 110 break; 111 112 case 0xA001: 113 /* Save RAM enable / disable */ 114 /* Messes up Startropics I/II if implemented -- bah */ 115 break; 116 117 case 0xC000: 118 irq.latch = value; 119 // if (irq.reset) 120 // irq.counter = irq.latch; 121 break; 122 123 case 0xC001: 124 irq.reset = true; 125 irq.counter = irq.latch; 126 break; 127 128 case 0xE000: 129 irq.enabled = false; 130 // if (irq.reset) 131 // irq.counter = irq.latch; 132 break; 133 134 case 0xE001: 135 irq.enabled = true; 136 // if (irq.reset) 137 // irq.counter = irq.latch; 138 break; 139 140 default: 141 break; 142 } 143 144 if (true == irq.reset) 145 irq.counter = irq.latch; 146 } 147 148 static void map4_hblank(int vblank) 149 { 150 if (vblank) 151 return; 152 153 if (ppu_enabled()) 154 { 155 if (irq.counter >= 0) 156 { 157 irq.reset = false; 158 irq.counter--; 159 160 if (irq.counter < 0) 161 { 162 if (irq.enabled) 163 { 164 irq.reset = true; 165 nes_irq(); 166 } 167 } 168 } 169 } 170 } 171 172 static void map4_getstate(SnssMapperBlock *state) 173 { 174 state->extraData.mapper4.irqCounter = irq.counter; 175 state->extraData.mapper4.irqLatchCounter = irq.latch; 176 state->extraData.mapper4.irqCounterEnabled = irq.enabled; 177 state->extraData.mapper4.last8000Write = command; 178 } 179 180 static void map4_setstate(SnssMapperBlock *state) 181 { 182 irq.counter = state->extraData.mapper4.irqCounter; 183 irq.latch = state->extraData.mapper4.irqLatchCounter; 184 irq.enabled = state->extraData.mapper4.irqCounterEnabled; 185 command = state->extraData.mapper4.last8000Write; 186 } 187 188 static void map4_init(void) 189 { 190 irq.counter = irq.latch = 0; 191 irq.enabled = irq.reset = false; 192 reg = command = 0; 193 vrombase = 0x0000; 194 } 195 196 static const map_memwrite map4_memwrite[] = 197 { 198 { 0x8000, 0xFFFF, map4_write }, 199 { -1, -1, NULL } 200 }; 201 202 const mapintf_t map4_intf = 203 { 204 4, /* mapper number */ 205 "MMC3", /* mapper name */ 206 map4_init, /* init routine */ 207 NULL, /* vblank callback */ 208 map4_hblank, /* hblank callback */ 209 map4_getstate, /* get state (snss) */ 210 map4_setstate, /* set state (snss) */ 211 NULL, /* memory read structure */ 212 map4_memwrite, /* memory write structure */ 213 NULL /* external sound device */ 214 }; 215 216 /* 217 ** $Log: map004.c,v $ 218 ** Revision 1.2 2001/04/27 14:37:11 neil 219 ** wheeee 220 ** 221 ** Revision 1.1 2001/04/27 12:54:40 neil 222 ** blah 223 ** 224 ** Revision 1.1.1.1 2001/04/27 07:03:54 neil 225 ** initial 226 ** 227 ** Revision 1.2 2000/11/26 15:40:49 matt 228 ** hey, it actually works now 229 ** 230 ** Revision 1.1 2000/10/24 12:19:32 matt 231 ** changed directory structure 232 ** 233 ** Revision 1.12 2000/10/23 15:53:27 matt 234 ** suppressed warnings 235 ** 236 ** Revision 1.11 2000/10/22 19:17:46 matt 237 ** mapper cleanups galore 238 ** 239 ** Revision 1.10 2000/10/22 15:03:13 matt 240 ** simplified mirroring 241 ** 242 ** Revision 1.9 2000/10/21 19:33:38 matt 243 ** many more cleanups 244 ** 245 ** Revision 1.8 2000/10/10 13:58:17 matt 246 ** stroustrup squeezing his way in the door 247 ** 248 ** Revision 1.7 2000/10/08 18:05:44 matt 249 ** kept old version around, just in case.... 250 ** 251 ** Revision 1.6 2000/07/15 23:52:19 matt 252 ** rounded out a bunch more mapper interfaces 253 ** 254 ** Revision 1.5 2000/07/10 13:51:25 matt 255 ** using generic nes_irq() routine now 256 ** 257 ** Revision 1.4 2000/07/10 05:29:03 matt 258 ** cleaned up some mirroring issues 259 ** 260 ** Revision 1.3 2000/07/06 02:48:43 matt 261 ** clearly labelled structure members 262 ** 263 ** Revision 1.2 2000/07/05 05:04:39 matt 264 ** minor modifications 265 ** 266 ** Revision 1.1 2000/07/04 23:11:45 matt 267 ** initial revision 268 ** 269 */