summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Angelo Salese <angelosa@users.noreply.github.com>2012-09-04 19:08:03 +0000
committer Angelo Salese <angelosa@users.noreply.github.com>2012-09-04 19:08:03 +0000
commit38def1aaed471be821c0768d0327e7315c703449 (patch)
tree2c0ef5fd7d6a164d59648f747039104e67a271dd
parent05054328f2a32f03e3a9b88a694b8d69bafca484 (diff)
Moved multiplication and division operation from SNES to 5A22 CPU core file [Angelo Salese]
-rw-r--r--src/emu/cpu/g65816/g65816.c102
-rw-r--r--src/emu/cpu/g65816/g65816cm.h7
-rw-r--r--src/mame/includes/snes.h22
-rw-r--r--src/mame/machine/snes.c97
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)
{