#include "sim-main.h"
#include "hw-main.h"
struct tx3904cpu {
int pending_reset, pending_nmi, pending_level;
struct hw_event* event;
};
enum {
RESET_PORT,
NMI_PORT,
LEVEL_PORT,
};
static const struct hw_port_descriptor tx3904cpu_ports[] = {
{ "reset", RESET_PORT, 0, input_port, },
{ "nmi", NMI_PORT, 0, input_port, },
{ "level", LEVEL_PORT, 0, input_port, },
{ NULL, },
};
static hw_port_event_method tx3904cpu_port_event;
static void
tx3904cpu_finish (struct hw *me)
{
struct tx3904cpu *controller;
controller = HW_ZALLOC (me, struct tx3904cpu);
set_hw_data (me, controller);
set_hw_ports (me, tx3904cpu_ports);
set_hw_port_event (me, tx3904cpu_port_event);
controller->pending_level = 0;
controller->pending_reset = 0;
controller->pending_nmi = 0;
controller->event = NULL;
}
static void
deliver_tx3904cpu_interrupt (struct hw *me,
void *data)
{
struct tx3904cpu *controller = hw_data (me);
SIM_DESC sd = hw_system (me);
sim_cpu *cpu = STATE_CPU (sd, 0);
address_word cia = CIA_GET (cpu);
#define CPU cpu
#define SD current_state
if (controller->pending_reset)
{
controller->pending_reset = 0;
HW_TRACE ((me, "reset pc=0x%08lx", (long) CIA_GET (cpu)));
SignalExceptionNMIReset();
}
else if (controller->pending_nmi)
{
controller->pending_nmi = 0;
HW_TRACE ((me, "nmi pc=0x%08lx", (long) CIA_GET (cpu)));
SignalExceptionNMIReset();
}
else if (controller->pending_level)
{
HW_TRACE ((me, "interrupt level=%d pc=0x%08lx sr=0x%08lx",
controller->pending_level,
(long) CIA_GET (cpu), (long) SR));
CAUSE &= ~ (cause_IP_mask << cause_IP_shift);
if(controller->pending_level > 0)
{
CAUSE |= (controller->pending_level & cause_IP_mask) << cause_IP_shift;
if((SR & status_IEc) &&
(controller->pending_level & ((SR >> status_IM_shift) & status_IM_mask)))
{
controller->pending_level = 0;
SignalExceptionInterrupt(0 );
}
else
{
if(controller->event != NULL)
hw_event_queue_deschedule(me, controller->event);
controller->event =
hw_event_queue_schedule (me, 1, deliver_tx3904cpu_interrupt, NULL);
}
}
}
#undef CPU cpu
#undef SD current_state
}
static void
tx3904cpu_port_event (struct hw *me,
int my_port,
struct hw *source,
int source_port,
int level)
{
struct tx3904cpu *controller = hw_data (me);
switch (my_port)
{
case RESET_PORT:
controller->pending_reset = 1;
HW_TRACE ((me, "port-in reset"));
break;
case NMI_PORT:
controller->pending_nmi = 1;
HW_TRACE ((me, "port-in nmi"));
break;
case LEVEL_PORT:
if(level == 0)
controller->pending_level = -1;
else
controller->pending_level = level;
HW_TRACE ((me, "port-in level=%d", level));
break;
default:
hw_abort (me, "bad switch");
break;
}
if(controller->event != NULL)
hw_event_queue_deschedule(me, controller->event);
controller->event =
hw_event_queue_schedule (me, 0, deliver_tx3904cpu_interrupt, NULL);
}
const struct hw_descriptor dv_tx3904cpu_descriptor[] = {
{ "tx3904cpu", tx3904cpu_finish, },
{ NULL },
};