ubsan: alpha-coff: signed integer overflow
[deliverable/binutils-gdb.git] / sim / common / dv-pal.c
index c98ff6860f10336b389a1c0e8494d66fedfaeb74..abe3bbc466f43b323df9f5abcedf36c406b92d20 100644 (file)
@@ -1,26 +1,28 @@
-/*  This file is part of the program psim.
-    
-    Copyright (C) 1994-1996,1998, Andrew Cagney <cagney@highland.com.au>
-    
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-    
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-    
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-    
-    */
+/* The common simulator framework for GDB, the GNU Debugger.
 
+   Copyright 2002-2020 Free Software Foundation, Inc.
 
+   Contributed by Andrew Cagney and Red Hat.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
 #include "sim-main.h"
-#include "hw-base.h"
+#include "hw-main.h"
+#include "sim-io.h"
 
 /* NOTE: pal is naughty and grubs around looking at things outside of
    its immediate domain */
 
 /* DEVICE
 
-   
+
    pal - glue logic device containing assorted junk
 
-   
+
    DESCRIPTION
 
-   
+
    Typical hardware dependant hack.  This device allows the firmware
    to gain access to all the things the firmware needs (but the OS
    doesn't).
 
-   The pal contains the following registers.  Except for the interrupt
-   level register, each of the below is 8 bytes in size and must be
-   accessed using correct alignment.  For 16 and 32 bit accesses the
-   bytes not directed to the register are ignored:
-   
-   |0  reset register (write)
-   |4  processor id register (read)
-   |8  interrupt port (write)
-   |9  interrupt level (write)
-   |12 processor count register (read)
-   |16 tty input fifo register (read)
-   |20 tty input status register (read)
-   |24 tty output fifo register (write)
-   |28 tty output status register (read)
-
-   Reset register (write) halts the simulator exiting with the
-   value written.
-   
-   Processor id register (read) returns the processor number (0
-   .. N-1) of the processor performing the read.
-   
-   The interrupt registers should be accessed as a pair (using a 16 or
-   32 bit store).  The low byte specifies the interrupt port while the
-   high byte specifies the level to drive that port at.  By
+   The pal contains the following registers:
+
+   |0  reset register (write, 8bit)
+   |4  processor id register (read, 8bit)
+   |8  interrupt register (8 - port, 9 - level) (write, 16bit)
+   |12 processor count register (read, 8bit)
+
+   |16 tty input fifo register (read, 8bit)
+   |20 tty input status register (read, 8bit)
+   |24 tty output fifo register (write, 8bit)
+   |28 tty output status register (read, 8bit)
+
+   |32  countdown register (read/write, 32bit, big-endian)
+   |36  countdown value register (read, 32bit, big-endian)
+   |40  timer register (read/write, 32bit, big-endian)
+   |44  timer value register (read, 32bit, big-endian)
+
+   RESET (write): halts the simulator.  The value written to the
+   register is used as an exit status.
+
+   PROCESSOR ID (read): returns the processor identifier (0 .. N-1) of
+   the processor performing the read.
+
+   INTERRUPT (write): This register must be written using a two byte
+   store.  The low byte specifies a port and the upper byte specifies
+   the a level.  LEVEL is driven on the specified port.  By
    convention, the pal's interrupt ports (int0, int1, ...) are wired
    up to the corresponding processor's level sensative external
    interrupt pin.  Eg: A two byte write to address 8 of 0x0102
-   (big-endian) will result in processor 2's external interrupt pin to
-   be asserted.
+   (big-endian) will result in processor 2's external interrupt pin
+   being asserted.
 
-   Processor count register (read) returns the total number of
-   processors active in the current simulation.
+   PROCESSOR COUNT (read): returns the total number of processors
+   active in the current simulation.
 
-   TTY input fifo register (read), if the TTY input status register
-   indicates a character is available by being nonzero, returns the
-   next available character from the pal's tty input port.
+   TTY INPUT FIFO (read): if the TTY input status register indicates a
+   character is available by being nonzero, returns the next available
+   character from the pal's tty input port.
 
-   Similarly, the TTY output fifo register (write), if the TTY output
-   status register indicates the output fifo is not full by being
-   nonzero, outputs the character written to the tty's output port.
+   TTY OUTPUT FIFO (write): if the TTY output status register
+   indicates the output fifo is not full by being nonzero, outputs the
+   character written to the tty's output port.
+
+   COUNDOWN (read/write): The countdown registers provide a
+   non-repeating timed interrupt source.  Writing a 32 bit big-endian
+   zero value to this register clears the countdown timer.  Writing a
+   non-zero 32 bit big-endian value to this register sets the
+   countdown timer to expire in VALUE ticks (ticks is target
+   dependant).  Reading the countdown register returns the last value
+   writen.
+
+   COUNTDOWN VALUE (read): Reading this 32 bit big-endian register
+   returns the number of ticks remaining until the countdown timer
+   expires.
+
+   TIMER (read/write): The timer registers provide a periodic timed
+   interrupt source.  Writing a 32 bit big-endian zero value to this
+   register clears the periodic timer.  Writing a 32 bit non-zero
+   value to this register sets the periodic timer to triger every
+   VALUE ticks (ticks is target dependant).  Reading the timer
+   register returns the last value written.
+
+   TIMER VALUE (read): Reading this 32 bit big-endian register returns
+   the number of ticks until the next periodic interrupt.
 
 
    PROPERTIES
-   
+
 
    reg = <address> <size> (required)
 
    Specify the address (within the parent bus) that this device is to
-   live.
+   be located.
+
+   poll? = <boolean>
+
+   If present and true, indicates that the device should poll its
+   input.
 
 
    PORTS
    interrupt-level register pair.
 
 
+   countdown
+
+   Driven whenever the countdown counter reaches zero.
+
+
+   timer
+
+   Driven whenever the timer counter reaches zero.
+
+
+   BUGS
+
+
+   At present the common simulator framework does not support input
+   polling.
+
    */
 
 
