mirror of
https://github.com/holub/mame
synced 2025-05-21 05:08:54 +03:00

related APIs now take a device pointer instead of an index. All functions that take a CPU device are prefixed with cpu_* All functions that are globally related to cpu execution are prefixed with cpuexec_*. Below is a list of some of the mappings: cpu_boost_interleave -> cpuexec_boost_interleave cpunum_suspend -> cpu_suspend cpunum_resume -> cpu_resume cpunum_is_suspended -> cpu_is_suspended cpunum_get_clock -> cpu_get_clock cpunum_set_clock -> cpu_set_clock cpunum_get_clockscale -> cpu_get_clockscale cpunum_set_clockscale -> cpu_set_clockscale cpunum_get_localtime -> cpu_get_local_time cpunum_gettotalcycles -> cpu_get_total_cycles activecpu_eat_cycles -> cpu_eat_cycles activecpu_adjust_icount -> cpu_adjust_icount cpu_trigger -> cpuexec_trigger cpu_triggertime -> cpuexec_triggertime cpunum_set_input_line -> cpu_set_input_line cpunum_set_irq_callback -> cpu_set_irq_callback In addition, a number of functions retain the same name but now require a specific CPU parameter to be passed in: cpu_yield cpu_spin cpu_spinuntil_time cpu_spinuntil_int cpu_spinuntil_trigger cpu_triggerint Merged cpuint.c into cpuexec.c. One side-effect of this change is that driver reset callbacks are called AFTER the CPUs and devices are reset. This means that if you make changes to the CPU state and expect the reset vectors to recognize the changes in your reset routine, you will need to manually reset the CPU after making the change (since it has already been reset). Added a number of inline helper functions to cpuintrf.h for managing addresses Removed cpu_gettotalcpu(). This information is rarely needed outside of the core and can be obtained by looking at the machine->cpu[] array. Changed CPU interrupt acknowledge callbacks to pass a CPU device instead of machine/cpunum pair. Changed VBLANK and periodic timer callbacks to pass a CPU device instead of machine/cpunum pair. Renamed all information getters from cpu_* to cpu_get_* and from cputype_* to cputype_get_*.
180 lines
4.6 KiB
C
180 lines
4.6 KiB
C
/***************************************************************************
|
|
|
|
TMP68301 basic emulation + Interrupt Handling
|
|
|
|
The Toshiba TMP68301 is a 68HC000 + serial I/O, parallel I/O,
|
|
3 timers, address decoder, wait generator, interrupt controller,
|
|
all integrated in a single chip.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "driver.h"
|
|
#include "machine/tmp68301.h"
|
|
|
|
UINT16 *tmp68301_regs;
|
|
|
|
static UINT8 tmp68301_IE[3]; // 3 External Interrupt Lines
|
|
static emu_timer *tmp68301_timer[3]; // 3 Timers
|
|
|
|
static int tmp68301_irq_vector[8];
|
|
|
|
static void tmp68301_update_timer( running_machine *machine, int i );
|
|
|
|
static IRQ_CALLBACK(tmp68301_irq_callback)
|
|
{
|
|
int vector = tmp68301_irq_vector[irqline];
|
|
// logerror("CPU #0 PC %06X: irq callback returns %04X for level %x\n",cpu_get_pc(machine->activecpu),vector,int_level);
|
|
return vector;
|
|
}
|
|
|
|
static TIMER_CALLBACK( tmp68301_timer_callback )
|
|
{
|
|
int i = param;
|
|
UINT16 TCR = tmp68301_regs[(0x200 + i * 0x20)/2];
|
|
UINT16 IMR = tmp68301_regs[0x94/2]; // Interrupt Mask Register (IMR)
|
|
UINT16 ICR = tmp68301_regs[0x8e/2+i]; // Interrupt Controller Register (ICR7..9)
|
|
UINT16 IVNR = tmp68301_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR)
|
|
|
|
// logerror("CPU #0 PC %06X: callback timer %04X, j = %d\n",cpu_get_pc(machine->activecpu),i,tcount);
|
|
|
|
if ( (TCR & 0x0004) && // INT
|
|
!(IMR & (0x100<<i))
|
|
)
|
|
{
|
|
int level = ICR & 0x0007;
|
|
|
|
// Interrupt Vector Number Register (IVNR)
|
|
tmp68301_irq_vector[level] = IVNR & 0x00e0;
|
|
tmp68301_irq_vector[level] += 4+i;
|
|
|
|
cpu_set_input_line(machine->cpu[0],level,HOLD_LINE);
|
|
}
|
|
|
|
if (TCR & 0x0080) // N/1
|
|
{
|
|
// Repeat
|
|
tmp68301_update_timer(machine, i);
|
|
}
|
|
else
|
|
{
|
|
// One Shot
|
|
}
|
|
}
|
|
|
|
static void tmp68301_update_timer( running_machine *machine, int i )
|
|
{
|
|
UINT16 TCR = tmp68301_regs[(0x200 + i * 0x20)/2];
|
|
UINT16 MAX1 = tmp68301_regs[(0x204 + i * 0x20)/2];
|
|
UINT16 MAX2 = tmp68301_regs[(0x206 + i * 0x20)/2];
|
|
|
|
int max = 0;
|
|
attotime duration = attotime_zero;
|
|
|
|
timer_adjust_oneshot(tmp68301_timer[i],attotime_never,i);
|
|
|
|
// timers 1&2 only
|
|
switch( (TCR & 0x0030)>>4 ) // MR2..1
|
|
{
|
|
case 1:
|
|
max = MAX1;
|
|
break;
|
|
case 2:
|
|
max = MAX2;
|
|
break;
|
|
}
|
|
|
|
switch ( (TCR & 0xc000)>>14 ) // CK2..1
|
|
{
|
|
case 0: // System clock (CLK)
|
|
if (max)
|
|
{
|
|
int scale = (TCR & 0x3c00)>>10; // P4..1
|
|
if (scale > 8) scale = 8;
|
|
duration = attotime_mul(ATTOTIME_IN_HZ(cpu_get_clock(machine->cpu[0])), (1 << scale) * max);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// logerror("CPU #0 PC %06X: TMP68301 Timer %d, duration %lf, max %04X\n",cpu_get_pc(machine->activecpu),i,duration,max);
|
|
|
|
if (!(TCR & 0x0002)) // CS
|
|
{
|
|
if (attotime_compare(duration, attotime_zero))
|
|
timer_adjust_oneshot(tmp68301_timer[i],duration,i);
|
|
else
|
|
logerror("CPU #0 PC %06X: TMP68301 error, timer %d duration is 0\n",cpu_get_pc(machine->activecpu),i);
|
|
}
|
|
}
|
|
|
|
MACHINE_RESET( tmp68301 )
|
|
{
|
|
int i;
|
|
for (i = 0; i < 3; i++)
|
|
tmp68301_timer[i] = timer_alloc(tmp68301_timer_callback, NULL);
|
|
|
|
for (i = 0; i < 3; i++)
|
|
tmp68301_IE[i] = 0;
|
|
|
|
cpu_set_irq_callback(machine->cpu[0], tmp68301_irq_callback);
|
|
}
|
|
|
|
/* Update the IRQ state based on all possible causes */
|
|
static void update_irq_state(running_machine *machine)
|
|
{
|
|
int i;
|
|
|
|
/* Take care of external interrupts */
|
|
|
|
UINT16 IMR = tmp68301_regs[0x94/2]; // Interrupt Mask Register (IMR)
|
|
UINT16 IVNR = tmp68301_regs[0x9a/2]; // Interrupt Vector Number Register (IVNR)
|
|
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
if ( (tmp68301_IE[i]) &&
|
|
!(IMR & (1<<i))
|
|
)
|
|
{
|
|
UINT16 ICR = tmp68301_regs[0x80/2+i]; // Interrupt Controller Register (ICR0..2)
|
|
|
|
// Interrupt Controller Register (ICR0..2)
|
|
int level = ICR & 0x0007;
|
|
|
|
// Interrupt Vector Number Register (IVNR)
|
|
tmp68301_irq_vector[level] = IVNR & 0x00e0;
|
|
tmp68301_irq_vector[level] += i;
|
|
|
|
tmp68301_IE[i] = 0; // Interrupts are edge triggerred
|
|
|
|
cpu_set_input_line(machine->cpu[0],level,HOLD_LINE);
|
|
}
|
|
}
|
|
}
|
|
|
|
WRITE16_HANDLER( tmp68301_regs_w )
|
|
{
|
|
COMBINE_DATA(&tmp68301_regs[offset]);
|
|
|
|
if (!ACCESSING_BITS_0_7) return;
|
|
|
|
// logerror("CPU #0 PC %06X: TMP68301 Reg %04X<-%04X & %04X\n",cpu_get_pc(machine->activecpu),offset*2,data,mem_mask^0xffff);
|
|
|
|
switch( offset * 2 )
|
|
{
|
|
// Timers
|
|
case 0x200:
|
|
case 0x220:
|
|
case 0x240:
|
|
{
|
|
int i = ((offset*2) >> 5) & 3;
|
|
|
|
tmp68301_update_timer( machine, i );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void tmp68301_external_interrupt_0(running_machine *machine) { tmp68301_IE[0] = 1; update_irq_state(machine); }
|
|
void tmp68301_external_interrupt_1(running_machine *machine) { tmp68301_IE[1] = 1; update_irq_state(machine); }
|
|
void tmp68301_external_interrupt_2(running_machine *machine) { tmp68301_IE[2] = 1; update_irq_state(machine); }
|
|
|