]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/dv-glue.c
sim: switch config.h usage to defs.h
[thirdparty/binutils-gdb.git] / sim / common / dv-glue.c
CommitLineData
b85e4829
AC
1/* The common simulator framework for GDB, the GNU Debugger.
2
3666a048 3 Copyright 2002-2021 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 21
6df01ab8
MF
22/* This must come before any other includes. */
23#include "defs.h"
c906108c
SS
24
25#include "hw-main.h"
26
c906108c 27#include <string.h>
c906108c
SS
28
29/* DEVICE
028f6515 30
c906108c
SS
31
32 glue - glue to interconnect and test hardware ports
028f6515 33
c906108c
SS
34
35 DESCRIPTION
028f6515 36
c906108c
SS
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
028f6515 69
c906108c
SS
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
028f6515 87
c906108c
SS
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();
028f6515 136
c906108c
SS
137
138 BUGS
139
028f6515 140
c906108c
SS
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
d45bea91
MF
152enum
153{
c906108c
SS
154 max_nr_ports = 2048,
155};
156
d45bea91
MF
157enum hw_glue_type
158{
c906108c
SS
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
d45bea91
MF
169struct hw_glue
170{
c906108c
SS
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
185static hw_io_read_buffer_method hw_glue_io_read_buffer;
186static hw_io_write_buffer_method hw_glue_io_write_buffer;
187static hw_port_event_method hw_glue_port_event;
59db87ad 188static const struct hw_port_descriptor hw_glue_ports[];
c906108c
SS
189
190static void
191hw_glue_finish (struct hw *me)
192{
193 struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
dd931b2f 194 const char *name = hw_name (me);
028f6515 195
c906108c
SS
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);
028f6515 205
c906108c 206 /* establish the output registers */
dd931b2f
MF
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);
028f6515 250
c906108c
SS
251 /* establish the input ports */
252 {
253 const struct hw_property *ranges;
d45bea91 254
c906108c
SS
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;
d45bea91 268
c906108c
SS
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 }
028f6515 275
c906108c 276 /* determine our type */
dd931b2f
MF
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");
028f6515 287
c906108c
SS
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
292static unsigned
293hw_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;
d45bea91 301
c906108c
SS
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);
d45bea91
MF
306
307 *(unsigned_word *)dest = H2BE_4 (glue->output[reg]);
308
c906108c
SS
309 HW_TRACE ((me, "read - port %d (0x%lx), level %d",
310 reg, (unsigned long) addr, glue->output[reg]));
d45bea91 311
c906108c
SS
312 return nr_bytes;
313}
314
315
316static unsigned
317hw_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;
d45bea91 325
c906108c
SS
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);
d45bea91
MF
330
331 glue->output[reg] = H2BE_4 (*(unsigned_word *)source);
332
c906108c
SS
333 HW_TRACE ((me, "write - port %d (0x%lx), level %d",
334 reg, (unsigned long) addr, glue->output[reg]));
d45bea91 335
c906108c 336 hw_port_event (me, reg, glue->output[reg]);
d45bea91 337
c906108c
SS
338 return nr_bytes;
339}
340
341static void
342hw_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;
d45bea91 350
c906108c
SS
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);
d45bea91 354
c906108c
SS
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;
d45bea91 361
c906108c 362 glue->output[port] = level;
d45bea91 363
c906108c
SS
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));
0e31da21 368 return;
c906108c
SS
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];
0e31da21
MF
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];
c906108c
SS
389 break;
390 }
391 default:
392 {
393 hw_abort (me, "operator not implemented");
0e31da21 394 return;
c906108c
SS
395 }
396 }
0e31da21
MF
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]);
c906108c
SS
403}
404
405
d45bea91
MF
406static const struct hw_port_descriptor hw_glue_ports[] =
407{
21cf617c
MF
408 { "int", 0, max_nr_ports, 0 },
409 { NULL, 0, 0, 0 }
c906108c
SS
410};
411
412
d45bea91
MF
413const struct hw_descriptor dv_glue_descriptor[] =
414{
c906108c
SS
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, },
21cf617c 422 { NULL, NULL },
c906108c 423};