import gdb-1999-07-19 snapshot
[external/binutils.git] / sim / common / dv-pal.c
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 "hw-main.h"
23 #include "sim-io.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
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
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.
76    
77    PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of
78    the processor performing the read.
79    
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
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
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.
91
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.
95
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.
99
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.
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
129    be located.
130
131    poll? = <boolean>
132
133    If present and true, indicates that the device should poll its
134    input.
135
136
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
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
162    */
163
164
165 enum {
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,
174   hw_pal_countdown = 0x20,
175   hw_pal_countdown_value = 0x24,
176   hw_pal_timer = 0x28,
177   hw_pal_timer_value = 0x2c,
178   hw_pal_address_mask = 0x3f,
179 };
180
181
182 typedef struct _hw_pal_console_buffer {
183   char buffer;
184   int status;
185 } hw_pal_console_buffer;
186
187 typedef struct _hw_pal_counter {
188   struct hw_event *handler;
189   signed64 start;
190   unsigned32 delta;
191   int periodic_p;
192 } hw_pal_counter;
193
194
195 typedef struct _hw_pal_device {
196   hw_pal_console_buffer input;
197   hw_pal_console_buffer output;
198   hw_pal_counter countdown;
199   hw_pal_counter timer;
200   struct hw *disk;
201   do_hw_poll_read_method *reader;
202 } hw_pal_device;
203
204 enum {
205   COUNTDOWN_PORT,
206   TIMER_PORT,
207   INT_PORT,
208 };
209
210 static 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
220 static void
221 do_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);
229       hw_port_event (me, TIMER_PORT, 1);
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;
236       hw_port_event (me, COUNTDOWN_PORT, 1);
237     }
238 }
239
240 static void
241 do_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
256 static void
257 do_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
276 static void
277 do_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
300
301 /* check the console for an available character */
302 static void
303 scan_hw_pal (struct hw *me)
304 {
305   hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me);
306   char c;
307   int count;
308   count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof(c));
309   switch (count)
310     {
311     case HW_IO_NOT_READY:
312     case HW_IO_EOF:
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     }
320 }
321
322 /* write the character to the hw_pal */
323
324 static void
325 write_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
335 /* Reads/writes */
336
337 static unsigned
338 hw_pal_io_read_buffer (struct hw *me,
339                        void *dest,
340                        int space,
341                        unsigned_word addr,
342                        unsigned nr_bytes)
343 {
344   hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
345   unsigned_1 *byte = (unsigned_1 *) dest;
346   memset (dest, 0, nr_bytes);
347   switch (addr & hw_pal_address_mask)
348     {
349
350     case hw_pal_cpu_nr_register:
351 #ifdef CPU_INDEX
352       *byte = CPU_INDEX (hw_system_cpu (me));
353 #else
354       *byte = 0;
355 #endif
356       HW_TRACE ((me, "read - cpu-nr %d\n", *byte));
357       break;
358
359     case hw_pal_nr_cpu_register:
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         }
370       break;
371
372     case hw_pal_read_fifo:
373       *byte = hw_pal->input.buffer;
374       HW_TRACE ((me, "read - input-fifo %d\n", *byte));
375       break;
376
377     case hw_pal_read_status:
378       scan_hw_pal (me);
379       *byte = hw_pal->input.status;
380       HW_TRACE ((me, "read - input-status %d\n", *byte));
381       break;
382
383     case hw_pal_write_fifo:
384       *byte = hw_pal->output.buffer;
385       HW_TRACE ((me, "read - output-fifo %d\n", *byte));
386       break;
387
388     case hw_pal_write_status:
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);
401       break;
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
413     default:
414       HW_TRACE ((me, "read - ???\n"));
415       break;
416
417     }
418   return nr_bytes;
419 }
420
421
422 static unsigned
423 hw_pal_io_write_buffer (struct hw *me,
424                         const void *source,
425                         int space,
426                         unsigned_word addr,
427                         unsigned nr_bytes)
428 {
429   hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me);
430   unsigned_1 *byte = (unsigned_1 *) source;
431   
432   switch (addr & hw_pal_address_mask)
433     {
434
435     case hw_pal_reset_register:
436       hw_halt (me, sim_exited, byte[0]);
437       break;
438
439     case hw_pal_int_register:
440       hw_port_event (me,
441                      INT_PORT + byte[0], /*port*/
442                      (nr_bytes > 1 ? byte[1] : 0)); /* val */
443       break;
444
445     case hw_pal_read_fifo:
446       hw_pal->input.buffer = byte[0];
447       HW_TRACE ((me, "write - input-fifo %d\n", byte[0]));
448       break;
449
450     case hw_pal_read_status:
451       hw_pal->input.status = byte[0];
452       HW_TRACE ((me, "write - input-status %d\n", byte[0]));
453       break;
454
455     case hw_pal_write_fifo:
456       write_hw_pal (me, byte[0]);
457       HW_TRACE ((me, "write - output-fifo %d\n", byte[0]));
458       break;
459
460     case hw_pal_write_status:
461       hw_pal->output.status = byte[0];
462       HW_TRACE ((me, "write - output-status %d\n", byte[0]));
463       break;
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       
475     }
476   return nr_bytes;
477 }
478
479
480 /* instances of the hw_pal struct hw */
481
482 #if NOT_YET
483 static void
484 hw_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
492 static int
493 hw_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
503 static int
504 hw_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
520 static 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
528 static hw_instance *
529 hw_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
540
541 static void
542 hw_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
555 static 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
571 static void
572 hw_pal_finish (struct hw *hw)
573 {
574   /* create the descriptor */
575   hw_pal_device *hw_pal = HW_ZALLOC (hw, hw_pal_device);
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);
585   /* attach ourselves */
586   do_hw_attach_regs (hw);
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     }
597   /* tag the periodic timer */
598   hw_pal->timer.periodic_p = 1;
599 }
600
601
602 const struct hw_descriptor dv_pal_descriptor[] = {
603   { "pal", hw_pal_finish, },
604   { NULL },
605 };