xref: /netbsd-src/external/gpl3/gdb/dist/sim/cris/dv-rv.c (revision 05d8e8fe083a4bc28647839371f28bad98396c12)
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, &reg))
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 					     &reg.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 				       &reg.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