14e98e3e1Schristos /* The remote-virtual-component simulator framework 24e98e3e1Schristos for GDB, the GNU Debugger. 34e98e3e1Schristos 4*05d8e8feSchristos Copyright 2006-2024 Free Software Foundation, Inc. 54e98e3e1Schristos 64e98e3e1Schristos This file is part of GDB. 74e98e3e1Schristos 84e98e3e1Schristos This program is free software; you can redistribute it and/or modify 94e98e3e1Schristos it under the terms of the GNU General Public License as published by 104e98e3e1Schristos the Free Software Foundation; either version 3 of the License, or 114e98e3e1Schristos (at your option) any later version. 124e98e3e1Schristos 134e98e3e1Schristos This program is distributed in the hope that it will be useful, 144e98e3e1Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of 154e98e3e1Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164e98e3e1Schristos GNU General Public License for more details. 174e98e3e1Schristos 184e98e3e1Schristos You should have received a copy of the GNU General Public License 194e98e3e1Schristos along with this program. If not, see <http://www.gnu.org/licenses/>. */ 204e98e3e1Schristos 214b169a6bSchristos /* This must come before any other includes. */ 224b169a6bSchristos #include "defs.h" 234e98e3e1Schristos 244e98e3e1Schristos #include "sim-main.h" 254e98e3e1Schristos #include "hw-main.h" 264e98e3e1Schristos 274e98e3e1Schristos #include "hw-tree.h" 284e98e3e1Schristos 294e98e3e1Schristos #include <ctype.h> 304e98e3e1Schristos #include <errno.h> 314e98e3e1Schristos #include <string.h> 324e98e3e1Schristos #include <unistd.h> 334e98e3e1Schristos #include <stdlib.h> 344e98e3e1Schristos #ifdef HAVE_SYS_TYPES_H 354e98e3e1Schristos #include <sys/types.h> 364e98e3e1Schristos #endif 374e98e3e1Schristos 384e98e3e1Schristos #include <sys/time.h> 394e98e3e1Schristos 404e98e3e1Schristos #include <sys/select.h> 414e98e3e1Schristos 424e98e3e1Schristos /* Not guarded in dv-sockser.c, so why here. */ 434e98e3e1Schristos #include <netinet/in.h> 444e98e3e1Schristos #include <arpa/inet.h> 454e98e3e1Schristos #include <netdb.h> 464e98e3e1Schristos #include <sys/socket.h> 474e98e3e1Schristos 484e98e3e1Schristos 494e98e3e1Schristos /* DEVICE 504e98e3e1Schristos 514e98e3e1Schristos 524e98e3e1Schristos rv - Remote Virtual component 534e98e3e1Schristos 544e98e3e1Schristos 554e98e3e1Schristos DESCRIPTION 564e98e3e1Schristos 574e98e3e1Schristos 584e98e3e1Schristos Socket connection to a remote simulator component, for example one 594e98e3e1Schristos for testing a verilog construction. Protocol defined below. 604e98e3e1Schristos 614e98e3e1Schristos There is a set of 32-bit I/O ports, with a mapping from local to 624e98e3e1Schristos remote addresses. There is a set of interrupts expressed as a 634e98e3e1Schristos bit-mask, with a mapping from remote to local. There is a set of 644e98e3e1Schristos memory ranges (actual memory defined elsewhere), also with a 654e98e3e1Schristos mapping from remote to local addresses, that is expected to be 664e98e3e1Schristos accessible to the remote simulator in 32-byte chunks (simulating 674e98e3e1Schristos DMA). There is a mapping from remote cycles (or an appropriate 684e98e3e1Schristos elsewhere defined time-slice) to local cycles. 694e98e3e1Schristos 704e98e3e1Schristos PROPERTIES 714e98e3e1Schristos 724e98e3e1Schristos reg = <address> <size> 734e98e3e1Schristos The address (within the parent bus) that this device is to 744e98e3e1Schristos be located. 754e98e3e1Schristos 764e98e3e1Schristos remote-reg = <remote-address> 774e98e3e1Schristos The address of reg on the remote side. Defaults to 0. 784e98e3e1Schristos 794e98e3e1Schristos mem = <address> <size> 804e98e3e1Schristos Specify an address-range (within the parent bus) that the remote 814e98e3e1Schristos device can access. The memory is assumed to be already defined. 824e98e3e1Schristos If there's no memory defined but the remote side asks for a memory 834e98e3e1Schristos access, the simulation is aborted. 844e98e3e1Schristos 854e98e3e1Schristos remote-mem = <remote-address> 864e98e3e1Schristos The address of mem on the remote side. Defaults to 0. 874e98e3e1Schristos 884e98e3e1Schristos mbox = <address> 894e98e3e1Schristos Address of the mailbox interface. Writes to this address with the 904e98e3e1Schristos local address of a mailbox command, a complete packet with length 914e98e3e1Schristos and command; (4 or 6)) invokes the mailbox interface. Reads are 924e98e3e1Schristos invalid. Replies are written to the same address. Address space 934e98e3e1Schristos from <address> up-to-and-including <address>+3 is allocated. 944e98e3e1Schristos 954e98e3e1Schristos max-poll-ticks = <local-count> 964e98e3e1Schristos Sets the maximum interval between polling the external component, 974e98e3e1Schristos expressed in internal cycles. Defaults to 10000. 984e98e3e1Schristos 994e98e3e1Schristos watchdog-interval = <seconds> 1004e98e3e1Schristos Sets the wallclock seconds between watchdog packets sent to the 1014e98e3e1Schristos remote side (may be larger if there's no rv activity in that time). 1024e98e3e1Schristos Defaults to 30. If set to 0, no watchdog packets are sent. 1034e98e3e1Schristos 1044e98e3e1Schristos intnum = <local-int-0> <local-int-1> ... <local-int-31> 1054e98e3e1Schristos Defines a map from remote bit numbers to local values to be emitted 1064e98e3e1Schristos on the "int" port, with the external bit number as the ordinal - 1 1074e98e3e1Schristos of the local translation. E.g. 43 121 would mean map external 1084e98e3e1Schristos (1<<0) to internal 43 and external (1<<1) to internal 121. The 1094e98e3e1Schristos default is unity; no translation. If more than one bit is set in 1104e98e3e1Schristos the remote interrupt word, the intmultiple property can be used to 1114e98e3e1Schristos control the translation. 1124e98e3e1Schristos 1134e98e3e1Schristos intmultiple = <intvalue> 1144e98e3e1Schristos When more than one bit is set in the remote interrupt word, you may 1154e98e3e1Schristos want to map this situation to a separate interrupt value. If this 1164e98e3e1Schristos property is non-zero, it is used as that value. If it is zero, the 1174e98e3e1Schristos local value for the "int" port is the bitwise-or of the translated 1184e98e3e1Schristos local values. 1194e98e3e1Schristos 1204e98e3e1Schristos host = <hostid> 1214e98e3e1Schristos The hostname or address where the simulator to be used listens. 1224e98e3e1Schristos Defaults to "127.0.0.1" 1234e98e3e1Schristos 1244e98e3e1Schristos port = <portnumber> 1254e98e3e1Schristos The hostname or address where the simulator to be used listens. 1264e98e3e1Schristos Defaults to 10000. 1274e98e3e1Schristos 1284e98e3e1Schristos dummy = <value> 1294e98e3e1Schristos or 1304e98e3e1Schristos dummy = <filename> 1314e98e3e1Schristos Don't connect to a remote side; use initial dummy contents from 1324e98e3e1Schristos <filename> (which has to be at least as big as the <size> argument 1334e98e3e1Schristos of reg above) or filled with byte-value <value>. Mailboxes are not 1344e98e3e1Schristos supported (can be defined but can not be used) and remote-memory 1354e98e3e1Schristos accesses don't apply. The main purpose for this property is to 1364e98e3e1Schristos simplify use of configuration and simulated hardware that is 1374e98e3e1Schristos e.g. only trivially initialized but not actually used. 1384e98e3e1Schristos 1394e98e3e1Schristos 1404e98e3e1Schristos PORTS 1414e98e3e1Schristos 1424e98e3e1Schristos int (output) 1434e98e3e1Schristos Driven as a result of a remote interrupt request. The value is a 1444e98e3e1Schristos 32-bit bitset of active interrupts. 1454e98e3e1Schristos 1464e98e3e1Schristos 1474e98e3e1Schristos BUGS 1484e98e3e1Schristos 1494e98e3e1Schristos All and none. 1504e98e3e1Schristos 1514e98e3e1Schristos 1524e98e3e1Schristos PROTOCOL 1534e98e3e1Schristos 1544e98e3e1Schristos This is version 1.0 of this protocol, defining packet format and 1554e98e3e1Schristos actions in a supposedly upward-compatible manner where client and 1564e98e3e1Schristos servers of different versions are expected to interoperate; the 1574e98e3e1Schristos format and the definitions below are hopefully generic enough to 1584e98e3e1Schristos allow this. 1594e98e3e1Schristos 1604e98e3e1Schristos Each connection has a server and a client (this code); the roles 1614e98e3e1Schristos are known beforehand. The client usually corresponds to a CPU and 1624e98e3e1Schristos memory system and the server corresponds to a memory-mapped 1634e98e3e1Schristos register hardware interface and/or a DMA controller. They 1644e98e3e1Schristos communicate using packets with specific commands, of which some 1654e98e3e1Schristos require replies from the other side; most are intiated by the 1664e98e3e1Schristos client with one exception. A reply uses the same format as the 1674e98e3e1Schristos command. 1684e98e3e1Schristos 1694e98e3e1Schristos Packets are at least three bytes long, where the first two bytes 1704e98e3e1Schristos form a header, a 16-bit little-endian number that is the total 1714e98e3e1Schristos length of the packet including the header. There is also a 1724e98e3e1Schristos one-byte command. The payload is optional, depending on the 1734e98e3e1Schristos command. 1744e98e3e1Schristos 1754e98e3e1Schristos [[16-bit-low-byte-of-length] [16-bit-high-byte-of-length] 1764e98e3e1Schristos [command/reply] [payload byte 0] [payload byte 1] 1774e98e3e1Schristos ... [payload byte (length-of-packet - 3)]] 1784e98e3e1Schristos 1794e98e3e1Schristos Commands: 1804e98e3e1Schristos 1814e98e3e1Schristos A client or server that reads an undocumented command may exit with 1824e98e3e1Schristos a hard error. Payload not defined or disallowed below is ignored. 1834e98e3e1Schristos 1844e98e3e1Schristos It is expected that future client versions find out the version of 1854e98e3e1Schristos the server side by polling with base commands, assuming earlier 1864e98e3e1Schristos versions if a certain reply isn't seen, with newly defined payload 1874e98e3e1Schristos parts where earlier versions left it undefined. New commands and 1884e98e3e1Schristos formats are sent only to the other side after the client and server 1894e98e3e1Schristos has found out each others version. Not all servers support all 1904e98e3e1Schristos commands; the type of server and supported set of commands is 1914e98e3e1Schristos expected to be known beforehand. 1924e98e3e1Schristos 1934e98e3e1Schristos RV_READ_CMD = 0 1944e98e3e1Schristos Initiated by the client, requires a reply from the server. The 1954e98e3e1Schristos payload from the client is at least 4 bytes, forming a 4-byte 1964e98e3e1Schristos little-endian address, the rest being undefined. The reply from 1974e98e3e1Schristos the server is at least 8 bytes, forming the same address data as in 1984e98e3e1Schristos the request and the second 4-byte data being the little-endian 1994e98e3e1Schristos contents. 2004e98e3e1Schristos 2014e98e3e1Schristos RV_WRITE_CMD = 1 2024e98e3e1Schristos Initiated by the client, requires a reply from the server. Payload 2034e98e3e1Schristos from the client is at least 8 bytes, forming a 4-byte little-endian 2044e98e3e1Schristos word being the address, the rest being the little-endian contents 2054e98e3e1Schristos to write. The reply from the server is 8 bytes unless elsewhere 2064e98e3e1Schristos agreed otherwise, forming the same address and data as in the 2074e98e3e1Schristos request. The data sent back may have been altered to correspond to 2084e98e3e1Schristos defined parts but can safely be discarded. 2094e98e3e1Schristos 2104e98e3e1Schristos RV_IRQ_CMD = 2 2114e98e3e1Schristos Initiated by the server, no reply. The payload is 4 bytes, forming 2124e98e3e1Schristos a little-endian word with bits numbers corresponding to currently 2134e98e3e1Schristos active interrupt sources; value (1<<N) indicating interrupt source 2144e98e3e1Schristos N being active. 2154e98e3e1Schristos 2164e98e3e1Schristos RV_MEM_RD_CMD = 3 2174e98e3e1Schristos Initiated by the server, requires a reply. A client must know 2184e98e3e1Schristos beforehand when (in command sequence or constant) the server can 2194e98e3e1Schristos send this command and if so must then not send any commands of its 2204e98e3e1Schristos own (including watchdog commands); the server is allowed to assume 2214e98e3e1Schristos that incoming data is only replies to this command. The format is 2224e98e3e1Schristos 8 bytes of data; 4 bytes of little-endian address followed by a 2234e98e3e1Schristos 32-bit little endian word with the number of bytes to read. The 2244e98e3e1Schristos reply is the same address and number of bytes, followed by the data 2254e98e3e1Schristos that had been read. 2264e98e3e1Schristos 2274e98e3e1Schristos RV_MEM_WR_CMD = 4 2284e98e3e1Schristos Initiated by the server, no reply. The format is the same as a 2294e98e3e1Schristos reply to RV_MEM_RD_CMD; a 32-bit little-endian address, followed by 2304e98e3e1Schristos the 32-bit little-endian number of bytes to write (redundant 2314e98e3e1Schristos information but must be consistent with the packet header). 2324e98e3e1Schristos 2334e98e3e1Schristos RV_MBOX_HANDLE_CMD = 5 2344e98e3e1Schristos Initiated by the client, requires a reply. The payload is 4 2354e98e3e1Schristos undefined bytes followed by an binary blob, the size of the 2364e98e3e1Schristos blob given by the packet header. The reply is a 32-bit little 2374e98e3e1Schristos endian number at the same index as the undefined bytes. Actual 2384e98e3e1Schristos semantics are application-specific. 2394e98e3e1Schristos 2404e98e3e1Schristos RV_MBOX_PUT_CMD = 6 2414e98e3e1Schristos Initiated by the client, requires a reply, with the reply using the 2424e98e3e1Schristos RV_MBOX_HANDLE_CMD reply format (i.e. *both* that command and 2434e98e3e1Schristos 32-bit little-endian number). The payload is a 32-bit little 2444e98e3e1Schristos endian number followed by an undefined payload, at most 20 bytes 2454e98e3e1Schristos long. The reply is a 32-bit little endian number. Actual 2464e98e3e1Schristos semantics are application-specific. 2474e98e3e1Schristos 2484e98e3e1Schristos RV_WATCHDOG_CMD = 7 2494e98e3e1Schristos Initiated by the client, no reply. A version 1.0 client sends no 2504e98e3e1Schristos payload; a version 1.0 server should ignore any such payload. A 2514e98e3e1Schristos version 1.0 server must not send a reply. 2524e98e3e1Schristos 2534e98e3e1Schristos 2544e98e3e1Schristos Possible future enhancements: 2554e98e3e1Schristos 2564e98e3e1Schristos Synchronization; server and client reports the number of elapsed 2574e98e3e1Schristos cycles (unit to-be-defined) at each request or notification. 2584e98e3e1Schristos Pretty much the top-of-the-todo-list item. 2594e98e3e1Schristos 2604e98e3e1Schristos Large addresses; 1.0 being restricted to 32-bit addresses. 2614e98e3e1Schristos 2624e98e3e1Schristos Variable-size data; currently restricted to 32-bit register 2634e98e3e1Schristos accesses. 2644e98e3e1Schristos 2654e98e3e1Schristos Specified data endianness (not the packet header) perhaps as part 2664e98e3e1Schristos of an initial format request; currently little-endian only. 2674e98e3e1Schristos 2684e98e3e1Schristos 2694e98e3e1Schristos Usage notes: 2704e98e3e1Schristos When used with servers sending RV_MEM_RD_CMD but being 2714e98e3e1Schristos narrow-minded about indata, set watchdog-interval to 0. Use 2724e98e3e1Schristos multiple rv instances when there are e.g. separate register and 2734e98e3e1Schristos memory servers. Alway log, setting "/rv/trace? true", at the 2744e98e3e1Schristos development phase. Borrow from the test-suite. 2754e98e3e1Schristos */ 2764e98e3e1Schristos 2774e98e3e1Schristos #define RV_FAMILY_NAME "rv" 2784e98e3e1Schristos 2794e98e3e1Schristos enum rv_command { 2804e98e3e1Schristos RV_READ_CMD = 0, 2814e98e3e1Schristos RV_WRITE_CMD = 1, 2824e98e3e1Schristos RV_IRQ_CMD = 2, 2834e98e3e1Schristos RV_MEM_RD_CMD = 3, 2844e98e3e1Schristos RV_MEM_WR_CMD = 4, 2854e98e3e1Schristos RV_MBOX_HANDLE_CMD = 5, 2864e98e3e1Schristos RV_MBOX_PUT_CMD = 6, 2874e98e3e1Schristos RV_WATCHDOG_CMD = 7 2884e98e3e1Schristos }; 2894e98e3e1Schristos 2904e98e3e1Schristos 2914e98e3e1Schristos typedef struct _hw_rv_device 2924e98e3e1Schristos { 2934e98e3e1Schristos /* Mapping of remote interrupt bit-numbers to local ones. */ 2944b169a6bSchristos uint32_t remote_to_local_int[32]; 2954e98e3e1Schristos 2964e98e3e1Schristos /* When multiple bits are set, a non-zero value here indicates that 2974e98e3e1Schristos this value should be used instead. */ 2984b169a6bSchristos uint32_t intmultiple; 2994e98e3e1Schristos 3004e98e3e1Schristos /* Local address of registers. */ 3014b169a6bSchristos uint32_t reg_address; 3024e98e3e1Schristos 3034e98e3e1Schristos /* Size of register bank in bytes. */ 3044b169a6bSchristos uint32_t reg_size; 3054e98e3e1Schristos 3064e98e3e1Schristos /* Remote address of registers. */ 3074b169a6bSchristos uint32_t remote_reg_address; 3084e98e3e1Schristos 3094e98e3e1Schristos /* Local address of DMA:able memory. */ 3104b169a6bSchristos uint32_t mem_address; 3114e98e3e1Schristos 3124e98e3e1Schristos /* Size of DMA:able memory in bytes. */ 3134b169a6bSchristos uint32_t mem_size; 3144e98e3e1Schristos 3154e98e3e1Schristos /* Bitmask for valid DMA request size. */ 3164b169a6bSchristos uint32_t mem_burst_mask; 3174e98e3e1Schristos 3184e98e3e1Schristos /* Remote address of DMA:able memory. */ 3194b169a6bSchristos uint32_t remote_mem_address; 3204e98e3e1Schristos 3214e98e3e1Schristos /* (Local) address of mbox; where to put a pointer to the mbox to be 3224e98e3e1Schristos sent. */ 3234b169a6bSchristos uint32_t mbox_address; 3244e98e3e1Schristos 3254e98e3e1Schristos /* Probably not 127.0.0.1:10000. */ 3264e98e3e1Schristos const char *host; 3274e98e3e1Schristos int port; 3284e98e3e1Schristos 3294e98e3e1Schristos /* If non-NULL, points to memory to use instead of connection. */ 3304b169a6bSchristos uint8_t *dummy; 3314e98e3e1Schristos 3324e98e3e1Schristos /* File descriptor for the socket. Set to -1 when error. Only one 3334e98e3e1Schristos of dummy and this is active. */ 3344e98e3e1Schristos int fd; 3354e98e3e1Schristos 3364e98e3e1Schristos /* Stashed errno, as we don't emit an error right away. */ 3374e98e3e1Schristos int saved_errno; 3384e98e3e1Schristos 3394e98e3e1Schristos /* This, plus latency because the CPU might not be checking until a 3404e98e3e1Schristos CTI insn (usually a branch or a jump) is the interval in cycles 3414e98e3e1Schristos between the rv is polled for e.g. DMA requests. */ 3424b169a6bSchristos uint32_t max_tick_poll_interval; 3434e98e3e1Schristos 3444e98e3e1Schristos /* Running counter for exponential backoff up to 3454e98e3e1Schristos max_tick_poll_interval to avoid polling the connection 3464e98e3e1Schristos unnecessarily often. Set to 1 when rv activity (read/write 3474e98e3e1Schristos register, DMA request) is detected. */ 3484b169a6bSchristos uint32_t next_period; 3494e98e3e1Schristos 3504e98e3e1Schristos /* This is the interval in wall-clock seconds between watchdog 3514e98e3e1Schristos packets are sent to the remote side. Zero means no watchdog 3524e98e3e1Schristos packets. */ 3534b169a6bSchristos uint32_t watchdog_interval; 3544e98e3e1Schristos 3554e98e3e1Schristos /* Last time we sent a watchdog packet. */ 3564e98e3e1Schristos struct timeval last_wdog_time; 3574e98e3e1Schristos 3584e98e3e1Schristos /* Mostly used as a kludge for knowing which rv:s have poll events 3594e98e3e1Schristos active. */ 3604e98e3e1Schristos struct hw_event *poll_callback; 3614e98e3e1Schristos } hw_rv_device; 3624e98e3e1Schristos 3634e98e3e1Schristos 3644e98e3e1Schristos /* We might add ports in the future, so keep this an enumeration. */ 3654e98e3e1Schristos enum 3664e98e3e1Schristos { 3674e98e3e1Schristos INT_PORT 3684e98e3e1Schristos }; 3694e98e3e1Schristos 3704e98e3e1Schristos /* Our ports. */ 3714e98e3e1Schristos static const struct hw_port_descriptor hw_rv_ports[] = { 3724e98e3e1Schristos { "int", INT_PORT, 0, output_port }, 3734e98e3e1Schristos { NULL } 3744e98e3e1Schristos }; 3754e98e3e1Schristos 3764e98e3e1Schristos /* Send LEN bytes of data from BUF to the socket. Abort on 3774e98e3e1Schristos errors. */ 3784e98e3e1Schristos 3794e98e3e1Schristos static void 3804e98e3e1Schristos hw_rv_write (struct hw *me, 3814e98e3e1Schristos void *buf, 3824e98e3e1Schristos unsigned int len) 3834e98e3e1Schristos { 3844e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 3854b169a6bSchristos uint8_t *bufp = buf; 3864e98e3e1Schristos 3874e98e3e1Schristos /* If we don't have a valid fd here, it's because we got an error 3884e98e3e1Schristos initially, and we suppressed that error. */ 3894e98e3e1Schristos if (rv->fd == -1) 3904e98e3e1Schristos hw_abort (me, "couldn't open a connection to %s:%d because: %s", 3914e98e3e1Schristos rv->host, rv->port, strerror (rv->saved_errno)); 3924e98e3e1Schristos 3934e98e3e1Schristos while (len > 0) 3944e98e3e1Schristos { 3954e98e3e1Schristos ssize_t ret = write (rv->fd, bufp, len); 3964e98e3e1Schristos if (ret < 0) 3974e98e3e1Schristos /* FIXME: More graceful exit. */ 3984e98e3e1Schristos hw_abort (me, "write to %s:%d failed: %s\n", rv->host, rv->port, 3994e98e3e1Schristos strerror (errno)); 4004e98e3e1Schristos 4014e98e3e1Schristos len -= ret; 4024e98e3e1Schristos bufp += ret; 4034e98e3e1Schristos } 4044e98e3e1Schristos } 4054e98e3e1Schristos 4064e98e3e1Schristos /* Read LEN bytes of data into BUF from the socket. Set the file 4074e98e3e1Schristos descriptor to -1 if there's an error. */ 4084e98e3e1Schristos 4094e98e3e1Schristos static void 4104e98e3e1Schristos hw_rv_read (struct hw *me, 4114e98e3e1Schristos void *buf, 4124e98e3e1Schristos unsigned int len) 4134e98e3e1Schristos { 4144e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 4154b169a6bSchristos uint8_t *bufp = buf; 4164e98e3e1Schristos 4174e98e3e1Schristos while (len > 0) 4184e98e3e1Schristos { 4194e98e3e1Schristos ssize_t ret = read (rv->fd, bufp, len); 4204e98e3e1Schristos 4214e98e3e1Schristos /* We get all zero if the remote end quits, but no error 4224e98e3e1Schristos indication; even select says there's data active. */ 4234e98e3e1Schristos if (ret <= 0) 4244e98e3e1Schristos { 4254e98e3e1Schristos if (close (rv->fd) != 0) 4264e98e3e1Schristos /* FIXME: More graceful exit. */ 4274e98e3e1Schristos hw_abort (me, "read from %s:%d failed: %d\n", rv->host, rv->port, errno); 4284e98e3e1Schristos rv->fd = -1; 4294e98e3e1Schristos return; 4304e98e3e1Schristos } 4314e98e3e1Schristos 4324e98e3e1Schristos len -= ret; 4334e98e3e1Schristos bufp += ret; 4344e98e3e1Schristos } 4354e98e3e1Schristos } 4364e98e3e1Schristos 4374e98e3e1Schristos /* Construct and send a packet of data of type CMD and len 4384e98e3e1Schristos LEN_NOHEADER (not counting the header...). */ 4394e98e3e1Schristos 4404e98e3e1Schristos static void 4414e98e3e1Schristos hw_rv_send (struct hw *me, 4424e98e3e1Schristos unsigned int cmd, 4434e98e3e1Schristos void *msg, 4444e98e3e1Schristos unsigned int len_noheader) 4454e98e3e1Schristos { 4464b169a6bSchristos uint8_t buf[32+3]; 4474b169a6bSchristos uint8_t *bufp; 4484e98e3e1Schristos unsigned int len = len_noheader + 3; 4494e98e3e1Schristos 4504e98e3e1Schristos buf[0] = len & 255; 4514e98e3e1Schristos buf[1] = (len >> 8) & 255; 4524e98e3e1Schristos buf[2] = cmd; 4534e98e3e1Schristos 4544e98e3e1Schristos if (len > sizeof (buf)) 4554e98e3e1Schristos { 4564e98e3e1Schristos hw_rv_write (me, buf, 3); 4574e98e3e1Schristos len = len_noheader; 4584e98e3e1Schristos bufp = msg; 4594e98e3e1Schristos } 4604e98e3e1Schristos else 4614e98e3e1Schristos { 4624e98e3e1Schristos memcpy (buf + 3, msg, len_noheader); 4634e98e3e1Schristos bufp = buf; 4644e98e3e1Schristos } 4654e98e3e1Schristos 4664e98e3e1Schristos hw_rv_write (me, bufp, len); 4674e98e3e1Schristos } 4684e98e3e1Schristos 4694e98e3e1Schristos /* Handle incoming DMA requests as per the RV_MEM_RD_CMD packet. 4704e98e3e1Schristos Abort on errors. */ 4714e98e3e1Schristos 4724e98e3e1Schristos static void 4734e98e3e1Schristos hw_rv_read_mem (struct hw *me, unsigned int len) 4744e98e3e1Schristos { 4754e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 4764e98e3e1Schristos /* If you change this size, please adjust the mem2 testcase. */ 4774b169a6bSchristos uint8_t buf[32+8]; 4784b169a6bSchristos uint8_t *bufp = buf; 4794b169a6bSchristos uint32_t leaddr; 4804b169a6bSchristos uint32_t addr; 4814b169a6bSchristos uint32_t lelen; 4824b169a6bSchristos uint32_t i; 4834e98e3e1Schristos 4844e98e3e1Schristos if (len != 8) 4854e98e3e1Schristos hw_abort (me, "expected DMA read request len 8+3, got %d+3", len); 4864e98e3e1Schristos 4874e98e3e1Schristos hw_rv_read (me, &leaddr, 4); 4884e98e3e1Schristos hw_rv_read (me, &lelen, 4); 4894e98e3e1Schristos len = LE2H_4 (lelen); 4904e98e3e1Schristos addr = LE2H_4 (leaddr); 4914e98e3e1Schristos 4924e98e3e1Schristos if (addr < rv->remote_mem_address 4934e98e3e1Schristos || addr >= rv->remote_mem_address + rv->mem_size) 4944e98e3e1Schristos hw_abort (me, "DMA read at remote 0x%x; outside [0x%x..0x%x-1]", 4954e98e3e1Schristos (unsigned) addr, (unsigned) rv->remote_mem_address, 4964e98e3e1Schristos (unsigned) (rv->remote_mem_address + rv->mem_size)); 4974e98e3e1Schristos addr = addr - rv->remote_mem_address + rv->mem_address; 4984e98e3e1Schristos 4994e98e3e1Schristos if (len == 0) 5004e98e3e1Schristos hw_abort (me, "DMA read request for 0 bytes isn't supported"); 5014e98e3e1Schristos 5024e98e3e1Schristos if (len & ~rv->mem_burst_mask) 5034e98e3e1Schristos hw_abort (me, "DMA trying to read %d bytes; not matching mask of 0x%x", 5044e98e3e1Schristos len, rv->mem_burst_mask); 5054e98e3e1Schristos if (len + 8 > sizeof (buf)) 5064e98e3e1Schristos bufp = hw_malloc (me, len + 8); 5074e98e3e1Schristos 5084e98e3e1Schristos HW_TRACE ((me, "DMA R 0x%x..0x%x", addr, addr + len -1)); 5094e98e3e1Schristos hw_dma_read_buffer (me, bufp + 8, 0, addr, len); 5104e98e3e1Schristos if (hw_trace_p (me)) 5114e98e3e1Schristos for (i = 0; i < len; i += 4) 5124e98e3e1Schristos HW_TRACE ((me, "0x%x: %02x %02x %02x %02x", 5134e98e3e1Schristos addr + i, 5144e98e3e1Schristos bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11])); 5154e98e3e1Schristos 5164e98e3e1Schristos memcpy (bufp, &leaddr, 4); 5174e98e3e1Schristos memcpy (bufp + 4, &lelen, 4); 5184e98e3e1Schristos hw_rv_send (me, RV_MEM_RD_CMD, bufp, len + 8); 5194e98e3e1Schristos if (bufp != buf) 5204e98e3e1Schristos hw_free (me, bufp); 5214e98e3e1Schristos } 5224e98e3e1Schristos 5234e98e3e1Schristos /* Handle incoming DMA requests as per the RV_MEM_WR_CMD packet. 5244e98e3e1Schristos Abort on errors. */ 5254e98e3e1Schristos 5264e98e3e1Schristos static void 5274e98e3e1Schristos hw_rv_write_mem (struct hw *me, unsigned int plen) 5284e98e3e1Schristos { 5294e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 5304e98e3e1Schristos /* If you change this size, please adjust the mem2 testcase. */ 5314b169a6bSchristos uint8_t buf[32+8]; 5324b169a6bSchristos uint8_t *bufp = buf; 5334b169a6bSchristos uint32_t leaddr; 5344b169a6bSchristos uint32_t addr; 5354b169a6bSchristos uint32_t lelen; 5364b169a6bSchristos uint32_t len; 5374b169a6bSchristos uint32_t i; 5384e98e3e1Schristos 5394e98e3e1Schristos hw_rv_read (me, &leaddr, 4); 5404e98e3e1Schristos hw_rv_read (me, &lelen, 4); 5414e98e3e1Schristos len = LE2H_4 (lelen); 5424e98e3e1Schristos addr = LE2H_4 (leaddr); 5434e98e3e1Schristos 5444e98e3e1Schristos if (len != plen - 8) 5454e98e3e1Schristos hw_abort (me, 5464e98e3e1Schristos "inconsistency in DMA write request packet: " 5474e98e3e1Schristos "envelope %d+3, inner %d bytes", plen, len); 5484e98e3e1Schristos 5494e98e3e1Schristos if (addr < rv->remote_mem_address 5504e98e3e1Schristos || addr >= rv->remote_mem_address + rv->mem_size) 5514e98e3e1Schristos hw_abort (me, "DMA write at remote 0x%x; outside [0x%x..0x%x-1]", 5524e98e3e1Schristos (unsigned) addr, (unsigned) rv->remote_mem_address, 5534e98e3e1Schristos (unsigned) (rv->remote_mem_address + rv->mem_size)); 5544e98e3e1Schristos 5554e98e3e1Schristos addr = addr - rv->remote_mem_address + rv->mem_address; 5564e98e3e1Schristos if (len == 0) 5574e98e3e1Schristos hw_abort (me, "DMA write request for 0 bytes isn't supported"); 5584e98e3e1Schristos 5594e98e3e1Schristos if (len & ~rv->mem_burst_mask) 5604e98e3e1Schristos hw_abort (me, "DMA trying to write %d bytes; not matching mask of 0x%x", 5614e98e3e1Schristos len, rv->mem_burst_mask); 5624e98e3e1Schristos if (len + 8 > sizeof (buf)) 5634e98e3e1Schristos bufp = hw_malloc (me, len + 8); 5644e98e3e1Schristos 5654e98e3e1Schristos hw_rv_read (me, bufp + 8, len); 5664e98e3e1Schristos HW_TRACE ((me, "DMA W 0x%x..0x%x", addr, addr + len - 1)); 5674e98e3e1Schristos hw_dma_write_buffer (me, bufp + 8, 0, addr, len, 0); 5684e98e3e1Schristos if (hw_trace_p (me)) 5694e98e3e1Schristos for (i = 0; i < len; i += 4) 5704e98e3e1Schristos HW_TRACE ((me, "0x%x: %02x %02x %02x %02x", 5714e98e3e1Schristos addr + i, 5724e98e3e1Schristos bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11])); 5734e98e3e1Schristos if (bufp != buf) 5744e98e3e1Schristos hw_free (me, bufp); 5754e98e3e1Schristos } 5764e98e3e1Schristos 5774e98e3e1Schristos static void 5784e98e3e1Schristos hw_rv_irq (struct hw *me, unsigned int len) 5794e98e3e1Schristos { 5804e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 5814b169a6bSchristos uint32_t intbitsle; 5824b169a6bSchristos uint32_t intbits_ext; 5834b169a6bSchristos uint32_t intval = 0; 5844e98e3e1Schristos int i; 5854e98e3e1Schristos 5864e98e3e1Schristos if (len != 4) 5874e98e3e1Schristos hw_abort (me, "IRQ with %d data not supported", len); 5884e98e3e1Schristos 5894e98e3e1Schristos hw_rv_read (me, &intbitsle, 4); 5904e98e3e1Schristos intbits_ext = LE2H_4 (intbitsle); 5914e98e3e1Schristos for (i = 0; i < 32; i++) 5924e98e3e1Schristos if ((intbits_ext & (1 << i)) != 0) 5934e98e3e1Schristos intval |= rv->remote_to_local_int[i]; 5944e98e3e1Schristos if ((intbits_ext & ~(intbits_ext - 1)) != intbits_ext 5954e98e3e1Schristos && rv->intmultiple != 0) 5964e98e3e1Schristos intval = rv->intmultiple; 5974e98e3e1Schristos 5984e98e3e1Schristos HW_TRACE ((me, "IRQ 0x%x", intval)); 5994e98e3e1Schristos hw_port_event (me, INT_PORT, intval); 6004e98e3e1Schristos } 6014e98e3e1Schristos 6024e98e3e1Schristos /* Handle incoming interrupt notifications as per the RV_IRQ_CMD 6034e98e3e1Schristos packet. Abort on errors. */ 6044e98e3e1Schristos 6054e98e3e1Schristos static void 6064e98e3e1Schristos hw_rv_handle_incoming (struct hw *me, 6074e98e3e1Schristos int expected_type, 6084b169a6bSchristos uint8_t *buf, 6094e98e3e1Schristos unsigned int *return_len) 6104e98e3e1Schristos { 6114e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 6124b169a6bSchristos uint8_t cbuf[32]; 6134e98e3e1Schristos unsigned int len; 6144e98e3e1Schristos unsigned int cmd; 6154e98e3e1Schristos 6164e98e3e1Schristos while (1) 6174e98e3e1Schristos { 6184e98e3e1Schristos hw_rv_read (me, cbuf, 3); 6194e98e3e1Schristos 6204e98e3e1Schristos if (rv->fd == -1) 6214e98e3e1Schristos return; 6224e98e3e1Schristos 6234e98e3e1Schristos len = cbuf[0] + cbuf[1] * 256 - 3; 6244e98e3e1Schristos cmd = cbuf[2]; 6254e98e3e1Schristos 6264e98e3e1Schristos /* These come in "asynchronously"; not as a reply. */ 6274e98e3e1Schristos switch (cmd) 6284e98e3e1Schristos { 6294e98e3e1Schristos case RV_IRQ_CMD: 6304e98e3e1Schristos hw_rv_irq (me, len); 6314e98e3e1Schristos break; 6324e98e3e1Schristos 6334e98e3e1Schristos case RV_MEM_RD_CMD: 6344e98e3e1Schristos hw_rv_read_mem (me, len); 6354e98e3e1Schristos break; 6364e98e3e1Schristos 6374e98e3e1Schristos case RV_MEM_WR_CMD: 6384e98e3e1Schristos hw_rv_write_mem (me, len); 6394e98e3e1Schristos break; 6404e98e3e1Schristos } 6414e98e3e1Schristos 6424e98e3e1Schristos /* Something is incoming from the other side, so tighten up all 6434e98e3e1Schristos slack at the next wait. */ 6444e98e3e1Schristos rv->next_period = 1; 6454e98e3e1Schristos 6464e98e3e1Schristos switch (cmd) 6474e98e3e1Schristos { 6484e98e3e1Schristos case RV_MEM_RD_CMD: 6494e98e3e1Schristos case RV_MEM_WR_CMD: 6504e98e3e1Schristos case RV_IRQ_CMD: 6514e98e3e1Schristos /* Don't try to handle more than one of these if we were'nt 6524e98e3e1Schristos expecting a reply. */ 6534e98e3e1Schristos if (expected_type == -1) 6544e98e3e1Schristos return; 6554e98e3e1Schristos continue; 6564e98e3e1Schristos } 6574e98e3e1Schristos 6584e98e3e1Schristos /* Require a match between this supposed-reply and the command 6594e98e3e1Schristos for the rest. */ 6604e98e3e1Schristos if (cmd != expected_type) 6614e98e3e1Schristos hw_abort (me, "unexpected reply, expected command %d, got %d", 6624e98e3e1Schristos expected_type, cmd); 6634e98e3e1Schristos 6644e98e3e1Schristos switch (cmd) 6654e98e3e1Schristos { 6664e98e3e1Schristos case RV_MBOX_PUT_CMD: 6674e98e3e1Schristos case RV_MBOX_HANDLE_CMD: 6684e98e3e1Schristos case RV_WRITE_CMD: 6694e98e3e1Schristos case RV_READ_CMD: 6704e98e3e1Schristos hw_rv_read (me, buf, len <= *return_len ? len : *return_len); 6714e98e3e1Schristos *return_len = len; 6724e98e3e1Schristos break; 6734e98e3e1Schristos } 6744e98e3e1Schristos break; 6754e98e3e1Schristos } 6764e98e3e1Schristos } 6774e98e3e1Schristos 6784e98e3e1Schristos /* Send a watchdog packet. Make a note of wallclock time. */ 6794e98e3e1Schristos 6804e98e3e1Schristos static void 6814e98e3e1Schristos hw_rv_send_wdog (struct hw *me) 6824e98e3e1Schristos { 6834e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 6844e98e3e1Schristos HW_TRACE ((me, "WD")); 6854e98e3e1Schristos gettimeofday (&rv->last_wdog_time, NULL); 6864e98e3e1Schristos hw_rv_send (me, RV_WATCHDOG_CMD, "", 0); 6874e98e3e1Schristos } 6884e98e3e1Schristos 6894e98e3e1Schristos /* Poll the remote side: see if there's any incoming traffic; handle a 6904e98e3e1Schristos packet if so. Send a watchdog packet if it's time to do so. 6914e98e3e1Schristos Beware that the Linux select call indicates traffic for a socket 6924e98e3e1Schristos that the remote side has closed (which may be because it was 6934e98e3e1Schristos finished; don't hork until we need to write something just because 6944e98e3e1Schristos we're polling). */ 6954e98e3e1Schristos 6964e98e3e1Schristos static void 6974e98e3e1Schristos hw_rv_poll_once (struct hw *me) 6984e98e3e1Schristos { 6994e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 7004e98e3e1Schristos fd_set rfds; 7014e98e3e1Schristos fd_set efds; 7024e98e3e1Schristos struct timeval now; 7034e98e3e1Schristos int ret; 7044e98e3e1Schristos struct timeval tv; 7054e98e3e1Schristos 7064e98e3e1Schristos if (rv->fd == -1) 7074e98e3e1Schristos /* Connection has died or was never initiated. */ 7084e98e3e1Schristos return; 7094e98e3e1Schristos 7104e98e3e1Schristos FD_ZERO (&rfds); 7114e98e3e1Schristos FD_SET (rv->fd, &rfds); 7124e98e3e1Schristos FD_ZERO (&efds); 7134e98e3e1Schristos FD_SET (rv->fd, &efds); 7144e98e3e1Schristos tv.tv_sec = 0; 7154e98e3e1Schristos tv.tv_usec = 0; 7164e98e3e1Schristos 7174e98e3e1Schristos ret = select (rv->fd + 1, &rfds, NULL, &efds, &tv); 7184e98e3e1Schristos gettimeofday (&now, NULL); 7194e98e3e1Schristos 7204e98e3e1Schristos if (ret < 0) 7214e98e3e1Schristos hw_abort (me, "select failed: %d\n", errno); 7224e98e3e1Schristos 7234e98e3e1Schristos if (rv->watchdog_interval != 0 7244e98e3e1Schristos && now.tv_sec - rv->last_wdog_time.tv_sec >= rv->watchdog_interval) 7254e98e3e1Schristos hw_rv_send_wdog (me); 7264e98e3e1Schristos 7274e98e3e1Schristos if (FD_ISSET (rv->fd, &rfds)) 7284e98e3e1Schristos hw_rv_handle_incoming (me, -1, NULL, NULL); 7294e98e3e1Schristos } 7304e98e3e1Schristos 7314e98e3e1Schristos /* Initialize mapping of remote-to-local interrupt data. */ 7324e98e3e1Schristos 7334e98e3e1Schristos static void 7344e98e3e1Schristos hw_rv_map_ints (struct hw *me) 7354e98e3e1Schristos { 7364e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 7374e98e3e1Schristos int i; 7384e98e3e1Schristos 7394e98e3e1Schristos for (i = 0; i < 32; i++) 7404e98e3e1Schristos rv->remote_to_local_int[i] = 1 << i; 7414e98e3e1Schristos 7424e98e3e1Schristos if (hw_find_property (me, "intnum") != NULL) 7434e98e3e1Schristos for (i = 0; i < 32; i++) 7444e98e3e1Schristos { 7454e98e3e1Schristos signed_cell val = -1; 7464e98e3e1Schristos if (hw_find_integer_array_property (me, "intnum", i, &val) > 0) 7474e98e3e1Schristos { 7484e98e3e1Schristos if (val > 0) 7494e98e3e1Schristos rv->remote_to_local_int[i] = val; 7504e98e3e1Schristos else 7514e98e3e1Schristos hw_abort (me, "property \"intnum@%d\" must be > 0; is %d", 7524e98e3e1Schristos i, (int) val); 7534e98e3e1Schristos } 7544e98e3e1Schristos } 7554e98e3e1Schristos } 7564e98e3e1Schristos 7574e98e3e1Schristos /* Handle the after-N-ticks "poll event", calling the poll-the-fd 7584e98e3e1Schristos method. Update the period. */ 7594e98e3e1Schristos 7604e98e3e1Schristos static void 7614e98e3e1Schristos do_poll_event (struct hw *me, void *data) 7624e98e3e1Schristos { 7634e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 7644b169a6bSchristos uint32_t new_period; 7654e98e3e1Schristos 7664e98e3e1Schristos if (rv->dummy != NULL) 7674e98e3e1Schristos return; 7684e98e3e1Schristos 7694e98e3e1Schristos hw_rv_poll_once (me); 7704e98e3e1Schristos if (rv->fd >= 0) 7714e98e3e1Schristos rv->poll_callback 7724e98e3e1Schristos = hw_event_queue_schedule (me, rv->next_period, do_poll_event, NULL); 7734e98e3e1Schristos 7744e98e3e1Schristos new_period = rv->next_period * 2; 7754e98e3e1Schristos if (new_period <= rv->max_tick_poll_interval) 7764e98e3e1Schristos rv->next_period = new_period; 7774e98e3e1Schristos } 7784e98e3e1Schristos 7794e98e3e1Schristos /* HW tree traverse function for hw_rv_add_init. */ 7804e98e3e1Schristos 7814e98e3e1Schristos static void 7824e98e3e1Schristos hw_rv_add_poller (struct hw *me, void *data) 7834e98e3e1Schristos { 7844e98e3e1Schristos hw_rv_device *rv; 7854e98e3e1Schristos 7864e98e3e1Schristos if (hw_family (me) == NULL 7874e98e3e1Schristos || strcmp (hw_family (me), RV_FAMILY_NAME) != 0) 7884e98e3e1Schristos return; 7894e98e3e1Schristos 7904e98e3e1Schristos rv = (hw_rv_device *) hw_data (me); 7914e98e3e1Schristos if (rv->poll_callback != NULL) 7924e98e3e1Schristos return; 7934e98e3e1Schristos 7944e98e3e1Schristos rv->poll_callback 7954e98e3e1Schristos = hw_event_queue_schedule (me, 1, do_poll_event, NULL); 7964e98e3e1Schristos } 7974e98e3e1Schristos 7984e98e3e1Schristos /* Simulator module init function for hw_rv_add_init. */ 7994e98e3e1Schristos 8004e98e3e1Schristos /* FIXME: For the call so hw_tree_traverse, we need to know that the 8014e98e3e1Schristos first member of struct sim_hw is the struct hw *root, but there's 8024e98e3e1Schristos no accessor method and struct sim_hw is defined in sim-hw.c only. 8034e98e3e1Schristos Hence this hack, until an accessor is added, or there's a traverse 8044e98e3e1Schristos function that takes a SIM_DESC argument. */ 8054e98e3e1Schristos struct sim_hw { struct hw *tree; }; 8064e98e3e1Schristos 8074e98e3e1Schristos static SIM_RC 8084e98e3e1Schristos hw_rv_add_rv_pollers (SIM_DESC sd) 8094e98e3e1Schristos { 8104e98e3e1Schristos hw_tree_traverse (STATE_HW (sd)->tree, hw_rv_add_poller, NULL, NULL); 8114e98e3e1Schristos return SIM_RC_OK; 8124e98e3e1Schristos } 8134e98e3e1Schristos 8144e98e3e1Schristos /* We need to add events for polling, but we can't add one from the 8154e98e3e1Schristos finish-function, and there are no other call points, at least for 8164e98e3e1Schristos instances without "reg" (when there are just DMA requests from the 8174e98e3e1Schristos remote end; no locally initiated activity). Therefore we add a 8184e98e3e1Schristos simulator module init function, but those don't have private 8194e98e3e1Schristos payload arguments; just a SD argument. We cope by parsing the HW 8204e98e3e1Schristos root and making sure *all* "rv":s have poll callbacks installed. 8214e98e3e1Schristos Luckily, this is just an initialization step, and not many 8224e98e3e1Schristos simultaneous instances of rv are expected: we get a N**2 complexity 8234e98e3e1Schristos for visits to each rv node by this method. */ 8244e98e3e1Schristos 8254e98e3e1Schristos static void 8264e98e3e1Schristos hw_rv_add_init (struct hw *me) 8274e98e3e1Schristos { 8284e98e3e1Schristos sim_module_add_init_fn (hw_system (me), hw_rv_add_rv_pollers); 8294e98e3e1Schristos } 8304e98e3e1Schristos 8314e98e3e1Schristos /* Open up a connection to the other side. Abort on errors. */ 8324e98e3e1Schristos 8334e98e3e1Schristos static void 8344e98e3e1Schristos hw_rv_init_socket (struct hw *me) 8354e98e3e1Schristos { 8364e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 8374e98e3e1Schristos int sock; 8384e98e3e1Schristos struct sockaddr_in server; 8394e98e3e1Schristos 8404e98e3e1Schristos rv->fd = -1; 8414e98e3e1Schristos 8424e98e3e1Schristos if (rv->dummy != NULL) 8434e98e3e1Schristos return; 8444e98e3e1Schristos 8454e98e3e1Schristos memset (&server, 0, sizeof (server)); 8464e98e3e1Schristos server.sin_family = AF_INET; 8474e98e3e1Schristos server.sin_addr.s_addr = inet_addr (rv->host); 8484e98e3e1Schristos 8494e98e3e1Schristos /* Solaris 2.7 lacks this macro. */ 8504e98e3e1Schristos #ifndef INADDR_NONE 8514e98e3e1Schristos #define INADDR_NONE -1 8524e98e3e1Schristos #endif 8534e98e3e1Schristos 8544e98e3e1Schristos if (server.sin_addr.s_addr == INADDR_NONE) 8554e98e3e1Schristos { 8564e98e3e1Schristos struct hostent *h; 8574e98e3e1Schristos h = gethostbyname (rv->host); 8584e98e3e1Schristos if (h != NULL) 8594e98e3e1Schristos { 8604e98e3e1Schristos memcpy (&server.sin_addr, h->h_addr, h->h_length); 8614e98e3e1Schristos server.sin_family = h->h_addrtype; 8624e98e3e1Schristos } 8634e98e3e1Schristos else 8644e98e3e1Schristos hw_abort (me, "can't resolve host %s", rv->host); 8654e98e3e1Schristos } 8664e98e3e1Schristos 8674e98e3e1Schristos server.sin_port = htons (rv->port); 8684e98e3e1Schristos sock = socket (AF_INET, SOCK_STREAM, 0); 8694e98e3e1Schristos 8704e98e3e1Schristos if (sock == -1) 8714e98e3e1Schristos hw_abort (me, "can't get a socket for %s:%d connection", 8724e98e3e1Schristos rv->host, rv->port); 8734e98e3e1Schristos 8744e98e3e1Schristos if (connect (sock, (struct sockaddr *) &server, sizeof server) >= 0) 8754e98e3e1Schristos { 8764e98e3e1Schristos rv->fd = sock; 8774e98e3e1Schristos 8784e98e3e1Schristos /* FIXME: init packet here. Maybe start packet too. */ 8794e98e3e1Schristos if (rv->watchdog_interval != 0) 8804e98e3e1Schristos hw_rv_send_wdog (me); 8814e98e3e1Schristos } 8824e98e3e1Schristos else 8834e98e3e1Schristos /* Stash the errno for later display, if some connection activity 8844e98e3e1Schristos is requested. Don't emit an error here; we might have been 8854e98e3e1Schristos called just for test purposes. */ 8864e98e3e1Schristos rv->saved_errno = errno; 8874e98e3e1Schristos } 8884e98e3e1Schristos 8894e98e3e1Schristos /* Local rv register reads end up here. */ 8904e98e3e1Schristos 8914e98e3e1Schristos static unsigned int 8924e98e3e1Schristos hw_rv_reg_read (struct hw *me, 8934e98e3e1Schristos void *dest, 8944e98e3e1Schristos int space, 8954e98e3e1Schristos unsigned_word addr, 8964e98e3e1Schristos unsigned int nr_bytes) 8974e98e3e1Schristos { 8984e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 8994b169a6bSchristos uint8_t addr_data[8] = ""; 9004b169a6bSchristos uint32_t a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address); 9014e98e3e1Schristos unsigned int len = 8; 9024e98e3e1Schristos 9034e98e3e1Schristos if (nr_bytes != 4) 9044e98e3e1Schristos hw_abort (me, "must be four byte read"); 9054e98e3e1Schristos 9064e98e3e1Schristos if (addr == rv->mbox_address) 9074e98e3e1Schristos hw_abort (me, "invalid read of mbox address 0x%x", 9084e98e3e1Schristos (unsigned) rv->mbox_address); 9094e98e3e1Schristos 9104e98e3e1Schristos memcpy (addr_data, &a_l, 4); 9114e98e3e1Schristos HW_TRACE ((me, "REG R 0x%x", addr)); 9124e98e3e1Schristos if (rv->dummy != NULL) 9134e98e3e1Schristos { 9144e98e3e1Schristos len = 8; 9154e98e3e1Schristos memcpy (addr_data + 4, rv->dummy + addr - rv->reg_address, 4); 9164e98e3e1Schristos } 9174e98e3e1Schristos else 9184e98e3e1Schristos { 9194e98e3e1Schristos hw_rv_send (me, RV_READ_CMD, addr_data, len); 9204e98e3e1Schristos hw_rv_handle_incoming (me, RV_READ_CMD, addr_data, &len); 9214e98e3e1Schristos } 9224e98e3e1Schristos 9234e98e3e1Schristos if (len != 8) 9244e98e3e1Schristos hw_abort (me, "read %d != 8 bytes returned", len); 9254e98e3e1Schristos HW_TRACE ((me, ":= 0x%02x%02x%02x%02x", 9264e98e3e1Schristos addr_data[7], addr_data[6], addr_data[5], addr_data[4])); 9274e98e3e1Schristos memcpy (dest, addr_data + 4, 4); 9284e98e3e1Schristos return nr_bytes; 9294e98e3e1Schristos } 9304e98e3e1Schristos 9314e98e3e1Schristos /* Local rv mbox requests (handle or put) end up here. */ 9324e98e3e1Schristos 9334e98e3e1Schristos static void 9344e98e3e1Schristos hw_rv_mbox (struct hw *me, unsigned_word address) 9354e98e3e1Schristos { 9364b169a6bSchristos uint8_t buf[256+3]; 9374e98e3e1Schristos unsigned int cmd; 9384e98e3e1Schristos unsigned int rlen; 9394b169a6bSchristos uint32_t i; 9404e98e3e1Schristos unsigned int len 9414e98e3e1Schristos = hw_dma_read_buffer (me, buf, 0, address, 3); 9424e98e3e1Schristos 9434e98e3e1Schristos if (len != 3) 9444e98e3e1Schristos hw_abort (me, "mbox read %d != 3 bytes returned", len); 9454e98e3e1Schristos 9464e98e3e1Schristos cmd = buf[2]; 9474e98e3e1Schristos if (cmd != RV_MBOX_HANDLE_CMD && cmd != RV_MBOX_PUT_CMD) 9484e98e3e1Schristos hw_abort (me, "unsupported mbox command %d", cmd); 9494e98e3e1Schristos 9504e98e3e1Schristos len = buf[0] + buf[1]*256; 9514e98e3e1Schristos 9524e98e3e1Schristos if (len > sizeof (buf)) 9534e98e3e1Schristos hw_abort (me, "mbox cmd %d send size %d unsupported", cmd, len); 9544e98e3e1Schristos 9554e98e3e1Schristos rlen = hw_dma_read_buffer (me, buf + 3, 0, address + 3, len - 3); 9564e98e3e1Schristos if (rlen != len - 3) 9574e98e3e1Schristos hw_abort (me, "mbox read %d != %d bytes returned", rlen, len - 3); 9584e98e3e1Schristos 9594e98e3e1Schristos HW_TRACE ((me, "MBOX %s 0x%x..0x%x", 9604e98e3e1Schristos cmd == RV_MBOX_HANDLE_CMD ? "H" : "P", 9614e98e3e1Schristos address, address + len - 1)); 9624e98e3e1Schristos for (i = 0; i < rlen; i += 8) 9634e98e3e1Schristos HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x", 9644e98e3e1Schristos address + 3 + i, 9654e98e3e1Schristos buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i], 9664e98e3e1Schristos buf[9+i], buf[10+i])); 9674e98e3e1Schristos 9684e98e3e1Schristos len -= 3; 9694e98e3e1Schristos hw_rv_send (me, cmd, buf + 3, len); 9704e98e3e1Schristos 9714e98e3e1Schristos /* Note: both ..._PUT and ..._HANDLE get the ..._HANDLE reply. */ 9724e98e3e1Schristos hw_rv_handle_incoming (me, RV_MBOX_HANDLE_CMD, buf + 3, &len); 9734e98e3e1Schristos if (len > sizeof (buf)) 9744e98e3e1Schristos hw_abort (me, "mbox cmd %d receive size %d unsupported", cmd, len); 9754e98e3e1Schristos HW_TRACE ((me, "-> 0x%x..0x%x", address, address + len + 3 - 1)); 9764e98e3e1Schristos for (i = 0; i < len; i += 8) 9774e98e3e1Schristos HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x", 9784e98e3e1Schristos address + 3 + i, 9794e98e3e1Schristos buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i], 9804e98e3e1Schristos buf[9+i], buf[10+i])); 9814e98e3e1Schristos 9824e98e3e1Schristos len += 3; 9834e98e3e1Schristos buf[0] = len & 255; 9844e98e3e1Schristos buf[1] = len / 256; 9854e98e3e1Schristos rlen = hw_dma_write_buffer (me, buf, 0, address, len, 0); 9864e98e3e1Schristos if (rlen != len) 9874e98e3e1Schristos hw_abort (me, "mbox write %d != %d bytes", rlen, len); 9884e98e3e1Schristos } 9894e98e3e1Schristos 9904e98e3e1Schristos /* Local rv register writes end up here. */ 9914e98e3e1Schristos 9924e98e3e1Schristos static unsigned int 9934e98e3e1Schristos hw_rv_reg_write (struct hw *me, 9944e98e3e1Schristos const void *source, 9954e98e3e1Schristos int space, 9964e98e3e1Schristos unsigned_word addr, 9974e98e3e1Schristos unsigned int nr_bytes) 9984e98e3e1Schristos { 9994e98e3e1Schristos hw_rv_device *rv = (hw_rv_device *) hw_data (me); 10004e98e3e1Schristos 10014b169a6bSchristos uint8_t addr_data[8] = ""; 10024b169a6bSchristos uint32_t a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address); 10034e98e3e1Schristos unsigned int len = 8; 10044e98e3e1Schristos 10054e98e3e1Schristos if (nr_bytes != 4) 10064e98e3e1Schristos hw_abort (me, "must be four byte write"); 10074e98e3e1Schristos 10084e98e3e1Schristos memcpy (addr_data, &a_l, 4); 10094e98e3e1Schristos memcpy (addr_data + 4, source, 4); 10104e98e3e1Schristos 10114e98e3e1Schristos if (addr == rv->mbox_address) 10124e98e3e1Schristos { 10134b169a6bSchristos uint32_t mbox_addr_le; 10144e98e3e1Schristos if (rv->dummy != NULL) 10154e98e3e1Schristos hw_abort (me, "mbox not supported for a dummy instance"); 10164e98e3e1Schristos memcpy (&mbox_addr_le, source, 4); 10174e98e3e1Schristos hw_rv_mbox (me, LE2H_4 (mbox_addr_le)); 10184e98e3e1Schristos return nr_bytes; 10194e98e3e1Schristos } 10204e98e3e1Schristos 10214e98e3e1Schristos HW_TRACE ((me, "REG W 0x%x := 0x%02x%02x%02x%02x", addr, 10224e98e3e1Schristos addr_data[7], addr_data[6], addr_data[5], addr_data[4])); 10234e98e3e1Schristos if (rv->dummy != NULL) 10244e98e3e1Schristos { 10254e98e3e1Schristos len = 8; 10264e98e3e1Schristos memcpy (rv->dummy + addr - rv->reg_address, addr_data + 4, 4); 10274e98e3e1Schristos } 10284e98e3e1Schristos else 10294e98e3e1Schristos { 10304e98e3e1Schristos hw_rv_send (me, RV_WRITE_CMD, addr_data, len); 10314e98e3e1Schristos hw_rv_handle_incoming (me, RV_WRITE_CMD, addr_data, &len); 10324e98e3e1Schristos } 10334e98e3e1Schristos 10344e98e3e1Schristos if (len != 8) 10354e98e3e1Schristos hw_abort (me, "read %d != 8 bytes returned", len); 10364e98e3e1Schristos 10374e98e3e1Schristos /* We had an access: tighten up all slack. */ 10384e98e3e1Schristos rv->next_period = 1; 10394e98e3e1Schristos 10404e98e3e1Schristos return nr_bytes; 10414e98e3e1Schristos } 10424e98e3e1Schristos 10434e98e3e1Schristos /* Instance initializer function. */ 10444e98e3e1Schristos 10454e98e3e1Schristos static void 10464e98e3e1Schristos hw_rv_finish (struct hw *me) 10474e98e3e1Schristos { 10484e98e3e1Schristos hw_rv_device *rv = HW_ZALLOC (me, hw_rv_device); 10494e98e3e1Schristos const struct hw_property *mem_prop; 10504e98e3e1Schristos const struct hw_property *dummy_prop; 10514e98e3e1Schristos const struct hw_property *mbox_prop; 10524e98e3e1Schristos 10534e98e3e1Schristos set_hw_data (me, rv); 10544e98e3e1Schristos 10554e98e3e1Schristos #undef RV_GET_IPROP 10564e98e3e1Schristos #undef RV_GET_PROP 10574e98e3e1Schristos #define RV_GET_PROP(T, N, M, D) \ 10584e98e3e1Schristos do \ 10594e98e3e1Schristos { \ 10604e98e3e1Schristos if (hw_find_property (me, N) != NULL) \ 10614e98e3e1Schristos rv->M = hw_find_ ## T ## _property (me, N); \ 10624e98e3e1Schristos else \ 10634e98e3e1Schristos rv->M = (D); \ 10644e98e3e1Schristos } \ 10654e98e3e1Schristos while (0) 10664e98e3e1Schristos #define RV_GET_IPROP(N, M, D) RV_GET_PROP (integer, N, M, D) 10674e98e3e1Schristos 10684e98e3e1Schristos RV_GET_PROP (string, "host", host, "127.0.0.1"); 10694e98e3e1Schristos RV_GET_IPROP ("port", port, 10000); 10704e98e3e1Schristos RV_GET_IPROP ("remote-reg", remote_reg_address, 0); 10714e98e3e1Schristos RV_GET_IPROP ("max-poll-ticks", max_tick_poll_interval, 10000); 10724e98e3e1Schristos RV_GET_IPROP ("watchdog-interval", watchdog_interval, 30); 10734e98e3e1Schristos RV_GET_IPROP ("remote-mem", remote_mem_address, 0); 10744e98e3e1Schristos RV_GET_IPROP ("mem-burst-mask", mem_burst_mask, 0xffff); 10754e98e3e1Schristos RV_GET_IPROP ("intmultiple", intmultiple, 0); 10764e98e3e1Schristos 10774e98e3e1Schristos set_hw_io_read_buffer (me, hw_rv_reg_read); 10784e98e3e1Schristos set_hw_io_write_buffer (me, hw_rv_reg_write); 10794e98e3e1Schristos set_hw_ports (me, hw_rv_ports); 10804e98e3e1Schristos rv->next_period = 1; 10814e98e3e1Schristos 10824e98e3e1Schristos /* FIXME: We only support zero or one reg and zero or one mem area. */ 10834e98e3e1Schristos if (hw_find_property (me, "reg") != NULL) 10844e98e3e1Schristos { 10854e98e3e1Schristos reg_property_spec reg; 10864e98e3e1Schristos if (hw_find_reg_array_property (me, "reg", 0, ®)) 10874e98e3e1Schristos { 10884e98e3e1Schristos unsigned_word attach_address; 10894e98e3e1Schristos int attach_space; 10904e98e3e1Schristos unsigned int attach_size; 10914e98e3e1Schristos 10924e98e3e1Schristos hw_unit_address_to_attach_address (hw_parent (me), 10934e98e3e1Schristos ®.address, 10944e98e3e1Schristos &attach_space, 10954e98e3e1Schristos &attach_address, 10964e98e3e1Schristos me); 10974e98e3e1Schristos rv->reg_address = attach_address; 10984e98e3e1Schristos hw_unit_size_to_attach_size (hw_parent (me), 10994e98e3e1Schristos ®.size, 11004e98e3e1Schristos &attach_size, me); 11014e98e3e1Schristos rv->reg_size = attach_size; 11024e98e3e1Schristos if ((attach_address & 3) != 0) 11034e98e3e1Schristos hw_abort (me, "register block must be 4 byte aligned"); 11044e98e3e1Schristos hw_attach_address (hw_parent (me), 11054e98e3e1Schristos 0, 11064e98e3e1Schristos attach_space, attach_address, attach_size, 11074e98e3e1Schristos me); 11084e98e3e1Schristos } 11094e98e3e1Schristos else 11104e98e3e1Schristos hw_abort (me, "property \"reg\" has the wrong type"); 11114e98e3e1Schristos } 11124e98e3e1Schristos 11134e98e3e1Schristos dummy_prop = hw_find_property (me, "dummy"); 11144e98e3e1Schristos if (dummy_prop != NULL) 11154e98e3e1Schristos { 11164e98e3e1Schristos if (rv->reg_size == 0) 11174e98e3e1Schristos hw_abort (me, "dummy argument requires a \"reg\" property"); 11184e98e3e1Schristos 11194e98e3e1Schristos if (hw_property_type (dummy_prop) == integer_property) 11204e98e3e1Schristos { 11214b169a6bSchristos uint32_t dummyfill = hw_find_integer_property (me, "dummy"); 11224b169a6bSchristos uint8_t *dummymem = hw_malloc (me, rv->reg_size); 11234e98e3e1Schristos memset (dummymem, dummyfill, rv->reg_size); 11244e98e3e1Schristos rv->dummy = dummymem; 11254e98e3e1Schristos } 11264e98e3e1Schristos else 11274e98e3e1Schristos { 11284e98e3e1Schristos const char *dummyarg = hw_find_string_property (me, "dummy"); 11294b169a6bSchristos uint8_t *dummymem = hw_malloc (me, rv->reg_size); 11304e98e3e1Schristos FILE *f = fopen (dummyarg, "rb"); 11314e98e3e1Schristos 11324e98e3e1Schristos if (f == NULL) 11334e98e3e1Schristos hw_abort (me, "opening dummy-file \"%s\": %s", 11344e98e3e1Schristos dummyarg, strerror (errno)); 11354e98e3e1Schristos if (fread (dummymem, 1, rv->reg_size, f) != rv->reg_size) 11364e98e3e1Schristos hw_abort (me, "reading dummy-file \"%s\": %s", 11374e98e3e1Schristos dummyarg, strerror (errno)); 11384e98e3e1Schristos fclose (f); 11394e98e3e1Schristos rv->dummy = dummymem; 11404e98e3e1Schristos } 11414e98e3e1Schristos } 11424e98e3e1Schristos 11434e98e3e1Schristos mbox_prop = hw_find_property (me, "mbox"); 11444e98e3e1Schristos if (mbox_prop != NULL) 11454e98e3e1Schristos { 11464e98e3e1Schristos if (hw_property_type (mbox_prop) == integer_property) 11474e98e3e1Schristos { 11484e98e3e1Schristos signed_cell attach_address_sc 11494e98e3e1Schristos = hw_find_integer_property (me, "mbox"); 11504e98e3e1Schristos 11514b169a6bSchristos rv->mbox_address = (uint32_t) attach_address_sc; 11524e98e3e1Schristos hw_attach_address (hw_parent (me), 11534e98e3e1Schristos 0, 11544b169a6bSchristos 0, (uint32_t) attach_address_sc, 4, me); 11554e98e3e1Schristos } 11564e98e3e1Schristos else 11574e98e3e1Schristos hw_abort (me, "property \"mbox\" has the wrong type"); 11584e98e3e1Schristos } 11594e98e3e1Schristos 11604e98e3e1Schristos mem_prop = hw_find_property (me, "mem"); 11614e98e3e1Schristos if (mem_prop != NULL) 11624e98e3e1Schristos { 11634e98e3e1Schristos signed_cell attach_address_sc; 11644e98e3e1Schristos signed_cell attach_size_sc; 11654e98e3e1Schristos 11664e98e3e1Schristos /* Only specific names are reg_array_properties, the rest are 11674e98e3e1Schristos array_properties. */ 11684e98e3e1Schristos if (hw_property_type (mem_prop) == array_property 11694e98e3e1Schristos && hw_property_sizeof_array (mem_prop) == 2 * sizeof (attach_address_sc) 11704e98e3e1Schristos && hw_find_integer_array_property (me, "mem", 0, &attach_address_sc) 11714e98e3e1Schristos && hw_find_integer_array_property (me, "mem", 1, &attach_size_sc)) 11724e98e3e1Schristos { 11734e98e3e1Schristos /* Unfortunate choice of types forces us to dance around a bit. */ 11744b169a6bSchristos rv->mem_address = (uint32_t) attach_address_sc; 11754b169a6bSchristos rv->mem_size = (uint32_t) attach_size_sc; 11764e98e3e1Schristos if ((attach_address_sc & 3) != 0) 11774e98e3e1Schristos hw_abort (me, "memory block must be 4 byte aligned"); 11784e98e3e1Schristos } 11794e98e3e1Schristos else 11804e98e3e1Schristos hw_abort (me, "property \"mem\" has the wrong type"); 11814e98e3e1Schristos } 11824e98e3e1Schristos 11834e98e3e1Schristos hw_rv_map_ints (me); 11844e98e3e1Schristos 11854e98e3e1Schristos hw_rv_init_socket (me); 11864e98e3e1Schristos 11874e98e3e1Schristos /* We need an extra initialization pass, after all others currently 11884e98e3e1Schristos scheduled (mostly, after the simulation events machinery has been 11894e98e3e1Schristos initialized so the events we want don't get thrown out). */ 11904e98e3e1Schristos hw_rv_add_init (me); 11914e98e3e1Schristos } 11924e98e3e1Schristos 11934e98e3e1Schristos /* Our root structure; see dv-* build machinery for usage. */ 11944e98e3e1Schristos 11954e98e3e1Schristos const struct hw_descriptor dv_rv_descriptor[] = { 11964e98e3e1Schristos { RV_FAMILY_NAME, hw_rv_finish }, 11974e98e3e1Schristos { NULL } 11984e98e3e1Schristos }; 1199