1 |
330 |
jeremybenn |
/* The remote-virtual-component simulator framework
|
2 |
|
|
for GDB, the GNU Debugger.
|
3 |
|
|
|
4 |
|
|
Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
|
5 |
|
|
|
6 |
|
|
This file is part of GDB.
|
7 |
|
|
|
8 |
|
|
This program is free software; you can redistribute it and/or modify
|
9 |
|
|
it under the terms of the GNU General Public License as published by
|
10 |
|
|
the Free Software Foundation; either version 3 of the License, or
|
11 |
|
|
(at your option) any later version.
|
12 |
|
|
|
13 |
|
|
This program is distributed in the hope that it will be useful,
|
14 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
15 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
16 |
|
|
GNU General Public License for more details.
|
17 |
|
|
|
18 |
|
|
You should have received a copy of the GNU General Public License
|
19 |
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
20 |
|
|
|
21 |
|
|
|
22 |
|
|
#include "sim-main.h"
|
23 |
|
|
#include "hw-main.h"
|
24 |
|
|
|
25 |
|
|
#include "hw-tree.h"
|
26 |
|
|
|
27 |
|
|
#include <ctype.h>
|
28 |
|
|
|
29 |
|
|
#ifdef HAVE_ERRNO_H
|
30 |
|
|
#include <errno.h>
|
31 |
|
|
#endif
|
32 |
|
|
|
33 |
|
|
#ifdef HAVE_STRING_H
|
34 |
|
|
#include <string.h>
|
35 |
|
|
#else
|
36 |
|
|
#ifdef HAVE_STRINGS_H
|
37 |
|
|
#include <strings.h>
|
38 |
|
|
#endif
|
39 |
|
|
#endif
|
40 |
|
|
|
41 |
|
|
#ifdef HAVE_UNISTD_H
|
42 |
|
|
#include <unistd.h>
|
43 |
|
|
#endif
|
44 |
|
|
#ifdef HAVE_STDLIB_H
|
45 |
|
|
#include <stdlib.h>
|
46 |
|
|
#endif
|
47 |
|
|
|
48 |
|
|
#ifdef HAVE_SYS_TYPES_H
|
49 |
|
|
#include <sys/types.h>
|
50 |
|
|
#endif
|
51 |
|
|
|
52 |
|
|
#ifdef HAVE_SYS_TIME_H
|
53 |
|
|
#include <sys/time.h>
|
54 |
|
|
#endif
|
55 |
|
|
|
56 |
|
|
#ifdef HAVE_SYS_SELECT_H
|
57 |
|
|
#include <sys/select.h>
|
58 |
|
|
#endif
|
59 |
|
|
|
60 |
|
|
/* Not guarded in dv-sockser.c, so why here. */
|
61 |
|
|
#include <netinet/in.h>
|
62 |
|
|
#include <arpa/inet.h>
|
63 |
|
|
#include <netdb.h>
|
64 |
|
|
#include <sys/socket.h>
|
65 |
|
|
|
66 |
|
|
|
67 |
|
|
/* DEVICE
|
68 |
|
|
|
69 |
|
|
|
70 |
|
|
rv - Remote Virtual component
|
71 |
|
|
|
72 |
|
|
|
73 |
|
|
DESCRIPTION
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
Socket connection to a remote simulator component, for example one
|
77 |
|
|
for testing a verilog construction. Protocol defined below.
|
78 |
|
|
|
79 |
|
|
There is a set of 32-bit I/O ports, with a mapping from local to
|
80 |
|
|
remote addresses. There is a set of interrupts expressed as a
|
81 |
|
|
bit-mask, with a mapping from remote to local. There is a set of
|
82 |
|
|
memory ranges (actual memory defined elsewhere), also with a
|
83 |
|
|
mapping from remote to local addresses, that is expected to be
|
84 |
|
|
accessible to the remote simulator in 32-byte chunks (simulating
|
85 |
|
|
DMA). There is a mapping from remote cycles (or an appropriate
|
86 |
|
|
elsewhere defined time-slice) to local cycles.
|
87 |
|
|
|
88 |
|
|
PROPERTIES
|
89 |
|
|
|
90 |
|
|
reg = <address> <size>
|
91 |
|
|
The address (within the parent bus) that this device is to
|
92 |
|
|
be located.
|
93 |
|
|
|
94 |
|
|
remote-reg = <remote-address>
|
95 |
|
|
The address of reg on the remote side. Defaults to 0.
|
96 |
|
|
|
97 |
|
|
mem = <address> <size>
|
98 |
|
|
Specify an address-range (within the parent bus) that the remote
|
99 |
|
|
device can access. The memory is assumed to be already defined.
|
100 |
|
|
If there's no memory defined but the remote side asks for a memory
|
101 |
|
|
access, the simulation is aborted.
|
102 |
|
|
|
103 |
|
|
remote-mem = <remote-address>
|
104 |
|
|
The address of mem on the remote side. Defaults to 0.
|
105 |
|
|
|
106 |
|
|
mbox = <address>
|
107 |
|
|
Address of the mailbox interface. Writes to this address with the
|
108 |
|
|
local address of a mailbox command, a complete packet with length
|
109 |
|
|
and command; (4 or 6)) invokes the mailbox interface. Reads are
|
110 |
|
|
invalid. Replies are written to the same address. Address space
|
111 |
|
|
from <address> up-to-and-including <address>+3 is allocated.
|
112 |
|
|
|
113 |
|
|
max-poll-ticks = <local-count>
|
114 |
|
|
Sets the maximum interval between polling the external component,
|
115 |
|
|
expressed in internal cycles. Defaults to 10000.
|
116 |
|
|
|
117 |
|
|
watchdog-interval = <seconds>
|
118 |
|
|
Sets the wallclock seconds between watchdog packets sent to the
|
119 |
|
|
remote side (may be larger if there's no rv activity in that time).
|
120 |
|
|
Defaults to 30. If set to 0, no watchdog packets are sent.
|
121 |
|
|
|
122 |
|
|
intnum = <local-int-0> <local-int-1> ... <local-int-31>
|
123 |
|
|
Defines a map from remote bit numbers to local values to be emitted
|
124 |
|
|
on the "int" port, with the external bit number as the ordinal - 1
|
125 |
|
|
of the local translation. E.g. 43 121 would mean map external
|
126 |
|
|
(1<<0) to internal 43 and external (1<<1) to internal 121. The
|
127 |
|
|
default is unity; no translation. If more than one bit is set in
|
128 |
|
|
the remote interrupt word, the intmultiple property can be used to
|
129 |
|
|
control the translation.
|
130 |
|
|
|
131 |
|
|
intmultiple = <intvalue>
|
132 |
|
|
When more than one bit is set in the remote interrupt word, you may
|
133 |
|
|
want to map this situation to a separate interrupt value. If this
|
134 |
|
|
property is non-zero, it is used as that value. If it is zero, the
|
135 |
|
|
local value for the "int" port is the bitwise-or of the translated
|
136 |
|
|
local values.
|
137 |
|
|
|
138 |
|
|
host = <hostid>
|
139 |
|
|
The hostname or address where the simulator to be used listens.
|
140 |
|
|
Defaults to "127.0.0.1"
|
141 |
|
|
|
142 |
|
|
port = <portnumber>
|
143 |
|
|
The hostname or address where the simulator to be used listens.
|
144 |
|
|
Defaults to 10000.
|
145 |
|
|
|
146 |
|
|
dummy = <value>
|
147 |
|
|
or
|
148 |
|
|
dummy = <filename>
|
149 |
|
|
Don't connect to a remote side; use initial dummy contents from
|
150 |
|
|
<filename> (which has to be at least as big as the <size> argument
|
151 |
|
|
of reg above) or filled with byte-value <value>. Mailboxes are not
|
152 |
|
|
supported (can be defined but can not be used) and remote-memory
|
153 |
|
|
accesses don't apply. The main purpose for this property is to
|
154 |
|
|
simplify use of configuration and simulated hardware that is
|
155 |
|
|
e.g. only trivially initialized but not actually used.
|
156 |
|
|
|
157 |
|
|
|
158 |
|
|
PORTS
|
159 |
|
|
|
160 |
|
|
int (output)
|
161 |
|
|
Driven as a result of a remote interrupt request. The value is a
|
162 |
|
|
32-bit bitset of active interrupts.
|
163 |
|
|
|
164 |
|
|
|
165 |
|
|
BUGS
|
166 |
|
|
|
167 |
|
|
All and none.
|
168 |
|
|
|
169 |
|
|
|
170 |
|
|
PROTOCOL
|
171 |
|
|
|
172 |
|
|
This is version 1.0 of this protocol, defining packet format and
|
173 |
|
|
actions in a supposedly upward-compatible manner where client and
|
174 |
|
|
servers of different versions are expected to interoperate; the
|
175 |
|
|
format and the definitions below are hopefully generic enough to
|
176 |
|
|
allow this.
|
177 |
|
|
|
178 |
|
|
Each connection has a server and a client (this code); the roles
|
179 |
|
|
are known beforehand. The client usually corresponds to a CPU and
|
180 |
|
|
memory system and the server corresponds to a memory-mapped
|
181 |
|
|
register hardware interface and/or a DMA controller. They
|
182 |
|
|
communicate using packets with specific commands, of which some
|
183 |
|
|
require replies from the other side; most are intiated by the
|
184 |
|
|
client with one exception. A reply uses the same format as the
|
185 |
|
|
command.
|
186 |
|
|
|
187 |
|
|
Packets are at least three bytes long, where the first two bytes
|
188 |
|
|
form a header, a 16-bit little-endian number that is the total
|
189 |
|
|
length of the packet including the header. There is also a
|
190 |
|
|
one-byte command. The payload is optional, depending on the
|
191 |
|
|
command.
|
192 |
|
|
|
193 |
|
|
[[16-bit-low-byte-of-length] [16-bit-high-byte-of-length]
|
194 |
|
|
[command/reply] [payload byte 0] [payload byte 1]
|
195 |
|
|
... [payload byte (length-of-packet - 3)]]
|
196 |
|
|
|
197 |
|
|
Commands:
|
198 |
|
|
|
199 |
|
|
A client or server that reads an undocumented command may exit with
|
200 |
|
|
a hard error. Payload not defined or disallowed below is ignored.
|
201 |
|
|
|
202 |
|
|
It is expected that future client versions find out the version of
|
203 |
|
|
the server side by polling with base commands, assuming earlier
|
204 |
|
|
versions if a certain reply isn't seen, with newly defined payload
|
205 |
|
|
parts where earlier versions left it undefined. New commands and
|
206 |
|
|
formats are sent only to the other side after the client and server
|
207 |
|
|
has found out each others version. Not all servers support all
|
208 |
|
|
commands; the type of server and supported set of commands is
|
209 |
|
|
expected to be known beforehand.
|
210 |
|
|
|
211 |
|
|
RV_READ_CMD = 0
|
212 |
|
|
Initiated by the client, requires a reply from the server. The
|
213 |
|
|
payload from the client is at least 4 bytes, forming a 4-byte
|
214 |
|
|
little-endian address, the rest being undefined. The reply from
|
215 |
|
|
the server is at least 8 bytes, forming the same address data as in
|
216 |
|
|
the request and the second 4-byte data being the little-endian
|
217 |
|
|
contents.
|
218 |
|
|
|
219 |
|
|
RV_WRITE_CMD = 1
|
220 |
|
|
Initiated by the client, requires a reply from the server. Payload
|
221 |
|
|
from the client is at least 8 bytes, forming a 4-byte little-endian
|
222 |
|
|
word being the address, the rest being the little-endian contents
|
223 |
|
|
to write. The reply from the server is 8 bytes unless elsewhere
|
224 |
|
|
agreed otherwise, forming the same address and data as in the
|
225 |
|
|
request. The data sent back may have been altered to correspond to
|
226 |
|
|
defined parts but can safely be discarded.
|
227 |
|
|
|
228 |
|
|
RV_IRQ_CMD = 2
|
229 |
|
|
Initiated by the server, no reply. The payload is 4 bytes, forming
|
230 |
|
|
a little-endian word with bits numbers corresponding to currently
|
231 |
|
|
active interrupt sources; value (1<<N) indicating interrupt source
|
232 |
|
|
N being active.
|
233 |
|
|
|
234 |
|
|
RV_MEM_RD_CMD = 3
|
235 |
|
|
Initiated by the server, requires a reply. A client must know
|
236 |
|
|
beforehand when (in command sequence or constant) the server can
|
237 |
|
|
send this command and if so must then not send any commands of its
|
238 |
|
|
own (including watchdog commands); the server is allowed to assume
|
239 |
|
|
that incoming data is only replies to this command. The format is
|
240 |
|
|
8 bytes of data; 4 bytes of little-endian address followed by a
|
241 |
|
|
32-bit little endian word with the number of bytes to read. The
|
242 |
|
|
reply is the same address and number of bytes, followed by the data
|
243 |
|
|
that had been read.
|
244 |
|
|
|
245 |
|
|
RV_MEM_WR_CMD = 4
|
246 |
|
|
Initiated by the server, no reply. The format is the same as a
|
247 |
|
|
reply to RV_MEM_RD_CMD; a 32-bit little-endian address, followed by
|
248 |
|
|
the 32-bit little-endian number of bytes to write (redundant
|
249 |
|
|
information but must be consistent with the packet header).
|
250 |
|
|
|
251 |
|
|
RV_MBOX_HANDLE_CMD = 5
|
252 |
|
|
Initiated by the client, requires a reply. The payload is 4
|
253 |
|
|
undefined bytes followed by an binary blob, the size of the
|
254 |
|
|
blob given by the packet header. The reply is a 32-bit little
|
255 |
|
|
endian number at the same index as the undefined bytes. Actual
|
256 |
|
|
semantics are application-specific.
|
257 |
|
|
|
258 |
|
|
RV_MBOX_PUT_CMD = 6
|
259 |
|
|
Initiated by the client, requires a reply, with the reply using the
|
260 |
|
|
RV_MBOX_HANDLE_CMD reply format (i.e. *both* that command and
|
261 |
|
|
32-bit little-endian number). The payload is a 32-bit little
|
262 |
|
|
endian number followed by an undefined payload, at most 20 bytes
|
263 |
|
|
long. The reply is a 32-bit little endian number. Actual
|
264 |
|
|
semantics are application-specific.
|
265 |
|
|
|
266 |
|
|
RV_WATCHDOG_CMD = 7
|
267 |
|
|
Initiated by the client, no reply. A version 1.0 client sends no
|
268 |
|
|
payload; a version 1.0 server should ignore any such payload. A
|
269 |
|
|
version 1.0 server must not send a reply.
|
270 |
|
|
|
271 |
|
|
|
272 |
|
|
Possible future enhancements:
|
273 |
|
|
|
274 |
|
|
Synchronization; server and client reports the number of elapsed
|
275 |
|
|
cycles (unit to-be-defined) at each request or notification.
|
276 |
|
|
Pretty much the top-of-the-todo-list item.
|
277 |
|
|
|
278 |
|
|
Large addresses; 1.0 being restricted to 32-bit addresses.
|
279 |
|
|
|
280 |
|
|
Variable-size data; currently restricted to 32-bit register
|
281 |
|
|
accesses.
|
282 |
|
|
|
283 |
|
|
Specified data endianness (not the packet header) perhaps as part
|
284 |
|
|
of an initial format request; currently little-endian only.
|
285 |
|
|
|
286 |
|
|
|
287 |
|
|
Usage notes:
|
288 |
|
|
When used with servers sending RV_MEM_RD_CMD but being
|
289 |
|
|
narrow-minded about indata, set watchdog-interval to 0. Use
|
290 |
|
|
multiple rv instances when there are e.g. separate register and
|
291 |
|
|
memory servers. Alway log, setting "/rv/trace? true", at the
|
292 |
|
|
development phase. Borrow from the test-suite.
|
293 |
|
|
*/
|
294 |
|
|
|
295 |
|
|
#define RV_FAMILY_NAME "rv"
|
296 |
|
|
|
297 |
|
|
enum rv_command {
|
298 |
|
|
RV_READ_CMD = 0,
|
299 |
|
|
RV_WRITE_CMD = 1,
|
300 |
|
|
RV_IRQ_CMD = 2,
|
301 |
|
|
RV_MEM_RD_CMD = 3,
|
302 |
|
|
RV_MEM_WR_CMD = 4,
|
303 |
|
|
RV_MBOX_HANDLE_CMD = 5,
|
304 |
|
|
RV_MBOX_PUT_CMD = 6,
|
305 |
|
|
RV_WATCHDOG_CMD = 7
|
306 |
|
|
};
|
307 |
|
|
|
308 |
|
|
|
309 |
|
|
typedef struct _hw_rv_device
|
310 |
|
|
{
|
311 |
|
|
/* Mapping of remote interrupt bit-numbers to local ones. */
|
312 |
|
|
unsigned32 remote_to_local_int[32];
|
313 |
|
|
|
314 |
|
|
/* When multiple bits are set, a non-zero value here indicates that
|
315 |
|
|
this value should be used instead. */
|
316 |
|
|
unsigned32 intmultiple;
|
317 |
|
|
|
318 |
|
|
/* Local address of registers. */
|
319 |
|
|
unsigned32 reg_address;
|
320 |
|
|
|
321 |
|
|
/* Size of register bank in bytes. */
|
322 |
|
|
unsigned32 reg_size;
|
323 |
|
|
|
324 |
|
|
/* Remote address of registers. */
|
325 |
|
|
unsigned32 remote_reg_address;
|
326 |
|
|
|
327 |
|
|
/* Local address of DMA:able memory. */
|
328 |
|
|
unsigned32 mem_address;
|
329 |
|
|
|
330 |
|
|
/* Size of DMA:able memory in bytes. */
|
331 |
|
|
unsigned32 mem_size;
|
332 |
|
|
|
333 |
|
|
/* Bitmask for valid DMA request size. */
|
334 |
|
|
unsigned32 mem_burst_mask;
|
335 |
|
|
|
336 |
|
|
/* Remote address of DMA:able memory. */
|
337 |
|
|
unsigned32 remote_mem_address;
|
338 |
|
|
|
339 |
|
|
/* (Local) address of mbox; where to put a pointer to the mbox to be
|
340 |
|
|
sent. */
|
341 |
|
|
unsigned32 mbox_address;
|
342 |
|
|
|
343 |
|
|
/* Probably not 127.0.0.1:10000. */
|
344 |
|
|
const char *host;
|
345 |
|
|
int port;
|
346 |
|
|
|
347 |
|
|
/* If non-NULL, points to memory to use instead of connection. */
|
348 |
|
|
unsigned8 *dummy;
|
349 |
|
|
|
350 |
|
|
/* File descriptor for the socket. Set to -1 when error. Only one
|
351 |
|
|
of dummy and this is active. */
|
352 |
|
|
int fd;
|
353 |
|
|
|
354 |
|
|
/* Stashed errno, as we don't emit an error right away. */
|
355 |
|
|
int saved_errno;
|
356 |
|
|
|
357 |
|
|
/* This, plus latency because the CPU might not be checking until a
|
358 |
|
|
CTI insn (usually a branch or a jump) is the interval in cycles
|
359 |
|
|
between the rv is polled for e.g. DMA requests. */
|
360 |
|
|
unsigned32 max_tick_poll_interval;
|
361 |
|
|
|
362 |
|
|
/* Running counter for exponential backoff up to
|
363 |
|
|
max_tick_poll_interval to avoid polling the connection
|
364 |
|
|
unnecessarily often. Set to 1 when rv activity (read/write
|
365 |
|
|
register, DMA request) is detected. */
|
366 |
|
|
unsigned32 next_period;
|
367 |
|
|
|
368 |
|
|
/* This is the interval in wall-clock seconds between watchdog
|
369 |
|
|
packets are sent to the remote side. Zero means no watchdog
|
370 |
|
|
packets. */
|
371 |
|
|
unsigned32 watchdog_interval;
|
372 |
|
|
|
373 |
|
|
/* Last time we sent a watchdog packet. */
|
374 |
|
|
struct timeval last_wdog_time;
|
375 |
|
|
|
376 |
|
|
/* Mostly used as a kludge for knowing which rv:s have poll events
|
377 |
|
|
active. */
|
378 |
|
|
struct hw_event *poll_callback;
|
379 |
|
|
} hw_rv_device;
|
380 |
|
|
|
381 |
|
|
|
382 |
|
|
/* We might add ports in the future, so keep this an enumeration. */
|
383 |
|
|
enum
|
384 |
|
|
{
|
385 |
|
|
INT_PORT
|
386 |
|
|
};
|
387 |
|
|
|
388 |
|
|
/* Our ports. */
|
389 |
|
|
static const struct hw_port_descriptor hw_rv_ports[] = {
|
390 |
|
|
{ "int", INT_PORT, 0, output_port },
|
391 |
|
|
{ NULL }
|
392 |
|
|
};
|
393 |
|
|
|
394 |
|
|
/* Send LEN bytes of data from BUF to the socket. Abort on
|
395 |
|
|
errors. */
|
396 |
|
|
|
397 |
|
|
static void
|
398 |
|
|
hw_rv_write (struct hw *me,
|
399 |
|
|
void *buf,
|
400 |
|
|
unsigned int len)
|
401 |
|
|
{
|
402 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
403 |
|
|
unsigned8 *bufp = buf;
|
404 |
|
|
|
405 |
|
|
/* If we don't have a valid fd here, it's because we got an error
|
406 |
|
|
initially, and we suppressed that error. */
|
407 |
|
|
if (rv->fd == -1)
|
408 |
|
|
hw_abort (me, "couldn't open a connection to %s:%d because: %s",
|
409 |
|
|
rv->host, rv->port, strerror (rv->saved_errno));
|
410 |
|
|
|
411 |
|
|
while (len > 0)
|
412 |
|
|
{
|
413 |
|
|
ssize_t ret = write (rv->fd, bufp, len);
|
414 |
|
|
if (ret < 0)
|
415 |
|
|
/* FIXME: More graceful exit. */
|
416 |
|
|
hw_abort (me, "write to %s:%d failed: %s\n", rv->host, rv->port,
|
417 |
|
|
strerror (errno));
|
418 |
|
|
|
419 |
|
|
len -= ret;
|
420 |
|
|
bufp += ret;
|
421 |
|
|
}
|
422 |
|
|
}
|
423 |
|
|
|
424 |
|
|
/* Read LEN bytes of data into BUF from the socket. Set the file
|
425 |
|
|
descriptor to -1 if there's an error. */
|
426 |
|
|
|
427 |
|
|
static void
|
428 |
|
|
hw_rv_read (struct hw *me,
|
429 |
|
|
void *buf,
|
430 |
|
|
unsigned int len)
|
431 |
|
|
{
|
432 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
433 |
|
|
unsigned8 *bufp = buf;
|
434 |
|
|
|
435 |
|
|
while (len > 0)
|
436 |
|
|
{
|
437 |
|
|
ssize_t ret = read (rv->fd, bufp, len);
|
438 |
|
|
|
439 |
|
|
/* We get all zero if the remote end quits, but no error
|
440 |
|
|
indication; even select says there's data active. */
|
441 |
|
|
if (ret <= 0)
|
442 |
|
|
{
|
443 |
|
|
if (close (rv->fd) != 0)
|
444 |
|
|
/* FIXME: More graceful exit. */
|
445 |
|
|
hw_abort (me, "read from %s:%d failed: %d\n", rv->host, rv->port, errno);
|
446 |
|
|
rv->fd = -1;
|
447 |
|
|
return;
|
448 |
|
|
}
|
449 |
|
|
|
450 |
|
|
len -= ret;
|
451 |
|
|
bufp += ret;
|
452 |
|
|
}
|
453 |
|
|
}
|
454 |
|
|
|
455 |
|
|
/* Construct and send a packet of data of type CMD and len
|
456 |
|
|
LEN_NOHEADER (not counting the header...). */
|
457 |
|
|
|
458 |
|
|
static void
|
459 |
|
|
hw_rv_send (struct hw *me,
|
460 |
|
|
unsigned int cmd,
|
461 |
|
|
void *msg,
|
462 |
|
|
unsigned int len_noheader)
|
463 |
|
|
{
|
464 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
465 |
|
|
unsigned8 buf[32+3];
|
466 |
|
|
unsigned8 *bufp;
|
467 |
|
|
unsigned int len = len_noheader + 3;
|
468 |
|
|
int ret;
|
469 |
|
|
|
470 |
|
|
buf[0] = len & 255;
|
471 |
|
|
buf[1] = (len >> 8) & 255;
|
472 |
|
|
buf[2] = cmd;
|
473 |
|
|
|
474 |
|
|
if (len > sizeof (buf))
|
475 |
|
|
{
|
476 |
|
|
hw_rv_write (me, buf, 3);
|
477 |
|
|
len = len_noheader;
|
478 |
|
|
bufp = msg;
|
479 |
|
|
}
|
480 |
|
|
else
|
481 |
|
|
{
|
482 |
|
|
memcpy (buf + 3, msg, len_noheader);
|
483 |
|
|
bufp = buf;
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
hw_rv_write (me, bufp, len);
|
487 |
|
|
}
|
488 |
|
|
|
489 |
|
|
/* Handle incoming DMA requests as per the RV_MEM_RD_CMD packet.
|
490 |
|
|
Abort on errors. */
|
491 |
|
|
|
492 |
|
|
static void
|
493 |
|
|
hw_rv_read_mem (struct hw *me, unsigned int len)
|
494 |
|
|
{
|
495 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
496 |
|
|
/* If you change this size, please adjust the mem2 testcase. */
|
497 |
|
|
unsigned8 buf[32+8];
|
498 |
|
|
unsigned8 *bufp = buf;
|
499 |
|
|
unsigned32 leaddr;
|
500 |
|
|
unsigned32 addr;
|
501 |
|
|
unsigned32 lelen;
|
502 |
|
|
unsigned32 i;
|
503 |
|
|
|
504 |
|
|
if (len != 8)
|
505 |
|
|
hw_abort (me, "expected DMA read request len 8+3, got %d+3", len);
|
506 |
|
|
|
507 |
|
|
hw_rv_read (me, &leaddr, 4);
|
508 |
|
|
hw_rv_read (me, &lelen, 4);
|
509 |
|
|
len = LE2H_4 (lelen);
|
510 |
|
|
addr = LE2H_4 (leaddr);
|
511 |
|
|
|
512 |
|
|
if (addr < rv->remote_mem_address
|
513 |
|
|
|| addr >= rv->remote_mem_address + rv->mem_size)
|
514 |
|
|
hw_abort (me, "DMA read at remote 0x%x; outside [0x%x..0x%x-1]",
|
515 |
|
|
(unsigned) addr, (unsigned) rv->remote_mem_address,
|
516 |
|
|
(unsigned) (rv->remote_mem_address + rv->mem_size));
|
517 |
|
|
addr = addr - rv->remote_mem_address + rv->mem_address;
|
518 |
|
|
|
519 |
|
|
if (len == 0)
|
520 |
|
|
hw_abort (me, "DMA read request for 0 bytes isn't supported");
|
521 |
|
|
|
522 |
|
|
if (len & ~rv->mem_burst_mask)
|
523 |
|
|
hw_abort (me, "DMA trying to read %d bytes; not matching mask of 0x%x",
|
524 |
|
|
len, rv->mem_burst_mask);
|
525 |
|
|
if (len + 8 > sizeof (buf))
|
526 |
|
|
bufp = hw_malloc (me, len + 8);
|
527 |
|
|
|
528 |
|
|
HW_TRACE ((me, "DMA R 0x%x..0x%x", addr, addr + len -1));
|
529 |
|
|
hw_dma_read_buffer (me, bufp + 8, 0, addr, len);
|
530 |
|
|
if (hw_trace_p (me))
|
531 |
|
|
for (i = 0; i < len; i += 4)
|
532 |
|
|
HW_TRACE ((me, "0x%x: %02x %02x %02x %02x",
|
533 |
|
|
addr + i,
|
534 |
|
|
bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11]));
|
535 |
|
|
|
536 |
|
|
memcpy (bufp, &leaddr, 4);
|
537 |
|
|
memcpy (bufp + 4, &lelen, 4);
|
538 |
|
|
hw_rv_send (me, RV_MEM_RD_CMD, bufp, len + 8);
|
539 |
|
|
if (bufp != buf)
|
540 |
|
|
hw_free (me, bufp);
|
541 |
|
|
}
|
542 |
|
|
|
543 |
|
|
/* Handle incoming DMA requests as per the RV_MEM_WR_CMD packet.
|
544 |
|
|
Abort on errors. */
|
545 |
|
|
|
546 |
|
|
static void
|
547 |
|
|
hw_rv_write_mem (struct hw *me, unsigned int plen)
|
548 |
|
|
{
|
549 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
550 |
|
|
/* If you change this size, please adjust the mem2 testcase. */
|
551 |
|
|
unsigned8 buf[32+8];
|
552 |
|
|
unsigned8 *bufp = buf;
|
553 |
|
|
unsigned32 leaddr;
|
554 |
|
|
unsigned32 addr;
|
555 |
|
|
unsigned32 lelen;
|
556 |
|
|
unsigned32 len;
|
557 |
|
|
unsigned32 i;
|
558 |
|
|
|
559 |
|
|
hw_rv_read (me, &leaddr, 4);
|
560 |
|
|
hw_rv_read (me, &lelen, 4);
|
561 |
|
|
len = LE2H_4 (lelen);
|
562 |
|
|
addr = LE2H_4 (leaddr);
|
563 |
|
|
|
564 |
|
|
if (len != plen - 8)
|
565 |
|
|
hw_abort (me,
|
566 |
|
|
"inconsistency in DMA write request packet: "
|
567 |
|
|
"envelope %d+3, inner %d bytes", plen, len);
|
568 |
|
|
|
569 |
|
|
if (addr < rv->remote_mem_address
|
570 |
|
|
|| addr >= rv->remote_mem_address + rv->mem_size)
|
571 |
|
|
hw_abort (me, "DMA write at remote 0x%x; outside [0x%x..0x%x-1]",
|
572 |
|
|
(unsigned) addr, (unsigned) rv->remote_mem_address,
|
573 |
|
|
(unsigned) (rv->remote_mem_address + rv->mem_size));
|
574 |
|
|
|
575 |
|
|
addr = addr - rv->remote_mem_address + rv->mem_address;
|
576 |
|
|
if (len == 0)
|
577 |
|
|
hw_abort (me, "DMA write request for 0 bytes isn't supported");
|
578 |
|
|
|
579 |
|
|
if (len & ~rv->mem_burst_mask)
|
580 |
|
|
hw_abort (me, "DMA trying to write %d bytes; not matching mask of 0x%x",
|
581 |
|
|
len, rv->mem_burst_mask);
|
582 |
|
|
if (len + 8 > sizeof (buf))
|
583 |
|
|
bufp = hw_malloc (me, len + 8);
|
584 |
|
|
|
585 |
|
|
hw_rv_read (me, bufp + 8, len);
|
586 |
|
|
HW_TRACE ((me, "DMA W 0x%x..0x%x", addr, addr + len - 1));
|
587 |
|
|
hw_dma_write_buffer (me, bufp + 8, 0, addr, len, 0);
|
588 |
|
|
if (hw_trace_p (me))
|
589 |
|
|
for (i = 0; i < len; i += 4)
|
590 |
|
|
HW_TRACE ((me, "0x%x: %02x %02x %02x %02x",
|
591 |
|
|
addr + i,
|
592 |
|
|
bufp[i+8], bufp[i+9], bufp[i+10], bufp[i+11]));
|
593 |
|
|
if (bufp != buf)
|
594 |
|
|
hw_free (me, bufp);
|
595 |
|
|
}
|
596 |
|
|
|
597 |
|
|
static void
|
598 |
|
|
hw_rv_irq (struct hw *me, unsigned int len)
|
599 |
|
|
{
|
600 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
601 |
|
|
unsigned32 intbitsle;
|
602 |
|
|
unsigned32 intbits_ext;
|
603 |
|
|
unsigned32 intval = 0;
|
604 |
|
|
int i;
|
605 |
|
|
|
606 |
|
|
if (len != 4)
|
607 |
|
|
hw_abort (me, "IRQ with %d data not supported", len);
|
608 |
|
|
|
609 |
|
|
hw_rv_read (me, &intbitsle, 4);
|
610 |
|
|
intbits_ext = LE2H_4 (intbitsle);
|
611 |
|
|
for (i = 0; i < 32; i++)
|
612 |
|
|
if ((intbits_ext & (1 << i)) != 0)
|
613 |
|
|
intval |= rv->remote_to_local_int[i];
|
614 |
|
|
if ((intbits_ext & ~(intbits_ext - 1)) != intbits_ext
|
615 |
|
|
&& rv->intmultiple != 0)
|
616 |
|
|
intval = rv->intmultiple;
|
617 |
|
|
|
618 |
|
|
HW_TRACE ((me, "IRQ 0x%x", intval));
|
619 |
|
|
hw_port_event (me, INT_PORT, intval);
|
620 |
|
|
}
|
621 |
|
|
|
622 |
|
|
/* Handle incoming interrupt notifications as per the RV_IRQ_CMD
|
623 |
|
|
packet. Abort on errors. */
|
624 |
|
|
|
625 |
|
|
static void
|
626 |
|
|
hw_rv_handle_incoming (struct hw *me,
|
627 |
|
|
int expected_type,
|
628 |
|
|
unsigned8 *buf,
|
629 |
|
|
unsigned int *return_len)
|
630 |
|
|
{
|
631 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
632 |
|
|
unsigned8 cbuf[32];
|
633 |
|
|
unsigned int len;
|
634 |
|
|
unsigned int cmd;
|
635 |
|
|
|
636 |
|
|
while (1)
|
637 |
|
|
{
|
638 |
|
|
hw_rv_read (me, cbuf, 3);
|
639 |
|
|
|
640 |
|
|
if (rv->fd == -1)
|
641 |
|
|
return;
|
642 |
|
|
|
643 |
|
|
len = cbuf[0] + cbuf[1] * 256 - 3;
|
644 |
|
|
cmd = cbuf[2];
|
645 |
|
|
|
646 |
|
|
/* These come in "asynchronously"; not as a reply. */
|
647 |
|
|
switch (cmd)
|
648 |
|
|
{
|
649 |
|
|
case RV_IRQ_CMD:
|
650 |
|
|
hw_rv_irq (me, len);
|
651 |
|
|
break;
|
652 |
|
|
|
653 |
|
|
case RV_MEM_RD_CMD:
|
654 |
|
|
hw_rv_read_mem (me, len);
|
655 |
|
|
break;
|
656 |
|
|
|
657 |
|
|
case RV_MEM_WR_CMD:
|
658 |
|
|
hw_rv_write_mem (me, len);
|
659 |
|
|
break;
|
660 |
|
|
}
|
661 |
|
|
|
662 |
|
|
/* Something is incoming from the other side, so tighten up all
|
663 |
|
|
slack at the next wait. */
|
664 |
|
|
rv->next_period = 1;
|
665 |
|
|
|
666 |
|
|
switch (cmd)
|
667 |
|
|
{
|
668 |
|
|
case RV_MEM_RD_CMD:
|
669 |
|
|
case RV_MEM_WR_CMD:
|
670 |
|
|
case RV_IRQ_CMD:
|
671 |
|
|
/* Don't try to handle more than one of these if we were'nt
|
672 |
|
|
expecting a reply. */
|
673 |
|
|
if (expected_type == -1)
|
674 |
|
|
return;
|
675 |
|
|
continue;
|
676 |
|
|
}
|
677 |
|
|
|
678 |
|
|
/* Require a match between this supposed-reply and the command
|
679 |
|
|
for the rest. */
|
680 |
|
|
if (cmd != expected_type)
|
681 |
|
|
hw_abort (me, "unexpected reply, expected command %d, got %d",
|
682 |
|
|
expected_type, cmd);
|
683 |
|
|
|
684 |
|
|
switch (cmd)
|
685 |
|
|
{
|
686 |
|
|
case RV_MBOX_PUT_CMD:
|
687 |
|
|
case RV_MBOX_HANDLE_CMD:
|
688 |
|
|
case RV_WRITE_CMD:
|
689 |
|
|
case RV_READ_CMD:
|
690 |
|
|
hw_rv_read (me, buf, len <= *return_len ? len : *return_len);
|
691 |
|
|
*return_len = len;
|
692 |
|
|
break;
|
693 |
|
|
}
|
694 |
|
|
break;
|
695 |
|
|
}
|
696 |
|
|
}
|
697 |
|
|
|
698 |
|
|
/* Send a watchdog packet. Make a note of wallclock time. */
|
699 |
|
|
|
700 |
|
|
static void
|
701 |
|
|
hw_rv_send_wdog (struct hw *me)
|
702 |
|
|
{
|
703 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
704 |
|
|
HW_TRACE ((me, "WD"));
|
705 |
|
|
gettimeofday (&rv->last_wdog_time, NULL);
|
706 |
|
|
hw_rv_send (me, RV_WATCHDOG_CMD, "", 0);
|
707 |
|
|
}
|
708 |
|
|
|
709 |
|
|
/* Poll the remote side: see if there's any incoming traffic; handle a
|
710 |
|
|
packet if so. Send a watchdog packet if it's time to do so.
|
711 |
|
|
Beware that the Linux select call indicates traffic for a socket
|
712 |
|
|
that the remote side has closed (which may be because it was
|
713 |
|
|
finished; don't hork until we need to write something just because
|
714 |
|
|
we're polling). */
|
715 |
|
|
|
716 |
|
|
static void
|
717 |
|
|
hw_rv_poll_once (struct hw *me)
|
718 |
|
|
{
|
719 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
720 |
|
|
fd_set rfds;
|
721 |
|
|
fd_set efds;
|
722 |
|
|
struct timeval now;
|
723 |
|
|
int ret;
|
724 |
|
|
struct timeval tv;
|
725 |
|
|
|
726 |
|
|
if (rv->fd == -1)
|
727 |
|
|
/* Connection has died or was never initiated. */
|
728 |
|
|
return;
|
729 |
|
|
|
730 |
|
|
FD_ZERO (&rfds);
|
731 |
|
|
FD_SET (rv->fd, &rfds);
|
732 |
|
|
FD_ZERO (&efds);
|
733 |
|
|
FD_SET (rv->fd, &efds);
|
734 |
|
|
tv.tv_sec = 0;
|
735 |
|
|
tv.tv_usec = 0;
|
736 |
|
|
|
737 |
|
|
ret = select (rv->fd + 1, &rfds, NULL, &efds, &tv);
|
738 |
|
|
gettimeofday (&now, NULL);
|
739 |
|
|
|
740 |
|
|
if (ret < 0)
|
741 |
|
|
hw_abort (me, "select failed: %d\n", errno);
|
742 |
|
|
|
743 |
|
|
if (rv->watchdog_interval != 0
|
744 |
|
|
&& now.tv_sec - rv->last_wdog_time.tv_sec >= rv->watchdog_interval)
|
745 |
|
|
hw_rv_send_wdog (me);
|
746 |
|
|
|
747 |
|
|
if (FD_ISSET (rv->fd, &rfds))
|
748 |
|
|
hw_rv_handle_incoming (me, -1, NULL, NULL);
|
749 |
|
|
}
|
750 |
|
|
|
751 |
|
|
/* Initialize mapping of remote-to-local interrupt data. */
|
752 |
|
|
|
753 |
|
|
static void
|
754 |
|
|
hw_rv_map_ints (struct hw *me)
|
755 |
|
|
{
|
756 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
757 |
|
|
int i;
|
758 |
|
|
|
759 |
|
|
for (i = 0; i < 32; i++)
|
760 |
|
|
rv->remote_to_local_int[i] = 1 << i;
|
761 |
|
|
|
762 |
|
|
if (hw_find_property (me, "intnum") != NULL)
|
763 |
|
|
for (i = 0; i < 32; i++)
|
764 |
|
|
{
|
765 |
|
|
signed_cell val = -1;
|
766 |
|
|
if (hw_find_integer_array_property (me, "intnum", i, &val) > 0)
|
767 |
|
|
{
|
768 |
|
|
if (val > 0)
|
769 |
|
|
rv->remote_to_local_int[i] = val;
|
770 |
|
|
else
|
771 |
|
|
hw_abort (me, "property \"intnum@%d\" must be > 0; is %d",
|
772 |
|
|
i, (int) val);
|
773 |
|
|
}
|
774 |
|
|
}
|
775 |
|
|
}
|
776 |
|
|
|
777 |
|
|
/* Handle the after-N-ticks "poll event", calling the poll-the-fd
|
778 |
|
|
method. Update the period. */
|
779 |
|
|
|
780 |
|
|
static void
|
781 |
|
|
do_poll_event (struct hw *me, void *data)
|
782 |
|
|
{
|
783 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
784 |
|
|
unsigned32 new_period;
|
785 |
|
|
|
786 |
|
|
if (rv->dummy != NULL)
|
787 |
|
|
return;
|
788 |
|
|
|
789 |
|
|
hw_rv_poll_once (me);
|
790 |
|
|
if (rv->fd >= 0)
|
791 |
|
|
rv->poll_callback
|
792 |
|
|
= hw_event_queue_schedule (me, rv->next_period, do_poll_event, NULL);
|
793 |
|
|
|
794 |
|
|
new_period = rv->next_period * 2;
|
795 |
|
|
if (new_period <= rv->max_tick_poll_interval)
|
796 |
|
|
rv->next_period = new_period;
|
797 |
|
|
}
|
798 |
|
|
|
799 |
|
|
/* HW tree traverse function for hw_rv_add_init. */
|
800 |
|
|
|
801 |
|
|
static void
|
802 |
|
|
hw_rv_add_poller (struct hw *me, void *data)
|
803 |
|
|
{
|
804 |
|
|
hw_rv_device *rv;
|
805 |
|
|
|
806 |
|
|
if (hw_family (me) == NULL
|
807 |
|
|
|| strcmp (hw_family (me), RV_FAMILY_NAME) != 0)
|
808 |
|
|
return;
|
809 |
|
|
|
810 |
|
|
rv = (hw_rv_device *) hw_data (me);
|
811 |
|
|
if (rv->poll_callback != NULL)
|
812 |
|
|
return;
|
813 |
|
|
|
814 |
|
|
rv->poll_callback
|
815 |
|
|
= hw_event_queue_schedule (me, 1, do_poll_event, NULL);
|
816 |
|
|
}
|
817 |
|
|
|
818 |
|
|
/* Simulator module init function for hw_rv_add_init. */
|
819 |
|
|
|
820 |
|
|
/* FIXME: For the call so hw_tree_traverse, we need to know that the
|
821 |
|
|
first member of struct sim_hw is the struct hw *root, but there's
|
822 |
|
|
no accessor method and struct sim_hw is defined in sim-hw.c only.
|
823 |
|
|
Hence this hack, until an accessor is added, or there's a traverse
|
824 |
|
|
function that takes a SIM_DESC argument. */
|
825 |
|
|
struct sim_hw { struct hw *tree; };
|
826 |
|
|
|
827 |
|
|
static SIM_RC
|
828 |
|
|
hw_rv_add_rv_pollers (SIM_DESC sd)
|
829 |
|
|
{
|
830 |
|
|
hw_tree_traverse (STATE_HW (sd)->tree, hw_rv_add_poller, NULL, NULL);
|
831 |
|
|
return SIM_RC_OK;
|
832 |
|
|
}
|
833 |
|
|
|
834 |
|
|
/* We need to add events for polling, but we can't add one from the
|
835 |
|
|
finish-function, and there are no other call points, at least for
|
836 |
|
|
instances without "reg" (when there are just DMA requests from the
|
837 |
|
|
remote end; no locally initiated activity). Therefore we add a
|
838 |
|
|
simulator module init function, but those don't have private
|
839 |
|
|
payload arguments; just a SD argument. We cope by parsing the HW
|
840 |
|
|
root and making sure *all* "rv":s have poll callbacks installed.
|
841 |
|
|
Luckily, this is just an initialization step, and not many
|
842 |
|
|
simultaneous instances of rv are expected: we get a N**2 complexity
|
843 |
|
|
for visits to each rv node by this method. */
|
844 |
|
|
|
845 |
|
|
static void
|
846 |
|
|
hw_rv_add_init (struct hw *me)
|
847 |
|
|
{
|
848 |
|
|
sim_module_add_init_fn (hw_system (me), hw_rv_add_rv_pollers);
|
849 |
|
|
}
|
850 |
|
|
|
851 |
|
|
/* Open up a connection to the other side. Abort on errors. */
|
852 |
|
|
|
853 |
|
|
static void
|
854 |
|
|
hw_rv_init_socket (struct hw *me)
|
855 |
|
|
{
|
856 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
857 |
|
|
int sock;
|
858 |
|
|
struct sockaddr_in server;
|
859 |
|
|
|
860 |
|
|
rv->fd = -1;
|
861 |
|
|
|
862 |
|
|
if (rv->dummy != NULL)
|
863 |
|
|
return;
|
864 |
|
|
|
865 |
|
|
memset (&server, 0, sizeof (server));
|
866 |
|
|
server.sin_family = AF_INET;
|
867 |
|
|
server.sin_addr.s_addr = inet_addr (rv->host);
|
868 |
|
|
|
869 |
|
|
/* Solaris 2.7 lacks this macro. */
|
870 |
|
|
#ifndef INADDR_NONE
|
871 |
|
|
#define INADDR_NONE -1
|
872 |
|
|
#endif
|
873 |
|
|
|
874 |
|
|
if (server.sin_addr.s_addr == INADDR_NONE)
|
875 |
|
|
{
|
876 |
|
|
struct hostent *h;
|
877 |
|
|
h = gethostbyname (rv->host);
|
878 |
|
|
if (h != NULL)
|
879 |
|
|
{
|
880 |
|
|
memcpy (&server.sin_addr, h->h_addr, h->h_length);
|
881 |
|
|
server.sin_family = h->h_addrtype;
|
882 |
|
|
}
|
883 |
|
|
else
|
884 |
|
|
hw_abort (me, "can't resolve host %s", rv->host);
|
885 |
|
|
}
|
886 |
|
|
|
887 |
|
|
server.sin_port = htons (rv->port);
|
888 |
|
|
sock = socket (AF_INET, SOCK_STREAM, 0);
|
889 |
|
|
|
890 |
|
|
if (sock == -1)
|
891 |
|
|
hw_abort (me, "can't get a socket for %s:%d connection",
|
892 |
|
|
rv->host, rv->port);
|
893 |
|
|
|
894 |
|
|
if (connect (sock, (struct sockaddr *) &server, sizeof server) >= 0)
|
895 |
|
|
{
|
896 |
|
|
rv->fd = sock;
|
897 |
|
|
|
898 |
|
|
/* FIXME: init packet here. Maybe start packet too. */
|
899 |
|
|
if (rv->watchdog_interval != 0)
|
900 |
|
|
hw_rv_send_wdog (me);
|
901 |
|
|
}
|
902 |
|
|
else
|
903 |
|
|
/* Stash the errno for later display, if some connection activity
|
904 |
|
|
is requested. Don't emit an error here; we might have been
|
905 |
|
|
called just for test purposes. */
|
906 |
|
|
rv->saved_errno = errno;
|
907 |
|
|
}
|
908 |
|
|
|
909 |
|
|
/* Local rv register reads end up here. */
|
910 |
|
|
|
911 |
|
|
static unsigned int
|
912 |
|
|
hw_rv_reg_read (struct hw *me,
|
913 |
|
|
void *dest,
|
914 |
|
|
int space,
|
915 |
|
|
unsigned_word addr,
|
916 |
|
|
unsigned int nr_bytes)
|
917 |
|
|
{
|
918 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
919 |
|
|
unsigned8 addr_data[8] = "";
|
920 |
|
|
unsigned32 a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address);
|
921 |
|
|
unsigned int len = 8;
|
922 |
|
|
|
923 |
|
|
if (nr_bytes != 4)
|
924 |
|
|
hw_abort (me, "must be four byte read");
|
925 |
|
|
|
926 |
|
|
if (addr == rv->mbox_address)
|
927 |
|
|
hw_abort (me, "invalid read of mbox address 0x%x",
|
928 |
|
|
(unsigned) rv->mbox_address);
|
929 |
|
|
|
930 |
|
|
memcpy (addr_data, &a_l, 4);
|
931 |
|
|
HW_TRACE ((me, "REG R 0x%x", addr));
|
932 |
|
|
if (rv->dummy != NULL)
|
933 |
|
|
{
|
934 |
|
|
len = 8;
|
935 |
|
|
memcpy (addr_data + 4, rv->dummy + addr - rv->reg_address, 4);
|
936 |
|
|
}
|
937 |
|
|
else
|
938 |
|
|
{
|
939 |
|
|
hw_rv_send (me, RV_READ_CMD, addr_data, len);
|
940 |
|
|
hw_rv_handle_incoming (me, RV_READ_CMD, addr_data, &len);
|
941 |
|
|
}
|
942 |
|
|
|
943 |
|
|
if (len != 8)
|
944 |
|
|
hw_abort (me, "read %d != 8 bytes returned", len);
|
945 |
|
|
HW_TRACE ((me, ":= 0x%02x%02x%02x%02x",
|
946 |
|
|
addr_data[7], addr_data[6], addr_data[5], addr_data[4]));
|
947 |
|
|
memcpy (dest, addr_data + 4, 4);
|
948 |
|
|
return nr_bytes;
|
949 |
|
|
}
|
950 |
|
|
|
951 |
|
|
/* Local rv mbox requests (handle or put) end up here. */
|
952 |
|
|
|
953 |
|
|
static void
|
954 |
|
|
hw_rv_mbox (struct hw *me, unsigned_word address)
|
955 |
|
|
{
|
956 |
|
|
unsigned8 buf[256+3];
|
957 |
|
|
unsigned int cmd;
|
958 |
|
|
unsigned int rlen;
|
959 |
|
|
unsigned32 i;
|
960 |
|
|
unsigned int len
|
961 |
|
|
= hw_dma_read_buffer (me, buf, 0, address, 3);
|
962 |
|
|
|
963 |
|
|
if (len != 3)
|
964 |
|
|
hw_abort (me, "mbox read %d != 3 bytes returned", len);
|
965 |
|
|
|
966 |
|
|
cmd = buf[2];
|
967 |
|
|
if (cmd != RV_MBOX_HANDLE_CMD && cmd != RV_MBOX_PUT_CMD)
|
968 |
|
|
hw_abort (me, "unsupported mbox command %d", cmd);
|
969 |
|
|
|
970 |
|
|
len = buf[0] + buf[1]*256;
|
971 |
|
|
|
972 |
|
|
if (len > sizeof (buf))
|
973 |
|
|
hw_abort (me, "mbox cmd %d send size %d unsupported", cmd, len);
|
974 |
|
|
|
975 |
|
|
rlen = hw_dma_read_buffer (me, buf + 3, 0, address + 3, len - 3);
|
976 |
|
|
if (rlen != len - 3)
|
977 |
|
|
hw_abort (me, "mbox read %d != %d bytes returned", rlen, len - 3);
|
978 |
|
|
|
979 |
|
|
HW_TRACE ((me, "MBOX %s 0x%x..0x%x",
|
980 |
|
|
cmd == RV_MBOX_HANDLE_CMD ? "H" : "P",
|
981 |
|
|
address, address + len - 1));
|
982 |
|
|
for (i = 0; i < rlen; i += 8)
|
983 |
|
|
HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x",
|
984 |
|
|
address + 3 + i,
|
985 |
|
|
buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i],
|
986 |
|
|
buf[9+i], buf[10+i]));
|
987 |
|
|
|
988 |
|
|
len -= 3;
|
989 |
|
|
hw_rv_send (me, cmd, buf + 3, len);
|
990 |
|
|
|
991 |
|
|
/* Note: both ..._PUT and ..._HANDLE get the ..._HANDLE reply. */
|
992 |
|
|
hw_rv_handle_incoming (me, RV_MBOX_HANDLE_CMD, buf + 3, &len);
|
993 |
|
|
if (len > sizeof (buf))
|
994 |
|
|
hw_abort (me, "mbox cmd %d receive size %d unsupported", cmd, len);
|
995 |
|
|
HW_TRACE ((me, "-> 0x%x..0x%x", address, address + len + 3 - 1));
|
996 |
|
|
for (i = 0; i < len; i += 8)
|
997 |
|
|
HW_TRACE ((me, "0x%x: %02x %02x %02x %02x %02x %02x %02x %02x",
|
998 |
|
|
address + 3 + i,
|
999 |
|
|
buf[3+i], buf[4+i], buf[5+i], buf[6+i], buf[7+i], buf[8+i],
|
1000 |
|
|
buf[9+i], buf[10+i]));
|
1001 |
|
|
|
1002 |
|
|
len += 3;
|
1003 |
|
|
buf[0] = len & 255;
|
1004 |
|
|
buf[1] = len / 256;
|
1005 |
|
|
rlen = hw_dma_write_buffer (me, buf, 0, address, len, 0);
|
1006 |
|
|
if (rlen != len)
|
1007 |
|
|
hw_abort (me, "mbox write %d != %d bytes", rlen, len);
|
1008 |
|
|
}
|
1009 |
|
|
|
1010 |
|
|
/* Local rv register writes end up here. */
|
1011 |
|
|
|
1012 |
|
|
static unsigned int
|
1013 |
|
|
hw_rv_reg_write (struct hw *me,
|
1014 |
|
|
const void *source,
|
1015 |
|
|
int space,
|
1016 |
|
|
unsigned_word addr,
|
1017 |
|
|
unsigned int nr_bytes)
|
1018 |
|
|
{
|
1019 |
|
|
hw_rv_device *rv = (hw_rv_device *) hw_data (me);
|
1020 |
|
|
|
1021 |
|
|
unsigned8 addr_data[8] = "";
|
1022 |
|
|
unsigned32 a_l = H2LE_4 (addr - rv->reg_address + rv->remote_reg_address);
|
1023 |
|
|
unsigned int len = 8;
|
1024 |
|
|
|
1025 |
|
|
if (nr_bytes != 4)
|
1026 |
|
|
hw_abort (me, "must be four byte write");
|
1027 |
|
|
|
1028 |
|
|
memcpy (addr_data, &a_l, 4);
|
1029 |
|
|
memcpy (addr_data + 4, source, 4);
|
1030 |
|
|
|
1031 |
|
|
if (addr == rv->mbox_address)
|
1032 |
|
|
{
|
1033 |
|
|
unsigned32 mbox_addr_le;
|
1034 |
|
|
if (rv->dummy != NULL)
|
1035 |
|
|
hw_abort (me, "mbox not supported for a dummy instance");
|
1036 |
|
|
memcpy (&mbox_addr_le, source, 4);
|
1037 |
|
|
hw_rv_mbox (me, LE2H_4 (mbox_addr_le));
|
1038 |
|
|
return nr_bytes;
|
1039 |
|
|
}
|
1040 |
|
|
|
1041 |
|
|
HW_TRACE ((me, "REG W 0x%x := 0x%02x%02x%02x%02x", addr,
|
1042 |
|
|
addr_data[7], addr_data[6], addr_data[5], addr_data[4]));
|
1043 |
|
|
if (rv->dummy != NULL)
|
1044 |
|
|
{
|
1045 |
|
|
len = 8;
|
1046 |
|
|
memcpy (rv->dummy + addr - rv->reg_address, addr_data + 4, 4);
|
1047 |
|
|
}
|
1048 |
|
|
else
|
1049 |
|
|
{
|
1050 |
|
|
hw_rv_send (me, RV_WRITE_CMD, addr_data, len);
|
1051 |
|
|
hw_rv_handle_incoming (me, RV_WRITE_CMD, addr_data, &len);
|
1052 |
|
|
}
|
1053 |
|
|
|
1054 |
|
|
if (len != 8)
|
1055 |
|
|
hw_abort (me, "read %d != 8 bytes returned", len);
|
1056 |
|
|
|
1057 |
|
|
/* We had an access: tighten up all slack. */
|
1058 |
|
|
rv->next_period = 1;
|
1059 |
|
|
|
1060 |
|
|
return nr_bytes;
|
1061 |
|
|
}
|
1062 |
|
|
|
1063 |
|
|
/* Instance initializer function. */
|
1064 |
|
|
|
1065 |
|
|
static void
|
1066 |
|
|
hw_rv_finish (struct hw *me)
|
1067 |
|
|
{
|
1068 |
|
|
hw_rv_device *rv = HW_ZALLOC (me, hw_rv_device);
|
1069 |
|
|
int i;
|
1070 |
|
|
const struct hw_property *mem_prop;
|
1071 |
|
|
const struct hw_property *dummy_prop;
|
1072 |
|
|
const struct hw_property *mbox_prop;
|
1073 |
|
|
|
1074 |
|
|
set_hw_data (me, rv);
|
1075 |
|
|
|
1076 |
|
|
#undef RV_GET_IPROP
|
1077 |
|
|
#undef RV_GET_PROP
|
1078 |
|
|
#define RV_GET_PROP(T, N, M, D) \
|
1079 |
|
|
do \
|
1080 |
|
|
{ \
|
1081 |
|
|
if (hw_find_property (me, N) != NULL) \
|
1082 |
|
|
rv->M = hw_find_ ## T ## _property (me, N); \
|
1083 |
|
|
else \
|
1084 |
|
|
rv->M = (D); \
|
1085 |
|
|
} \
|
1086 |
|
|
while (0)
|
1087 |
|
|
#define RV_GET_IPROP(N, M, D) RV_GET_PROP (integer, N, M, D)
|
1088 |
|
|
|
1089 |
|
|
RV_GET_PROP (string, "host", host, "127.0.0.1");
|
1090 |
|
|
RV_GET_IPROP ("port", port, 10000);
|
1091 |
|
|
RV_GET_IPROP ("remote-reg", remote_reg_address, 0);
|
1092 |
|
|
RV_GET_IPROP ("max-poll-ticks", max_tick_poll_interval, 10000);
|
1093 |
|
|
RV_GET_IPROP ("watchdog-interval", watchdog_interval, 30);
|
1094 |
|
|
RV_GET_IPROP ("remote-mem", remote_mem_address, 0);
|
1095 |
|
|
RV_GET_IPROP ("mem-burst-mask", mem_burst_mask, 0xffff);
|
1096 |
|
|
RV_GET_IPROP ("intmultiple", intmultiple, 0);
|
1097 |
|
|
|
1098 |
|
|
set_hw_io_read_buffer (me, hw_rv_reg_read);
|
1099 |
|
|
set_hw_io_write_buffer (me, hw_rv_reg_write);
|
1100 |
|
|
set_hw_ports (me, hw_rv_ports);
|
1101 |
|
|
rv->next_period = 1;
|
1102 |
|
|
|
1103 |
|
|
/* FIXME: We only support zero or one reg and zero or one mem area. */
|
1104 |
|
|
if (hw_find_property (me, "reg") != NULL)
|
1105 |
|
|
{
|
1106 |
|
|
reg_property_spec reg;
|
1107 |
|
|
if (hw_find_reg_array_property (me, "reg", 0, ®))
|
1108 |
|
|
{
|
1109 |
|
|
unsigned_word attach_address;
|
1110 |
|
|
int attach_space;
|
1111 |
|
|
unsigned int attach_size;
|
1112 |
|
|
|
1113 |
|
|
hw_unit_address_to_attach_address (hw_parent (me),
|
1114 |
|
|
®.address,
|
1115 |
|
|
&attach_space,
|
1116 |
|
|
&attach_address,
|
1117 |
|
|
me);
|
1118 |
|
|
rv->reg_address = attach_address;
|
1119 |
|
|
hw_unit_size_to_attach_size (hw_parent (me),
|
1120 |
|
|
®.size,
|
1121 |
|
|
&attach_size, me);
|
1122 |
|
|
rv->reg_size = attach_size;
|
1123 |
|
|
if ((attach_address & 3) != 0)
|
1124 |
|
|
hw_abort (me, "register block must be 4 byte aligned");
|
1125 |
|
|
hw_attach_address (hw_parent (me),
|
1126 |
|
|
0,
|
1127 |
|
|
attach_space, attach_address, attach_size,
|
1128 |
|
|
me);
|
1129 |
|
|
}
|
1130 |
|
|
else
|
1131 |
|
|
hw_abort (me, "property \"reg\" has the wrong type");
|
1132 |
|
|
}
|
1133 |
|
|
|
1134 |
|
|
dummy_prop = hw_find_property (me, "dummy");
|
1135 |
|
|
if (dummy_prop != NULL)
|
1136 |
|
|
{
|
1137 |
|
|
if (rv->reg_size == 0)
|
1138 |
|
|
hw_abort (me, "dummy argument requires a \"reg\" property");
|
1139 |
|
|
|
1140 |
|
|
if (hw_property_type (dummy_prop) == integer_property)
|
1141 |
|
|
{
|
1142 |
|
|
unsigned32 dummyfill = hw_find_integer_property (me, "dummy");
|
1143 |
|
|
unsigned8 *dummymem = hw_malloc (me, rv->reg_size);
|
1144 |
|
|
memset (dummymem, dummyfill, rv->reg_size);
|
1145 |
|
|
rv->dummy = dummymem;
|
1146 |
|
|
}
|
1147 |
|
|
else
|
1148 |
|
|
{
|
1149 |
|
|
const char *dummyarg = hw_find_string_property (me, "dummy");
|
1150 |
|
|
unsigned8 *dummymem = hw_malloc (me, rv->reg_size);
|
1151 |
|
|
FILE *f = fopen (dummyarg, "rb");
|
1152 |
|
|
|
1153 |
|
|
if (f == NULL)
|
1154 |
|
|
hw_abort (me, "opening dummy-file \"%s\": %s",
|
1155 |
|
|
dummyarg, strerror (errno));
|
1156 |
|
|
if (fread (dummymem, 1, rv->reg_size, f) != rv->reg_size)
|
1157 |
|
|
hw_abort (me, "reading dummy-file \"%s\": %s",
|
1158 |
|
|
dummyarg, strerror (errno));
|
1159 |
|
|
fclose (f);
|
1160 |
|
|
rv->dummy = dummymem;
|
1161 |
|
|
}
|
1162 |
|
|
}
|
1163 |
|
|
|
1164 |
|
|
mbox_prop = hw_find_property (me, "mbox");
|
1165 |
|
|
if (mbox_prop != NULL)
|
1166 |
|
|
{
|
1167 |
|
|
if (hw_property_type (mbox_prop) == integer_property)
|
1168 |
|
|
{
|
1169 |
|
|
signed_cell attach_address_sc
|
1170 |
|
|
= hw_find_integer_property (me, "mbox");
|
1171 |
|
|
|
1172 |
|
|
rv->mbox_address = (unsigned32) attach_address_sc;
|
1173 |
|
|
hw_attach_address (hw_parent (me),
|
1174 |
|
|
0,
|
1175 |
|
|
0, (unsigned32) attach_address_sc, 4, me);
|
1176 |
|
|
}
|
1177 |
|
|
else
|
1178 |
|
|
hw_abort (me, "property \"mbox\" has the wrong type");
|
1179 |
|
|
}
|
1180 |
|
|
|
1181 |
|
|
mem_prop = hw_find_property (me, "mem");
|
1182 |
|
|
if (mem_prop != NULL)
|
1183 |
|
|
{
|
1184 |
|
|
signed_cell attach_address_sc;
|
1185 |
|
|
signed_cell attach_size_sc;
|
1186 |
|
|
|
1187 |
|
|
/* Only specific names are reg_array_properties, the rest are
|
1188 |
|
|
array_properties. */
|
1189 |
|
|
if (hw_property_type (mem_prop) == array_property
|
1190 |
|
|
&& hw_property_sizeof_array (mem_prop) == 2 * sizeof (attach_address_sc)
|
1191 |
|
|
&& hw_find_integer_array_property (me, "mem", 0, &attach_address_sc)
|
1192 |
|
|
&& hw_find_integer_array_property (me, "mem", 1, &attach_size_sc))
|
1193 |
|
|
{
|
1194 |
|
|
/* Unfortunate choice of types forces us to dance around a bit. */
|
1195 |
|
|
rv->mem_address = (unsigned32) attach_address_sc;
|
1196 |
|
|
rv->mem_size = (unsigned32) attach_size_sc;
|
1197 |
|
|
if ((attach_address_sc & 3) != 0)
|
1198 |
|
|
hw_abort (me, "memory block must be 4 byte aligned");
|
1199 |
|
|
}
|
1200 |
|
|
else
|
1201 |
|
|
hw_abort (me, "property \"mem\" has the wrong type");
|
1202 |
|
|
}
|
1203 |
|
|
|
1204 |
|
|
hw_rv_map_ints (me);
|
1205 |
|
|
|
1206 |
|
|
hw_rv_init_socket (me);
|
1207 |
|
|
|
1208 |
|
|
/* We need an extra initialization pass, after all others currently
|
1209 |
|
|
scheduled (mostly, after the simulation events machinery has been
|
1210 |
|
|
initialized so the events we want don't get thrown out). */
|
1211 |
|
|
hw_rv_add_init (me);
|
1212 |
|
|
}
|
1213 |
|
|
|
1214 |
|
|
/* Our root structure; see dv-* build machinery for usage. */
|
1215 |
|
|
|
1216 |
|
|
const struct hw_descriptor dv_rv_descriptor[] = {
|
1217 |
|
|
{ RV_FAMILY_NAME, hw_rv_finish },
|
1218 |
|
|
{ NULL }
|
1219 |
|
|
};
|