This commit was generated by cvs2svn to track changes on a CVS vendor
[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 130
39e953a7
AC
131 poll? = <boolean>
132
133 If present and true, indicates that the device should poll its
134 input.
135
b1e9223c 136
937a4bdc
AC
137 PORTS
138
139
140 int[0..NR_PROCESSORS] (output)
141
142 Driven as a result of a write to the interrupt-port /
143 interrupt-level register pair.
144
145
05d7918e
AC
146 countdown
147
148 Driven whenever the countdown counter reaches zero.
149
150
151 timer
152
153 Driven whenever the timer counter reaches zero.
154
155
156 BUGS
157
158
159 At present the common simulator framework does not support input
160 polling.
161
b1e9223c
AC
162 */
163
164
165enum {
166 hw_pal_reset_register = 0x0,
167 hw_pal_cpu_nr_register = 0x4,
168 hw_pal_int_register = 0x8,
169 hw_pal_nr_cpu_register = 0xa,
170 hw_pal_read_fifo = 0x10,
171 hw_pal_read_status = 0x14,
172 hw_pal_write_fifo = 0x18,
173 hw_pal_write_status = 0x1a,
05d7918e
AC
174 hw_pal_countdown = 0x20,
175 hw_pal_countdown_value = 0x24,
176 hw_pal_timer = 0x28,
177 hw_pal_timer_value = 0x2c,
39e953a7 178 hw_pal_address_mask = 0x3f,
b1e9223c
AC
179};
180
181
182typedef struct _hw_pal_console_buffer {
183 char buffer;
184 int status;
185} hw_pal_console_buffer;
186
05d7918e 187typedef struct _hw_pal_counter {
39e953a7 188 struct hw_event *handler;
05d7918e
AC
189 signed64 start;
190 unsigned32 delta;
191 int periodic_p;
192} hw_pal_counter;
193
194
b1e9223c
AC
195typedef struct _hw_pal_device {
196 hw_pal_console_buffer input;
197 hw_pal_console_buffer output;
05d7918e
AC
198 hw_pal_counter countdown;
199 hw_pal_counter timer;
b1e9223c 200 struct hw *disk;
39e953a7 201 do_hw_poll_read_method *reader;
b1e9223c
AC
202} hw_pal_device;
203
05d7918e
AC
204enum {
205 COUNTDOWN_PORT,
206 TIMER_PORT,
207 INT_PORT,
208};
209
210static const struct hw_port_descriptor hw_pal_ports[] = {
211 { "countdown", COUNTDOWN_PORT, 0, output_port, },
212 { "timer", TIMER_PORT, 0, output_port, },
213 { "int", INT_PORT, MAX_NR_PROCESSORS, output_port, },
214 { NULL }
215};
216
217
218/* countdown and simple timer */
219
220static void
221do_counter_event (struct hw *me,
222 void *data)
223{
224 hw_pal_counter *counter = (hw_pal_counter *) data;
225 if (counter->periodic_p)
226 {
227 HW_TRACE ((me, "timer expired"));
228 counter->start = hw_event_queue_time (me);
39e953a7 229 hw_port_event (me, TIMER_PORT, 1);
05d7918e
AC
230 hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
231 }
232 else
233 {
234 HW_TRACE ((me, "countdown expired"));
235 counter->delta = 0;
39e953a7 236 hw_port_event (me, COUNTDOWN_PORT, 1);
05d7918e
AC
237 }
238}
239
240static void
241do_counter_read (struct hw *me,
242 hw_pal_device *pal,
243 const char *reg,
244 hw_pal_counter *counter,
245 unsigned32 *word,
246 unsigned nr_bytes)
247{
248 unsigned32 val;
249 if (nr_bytes != 4)
250 hw_abort (me, "%s - bad read size must be 4 bytes", reg);
251 val = counter->delta;
252 HW_TRACE ((me, "read - %s %ld", reg, (long) val));
253 *word = H2BE_4 (val);
254}
255
256static void
257do_counter_value (struct hw *me,
258 hw_pal_device *pal,
259 const char *reg,
260 hw_pal_counter *counter,
261 unsigned32 *word,
262 unsigned nr_bytes)
263{
264 unsigned32 val;
265 if (nr_bytes != 4)
266 hw_abort (me, "%s - bad read size must be 4 bytes", reg);
267 if (counter->delta != 0)
268 val = (counter->start + counter->delta
269 - hw_event_queue_time (me));
270 else
271 val = 0;
272 HW_TRACE ((me, "read - %s %ld", reg, (long) val));
273 *word = H2BE_4 (val);
274}
275
276static void
277do_counter_write (struct hw *me,
278 hw_pal_device *pal,
279 const char *reg,
280 hw_pal_counter *counter,
281 const unsigned32 *word,
282 unsigned nr_bytes)
283{
284 if (nr_bytes != 4)
285 hw_abort (me, "%s - bad write size must be 4 bytes", reg);
286 if (counter->handler != NULL)
287 {
288 hw_event_queue_deschedule (me, counter->handler);
289 counter->handler = NULL;
290 }
291 counter->delta = BE2H_4 (*word);
292 counter->start = hw_event_queue_time (me);
293 HW_TRACE ((me, "write - %s %ld", reg, (long) counter->delta));
294 if (counter->delta > 0)
295 hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
296}
297
298
299
b1e9223c
AC
300
301/* check the console for an available character */
302static void
303scan_hw_pal (struct hw *me)
304{
39e953a7 305 hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me);
b1e9223c
AC
306 char c;
307 int count;
39e953a7 308 count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof(c));
b1e9223c
AC
309 switch (count)
310 {
39e953a7
AC
311 case HW_IO_NOT_READY:
312 case HW_IO_EOF:
b1e9223c
AC
313 hw_pal->input.buffer = 0;
314 hw_pal->input.status = 0;
315 break;
316 default:
317 hw_pal->input.buffer = c;
318 hw_pal->input.status = 1;
319 }
b1e9223c
AC
320}
321
322/* write the character to the hw_pal */
05d7918e 323
b1e9223c
AC
324static void
325write_hw_pal (struct hw *me,
326 char val)
327{
328 hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
329 sim_io_write_stdout (hw_system (me), &val, 1);
330 hw_pal->output.buffer = val;
331 hw_pal->output.status = 1;
332}
333
334
05d7918e
AC
335/* Reads/writes */
336
b1e9223c
AC
337static unsigned
338hw_pal_io_read_buffer (struct hw *me,
339 void *dest,
340 int space,
341 unsigned_word addr,
39e953a7 342 unsigned nr_bytes)
b1e9223c
AC
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
39e953a7 352 *byte = CPU_INDEX (hw_system_cpu (me));
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,
39e953a7 427 unsigned nr_bytes)
b1e9223c
AC
428{
429 hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me);
05d7918e 430 unsigned_1 *byte = (unsigned_1 *) source;
b1e9223c
AC
431
432 switch (addr & hw_pal_address_mask)
433 {
05d7918e 434
b1e9223c 435 case hw_pal_reset_register:
39e953a7 436 hw_halt (me, sim_exited, byte[0]);
b1e9223c 437 break;
05d7918e 438
b1e9223c
AC
439 case hw_pal_int_register:
440 hw_port_event (me,
05d7918e 441 INT_PORT + byte[0], /*port*/
39e953a7 442 (nr_bytes > 1 ? byte[1] : 0)); /* val */
b1e9223c 443 break;
05d7918e 444
b1e9223c
AC
445 case hw_pal_read_fifo:
446 hw_pal->input.buffer = byte[0];
937a4bdc 447 HW_TRACE ((me, "write - input-fifo %d\n", byte[0]));
b1e9223c 448 break;
05d7918e 449
b1e9223c
AC
450 case hw_pal_read_status:
451 hw_pal->input.status = byte[0];
937a4bdc 452 HW_TRACE ((me, "write - input-status %d\n", byte[0]));
b1e9223c 453 break;
05d7918e 454
b1e9223c
AC
455 case hw_pal_write_fifo:
456 write_hw_pal (me, byte[0]);
937a4bdc 457 HW_TRACE ((me, "write - output-fifo %d\n", byte[0]));
b1e9223c 458 break;
05d7918e 459
b1e9223c
AC
460 case hw_pal_write_status:
461 hw_pal->output.status = byte[0];
937a4bdc 462 HW_TRACE ((me, "write - output-status %d\n", byte[0]));
b1e9223c 463 break;
05d7918e
AC
464
465 case hw_pal_countdown:
466 do_counter_write (me, hw_pal, "countdown",
467 &hw_pal->countdown, source, nr_bytes);
468 break;
469
470 case hw_pal_timer:
471 do_counter_write (me, hw_pal, "timer",
472 &hw_pal->timer, source, nr_bytes);
473 break;
474
b1e9223c
AC
475 }
476 return nr_bytes;
477}
478
479
480/* instances of the hw_pal struct hw */
481
482#if NOT_YET
483static void
484hw_pal_instance_delete_callback(hw_instance *instance)
485{
486 /* nothing to delete, the hw_pal is attached to the struct hw */
487 return;
488}
489#endif
490
491#if NOT_YET
492static int
493hw_pal_instance_read_callback (hw_instance *instance,
494 void *buf,
495 unsigned_word len)
496{
497 DITRACE (pal, ("read - %s (%ld)", (const char*) buf, (long int) len));
498 return sim_io_read_stdin (buf, len);
499}
500#endif
501
502#if NOT_YET
503static int
504hw_pal_instance_write_callback (hw_instance *instance,
505 const void *buf,
506 unsigned_word len)
507{
508 int i;
509 const char *chp = buf;
510 hw_pal_device *hw_pal = hw_instance_data (instance);
511 DITRACE (pal, ("write - %s (%ld)", (const char*) buf, (long int) len));
512 for (i = 0; i < len; i++)
513 write_hw_pal (hw_pal, chp[i]);
514 sim_io_flush_stdoutput ();
515 return i;
516}
517#endif
518
519#if NOT_YET
520static const hw_instance_callbacks hw_pal_instance_callbacks = {
521 hw_pal_instance_delete_callback,
522 hw_pal_instance_read_callback,
523 hw_pal_instance_write_callback,
524};
525#endif
526
527#if 0
528static hw_instance *
529hw_pal_create_instance (struct hw *me,
530 const char *path,
531 const char *args)
532{
533 return hw_create_instance_from (me, NULL,
534 hw_data (me),
535 path, args,
536 &hw_pal_instance_callbacks);
537}
538#endif
539
b1e9223c
AC
540
541static void
542hw_pal_attach_address (struct hw *me,
543 int level,
544 int space,
545 address_word addr,
546 address_word nr_bytes,
547 struct hw *client)
548{
549 hw_pal_device *pal = (hw_pal_device*) hw_data (me);
550 pal->disk = client;
551}
552
553
554#if 0
555static hw_callbacks const hw_pal_callbacks = {
556 { generic_hw_init_address, },
557 { hw_pal_attach_address, }, /* address */
558 { hw_pal_io_read_buffer_callback,
559 hw_pal_io_write_buffer_callback, },
560 { NULL, }, /* DMA */
561 { NULL, NULL, hw_pal_interrupt_ports }, /* interrupt */
562 { generic_hw_unit_decode,
563 generic_hw_unit_encode,
564 generic_hw_address_to_attach_address,
565 generic_hw_size_to_attach_size },
566 hw_pal_create_instance,
567};
568#endif
569
570
571static void
572hw_pal_finish (struct hw *hw)
573{
574 /* create the descriptor */
e5f0d498 575 hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device);
b1e9223c
AC
576 hw_pal->output.status = 1;
577 hw_pal->output.buffer = '\0';
578 hw_pal->input.status = 0;
579 hw_pal->input.buffer = '\0';
580 set_hw_data (hw, hw_pal);
581 set_hw_attach_address (hw, hw_pal_attach_address);
582 set_hw_io_read_buffer (hw, hw_pal_io_read_buffer);
583 set_hw_io_write_buffer (hw, hw_pal_io_write_buffer);
584 set_hw_ports (hw, hw_pal_ports);
775b309a 585 /* attach ourselves */
05d7918e 586 do_hw_attach_regs (hw);
39e953a7
AC
587 /* If so configured, enable polled input */
588 if (hw_find_property (hw, "poll?") != NULL
589 && hw_find_boolean_property (hw, "poll?"))
590 {
591 hw_pal->reader = sim_io_poll_read;
592 }
593 else
594 {
595 hw_pal->reader = sim_io_read;
596 }
05d7918e
AC
597 /* tag the periodic timer */
598 hw_pal->timer.periodic_p = 1;
b1e9223c
AC
599}
600
601
602const struct hw_device_descriptor dv_pal_descriptor[] = {
603 { "pal", hw_pal_finish, },
604 { NULL },
605};
This page took 0.071589 seconds and 4 git commands to generate.