1 /***************************************************************************
2
3 snes.c
4
5 Machine file to handle emulation of the Nintendo Super NES
6
7 Anthony Kruize
8 Based on the original code by Lee Hammerton (aka Savoury Snax)
9
10 ***************************************************************************/
11 #define __MACHINE_SNES_C
12
13 #include "driver.h"
14 #include "includes/snes.h"
15 #include "cpu/g65816/g65816.h"
16
17 /* -- Globals -- */
18 UINT8 *snes_ram = NULL; /* 65816 ram */
19 UINT8 *spc_ram = NULL; /* spc700 ram */
20 UINT8 *snes_vram = NULL; /* Video RAM (Should be 16-bit, but it's easier this way) */
21 UINT16 *snes_cgram = NULL; /* Colour RAM */
22 UINT16 *snes_oam = NULL; /* Object Attribute Memory */
23 static UINT16 cgram_address; /* CGRAM address */
24 static UINT8 vram_read_offset; /* VRAM read offset */
25 static UINT16 vram_fg_count; /* Fullgraphic increase count */
26 static UINT16 vram_fg_incr; /* Fullgraphic increase */
27 static UINT16 vram_fg_cntr; /* Fullgraphic counter */
28 static INT16 vram_fg_offset; /* Fullgraphic offset */
29 UINT8 spc_port_in[4]; /* Port for sending data to the SPC700 */
30 UINT8 spc_port_out[4]; /* Port for receiving data from the SPC700 */
31 static UINT8 snes_hdma_chnl; /* channels enabled for HDMA */
32 static struct
33 {
34 UINT8 mode; /* ROM memory mode */
35 UINT32 sram; /* Amount of sram in cart */
36 UINT32 sram_max; /* Maximum amount sram in cart (based on ROM mode) */
37 } cart = { SNES_MODE_20, 0x40000, 0x40000 };
38 static struct
39 {
40 UINT8 low;
41 UINT8 high;
42 UINT32 value;
43 UINT8 oldrol;
44 } joypad[4];
45
snes_init_ram(void)46 static void snes_init_ram(void)
47 {
48 /* Init VRAM */
49 snes_vram = (UINT8 *)memory_region( REGION_GFX1 );
50 memset( snes_vram, 0, SNES_VRAM_SIZE );
51
52 /* Init Colour RAM */
53 snes_cgram = (UINT16 *)memory_region( REGION_USER1 );
54 memset( (UINT8 *)snes_cgram, 0, SNES_CGRAM_SIZE );
55
56 /* Init oam RAM */
57 snes_oam = (UINT16 *)memory_region( REGION_USER2 );
58 memset( snes_oam, 0xff, SNES_OAM_SIZE );
59
60 /* Inititialize registers/variables */
61 snes_ppu.update_windows = 1;
62 snes_ppu.update_palette = 1;
63 snes_ppu.beam.latch_vert = 0;
64 snes_ppu.beam.latch_horz = 0;
65 snes_ppu.beam.current_vert = 0;
66 snes_ppu.beam.current_horz = 0;
67 snes_ppu.beam.last_visible_line = 240;
68 snes_ppu.mode = 0;
69 cgram_address = 0;
70 vram_read_offset = 2;
71 /* Force the use of the SPCSkipper for now.
72 * Once the two CPU's are running in sync. we should check that sound is
73 * enabled here and only use the SPCSkipper if it is. */
74 spc_usefakeapu = 1;
75 }
76
77
MACHINE_INIT(snes)78 MACHINE_INIT( snes )
79 {
80 snes_init_ram();
81
82 /* Set STAT78 to NTSC or PAL */
83 if( Machine->drv->frames_per_second == 60 )
84 snes_ram[STAT78] = SNES_NTSC;
85 else /* if( Machine->drv->frames_per_second == 50 ) */
86 snes_ram[STAT78] = SNES_PAL;
87 }
88
89
90 /* Handle reading of Mode 20 SRAM */
91 /* 0x700000 - 0x77ffff */
READ_HANDLER(snes_r_sram)92 READ_HANDLER( snes_r_sram )
93 {
94 UINT8 value = 0xff;
95
96 if( cart.sram > 0 )
97 {
98 value = snes_ram[0x700000 + offset];
99 }
100
101 return value;
102 }
103
104 /* 0x000000 - 0x2fffff */
READ_HANDLER(snes_r_bank1)105 READ_HANDLER( snes_r_bank1 )
106 {
107 UINT16 address = offset & 0xffff;
108
109 if( address <= 0x1fff ) /* Mirror of Low RAM */
110 return cpu_readmem24( 0x7e0000 + address );
111 else if( address >= 0x2000 && address <= 0x5fff ) /* I/O */
112 return snes_r_io( address );
113 else if( address >= 0x6000 && address <= 0x7fff ) /* Reserved */
114 return 0xff;
115 else
116 {
117 if( cart.mode == SNES_MODE_20 )
118 return snes_ram[offset];
119 else /* MODE_21 */
120 return snes_ram[0xc00000 + offset];
121 }
122
123 return 0xff;
124 }
125
126 /* 0x300000 - 0x3fffff */
READ_HANDLER(snes_r_bank2)127 READ_HANDLER( snes_r_bank2 )
128 {
129 UINT16 address = offset & 0xffff;
130
131 if( address <= 0x1fff ) /* Mirror of Low RAM */
132 return cpu_readmem24( 0x7e0000 + address );
133 else if( address >= 0x2000 && address <= 0x5fff ) /* I/O */
134 return snes_r_io( address );
135 else if( address >= 0x6000 && address <= 0x7fff )
136 {
137 if( cart.mode == SNES_MODE_20 )
138 return 0xff; /* Reserved */
139 else /* MODE_21 */
140 return snes_ram[0x300000 + offset]; /* sram */
141 }
142 else
143 {
144 if( cart.mode == SNES_MODE_20 )
145 return snes_ram[0x300000 + offset];
146 else /* MODE_21 */
147 return snes_ram[0xf00000 + offset];
148 }
149
150 return 0xff;
151 }
152
153 /* 0x400000 - 0x5fffff */
READ_HANDLER(snes_r_bank3)154 READ_HANDLER( snes_r_bank3 )
155 {
156 UINT16 address = offset & 0xffff;
157
158 if( cart.mode == SNES_MODE_20 )
159 {
160 if( address <= 0x7fff )
161 return 0xff; /* Reserved */
162 else
163 return snes_ram[0x400000 + offset];
164 }
165 else /* MODE_21 */
166 {
167 return snes_ram[0x400000 + offset];
168 }
169
170 return 0xff;
171 }
172
173 /* 0x800000 - 0xffffff */
READ_HANDLER(snes_r_bank4)174 READ_HANDLER( snes_r_bank4 )
175 {
176 if( cart.mode == SNES_MODE_20 )
177 {
178 if( offset <= 0x5fffff )
179 return cpu_readmem24( offset );
180 else
181 return 0xff;
182 }
183 else /* MODE_21 */
184 {
185 if( offset <= 0x3fffff )
186 return cpu_readmem24( offset );
187 else
188 return snes_ram[offset + 0x800000];
189 }
190
191 return 0xff;
192 }
193
194 /* 0x000000 - 0x2fffff */
WRITE_HANDLER(snes_w_bank1)195 WRITE_HANDLER( snes_w_bank1 )
196 {
197 UINT16 address = offset & 0xffff;
198
199 if( address <= 0x1fff ) /* Mirror of Low RAM */
200 cpu_writemem24( 0x7e0000 + address, data );
201 else if( address >= 0x2000 && address <= 0x5fff ) /* I/O */
202 snes_w_io( address, data );
203 else if( address >= 0x6000 && address <= 0x7fff ) /* Reserved */
204 log_cb(RETRO_LOG_DEBUG, LOGPRE "Attempt to write to reserved address: %X\n", offset );
205 else
206 log_cb(RETRO_LOG_DEBUG, LOGPRE "Attempt to write to ROM address: %X\n", offset );
207 }
208
209 /* 0x300000 - 0x3fffff */
WRITE_HANDLER(snes_w_bank2)210 WRITE_HANDLER( snes_w_bank2 )
211 {
212 UINT16 address = offset & 0xffff;
213
214 if( address <= 0x1fff ) /* Mirror of Low RAM */
215 cpu_writemem24( 0x7e0000 + address, data );
216 else if( address >= 0x2000 && address <= 0x5fff ) /* I/O */
217 snes_w_io( address, data );
218 else if( address >= 0x6000 && address <= 0x7fff )
219 {
220 if( cart.mode == SNES_MODE_20 ) /* Reserved */
221 log_cb(RETRO_LOG_DEBUG, LOGPRE "Attempt to write to reserved address: %X\n", offset );
222 else /* MODE_21 */
223 snes_ram[0x300000 + offset] = data; /* sram */
224 }
225 else
226 log_cb(RETRO_LOG_DEBUG, LOGPRE "Attempt to write to ROM address: %X\n", offset );
227 }
228
229 /* 0x800000 - 0xffffff */
WRITE_HANDLER(snes_w_bank4)230 WRITE_HANDLER( snes_w_bank4 )
231 {
232 if( cart.mode == SNES_MODE_20 )
233 {
234 if( offset <= 0x2fffff )
235 snes_w_bank1( offset, data );
236 else if( offset >= 0x300000 && offset <= 0x3fffff )
237 snes_w_bank2( offset - 0x300000, data );
238 }
239 else /* MODE_21 */
240 {
241 if( offset <= 0x2fffff )
242 snes_w_bank1( offset, data );
243 else if( offset >= 0x300000 && offset <= 0x3fffff )
244 snes_w_bank2( offset - 0x300000, data );
245 else
246 log_cb(RETRO_LOG_DEBUG, LOGPRE "Attempt to write to ROM address: %X\n", offset );
247 }
248 }
249
250 /*
251 * DR - Double read : address is read twice to return a 16bit value.
252 * low - This is the low byte of a 16 or 24 bit value
253 * mid - This is the middle byte of a 24 bit value
254 * high - This is the high byte of a 16 or 24 bit value
255 */
READ_HANDLER(snes_r_io)256 READ_HANDLER( snes_r_io )
257 {
258 UINT8 value = 0;
259
260 /* offset is from 0x000000 */
261 switch( offset )
262 {
263 case OAMADDL:
264 case OAMADDH:
265 case VMADDL:
266 case VMADDH:
267 case VMDATAL:
268 case VMDATAH:
269 case CGADD:
270 case CGDATA:
271 return snes_ram[offset];
272 case MPYL: /* Multiplication result (low) */
273 case MPYM: /* Multiplication result (mid) */
274 case MPYH: /* Multiplication result (high) */
275 {
276 /* Perform 16bit * 8bit multiply */
277 INT32 c = snes_ppu.mode7.matrix_a * (snes_ppu.mode7.matrix_b >> 8);
278 snes_ram[MPYL] = c & 0xff;
279 snes_ram[MPYM] = (c >> 8) & 0xff;
280 snes_ram[MPYH] = (c >> 16) & 0xff;
281 return snes_ram[offset];
282 }
283 case SLHV: /* Software latch for H/V counter */
284 /* FIXME: horizontal latch is a major fudge!!! */
285 snes_ppu.beam.latch_vert = snes_ppu.beam.current_vert;
286 snes_ppu.beam.latch_horz = snes_ppu.beam.current_horz;
287 snes_ppu.beam.current_horz = 0;
288 return 0x0; /* Return value is meaningless */
289 case ROAMDATA: /* Read data from OAM (DR) */
290 {
291 value = (snes_oam[snes_ppu.oam.address] >> (snes_ram[OAMDATA] << 3)) & 0xff;
292 snes_ram[OAMDATA] = (snes_ram[OAMDATA] + 1) % 2;
293 if( snes_ram[OAMDATA] == 0 )
294 {
295 snes_ppu.oam.address++;
296 snes_ram[OAMADDL] = snes_ppu.oam.address & 0xff;
297 snes_ram[OAMADDH] = (snes_ppu.oam.address >> 8) & 0x1;
298 }
299 return value;
300 }
301 case RVMDATAL: /* Read data from VRAM (low) */
302 {
303 UINT16 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL];
304 value = snes_vram[(addr << 1) - vram_read_offset];
305 if( !(snes_ram[VMAIN] & 0x80) )
306 {
307 if( vram_read_offset == 0 )
308 {
309 vram_read_offset = 2;
310 }
311 /* Increase the address */
312 if( snes_ram[VMAIN] & 0xc )
313 {
314 addr++;
315 vram_fg_offset += 7; /* addr increases by 1, plus 7 = 8 */
316 vram_fg_count--;
317 if( vram_fg_count == 0 )
318 {
319 vram_fg_cntr--;
320 vram_fg_count = vram_fg_incr;
321 if( vram_fg_cntr == 0 )
322 {
323 vram_fg_cntr = 8;
324 vram_fg_offset -= 7;
325 }
326 else
327 {
328 vram_fg_offset -= (vram_fg_count * 8) - 1;
329 }
330 }
331 }
332 else
333 {
334 switch( snes_ram[VMAIN] & 0x03 )
335 {
336 case 0: addr++; break;
337 case 1: addr += 32; break;
338 case 2: addr += 128; break; /* Should be 64, but a bug in the snes means it's 128 */
339 case 3: addr += 128; break;
340 }
341 }
342 snes_ram[VMADDL] = addr & 0xff;
343 snes_ram[VMADDH] = (addr >> 8) & 0xff;
344 }
345 return value;
346 }
347 case RVMDATAH: /* Read data from VRAM (high) */
348 {
349 UINT16 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL];
350
351 value = snes_vram[(addr << 1) + 1 - vram_read_offset];
352 if( snes_ram[VMAIN] & 0x80 )
353 {
354 if( vram_read_offset == 0 )
355 {
356 vram_read_offset = 2;
357 }
358 /* Increase the address */
359 if( snes_ram[VMAIN] & 0xc )
360 {
361 addr++;
362 vram_fg_offset += 7; /* addr increases by 1, plus 7 = 8 */
363 vram_fg_count--;
364 if( vram_fg_count == 0 )
365 {
366 vram_fg_cntr--;
367 vram_fg_count = vram_fg_incr;
368 if( vram_fg_cntr == 0 )
369 {
370 vram_fg_cntr = 8;
371 vram_fg_offset -= 7;
372 }
373 else
374 {
375 vram_fg_offset -= (vram_fg_count * 8) - 1;
376 }
377 }
378 }
379 else
380 {
381 switch( snes_ram[VMAIN] & 0x03 )
382 {
383 case 0: addr++; break;
384 case 1: addr += 32; break;
385 case 2: addr += 128; break; /* Should be 64, but a bug in the snes means it's 128 */
386 case 3: addr += 128; break;
387 }
388 }
389 snes_ram[VMADDL] = addr & 0xff;
390 snes_ram[VMADDH] = (addr >> 8) & 0xff;
391 }
392 return value;
393 }
394 case RCGDATA: /* Read data from CGRAM */
395 value = ((UINT8 *)snes_cgram)[cgram_address];
396 cgram_address = (cgram_address + 1) % (SNES_CGRAM_SIZE - 2);
397 return value;
398 case OPHCT: /* Horizontal counter data by ext/soft latch */
399 {
400 /* FIXME: need to handle STAT78 reset */
401 static UINT8 read_ophct = 0;
402 if( read_ophct )
403 {
404 value = (snes_ppu.beam.latch_horz >> 8) & 0x1;
405 read_ophct = 0;
406 }
407 else
408 {
409 value = snes_ppu.beam.latch_horz & 0xff;
410 read_ophct = 1;
411 }
412 return value;
413 }
414 case OPVCT: /* Vertical counter data by ext/soft latch */
415 {
416 /* FIXME: need to handle STAT78 reset */
417 static UINT8 read_opvct = 0;
418 if( read_opvct )
419 {
420 value = (snes_ppu.beam.latch_vert >> 8) & 0x1;
421 read_opvct = 0;
422 }
423 else
424 {
425 value = snes_ppu.beam.latch_vert & 0xff;
426 read_opvct = 1;
427 }
428 return value;
429 }
430 case STAT77: /* PPU status flag and version number */
431 return snes_ram[offset];
432 case STAT78: /* PPU status flag and version number */
433 /* FIXME: need to reset OPHCT and OPVCT */
434 return snes_ram[offset];
435 case APU00: /* Audio port register */
436 case APU01: /* Audio port register */
437 case APU02: /* Audio port register */
438 case APU03: /* Audio port register */
439 if( spc_usefakeapu )
440 return fakespc_port_r( offset & 0x3 );
441 else
442 return spc_port_out[offset & 0x3];
443 case WMDATA: /* Data to read from WRAM */
444 {
445 UINT32 addr = ((snes_ram[WMADDH] & 0x1) << 16) | (snes_ram[WMADDM] << 8) | snes_ram[WMADDL];
446
447 value = cpu_readmem24(0x7e0000 + addr++);
448 snes_ram[WMADDH] = (addr >> 16) & 0x1;
449 snes_ram[WMADDM] = (addr >> 8) & 0xff;
450 snes_ram[WMADDL] = addr & 0xff;
451 return value;
452 }
453 case WMADDL: /* Address to read/write to wram (low) */
454 case WMADDM: /* Address to read/write to wram (mid) */
455 case WMADDH: /* Address to read/write to wram (high) */
456 return snes_ram[offset];
457 case OLDJOY1: /* Data for old NES controllers */
458 {
459 if( snes_ram[offset] & 0x1 )
460 {
461 return 0;
462 }
463 value = ((joypad[0].low | (joypad[0].high << 8) | 0x10000) >> (15 - (joypad[0].oldrol++ % 16))) & 0x1;
464 if( !(joypad[0].oldrol % 17) )
465 value = 0x1;
466 return value;
467 }
468 case OLDJOY2: /* Data for old NES controllers */
469 {
470 if( snes_ram[OLDJOY1] & 0x1 )
471 {
472 return 0;
473 }
474 value = ((joypad[1].low | (joypad[1].high << 8) | 0x10000) >> (15 - (joypad[1].oldrol++ % 16))) & 0x1;
475 if( !(joypad[1].oldrol % 17) )
476 value = 0x1;
477 return value;
478 }
479 case HTIMEL:
480 case HTIMEH:
481 case VTIMEL:
482 case VTIMEH:
483 return snes_ram[offset];
484 case MDMAEN: /* GDMA channel designation and trigger */
485 /* FIXME: Is this really read-only? - Villgust needs to read it */
486 return snes_ram[offset];
487 case RDNMI: /* NMI flag by v-blank and version number */
488 value = snes_ram[offset];
489 snes_ram[offset] &= 0xf; /* NMI flag is reset on read */
490 return value;
491 case TIMEUP: /* IRQ flag by H/V count timer */
492 value = snes_ram[offset];
493 snes_ram[offset] = 0; /* Register is reset on read */
494 return value;
495 case HVBJOY: /* H/V blank and joypad controller enable */
496 /* FIXME: JOYCONT and HBLANK are emulated wrong at present */
497 value = snes_ram[offset] & 0xbe;
498 snes_ram[offset] = ((snes_ram[offset]^0x41)&0x41)|value;
499 return snes_ram[offset];
500 case RDIO: /* Programmable I/O port (in port ) */
501 /* FIXME: do something here */
502 case RDDIVL: /* Quotient of divide result (low) */
503 case RDDIVH: /* Quotient of divide result (high) */
504 case RDMPYL: /* Product/Remainder of mult/div result (low) */
505 case RDMPYH: /* Product/Remainder of mult/div result (high) */
506 return snes_ram[offset];
507 case JOY1L: /* Joypad 1 status register (low) */
508 return joypad[0].low;
509 case JOY1H: /* Joypad 1 status register (high) */
510 return joypad[0].high;
511 case JOY2L: /* Joypad 2 status register (low) */
512 return joypad[1].low;
513 case JOY2H: /* Joypad 2 status register (high) */
514 return joypad[1].high;
515 case JOY3L: /* Joypad 3 status register (low) */
516 return joypad[2].low;
517 case JOY3H: /* Joypad 3 status register (high) */
518 return joypad[2].high;
519 case JOY4L: /* Joypad 4 status register (low) */
520 return joypad[3].low;
521 case JOY4H: /* Joypad 4 status register (high) */
522 return joypad[3].high;
523 case DMAP0: case BBAD0: case A1T0L: case A1T0H: case A1B0: case DAS0L:
524 case DAS0H: case DSAB0: case A2A0L: case A2A0H: case NTRL0:
525 case DMAP1: case BBAD1: case A1T1L: case A1T1H: case A1B1: case DAS1L:
526 case DAS1H: case DSAB1: case A2A1L: case A2A1H: case NTRL1:
527 case DMAP2: case BBAD2: case A1T2L: case A1T2H: case A1B2: case DAS2L:
528 case DAS2H: case DSAB2: case A2A2L: case A2A2H: case NTRL2:
529 case DMAP3: case BBAD3: case A1T3L: case A1T3H: case A1B3: case DAS3L:
530 case DAS3H: case DSAB3: case A2A3L: case A2A3H: case NTRL3:
531 case DMAP4: case BBAD4: case A1T4L: case A1T4H: case A1B4: case DAS4L:
532 case DAS4H: case DSAB4: case A2A4L: case A2A4H: case NTRL4:
533 case DMAP5: case BBAD5: case A1T5L: case A1T5H: case A1B5: case DAS5L:
534 case DAS5H: case DSAB5: case A2A5L: case A2A5H: case NTRL5:
535 case DMAP6: case BBAD6: case A1T6L: case A1T6H: case A1B6: case DAS6L:
536 case DAS6H: case DSAB6: case A2A6L: case A2A6H: case NTRL6:
537 case DMAP7: case BBAD7: case A1T7L: case A1T7H: case A1B7: case DAS7L:
538 case DAS7H: case DSAB7: case A2A7L: case A2A7H: case NTRL7:
539 return snes_ram[offset];
540
541 case 0x4100: /* NSS Dip-Switches */
542 #ifdef MAME_DEBUG
543 return readinputport(12);
544 #else
545 return readinputport(9);
546 #endif /* MAME_DEBUG */
547 /* case 0x4101: // PC: a104 - a10e - a12a */ /*only nss_actr*/
548 /* case 0x420c: // PC: 9c7d - 8fab */ /*only nss_ssoc*/
549 default:
550 log_cb(RETRO_LOG_DEBUG, LOGPRE "offset = %x pc = %x\n",offset,activecpu_get_pc());
551 }
552
553 /* Unsupported reads return 0xff */
554 return 0xff;
555 }
556
557 /*
558 * DW - Double write : address is written twice to set a 16bit value.
559 * low - This is the low byte of a 16 or 24 bit value
560 * mid - This is the middle byte of a 24 bit value
561 * high - This is the high byte of a 16 or 24 bit value
562 */
WRITE_HANDLER(snes_w_io)563 WRITE_HANDLER( snes_w_io )
564 {
565 /* offset is from 0x000000 */
566 switch( offset )
567 {
568 case INIDISP: /* Initial settings for screen */
569 snes_ppu.update_palette = 1;
570 break;
571 case OBSEL: /* Object size and data area designation */
572 snes_ppu.layer[4].data = ((data & 0x3) * 0x2000) << 1;
573 snes_ppu.oam.name_select = (((data & 0x18)>>3) * 0x1000) << 1;
574 /* Determine object size */
575 switch( (data & 0xe0) >> 5 )
576 {
577 case 0: /* 8 & 16 */
578 snes_ppu.oam.size[0] = 1;
579 snes_ppu.oam.size[1] = 2;
580 break;
581 case 1: /* 8 & 32 */
582 snes_ppu.oam.size[0] = 1;
583 snes_ppu.oam.size[1] = 4;
584 break;
585 case 2: /* 8 & 64 */
586 snes_ppu.oam.size[0] = 1;
587 snes_ppu.oam.size[1] = 8;
588 break;
589 case 3: /* 16 & 32 */
590 snes_ppu.oam.size[0] = 2;
591 snes_ppu.oam.size[1] = 4;
592 break;
593 case 4: /* 16 & 64 */
594 snes_ppu.oam.size[0] = 2;
595 snes_ppu.oam.size[1] = 8;
596 break;
597 case 5: /* 32 & 64 */
598 snes_ppu.oam.size[0] = 4;
599 snes_ppu.oam.size[1] = 8;
600 break;
601 default:
602 /* Unknown size so default to 8 & 16 */
603 snes_ppu.oam.size[0] = 1;
604 snes_ppu.oam.size[1] = 2;
605 #ifdef SNES_DBG_REG_W
606 log_cb(RETRO_LOG_DEBUG, LOGPRE "Object size unsupported: %d\n", (data & 0xe0) >> 5 );
607 #endif
608 }
609 break;
610 case OAMADDL: /* Address for accessing OAM (low) */
611 snes_ppu.oam.address_low = data;
612 snes_ppu.oam.address = ((snes_ppu.oam.address_high & 0x1) << 8) + data;
613 snes_ram[OAMDATA] = 0;
614 break;
615 case OAMADDH: /* Address for accessing OAM (high) */
616 snes_ppu.oam.address_high = data & 0x1;
617 snes_ppu.oam.address = ((data & 0x1) << 8) + snes_ppu.oam.address_low;
618 if( data & 0x80 )
619 snes_ppu.oam.high_priority = snes_ppu.oam.address;
620 snes_ram[OAMDATA] = 0;
621 break;
622 case OAMDATA: /* Data for OAM write (DW) */
623 {
624 snes_oam[snes_ppu.oam.address] = ((snes_oam[snes_ppu.oam.address] >> 8) & 0xff) + (data << 8);
625 snes_ram[OAMDATA] = (snes_ram[OAMDATA] + 1) % 2;
626 if( snes_ram[OAMDATA] == 0 )
627 {
628 snes_ram[OAMDATA] = 0;
629 snes_ppu.oam.address++;
630 snes_ram[OAMADDL] = snes_ppu.oam.address & 0xff;
631 snes_ram[OAMADDH] = (snes_ppu.oam.address >> 8) & 0x1;
632 }
633 return;
634 }
635 case BGMODE: /* BG mode and character size settings */
636 snes_ppu.mode = data & 0x7;
637 #ifdef SNES_DBG_VIDHRDW
638 if( snes_ppu.mode == 5 || snes_ppu.mode == 6 )
639 set_visible_area(0, (SNES_SCR_WIDTH * 2 * 1.75) - 1, 0, snes_ppu.beam.last_visible_line - 1);
640 else
641 set_visible_area(0, (SNES_SCR_WIDTH * 2 * 1.75) - 1, 0, snes_ppu.beam.last_visible_line - 1 );
642 #else
643 if( snes_ppu.mode == 5 || snes_ppu.mode == 6 )
644 set_visible_area(0, (SNES_SCR_WIDTH * 2) - 1, 0, snes_ppu.beam.last_visible_line - 1 );
645 else
646 set_visible_area(0, SNES_SCR_WIDTH - 1, 0, snes_ppu.beam.last_visible_line - 1 );
647 #endif
648
649 snes_ppu.layer[0].tile_size = (data >> 4) & 0x1;
650 snes_ppu.layer[1].tile_size = (data >> 5) & 0x1;
651 snes_ppu.layer[2].tile_size = (data >> 6) & 0x1;
652 snes_ppu.layer[3].tile_size = (data >> 7) & 0x1;
653 snes_ppu.update_offsets = 1;
654 break;
655 case MOSAIC: /* Size and screen designation for mosaic */
656 /* FIXME: We don't support horizontal mosaic yet */
657 break;
658 case BG1SC: /* Address for storing SC data BG1 SC size designation */
659 case BG2SC: /* Address for storing SC data BG2 SC size designation */
660 case BG3SC: /* Address for storing SC data BG3 SC size designation */
661 case BG4SC: /* Address for storing SC data BG4 SC size designation */
662 snes_ppu.layer[offset - BG1SC].map = (data & 0xfc) << 9;
663 snes_ppu.layer[offset - BG1SC].map_size = data & 0x3;
664 break;
665 case BG12NBA: /* Address for BG 1 and 2 character data */
666 snes_ppu.layer[0].data = (data & 0xf) << 13;
667 snes_ppu.layer[1].data = (data & 0xf0) << 9;
668 break;
669 case BG34NBA: /* Address for BG 3 and 4 character data */
670 snes_ppu.layer[2].data = (data & 0xf) << 13;
671 snes_ppu.layer[3].data = (data & 0xf0) << 9;
672 break;
673 case BG1HOFS: /* BG1 - horizontal scroll (DW) */
674 snes_ppu.layer[0].offset.horizontal = ((snes_ppu.layer[0].offset.horizontal >> 8) & 0xff) + (data << 8);
675 snes_ppu.update_offsets = 1;
676 return;
677 case BG1VOFS: /* BG1 - vertical scroll (DW) */
678 snes_ppu.layer[0].offset.vertical = ((snes_ppu.layer[0].offset.vertical >> 8) & 0xff) + (data << 8);
679 snes_ppu.update_offsets = 1;
680 return;
681 case BG2HOFS: /* BG2 - horizontal scroll (DW) */
682 snes_ppu.layer[1].offset.horizontal = ((snes_ppu.layer[1].offset.horizontal >> 8) & 0xff) + (data << 8);
683 snes_ppu.update_offsets = 1;
684 return;
685 case BG2VOFS: /* BG2 - vertical scroll (DW) */
686 snes_ppu.layer[1].offset.vertical = ((snes_ppu.layer[1].offset.vertical >> 8) & 0xff) + (data << 8);
687 snes_ppu.update_offsets = 1;
688 return;
689 case BG3HOFS: /* BG3 - horizontal scroll (DW) */
690 snes_ppu.layer[2].offset.horizontal = ((snes_ppu.layer[2].offset.horizontal >> 8) & 0xff) + (data << 8);
691 snes_ppu.update_offsets = 1;
692 return;
693 case BG3VOFS: /* BG3 - vertical scroll (DW) */
694 snes_ppu.layer[2].offset.vertical = ((snes_ppu.layer[2].offset.vertical >> 8) & 0xff) + (data << 8);
695 snes_ppu.update_offsets = 1;
696 return;
697 case BG4HOFS: /* BG4 - horizontal scroll (DW) */
698 snes_ppu.layer[3].offset.horizontal = ((snes_ppu.layer[3].offset.horizontal >> 8) & 0xff) + (data << 8);
699 snes_ppu.update_offsets = 1;
700 return;
701 case BG4VOFS: /* BG4 - vertical scroll (DW) */
702 snes_ppu.layer[3].offset.vertical = ((snes_ppu.layer[3].offset.vertical >> 8) & 0xff) + (data << 8);
703 snes_ppu.update_offsets = 1;
704 return;
705 case VMAIN: /* VRAM address increment value designation */
706 {
707 /* FIXME: We don't support full graphic properly yet */
708 if( data & 0xc )
709 {
710 vram_fg_incr = vram_fg_count = 0x10 << ((data & 0xc) >> 2);
711 vram_fg_cntr = 8;
712 vram_fg_offset = 0;
713 }
714 #ifdef SNES_DBG_REG_W
715 if( (data & 0x80) != (snes_ram[VMAIN] & 0x80) )
716 log_cb(RETRO_LOG_DEBUG, LOGPRE "VRAM access: %s(%d)\n", (data & 0x80) >> 7?"Word":"Byte", (data & 0x80) >> 7 );
717 if( (data & 0xc) && (data & 0xc) != (snes_ram[VMAIN] & 0xc) )
718 log_cb(RETRO_LOG_DEBUG, LOGPRE "Full graphic specified: %d, incr: %d\n", (data & 0xc) >> 2, vram_fg_incr );
719 #endif
720 }
721 break;
722 case VMADDL: /* Address for VRAM read/write (low) */
723 case VMADDH: /* Address for VRAM read/write (high) */
724 vram_read_offset = 0;
725 vram_fg_count = vram_fg_incr;
726 vram_fg_cntr = 8;
727 break;
728 case VMDATAL: /* Data for VRAM write (low) */
729 {
730 UINT16 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL];
731 if( snes_ram[VMAIN] & 0xc )
732 snes_vram[(addr + vram_fg_offset) << 1] = data;
733 else
734 snes_vram[addr << 1] = data;
735
736 vram_read_offset = 0;
737 if( !(snes_ram[VMAIN] & 0x80) )
738 {
739 if( snes_ram[VMAIN] & 0xc )
740 {
741 addr++;
742 vram_fg_offset += 7; /* addr increases by 1, plus 7 = 8 */
743 vram_fg_count--;
744 if( vram_fg_count == 0 )
745 {
746 vram_fg_cntr--;
747 vram_fg_count = vram_fg_incr;
748 if( vram_fg_cntr == 0 )
749 {
750 vram_fg_cntr = 8;
751 vram_fg_offset -= 7;
752 }
753 else
754 {
755 vram_fg_offset -= (vram_fg_count * 8) - 1;
756 }
757 }
758 }
759 else
760 {
761 switch( snes_ram[VMAIN] & 0x03 )
762 {
763 case 0: addr++; break;
764 case 1: addr += 32; break;
765 case 2: addr += 128; break; /* Should be 64, but a bug in the snes means it's 128 */
766 case 3: addr += 128; break;
767 }
768 }
769 snes_ram[VMADDL] = addr & 0xff;
770 snes_ram[VMADDH] = (addr >> 8) & 0xff;
771 }
772 } return;
773 case VMDATAH: /* Data for VRAM write (high) */
774 {
775 UINT16 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL];
776 if( snes_ram[VMAIN] & 0xc )
777 snes_vram[((addr + vram_fg_offset) << 1) + 1] = data;
778 else
779 snes_vram[(addr << 1) + 1] = data;
780
781 vram_read_offset = 0;
782 if( (snes_ram[VMAIN] & 0x80) )
783 {
784 if( snes_ram[VMAIN] & 0xc )
785 {
786 addr++;
787 vram_fg_offset += 7; /* addr increases by 1, plus 7 = 8 */
788 vram_fg_count--;
789 if( vram_fg_count == 0 )
790 {
791 vram_fg_cntr--;
792 vram_fg_count = vram_fg_incr;
793 if( vram_fg_cntr == 0 )
794 {
795 vram_fg_cntr = 8;
796 vram_fg_offset -= 7;
797 }
798 else
799 {
800 vram_fg_offset -= (vram_fg_count * 8) - 1;
801 }
802 }
803 }
804 else
805 {
806 switch( snes_ram[VMAIN] & 0x03 )
807 {
808 case 0: addr++; break;
809 case 1: addr += 32; break;
810 case 2: addr += 128; break; /* Should be 64, but a bug in the snes means it's 128 */
811 case 3: addr += 128; break;
812 }
813 }
814 snes_ram[VMADDL] = addr & 0xff;
815 snes_ram[VMADDH] = (addr >> 8) & 0xff;
816 }
817 } return;
818 case M7SEL: /* Mode 7 initial settings */
819 break;
820 case M7A: /* Mode 7 COS angle/x expansion (DW) */
821 snes_ppu.mode7.matrix_a = ((snes_ppu.mode7.matrix_a >> 8) & 0xff) + (data << 8);
822 break;
823 case M7B: /* Mode 7 SIN angle/ x expansion (DW) */
824 snes_ppu.mode7.matrix_b = ((snes_ppu.mode7.matrix_b >> 8) & 0xff) + (data << 8);
825 break;
826 case M7C: /* Mode 7 SIN angle/y expansion (DW) */
827 snes_ppu.mode7.matrix_c = ((snes_ppu.mode7.matrix_c >> 8) & 0xff) + (data << 8);
828 break;
829 case M7D: /* Mode 7 COS angle/y expansion (DW) */
830 snes_ppu.mode7.matrix_d = ((snes_ppu.mode7.matrix_d >> 8) & 0xff) + (data << 8);
831 break;
832 case M7X: /* Mode 7 x center position (DW) */
833 snes_ppu.mode7.origin_x = ((snes_ppu.mode7.origin_x >> 8) & 0xff) + (data << 8);
834 break;
835 case M7Y: /* Mode 7 y center position (DW) */
836 snes_ppu.mode7.origin_y = ((snes_ppu.mode7.origin_y >> 8) & 0xff) + (data << 8);
837 break;
838 case CGADD: /* Initial address for colour RAM writing */
839 /* CGRAM is 16-bit, but when reading/writing we treat it as
840 * 8-bit, so we need to double the address */
841 cgram_address = data << 1;
842 break;
843 case CGDATA: /* Data for colour RAM */
844 ((UINT8 *)snes_cgram)[cgram_address] = data;
845 cgram_address = (cgram_address + 1) % (SNES_CGRAM_SIZE - 2);
846 snes_ppu.update_palette = 1;
847 break;
848 case W12SEL: /* Window mask settings for BG1-2 */
849 case W34SEL: /* Window mask settings for BG3-4 */
850 case WOBJSEL: /* Window mask settings for objects */
851 case WH0: /* Window 1 left position */
852 case WH1: /* Window 1 right position */
853 case WH2: /* Window 2 left position */
854 case WH3: /* Window 2 right position */
855 case WBGLOG: /* Window mask logic for BG's */
856 case WOBJLOG: /* Window mask logic for objects */
857 if( data != snes_ram[offset] )
858 snes_ppu.update_windows = 1;
859 break;
860 case TM: /* Main screen designation */
861 case TS: /* Subscreen designation */
862 case TMW: /* Window mask for main screen designation */
863 case TSW: /* Window mask for subscreen designation */
864 break;
865 case CGWSEL: /* Initial settings for Fixed colour addition or screen addition */
866 /* FIXME: We don't support direct select for modes 3 & 4 or subscreen window stuff */
867 #ifdef SNES_DBG_REG_W
868 if( (data & 0x2) != (snes_ram[CGWSEL] & 0x2) )
869 log_cb(RETRO_LOG_DEBUG, LOGPRE "Add/Sub Layer: %s\n", ((data & 0x2) >> 1) ? "Subscreen" : "Fixed colour" );
870 #endif
871 break;
872 case CGADSUB: /* Addition/Subtraction designation for each screen */
873 {
874 UINT8 sub = (data & 0x80) >> 7;
875 snes_ppu.layer[0].blend = (data & 0x1) << sub;
876 snes_ppu.layer[1].blend = ((data & 0x2) >> 1) << sub;
877 snes_ppu.layer[2].blend = ((data & 0x4) >> 2) << sub;
878 snes_ppu.layer[3].blend = ((data & 0x8) >> 3) << sub;
879 snes_ppu.layer[4].blend = ((data & 0x10) >> 4) << sub;
880 } break;
881 case COLDATA: /* Fixed colour data for fixed colour addition/subtraction */
882 {
883 /* Store it in the extra space we made in the CGRAM
884 * It doesn't really go there, but it's as good a place as any. */
885 UINT8 r,g,b,fade;
886
887 /* Get existing value. */
888 r = snes_cgram[FIXED_COLOUR] & 0x1f;
889 g = (snes_cgram[FIXED_COLOUR] & 0x3e0) >> 5;
890 b = (snes_cgram[FIXED_COLOUR] & 0x7c00) >> 10;
891 /* Set new value */
892 if( data & 0x20 )
893 r = data & 0x1f;
894 if( data & 0x40 )
895 g = data & 0x1f;
896 if( data & 0x80 )
897 b = data & 0x1f;
898 snes_cgram[FIXED_COLOUR] = (r | (g << 5) | (b << 10));
899
900 /* set the palette entry, adjusting to the fade setting */
901 fade = (snes_ram[INIDISP] & 0xf) + 1;
902 r = (r * fade) >> 4;
903 g = (g * fade) >> 4;
904 b = (b * fade) >> 4;
905 Machine->remapped_colortable[FIXED_COLOUR] = ((r & 0x1f) | ((g & 0x1f) << 5) | ((b & 0x1f) << 10));
906 } break;
907 case SETINI: /* Screen mode/video select */
908 /* FIXME: We only support line count here */
909 snes_ppu.beam.last_visible_line = (data & 0x4) ? 240 : 225;
910 #ifdef SNES_DBG_REG_W
911 if( (data & 0x8) != (snes_ram[SETINI] & 0x8) )
912 log_cb(RETRO_LOG_DEBUG, LOGPRE "Pseudo 512 mode: %s\n", (data & 0x8) ? "on" : "off" );
913 #endif
914 break;
915 case APU00: /* Audio port register */
916 case APU01: /* Audio port register */
917 case APU02: /* Audio port register */
918 case APU03: /* Audio port register */
919 if( spc_usefakeapu )
920 fakespc_port_w( offset & 0x3, data );
921 else
922 {
923 cpu_boost_interleave(0, TIME_IN_USEC(20));
924 spc_port_in[offset & 0x3] = data;
925 }
926 return;
927 case WMDATA: /* Data to write to WRAM */
928 {
929 UINT32 addr = ((snes_ram[WMADDH] & 0x1) << 16) | (snes_ram[WMADDM] << 8) | snes_ram[WMADDL];
930
931 cpu_writemem24( 0x7e0000 + addr++, data );
932 snes_ram[WMADDH] = (addr >> 16) & 0x1;
933 snes_ram[WMADDM] = (addr >> 8) & 0xff;
934 snes_ram[WMADDL] = addr & 0xff;
935 return;
936 }
937 case WMADDL: /* Address to read/write to wram (low) */
938 case WMADDM: /* Address to read/write to wram (mid) */
939 case WMADDH: /* Address to read/write to wram (high) */
940 break;
941 case OLDJOY1: /* Old NES joystick support */
942 if( (data & 0x1) && !(snes_ram[offset] & 0x1) )
943 {
944 joypad[0].oldrol = 0;
945 joypad[1].oldrol = 0;
946 joypad[2].oldrol = 0;
947 joypad[3].oldrol = 0;
948 }
949 break;
950 case OLDJOY2: /* Old NES joystick support */
951 case NMITIMEN: /* Flag for v-blank, timer int. and joy read */
952 case WRIO: /* Programmable I/O port */
953 case WRMPYA: /* Multiplier A */
954 break;
955 case WRMPYB: /* Multiplier B */
956 {
957 UINT32 c = snes_ram[WRMPYA] * data;
958 snes_ram[RDMPYL] = c & 0xff;
959 snes_ram[RDMPYH] = (c >> 8) & 0xff;
960 } break;
961 case WRDIVL: /* Dividend (low) */
962 case WRDIVH: /* Dividend (high) */
963 break;
964 case WRDVDD: /* Divisor */
965 {
966 UINT16 value, dividend, remainder;
967 dividend = remainder = 0;
968 value = (snes_ram[WRDIVH] << 8) + snes_ram[WRDIVL];
969 if( data > 0 )
970 {
971 dividend = value / data;
972 remainder = value % data;
973 }
974 else
975 {
976 dividend = 0xffff;
977 remainder = value;
978 }
979 snes_ram[RDDIVL] = dividend & 0xff;
980 snes_ram[RDDIVH] = (dividend >> 8) & 0xff;
981 snes_ram[RDMPYL] = remainder & 0xff;
982 snes_ram[RDMPYH] = (remainder >> 8) & 0xff;
983 } break;
984 case HTIMEL: /* H-Count timer settings (low) */
985 case HTIMEH: /* H-Count timer settings (high) */
986 case VTIMEL: /* V-Count timer settings (low) */
987 case VTIMEH: /* V-Count timer settings (high) */
988 break;
989 case MDMAEN: /* GDMA channel designation and trigger */
990 snes_gdma( data );
991 data = 0; /* Once DMA is done we need to reset all bits to 0 */
992 break;
993 case HDMAEN: /* HDMA channel designation */
994 break;
995 case MEMSEL: /* Access cycle designation in memory (2) area */
996 /* FIXME: Need to adjust the speed only during access of banks 0x80+
997 * Currently we are just increasing it no matter what */
998 cpunum_set_clockscale( 0, (data & 0x1) ? 1.335820896 : 1.0 );
999 #ifdef SNES_DBG_REG_W
1000 if( (data & 0x1) != (snes_ram[MEMSEL] & 0x1) )
1001 log_cb(RETRO_LOG_DEBUG, LOGPRE "CPU speed: %f Mhz\n", (data & 0x1) ? 3.58 : 2.68 );
1002 #endif
1003 break;
1004 /* Following are read-only */
1005 case HVBJOY: /* H/V blank and joypad enable */
1006 case MPYL: /* Multiplication result (low) */
1007 case MPYM: /* Multiplication result (mid) */
1008 case MPYH: /* Multiplication result (high) */
1009 case RDIO:
1010 case RDDIVL:
1011 case RDDIVH:
1012 case RDMPYL:
1013 case RDMPYH:
1014 case JOY1L:
1015 case JOY1H:
1016 case JOY2L:
1017 case JOY2H:
1018 case JOY3L:
1019 case JOY3H:
1020 case JOY4L:
1021 case JOY4H:
1022 #ifdef MAME_DEBUG
1023 log_cb(RETRO_LOG_DEBUG, LOGPRE "Write to read-only register: %X value: %X", offset, data );
1024 #endif /* MAME_DEBUG */
1025 return;
1026 /* Below is all DMA related */
1027 case DMAP0: case BBAD0: case A1T0L: case A1T0H: case A1B0: case DAS0L:
1028 case DAS0H: case DSAB0: case A2A0L: case A2A0H: case NTRL0:
1029 case DMAP1: case BBAD1: case A1T1L: case A1T1H: case A1B1: case DAS1L:
1030 case DAS1H: case DSAB1: case A2A1L: case A2A1H: case NTRL1:
1031 case DMAP2: case BBAD2: case A1T2L: case A1T2H: case A1B2: case DAS2L:
1032 case DAS2H: case DSAB2: case A2A2L: case A2A2H: case NTRL2:
1033 case DMAP3: case BBAD3: case A1T3L: case A1T3H: case A1B3: case DAS3L:
1034 case DAS3H: case DSAB3: case A2A3L: case A2A3H: case NTRL3:
1035 case DMAP4: case BBAD4: case A1T4L: case A1T4H: case A1B4: case DAS4L:
1036 case DAS4H: case DSAB4: case A2A4L: case A2A4H: case NTRL4:
1037 case DMAP5: case BBAD5: case A1T5L: case A1T5H: case A1B5: case DAS5L:
1038 case DAS5H: case DSAB5: case A2A5L: case A2A5H: case NTRL5:
1039 case DMAP6: case BBAD6: case A1T6L: case A1T6H: case A1B6: case DAS6L:
1040 case DAS6H: case DSAB6: case A2A6L: case A2A6H: case NTRL6:
1041 case DMAP7: case BBAD7: case A1T7L: case A1T7H: case A1B7: case DAS7L:
1042 case DAS7H: case DSAB7: case A2A7L: case A2A7H: case NTRL7:
1043 break;
1044 }
1045
1046 snes_ram[offset] = data;
1047 }
1048
1049 /* This function checks everything is in a valid range and returns how
1050 * 'valid' this section is as an information block. */
snes_validate_infoblock(UINT8 * infoblock,UINT16 offset)1051 static int snes_validate_infoblock( UINT8 *infoblock, UINT16 offset )
1052 {
1053 INT8 valid = 6;
1054
1055 /* Check the CRC and inverse CRC */
1056 if( ((infoblock[offset + 0x1c] + (infoblock[offset + 0x1d] << 8)) |
1057 (infoblock[offset + 0x1e] + (infoblock[offset + 0x1f] << 8))) != 0xffff )
1058 {
1059 valid -= 3;
1060 }
1061 /* Check the ROM Size is in a valid range */
1062 if( infoblock[offset + 0x17] > 13 )
1063 {
1064 valid--;
1065 }
1066 /* Check the SRAM size */
1067 if( infoblock[offset + 0x18] > 8 )
1068 {
1069 valid--;
1070 }
1071 /* Check the Country is in a valid range */
1072 if( infoblock[offset + 0x19] > 13 )
1073 {
1074 valid--;
1075 }
1076 /* Check the game version */
1077 if( infoblock[offset + 0x1b] >= 128 )
1078 {
1079 valid--;
1080 }
1081
1082 if( valid < 0 )
1083 {
1084 valid = 0;
1085 }
1086
1087 return valid;
1088 }
1089
DRIVER_INIT(snes)1090 DRIVER_INIT( snes )
1091 {
1092 int i;
1093 UINT16 totalblocks, readblocks;
1094 UINT8 *rom;
1095
1096 rom = memory_region( REGION_USER3 );
1097 snes_ram = memory_region( REGION_CPU1 );
1098 memset( snes_ram, 0, 0x1000000 );
1099
1100 /* all NSS games seem to use MODE 20 */
1101 cart.mode = SNES_MODE_20;
1102 cart.sram_max = 0x40000;
1103
1104 /* Find the number of blocks in this ROM */
1105 /*totalblocks = ((mame_fsize(file) - offset) >> (cart.mode == MODE_20 ? 15 : 16));*/
1106 totalblocks = (memory_region_length(REGION_USER3) / 0x8000) - 1;
1107
1108 /* FIXME: Insert crc check here */
1109
1110 readblocks = 0;
1111 {
1112 /* In mode 20, all blocks are 32kb. There are upto 96 blocks, giving a
1113 * total of 24mbit(3mb) of ROM.
1114 * The first 48 blocks are located in banks 0x00 to 0x2f at address
1115 * 0x8000. They are mirrored in banks 0x80 to 0xaf.
1116 * The next 16 blocks are located in banks 0x30 to 0x3f at address
1117 * 0x8000. They are mirrored in banks 0xb0 to 0xbf.
1118 * The final 32 blocks are located in banks 0x40 - 0x5f at address
1119 * 0x8000. They are mirrored in banks 0xc0 to 0xdf.
1120 */
1121 i = 0;
1122 while( i < 96 && readblocks <= totalblocks )
1123 {
1124 /*mame_fread( file, &snes_ram[(i++ * 0x10000) + 0x8000], 0x8000);*/
1125 memcpy(&snes_ram[(i * 0x10000) + 0x8000], &rom[i * 0x8000], 0x8000);
1126 i++;
1127 readblocks++;
1128 }
1129 }
1130
1131 /* Find the amount of sram */
1132 cart.sram = snes_r_bank1(0x00ffd8);
1133 if( cart.sram > 0 )
1134 {
1135 cart.sram = ((1 << (cart.sram + 3)) / 8);
1136 if( cart.sram > cart.sram_max )
1137 cart.sram = cart.sram_max;
1138 }
1139
1140 free_memory_region(REGION_USER3);
1141 }
1142
1143
INTERRUPT_GEN(snes_scanline_interrupt)1144 INTERRUPT_GEN(snes_scanline_interrupt)
1145 {
1146 /* Start of VBlank */
1147 if( snes_ppu.beam.current_vert == snes_ppu.beam.last_visible_line )
1148 {
1149 snes_ram[HVBJOY] |= 0x80; /* Set vblank bit to on */
1150 snes_ram[STAT77] &= 0x3f; /* Clear Time Over and Range Over bits - done every nmi (presumably because no sprites drawn here) */
1151 snes_ram[RDNMI] |= 0x80; /* Set NMI occured bit */
1152 if( snes_ram[NMITIMEN] & 0x80 ) /* NMI only signaled if this bit set */
1153 {
1154 cpu_set_irq_line( 0, G65816_LINE_NMI, HOLD_LINE );
1155 }
1156 }
1157
1158 /* Setup HDMA on start of new frame */
1159 if( snes_ppu.beam.current_vert == 0 )
1160 snes_hdma_init();
1161
1162 /* Let's draw the current line */
1163 if( snes_ppu.beam.current_vert < snes_ppu.beam.last_visible_line )
1164 {
1165 /* Do HDMA */
1166 if( snes_ram[HDMAEN] )
1167 snes_hdma();
1168
1169 snes_refresh_scanline( snes_ppu.beam.current_vert );
1170 }
1171 else
1172 {
1173 joypad[0].low = readinputport( 0 );
1174 joypad[0].high = readinputport( 1 );
1175 joypad[1].low = readinputport( 2 );
1176 joypad[1].high = readinputport( 3 );
1177 joypad[2].low = readinputport( 4 );
1178 joypad[2].high = readinputport( 5 );
1179 joypad[3].low = readinputport( 6 );
1180 joypad[3].high = readinputport( 7 );
1181 }
1182
1183 /* Vertical IRQ timer */
1184 if( snes_ram[NMITIMEN] & 0x20 )
1185 {
1186 if( snes_ppu.beam.current_vert == (((snes_ram[VTIMEH] << 8) | snes_ram[VTIMEL]) & 0x1ff) )
1187 {
1188 snes_ram[TIMEUP] = 0x80; /* Indicate that irq occured */
1189 cpu_set_irq_line( 0, G65816_LINE_IRQ, HOLD_LINE );
1190 }
1191 }
1192 /* Horizontal IRQ timer */
1193 /* FIXME: Commented out as it causes heaps of trouble right now */
1194 /* if( snes_ram[NMITIMEN] & 0x10 )
1195 {
1196 if( (((snes_ram[HTIMEH] << 8) | snes_ram[HTIMEL]) & 0x1ff) )
1197 {
1198 snes_ram[TIMEUP] = 0x80;
1199 cpu_set_irq_line( 0, G65816_LINE_IRQ, HOLD_LINE );
1200 }
1201 } */
1202
1203 /* Increase current line */
1204 snes_ppu.beam.current_vert = (snes_ppu.beam.current_vert + 1) % (snes_ram[STAT78] == SNES_NTSC ? SNES_MAX_LINES_NTSC : SNES_MAX_LINES_PAL);
1205 if( snes_ppu.beam.current_vert == 0 )
1206 { /* VBlank is over, time for a new frame */
1207 cpu_writemem24( OAMADDL, snes_ppu.oam.address_low ); /* Reset oam address */
1208 cpu_writemem24( OAMADDH, snes_ppu.oam.address_high );
1209 snes_ram[HVBJOY] &= 0x7f; /* Clear vblank bit */
1210 snes_ram[RDNMI] &= 0x7f; /* Clear nmi occured bit */
1211 cpu_set_irq_line( 0, G65816_LINE_NMI, CLEAR_LINE );
1212 }
1213 }
1214
snes_hdma_init()1215 void snes_hdma_init()
1216 {
1217 UINT8 mask = 1, dma = 0, i;
1218
1219 snes_hdma_chnl = snes_ram[HDMAEN];
1220 for( i = 0; i < 8; i++ )
1221 {
1222 if( snes_ram[HDMAEN] & mask )
1223 {
1224 snes_ram[SNES_DMA_BASE + dma + 8] = snes_ram[SNES_DMA_BASE + dma + 2];
1225 snes_ram[SNES_DMA_BASE + dma + 9] = snes_ram[SNES_DMA_BASE + dma + 3];
1226 snes_ram[SNES_DMA_BASE + dma + 0xa] = 0;
1227 }
1228 dma += 0x10;
1229 mask <<= 1;
1230 }
1231 }
1232
snes_hdma()1233 void snes_hdma()
1234 {
1235 UINT8 mask = 1, dma = 0, i, contmode;
1236 UINT16 bbus;
1237 UINT32 abus;
1238
1239 /* Assume priority of the 8 DMA channels is 0-7 */
1240 for( i = 0; i < 8; i++ )
1241 {
1242 if( snes_hdma_chnl & mask )
1243 {
1244 /* Check if we need to read a new line from the table */
1245 if( !(snes_ram[SNES_DMA_BASE + dma + 0xa] & 0x7f ) )
1246 {
1247 abus = (snes_ram[SNES_DMA_BASE + dma + 4] << 16) + (snes_ram[SNES_DMA_BASE + dma + 9] << 8) + snes_ram[SNES_DMA_BASE + dma + 8];
1248
1249 /* Get the number of lines */
1250 snes_ram[SNES_DMA_BASE + dma + 0xa] = cpu_readmem24(abus);
1251 if( !snes_ram[SNES_DMA_BASE + dma + 0xa] )
1252 {
1253 /* No more lines so clear HDMA */
1254 snes_hdma_chnl &= ~mask;
1255 continue;
1256 }
1257 abus++;
1258 snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
1259 snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
1260 if( snes_ram[SNES_DMA_BASE + dma] & 0x40 )
1261 {
1262 snes_ram[SNES_DMA_BASE + dma + 5] = cpu_readmem24(abus++);
1263 snes_ram[SNES_DMA_BASE + dma + 6] = cpu_readmem24(abus++);
1264 snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
1265 snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
1266 }
1267 }
1268
1269 contmode = (--snes_ram[SNES_DMA_BASE + dma + 0xa]) & 0x80;
1270
1271 /* Transfer addresses */
1272 if( snes_ram[SNES_DMA_BASE + dma] & 0x40 ) /* Indirect */
1273 abus = (snes_ram[SNES_DMA_BASE + dma + 7] << 16) + (snes_ram[SNES_DMA_BASE + dma + 6] << 8) + snes_ram[SNES_DMA_BASE + dma + 5];
1274 else /* Absolute */
1275 abus = (snes_ram[SNES_DMA_BASE + dma + 4] << 16) + (snes_ram[SNES_DMA_BASE + dma + 9] << 8) + snes_ram[SNES_DMA_BASE + dma + 8];
1276 bbus = 0x2100 + snes_ram[SNES_DMA_BASE + dma + 1];
1277
1278 #ifdef SNES_DBG_HDMA
1279 log_cb(RETRO_LOG_DEBUG, LOGPRE "HDMA-Ch: %d(%s) abus: %X bbus: %X type: %d(%X %X)\n", i, snes_ram[SNES_DMA_BASE + dma] & 0x40 ? "Indirect" : "Absolute", abus, bbus, snes_ram[SNES_DMA_BASE + dma] & 0x7, snes_ram[SNES_DMA_BASE + dma + 8],snes_ram[SNES_DMA_BASE + dma + 9] );
1280 #endif
1281
1282 switch( snes_ram[SNES_DMA_BASE + dma] & 0x7 )
1283 {
1284 case 0: /* 1 address */
1285 {
1286 cpu_writemem24( bbus, cpu_readmem24(abus++));
1287 } break;
1288 case 1: /* 2 addresses (l,h) */
1289 {
1290 cpu_writemem24( bbus, cpu_readmem24(abus++));
1291 cpu_writemem24( bbus + 1, cpu_readmem24(abus++));
1292 } break;
1293 case 2: /* Write twice (l,l) */
1294 {
1295 cpu_writemem24( bbus, cpu_readmem24(abus++));
1296 cpu_writemem24( bbus, cpu_readmem24(abus++));
1297 } break;
1298 case 3: /* 2 addresses/Write twice (l,l,h,h) */
1299 {
1300 cpu_writemem24( bbus, cpu_readmem24(abus++));
1301 cpu_writemem24( bbus, cpu_readmem24(abus++));
1302 cpu_writemem24( bbus + 1, cpu_readmem24(abus++));
1303 cpu_writemem24( bbus + 1, cpu_readmem24(abus++));
1304 } break;
1305 case 4: /* 4 addresses (l,h,l,h) */
1306 {
1307 cpu_writemem24( bbus, cpu_readmem24(abus++));
1308 cpu_writemem24( bbus + 1, cpu_readmem24(abus++));
1309 cpu_writemem24( bbus + 2, cpu_readmem24(abus++));
1310 cpu_writemem24( bbus + 3, cpu_readmem24(abus++));
1311 } break;
1312 default:
1313 #ifdef MAME_DEBUG
1314 log_cb(RETRO_LOG_DEBUG, LOGPRE " HDMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x7 );
1315 #endif
1316 break;
1317 }
1318
1319 /* Update address */
1320 if( contmode )
1321 {
1322 if( snes_ram[SNES_DMA_BASE + dma] & 0x40 ) /* Indirect */
1323 {
1324 snes_ram[SNES_DMA_BASE + dma + 5] = abus & 0xff;
1325 snes_ram[SNES_DMA_BASE + dma + 6] = (abus >> 8) & 0xff;
1326 }
1327 else /* Absolute */
1328 {
1329 snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
1330 snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
1331 }
1332 }
1333
1334 if( !(snes_ram[SNES_DMA_BASE + dma + 0xa] & 0x7f) )
1335 {
1336 if( !(snes_ram[SNES_DMA_BASE + dma] & 0x40) ) /* Absolute */
1337 {
1338 if( !contmode )
1339 {
1340 snes_ram[SNES_DMA_BASE + dma + 8] = abus & 0xff;
1341 snes_ram[SNES_DMA_BASE + dma + 9] = (abus >> 8) & 0xff;
1342 }
1343 }
1344 }
1345 }
1346 dma += 0x10;
1347 mask <<= 1;
1348 }
1349 }
1350
snes_gdma(UINT8 channels)1351 void snes_gdma( UINT8 channels )
1352 {
1353 UINT8 mask = 1, dma = 0, i;
1354 INT8 increment;
1355 UINT16 bbus;
1356 UINT32 abus, length;
1357
1358 /* Assume priority of the 8 DMA channels is 0-7 */
1359 for( i = 0; i < 8; i++ )
1360 {
1361 if( channels & mask )
1362 {
1363 /* Find transfer addresses */
1364 abus = (snes_ram[SNES_DMA_BASE + dma + 4] << 16) + (snes_ram[SNES_DMA_BASE + dma + 3] << 8) + snes_ram[SNES_DMA_BASE + dma + 2];
1365 bbus = 0x2100 + snes_ram[SNES_DMA_BASE + dma + 1];
1366
1367 /* Auto increment */
1368 if( snes_ram[SNES_DMA_BASE + dma] & 0x8 )
1369 {
1370 increment = 0;
1371 }
1372 else
1373 {
1374 if( snes_ram[SNES_DMA_BASE + dma] & 0x10 )
1375 increment = -1;
1376 else
1377 increment = 1;
1378 }
1379
1380 /* Number of bytes to transfer */
1381 length = (snes_ram[SNES_DMA_BASE + dma + 6] << 8) + snes_ram[SNES_DMA_BASE + dma + 5];
1382 if( !length )
1383 length = 0x10000; /* 0x0000 really means 0x10000 */
1384
1385 #ifdef SNES_DBG_GDMA
1386 log_cb(RETRO_LOG_DEBUG, LOGPRE "GDMA-Ch %d: len: %X, abus: %X, bbus: %X, incr: %d, dir: %s, type: %d\n", i, length, abus, bbus, increment, snes_ram[SNES_DMA_BASE + dma] & 0x80 ? "PPU->CPU" : "CPU->PPU", snes_ram[SNES_DMA_BASE + dma] & 0x7 );
1387 #endif
1388
1389 switch( snes_ram[SNES_DMA_BASE + dma] & 0x7 )
1390 {
1391 case 0: /* 1 address */
1392 case 2: /* 1 address ?? */
1393 {
1394 while( length-- )
1395 {
1396 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1397 cpu_writemem24( abus, cpu_readmem24(bbus) );
1398 else /* CPU->PPU */
1399 cpu_writemem24( bbus, cpu_readmem24(abus) );
1400 abus += increment;
1401 }
1402 } break;
1403 case 1: /* 2 addresses (l,h) */
1404 {
1405 while( length-- )
1406 {
1407 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1408 cpu_writemem24( abus, cpu_readmem24(bbus) );
1409 else /* CPU->PPU */
1410 cpu_writemem24( bbus, cpu_readmem24(abus) );
1411 abus += increment;
1412 if( !(length--) )
1413 break;
1414 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1415 cpu_writemem24( abus, cpu_readmem24(bbus + 1) );
1416 else /* CPU->PPU */
1417 cpu_writemem24( bbus + 1, cpu_readmem24(abus) );
1418 abus += increment;
1419 }
1420 } break;
1421 case 3: /* 2 addresses/write twice (l,l,h,h) */
1422 {
1423 while( length-- )
1424 {
1425 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1426 cpu_writemem24( abus, cpu_readmem24(bbus) );
1427 else /* CPU->PPU */
1428 cpu_writemem24( bbus, cpu_readmem24(abus) );
1429 abus += increment;
1430 if( !(length--) )
1431 break;
1432 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1433 cpu_writemem24( abus, cpu_readmem24(bbus) );
1434 else /* CPU->PPU */
1435 cpu_writemem24( bbus, cpu_readmem24(abus) );
1436 abus += increment;
1437 if( !(length--) )
1438 break;
1439 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1440 cpu_writemem24( abus, cpu_readmem24(bbus + 1) );
1441 else /* CPU->PPU */
1442 cpu_writemem24( bbus + 1, cpu_readmem24(abus) );
1443 abus += increment;
1444 if( !(length--) )
1445 break;
1446 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1447 cpu_writemem24( abus, cpu_readmem24(bbus + 1) );
1448 else /* CPU->PPU */
1449 cpu_writemem24( bbus + 1, cpu_readmem24(abus) );
1450 abus += increment;
1451 }
1452 } break;
1453 case 4: /* 4 addresses (l,h,l,h) */
1454 {
1455 while( length-- )
1456 {
1457 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1458 cpu_writemem24( abus, cpu_readmem24(bbus) );
1459 else /* CPU->PPU */
1460 cpu_writemem24( bbus, cpu_readmem24(abus) );
1461 abus += increment;
1462 if( !(length--) )
1463 break;
1464 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1465 cpu_writemem24( abus, cpu_readmem24(bbus + 1) );
1466 else /* CPU->PPU */
1467 cpu_writemem24( bbus + 1, cpu_readmem24(abus) );
1468 abus += increment;
1469 if( !(length--) )
1470 break;
1471 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1472 cpu_writemem24( abus, cpu_readmem24(bbus + 2) );
1473 else /* CPU->PPU */
1474 cpu_writemem24( bbus + 2, cpu_readmem24(abus) );
1475 abus += increment;
1476 if( !(length--) )
1477 break;
1478 if( snes_ram[SNES_DMA_BASE + dma] & 0x80 ) /* PPU->CPU */
1479 cpu_writemem24( abus, cpu_readmem24(bbus + 3) );
1480 else /* CPU->PPU */
1481 cpu_writemem24( bbus + 3, cpu_readmem24(abus) );
1482 abus += increment;
1483 }
1484 } break;
1485 default:
1486 #ifdef MAME_DEBUG
1487 log_cb(RETRO_LOG_DEBUG, LOGPRE " GDMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x7 );
1488 #endif
1489 break;
1490 }
1491 /* We're done so write the new abus back to the registers */
1492 snes_ram[SNES_DMA_BASE + dma + 2] = abus & 0xff;
1493 snes_ram[SNES_DMA_BASE + dma + 3] = (abus >> 8) & 0xff;
1494 snes_ram[SNES_DMA_BASE + dma + 5] = 0;
1495 snes_ram[SNES_DMA_BASE + dma + 6] = 0;
1496 }
1497 dma += 0x10;
1498 mask <<= 1;
1499 }
1500 }
1501