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 2 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, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #include "device_table.h"
31 glue - glue to interconnect and test interrupts
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.
42 Glue devices have a variable number of big endian <<output>>
43 registers. Each host-word size. The registers can be both read
46 Writing a value to an output register causes an interrupt (of the
47 specified level) to be driven on the devices corresponding output
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).
54 At present the following sub device types are available:
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.
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.
69 reg = <address> <size> (required)
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
76 interrupt-ranges = <int-number> <range> (optional)
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.
86 Enable tracing of the device:
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.
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' \
101 Wire the two source interrupts to the AND device:
103 | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \
104 | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \
107 Wire the AND device up to the sink so that the and's output is not
110 | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \
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
117 | unsigned *input = (void*)0xf0010000;
118 | unsigned *output = (void*)0xf0030000;
120 | input[0] = htonl(1);
121 | input[1] = htonl(0);
122 | ans = ntohl(*output);
123 | write_string("AND is ");
131 A future implementation of this device may support multiple
134 Some of the devices listed may not yet be fully implemented.
136 Additional devices such as a dff, an inverter or a latch may be
143 max_nr_interrupts
= 2048,
146 typedef enum _hw_glue_type
{
157 typedef struct _hw_glue_device
{
162 unsigned sizeof_input
;
163 /* our output registers */
165 unsigned_word address
;
166 unsigned sizeof_output
;
173 hw_glue_init_address(device
*me
)
175 hw_glue_device
*glue
= (hw_glue_device
*)device_data(me
);
177 /* attach to my parent */
178 generic_device_init_address(me
);
180 /* establish the output registers */
181 if (glue
->output
!= NULL
) {
182 memset(glue
->output
, 0, glue
->sizeof_output
);
185 reg_property_spec unit
;
187 /* find a relevant reg entry */
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
))
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
,
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
);
209 /* establish the input interrupt ports */
210 if (glue
->input
!= NULL
) {
211 memset(glue
->input
, 0, glue
->sizeof_input
);
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
;
219 else if (ranges
->sizeof_array
!= sizeof(unsigned_cell
) * 2) {
220 device_error(me
, "invalid interrupt-ranges property (incorrect size)");
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]);
227 glue
->sizeof_input
= glue
->nr_inputs
* sizeof(unsigned);
228 glue
->input
= zalloc(glue
->sizeof_input
);
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
;
239 device_error(me
, "unimplemented glue type");
242 DTRACE(glue
, ("int-number %d, nr_inputs %d, nr_outputs %d\n",
243 glue
->int_number
, glue
->nr_inputs
, glue
->nr_outputs
));
247 hw_glue_io_read_buffer_callback(device
*me
,
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
]));
269 hw_glue_io_write_buffer_callback(device
*me
,
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
);
291 hw_glue_interrupt_event(device
*me
,
299 hw_glue_device
*glue
= (hw_glue_device
*)device_data(me
);
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
) {
308 int port
= my_port
% glue
->nr_outputs
;
309 glue
->output
[port
] = level
;
310 DTRACE(glue
, ("input - interrupt %d (0x%lx), level %d\n",
312 (unsigned long)glue
->address
+ port
* sizeof(unsigned_word
),
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
);
325 device_error(me
, "operator not implemented");
331 static const device_interrupt_port_descriptor hw_glue_interrupt_ports
[] = {
332 { "int", 0, max_nr_interrupts
},
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
, },
343 { hw_glue_interrupt_event
, NULL
, hw_glue_interrupt_ports
}, /* interrupt */
344 { NULL
, }, /* unit */
350 hw_glue_create(const char *name
,
351 const device_unit
*unit_address
,
354 /* create the descriptor */
355 hw_glue_device
*glue
= ZALLOC(hw_glue_device
);
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
},
371 #endif /* _HW_GLUE_C_ */