src/mame/machine/snes.c
| r7584 | r7585 | |
| 26 | 26 | UINT8 *snes_vram = NULL; /* Video RAM (Should be 16-bit, but it's easier this way) */ |
| 27 | 27 | UINT16 *snes_cgram = NULL; /* Colour RAM */ |
| 28 | 28 | UINT16 *snes_oam = NULL; /* Object Attribute Memory */ |
| 29 | | static UINT16 cgram_address; /* CGRAM address */ |
| 30 | | static UINT8 vram_read_offset; /* VRAM read offset */ |
| 31 | 29 | UINT8 spc_port_in[4]; /* Port for sending data to the SPC700 */ |
| 32 | 30 | UINT8 spc_port_out[4]; /* Port for receiving data from the SPC700 */ |
| 33 | | static UINT8 snes_hdma_chnl; /* channels enabled for HDMA */ |
| 34 | | static UINT8 read_ophct = 0, read_opvct = 0; |
| 35 | | static emu_timer *snes_scanline_timer; |
| 36 | | static emu_timer *snes_hblank_timer; |
| 37 | | static emu_timer *snes_nmi_timer; |
| 38 | | static emu_timer *snes_hirq_timer; |
| 39 | | static emu_timer *snes_div_timer; |
| 40 | | static emu_timer *snes_mult_timer; |
| 41 | | static UINT16 hblank_offset; |
| 42 | | UINT16 snes_htmult; /* in 512 wide, we run HTOTAL double and halve it on latching */ |
| 31 | |
| 43 | 32 | UINT8 snes_has_addon_chip; |
| 44 | 33 | UINT32 snes_rom_size; |
| 45 | 34 | |
| 46 | 35 | // full graphic variables |
| 47 | | static UINT16 vram_fgr_high, vram_fgr_increment, vram_fgr_count, vram_fgr_mask, vram_fgr_shift, vram_read_buffer; |
| 48 | 36 | static const UINT16 vram_fgr_inctab[4] = { 1, 32, 128, 128 }; |
| 49 | 37 | static const UINT16 vram_fgr_inccnts[4] = { 0, 32, 64, 128 }; |
| 50 | 38 | static const UINT16 vram_fgr_shiftab[4] = { 0, 5, 6, 7 }; |
| 51 | 39 | |
| 40 | static void snes_dma(const address_space *space, UINT8 channels); |
| 41 | static void snes_hdma_init(running_machine *machine); |
| 42 | static void snes_hdma(const address_space *space); |
| 43 | |
| 52 | 44 | struct snes_cart_info snes_cart; |
| 53 | 45 | |
| 54 | 46 | // add-on chip emulators |
| r7584 | r7585 | |
| 70 | 62 | *************************************/ |
| 71 | 63 | |
| 72 | 64 | // utility function - latches the H/V counters. Used by IRQ, writes to WRIO, etc. |
| 73 | | void snes_latch_counters(running_machine *machine) |
| 65 | void snes_latch_counters( running_machine *machine ) |
| 74 | 66 | { |
| 75 | | snes_ppu.beam.current_horz = video_screen_get_hpos(machine->primary_screen) / snes_htmult; |
| 67 | snes_state *state = (snes_state *)machine->driver_data; |
| 68 | |
| 69 | snes_ppu.beam.current_horz = video_screen_get_hpos(machine->primary_screen) / state->htmult; |
| 76 | 70 | snes_ppu.beam.latch_vert = video_screen_get_vpos(machine->primary_screen); |
| 77 | 71 | snes_ppu.beam.latch_horz = snes_ppu.beam.current_horz; |
| 78 | 72 | snes_ram[STAT78] |= 0x40; // indicate we latched |
| 79 | | // read_ophct = read_opvct = 0; // clear read flags - 2009-08: I think we must clear these when STAT78 is read... |
| 73 | // state->read_ophct = state->read_opvct = 0; // clear read flags - 2009-08: I think we must clear these when STAT78 is read... |
| 80 | 74 | |
| 81 | 75 | // printf("latched @ H %d V %d\n", snes_ppu.beam.latch_horz, snes_ppu.beam.latch_vert); |
| 82 | 76 | } |
| 83 | 77 | |
| 84 | 78 | static TIMER_CALLBACK( snes_nmi_tick ) |
| 85 | 79 | { |
| 80 | snes_state *state = (snes_state *)machine->driver_data; |
| 81 | |
| 86 | 82 | // pull NMI |
| 87 | | cputag_set_input_line(machine, "maincpu", G65816_LINE_NMI, ASSERT_LINE ); |
| 83 | cputag_set_input_line(machine, "maincpu", G65816_LINE_NMI, ASSERT_LINE); |
| 88 | 84 | |
| 89 | 85 | // don't happen again |
| 90 | | timer_adjust_oneshot(snes_nmi_timer, attotime_never, 0); |
| 86 | timer_adjust_oneshot(state->nmi_timer, attotime_never, 0); |
| 91 | 87 | } |
| 92 | 88 | |
| 93 | | static void snes_hirq_tick(running_machine *machine) |
| 89 | static void snes_hirq_tick( running_machine *machine ) |
| 94 | 90 | { |
| 91 | snes_state *state = (snes_state *)machine->driver_data; |
| 92 | |
| 95 | 93 | // latch the counters and pull IRQ |
| 96 | 94 | // (don't need to switch to the 65816 context, we don't do anything dependant on it) |
| 97 | 95 | snes_latch_counters(machine); |
| 98 | 96 | snes_ram[TIMEUP] = 0x80; /* Indicate that irq occured */ |
| 99 | | cputag_set_input_line(machine, "maincpu", G65816_LINE_IRQ, ASSERT_LINE ); |
| 97 | cputag_set_input_line(machine, "maincpu", G65816_LINE_IRQ, ASSERT_LINE); |
| 100 | 98 | |
| 101 | 99 | // don't happen again |
| 102 | | timer_adjust_oneshot(snes_hirq_timer, attotime_never, 0); |
| 100 | timer_adjust_oneshot(state->hirq_timer, attotime_never, 0); |
| 103 | 101 | } |
| 104 | 102 | |
| 105 | 103 | static TIMER_CALLBACK( snes_hirq_tick_callback ) |
| r7584 | r7585 | |
| 122 | 120 | |
| 123 | 121 | static TIMER_CALLBACK( snes_reset_hdma ) |
| 124 | 122 | { |
| 125 | | snes_hdma_init(); |
| 123 | snes_hdma_init(machine); |
| 126 | 124 | } |
| 127 | 125 | |
| 128 | 126 | static TIMER_CALLBACK( snes_scanline_tick ) |
| r7584 | r7585 | |
| 163 | 161 | |
| 164 | 162 | if (setirq) |
| 165 | 163 | { |
| 166 | | // printf("HIRQ @ %d, %d\n", pixel*snes_htmult, snes_ppu.beam.current_vert); |
| 164 | // printf("HIRQ @ %d, %d\n", pixel * state->htmult, snes_ppu.beam.current_vert); |
| 167 | 165 | if (pixel == 0) |
| 168 | 166 | { |
| 169 | 167 | snes_hirq_tick(machine); |
| 170 | 168 | } |
| 171 | 169 | else |
| 172 | 170 | { |
| 173 | | timer_adjust_oneshot(snes_hirq_timer, video_screen_get_time_until_pos(machine->primary_screen, snes_ppu.beam.current_vert, pixel*snes_htmult), 0); |
| 171 | timer_adjust_oneshot(state->hirq_timer, video_screen_get_time_until_pos(machine->primary_screen, snes_ppu.beam.current_vert, pixel * state->htmult), 0); |
| 174 | 172 | } |
| 175 | 173 | } |
| 176 | 174 | } |
| r7584 | r7585 | |
| 186 | 184 | if (snes_ram[NMITIMEN] & 0x80) /* NMI only signaled if this bit set */ |
| 187 | 185 | { |
| 188 | 186 | // NMI goes off about 12 cycles after this (otherwise Chrono Trigger, NFL QB Club, etc. lock up) |
| 189 | | timer_adjust_oneshot(snes_nmi_timer, cputag_clocks_to_attotime(machine, "maincpu", 12), 0); |
| 187 | timer_adjust_oneshot(state->nmi_timer, cputag_clocks_to_attotime(machine, "maincpu", 12), 0); |
| 190 | 188 | } |
| 191 | 189 | } |
| 192 | 190 | |
| 193 | 191 | // hdma reset happens at scanline 0, H=~6 |
| 194 | 192 | if (snes_ppu.beam.current_vert == 0) |
| 195 | 193 | { |
| 196 | | snes_hdma_init(); |
| 194 | snes_hdma_init(machine); |
| 197 | 195 | } |
| 198 | 196 | |
| 199 | 197 | /* three lines after start of vblank we update the controllers (value from snes9x) */ |
| r7584 | r7585 | |
| 213 | 211 | cputag_set_input_line(machine, "maincpu", G65816_LINE_NMI, CLEAR_LINE ); |
| 214 | 212 | } |
| 215 | 213 | |
| 216 | | timer_adjust_oneshot(snes_scanline_timer, attotime_never, 0); |
| 217 | | timer_adjust_oneshot(snes_hblank_timer, video_screen_get_time_until_pos(machine->primary_screen, snes_ppu.beam.current_vert, hblank_offset*snes_htmult), 0); |
| 214 | timer_adjust_oneshot(state->scanline_timer, attotime_never, 0); |
| 215 | timer_adjust_oneshot(state->hblank_timer, video_screen_get_time_until_pos(machine->primary_screen, snes_ppu.beam.current_vert, state->hblank_offset * state->htmult), 0); |
| 218 | 216 | } |
| 219 | 217 | |
| 220 | 218 | /* This is called at the start of hblank *before* the scanline indicated in current_vert! */ |
| 221 | 219 | static TIMER_CALLBACK( snes_hblank_tick ) |
| 222 | 220 | { |
| 221 | snes_state *state = (snes_state *)machine->driver_data; |
| 223 | 222 | const address_space *cpu0space = cputag_get_address_space(machine, "maincpu", ADDRESS_SPACE_PROGRAM); |
| 224 | 223 | int nextscan; |
| 225 | 224 | |
| 226 | 225 | snes_ppu.beam.current_vert = video_screen_get_vpos(machine->primary_screen); |
| 227 | 226 | |
| 228 | 227 | /* make sure we halt */ |
| 229 | | timer_adjust_oneshot(snes_hblank_timer, attotime_never, 0); |
| 228 | timer_adjust_oneshot(state->hblank_timer, attotime_never, 0); |
| 230 | 229 | |
| 231 | 230 | /* draw a scanline */ |
| 232 | 231 | if (snes_ppu.beam.current_vert <= snes_ppu.beam.last_visible_line) |
| r7584 | r7585 | |
| 251 | 250 | nextscan = 0; |
| 252 | 251 | } |
| 253 | 252 | |
| 254 | | timer_adjust_oneshot(snes_scanline_timer, video_screen_get_time_until_pos(machine->primary_screen, nextscan, 0), 0); |
| 253 | timer_adjust_oneshot(state->scanline_timer, video_screen_get_time_until_pos(machine->primary_screen, nextscan, 0), 0); |
| 255 | 254 | } |
| 256 | 255 | |
| 257 | 256 | /* FIXME: multiplication should take 8 CPU cycles & division 16 CPU cycles, but |
| r7584 | r7585 | |
| 298 | 297 | |
| 299 | 298 | static void snes_dynamic_res_change( running_machine *machine ) |
| 300 | 299 | { |
| 300 | snes_state *state = (snes_state *)machine->driver_data; |
| 301 | 301 | rectangle visarea = *video_screen_get_visible_area(machine->primary_screen); |
| 302 | 302 | attoseconds_t refresh; |
| 303 | 303 | |
| r7584 | r7585 | |
| 307 | 307 | |
| 308 | 308 | // fixme: should compensate for SNES_DBG_video |
| 309 | 309 | if (snes_ppu.mode == 5 || snes_ppu.mode == 6 ) |
| 310 | | snes_htmult = 2; |
| 310 | state->htmult = 2; |
| 311 | 311 | else |
| 312 | | snes_htmult = 1; |
| 312 | state->htmult = 1; |
| 313 | 313 | |
| 314 | 314 | /* FIXME: does the timing changes when the gfx mode is equal to 5 or 6? */ |
| 315 | 315 | if ((snes_ram[STAT78] & 0x10) == SNES_NTSC) |
| r7584 | r7585 | |
| 470 | 470 | { |
| 471 | 471 | UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL]; |
| 472 | 472 | |
| 473 | | snes_ppu.ppu1_open_bus = vram_read_buffer & 0xff; |
| 473 | snes_ppu.ppu1_open_bus = state->vram_read_buffer & 0xff; |
| 474 | 474 | |
| 475 | | if (!vram_fgr_high) |
| 475 | if (!state->vram_fgr_high) |
| 476 | 476 | { |
| 477 | | if (vram_fgr_count) |
| 477 | if (state->vram_fgr_count) |
| 478 | 478 | { |
| 479 | | UINT32 rem = addr & vram_fgr_mask; |
| 480 | | UINT32 faddr = (addr & ~vram_fgr_mask) + (rem >> vram_fgr_shift) + |
| 481 | | ((rem & (vram_fgr_count - 1)) << 3); |
| 479 | UINT32 rem = addr & state->vram_fgr_mask; |
| 480 | UINT32 faddr = (addr & ~state->vram_fgr_mask) + (rem >> state->vram_fgr_shift) + ((rem & (state->vram_fgr_count - 1)) << 3); |
| 482 | 481 | |
| 483 | | vram_read_buffer = snes_vram[(faddr<<1)&0x1ffff] | snes_vram[((faddr<<1)+1) & 0x1ffff]<<8; |
| 482 | state->vram_read_buffer = snes_vram[(faddr << 1) & 0x1ffff] | snes_vram[((faddr << 1) + 1) & 0x1ffff] << 8; |
| 484 | 483 | } |
| 485 | 484 | else |
| 486 | 485 | { |
| 487 | | vram_read_buffer = snes_vram[(addr<<1)&0x1ffff] | snes_vram[((addr<<1)+1) & 0x1ffff]<<8; |
| 486 | state->vram_read_buffer = snes_vram[(addr<<1)&0x1ffff] | snes_vram[((addr<<1)+1) & 0x1ffff]<<8; |
| 488 | 487 | } |
| 489 | 488 | |
| 490 | | addr += vram_fgr_increment; |
| 491 | | snes_ram[VMADDL] = addr&0xff; |
| 492 | | snes_ram[VMADDH] = (addr>>8)&0xff; |
| 489 | addr += state->vram_fgr_increment; |
| 490 | snes_ram[VMADDL] = addr & 0xff; |
| 491 | snes_ram[VMADDH] = (addr >> 8) & 0xff; |
| 493 | 492 | } |
| 494 | 493 | } |
| 495 | 494 | return snes_ppu.ppu1_open_bus; |
| r7584 | r7585 | |
| 497 | 496 | { |
| 498 | 497 | UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL]; |
| 499 | 498 | |
| 500 | | snes_ppu.ppu1_open_bus = (vram_read_buffer>>8) & 0xff; |
| 499 | snes_ppu.ppu1_open_bus = (state->vram_read_buffer >> 8) & 0xff; |
| 501 | 500 | |
| 502 | | if (vram_fgr_high) |
| 501 | if (state->vram_fgr_high) |
| 503 | 502 | { |
| 504 | | if (vram_fgr_count) |
| 503 | if (state->vram_fgr_count) |
| 505 | 504 | { |
| 506 | | UINT32 rem = addr & vram_fgr_mask; |
| 507 | | UINT32 faddr = (addr & ~vram_fgr_mask) + (rem >> vram_fgr_shift) + |
| 508 | | ((rem & (vram_fgr_count - 1)) << 3); |
| 505 | UINT32 rem = addr & state->vram_fgr_mask; |
| 506 | UINT32 faddr = (addr & ~state->vram_fgr_mask) + (rem >> state->vram_fgr_shift) + ((rem & (state->vram_fgr_count - 1)) << 3); |
| 509 | 507 | |
| 510 | | vram_read_buffer = snes_vram[(faddr<<1)&0x1ffff] | snes_vram[((faddr<<1)+1) & 0x1ffff]<<8; |
| 508 | state->vram_read_buffer = snes_vram[(faddr << 1) & 0x1ffff] | snes_vram[((faddr << 1) + 1) & 0x1ffff] << 8; |
| 511 | 509 | } |
| 512 | 510 | else |
| 513 | 511 | { |
| 514 | | vram_read_buffer = snes_vram[(addr<<1)&0x1ffff] | snes_vram[((addr<<1)+1) & 0x1ffff]<<8; |
| 512 | state->vram_read_buffer = snes_vram[(addr << 1) & 0x1ffff] | snes_vram[((addr << 1) + 1) & 0x1ffff] << 8; |
| 515 | 513 | } |
| 516 | 514 | |
| 517 | | addr += vram_fgr_increment; |
| 518 | | snes_ram[VMADDL] = addr&0xff; |
| 519 | | snes_ram[VMADDH] = (addr>>8)&0xff; |
| 515 | addr += state->vram_fgr_increment; |
| 516 | snes_ram[VMADDL] = addr & 0xff; |
| 517 | snes_ram[VMADDH] = (addr >> 8) & 0xff; |
| 520 | 518 | } |
| 521 | 519 | } |
| 522 | 520 | return snes_ppu.ppu1_open_bus; |
| 523 | 521 | case RCGDATA: /* Read data from CGRAM */ |
| 524 | | if (!(cgram_address & 0x01)) |
| 522 | if (!(state->cgram_address & 0x01)) |
| 525 | 523 | { |
| 526 | | snes_ppu.ppu2_open_bus = ((UINT8 *)snes_cgram)[cgram_address] & 0xff; |
| 524 | snes_ppu.ppu2_open_bus = ((UINT8 *)snes_cgram)[state->cgram_address] & 0xff; |
| 527 | 525 | } |
| 528 | 526 | else |
| 529 | 527 | { |
| 530 | 528 | snes_ppu.ppu2_open_bus &= 0x80; |
| 531 | | snes_ppu.ppu2_open_bus |= ((UINT8 *)snes_cgram)[cgram_address] & 0x7f; |
| 529 | snes_ppu.ppu2_open_bus |= ((UINT8 *)snes_cgram)[state->cgram_address] & 0x7f; |
| 532 | 530 | } |
| 533 | 531 | |
| 534 | | cgram_address = (cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 532 | state->cgram_address = (state->cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 535 | 533 | return snes_ppu.ppu2_open_bus; |
| 536 | 534 | case OPHCT: /* Horizontal counter data by ext/soft latch */ |
| 537 | 535 | { |
| 538 | | if (read_ophct) |
| 536 | if (state->read_ophct) |
| 539 | 537 | { |
| 540 | 538 | snes_ppu.ppu2_open_bus &= 0xfe; |
| 541 | 539 | snes_ppu.ppu2_open_bus |= (snes_ppu.beam.latch_horz >> 8) & 0x01; |
| r7584 | r7585 | |
| 544 | 542 | { |
| 545 | 543 | snes_ppu.ppu2_open_bus = snes_ppu.beam.latch_horz & 0xff; |
| 546 | 544 | } |
| 547 | | read_ophct ^= 1; |
| 545 | state->read_ophct ^= 1; |
| 548 | 546 | return snes_ppu.ppu2_open_bus; |
| 549 | 547 | } |
| 550 | 548 | case OPVCT: /* Vertical counter data by ext/soft latch */ |
| 551 | 549 | { |
| 552 | | if (read_opvct) |
| 550 | if (state->read_opvct) |
| 553 | 551 | { |
| 554 | 552 | snes_ppu.ppu2_open_bus &= 0xfe; |
| 555 | 553 | snes_ppu.ppu2_open_bus |= (snes_ppu.beam.latch_vert >> 8) & 0x01; |
| r7584 | r7585 | |
| 558 | 556 | { |
| 559 | 557 | snes_ppu.ppu2_open_bus = snes_ppu.beam.latch_vert & 0xff; |
| 560 | 558 | } |
| 561 | | read_opvct ^= 1; |
| 559 | state->read_opvct ^= 1; |
| 562 | 560 | return snes_ppu.ppu2_open_bus; |
| 563 | 561 | } |
| 564 | 562 | case STAT77: /* PPU status flag and version number */ |
| r7584 | r7585 | |
| 570 | 568 | snes_ppu.ppu1_open_bus = value; |
| 571 | 569 | return snes_ppu.ppu1_open_bus; |
| 572 | 570 | case STAT78: /* PPU status flag and version number */ |
| 573 | | read_ophct = 0; |
| 574 | | read_opvct = 0; |
| 571 | state->read_ophct = 0; |
| 572 | state->read_opvct = 0; |
| 575 | 573 | value = snes_ram[offset]; |
| 576 | 574 | value |= (snes_ppu.ppu1_open_bus & 0x20); |
| 577 | 575 | value |= (snes_ppu.ppu2_version & 0x0f); |
| r7584 | r7585 | |
| 778 | 776 | snes_ppu.oam.next_charmap = (data & 0x03) << 1; |
| 779 | 777 | snes_ppu.oam.next_name_select = (((data & 0x18) >> 3) * 0x1000) << 1; |
| 780 | 778 | snes_ppu.oam.next_size = (data & 0xe0) >> 5; |
| 781 | | switch ((data & 0xe0) >> 5) |
| 782 | | { |
| 783 | | case 0: /* 8 & 16 */ |
| 784 | | snes_ppu.oam.size[0] = 1; |
| 785 | | snes_ppu.oam.size[1] = 2; |
| 786 | | break; |
| 787 | | case 1: /* 8 & 32 */ |
| 788 | | snes_ppu.oam.size[0] = 1; |
| 789 | | snes_ppu.oam.size[1] = 4; |
| 790 | | break; |
| 791 | | case 2: /* 8 & 64 */ |
| 792 | | snes_ppu.oam.size[0] = 1; |
| 793 | | snes_ppu.oam.size[1] = 8; |
| 794 | | break; |
| 795 | | case 3: /* 16 & 32 */ |
| 796 | | snes_ppu.oam.size[0] = 2; |
| 797 | | snes_ppu.oam.size[1] = 4; |
| 798 | | break; |
| 799 | | case 4: /* 16 & 64 */ |
| 800 | | snes_ppu.oam.size[0] = 2; |
| 801 | | snes_ppu.oam.size[1] = 8; |
| 802 | | break; |
| 803 | | case 5: /* 32 & 64 */ |
| 804 | | snes_ppu.oam.size[0] = 4; |
| 805 | | snes_ppu.oam.size[1] = 8; |
| 806 | | break; |
| 807 | | default: |
| 808 | | /* Unknown size so default to 8 & 16 */ |
| 809 | | logerror("Object size unsupported: %d\n", (data & 0xe0) >> 5); |
| 810 | | |
| 811 | | snes_ppu.oam.size[0] = 1; |
| 812 | | snes_ppu.oam.size[1] = 2; |
| 813 | | break; |
| 814 | | } |
| 815 | 779 | break; |
| 816 | 780 | case OAMADDL: /* Address for accessing OAM (low) */ |
| 817 | 781 | snes_ppu.oam.saved_address_low = data; |
| r7584 | r7585 | |
| 950 | 914 | snes_ppu.update_offsets = 1; |
| 951 | 915 | return; |
| 952 | 916 | case VMAIN: /* VRAM address increment value designation */ |
| 953 | | vram_fgr_high = (data & 0x80); |
| 954 | | vram_fgr_increment = vram_fgr_inctab[data & 3]; |
| 917 | state->vram_fgr_high = (data & 0x80); |
| 918 | state->vram_fgr_increment = vram_fgr_inctab[data & 3]; |
| 955 | 919 | |
| 956 | 920 | if (data & 0xc) |
| 957 | 921 | { |
| 958 | 922 | int md = (data & 0xc) >> 2; |
| 959 | 923 | |
| 960 | | vram_fgr_count = vram_fgr_inccnts[md]; |
| 961 | | vram_fgr_mask = (vram_fgr_count * 8) - 1; |
| 962 | | vram_fgr_shift = vram_fgr_shiftab[md]; |
| 924 | state->vram_fgr_count = vram_fgr_inccnts[md]; |
| 925 | state->vram_fgr_mask = (state->vram_fgr_count * 8) - 1; |
| 926 | state->vram_fgr_shift = vram_fgr_shiftab[md]; |
| 963 | 927 | } |
| 964 | 928 | else |
| 965 | 929 | { |
| 966 | | vram_fgr_count = 0; |
| 930 | state->vram_fgr_count = 0; |
| 967 | 931 | } |
| 968 | | // printf("VMAIN: high %x inc %x count %x mask %x shift %x\n", vram_fgr_high, vram_fgr_increment, vram_fgr_count, vram_fgr_mask, vram_fgr_shift); |
| 932 | // printf("VMAIN: high %x inc %x count %x mask %x shift %x\n", state->vram_fgr_high, state->vram_fgr_increment, state->vram_fgr_count, state->vram_fgr_mask, state->vram_fgr_shift); |
| 969 | 933 | break; |
| 970 | 934 | case VMADDL: /* Address for VRAM read/write (low) */ |
| 971 | 935 | case VMADDH: /* Address for VRAM read/write (high) */ |
| r7584 | r7585 | |
| 975 | 939 | snes_ram[offset] = data; |
| 976 | 940 | addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL]; |
| 977 | 941 | |
| 978 | | if (vram_fgr_count) |
| 942 | if (state->vram_fgr_count) |
| 979 | 943 | { |
| 980 | | UINT32 rem = addr & vram_fgr_mask; |
| 981 | | UINT32 faddr = (addr & ~vram_fgr_mask) + (rem >> vram_fgr_shift) + ((rem & (vram_fgr_count - 1)) << 3); |
| 944 | UINT32 rem = addr & state->vram_fgr_mask; |
| 945 | UINT32 faddr = (addr & ~state->vram_fgr_mask) + (rem >> state->vram_fgr_shift) + ((rem & (state->vram_fgr_count - 1)) << 3); |
| 982 | 946 | |
| 983 | | vram_read_buffer = snes_vram[(faddr << 1) & 0x1ffff] | snes_vram[((faddr << 1) + 1) & 0x1ffff] << 8; |
| 947 | state->vram_read_buffer = snes_vram[(faddr << 1) & 0x1ffff] | snes_vram[((faddr << 1) + 1) & 0x1ffff] << 8; |
| 984 | 948 | } |
| 985 | 949 | else |
| 986 | 950 | { |
| 987 | | vram_read_buffer = snes_vram[(addr << 1) & 0x1ffff] | snes_vram[((addr << 1) + 1) & 0x1ffff] << 8; |
| 951 | state->vram_read_buffer = snes_vram[(addr << 1) & 0x1ffff] | snes_vram[((addr << 1) + 1) & 0x1ffff] << 8; |
| 988 | 952 | } |
| 989 | 953 | |
| 990 | 954 | } |
| r7584 | r7585 | |
| 993 | 957 | { |
| 994 | 958 | UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL]; |
| 995 | 959 | |
| 996 | | if (vram_fgr_count) |
| 960 | if (state->vram_fgr_count) |
| 997 | 961 | { |
| 998 | | UINT32 rem = addr & vram_fgr_mask; |
| 999 | | UINT32 faddr = (addr & ~vram_fgr_mask) + (rem >> vram_fgr_shift) + ((rem & (vram_fgr_count - 1)) << 3); |
| 962 | UINT32 rem = addr & state->vram_fgr_mask; |
| 963 | UINT32 faddr = (addr & ~state->vram_fgr_mask) + (rem >> state->vram_fgr_shift) + ((rem & (state->vram_fgr_count - 1)) << 3); |
| 1000 | 964 | |
| 1001 | 965 | snes_vram[(faddr << 1) & 0x1ffff] = data; |
| 1002 | 966 | } |
| r7584 | r7585 | |
| 1005 | 969 | snes_vram[(addr << 1) & 0x1ffff] = data; |
| 1006 | 970 | } |
| 1007 | 971 | |
| 1008 | | if (!vram_fgr_high) |
| 972 | if (!state->vram_fgr_high) |
| 1009 | 973 | { |
| 1010 | | addr += vram_fgr_increment; |
| 974 | addr += state->vram_fgr_increment; |
| 1011 | 975 | snes_ram[VMADDL] = addr & 0xff; |
| 1012 | 976 | snes_ram[VMADDH] = (addr >> 8) & 0xff; |
| 1013 | 977 | } |
| r7584 | r7585 | |
| 1017 | 981 | { |
| 1018 | 982 | UINT32 addr = (snes_ram[VMADDH] << 8) | snes_ram[VMADDL]; |
| 1019 | 983 | |
| 1020 | | if (vram_fgr_count) |
| 984 | if (state->vram_fgr_count) |
| 1021 | 985 | { |
| 1022 | | UINT32 rem = addr & vram_fgr_mask; |
| 1023 | | UINT32 faddr = (addr & ~vram_fgr_mask) + (rem >> vram_fgr_shift) + ((rem & (vram_fgr_count - 1)) << 3); |
| 986 | UINT32 rem = addr & state->vram_fgr_mask; |
| 987 | UINT32 faddr = (addr & ~state->vram_fgr_mask) + (rem >> state->vram_fgr_shift) + ((rem & (state->vram_fgr_count - 1)) << 3); |
| 1024 | 988 | |
| 1025 | 989 | snes_vram[((faddr << 1) + 1) & 0x1ffff] = data; |
| 1026 | 990 | } |
| r7584 | r7585 | |
| 1029 | 993 | snes_vram[((addr << 1) + 1) & 0x1ffff] = data; |
| 1030 | 994 | } |
| 1031 | 995 | |
| 1032 | | if (vram_fgr_high) |
| 996 | if (state->vram_fgr_high) |
| 1033 | 997 | { |
| 1034 | | addr += vram_fgr_increment; |
| 998 | addr += state->vram_fgr_increment; |
| 1035 | 999 | snes_ram[VMADDL] = addr & 0xff; |
| 1036 | 1000 | snes_ram[VMADDH] = (addr >> 8) & 0xff; |
| 1037 | 1001 | } |
| r7584 | r7585 | |
| 1070 | 1034 | case CGADD: /* Initial address for colour RAM writing */ |
| 1071 | 1035 | /* CGRAM is 16-bit, but when reading/writing we treat it as |
| 1072 | 1036 | * 8-bit, so we need to double the address */ |
| 1073 | | cgram_address = data << 1; |
| 1037 | state->cgram_address = data << 1; |
| 1074 | 1038 | break; |
| 1075 | 1039 | case CGDATA: /* Data for colour RAM */ |
| 1076 | | ((UINT8 *)snes_cgram)[cgram_address] = data; |
| 1077 | | cgram_address = (cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 1040 | ((UINT8 *)snes_cgram)[state->cgram_address] = data; |
| 1041 | state->cgram_address = (state->cgram_address + 1) % (SNES_CGRAM_SIZE - 2); |
| 1078 | 1042 | break; |
| 1079 | 1043 | case W12SEL: /* Window mask settings for BG1-2 */ |
| 1080 | 1044 | if (data != snes_ram[offset]) |
| r7584 | r7585 | |
| 1278 | 1242 | break; |
| 1279 | 1243 | case WRMPYB: /* Multiplier B */ |
| 1280 | 1244 | snes_ram[WRMPYB] = data; |
| 1281 | | // timer_adjust_oneshot(snes_mult_timer, cputag_clocks_to_attotime(space->machine, "maincpu", 8), 0); |
| 1245 | // timer_adjust_oneshot(state->mult_timer, cputag_clocks_to_attotime(space->machine, "maincpu", 8), 0); |
| 1282 | 1246 | { |
| 1283 | 1247 | UINT32 c = snes_ram[WRMPYA] * snes_ram[WRMPYB]; |
| 1284 | 1248 | snes_ram[RDMPYL] = c & 0xff; |
| r7584 | r7585 | |
| 1290 | 1254 | break; |
| 1291 | 1255 | case WRDVDD: /* Divisor */ |
| 1292 | 1256 | snes_ram[WRDVDD] = data; |
| 1293 | | // timer_adjust_oneshot(snes_div_timer, cputag_clocks_to_attotime(space->machine, "maincpu", 16), 0); |
| 1257 | // timer_adjust_oneshot(state->div_timer, cputag_clocks_to_attotime(space->machine, "maincpu", 16), 0); |
| 1294 | 1258 | { |
| 1295 | 1259 | UINT16 value, dividend, remainder; |
| 1296 | 1260 | dividend = remainder = 0; |
| r7584 | r7585 | |
| 1316 | 1280 | case VTIMEL: /* V-Count timer settings (low) */ |
| 1317 | 1281 | case VTIMEH: /* V-Count timer settings (high) */ |
| 1318 | 1282 | break; |
| 1319 | | case MDMAEN: /* GDMA channel designation and trigger */ |
| 1320 | | snes_gdma(space, data); |
| 1283 | case MDMAEN: /* DMA channel designation and trigger */ |
| 1284 | snes_dma(space, data); |
| 1321 | 1285 | data = 0; /* Once DMA is done we need to reset all bits to 0 */ |
| 1322 | 1286 | break; |
| 1323 | 1287 | case HDMAEN: /* HDMA channel designation */ |
| r7584 | r7585 | |
| 2045 | 2009 | |
| 2046 | 2010 | *************************************/ |
| 2047 | 2011 | |
| 2048 | | static void snes_init_timers(running_machine *machine) |
| 2012 | static void snes_init_timers( running_machine *machine ) |
| 2049 | 2013 | { |
| 2014 | snes_state *state = (snes_state *)machine->driver_data; |
| 2015 | |
| 2050 | 2016 | /* init timers and stop them */ |
| 2051 | | snes_scanline_timer = timer_alloc(machine, snes_scanline_tick, NULL); |
| 2052 | | timer_adjust_oneshot(snes_scanline_timer, attotime_never, 0); |
| 2053 | | snes_hblank_timer = timer_alloc(machine, snes_hblank_tick, NULL); |
| 2054 | | timer_adjust_oneshot(snes_hblank_timer, attotime_never, 0); |
| 2055 | | snes_nmi_timer = timer_alloc(machine, snes_nmi_tick, NULL); |
| 2056 | | timer_adjust_oneshot(snes_nmi_timer, attotime_never, 0); |
| 2057 | | snes_hirq_timer = timer_alloc(machine, snes_hirq_tick_callback, NULL); |
| 2058 | | timer_adjust_oneshot(snes_hirq_timer, attotime_never, 0); |
| 2059 | | snes_div_timer = timer_alloc(machine, snes_div_callback, NULL); |
| 2060 | | timer_adjust_oneshot(snes_div_timer, attotime_never, 0); |
| 2061 | | snes_mult_timer = timer_alloc(machine, snes_mult_callback, NULL); |
| 2062 | | timer_adjust_oneshot(snes_mult_timer, attotime_never, 0); |
| 2017 | state->scanline_timer = timer_alloc(machine, snes_scanline_tick, NULL); |
| 2018 | timer_adjust_oneshot(state->scanline_timer, attotime_never, 0); |
| 2019 | state->hblank_timer = timer_alloc(machine, snes_hblank_tick, NULL); |
| 2020 | timer_adjust_oneshot(state->hblank_timer, attotime_never, 0); |
| 2021 | state->nmi_timer = timer_alloc(machine, snes_nmi_tick, NULL); |
| 2022 | timer_adjust_oneshot(state->nmi_timer, attotime_never, 0); |
| 2023 | state->hirq_timer = timer_alloc(machine, snes_hirq_tick_callback, NULL); |
| 2024 | timer_adjust_oneshot(state->hirq_timer, attotime_never, 0); |
| 2025 | state->div_timer = timer_alloc(machine, snes_div_callback, NULL); |
| 2026 | timer_adjust_oneshot(state->div_timer, attotime_never, 0); |
| 2027 | state->mult_timer = timer_alloc(machine, snes_mult_callback, NULL); |
| 2028 | timer_adjust_oneshot(state->mult_timer, attotime_never, 0); |
| 2063 | 2029 | |
| 2064 | 2030 | // SNES hcounter has a 0-339 range. hblank starts at counter 260. |
| 2065 | 2031 | // clayfighter sets an HIRQ at 260, apparently it wants it to be before hdma kicks off, so we'll delay 2 pixels. |
| 2066 | | hblank_offset = 268; |
| 2067 | | timer_adjust_oneshot(snes_hblank_timer, video_screen_get_time_until_pos(machine->primary_screen, ((snes_ram[STAT78] & 0x10) == SNES_NTSC) ? SNES_VTOTAL_NTSC-1 : SNES_VTOTAL_PAL-1, hblank_offset), 0); |
| 2068 | | |
| 2032 | state->hblank_offset = 268; |
| 2033 | timer_adjust_oneshot(state->hblank_timer, video_screen_get_time_until_pos(machine->primary_screen, ((snes_ram[STAT78] & 0x10) == SNES_NTSC) ? SNES_VTOTAL_NTSC - 1 : SNES_VTOTAL_PAL - 1, state->hblank_offset), 0); |
| 2069 | 2034 | } |
| 2070 | 2035 | |
| 2071 | 2036 | static void snes_init_ram(running_machine *machine) |
| r7584 | r7585 | |
| 2075 | 2040 | int i, j; |
| 2076 | 2041 | |
| 2077 | 2042 | /* Init VRAM */ |
| 2078 | | memset(snes_vram, 0, SNES_VRAM_SIZE ); |
| 2043 | memset(snes_vram, 0, SNES_VRAM_SIZE); |
| 2079 | 2044 | |
| 2080 | 2045 | /* Init Colour RAM */ |
| 2081 | 2046 | memset((UINT8 *)snes_cgram, 0, SNES_CGRAM_SIZE); |
| 2082 | 2047 | |
| 2083 | 2048 | /* Init oam RAM */ |
| 2084 | | memset(snes_oam, 0xff, SNES_OAM_SIZE ); |
| 2049 | memset(snes_oam, 0xff, SNES_OAM_SIZE); |
| 2085 | 2050 | |
| 2086 | 2051 | /* Init work RAM - 0x55 isn't exactly right but it's close */ |
| 2087 | 2052 | /* make sure it happens to the 65816 (CPU 0) */ |
| r7584 | r7585 | |
| 2100 | 2065 | snes_ppu.mode = 0; |
| 2101 | 2066 | snes_ppu.ppu1_version = 1; // 5C77 chip version number, read by STAT77, only '1' is known |
| 2102 | 2067 | snes_ppu.ppu2_version = 3; // 5C78 chip version number, read by STAT78, only '2' & '3' encountered so far. |
| 2103 | | cgram_address = 0; |
| 2104 | | vram_read_offset = 2; |
| 2105 | 2068 | |
| 2069 | state->cgram_address = 0; |
| 2070 | state->vram_read_offset = 2; |
| 2071 | state->read_ophct = 0; |
| 2072 | state->read_opvct = 0; |
| 2073 | |
| 2106 | 2074 | state->joy1l = state->joy1h = state->joy2l = state->joy2h = state->joy3l = state->joy3h = 0; |
| 2107 | 2075 | state->data1[0] = state->data2[0] = state->data1[1] = state->data2[1] = 0; |
| 2108 | 2076 | |
| r7584 | r7585 | |
| 2172 | 2140 | } |
| 2173 | 2141 | } |
| 2174 | 2142 | |
| 2175 | | void snes_hdma_init() |
| 2176 | | { |
| 2177 | | UINT8 mask = 1, dma = 0, i; |
| 2178 | 2143 | |
| 2179 | | snes_hdma_chnl = snes_ram[HDMAEN]; |
| 2180 | | for (i = 0; i < 8; i++) |
| 2181 | | { |
| 2182 | | if (snes_ram[HDMAEN] & mask) |
| 2183 | | { |
| 2184 | | snes_ram[SNES_DMA_BASE + dma + 8] = snes_ram[SNES_DMA_BASE + dma + 2]; |
| 2185 | | snes_ram[SNES_DMA_BASE + dma + 9] = snes_ram[SNES_DMA_BASE + dma + 3]; |
| 2186 | | snes_ram[SNES_DMA_BASE + dma + 0xa] = 0; |
| 2187 | | } |
| 2188 | | dma += 0x10; |
| 2189 | | mask <<= 1; |
| 2190 | | } |
| 2191 | | } |
| 2192 | | |
| 2193 | | |
| 2194 | 2144 | /* should we treat this as nvram in MAME? */ |
| 2195 | | static DIRECT_UPDATE_HANDLER(spc_direct) |
| 2145 | static DIRECT_UPDATE_HANDLER( spc_direct ) |
| 2196 | 2146 | { |
| 2197 | 2147 | direct->raw = direct->decrypted = spc_ram; |
| 2198 | 2148 | return ~0; |
| 2199 | 2149 | } |
| 2200 | 2150 | |
| 2201 | | static DIRECT_UPDATE_HANDLER(snes_direct) |
| 2151 | static DIRECT_UPDATE_HANDLER( snes_direct ) |
| 2202 | 2152 | { |
| 2203 | 2153 | direct->raw = direct->decrypted = snes_ram; |
| 2204 | 2154 | return ~0; |
| r7584 | r7585 | |
| 2237 | 2187 | |
| 2238 | 2188 | MACHINE_RESET( snes ) |
| 2239 | 2189 | { |
| 2190 | snes_state *state = (snes_state *)machine->driver_data; |
| 2191 | |
| 2240 | 2192 | snes_init_ram(machine); |
| 2241 | 2193 | |
| 2242 | 2194 | /* Set STAT78 to NTSC or PAL */ |
| r7584 | r7585 | |
| 2252 | 2204 | snes_ram[VTIMEL] = 0xff; |
| 2253 | 2205 | snes_ram[VTIMEH] = 0x1; |
| 2254 | 2206 | |
| 2255 | | snes_htmult = 1; |
| 2207 | state->htmult = 1; |
| 2256 | 2208 | snes_ppu.interlace = 1; |
| 2257 | 2209 | snes_ppu.obj_interlace = 1; |
| 2258 | 2210 | } |
| r7584 | r7585 | |
| 2391 | 2343 | |
| 2392 | 2344 | *************************************/ |
| 2393 | 2345 | |
| 2346 | INLINE void snes_dma_transfer( const address_space *space, UINT8 dma, UINT32 abus, UINT16 bbus ) |
| 2347 | { |
| 2348 | /* TODO: implement open bus access when DMA tries to transfer from not accessible regs */ |
| 2349 | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2350 | memory_write_byte(space, abus, memory_read_byte(space, bbus)); |
| 2351 | else /* CPU->PPU */ |
| 2352 | memory_write_byte(space, bbus, memory_read_byte(space, abus)); |
| 2353 | } |
| 2394 | 2354 | |
| 2395 | | void snes_hdma(const address_space *space) |
| 2355 | static void snes_hdma_init( running_machine *machine ) |
| 2396 | 2356 | { |
| 2357 | snes_state *state = (snes_state *)machine->driver_data; |
| 2358 | UINT8 mask = 1, dma = 0, i; |
| 2359 | |
| 2360 | state->hdma_chnl = snes_ram[HDMAEN]; |
| 2361 | for (i = 0; i < 8; i++) |
| 2362 | { |
| 2363 | if (snes_ram[HDMAEN] & mask) |
| 2364 | { |
| 2365 | snes_ram[SNES_DMA_BASE + dma + 8] = snes_ram[SNES_DMA_BASE + dma + 2]; |
| 2366 | snes_ram[SNES_DMA_BASE + dma + 9] = snes_ram[SNES_DMA_BASE + dma + 3]; |
| 2367 | snes_ram[SNES_DMA_BASE + dma + 0xa] = 0; |
| 2368 | } |
| 2369 | dma += 0x10; |
| 2370 | mask <<= 1; |
| 2371 | } |
| 2372 | } |
| 2373 | |
| 2374 | static void snes_hdma( const address_space *space ) |
| 2375 | { |
| 2376 | snes_state *state = (snes_state *)space->machine->driver_data; |
| 2397 | 2377 | UINT8 mask = 1, dma = 0, i, contmode; |
| 2398 | 2378 | UINT16 bbus; |
| 2399 | 2379 | UINT32 abus; |
| r7584 | r7585 | |
| 2401 | 2381 | /* Assume priority of the 8 DMA channels is 0-7 */ |
| 2402 | 2382 | for (i = 0; i < 8; i++) |
| 2403 | 2383 | { |
| 2404 | | if (snes_hdma_chnl & mask) |
| 2384 | if (state->hdma_chnl & mask) |
| 2405 | 2385 | { |
| 2406 | 2386 | /* Check if we need to read a new line from the table */ |
| 2407 | 2387 | if (!(snes_ram[SNES_DMA_BASE + dma + 0xa] & 0x7f)) |
| r7584 | r7585 | |
| 2413 | 2393 | if (!snes_ram[SNES_DMA_BASE + dma + 0xa]) |
| 2414 | 2394 | { |
| 2415 | 2395 | /* No more lines so clear HDMA */ |
| 2416 | | snes_hdma_chnl &= ~mask; |
| 2396 | state->hdma_chnl &= ~mask; |
| 2417 | 2397 | continue; |
| 2418 | 2398 | } |
| 2419 | 2399 | abus++; |
| r7584 | r7585 | |
| 2438 | 2418 | bbus = 0x2100 + snes_ram[SNES_DMA_BASE + dma + 1]; |
| 2439 | 2419 | |
| 2440 | 2420 | #ifdef SNES_DBG_HDMA |
| 2441 | | mame_printf_debug( "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] ); |
| 2421 | mame_printf_debug( "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] & 0x07, snes_ram[SNES_DMA_BASE + dma + 8],snes_ram[SNES_DMA_BASE + dma + 9] ); |
| 2442 | 2422 | #endif |
| 2443 | 2423 | |
| 2444 | | switch (snes_ram[SNES_DMA_BASE + dma] & 0x7) |
| 2424 | switch (snes_ram[SNES_DMA_BASE + dma] & 0x07) |
| 2445 | 2425 | { |
| 2446 | | case 0: /* 1 address */ |
| 2447 | | { |
| 2448 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2449 | | } break; |
| 2450 | | case 5: /* 4 bytes to 2 addresses (l,h,l,h) */ |
| 2451 | | { |
| 2452 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2453 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2454 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2455 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2456 | | } break; |
| 2457 | | case 1: /* 2 addresses (l,h) */ |
| 2458 | | { |
| 2459 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2460 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2461 | | } break; |
| 2462 | | case 2: /* Write twice (l,l) */ |
| 2463 | | case 6: |
| 2464 | | { |
| 2465 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2466 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2467 | | } break; |
| 2468 | | case 3: /* 2 addresses/Write twice (l,l,h,h) */ |
| 2469 | | case 7: |
| 2470 | | { |
| 2471 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2472 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2473 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2474 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2475 | | } break; |
| 2476 | | case 4: /* 4 addresses (l,h,l,h) */ |
| 2477 | | { |
| 2478 | | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2479 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2480 | | memory_write_byte(space, bbus + 2, memory_read_byte(space, abus++)); |
| 2481 | | memory_write_byte(space, bbus + 3, memory_read_byte(space, abus++)); |
| 2482 | | } break; |
| 2483 | | default: |
| 2426 | case 0: /* 1 register write once (1 byte: p ) */ |
| 2427 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2428 | break; |
| 2429 | case 5: /* 2 registers write twice alternate (4 bytes: p, p+1, p, p+1) */ |
| 2430 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2431 | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2432 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2433 | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2434 | break; |
| 2435 | case 1: /* 2 registers write once (2 bytes: p, p+1 ) */ |
| 2436 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2437 | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2438 | break; |
| 2439 | case 2: /* 1 register write twice (2 bytes: p, p ) */ |
| 2440 | case 6: |
| 2441 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2442 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2443 | break; |
| 2444 | case 3: /* 2 registers write twice each (4 bytes: p, p, p+1, p+1) */ |
| 2445 | case 7: |
| 2446 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2447 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2448 | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2449 | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2450 | break; |
| 2451 | case 4: /* 4 registers write once (4 bytes: p, p+1, p+2, p+3) */ |
| 2452 | memory_write_byte(space, bbus, memory_read_byte(space, abus++)); |
| 2453 | memory_write_byte(space, bbus + 1, memory_read_byte(space, abus++)); |
| 2454 | memory_write_byte(space, bbus + 2, memory_read_byte(space, abus++)); |
| 2455 | memory_write_byte(space, bbus + 3, memory_read_byte(space, abus++)); |
| 2456 | break; |
| 2457 | default: |
| 2484 | 2458 | #ifdef MAME_DEBUG |
| 2485 | | mame_printf_debug( " HDMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x7 ); |
| 2459 | mame_printf_debug( " HDMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x07); |
| 2486 | 2460 | #endif |
| 2487 | | break; |
| 2461 | break; |
| 2488 | 2462 | } |
| 2489 | 2463 | |
| 2490 | 2464 | /* Update address */ |
| r7584 | r7585 | |
| 2519 | 2493 | } |
| 2520 | 2494 | } |
| 2521 | 2495 | |
| 2522 | | void snes_gdma( const address_space *space, UINT8 channels ) |
| 2496 | static void snes_dma( const address_space *space, UINT8 channels ) |
| 2523 | 2497 | { |
| 2498 | snes_state *state = (snes_state *)space->machine->driver_data; |
| 2524 | 2499 | UINT8 mask = 1, dma = 0, i; |
| 2525 | 2500 | INT8 increment; |
| 2526 | 2501 | UINT16 bbus; |
| r7584 | r7585 | |
| 2531 | 2506 | { |
| 2532 | 2507 | if (channels & mask) |
| 2533 | 2508 | { |
| 2509 | /* FIXME: the following should be used to stop DMA if the same channel is used by HDMA (being set to 1 in snes_hdma) |
| 2510 | However, this cannot be implemented as is atm, because currently DMA transfers always happen as soon as they are enabled... */ |
| 2511 | state->dma_disabled[i] = 0; |
| 2512 | |
| 2534 | 2513 | //printf( "Making a transfer on channel %d\n", i ); |
| 2535 | 2514 | /* Find transfer addresses */ |
| 2536 | 2515 | abus = (snes_ram[SNES_DMA_BASE + dma + 3] << 8) + snes_ram[SNES_DMA_BASE + dma + 2]; |
| r7584 | r7585 | |
| 2556 | 2535 | if (!length) |
| 2557 | 2536 | length = 0x10000; /* 0x0000 really means 0x10000 */ |
| 2558 | 2537 | |
| 2559 | | // printf( "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 ); |
| 2538 | // printf( "DMA-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] & 0x07); |
| 2560 | 2539 | |
| 2561 | | #ifdef SNES_DBG_GDMA |
| 2562 | | mame_printf_debug( "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 ); |
| 2540 | #ifdef SNES_DBG_DMA |
| 2541 | mame_printf_debug( "DMA-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] & 0x07); |
| 2563 | 2542 | #endif |
| 2564 | 2543 | |
| 2565 | | switch (snes_ram[SNES_DMA_BASE + dma] & 0x7) |
| 2544 | switch (snes_ram[SNES_DMA_BASE + dma] & 0x07) |
| 2566 | 2545 | { |
| 2567 | | case 0: /* 1 address */ |
| 2568 | | case 2: /* 1 address ?? */ |
| 2569 | | case 6: |
| 2546 | case 0: /* 1 register write once */ |
| 2547 | case 2: /* 1 register write twice */ |
| 2548 | case 6: /* 1 register write twice */ |
| 2549 | |
| 2550 | while (length-- && !state->dma_disabled[i]) |
| 2570 | 2551 | { |
| 2571 | | while (length--) |
| 2572 | | { |
| 2573 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2574 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus) ); |
| 2575 | | else /* CPU->PPU */ |
| 2576 | | memory_write_byte(space, bbus, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2577 | | abus += increment; |
| 2578 | | } |
| 2579 | | } break; |
| 2580 | | case 1: /* 2 addresses (l,h) */ |
| 2581 | | case 5: |
| 2552 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2553 | abus += increment; |
| 2554 | } |
| 2555 | break; |
| 2556 | case 1: /* 2 registers write once */ |
| 2557 | case 5: /* 2 registers write twice alternate */ |
| 2558 | while (length-- && !state->dma_disabled[i]) |
| 2582 | 2559 | { |
| 2583 | | while (length--) |
| 2584 | | { |
| 2585 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2586 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus) ); |
| 2587 | | else /* CPU->PPU */ |
| 2588 | | memory_write_byte(space, bbus, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2589 | | abus += increment; |
| 2590 | | if (!(length--)) |
| 2591 | | break; |
| 2592 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2593 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus + 1) ); |
| 2594 | | else /* CPU->PPU */ |
| 2595 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2596 | | abus += increment; |
| 2597 | | } |
| 2598 | | } break; |
| 2599 | | case 3: /* 2 addresses/write twice (l,l,h,h) */ |
| 2600 | | case 7: |
| 2560 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2561 | abus += increment; |
| 2562 | if (!(length--) || state->dma_disabled[i]) |
| 2563 | break; |
| 2564 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2565 | abus += increment; |
| 2566 | } |
| 2567 | break; |
| 2568 | case 3: /* 2 registers write twice each */ |
| 2569 | case 7: /* 2 registers write twice each */ |
| 2570 | while (length-- && !state->dma_disabled[i]) |
| 2601 | 2571 | { |
| 2602 | | while (length--) |
| 2603 | | { |
| 2604 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2605 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus) ); |
| 2606 | | else /* CPU->PPU */ |
| 2607 | | memory_write_byte(space, bbus, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2608 | | abus += increment; |
| 2609 | | if (!(length--)) |
| 2610 | | break; |
| 2611 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2612 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus) ); |
| 2613 | | else /* CPU->PPU */ |
| 2614 | | memory_write_byte(space, bbus, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2615 | | abus += increment; |
| 2616 | | if (!(length--)) |
| 2617 | | break; |
| 2618 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2619 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus + 1) ); |
| 2620 | | else /* CPU->PPU */ |
| 2621 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2622 | | abus += increment; |
| 2623 | | if (!(length--)) |
| 2624 | | break; |
| 2625 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2626 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus + 1) ); |
| 2627 | | else /* CPU->PPU */ |
| 2628 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2629 | | abus += increment; |
| 2630 | | } |
| 2631 | | } break; |
| 2632 | | case 4: /* 4 addresses (l,h,l,h) */ |
| 2572 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2573 | abus += increment; |
| 2574 | if (!(length--) || state->dma_disabled[i]) |
| 2575 | break; |
| 2576 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2577 | abus += increment; |
| 2578 | if (!(length--) || state->dma_disabled[i]) |
| 2579 | break; |
| 2580 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2581 | abus += increment; |
| 2582 | if (!(length--) || state->dma_disabled[i]) |
| 2583 | break; |
| 2584 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2585 | abus += increment; |
| 2586 | } |
| 2587 | break; |
| 2588 | case 4: /* 4 registers write once */ |
| 2589 | while (length-- && !state->dma_disabled[i]) |
| 2633 | 2590 | { |
| 2634 | | while (length--) |
| 2635 | | { |
| 2636 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2637 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus) ); |
| 2638 | | else /* CPU->PPU */ |
| 2639 | | memory_write_byte(space, bbus, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2640 | | abus += increment; |
| 2641 | | if (!(length--)) |
| 2642 | | break; |
| 2643 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2644 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus + 1) ); |
| 2645 | | else /* CPU->PPU */ |
| 2646 | | memory_write_byte(space, bbus + 1, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2647 | | abus += increment; |
| 2648 | | if (!(length--)) |
| 2649 | | break; |
| 2650 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2651 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus + 2) ); |
| 2652 | | else /* CPU->PPU */ |
| 2653 | | memory_write_byte(space, bbus + 2, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2654 | | abus += increment; |
| 2655 | | if (!(length--)) |
| 2656 | | break; |
| 2657 | | if (snes_ram[SNES_DMA_BASE + dma] & 0x80) /* PPU->CPU */ |
| 2658 | | memory_write_byte(space, ((abus & 0xffff) | (abus_bank)), memory_read_byte(space, bbus + 3) ); |
| 2659 | | else /* CPU->PPU */ |
| 2660 | | memory_write_byte(space, bbus + 3, memory_read_byte(space, ((abus & 0xffff) | (abus_bank))) ); |
| 2661 | | abus += increment; |
| 2662 | | } |
| 2663 | | } break; |
| 2664 | | default: |
| 2591 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus); |
| 2592 | abus += increment; |
| 2593 | if (!(length--) || state->dma_disabled[i]) |
| 2594 | break; |
| 2595 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 1); |
| 2596 | abus += increment; |
| 2597 | if (!(length--) || state->dma_disabled[i]) |
| 2598 | break; |
| 2599 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 2); |
| 2600 | abus += increment; |
| 2601 | if (!(length--) || state->dma_disabled[i]) |
| 2602 | break; |
| 2603 | snes_dma_transfer(space, dma, (abus & 0xffff) | abus_bank, bbus + 3); |
| 2604 | abus += increment; |
| 2605 | } |
| 2606 | break; |
| 2607 | default: |
| 2665 | 2608 | #ifdef MAME_DEBUG |
| 2666 | | mame_printf_debug( " GDMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x7 ); |
| 2609 | mame_printf_debug( " DMA of unsupported type: %d\n", snes_ram[SNES_DMA_BASE + dma] & 0x07); |
| 2667 | 2610 | #endif |
| 2668 | | break; |
| 2611 | break; |
| 2669 | 2612 | } |
| 2670 | 2613 | |
| 2671 | 2614 | /* We're done so write the new abus back to the registers */ |
| r7584 | r7585 | |
| 2673 | 2616 | snes_w_io(space, SNES_DMA_BASE + dma + 3, (abus >> 8) & 0xff); |
| 2674 | 2617 | snes_w_io(space, SNES_DMA_BASE + dma + 5, 0); |
| 2675 | 2618 | snes_w_io(space, SNES_DMA_BASE + dma + 6, 0); |
| 2676 | | //snes_ram[SNES_DMA_BASE + dma + 2] = abus & 0xff; |
| 2677 | | //snes_ram[SNES_DMA_BASE + dma + 3] = (abus >> 8) & 0xff; |
| 2678 | | //snes_ram[SNES_DMA_BASE + dma + 5] = 0; |
| 2679 | | //snes_ram[SNES_DMA_BASE + dma + 6] = 0; |
| 2680 | 2619 | } |
| 2681 | 2620 | dma += 0x10; |
| 2682 | 2621 | mask <<= 1; |