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