]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - sim/common/dv-glue.c
* config/sh/tm-sh.h (BELIEVE_PCC_PROMOTION): Define, so that
[thirdparty/binutils-gdb.git] / sim / common / dv-glue.c
CommitLineData
7c130f29
AC
1/* This file is part of the program psim.
2
3 Copyright (C) 1994-1996,1998 Andrew Cagney <cagney@highland.com.au>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20
21
22#include "sim-main.h"
23#include "hw-base.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_callback hw_glue_io_read_buffer;
187static hw_io_write_buffer_callback hw_glue_io_write_buffer;
188static hw_port_event_callback 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 %d aligned",
223 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 %d aligned",
232 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 sim_cpu *cpu,
282 sim_cia cia)
283{
284 struct hw_glue *glue = (struct hw_glue *) hw_data (me);
285 int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs;
286 if (nr_bytes != sizeof (unsigned_word)
287 || (addr % sizeof (unsigned_word)) != 0)
288 hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported",
289 space, (unsigned long)addr, nr_bytes);
290 *(unsigned_word*)dest = H2BE_4(glue->output[reg]);
291 HW_TRACE ((me, "read - port %d (0x%lx), level %d",
292 reg, (unsigned long) addr, glue->output[reg]));
293 return nr_bytes;
294}
295
296
297static unsigned
298hw_glue_io_write_buffer (struct hw *me,
299 const void *source,
300 int space,
301 unsigned_word addr,
302 unsigned nr_bytes,
303 sim_cpu *cpu,
304 sim_cia cia)
305{
306 struct hw_glue *glue = (struct hw_glue *) hw_data (me);
307 int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports;
308 if (nr_bytes != sizeof (unsigned_word)
309 || (addr % sizeof (unsigned_word)) != 0)
310 hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported",
311 space, (unsigned long) addr, nr_bytes);
312 glue->output[reg] = H2BE_4 (*(unsigned_word*)source);
313 HW_TRACE ((me, "write - port %d (0x%lx), level %d",
314 reg, (unsigned long) addr, glue->output[reg]));
315 hw_port_event (me, reg, glue->output[reg], cpu, cia);
316 return nr_bytes;
317}
318
319static void
320hw_glue_port_event (struct hw *me,
321 int my_port,
322 struct hw *source,
323 int source_port,
324 int level,
325 sim_cpu *cpu,
326 sim_cia cia)
327{
328 struct hw_glue *glue = (struct hw_glue *) hw_data (me);
329 int i;
330 if (my_port < glue->int_number
331 || my_port >= glue->int_number + glue->nr_inputs)
332 hw_abort (me, "port %d outside of valid range", my_port);
333 glue->input[my_port - glue->int_number] = level;
334 switch (glue->type)
335 {
336 case glue_io:
337 {
338 int port = my_port % glue->nr_outputs;
339 glue->output[port] = level;
340 HW_TRACE ((me, "input - port %d (0x%lx), level %d",
341 my_port,
342 (unsigned long) glue->address + port * sizeof (unsigned_word),
343 level));
344 break;
345 }
346 case glue_and:
347 {
348 glue->output[0] = glue->input[0];
349 for (i = 1; i < glue->nr_inputs; i++)
350 glue->output[0] &= glue->input[i];
351 HW_TRACE ((me, "and - port %d, level %d arrived - output %d",
352 my_port, level, glue->output[0]));
353 hw_port_event (me, 0, glue->output[0], cpu, cia);
354 break;
355 }
356 default:
357 {
358 hw_abort (me, "operator not implemented");
359 break;
360 }
361 }
362}
363
364
365static const struct hw_port_descriptor hw_glue_ports[] = {
366 { "int", 0, max_nr_ports },
367 { NULL }
368};
369
370
371const struct hw_device_descriptor dv_glue_descriptor[] = {
372 { "glue", hw_glue_finish, },
373 { "glue-and", hw_glue_finish, },
374 { "glue-nand", hw_glue_finish, },
375 { "glue-or", hw_glue_finish, },
376 { "glue-xor", hw_glue_finish, },
377 { "glue-nor", hw_glue_finish, },
378 { "glue-not", hw_glue_finish, },
379 { NULL },
380};