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