xref: /netbsd-src/external/gpl3/gdb/dist/sim/common/dv-glue.c (revision 88241920d21b339bf319c0e979ffda80c49a2936)
198b9484cSchristos /* The common simulator framework for GDB, the GNU Debugger.
298b9484cSchristos 
3*88241920Schristos    Copyright 2002-2024 Free Software Foundation, Inc.
498b9484cSchristos 
598b9484cSchristos    Contributed by Andrew Cagney and Red Hat.
698b9484cSchristos 
798b9484cSchristos    This file is part of GDB.
898b9484cSchristos 
998b9484cSchristos    This program is free software; you can redistribute it and/or modify
1098b9484cSchristos    it under the terms of the GNU General Public License as published by
1198b9484cSchristos    the Free Software Foundation; either version 3 of the License, or
1298b9484cSchristos    (at your option) any later version.
1398b9484cSchristos 
1498b9484cSchristos    This program is distributed in the hope that it will be useful,
1598b9484cSchristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1698b9484cSchristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1798b9484cSchristos    GNU General Public License for more details.
1898b9484cSchristos 
1998b9484cSchristos    You should have received a copy of the GNU General Public License
2098b9484cSchristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
2198b9484cSchristos 
224b169a6bSchristos /* This must come before any other includes.  */
234b169a6bSchristos #include "defs.h"
244b169a6bSchristos 
254b169a6bSchristos #include <string.h>
2698b9484cSchristos 
2798b9484cSchristos #include "hw-main.h"
2898b9484cSchristos 
2998b9484cSchristos /* DEVICE
3098b9484cSchristos 
3198b9484cSchristos 
3298b9484cSchristos    glue - glue to interconnect and test hardware ports
3398b9484cSchristos 
3498b9484cSchristos 
3598b9484cSchristos    DESCRIPTION
3698b9484cSchristos 
3798b9484cSchristos 
3898b9484cSchristos    The glue device provides two functions.  Firstly, it provides a
3998b9484cSchristos    mechanism for inspecting and driving the port network.  Secondly,
4098b9484cSchristos    it provides a set of boolean primitives that can be used to apply
4198b9484cSchristos    combinatorial operations to the port network.
4298b9484cSchristos 
4398b9484cSchristos    Glue devices have a variable number of big endian <<output>>
4498b9484cSchristos    registers.  Each register is target-word sized.  The registers can
4598b9484cSchristos    be read and written.
4698b9484cSchristos 
4798b9484cSchristos    Writing to an output register results in an event being driven
4898b9484cSchristos    (level determined by the value written) on the devices
4998b9484cSchristos    corresponding output port.
5098b9484cSchristos 
5198b9484cSchristos    Reading an <<output>> register returns either the last value
5298b9484cSchristos    written or the most recently computed value (for that register) as
5398b9484cSchristos    a result of an event ariving on that port (which ever was computed
5498b9484cSchristos    last).
5598b9484cSchristos 
5698b9484cSchristos    At present the following sub device types are available:
5798b9484cSchristos 
5898b9484cSchristos    <<glue>>: In addition to driving its output interrupt port with any
5998b9484cSchristos    value written to an interrupt input port is stored in the
6098b9484cSchristos    corresponding <<output>> register.  Such input interrupts, however,
6198b9484cSchristos    are not propogated to an output interrupt port.
6298b9484cSchristos 
6398b9484cSchristos    <<glue-and>>: The bit-wise AND of the interrupt inputs is computed
6498b9484cSchristos    and then both stored in <<output>> register zero and propogated to
6598b9484cSchristos    output interrupt output port zero.
6698b9484cSchristos 
6798b9484cSchristos 
6898b9484cSchristos    PROPERTIES
6998b9484cSchristos 
7098b9484cSchristos 
7198b9484cSchristos    reg = <address> <size> (required)
7298b9484cSchristos 
7398b9484cSchristos    Specify the address (within the parent bus) that this device is to
7498b9484cSchristos    live.  The address must be 2048 * sizeof (word) (8k in a 32bit
7598b9484cSchristos    simulation) aligned.
7698b9484cSchristos 
7798b9484cSchristos 
7898b9484cSchristos    interrupt-ranges = <int-number> <range> (optional)
7998b9484cSchristos 
8098b9484cSchristos    If present, this specifies the number of valid interrupt inputs (up
8198b9484cSchristos    to the maximum of 2048).  By default, <<int-number>> is zero and
8298b9484cSchristos    range is determined by the <<reg>> size.
8398b9484cSchristos 
8498b9484cSchristos 
8598b9484cSchristos    PORTS
8698b9484cSchristos 
8798b9484cSchristos 
8898b9484cSchristos    int[0..] (input, output)
8998b9484cSchristos 
9098b9484cSchristos    Both an input and an output port.
9198b9484cSchristos 
9298b9484cSchristos 
9398b9484cSchristos    EXAMPLES
9498b9484cSchristos 
9598b9484cSchristos 
9698b9484cSchristos    Enable tracing of the device:
9798b9484cSchristos 
9898b9484cSchristos    | -t glue-device \
9998b9484cSchristos 
10098b9484cSchristos 
10198b9484cSchristos    Create source, bitwize-and, and sink glue devices.  Since the
10298b9484cSchristos    device at address <<0x10000>> is of size <<8>> it will have two
10398b9484cSchristos    output interrupt ports.
10498b9484cSchristos 
10598b9484cSchristos    | -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \
10698b9484cSchristos    | -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \
10798b9484cSchristos    | -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \
10898b9484cSchristos    | -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \
10998b9484cSchristos 
11098b9484cSchristos 
11198b9484cSchristos    Wire the two source interrupts to the AND device:
11298b9484cSchristos 
11398b9484cSchristos    | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
11498b9484cSchristos    | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
11598b9484cSchristos 
11698b9484cSchristos 
11798b9484cSchristos    Wire the AND device up to the sink so that the and's output is not
11898b9484cSchristos    left open.
11998b9484cSchristos 
12098b9484cSchristos    | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
12198b9484cSchristos 
12298b9484cSchristos 
12398b9484cSchristos    With the above configuration.  The client program is able to
12498b9484cSchristos    compute a two bit AND.  For instance the <<C>> stub below prints 1
12598b9484cSchristos    AND 0.
12698b9484cSchristos 
12798b9484cSchristos    |  unsigned *input = (void*)0xf0010000;
12898b9484cSchristos    |  unsigned *output = (void*)0xf0030000;
12998b9484cSchristos    |  unsigned ans;
13098b9484cSchristos    |  input[0] = htonl(1);
13198b9484cSchristos    |  input[1] = htonl(0);
13298b9484cSchristos    |  ans = ntohl(*output);
13398b9484cSchristos    |  write_string("AND is ");
13498b9484cSchristos    |  write_int(ans);
13598b9484cSchristos    |  write_line();
13698b9484cSchristos 
13798b9484cSchristos 
13898b9484cSchristos    BUGS
13998b9484cSchristos 
14098b9484cSchristos 
14198b9484cSchristos    A future implementation of this device may support multiple
14298b9484cSchristos    interrupt ranges.
14398b9484cSchristos 
14498b9484cSchristos    Some of the devices listed may not yet be fully implemented.
14598b9484cSchristos 
14698b9484cSchristos    Additional devices such as a D flip-flop (DFF), an inverter (INV)
14798b9484cSchristos    or a latch (LAT) may prove useful.
14898b9484cSchristos 
14998b9484cSchristos    */
15098b9484cSchristos 
15198b9484cSchristos 
15298b9484cSchristos enum
15398b9484cSchristos {
15498b9484cSchristos   max_nr_ports = 2048,
15598b9484cSchristos };
15698b9484cSchristos 
15798b9484cSchristos enum hw_glue_type
15898b9484cSchristos {
15998b9484cSchristos   glue_undefined = 0,
16098b9484cSchristos   glue_io,
16198b9484cSchristos   glue_and,
16298b9484cSchristos   glue_nand,
16398b9484cSchristos   glue_or,
16498b9484cSchristos   glue_xor,
16598b9484cSchristos   glue_nor,
16698b9484cSchristos   glue_not,
16798b9484cSchristos };
16898b9484cSchristos 
16998b9484cSchristos struct hw_glue
17098b9484cSchristos {
17198b9484cSchristos   enum hw_glue_type type;
17298b9484cSchristos   int int_number;
17398b9484cSchristos   int *input;
17498b9484cSchristos   int nr_inputs;
17598b9484cSchristos   unsigned sizeof_input;
17698b9484cSchristos   /* our output registers */
17798b9484cSchristos   int space;
17898b9484cSchristos   unsigned_word address;
17998b9484cSchristos   unsigned sizeof_output;
18098b9484cSchristos   int *output;
18198b9484cSchristos   int nr_outputs;
18298b9484cSchristos };
18398b9484cSchristos 
18498b9484cSchristos 
18598b9484cSchristos static hw_io_read_buffer_method hw_glue_io_read_buffer;
18698b9484cSchristos static hw_io_write_buffer_method hw_glue_io_write_buffer;
18798b9484cSchristos static hw_port_event_method hw_glue_port_event;
18898b9484cSchristos static const struct hw_port_descriptor hw_glue_ports[];
18998b9484cSchristos 
19098b9484cSchristos static void
19198b9484cSchristos hw_glue_finish (struct hw *me)
19298b9484cSchristos {
19398b9484cSchristos   struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
194a2e2270fSchristos   const char *name = hw_name (me);
19598b9484cSchristos 
19698b9484cSchristos   /* establish our own methods */
19798b9484cSchristos   set_hw_data (me, glue);
19898b9484cSchristos   set_hw_io_read_buffer (me, hw_glue_io_read_buffer);
19998b9484cSchristos   set_hw_io_write_buffer (me, hw_glue_io_write_buffer);
20098b9484cSchristos   set_hw_ports (me, hw_glue_ports);
20198b9484cSchristos   set_hw_port_event (me, hw_glue_port_event);
20298b9484cSchristos 
20398b9484cSchristos   /* attach to our parent bus */
20498b9484cSchristos   do_hw_attach_regs (me);
20598b9484cSchristos 
20698b9484cSchristos   /* establish the output registers */
207a2e2270fSchristos   if (hw_find_property (me, "reg"))
20898b9484cSchristos     {
20998b9484cSchristos       reg_property_spec unit;
21098b9484cSchristos       int reg_nr;
21198b9484cSchristos 
212a2e2270fSchristos       /* Find a relevant reg entry.  */
21398b9484cSchristos       reg_nr = 0;
21498b9484cSchristos       while (hw_find_reg_array_property (me, "reg", reg_nr, &unit)
21598b9484cSchristos 	     && !hw_unit_size_to_attach_size (hw_parent (me),
21698b9484cSchristos 					      &unit.size,
21798b9484cSchristos 					      &glue->sizeof_output,
21898b9484cSchristos 					      me))
21998b9484cSchristos 	reg_nr++;
22098b9484cSchristos 
221a2e2270fSchristos       /* Check out the size ...  */
22298b9484cSchristos       if (glue->sizeof_output == 0)
22398b9484cSchristos 	hw_abort (me, "at least one reg property size must be nonzero");
22498b9484cSchristos       if (glue->sizeof_output % sizeof (unsigned_word) != 0)
22598b9484cSchristos 	hw_abort (me, "reg property size must be %ld aligned",
22698b9484cSchristos 		  (long) sizeof (unsigned_word));
22798b9484cSchristos 
228a2e2270fSchristos       /* ... and the address.  */
22998b9484cSchristos       hw_unit_address_to_attach_address (hw_parent (me),
23098b9484cSchristos 					 &unit.address,
23198b9484cSchristos 					 &glue->space,
23298b9484cSchristos 					 &glue->address,
23398b9484cSchristos 					 me);
23498b9484cSchristos       if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0)
23598b9484cSchristos 	hw_abort (me, "reg property address must be %ld aligned",
23698b9484cSchristos 		  (long) (sizeof (unsigned_word) * max_nr_ports));
23798b9484cSchristos 
23898b9484cSchristos       glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word);
23998b9484cSchristos     }
240a2e2270fSchristos   else
241a2e2270fSchristos     {
242a2e2270fSchristos       /* Allow bitwise glue devices to declare only ports.  */
243a2e2270fSchristos       if (!strcmp (name, "glue"))
244a2e2270fSchristos 	hw_abort (me, "Missing \"reg\" property");
245a2e2270fSchristos 
246a2e2270fSchristos       glue->nr_outputs = 1;
247a2e2270fSchristos       glue->sizeof_output = sizeof (unsigned_word);
248a2e2270fSchristos     }
249a2e2270fSchristos   glue->output = hw_zalloc (me, glue->sizeof_output);
25098b9484cSchristos 
25198b9484cSchristos   /* establish the input ports */
25298b9484cSchristos   {
25398b9484cSchristos     const struct hw_property *ranges;
25498b9484cSchristos 
25598b9484cSchristos     ranges = hw_find_property (me, "interrupt-ranges");
25698b9484cSchristos     if (ranges == NULL)
25798b9484cSchristos       {
25898b9484cSchristos 	glue->int_number = 0;
25998b9484cSchristos 	glue->nr_inputs = glue->nr_outputs;
26098b9484cSchristos       }
26198b9484cSchristos     else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2)
26298b9484cSchristos       {
26398b9484cSchristos 	hw_abort (me, "invalid interrupt-ranges property (incorrect size)");
26498b9484cSchristos       }
26598b9484cSchristos     else
26698b9484cSchristos       {
26798b9484cSchristos 	const unsigned_cell *int_range = ranges->array;
26898b9484cSchristos 
26998b9484cSchristos 	glue->int_number = BE2H_cell (int_range[0]);
27098b9484cSchristos 	glue->nr_inputs = BE2H_cell (int_range[1]);
27198b9484cSchristos       }
27298b9484cSchristos     glue->sizeof_input = glue->nr_inputs * sizeof (unsigned);
27398b9484cSchristos     glue->input = hw_zalloc (me, glue->sizeof_input);
27498b9484cSchristos   }
27598b9484cSchristos 
27698b9484cSchristos   /* determine our type */
27798b9484cSchristos   if (strcmp (name, "glue") == 0)
27898b9484cSchristos     glue->type = glue_io;
27998b9484cSchristos   else if (strcmp (name, "glue-and") == 0)
28098b9484cSchristos     glue->type = glue_and;
281a2e2270fSchristos   else if (strcmp (name, "glue-or") == 0)
282a2e2270fSchristos     glue->type = glue_or;
283a2e2270fSchristos   else if (strcmp (name, "glue-xor") == 0)
284a2e2270fSchristos     glue->type = glue_xor;
28598b9484cSchristos   else
28698b9484cSchristos     hw_abort (me, "unimplemented glue type");
28798b9484cSchristos 
28898b9484cSchristos   HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d",
28998b9484cSchristos 	     glue->int_number, glue->nr_inputs, glue->nr_outputs));
29098b9484cSchristos }
29198b9484cSchristos 
29298b9484cSchristos static unsigned
29398b9484cSchristos hw_glue_io_read_buffer (struct hw *me,
29498b9484cSchristos 			void *dest,
29598b9484cSchristos 			int space,
29698b9484cSchristos 			unsigned_word addr,
29798b9484cSchristos 			unsigned nr_bytes)
29898b9484cSchristos {
29998b9484cSchristos   struct hw_glue *glue = (struct hw_glue *) hw_data (me);
30098b9484cSchristos   int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs;
30198b9484cSchristos 
30298b9484cSchristos   if (nr_bytes != sizeof (unsigned_word)
30398b9484cSchristos       || (addr % sizeof (unsigned_word)) != 0)
30498b9484cSchristos     hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported",
30598b9484cSchristos 	      space, (unsigned long)addr, nr_bytes);
30698b9484cSchristos 
30798b9484cSchristos   *(unsigned_word *)dest = H2BE_4 (glue->output[reg]);
30898b9484cSchristos 
30998b9484cSchristos   HW_TRACE ((me, "read - port %d (0x%lx), level %d",
31098b9484cSchristos 	     reg, (unsigned long) addr, glue->output[reg]));
31198b9484cSchristos 
31298b9484cSchristos   return nr_bytes;
31398b9484cSchristos }
31498b9484cSchristos 
31598b9484cSchristos 
31698b9484cSchristos static unsigned
31798b9484cSchristos hw_glue_io_write_buffer (struct hw *me,
31898b9484cSchristos 			 const void *source,
31998b9484cSchristos 			 int space,
32098b9484cSchristos 			 unsigned_word addr,
32198b9484cSchristos 			 unsigned nr_bytes)
32298b9484cSchristos {
32398b9484cSchristos   struct hw_glue *glue = (struct hw_glue *) hw_data (me);
32498b9484cSchristos   int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports;
32598b9484cSchristos 
32698b9484cSchristos   if (nr_bytes != sizeof (unsigned_word)
32798b9484cSchristos       || (addr % sizeof (unsigned_word)) != 0)
32898b9484cSchristos     hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported",
32998b9484cSchristos 	      space, (unsigned long) addr, nr_bytes);
33098b9484cSchristos 
33198b9484cSchristos   glue->output[reg] = H2BE_4 (*(unsigned_word *)source);
33298b9484cSchristos 
33398b9484cSchristos   HW_TRACE ((me, "write - port %d (0x%lx), level %d",
33498b9484cSchristos 	     reg, (unsigned long) addr, glue->output[reg]));
33598b9484cSchristos 
33698b9484cSchristos   hw_port_event (me, reg, glue->output[reg]);
33798b9484cSchristos 
33898b9484cSchristos   return nr_bytes;
33998b9484cSchristos }
34098b9484cSchristos 
34198b9484cSchristos static void
34298b9484cSchristos hw_glue_port_event (struct hw *me,
34398b9484cSchristos 		    int my_port,
34498b9484cSchristos 		    struct hw *source,
34598b9484cSchristos 		    int source_port,
34698b9484cSchristos 		    int level)
34798b9484cSchristos {
34898b9484cSchristos   struct hw_glue *glue = (struct hw_glue *) hw_data (me);
34998b9484cSchristos   int i;
35098b9484cSchristos 
35198b9484cSchristos   if (my_port < glue->int_number
35298b9484cSchristos       || my_port >= glue->int_number + glue->nr_inputs)
35398b9484cSchristos     hw_abort (me, "port %d outside of valid range", my_port);
35498b9484cSchristos 
35598b9484cSchristos   glue->input[my_port - glue->int_number] = level;
35698b9484cSchristos   switch (glue->type)
35798b9484cSchristos     {
35898b9484cSchristos     case glue_io:
35998b9484cSchristos       {
36098b9484cSchristos 	int port = my_port % glue->nr_outputs;
36198b9484cSchristos 
36298b9484cSchristos 	glue->output[port] = level;
36398b9484cSchristos 
36498b9484cSchristos 	HW_TRACE ((me, "input - port %d (0x%lx), level %d",
36598b9484cSchristos 		   my_port,
36698b9484cSchristos 		   (unsigned long) glue->address + port * sizeof (unsigned_word),
36798b9484cSchristos 		   level));
368a2e2270fSchristos 	return;
36998b9484cSchristos       }
37098b9484cSchristos     case glue_and:
37198b9484cSchristos       {
37298b9484cSchristos 	glue->output[0] = glue->input[0];
37398b9484cSchristos 	for (i = 1; i < glue->nr_inputs; i++)
37498b9484cSchristos 	  glue->output[0] &= glue->input[i];
375a2e2270fSchristos 	break;
376a2e2270fSchristos       }
377a2e2270fSchristos     case glue_or:
378a2e2270fSchristos       {
379a2e2270fSchristos 	glue->output[0] = glue->input[0];
380a2e2270fSchristos 	for (i = 1; i < glue->nr_inputs; i++)
381a2e2270fSchristos 	  glue->output[0] |= glue->input[i];
382a2e2270fSchristos 	break;
383a2e2270fSchristos       }
384a2e2270fSchristos     case glue_xor:
385a2e2270fSchristos       {
386a2e2270fSchristos 	glue->output[0] = glue->input[0];
387a2e2270fSchristos 	for (i = 1; i < glue->nr_inputs; i++)
388a2e2270fSchristos 	  glue->output[0] ^= glue->input[i];
38998b9484cSchristos 	break;
39098b9484cSchristos       }
39198b9484cSchristos     default:
39298b9484cSchristos       {
39398b9484cSchristos 	hw_abort (me, "operator not implemented");
394a2e2270fSchristos 	return;
39598b9484cSchristos       }
39698b9484cSchristos     }
397a2e2270fSchristos 
398a2e2270fSchristos   /* If we fell through, we want to generate a port event.  */
399a2e2270fSchristos   HW_TRACE ((me, "port %d, level %d arrived - output %d",
400a2e2270fSchristos 	     my_port, level, glue->output[0]));
401a2e2270fSchristos 
402a2e2270fSchristos   hw_port_event (me, 0, glue->output[0]);
40398b9484cSchristos }
40498b9484cSchristos 
40598b9484cSchristos 
40698b9484cSchristos static const struct hw_port_descriptor hw_glue_ports[] =
40798b9484cSchristos {
40898b9484cSchristos   { "int", 0, max_nr_ports, 0 },
40998b9484cSchristos   { NULL, 0, 0, 0 }
41098b9484cSchristos };
41198b9484cSchristos 
41298b9484cSchristos 
41398b9484cSchristos const struct hw_descriptor dv_glue_descriptor[] =
41498b9484cSchristos {
41598b9484cSchristos   { "glue", hw_glue_finish, },
41698b9484cSchristos   { "glue-and", hw_glue_finish, },
41798b9484cSchristos   { "glue-nand", hw_glue_finish, },
41898b9484cSchristos   { "glue-or", hw_glue_finish, },
41998b9484cSchristos   { "glue-xor", hw_glue_finish, },
42098b9484cSchristos   { "glue-nor", hw_glue_finish, },
42198b9484cSchristos   { "glue-not", hw_glue_finish, },
42298b9484cSchristos   { NULL, NULL },
42398b9484cSchristos };
424