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