dv-tx3904cpu.c revision 1.1 1 1.1 christos /* This file is part of the program GDB, the GNU debugger.
2 1.1 christos
3 1.1 christos Copyright (C) 1998-2014 Free Software Foundation, Inc.
4 1.1 christos Contributed by Cygnus Solutions.
5 1.1 christos
6 1.1 christos This program is free software; you can redistribute it and/or modify
7 1.1 christos it under the terms of the GNU General Public License as published by
8 1.1 christos the Free Software Foundation; either version 3 of the License, or
9 1.1 christos (at your option) any later version.
10 1.1 christos
11 1.1 christos This program is distributed in the hope that it will be useful,
12 1.1 christos but WITHOUT ANY WARRANTY; without even the implied warranty of
13 1.1 christos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 1.1 christos GNU General Public License for more details.
15 1.1 christos
16 1.1 christos You should have received a copy of the GNU General Public License
17 1.1 christos along with this program. If not, see <http://www.gnu.org/licenses/>.
18 1.1 christos
19 1.1 christos */
20 1.1 christos
21 1.1 christos
22 1.1 christos #include "sim-main.h"
23 1.1 christos #include "hw-main.h"
24 1.1 christos
25 1.1 christos /* DEVICE
26 1.1 christos
27 1.1 christos
28 1.1 christos tx3904cpu - tx3904 cpu virtual device
29 1.1 christos
30 1.1 christos
31 1.1 christos DESCRIPTION
32 1.1 christos
33 1.1 christos
34 1.1 christos Implements the external tx3904 functionality. This includes the
35 1.1 christos delivery of of interrupts generated from other devices and the
36 1.1 christos handling of device specific registers.
37 1.1 christos
38 1.1 christos
39 1.1 christos PROPERTIES
40 1.1 christos
41 1.1 christos none
42 1.1 christos
43 1.1 christos
44 1.1 christos PORTS
45 1.1 christos
46 1.1 christos
47 1.1 christos reset (input)
48 1.1 christos
49 1.1 christos Currently ignored.
50 1.1 christos
51 1.1 christos
52 1.1 christos nmi (input)
53 1.1 christos
54 1.1 christos Deliver a non-maskable interrupt to the processor.
55 1.1 christos
56 1.1 christos
57 1.1 christos level (input)
58 1.1 christos
59 1.1 christos Deliver a maskable interrupt of given level, corresponding to
60 1.1 christos IP[5:0], to processor.
61 1.1 christos
62 1.1 christos
63 1.1 christos
64 1.1 christos BUGS
65 1.1 christos
66 1.1 christos
67 1.1 christos When delivering an interrupt, this code assumes that there is only
68 1.1 christos one processor (number 0).
69 1.1 christos
70 1.1 christos This code does not attempt to be efficient at handling pending
71 1.1 christos interrupts. It simply schedules the interrupt delivery handler
72 1.1 christos every instruction cycle until all pending interrupts go away. An
73 1.1 christos alternative implementation might modify instructions that change
74 1.1 christos the PSW and have them check to see if the change makes an interrupt
75 1.1 christos delivery possible.
76 1.1 christos
77 1.1 christos */
78 1.1 christos
79 1.1 christos
80 1.1 christos
81 1.1 christos struct tx3904cpu {
82 1.1 christos /* Pending interrupts for delivery by event handler */
83 1.1 christos int pending_reset, pending_nmi, pending_level;
84 1.1 christos struct hw_event* event;
85 1.1 christos };
86 1.1 christos
87 1.1 christos
88 1.1 christos
89 1.1 christos /* input port ID's */
90 1.1 christos
91 1.1 christos enum {
92 1.1 christos RESET_PORT,
93 1.1 christos NMI_PORT,
94 1.1 christos LEVEL_PORT,
95 1.1 christos };
96 1.1 christos
97 1.1 christos
98 1.1 christos static const struct hw_port_descriptor tx3904cpu_ports[] = {
99 1.1 christos
100 1.1 christos /* interrupt inputs */
101 1.1 christos { "reset", RESET_PORT, 0, input_port, },
102 1.1 christos { "nmi", NMI_PORT, 0, input_port, },
103 1.1 christos { "level", LEVEL_PORT, 0, input_port, },
104 1.1 christos
105 1.1 christos { NULL, },
106 1.1 christos };
107 1.1 christos
108 1.1 christos
109 1.1 christos /* Finish off the partially created hw device. Attach our local
110 1.1 christos callbacks. Wire up our port names etc */
111 1.1 christos
112 1.1 christos static hw_port_event_method tx3904cpu_port_event;
113 1.1 christos
114 1.1 christos
115 1.1 christos
116 1.1 christos static void
117 1.1 christos tx3904cpu_finish (struct hw *me)
118 1.1 christos {
119 1.1 christos struct tx3904cpu *controller;
120 1.1 christos
121 1.1 christos controller = HW_ZALLOC (me, struct tx3904cpu);
122 1.1 christos set_hw_data (me, controller);
123 1.1 christos set_hw_ports (me, tx3904cpu_ports);
124 1.1 christos set_hw_port_event (me, tx3904cpu_port_event);
125 1.1 christos
126 1.1 christos /* Initialize the pending interrupt flags */
127 1.1 christos controller->pending_level = 0;
128 1.1 christos controller->pending_reset = 0;
129 1.1 christos controller->pending_nmi = 0;
130 1.1 christos controller->event = NULL;
131 1.1 christos }
132 1.1 christos
133 1.1 christos
134 1.1 christos
135 1.1 christos /* An event arrives on an interrupt port */
136 1.1 christos
137 1.1 christos static void
138 1.1 christos deliver_tx3904cpu_interrupt (struct hw *me,
139 1.1 christos void *data)
140 1.1 christos {
141 1.1 christos struct tx3904cpu *controller = hw_data (me);
142 1.1 christos SIM_DESC sd = hw_system (me);
143 1.1 christos sim_cpu *cpu = STATE_CPU (sd, 0); /* NB: fix CPU 0. */
144 1.1 christos address_word cia = CIA_GET (cpu);
145 1.1 christos
146 1.1 christos #define CPU cpu
147 1.1 christos #define SD current_state
148 1.1 christos
149 1.1 christos if (controller->pending_reset)
150 1.1 christos {
151 1.1 christos controller->pending_reset = 0;
152 1.1 christos HW_TRACE ((me, "reset pc=0x%08lx", (long) CIA_GET (cpu)));
153 1.1 christos SignalExceptionNMIReset();
154 1.1 christos }
155 1.1 christos else if (controller->pending_nmi)
156 1.1 christos {
157 1.1 christos controller->pending_nmi = 0;
158 1.1 christos HW_TRACE ((me, "nmi pc=0x%08lx", (long) CIA_GET (cpu)));
159 1.1 christos SignalExceptionNMIReset();
160 1.1 christos }
161 1.1 christos else if (controller->pending_level)
162 1.1 christos {
163 1.1 christos HW_TRACE ((me, "interrupt level=%d pc=0x%08lx sr=0x%08lx",
164 1.1 christos controller->pending_level,
165 1.1 christos (long) CIA_GET (cpu), (long) SR));
166 1.1 christos
167 1.1 christos /* Clear CAUSE register. It may stay this way if the interrupt
168 1.1 christos was cleared with a negative pending_level. */
169 1.1 christos CAUSE &= ~ (cause_IP_mask << cause_IP_shift);
170 1.1 christos
171 1.1 christos if(controller->pending_level > 0) /* interrupt set */
172 1.1 christos {
173 1.1 christos /* set hardware-interrupt subfields of CAUSE register */
174 1.1 christos CAUSE |= (controller->pending_level & cause_IP_mask) << cause_IP_shift;
175 1.1 christos
176 1.1 christos /* check for enabled / unmasked interrupts */
177 1.1 christos if((SR & status_IEc) &&
178 1.1 christos (controller->pending_level & ((SR >> status_IM_shift) & status_IM_mask)))
179 1.1 christos {
180 1.1 christos controller->pending_level = 0;
181 1.1 christos SignalExceptionInterrupt(0 /* dummy value */);
182 1.1 christos }
183 1.1 christos else
184 1.1 christos {
185 1.1 christos /* reschedule soon */
186 1.1 christos if(controller->event != NULL)
187 1.1 christos hw_event_queue_deschedule(me, controller->event);
188 1.1 christos controller->event =
189 1.1 christos hw_event_queue_schedule (me, 1, deliver_tx3904cpu_interrupt, NULL);
190 1.1 christos }
191 1.1 christos } /* interrupt set */
192 1.1 christos }
193 1.1 christos #undef CPU cpu
194 1.1 christos #undef SD current_state
195 1.1 christos }
196 1.1 christos
197 1.1 christos
198 1.1 christos static void
199 1.1 christos tx3904cpu_port_event (struct hw *me,
200 1.1 christos int my_port,
201 1.1 christos struct hw *source,
202 1.1 christos int source_port,
203 1.1 christos int level)
204 1.1 christos {
205 1.1 christos struct tx3904cpu *controller = hw_data (me);
206 1.1 christos
207 1.1 christos switch (my_port)
208 1.1 christos {
209 1.1 christos case RESET_PORT:
210 1.1 christos controller->pending_reset = 1;
211 1.1 christos HW_TRACE ((me, "port-in reset"));
212 1.1 christos break;
213 1.1 christos
214 1.1 christos case NMI_PORT:
215 1.1 christos controller->pending_nmi = 1;
216 1.1 christos HW_TRACE ((me, "port-in nmi"));
217 1.1 christos break;
218 1.1 christos
219 1.1 christos case LEVEL_PORT:
220 1.1 christos /* level == 0 means that the interrupt was cleared */
221 1.1 christos if(level == 0)
222 1.1 christos controller->pending_level = -1; /* signal end of interrupt */
223 1.1 christos else
224 1.1 christos controller->pending_level = level;
225 1.1 christos HW_TRACE ((me, "port-in level=%d", level));
226 1.1 christos break;
227 1.1 christos
228 1.1 christos default:
229 1.1 christos hw_abort (me, "bad switch");
230 1.1 christos break;
231 1.1 christos }
232 1.1 christos
233 1.1 christos /* Schedule an event to be delivered immediately after current
234 1.1 christos instruction. */
235 1.1 christos if(controller->event != NULL)
236 1.1 christos hw_event_queue_deschedule(me, controller->event);
237 1.1 christos controller->event =
238 1.1 christos hw_event_queue_schedule (me, 0, deliver_tx3904cpu_interrupt, NULL);
239 1.1 christos }
240 1.1 christos
241 1.1 christos
242 1.1 christos const struct hw_descriptor dv_tx3904cpu_descriptor[] = {
243 1.1 christos { "tx3904cpu", tx3904cpu_finish, },
244 1.1 christos { NULL },
245 1.1 christos };
246