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