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