| 1 | /* The remote-virtual-component simulator framework |
| 2 | for GDB, the GNU Debugger. |
| 3 | |
| 4 | Copyright 2006-2020 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 | }; |