xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/dv-pal.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
1 /* The common simulator framework for GDB, the GNU Debugger.
2 
3    Copyright 2002-2024 Free Software Foundation, Inc.
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
11    the Free Software Foundation; either version 3 of the License, or
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
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
21 
22 /* This must come before any other includes.  */
23 #include "defs.h"
24 
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 
29 #include "sim-main.h"
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 
37 /* DEVICE
38 
39 
40    pal - glue logic device containing assorted junk
41 
42 
43    DESCRIPTION
44 
45 
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.
69 
70    PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of
71    the processor performing the read.
72 
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
117 
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 
158 enum {
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 
175 typedef struct _hw_pal_console_buffer {
176   char buffer;
177   int status;
178 } hw_pal_console_buffer;
179 
180 typedef struct _hw_pal_counter {
181   struct hw_event *handler;
182   int64_t start;
183   uint32_t delta;
184   int periodic_p;
185 } hw_pal_counter;
186 
187 
188 typedef 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 
197 enum {
198   COUNTDOWN_PORT,
199   TIMER_PORT,
200   INT_PORT,
201 };
202 
203 static 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, },
207   { NULL, 0, 0, 0 }
208 };
209 
210 
211 /* countdown and simple timer */
212 
213 static void
214 do_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 
233 static void
234 do_counter_read (struct hw *me,
235 		 hw_pal_device *pal,
236 		 const char *reg,
237 		 hw_pal_counter *counter,
238 		 uint32_t *word,
239 		 unsigned nr_bytes)
240 {
241   uint32_t val;
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 
249 static void
250 do_counter_value (struct hw *me,
251 		  hw_pal_device *pal,
252 		  const char *reg,
253 		  hw_pal_counter *counter,
254 		  uint32_t *word,
255 		  unsigned nr_bytes)
256 {
257   uint32_t val;
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 
269 static void
270 do_counter_write (struct hw *me,
271 		  hw_pal_device *pal,
272 		  const char *reg,
273 		  hw_pal_counter *counter,
274 		  const uint32_t *word,
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 */
295 static void
296 scan_hw_pal (struct hw *me)
297 {
298   hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me);
299   char c;
300   int count;
301   count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof (c));
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 
317 static void
318 write_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 
330 static unsigned
331 hw_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:
344       *byte = CPU_INDEX (hw_system_cpu (me));
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 
411 static unsigned
412 hw_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;
420 
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;
458 
459     case hw_pal_timer:
460       do_counter_write (me, hw_pal, "timer",
461 			&hw_pal->timer, source, nr_bytes);
462       break;
463 
464     }
465   return nr_bytes;
466 }
467 
468 
469 /* instances of the hw_pal struct hw */
470 
471 #if NOT_YET
472 static void
473 hw_pal_instance_delete_callback (hw_instance *instance)
474 {
475   /* nothing to delete, the hw_pal is attached to the struct hw */
476   return;
477 }
478 #endif
479 
480 #if NOT_YET
481 static int
482 hw_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
492 static int
493 hw_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
509 static 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
517 static hw_instance *
518 hw_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 
530 static void
531 hw_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
544 static 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 
560 static void
561 hw_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 
591 const struct hw_descriptor dv_pal_descriptor[] = {
592   { "pal", hw_pal_finish, },
593   { NULL, NULL },
594 };
595