]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/dv-glue.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / common / dv-glue.c
CommitLineData
b85e4829
AC
1/* The common simulator framework for GDB, the GNU Debugger.
2
8acc9f48 3 Copyright 2002-2013 Free Software Foundation, Inc.
b85e4829
AC
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
4744ac1b 11 the Free Software Foundation; either version 3 of the License, or
b85e4829
AC
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
4744ac1b 20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
c906108c
SS
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
028f6515 34
c906108c
SS
35
36 glue - glue to interconnect and test hardware ports
028f6515 37
c906108c
SS
38
39 DESCRIPTION
028f6515 40
c906108c
SS
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
028f6515 73
c906108c
SS
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
028f6515 91
c906108c
SS
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();
028f6515 140
c906108c
SS
141
142 BUGS
143
028f6515 144
c906108c
SS
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
d45bea91
MF
156enum
157{
c906108c
SS
158 max_nr_ports = 2048,
159};
160
d45bea91
MF
161enum hw_glue_type
162{
c906108c
SS
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
d45bea91
MF
173struct hw_glue
174{
c906108c
SS
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;
59db87ad 192static const struct hw_port_descriptor hw_glue_ports[];
c906108c
SS
193
194static void
195hw_glue_finish (struct hw *me)
196{
197 struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
dd931b2f 198 const char *name = hw_name (me);
028f6515 199
c906108c
SS
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);
028f6515 209
c906108c 210 /* establish the output registers */
dd931b2f
MF
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);
028f6515 254
c906108c
SS
255 /* establish the input ports */
256 {
257 const struct hw_property *ranges;
d45bea91 258
c906108c
SS
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;
d45bea91 272
c906108c
SS
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 }
028f6515 279
c906108c 280 /* determine our type */
dd931b2f
MF
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");
028f6515 291
c906108c
SS
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;
d45bea91 305
c906108c
SS
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);
d45bea91
MF
310
311 *(unsigned_word *)dest = H2BE_4 (glue->output[reg]);
312
c906108c
SS
313 HW_TRACE ((me, "read - port %d (0x%lx), level %d",
314 reg, (unsigned long) addr, glue->output[reg]));
d45bea91 315
c906108c
SS
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;
d45bea91 329
c906108c
SS
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);
d45bea91
MF
334
335 glue->output[reg] = H2BE_4 (*(unsigned_word *)source);
336
c906108c
SS
337 HW_TRACE ((me, "write - port %d (0x%lx), level %d",
338 reg, (unsigned long) addr, glue->output[reg]));
d45bea91 339
c906108c 340 hw_port_event (me, reg, glue->output[reg]);
d45bea91 341
c906108c
SS
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;
d45bea91 354
c906108c
SS
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);
d45bea91 358
c906108c
SS
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;
d45bea91 365
c906108c 366 glue->output[port] = level;
d45bea91 367
c906108c
SS
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));
0e31da21 372 return;
c906108c
SS
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];
0e31da21
MF
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];
c906108c
SS
393 break;
394 }
395 default:
396 {
397 hw_abort (me, "operator not implemented");
0e31da21 398 return;
c906108c
SS
399 }
400 }
0e31da21
MF
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]);
c906108c
SS
407}
408
409
d45bea91
MF
410static const struct hw_port_descriptor hw_glue_ports[] =
411{
21cf617c
MF
412 { "int", 0, max_nr_ports, 0 },
413 { NULL, 0, 0, 0 }
c906108c
SS
414};
415
416
d45bea91
MF
417const struct hw_descriptor dv_glue_descriptor[] =
418{
c906108c
SS
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, },
21cf617c 426 { NULL, NULL },
c906108c 427};