1/* The common simulator framework for GDB, the GNU Debugger.
2
3   Copyright 2002, 2007 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  max_nr_ports = 2048,
158};
159
160enum hw_glue_type {
161  glue_undefined = 0,
162  glue_io,
163  glue_and,
164  glue_nand,
165  glue_or,
166  glue_xor,
167  glue_nor,
168  glue_not,
169};
170
171struct hw_glue {
172  enum hw_glue_type type;
173  int int_number;
174  int *input;
175  int nr_inputs;
176  unsigned sizeof_input;
177  /* our output registers */
178  int space;
179  unsigned_word address;
180  unsigned sizeof_output;
181  int *output;
182  int nr_outputs;
183};
184
185
186static hw_io_read_buffer_method hw_glue_io_read_buffer;
187static hw_io_write_buffer_method hw_glue_io_write_buffer;
188static hw_port_event_method hw_glue_port_event;
189const static struct hw_port_descriptor hw_glue_ports[];
190
191static void
192hw_glue_finish (struct hw *me)
193{
194  struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
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  {
208    reg_property_spec unit;
209    int reg_nr;
210    /* find a relevant reg entry */
211    reg_nr = 0;
212    while (hw_find_reg_array_property (me, "reg", reg_nr, &unit)
213	   && !hw_unit_size_to_attach_size (hw_parent (me),
214					    &unit.size,
215					    &glue->sizeof_output,
216					    me))
217      reg_nr++;
218    /* check out the size */
219    if (glue->sizeof_output == 0)
220      hw_abort (me, "at least one reg property size must be nonzero");
221    if (glue->sizeof_output % sizeof (unsigned_word) != 0)
222      hw_abort (me, "reg property size must be %ld aligned",
223		(long) sizeof (unsigned_word));
224    /* and the address */
225    hw_unit_address_to_attach_address (hw_parent (me),
226				       &unit.address,
227				       &glue->space,
228				       &glue->address,
229				       me);
230    if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0)
231      hw_abort (me, "reg property address must be %ld aligned",
232		(long) (sizeof (unsigned_word) * max_nr_ports));
233    glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word);
234    glue->output = hw_zalloc (me, glue->sizeof_output);
235  }
236
237  /* establish the input ports */
238  {
239    const struct hw_property *ranges;
240    ranges = hw_find_property (me, "interrupt-ranges");
241    if (ranges == NULL)
242      {
243	glue->int_number = 0;
244	glue->nr_inputs = glue->nr_outputs;
245      }
246    else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2)
247      {
248	hw_abort (me, "invalid interrupt-ranges property (incorrect size)");
249      }
250    else
251      {
252	const unsigned_cell *int_range = ranges->array;
253	glue->int_number = BE2H_cell (int_range[0]);
254	glue->nr_inputs = BE2H_cell (int_range[1]);
255      }
256    glue->sizeof_input = glue->nr_inputs * sizeof (unsigned);
257    glue->input = hw_zalloc (me, glue->sizeof_input);
258  }
259
260  /* determine our type */
261  {
262    const char *name = hw_name(me);
263    if (strcmp (name, "glue") == 0)
264      glue->type = glue_io;
265    else if (strcmp (name, "glue-and") == 0)
266      glue->type = glue_and;
267    else
268      hw_abort (me, "unimplemented glue type");
269  }
270
271  HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d",
272	     glue->int_number, glue->nr_inputs, glue->nr_outputs));
273}
274
275static unsigned
276hw_glue_io_read_buffer (struct hw *me,
277			void *dest,
278			int space,
279			unsigned_word addr,
280			unsigned nr_bytes)
281{
282  struct hw_glue *glue = (struct hw_glue *) hw_data (me);
283  int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs;
284  if (nr_bytes != sizeof (unsigned_word)
285      || (addr % sizeof (unsigned_word)) != 0)
286    hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported",
287	      space, (unsigned long)addr, nr_bytes);
288  *(unsigned_word*)dest = H2BE_4(glue->output[reg]);
289  HW_TRACE ((me, "read - port %d (0x%lx), level %d",
290	     reg, (unsigned long) addr, glue->output[reg]));
291  return nr_bytes;
292}
293
294
295static unsigned
296hw_glue_io_write_buffer (struct hw *me,
297			 const void *source,
298			 int space,
299			 unsigned_word addr,
300			 unsigned nr_bytes)
301{
302  struct hw_glue *glue = (struct hw_glue *) hw_data (me);
303  int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports;
304  if (nr_bytes != sizeof (unsigned_word)
305      || (addr % sizeof (unsigned_word)) != 0)
306    hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported",
307	      space, (unsigned long) addr, nr_bytes);
308  glue->output[reg] = H2BE_4 (*(unsigned_word*)source);
309  HW_TRACE ((me, "write - port %d (0x%lx), level %d",
310	     reg, (unsigned long) addr, glue->output[reg]));
311  hw_port_event (me, reg, glue->output[reg]);
312  return nr_bytes;
313}
314
315static void
316hw_glue_port_event (struct hw *me,
317		    int my_port,
318		    struct hw *source,
319		    int source_port,
320		    int level)
321{
322  struct hw_glue *glue = (struct hw_glue *) hw_data (me);
323  int i;
324  if (my_port < glue->int_number
325      || my_port >= glue->int_number + glue->nr_inputs)
326    hw_abort (me, "port %d outside of valid range", my_port);
327  glue->input[my_port - glue->int_number] = level;
328  switch (glue->type)
329    {
330    case glue_io:
331      {
332	int port = my_port % glue->nr_outputs;
333	glue->output[port] = level;
334	HW_TRACE ((me, "input - port %d (0x%lx), level %d",
335		   my_port,
336		   (unsigned long) glue->address + port * sizeof (unsigned_word),
337		   level));
338	break;
339      }
340    case glue_and:
341      {
342	glue->output[0] = glue->input[0];
343	for (i = 1; i < glue->nr_inputs; i++)
344	  glue->output[0] &= glue->input[i];
345	HW_TRACE ((me, "and - port %d, level %d arrived - output %d",
346		   my_port, level, glue->output[0]));
347	hw_port_event (me, 0, glue->output[0]);
348	break;
349      }
350    default:
351      {
352	hw_abort (me, "operator not implemented");
353	break;
354      }
355    }
356}
357
358
359static const struct hw_port_descriptor hw_glue_ports[] = {
360  { "int", 0, max_nr_ports },
361  { NULL }
362};
363
364
365const struct hw_descriptor dv_glue_descriptor[] = {
366  { "glue", hw_glue_finish, },
367  { "glue-and", hw_glue_finish, },
368  { "glue-nand", hw_glue_finish, },
369  { "glue-or", hw_glue_finish, },
370  { "glue-xor", hw_glue_finish, },
371  { "glue-nor", hw_glue_finish, },
372  { "glue-not", hw_glue_finish, },
373  { NULL },
374};
375