xref: /netbsd/external/gpl3/gdb/dist/sim/cris/dv-rv.c (revision 1424dfb3)
166e63ce3Schristos /* The remote-virtual-component simulator framework
266e63ce3Schristos    for GDB, the GNU Debugger.
366e63ce3Schristos 
4*1424dfb3Schristos    Copyright 2006-2020 Free Software Foundation, Inc.
566e63ce3Schristos 
666e63ce3Schristos    This file is part of GDB.
766e63ce3Schristos 
866e63ce3Schristos    This program is free software; you can redistribute it and/or modify
966e63ce3Schristos    it under the terms of the GNU General Public License as published by
1066e63ce3Schristos    the Free Software Foundation; either version 3 of the License, or
1166e63ce3Schristos    (at your option) any later version.
1266e63ce3Schristos 
1366e63ce3Schristos    This program is distributed in the hope that it will be useful,
1466e63ce3Schristos    but WITHOUT ANY WARRANTY; without even the implied warranty of
1566e63ce3Schristos    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1666e63ce3Schristos    GNU General Public License for more details.
1766e63ce3Schristos 
1866e63ce3Schristos    You should have received a copy of the GNU General Public License
1966e63ce3Schristos    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
2066e63ce3Schristos 
2166e63ce3Schristos 
2266e63ce3Schristos #include "sim-main.h"
2366e63ce3Schristos #include "hw-main.h"
2466e63ce3Schristos 
2566e63ce3Schristos #include "hw-tree.h"
2666e63ce3Schristos 
2766e63ce3Schristos #include <ctype.h>
2866e63ce3Schristos 
2966e63ce3Schristos #ifdef HAVE_ERRNO_H
3066e63ce3Schristos #include <errno.h>
3166e63ce3Schristos #endif
3266e63ce3Schristos 
3366e63ce3Schristos #ifdef HAVE_STRING_H
3466e63ce3Schristos #include <string.h>
3566e63ce3Schristos #else
3666e63ce3Schristos #ifdef HAVE_STRINGS_H
3766e63ce3Schristos #include <strings.h>
3866e63ce3Schristos #endif
3966e63ce3Schristos #endif
4066e63ce3Schristos 
4166e63ce3Schristos #ifdef HAVE_UNISTD_H
4266e63ce3Schristos #include <unistd.h>
4366e63ce3Schristos #endif
4466e63ce3Schristos #ifdef HAVE_STDLIB_H
4566e63ce3Schristos #include <stdlib.h>
4666e63ce3Schristos #endif
4766e63ce3Schristos 
4866e63ce3Schristos #ifdef HAVE_SYS_TYPES_H
4966e63ce3Schristos #include <sys/types.h>
5066e63ce3Schristos #endif
5166e63ce3Schristos 
5266e63ce3Schristos #ifdef HAVE_SYS_TIME_H
5366e63ce3Schristos #include <sys/time.h>
5466e63ce3Schristos #endif
5566e63ce3Schristos 
5666e63ce3Schristos #ifdef HAVE_SYS_SELECT_H
5766e63ce3Schristos #include <sys/select.h>
5866e63ce3Schristos #endif
5966e63ce3Schristos 
6066e63ce3Schristos /* Not guarded in dv-sockser.c, so why here.  */
6166e63ce3Schristos #include <netinet/in.h>
6266e63ce3Schristos #include <arpa/inet.h>
6366e63ce3Schristos #include <netdb.h>
6466e63ce3Schristos #include <sys/socket.h>
6566e63ce3Schristos 
6666e63ce3Schristos 
6766e63ce3Schristos /* DEVICE
6866e63ce3Schristos 
6966e63ce3Schristos 
7066e63ce3Schristos    rv - Remote Virtual component
7166e63ce3Schristos 
7266e63ce3Schristos 
7366e63ce3Schristos    DESCRIPTION
7466e63ce3Schristos 
7566e63ce3Schristos 
7666e63ce3Schristos    Socket connection to a remote simulator component, for example one
7766e63ce3Schristos    for testing a verilog construction.  Protocol defined below.
7866e63ce3Schristos 
7966e63ce3Schristos    There is a set of 32-bit I/O ports, with a mapping from local to
8066e63ce3Schristos    remote addresses.  There is a set of interrupts expressed as a
8166e63ce3Schristos    bit-mask, with a mapping from remote to local.  There is a set of
8266e63ce3Schristos    memory ranges (actual memory defined elsewhere), also with a
8366e63ce3Schristos    mapping from remote to local addresses, that is expected to be
8466e63ce3Schristos    accessible to the remote simulator in 32-byte chunks (simulating
8566e63ce3Schristos    DMA).  There is a mapping from remote cycles (or an appropriate
8666e63ce3Schristos    elsewhere defined time-slice) to local cycles.
8766e63ce3Schristos 
8866e63ce3Schristos    PROPERTIES
8966e63ce3Schristos 
9066e63ce3Schristos    reg = <address> <size>
9166e63ce3Schristos    The address (within the parent bus) that this device is to
9266e63ce3Schristos    be located.
9366e63ce3Schristos 
9466e63ce3Schristos    remote-reg = <remote-address>
9566e63ce3Schristos    The address of reg on the remote side.  Defaults to 0.
9666e63ce3Schristos 
9766e63ce3Schristos    mem = <address> <size>
9866e63ce3Schristos    Specify an address-range (within the parent bus) that the remote
9966e63ce3Schristos    device can access.  The memory is assumed to be already defined.
10066e63ce3Schristos    If there's no memory defined but the remote side asks for a memory
10166e63ce3Schristos    access, the simulation is aborted.
10266e63ce3Schristos 
10366e63ce3Schristos    remote-mem = <remote-address>
10466e63ce3Schristos    The address of mem on the remote side.  Defaults to 0.
10566e63ce3Schristos 
10666e63ce3Schristos    mbox = <address>
10766e63ce3Schristos    Address of the mailbox interface.  Writes to this address with the
10866e63ce3Schristos    local address of a mailbox command, a complete packet with length
10966e63ce3Schristos    and command; (4 or 6)) invokes the mailbox interface.  Reads are
11066e63ce3Schristos    invalid.  Replies are written to the same address.  Address space
11166e63ce3Schristos    from <address> up-to-and-including <address>+3 is allocated.
11266e63ce3Schristos 
11366e63ce3Schristos    max-poll-ticks = <local-count>
11466e63ce3Schristos    Sets the maximum interval between polling the external component,
11566e63ce3Schristos    expressed in internal cycles.  Defaults to 10000.
11666e63ce3Schristos 
11766e63ce3Schristos    watchdog-interval = <seconds>
11866e63ce3Schristos    Sets the wallclock seconds between watchdog packets sent to the
11966e63ce3Schristos    remote side (may be larger if there's no rv activity in that time).
12066e63ce3Schristos    Defaults to 30.  If set to 0, no watchdog packets are sent.
12166e63ce3Schristos 
12266e63ce3Schristos    intnum = <local-int-0> <local-int-1> ... <local-int-31>
12366e63ce3Schristos    Defines a map from remote bit numbers to local values to be emitted
12466e63ce3Schristos    on the "int" port, with the external bit number as the ordinal - 1
12566e63ce3Schristos    of the local translation.  E.g. 43 121 would mean map external
12666e63ce3Schristos    (1<<0) to internal 43 and external (1<<1) to internal 121.  The
12766e63ce3Schristos    default is unity; no translation.  If more than one bit is set in
12866e63ce3Schristos    the remote interrupt word, the intmultiple property can be used to
12966e63ce3Schristos    control the translation.
13066e63ce3Schristos 
13166e63ce3Schristos    intmultiple = <intvalue>
13266e63ce3Schristos    When more than one bit is set in the remote interrupt word, you may
13366e63ce3Schristos    want to map this situation to a separate interrupt value.  If this
13466e63ce3Schristos    property is non-zero, it is used as that value.  If it is zero, the
13566e63ce3Schristos    local value for the "int" port is the bitwise-or of the translated
13666e63ce3Schristos    local values.
13766e63ce3Schristos 
13866e63ce3Schristos    host = <hostid>
13966e63ce3Schristos    The hostname or address where the simulator to be used listens.
14066e63ce3Schristos    Defaults to "127.0.0.1"
14166e63ce3Schristos 
14266e63ce3Schristos    port = <portnumber>
14366e63ce3Schristos    The hostname or address where the simulator to be used listens.
14466e63ce3Schristos    Defaults to 10000.
14566e63ce3Schristos 
14666e63ce3Schristos    dummy = <value>
14766e63ce3Schristos     or
14866e63ce3Schristos    dummy = <filename>
14966e63ce3Schristos    Don't connect to a remote side; use initial dummy contents from
15066e63ce3Schristos    <filename> (which has to be at least as big as the <size> argument
15166e63ce3Schristos    of reg above) or filled with byte-value <value>.  Mailboxes are not
15266e63ce3Schristos    supported (can be defined but can not be used) and remote-memory
15366e63ce3Schristos    accesses don't apply.  The main purpose for this property is to
15466e63ce3Schristos    simplify use of configuration and simulated hardware that is
15566e63ce3Schristos    e.g. only trivially initialized but not actually used.
15666e63ce3Schristos 
15766e63ce3Schristos 
15866e63ce3Schristos    PORTS
15966e63ce3Schristos 
16066e63ce3Schristos    int (output)
16166e63ce3Schristos    Driven as a result of a remote interrupt request.  The value is a
16266e63ce3Schristos    32-bit bitset of active interrupts.
16366e63ce3Schristos 
16466e63ce3Schristos 
16566e63ce3Schristos    BUGS
16666e63ce3Schristos 
16766e63ce3Schristos    All and none.
16866e63ce3Schristos 
16966e63ce3Schristos 
17066e63ce3Schristos    PROTOCOL
17166e63ce3Schristos 
17266e63ce3Schristos    This is version 1.0 of this protocol, defining packet format and
17366e63ce3Schristos    actions in a supposedly upward-compatible manner where client and
17466e63ce3Schristos    servers of different versions are expected to interoperate; the
17566e63ce3Schristos    format and the definitions below are hopefully generic enough to
17666e63ce3Schristos    allow this.
17766e63ce3Schristos 
17866e63ce3Schristos    Each connection has a server and a client (this code); the roles
17966e63ce3Schristos    are known beforehand.  The client usually corresponds to a CPU and
18066e63ce3Schristos    memory system and the server corresponds to a memory-mapped
18166e63ce3Schristos    register hardware interface and/or a DMA controller.  They
18266e63ce3Schristos    communicate using packets with specific commands, of which some
18366e63ce3Schristos    require replies from the other side; most are intiated by the
18466e63ce3Schristos    client with one exception.  A reply uses the same format as the
18566e63ce3Schristos    command.
18666e63ce3Schristos 
18766e63ce3Schristos    Packets are at least three bytes long, where the first two bytes
18866e63ce3Schristos    form a header, a 16-bit little-endian number that is the total
18966e63ce3Schristos    length of the packet including the header.  There is also a
19066e63ce3Schristos    one-byte command.  The payload is optional, depending on the
19166e63ce3Schristos    command.
19266e63ce3Schristos 
19366e63ce3Schristos    [[16-bit-low-byte-of-length] [16-bit-high-byte-of-length]
19466e63ce3Schristos     [command/reply] [payload byte 0] [payload byte 1]
19566e63ce3Schristos     ... [payload byte (length-of-packet - 3)]]
19666e63ce3Schristos 
19766e63ce3Schristos    Commands:
19866e63ce3Schristos 
19966e63ce3Schristos    A client or server that reads an undocumented command may exit with
20066e63ce3Schristos    a hard error.  Payload not defined or disallowed below is ignored.
20166e63ce3Schristos 
20266e63ce3Schristos    It is expected that future client versions find out the version of
20366e63ce3Schristos    the server side by polling with base commands, assuming earlier
20466e63ce3Schristos    versions if a certain reply isn't seen, with newly defined payload
20566e63ce3Schristos    parts where earlier versions left it undefined.  New commands and
20666e63ce3Schristos    formats are sent only to the other side after the client and server
20766e63ce3Schristos    has found out each others version.  Not all servers support all
20866e63ce3Schristos    commands; the type of server and supported set of commands is
20966e63ce3Schristos    expected to be known beforehand.
21066e63ce3Schristos 
21166e63ce3Schristos    RV_READ_CMD = 0
21266e63ce3Schristos    Initiated by the client, requires a reply from the server.  The
21366e63ce3Schristos    payload from the client is at least 4 bytes, forming a 4-byte
21466e63ce3Schristos    little-endian address, the rest being undefined.  The reply from
21566e63ce3Schristos    the server is at least 8 bytes, forming the same address data as in
21666e63ce3Schristos    the request and the second 4-byte data being the little-endian
21766e63ce3Schristos    contents.
21866e63ce3Schristos 
21966e63ce3Schristos    RV_WRITE_CMD = 1
22066e63ce3Schristos    Initiated by the client, requires a reply from the server.  Payload
22166e63ce3Schristos    from the client is at least 8 bytes, forming a 4-byte little-endian
22266e63ce3Schristos    word being the address, the rest being the little-endian contents
22366e63ce3Schristos    to write.  The reply from the server is 8 bytes unless elsewhere
22466e63ce3Schristos    agreed otherwise, forming the same address and data as in the
22566e63ce3Schristos    request.  The data sent back may have been altered to correspond to
22666e63ce3Schristos    defined parts but can safely be discarded.
22766e63ce3Schristos 
22866e63ce3Schristos    RV_IRQ_CMD = 2
22966e63ce3Schristos    Initiated by the server, no reply.  The payload is 4 bytes, forming
23066e63ce3Schristos    a little-endian word with bits numbers corresponding to currently
23166e63ce3Schristos    active interrupt sources; value (1<<N) indicating interrupt source
23266e63ce3Schristos    N being active.
23366e63ce3Schristos 
23466e63ce3Schristos    RV_MEM_RD_CMD = 3
23566e63ce3Schristos    Initiated by the server, requires a reply.  A client must know
23666e63ce3Schristos    beforehand when (in command sequence or constant) the server can
23766e63ce3Schristos    send this command and if so must then not send any commands of its
23866e63ce3Schristos    own (including watchdog commands); the server is allowed to assume
23966e63ce3Schristos    that incoming data is only replies to this command.  The format is
24066e63ce3Schristos    8 bytes of data; 4 bytes of little-endian address followed by a
24166e63ce3Schristos    32-bit little endian word with the number of bytes to read.  The
24266e63ce3Schristos    reply is the same address and number of bytes, followed by the data
24366e63ce3Schristos    that had been read.
24466e63ce3Schristos 
24566e63ce3Schristos    RV_MEM_WR_CMD = 4
24666e63ce3Schristos    Initiated by the server, no reply.  The format is the same as a
24766e63ce3Schristos    reply to RV_MEM_RD_CMD; a 32-bit little-endian address, followed by
24866e63ce3Schristos    the 32-bit little-endian number of bytes to write (redundant
24966e63ce3Schristos    information but must be consistent with the packet header).
25066e63ce3Schristos 
25166e63ce3Schristos    RV_MBOX_HANDLE_CMD = 5
25266e63ce3Schristos    Initiated by the client, requires a reply.  The payload is 4
25366e63ce3Schristos    undefined bytes followed by an binary blob, the size of the
25466e63ce3Schristos    blob given by the packet header.  The reply is a 32-bit little
25566e63ce3Schristos    endian number at the same index as the undefined bytes.  Actual
25666e63ce3Schristos    semantics are application-specific.
25766e63ce3Schristos 
25866e63ce3Schristos    RV_MBOX_PUT_CMD = 6
25966e63ce3Schristos    Initiated by the client, requires a reply, with the reply using the
26066e63ce3Schristos    RV_MBOX_HANDLE_CMD reply format (i.e. *both* that command and
26166e63ce3Schristos    32-bit little-endian number).  The payload is a 32-bit little
26266e63ce3Schristos    endian number followed by an undefined payload, at most 20 bytes
26366e63ce3Schristos    long.  The reply is a 32-bit little endian number.  Actual
26466e63ce3Schristos    semantics are application-specific.
26566e63ce3Schristos 
26666e63ce3Schristos    RV_WATCHDOG_CMD = 7
26766e63ce3Schristos    Initiated by the client, no reply.  A version 1.0 client sends no
26866e63ce3Schristos    payload; a version 1.0 server should ignore any such payload.  A
26966e63ce3Schristos    version 1.0 server must not send a reply.
27066e63ce3Schristos 
27166e63ce3Schristos 
27266e63ce3Schristos    Possible future enhancements:
27366e63ce3Schristos 
27466e63ce3Schristos    Synchronization; server and client reports the number of elapsed
27566e63ce3Schristos    cycles (unit to-be-defined) at each request or notification.
27666e63ce3Schristos    Pretty much the top-of-the-todo-list item.
27766e63ce3Schristos 
27866e63ce3Schristos    Large addresses; 1.0 being restricted to 32-bit addresses.
27966e63ce3Schristos 
28066e63ce3Schristos    Variable-size data; currently restricted to 32-bit register
28166e63ce3Schristos    accesses.
28266e63ce3Schristos 
28366e63ce3Schristos    Specified data endianness (not the packet header) perhaps as part
28466e63ce3Schristos    of an initial format request; currently little-endian only.
28566e63ce3Schristos 
28666e63ce3Schristos 
28766e63ce3Schristos    Usage notes:
28866e63ce3Schristos    When used with servers sending RV_MEM_RD_CMD but being
28966e63ce3Schristos    narrow-minded about indata, set watchdog-interval to 0.  Use
29066e63ce3Schristos    multiple rv instances when there are e.g. separate register and
29166e63ce3Schristos    memory servers.  Alway log, setting "/rv/trace? true", at the
29266e63ce3Schristos    development phase.  Borrow from the test-suite.
29366e63ce3Schristos    */
29466e63ce3Schristos 
29566e63ce3Schristos #define RV_FAMILY_NAME "rv"
29666e63ce3Schristos 
29766e63ce3Schristos enum rv_command {
29866e63ce3Schristos   RV_READ_CMD = 0,
29966e63ce3Schristos   RV_WRITE_CMD = 1,
30066e63ce3Schristos   RV_IRQ_CMD = 2,
30166e63ce3Schristos   RV_MEM_RD_CMD = 3,
30266e63ce3Schristos   RV_MEM_WR_CMD = 4,
30366e63ce3Schristos   RV_MBOX_HANDLE_CMD = 5,
30466e63ce3Schristos   RV_MBOX_PUT_CMD = 6,
30566e63ce3Schristos   RV_WATCHDOG_CMD = 7
30666e63ce3Schristos };
30766e63ce3Schristos 
30866e63ce3Schristos 
30966e63ce3Schristos typedef struct _hw_rv_device
31066e63ce3Schristos {
31166e63ce3Schristos   /* Mapping of remote interrupt bit-numbers to local ones.  */
31266e63ce3Schristos   unsigned32 remote_to_local_int[32];
31366e63ce3Schristos 
31466e63ce3Schristos   /* When multiple bits are set, a non-zero value here indicates that
31566e63ce3Schristos      this value should be used instead.  */
31666e63ce3Schristos   unsigned32 intmultiple;
31766e63ce3Schristos 
31866e63ce3Schristos   /* Local address of registers.  */
31966e63ce3Schristos   unsigned32 reg_address;
32066e63ce3Schristos 
32166e63ce3Schristos   /* Size of register bank in bytes.  */
32266e63ce3Schristos   unsigned32 reg_size;
32366e63ce3Schristos 
32466e63ce3Schristos   /* Remote address of registers.  */
32566e63ce3Schristos   unsigned32 remote_reg_address;
32666e63ce3Schristos 
32766e63ce3Schristos   /* Local address of DMA:able memory.  */
32866e63ce3Schristos   unsigned32 mem_address;
32966e63ce3Schristos 
33066e63ce3Schristos   /* Size of DMA:able memory in bytes.  */
33166e63ce3Schristos   unsigned32 mem_size;
33266e63ce3Schristos 
33366e63ce3Schristos   /* Bitmask for valid DMA request size.  */
33466e63ce3Schristos   unsigned32 mem_burst_mask;
33566e63ce3Schristos 
33666e63ce3Schristos   /* Remote address of DMA:able memory.  */
33766e63ce3Schristos   unsigned32 remote_mem_address;
33866e63ce3Schristos 
33966e63ce3Schristos   /* (Local) address of mbox; where to put a pointer to the mbox to be
34066e63ce3Schristos      sent.  */
34166e63ce3Schristos   unsigned32 mbox_address;
34266e63ce3Schristos 
34366e63ce3Schristos   /* Probably not 127.0.0.1:10000.  */
34466e63ce3Schristos   const char *host;
34566e63ce3Schristos   int port;
34666e63ce3Schristos 
34766e63ce3Schristos   /* If non-NULL, points to memory to use instead of connection.  */
34866e63ce3Schristos   unsigned8 *dummy;
34966e63ce3Schristos 
35066e63ce3Schristos   /* File descriptor for the socket.  Set to -1 when error.  Only one
35166e63ce3Schristos      of dummy and this is active.  */
35266e63ce3Schristos   int fd;
35366e63ce3Schristos 
35466e63ce3Schristos   /* Stashed errno, as we don't emit an error right away.  */
35566e63ce3Schristos   int saved_errno;
35666e63ce3Schristos 
35766e63ce3Schristos   /* This, plus latency because the CPU might not be checking until a
35866e63ce3Schristos      CTI insn (usually a branch or a jump) is the interval in cycles
35966e63ce3Schristos      between the rv is polled for e.g. DMA requests.  */
36066e63ce3Schristos   unsigned32 max_tick_poll_interval;
36166e63ce3Schristos 
36266e63ce3Schristos   /* Running counter for exponential backoff up to
36366e63ce3Schristos      max_tick_poll_interval to avoid polling the connection
36466e63ce3Schristos      unnecessarily often.  Set to 1 when rv activity (read/write
36566e63ce3Schristos      register, DMA request) is detected.  */
36666e63ce3Schristos   unsigned32 next_period;
36766e63ce3Schristos 
36866e63ce3Schristos   /* This is the interval in wall-clock seconds between watchdog
36966e63ce3Schristos      packets are sent to the remote side.  Zero means no watchdog
37066e63ce3Schristos      packets. */
37166e63ce3Schristos   unsigned32 watchdog_interval;
37266e63ce3Schristos 
37366e63ce3Schristos   /* Last time we sent a watchdog packet.  */
37466e63ce3Schristos   struct timeval last_wdog_time;
37566e63ce3Schristos 
37666e63ce3Schristos   /* Mostly used as a kludge for knowing which rv:s have poll events
37766e63ce3Schristos      active.  */
37866e63ce3Schristos   struct hw_event *poll_callback;
37966e63ce3Schristos } hw_rv_device;
38066e63ce3Schristos 
38166e63ce3Schristos 
38266e63ce3Schristos /* We might add ports in the future, so keep this an enumeration.  */
38366e63ce3Schristos enum
38466e63ce3Schristos   {
38566e63ce3Schristos     INT_PORT
38666e63ce3Schristos   };
38766e63ce3Schristos 
38866e63ce3Schristos /* Our ports.  */
38966e63ce3Schristos static const struct hw_port_descriptor hw_rv_ports[] = {
39066e63ce3Schristos   { "int", INT_PORT, 0, output_port },
39166e63ce3Schristos   { NULL }
39266e63ce3Schristos };
39366e63ce3Schristos 
39466e63ce3Schristos /* Send LEN bytes of data from BUF to the socket.  Abort on
39566e63ce3Schristos    errors.  */
39666e63ce3Schristos 
39766e63ce3Schristos static void
hw_rv_write(struct hw * me,void * buf,unsigned int len)39866e63ce3Schristos hw_rv_write (struct hw *me,
39966e63ce3Schristos 	     void *buf,
40066e63ce3Schristos 	     unsigned int len)
40166e63ce3Schristos {
40266e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
40366e63ce3Schristos   unsigned8 *bufp = buf;
40466e63ce3Schristos 
40566e63ce3Schristos   /* If we don't have a valid fd here, it's because we got an error
40666e63ce3Schristos      initially, and we suppressed that error.  */
40766e63ce3Schristos   if (rv->fd == -1)
40866e63ce3Schristos     hw_abort (me, "couldn't open a connection to %s:%d because: %s",
40966e63ce3Schristos 	      rv->host, rv->port, strerror (rv->saved_errno));
41066e63ce3Schristos 
41166e63ce3Schristos   while (len > 0)
41266e63ce3Schristos     {
41366e63ce3Schristos       ssize_t ret = write (rv->fd, bufp, len);
41466e63ce3Schristos       if (ret < 0)
41566e63ce3Schristos 	/* FIXME: More graceful exit.  */
41666e63ce3Schristos 	hw_abort (me, "write to %s:%d failed: %s\n", rv->host, rv->port,
41766e63ce3Schristos 		  strerror (errno));
41866e63ce3Schristos 
41966e63ce3Schristos       len -= ret;
42066e63ce3Schristos       bufp += ret;
42166e63ce3Schristos     }
42266e63ce3Schristos }
42366e63ce3Schristos 
42466e63ce3Schristos /* Read LEN bytes of data into BUF from the socket.  Set the file
42566e63ce3Schristos    descriptor to -1 if there's an error.  */
42666e63ce3Schristos 
42766e63ce3Schristos static void
hw_rv_read(struct hw * me,void * buf,unsigned int len)42866e63ce3Schristos hw_rv_read (struct hw *me,
42966e63ce3Schristos 	    void *buf,
43066e63ce3Schristos 	    unsigned int len)
43166e63ce3Schristos {
43266e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
43366e63ce3Schristos   unsigned8 *bufp = buf;
43466e63ce3Schristos 
43566e63ce3Schristos   while (len > 0)
43666e63ce3Schristos     {
43766e63ce3Schristos       ssize_t ret = read (rv->fd, bufp, len);
43866e63ce3Schristos 
43966e63ce3Schristos       /* We get all zero if the remote end quits, but no error
44066e63ce3Schristos 	 indication; even select says there's data active.  */
44166e63ce3Schristos       if (ret <= 0)
44266e63ce3Schristos 	{
44366e63ce3Schristos 	  if (close (rv->fd) != 0)
44466e63ce3Schristos 	    /* FIXME: More graceful exit.  */
44566e63ce3Schristos 	    hw_abort (me, "read from %s:%d failed: %d\n", rv->host, rv->port, errno);
44666e63ce3Schristos 	  rv->fd = -1;
44766e63ce3Schristos 	  return;
44866e63ce3Schristos 	}
44966e63ce3Schristos 
45066e63ce3Schristos       len -= ret;
45166e63ce3Schristos       bufp += ret;
45266e63ce3Schristos     }
45366e63ce3Schristos }
45466e63ce3Schristos 
45566e63ce3Schristos /* Construct and send a packet of data of type CMD and len
45666e63ce3Schristos    LEN_NOHEADER (not counting the header...).  */
45766e63ce3Schristos 
45866e63ce3Schristos static void
hw_rv_send(struct hw * me,unsigned int cmd,void * msg,unsigned int len_noheader)45966e63ce3Schristos hw_rv_send (struct hw *me,
46066e63ce3Schristos 	    unsigned int cmd,
46166e63ce3Schristos 	    void *msg,
46266e63ce3Schristos 	    unsigned int len_noheader)
46366e63ce3Schristos {
46466e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
46566e63ce3Schristos   unsigned8 buf[32+3];
46666e63ce3Schristos   unsigned8 *bufp;
46766e63ce3Schristos   unsigned int len = len_noheader + 3;
46866e63ce3Schristos   int ret;
46966e63ce3Schristos 
47066e63ce3Schristos   buf[0] = len & 255;
47166e63ce3Schristos   buf[1] = (len >> 8) & 255;
47266e63ce3Schristos   buf[2] = cmd;
47366e63ce3Schristos 
47466e63ce3Schristos   if (len > sizeof (buf))
47566e63ce3Schristos     {
47666e63ce3Schristos       hw_rv_write (me, buf, 3);
47766e63ce3Schristos       len = len_noheader;
47866e63ce3Schristos       bufp = msg;
47966e63ce3Schristos     }
48066e63ce3Schristos   else
48166e63ce3Schristos     {
48266e63ce3Schristos       memcpy (buf + 3, msg, len_noheader);
48366e63ce3Schristos       bufp = buf;
48466e63ce3Schristos     }
48566e63ce3Schristos 
48666e63ce3Schristos   hw_rv_write (me, bufp, len);
48766e63ce3Schristos }
48866e63ce3Schristos 
48966e63ce3Schristos /* Handle incoming DMA requests as per the RV_MEM_RD_CMD packet.
49066e63ce3Schristos    Abort on errors.  */
49166e63ce3Schristos 
49266e63ce3Schristos static void
hw_rv_read_mem(struct hw * me,unsigned int len)49366e63ce3Schristos hw_rv_read_mem (struct hw *me, unsigned int len)
49466e63ce3Schristos {
49566e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
49666e63ce3Schristos   /* If you change this size, please adjust the mem2 testcase.  */
49766e63ce3Schristos   unsigned8 buf[32+8];
49866e63ce3Schristos   unsigned8 *bufp = buf;
49966e63ce3Schristos   unsigned32 leaddr;
50066e63ce3Schristos   unsigned32 addr;
50166e63ce3Schristos   unsigned32 lelen;
50266e63ce3Schristos   unsigned32 i;
50366e63ce3Schristos 
50466e63ce3Schristos   if (len != 8)
50566e63ce3Schristos     hw_abort (me, "expected DMA read request len 8+3, got %d+3", len);
50666e63ce3Schristos 
50766e63ce3Schristos   hw_rv_read (me, &leaddr, 4);
50866e63ce3Schristos   hw_rv_read (me, &lelen, 4);
50966e63ce3Schristos   len = LE2H_4 (lelen);
51066e63ce3Schristos   addr = LE2H_4 (leaddr);
51166e63ce3Schristos 
51266e63ce3Schristos   if (addr < rv->remote_mem_address
51366e63ce3Schristos       || addr >= rv->remote_mem_address + rv->mem_size)
51466e63ce3Schristos     hw_abort (me, "DMA read at remote 0x%x; outside [0x%x..0x%x-1]",
51566e63ce3Schristos 	      (unsigned) addr, (unsigned) rv->remote_mem_address,
51666e63ce3Schristos 	      (unsigned) (rv->remote_mem_address + rv->mem_size));
51766e63ce3Schristos   addr = addr - rv->remote_mem_address + rv->mem_address;
51866e63ce3Schristos 
51966e63ce3Schristos   if (len == 0)
52066e63ce3Schristos     hw_abort (me, "DMA read request for 0 bytes isn't supported");
52166e63ce3Schristos 
52266e63ce3Schristos   if (len & ~rv->mem_burst_mask)
52366e63ce3Schristos     hw_abort (me, "DMA trying to read %d bytes; not matching mask of 0x%x",
52466e63ce3Schristos 	      len, rv->mem_burst_mask);
52566e63ce3Schristos   if (len + 8 > sizeof (buf))
52666e63ce3Schristos     bufp = hw_malloc (me, len + 8);
52766e63ce3Schristos 
52866e63ce3Schristos   HW_TRACE ((me, "DMA R 0x%x..0x%x", addr, addr + len -1));
52966e63ce3Schristos   hw_dma_read_buffer (me, bufp + 8, 0, addr, len);
53066e63ce3Schristos   if (hw_trace_p (me))
53166e63ce3Schristos     for (i = 0; i < len; i += 4)
53266e63ce3Schristos       HW_TRACE ((me, "0x%x: %02x %02x %02x %02x",
53366e63ce3Schristos 		 addr + i,
53466e63ce3Schristos 		 bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11]));
53566e63ce3Schristos 
53666e63ce3Schristos   memcpy (bufp, &leaddr, 4);
53766e63ce3Schristos   memcpy (bufp + 4, &lelen, 4);
53866e63ce3Schristos   hw_rv_send (me, RV_MEM_RD_CMD, bufp, len + 8);
53966e63ce3Schristos   if (bufp != buf)
54066e63ce3Schristos     hw_free (me, bufp);
54166e63ce3Schristos }
54266e63ce3Schristos 
54366e63ce3Schristos /* Handle incoming DMA requests as per the RV_MEM_WR_CMD packet.
54466e63ce3Schristos    Abort on errors.  */
54566e63ce3Schristos 
54666e63ce3Schristos static void
hw_rv_write_mem(struct hw * me,unsigned int plen)54766e63ce3Schristos hw_rv_write_mem (struct hw *me, unsigned int plen)
54866e63ce3Schristos {
54966e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
55066e63ce3Schristos   /* If you change this size, please adjust the mem2 testcase.  */
55166e63ce3Schristos   unsigned8 buf[32+8];
55266e63ce3Schristos   unsigned8 *bufp = buf;
55366e63ce3Schristos   unsigned32 leaddr;
55466e63ce3Schristos   unsigned32 addr;
55566e63ce3Schristos   unsigned32 lelen;
55666e63ce3Schristos   unsigned32 len;
55766e63ce3Schristos   unsigned32 i;
55866e63ce3Schristos 
55966e63ce3Schristos   hw_rv_read (me, &leaddr, 4);
56066e63ce3Schristos   hw_rv_read (me, &lelen, 4);
56166e63ce3Schristos   len = LE2H_4 (lelen);
56266e63ce3Schristos   addr = LE2H_4 (leaddr);
56366e63ce3Schristos 
56466e63ce3Schristos   if (len != plen - 8)
56566e63ce3Schristos     hw_abort (me,
56666e63ce3Schristos 	      "inconsistency in DMA write request packet: "
56766e63ce3Schristos 	      "envelope %d+3, inner %d bytes", plen, len);
56866e63ce3Schristos 
56966e63ce3Schristos   if (addr < rv->remote_mem_address
57066e63ce3Schristos       || addr >= rv->remote_mem_address + rv->mem_size)
57166e63ce3Schristos     hw_abort (me, "DMA write at remote 0x%x; outside [0x%x..0x%x-1]",
57266e63ce3Schristos 	      (unsigned) addr, (unsigned) rv->remote_mem_address,
57366e63ce3Schristos 	      (unsigned) (rv->remote_mem_address + rv->mem_size));
57466e63ce3Schristos 
57566e63ce3Schristos   addr = addr - rv->remote_mem_address + rv->mem_address;
57666e63ce3Schristos   if (len == 0)
57766e63ce3Schristos     hw_abort (me, "DMA write request for 0 bytes isn't supported");
57866e63ce3Schristos 
57966e63ce3Schristos   if (len & ~rv->mem_burst_mask)
58066e63ce3Schristos     hw_abort (me, "DMA trying to write %d bytes; not matching mask of 0x%x",
58166e63ce3Schristos 	      len, rv->mem_burst_mask);
58266e63ce3Schristos   if (len + 8 > sizeof (buf))
58366e63ce3Schristos     bufp = hw_malloc (me, len + 8);
58466e63ce3Schristos 
58566e63ce3Schristos   hw_rv_read (me, bufp + 8, len);
58666e63ce3Schristos   HW_TRACE ((me, "DMA W 0x%x..0x%x", addr, addr + len - 1));
58766e63ce3Schristos   hw_dma_write_buffer (me, bufp + 8, 0, addr, len, 0);
58866e63ce3Schristos   if (hw_trace_p (me))
58966e63ce3Schristos     for (i = 0; i < len; i += 4)
59066e63ce3Schristos       HW_TRACE ((me, "0x%x: %02x %02x %02x %02x",
59166e63ce3Schristos 		 addr + i,
59266e63ce3Schristos 		 bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11]));
59366e63ce3Schristos   if (bufp != buf)
59466e63ce3Schristos     hw_free (me, bufp);
59566e63ce3Schristos }
59666e63ce3Schristos 
59766e63ce3Schristos static void
hw_rv_irq(struct hw * me,unsigned int len)59866e63ce3Schristos hw_rv_irq (struct hw *me, unsigned int len)
59966e63ce3Schristos {
60066e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
60166e63ce3Schristos   unsigned32 intbitsle;
60266e63ce3Schristos   unsigned32 intbits_ext;
60366e63ce3Schristos   unsigned32 intval = 0;
60466e63ce3Schristos   int i;
60566e63ce3Schristos 
60666e63ce3Schristos   if (len != 4)
60766e63ce3Schristos     hw_abort (me, "IRQ with %d data not supported", len);
60866e63ce3Schristos 
60966e63ce3Schristos   hw_rv_read (me, &intbitsle, 4);
61066e63ce3Schristos   intbits_ext = LE2H_4 (intbitsle);
61166e63ce3Schristos   for (i = 0; i < 32; i++)
61266e63ce3Schristos     if ((intbits_ext & (1 << i)) != 0)
61366e63ce3Schristos       intval |= rv->remote_to_local_int[i];
61466e63ce3Schristos   if ((intbits_ext & ~(intbits_ext - 1)) != intbits_ext
61566e63ce3Schristos       && rv->intmultiple != 0)
61666e63ce3Schristos     intval = rv->intmultiple;
61766e63ce3Schristos 
61866e63ce3Schristos   HW_TRACE ((me, "IRQ 0x%x", intval));
61966e63ce3Schristos   hw_port_event (me, INT_PORT, intval);
62066e63ce3Schristos }
62166e63ce3Schristos 
62266e63ce3Schristos /* Handle incoming interrupt notifications as per the RV_IRQ_CMD
62366e63ce3Schristos    packet.  Abort on errors.  */
62466e63ce3Schristos 
62566e63ce3Schristos static void
hw_rv_handle_incoming(struct hw * me,int expected_type,unsigned8 * buf,unsigned int * return_len)62666e63ce3Schristos hw_rv_handle_incoming (struct hw *me,
62766e63ce3Schristos 		       int expected_type,
62866e63ce3Schristos 		       unsigned8 *buf,
62966e63ce3Schristos 		       unsigned int *return_len)
63066e63ce3Schristos {
63166e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
63266e63ce3Schristos   unsigned8 cbuf[32];
63366e63ce3Schristos   unsigned int len;
63466e63ce3Schristos   unsigned int cmd;
63566e63ce3Schristos 
63666e63ce3Schristos   while (1)
63766e63ce3Schristos     {
63866e63ce3Schristos       hw_rv_read (me, cbuf, 3);
63966e63ce3Schristos 
64066e63ce3Schristos       if (rv->fd == -1)
64166e63ce3Schristos 	return;
64266e63ce3Schristos 
64366e63ce3Schristos       len = cbuf[0] + cbuf[1] * 256 - 3;
64466e63ce3Schristos       cmd = cbuf[2];
64566e63ce3Schristos 
64666e63ce3Schristos       /* These come in "asynchronously"; not as a reply.  */
64766e63ce3Schristos       switch (cmd)
64866e63ce3Schristos 	{
64966e63ce3Schristos 	case RV_IRQ_CMD:
65066e63ce3Schristos 	  hw_rv_irq (me, len);
65166e63ce3Schristos 	  break;
65266e63ce3Schristos 
65366e63ce3Schristos 	case RV_MEM_RD_CMD:
65466e63ce3Schristos 	  hw_rv_read_mem (me, len);
65566e63ce3Schristos 	  break;
65666e63ce3Schristos 
65766e63ce3Schristos 	case RV_MEM_WR_CMD:
65866e63ce3Schristos 	  hw_rv_write_mem (me, len);
65966e63ce3Schristos 	  break;
66066e63ce3Schristos 	}
66166e63ce3Schristos 
66266e63ce3Schristos       /* Something is incoming from the other side, so tighten up all
66366e63ce3Schristos 	 slack at the next wait.  */
66466e63ce3Schristos       rv->next_period = 1;
66566e63ce3Schristos 
66666e63ce3Schristos       switch (cmd)
66766e63ce3Schristos 	{
66866e63ce3Schristos 	case RV_MEM_RD_CMD:
66966e63ce3Schristos 	case RV_MEM_WR_CMD:
67066e63ce3Schristos 	case RV_IRQ_CMD:
67166e63ce3Schristos 	  /* Don't try to handle more than one of these if we were'nt
67266e63ce3Schristos 	     expecting a reply.  */
67366e63ce3Schristos 	  if (expected_type == -1)
67466e63ce3Schristos 	    return;
67566e63ce3Schristos 	  continue;
67666e63ce3Schristos 	}
67766e63ce3Schristos 
67866e63ce3Schristos       /* Require a match between this supposed-reply and the command
67966e63ce3Schristos 	 for the rest.  */
68066e63ce3Schristos       if (cmd != expected_type)
68166e63ce3Schristos 	hw_abort (me, "unexpected reply, expected command %d, got %d",
68266e63ce3Schristos 		  expected_type, cmd);
68366e63ce3Schristos 
68466e63ce3Schristos       switch (cmd)
68566e63ce3Schristos 	{
68666e63ce3Schristos 	case RV_MBOX_PUT_CMD:
68766e63ce3Schristos 	case RV_MBOX_HANDLE_CMD:
68866e63ce3Schristos 	case RV_WRITE_CMD:
68966e63ce3Schristos 	case RV_READ_CMD:
69066e63ce3Schristos 	  hw_rv_read (me, buf, len <= *return_len ? len : *return_len);
69166e63ce3Schristos 	  *return_len = len;
69266e63ce3Schristos 	  break;
69366e63ce3Schristos 	}
69466e63ce3Schristos       break;
69566e63ce3Schristos     }
69666e63ce3Schristos }
69766e63ce3Schristos 
69866e63ce3Schristos /* Send a watchdog packet.  Make a note of wallclock time.  */
69966e63ce3Schristos 
70066e63ce3Schristos static void
hw_rv_send_wdog(struct hw * me)70166e63ce3Schristos hw_rv_send_wdog (struct hw *me)
70266e63ce3Schristos {
70366e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
70466e63ce3Schristos   HW_TRACE ((me, "WD"));
70566e63ce3Schristos   gettimeofday (&rv->last_wdog_time, NULL);
70666e63ce3Schristos   hw_rv_send (me, RV_WATCHDOG_CMD, "", 0);
70766e63ce3Schristos }
70866e63ce3Schristos 
70966e63ce3Schristos /* Poll the remote side: see if there's any incoming traffic; handle a
71066e63ce3Schristos    packet if so.  Send a watchdog packet if it's time to do so.
71166e63ce3Schristos    Beware that the Linux select call indicates traffic for a socket
71266e63ce3Schristos    that the remote side has closed (which may be because it was
71366e63ce3Schristos    finished; don't hork until we need to write something just because
71466e63ce3Schristos    we're polling).  */
71566e63ce3Schristos 
71666e63ce3Schristos static void
hw_rv_poll_once(struct hw * me)71766e63ce3Schristos hw_rv_poll_once (struct hw *me)
71866e63ce3Schristos {
71966e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
72066e63ce3Schristos   fd_set rfds;
72166e63ce3Schristos   fd_set efds;
72266e63ce3Schristos   struct timeval now;
72366e63ce3Schristos   int ret;
72466e63ce3Schristos   struct timeval tv;
72566e63ce3Schristos 
72666e63ce3Schristos   if (rv->fd == -1)
72766e63ce3Schristos     /* Connection has died or was never initiated.  */
72866e63ce3Schristos     return;
72966e63ce3Schristos 
73066e63ce3Schristos   FD_ZERO (&rfds);
73166e63ce3Schristos   FD_SET (rv->fd, &rfds);
73266e63ce3Schristos   FD_ZERO (&efds);
73366e63ce3Schristos   FD_SET (rv->fd, &efds);
73466e63ce3Schristos   tv.tv_sec = 0;
73566e63ce3Schristos   tv.tv_usec = 0;
73666e63ce3Schristos 
73766e63ce3Schristos   ret = select (rv->fd + 1, &rfds, NULL, &efds, &tv);
73866e63ce3Schristos   gettimeofday (&now, NULL);
73966e63ce3Schristos 
74066e63ce3Schristos   if (ret < 0)
74166e63ce3Schristos     hw_abort (me, "select failed: %d\n", errno);
74266e63ce3Schristos 
74366e63ce3Schristos   if (rv->watchdog_interval != 0
74466e63ce3Schristos       && now.tv_sec - rv->last_wdog_time.tv_sec >= rv->watchdog_interval)
74566e63ce3Schristos     hw_rv_send_wdog (me);
74666e63ce3Schristos 
74766e63ce3Schristos   if (FD_ISSET (rv->fd, &rfds))
74866e63ce3Schristos     hw_rv_handle_incoming (me, -1, NULL, NULL);
74966e63ce3Schristos }
75066e63ce3Schristos 
75166e63ce3Schristos /* Initialize mapping of remote-to-local interrupt data.  */
75266e63ce3Schristos 
75366e63ce3Schristos static void
hw_rv_map_ints(struct hw * me)75466e63ce3Schristos hw_rv_map_ints (struct hw *me)
75566e63ce3Schristos {
75666e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
75766e63ce3Schristos   int i;
75866e63ce3Schristos 
75966e63ce3Schristos   for (i = 0; i < 32; i++)
76066e63ce3Schristos     rv->remote_to_local_int[i] = 1 << i;
76166e63ce3Schristos 
76266e63ce3Schristos   if (hw_find_property (me, "intnum") != NULL)
76366e63ce3Schristos     for (i = 0; i < 32; i++)
76466e63ce3Schristos       {
76566e63ce3Schristos 	signed_cell val = -1;
76666e63ce3Schristos 	if (hw_find_integer_array_property (me, "intnum", i, &val) > 0)
76766e63ce3Schristos 	  {
76866e63ce3Schristos 	    if (val > 0)
76966e63ce3Schristos 	      rv->remote_to_local_int[i] = val;
77066e63ce3Schristos 	    else
77166e63ce3Schristos 	      hw_abort (me, "property \"intnum@%d\" must be > 0; is %d",
77266e63ce3Schristos 			i, (int) val);
77366e63ce3Schristos 	  }
77466e63ce3Schristos       }
77566e63ce3Schristos }
77666e63ce3Schristos 
77766e63ce3Schristos /* Handle the after-N-ticks "poll event", calling the poll-the-fd
77866e63ce3Schristos    method.  Update the period.  */
77966e63ce3Schristos 
78066e63ce3Schristos static void
do_poll_event(struct hw * me,void * data)78166e63ce3Schristos do_poll_event (struct hw *me, void *data)
78266e63ce3Schristos {
78366e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
78466e63ce3Schristos   unsigned32 new_period;
78566e63ce3Schristos 
78666e63ce3Schristos   if (rv->dummy != NULL)
78766e63ce3Schristos     return;
78866e63ce3Schristos 
78966e63ce3Schristos   hw_rv_poll_once (me);
79066e63ce3Schristos   if (rv->fd >= 0)
79166e63ce3Schristos     rv->poll_callback
79266e63ce3Schristos       = hw_event_queue_schedule (me, rv->next_period, do_poll_event, NULL);
79366e63ce3Schristos 
79466e63ce3Schristos   new_period = rv->next_period * 2;
79566e63ce3Schristos   if (new_period <= rv->max_tick_poll_interval)
79666e63ce3Schristos     rv->next_period = new_period;
79766e63ce3Schristos }
79866e63ce3Schristos 
79966e63ce3Schristos /* HW tree traverse function for hw_rv_add_init.  */
80066e63ce3Schristos 
80166e63ce3Schristos static void
hw_rv_add_poller(struct hw * me,void * data)80266e63ce3Schristos hw_rv_add_poller (struct hw *me, void *data)
80366e63ce3Schristos {
80466e63ce3Schristos   hw_rv_device *rv;
80566e63ce3Schristos 
80666e63ce3Schristos   if (hw_family (me) == NULL
80766e63ce3Schristos       || strcmp (hw_family (me), RV_FAMILY_NAME) != 0)
80866e63ce3Schristos     return;
80966e63ce3Schristos 
81066e63ce3Schristos   rv = (hw_rv_device *) hw_data (me);
81166e63ce3Schristos   if (rv->poll_callback != NULL)
81266e63ce3Schristos     return;
81366e63ce3Schristos 
81466e63ce3Schristos   rv->poll_callback
81566e63ce3Schristos     = hw_event_queue_schedule (me, 1, do_poll_event, NULL);
81666e63ce3Schristos }
81766e63ce3Schristos 
81866e63ce3Schristos /* Simulator module init function for hw_rv_add_init.  */
81966e63ce3Schristos 
82066e63ce3Schristos /* FIXME: For the call so hw_tree_traverse, we need to know that the
82166e63ce3Schristos    first member of struct sim_hw is the struct hw *root, but there's
82266e63ce3Schristos    no accessor method and struct sim_hw is defined in sim-hw.c only.
82366e63ce3Schristos    Hence this hack, until an accessor is added, or there's a traverse
82466e63ce3Schristos    function that takes a SIM_DESC argument.  */
82566e63ce3Schristos struct sim_hw { struct hw *tree; };
82666e63ce3Schristos 
82766e63ce3Schristos static SIM_RC
hw_rv_add_rv_pollers(SIM_DESC sd)82866e63ce3Schristos hw_rv_add_rv_pollers (SIM_DESC sd)
82966e63ce3Schristos {
83066e63ce3Schristos   hw_tree_traverse (STATE_HW (sd)->tree, hw_rv_add_poller, NULL, NULL);
83166e63ce3Schristos   return SIM_RC_OK;
83266e63ce3Schristos }
83366e63ce3Schristos 
83466e63ce3Schristos /* We need to add events for polling, but we can't add one from the
83566e63ce3Schristos    finish-function, and there are no other call points, at least for
83666e63ce3Schristos    instances without "reg" (when there are just DMA requests from the
83766e63ce3Schristos    remote end; no locally initiated activity).  Therefore we add a
83866e63ce3Schristos    simulator module init function, but those don't have private
83966e63ce3Schristos    payload arguments; just a SD argument.  We cope by parsing the HW
84066e63ce3Schristos    root and making sure *all* "rv":s have poll callbacks installed.
84166e63ce3Schristos    Luckily, this is just an initialization step, and not many
84266e63ce3Schristos    simultaneous instances of rv are expected: we get a N**2 complexity
84366e63ce3Schristos    for visits to each rv node by this method.  */
84466e63ce3Schristos 
84566e63ce3Schristos static void
hw_rv_add_init(struct hw * me)84666e63ce3Schristos hw_rv_add_init (struct hw *me)
84766e63ce3Schristos {
84866e63ce3Schristos   sim_module_add_init_fn (hw_system (me), hw_rv_add_rv_pollers);
84966e63ce3Schristos }
85066e63ce3Schristos 
85166e63ce3Schristos /* Open up a connection to the other side.  Abort on errors.  */
85266e63ce3Schristos 
85366e63ce3Schristos static void
hw_rv_init_socket(struct hw * me)85466e63ce3Schristos hw_rv_init_socket (struct hw *me)
85566e63ce3Schristos {
85666e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
85766e63ce3Schristos   int sock;
85866e63ce3Schristos   struct sockaddr_in server;
85966e63ce3Schristos 
86066e63ce3Schristos   rv->fd = -1;
86166e63ce3Schristos 
86266e63ce3Schristos   if (rv->dummy != NULL)
86366e63ce3Schristos     return;
86466e63ce3Schristos 
86566e63ce3Schristos   memset (&server, 0, sizeof (server));
86666e63ce3Schristos   server.sin_family = AF_INET;
86766e63ce3Schristos   server.sin_addr.s_addr = inet_addr (rv->host);
86866e63ce3Schristos 
86966e63ce3Schristos   /* Solaris 2.7 lacks this macro.  */
87066e63ce3Schristos #ifndef INADDR_NONE
87166e63ce3Schristos #define INADDR_NONE -1
87266e63ce3Schristos #endif
87366e63ce3Schristos 
87466e63ce3Schristos   if (server.sin_addr.s_addr == INADDR_NONE)
87566e63ce3Schristos     {
87666e63ce3Schristos       struct hostent *h;
87766e63ce3Schristos       h = gethostbyname (rv->host);
87866e63ce3Schristos       if (h != NULL)
87966e63ce3Schristos 	{
88066e63ce3Schristos 	  memcpy (&server.sin_addr, h->h_addr, h->h_length);
88166e63ce3Schristos 	  server.sin_family = h->h_addrtype;
88266e63ce3Schristos 	}
88366e63ce3Schristos       else
88466e63ce3Schristos 	hw_abort (me, "can't resolve host %s", rv->host);
88566e63ce3Schristos     }
88666e63ce3Schristos 
88766e63ce3Schristos   server.sin_port = htons (rv->port);
88866e63ce3Schristos   sock = socket (AF_INET, SOCK_STREAM, 0);
88966e63ce3Schristos 
89066e63ce3Schristos   if (sock == -1)
89166e63ce3Schristos     hw_abort (me, "can't get a socket for %s:%d connection",
89266e63ce3Schristos 	      rv->host, rv->port);
89366e63ce3Schristos 
89466e63ce3Schristos   if (connect (sock, (struct sockaddr *) &server, sizeof server) >= 0)
89566e63ce3Schristos     {
89666e63ce3Schristos       rv->fd = sock;
89766e63ce3Schristos 
89866e63ce3Schristos       /* FIXME: init packet here.  Maybe start packet too.  */
89966e63ce3Schristos       if (rv->watchdog_interval != 0)
90066e63ce3Schristos 	hw_rv_send_wdog (me);
90166e63ce3Schristos     }
90266e63ce3Schristos   else
90366e63ce3Schristos     /* Stash the errno for later display, if some connection activity
90466e63ce3Schristos        is requested.  Don't emit an error here; we might have been
90566e63ce3Schristos        called just for test purposes.  */
90666e63ce3Schristos     rv->saved_errno = errno;
90766e63ce3Schristos }
90866e63ce3Schristos 
90966e63ce3Schristos /* Local rv register reads end up here.  */
91066e63ce3Schristos 
91166e63ce3Schristos static unsigned int
hw_rv_reg_read(struct hw * me,void * dest,int space,unsigned_word addr,unsigned int nr_bytes)91266e63ce3Schristos hw_rv_reg_read (struct hw *me,
91366e63ce3Schristos 		void *dest,
91466e63ce3Schristos 		int space,
91566e63ce3Schristos 		unsigned_word addr,
91666e63ce3Schristos 		unsigned int nr_bytes)
91766e63ce3Schristos {
91866e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
91966e63ce3Schristos   unsigned8 addr_data[8] = "";
92066e63ce3Schristos   unsigned32 a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address);
92166e63ce3Schristos   unsigned int len = 8;
92266e63ce3Schristos 
92366e63ce3Schristos   if (nr_bytes != 4)
92466e63ce3Schristos     hw_abort (me, "must be four byte read");
92566e63ce3Schristos 
92666e63ce3Schristos   if (addr == rv->mbox_address)
92766e63ce3Schristos     hw_abort (me, "invalid read of mbox address 0x%x",
92866e63ce3Schristos 	      (unsigned) rv->mbox_address);
92966e63ce3Schristos 
93066e63ce3Schristos   memcpy (addr_data, &a_l, 4);
93166e63ce3Schristos   HW_TRACE ((me, "REG R 0x%x", addr));
93266e63ce3Schristos   if (rv->dummy != NULL)
93366e63ce3Schristos     {
93466e63ce3Schristos       len = 8;
93566e63ce3Schristos       memcpy (addr_data + 4, rv->dummy + addr - rv->reg_address, 4);
93666e63ce3Schristos     }
93766e63ce3Schristos   else
93866e63ce3Schristos     {
93966e63ce3Schristos       hw_rv_send (me, RV_READ_CMD, addr_data, len);
94066e63ce3Schristos       hw_rv_handle_incoming (me, RV_READ_CMD, addr_data, &len);
94166e63ce3Schristos     }
94266e63ce3Schristos 
94366e63ce3Schristos   if (len != 8)
94466e63ce3Schristos     hw_abort (me, "read %d != 8 bytes returned", len);
94566e63ce3Schristos   HW_TRACE ((me, ":= 0x%02x%02x%02x%02x",
94666e63ce3Schristos 	     addr_data[7], addr_data[6], addr_data[5], addr_data[4]));
94766e63ce3Schristos   memcpy (dest, addr_data + 4, 4);
94866e63ce3Schristos   return nr_bytes;
94966e63ce3Schristos }
95066e63ce3Schristos 
95166e63ce3Schristos /* Local rv mbox requests (handle or put) end up here.  */
95266e63ce3Schristos 
95366e63ce3Schristos static void
hw_rv_mbox(struct hw * me,unsigned_word address)95466e63ce3Schristos hw_rv_mbox (struct hw *me, unsigned_word address)
95566e63ce3Schristos {
95666e63ce3Schristos   unsigned8 buf[256+3];
95766e63ce3Schristos   unsigned int cmd;
95866e63ce3Schristos   unsigned int rlen;
95966e63ce3Schristos   unsigned32 i;
96066e63ce3Schristos   unsigned int len
96166e63ce3Schristos     = hw_dma_read_buffer (me, buf, 0, address, 3);
96266e63ce3Schristos 
96366e63ce3Schristos   if (len != 3)
96466e63ce3Schristos     hw_abort (me, "mbox read %d != 3 bytes returned", len);
96566e63ce3Schristos 
96666e63ce3Schristos   cmd = buf[2];
96766e63ce3Schristos   if (cmd != RV_MBOX_HANDLE_CMD && cmd != RV_MBOX_PUT_CMD)
96866e63ce3Schristos     hw_abort (me, "unsupported mbox command %d", cmd);
96966e63ce3Schristos 
97066e63ce3Schristos   len = buf[0] + buf[1]*256;
97166e63ce3Schristos 
97266e63ce3Schristos   if (len > sizeof (buf))
97366e63ce3Schristos     hw_abort (me, "mbox cmd %d send size %d unsupported", cmd, len);
97466e63ce3Schristos 
97566e63ce3Schristos   rlen = hw_dma_read_buffer (me, buf + 3, 0, address + 3, len - 3);
97666e63ce3Schristos   if (rlen != len - 3)
97766e63ce3Schristos     hw_abort (me, "mbox read %d != %d bytes returned", rlen, len - 3);
97866e63ce3Schristos 
97966e63ce3Schristos   HW_TRACE ((me, "MBOX %s 0x%x..0x%x",
98066e63ce3Schristos 	     cmd == RV_MBOX_HANDLE_CMD ? "H" : "P",
98166e63ce3Schristos 	     address, address + len - 1));
98266e63ce3Schristos   for (i = 0; i < rlen; i += 8)
98366e63ce3Schristos     HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x",
98466e63ce3Schristos 	       address + 3 + i,
98566e63ce3Schristos 	       buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i],
98666e63ce3Schristos 	       buf[9+i], buf[10+i]));
98766e63ce3Schristos 
98866e63ce3Schristos   len -= 3;
98966e63ce3Schristos   hw_rv_send (me, cmd, buf + 3, len);
99066e63ce3Schristos 
99166e63ce3Schristos   /* Note: both ..._PUT and ..._HANDLE get the ..._HANDLE reply.  */
99266e63ce3Schristos   hw_rv_handle_incoming (me, RV_MBOX_HANDLE_CMD, buf + 3, &len);
99366e63ce3Schristos   if (len > sizeof (buf))
99466e63ce3Schristos     hw_abort (me, "mbox cmd %d receive size %d unsupported", cmd, len);
99566e63ce3Schristos   HW_TRACE ((me, "-> 0x%x..0x%x", address, address + len + 3 - 1));
99666e63ce3Schristos   for (i = 0; i < len; i += 8)
99766e63ce3Schristos     HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x",
99866e63ce3Schristos 	       address + 3 + i,
99966e63ce3Schristos 	       buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i],
100066e63ce3Schristos 	       buf[9+i], buf[10+i]));
100166e63ce3Schristos 
100266e63ce3Schristos   len += 3;
100366e63ce3Schristos   buf[0] = len & 255;
100466e63ce3Schristos   buf[1] = len / 256;
100566e63ce3Schristos   rlen = hw_dma_write_buffer (me, buf, 0, address, len, 0);
100666e63ce3Schristos   if (rlen != len)
100766e63ce3Schristos     hw_abort (me, "mbox write %d != %d bytes", rlen, len);
100866e63ce3Schristos }
100966e63ce3Schristos 
101066e63ce3Schristos /* Local rv register writes end up here.  */
101166e63ce3Schristos 
101266e63ce3Schristos static unsigned int
hw_rv_reg_write(struct hw * me,const void * source,int space,unsigned_word addr,unsigned int nr_bytes)101366e63ce3Schristos hw_rv_reg_write (struct hw *me,
101466e63ce3Schristos 		 const void *source,
101566e63ce3Schristos 		 int space,
101666e63ce3Schristos 		 unsigned_word addr,
101766e63ce3Schristos 		 unsigned int nr_bytes)
101866e63ce3Schristos {
101966e63ce3Schristos   hw_rv_device *rv = (hw_rv_device *) hw_data (me);
102066e63ce3Schristos 
102166e63ce3Schristos   unsigned8 addr_data[8] = "";
102266e63ce3Schristos   unsigned32 a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address);
102366e63ce3Schristos   unsigned int len = 8;
102466e63ce3Schristos 
102566e63ce3Schristos   if (nr_bytes != 4)
102666e63ce3Schristos     hw_abort (me, "must be four byte write");
102766e63ce3Schristos 
102866e63ce3Schristos   memcpy (addr_data, &a_l, 4);
102966e63ce3Schristos   memcpy (addr_data + 4, source, 4);
103066e63ce3Schristos 
103166e63ce3Schristos   if (addr == rv->mbox_address)
103266e63ce3Schristos     {
103366e63ce3Schristos       unsigned32 mbox_addr_le;
103466e63ce3Schristos       if (rv->dummy != NULL)
103566e63ce3Schristos 	hw_abort (me, "mbox not supported for a dummy instance");
103666e63ce3Schristos       memcpy (&mbox_addr_le, source, 4);
103766e63ce3Schristos       hw_rv_mbox (me, LE2H_4 (mbox_addr_le));
103866e63ce3Schristos       return nr_bytes;
103966e63ce3Schristos     }
104066e63ce3Schristos 
104166e63ce3Schristos   HW_TRACE ((me, "REG W 0x%x := 0x%02x%02x%02x%02x", addr,
104266e63ce3Schristos 	     addr_data[7], addr_data[6], addr_data[5], addr_data[4]));
104366e63ce3Schristos   if (rv->dummy != NULL)
104466e63ce3Schristos     {
104566e63ce3Schristos       len = 8;
104666e63ce3Schristos       memcpy (rv->dummy + addr - rv->reg_address, addr_data + 4, 4);
104766e63ce3Schristos     }
104866e63ce3Schristos   else
104966e63ce3Schristos     {
105066e63ce3Schristos       hw_rv_send (me, RV_WRITE_CMD, addr_data, len);
105166e63ce3Schristos       hw_rv_handle_incoming (me, RV_WRITE_CMD, addr_data, &len);
105266e63ce3Schristos     }
105366e63ce3Schristos 
105466e63ce3Schristos   if (len != 8)
105566e63ce3Schristos     hw_abort (me, "read %d != 8 bytes returned", len);
105666e63ce3Schristos 
105766e63ce3Schristos   /* We had an access: tighten up all slack.  */
105866e63ce3Schristos   rv->next_period = 1;
105966e63ce3Schristos 
106066e63ce3Schristos   return nr_bytes;
106166e63ce3Schristos }
106266e63ce3Schristos 
106366e63ce3Schristos /* Instance initializer function.  */
106466e63ce3Schristos 
106566e63ce3Schristos static void
hw_rv_finish(struct hw * me)106666e63ce3Schristos hw_rv_finish (struct hw *me)
106766e63ce3Schristos {
106866e63ce3Schristos   hw_rv_device *rv = HW_ZALLOC (me, hw_rv_device);
106966e63ce3Schristos   int i;
107066e63ce3Schristos   const struct hw_property *mem_prop;
107166e63ce3Schristos   const struct hw_property *dummy_prop;
107266e63ce3Schristos   const struct hw_property *mbox_prop;
107366e63ce3Schristos 
107466e63ce3Schristos   set_hw_data (me, rv);
107566e63ce3Schristos 
107666e63ce3Schristos #undef RV_GET_IPROP
107766e63ce3Schristos #undef RV_GET_PROP
107866e63ce3Schristos #define RV_GET_PROP(T, N, M, D)				\
107966e63ce3Schristos   do							\
108066e63ce3Schristos     {							\
108166e63ce3Schristos       if (hw_find_property (me, N) != NULL)		\
108266e63ce3Schristos 	rv->M = hw_find_ ## T ## _property (me, N);	\
108366e63ce3Schristos       else						\
108466e63ce3Schristos 	rv->M = (D);					\
108566e63ce3Schristos     }							\
108666e63ce3Schristos   while (0)
108766e63ce3Schristos #define RV_GET_IPROP(N, M, D) RV_GET_PROP (integer, N, M, D)
108866e63ce3Schristos 
108966e63ce3Schristos   RV_GET_PROP (string, "host", host, "127.0.0.1");
109066e63ce3Schristos   RV_GET_IPROP ("port", port, 10000);
109166e63ce3Schristos   RV_GET_IPROP ("remote-reg", remote_reg_address, 0);
109266e63ce3Schristos   RV_GET_IPROP ("max-poll-ticks", max_tick_poll_interval, 10000);
109366e63ce3Schristos   RV_GET_IPROP ("watchdog-interval", watchdog_interval, 30);
109466e63ce3Schristos   RV_GET_IPROP ("remote-mem", remote_mem_address, 0);
109566e63ce3Schristos   RV_GET_IPROP ("mem-burst-mask", mem_burst_mask, 0xffff);
109666e63ce3Schristos   RV_GET_IPROP ("intmultiple", intmultiple, 0);
109766e63ce3Schristos 
109866e63ce3Schristos   set_hw_io_read_buffer (me, hw_rv_reg_read);
109966e63ce3Schristos   set_hw_io_write_buffer (me, hw_rv_reg_write);
110066e63ce3Schristos   set_hw_ports (me, hw_rv_ports);
110166e63ce3Schristos   rv->next_period = 1;
110266e63ce3Schristos 
110366e63ce3Schristos   /* FIXME: We only support zero or one reg and zero or one mem area.  */
110466e63ce3Schristos   if (hw_find_property (me, "reg") != NULL)
110566e63ce3Schristos     {
110666e63ce3Schristos       reg_property_spec reg;
110766e63ce3Schristos       if (hw_find_reg_array_property (me, "reg", 0, &reg))
110866e63ce3Schristos 	{
110966e63ce3Schristos 	  unsigned_word attach_address;
111066e63ce3Schristos 	  int attach_space;
111166e63ce3Schristos 	  unsigned int attach_size;
111266e63ce3Schristos 
111366e63ce3Schristos 	  hw_unit_address_to_attach_address (hw_parent (me),
111466e63ce3Schristos 					     &reg.address,
111566e63ce3Schristos 					     &attach_space,
111666e63ce3Schristos 					     &attach_address,
111766e63ce3Schristos 					     me);
111866e63ce3Schristos 	  rv->reg_address = attach_address;
111966e63ce3Schristos 	  hw_unit_size_to_attach_size (hw_parent (me),
112066e63ce3Schristos 				       &reg.size,
112166e63ce3Schristos 				       &attach_size, me);
112266e63ce3Schristos 	  rv->reg_size = attach_size;
112366e63ce3Schristos 	  if ((attach_address & 3) != 0)
112466e63ce3Schristos 	    hw_abort (me, "register block must be 4 byte aligned");
112566e63ce3Schristos 	  hw_attach_address (hw_parent (me),
112666e63ce3Schristos 			     0,
112766e63ce3Schristos 			     attach_space, attach_address, attach_size,
112866e63ce3Schristos 			     me);
112966e63ce3Schristos 	}
113066e63ce3Schristos       else
113166e63ce3Schristos 	hw_abort (me, "property \"reg\" has the wrong type");
113266e63ce3Schristos     }
113366e63ce3Schristos 
113466e63ce3Schristos   dummy_prop = hw_find_property (me, "dummy");
113566e63ce3Schristos   if (dummy_prop != NULL)
113666e63ce3Schristos     {
113766e63ce3Schristos       if (rv->reg_size == 0)
113866e63ce3Schristos 	hw_abort (me, "dummy argument requires a \"reg\" property");
113966e63ce3Schristos 
114066e63ce3Schristos       if (hw_property_type (dummy_prop) == integer_property)
114166e63ce3Schristos 	{
114266e63ce3Schristos 	  unsigned32 dummyfill = hw_find_integer_property (me, "dummy");
114366e63ce3Schristos 	  unsigned8 *dummymem = hw_malloc (me, rv->reg_size);
114466e63ce3Schristos 	  memset (dummymem, dummyfill, rv->reg_size);
114566e63ce3Schristos 	  rv->dummy = dummymem;
114666e63ce3Schristos 	}
114766e63ce3Schristos       else
114866e63ce3Schristos 	{
114966e63ce3Schristos 	  const char *dummyarg = hw_find_string_property (me, "dummy");
115066e63ce3Schristos 	  unsigned8 *dummymem = hw_malloc (me, rv->reg_size);
115166e63ce3Schristos 	  FILE *f = fopen (dummyarg, "rb");
115266e63ce3Schristos 
115366e63ce3Schristos 	  if (f == NULL)
115466e63ce3Schristos 	    hw_abort (me, "opening dummy-file \"%s\": %s",
115566e63ce3Schristos 		      dummyarg, strerror (errno));
115666e63ce3Schristos 	  if (fread (dummymem, 1, rv->reg_size, f) != rv->reg_size)
115766e63ce3Schristos 	    hw_abort (me, "reading dummy-file \"%s\": %s",
115866e63ce3Schristos 		      dummyarg, strerror (errno));
115966e63ce3Schristos 	  fclose (f);
116066e63ce3Schristos 	  rv->dummy = dummymem;
116166e63ce3Schristos 	}
116266e63ce3Schristos     }
116366e63ce3Schristos 
116466e63ce3Schristos   mbox_prop = hw_find_property (me, "mbox");
116566e63ce3Schristos   if (mbox_prop != NULL)
116666e63ce3Schristos     {
116766e63ce3Schristos       if (hw_property_type (mbox_prop) == integer_property)
116866e63ce3Schristos 	{
116966e63ce3Schristos 	  signed_cell attach_address_sc
117066e63ce3Schristos 	    = hw_find_integer_property (me, "mbox");
117166e63ce3Schristos 
117266e63ce3Schristos 	  rv->mbox_address = (unsigned32) attach_address_sc;
117366e63ce3Schristos 	  hw_attach_address (hw_parent (me),
117466e63ce3Schristos 			     0,
117566e63ce3Schristos 			     0, (unsigned32) attach_address_sc, 4, me);
117666e63ce3Schristos 	}
117766e63ce3Schristos       else
117866e63ce3Schristos 	hw_abort (me, "property \"mbox\" has the wrong type");
117966e63ce3Schristos     }
118066e63ce3Schristos 
118166e63ce3Schristos   mem_prop = hw_find_property (me, "mem");
118266e63ce3Schristos   if (mem_prop != NULL)
118366e63ce3Schristos     {
118466e63ce3Schristos       signed_cell attach_address_sc;
118566e63ce3Schristos       signed_cell attach_size_sc;
118666e63ce3Schristos 
118766e63ce3Schristos       /* Only specific names are reg_array_properties, the rest are
118866e63ce3Schristos 	 array_properties.  */
118966e63ce3Schristos       if (hw_property_type (mem_prop) == array_property
119066e63ce3Schristos 	  && hw_property_sizeof_array (mem_prop) == 2 * sizeof (attach_address_sc)
119166e63ce3Schristos 	  && hw_find_integer_array_property (me, "mem", 0, &attach_address_sc)
119266e63ce3Schristos 	  && hw_find_integer_array_property (me, "mem", 1, &attach_size_sc))
119366e63ce3Schristos 	{
119466e63ce3Schristos 	  /* Unfortunate choice of types forces us to dance around a bit.  */
119566e63ce3Schristos 	  rv->mem_address = (unsigned32) attach_address_sc;
119666e63ce3Schristos 	  rv->mem_size = (unsigned32) attach_size_sc;
119766e63ce3Schristos 	  if ((attach_address_sc & 3) != 0)
119866e63ce3Schristos 	    hw_abort (me, "memory block must be 4 byte aligned");
119966e63ce3Schristos 	}
120066e63ce3Schristos       else
120166e63ce3Schristos 	hw_abort (me, "property \"mem\" has the wrong type");
120266e63ce3Schristos     }
120366e63ce3Schristos 
120466e63ce3Schristos   hw_rv_map_ints (me);
120566e63ce3Schristos 
120666e63ce3Schristos   hw_rv_init_socket (me);
120766e63ce3Schristos 
120866e63ce3Schristos   /* We need an extra initialization pass, after all others currently
120966e63ce3Schristos      scheduled (mostly, after the simulation events machinery has been
121066e63ce3Schristos      initialized so the events we want don't get thrown out).  */
121166e63ce3Schristos   hw_rv_add_init (me);
121266e63ce3Schristos }
121366e63ce3Schristos 
121466e63ce3Schristos /* Our root structure; see dv-* build machinery for usage.  */
121566e63ce3Schristos 
121666e63ce3Schristos const struct hw_descriptor dv_rv_descriptor[] = {
121766e63ce3Schristos   { RV_FAMILY_NAME, hw_rv_finish },
121866e63ce3Schristos   { NULL }
121966e63ce3Schristos };
1220