1 /* This file is part of the program psim.
3 Copyright (C) 1994-1996, Andrew Cagney <cagney@highland.com.au>
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.
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.
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/>.
24 #include "device_table.h"
30 glue - glue to interconnect and test interrupts
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.
41 Glue devices have a variable number of big endian <<output>>
42 registers. Each host-word size. The registers can be both read
45 Writing a value to an output register causes an interrupt (of the
46 specified level) to be driven on the devices corresponding output
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).
53 At present the following sub device types are available:
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.
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.
68 reg = <address> <size> (required)
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
75 interrupt-ranges = <int-number> <range> (optional)
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.
85 Enable tracing of the device:
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.
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' \
100 Wire the two source interrupts to the AND device:
102 | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
103 | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
106 Wire the AND device up to the sink so that the and's output is not
109 | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
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
116 | unsigned *input = (void*)0xf0010000;
117 | unsigned *output = (void*)0xf0030000;
119 | input[0] = htonl(1);
120 | input[1] = htonl(0);
121 | ans = ntohl(*output);
122 | write_string("AND is ");
130 A future implementation of this device may support multiple
133 Some of the devices listed may not yet be fully implemented.
135 Additional devices such as a dff, an inverter or a latch may be
142 max_nr_interrupts
= 2048,
145 typedef enum _hw_glue_type
{
156 typedef struct _hw_glue_device
{
161 unsigned sizeof_input
;
162 /* our output registers */
164 unsigned_word address
;
165 unsigned sizeof_output
;
172 hw_glue_init_address(device
*me
)
174 hw_glue_device
*glue
= (hw_glue_device
*)device_data(me
);
176 /* attach to my parent */
177 generic_device_init_address(me
);
179 /* establish the output registers */
180 if (glue
->output
!= NULL
) {
181 memset(glue
->output
, 0, glue
->sizeof_output
);
184 reg_property_spec unit
;
186 /* find a relevant reg entry */
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
))
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 %zu aligned", sizeof(unsigned_word
));
197 /* and the address */
198 device_address_to_attach_address(device_parent(me
),
199 &unit
.address
, &glue
->space
, &glue
->address
,
201 if (glue
->address
% (sizeof(unsigned_word
) * max_nr_interrupts
) != 0)
202 device_error(me
, "reg property address must be %zu 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
);
208 /* establish the input interrupt ports */
209 if (glue
->input
!= NULL
) {
210 memset(glue
->input
, 0, glue
->sizeof_input
);
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
;
218 else if (ranges
->sizeof_array
!= sizeof(unsigned_cell
) * 2) {
219 device_error(me
, "invalid interrupt-ranges property (incorrect size)");
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]);
226 glue
->sizeof_input
= glue
->nr_inputs
* sizeof(unsigned);
227 glue
->input
= zalloc(glue
->sizeof_input
);
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
;
238 device_error(me
, "unimplemented glue type");
241 DTRACE(glue
, ("int-number %d, nr_inputs %d, nr_outputs %d\n",
242 glue
->int_number
, glue
->nr_inputs
, glue
->nr_outputs
));
246 hw_glue_io_read_buffer_callback(device
*me
,
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
]));
268 hw_glue_io_write_buffer_callback(device
*me
,
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
);
290 hw_glue_interrupt_event(device
*me
,
298 hw_glue_device
*glue
= (hw_glue_device
*)device_data(me
);
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
) {
307 int port
= my_port
% glue
->nr_outputs
;
308 glue
->output
[port
] = level
;
309 DTRACE(glue
, ("input - interrupt %d (0x%lx), level %d\n",
311 (unsigned long)glue
->address
+ port
* sizeof(unsigned_word
),
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
);
324 device_error(me
, "operator not implemented");
330 static const device_interrupt_port_descriptor hw_glue_interrupt_ports
[] = {
331 { "int", 0, max_nr_interrupts
},
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
, },
342 { hw_glue_interrupt_event
, NULL
, hw_glue_interrupt_ports
}, /* interrupt */
343 { NULL
, }, /* unit */
349 hw_glue_create(const char *name
,
350 const device_unit
*unit_address
,
353 /* create the descriptor */
354 hw_glue_device
*glue
= ZALLOC(hw_glue_device
);
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
},
370 #endif /* _HW_GLUE_C_ */