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