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