binutils-gdb/sim/ppc/hw_pic.c

99 lines
2.4 KiB
C

/* ICU device: icu@<address>
<address> : read - processor nr
<address> : write - interrupt processor nr
<address> + 4 : read - nr processors
Single byte registers that control a simple ICU.
Illustrates passing of events to parent device. Passing of
interrupts to an interrupt destination. */
static unsigned
icu_io_read_buffer_callback(device *me,
void *dest,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
memset(dest, 0, nr_bytes);
switch (addr & 4) {
case 0:
*(unsigned_1*)dest = cpu_nr(processor);
break;
case 4:
*(unsigned_1*)dest =
device_find_integer_property(me, "/openprom/options/smp");
break;
}
return nr_bytes;
}
static unsigned
icu_io_write_buffer_callback(device *me,
const void *source,
int space,
unsigned_word addr,
unsigned nr_bytes,
cpu *processor,
unsigned_word cia)
{
unsigned_1 val = H2T_1(*(unsigned_1*)source);
/* tell the parent device that the interrupt lines have changed.
For this fake ICU. The interrupt lines just indicate the cpu to
interrupt next */
device_interrupt_event(me,
val, /*my_port*/
val, /*val*/
processor, cia);
return nr_bytes;
}
static void
icu_do_interrupt(event_queue *queue,
void *data)
{
cpu *target = (cpu*)data;
/* try to interrupt the processor. If the attempt fails, try again
on the next tick */
if (!external_interrupt(target))
event_queue_schedule(queue, 1, icu_do_interrupt, target);
}
static void
icu_interrupt_event_callback(device *me,
int my_port,
device *source,
int source_port,
int level,
cpu *processor,
unsigned_word cia)
{
/* the interrupt controller can't interrupt a cpu at any time.
Rather it must synchronize with the system clock before
performing an interrupt on the given processor */
psim *system = cpu_system(processor);
cpu *target = psim_cpu(system, my_port);
if (target != NULL) {
event_queue *events = cpu_event_queue(target);
event_queue_schedule(events, 1, icu_do_interrupt, target);
}
}
static device_callbacks const icu_callbacks = {
{ generic_device_init_address, },
{ NULL, }, /* address */
{ icu_io_read_buffer_callback,
icu_io_write_buffer_callback, },
{ NULL, }, /* DMA */
{ icu_interrupt_event_callback, },
{ NULL, }, /* unit */
};