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