1 /* The common simulator framework for GDB, the GNU Debugger.
3 Copyright 2002-2024 Free Software Foundation, Inc.
5 Contributed by Andrew Cagney and Red Hat.
7 This file is part of GDB.
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.
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.
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/>. */
22 /* This must come before any other includes. */
32 glue - glue to interconnect and test hardware ports
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.
43 Glue devices have a variable number of big endian <<output>>
44 registers. Each register is target-word sized. The registers can
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.
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
56 At present the following sub device types are available:
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.
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.
71 reg = <address> <size> (required)
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
78 interrupt-ranges = <int-number> <range> (optional)
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.
88 int[0..] (input, output)
90 Both an input and an output port.
96 Enable tracing of the device:
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.
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' \
111 Wire the two source interrupts to the AND device:
113 | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
114 | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
117 Wire the AND device up to the sink so that the and's output is not
120 | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
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
127 | unsigned *input = (void*)0xf0010000;
128 | unsigned *output = (void*)0xf0030000;
130 | input[0] = htonl(1);
131 | input[1] = htonl(0);
132 | ans = ntohl(*output);
133 | write_string("AND is ");
141 A future implementation of this device may support multiple
144 Some of the devices listed may not yet be fully implemented.
146 Additional devices such as a D flip-flop (DFF), an inverter (INV)
147 or a latch (LAT) may prove useful.
171 enum hw_glue_type type
;
175 unsigned sizeof_input
;
176 /* our output registers */
178 unsigned_word address
;
179 unsigned sizeof_output
;
185 static hw_io_read_buffer_method hw_glue_io_read_buffer
;
186 static hw_io_write_buffer_method hw_glue_io_write_buffer
;
187 static hw_port_event_method hw_glue_port_event
;
188 static const struct hw_port_descriptor hw_glue_ports
[];
191 hw_glue_finish (struct hw
*me
)
193 struct hw_glue
*glue
= HW_ZALLOC (me
, struct hw_glue
);
194 const char *name
= hw_name (me
);
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
);
203 /* attach to our parent bus */
204 do_hw_attach_regs (me
);
206 /* establish the output registers */
207 if (hw_find_property (me
, "reg"))
209 reg_property_spec unit
;
212 /* Find a relevant reg entry. */
214 while (hw_find_reg_array_property (me
, "reg", reg_nr
, &unit
)
215 && !hw_unit_size_to_attach_size (hw_parent (me
),
217 &glue
->sizeof_output
,
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
));
228 /* ... and the address. */
229 hw_unit_address_to_attach_address (hw_parent (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
));
238 glue
->nr_outputs
= glue
->sizeof_output
/ sizeof (unsigned_word
);
242 /* Allow bitwise glue devices to declare only ports. */
243 if (!strcmp (name
, "glue"))
244 hw_abort (me
, "Missing \"reg\" property");
246 glue
->nr_outputs
= 1;
247 glue
->sizeof_output
= sizeof (unsigned_word
);
249 glue
->output
= hw_zalloc (me
, glue
->sizeof_output
);
251 /* establish the input ports */
253 const struct hw_property
*ranges
;
255 ranges
= hw_find_property (me
, "interrupt-ranges");
258 glue
->int_number
= 0;
259 glue
->nr_inputs
= glue
->nr_outputs
;
261 else if (ranges
->sizeof_array
!= sizeof (unsigned_cell
) * 2)
263 hw_abort (me
, "invalid interrupt-ranges property (incorrect size)");
267 const unsigned_cell
*int_range
= ranges
->array
;
269 glue
->int_number
= BE2H_cell (int_range
[0]);
270 glue
->nr_inputs
= BE2H_cell (int_range
[1]);
272 glue
->sizeof_input
= glue
->nr_inputs
* sizeof (unsigned);
273 glue
->input
= hw_zalloc (me
, glue
->sizeof_input
);
276 /* determine our type */
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
;
286 hw_abort (me
, "unimplemented glue type");
288 HW_TRACE ((me
, "int-number %d, nr_inputs %d, nr_outputs %d",
289 glue
->int_number
, glue
->nr_inputs
, glue
->nr_outputs
));
293 hw_glue_io_read_buffer (struct hw
*me
,
299 struct hw_glue
*glue
= (struct hw_glue
*) hw_data (me
);
300 int reg
= ((addr
- glue
->address
) / sizeof (unsigned_word
)) % glue
->nr_outputs
;
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
);
307 *(unsigned_word
*)dest
= H2BE_4 (glue
->output
[reg
]);
309 HW_TRACE ((me
, "read - port %d (0x%lx), level %d",
310 reg
, (unsigned long) addr
, glue
->output
[reg
]));
317 hw_glue_io_write_buffer (struct hw
*me
,
323 struct hw_glue
*glue
= (struct hw_glue
*) hw_data (me
);
324 int reg
= ((addr
- glue
->address
) / sizeof (unsigned_word
)) % max_nr_ports
;
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
);
331 glue
->output
[reg
] = H2BE_4 (*(unsigned_word
*)source
);
333 HW_TRACE ((me
, "write - port %d (0x%lx), level %d",
334 reg
, (unsigned long) addr
, glue
->output
[reg
]));
336 hw_port_event (me
, reg
, glue
->output
[reg
]);
342 hw_glue_port_event (struct hw
*me
,
348 struct hw_glue
*glue
= (struct hw_glue
*) hw_data (me
);
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
);
355 glue
->input
[my_port
- glue
->int_number
] = level
;
360 int port
= my_port
% glue
->nr_outputs
;
362 glue
->output
[port
] = level
;
364 HW_TRACE ((me
, "input - port %d (0x%lx), level %d",
366 (unsigned long) glue
->address
+ port
* sizeof (unsigned_word
),
372 glue
->output
[0] = glue
->input
[0];
373 for (i
= 1; i
< glue
->nr_inputs
; i
++)
374 glue
->output
[0] &= glue
->input
[i
];
379 glue
->output
[0] = glue
->input
[0];
380 for (i
= 1; i
< glue
->nr_inputs
; i
++)
381 glue
->output
[0] |= glue
->input
[i
];
386 glue
->output
[0] = glue
->input
[0];
387 for (i
= 1; i
< glue
->nr_inputs
; i
++)
388 glue
->output
[0] ^= glue
->input
[i
];
393 hw_abort (me
, "operator not implemented");
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]));
402 hw_port_event (me
, 0, glue
->output
[0]);
406 static const struct hw_port_descriptor hw_glue_ports
[] =
408 { "int", 0, max_nr_ports
, 0 },
413 const struct hw_descriptor dv_glue_descriptor
[] =
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
, },