@@ -126,7 +173,11 @@ enum {
   hw_pal_read_status = 0x14,
   hw_pal_write_fifo = 0x18,
   hw_pal_write_status = 0x1a,
-  hw_pal_address_mask = 0x1f,
+  hw_pal_countdown = 0x20,
+  hw_pal_countdown_value = 0x24,
+  hw_pal_timer = 0x28,
+  hw_pal_timer_value = 0x2c,
+  hw_pal_address_mask = 0x3f,
 };
 
 
@@ -135,28 +186,132 @@ typedef struct _hw_pal_console_buffer {
   int status;
 } hw_pal_console_buffer;
 
+typedef struct _hw_pal_counter {
+  struct hw_event *handler;
+  signed64 start;
+  unsigned32 delta;
+  int periodic_p;
+} hw_pal_counter;
+
+
 typedef struct _hw_pal_device {
   hw_pal_console_buffer input;
   hw_pal_console_buffer output;
+  hw_pal_counter countdown;
+  hw_pal_counter timer;
   struct hw *disk;
+  do_hw_poll_read_method *reader;
 } hw_pal_device;
 
+enum {
+  COUNTDOWN_PORT,
+  TIMER_PORT,
+  INT_PORT,
+};
+
+static const struct hw_port_descriptor hw_pal_ports[] = {
+  { "countdown", COUNTDOWN_PORT, 0, output_port, },
+  { "timer", TIMER_PORT, 0, output_port, },
+  { "int", INT_PORT, MAX_NR_PROCESSORS, output_port, },
+  { NULL, 0, 0, 0 }
+};
+
+
+/* countdown and simple timer */
+
+static void
+do_counter_event (struct hw *me,
+                 void *data)
+{
+  hw_pal_counter *counter = (hw_pal_counter *) data;
+  if (counter->periodic_p)
+    {
+      HW_TRACE ((me, "timer expired"));
+      counter->start = hw_event_queue_time (me);
+      hw_port_event (me, TIMER_PORT, 1);
+      hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
+    }
+  else
+    {
+      HW_TRACE ((me, "countdown expired"));
+      counter->delta = 0;
+      hw_port_event (me, COUNTDOWN_PORT, 1);
+    }
+}
+
+static void
+do_counter_read (struct hw *me,
+                hw_pal_device *pal,
+                const char *reg,
+                hw_pal_counter *counter,
+                unsigned32 *word,
+                unsigned nr_bytes)
+{
+  unsigned32 val;
+  if (nr_bytes != 4)
+    hw_abort (me, "%s - bad read size must be 4 bytes", reg);
+  val = counter->delta;
+  HW_TRACE ((me, "read - %s %ld", reg, (long) val));
+  *word = H2BE_4 (val);
+}
+
+static void
+do_counter_value (struct hw *me,
+                 hw_pal_device *pal,
+                 const char *reg,
+                 hw_pal_counter *counter,
+                 unsigned32 *word,
+                 unsigned nr_bytes)
+{
+  unsigned32 val;
+  if (nr_bytes != 4)
+    hw_abort (me, "%s - bad read size must be 4 bytes", reg);
+  if (counter->delta != 0)
+    val = (counter->start + counter->delta
+          - hw_event_queue_time (me));
+  else
+    val = 0;
+  HW_TRACE ((me, "read - %s %ld", reg, (long) val));
+  *word = H2BE_4 (val);
+}
+
+static void
+do_counter_write (struct hw *me,
+                 hw_pal_device *pal,
+                 const char *reg,
+                 hw_pal_counter *counter,
+                 const unsigned32 *word,
+                 unsigned nr_bytes)
+{
+  if (nr_bytes != 4)
+    hw_abort (me, "%s - bad write size must be 4 bytes", reg);
+  if (counter->handler != NULL)
+    {
+      hw_event_queue_deschedule (me, counter->handler);
+      counter->handler = NULL;
+    }
+  counter->delta = BE2H_4 (*word);
+  counter->start = hw_event_queue_time (me);
+  HW_TRACE ((me, "write - %s %ld", reg, (long) counter->delta));
+  if (counter->delta > 0)
+    hw_event_queue_schedule (me, counter->delta, do_counter_event, counter);
+}
+
+
+
 
 /* check the console for an available character */
 static void
 scan_hw_pal (struct hw *me)
 {
-#if 0
-  hw_pal_struct hw *hw_pal = (hw_pal_struct hw *) hw_data (me);
-#endif
+  hw_pal_device *hw_pal = (hw_pal_device *)hw_data (me);
   char c;
   int count;
-  count = sim_io_read_stdin (hw_system (me), &c, sizeof(c));
-#if 0
+  count = do_hw_poll_read (me, hw_pal->reader, 0/*STDIN*/, &c, sizeof (c));
   switch (count)
     {
-    case sim_io_not_ready:
-    case sim_io_eof:
+    case HW_IO_NOT_READY:
+    case HW_IO_EOF:
       hw_pal->input.buffer = 0;
       hw_pal->input.status = 0;
       break;
@@ -164,10 +319,10 @@ scan_hw_pal (struct hw *me)
       hw_pal->input.buffer = c;
       hw_pal->input.status = 1;
     }
-#endif
 }
 
 /* write the character to the hw_pal */
