trunk/src/mame/machine/snes.c
r17641 | r17642 | |
291 | 291 | state->m_scanline_timer->adjust(machine.primary_screen->time_until_pos(nextscan)); |
292 | 292 | } |
293 | 293 | |
294 | | /* FIXME: multiplication should take 8 CPU cycles & division 16 CPU cycles, but |
295 | | using these timers breaks e.g. Chrono Trigger intro and Super Tennis gameplay. |
296 | | On the other hand, timers are needed for the translation of Breath of Fire 2 |
297 | | to work. More weirdness: we might need to leave 8 CPU cycles for division at |
298 | | first, since using 16 produces bugs (see e.g. Triforce pieces in Zelda 3 intro) */ |
299 | 294 | |
300 | | static TIMER_CALLBACK(snes_div_callback) |
301 | | { |
302 | | UINT16 value, dividend, remainder; |
303 | | dividend = remainder = 0; |
304 | | value = (snes_ram[WRDIVH] << 8) + snes_ram[WRDIVL]; |
305 | | if (snes_ram[WRDVDD] > 0) |
306 | | { |
307 | | dividend = value / snes_ram[WRDVDD]; |
308 | | remainder = value % snes_ram[WRDVDD]; |
309 | | } |
310 | | else |
311 | | { |
312 | | dividend = 0xffff; |
313 | | remainder = value; |
314 | | } |
315 | | snes_ram[RDDIVL] = dividend & 0xff; |
316 | | snes_ram[RDDIVH] = (dividend >> 8) & 0xff; |
317 | | snes_ram[RDMPYL] = remainder & 0xff; |
318 | | snes_ram[RDMPYH] = (remainder >> 8) & 0xff; |
319 | | } |
320 | | |
321 | | |
322 | | static TIMER_CALLBACK(snes_mult_callback) |
323 | | { |
324 | | UINT32 c = snes_ram[WRMPYA] * snes_ram[WRMPYB]; |
325 | | snes_ram[RDMPYL] = c & 0xff; |
326 | | snes_ram[RDMPYH] = (c >> 8) & 0xff; |
327 | | } |
328 | | |
329 | 295 | /************************************* |
330 | 296 | |
331 | 297 | Input Handlers |
r17641 | r17642 | |
555 | 521 | return (snes_ram[offset] & 0xc1) | (snes_open_bus_r(space, 0) & 0x3e); |
556 | 522 | case RDIO: /* Programmable I/O port - echos back what's written to WRIO */ |
557 | 523 | return snes_ram[WRIO]; |
558 | | case RDDIVL: /* Quotient of divide result (low) */ |
559 | | case RDDIVH: /* Quotient of divide result (high) */ |
560 | | case RDMPYL: /* Product/Remainder of mult/div result (low) */ |
561 | | case RDMPYH: /* Product/Remainder of mult/div result (high) */ |
562 | | return snes_ram[offset]; |
563 | 524 | case JOY1L: /* Joypad 1 status register (low) */ |
564 | 525 | if(state->m_is_nss && state->m_input_disabled) |
565 | 526 | return 0; |
r17641 | r17642 | |
740 | 701 | snes_latch_counters(space->machine()); |
741 | 702 | } |
742 | 703 | break; |
743 | | case WRMPYA: /* Multiplier A */ |
744 | | break; |
745 | | case WRMPYB: /* Multiplier B */ |
746 | | snes_ram[WRMPYB] = data; |
747 | | // state->m_mult_timer->adjust(state->m_maincpu->cycles_to_attotime(8)); |
748 | | { |
749 | | UINT32 c = snes_ram[WRMPYA] * snes_ram[WRMPYB]; |
750 | | snes_ram[RDMPYL] = c & 0xff; |
751 | | snes_ram[RDMPYH] = (c >> 8) & 0xff; |
752 | | } |
753 | | break; |
754 | | case WRDIVL: /* Dividend (low) */ |
755 | | case WRDIVH: /* Dividend (high) */ |
756 | | break; |
757 | | case WRDVDD: /* Divisor */ |
758 | | snes_ram[WRDVDD] = data; |
759 | | // state->m_div_timer->adjust(state->m_maincpu->cycles_to_attotime(16)); |
760 | | { |
761 | | UINT16 value, dividend, remainder; |
762 | | value = (snes_ram[WRDIVH] << 8) + snes_ram[WRDIVL]; |
763 | | if (snes_ram[WRDVDD] > 0) |
764 | | { |
765 | | dividend = value / data; |
766 | | remainder = value % data; |
767 | | } |
768 | | else |
769 | | { |
770 | | dividend = 0xffff; |
771 | | remainder = value; |
772 | | } |
773 | | snes_ram[RDDIVL] = dividend & 0xff; |
774 | | snes_ram[RDDIVH] = (dividend >> 8) & 0xff; |
775 | | snes_ram[RDMPYL] = remainder & 0xff; |
776 | | snes_ram[RDMPYH] = (remainder >> 8) & 0xff; |
777 | | } |
778 | | break; |
779 | 704 | case HTIMEL: /* H-Count timer settings (low) */ |
780 | 705 | state->m_htime = (state->m_htime & 0xff00) | (data << 0); |
781 | 706 | state->m_htime &= 0x1ff; |
r17641 | r17642 | |
813 | 738 | case MPYM: /* Multiplication result (mid) */ |
814 | 739 | case MPYH: /* Multiplication result (high) */ |
815 | 740 | case RDIO: |
816 | | case RDDIVL: |
817 | | case RDDIVH: |
818 | | case RDMPYL: |
819 | | case RDMPYH: |
| 741 | // case RDDIVL: |
| 742 | // case RDDIVH: |
| 743 | // case RDMPYL: |
| 744 | // case RDMPYH: |
820 | 745 | case JOY1L: |
821 | 746 | case JOY1H: |
822 | 747 | case JOY2L: |
r17641 | r17642 | |
1620 | 1545 | state->m_nmi_timer->adjust(attotime::never); |
1621 | 1546 | state->m_hirq_timer = machine.scheduler().timer_alloc(FUNC(snes_hirq_tick_callback)); |
1622 | 1547 | state->m_hirq_timer->adjust(attotime::never); |
1623 | | state->m_div_timer = machine.scheduler().timer_alloc(FUNC(snes_div_callback)); |
1624 | | state->m_div_timer->adjust(attotime::never); |
1625 | | state->m_mult_timer = machine.scheduler().timer_alloc(FUNC(snes_mult_callback)); |
1626 | | state->m_mult_timer->adjust(attotime::never); |
| 1548 | //state->m_div_timer = machine.scheduler().timer_alloc(FUNC(snes_div_callback)); |
| 1549 | //state->m_div_timer->adjust(attotime::never); |
| 1550 | //state->m_mult_timer = machine.scheduler().timer_alloc(FUNC(snes_mult_callback)); |
| 1551 | //state->m_mult_timer->adjust(attotime::never); |
1627 | 1552 | state->m_io_timer = machine.scheduler().timer_alloc(FUNC(snes_update_io)); |
1628 | 1553 | state->m_io_timer->adjust(attotime::never); |
1629 | 1554 | |
r17641 | r17642 | |
1762 | 1687 | |
1763 | 1688 | // power-on sets these registers like this |
1764 | 1689 | snes_ram[WRIO] = 0xff; |
1765 | | snes_ram[WRMPYA] = 0xff; |
1766 | | snes_ram[WRDIVL] = 0xff; |
1767 | | snes_ram[WRDIVH] = 0xff; |
| 1690 | // snes_ram[WRMPYA] = 0xff; |
| 1691 | // snes_ram[WRDIVL] = 0xff; |
| 1692 | // snes_ram[WRDIVH] = 0xff; |
1768 | 1693 | |
1769 | 1694 | switch (state->m_has_addon_chip) |
1770 | 1695 | { |
trunk/src/emu/cpu/g65816/g65816.c
r17641 | r17642 | |
571 | 571 | CPU_RESET_CALL(g65816); |
572 | 572 | |
573 | 573 | cpustate->fastROM = 0; |
| 574 | cpustate->wrmpya = 0xff; |
| 575 | cpustate->wrdiv = 0xffff; |
574 | 576 | } |
575 | 577 | |
| 578 | /* TODO: multiplication / division should actually occur inside CPU_EXECUTE */ |
| 579 | /* (Old note, for reference): multiplication should take 8 CPU cycles & |
| 580 | division 16 CPU cycles, but using these timers breaks e.g. Chrono Trigger |
| 581 | intro and Super Tennis gameplay. On the other hand, timers are needed for the |
| 582 | translation of Breath of Fire 2 to work. More weirdness: we might need to leave |
| 583 | 8 CPU cycles for division at first, since using 16 produces bugs (see e.g. |
| 584 | Triforce pieces in Zelda 3 intro) */ |
| 585 | |
| 586 | static WRITE8_HANDLER( wrmpya_w ) |
| 587 | { |
| 588 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 589 | |
| 590 | cpustate->wrmpya = data; |
| 591 | } |
| 592 | |
| 593 | static WRITE8_HANDLER( wrmpyb_w ) |
| 594 | { |
| 595 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 596 | |
| 597 | cpustate->wrmpyb = data; |
| 598 | cpustate->rdmpy = cpustate->wrmpya * cpustate->wrmpyb; |
| 599 | /* TODO: cpustate->rddiv == 0? */ |
| 600 | } |
| 601 | |
| 602 | static WRITE8_HANDLER( wrdivl_w ) |
| 603 | { |
| 604 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 605 | |
| 606 | cpustate->wrdiv = (data) | (cpustate->wrdiv & 0xff00); |
| 607 | } |
| 608 | |
| 609 | static WRITE8_HANDLER( wrdivh_w ) |
| 610 | { |
| 611 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 612 | |
| 613 | cpustate->wrdiv = (data << 8) | (cpustate->wrdiv & 0xff); |
| 614 | } |
| 615 | |
| 616 | static WRITE8_HANDLER( wrdvdd_w ) |
| 617 | { |
| 618 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 619 | UINT16 quotient, remainder; |
| 620 | |
| 621 | cpustate->dvdd = data; |
| 622 | |
| 623 | if(cpustate->dvdd != 0) |
| 624 | { |
| 625 | quotient = cpustate->wrdiv / cpustate->dvdd; |
| 626 | remainder = cpustate->wrdiv % cpustate->dvdd; |
| 627 | } |
| 628 | else |
| 629 | { |
| 630 | quotient = 0xffff; |
| 631 | remainder = 0x000c; |
| 632 | } |
| 633 | |
| 634 | cpustate->rddiv = quotient; |
| 635 | cpustate->rdmpy = remainder; |
| 636 | } |
| 637 | |
| 638 | static READ8_HANDLER( rddivl_r ) |
| 639 | { |
| 640 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 641 | return cpustate->rddiv & 0xff; |
| 642 | } |
| 643 | |
| 644 | static READ8_HANDLER( rddivh_r ) |
| 645 | { |
| 646 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 647 | return cpustate->rddiv >> 8; |
| 648 | } |
| 649 | |
| 650 | static READ8_HANDLER( rdmpyl_r ) |
| 651 | { |
| 652 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 653 | return cpustate->rdmpy & 0xff; |
| 654 | } |
| 655 | |
| 656 | static READ8_HANDLER( rdmpyh_r ) |
| 657 | { |
| 658 | g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); |
| 659 | return cpustate->rdmpy >> 8; |
| 660 | } |
| 661 | |
| 662 | |
| 663 | static ADDRESS_MAP_START(_5a22_map, AS_PROGRAM, 8, legacy_cpu_device) |
| 664 | AM_RANGE(0x4202, 0x4202) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrmpya_w) |
| 665 | AM_RANGE(0x4203, 0x4203) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrmpyb_w) |
| 666 | AM_RANGE(0x4204, 0x4204) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdivl_w) |
| 667 | AM_RANGE(0x4205, 0x4205) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdivh_w) |
| 668 | AM_RANGE(0x4206, 0x4206) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdvdd_w) |
| 669 | |
| 670 | AM_RANGE(0x4214, 0x4214) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rddivl_r) |
| 671 | AM_RANGE(0x4215, 0x4215) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rddivh_r) |
| 672 | AM_RANGE(0x4216, 0x4216) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rdmpyl_r) |
| 673 | AM_RANGE(0x4217, 0x4217) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rdmpyh_r) |
| 674 | |
| 675 | ADDRESS_MAP_END |
| 676 | |
576 | 677 | CPU_SET_INFO( _5a22 ) |
577 | 678 | { |
578 | 679 | g65816i_cpu_struct *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; |
r17641 | r17642 | |
600 | 701 | case CPUINFO_STR_NAME: strcpy(info->s, "5A22"); break; |
601 | 702 | case CPUINFO_INT_REGISTER + _5A22_FASTROM: info->i = g65816_get_reg(cpustate, _5A22_FASTROM); break; |
602 | 703 | case CPUINFO_STR_REGISTER + _5A22_FASTROM: sprintf(info->s, "fastROM:%d", cpustate->fastROM & 1 ? 1 : 0); break; |
| 704 | case CPUINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map8 = ADDRESS_MAP_NAME(_5a22_map); break; |
603 | 705 | |
604 | 706 | default: CPU_GET_INFO_CALL(g65816); break; |
605 | 707 | } |