]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/mn10300/dv-mn103cpu.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / sim / mn10300 / dv-mn103cpu.c
CommitLineData
c906108c
SS
1/* This file is part of the program GDB, the GNU debugger.
2
1d506c26 3 Copyright (C) 1998-2024 Free Software Foundation, Inc.
c906108c
SS
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
4744ac1b 8 the Free Software Foundation; either version 3 of the License, or
c906108c 9 (at your option) any later version.
4744ac1b 10
c906108c
SS
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.
4744ac1b 15
c906108c 16 You should have received a copy of the GNU General Public License
4744ac1b 17 along with this program. If not, see <http://www.gnu.org/licenses/>.
c906108c
SS
18
19 */
20
6df01ab8
MF
21/* This must come before any other includes. */
22#include "defs.h"
c906108c
SS
23
24#include "sim-main.h"
c064fab2
MW
25#include "sim-fpu.h"
26#include "sim-signal.h"
c906108c
SS
27#include "hw-main.h"
28
c064fab2
MW
29#include "mn10300-sim.h"
30
c906108c
SS
31/* DEVICE
32
33
34 mn103cpu - mn10300 cpu virtual device
35
36
37 DESCRIPTION
38
39
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.
43
44
45 PROPERTIES
46
47
48 reg = <address> <size>
49
50 Specify the address of the mn10300's control register block. This
51 block contains the Interrupt Vector Registers.
52
53 The reg property value `0x20000000 0x42' locates the register block
54 at the address specified in the mn10300 user guide.
55
56
57 PORTS
58
59
60 reset (input)
61
62 Currently ignored.
63
64
65 nmi (input)
66
67 Deliver a non-maskable interrupt to the processor.
68
69
70 level (input)
71
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.
75
76
77 ack (output)
78
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.
82
83
84 BUGS
85
86
87 When delivering an interrupt, this code assumes that there is only
88 one processor (number 0).
89
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
95 delivery possible.
96
97 */
98
99
100/* The interrupt vectors */
101
102enum { NR_VECTORS = 7, };
103
104
105/* The interrupt controller register address blocks */
106
107struct mn103cpu_block {
108 unsigned_word base;
109 unsigned_word bound;
110};
111
112
113struct mn103cpu {
114 struct mn103cpu_block block;
115 struct hw_event *pending_handler;
116 int pending_level;
117 int pending_nmi;
118 int pending_reset;
119 /* the visible registers */
74ccc978
MF
120 uint16_t interrupt_vector[NR_VECTORS];
121 uint16_t internal_memory_control;
122 uint16_t cpu_mode;
c906108c
SS
123};
124
125
126
127/* input port ID's */
128
129enum {
130 RESET_PORT,
131 NMI_PORT,
132 LEVEL_PORT,
133};
134
135
136/* output port ID's */
137
138enum {
139 ACK_PORT,
140};
141
142static const struct hw_port_descriptor mn103cpu_ports[] = {
143
144 /* interrupt inputs */
145 { "reset", RESET_PORT, 0, input_port, },
146 { "nmi", NMI_PORT, 0, input_port, },
147 { "level", LEVEL_PORT, 0, input_port, },
148
149 /* interrupt ack (latch) output from cpu */
150 { "ack", ACK_PORT, 0, output_port, },
151
152 { NULL, },
153};
154
155
156/* Finish off the partially created hw device. Attach our local
157 callbacks. Wire up our port names etc */
158
159static hw_io_read_buffer_method mn103cpu_io_read_buffer;
160static hw_io_write_buffer_method mn103cpu_io_write_buffer;
161static hw_port_event_method mn103cpu_port_event;
162
163static void
164attach_mn103cpu_regs (struct hw *me,
165 struct mn103cpu *controller)
166{
167 unsigned_word attach_address;
168 int attach_space;
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, &reg))
174 hw_abort (me, "\"reg\" property must contain three addr/size entries");
175 hw_unit_address_to_attach_address (hw_parent (me),
176 &reg.address,
177 &attach_space,
178 &attach_address,
179 me);
180 controller->block.base = attach_address;
181 hw_unit_size_to_attach_size (hw_parent (me),
182 &reg.size,
183 &attach_size, 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),
188 0,
189 attach_space, attach_address, attach_size,
190 me);
191}
192
193
194static void
195mn103cpu_finish (struct hw *me)
196{
197 struct mn103cpu *controller;
198
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);
205
206 /* Attach ourself to our parent bus */
207 attach_mn103cpu_regs (me, controller);
208
209 /* Initialize the read-only registers */
210 controller->pending_level = 7; /* FIXME */
211 /* ... */
212}
213
214
215
216/* An event arrives on an interrupt port */
217
218static void
219deliver_mn103cpu_interrupt (struct hw *me,
220 void *data)
221{
222 struct mn103cpu *controller = hw_data (me);
223 SIM_DESC simulator = hw_system (me);
224 sim_cpu *cpu = STATE_CPU (simulator, 0);
225
226 if (controller->pending_reset)
227 {
228 controller->pending_reset = 0;
229 /* need to clear all registers et.al! */
230 HW_TRACE ((me, "Reset!"));
231 hw_abort (me, "Reset!");
232 }
233 else if (controller->pending_nmi)
234 {
235 controller->pending_nmi = 0;
034685f9 236 store_word (SP - 4, CPU_PC_GET (cpu));
c906108c
SS
237 store_half (SP - 8, PSW);
238 PSW &= ~PSW_IE;
239 SP = SP - 8;
034685f9 240 CPU_PC_SET (cpu, 0x40000008);
c906108c 241 HW_TRACE ((me, "nmi pc=0x%08lx psw=0x%04x sp=0x%08lx",
034685f9 242 (long) CPU_PC_GET (cpu), (unsigned) PSW, (long) SP));
c906108c
SS
243 }
244 else if ((controller->pending_level < EXTRACT_PSW_LM)
245 && (PSW & PSW_IE))
246 {
247 /* Don't clear pending level. Request continues to be pending
248 until the interrupt controller clears/changes it */
034685f9 249 store_word (SP - 4, CPU_PC_GET (cpu));
c906108c
SS
250 store_half (SP - 8, PSW);
251 PSW &= ~PSW_IE;
252 PSW &= ~PSW_LM;
253 PSW |= INSERT_PSW_LM (controller->pending_level);
254 SP = SP - 8;
034685f9 255 CPU_PC_SET (cpu, 0x40000000 + controller->interrupt_vector[controller->pending_level]);
c906108c
SS
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,
034685f9 260 (long) CPU_PC_GET (cpu), (unsigned) PSW, (long) SP));
c906108c
SS
261 }
262
263 if (controller->pending_level < 7) /* FIXME */
264 {
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);
270 }
271 else
272 {
273 /* Don't bother re-scheduling the interrupt handler as there is
274 nothing to deliver */
275 controller->pending_handler = NULL;
276 }
277
278}
279
280
281static void
282mn103cpu_port_event (struct hw *me,
283 int my_port,
284 struct hw *source,
285 int source_port,
286 int level)
287{
288 struct mn103cpu *controller = hw_data (me);
289
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);
294
295 switch (my_port)
296 {
297
298 case RESET_PORT:
299 controller->pending_reset = 1;
300 HW_TRACE ((me, "port-in reset"));
301 break;
302
303 case NMI_PORT:
304 controller->pending_nmi = 1;
305 HW_TRACE ((me, "port-in nmi"));
306 break;
307
308 case LEVEL_PORT:
309 controller->pending_level = level;
310 HW_TRACE ((me, "port-in level=%d", level));
311 break;
312
313 default:
314 hw_abort (me, "bad switch");
315 break;
316
317 }
318}
319
320
321/* Read/write to a CPU register */
322
323enum mn103cpu_regs {
324 INVALID_REG,
325 IVR0_REG,
326 IVR1_REG,
327 IVR2_REG,
328 IVR3_REG,
329 IVR4_REG,
330 IVR5_REG,
331 IVR6_REG,
332 IMCR_REG,
333 CPUM_REG,
334};
335
336static enum mn103cpu_regs
337decode_mn103cpu_addr (struct hw *me,
338 struct mn103cpu *controller,
339 unsigned_word base)
340{
341 switch (base - controller->block.base)
342 {
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;
353 }
354}
355
356static unsigned
357mn103cpu_io_read_buffer (struct hw *me,
358 void *dest,
359 int space,
360 unsigned_word base,
361 unsigned nr_bytes)
362{
363 struct mn103cpu *controller = hw_data (me);
74ccc978 364 uint16_t val = 0;
c906108c
SS
365 enum mn103cpu_regs reg = decode_mn103cpu_addr (me, controller, base);
366
367 switch (reg)
368 {
369 case IVR0_REG:
370 case IVR1_REG:
371 case IVR2_REG:
372 case IVR3_REG:
373 case IVR4_REG:
374 case IVR5_REG:
375 case IVR6_REG:
376 val = controller->interrupt_vector[reg - IVR0_REG];
377 break;
378 case IMCR_REG:
379 val = controller->internal_memory_control;
380 break;
381 case CPUM_REG:
382 val = controller->cpu_mode;
383 break;
384 default:
385 /* just ignore the read */
386 break;
387 }
388
389 if (nr_bytes == 2)
74ccc978 390 *(uint16_t*) dest = H2LE_2 (val);
c906108c
SS
391
392 return nr_bytes;
393}
394
395static unsigned
396mn103cpu_io_write_buffer (struct hw *me,
397 const void *source,
398 int space,
399 unsigned_word base,
400 unsigned nr_bytes)
401{
402 struct mn103cpu *controller = hw_data (me);
74ccc978 403 uint16_t val;
c906108c
SS
404 enum mn103cpu_regs reg;
405
406 if (nr_bytes != 2)
407 hw_abort (me, "must be two byte write");
408
409 reg = decode_mn103cpu_addr (me, controller, base);
74ccc978 410 val = LE2H_2 (* (uint16_t *) source);
c906108c
SS
411
412 switch (reg)
413 {
414 case IVR0_REG:
415 case IVR1_REG:
416 case IVR2_REG:
417 case IVR3_REG:
418 case IVR4_REG:
419 case IVR5_REG:
420 case IVR6_REG:
421 controller->interrupt_vector[reg - IVR0_REG] = val;
422 HW_TRACE ((me, "ivr%d = 0x%04lx", reg - IVR0_REG, (long) val));
423 break;
424 default:
425 /* just ignore the write */
426 break;
427 }
428
429 return nr_bytes;
430}
431
432
433const struct hw_descriptor dv_mn103cpu_descriptor[] = {
434 { "mn103cpu", mn103cpu_finish, },
435 { NULL },
436};