1 /* This file is part of the program GDB, the GNU debugger.
3 Copyright (C) 1998-2021 Free Software Foundation, Inc.
4 Contributed by Cygnus Solutions.
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 3 of the License, or
9 (at your option) any later version.
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.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /* This must come before any other includes. */
30 mn103cpu - mn10300 cpu virtual device
36 Implements the external mn10300 functionality. This includes the
37 delivery of interrupts generated from other devices and the
38 handling of device specific registers.
44 reg = <address> <size>
46 Specify the address of the mn10300's control register block. This
47 block contains the Interrupt Vector Registers.
49 The reg property value `0x20000000 0x42' locates the register block
50 at the address specified in the mn10300 user guide.
63 Deliver a non-maskable interrupt to the processor.
68 Maskable interrupt level port port. The interrupt controller
69 notifies the processor of any change in the level of pending
70 requested interrupts via this port.
75 Output signal indicating that the processor is delivering a level
76 interrupt. The value passed with the event specifies the level of
77 the interrupt being delivered.
83 When delivering an interrupt, this code assumes that there is only
84 one processor (number 0).
86 This code does not attempt to be efficient at handling pending
87 interrupts. It simply schedules the interrupt delivery handler
88 every instruction cycle until all pending interrupts go away. An
89 alternative implementation might modify instructions that change
90 the PSW and have them check to see if the change makes an interrupt
96 /* The interrupt vectors */
98 enum { NR_VECTORS
= 7, };
101 /* The interrupt controller register address blocks */
103 struct mn103cpu_block
{
110 struct mn103cpu_block block
;
111 struct hw_event
*pending_handler
;
115 /* the visible registers */
116 unsigned16 interrupt_vector
[NR_VECTORS
];
117 unsigned16 internal_memory_control
;
123 /* input port ID's */
132 /* output port ID's */
138 static const struct hw_port_descriptor mn103cpu_ports
[] = {
140 /* interrupt inputs */
141 { "reset", RESET_PORT
, 0, input_port
, },
142 { "nmi", NMI_PORT
, 0, input_port
, },
143 { "level", LEVEL_PORT
, 0, input_port
, },
145 /* interrupt ack (latch) output from cpu */
146 { "ack", ACK_PORT
, 0, output_port
, },
152 /* Finish off the partially created hw device. Attach our local
153 callbacks. Wire up our port names etc */
155 static hw_io_read_buffer_method mn103cpu_io_read_buffer
;
156 static hw_io_write_buffer_method mn103cpu_io_write_buffer
;
157 static hw_port_event_method mn103cpu_port_event
;
160 attach_mn103cpu_regs (struct hw
*me
,
161 struct mn103cpu
*controller
)
163 unsigned_word attach_address
;
165 unsigned attach_size
;
166 reg_property_spec reg
;
167 if (hw_find_property (me
, "reg") == NULL
)
168 hw_abort (me
, "Missing \"reg\" property");
169 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
170 hw_abort (me
, "\"reg\" property must contain three addr/size entries");
171 hw_unit_address_to_attach_address (hw_parent (me
),
176 controller
->block
.base
= attach_address
;
177 hw_unit_size_to_attach_size (hw_parent (me
),
180 controller
->block
.bound
= attach_address
+ (attach_size
- 1);
181 if ((controller
->block
.base
& 3) != 0)
182 hw_abort (me
, "cpu register block must be 4 byte aligned");
183 hw_attach_address (hw_parent (me
),
185 attach_space
, attach_address
, attach_size
,
191 mn103cpu_finish (struct hw
*me
)
193 struct mn103cpu
*controller
;
195 controller
= HW_ZALLOC (me
, struct mn103cpu
);
196 set_hw_data (me
, controller
);
197 set_hw_io_read_buffer (me
, mn103cpu_io_read_buffer
);
198 set_hw_io_write_buffer (me
, mn103cpu_io_write_buffer
);
199 set_hw_ports (me
, mn103cpu_ports
);
200 set_hw_port_event (me
, mn103cpu_port_event
);
202 /* Attach ourself to our parent bus */
203 attach_mn103cpu_regs (me
, controller
);
205 /* Initialize the read-only registers */
206 controller
->pending_level
= 7; /* FIXME */
212 /* An event arrives on an interrupt port */
215 deliver_mn103cpu_interrupt (struct hw
*me
,
218 struct mn103cpu
*controller
= hw_data (me
);
219 SIM_DESC simulator
= hw_system (me
);
220 sim_cpu
*cpu
= STATE_CPU (simulator
, 0);
222 if (controller
->pending_reset
)
224 controller
->pending_reset
= 0;
225 /* need to clear all registers et.al! */
226 HW_TRACE ((me
, "Reset!"));
227 hw_abort (me
, "Reset!");
229 else if (controller
->pending_nmi
)
231 controller
->pending_nmi
= 0;
232 store_word (SP
- 4, CPU_PC_GET (cpu
));
233 store_half (SP
- 8, PSW
);
236 CPU_PC_SET (cpu
, 0x40000008);
237 HW_TRACE ((me
, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
238 (long) CPU_PC_GET (cpu
), (unsigned) PSW
, (long) SP
));
240 else if ((controller
->pending_level
< EXTRACT_PSW_LM
)
243 /* Don't clear pending level. Request continues to be pending
244 until the interrupt controller clears/changes it */
245 store_word (SP
- 4, CPU_PC_GET (cpu
));
246 store_half (SP
- 8, PSW
);
249 PSW
|= INSERT_PSW_LM (controller
->pending_level
);
251 CPU_PC_SET (cpu
, 0x40000000 + controller
->interrupt_vector
[controller
->pending_level
]);
252 HW_TRACE ((me
, "port-out ack %d", controller
->pending_level
));
253 hw_port_event (me
, ACK_PORT
, controller
->pending_level
);
254 HW_TRACE ((me
, "int level=%d pc=0x%08lx psw=0x%04x sp=0x%08lx",
255 controller
->pending_level
,
256 (long) CPU_PC_GET (cpu
), (unsigned) PSW
, (long) SP
));
259 if (controller
->pending_level
< 7) /* FIXME */
261 /* As long as there is the potential need to deliver an
262 interrupt we keep rescheduling this routine. */
263 if (controller
->pending_handler
!= NULL
)
264 controller
->pending_handler
=
265 hw_event_queue_schedule (me
, 1, deliver_mn103cpu_interrupt
, NULL
);
269 /* Don't bother re-scheduling the interrupt handler as there is
270 nothing to deliver */
271 controller
->pending_handler
= NULL
;
278 mn103cpu_port_event (struct hw
*me
,
284 struct mn103cpu
*controller
= hw_data (me
);
286 /* Schedule our event handler *now* */
287 if (controller
->pending_handler
== NULL
)
288 controller
->pending_handler
=
289 hw_event_queue_schedule (me
, 0, deliver_mn103cpu_interrupt
, NULL
);
295 controller
->pending_reset
= 1;
296 HW_TRACE ((me
, "port-in reset"));
300 controller
->pending_nmi
= 1;
301 HW_TRACE ((me
, "port-in nmi"));
305 controller
->pending_level
= level
;
306 HW_TRACE ((me
, "port-in level=%d", level
));
310 hw_abort (me
, "bad switch");
317 /* Read/write to a CPU register */
332 static enum mn103cpu_regs
333 decode_mn103cpu_addr (struct hw
*me
,
334 struct mn103cpu
*controller
,
337 switch (base
- controller
->block
.base
)
339 case 0x000: return IVR0_REG
;
340 case 0x004: return IVR1_REG
;
341 case 0x008: return IVR2_REG
;
342 case 0x00c: return IVR3_REG
;
343 case 0x010: return IVR4_REG
;
344 case 0x014: return IVR5_REG
;
345 case 0x018: return IVR6_REG
;
346 case 0x020: return IMCR_REG
;
347 case 0x040: return CPUM_REG
;
348 default: return INVALID_REG
;
353 mn103cpu_io_read_buffer (struct hw
*me
,
359 struct mn103cpu
*controller
= hw_data (me
);
361 enum mn103cpu_regs reg
= decode_mn103cpu_addr (me
, controller
, base
);
372 val
= controller
->interrupt_vector
[reg
- IVR0_REG
];
375 val
= controller
->internal_memory_control
;
378 val
= controller
->cpu_mode
;
381 /* just ignore the read */
386 *(unsigned16
*) dest
= H2LE_2 (val
);
392 mn103cpu_io_write_buffer (struct hw
*me
,
398 struct mn103cpu
*controller
= hw_data (me
);
400 enum mn103cpu_regs reg
;
403 hw_abort (me
, "must be two byte write");
405 reg
= decode_mn103cpu_addr (me
, controller
, base
);
406 val
= LE2H_2 (* (unsigned16
*) source
);
417 controller
->interrupt_vector
[reg
- IVR0_REG
] = val
;
418 HW_TRACE ((me
, "ivr%d = 0x%04lx", reg
- IVR0_REG
, (long) val
));
421 /* just ignore the write */
429 const struct hw_descriptor dv_mn103cpu_descriptor
[] = {
430 { "mn103cpu", mn103cpu_finish
, },