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