+
 static void
 write_hw_pal (struct hw *me,
              char val)
@@ -179,54 +334,85 @@ write_hw_pal (struct hw *me,
 }
 
 
+/* Reads/writes */
+
 static unsigned
 hw_pal_io_read_buffer (struct hw *me,
                       void *dest,
                       int space,
                       unsigned_word addr,
-                      unsigned nr_bytes,
-                      sim_cpu *cpu,
-                      sim_cia cia)
+                      unsigned nr_bytes)
 {
   hw_pal_device *hw_pal = (hw_pal_device *) hw_data (me);
-  unsigned_1 val;
+  unsigned_1 *byte = (unsigned_1 *) dest;
+  memset (dest, 0, nr_bytes);
   switch (addr & hw_pal_address_mask)
     {
+
     case hw_pal_cpu_nr_register:
-#ifdef CPU_INDEX
-      val = CPU_INDEX (cpu);
-#else
-      val = 0;
-#endif
-      HW_TRACE ((me, "read - cpu-nr %d\n", val));
+      *byte = CPU_INDEX (hw_system_cpu (me));
+      HW_TRACE ((me, "read - cpu-nr %d\n", *byte));
       break;
+
     case hw_pal_nr_cpu_register:
-      val = hw_tree_find_integer_property (me, "/openprom/options/smp");
-      HW_TRACE ((me, "read - nr-cpu %d\n", val));
+      if (hw_tree_find_property (me, "/openprom/options/smp") == NULL)
+       {
+         *byte = 1;
+         HW_TRACE ((me, "read - nr-cpu %d (not defined)\n", *byte));
+       }
+      else
+       {
+         *byte = hw_tree_find_integer_property (me, "/openprom/options/smp");
+         HW_TRACE ((me, "read - nr-cpu %d\n", *byte));
+       }
       break;
+
     case hw_pal_read_fifo:
-      val = hw_pal->input.buffer;
-      HW_TRACE ((me, "read - input-fifo %d\n", val));
+      *byte = hw_pal->input.buffer;
+      HW_TRACE ((me, "read - input-fifo %d\n", *byte));
       break;
+
     case hw_pal_read_status:
       scan_hw_pal (me);
-      val = hw_pal->input.status;
-      HW_TRACE ((me, "read - input-status %d\n", val));
+      *byte = hw_pal->input.status;
+      HW_TRACE ((me, "read - input-status %d\n", *byte));
       break;
+
     case hw_pal_write_fifo:
-      val = hw_pal->output.buffer;
-      HW_TRACE ((me, "read - output-fifo %d\n", val));
+      *byte = hw_pal->output.buffer;
+      HW_TRACE ((me, "read - output-fifo %d\n", *byte));
       break;
+
     case hw_pal_write_status:
-      val = hw_pal->output.status;
-      HW_TRACE ((me, "read - output-status %d\n", val));
+      *byte = hw_pal->output.status;
+      HW_TRACE ((me, "read - output-status %d\n", *byte));
+      break;
+
+    case hw_pal_countdown:
+      do_counter_read (me, hw_pal, "countdown",
+                      &hw_pal->countdown, dest, nr_bytes);
+      break;
+
+    case hw_pal_countdown_value:
+      do_counter_value (me, hw_pal, "countdown-value",
+                       &hw_pal->countdown, dest, nr_bytes);
       break;
+
+    case hw_pal_timer:
+      do_counter_read (me, hw_pal, "timer",
+                      &hw_pal->timer, dest, nr_bytes);
+      break;
+
+    case hw_pal_timer_value:
+      do_counter_value (me, hw_pal, "timer-value",
+                       &hw_pal->timer, dest, nr_bytes);
+      break;
+
     default:
-      val = 0;
       HW_TRACE ((me, "read - ???\n"));
+      break;
+
     }
-  memset (dest, 0, nr_bytes);
-  *(unsigned_1*)dest = val;
   return nr_bytes;
 }
 
