Commit | Line | Data |
---|---|---|
d4d3c7ad MM |
1 | /* ICU device: icu@<address> |
2 | ||
3 | <address> : read - processor nr | |
4 | <address> : write - interrupt processor nr | |
5 | <address> + 4 : read - nr processors | |
6 | ||
7 | Single byte registers that control a simple ICU. | |
8 | ||
9 | Illustrates passing of events to parent device. Passing of | |
10 | interrupts to an interrupt destination. */ | |
11 | ||
12 | ||
13 | static unsigned | |
14 | icu_io_read_buffer_callback(device *me, | |
15 | void *dest, | |
16 | int space, | |
17 | unsigned_word addr, | |
18 | unsigned nr_bytes, | |
19 | cpu *processor, | |
20 | unsigned_word cia) | |
21 | { | |
22 | memset(dest, 0, nr_bytes); | |
23 | switch (addr & 4) { | |
24 | case 0: | |
25 | *(unsigned_1*)dest = cpu_nr(processor); | |
26 | break; | |
27 | case 4: | |
28 | *(unsigned_1*)dest = | |
29 | device_find_integer_property(me, "/openprom/options/smp"); | |
30 | break; | |
31 | } | |
32 | return nr_bytes; | |
33 | } | |
34 | ||
35 | ||
36 | static unsigned | |
37 | icu_io_write_buffer_callback(device *me, | |
38 | const void *source, | |
39 | int space, | |
40 | unsigned_word addr, | |
41 | unsigned nr_bytes, | |
42 | cpu *processor, | |
43 | unsigned_word cia) | |
44 | { | |
45 | unsigned_1 val = H2T_1(*(unsigned_1*)source); | |
46 | /* tell the parent device that the interrupt lines have changed. | |
47 | For this fake ICU. The interrupt lines just indicate the cpu to | |
48 | interrupt next */ | |
49 | device_interrupt_event(me, | |
50 | val, /*my_port*/ | |
51 | val, /*val*/ | |
52 | processor, cia); | |
53 | return nr_bytes; | |
54 | } | |
55 | ||
56 | static void | |
57 | icu_do_interrupt(event_queue *queue, | |
58 | void *data) | |
59 | { | |
60 | cpu *target = (cpu*)data; | |
61 | /* try to interrupt the processor. If the attempt fails, try again | |
62 | on the next tick */ | |
63 | if (!external_interrupt(target)) | |
64 | event_queue_schedule(queue, 1, icu_do_interrupt, target); | |
65 | } | |
66 | ||
67 | ||
68 | static void | |
69 | icu_interrupt_event_callback(device *me, | |
70 | int my_port, | |
71 | device *source, | |
72 | int source_port, | |
73 | int level, | |
74 | cpu *processor, | |
75 | unsigned_word cia) | |
76 | { | |
77 | /* the interrupt controller can't interrupt a cpu at any time. | |
78 | Rather it must synchronize with the system clock before | |
79 | performing an interrupt on the given processor */ | |
80 | psim *system = cpu_system(processor); | |
81 | cpu *target = psim_cpu(system, my_port); | |
82 | if (target != NULL) { | |
83 | event_queue *events = cpu_event_queue(target); | |
84 | event_queue_schedule(events, 1, icu_do_interrupt, target); | |
85 | } | |
86 | } | |
87 | ||
88 | static device_callbacks const icu_callbacks = { | |
89 | { generic_device_init_address, }, | |
90 | { NULL, }, /* address */ | |
91 | { icu_io_read_buffer_callback, | |
92 | icu_io_write_buffer_callback, }, | |
93 | { NULL, }, /* DMA */ | |
94 | { icu_interrupt_event_callback, }, | |
95 | { NULL, }, /* unit */ | |
96 | }; | |
97 | ||
98 |