This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / sim / mn10300 / dv-mn103cpu.c
1 /* This file is part of the program GDB, the GU debugger.
2
3 Copyright (C) 1998 Free Software Foundation, Inc.
4 Contributed by Cygnus Solutions.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22
23 #include "sim-main.h"
24 #include "hw-base.h"
25
26 /* DEVICE
27
28
29 mn103cpu - mn10300 cpu virtual device
30
31
32 DESCRIPTION
33
34
35 Implements the external mn10300 functionality. This includes the
36 delivery of of interrupts generated from other devices and the
37 handling of device specific registers.
38
39
40 PROPERTIES
41
42
43 reg = <address> <size>
44
45 Specify the address of the mn10300's control register block. This
46 block contains the Interrupt Vector Registers.
47
48 The reg property value `0x20000000 0x42' locates the register block
49 at the address specified in the mn10300 user guide.
50
51
52 PORTS
53
54
55 reset (input)
56
57 Currently ignored.
58
59
60 nmi (input)
61
62 Deliver a non-maskable interrupt to the processor.
63
64
65 level (input)
66
67 Maskable interrupt level port port. The interrupt controller
68 notifies the processor of any change in the level of pending
69 requested interrupts via this port.
70
71
72 ack (output)
73
74 Output signal indicating that the processor is delivering a level
75 interrupt. The value passed with the event specfies the level of
76 the interrupt being delivered.
77
78
79 BUGS
80
81
82 When delivering an interrupt, this code assumes that there is only
83 one processor (number 0).
84
85 This code does not attempt to be efficient at handling pending
86 interrupts. It simply schedules the interrupt delivery handler
87 every instruction cycle until all pending interrupts go away. An
88 alternative implementation might modify instructions that change
89 the PSW and have them check to see if the change makes an interrupt
90 delivery possible.
91
92 */
93
94
95 /* The interrupt vectors */
96
97 enum { NR_VECTORS = 7, };
98
99
100 /* The interrupt controller register address blocks */
101
102 struct mn103cpu_block {
103 unsigned_word base;
104 unsigned_word bound;
105 };
106
107
108 struct mn103cpu {
109 struct mn103cpu_block block;
110 hw_event *pending_handler;
111 int pending_level;
112 int pending_nmi;
113 int pending_reset;
114 /* the visible registers */
115 unsigned16 interrupt_vector[NR_VECTORS];
116 unsigned16 internal_memory_control;
117 unsigned16 cpu_mode;
118 };
119
120
121
122 /* input port ID's */
123
124 enum {
125 RESET_PORT,
126 NMI_PORT,
127 LEVEL_PORT,
128 };
129
130
131 /* input port ID's */
132
133 enum {
134 ACK_PORT,
135 };
136
137 static const struct hw_port_descriptor mn103cpu_ports[] = {
138
139 /* interrupt inputs */
140 { "reset", RESET_PORT, 0, input_port, },
141 { "nmi", NMI_PORT, 0, input_port, },
142 { "level", LEVEL_PORT, 0, input_port, },
143
144 /* interrupt ack (latch) output from cpu */
145 { "ack", ACK_PORT, 0, output_port, },
146
147 { NULL, },
148 };
149
150
151 /* Finish off the partially created hw device. Attach our local
152 callbacks. Wire up our port names etc */
153
154 static hw_io_read_buffer_callback mn103cpu_io_read_buffer;
155 static hw_io_write_buffer_callback mn103cpu_io_write_buffer;
156 static hw_port_event_callback mn103cpu_port_event;
157
158 static void
159 attach_mn103cpu_regs (struct hw *me,
160 struct mn103cpu *controller)
161 {
162 unsigned_word attach_address;
163 int attach_space;
164 unsigned attach_size;
165 reg_property_spec reg;
166 if (hw_find_property (me, "reg") == NULL)
167 hw_abort (me, "Missing \"reg\" property");
168 if (!hw_find_reg_array_property (me, "reg", 0, &reg))
169 hw_abort (me, "\"reg\" property must contain three addr/size entries");
170 hw_unit_address_to_attach_address (hw_parent (me),
171 &reg.address,
172 &attach_space,
173 &attach_address,
174 me);
175 controller->block.base = attach_address;
176 hw_unit_size_to_attach_size (hw_parent (me),
177 &reg.size,
178 &attach_size, me);
179 controller->block.bound = attach_address + (attach_size - 1);
180 if ((controller->block.base & 3) != 0)
181 hw_abort (me, "cpu register block must be 4 byte aligned");
182 hw_attach_address (hw_parent (me),
183 0,
184 attach_space, attach_address, attach_size,
185 me);
186 }
187
188
189 static void
190 mn103cpu_finish (struct hw *me)
191 {
192 struct mn103cpu *controller;
193
194 controller = HW_ZALLOC (me, struct mn103cpu);
195 set_hw_data (me, controller);
196 set_hw_io_read_buffer (me, mn103cpu_io_read_buffer);
197 set_hw_io_write_buffer (me, mn103cpu_io_write_buffer);
198 set_hw_ports (me, mn103cpu_ports);
199 set_hw_port_event (me, mn103cpu_port_event);
200
201 /* Attach ourself to our parent bus */
202 attach_mn103cpu_regs (me, controller);
203
204 /* Initialize the read-only registers */
205 controller->pending_level = 7; /* FIXME */
206 /* ... */
207 }
208
209
210
211 /* An event arrives on an interrupt port */
212
213 static void
214 deliver_mn103cpu_interrupt (struct hw *me,
215 void *data)
216 {
217 struct mn103cpu *controller = hw_data (me);
218 SIM_DESC simulator = hw_system (me);
219 sim_cpu *cpu = STATE_CPU (simulator, 0);
220
221 if (controller->pending_reset)
222 {
223 controller->pending_reset = 0;
224 /* need to clear all registers et.al! */
225 HW_TRACE ((me, "Reset!"));
226 hw_abort (me, "Reset!");
227 }
228 else if (controller->pending_nmi)
229 {
230 controller->pending_nmi = 0;
231 store_half (SP - 4, CIA_GET (cpu));
232 store_half (SP - 8, PSW);
233 PSW &= ~PSW_IE;
234 SP = SP - 8;
235 CIA_SET (cpu, 0x40000008);
236 HW_TRACE ((me, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
237 (long) CIA_GET (cpu), (unsigned) PSW, (long) SP));
238 }
239 else if ((controller->pending_level < EXTRACT_PSW_LM)
240 && (PSW & PSW_IE))
241 {
242 /* Don't clear pending level. Request continues to be pending
243 until the interrupt controller clears/changes it */
244 store_half (SP - 4, CIA_GET (cpu));
245 store_half (SP - 8, PSW);
246 PSW &= ~PSW_IE;
247 PSW &= ~PSW_LM;
248 PSW |= INSERT_PSW_LM (controller->pending_level);
249 SP = SP - 8;
250 CIA_SET (cpu, 0x40000000 + controller->interrupt_vector[controller->pending_level]);
251 HW_TRACE ((me, "port-out ack %d", controller->pending_level));
252 hw_port_event (me, ACK_PORT, controller->pending_level, NULL, NULL_CIA);
253 HW_TRACE ((me, "int level=%d pc=0x%08lx psw=0x%04x sp=0x%08lx",
254 controller->pending_level,
255 (long) CIA_GET (cpu), (unsigned) PSW, (long) SP));
256 }
257
258 /* As long as there is the potential need to deliver an interrupt we
259 keep rescheduling this routine. */
260 if (controller->pending_level < 7) /* FIXME */
261 {
262 if (controller->pending_handler != NULL)
263 controller->pending_handler =
264 hw_event_queue_schedule (me, 1, deliver_mn103cpu_interrupt, NULL);
265 }
266
267 }
268
269
270 static void
271 mn103cpu_port_event (struct hw *me,
272 int my_port,
273 struct hw *source,
274 int source_port,
275 int level,
276 sim_cpu *processor,
277 sim_cia cia)
278 {
279 struct mn103cpu *controller = hw_data (me);
280
281 /* Schedule our event handler *now* */
282 if (controller->pending_handler == NULL)
283 controller->pending_handler =
284 hw_event_queue_schedule (me, 0, deliver_mn103cpu_interrupt, NULL);
285
286 switch (my_port)
287 {
288
289 case RESET_PORT:
290 controller->pending_reset = 1;
291 HW_TRACE ((me, "port-in reset"));
292 break;
293
294 case NMI_PORT:
295 controller->pending_nmi = 1;
296 HW_TRACE ((me, "port-in nmi"));
297 break;
298
299 case LEVEL_PORT:
300 controller->pending_level = level;
301 HW_TRACE ((me, "port-in level=%d", level));
302 break;
303
304 default:
305 hw_abort (me, "bad switch");
306 break;
307
308 }
309 }
310
311
312 /* Read/write to a CPU register */
313
314 enum mn103cpu_regs {
315 INVALID_REG,
316 IVR0_REG,
317 IVR1_REG,
318 IVR2_REG,
319 IVR3_REG,
320 IVR4_REG,
321 IVR5_REG,
322 IVR6_REG,
323 IMCR_REG,
324 CPUM_REG,
325 };
326
327 static enum mn103cpu_regs
328 decode_mn103cpu_addr (struct hw *me,
329 struct mn103cpu *controller,
330 unsigned_word base)
331 {
332 switch (base - controller->block.base)
333 {
334 case 0x000: return IVR0_REG;
335 case 0x004: return IVR1_REG;
336 case 0x008: return IVR2_REG;
337 case 0x00c: return IVR3_REG;
338 case 0x010: return IVR4_REG;
339 case 0x014: return IVR5_REG;
340 case 0x018: return IVR6_REG;
341 case 0x020: return IMCR_REG;
342 case 0x040: return CPUM_REG;
343 default: return INVALID_REG;
344 }
345 }
346
347 static unsigned
348 mn103cpu_io_read_buffer (struct hw *me,
349 void *dest,
350 int space,
351 unsigned_word base,
352 unsigned nr_bytes,
353 sim_cpu *processor,
354 sim_cia cia)
355 {
356 struct mn103cpu *controller = hw_data (me);
357 unsigned16 val = 0;
358 enum mn103cpu_regs reg = decode_mn103cpu_addr (me, controller, base);
359
360 switch (reg)
361 {
362 case IVR0_REG:
363 case IVR1_REG:
364 case IVR2_REG:
365 case IVR3_REG:
366 case IVR4_REG:
367 case IVR5_REG:
368 case IVR6_REG:
369 val = controller->interrupt_vector[reg - IVR0_REG];
370 break;
371 case IMCR_REG:
372 val = controller->internal_memory_control;
373 break;
374 case CPUM_REG:
375 val = controller->cpu_mode;
376 break;
377 default:
378 /* just ignore the read */
379 break;
380 }
381
382 if (nr_bytes == 2)
383 *(unsigned16*) dest = H2LE_2 (val);
384
385 return nr_bytes;
386 }
387
388 static unsigned
389 mn103cpu_io_write_buffer (struct hw *me,
390 const void *source,
391 int space,
392 unsigned_word base,
393 unsigned nr_bytes,
394 sim_cpu *cpu,
395 sim_cia cia)
396 {
397 struct mn103cpu *controller = hw_data (me);
398 unsigned16 val;
399 enum mn103cpu_regs reg;
400
401 if (nr_bytes != 2)
402 hw_abort (me, "must be two byte write");
403
404 reg = decode_mn103cpu_addr (me, controller, base);
405 val = LE2H_2 (* (unsigned16 *) source);
406
407 switch (reg)
408 {
409 case IVR0_REG:
410 case IVR1_REG:
411 case IVR2_REG:
412 case IVR3_REG:
413 case IVR4_REG:
414 case IVR5_REG:
415 case IVR6_REG:
416 controller->interrupt_vector[reg - IVR0_REG] = val;
417 HW_TRACE ((me, "ivr%d = 0x%04lx", reg - IVR0_REG, (long) val));
418 break;
419 default:
420 /* just ignore the write */
421 break;
422 }
423
424 return nr_bytes;
425 }
426
427
428 const struct hw_device_descriptor dv_mn103cpu_descriptor[] = {
429 { "mn103cpu", mn103cpu_finish, },
430 { NULL },
431 };
This page took 0.04004 seconds and 5 git commands to generate.