Home | History | Annotate | Line # | Download | only in common
      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 <string.h>
     26 
     27 #include "hw-main.h"
     28 
     29 /* DEVICE
     30 
     31 
     32    glue - glue to interconnect and test hardware ports
     33 
     34 
     35    DESCRIPTION
     36 
     37 
     38    The glue device provides two functions.  Firstly, it provides a
     39    mechanism for inspecting and driving the port network.  Secondly,
     40    it provides a set of boolean primitives that can be used to apply
     41    combinatorial operations to the port network.
     42 
     43    Glue devices have a variable number of big endian <<output>>
     44    registers.  Each register is target-word sized.  The registers can
     45    be read and written.
     46 
     47    Writing to an output register results in an event being driven
     48    (level determined by the value written) on the devices
     49    corresponding output port.
     50 
     51    Reading an <<output>> register returns either the last value
     52    written or the most recently computed value (for that register) as
     53    a result of an event ariving on that port (which ever was computed
     54    last).
     55 
     56    At present the following sub device types are available:
     57 
     58    <<glue>>: In addition to driving its output interrupt port with any
     59    value written to an interrupt input port is stored in the
     60    corresponding <<output>> register.  Such input interrupts, however,
     61    are not propogated to an output interrupt port.
     62 
     63    <<glue-and>>: The bit-wise AND of the interrupt inputs is computed
     64    and then both stored in <<output>> register zero and propogated to
     65    output interrupt output port zero.
     66 
     67 
     68    PROPERTIES
     69 
     70 
     71    reg = <address> <size> (required)
     72 
     73    Specify the address (within the parent bus) that this device is to
     74    live.  The address must be 2048 * sizeof (word) (8k in a 32bit
     75    simulation) aligned.
     76 
     77 
     78    interrupt-ranges = <int-number> <range> (optional)
     79 
     80    If present, this specifies the number of valid interrupt inputs (up
     81    to the maximum of 2048).  By default, <<int-number>> is zero and
     82    range is determined by the <<reg>> size.
     83 
     84 
     85    PORTS
     86 
     87 
     88    int[0..] (input, output)
     89 
     90    Both an input and an output port.
     91 
     92 
     93    EXAMPLES
     94 
     95 
     96    Enable tracing of the device:
     97 
     98    | -t glue-device \
     99 
    100 
    101    Create source, bitwize-and, and sink glue devices.  Since the
    102    device at address <<0x10000>> is of size <<8>> it will have two
    103    output interrupt ports.
    104 
    105    | -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \
    106    | -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \
    107    | -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \
    108    | -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \
    109 
    110 
    111    Wire the two source interrupts to the AND device:
    112 
    113    | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
    114    | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
    115 
    116 
    117    Wire the AND device up to the sink so that the and's output is not
    118    left open.
    119 
    120    | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
    121 
    122 
    123    With the above configuration.  The client program is able to
    124    compute a two bit AND.  For instance the <<C>> stub below prints 1
    125    AND 0.
    126 
    127    |  unsigned *input = (void*)0xf0010000;
    128    |  unsigned *output = (void*)0xf0030000;
    129    |  unsigned ans;
    130    |  input[0] = htonl(1);
    131    |  input[1] = htonl(0);
    132    |  ans = ntohl(*output);
    133    |  write_string("AND is ");
    134    |  write_int(ans);
    135    |  write_line();
    136 
    137 
    138    BUGS
    139 
    140 
    141    A future implementation of this device may support multiple
    142    interrupt ranges.
    143 
    144    Some of the devices listed may not yet be fully implemented.
    145 
    146    Additional devices such as a D flip-flop (DFF), an inverter (INV)
    147    or a latch (LAT) may prove useful.
    148 
    149    */
    150 
    151 
    152 enum
    153 {
    154   max_nr_ports = 2048,
    155 };
    156 
    157 enum hw_glue_type
    158 {
    159   glue_undefined = 0,
    160   glue_io,
    161   glue_and,
    162   glue_nand,
    163   glue_or,
    164   glue_xor,
    165   glue_nor,
    166   glue_not,
    167 };
    168 
    169 struct hw_glue
    170 {
    171   enum hw_glue_type type;
    172   int int_number;
    173   int *input;
    174   int nr_inputs;
    175   unsigned sizeof_input;
    176   /* our output registers */
    177   int space;
    178   unsigned_word address;
    179   unsigned sizeof_output;
    180   int *output;
    181   int nr_outputs;
    182 };
    183 
    184 
    185 static hw_io_read_buffer_method hw_glue_io_read_buffer;
    186 static hw_io_write_buffer_method hw_glue_io_write_buffer;
    187 static hw_port_event_method hw_glue_port_event;
    188 static const struct hw_port_descriptor hw_glue_ports[];
    189 
    190 static void
    191 hw_glue_finish (struct hw *me)
    192 {
    193   struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
    194   const char *name = hw_name (me);
    195 
    196   /* establish our own methods */
    197   set_hw_data (me, glue);
    198   set_hw_io_read_buffer (me, hw_glue_io_read_buffer);
    199   set_hw_io_write_buffer (me, hw_glue_io_write_buffer);
    200   set_hw_ports (me, hw_glue_ports);
    201   set_hw_port_event (me, hw_glue_port_event);
    202 
    203   /* attach to our parent bus */
    204   do_hw_attach_regs (me);
    205 
    206   /* establish the output registers */
    207   if (hw_find_property (me, "reg"))
    208     {
    209       reg_property_spec unit;
    210       int reg_nr;
    211 
    212       /* Find a relevant reg entry.  */
    213       reg_nr = 0;
    214       while (hw_find_reg_array_property (me, "reg", reg_nr, &unit)
    215 	     && !hw_unit_size_to_attach_size (hw_parent (me),
    216 					      &unit.size,
    217 					      &glue->sizeof_output,
    218 					      me))
    219 	reg_nr++;
    220 
    221       /* Check out the size ...  */
    222       if (glue->sizeof_output == 0)
    223 	hw_abort (me, "at least one reg property size must be nonzero");
    224       if (glue->sizeof_output % sizeof (unsigned_word) != 0)
    225 	hw_abort (me, "reg property size must be %ld aligned",
    226 		  (long) sizeof (unsigned_word));
    227 
    228       /* ... and the address.  */
    229       hw_unit_address_to_attach_address (hw_parent (me),
    230 					 &unit.address,
    231 					 &glue->space,
    232 					 &glue->address,
    233 					 me);
    234       if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0)
    235 	hw_abort (me, "reg property address must be %ld aligned",
    236 		  (long) (sizeof (unsigned_word) * max_nr_ports));
    237 
    238       glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word);
    239     }
    240   else
    241     {
    242       /* Allow bitwise glue devices to declare only ports.  */
    243       if (!strcmp (name, "glue"))
    244 	hw_abort (me, "Missing \"reg\" property");
    245 
    246       glue->nr_outputs = 1;
    247       glue->sizeof_output = sizeof (unsigned_word);
    248     }
    249   glue->output = hw_zalloc (me, glue->sizeof_output);
    250 
    251   /* establish the input ports */
    252   {
    253     const struct hw_property *ranges;
    254 
    255     ranges = hw_find_property (me, "interrupt-ranges");
    256     if (ranges == NULL)
    257       {
    258 	glue->int_number = 0;
    259 	glue->nr_inputs = glue->nr_outputs;
    260       }
    261     else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2)
    262       {
    263 	hw_abort (me, "invalid interrupt-ranges property (incorrect size)");
    264       }
    265     else
    266       {
    267 	const unsigned_cell *int_range = ranges->array;
    268 
    269 	glue->int_number = BE2H_cell (int_range[0]);
    270 	glue->nr_inputs = BE2H_cell (int_range[1]);
    271       }
    272     glue->sizeof_input = glue->nr_inputs * sizeof (unsigned);
    273     glue->input = hw_zalloc (me, glue->sizeof_input);
    274   }
    275 
    276   /* determine our type */
    277   if (strcmp (name, "glue") == 0)
    278     glue->type = glue_io;
    279   else if (strcmp (name, "glue-and") == 0)
    280     glue->type = glue_and;
    281   else if (strcmp (name, "glue-or") == 0)
    282     glue->type = glue_or;
    283   else if (strcmp (name, "glue-xor") == 0)
    284     glue->type = glue_xor;
    285   else
    286     hw_abort (me, "unimplemented glue type");
    287 
    288   HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d",
    289 	     glue->int_number, glue->nr_inputs, glue->nr_outputs));
    290 }
    291 
    292 static unsigned
    293 hw_glue_io_read_buffer (struct hw *me,
    294 			void *dest,
    295 			int space,
    296 			unsigned_word addr,
    297 			unsigned nr_bytes)
    298 {
    299   struct hw_glue *glue = (struct hw_glue *) hw_data (me);
    300   int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs;
    301 
    302   if (nr_bytes != sizeof (unsigned_word)
    303       || (addr % sizeof (unsigned_word)) != 0)
    304     hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported",
    305 	      space, (unsigned long)addr, nr_bytes);
    306 
    307   *(unsigned_word *)dest = H2BE_4 (glue->output[reg]);
    308 
    309   HW_TRACE ((me, "read - port %d (0x%lx), level %d",
    310 	     reg, (unsigned long) addr, glue->output[reg]));
    311 
    312   return nr_bytes;
    313 }
    314 
    315 
    316 static unsigned
    317 hw_glue_io_write_buffer (struct hw *me,
    318 			 const void *source,
    319 			 int space,
    320 			 unsigned_word addr,
    321 			 unsigned nr_bytes)
    322 {
    323   struct hw_glue *glue = (struct hw_glue *) hw_data (me);
    324   int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports;
    325 
    326   if (nr_bytes != sizeof (unsigned_word)
    327       || (addr % sizeof (unsigned_word)) != 0)
    328     hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported",
    329 	      space, (unsigned long) addr, nr_bytes);
    330 
    331   glue->output[reg] = H2BE_4 (*(unsigned_word *)source);
    332 
    333   HW_TRACE ((me, "write - port %d (0x%lx), level %d",
    334 	     reg, (unsigned long) addr, glue->output[reg]));
    335 
    336   hw_port_event (me, reg, glue->output[reg]);
    337 
    338   return nr_bytes;
    339 }
    340 
    341 static void
    342 hw_glue_port_event (struct hw *me,
    343 		    int my_port,
    344 		    struct hw *source,
    345 		    int source_port,
    346 		    int level)
    347 {
    348   struct hw_glue *glue = (struct hw_glue *) hw_data (me);
    349   int i;
    350 
    351   if (my_port < glue->int_number
    352       || my_port >= glue->int_number + glue->nr_inputs)
    353     hw_abort (me, "port %d outside of valid range", my_port);
    354 
    355   glue->input[my_port - glue->int_number] = level;
    356   switch (glue->type)
    357     {
    358     case glue_io:
    359       {
    360 	int port = my_port % glue->nr_outputs;
    361 
    362 	glue->output[port] = level;
    363 
    364 	HW_TRACE ((me, "input - port %d (0x%lx), level %d",
    365 		   my_port,
    366 		   (unsigned long) glue->address + port * sizeof (unsigned_word),
    367 		   level));
    368 	return;
    369       }
    370     case glue_and:
    371       {
    372 	glue->output[0] = glue->input[0];
    373 	for (i = 1; i < glue->nr_inputs; i++)
    374 	  glue->output[0] &= glue->input[i];
    375 	break;
    376       }
    377     case glue_or:
    378       {
    379 	glue->output[0] = glue->input[0];
    380 	for (i = 1; i < glue->nr_inputs; i++)
    381 	  glue->output[0] |= glue->input[i];
    382 	break;
    383       }
    384     case glue_xor:
    385       {
    386 	glue->output[0] = glue->input[0];
    387 	for (i = 1; i < glue->nr_inputs; i++)
    388 	  glue->output[0] ^= glue->input[i];
    389 	break;
    390       }
    391     default:
    392       {
    393 	hw_abort (me, "operator not implemented");
    394 	return;
    395       }
    396     }
    397 
    398   /* If we fell through, we want to generate a port event.  */
    399   HW_TRACE ((me, "port %d, level %d arrived - output %d",
    400 	     my_port, level, glue->output[0]));
    401 
    402   hw_port_event (me, 0, glue->output[0]);
    403 }
    404 
    405 
    406 static const struct hw_port_descriptor hw_glue_ports[] =
    407 {
    408   { "int", 0, max_nr_ports, 0 },
    409   { NULL, 0, 0, 0 }
    410 };
    411 
    412 
    413 const struct hw_descriptor dv_glue_descriptor[] =
    414 {
    415   { "glue", hw_glue_finish, },
    416   { "glue-and", hw_glue_finish, },
    417   { "glue-nand", hw_glue_finish, },
    418   { "glue-or", hw_glue_finish, },
    419   { "glue-xor", hw_glue_finish, },
    420   { "glue-nor", hw_glue_finish, },
    421   { "glue-not", hw_glue_finish, },
    422   { NULL, NULL },
    423 };
    424