1 /* This file is part of the program GDB, the GNU debugger.
3 Copyright (C) 1998-2024 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. */
26 #include "sim-signal.h"
29 #include "mn10300-sim.h"
34 mn103cpu - mn10300 cpu virtual device
40 Implements the external mn10300 functionality. This includes the
41 delivery of interrupts generated from other devices and the
42 handling of device specific registers.
48 reg = <address> <size>
50 Specify the address of the mn10300's control register block. This
51 block contains the Interrupt Vector Registers.
53 The reg property value `0x20000000 0x42' locates the register block
54 at the address specified in the mn10300 user guide.
67 Deliver a non-maskable interrupt to the processor.
72 Maskable interrupt level port port. The interrupt controller
73 notifies the processor of any change in the level of pending
74 requested interrupts via this port.
79 Output signal indicating that the processor is delivering a level
80 interrupt. The value passed with the event specifies the level of
81 the interrupt being delivered.
87 When delivering an interrupt, this code assumes that there is only
88 one processor (number 0).
90 This code does not attempt to be efficient at handling pending
91 interrupts. It simply schedules the interrupt delivery handler
92 every instruction cycle until all pending interrupts go away. An
93 alternative implementation might modify instructions that change
94 the PSW and have them check to see if the change makes an interrupt
100 /* The interrupt vectors */
102 enum { NR_VECTORS
= 7, };
105 /* The interrupt controller register address blocks */
107 struct mn103cpu_block
{
114 struct mn103cpu_block block
;
115 struct hw_event
*pending_handler
;
119 /* the visible registers */
120 uint16_t interrupt_vector
[NR_VECTORS
];
121 uint16_t internal_memory_control
;
127 /* input port ID's */
136 /* output port ID's */
142 static const struct hw_port_descriptor mn103cpu_ports
[] = {
144 /* interrupt inputs */
145 { "reset", RESET_PORT
, 0, input_port
, },
146 { "nmi", NMI_PORT
, 0, input_port
, },
147 { "level", LEVEL_PORT
, 0, input_port
, },
149 /* interrupt ack (latch) output from cpu */
150 { "ack", ACK_PORT
, 0, output_port
, },
156 /* Finish off the partially created hw device. Attach our local
157 callbacks. Wire up our port names etc */
159 static hw_io_read_buffer_method mn103cpu_io_read_buffer
;
160 static hw_io_write_buffer_method mn103cpu_io_write_buffer
;
161 static hw_port_event_method mn103cpu_port_event
;
164 attach_mn103cpu_regs (struct hw
*me
,
165 struct mn103cpu
*controller
)
167 unsigned_word attach_address
;
169 unsigned attach_size
;
170 reg_property_spec reg
;
171 if (hw_find_property (me
, "reg") == NULL
)
172 hw_abort (me
, "Missing \"reg\" property");
173 if (!hw_find_reg_array_property (me
, "reg", 0, ®
))
174 hw_abort (me
, "\"reg\" property must contain three addr/size entries");
175 hw_unit_address_to_attach_address (hw_parent (me
),
180 controller
->block
.base
= attach_address
;
181 hw_unit_size_to_attach_size (hw_parent (me
),
184 controller
->block
.bound
= attach_address
+ (attach_size
- 1);
185 if ((controller
->block
.base
& 3) != 0)
186 hw_abort (me
, "cpu register block must be 4 byte aligned");
187 hw_attach_address (hw_parent (me
),
189 attach_space
, attach_address
, attach_size
,
195 mn103cpu_finish (struct hw
*me
)
197 struct mn103cpu
*controller
;
199 controller
= HW_ZALLOC (me
, struct mn103cpu
);
200 set_hw_data (me
, controller
);
201 set_hw_io_read_buffer (me
, mn103cpu_io_read_buffer
);
202 set_hw_io_write_buffer (me
, mn103cpu_io_write_buffer
);
203 set_hw_ports (me
, mn103cpu_ports
);
204 set_hw_port_event (me
, mn103cpu_port_event
);
206 /* Attach ourself to our parent bus */
207 attach_mn103cpu_regs (me
, controller
);
209 /* Initialize the read-only registers */
210 controller
->pending_level
= 7; /* FIXME */
216 /* An event arrives on an interrupt port */
219 deliver_mn103cpu_interrupt (struct hw
*me
,
222 struct mn103cpu
*controller
= hw_data (me
);
223 SIM_DESC simulator
= hw_system (me
);
224 sim_cpu
*cpu
= STATE_CPU (simulator
, 0);
226 if (controller
->pending_reset
)
228 controller
->pending_reset
= 0;
229 /* need to clear all registers et.al! */
230 HW_TRACE ((me
, "Reset!"));
231 hw_abort (me
, "Reset!");
233 else if (controller
->pending_nmi
)
235 controller
->pending_nmi
= 0;
236 store_word (SP
- 4, CPU_PC_GET (cpu
));
237 store_half (SP
- 8, PSW
);
240 CPU_PC_SET (cpu
, 0x40000008);
241 HW_TRACE ((me
, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
242 (long) CPU_PC_GET (cpu
), (unsigned) PSW
, (long) SP
));
244 else if ((controller
->pending_level
< EXTRACT_PSW_LM
)
247 /* Don't clear pending level. Request continues to be pending
248 until the interrupt controller clears/changes it */
249 store_word (SP
- 4, CPU_PC_GET (cpu
));
250 store_half (SP
- 8, PSW
);
253 PSW
|= INSERT_PSW_LM (controller
->pending_level
);
255 CPU_PC_SET (cpu
, 0x40000000 + controller
->interrupt_vector
[controller
->pending_level
]);
256 HW_TRACE ((me
, "port-out ack %d", controller
->pending_level
));
257 hw_port_event (me
, ACK_PORT
, controller
->pending_level
);
258 HW_TRACE ((me
, "int level=%d pc=0x%08lx psw=0x%04x sp=0x%08lx",
259 controller
->pending_level
,
260 (long) CPU_PC_GET (cpu
), (unsigned) PSW
, (long) SP
));
263 if (controller
->pending_level
< 7) /* FIXME */
265 /* As long as there is the potential need to deliver an
266 interrupt we keep rescheduling this routine. */
267 if (controller
->pending_handler
!= NULL
)
268 controller
->pending_handler
=
269 hw_event_queue_schedule (me
, 1, deliver_mn103cpu_interrupt
, NULL
);
273 /* Don't bother re-scheduling the interrupt handler as there is
274 nothing to deliver */
275 controller
->pending_handler
= NULL
;
282 mn103cpu_port_event (struct hw
*me
,
288 struct mn103cpu
*controller
= hw_data (me
);
290 /* Schedule our event handler *now* */
291 if (controller
->pending_handler
== NULL
)
292 controller
->pending_handler
=
293 hw_event_queue_schedule (me
, 0, deliver_mn103cpu_interrupt
, NULL
);
299 controller
->pending_reset
= 1;
300 HW_TRACE ((me
, "port-in reset"));
304 controller
->pending_nmi
= 1;
305 HW_TRACE ((me
, "port-in nmi"));
309 controller
->pending_level
= level
;
310 HW_TRACE ((me
, "port-in level=%d", level
));
314 hw_abort (me
, "bad switch");
321 /* Read/write to a CPU register */
336 static enum mn103cpu_regs
337 decode_mn103cpu_addr (struct hw
*me
,
338 struct mn103cpu
*controller
,
341 switch (base
- controller
->block
.base
)
343 case 0x000: return IVR0_REG
;
344 case 0x004: return IVR1_REG
;
345 case 0x008: return IVR2_REG
;
346 case 0x00c: return IVR3_REG
;
347 case 0x010: return IVR4_REG
;
348 case 0x014: return IVR5_REG
;
349 case 0x018: return IVR6_REG
;
350 case 0x020: return IMCR_REG
;
351 case 0x040: return CPUM_REG
;
352 default: return INVALID_REG
;
357 mn103cpu_io_read_buffer (struct hw
*me
,
363 struct mn103cpu
*controller
= hw_data (me
);
365 enum mn103cpu_regs reg
= decode_mn103cpu_addr (me
, controller
, base
);
376 val
= controller
->interrupt_vector
[reg
- IVR0_REG
];
379 val
= controller
->internal_memory_control
;
382 val
= controller
->cpu_mode
;
385 /* just ignore the read */
390 *(uint16_t*) dest
= H2LE_2 (val
);
396 mn103cpu_io_write_buffer (struct hw
*me
,
402 struct mn103cpu
*controller
= hw_data (me
);
404 enum mn103cpu_regs reg
;
407 hw_abort (me
, "must be two byte write");
409 reg
= decode_mn103cpu_addr (me
, controller
, base
);
410 val
= LE2H_2 (* (uint16_t *) source
);
421 controller
->interrupt_vector
[reg
- IVR0_REG
] = val
;
422 HW_TRACE ((me
, "ivr%d = 0x%04lx", reg
- IVR0_REG
, (long) val
));
425 /* just ignore the write */
433 const struct hw_descriptor dv_mn103cpu_descriptor
[] = {
434 { "mn103cpu", mn103cpu_finish
, },