diff options
author | 2012-09-04 19:08:03 +0000 | |
---|---|---|
committer | 2012-09-04 19:08:03 +0000 | |
commit | 38def1aaed471be821c0768d0327e7315c703449 (patch) | |
tree | 2c0ef5fd7d6a164d59648f747039104e67a271dd | |
parent | 05054328f2a32f03e3a9b88a694b8d69bafca484 (diff) |
Moved multiplication and division operation from SNES to 5A22 CPU core file [Angelo Salese]
-rw-r--r-- | src/emu/cpu/g65816/g65816.c | 102 | ||||
-rw-r--r-- | src/emu/cpu/g65816/g65816cm.h | 7 | ||||
-rw-r--r-- | src/mame/includes/snes.h | 22 | ||||
-rw-r--r-- | src/mame/machine/snes.c | 97 |
4 files changed, 131 insertions, 97 deletions
diff --git a/src/emu/cpu/g65816/g65816.c b/src/emu/cpu/g65816/g65816.c index 0d97a353de9..a87a8ed4a1d 100644 --- a/src/emu/cpu/g65816/g65816.c +++ b/src/emu/cpu/g65816/g65816.c @@ -571,8 +571,109 @@ static CPU_RESET( 5a22 ) CPU_RESET_CALL(g65816); cpustate->fastROM = 0; + cpustate->wrmpya = 0xff; + cpustate->wrdiv = 0xffff; } +/* TODO: multiplication / division should actually occur inside CPU_EXECUTE */ +/* (Old note, for reference): multiplication should take 8 CPU cycles & +division 16 CPU cycles, but using these timers breaks e.g. Chrono Trigger +intro and Super Tennis gameplay. On the other hand, timers are needed for the +translation of Breath of Fire 2 to work. More weirdness: we might need to leave +8 CPU cycles for division at first, since using 16 produces bugs (see e.g. +Triforce pieces in Zelda 3 intro) */ + +static WRITE8_HANDLER( wrmpya_w ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + + cpustate->wrmpya = data; +} + +static WRITE8_HANDLER( wrmpyb_w ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + + cpustate->wrmpyb = data; + cpustate->rdmpy = cpustate->wrmpya * cpustate->wrmpyb; + /* TODO: cpustate->rddiv == 0? */ +} + +static WRITE8_HANDLER( wrdivl_w ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + + cpustate->wrdiv = (data) | (cpustate->wrdiv & 0xff00); +} + +static WRITE8_HANDLER( wrdivh_w ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + + cpustate->wrdiv = (data << 8) | (cpustate->wrdiv & 0xff); +} + +static WRITE8_HANDLER( wrdvdd_w ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + UINT16 quotient, remainder; + + cpustate->dvdd = data; + + if(cpustate->dvdd != 0) + { + quotient = cpustate->wrdiv / cpustate->dvdd; + remainder = cpustate->wrdiv % cpustate->dvdd; + } + else + { + quotient = 0xffff; + remainder = 0x000c; + } + + cpustate->rddiv = quotient; + cpustate->rdmpy = remainder; +} + +static READ8_HANDLER( rddivl_r ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + return cpustate->rddiv & 0xff; +} + +static READ8_HANDLER( rddivh_r ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + return cpustate->rddiv >> 8; +} + +static READ8_HANDLER( rdmpyl_r ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + return cpustate->rdmpy & 0xff; +} + +static READ8_HANDLER( rdmpyh_r ) +{ + g65816i_cpu_struct *cpustate = get_safe_token(&space->device()); + return cpustate->rdmpy >> 8; +} + + +static ADDRESS_MAP_START(_5a22_map, AS_PROGRAM, 8, legacy_cpu_device) + AM_RANGE(0x4202, 0x4202) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrmpya_w) + AM_RANGE(0x4203, 0x4203) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrmpyb_w) + AM_RANGE(0x4204, 0x4204) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdivl_w) + AM_RANGE(0x4205, 0x4205) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdivh_w) + AM_RANGE(0x4206, 0x4206) AM_MIRROR(0x3f0000) AM_WRITE_LEGACY(wrdvdd_w) + + AM_RANGE(0x4214, 0x4214) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rddivl_r) + AM_RANGE(0x4215, 0x4215) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rddivh_r) + AM_RANGE(0x4216, 0x4216) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rdmpyl_r) + AM_RANGE(0x4217, 0x4217) AM_MIRROR(0x3f0000) AM_READ_LEGACY(rdmpyh_r) + +ADDRESS_MAP_END + CPU_SET_INFO( _5a22 ) { g65816i_cpu_struct *cpustate = (device != NULL && device->token() != NULL) ? get_safe_token(device) : NULL; @@ -600,6 +701,7 @@ CPU_GET_INFO( _5a22 ) case CPUINFO_STR_NAME: strcpy(info->s, "5A22"); break; case CPUINFO_INT_REGISTER + _5A22_FASTROM: info->i = g65816_get_reg(cpustate, _5A22_FASTROM); break; case CPUINFO_STR_REGISTER + _5A22_FASTROM: sprintf(info->s, "fastROM:%d", cpustate->fastROM & 1 ? 1 : 0); break; + case CPUINFO_PTR_INTERNAL_MEMORY_MAP + AS_PROGRAM: info->internal_map8 = ADDRESS_MAP_NAME(_5a22_map); break; default: CPU_GET_INFO_CALL(g65816); break; } diff --git a/src/emu/cpu/g65816/g65816cm.h b/src/emu/cpu/g65816/g65816cm.h index 79ee2d0190c..054a32a0c1a 100644 --- a/src/emu/cpu/g65816/g65816cm.h +++ b/src/emu/cpu/g65816/g65816cm.h @@ -110,6 +110,13 @@ struct _g65816i_cpu_struct int ICount; int cpu_type; UINT8 rw8_cycles, rw16_cycles, rw24_cycles; + + /* 5A22 specific registers */ + UINT8 wrmpya, wrmpyb; + UINT16 rdmpy; + UINT16 wrdiv; + UINT8 dvdd; + UINT16 rddiv; }; extern void (*const *const g65816i_opcodes[])(g65816i_cpu_struct *cpustate); diff --git a/src/mame/includes/snes.h b/src/mame/includes/snes.h index ef8fb4d671a..6488cc91697 100644 --- a/src/mame/includes/snes.h +++ b/src/mame/includes/snes.h @@ -146,11 +146,11 @@ #define OLDJOY2 0x4017 #define NMITIMEN 0x4200 #define WRIO 0x4201 -#define WRMPYA 0x4202 -#define WRMPYB 0x4203 -#define WRDIVL 0x4204 -#define WRDIVH 0x4205 -#define WRDVDD 0x4206 +//#define WRMPYA 0x4202 +//#define WRMPYB 0x4203 +//#define WRDIVL 0x4204 +//#define WRDIVH 0x4205 +//#define WRDVDD 0x4206 #define HTIMEL 0x4207 #define HTIMEH 0x4208 #define VTIMEL 0x4209 @@ -162,10 +162,10 @@ #define TIMEUP 0x4211 #define HVBJOY 0x4212 #define RDIO 0x4213 -#define RDDIVL 0x4214 -#define RDDIVH 0x4215 -#define RDMPYL 0x4216 -#define RDMPYH 0x4217 +//#define RDDIVL 0x4214 +//#define RDDIVH 0x4215 +//#define RDMPYL 0x4216 +//#define RDMPYH 0x4217 #define JOY1L 0x4218 #define JOY1H 0x4219 #define JOY2L 0x421A @@ -439,8 +439,8 @@ public: emu_timer *m_hblank_timer; emu_timer *m_nmi_timer; emu_timer *m_hirq_timer; - emu_timer *m_div_timer; - emu_timer *m_mult_timer; +// emu_timer *m_div_timer; +// emu_timer *m_mult_timer; emu_timer *m_io_timer; /* DMA/HDMA-related */ diff --git a/src/mame/machine/snes.c b/src/mame/machine/snes.c index 3601cc78f7e..7ab8aadbef4 100644 --- a/src/mame/machine/snes.c +++ b/src/mame/machine/snes.c @@ -291,40 +291,6 @@ static TIMER_CALLBACK( snes_hblank_tick ) state->m_scanline_timer->adjust(machine.primary_screen->time_until_pos(nextscan)); } -/* FIXME: multiplication should take 8 CPU cycles & division 16 CPU cycles, but -using these timers breaks e.g. Chrono Trigger intro and Super Tennis gameplay. -On the other hand, timers are needed for the translation of Breath of Fire 2 -to work. More weirdness: we might need to leave 8 CPU cycles for division at -first, since using 16 produces bugs (see e.g. Triforce pieces in Zelda 3 intro) */ - -static TIMER_CALLBACK(snes_div_callback) -{ - UINT16 value, dividend, remainder; - dividend = remainder = 0; - value = (snes_ram[WRDIVH] << 8) + snes_ram[WRDIVL]; - if (snes_ram[WRDVDD] > 0) - { - dividend = value / snes_ram[WRDVDD]; - remainder = value % snes_ram[WRDVDD]; - } - else - { - dividend = 0xffff; - remainder = value; - } - snes_ram[RDDIVL] = dividend & 0xff; - snes_ram[RDDIVH] = (dividend >> 8) & 0xff; - snes_ram[RDMPYL] = remainder & 0xff; - snes_ram[RDMPYH] = (remainder >> 8) & 0xff; -} - - -static TIMER_CALLBACK(snes_mult_callback) -{ - UINT32 c = snes_ram[WRMPYA] * snes_ram[WRMPYB]; - snes_ram[RDMPYL] = c & 0xff; - snes_ram[RDMPYH] = (c >> 8) & 0xff; -} /************************************* @@ -555,11 +521,6 @@ READ8_HANDLER( snes_r_io ) return (snes_ram[offset] & 0xc1) | (snes_open_bus_r(space, 0) & 0x3e); case RDIO: /* Programmable I/O port - echos back what's written to WRIO */ return snes_ram[WRIO]; - case RDDIVL: /* Quotient of divide result (low) */ - case RDDIVH: /* Quotient of divide result (high) */ - case RDMPYL: /* Product/Remainder of mult/div result (low) */ - case RDMPYH: /* Product/Remainder of mult/div result (high) */ - return snes_ram[offset]; case JOY1L: /* Joypad 1 status register (low) */ if(state->m_is_nss && state->m_input_disabled) return 0; @@ -740,42 +701,6 @@ WRITE8_HANDLER( snes_w_io ) snes_latch_counters(space->machine()); } break; - case WRMPYA: /* Multiplier A */ - break; - case WRMPYB: /* Multiplier B */ - snes_ram[WRMPYB] = data; -// state->m_mult_timer->adjust(state->m_maincpu->cycles_to_attotime(8)); - { - UINT32 c = snes_ram[WRMPYA] * snes_ram[WRMPYB]; - snes_ram[RDMPYL] = c & 0xff; - snes_ram[RDMPYH] = (c >> 8) & 0xff; - } - break; - case WRDIVL: /* Dividend (low) */ - case WRDIVH: /* Dividend (high) */ - break; - case WRDVDD: /* Divisor */ - snes_ram[WRDVDD] = data; -// state->m_div_timer->adjust(state->m_maincpu->cycles_to_attotime(16)); - { - UINT16 value, dividend, remainder; - value = (snes_ram[WRDIVH] << 8) + snes_ram[WRDIVL]; - if (snes_ram[WRDVDD] > 0) - { - dividend = value / data; - remainder = value % data; - } - else - { - dividend = 0xffff; - remainder = value; - } - snes_ram[RDDIVL] = dividend & 0xff; - snes_ram[RDDIVH] = (dividend >> 8) & 0xff; - snes_ram[RDMPYL] = remainder & 0xff; - snes_ram[RDMPYH] = (remainder >> 8) & 0xff; - } - break; case HTIMEL: /* H-Count timer settings (low) */ state->m_htime = (state->m_htime & 0xff00) | (data << 0); state->m_htime &= 0x1ff; @@ -813,10 +738,10 @@ WRITE8_HANDLER( snes_w_io ) case MPYM: /* Multiplication result (mid) */ case MPYH: /* Multiplication result (high) */ case RDIO: - case RDDIVL: - case RDDIVH: - case RDMPYL: - case RDMPYH: +// case RDDIVL: +// case RDDIVH: +// case RDMPYL: +// case RDMPYH: case JOY1L: case JOY1H: case JOY2L: @@ -1620,10 +1545,10 @@ static void snes_init_timers( running_machine &machine ) state->m_nmi_timer->adjust(attotime::never); state->m_hirq_timer = machine.scheduler().timer_alloc(FUNC(snes_hirq_tick_callback)); state->m_hirq_timer->adjust(attotime::never); - state->m_div_timer = machine.scheduler().timer_alloc(FUNC(snes_div_callback)); - state->m_div_timer->adjust(attotime::never); - state->m_mult_timer = machine.scheduler().timer_alloc(FUNC(snes_mult_callback)); - state->m_mult_timer->adjust(attotime::never); + //state->m_div_timer = machine.scheduler().timer_alloc(FUNC(snes_div_callback)); + //state->m_div_timer->adjust(attotime::never); + //state->m_mult_timer = machine.scheduler().timer_alloc(FUNC(snes_mult_callback)); + //state->m_mult_timer->adjust(attotime::never); state->m_io_timer = machine.scheduler().timer_alloc(FUNC(snes_update_io)); state->m_io_timer->adjust(attotime::never); @@ -1762,9 +1687,9 @@ MACHINE_START( snes ) // power-on sets these registers like this snes_ram[WRIO] = 0xff; - snes_ram[WRMPYA] = 0xff; - snes_ram[WRDIVL] = 0xff; - snes_ram[WRDIVH] = 0xff; +// snes_ram[WRMPYA] = 0xff; +// snes_ram[WRDIVL] = 0xff; +// snes_ram[WRDIVH] = 0xff; switch (state->m_has_addon_chip) { |