1/* The common simulator framework for GDB, the GNU Debugger. 2 3 Copyright 2002, 2007 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 156enum { 157 max_nr_ports = 2048, 158}; 159 160enum hw_glue_type { 161 glue_undefined = 0, 162 glue_io, 163 glue_and, 164 glue_nand, 165 glue_or, 166 glue_xor, 167 glue_nor, 168 glue_not, 169}; 170 171struct hw_glue { 172 enum hw_glue_type type; 173 int int_number; 174 int *input; 175 int nr_inputs; 176 unsigned sizeof_input; 177 /* our output registers */ 178 int space; 179 unsigned_word address; 180 unsigned sizeof_output; 181 int *output; 182 int nr_outputs; 183}; 184 185 186static hw_io_read_buffer_method hw_glue_io_read_buffer; 187static hw_io_write_buffer_method hw_glue_io_write_buffer; 188static hw_port_event_method hw_glue_port_event; 189const static struct hw_port_descriptor hw_glue_ports[]; 190 191static void 192hw_glue_finish (struct hw *me) 193{ 194 struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue); 195 196 /* establish our own methods */ 197 set_hw_data (me, glue); 198 set_hw_io_read_buffer (me, hw_glue_io_read_buffer); 199 set_hw_io_write_buffer (me, hw_glue_io_write_buffer); 200 set_hw_ports (me, hw_glue_ports); 201 set_hw_port_event (me, hw_glue_port_event); 202 203 /* attach to our parent bus */ 204 do_hw_attach_regs (me); 205 206 /* establish the output registers */ 207 { 208 reg_property_spec unit; 209 int reg_nr; 210 /* find a relevant reg entry */ 211 reg_nr = 0; 212 while (hw_find_reg_array_property (me, "reg", reg_nr, &unit) 213 && !hw_unit_size_to_attach_size (hw_parent (me), 214 &unit.size, 215 &glue->sizeof_output, 216 me)) 217 reg_nr++; 218 /* check out the size */ 219 if (glue->sizeof_output == 0) 220 hw_abort (me, "at least one reg property size must be nonzero"); 221 if (glue->sizeof_output % sizeof (unsigned_word) != 0) 222 hw_abort (me, "reg property size must be %ld aligned", 223 (long) sizeof (unsigned_word)); 224 /* and the address */ 225 hw_unit_address_to_attach_address (hw_parent (me), 226 &unit.address, 227 &glue->space, 228 &glue->address, 229 me); 230 if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0) 231 hw_abort (me, "reg property address must be %ld aligned", 232 (long) (sizeof (unsigned_word) * max_nr_ports)); 233 glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word); 234 glue->output = hw_zalloc (me, glue->sizeof_output); 235 } 236 237 /* establish the input ports */ 238 { 239 const struct hw_property *ranges; 240 ranges = hw_find_property (me, "interrupt-ranges"); 241 if (ranges == NULL) 242 { 243 glue->int_number = 0; 244 glue->nr_inputs = glue->nr_outputs; 245 } 246 else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2) 247 { 248 hw_abort (me, "invalid interrupt-ranges property (incorrect size)"); 249 } 250 else 251 { 252 const unsigned_cell *int_range = ranges->array; 253 glue->int_number = BE2H_cell (int_range[0]); 254 glue->nr_inputs = BE2H_cell (int_range[1]); 255 } 256 glue->sizeof_input = glue->nr_inputs * sizeof (unsigned); 257 glue->input = hw_zalloc (me, glue->sizeof_input); 258 } 259 260 /* determine our type */ 261 { 262 const char *name = hw_name(me); 263 if (strcmp (name, "glue") == 0) 264 glue->type = glue_io; 265 else if (strcmp (name, "glue-and") == 0) 266 glue->type = glue_and; 267 else 268 hw_abort (me, "unimplemented glue type"); 269 } 270 271 HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d", 272 glue->int_number, glue->nr_inputs, glue->nr_outputs)); 273} 274 275static unsigned 276hw_glue_io_read_buffer (struct hw *me, 277 void *dest, 278 int space, 279 unsigned_word addr, 280 unsigned nr_bytes) 281{ 282 struct hw_glue *glue = (struct hw_glue *) hw_data (me); 283 int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs; 284 if (nr_bytes != sizeof (unsigned_word) 285 || (addr % sizeof (unsigned_word)) != 0) 286 hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported", 287 space, (unsigned long)addr, nr_bytes); 288 *(unsigned_word*)dest = H2BE_4(glue->output[reg]); 289 HW_TRACE ((me, "read - port %d (0x%lx), level %d", 290 reg, (unsigned long) addr, glue->output[reg])); 291 return nr_bytes; 292} 293 294 295static unsigned 296hw_glue_io_write_buffer (struct hw *me, 297 const void *source, 298 int space, 299 unsigned_word addr, 300 unsigned nr_bytes) 301{ 302 struct hw_glue *glue = (struct hw_glue *) hw_data (me); 303 int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports; 304 if (nr_bytes != sizeof (unsigned_word) 305 || (addr % sizeof (unsigned_word)) != 0) 306 hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported", 307 space, (unsigned long) addr, nr_bytes); 308 glue->output[reg] = H2BE_4 (*(unsigned_word*)source); 309 HW_TRACE ((me, "write - port %d (0x%lx), level %d", 310 reg, (unsigned long) addr, glue->output[reg])); 311 hw_port_event (me, reg, glue->output[reg]); 312 return nr_bytes; 313} 314 315static void 316hw_glue_port_event (struct hw *me, 317 int my_port, 318 struct hw *source, 319 int source_port, 320 int level) 321{ 322 struct hw_glue *glue = (struct hw_glue *) hw_data (me); 323 int i; 324 if (my_port < glue->int_number 325 || my_port >= glue->int_number + glue->nr_inputs) 326 hw_abort (me, "port %d outside of valid range", my_port); 327 glue->input[my_port - glue->int_number] = level; 328 switch (glue->type) 329 { 330 case glue_io: 331 { 332 int port = my_port % glue->nr_outputs; 333 glue->output[port] = level; 334 HW_TRACE ((me, "input - port %d (0x%lx), level %d", 335 my_port, 336 (unsigned long) glue->address + port * sizeof (unsigned_word), 337 level)); 338 break; 339 } 340 case glue_and: 341 { 342 glue->output[0] = glue->input[0]; 343 for (i = 1; i < glue->nr_inputs; i++) 344 glue->output[0] &= glue->input[i]; 345 HW_TRACE ((me, "and - port %d, level %d arrived - output %d", 346 my_port, level, glue->output[0])); 347 hw_port_event (me, 0, glue->output[0]); 348 break; 349 } 350 default: 351 { 352 hw_abort (me, "operator not implemented"); 353 break; 354 } 355 } 356} 357 358 359static const struct hw_port_descriptor hw_glue_ports[] = { 360 { "int", 0, max_nr_ports }, 361 { NULL } 362}; 363 364 365const struct hw_descriptor dv_glue_descriptor[] = { 366 { "glue", hw_glue_finish, }, 367 { "glue-and", hw_glue_finish, }, 368 { "glue-nand", hw_glue_finish, }, 369 { "glue-or", hw_glue_finish, }, 370 { "glue-xor", hw_glue_finish, }, 371 { "glue-nor", hw_glue_finish, }, 372 { "glue-not", hw_glue_finish, }, 373 { NULL }, 374}; 375