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