@@ -236,40 +422,54 @@ hw_pal_io_write_buffer (struct hw *me,
                        const void *source,
                        int space,
                        unsigned_word addr,
-                       unsigned nr_bytes,
-                       sim_cpu *cpu,
-                       sim_cia cia)
+                       unsigned nr_bytes)
 {
   hw_pal_device *hw_pal = (hw_pal_device*) hw_data (me);
-  unsigned_1 *byte = (unsigned_1*) source;
-  
+  unsigned_1 *byte = (unsigned_1 *) source;
+
   switch (addr & hw_pal_address_mask)
     {
+
     case hw_pal_reset_register:
-      sim_engine_halt (NULL, cpu, NULL, cia, sim_exited, byte[0]);
+      hw_halt (me, sim_exited, byte[0]);
       break;
+
     case hw_pal_int_register:
       hw_port_event (me,
-                    byte[0], /*port*/
-                    (nr_bytes > 1 ? byte[1] : 0), /* val */
-                    cpu, cia);
+                    INT_PORT + byte[0], /*port*/
+                    (nr_bytes > 1 ? byte[1] : 0)); /* val */
       break;
+
     case hw_pal_read_fifo:
       hw_pal->input.buffer = byte[0];
       HW_TRACE ((me, "write - input-fifo %d\n", byte[0]));
       break;
+
     case hw_pal_read_status:
       hw_pal->input.status = byte[0];
       HW_TRACE ((me, "write - input-status %d\n", byte[0]));
       break;
+
     case hw_pal_write_fifo:
       write_hw_pal (me, byte[0]);
       HW_TRACE ((me, "write - output-fifo %d\n", byte[0]));
       break;
+
     case hw_pal_write_status:
       hw_pal->output.status = byte[0];
       HW_TRACE ((me, "write - output-status %d\n", byte[0]));
       break;
+
+    case hw_pal_countdown:
+      do_counter_write (me, hw_pal, "countdown",
+                       &hw_pal->countdown, source, nr_bytes);
+      break;
+
+    case hw_pal_timer:
+      do_counter_write (me, hw_pal, "timer",
+                       &hw_pal->timer, source, nr_bytes);
+      break;
+
     }
   return nr_bytes;
 }
@@ -279,7 +479,7 @@ hw_pal_io_write_buffer (struct hw *me,
 
 #if NOT_YET
 static void
-hw_pal_instance_delete_callback(hw_instance *instance)
+hw_pal_instance_delete_callback (hw_instance *instance)
 {
   /* nothing to delete, the hw_pal is attached to the struct hw */
   return;
@@ -335,11 +535,6 @@ hw_pal_create_instance (struct hw *me,
 }
 #endif
 
-static const struct hw_port_descriptor hw_pal_ports[] = {
-  { "int", 0, MAX_NR_PROCESSORS },
-  { NULL }
-};
-
 
 static void
 hw_pal_attach_address (struct hw *me,
@@ -386,11 +581,23 @@ hw_pal_finish (struct hw *hw)
   set_hw_io_write_buffer (hw, hw_pal_io_write_buffer);
   set_hw_ports (hw, hw_pal_ports);
   /* attach ourselves */
-  do_hw_attach_regs (me);
+  do_hw_attach_regs (hw);
+  /* If so configured, enable polled input */
+  if (hw_find_property (hw, "poll?") != NULL
+      && hw_find_boolean_property (hw, "poll?"))
+    {
+      hw_pal->reader = sim_io_poll_read;
+    }
+  else
+    {
+      hw_pal->reader = sim_io_read;
+    }
+  /* tag the periodic timer */
+  hw_pal->timer.periodic_p = 1;
 }
 
 
-const struct hw_device_descriptor dv_pal_descriptor[] = {
+const struct hw_descriptor dv_pal_descriptor[] = {
   { "pal", hw_pal_finish, },
-  { NULL },
+  { NULL, NULL },
 };
This page took 0.04504 seconds and 4 git commands to generate.