]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/dv-pal.c
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / sim / common / dv-pal.c
CommitLineData
b85e4829
AC
1/* The common simulator framework for GDB, the GNU Debugger.
2
213516ef 3 Copyright 2002-2023 Free Software Foundation, Inc.
b85e4829
AC
4
5 Contributed by Andrew Cagney and Red Hat.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
4744ac1b 11 the Free Software Foundation; either version 3 of the License, or
b85e4829
AC
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
4744ac1b 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c 21
6df01ab8
MF
22/* This must come before any other includes. */
23#include "defs.h"
24
20a8e078
MF
25#include <stdlib.h>
26#include <string.h>
27#ifdef HAVE_UNISTD_H
28#include <unistd.h>
29#endif
30
268c9139 31#include "sim-main.h"
c906108c
SS
32#include "hw-main.h"
33#include "sim-io.h"
34
35/* NOTE: pal is naughty and grubs around looking at things outside of
36 its immediate domain */
37#include "hw-tree.h"
38
c906108c
SS
39/* DEVICE
40
028f6515 41
c906108c
SS
42 pal - glue logic device containing assorted junk
43
028f6515 44
c906108c
SS
45 DESCRIPTION
46
028f6515 47
c906108c
SS
48 Typical hardware dependant hack. This device allows the firmware
49 to gain access to all the things the firmware needs (but the OS
50 doesn't).
51
52 The pal contains the following registers:
53
54 |0 reset register (write, 8bit)
55 |4 processor id register (read, 8bit)
56 |8 interrupt register (8 - port, 9 - level) (write, 16bit)
57 |12 processor count register (read, 8bit)
58
59 |16 tty input fifo register (read, 8bit)
60 |20 tty input status register (read, 8bit)
61 |24 tty output fifo register (write, 8bit)
62 |28 tty output status register (read, 8bit)
63
64 |32 countdown register (read/write, 32bit, big-endian)
65 |36 countdown value register (read, 32bit, big-endian)
66 |40 timer register (read/write, 32bit, big-endian)
67 |44 timer value register (read, 32bit, big-endian)
68
69 RESET (write): halts the simulator. The value written to the
70 register is used as an exit status.
028f6515 71
c906108c
SS
72 PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of
73 the processor performing the read.
028f6515 74
c906108c
SS
75 INTERRUPT (write): This register must be written using a two byte
76 store. The low byte specifies a port and the upper byte specifies
77 the a level. LEVEL is driven on the specified port. By
78 convention, the pal's interrupt ports (int0, int1, ...) are wired
79 up to the corresponding processor's level sensative external
80 interrupt pin. Eg: A two byte write to address 8 of 0x0102
81 (big-endian) will result in processor 2's external interrupt pin
82 being asserted.
83
84 PROCESSOR COUNT (read): returns the total number of processors
85 active in the current simulation.
86
87 TTY INPUT FIFO (read): if the TTY input status register indicates a
88 character is available by being nonzero, returns the next available
89 character from the pal's tty input port.
90
91 TTY OUTPUT FIFO (write): if the TTY output status register
92 indicates the output fifo is not full by being nonzero, outputs the
93 character written to the tty's output port.
94
95 COUNDOWN (read/write): The countdown registers provide a
96 non-repeating timed interrupt source. Writing a 32 bit big-endian
97 zero value to this register clears the countdown timer. Writing a
98 non-zero 32 bit big-endian value to this register sets the
99 countdown timer to expire in VALUE ticks (ticks is target
100 dependant). Reading the countdown register returns the last value
101 writen.
102
103 COUNTDOWN VALUE (read): Reading this 32 bit big-endian register
104 returns the number of ticks remaining until the countdown timer
105 expires.
106
107 TIMER (read/write): The timer registers provide a periodic timed
108 interrupt source. Writing a 32 bit big-endian zero value to this
109 register clears the periodic timer. Writing a 32 bit non-zero
110 value to this register sets the periodic timer to triger every
111 VALUE ticks (ticks is target dependant). Reading the timer
112 register returns the last value written.
113
114 TIMER VALUE (read): Reading this 32 bit big-endian register returns
115 the number of ticks until the next periodic interrupt.
116
117
118 PROPERTIES
028f6515 119
c906108c
SS
120
121 reg = <address> <size> (required)
122
123 Specify the address (within the parent bus) that this device is to
124 be located.
125
126 poll? = <boolean>
127
128 If present and true, indicates that the device should poll its
129 input.
130
131
132 PORTS
133
134
135 int[0..NR_PROCESSORS] (output)
136
137 Driven as a result of a write to the interrupt-port /
138 interrupt-level register pair.
139
140
141 countdown
142
143 Driven whenever the countdown counter reaches zero.
144
145
146 timer
147
148 Driven whenever the timer counter reaches zero.
149
150
151 BUGS
152
153
154 At present the common simulator framework does not support input
155 polling.
156
157 */
158
159
160enum {
161 hw_pal_reset_register = 0x0,
162 hw_pal_cpu_nr_register = 0x4,
163 hw_pal_int_register = 0x8,
164 hw_pal_nr_cpu_register = 0xa,
165 hw_pal_read_fifo = 0x10,
166 hw_pal_read_status = 0x14,
167 hw_pal_write_fifo = 0x18,
168 hw_pal_write_status = 0x1a,
169 hw_pal_countdown = 0x20,
170 hw_pal_countdown_value = 0x24,
171 hw_pal_timer = 0x28,
172 hw_pal_timer_value = 0x2c,
173 hw_pal_address_mask = 0x3f,
174};
175
176
177typedef struct _hw_pal_console_buffer {
178 char buffer;
179 int status;
180} hw_pal_console_buffer;
181
182typedef struct _hw_pal_counter {
183 struct hw_event *handler;
e4c803f5
MF
184 int64_t start;
185 uint32_t delta;
c906108c
SS
186 int periodic_p;
187} hw_pal_counter;
188
189
190typedef struct _hw_pal_device {
191 hw_pal_console_buffer input;
192 hw_pal_console_buffer output;
193 hw_pal_counter countdown;
194 hw_pal_counter timer;
195 struct hw *disk;
196 do_hw_poll_read_method *reader;
197} hw_pal_device;
198
199enum {
200 COUNTDOWN_PORT,
201 TIMER_PORT,
202 INT_PORT,
203};
204
205static const struct hw_port_descriptor hw_pal_ports[] = {
206 { "countdown", COUNTDOWN_PORT, 0, output_port, },
207 { "timer", TIMER_PORT, 0, output_port, },
208 { "int", INT_PORT, MAX_NR_PROCESSORS, output_port, },
21cf617c 209 { NULL, 0, 0, 0 }
c906108c
SS
210};
211
212
213/* countdown and simple timer */
214
215static void
216do_counter_event (struct hw *me,
217 void *data)
218{
219 hw_pal_counter *counter = (hw_pal_counter *) data;
220 if (counter->periodic_p)
221 {
222 HW_TRACE ((me, "timer expired"));
223 counter->start = hw_event_queue_time (me);
224 hw_port_event (me, TIMER_PORT, 1);
225 hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
226 }
227 else
228 {
229 HW_TRACE ((me, "countdown expired"));
230 counter->delta = 0;
231 hw_port_event (me, COUNTDOWN_PORT, 1);
232 }
233}
234
235static void
236do_counter_read (struct hw *me,
237 hw_pal_device *pal,
238 const char *reg,
239 hw_pal_counter *counter,
e4c803f5 240 uint32_t *word,
c906108c
SS
241 unsigned nr_bytes)
242{
e4c803f5 243 uint32_t val;
c906108c
SS
244 if (nr_bytes != 4)
245 hw_abort (me, "%s - bad read size must be 4 bytes", reg);
246 val = counter->delta;
247 HW_TRACE ((me, "read - %s %ld", reg, (long) val));
248 *word = H2BE_4 (val);
249}
250
251static void
252do_counter_value (struct hw *me,
253 hw_pal_device *pal,
254 const char *reg,
255 hw_pal_counter *counter,
e4c803f5 256 uint32_t *word,
c906108c
SS
257 unsigned nr_bytes)
258{
e4c803f5 259 uint32_t val;
c906108c
SS
260 if (nr_bytes != 4)
261 hw_abort (me, "%s - bad read size must be 4 bytes", reg);
262 if (counter->delta != 0)
263 val = (counter->start + counter->delta
264 - hw_event_queue_time (me));
265 else
266 val = 0;
267 HW_TRACE ((me, "read - %s %ld", reg, (long) val));
268 *word = H2BE_4 (val);
269}
270
271static void
272do_counter_write (struct hw *me,
273 hw_pal_device *pal,
274 const char *reg,
275 hw_pal_counter *counter,
e4c803f5 276 const uint32_t *word,
c906108c
SS
277 unsigned nr_bytes)
278{
279 if (nr_bytes != 4)
280 hw_abort (me, "%s - bad write size must be 4 bytes", reg);
281 if (counter->handler != NULL)
282 {
283 hw_event_queue_deschedule (me, counter->handler);
284 counter->handler = NULL;
285 }
286 counter->delta = BE2H_4 (*word);
287 counter->start = hw_event_queue_time (me);
288 HW_TRACE ((me, "write - %s %ld", reg, (long) counter->delta));
289 if (counter->delta > 0)
290 hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
291}
292
293
294
295
296/* check the console for an available character */
297static void
298scan_hw_pal (struct hw *me)
299{
300 hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me);
301 char c;
302 int count;
34b47c38 303 count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof (c));
c906108c
SS
304 switch (count)
305 {
306 case HW_IO_NOT_READY:
307 case HW_IO_EOF:
308 hw_pal->input.buffer = 0;
309 hw_pal->input.status = 0;
310 break;
311 default:
312 hw_pal->input.buffer = c;
313 hw_pal->input.status = 1;
314 }
315}
316
317/* write the character to the hw_pal */
318
319static void
320write_hw_pal (struct hw *me,
321 char val)
322{
323 hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
324 sim_io_write_stdout (hw_system (me), &val, 1);
325 hw_pal->output.buffer = val;
326 hw_pal->output.status = 1;
327}
328
329
330/* Reads/writes */
331
332static unsigned
333hw_pal_io_read_buffer (struct hw *me,
334 void *dest,
335 int space,
336 unsigned_word addr,
337 unsigned nr_bytes)
338{
339 hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
340 unsigned_1 *byte = (unsigned_1 *) dest;
341 memset (dest, 0, nr_bytes);
342 switch (addr & hw_pal_address_mask)
343 {
344
345 case hw_pal_cpu_nr_register:
c906108c 346 *byte = CPU_INDEX (hw_system_cpu (me));
c906108c
SS
347 HW_TRACE ((me, "read - cpu-nr %d\n", *byte));
348 break;
349
350 case hw_pal_nr_cpu_register:
351 if (hw_tree_find_property (me, "/openprom/options/smp") == NULL)
352 {
353 *byte = 1;
354 HW_TRACE ((me, "read - nr-cpu %d (not defined)\n", *byte));
355 }
356 else
357 {
358 *byte = hw_tree_find_integer_property (me, "/openprom/options/smp");
359 HW_TRACE ((me, "read - nr-cpu %d\n", *byte));
360 }
361 break;
362
363 case hw_pal_read_fifo:
364 *byte = hw_pal->input.buffer;
365 HW_TRACE ((me, "read - input-fifo %d\n", *byte));
366 break;
367
368 case hw_pal_read_status:
369 scan_hw_pal (me);
370 *byte = hw_pal->input.status;
371 HW_TRACE ((me, "read - input-status %d\n", *byte));
372 break;
373
374 case hw_pal_write_fifo:
375 *byte = hw_pal->output.buffer;
376 HW_TRACE ((me, "read - output-fifo %d\n", *byte));
377 break;
378
379 case hw_pal_write_status:
380 *byte = hw_pal->output.status;
381 HW_TRACE ((me, "read - output-status %d\n", *byte));
382 break;
383
384 case hw_pal_countdown:
385 do_counter_read (me, hw_pal, "countdown",
386 &hw_pal->countdown, dest, nr_bytes);
387 break;
388
389 case hw_pal_countdown_value:
390 do_counter_value (me, hw_pal, "countdown-value",
391 &hw_pal->countdown, dest, nr_bytes);
392 break;
393
394 case hw_pal_timer:
395 do_counter_read (me, hw_pal, "timer",
396 &hw_pal->timer, dest, nr_bytes);
397 break;
398
399 case hw_pal_timer_value:
400 do_counter_value (me, hw_pal, "timer-value",
401 &hw_pal->timer, dest, nr_bytes);
402 break;
403
404 default:
405 HW_TRACE ((me, "read - ???\n"));
406 break;
407
408 }
409 return nr_bytes;
410}
411
412
413static unsigned
414hw_pal_io_write_buffer (struct hw *me,
415 const void *source,
416 int space,
417 unsigned_word addr,
418 unsigned nr_bytes)
419{
420 hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me);
421 unsigned_1 *byte = (unsigned_1 *) source;
028f6515 422
c906108c
SS
423 switch (addr & hw_pal_address_mask)
424 {
425
426 case hw_pal_reset_register:
427 hw_halt (me, sim_exited, byte[0]);
428 break;
429
430 case hw_pal_int_register:
431 hw_port_event (me,
432 INT_PORT + byte[0], /*port*/
433 (nr_bytes > 1 ? byte[1] : 0)); /* val */
434 break;
435
436 case hw_pal_read_fifo:
437 hw_pal->input.buffer = byte[0];
438 HW_TRACE ((me, "write - input-fifo %d\n", byte[0]));
439 break;
440
441 case hw_pal_read_status:
442 hw_pal->input.status = byte[0];
443 HW_TRACE ((me, "write - input-status %d\n", byte[0]));
444 break;
445
446 case hw_pal_write_fifo:
447 write_hw_pal (me, byte[0]);
448 HW_TRACE ((me, "write - output-fifo %d\n", byte[0]));
449 break;
450
451 case hw_pal_write_status:
452 hw_pal->output.status = byte[0];
453 HW_TRACE ((me, "write - output-status %d\n", byte[0]));
454 break;
455
456 case hw_pal_countdown:
457 do_counter_write (me, hw_pal, "countdown",
458 &hw_pal->countdown, source, nr_bytes);
459 break;
028f6515 460
c906108c
SS
461 case hw_pal_timer:
462 do_counter_write (me, hw_pal, "timer",
463 &hw_pal->timer, source, nr_bytes);
464 break;
028f6515 465
c906108c
SS
466 }
467 return nr_bytes;
468}
469
470
471/* instances of the hw_pal struct hw */
472
473#if NOT_YET
474static void
34b47c38 475hw_pal_instance_delete_callback (hw_instance *instance)
c906108c
SS
476{
477 /* nothing to delete, the hw_pal is attached to the struct hw */
478 return;
479}
480#endif
481
482#if NOT_YET
483static int
484hw_pal_instance_read_callback (hw_instance *instance,
485 void *buf,
486 unsigned_word len)
487{
488 DITRACE (pal, ("read - %s (%ld)", (const char*) buf, (long int) len));
489 return sim_io_read_stdin (buf, len);
490}
491#endif
492
493#if NOT_YET
494static int
495hw_pal_instance_write_callback (hw_instance *instance,
496 const void *buf,
497 unsigned_word len)
498{
499 int i;
500 const char *chp = buf;
501 hw_pal_device *hw_pal = hw_instance_data (instance);
502 DITRACE (pal, ("write - %s (%ld)", (const char*) buf, (long int) len));
503 for (i = 0; i < len; i++)
504 write_hw_pal (hw_pal, chp[i]);
505 sim_io_flush_stdoutput ();
506 return i;
507}
508#endif
509
510#if NOT_YET
511static const hw_instance_callbacks hw_pal_instance_callbacks = {
512 hw_pal_instance_delete_callback,
513 hw_pal_instance_read_callback,
514 hw_pal_instance_write_callback,
515};
516#endif
517
518#if 0
519static hw_instance *
520hw_pal_create_instance (struct hw *me,
521 const char *path,
522 const char *args)
523{
524 return hw_create_instance_from (me, NULL,
525 hw_data (me),
526 path, args,
527 &hw_pal_instance_callbacks);
528}
529#endif
530
531
532static void
533hw_pal_attach_address (struct hw *me,
534 int level,
535 int space,
536 address_word addr,
537 address_word nr_bytes,
538 struct hw *client)
539{
540 hw_pal_device *pal = (hw_pal_device*) hw_data (me);
541 pal->disk = client;
542}
543
544
545#if 0
546static hw_callbacks const hw_pal_callbacks = {
547 { generic_hw_init_address, },
548 { hw_pal_attach_address, }, /* address */
549 { hw_pal_io_read_buffer_callback,
550 hw_pal_io_write_buffer_callback, },
551 { NULL, }, /* DMA */
552 { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
553 { generic_hw_unit_decode,
554 generic_hw_unit_encode,
555 generic_hw_address_to_attach_address,
556 generic_hw_size_to_attach_size },
557 hw_pal_create_instance,
558};
559#endif
560
561
562static void
563hw_pal_finish (struct hw *hw)
564{
565 /* create the descriptor */
566 hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device);
567 hw_pal->output.status = 1;
568 hw_pal->output.buffer = '\0';
569 hw_pal->input.status = 0;
570 hw_pal->input.buffer = '\0';
571 set_hw_data (hw, hw_pal);
572 set_hw_attach_address (hw, hw_pal_attach_address);
573 set_hw_io_read_buffer (hw, hw_pal_io_read_buffer);
574 set_hw_io_write_buffer (hw, hw_pal_io_write_buffer);
575 set_hw_ports (hw, hw_pal_ports);
576 /* attach ourselves */
577 do_hw_attach_regs (hw);
578 /* If so configured, enable polled input */
579 if (hw_find_property (hw, "poll?") != NULL
580 && hw_find_boolean_property (hw, "poll?"))
581 {
582 hw_pal->reader = sim_io_poll_read;
583 }
584 else
585 {
586 hw_pal->reader = sim_io_read;
587 }
588 /* tag the periodic timer */
589 hw_pal->timer.periodic_p = 1;
590}
591
592
593const struct hw_descriptor dv_pal_descriptor[] = {
594 { "pal", hw_pal_finish, },
21cf617c 595 { NULL, NULL },
c906108c 596};