trunk/src/mame/machine/snes.c
| r21565 | r21566 | |
| 36 | 36 | |
| 37 | 37 | struct snes_cart_info snes_cart; |
| 38 | 38 | |
| 39 | #define DMA_REG(a) state->m_dma_regs[a - 0x4300] // regs 0x4300-0x437f |
| 40 | |
| 39 | 41 | // DSP accessors |
| 40 | 42 | #define dsp_get_sr() state->m_upd7725->snesdsp_read(false) |
| 41 | 43 | #define dsp_get_dr() state->m_upd7725->snesdsp_read(true) |
| r21565 | r21566 | |
| 128 | 130 | // latch the counters and pull IRQ |
| 129 | 131 | // (don't need to switch to the 65816 context, we don't do anything dependant on it) |
| 130 | 132 | m_ppu.latch_counters(machine()); |
| 131 | | snes_ram[TIMEUP] = 0x80; /* Indicate that irq occurred */ |
| 133 | SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */ |
| 132 | 134 | m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE); |
| 133 | 135 | |
| 134 | 136 | // don't happen again |
| r21565 | r21566 | |
| 163 | 165 | { |
| 164 | 166 | address_space &cpu0space = m_maincpu->space(AS_PROGRAM); |
| 165 | 167 | m_io_read(cpu0space.machine()); |
| 166 | | snes_ram[HVBJOY] &= 0xfe; /* Clear busy bit */ |
| 168 | SNES_CPU_REG(HVBJOY) &= 0xfe; /* Clear busy bit */ |
| 167 | 169 | |
| 168 | 170 | m_io_timer->adjust(attotime::never); |
| 169 | 171 | } |
| r21565 | r21566 | |
| 174 | 176 | m_ppu.m_beam.current_vert = machine().primary_screen->vpos(); |
| 175 | 177 | |
| 176 | 178 | // not in hblank |
| 177 | | snes_ram[HVBJOY] &= ~0x40; |
| 179 | SNES_CPU_REG(HVBJOY) &= ~0x40; |
| 178 | 180 | |
| 179 | 181 | /* Vertical IRQ timer - only if horizontal isn't also enabled! */ |
| 180 | | if ((snes_ram[NMITIMEN] & 0x20) && !(snes_ram[NMITIMEN] & 0x10)) |
| 182 | if ((SNES_CPU_REG(NMITIMEN) & 0x20) && !(SNES_CPU_REG(NMITIMEN) & 0x10)) |
| 181 | 183 | { |
| 182 | 184 | if (m_ppu.m_beam.current_vert == m_vtime) |
| 183 | 185 | { |
| 184 | | snes_ram[TIMEUP] = 0x80; /* Indicate that irq occurred */ |
| 186 | SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */ |
| 185 | 187 | // IRQ latches the counters, do it now |
| 186 | 188 | m_ppu.latch_counters(machine()); |
| 187 | 189 | m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE ); |
| 188 | 190 | } |
| 189 | 191 | } |
| 190 | 192 | /* Horizontal IRQ timer */ |
| 191 | | if (snes_ram[NMITIMEN] & 0x10) |
| 193 | if (SNES_CPU_REG(NMITIMEN) & 0x10) |
| 192 | 194 | { |
| 193 | 195 | int setirq = 1; |
| 194 | 196 | int pixel = m_htime; |
| 195 | 197 | |
| 196 | 198 | // is the HIRQ on a specific scanline? |
| 197 | | if (snes_ram[NMITIMEN] & 0x20) |
| 199 | if (SNES_CPU_REG(NMITIMEN) & 0x20) |
| 198 | 200 | { |
| 199 | 201 | if (m_ppu.m_beam.current_vert != m_vtime) |
| 200 | 202 | { |
| r21565 | r21566 | |
| 221 | 223 | { |
| 222 | 224 | machine().scheduler().timer_set(machine().primary_screen->time_until_pos(m_ppu.m_beam.current_vert, 10), timer_expired_delegate(FUNC(snes_state::snes_reset_oam_address),this)); |
| 223 | 225 | |
| 224 | | snes_ram[HVBJOY] |= 0x81; /* Set vblank bit to on & indicate controllers being read */ |
| 225 | | snes_ram[RDNMI] |= 0x80; /* Set NMI occurred bit */ |
| 226 | SNES_CPU_REG(HVBJOY) |= 0x81; /* Set vblank bit to on & indicate controllers being read */ |
| 227 | SNES_CPU_REG(RDNMI) |= 0x80; /* Set NMI occurred bit */ |
| 226 | 228 | |
| 227 | | if (snes_ram[NMITIMEN] & 0x80) /* NMI only signaled if this bit set */ |
| 229 | if (SNES_CPU_REG(NMITIMEN) & 0x80) /* NMI only signaled if this bit set */ |
| 228 | 230 | { |
| 229 | 231 | // NMI goes off about 12 cycles after this (otherwise Chrono Trigger, NFL QB Club, etc. lock up) |
| 230 | 232 | m_nmi_timer->adjust(m_maincpu->cycles_to_attotime(12)); |
| r21565 | r21566 | |
| 243 | 245 | |
| 244 | 246 | if (m_ppu.m_beam.current_vert == 0) |
| 245 | 247 | { /* VBlank is over, time for a new frame */ |
| 246 | | snes_ram[HVBJOY] &= 0x7f; /* Clear vblank bit */ |
| 247 | | snes_ram[RDNMI] &= 0x7f; /* Clear nmi occurred bit */ |
| 248 | SNES_CPU_REG(HVBJOY) &= 0x7f; /* Clear vblank bit */ |
| 249 | SNES_CPU_REG(RDNMI) &= 0x7f; /* Clear nmi occurred bit */ |
| 248 | 250 | m_ppu.m_stat78 ^= 0x80; /* Toggle field flag */ |
| 249 | 251 | m_ppu.m_stat77 &= 0x3f; /* Clear Time Over and Range Over bits */ |
| 250 | 252 | |
| r21565 | r21566 | |
| 254 | 256 | m_scanline_timer->adjust(attotime::never); |
| 255 | 257 | m_hblank_timer->adjust(machine().primary_screen->time_until_pos(m_ppu.m_beam.current_vert, m_hblank_offset * m_ppu.m_htmult)); |
| 256 | 258 | |
| 257 | | // printf("%02x %d\n",snes_ram[HVBJOY],m_ppu.m_beam.current_vert); |
| 259 | // printf("%02x %d\n",SNES_CPU_REG(HVBJOY),m_ppu.m_beam.current_vert); |
| 258 | 260 | } |
| 259 | 261 | |
| 260 | 262 | /* This is called at the start of hblank *before* the scanline indicated in current_vert! */ |
| r21565 | r21566 | |
| 274 | 276 | if (machine().primary_screen->vpos() > 0) |
| 275 | 277 | { |
| 276 | 278 | /* Do HDMA */ |
| 277 | | if (snes_ram[HDMAEN]) |
| 279 | if (SNES_CPU_REG(HDMAEN)) |
| 278 | 280 | hdma(cpu0space); |
| 279 | 281 | |
| 280 | 282 | machine().primary_screen->update_partial((m_ppu.m_interlace == 2) ? (m_ppu.m_beam.current_vert * m_ppu.m_interlace) : m_ppu.m_beam.current_vert - 1); |
| r21565 | r21566 | |
| 282 | 284 | } |
| 283 | 285 | |
| 284 | 286 | // signal hblank |
| 285 | | snes_ram[HVBJOY] |= 0x40; |
| 287 | SNES_CPU_REG(HVBJOY) |= 0x40; |
| 286 | 288 | |
| 287 | 289 | /* kick off the start of scanline timer */ |
| 288 | 290 | nextscan = m_ppu.m_beam.current_vert + 1; |
| r21565 | r21566 | |
| 422 | 424 | break; |
| 423 | 425 | } |
| 424 | 426 | |
| 425 | | snes_ram[offset] = data; |
| 427 | DMA_REG(offset) = data; |
| 426 | 428 | } |
| 427 | 429 | |
| 428 | 430 | /* |
| r21565 | r21566 | |
| 439 | 441 | // PPU accesses are from 2100 to 213f |
| 440 | 442 | if (offset >= INIDISP && offset < APU00) |
| 441 | 443 | { |
| 442 | | return state->m_ppu.read(space, offset, snes_ram[WRIO] & 0x80); |
| 444 | return state->m_ppu.read(space, offset, SNES_CPU_REG_STATE(WRIO) & 0x80); |
| 443 | 445 | } |
| 444 | 446 | |
| 445 | 447 | // APU is mirrored from 2140 to 217f |
| r21565 | r21566 | |
| 495 | 497 | state->m_wram_address &= 0x1ffff; |
| 496 | 498 | return value; |
| 497 | 499 | case OLDJOY1: /* Data for old NES controllers (JOYSER1) */ |
| 498 | | if (snes_ram[OLDJOY1] & 0x1) |
| 500 | if (state->m_oldjoy1_latch & 0x1) |
| 499 | 501 | return 0 | (snes_open_bus_r(space, 0) & 0xfc); //correct? |
| 500 | 502 | |
| 501 | 503 | value = state->m_oldjoy1_read(space.machine()); |
| 502 | 504 | |
| 503 | 505 | return (value & 0x03) | (snes_open_bus_r(space, 0) & 0xfc); //correct? |
| 504 | 506 | case OLDJOY2: /* Data for old NES controllers (JOYSER2) */ |
| 505 | | if (snes_ram[OLDJOY1] & 0x1) |
| 507 | if (state->m_oldjoy1_latch & 0x1) |
| 506 | 508 | return 0 | 0x1c | (snes_open_bus_r(space, 0) & 0xe0); //correct? |
| 507 | 509 | |
| 508 | 510 | value = state->m_oldjoy2_read(space.machine()); |
| 509 | 511 | |
| 510 | 512 | return value | 0x1c | (snes_open_bus_r(space, 0) & 0xe0); //correct? |
| 511 | 513 | case RDNMI: /* NMI flag by v-blank and version number */ |
| 512 | | value = (snes_ram[RDNMI] & 0x80) | (snes_open_bus_r(space, 0) & 0x70); |
| 513 | | snes_ram[RDNMI] &= 0x70; /* NMI flag is reset on read */ |
| 514 | value = (SNES_CPU_REG_STATE(RDNMI) & 0x80) | (snes_open_bus_r(space, 0) & 0x70); |
| 515 | SNES_CPU_REG_STATE(RDNMI) &= 0x70; /* NMI flag is reset on read */ |
| 514 | 516 | return value | 2; //CPU version number |
| 515 | 517 | case TIMEUP: /* IRQ flag by H/V count timer */ |
| 516 | | value = (snes_open_bus_r(space, 0) & 0x7f) | (snes_ram[TIMEUP] & 0x80); |
| 518 | value = (snes_open_bus_r(space, 0) & 0x7f) | (SNES_CPU_REG_STATE(TIMEUP) & 0x80); |
| 517 | 519 | state->m_maincpu->set_input_line(G65816_LINE_IRQ, CLEAR_LINE ); |
| 518 | | snes_ram[TIMEUP] = 0; // flag is cleared on both read and write |
| 520 | SNES_CPU_REG_STATE(TIMEUP) = 0; // flag is cleared on both read and write |
| 519 | 521 | return value; |
| 520 | 522 | case HVBJOY: /* H/V blank and joypad controller enable */ |
| 521 | 523 | // electronics test says hcounter 272 is start of hblank, which is beampos 363 |
| 522 | | // if (space.machine().primary_screen->hpos() >= 363) snes_ram[HVBJOY] |= 0x40; |
| 523 | | // else snes_ram[HVBJOY] &= ~0x40; |
| 524 | | return (snes_ram[HVBJOY] & 0xc1) | (snes_open_bus_r(space, 0) & 0x3e); |
| 524 | // if (space.machine().primary_screen->hpos() >= 363) SNES_CPU_REG_STATE(HVBJOY) |= 0x40; |
| 525 | // else SNES_CPU_REG_STATE(HVBJOY) &= ~0x40; |
| 526 | return (SNES_CPU_REG_STATE(HVBJOY) & 0xc1) | (snes_open_bus_r(space, 0) & 0x3e); |
| 525 | 527 | case RDIO: /* Programmable I/O port - echos back what's written to WRIO */ |
| 526 | | return snes_ram[WRIO]; |
| 528 | return SNES_CPU_REG_STATE(WRIO); |
| 527 | 529 | case JOY1L: /* Joypad 1 status register (low) */ |
| 528 | 530 | if(state->m_is_nss && state->m_input_disabled) |
| 529 | 531 | return 0; |
| r21565 | r21566 | |
| 577 | 579 | default: |
| 578 | 580 | // mame_printf_debug("snes_r: offset = %x pc = %x\n",offset,space.device().safe_pc()); |
| 579 | 581 | // Added break; after commenting above line. If uncommenting, drop the break; |
| 580 | | break; |
| 582 | break; |
| 581 | 583 | } |
| 582 | 584 | |
| 583 | 585 | // printf("unsupported read: offset == %08x\n", offset); |
| r21565 | r21566 | |
| 678 | 680 | state->m_wram_address &= 0x1ffff; |
| 679 | 681 | return; |
| 680 | 682 | case OLDJOY1: /* Old NES joystick support */ |
| 681 | | if (((!(data & 0x1)) && (snes_ram[OLDJOY1] & 0x1))) |
| 683 | if (((!(data & 0x1)) && (state->m_oldjoy1_latch & 0x1))) |
| 682 | 684 | { |
| 683 | 685 | state->m_read_idx[0] = 0; |
| 684 | 686 | state->m_read_idx[1] = 0; |
| 685 | 687 | } |
| 686 | | if(state->m_is_nss) |
| 688 | if (state->m_is_nss) |
| 687 | 689 | { |
| 688 | 690 | state->m_game_over_flag = (data & 4) >> 2; |
| 689 | 691 | } |
| 690 | | break; |
| 692 | state->m_oldjoy1_latch = data; |
| 693 | return; |
| 694 | case OLDJOY2: /* Old NES joystick support */ |
| 695 | return; |
| 691 | 696 | case NMITIMEN: /* Flag for v-blank, timer int. and joy read */ |
| 692 | | if((data & 0x30) == 0x00) |
| 697 | if ((data & 0x30) == 0x00) |
| 693 | 698 | { |
| 694 | 699 | state->m_maincpu->set_input_line(G65816_LINE_IRQ, CLEAR_LINE ); |
| 695 | | snes_ram[TIMEUP] = 0; // clear pending IRQ if irq is disabled here, 3x3 Eyes - Seima Korin Den behaves on this |
| 700 | SNES_CPU_REG_STATE(TIMEUP) = 0; // clear pending IRQ if irq is disabled here, 3x3 Eyes - Seima Korin Den behaves on this |
| 696 | 701 | } |
| 697 | | break; |
| 698 | | case OLDJOY2: /* Old NES joystick support */ |
| 699 | | break; |
| 702 | SNES_CPU_REG_STATE(NMITIMEN) = data; |
| 703 | return; |
| 700 | 704 | case WRIO: /* Programmable I/O port - latches H/V counters on a 0->1 transition */ |
| 701 | | if (!(snes_ram[WRIO] & 0x80) && (data & 0x80)) |
| 705 | if (!(SNES_CPU_REG_STATE(WRIO) & 0x80) && (data & 0x80)) |
| 702 | 706 | { |
| 703 | 707 | // external latch |
| 704 | 708 | state->m_ppu.latch_counters(space.machine()); |
| 705 | 709 | } |
| 706 | | break; |
| 710 | SNES_CPU_REG_STATE(WRIO) = data; |
| 711 | return; |
| 707 | 712 | case HTIMEL: /* H-Count timer settings (low) */ |
| 708 | 713 | state->m_htime = (state->m_htime & 0xff00) | (data << 0); |
| 709 | 714 | state->m_htime &= 0x1ff; |
| r21565 | r21566 | |
| 722 | 727 | return; |
| 723 | 728 | case MDMAEN: /* DMA channel designation and trigger */ |
| 724 | 729 | state->dma(space, data); |
| 725 | | data = 0; /* Once DMA is done we need to reset all bits to 0 */ |
| 726 | | break; |
| 730 | SNES_CPU_REG_STATE(MDMAEN) = 0; /* Once DMA is done we need to reset all bits to 0 */ |
| 731 | return; |
| 727 | 732 | case HDMAEN: /* HDMA channel designation */ |
| 728 | 733 | if (data) //if a HDMA is enabled, data is inited at the next scanline |
| 729 | 734 | space.machine().scheduler().timer_set(space.machine().primary_screen->time_until_pos(state->m_ppu.m_beam.current_vert + 1), timer_expired_delegate(FUNC(snes_state::snes_reset_hdma),state)); |
| 730 | | break; |
| 735 | SNES_CPU_REG_STATE(HDMAEN) = data; |
| 736 | return; |
| 731 | 737 | case TIMEUP: // IRQ Flag is cleared on both read and write |
| 732 | 738 | state->m_maincpu->set_input_line(G65816_LINE_IRQ, CLEAR_LINE ); |
| 733 | | snes_ram[TIMEUP] = 0; |
| 739 | SNES_CPU_REG_STATE(TIMEUP) = 0; |
| 734 | 740 | return; |
| 735 | 741 | /* Following are read-only */ |
| 736 | 742 | case HVBJOY: /* H/V blank and joypad enable */ |
| r21565 | r21566 | |
| 1491 | 1497 | |
| 1492 | 1498 | // is automatic reading on? if so, copy port data1/data2 to joy1l->joy4h |
| 1493 | 1499 | // this actually works like reading the first 16bits from oldjoy1/2 in reverse order |
| 1494 | | if (snes_ram[NMITIMEN] & 1) |
| 1500 | if (SNES_CPU_REG_STATE(NMITIMEN) & 1) |
| 1495 | 1501 | { |
| 1496 | 1502 | state->m_joy1l = (state->m_data1[0] & 0x00ff) >> 0; |
| 1497 | 1503 | state->m_joy1h = (state->m_data1[0] & 0xff00) >> 8; |
| r21565 | r21566 | |
| 1593 | 1599 | state->m_oldjoy2_read = nss_oldjoy2_read; |
| 1594 | 1600 | |
| 1595 | 1601 | // set up some known register power-up defaults |
| 1596 | | snes_ram[WRIO] = 0xff; |
| 1597 | | snes_ram[VMAIN] = 0x80; |
| 1602 | SNES_CPU_REG_STATE(WRIO) = 0xff; |
| 1598 | 1603 | |
| 1599 | 1604 | // see if there's a uPD7725 DSP in the machine config |
| 1600 | 1605 | state->m_upd7725 = machine.device<upd7725_device>("dsp"); |
| r21565 | r21566 | |
| 1694 | 1699 | // state->m_soundcpu->space(AS_PROGRAM).set_direct_update_handler(direct_update_delegate(FUNC(snes_state::snes_spc_direct), state)); |
| 1695 | 1700 | |
| 1696 | 1701 | // power-on sets these registers like this |
| 1697 | | snes_ram[WRIO] = 0xff; |
| 1698 | | // snes_ram[WRMPYA] = 0xff; |
| 1699 | | // snes_ram[WRDIVL] = 0xff; |
| 1700 | | // snes_ram[WRDIVH] = 0xff; |
| 1702 | SNES_CPU_REG_STATE(WRIO) = 0xff; |
| 1703 | // SNES_CPU_REG_STATE(WRMPYA) = 0xff; |
| 1704 | // SNES_CPU_REG_STATE(WRDIVL) = 0xff; |
| 1705 | // SNES_CPU_REG_STATE(WRDIVH) = 0xff; |
| 1701 | 1706 | |
| 1702 | 1707 | switch (state->m_has_addon_chip) |
| 1703 | 1708 | { |
| r21565 | r21566 | |
| 1748 | 1753 | state->save_item(NAME(state->m_data1)); |
| 1749 | 1754 | state->save_item(NAME(state->m_data2)); |
| 1750 | 1755 | state->save_item(NAME(state->m_read_idx)); |
| 1756 | state->save_item(NAME(state->m_dma_regs)); |
| 1757 | state->save_item(NAME(state->m_cpu_regs)); |
| 1758 | state->save_item(NAME(state->m_oldjoy1_latch)); |
| 1751 | 1759 | |
| 1752 | 1760 | for (int i = 0; i < 2; i++) |
| 1753 | 1761 | { |
| r21565 | r21566 | |
| 1801 | 1809 | state->m_ppu.m_stat78 = SNES_PAL; |
| 1802 | 1810 | |
| 1803 | 1811 | // reset does this to these registers |
| 1804 | | snes_ram[NMITIMEN] = 0; |
| 1812 | SNES_CPU_REG_STATE(NMITIMEN) = 0; |
| 1805 | 1813 | state->m_htime = 0x1ff; |
| 1806 | 1814 | state->m_vtime = 0x1ff; |
| 1807 | 1815 | |
| r21565 | r21566 | |
| 2054 | 2062 | |
| 2055 | 2063 | void snes_state::hdma_init( address_space &space ) |
| 2056 | 2064 | { |
| 2057 | | m_hdmaen = snes_ram[HDMAEN]; |
| 2065 | m_hdmaen = SNES_CPU_REG(HDMAEN); |
| 2058 | 2066 | for (int i = 0; i < 8; i++) |
| 2059 | 2067 | { |
| 2060 | 2068 | if (BIT(m_hdmaen, i)) |