198b9484cSchristos /* The common simulator framework for GDB, the GNU Debugger. 298b9484cSchristos 3*88241920Schristos Copyright 2002-2024 Free Software Foundation, Inc. 498b9484cSchristos 598b9484cSchristos Contributed by Andrew Cagney and Red Hat. 698b9484cSchristos 798b9484cSchristos This file is part of GDB. 898b9484cSchristos 998b9484cSchristos This program is free software; you can redistribute it and/or modify 1098b9484cSchristos it under the terms of the GNU General Public License as published by 1198b9484cSchristos the Free Software Foundation; either version 3 of the License, or 1298b9484cSchristos (at your option) any later version. 1398b9484cSchristos 1498b9484cSchristos This program is distributed in the hope that it will be useful, 1598b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1698b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1798b9484cSchristos GNU General Public License for more details. 1898b9484cSchristos 1998b9484cSchristos You should have received a copy of the GNU General Public License 2098b9484cSchristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 2198b9484cSchristos 224b169a6bSchristos /* This must come before any other includes. */ 234b169a6bSchristos #include "defs.h" 244b169a6bSchristos 254b169a6bSchristos #include <string.h> 2698b9484cSchristos 2798b9484cSchristos #include "hw-main.h" 2898b9484cSchristos 2998b9484cSchristos /* DEVICE 3098b9484cSchristos 3198b9484cSchristos 3298b9484cSchristos glue - glue to interconnect and test hardware ports 3398b9484cSchristos 3498b9484cSchristos 3598b9484cSchristos DESCRIPTION 3698b9484cSchristos 3798b9484cSchristos 3898b9484cSchristos The glue device provides two functions. Firstly, it provides a 3998b9484cSchristos mechanism for inspecting and driving the port network. Secondly, 4098b9484cSchristos it provides a set of boolean primitives that can be used to apply 4198b9484cSchristos combinatorial operations to the port network. 4298b9484cSchristos 4398b9484cSchristos Glue devices have a variable number of big endian <<output>> 4498b9484cSchristos registers. Each register is target-word sized. The registers can 4598b9484cSchristos be read and written. 4698b9484cSchristos 4798b9484cSchristos Writing to an output register results in an event being driven 4898b9484cSchristos (level determined by the value written) on the devices 4998b9484cSchristos corresponding output port. 5098b9484cSchristos 5198b9484cSchristos Reading an <<output>> register returns either the last value 5298b9484cSchristos written or the most recently computed value (for that register) as 5398b9484cSchristos a result of an event ariving on that port (which ever was computed 5498b9484cSchristos last). 5598b9484cSchristos 5698b9484cSchristos At present the following sub device types are available: 5798b9484cSchristos 5898b9484cSchristos <<glue>>: In addition to driving its output interrupt port with any 5998b9484cSchristos value written to an interrupt input port is stored in the 6098b9484cSchristos corresponding <<output>> register. Such input interrupts, however, 6198b9484cSchristos are not propogated to an output interrupt port. 6298b9484cSchristos 6398b9484cSchristos <<glue-and>>: The bit-wise AND of the interrupt inputs is computed 6498b9484cSchristos and then both stored in <<output>> register zero and propogated to 6598b9484cSchristos output interrupt output port zero. 6698b9484cSchristos 6798b9484cSchristos 6898b9484cSchristos PROPERTIES 6998b9484cSchristos 7098b9484cSchristos 7198b9484cSchristos reg = <address> <size> (required) 7298b9484cSchristos 7398b9484cSchristos Specify the address (within the parent bus) that this device is to 7498b9484cSchristos live. The address must be 2048 * sizeof (word) (8k in a 32bit 7598b9484cSchristos simulation) aligned. 7698b9484cSchristos 7798b9484cSchristos 7898b9484cSchristos interrupt-ranges = <int-number> <range> (optional) 7998b9484cSchristos 8098b9484cSchristos If present, this specifies the number of valid interrupt inputs (up 8198b9484cSchristos to the maximum of 2048). By default, <<int-number>> is zero and 8298b9484cSchristos range is determined by the <<reg>> size. 8398b9484cSchristos 8498b9484cSchristos 8598b9484cSchristos PORTS 8698b9484cSchristos 8798b9484cSchristos 8898b9484cSchristos int[0..] (input, output) 8998b9484cSchristos 9098b9484cSchristos Both an input and an output port. 9198b9484cSchristos 9298b9484cSchristos 9398b9484cSchristos EXAMPLES 9498b9484cSchristos 9598b9484cSchristos 9698b9484cSchristos Enable tracing of the device: 9798b9484cSchristos 9898b9484cSchristos | -t glue-device \ 9998b9484cSchristos 10098b9484cSchristos 10198b9484cSchristos Create source, bitwize-and, and sink glue devices. Since the 10298b9484cSchristos device at address <<0x10000>> is of size <<8>> it will have two 10398b9484cSchristos output interrupt ports. 10498b9484cSchristos 10598b9484cSchristos | -o '/iobus@0xf0000000/glue@0x10000/reg 0x10000 8' \ 10698b9484cSchristos | -o '/iobus@0xf0000000/glue-and@0x20000/reg 0x20000 4' \ 10798b9484cSchristos | -o '/iobus@0xf0000000/glue-and/interrupt-ranges 0 2' \ 10898b9484cSchristos | -o '/iobus@0xf0000000/glue@0x30000/reg 0x30000 4' \ 10998b9484cSchristos 11098b9484cSchristos 11198b9484cSchristos Wire the two source interrupts to the AND device: 11298b9484cSchristos 11398b9484cSchristos | -o '/iobus@0xf0000000/glue@0x10000 > 0 0 /iobus/glue-and' \ 11498b9484cSchristos | -o '/iobus@0xf0000000/glue@0x10000 > 1 1 /iobus/glue-and' \ 11598b9484cSchristos 11698b9484cSchristos 11798b9484cSchristos Wire the AND device up to the sink so that the and's output is not 11898b9484cSchristos left open. 11998b9484cSchristos 12098b9484cSchristos | -o '/iobus@0xf0000000/glue-and > 0 0 /iobus/glue@0x30000' \ 12198b9484cSchristos 12298b9484cSchristos 12398b9484cSchristos With the above configuration. The client program is able to 12498b9484cSchristos compute a two bit AND. For instance the <<C>> stub below prints 1 12598b9484cSchristos AND 0. 12698b9484cSchristos 12798b9484cSchristos | unsigned *input = (void*)0xf0010000; 12898b9484cSchristos | unsigned *output = (void*)0xf0030000; 12998b9484cSchristos | unsigned ans; 13098b9484cSchristos | input[0] = htonl(1); 13198b9484cSchristos | input[1] = htonl(0); 13298b9484cSchristos | ans = ntohl(*output); 13398b9484cSchristos | write_string("AND is "); 13498b9484cSchristos | write_int(ans); 13598b9484cSchristos | write_line(); 13698b9484cSchristos 13798b9484cSchristos 13898b9484cSchristos BUGS 13998b9484cSchristos 14098b9484cSchristos 14198b9484cSchristos A future implementation of this device may support multiple 14298b9484cSchristos interrupt ranges. 14398b9484cSchristos 14498b9484cSchristos Some of the devices listed may not yet be fully implemented. 14598b9484cSchristos 14698b9484cSchristos Additional devices such as a D flip-flop (DFF), an inverter (INV) 14798b9484cSchristos or a latch (LAT) may prove useful. 14898b9484cSchristos 14998b9484cSchristos */ 15098b9484cSchristos 15198b9484cSchristos 15298b9484cSchristos enum 15398b9484cSchristos { 15498b9484cSchristos max_nr_ports = 2048, 15598b9484cSchristos }; 15698b9484cSchristos 15798b9484cSchristos enum hw_glue_type 15898b9484cSchristos { 15998b9484cSchristos glue_undefined = 0, 16098b9484cSchristos glue_io, 16198b9484cSchristos glue_and, 16298b9484cSchristos glue_nand, 16398b9484cSchristos glue_or, 16498b9484cSchristos glue_xor, 16598b9484cSchristos glue_nor, 16698b9484cSchristos glue_not, 16798b9484cSchristos }; 16898b9484cSchristos 16998b9484cSchristos struct hw_glue 17098b9484cSchristos { 17198b9484cSchristos enum hw_glue_type type; 17298b9484cSchristos int int_number; 17398b9484cSchristos int *input; 17498b9484cSchristos int nr_inputs; 17598b9484cSchristos unsigned sizeof_input; 17698b9484cSchristos /* our output registers */ 17798b9484cSchristos int space; 17898b9484cSchristos unsigned_word address; 17998b9484cSchristos unsigned sizeof_output; 18098b9484cSchristos int *output; 18198b9484cSchristos int nr_outputs; 18298b9484cSchristos }; 18398b9484cSchristos 18498b9484cSchristos 18598b9484cSchristos static hw_io_read_buffer_method hw_glue_io_read_buffer; 18698b9484cSchristos static hw_io_write_buffer_method hw_glue_io_write_buffer; 18798b9484cSchristos static hw_port_event_method hw_glue_port_event; 18898b9484cSchristos static const struct hw_port_descriptor hw_glue_ports[]; 18998b9484cSchristos 19098b9484cSchristos static void 19198b9484cSchristos hw_glue_finish (struct hw *me) 19298b9484cSchristos { 19398b9484cSchristos struct hw_glue *glue = HW_ZALLOC (me, struct hw_glue); 194a2e2270fSchristos const char *name = hw_name (me); 19598b9484cSchristos 19698b9484cSchristos /* establish our own methods */ 19798b9484cSchristos set_hw_data (me, glue); 19898b9484cSchristos set_hw_io_read_buffer (me, hw_glue_io_read_buffer); 19998b9484cSchristos set_hw_io_write_buffer (me, hw_glue_io_write_buffer); 20098b9484cSchristos set_hw_ports (me, hw_glue_ports); 20198b9484cSchristos set_hw_port_event (me, hw_glue_port_event); 20298b9484cSchristos 20398b9484cSchristos /* attach to our parent bus */ 20498b9484cSchristos do_hw_attach_regs (me); 20598b9484cSchristos 20698b9484cSchristos /* establish the output registers */ 207a2e2270fSchristos if (hw_find_property (me, "reg")) 20898b9484cSchristos { 20998b9484cSchristos reg_property_spec unit; 21098b9484cSchristos int reg_nr; 21198b9484cSchristos 212a2e2270fSchristos /* Find a relevant reg entry. */ 21398b9484cSchristos reg_nr = 0; 21498b9484cSchristos while (hw_find_reg_array_property (me, "reg", reg_nr, &unit) 21598b9484cSchristos && !hw_unit_size_to_attach_size (hw_parent (me), 21698b9484cSchristos &unit.size, 21798b9484cSchristos &glue->sizeof_output, 21898b9484cSchristos me)) 21998b9484cSchristos reg_nr++; 22098b9484cSchristos 221a2e2270fSchristos /* Check out the size ... */ 22298b9484cSchristos if (glue->sizeof_output == 0) 22398b9484cSchristos hw_abort (me, "at least one reg property size must be nonzero"); 22498b9484cSchristos if (glue->sizeof_output % sizeof (unsigned_word) != 0) 22598b9484cSchristos hw_abort (me, "reg property size must be %ld aligned", 22698b9484cSchristos (long) sizeof (unsigned_word)); 22798b9484cSchristos 228a2e2270fSchristos /* ... and the address. */ 22998b9484cSchristos hw_unit_address_to_attach_address (hw_parent (me), 23098b9484cSchristos &unit.address, 23198b9484cSchristos &glue->space, 23298b9484cSchristos &glue->address, 23398b9484cSchristos me); 23498b9484cSchristos if (glue->address % (sizeof (unsigned_word) * max_nr_ports) != 0) 23598b9484cSchristos hw_abort (me, "reg property address must be %ld aligned", 23698b9484cSchristos (long) (sizeof (unsigned_word) * max_nr_ports)); 23798b9484cSchristos 23898b9484cSchristos glue->nr_outputs = glue->sizeof_output / sizeof (unsigned_word); 23998b9484cSchristos } 240a2e2270fSchristos else 241a2e2270fSchristos { 242a2e2270fSchristos /* Allow bitwise glue devices to declare only ports. */ 243a2e2270fSchristos if (!strcmp (name, "glue")) 244a2e2270fSchristos hw_abort (me, "Missing \"reg\" property"); 245a2e2270fSchristos 246a2e2270fSchristos glue->nr_outputs = 1; 247a2e2270fSchristos glue->sizeof_output = sizeof (unsigned_word); 248a2e2270fSchristos } 249a2e2270fSchristos glue->output = hw_zalloc (me, glue->sizeof_output); 25098b9484cSchristos 25198b9484cSchristos /* establish the input ports */ 25298b9484cSchristos { 25398b9484cSchristos const struct hw_property *ranges; 25498b9484cSchristos 25598b9484cSchristos ranges = hw_find_property (me, "interrupt-ranges"); 25698b9484cSchristos if (ranges == NULL) 25798b9484cSchristos { 25898b9484cSchristos glue->int_number = 0; 25998b9484cSchristos glue->nr_inputs = glue->nr_outputs; 26098b9484cSchristos } 26198b9484cSchristos else if (ranges->sizeof_array != sizeof (unsigned_cell) * 2) 26298b9484cSchristos { 26398b9484cSchristos hw_abort (me, "invalid interrupt-ranges property (incorrect size)"); 26498b9484cSchristos } 26598b9484cSchristos else 26698b9484cSchristos { 26798b9484cSchristos const unsigned_cell *int_range = ranges->array; 26898b9484cSchristos 26998b9484cSchristos glue->int_number = BE2H_cell (int_range[0]); 27098b9484cSchristos glue->nr_inputs = BE2H_cell (int_range[1]); 27198b9484cSchristos } 27298b9484cSchristos glue->sizeof_input = glue->nr_inputs * sizeof (unsigned); 27398b9484cSchristos glue->input = hw_zalloc (me, glue->sizeof_input); 27498b9484cSchristos } 27598b9484cSchristos 27698b9484cSchristos /* determine our type */ 27798b9484cSchristos if (strcmp (name, "glue") == 0) 27898b9484cSchristos glue->type = glue_io; 27998b9484cSchristos else if (strcmp (name, "glue-and") == 0) 28098b9484cSchristos glue->type = glue_and; 281a2e2270fSchristos else if (strcmp (name, "glue-or") == 0) 282a2e2270fSchristos glue->type = glue_or; 283a2e2270fSchristos else if (strcmp (name, "glue-xor") == 0) 284a2e2270fSchristos glue->type = glue_xor; 28598b9484cSchristos else 28698b9484cSchristos hw_abort (me, "unimplemented glue type"); 28798b9484cSchristos 28898b9484cSchristos HW_TRACE ((me, "int-number %d, nr_inputs %d, nr_outputs %d", 28998b9484cSchristos glue->int_number, glue->nr_inputs, glue->nr_outputs)); 29098b9484cSchristos } 29198b9484cSchristos 29298b9484cSchristos static unsigned 29398b9484cSchristos hw_glue_io_read_buffer (struct hw *me, 29498b9484cSchristos void *dest, 29598b9484cSchristos int space, 29698b9484cSchristos unsigned_word addr, 29798b9484cSchristos unsigned nr_bytes) 29898b9484cSchristos { 29998b9484cSchristos struct hw_glue *glue = (struct hw_glue *) hw_data (me); 30098b9484cSchristos int reg = ((addr - glue->address) / sizeof (unsigned_word)) % glue->nr_outputs; 30198b9484cSchristos 30298b9484cSchristos if (nr_bytes != sizeof (unsigned_word) 30398b9484cSchristos || (addr % sizeof (unsigned_word)) != 0) 30498b9484cSchristos hw_abort (me, "missaligned read access (%d:0x%lx:%d) not supported", 30598b9484cSchristos space, (unsigned long)addr, nr_bytes); 30698b9484cSchristos 30798b9484cSchristos *(unsigned_word *)dest = H2BE_4 (glue->output[reg]); 30898b9484cSchristos 30998b9484cSchristos HW_TRACE ((me, "read - port %d (0x%lx), level %d", 31098b9484cSchristos reg, (unsigned long) addr, glue->output[reg])); 31198b9484cSchristos 31298b9484cSchristos return nr_bytes; 31398b9484cSchristos } 31498b9484cSchristos 31598b9484cSchristos 31698b9484cSchristos static unsigned 31798b9484cSchristos hw_glue_io_write_buffer (struct hw *me, 31898b9484cSchristos const void *source, 31998b9484cSchristos int space, 32098b9484cSchristos unsigned_word addr, 32198b9484cSchristos unsigned nr_bytes) 32298b9484cSchristos { 32398b9484cSchristos struct hw_glue *glue = (struct hw_glue *) hw_data (me); 32498b9484cSchristos int reg = ((addr - glue->address) / sizeof (unsigned_word)) % max_nr_ports; 32598b9484cSchristos 32698b9484cSchristos if (nr_bytes != sizeof (unsigned_word) 32798b9484cSchristos || (addr % sizeof (unsigned_word)) != 0) 32898b9484cSchristos hw_abort (me, "missaligned write access (%d:0x%lx:%d) not supported", 32998b9484cSchristos space, (unsigned long) addr, nr_bytes); 33098b9484cSchristos 33198b9484cSchristos glue->output[reg] = H2BE_4 (*(unsigned_word *)source); 33298b9484cSchristos 33398b9484cSchristos HW_TRACE ((me, "write - port %d (0x%lx), level %d", 33498b9484cSchristos reg, (unsigned long) addr, glue->output[reg])); 33598b9484cSchristos 33698b9484cSchristos hw_port_event (me, reg, glue->output[reg]); 33798b9484cSchristos 33898b9484cSchristos return nr_bytes; 33998b9484cSchristos } 34098b9484cSchristos 34198b9484cSchristos static void 34298b9484cSchristos hw_glue_port_event (struct hw *me, 34398b9484cSchristos int my_port, 34498b9484cSchristos struct hw *source, 34598b9484cSchristos int source_port, 34698b9484cSchristos int level) 34798b9484cSchristos { 34898b9484cSchristos struct hw_glue *glue = (struct hw_glue *) hw_data (me); 34998b9484cSchristos int i; 35098b9484cSchristos 35198b9484cSchristos if (my_port < glue->int_number 35298b9484cSchristos || my_port >= glue->int_number + glue->nr_inputs) 35398b9484cSchristos hw_abort (me, "port %d outside of valid range", my_port); 35498b9484cSchristos 35598b9484cSchristos glue->input[my_port - glue->int_number] = level; 35698b9484cSchristos switch (glue->type) 35798b9484cSchristos { 35898b9484cSchristos case glue_io: 35998b9484cSchristos { 36098b9484cSchristos int port = my_port % glue->nr_outputs; 36198b9484cSchristos 36298b9484cSchristos glue->output[port] = level; 36398b9484cSchristos 36498b9484cSchristos HW_TRACE ((me, "input - port %d (0x%lx), level %d", 36598b9484cSchristos my_port, 36698b9484cSchristos (unsigned long) glue->address + port * sizeof (unsigned_word), 36798b9484cSchristos level)); 368a2e2270fSchristos return; 36998b9484cSchristos } 37098b9484cSchristos case glue_and: 37198b9484cSchristos { 37298b9484cSchristos glue->output[0] = glue->input[0]; 37398b9484cSchristos for (i = 1; i < glue->nr_inputs; i++) 37498b9484cSchristos glue->output[0] &= glue->input[i]; 375a2e2270fSchristos break; 376a2e2270fSchristos } 377a2e2270fSchristos case glue_or: 378a2e2270fSchristos { 379a2e2270fSchristos glue->output[0] = glue->input[0]; 380a2e2270fSchristos for (i = 1; i < glue->nr_inputs; i++) 381a2e2270fSchristos glue->output[0] |= glue->input[i]; 382a2e2270fSchristos break; 383a2e2270fSchristos } 384a2e2270fSchristos case glue_xor: 385a2e2270fSchristos { 386a2e2270fSchristos glue->output[0] = glue->input[0]; 387a2e2270fSchristos for (i = 1; i < glue->nr_inputs; i++) 388a2e2270fSchristos glue->output[0] ^= glue->input[i]; 38998b9484cSchristos break; 39098b9484cSchristos } 39198b9484cSchristos default: 39298b9484cSchristos { 39398b9484cSchristos hw_abort (me, "operator not implemented"); 394a2e2270fSchristos return; 39598b9484cSchristos } 39698b9484cSchristos } 397a2e2270fSchristos 398a2e2270fSchristos /* If we fell through, we want to generate a port event. */ 399a2e2270fSchristos HW_TRACE ((me, "port %d, level %d arrived - output %d", 400a2e2270fSchristos my_port, level, glue->output[0])); 401a2e2270fSchristos 402a2e2270fSchristos hw_port_event (me, 0, glue->output[0]); 40398b9484cSchristos } 40498b9484cSchristos 40598b9484cSchristos 40698b9484cSchristos static const struct hw_port_descriptor hw_glue_ports[] = 40798b9484cSchristos { 40898b9484cSchristos { "int", 0, max_nr_ports, 0 }, 40998b9484cSchristos { NULL, 0, 0, 0 } 41098b9484cSchristos }; 41198b9484cSchristos 41298b9484cSchristos 41398b9484cSchristos const struct hw_descriptor dv_glue_descriptor[] = 41498b9484cSchristos { 41598b9484cSchristos { "glue", hw_glue_finish, }, 41698b9484cSchristos { "glue-and", hw_glue_finish, }, 41798b9484cSchristos { "glue-nand", hw_glue_finish, }, 41898b9484cSchristos { "glue-or", hw_glue_finish, }, 41998b9484cSchristos { "glue-xor", hw_glue_finish, }, 42098b9484cSchristos { "glue-nor", hw_glue_finish, }, 42198b9484cSchristos { "glue-not", hw_glue_finish, }, 42298b9484cSchristos { NULL, NULL }, 42398b9484cSchristos }; 424