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