* dv-pal.c (hw_pal_countdown, hw_pal_countdown_value,
authorAndrew Cagney <cagney@redhat.com>
Wed, 25 Mar 1998 03:44:37 +0000 (03:44 +0000)
committerAndrew Cagney <cagney@redhat.com>
Wed, 25 Mar 1998 03:44:37 +0000 (03:44 +0000)
hw_pal_timer, hw_pal_timer_value): Define.
(hw_pal_io_read_buffer, hw_pal_io_write_buffer): Add timer support
(do_counter_event, do_counter_read, do_counter_value,
do_counter_write): new functions.

* hw-tree.c (hw_printf): Send tree dump to stderr, same as other
trace output.
* hw-base.c (hw_create): Stop searching for a device when one is
found.

sim/common/ChangeLog
sim/common/dv-pal.c
sim/common/hw-tree.c

index c98617cd5d361484881f0ced6a054b128b7ff7ff..d64b7b455e5628d6bb92cc18933a9d9cdab9670d 100644 (file)
@@ -1,3 +1,19 @@
+Wed Mar 25 09:18:34 1998  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * dv-pal.c (hw_pal_countdown, hw_pal_countdown_value,
+       hw_pal_timer, hw_pal_timer_value): Define.
+       (hw_pal_io_read_buffer, hw_pal_io_write_buffer): Add timer support
+       (do_counter_event, do_counter_read, do_counter_value,
+       do_counter_write): new functions.
+
+Tue Mar 24 12:24:24 1998  Andrew Cagney  <cagney@b1.cygnus.com>
+
+       * hw-tree.c (hw_printf): Send tree dump to stderr, same as other
+       trace output.
+
+       * hw-base.c (hw_create): Stop searching for a device when one is
+       found.
+
 Wed Mar 25 12:35:29 1998  Andrew Cagney  <cagney@b1.cygnus.com>
 
        * configure: Regenerated to track ../common/aclocal.m4 changes.
index c98ff6860f10336b389a1c0e8494d66fedfaeb74..95554aab842ce1744dfd2673b2659726d6d1f81a 100644 (file)
    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.
+   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 register (read) returns the processor number (0
-   .. N-1) of the processor performing the read.
+   PROCESSOR ID (read): returns the processor identifier (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
+   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 (read): returns the total number of processors
+   active in the current simulation.
 
-   Processor count register (read) returns the total number of
-   processors active in the current simulation.
+   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.
 
-   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 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.
 
-   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.
+   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.
 
 
    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 +166,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 = 0x2f,
 };
 
 
@@ -135,12 +179,118 @@ typedef struct _hw_pal_console_buffer {
   int status;
 } hw_pal_console_buffer;
 
+typedef struct _hw_pal_counter {
+  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;
 } 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 }
+};
+
+
+/* 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, NULL, NULL_CIA);
+      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, NULL, NULL_CIA);
+    }
+}
+
+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
@@ -168,6 +318,7 @@ scan_hw_pal (struct hw *me)
 }
 
 /* write the character to the hw_pal */
+
 static void
 write_hw_pal (struct hw *me,
              char val)
@@ -179,6 +330,8 @@ write_hw_pal (struct hw *me,
 }
 
 
+/* Reads/writes */
+
 static unsigned
 hw_pal_io_read_buffer (struct hw *me,
                       void *dest,
@@ -189,44 +342,71 @@ hw_pal_io_read_buffer (struct hw *me,
                       sim_cia cia)
 {
   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);
+      *byte = CPU_INDEX (cpu);
 #else
-      val = 0;
+      *byte = 0;
 #endif
-      HW_TRACE ((me, "read - cpu-nr %d\n", val));
+      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));
+      *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;
 }
 
@@ -241,35 +421,52 @@ hw_pal_io_write_buffer (struct hw *me,
                        sim_cia cia)
 {
   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]);
+      sim_engine_halt (hw_system (me), cpu, NULL, cia, sim_exited, byte[0]);
       break;
+
     case hw_pal_int_register:
       hw_port_event (me,
-                    byte[0], /*port*/
+                    INT_PORT + byte[0], /*port*/
                     (nr_bytes > 1 ? byte[1] : 0), /* val */
                     cpu, cia);
       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;
 }
@@ -335,11 +532,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,7 +578,10 @@ 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);
+
+  /* tag the periodic timer */
+  hw_pal->timer.periodic_p = 1;
 }
 
 
index 219b75b28600458684a2f5089d4d96e9ec39bbd9..da9cc57874e1ff07062a5a6c62de04b21be5148d 100644 (file)
@@ -831,10 +831,13 @@ hw_tree_parse (struct hw *current,
            char *dest_hw_name = split_value (&spec);
            struct hw *dest;
            /* find my name */
-           my_port = hw_port_decode (current, my_port_name,
-                                     output_port);
+           if (!hw_finished_p (current))
+             hw_finish (current);
+           my_port = hw_port_decode (current, my_port_name, output_port);
            /* find the dest device and port */
-           dest = split_fill_path(current, dest_hw_name, &dest_spec);
+           dest = split_fill_path (current, dest_hw_name, &dest_spec);
+           if (!hw_finished_p (dest))
+             hw_finish (dest);
            dest_port = hw_port_decode (dest, dest_port_name,
                                        input_port);
            /* connect the two */
@@ -981,7 +984,7 @@ hw_printf (struct hw *me,
 {
   va_list ap;
   va_start (ap, fmt);
-  sim_io_vprintf (hw_system (me), fmt, ap);
+  sim_io_evprintf (hw_system (me), fmt, ap);
   va_end (ap);
 }