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, ®))
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 ®.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 ®.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