]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - sim/common/dv-glue.c
Initial creation of sourceware repository
[thirdparty/binutils-gdb.git] / sim / common / dv-glue.c
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 "hw-main.h"
23
24 #ifdef HAVE_STRING_H
25 #include <string.h>
26 #else
27 #ifdef HAVE_STRINGS_H
28 #include <strings.h>
29 #endif
30 #endif
31
32 /* DEVICE
33
34
35 glue - glue to interconnect and test hardware ports
36
37
38 DESCRIPTION
39
40
41 The glue device provides two functions. Firstly, it provides a
42 mechanism for inspecting and driving the port network. Secondly,
43 it provides a set of boolean primitives that can be used to apply
44 combinatorial operations to the port network.
45
46 Glue devices have a variable number of big endian <<output>>
47 registers. Each register is target-word sized. The registers can
48 be read and written.
49
50 Writing to an output register results in an event being driven
51 (level determined by the value written) on the devices
52 corresponding output port.
53
54 Reading an <<output>> register returns either the last value
55 written or the most recently computed value (for that register) as
56 a result of an event ariving on that port (which ever was computed
57 last).
58
59 At present the following sub device types are available:
60
61 <<glue>>: In addition to driving its output interrupt port with any
62 value written to an interrupt input port is stored in the
63 corresponding <<output>> register. Such input interrupts, however,
64 are not propogated to an output interrupt port.
65
66 <<glue-and>>: The bit-wise AND of the interrupt inputs is computed
67 and then both stored in <<output>> register zero and propogated to
68 output interrupt output port zero.
69
70
71 PROPERTIES
72
73
74 reg = <address> <size> (required)
75
76 Specify the address (within the parent bus) that this device is to
77 live. The address must be 2048 * sizeof (word) (8k in a 32bit
78 simulation) aligned.
79
80
81 interrupt-ranges = <int-number> <range> (optional)
82
83 If present, this specifies the number of valid interrupt inputs (up
84 to the maximum of 2048). By default, <<int-number>> is zero and
85 range is determined by the <<reg>> size.
86
87
88 PORTS
89
90
91 int[0..] (input, output)
92
93 Both an input and an output port.
94
95
96 EXAMPLES
97
98
99 Enable tracing of the device:
100
101 | -t glue-device \
102
103
104 Create source, bitwize-and, and sink glue devices. Since the
105 device at address <<0x10000>> is of size <<8>> it will have two
106 output interrupt ports.
107
108 | -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \
109 | -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \
110 | -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \
111 | -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \
112
113
114 Wire the two source interrupts to the AND device:
115
116 | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
117 | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
118
119
120 Wire the AND device up to the sink so that the and's output is not
121 left open.
122
123 | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
124
125
126 With the above configuration. The client program is able to
127 compute a two bit AND. For instance the <<C>> stub below prints 1
128 AND 0.
129
130 | unsigned *input = (void*)0xf0010000;
131 | unsigned *output = (void*)0xf0030000;
132 | unsigned ans;
133 | input[0] = htonl(1);
134 | input[1] = htonl(0);
135 | ans = ntohl(*output);
136 | write_string("AND is ");
137 | write_int(ans);
138 | write_line();
139
140
141 BUGS
142
143
144 A future implementation of this device may support multiple
145 interrupt ranges.
146
147 Some of the devices listed may not yet be fully implemented.
148
149 Additional devices such as a D flip-flop (DFF), an inverter (INV)
150 or a latch (LAT) may prove useful.
151
152 */
153
154
155 enum {
156 max_nr_ports = 2048,
157 };
158
159 enum hw_glue_type {
160 glue_undefined = 0,
161 glue_io,
162 glue_and,
163 glue_nand,
164 glue_or,
165 glue_xor,
166 glue_nor,
167 glue_not,
168 };
169
170 struct hw_glue {
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
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 const static struct hw_port_descriptor hw_glue_ports[];
189
190 static void
191 hw_glue_finish (struct hw *me)
192 {
193 struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue);
194
195 /* establish our own methods */
196 set_hw_data (me, glue);
197 set_hw_io_read_buffer (me, hw_glue_io_read_buffer);
198 set_hw_io_write_buffer (me, hw_glue_io_write_buffer);
199 set_hw_ports (me, hw_glue_ports);
200 set_hw_port_event (me, hw_glue_port_event);
201
202 /* attach to our parent bus */
203 do_hw_attach_regs (me);
204
205 /* establish the output registers */
206 {
207 reg_property_spec unit;
208 int reg_nr;
209 /* find a relevant reg entry */
210 reg_nr = 0;
211 while (hw_find_reg_array_property (me, "reg", reg_nr, &unit)
212 && !hw_unit_size_to_attach_size (hw_parent (me),
213 &unit.size,
214 &glue->sizeof_output,
215 me))
216 reg_nr++;
217 /* check out the size */
218 if (glue->sizeof_output == 0)
219 hw_abort (me, "at least one reg property size must be nonzero");
220 if (glue->sizeof_output % sizeof (unsigned_word) != 0)
221 hw_abort (me, "reg property size must be %d aligned",
222 sizeof (unsigned_word));
223 /* and the address */
224 hw_unit_address_to_attach_address (hw_parent (me),
225 &unit.address,
226 &glue->space,
227 &glue->address,
228 me);
229 if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0)
230 hw_abort (me, "reg property address must be %d aligned",
231 sizeof (unsigned_word) * max_nr_ports);
232 glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word);
233 glue->output = hw_zalloc (me, glue->sizeof_output);
234 }
235
236 /* establish the input ports */
237 {
238 const struct hw_property *ranges;
239 ranges = hw_find_property (me, "interrupt-ranges");
240 if (ranges == NULL)
241 {
242 glue->int_number = 0;
243 glue->nr_inputs = glue->nr_outputs;
244 }
245 else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2)
246 {
247 hw_abort (me, "invalid interrupt-ranges property (incorrect size)");
248 }
249 else
250 {
251 const unsigned_cell *int_range = ranges->array;
252 glue->int_number = BE2H_cell (int_range[0]);
253 glue->nr_inputs = BE2H_cell (int_range[1]);
254 }
255 glue->sizeof_input = glue->nr_inputs * sizeof (unsigned);
256 glue->input = hw_zalloc (me, glue->sizeof_input);
257 }
258
259 /* determine our type */
260 {
261 const char *name = hw_name(me);
262 if (strcmp (name, "glue") == 0)
263 glue->type = glue_io;
264 else if (strcmp (name, "glue-and") == 0)
265 glue->type = glue_and;
266 else
267 hw_abort (me, "unimplemented glue type");
268 }
269
270 HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d",
271 glue->int_number, glue->nr_inputs, glue->nr_outputs));
272 }
273
274 static unsigned
275 hw_glue_io_read_buffer (struct hw *me,
276 void *dest,
277 int space,
278 unsigned_word addr,
279 unsigned nr_bytes)
280 {
281 struct hw_glue *glue = (struct hw_glue *) hw_data (me);
282 int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs;
283 if (nr_bytes != sizeof (unsigned_word)
284 || (addr % sizeof (unsigned_word)) != 0)
285 hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported",
286 space, (unsigned long)addr, nr_bytes);
287 *(unsigned_word*)dest = H2BE_4(glue->output[reg]);
288 HW_TRACE ((me, "read - port %d (0x%lx), level %d",
289 reg, (unsigned long) addr, glue->output[reg]));
290 return nr_bytes;
291 }
292
293
294 static unsigned
295 hw_glue_io_write_buffer (struct hw *me,
296 const void *source,
297 int space,
298 unsigned_word addr,
299 unsigned nr_bytes)
300 {
301 struct hw_glue *glue = (struct hw_glue *) hw_data (me);
302 int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports;
303 if (nr_bytes != sizeof (unsigned_word)
304 || (addr % sizeof (unsigned_word)) != 0)
305 hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported",
306 space, (unsigned long) addr, nr_bytes);
307 glue->output[reg] = H2BE_4 (*(unsigned_word*)source);
308 HW_TRACE ((me, "write - port %d (0x%lx), level %d",
309 reg, (unsigned long) addr, glue->output[reg]));
310 hw_port_event (me, reg, glue->output[reg]);
311 return nr_bytes;
312 }
313
314 static void
315 hw_glue_port_event (struct hw *me,
316 int my_port,
317 struct hw *source,
318 int source_port,
319 int level)
320 {
321 struct hw_glue *glue = (struct hw_glue *) hw_data (me);
322 int i;
323 if (my_port < glue->int_number
324 || my_port >= glue->int_number + glue->nr_inputs)
325 hw_abort (me, "port %d outside of valid range", my_port);
326 glue->input[my_port - glue->int_number] = level;
327 switch (glue->type)
328 {
329 case glue_io:
330 {
331 int port = my_port % glue->nr_outputs;
332 glue->output[port] = level;
333 HW_TRACE ((me, "input - port %d (0x%lx), level %d",
334 my_port,
335 (unsigned long) glue->address + port * sizeof (unsigned_word),
336 level));
337 break;
338 }
339 case glue_and:
340 {
341 glue->output[0] = glue->input[0];
342 for (i = 1; i < glue->nr_inputs; i++)
343 glue->output[0] &= glue->input[i];
344 HW_TRACE ((me, "and - port %d, level %d arrived - output %d",
345 my_port, level, glue->output[0]));
346 hw_port_event (me, 0, glue->output[0]);
347 break;
348 }
349 default:
350 {
351 hw_abort (me, "operator not implemented");
352 break;
353 }
354 }
355 }
356
357
358 static const struct hw_port_descriptor hw_glue_ports[] = {
359 { "int", 0, max_nr_ports },
360 { NULL }
361 };
362
363
364 const struct hw_descriptor dv_glue_descriptor[] = {
365 { "glue", hw_glue_finish, },
366 { "glue-and", hw_glue_finish, },
367 { "glue-nand", hw_glue_finish, },
368 { "glue-or", hw_glue_finish, },
369 { "glue-xor", hw_glue_finish, },
370 { "glue-nor", hw_glue_finish, },
371 { "glue-not", hw_glue_finish, },
372 { NULL },
373 };