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