Commit d4666c97 authored by Antoine Kaufmann's avatar Antoine Kaufmann
Browse files

Reformat closer to google style

parent eb125a88
...@@ -22,183 +22,174 @@ ...@@ -22,183 +22,174 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <simbricks/netif/netsim.h> #include <simbricks/netif/netsim.h>
#include "lib/simbricks/netif/internal.h" #include "lib/simbricks/netif/internal.h"
static uint64_t current_epoch = 0; static uint64_t current_epoch = 0;
int netsim_init(struct netsim_interface *nsif, int netsim_init(struct netsim_interface *nsif, const char *eth_socket_path,
const char *eth_socket_path, int *sync_eth) int *sync_eth) {
{ struct cosim_eth_proto_dev_intro di;
struct cosim_eth_proto_dev_intro di; struct cosim_eth_proto_net_intro ni;
struct cosim_eth_proto_net_intro ni; int cfd, shm_fd;
int cfd, shm_fd; void *p;
void *p;
if ((cfd = uxsocket_connect(eth_socket_path)) < 0) {
if ((cfd = uxsocket_connect(eth_socket_path)) < 0) { return -1;
return -1; }
}
memset(&ni, 0, sizeof(ni));
memset(&ni, 0, sizeof(ni));
if (*sync_eth)
if (*sync_eth) ni.flags |= COSIM_ETH_PROTO_FLAGS_NI_SYNC;
ni.flags |= COSIM_ETH_PROTO_FLAGS_NI_SYNC;
if (send(cfd, &ni, sizeof(ni), 0) != sizeof(ni)) {
if (send(cfd, &ni, sizeof(ni), 0) != sizeof(ni)) { perror("sending net intro failed");
perror("sending net intro failed"); return -1;
return -1; }
}
if (uxsocket_recv(cfd, &di, sizeof(di), &shm_fd)) {
if (uxsocket_recv(cfd, &di, sizeof(di), &shm_fd)) { return -1;
return -1; }
}
if ((p = shm_map(shm_fd)) == NULL) {
if ((p = shm_map(shm_fd)) == NULL) { return -1;
return -1; }
} close(shm_fd);
close(shm_fd);
if ((di.flags & COSIM_ETH_PROTO_FLAGS_DI_SYNC) == 0) {
if ((di.flags & COSIM_ETH_PROTO_FLAGS_DI_SYNC) == 0) { *sync_eth = 0;
*sync_eth = 0; nsif->sync = 0;
nsif->sync = 0; } else {
} else { nsif->sync = *sync_eth;
nsif->sync = *sync_eth; }
}
nsif->d2n_queue = (uint8_t *)p + di.d2n_offset;
nsif->d2n_queue = (uint8_t *) p + di.d2n_offset; nsif->n2d_queue = (uint8_t *)p + di.n2d_offset;
nsif->n2d_queue = (uint8_t *) p + di.n2d_offset; nsif->d2n_elen = di.d2n_elen;
nsif->d2n_elen = di.d2n_elen; nsif->n2d_elen = di.n2d_elen;
nsif->n2d_elen = di.n2d_elen; nsif->d2n_enum = di.d2n_nentries;
nsif->d2n_enum = di.d2n_nentries; nsif->n2d_enum = di.n2d_nentries;
nsif->n2d_enum = di.n2d_nentries; nsif->d2n_pos = nsif->n2d_pos = 0;
nsif->d2n_pos = nsif->n2d_pos = 0; nsif->d2n_timestamp = nsif->n2d_timestamp = 0;
nsif->d2n_timestamp = nsif->n2d_timestamp = 0;
return 0;
return 0;
} }
void netsim_cleanup(struct netsim_interface *nsif) void netsim_cleanup(struct netsim_interface *nsif) {
{ fprintf(stderr, "netsim_cleanup: TODO\n");
fprintf(stderr, "netsim_cleanup: TODO\n"); abort();
abort();
} }
volatile union cosim_eth_proto_d2n *netsim_d2n_poll( volatile union cosim_eth_proto_d2n *netsim_d2n_poll(
struct netsim_interface *nsif, uint64_t timestamp) struct netsim_interface *nsif, uint64_t timestamp) {
{ volatile union cosim_eth_proto_d2n *msg =
volatile union cosim_eth_proto_d2n *msg = (volatile union cosim_eth_proto_d2n *)(nsif->d2n_queue +
(volatile union cosim_eth_proto_d2n *) nsif->d2n_pos * nsif->d2n_elen);
(nsif->d2n_queue + nsif->d2n_pos * nsif->d2n_elen);
/* message not ready */
/* message not ready */ if ((msg->dummy.own_type & COSIM_ETH_PROTO_D2N_OWN_MASK) !=
if ((msg->dummy.own_type & COSIM_ETH_PROTO_D2N_OWN_MASK) != COSIM_ETH_PROTO_D2N_OWN_NET)
COSIM_ETH_PROTO_D2N_OWN_NET) return NULL;
return NULL;
/* if in sync mode, wait till message is ready */
/* if in sync mode, wait till message is ready */ nsif->d2n_timestamp = msg->dummy.timestamp;
nsif->d2n_timestamp = msg->dummy.timestamp; if (nsif->sync && nsif->d2n_timestamp > timestamp)
if (nsif->sync && nsif->d2n_timestamp > timestamp) return NULL;
return NULL;
nsif->d2n_pos = (nsif->d2n_pos + 1) % nsif->d2n_enum;
nsif->d2n_pos = (nsif->d2n_pos + 1) % nsif->d2n_enum; return msg;
return msg;
} }
void netsim_d2n_done(struct netsim_interface *nsif, void netsim_d2n_done(struct netsim_interface *nsif,
volatile union cosim_eth_proto_d2n *msg) volatile union cosim_eth_proto_d2n *msg) {
{ msg->dummy.own_type = (msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK) |
msg->dummy.own_type = (msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK) COSIM_ETH_PROTO_D2N_OWN_DEV;
| COSIM_ETH_PROTO_D2N_OWN_DEV;
} }
volatile union cosim_eth_proto_n2d *netsim_n2d_alloc( volatile union cosim_eth_proto_n2d *netsim_n2d_alloc(
struct netsim_interface *nsif, uint64_t timestamp, struct netsim_interface *nsif, uint64_t timestamp, uint64_t latency) {
uint64_t latency) volatile union cosim_eth_proto_n2d *msg =
{ (volatile union cosim_eth_proto_n2d *)(nsif->n2d_queue +
volatile union cosim_eth_proto_n2d *msg = nsif->n2d_pos * nsif->n2d_elen);
(volatile union cosim_eth_proto_n2d *)
(nsif->n2d_queue + nsif->n2d_pos * nsif->n2d_elen); if ((msg->dummy.own_type & COSIM_ETH_PROTO_N2D_OWN_MASK) !=
COSIM_ETH_PROTO_N2D_OWN_NET) {
if ((msg->dummy.own_type & COSIM_ETH_PROTO_N2D_OWN_MASK) != return NULL;
COSIM_ETH_PROTO_N2D_OWN_NET) }
{
return NULL;
}
msg->dummy.timestamp = timestamp + latency; msg->dummy.timestamp = timestamp + latency;
nsif->n2d_timestamp = timestamp; nsif->n2d_timestamp = timestamp;
nsif->n2d_pos = (nsif->n2d_pos + 1) % nsif->n2d_enum; nsif->n2d_pos = (nsif->n2d_pos + 1) % nsif->n2d_enum;
return msg; return msg;
} }
int netsim_n2d_sync(struct netsim_interface *nsif, uint64_t timestamp, int netsim_n2d_sync(struct netsim_interface *nsif, uint64_t timestamp,
uint64_t latency, uint64_t sync_delay, int sync_mode) uint64_t latency, uint64_t sync_delay, int sync_mode) {
{ volatile union cosim_eth_proto_n2d *msg;
volatile union cosim_eth_proto_n2d *msg; volatile struct cosim_eth_proto_n2d_sync *sync;
volatile struct cosim_eth_proto_n2d_sync *sync; int do_sync;
int do_sync;
if (!nsif->sync) if (!nsif->sync)
return 0; return 0;
switch (sync_mode) { switch (sync_mode) {
case SYNC_MODES: case SYNC_MODES:
do_sync = nsif->n2d_timestamp == 0 || do_sync = nsif->n2d_timestamp == 0 ||
timestamp - nsif->n2d_timestamp >= sync_delay; timestamp - nsif->n2d_timestamp >= sync_delay;
break; break;
case SYNC_BARRIER: case SYNC_BARRIER:
do_sync = current_epoch == 0 || do_sync = current_epoch == 0 || timestamp - current_epoch >= sync_delay;
timestamp - current_epoch >= sync_delay; break;
break;
default: default:
fprintf(stderr, "unsupported sync mode=%u\n", sync_mode); fprintf(stderr, "unsupported sync mode=%u\n", sync_mode);
return 0; return 0;
} }
if (!do_sync) { if (!do_sync) {
return 0; return 0;
} }
msg = netsim_n2d_alloc(nsif, timestamp, latency); msg = netsim_n2d_alloc(nsif, timestamp, latency);
if (msg == NULL) if (msg == NULL)
return -1; return -1;
sync = &msg->sync; sync = &msg->sync;
// WMB(); // WMB();
sync->own_type = COSIM_ETH_PROTO_N2D_MSG_SYNC | COSIM_ETH_PROTO_N2D_OWN_DEV; sync->own_type = COSIM_ETH_PROTO_N2D_MSG_SYNC | COSIM_ETH_PROTO_N2D_OWN_DEV;
return 0; return 0;
} }
void netsim_advance_epoch(uint64_t timestamp, uint64_t sync_delay, void netsim_advance_epoch(uint64_t timestamp, uint64_t sync_delay,
int sync_mode) int sync_mode) {
{ if (sync_mode == SYNC_BARRIER) {
if (sync_mode == SYNC_BARRIER) { if (timestamp - current_epoch >= sync_delay) {
if (timestamp - current_epoch >= sync_delay) { current_epoch = timestamp;
current_epoch = timestamp;
}
} }
}
} }
uint64_t netsim_advance_time(uint64_t timestamp, uint64_t sync_delay, uint64_t netsim_advance_time(uint64_t timestamp, uint64_t sync_delay,
int sync_mode) int sync_mode) {
{ switch (sync_mode) {
switch (sync_mode) {
case SYNC_MODES: case SYNC_MODES:
return timestamp; return timestamp;
case SYNC_BARRIER: case SYNC_BARRIER:
return timestamp < current_epoch + sync_delay ? return timestamp < current_epoch + sync_delay
timestamp : current_epoch + sync_delay; ? timestamp
: current_epoch + sync_delay;
default: default:
fprintf(stderr, "unsupported sync mode=%u\n", sync_mode); fprintf(stderr, "unsupported sync mode=%u\n", sync_mode);
return timestamp; return timestamp;
} }
} }
...@@ -27,48 +27,47 @@ ...@@ -27,48 +27,47 @@
#include <stddef.h> #include <stddef.h>
#include <stdint.h> #include <stdint.h>
#include <simbricks/proto/network.h> #include <simbricks/proto/network.h>
#define SYNC_MODES 0 #define SYNC_MODES 0
#define SYNC_BARRIER 1 #define SYNC_BARRIER 1
struct netsim_interface { struct netsim_interface {
uint8_t *d2n_queue; uint8_t *d2n_queue;
size_t d2n_pos; size_t d2n_pos;
size_t d2n_elen; size_t d2n_elen;
size_t d2n_enum; size_t d2n_enum;
uint64_t d2n_timestamp; uint64_t d2n_timestamp;
uint8_t *n2d_queue; uint8_t *n2d_queue;
size_t n2d_pos; size_t n2d_pos;
size_t n2d_elen; size_t n2d_elen;
size_t n2d_enum; size_t n2d_enum;
uint64_t n2d_timestamp; uint64_t n2d_timestamp;
int sync; int sync;
}; };
int netsim_init(struct netsim_interface *nsif, int netsim_init(struct netsim_interface *nsif, const char *eth_socket_path,
const char *eth_socket_path, int *sync_eth); int *sync_eth);
void netsim_cleanup(struct netsim_interface *nsif); void netsim_cleanup(struct netsim_interface *nsif);
volatile union cosim_eth_proto_d2n *netsim_d2n_poll( volatile union cosim_eth_proto_d2n *netsim_d2n_poll(
struct netsim_interface *nsif, uint64_t timestamp); struct netsim_interface *nsif, uint64_t timestamp);
void netsim_d2n_done(struct netsim_interface *nsif, void netsim_d2n_done(struct netsim_interface *nsif,
volatile union cosim_eth_proto_d2n *msg); volatile union cosim_eth_proto_d2n *msg);
static inline uint64_t netsim_d2n_timestamp(struct netsim_interface *nsif) static inline uint64_t netsim_d2n_timestamp(struct netsim_interface *nsif) {
{ return nsif->d2n_timestamp;
return nsif->d2n_timestamp;
} }
volatile union cosim_eth_proto_n2d *netsim_n2d_alloc( volatile union cosim_eth_proto_n2d *netsim_n2d_alloc(
struct netsim_interface *nsif, uint64_t timestamp, struct netsim_interface *nsif, uint64_t timestamp, uint64_t latency);
uint64_t latency);
int netsim_n2d_sync(struct netsim_interface *nsif, uint64_t timestamp, int netsim_n2d_sync(struct netsim_interface *nsif, uint64_t timestamp,
uint64_t latency, uint64_t sync_delay, int sync_mode); uint64_t latency, uint64_t sync_delay, int sync_mode);
void netsim_advance_epoch(uint64_t timestamp, uint64_t sync_delay, void netsim_advance_epoch(uint64_t timestamp, uint64_t sync_delay,
int sync_mode); int sync_mode);
uint64_t netsim_advance_time(uint64_t timestamp, uint64_t sync_delay, uint64_t netsim_advance_time(uint64_t timestamp, uint64_t sync_delay,
int sync_mode); int sync_mode);
#endif // SIMBRICKS_NETIF_NETSIM_H_ #endif // SIMBRICKS_NETIF_NETSIM_H_
...@@ -24,96 +24,93 @@ ...@@ -24,96 +24,93 @@
#include <fcntl.h> #include <fcntl.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/un.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include "lib/simbricks/netif/internal.h" #include "lib/simbricks/netif/internal.h"
int uxsocket_connect(const char *path) int uxsocket_connect(const char *path) {
{ int fd;
int fd; struct sockaddr_un saun;
struct sockaddr_un saun;
/* prepare and connect socket */ /* prepare and connect socket */
memset(&saun, 0, sizeof(saun)); memset(&saun, 0, sizeof(saun));
saun.sun_family = AF_UNIX; saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, path); strcpy(saun.sun_path, path);
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket failed"); perror("socket failed");
return -1; return -1;
} }
if (connect(fd, (struct sockaddr *) &saun, sizeof(saun)) != 0) { if (connect(fd, (struct sockaddr *)&saun, sizeof(saun)) != 0) {
perror("connect failed"); perror("connect failed");
return -1; return -1;
} }
return fd; return fd;
} }
int uxsocket_recv(int fd, void *data, size_t len, int *pfd) int uxsocket_recv(int fd, void *data, size_t len, int *pfd) {
{ int *ppfd;
int *ppfd; ssize_t ret;
ssize_t ret; struct cmsghdr *cmsg;
struct cmsghdr *cmsg; union {
union { char buf[CMSG_SPACE(sizeof(int))];
char buf[CMSG_SPACE(sizeof(int))]; struct cmsghdr align;
struct cmsghdr align; } u;
} u; struct iovec iov = {
struct iovec iov = { .iov_base = data,
.iov_base = data, .iov_len = len,
.iov_len = len, };
}; struct msghdr msg = {
struct msghdr msg = { .msg_name = NULL,
.msg_name = NULL, .msg_namelen = 0,
.msg_namelen = 0, .msg_iov = &iov,
.msg_iov = &iov, .msg_iovlen = 1,
.msg_iovlen = 1, .msg_control = u.buf,
.msg_control = u.buf, .msg_controllen = sizeof(u.buf),
.msg_controllen = sizeof(u.buf), .msg_flags = 0,
.msg_flags = 0, };
};
if ((ret = recvmsg(fd, &msg, 0)) != (ssize_t) len) { if ((ret = recvmsg(fd, &msg, 0)) != (ssize_t)len) {
perror("recvmsg failed"); perror("recvmsg failed");
return -1; return -1;
} }
cmsg = CMSG_FIRSTHDR(&msg); cmsg = CMSG_FIRSTHDR(&msg);
ppfd = (int *) CMSG_DATA(cmsg); ppfd = (int *)CMSG_DATA(cmsg);
if (msg.msg_controllen <= 0 || cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { if (msg.msg_controllen <= 0 || cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
fprintf(stderr, "accessing ancillary data failed\n"); fprintf(stderr, "accessing ancillary data failed\n");
return -1; return -1;
} }
*pfd = *ppfd; *pfd = *ppfd;
return 0; return 0;
} }
void *shm_map(int shm_fd) void *shm_map(int shm_fd) {
{ void *p;
void *p; struct stat statbuf;
struct stat statbuf;
if (fstat(shm_fd, &statbuf) != 0) { if (fstat(shm_fd, &statbuf) != 0) {
perror("shm_map: fstat failed"); perror("shm_map: fstat failed");
return NULL; return NULL;
} }
p = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, p = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd,
0); 0);
if (p == MAP_FAILED) { if (p == MAP_FAILED) {
perror("shm_map: mmap failed"); perror("shm_map: mmap failed");
return NULL; return NULL;
} }
return p; return p;
} }
...@@ -22,483 +22,458 @@ ...@@ -22,483 +22,458 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <stdlib.h> #include <simbricks/nicbm/nicbm.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h>
#include <cassert> #include <cassert>
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#include <simbricks/nicbm/nicbm.h>
// #define DEBUG_NICBM 1 // #define DEBUG_NICBM 1
#define DMA_MAX_PENDING 64 #define DMA_MAX_PENDING 64
namespace nicbm {
using namespace nicbm;
static volatile int exiting = 0; static volatile int exiting = 0;
static uint64_t main_time = 0; static uint64_t main_time = 0;
static void sigint_handler(int dummy) {
static void sigint_handler(int dummy) exiting = 1;
{
exiting = 1;
} }
static void sigusr1_handler(int dummy) static void sigusr1_handler(int dummy) {
{ fprintf(stderr, "main_time = %lu\n", main_time);
fprintf(stderr, "main_time = %lu\n", main_time);
} }
volatile union cosim_pcie_proto_d2h *Runner::d2h_alloc(void) volatile union cosim_pcie_proto_d2h *Runner::d2h_alloc(void) {
{ volatile union cosim_pcie_proto_d2h *msg;
volatile union cosim_pcie_proto_d2h *msg; while ((msg = nicsim_d2h_alloc(&nsparams, main_time)) == NULL) {
while ((msg = nicsim_d2h_alloc(&nsparams, main_time)) == NULL) { fprintf(stderr, "d2h_alloc: no entry available\n");
fprintf(stderr, "d2h_alloc: no entry available\n"); }
} return msg;
return msg;
} }
volatile union cosim_eth_proto_d2n *Runner::d2n_alloc(void) volatile union cosim_eth_proto_d2n *Runner::d2n_alloc(void) {
{ volatile union cosim_eth_proto_d2n *msg;
volatile union cosim_eth_proto_d2n *msg; while ((msg = nicsim_d2n_alloc(&nsparams, main_time)) == NULL) {
while ((msg = nicsim_d2n_alloc(&nsparams, main_time)) == NULL) { fprintf(stderr, "d2n_alloc: no entry available\n");
fprintf(stderr, "d2n_alloc: no entry available\n"); }
} return msg;
return msg;
} }
void Runner::issue_dma(DMAOp &op) void Runner::issue_dma(DMAOp &op) {
{ if (dma_pending < DMA_MAX_PENDING) {
if (dma_pending < DMA_MAX_PENDING) { // can directly issue
// can directly issue
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: issuing dma op %p addr %lx len %zu pending %zu\n", &op, printf("nicbm: issuing dma op %p addr %lx len %zu pending %zu\n", &op,
op.dma_addr, op.len, dma_pending); op.dma_addr, op.len, dma_pending);
#endif #endif
dma_do(op); dma_do(op);
} else { } else {
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: enqueuing dma op %p addr %lx len %zu pending %zu\n", &op, printf("nicbm: enqueuing dma op %p addr %lx len %zu pending %zu\n", &op,
op.dma_addr, op.len, dma_pending); op.dma_addr, op.len, dma_pending);
#endif #endif
dma_queue.push_back(&op); dma_queue.push_back(&op);
} }
} }
void Runner::dma_trigger() void Runner::dma_trigger() {
{ if (dma_queue.empty() || dma_pending == DMA_MAX_PENDING)
if (dma_queue.empty() || dma_pending == DMA_MAX_PENDING) return;
return;
DMAOp *op = dma_queue.front(); DMAOp *op = dma_queue.front();
dma_queue.pop_front(); dma_queue.pop_front();
dma_do(*op); dma_do(*op);
} }
void Runner::dma_do(DMAOp &op) void Runner::dma_do(DMAOp &op) {
{ volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc(); dma_pending++;
dma_pending++;
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: executing dma op %p addr %lx len %zu pending %zu\n", &op, printf("nicbm: executing dma op %p addr %lx len %zu pending %zu\n", &op,
op.dma_addr, op.len, dma_pending); op.dma_addr, op.len, dma_pending);
#endif #endif
if (op.write) { if (op.write) {
volatile struct cosim_pcie_proto_d2h_write *write = &msg->write; volatile struct cosim_pcie_proto_d2h_write *write = &msg->write;
if (dintro.d2h_elen < sizeof(*write) + op.len) { if (dintro.d2h_elen < sizeof(*write) + op.len) {
fprintf(stderr, "issue_dma: write too big (%zu), can only fit up " fprintf(stderr,
"to (%zu)\n", op.len, dintro.d2h_elen - sizeof(*write)); "issue_dma: write too big (%zu), can only fit up "
abort(); "to (%zu)\n",
} op.len, dintro.d2h_elen - sizeof(*write));
abort();
write->req_id = (uintptr_t) &op; }
write->offset = op.dma_addr;
write->len = op.len; write->req_id = (uintptr_t)&op;
memcpy((void *)write->data, (void *)op.data, op.len); write->offset = op.dma_addr;
// WMB(); write->len = op.len;
write->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITE | memcpy((void *)write->data, (void *)op.data, op.len);
COSIM_PCIE_PROTO_D2H_OWN_HOST; // WMB();
} else { write->own_type =
volatile struct cosim_pcie_proto_d2h_read *read = &msg->read; COSIM_PCIE_PROTO_D2H_MSG_WRITE | COSIM_PCIE_PROTO_D2H_OWN_HOST;
if (dintro.h2d_elen < sizeof(struct cosim_pcie_proto_h2d_readcomp) + } else {
op.len) { volatile struct cosim_pcie_proto_d2h_read *read = &msg->read;
fprintf(stderr, "issue_dma: write too big (%zu), can only fit up " if (dintro.h2d_elen <
"to (%zu)\n", op.len, dintro.h2d_elen - sizeof(struct cosim_pcie_proto_h2d_readcomp) + op.len) {
sizeof(struct cosim_pcie_proto_h2d_readcomp)); fprintf(stderr,
abort(); "issue_dma: write too big (%zu), can only fit up "
} "to (%zu)\n",
op.len,
read->req_id = (uintptr_t) &op; dintro.h2d_elen - sizeof(struct cosim_pcie_proto_h2d_readcomp));
read->offset = op.dma_addr; abort();
read->len = op.len;
// WMB();
read->own_type = COSIM_PCIE_PROTO_D2H_MSG_READ |
COSIM_PCIE_PROTO_D2H_OWN_HOST;
} }
read->req_id = (uintptr_t)&op;
read->offset = op.dma_addr;
read->len = op.len;
// WMB();
read->own_type =
COSIM_PCIE_PROTO_D2H_MSG_READ | COSIM_PCIE_PROTO_D2H_OWN_HOST;
}
} }
void Runner::msi_issue(uint8_t vec) void Runner::msi_issue(uint8_t vec) {
{ volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: issue MSI interrupt vec %u\n", vec); printf("nicbm: issue MSI interrupt vec %u\n", vec);
#endif #endif
volatile struct cosim_pcie_proto_d2h_interrupt *intr = &msg->interrupt; volatile struct cosim_pcie_proto_d2h_interrupt *intr = &msg->interrupt;
intr->vector = vec; intr->vector = vec;
intr->inttype = COSIM_PCIE_PROTO_INT_MSI; intr->inttype = COSIM_PCIE_PROTO_INT_MSI;
// WMB(); // WMB();
intr->own_type = COSIM_PCIE_PROTO_D2H_MSG_INTERRUPT | intr->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_INTERRUPT | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} }
void Runner::msix_issue(uint8_t vec) void Runner::msix_issue(uint8_t vec) {
{ volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: issue MSI-X interrupt vec %u\n", vec); printf("nicbm: issue MSI-X interrupt vec %u\n", vec);
#endif #endif
volatile struct cosim_pcie_proto_d2h_interrupt *intr = &msg->interrupt; volatile struct cosim_pcie_proto_d2h_interrupt *intr = &msg->interrupt;
intr->vector = vec; intr->vector = vec;
intr->inttype = COSIM_PCIE_PROTO_INT_MSIX; intr->inttype = COSIM_PCIE_PROTO_INT_MSIX;
// WMB(); // WMB();
intr->own_type = COSIM_PCIE_PROTO_D2H_MSG_INTERRUPT | intr->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_INTERRUPT | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} }
void Runner::event_schedule(TimedEvent &evt) void Runner::event_schedule(TimedEvent &evt) {
{ events.insert(&evt);
events.insert(&evt);
} }
void Runner::event_cancel(TimedEvent &evt) void Runner::event_cancel(TimedEvent &evt) {
{ events.erase(&evt);
events.erase(&evt);
} }
void Runner::h2d_read(volatile struct cosim_pcie_proto_h2d_read *read) void Runner::h2d_read(volatile struct cosim_pcie_proto_h2d_read *read) {
{ volatile union cosim_pcie_proto_d2h *msg;
volatile union cosim_pcie_proto_d2h *msg; volatile struct cosim_pcie_proto_d2h_readcomp *rc;
volatile struct cosim_pcie_proto_d2h_readcomp *rc;
msg = d2h_alloc(); msg = d2h_alloc();
rc = &msg->readcomp; rc = &msg->readcomp;
dev.reg_read(read->bar, read->offset, (void *) rc->data, read->len); dev.reg_read(read->bar, read->offset, (void *)rc->data, read->len);
rc->req_id = read->req_id; rc->req_id = read->req_id;
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
uint64_t dbg_val = 0; uint64_t dbg_val = 0;
memcpy(&dbg_val, (const void *) rc->data, read->len <= 8 ? read->len : 8); memcpy(&dbg_val, (const void *)rc->data, read->len <= 8 ? read->len : 8);
printf("nicbm: read(off=0x%lx, len=%u, val=0x%lx)\n", read->offset, printf("nicbm: read(off=0x%lx, len=%u, val=0x%lx)\n", read->offset, read->len,
read->len, dbg_val); dbg_val);
#endif #endif
// WMB(); // WMB();
rc->own_type = COSIM_PCIE_PROTO_D2H_MSG_READCOMP | rc->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_READCOMP | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} }
void Runner::h2d_write(volatile struct cosim_pcie_proto_h2d_write *write) void Runner::h2d_write(volatile struct cosim_pcie_proto_h2d_write *write) {
{ volatile union cosim_pcie_proto_d2h *msg;
volatile union cosim_pcie_proto_d2h *msg; volatile struct cosim_pcie_proto_d2h_writecomp *wc;
volatile struct cosim_pcie_proto_d2h_writecomp *wc;
msg = d2h_alloc(); msg = d2h_alloc();
wc = &msg->writecomp; wc = &msg->writecomp;
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
uint64_t dbg_val = 0; uint64_t dbg_val = 0;
memcpy(&dbg_val, (const void *) write->data, write->len <= 8 ? write->len : memcpy(&dbg_val, (const void *)write->data, write->len <= 8 ? write->len : 8);
8); printf("nicbm: write(off=0x%lx, len=%u, val=0x%lx)\n", write->offset,
printf("nicbm: write(off=0x%lx, len=%u, val=0x%lx)\n", write->offset, write->len, dbg_val);
write->len, dbg_val);
#endif #endif
dev.reg_write(write->bar, write->offset, (void *) write->data, write->len); dev.reg_write(write->bar, write->offset, (void *)write->data, write->len);
wc->req_id = write->req_id; wc->req_id = write->req_id;
// WMB(); // WMB();
wc->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP | wc->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} }
void Runner::h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc) void Runner::h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc) {
{ DMAOp *op = (DMAOp *)(uintptr_t)rc->req_id;
DMAOp *op = (DMAOp *)(uintptr_t)rc->req_id;
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: completed dma read op %p addr %lx len %zu\n", op, printf("nicbm: completed dma read op %p addr %lx len %zu\n", op, op->dma_addr,
op->dma_addr, op->len); op->len);
#endif #endif
memcpy(op->data, (void *)rc->data, op->len); memcpy(op->data, (void *)rc->data, op->len);
dev.dma_complete(*op); dev.dma_complete(*op);
dma_pending--; dma_pending--;
dma_trigger(); dma_trigger();
} }
void Runner::h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc) void Runner::h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc) {
{ DMAOp *op = (DMAOp *)(uintptr_t)wc->req_id;
DMAOp *op = (DMAOp *)(uintptr_t)wc->req_id;
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: completed dma write op %p addr %lx len %zu\n", op, printf("nicbm: completed dma write op %p addr %lx len %zu\n", op,
op->dma_addr, op->len); op->dma_addr, op->len);
#endif #endif
dev.dma_complete(*op); dev.dma_complete(*op);
dma_pending--; dma_pending--;
dma_trigger(); dma_trigger();
} }
void Runner::h2d_devctrl(volatile struct cosim_pcie_proto_h2d_devctrl *dc) void Runner::h2d_devctrl(volatile struct cosim_pcie_proto_h2d_devctrl *dc) {
{ dev.devctrl_update(*(struct cosim_pcie_proto_h2d_devctrl *)dc);
dev.devctrl_update(*(struct cosim_pcie_proto_h2d_devctrl *) dc);
} }
void Runner::eth_recv(volatile struct cosim_eth_proto_n2d_recv *recv) void Runner::eth_recv(volatile struct cosim_eth_proto_n2d_recv *recv) {
{
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: eth rx: port %u len %u\n", recv->port, recv->len); printf("nicbm: eth rx: port %u len %u\n", recv->port, recv->len);
#endif #endif
dev.eth_rx(recv->port, (void *) recv->data, recv->len); dev.eth_rx(recv->port, (void *)recv->data, recv->len);
} }
void Runner::eth_send(const void *data, size_t len) void Runner::eth_send(const void *data, size_t len) {
{
#ifdef DEBUG_NICBM #ifdef DEBUG_NICBM
printf("nicbm: eth tx: len %zu\n", len); printf("nicbm: eth tx: len %zu\n", len);
#endif #endif
volatile union cosim_eth_proto_d2n *msg = d2n_alloc(); volatile union cosim_eth_proto_d2n *msg = d2n_alloc();
volatile struct cosim_eth_proto_d2n_send *send = &msg->send; volatile struct cosim_eth_proto_d2n_send *send = &msg->send;
send->port = 0; // single port send->port = 0; // single port
send->len = len; send->len = len;
memcpy((void *)send->data, data, len); memcpy((void *)send->data, data, len);
send->own_type = COSIM_ETH_PROTO_D2N_MSG_SEND | send->own_type = COSIM_ETH_PROTO_D2N_MSG_SEND | COSIM_ETH_PROTO_D2N_OWN_NET;
COSIM_ETH_PROTO_D2N_OWN_NET;
} }
void Runner::poll_h2d() void Runner::poll_h2d() {
{ volatile union cosim_pcie_proto_h2d *msg =
volatile union cosim_pcie_proto_h2d *msg = nicif_h2d_poll(&nsparams, main_time);
nicif_h2d_poll(&nsparams, main_time); uint8_t type;
uint8_t type;
if (msg == NULL) if (msg == NULL)
return; return;
type = msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK; type = msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK;
switch (type) { switch (type) {
case COSIM_PCIE_PROTO_H2D_MSG_READ: case COSIM_PCIE_PROTO_H2D_MSG_READ:
h2d_read(&msg->read); h2d_read(&msg->read);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_WRITE: case COSIM_PCIE_PROTO_H2D_MSG_WRITE:
h2d_write(&msg->write); h2d_write(&msg->write);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_READCOMP: case COSIM_PCIE_PROTO_H2D_MSG_READCOMP:
h2d_readcomp(&msg->readcomp); h2d_readcomp(&msg->readcomp);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_WRITECOMP: case COSIM_PCIE_PROTO_H2D_MSG_WRITECOMP:
h2d_writecomp(&msg->writecomp); h2d_writecomp(&msg->writecomp);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_DEVCTRL: case COSIM_PCIE_PROTO_H2D_MSG_DEVCTRL:
h2d_devctrl(&msg->devctrl); h2d_devctrl(&msg->devctrl);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_SYNC: case COSIM_PCIE_PROTO_H2D_MSG_SYNC:
break; break;
default: default:
fprintf(stderr, "poll_h2d: unsupported type=%u\n", type); fprintf(stderr, "poll_h2d: unsupported type=%u\n", type);
} }
nicif_h2d_done(msg); nicif_h2d_done(msg);
nicif_h2d_next(); nicif_h2d_next();
} }
void Runner::poll_n2d() void Runner::poll_n2d() {
{ volatile union cosim_eth_proto_n2d *msg =
volatile union cosim_eth_proto_n2d *msg = nicif_n2d_poll(&nsparams, main_time);
nicif_n2d_poll(&nsparams, main_time); uint8_t t;
uint8_t t;
if (msg == NULL) if (msg == NULL)
return; return;
t = msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK; t = msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK;
switch (t) { switch (t) {
case COSIM_ETH_PROTO_N2D_MSG_RECV: case COSIM_ETH_PROTO_N2D_MSG_RECV:
eth_recv(&msg->recv); eth_recv(&msg->recv);
break; break;
case COSIM_ETH_PROTO_N2D_MSG_SYNC: case COSIM_ETH_PROTO_N2D_MSG_SYNC:
break; break;
default: default:
fprintf(stderr, "poll_n2d: unsupported type=%u", t); fprintf(stderr, "poll_n2d: unsupported type=%u", t);
} }
nicif_n2d_done(msg); nicif_n2d_done(msg);
nicif_n2d_next(); nicif_n2d_next();
} }
uint64_t Runner::time_ps() const uint64_t Runner::time_ps() const {
{ return main_time;
return main_time;
} }
uint64_t Runner::get_mac_addr() const uint64_t Runner::get_mac_addr() const {
{ return mac_addr;
return mac_addr;
} }
bool Runner::event_next(uint64_t &retval) bool Runner::event_next(uint64_t &retval) {
{ if (events.empty())
if (events.empty()) return false;
return false;
retval = (*events.begin())->time; retval = (*events.begin())->time;
return true; return true;
} }
void Runner::event_trigger() void Runner::event_trigger() {
{ auto it = events.begin();
auto it = events.begin(); if (it == events.end())
if (it == events.end()) return;
return;
TimedEvent *ev = *it; TimedEvent *ev = *it;
// event is in the future // event is in the future
if (ev->time > main_time) if (ev->time > main_time)
return; return;
events.erase(it); events.erase(it);
dev.timed_event(*ev); dev.timed_event(*ev);
} }
Runner::Runner(Device &dev_) Runner::Runner(Device &dev_) : dev(dev_), events(event_cmp()) {
: dev(dev_), events(event_cmp()) // mac_addr = lrand48() & ~(3ULL << 46);
{ dma_pending = 0;
// mac_addr = lrand48() & ~(3ULL << 46); srand48(time(NULL) ^ getpid());
dma_pending = 0; mac_addr = lrand48();
srand48(time(NULL) ^ getpid()); mac_addr <<= 16;
mac_addr = lrand48(); mac_addr ^= lrand48();
mac_addr <<= 16; mac_addr &= ~3ULL;
mac_addr ^= lrand48();
mac_addr &= ~3ULL; std::cerr << std::hex << mac_addr << std::endl;
std::cerr << std::hex << mac_addr << std::endl;
} }
int Runner::runMain(int argc, char *argv[]) int Runner::runMain(int argc, char *argv[]) {
{ uint64_t next_ts;
uint64_t next_ts; uint64_t max_step = 10000;
uint64_t max_step = 10000; uint64_t sync_period = 100 * 1000ULL;
uint64_t sync_period = 100 * 1000ULL; uint64_t pci_latency = 500 * 1000ULL;
uint64_t pci_latency = 500 * 1000ULL; uint64_t eth_latency = 500 * 1000ULL;
uint64_t eth_latency = 500 * 1000ULL; int sync_mode = SYNC_MODES;
int sync_mode = SYNC_MODES;
if (argc < 4 && argc > 9) {
if (argc < 4 && argc > 9) { fprintf(stderr,
fprintf(stderr, "Usage: corundum_bm PCI-SOCKET ETH-SOCKET " "Usage: corundum_bm PCI-SOCKET ETH-SOCKET "
"SHM [SYNC-MODE] [START-TICK] [SYNC-PERIOD] [PCI-LATENCY] " "SHM [SYNC-MODE] [START-TICK] [SYNC-PERIOD] [PCI-LATENCY] "
"[ETH-LATENCY]\n"); "[ETH-LATENCY]\n");
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (argc >= 5) if (argc >= 5)
sync_mode = strtol(argv[4], NULL, 0); sync_mode = strtol(argv[4], NULL, 0);
if (argc >= 6) if (argc >= 6)
main_time = strtoull(argv[5], NULL, 0); main_time = strtoull(argv[5], NULL, 0);
if (argc >= 7) if (argc >= 7)
sync_period = strtoull(argv[6], NULL, 0) * 1000ULL; sync_period = strtoull(argv[6], NULL, 0) * 1000ULL;
if (argc >= 8) if (argc >= 8)
pci_latency = strtoull(argv[7], NULL, 0) * 1000ULL; pci_latency = strtoull(argv[7], NULL, 0) * 1000ULL;
if (argc >= 9) if (argc >= 9)
eth_latency = strtoull(argv[8], NULL, 0) * 1000ULL; eth_latency = strtoull(argv[8], NULL, 0) * 1000ULL;
signal(SIGINT, sigint_handler); signal(SIGINT, sigint_handler);
signal(SIGUSR1, sigusr1_handler); signal(SIGUSR1, sigusr1_handler);
memset(&dintro, 0, sizeof(dintro)); memset(&dintro, 0, sizeof(dintro));
dev.setup_intro(dintro); dev.setup_intro(dintro);
nsparams.sync_pci = 1; nsparams.sync_pci = 1;
nsparams.sync_eth = 1; nsparams.sync_eth = 1;
nsparams.pci_socket_path = argv[1]; nsparams.pci_socket_path = argv[1];
nsparams.eth_socket_path = argv[2]; nsparams.eth_socket_path = argv[2];
nsparams.shm_path = argv[3]; nsparams.shm_path = argv[3];
nsparams.pci_latency = pci_latency; nsparams.pci_latency = pci_latency;
nsparams.eth_latency = eth_latency; nsparams.eth_latency = eth_latency;
nsparams.sync_delay = sync_period; nsparams.sync_delay = sync_period;
assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER); assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER);
nsparams.sync_mode = sync_mode; nsparams.sync_mode = sync_mode;
if (nicsim_init(&nsparams, &dintro)) { if (nicsim_init(&nsparams, &dintro)) {
return EXIT_FAILURE; return EXIT_FAILURE;
}
fprintf(stderr, "sync_pci=%d sync_eth=%d\n", nsparams.sync_pci,
nsparams.sync_eth);
bool is_sync = nsparams.sync_pci || nsparams.sync_eth;
while (!exiting) {
while (nicsim_sync(&nsparams, main_time)) {
fprintf(stderr, "warn: nicsim_sync failed (t=%lu)\n", main_time);
} }
fprintf(stderr, "sync_pci=%d sync_eth=%d\n", nsparams.sync_pci, nicsim_advance_epoch(&nsparams, main_time);
nsparams.sync_eth);
do {
bool is_sync = nsparams.sync_pci || nsparams.sync_eth; poll_h2d();
poll_n2d();
while (!exiting) { event_trigger();
while (nicsim_sync(&nsparams, main_time)) {
fprintf(stderr, "warn: nicsim_sync failed (t=%lu)\n", main_time); if (is_sync) {
} next_ts = nicsim_next_timestamp(&nsparams);
nicsim_advance_epoch(&nsparams, main_time); if (next_ts > main_time + max_step)
next_ts = main_time + max_step;
do { } else {
poll_h2d(); next_ts = main_time + max_step;
poll_n2d(); }
event_trigger();
uint64_t ev_ts;
if (is_sync) { if (event_next(ev_ts) && ev_ts < next_ts)
next_ts = nicsim_next_timestamp(&nsparams); next_ts = ev_ts;
if (next_ts > main_time + max_step) } while (next_ts <= main_time && !exiting);
next_ts = main_time + max_step; main_time = nicsim_advance_time(&nsparams, next_ts);
} else { }
next_ts = main_time + max_step;
} fprintf(stderr, "exit main_time: %lu\n", main_time);
nicsim_cleanup();
uint64_t ev_ts; return 0;
if (event_next(ev_ts) && ev_ts < next_ts)
next_ts = ev_ts;
} while (next_ts <= main_time && !exiting);
main_time = nicsim_advance_time(&nsparams, next_ts);
}
fprintf(stderr, "exit main_time: %lu\n", main_time);
nicsim_cleanup();
return 0;
} }
void Runner::Device::timed_event(TimedEvent &te) void Runner::Device::timed_event(TimedEvent &te) {
{
} }
void Runner::Device::devctrl_update( void Runner::Device::devctrl_update(
struct cosim_pcie_proto_h2d_devctrl &devctrl) struct cosim_pcie_proto_h2d_devctrl &devctrl) {
{ int_intx_en = devctrl.flags & COSIM_PCIE_PROTO_CTRL_INTX_EN;
int_intx_en = devctrl.flags & COSIM_PCIE_PROTO_CTRL_INTX_EN; int_msi_en = devctrl.flags & COSIM_PCIE_PROTO_CTRL_MSI_EN;
int_msi_en = devctrl.flags & COSIM_PCIE_PROTO_CTRL_MSI_EN; int_msix_en = devctrl.flags & COSIM_PCIE_PROTO_CTRL_MSIX_EN;
int_msix_en = devctrl.flags & COSIM_PCIE_PROTO_CTRL_MSIX_EN;
} }
} // namespace nicbm
...@@ -27,10 +27,11 @@ ...@@ -27,10 +27,11 @@
#include <cassert> #include <cassert>
#include <cstring> #include <cstring>
#include <set>
#include <deque> #include <deque>
#include <set>
extern "C" { extern "C" {
#include <simbricks/nicif/nicsim.h> #include <simbricks/nicif/nicsim.h>
} }
namespace nicbm { namespace nicbm {
...@@ -38,21 +39,22 @@ namespace nicbm { ...@@ -38,21 +39,22 @@ namespace nicbm {
static const size_t MAX_DMA_LEN = 2048; static const size_t MAX_DMA_LEN = 2048;
class DMAOp { class DMAOp {
public: public:
virtual ~DMAOp() { } virtual ~DMAOp() {
bool write; }
uint64_t dma_addr; bool write;
size_t len; uint64_t dma_addr;
void *data; size_t len;
void *data;
}; };
class TimedEvent { class TimedEvent {
public: public:
virtual ~TimedEvent() { } virtual ~TimedEvent() {
uint64_t time; }
uint64_t time;
}; };
/** /**
* The Runner drives the main simulation loop. It's initialized with a reference * The Runner drives the main simulation loop. It's initialized with a reference
* to a device it should manage, and then once `runMain` is called, it will * to a device it should manage, and then once `runMain` is called, it will
...@@ -60,111 +62,107 @@ class TimedEvent { ...@@ -60,111 +62,107 @@ class TimedEvent {
* device as needed. * device as needed.
* */ * */
class Runner { class Runner {
public: public:
class Device { class Device {
protected: protected:
bool int_intx_en; bool int_intx_en;
bool int_msi_en; bool int_msi_en;
bool int_msix_en; bool int_msix_en;
public: public:
/** /**
* Initialize device specific parameters (pci dev/vendor id, * Initialize device specific parameters (pci dev/vendor id,
* BARs etc. in intro struct. * BARs etc. in intro struct.
*/ */
virtual void setup_intro(struct cosim_pcie_proto_dev_intro &di) virtual void setup_intro(struct cosim_pcie_proto_dev_intro &di) = 0;
= 0;
/**
/** * execute a register read from `bar`:`addr` of length `len`.
* execute a register read from `bar`:`addr` of length `len`. * Should store result in `dest`.
* Should store result in `dest`. */
*/ virtual void reg_read(uint8_t bar, uint64_t addr, void *dest,
virtual void reg_read(uint8_t bar, uint64_t addr, void *dest, size_t len) = 0;
size_t len) = 0;
/**
/** * execute a register write to `bar`:`addr` of length `len`,
* execute a register write to `bar`:`addr` of length `len`, * with the data in `src`.
* with the data in `src`. */
*/ virtual void reg_write(uint8_t bar, uint64_t addr, const void *src,
virtual void reg_write(uint8_t bar, uint64_t addr, size_t len) = 0;
const void *src, size_t len) = 0;
/**
/** * the previously issued DMA operation `op` completed.
* the previously issued DMA operation `op` completed. */
*/ virtual void dma_complete(DMAOp &op) = 0;
virtual void dma_complete(DMAOp &op) = 0;
/**
/** * A packet has arrived on the wire, of length `len` with
* A packet has arrived on the wire, of length `len` with * payload `data`.
* payload `data`. */
*/ virtual void eth_rx(uint8_t port, const void *data, size_t len) = 0;
virtual void eth_rx(uint8_t port, const void *data, size_t len)
= 0; /**
* A timed event is due.
/** */
* A timed event is due. virtual void timed_event(TimedEvent &ev);
*/
virtual void timed_event(TimedEvent &ev); /**
* Device control update
/** */
* Device control update virtual void devctrl_update(struct cosim_pcie_proto_h2d_devctrl &devctrl);
*/ };
virtual void devctrl_update(
struct cosim_pcie_proto_h2d_devctrl &devctrl); protected:
}; struct event_cmp {
bool operator()(TimedEvent *a, TimedEvent *b) {
protected: return a->time < b->time;
struct event_cmp { }
bool operator() (TimedEvent *a, TimedEvent *b) };
{
return a->time < b->time; Device &dev;
} std::set<TimedEvent *, event_cmp> events;
}; std::deque<DMAOp *> dma_queue;
size_t dma_pending;
Device &dev; uint64_t mac_addr;
std::set<TimedEvent *, event_cmp> events; struct nicsim_params nsparams;
std::deque<DMAOp *> dma_queue; struct cosim_pcie_proto_dev_intro dintro;
size_t dma_pending;
uint64_t mac_addr; volatile union cosim_pcie_proto_d2h *d2h_alloc(void);
struct nicsim_params nsparams; volatile union cosim_eth_proto_d2n *d2n_alloc(void);
struct cosim_pcie_proto_dev_intro dintro;
void h2d_read(volatile struct cosim_pcie_proto_h2d_read *read);
volatile union cosim_pcie_proto_d2h *d2h_alloc(void); void h2d_write(volatile struct cosim_pcie_proto_h2d_write *write);
volatile union cosim_eth_proto_d2n *d2n_alloc(void); void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc);
void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc);
void h2d_read(volatile struct cosim_pcie_proto_h2d_read *read); void h2d_devctrl(volatile struct cosim_pcie_proto_h2d_devctrl *dc);
void h2d_write(volatile struct cosim_pcie_proto_h2d_write *write); void poll_h2d();
void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc);
void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc); void eth_recv(volatile struct cosim_eth_proto_n2d_recv *recv);
void h2d_devctrl(volatile struct cosim_pcie_proto_h2d_devctrl *dc); void poll_n2d();
void poll_h2d();
bool event_next(uint64_t &retval);
void eth_recv(volatile struct cosim_eth_proto_n2d_recv *recv); void event_trigger();
void poll_n2d();
void dma_do(DMAOp &op);
bool event_next(uint64_t &retval); void dma_trigger();
void event_trigger();
public:
void dma_do(DMAOp &op); Runner(Device &dev_);
void dma_trigger();
/** Run the simulation */
public: int runMain(int argc, char *argv[]);
Runner(Device &dev_);
/* these three are for `Runner::Device`. */
/** Run the simulation */ void issue_dma(DMAOp &op);
int runMain(int argc, char *argv[]); void msi_issue(uint8_t vec);
void msix_issue(uint8_t vec);
/* these three are for `Runner::Device`. */ void eth_send(const void *data, size_t len);
void issue_dma(DMAOp &op);
void msi_issue(uint8_t vec); void event_schedule(TimedEvent &evt);
void msix_issue(uint8_t vec); void event_cancel(TimedEvent &evt);
void eth_send(const void *data, size_t len);
uint64_t time_ps() const;
void event_schedule(TimedEvent &evt); uint64_t get_mac_addr() const;
void event_cancel(TimedEvent &evt);
uint64_t time_ps() const;
uint64_t get_mac_addr() const;
}; };
/** /**
...@@ -172,26 +170,23 @@ class Runner { ...@@ -172,26 +170,23 @@ class Runner {
*/ */
template <class TReg = uint32_t> template <class TReg = uint32_t>
class SimpleDevice : public Runner::Device { class SimpleDevice : public Runner::Device {
public: public:
virtual TReg reg_read(uint8_t bar, uint64_t addr) = 0; virtual TReg reg_read(uint8_t bar, uint64_t addr) = 0;
virtual void reg_write(uint8_t bar, uint64_t addr, TReg val) = 0; virtual void reg_write(uint8_t bar, uint64_t addr, TReg val) = 0;
virtual void reg_read(uint8_t bar, uint64_t addr, void *dest, virtual void reg_read(uint8_t bar, uint64_t addr, void *dest, size_t len) {
size_t len) assert(len == sizeof(TReg));
{ TReg r = reg_read(bar, addr);
assert(len == sizeof(TReg)); memcpy(dest, &r, sizeof(r));
TReg r = reg_read(bar, addr); }
memcpy(dest, &r, sizeof(r));
} virtual void reg_write(uint8_t bar, uint64_t addr, const void *src,
size_t len) {
virtual void reg_write(uint8_t bar, uint64_t addr, assert(len == sizeof(TReg));
const void *src, size_t len) TReg r;
{ memcpy(&r, src, sizeof(r));
assert(len == sizeof(TReg)); reg_write(bar, addr, r);
TReg r; }
memcpy(&r, src, sizeof(r));
reg_write(bar, addr, r);
}
}; };
} // namespace nicbm } // namespace nicbm
......
...@@ -22,11 +22,11 @@ ...@@ -22,11 +22,11 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <stdlib.h> #include <poll.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <poll.h>
#include <unistd.h> #include <unistd.h>
#include <simbricks/nicif/nicsim.h> #include <simbricks/nicif/nicsim.h>
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
#define N2D_ELEN (9024 + 64) #define N2D_ELEN (9024 + 64)
#define N2D_ENUM 8192 #define N2D_ENUM 8192
static uint8_t *d2h_queue; static uint8_t *d2h_queue;
static size_t d2h_pos; static size_t d2h_pos;
static size_t d2h_off; /* offset in shm region */ static size_t d2h_off; /* offset in shm region */
...@@ -74,402 +73,373 @@ static int pci_cfd = -1; ...@@ -74,402 +73,373 @@ static int pci_cfd = -1;
static int eth_cfd = -1; static int eth_cfd = -1;
static int accept_pci(struct cosim_pcie_proto_dev_intro *di, int pci_lfd, static int accept_pci(struct cosim_pcie_proto_dev_intro *di, int pci_lfd,
int *sync_pci) int *sync_pci) {
{ if ((pci_cfd = accept(pci_lfd, NULL, NULL)) < 0) {
if ((pci_cfd = accept(pci_lfd, NULL, NULL)) < 0) { return -1;
return -1; }
} close(pci_lfd);
close(pci_lfd); printf("pci connection accepted\n");
printf("pci connection accepted\n");
di->d2h_offset = d2h_off;
di->d2h_offset = d2h_off; di->d2h_elen = D2H_ELEN;
di->d2h_elen = D2H_ELEN; di->d2h_nentries = D2H_ENUM;
di->d2h_nentries = D2H_ENUM;
di->h2d_offset = h2d_off;
di->h2d_offset = h2d_off; di->h2d_elen = H2D_ELEN;
di->h2d_elen = H2D_ELEN; di->h2d_nentries = H2D_ENUM;
di->h2d_nentries = H2D_ENUM;
if (*sync_pci)
if (*sync_pci) di->flags |= COSIM_PCIE_PROTO_FLAGS_DI_SYNC;
di->flags |= COSIM_PCIE_PROTO_FLAGS_DI_SYNC; else
else di->flags &= ~((uint64_t)COSIM_PCIE_PROTO_FLAGS_DI_SYNC);
di->flags &= ~((uint64_t) COSIM_PCIE_PROTO_FLAGS_DI_SYNC);
if (uxsocket_send(pci_cfd, di, sizeof(*di), shm_fd)) {
if (uxsocket_send(pci_cfd, di, sizeof(*di), shm_fd)) { return -1;
return -1; }
} printf("pci intro sent\n");
printf("pci intro sent\n"); return 0;
return 0;
} }
static int accept_eth(int eth_lfd, int *sync_eth) static int accept_eth(int eth_lfd, int *sync_eth) {
{ struct cosim_eth_proto_dev_intro di;
struct cosim_eth_proto_dev_intro di;
if ((eth_cfd = accept(eth_lfd, NULL, NULL)) < 0) {
return -1;
}
close(eth_lfd);
printf("eth connection accepted\n");
memset(&di, 0, sizeof(di));
di.flags = 0;
if (*sync_eth)
di.flags |= COSIM_ETH_PROTO_FLAGS_DI_SYNC;
di.d2n_offset = d2n_off;
di.d2n_elen = D2N_ELEN;
di.d2n_nentries = D2N_ENUM;
di.n2d_offset = n2d_off;
di.n2d_elen = N2D_ELEN;
di.n2d_nentries = N2D_ENUM;
if (uxsocket_send(eth_cfd, &di, sizeof(di), shm_fd)) {
return -1;
}
printf("eth intro sent\n");
return 0;
}
if ((eth_cfd = accept(eth_lfd, NULL, NULL)) < 0) { static int accept_conns(struct cosim_pcie_proto_dev_intro *di, int pci_lfd,
int *sync_pci, int eth_lfd, int *sync_eth) {
struct pollfd pfds[2];
int await_pci = pci_lfd != -1;
int await_eth = eth_lfd != -1;
int ret;
while (await_pci || await_eth) {
if (await_pci && await_eth) {
/* we're waiting on both fds */
pfds[0].fd = pci_lfd;
pfds[1].fd = eth_lfd;
pfds[0].events = pfds[1].events = POLLIN;
pfds[0].revents = pfds[1].revents = 0;
ret = poll(pfds, 2, -1);
if (ret < 0) {
perror("poll failed");
return -1; return -1;
} }
close(eth_lfd);
printf("eth connection accepted\n"); if (pfds[0].revents) {
if (accept_pci(di, pci_lfd, sync_pci) != 0)
memset(&di, 0, sizeof(di)); return -1;
di.flags = 0; await_pci = 0;
if (*sync_eth) }
di.flags |= COSIM_ETH_PROTO_FLAGS_DI_SYNC; if (pfds[1].revents) {
if (accept_eth(eth_lfd, sync_eth) != 0)
di.d2n_offset = d2n_off; return -1;
di.d2n_elen = D2N_ELEN; await_eth = 0;
di.d2n_nentries = D2N_ENUM; }
} else if (await_pci) {
di.n2d_offset = n2d_off; /* waiting just on pci */
di.n2d_elen = N2D_ELEN; if (accept_pci(di, pci_lfd, sync_pci) != 0)
di.n2d_nentries = N2D_ENUM;
if (uxsocket_send(eth_cfd, &di, sizeof(di), shm_fd)) {
return -1; return -1;
await_pci = 0;
} else {
/* waiting just on ethernet */
if (accept_eth(eth_lfd, sync_eth) != 0)
return -1;
await_eth = 0;
} }
printf("eth intro sent\n"); }
return 0;
}
static int accept_conns(struct cosim_pcie_proto_dev_intro *di,
int pci_lfd, int *sync_pci, int eth_lfd, int *sync_eth)
{
struct pollfd pfds[2];
int await_pci = pci_lfd != -1;
int await_eth = eth_lfd != -1;
int ret;
while (await_pci || await_eth) {
if (await_pci && await_eth) {
/* we're waiting on both fds */
pfds[0].fd = pci_lfd;
pfds[1].fd = eth_lfd;
pfds[0].events = pfds[1].events = POLLIN;
pfds[0].revents = pfds[1].revents = 0;
ret = poll(pfds, 2, -1);
if (ret < 0) {
perror("poll failed");
return -1;
}
if (pfds[0].revents) {
if (accept_pci(di, pci_lfd, sync_pci) != 0)
return -1;
await_pci = 0;
}
if (pfds[1].revents) {
if (accept_eth(eth_lfd, sync_eth) != 0)
return -1;
await_eth = 0;
}
} else if (await_pci) {
/* waiting just on pci */
if (accept_pci(di, pci_lfd, sync_pci) != 0)
return -1;
await_pci = 0;
} else {
/* waiting just on ethernet */
if (accept_eth(eth_lfd, sync_eth) != 0)
return -1;
await_eth = 0;
}
}
return 0; return 0;
} }
int nicsim_init(struct nicsim_params *params, int nicsim_init(struct nicsim_params *params,
struct cosim_pcie_proto_dev_intro *di) struct cosim_pcie_proto_dev_intro *di) {
{ int pci_lfd = -1, eth_lfd = -1;
int pci_lfd = -1, eth_lfd = -1; void *shmptr;
void *shmptr; size_t shm_size;
size_t shm_size;
/* ready in memory queues */
/* ready in memory queues */ shm_size = (uint64_t)D2H_ELEN * D2H_ENUM + (uint64_t)H2D_ELEN * H2D_ENUM +
shm_size = (uint64_t) D2H_ELEN * D2H_ENUM + (uint64_t)D2N_ELEN * D2N_ENUM + (uint64_t)N2D_ELEN * N2D_ENUM;
(uint64_t) H2D_ELEN * H2D_ENUM + if ((shm_fd = shm_create(params->shm_path, shm_size, &shmptr)) < 0) {
(uint64_t) D2N_ELEN * D2N_ENUM + return -1;
(uint64_t) N2D_ELEN * N2D_ENUM; }
if ((shm_fd = shm_create(params->shm_path, shm_size, &shmptr))
< 0) d2h_off = 0;
{ h2d_off = d2h_off + (uint64_t)D2H_ELEN * D2H_ENUM;
return -1; d2n_off = h2d_off + (uint64_t)H2D_ELEN * H2D_ENUM;
} n2d_off = d2n_off + (uint64_t)D2N_ELEN * D2N_ENUM;
d2h_off = 0; d2h_queue = (uint8_t *)shmptr + d2h_off;
h2d_off = d2h_off + (uint64_t) D2H_ELEN * D2H_ENUM; h2d_queue = (uint8_t *)shmptr + h2d_off;
d2n_off = h2d_off + (uint64_t) H2D_ELEN * H2D_ENUM; d2n_queue = (uint8_t *)shmptr + d2n_off;
n2d_off = d2n_off + (uint64_t) D2N_ELEN * D2N_ENUM; n2d_queue = (uint8_t *)shmptr + n2d_off;
d2h_queue = (uint8_t *) shmptr + d2h_off; d2h_pos = h2d_pos = d2n_pos = n2d_pos = 0;
h2d_queue = (uint8_t *) shmptr + h2d_off;
d2n_queue = (uint8_t *) shmptr + d2n_off; /* get listening sockets ready */
n2d_queue = (uint8_t *) shmptr + n2d_off; if (params->pci_socket_path != NULL) {
if ((pci_lfd = uxsocket_init(params->pci_socket_path)) < 0) {
d2h_pos = h2d_pos = d2n_pos = n2d_pos = 0; return -1;
/* get listening sockets ready */
if (params->pci_socket_path != NULL) {
if ((pci_lfd = uxsocket_init(params->pci_socket_path)) < 0) {
return -1;
}
}
if (params->eth_socket_path != NULL) {
if ((eth_lfd = uxsocket_init(params->eth_socket_path)) < 0) {
return -1;
}
} }
}
/* accept connection fds */ if (params->eth_socket_path != NULL) {
if (accept_conns(di, pci_lfd, &params->sync_pci, eth_lfd, if ((eth_lfd = uxsocket_init(params->eth_socket_path)) < 0) {
&params->sync_eth) != 0) return -1;
{
return -1;
} }
}
/* receive introductions from other end */
if (params->pci_socket_path != NULL) { /* accept connection fds */
struct cosim_pcie_proto_host_intro hi; if (accept_conns(di, pci_lfd, &params->sync_pci, eth_lfd,
if (recv(pci_cfd, &hi, sizeof(hi), 0) != sizeof(hi)) { &params->sync_eth) != 0) {
return -1; return -1;
} }
if ((hi.flags & COSIM_PCIE_PROTO_FLAGS_HI_SYNC) == 0)
params->sync_pci = 0; /* receive introductions from other end */
printf("pci host info received\n"); if (params->pci_socket_path != NULL) {
struct cosim_pcie_proto_host_intro hi;
if (recv(pci_cfd, &hi, sizeof(hi), 0) != sizeof(hi)) {
return -1;
} }
if (params->eth_socket_path != NULL) { if ((hi.flags & COSIM_PCIE_PROTO_FLAGS_HI_SYNC) == 0)
struct cosim_eth_proto_net_intro ni; params->sync_pci = 0;
if (recv(eth_cfd, &ni, sizeof(ni), 0) != sizeof(ni)) { printf("pci host info received\n");
return -1; }
} if (params->eth_socket_path != NULL) {
if ((ni.flags & COSIM_ETH_PROTO_FLAGS_NI_SYNC) == 0) struct cosim_eth_proto_net_intro ni;
params->sync_eth = 0; if (recv(eth_cfd, &ni, sizeof(ni), 0) != sizeof(ni)) {
printf("eth net info received\n"); return -1;
} }
if ((ni.flags & COSIM_ETH_PROTO_FLAGS_NI_SYNC) == 0)
params->sync_eth = 0;
printf("eth net info received\n");
}
return 0; return 0;
} }
void nicsim_cleanup(void) void nicsim_cleanup(void) {
{ close(pci_cfd);
close(pci_cfd); close(eth_cfd);
close(eth_cfd);
} }
/******************************************************************************/ /******************************************************************************/
/* Sync */ /* Sync */
int nicsim_sync(struct nicsim_params *params, uint64_t timestamp) int nicsim_sync(struct nicsim_params *params, uint64_t timestamp) {
{ int ret = 0;
int ret = 0; volatile union cosim_pcie_proto_d2h *d2h;
volatile union cosim_pcie_proto_d2h *d2h; volatile union cosim_eth_proto_d2n *d2n;
volatile union cosim_eth_proto_d2n *d2n;
/* sync PCI if necessary */
/* sync PCI if necessary */ if (params->sync_pci) {
if (params->sync_pci) { int sync;
int sync; switch (params->sync_mode) {
switch (params->sync_mode) { case SYNC_MODES:
case SYNC_MODES: sync = pci_last_tx_time == 0 ||
sync = pci_last_tx_time == 0 || timestamp - pci_last_tx_time >= params->sync_delay;
timestamp - pci_last_tx_time >= params->sync_delay; break;
break; case SYNC_BARRIER:
case SYNC_BARRIER: sync = current_epoch == 0 ||
sync = current_epoch == 0 || timestamp - current_epoch >= params->sync_delay;
timestamp - current_epoch >= params->sync_delay; break;
break; default:
default: fprintf(stderr, "unsupported sync mode=%u\n", params->sync_mode);
fprintf(stderr, "unsupported sync mode=%u\n", params->sync_mode); return ret;
return ret; }
}
if (sync) {
if (sync) d2h = nicsim_d2h_alloc(params, timestamp);
{ if (d2h == NULL) {
d2h = nicsim_d2h_alloc(params, timestamp); ret = -1;
if (d2h == NULL) { } else {
ret = -1; d2h->sync.own_type =
} else { COSIM_PCIE_PROTO_D2H_MSG_SYNC | COSIM_PCIE_PROTO_D2H_OWN_HOST;
d2h->sync.own_type = COSIM_PCIE_PROTO_D2H_MSG_SYNC | }
COSIM_PCIE_PROTO_D2H_OWN_HOST; }
} }
}
/* sync Ethernet if necessary */
if (params->sync_eth) {
int sync;
switch (params->sync_mode) {
case SYNC_MODES:
sync = eth_last_tx_time == 0 ||
timestamp - eth_last_tx_time >= params->sync_delay;
break;
case SYNC_BARRIER:
sync = current_epoch == 0 ||
timestamp - current_epoch >= params->sync_delay;
break;
default:
fprintf(stderr, "unsupported sync mode=%u\n", params->sync_mode);
return ret;
} }
/* sync Ethernet if necessary */ if (sync) {
if (params->sync_eth) { d2n = nicsim_d2n_alloc(params, timestamp);
int sync; if (d2n == NULL) {
switch (params->sync_mode) { ret = -1;
case SYNC_MODES: } else {
sync = eth_last_tx_time == 0 || d2n->sync.own_type =
timestamp - eth_last_tx_time >= params->sync_delay; COSIM_ETH_PROTO_D2N_MSG_SYNC | COSIM_ETH_PROTO_D2N_OWN_NET;
break; }
case SYNC_BARRIER:
sync = current_epoch == 0 ||
timestamp - current_epoch >= params->sync_delay;
break;
default:
fprintf(stderr, "unsupported sync mode=%u\n", params->sync_mode);
return ret;
}
if (sync)
{
d2n = nicsim_d2n_alloc(params, timestamp);
if (d2n == NULL) {
ret = -1;
} else {
d2n->sync.own_type = COSIM_ETH_PROTO_D2N_MSG_SYNC |
COSIM_ETH_PROTO_D2N_OWN_NET;
}
}
} }
}
return ret; return ret;
} }
void nicsim_advance_epoch(struct nicsim_params *params, uint64_t timestamp) void nicsim_advance_epoch(struct nicsim_params *params, uint64_t timestamp) {
{ if (params->sync_mode == SYNC_BARRIER) {
if (params->sync_mode == SYNC_BARRIER) { if ((params->sync_pci || params->sync_eth) &&
if ((params->sync_pci || params->sync_eth) && timestamp - current_epoch >= params->sync_delay) {
timestamp - current_epoch >= params->sync_delay) { current_epoch = timestamp;
current_epoch = timestamp;
}
} }
}
} }
uint64_t nicsim_advance_time(struct nicsim_params *params, uint64_t timestamp) uint64_t nicsim_advance_time(struct nicsim_params *params, uint64_t timestamp) {
{ switch (params->sync_mode) {
switch (params->sync_mode) {
case SYNC_MODES: case SYNC_MODES:
return timestamp; return timestamp;
case SYNC_BARRIER: case SYNC_BARRIER:
return timestamp < current_epoch + params->sync_delay ? return timestamp < current_epoch + params->sync_delay
timestamp : current_epoch + params->sync_delay; ? timestamp
: current_epoch + params->sync_delay;
default: default:
fprintf(stderr, "unsupported sync mode=%u\n", params->sync_mode); fprintf(stderr, "unsupported sync mode=%u\n", params->sync_mode);
return timestamp; return timestamp;
} }
} }
uint64_t nicsim_next_timestamp(struct nicsim_params *params) uint64_t nicsim_next_timestamp(struct nicsim_params *params) {
{ if (params->sync_pci && params->sync_eth) {
if (params->sync_pci && params->sync_eth) { return (pci_last_rx_time <= eth_last_rx_time ? pci_last_rx_time
return (pci_last_rx_time <= eth_last_rx_time ? pci_last_rx_time : : eth_last_rx_time);
eth_last_rx_time); } else if (params->sync_pci) {
} else if (params->sync_pci) { return pci_last_rx_time;
return pci_last_rx_time; } else if (params->sync_eth) {
} else if (params->sync_eth) { return eth_last_rx_time;
return eth_last_rx_time; } else {
} else { return 0;
return 0; }
}
} }
/******************************************************************************/ /******************************************************************************/
/* PCI */ /* PCI */
volatile union cosim_pcie_proto_h2d *nicif_h2d_poll( volatile union cosim_pcie_proto_h2d *nicif_h2d_poll(
struct nicsim_params *params, uint64_t timestamp) struct nicsim_params *params, uint64_t timestamp) {
{ volatile union cosim_pcie_proto_h2d *msg =
volatile union cosim_pcie_proto_h2d *msg = (volatile union cosim_pcie_proto_h2d *)(h2d_queue + h2d_pos * H2D_ELEN);
(volatile union cosim_pcie_proto_h2d *)
(h2d_queue + h2d_pos * H2D_ELEN); /* message not ready */
if ((msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_OWN_MASK) !=
/* message not ready */ COSIM_PCIE_PROTO_H2D_OWN_DEV)
if ((msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_OWN_MASK) != return NULL;
COSIM_PCIE_PROTO_H2D_OWN_DEV)
return NULL; /* if in sync mode, wait till message is ready */
pci_last_rx_time = msg->dummy.timestamp;
/* if in sync mode, wait till message is ready */ if (params->sync_pci && pci_last_rx_time > timestamp)
pci_last_rx_time = msg->dummy.timestamp; return NULL;
if (params->sync_pci && pci_last_rx_time > timestamp)
return NULL; return msg;
return msg;
} }
void nicif_h2d_done(volatile union cosim_pcie_proto_h2d *msg) void nicif_h2d_done(volatile union cosim_pcie_proto_h2d *msg) {
{ msg->dummy.own_type = (msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK) |
msg->dummy.own_type = (msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK) COSIM_PCIE_PROTO_H2D_OWN_HOST;
| COSIM_PCIE_PROTO_H2D_OWN_HOST;
} }
void nicif_h2d_next(void) void nicif_h2d_next(void) {
{ h2d_pos = (h2d_pos + 1) % H2D_ENUM;
h2d_pos = (h2d_pos + 1) % H2D_ENUM;
} }
volatile union cosim_pcie_proto_d2h *nicsim_d2h_alloc( volatile union cosim_pcie_proto_d2h *nicsim_d2h_alloc(
struct nicsim_params *params, uint64_t timestamp) struct nicsim_params *params, uint64_t timestamp) {
{ volatile union cosim_pcie_proto_d2h *msg =
volatile union cosim_pcie_proto_d2h *msg = (volatile union cosim_pcie_proto_d2h *)(d2h_queue + d2h_pos * D2H_ELEN);
(volatile union cosim_pcie_proto_d2h *)
(d2h_queue + d2h_pos * D2H_ELEN);
if ((msg->dummy.own_type & COSIM_PCIE_PROTO_D2H_OWN_MASK) !=
COSIM_PCIE_PROTO_D2H_OWN_DEV)
{
return NULL;
}
msg->dummy.timestamp = timestamp + params->pci_latency; if ((msg->dummy.own_type & COSIM_PCIE_PROTO_D2H_OWN_MASK) !=
pci_last_tx_time = timestamp; COSIM_PCIE_PROTO_D2H_OWN_DEV) {
return NULL;
}
d2h_pos = (d2h_pos + 1) % D2H_ENUM; msg->dummy.timestamp = timestamp + params->pci_latency;
return msg; pci_last_tx_time = timestamp;
d2h_pos = (d2h_pos + 1) % D2H_ENUM;
return msg;
} }
/******************************************************************************/ /******************************************************************************/
/* Ethernet */ /* Ethernet */
volatile union cosim_eth_proto_n2d *nicif_n2d_poll( volatile union cosim_eth_proto_n2d *nicif_n2d_poll(struct nicsim_params *params,
struct nicsim_params *params, uint64_t timestamp) uint64_t timestamp) {
{ volatile union cosim_eth_proto_n2d *msg =
volatile union cosim_eth_proto_n2d *msg = (volatile union cosim_eth_proto_n2d *)(n2d_queue + n2d_pos * N2D_ELEN);
(volatile union cosim_eth_proto_n2d *)
(n2d_queue + n2d_pos * N2D_ELEN);
/* message not ready */ /* message not ready */
if ((msg->dummy.own_type & COSIM_ETH_PROTO_N2D_OWN_MASK) != if ((msg->dummy.own_type & COSIM_ETH_PROTO_N2D_OWN_MASK) !=
COSIM_ETH_PROTO_N2D_OWN_DEV) COSIM_ETH_PROTO_N2D_OWN_DEV)
return NULL; return NULL;
/* if in sync mode, wait till message is ready */ /* if in sync mode, wait till message is ready */
eth_last_rx_time = msg->dummy.timestamp; eth_last_rx_time = msg->dummy.timestamp;
if (params->sync_eth && eth_last_rx_time > timestamp) if (params->sync_eth && eth_last_rx_time > timestamp)
return NULL; return NULL;
return msg; return msg;
} }
void nicif_n2d_done(volatile union cosim_eth_proto_n2d *msg) void nicif_n2d_done(volatile union cosim_eth_proto_n2d *msg) {
{ msg->dummy.own_type = (msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK) |
msg->dummy.own_type = (msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK) COSIM_ETH_PROTO_N2D_OWN_NET;
| COSIM_ETH_PROTO_N2D_OWN_NET;
} }
void nicif_n2d_next(void) void nicif_n2d_next(void) {
{ n2d_pos = (n2d_pos + 1) % N2D_ENUM;
n2d_pos = (n2d_pos + 1) % N2D_ENUM;
} }
volatile union cosim_eth_proto_d2n *nicsim_d2n_alloc( volatile union cosim_eth_proto_d2n *nicsim_d2n_alloc(
struct nicsim_params *params, uint64_t timestamp) struct nicsim_params *params, uint64_t timestamp) {
{ volatile union cosim_eth_proto_d2n *msg =
volatile union cosim_eth_proto_d2n *msg = (volatile union cosim_eth_proto_d2n *)(d2n_queue + d2n_pos * D2N_ELEN);
(volatile union cosim_eth_proto_d2n *)
(d2n_queue + d2n_pos * D2N_ELEN); if ((msg->dummy.own_type & COSIM_ETH_PROTO_D2N_OWN_MASK) !=
COSIM_ETH_PROTO_D2N_OWN_DEV) {
if ((msg->dummy.own_type & COSIM_ETH_PROTO_D2N_OWN_MASK) != return NULL;
COSIM_ETH_PROTO_D2N_OWN_DEV) }
{
return NULL;
}
msg->dummy.timestamp = timestamp + params->eth_latency; msg->dummy.timestamp = timestamp + params->eth_latency;
eth_last_tx_time = timestamp; eth_last_tx_time = timestamp;
d2n_pos = (d2n_pos + 1) % D2N_ENUM; d2n_pos = (d2n_pos + 1) % D2N_ENUM;
return msg; return msg;
} }
...@@ -25,28 +25,28 @@ ...@@ -25,28 +25,28 @@
#ifndef SIMBRICKS_NICIF_NICSIM_H_ #ifndef SIMBRICKS_NICIF_NICSIM_H_
#define SIMBRICKS_NICIF_NICSIM_H_ #define SIMBRICKS_NICIF_NICSIM_H_
#include <simbricks/proto/pcie.h>
#include <simbricks/proto/network.h> #include <simbricks/proto/network.h>
#include <simbricks/proto/pcie.h>
#define SYNC_MODES 0 // ModES style synchronization #define SYNC_MODES 0 // ModES style synchronization
#define SYNC_BARRIER 1 // Global barrier style synchronization #define SYNC_BARRIER 1 // Global barrier style synchronization
struct nicsim_params { struct nicsim_params {
const char *pci_socket_path; const char *pci_socket_path;
const char *eth_socket_path; const char *eth_socket_path;
const char *shm_path; const char *shm_path;
uint64_t pci_latency; uint64_t pci_latency;
uint64_t eth_latency; uint64_t eth_latency;
uint64_t sync_delay; uint64_t sync_delay;
int sync_pci; int sync_pci;
int sync_eth; int sync_eth;
int sync_mode; int sync_mode;
}; };
int nicsim_init(struct nicsim_params *params, int nicsim_init(struct nicsim_params *params,
struct cosim_pcie_proto_dev_intro *di); struct cosim_pcie_proto_dev_intro *di);
void nicsim_cleanup(void); void nicsim_cleanup(void);
int nicsim_sync(struct nicsim_params *params, uint64_t timestamp); int nicsim_sync(struct nicsim_params *params, uint64_t timestamp);
...@@ -55,20 +55,19 @@ uint64_t nicsim_advance_time(struct nicsim_params *params, uint64_t timestamp); ...@@ -55,20 +55,19 @@ uint64_t nicsim_advance_time(struct nicsim_params *params, uint64_t timestamp);
uint64_t nicsim_next_timestamp(struct nicsim_params *params); uint64_t nicsim_next_timestamp(struct nicsim_params *params);
volatile union cosim_pcie_proto_h2d *nicif_h2d_poll( volatile union cosim_pcie_proto_h2d *nicif_h2d_poll(
struct nicsim_params *params, uint64_t timestamp); struct nicsim_params *params, uint64_t timestamp);
void nicif_h2d_done(volatile union cosim_pcie_proto_h2d *msg); void nicif_h2d_done(volatile union cosim_pcie_proto_h2d *msg);
void nicif_h2d_next(void); void nicif_h2d_next(void);
volatile union cosim_pcie_proto_d2h *nicsim_d2h_alloc( volatile union cosim_pcie_proto_d2h *nicsim_d2h_alloc(
struct nicsim_params *params, uint64_t timestamp); struct nicsim_params *params, uint64_t timestamp);
volatile union cosim_eth_proto_n2d *nicif_n2d_poll( volatile union cosim_eth_proto_n2d *nicif_n2d_poll(struct nicsim_params *params,
struct nicsim_params *params, uint64_t timestamp); uint64_t timestamp);
void nicif_n2d_done(volatile union cosim_eth_proto_n2d *msg); void nicif_n2d_done(volatile union cosim_eth_proto_n2d *msg);
void nicif_n2d_next(void); void nicif_n2d_next(void);
volatile union cosim_eth_proto_d2n *nicsim_d2n_alloc( volatile union cosim_eth_proto_d2n *nicsim_d2n_alloc(
struct nicsim_params *params, uint64_t timestamp); struct nicsim_params *params, uint64_t timestamp);
#endif // SIMBRICKS_NICIF_NICSIM_H_ #endif // SIMBRICKS_NICIF_NICSIM_H_
...@@ -24,116 +24,112 @@ ...@@ -24,116 +24,112 @@
#include <errno.h> #include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include <sys/un.h> #include <stdio.h>
#include <sys/socket.h> #include <stdlib.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h> #include <unistd.h>
#include "lib/simbricks/nicif/internal.h" #include "lib/simbricks/nicif/internal.h"
int uxsocket_init(const char *path) int uxsocket_init(const char *path) {
{ int fd;
int fd; struct sockaddr_un saun;
struct sockaddr_un saun;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("uxsocket_init: socket failed"); perror("uxsocket_init: socket failed");
goto error_exit; goto error_exit;
} }
memset(&saun, 0, sizeof(saun)); memset(&saun, 0, sizeof(saun));
saun.sun_family = AF_UNIX; saun.sun_family = AF_UNIX;
memcpy(saun.sun_path, path, strlen(path)); memcpy(saun.sun_path, path, strlen(path));
if (bind(fd, (struct sockaddr *) &saun, sizeof(saun))) { if (bind(fd, (struct sockaddr *)&saun, sizeof(saun))) {
perror("uxsocket_init: bind failed"); perror("uxsocket_init: bind failed");
goto error_close; goto error_close;
} }
if (listen(fd, 5)) { if (listen(fd, 5)) {
perror("uxsocket_init: listen failed"); perror("uxsocket_init: listen failed");
goto error_close; goto error_close;
} }
return fd; return fd;
error_close: error_close:
close(fd); close(fd);
error_exit: error_exit:
return -1; return -1;
} }
int uxsocket_send(int connfd, void *data, size_t len, int fd) int uxsocket_send(int connfd, void *data, size_t len, int fd) {
{ ssize_t tx;
ssize_t tx; struct iovec iov = {
struct iovec iov = { .iov_base = data,
.iov_base = data, .iov_len = len,
.iov_len = len, };
}; union {
union { char buf[CMSG_SPACE(sizeof(int))];
char buf[CMSG_SPACE(sizeof(int))]; struct cmsghdr align;
struct cmsghdr align; } u;
} u; struct msghdr msg = {
struct msghdr msg = { .msg_name = NULL,
.msg_name = NULL, .msg_namelen = 0,
.msg_namelen = 0, .msg_iov = &iov,
.msg_iov = &iov, .msg_iovlen = 1,
.msg_iovlen = 1, .msg_control = u.buf,
.msg_control = u.buf, .msg_controllen = 0,
.msg_controllen = 0, .msg_flags = 0,
.msg_flags = 0, };
}; struct cmsghdr *cmsg = &u.align;
struct cmsghdr *cmsg = &u.align;
if (fd >= 0) {
if (fd >= 0) { msg.msg_controllen = sizeof(u.buf);
msg.msg_controllen = sizeof(u.buf);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(int));
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*(int *)CMSG_DATA(cmsg) = fd;
*(int *) CMSG_DATA(cmsg) = fd; }
}
if ((tx = sendmsg(connfd, &msg, 0)) != (ssize_t)len) {
if ((tx = sendmsg(connfd, &msg, 0)) != (ssize_t) len) { fprintf(stderr, "tx == %zd\n", tx);
fprintf(stderr, "tx == %zd\n", tx); return -1;
return -1; }
}
return 0;
return 0;
} }
int shm_create(const char *path, size_t size, void **addr) int shm_create(const char *path, size_t size, void **addr) {
{ int fd;
int fd; void *p;
void *p;
if ((fd = open(path, O_CREAT | O_RDWR, 0666)) == -1) { if ((fd = open(path, O_CREAT | O_RDWR, 0666)) == -1) {
perror("util_create_shmsiszed: open failed"); perror("util_create_shmsiszed: open failed");
goto error_out; goto error_out;
} }
if (ftruncate(fd, size) != 0) { if (ftruncate(fd, size) != 0) {
perror("util_create_shmsiszed: ftruncate failed"); perror("util_create_shmsiszed: ftruncate failed");
goto error_remove; goto error_remove;
} }
if ((p = mmap(NULL, size, PROT_READ | PROT_WRITE, if ((p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
MAP_SHARED | MAP_POPULATE, fd, 0)) == (void *) -1) fd, 0)) == (void *)-1) {
{ perror("util_create_shmsiszed: mmap failed");
perror("util_create_shmsiszed: mmap failed"); goto error_remove;
goto error_remove; }
}
memset(p, 0, size); memset(p, 0, size);
*addr = p; *addr = p;
return fd; return fd;
error_remove: error_remove:
close(fd); close(fd);
unlink(path); unlink(path);
error_out: error_out:
return -1; return -1;
} }
...@@ -38,34 +38,32 @@ ...@@ -38,34 +38,32 @@
* memory file descriptor attached. * memory file descriptor attached.
*/ */
struct cosim_eth_proto_dev_intro { struct cosim_eth_proto_dev_intro {
/** flags: see COSIM_ETH_PROTO_FLAGS_DI_* */ /** flags: see COSIM_ETH_PROTO_FLAGS_DI_* */
uint64_t flags; uint64_t flags;
/** offset of the device-to-network queue in shared memory region */
uint64_t d2n_offset;
/** size of an entry in the device-to-network queue in bytes */
uint64_t d2n_elen;
/** total device-to-network queue length in #entries */
uint64_t d2n_nentries;
/** offset of the net-to-device queue in shared memory region */
uint64_t n2d_offset;
/** size of an entry in the net-to-device queue in bytes */
uint64_t n2d_elen;
/** total net-to-device queue length in #entries */
uint64_t n2d_nentries;
} __attribute__((packed));
/** offset of the device-to-network queue in shared memory region */
uint64_t d2n_offset;
/** size of an entry in the device-to-network queue in bytes */
uint64_t d2n_elen;
/** total device-to-network queue length in #entries */
uint64_t d2n_nentries;
/** offset of the net-to-device queue in shared memory region */
uint64_t n2d_offset;
/** size of an entry in the net-to-device queue in bytes */
uint64_t n2d_elen;
/** total net-to-device queue length in #entries */
uint64_t n2d_nentries;
} __attribute__((packed));
#define COSIM_ETH_PROTO_FLAGS_NI_SYNC (1 << 0) #define COSIM_ETH_PROTO_FLAGS_NI_SYNC (1 << 0)
/** welcome message sent by network to device */ /** welcome message sent by network to device */
struct cosim_eth_proto_net_intro { struct cosim_eth_proto_net_intro {
/** flags: see COSIM_ETH_PROTO_FLAGS_IN_* */ /** flags: see COSIM_ETH_PROTO_FLAGS_IN_* */
uint64_t flags; uint64_t flags;
} __attribute__((packed)); } __attribute__((packed));
/******************************************************************************/ /******************************************************************************/
/* Messages on in-memory device to network channel */ /* Messages on in-memory device to network channel */
...@@ -82,36 +80,35 @@ struct cosim_eth_proto_net_intro { ...@@ -82,36 +80,35 @@ struct cosim_eth_proto_net_intro {
#define COSIM_ETH_PROTO_D2N_MSG_SEND 0x2 #define COSIM_ETH_PROTO_D2N_MSG_SEND 0x2
struct cosim_eth_proto_d2n_dummy { struct cosim_eth_proto_d2n_dummy {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
struct cosim_eth_proto_d2n_sync { struct cosim_eth_proto_d2n_sync {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
struct cosim_eth_proto_d2n_send { struct cosim_eth_proto_d2n_send {
uint16_t len; uint16_t len;
uint8_t port; uint8_t port;
uint8_t pad[45]; uint8_t pad[45];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
uint8_t data[]; uint8_t data[];
} __attribute__((packed)); } __attribute__((packed));
union cosim_eth_proto_d2n { union cosim_eth_proto_d2n {
struct cosim_eth_proto_d2n_dummy dummy; struct cosim_eth_proto_d2n_dummy dummy;
struct cosim_eth_proto_d2n_sync sync; struct cosim_eth_proto_d2n_sync sync;
struct cosim_eth_proto_d2n_send send; struct cosim_eth_proto_d2n_send send;
}; };
/******************************************************************************/ /******************************************************************************/
/* Messages on in-memory network to device channel */ /* Messages on in-memory network to device channel */
...@@ -126,33 +123,33 @@ union cosim_eth_proto_d2n { ...@@ -126,33 +123,33 @@ union cosim_eth_proto_d2n {
#define COSIM_ETH_PROTO_N2D_MSG_RECV 0x2 #define COSIM_ETH_PROTO_N2D_MSG_RECV 0x2
struct cosim_eth_proto_n2d_dummy { struct cosim_eth_proto_n2d_dummy {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
struct cosim_eth_proto_n2d_sync { struct cosim_eth_proto_n2d_sync {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
struct cosim_eth_proto_n2d_recv { struct cosim_eth_proto_n2d_recv {
uint16_t len; uint16_t len;
uint8_t port; uint8_t port;
uint8_t pad[45]; uint8_t pad[45];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
uint8_t data[]; uint8_t data[];
}; };
union cosim_eth_proto_n2d { union cosim_eth_proto_n2d {
struct cosim_eth_proto_n2d_dummy dummy; struct cosim_eth_proto_n2d_dummy dummy;
struct cosim_eth_proto_n2d_sync sync; struct cosim_eth_proto_n2d_sync sync;
struct cosim_eth_proto_n2d_recv recv; struct cosim_eth_proto_n2d_recv recv;
}; };
#endif // SIMBRICKS_PROTO_NETWORK_H_ #endif // SIMBRICKS_PROTO_NETWORK_H_
...@@ -55,69 +55,67 @@ ...@@ -55,69 +55,67 @@
* memory file descriptor attached. * memory file descriptor attached.
*/ */
struct cosim_pcie_proto_dev_intro { struct cosim_pcie_proto_dev_intro {
/** flags: see COSIM_PCIE_PROTO_FLAGS_DI_* */ /** flags: see COSIM_PCIE_PROTO_FLAGS_DI_* */
uint64_t flags; uint64_t flags;
/** offset of the device-to-host queue in shared memory region */ /** offset of the device-to-host queue in shared memory region */
uint64_t d2h_offset; uint64_t d2h_offset;
/** size of an entry in the device-to-host queue in bytes */ /** size of an entry in the device-to-host queue in bytes */
uint64_t d2h_elen; uint64_t d2h_elen;
/** total device-to-host queue length in #entries */ /** total device-to-host queue length in #entries */
uint64_t d2h_nentries; uint64_t d2h_nentries;
/** offset of the host-to-device queue in shared memory region */ /** offset of the host-to-device queue in shared memory region */
uint64_t h2d_offset; uint64_t h2d_offset;
/** size of an entry in the host-to-device queue in bytes */ /** size of an entry in the host-to-device queue in bytes */
uint64_t h2d_elen; uint64_t h2d_elen;
/** total host-to-device queue length in #entries */ /** total host-to-device queue length in #entries */
uint64_t h2d_nentries; uint64_t h2d_nentries;
/** information for each BAR exposed by the device */ /** information for each BAR exposed by the device */
struct { struct {
/** length of the bar in bytes (len = 0 indicates unused bar) */ /** length of the bar in bytes (len = 0 indicates unused bar) */
uint64_t len; uint64_t len;
/** flags (see COSIM_PCIE_PROTO_BAR_*) */ /** flags (see COSIM_PCIE_PROTO_BAR_*) */
uint64_t flags; uint64_t flags;
} __attribute__((packed)) bars[COSIM_PCIE_PROTO_NBARS]; } __attribute__((packed)) bars[COSIM_PCIE_PROTO_NBARS];
/** PCI vendor id */ /** PCI vendor id */
uint16_t pci_vendor_id; uint16_t pci_vendor_id;
/** PCI device id */ /** PCI device id */
uint16_t pci_device_id; uint16_t pci_device_id;
/* PCI class */ /* PCI class */
uint8_t pci_class; uint8_t pci_class;
/* PCI subclass */ /* PCI subclass */
uint8_t pci_subclass; uint8_t pci_subclass;
/* PCI revision */ /* PCI revision */
uint8_t pci_revision; uint8_t pci_revision;
/* PCI number of MSI vectors */ /* PCI number of MSI vectors */
uint8_t pci_msi_nvecs; uint8_t pci_msi_nvecs;
/* PCI number of MSI-X vectors */ /* PCI number of MSI-X vectors */
uint16_t pci_msix_nvecs; uint16_t pci_msix_nvecs;
/* BAR number for MSI-X table */ /* BAR number for MSI-X table */
uint8_t pci_msix_table_bar; uint8_t pci_msix_table_bar;
/* BAR number for MSI-X PBA */ /* BAR number for MSI-X PBA */
uint8_t pci_msix_pba_bar; uint8_t pci_msix_pba_bar;
/* Offset for MSI-X table */ /* Offset for MSI-X table */
uint32_t pci_msix_table_offset; uint32_t pci_msix_table_offset;
/* Offset for MSI-X PBA */ /* Offset for MSI-X PBA */
uint32_t pci_msix_pba_offset; uint32_t pci_msix_pba_offset;
/* MSI-X capability offset */ /* MSI-X capability offset */
uint16_t psi_msix_cap_offset; uint16_t psi_msix_cap_offset;
} __attribute__((packed)); } __attribute__((packed));
#define COSIM_PCIE_PROTO_FLAGS_HI_SYNC (1 << 0) #define COSIM_PCIE_PROTO_FLAGS_HI_SYNC (1 << 0)
/** welcome message sent by host to device */ /** welcome message sent by host to device */
struct cosim_pcie_proto_host_intro { struct cosim_pcie_proto_host_intro {
/** flags: see COSIM_PCIE_PROTO_FLAGS_HI_* */ /** flags: see COSIM_PCIE_PROTO_FLAGS_HI_* */
uint64_t flags; uint64_t flags;
} __attribute__((packed)); } __attribute__((packed));
/******************************************************************************/ /******************************************************************************/
/* Messages on in-memory device to host channel */ /* Messages on in-memory device to host channel */
...@@ -138,41 +136,41 @@ struct cosim_pcie_proto_host_intro { ...@@ -138,41 +136,41 @@ struct cosim_pcie_proto_host_intro {
#define COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP 0x6 #define COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP 0x6
struct cosim_pcie_proto_d2h_dummy { struct cosim_pcie_proto_d2h_dummy {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_dummy); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_dummy);
struct cosim_pcie_proto_d2h_sync { struct cosim_pcie_proto_d2h_sync {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_sync); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_sync);
struct cosim_pcie_proto_d2h_read { struct cosim_pcie_proto_d2h_read {
uint64_t req_id; uint64_t req_id;
uint64_t offset; uint64_t offset;
uint16_t len; uint16_t len;
uint8_t pad[30]; uint8_t pad[30];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_read); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_read);
struct cosim_pcie_proto_d2h_write { struct cosim_pcie_proto_d2h_write {
uint64_t req_id; uint64_t req_id;
uint64_t offset; uint64_t offset;
uint16_t len; uint16_t len;
uint8_t pad[30]; uint8_t pad[30];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
uint8_t data[]; uint8_t data[];
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_write); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_write);
...@@ -182,46 +180,45 @@ COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_write); ...@@ -182,46 +180,45 @@ COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_write);
#define COSIM_PCIE_PROTO_INT_MSIX 3 #define COSIM_PCIE_PROTO_INT_MSIX 3
struct cosim_pcie_proto_d2h_interrupt { struct cosim_pcie_proto_d2h_interrupt {
uint16_t vector; uint16_t vector;
uint8_t inttype; uint8_t inttype;
uint8_t pad[45]; uint8_t pad[45];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_interrupt); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_interrupt);
struct cosim_pcie_proto_d2h_readcomp { struct cosim_pcie_proto_d2h_readcomp {
uint64_t req_id; uint64_t req_id;
uint8_t pad[40]; uint8_t pad[40];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
uint8_t data[]; uint8_t data[];
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_readcomp); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_readcomp);
struct cosim_pcie_proto_d2h_writecomp { struct cosim_pcie_proto_d2h_writecomp {
uint64_t req_id; uint64_t req_id;
uint8_t pad[40]; uint8_t pad[40];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_writecomp); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_writecomp);
union cosim_pcie_proto_d2h { union cosim_pcie_proto_d2h {
struct cosim_pcie_proto_d2h_dummy dummy; struct cosim_pcie_proto_d2h_dummy dummy;
struct cosim_pcie_proto_d2h_sync sync; struct cosim_pcie_proto_d2h_sync sync;
struct cosim_pcie_proto_d2h_read read; struct cosim_pcie_proto_d2h_read read;
struct cosim_pcie_proto_d2h_write write; struct cosim_pcie_proto_d2h_write write;
struct cosim_pcie_proto_d2h_interrupt interrupt; struct cosim_pcie_proto_d2h_interrupt interrupt;
struct cosim_pcie_proto_d2h_readcomp readcomp; struct cosim_pcie_proto_d2h_readcomp readcomp;
struct cosim_pcie_proto_d2h_writecomp writecomp; struct cosim_pcie_proto_d2h_writecomp writecomp;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_d2h); COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_d2h);
/******************************************************************************/ /******************************************************************************/
/* Messages on in-memory host to device channel */ /* Messages on in-memory host to device channel */
...@@ -240,62 +237,62 @@ COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_d2h); ...@@ -240,62 +237,62 @@ COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_d2h);
#define COSIM_PCIE_PROTO_H2D_MSG_DEVCTRL 0x7 #define COSIM_PCIE_PROTO_H2D_MSG_DEVCTRL 0x7
struct cosim_pcie_proto_h2d_dummy { struct cosim_pcie_proto_h2d_dummy {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_dummy); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_dummy);
struct cosim_pcie_proto_h2d_sync { struct cosim_pcie_proto_h2d_sync {
uint8_t pad[48]; uint8_t pad[48];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_sync); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_sync);
struct cosim_pcie_proto_h2d_read { struct cosim_pcie_proto_h2d_read {
uint64_t req_id; uint64_t req_id;
uint64_t offset; uint64_t offset;
uint16_t len; uint16_t len;
uint8_t bar; uint8_t bar;
uint8_t pad[29]; uint8_t pad[29];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_read); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_read);
struct cosim_pcie_proto_h2d_write { struct cosim_pcie_proto_h2d_write {
uint64_t req_id; uint64_t req_id;
uint64_t offset; uint64_t offset;
uint16_t len; uint16_t len;
uint8_t bar; uint8_t bar;
uint8_t pad[29]; uint8_t pad[29];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
uint8_t data[]; uint8_t data[];
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_write); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_write);
struct cosim_pcie_proto_h2d_readcomp { struct cosim_pcie_proto_h2d_readcomp {
uint64_t req_id; uint64_t req_id;
uint8_t pad[40]; uint8_t pad[40];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
uint8_t data[]; uint8_t data[];
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_readcomp); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_readcomp);
struct cosim_pcie_proto_h2d_writecomp { struct cosim_pcie_proto_h2d_writecomp {
uint64_t req_id; uint64_t req_id;
uint8_t pad[40]; uint8_t pad[40];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_writecomp); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_writecomp);
...@@ -303,22 +300,22 @@ COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_writecomp); ...@@ -303,22 +300,22 @@ COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_writecomp);
#define COSIM_PCIE_PROTO_CTRL_MSI_EN (1 << 1) #define COSIM_PCIE_PROTO_CTRL_MSI_EN (1 << 1)
#define COSIM_PCIE_PROTO_CTRL_MSIX_EN (1 << 2) #define COSIM_PCIE_PROTO_CTRL_MSIX_EN (1 << 2)
struct cosim_pcie_proto_h2d_devctrl { struct cosim_pcie_proto_h2d_devctrl {
uint64_t flags; uint64_t flags;
uint8_t pad[40]; uint8_t pad[40];
uint64_t timestamp; uint64_t timestamp;
uint8_t pad_[7]; uint8_t pad_[7];
uint8_t own_type; uint8_t own_type;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_devctrl); COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_devctrl);
union cosim_pcie_proto_h2d { union cosim_pcie_proto_h2d {
struct cosim_pcie_proto_h2d_dummy dummy; struct cosim_pcie_proto_h2d_dummy dummy;
struct cosim_pcie_proto_h2d_sync sync; struct cosim_pcie_proto_h2d_sync sync;
struct cosim_pcie_proto_h2d_read read; struct cosim_pcie_proto_h2d_read read;
struct cosim_pcie_proto_h2d_write write; struct cosim_pcie_proto_h2d_write write;
struct cosim_pcie_proto_h2d_readcomp readcomp; struct cosim_pcie_proto_h2d_readcomp readcomp;
struct cosim_pcie_proto_h2d_writecomp writecomp; struct cosim_pcie_proto_h2d_writecomp writecomp;
struct cosim_pcie_proto_h2d_devctrl devctrl; struct cosim_pcie_proto_h2d_devctrl devctrl;
} __attribute__((packed)); } __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_h2d); COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_h2d);
......
...@@ -22,15 +22,16 @@ ...@@ -22,15 +22,16 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <unistd.h>
#include <cassert>
#include <climits>
#include <csignal>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <csignal>
#include <climits>
#include <cstring> #include <cstring>
#include <unistd.h>
#include <vector>
#include <unordered_map> #include <unordered_map>
#include <cassert> #include <vector>
extern "C" { extern "C" {
#include <simbricks/netif/netsim.h> #include <simbricks/netif/netsim.h>
...@@ -41,31 +42,30 @@ static uint64_t eth_latency = (500 * 1000ULL); // 500ns ...@@ -41,31 +42,30 @@ static uint64_t eth_latency = (500 * 1000ULL); // 500ns
/* MAC address type */ /* MAC address type */
struct MAC { struct MAC {
const volatile uint8_t *data; const volatile uint8_t *data;
MAC(const volatile uint8_t *data) MAC(const volatile uint8_t *data) : data(data) {
: data(data) {} }
bool operator==(const MAC &other) const { bool operator==(const MAC &other) const {
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
if (data[i] != other.data[i]) { if (data[i] != other.data[i]) {
return false; return false;
} }
}
return true;
} }
return true;
}
}; };
namespace std { namespace std {
template <> template <>
struct hash<MAC> struct hash<MAC> {
{ size_t operator()(const MAC &m) const {
size_t operator()(const MAC &m) const {
size_t res = 0; size_t res = 0;
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
res = (res << 4) | (res ^ m.data[i]); res = (res << 4) | (res ^ m.data[i]);
} }
return res; return res;
} }
}; };
} // namespace std } // namespace std
...@@ -77,149 +77,145 @@ static const MAC bcast_addr(bcast); ...@@ -77,149 +77,145 @@ static const MAC bcast_addr(bcast);
static std::vector<struct netsim_interface> nsifs; static std::vector<struct netsim_interface> nsifs;
static std::unordered_map<MAC, int> mac_table; static std::unordered_map<MAC, int> mac_table;
static void sigint_handler(int dummy) static void sigint_handler(int dummy) {
{ exiting = 1;
exiting = 1;
} }
static void forward_pkt(volatile struct cosim_eth_proto_d2n_send *tx, int port) static void forward_pkt(volatile struct cosim_eth_proto_d2n_send *tx,
{ int port) {
volatile union cosim_eth_proto_n2d *msg_to; volatile union cosim_eth_proto_n2d *msg_to;
msg_to = netsim_n2d_alloc(&nsifs[port], cur_ts, eth_latency); msg_to = netsim_n2d_alloc(&nsifs[port], cur_ts, eth_latency);
if (msg_to != NULL) { if (msg_to != NULL) {
volatile struct cosim_eth_proto_n2d_recv *rx; volatile struct cosim_eth_proto_n2d_recv *rx;
rx = &msg_to->recv; rx = &msg_to->recv;
rx->len = tx->len; rx->len = tx->len;
rx->port = 0; rx->port = 0;
memcpy((void *)rx->data, (void *)tx->data, tx->len); memcpy((void *)rx->data, (void *)tx->data, tx->len);
// WMB(); // WMB();
rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV | rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV | COSIM_ETH_PROTO_N2D_OWN_DEV;
COSIM_ETH_PROTO_N2D_OWN_DEV; } else {
} else { fprintf(stderr, "forward_pkt: dropping packet\n");
fprintf(stderr, "forward_pkt: dropping packet\n"); }
}
} }
static void switch_pkt(struct netsim_interface *nsif, int iport) static void switch_pkt(struct netsim_interface *nsif, int iport) {
{ volatile union cosim_eth_proto_d2n *msg_from = netsim_d2n_poll(nsif, cur_ts);
volatile union cosim_eth_proto_d2n *msg_from = netsim_d2n_poll(nsif, if (msg_from == NULL) {
cur_ts); return;
if (msg_from == NULL) { }
return;
uint8_t type = msg_from->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK;
if (type == COSIM_ETH_PROTO_D2N_MSG_SEND) {
volatile struct cosim_eth_proto_d2n_send *tx;
tx = &msg_from->send;
// Get MAC addresses
MAC dst(tx->data), src(tx->data + 6);
// MAC learning
if (!(src == bcast_addr)) {
mac_table[src] = iport;
} }
// L2 forwarding
uint8_t type = msg_from->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK; if (mac_table.count(dst) > 0) {
if (type == COSIM_ETH_PROTO_D2N_MSG_SEND) { int eport = mac_table.at(dst);
volatile struct cosim_eth_proto_d2n_send *tx; forward_pkt(tx, eport);
tx = &msg_from->send;
// Get MAC addresses
MAC dst(tx->data), src(tx->data+6);
// MAC learning
if (!(src == bcast_addr)) {
mac_table[src] = iport;
}
// L2 forwarding
if (mac_table.count(dst) > 0) {
int eport = mac_table.at(dst);
forward_pkt(tx, eport);
} else {
// Broadcast
for (int eport = 0; eport < nsifs.size(); eport++) {
if (eport != iport) {
// Do not forward to ingress port
forward_pkt(tx, eport);
}
}
}
} else if (type == COSIM_ETH_PROTO_D2N_MSG_SYNC) {
} else { } else {
fprintf(stderr, "switch_pkt: unsupported type=%u\n", type); // Broadcast
abort(); for (int eport = 0; eport < nsifs.size(); eport++) {
if (eport != iport) {
// Do not forward to ingress port
forward_pkt(tx, eport);
}
}
} }
netsim_d2n_done(nsif, msg_from); } else if (type == COSIM_ETH_PROTO_D2N_MSG_SYNC) {
} else {
fprintf(stderr, "switch_pkt: unsupported type=%u\n", type);
abort();
}
netsim_d2n_done(nsif, msg_from);
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{ int c;
int c; int bad_option = 0;
int bad_option = 0; int sync_mode = SYNC_MODES;
int sync_mode = SYNC_MODES;
// Parse command line argument
// Parse command line argument while ((c = getopt(argc, argv, "s:S:E:m:")) != -1 && !bad_option) {
while ((c = getopt(argc, argv, "s:S:E:m:")) != -1 && !bad_option) { switch (c) {
switch (c) { case 's': {
case 's': { struct netsim_interface nsif;
struct netsim_interface nsif; int sync = 1;
int sync = 1; if (netsim_init(&nsif, optarg, &sync) != 0) {
if (netsim_init(&nsif, optarg, &sync) != 0) { fprintf(stderr, "connecting to %s failed\n", optarg);
fprintf(stderr, "connecting to %s failed\n", optarg); return EXIT_FAILURE;
return EXIT_FAILURE;
}
nsifs.push_back(nsif);
break;
}
case 'S':
sync_period = strtoull(optarg, NULL, 0) * 1000ULL;
break;
case 'E':
eth_latency = strtoull(optarg, NULL, 0) * 1000ULL;
break;
case 'm':
sync_mode = strtol(optarg, NULL, 0);
assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER);
break;
default:
fprintf(stderr, "unknown option %c\n", c);
bad_option = 1;
break;
} }
nsifs.push_back(nsif);
break;
}
case 'S':
sync_period = strtoull(optarg, NULL, 0) * 1000ULL;
break;
case 'E':
eth_latency = strtoull(optarg, NULL, 0) * 1000ULL;
break;
case 'm':
sync_mode = strtol(optarg, NULL, 0);
assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER);
break;
default:
fprintf(stderr, "unknown option %c\n", c);
bad_option = 1;
break;
} }
}
if (nsifs.empty() || bad_option) {
fprintf(stderr, "Usage: net_switch [-S SYNC-PERIOD] [-E ETH-LATENCY] " if (nsifs.empty() || bad_option) {
"-s SOCKET-A [-s SOCKET-B ...]\n"); fprintf(stderr,
return EXIT_FAILURE; "Usage: net_switch [-S SYNC-PERIOD] [-E ETH-LATENCY] "
"-s SOCKET-A [-s SOCKET-B ...]\n");
return EXIT_FAILURE;
}
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
printf("start polling\n");
while (!exiting) {
// Sync all interfaces
for (auto &nsif : nsifs) {
if (netsim_n2d_sync(&nsif, cur_ts, eth_latency, sync_period, sync_mode) !=
0) {
fprintf(stderr, "netsim_n2d_sync failed\n");
abort();
}
} }
netsim_advance_epoch(cur_ts, sync_period, sync_mode);
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler); // Switch packets
uint64_t min_ts;
printf("start polling\n"); do {
while (!exiting) { min_ts = ULLONG_MAX;
// Sync all interfaces for (int port = 0; port < nsifs.size(); port++) {
for (auto &nsif : nsifs) { auto &nsif = nsifs.at(port);
if (netsim_n2d_sync(&nsif, cur_ts, eth_latency, switch_pkt(&nsif, port);
sync_period, sync_mode) != 0) { if (nsif.sync) {
fprintf(stderr, "netsim_n2d_sync failed\n"); uint64_t ts = netsim_d2n_timestamp(&nsif);
abort(); min_ts = ts < min_ts ? ts : min_ts;
}
}
netsim_advance_epoch(cur_ts, sync_period, sync_mode);
// Switch packets
uint64_t min_ts;
do {
min_ts = ULLONG_MAX;
for (int port = 0; port < nsifs.size(); port++) {
auto &nsif = nsifs.at(port);
switch_pkt(&nsif, port);
if (nsif.sync) {
uint64_t ts = netsim_d2n_timestamp(&nsif);
min_ts = ts < min_ts ? ts : min_ts;
}
}
} while (!exiting && (min_ts <= cur_ts));
// Update cur_ts
if (min_ts < ULLONG_MAX) {
cur_ts = netsim_advance_time(min_ts, sync_period, sync_mode);
} }
}
} while (!exiting && (min_ts <= cur_ts));
// Update cur_ts
if (min_ts < ULLONG_MAX) {
cur_ts = netsim_advance_time(min_ts, sync_period, sync_mode);
} }
}
return 0; return 0;
} }
...@@ -23,15 +23,15 @@ ...@@ -23,15 +23,15 @@
*/ */
#include <fcntl.h> #include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <simbricks/netif/netsim.h> #include <simbricks/netif/netsim.h>
...@@ -40,119 +40,113 @@ ...@@ -40,119 +40,113 @@
static struct netsim_interface nsif; static struct netsim_interface nsif;
static int tap_fd; static int tap_fd;
static int tap_open(const char *name) static int tap_open(const char *name) {
{ struct ifreq ifr;
struct ifreq ifr; int fd;
int fd;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) { if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
perror("tap_open: open failed"); perror("tap_open: open failed");
return -1; return -1;
} }
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy(ifr.ifr_name, name, IFNAMSIZ); strncpy(ifr.ifr_name, name, IFNAMSIZ);
if (ioctl(fd, TUNSETIFF, &ifr) != 0) { if (ioctl(fd, TUNSETIFF, &ifr) != 0) {
perror("tap_open: ioctl failed"); perror("tap_open: ioctl failed");
close(fd); close(fd);
return -1; return -1;
} }
return fd; return fd;
} }
static void d2n_send(volatile struct cosim_eth_proto_d2n_send *s) static void d2n_send(volatile struct cosim_eth_proto_d2n_send *s) {
{
#ifdef DEBUG_PKTMETA #ifdef DEBUG_PKTMETA
printf("sent packet: len=%u\n", s->len); printf("sent packet: len=%u\n", s->len);
#endif #endif
if (write(tap_fd, (void *) s->data, s->len) != (ssize_t) s->len) { if (write(tap_fd, (void *)s->data, s->len) != (ssize_t)s->len) {
perror("d2n_send: send failed"); perror("d2n_send: send failed");
} }
} }
static void poll_d2n(void) static void poll_d2n(void) {
{ volatile union cosim_eth_proto_d2n *msg = netsim_d2n_poll(&nsif, 0);
volatile union cosim_eth_proto_d2n *msg = netsim_d2n_poll(&nsif, 0); uint8_t type;
uint8_t type;
/* message not ready */ /* message not ready */
if (msg == NULL) if (msg == NULL)
return; return;
type = msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK; type = msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK;
switch (type) { switch (type) {
case COSIM_ETH_PROTO_D2N_MSG_SEND: case COSIM_ETH_PROTO_D2N_MSG_SEND:
d2n_send(&msg->send); d2n_send(&msg->send);
break; break;
default: default:
fprintf(stderr, "poll_d2n: unsupported type=%u\n", type); fprintf(stderr, "poll_d2n: unsupported type=%u\n", type);
} }
netsim_d2n_done(&nsif, msg); netsim_d2n_done(&nsif, msg);
} }
static void *rx_handler(void *arg) static void *rx_handler(void *arg) {
{ volatile union cosim_eth_proto_n2d *msg;
volatile union cosim_eth_proto_n2d *msg; volatile struct cosim_eth_proto_n2d_recv *rx;
volatile struct cosim_eth_proto_n2d_recv *rx; ssize_t len;
ssize_t len;
while (1) {
msg = netsim_n2d_alloc(&nsif, 0, 0);
if (msg == NULL) {
fprintf(stderr, "coudl not allocate message for rx\n");
abort();
}
rx = &msg->recv;
len = read(tap_fd, (void *) rx->data, nsif.n2d_elen - sizeof(*msg));
if (len <= 0) {
perror("rx handler: read failed");
}
rx->len = len;
rx->port = 0;
#ifdef DEBUG_PKTMETA
printf("received packet: len=%u\n", rx->len);
#endif
// WMB(); while (1) {
rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV | msg = netsim_n2d_alloc(&nsif, 0, 0);
COSIM_ETH_PROTO_N2D_OWN_DEV; if (msg == NULL) {
} fprintf(stderr, "coudl not allocate message for rx\n");
} abort();
int main(int argc, char *argv[])
{
int sync;
if (argc != 3) {
fprintf(stderr, "Usage: net_tap TAP_DEVICE_NAME SOCKET\n");
return EXIT_FAILURE;
}
if ((tap_fd = tap_open(argv[1])) < 0) {
return -1;
} }
rx = &msg->recv;
sync = 0; len = read(tap_fd, (void *)rx->data, nsif.n2d_elen - sizeof(*msg));
if (netsim_init(&nsif, argv[2], &sync) != 0) { if (len <= 0) {
close(tap_fd); perror("rx handler: read failed");
return -1;
} }
rx->len = len;
rx->port = 0;
#ifdef DEBUG_PKTMETA
printf("received packet: len=%u\n", rx->len);
#endif
pthread_t worker; // WMB();
if (pthread_create(&worker, NULL, rx_handler, NULL) != 0) { rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV | COSIM_ETH_PROTO_N2D_OWN_DEV;
return EXIT_FAILURE; }
} }
printf("start polling\n"); int main(int argc, char *argv[]) {
while (1) { int sync;
poll_d2n();
} if (argc != 3) {
return 0; fprintf(stderr, "Usage: net_tap TAP_DEVICE_NAME SOCKET\n");
return EXIT_FAILURE;
}
if ((tap_fd = tap_open(argv[1])) < 0) {
return -1;
}
sync = 0;
if (netsim_init(&nsif, argv[2], &sync) != 0) {
close(tap_fd);
return -1;
}
pthread_t worker;
if (pthread_create(&worker, NULL, rx_handler, NULL) != 0) {
return EXIT_FAILURE;
}
printf("start polling\n");
while (1) {
poll_d2n();
}
return 0;
} }
...@@ -22,19 +22,19 @@ ...@@ -22,19 +22,19 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <assert.h>
#include <fcntl.h> #include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <pcap/pcap.h>
#include <pthread.h> #include <pthread.h>
#include <stdlib.h> #include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <signal.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <pcap/pcap.h>
#include <assert.h>
#include <simbricks/netif/netsim.h> #include <simbricks/netif/netsim.h>
...@@ -44,147 +44,141 @@ static uint64_t cur_ts; ...@@ -44,147 +44,141 @@ static uint64_t cur_ts;
static int exiting = 0; static int exiting = 0;
static pcap_dumper_t *dumpfile = NULL; static pcap_dumper_t *dumpfile = NULL;
static void sigint_handler(int dummy) static void sigint_handler(int dummy) {
{ exiting = 1;
exiting = 1;
} }
static void sigusr1_handler(int dummy) static void sigusr1_handler(int dummy) {
{ fprintf(stderr, "main_time = %lu\n", cur_ts);
fprintf(stderr, "main_time = %lu\n", cur_ts);
} }
static void move_pkt(struct netsim_interface *from, struct netsim_interface *to) static void move_pkt(struct netsim_interface *from,
{ struct netsim_interface *to) {
volatile union cosim_eth_proto_d2n *msg_from = volatile union cosim_eth_proto_d2n *msg_from = netsim_d2n_poll(from, cur_ts);
netsim_d2n_poll(from, cur_ts); volatile union cosim_eth_proto_n2d *msg_to;
volatile union cosim_eth_proto_n2d *msg_to; volatile struct cosim_eth_proto_d2n_send *tx;
volatile struct cosim_eth_proto_d2n_send *tx; volatile struct cosim_eth_proto_n2d_recv *rx;
volatile struct cosim_eth_proto_n2d_recv *rx; struct pcap_pkthdr ph;
struct pcap_pkthdr ph; uint8_t type;
uint8_t type;
if (msg_from == NULL)
if (msg_from == NULL) return;
return;
type = msg_from->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK;
type = msg_from->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK; if (type == COSIM_ETH_PROTO_D2N_MSG_SEND) {
if (type == COSIM_ETH_PROTO_D2N_MSG_SEND) { tx = &msg_from->send;
tx = &msg_from->send;
// log to pcap file if initialized
// log to pcap file if initialized if (dumpfile) {
if (dumpfile) { memset(&ph, 0, sizeof(ph));
memset(&ph, 0, sizeof(ph)); ph.ts.tv_sec = cur_ts / 1000000000000ULL;
ph.ts.tv_sec = cur_ts / 1000000000000ULL; ph.ts.tv_usec = (cur_ts % 1000000000000ULL) / 1000ULL;
ph.ts.tv_usec = (cur_ts % 1000000000000ULL) / 1000ULL; ph.caplen = tx->len;
ph.caplen = tx->len; ph.len = tx->len;
ph.len = tx->len; pcap_dump((unsigned char *)dumpfile, &ph, (unsigned char *)tx->data);
pcap_dump((unsigned char *) dumpfile, &ph,
(unsigned char *) tx->data);
}
msg_to = netsim_n2d_alloc(to, cur_ts, eth_latency);
if (msg_to != NULL) {
rx = &msg_to->recv;
rx->len = tx->len;
rx->port = 0;
memcpy((void *) rx->data, (void *) tx->data, tx->len);
// WMB();
rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV |
COSIM_ETH_PROTO_N2D_OWN_DEV;
} else {
fprintf(stderr, "move_pkt: dropping packet\n");
}
} else if (type == COSIM_ETH_PROTO_D2N_MSG_SYNC) {
} else {
fprintf(stderr, "move_pkt: unsupported type=%u\n", type);
abort();
} }
netsim_d2n_done(from, msg_from); msg_to = netsim_n2d_alloc(to, cur_ts, eth_latency);
} if (msg_to != NULL) {
rx = &msg_to->recv;
rx->len = tx->len;
rx->port = 0;
memcpy((void *)rx->data, (void *)tx->data, tx->len);
int main(int argc, char *argv[]) // WMB();
{ rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV | COSIM_ETH_PROTO_N2D_OWN_DEV;
struct netsim_interface nsif_a, nsif_b; } else {
uint64_t ts_a, ts_b; fprintf(stderr, "move_pkt: dropping packet\n");
int sync_a, sync_b;
pcap_t *pc = NULL;
int sync_mode = SYNC_MODES;
if (argc < 3 && argc > 7) {
fprintf(stderr, "Usage: net_wire SOCKET-A SOCKET-B [SYNC-MODE] "
"[SYNC-PERIOD] [ETH-LATENCY] [PCAP-FILE]\n");
return EXIT_FAILURE;
} }
} else if (type == COSIM_ETH_PROTO_D2N_MSG_SYNC) {
} else {
fprintf(stderr, "move_pkt: unsupported type=%u\n", type);
abort();
}
signal(SIGINT, sigint_handler); netsim_d2n_done(from, msg_from);
signal(SIGTERM, sigint_handler); }
signal(SIGUSR1, sigusr1_handler);
if (argc >= 4)
sync_mode = strtol(argv[3], NULL, 0);
if (argc >= 5)
sync_period = strtoull(argv[4], NULL, 0) * 1000ULL;
if (argc >= 6)
eth_latency = strtoull(argv[5], NULL, 0) * 1000ULL;
if (argc >= 7) {
pc = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, 65535,
PCAP_TSTAMP_PRECISION_NANO);
if (pc == NULL) {
perror("pcap_open_dead failed");
return EXIT_FAILURE;
}
dumpfile = pcap_dump_open(pc, argv[6]); int main(int argc, char *argv[]) {
struct netsim_interface nsif_a, nsif_b;
uint64_t ts_a, ts_b;
int sync_a, sync_b;
pcap_t *pc = NULL;
int sync_mode = SYNC_MODES;
if (argc < 3 && argc > 7) {
fprintf(stderr,
"Usage: net_wire SOCKET-A SOCKET-B [SYNC-MODE] "
"[SYNC-PERIOD] [ETH-LATENCY] [PCAP-FILE]\n");
return EXIT_FAILURE;
}
signal(SIGINT, sigint_handler);
signal(SIGTERM, sigint_handler);
signal(SIGUSR1, sigusr1_handler);
if (argc >= 4)
sync_mode = strtol(argv[3], NULL, 0);
if (argc >= 5)
sync_period = strtoull(argv[4], NULL, 0) * 1000ULL;
if (argc >= 6)
eth_latency = strtoull(argv[5], NULL, 0) * 1000ULL;
if (argc >= 7) {
pc = pcap_open_dead_with_tstamp_precision(DLT_EN10MB, 65535,
PCAP_TSTAMP_PRECISION_NANO);
if (pc == NULL) {
perror("pcap_open_dead failed");
return EXIT_FAILURE;
} }
assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER); dumpfile = pcap_dump_open(pc, argv[6]);
}
sync_a = sync_b = 1;
if (netsim_init(&nsif_a, argv[1], &sync_a) != 0) { assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER);
return -1;
sync_a = sync_b = 1;
if (netsim_init(&nsif_a, argv[1], &sync_a) != 0) {
return -1;
}
if (netsim_init(&nsif_b, argv[2], &sync_b) != 0) {
return -1;
}
printf("start polling\n");
while (!exiting) {
if (netsim_n2d_sync(&nsif_a, cur_ts, eth_latency, sync_period, sync_mode) !=
0) {
fprintf(stderr, "netsim_n2d_sync(nsif_a) failed\n");
abort();
} }
if (netsim_init(&nsif_b, argv[2], &sync_b) != 0) { if (netsim_n2d_sync(&nsif_b, cur_ts, eth_latency, sync_period, sync_mode) !=
return -1; 0) {
fprintf(stderr, "netsim_n2d_sync(nsif_a) failed\n");
abort();
} }
netsim_advance_epoch(cur_ts, sync_period, sync_mode);
printf("start polling\n");
while (!exiting) { do {
if (netsim_n2d_sync(&nsif_a, cur_ts, eth_latency, sync_period, move_pkt(&nsif_a, &nsif_b);
sync_mode) != 0) { move_pkt(&nsif_b, &nsif_a);
fprintf(stderr, "netsim_n2d_sync(nsif_a) failed\n"); ts_a = netsim_d2n_timestamp(&nsif_a);
abort(); ts_b = netsim_d2n_timestamp(&nsif_b);
} } while (!exiting &&
if (netsim_n2d_sync(&nsif_b, cur_ts, eth_latency, sync_period, ((sync_a && ts_a <= cur_ts) || (sync_b && ts_b <= cur_ts)));
sync_mode) != 0) {
fprintf(stderr, "netsim_n2d_sync(nsif_a) failed\n"); if (sync_a && sync_b)
abort(); cur_ts = netsim_advance_time(ts_a <= ts_b ? ts_a : ts_b, sync_period,
} sync_mode);
netsim_advance_epoch(cur_ts, sync_period, sync_mode); else if (sync_a)
cur_ts = netsim_advance_time(ts_a, sync_period, sync_mode);
do { else if (sync_b)
move_pkt(&nsif_a, &nsif_b); cur_ts = netsim_advance_time(ts_b, sync_period, sync_mode);
move_pkt(&nsif_b, &nsif_a); }
ts_a = netsim_d2n_timestamp(&nsif_a);
ts_b = netsim_d2n_timestamp(&nsif_b); if (dumpfile)
} while (!exiting && pcap_dump_close(dumpfile);
((sync_a && ts_a <= cur_ts) || return 0;
(sync_b && ts_b <= cur_ts)));
if (sync_a && sync_b)
cur_ts = netsim_advance_time(ts_a <= ts_b ? ts_a : ts_b,
sync_period, sync_mode);
else if (sync_a)
cur_ts = netsim_advance_time(ts_a, sync_period, sync_mode);
else if (sync_b)
cur_ts = netsim_advance_time(ts_b, sync_period, sync_mode);
}
if (dumpfile)
pcap_dump_close(dumpfile);
return 0;
} }
...@@ -26,8 +26,8 @@ ...@@ -26,8 +26,8 @@
#define COORD_H_ #define COORD_H_
#include <deque> #include <deque>
#include <map>
#include <iostream> #include <iostream>
#include <map>
#include "sims/nic/corundum/debug.h" #include "sims/nic/corundum/debug.h"
...@@ -39,116 +39,107 @@ void pci_msi_issue(uint8_t vec); ...@@ -39,116 +39,107 @@ void pci_msi_issue(uint8_t vec);
void pci_rwcomp_issue(MMIOOp *op); void pci_rwcomp_issue(MMIOOp *op);
class PCICoordinator { class PCICoordinator {
protected: protected:
struct PCIOp { struct PCIOp {
union { union {
DMAOp *dma_op; DMAOp *dma_op;
MMIOOp *mmio_op; MMIOOp *mmio_op;
uint32_t msi_vec; uint32_t msi_vec;
}; };
enum { enum {
OP_DMA, OP_DMA,
OP_MSI, OP_MSI,
OP_RWCOMP, OP_RWCOMP,
} type; } type;
bool ready; bool ready;
}; };
std::deque<PCIOp *> queue; std::deque<PCIOp *> queue;
std::map<DMAOp *, PCIOp *> dmamap; std::map<DMAOp *, PCIOp *> dmamap;
void process() void process() {
{ PCIOp *op;
PCIOp *op; while (!queue.empty()) {
while (!queue.empty()) { op = queue.front();
op = queue.front(); if (!op->ready)
if (!op->ready) break;
break;
queue.pop_front();
queue.pop_front(); if (op->type == PCIOp::OP_MSI) {
if (op->type == PCIOp::OP_MSI) {
#ifdef COORD_DEBUG #ifdef COORD_DEBUG
std::cout << main_time << " issuing msi " << op->msi_vec << std::cout << main_time << " issuing msi " << op->msi_vec << std::endl;
std::endl;
#endif #endif
pci_msi_issue(op->msi_vec); pci_msi_issue(op->msi_vec);
} else if (op->type == PCIOp::OP_DMA) { } else if (op->type == PCIOp::OP_DMA) {
#ifdef COORD_DEBUG #ifdef COORD_DEBUG
std::cout << main_time << " issuing dma " << op->dma_op << std::cout << main_time << " issuing dma " << op->dma_op << std::endl;
std::endl;
#endif #endif
pci_dma_issue(op->dma_op); pci_dma_issue(op->dma_op);
dmamap.erase(op->dma_op); dmamap.erase(op->dma_op);
} else if (op->type == PCIOp::OP_RWCOMP) { } else if (op->type == PCIOp::OP_RWCOMP) {
#ifdef COORD_DEBUG #ifdef COORD_DEBUG
std::cout << main_time << " issuing mmio " << op->mmio_op << std::cout << main_time << " issuing mmio " << op->mmio_op << std::endl;
std::endl;
#endif #endif
pci_rwcomp_issue(op->mmio_op); pci_rwcomp_issue(op->mmio_op);
} else { } else {
throw "unknown type"; throw "unknown type";
} }
delete op; delete op;
} }
} }
public: public:
void dma_register(DMAOp *dma_op, bool ready) void dma_register(DMAOp *dma_op, bool ready) {
{
#ifdef COORD_DEBUG #ifdef COORD_DEBUG
std::cout << main_time << " registering dma op " << dma_op << " " std::cout << main_time << " registering dma op " << dma_op << " " << ready
<< ready << std::endl; << std::endl;
#endif #endif
PCIOp *op = new PCIOp; PCIOp *op = new PCIOp;
op->dma_op = dma_op; op->dma_op = dma_op;
op->type = PCIOp::OP_DMA; op->type = PCIOp::OP_DMA;
op->ready = ready; op->ready = ready;
queue.push_back(op); queue.push_back(op);
dmamap[dma_op] = op; dmamap[dma_op] = op;
process(); process();
} }
void dma_mark_ready(DMAOp *op) void dma_mark_ready(DMAOp *op) {
{
#ifdef COORD_DEBUG #ifdef COORD_DEBUG
std::cout << main_time << " readying dma op " << op << std::endl; std::cout << main_time << " readying dma op " << op << std::endl;
#endif #endif
dmamap[op]->ready = true; dmamap[op]->ready = true;
process(); process();
} }
void msi_enqueue(uint32_t vec) void msi_enqueue(uint32_t vec) {
{
#ifdef COORD_DEBUG #ifdef COORD_DEBUG
std::cout << main_time << " enqueuing MSI " << vec << std::endl; std::cout << main_time << " enqueuing MSI " << vec << std::endl;
#endif #endif
PCIOp *op = new PCIOp; PCIOp *op = new PCIOp;
op->msi_vec = vec; op->msi_vec = vec;
op->type = PCIOp::OP_MSI; op->type = PCIOp::OP_MSI;
op->ready = true; op->ready = true;
queue.push_back(op); queue.push_back(op);
process(); process();
} }
void mmio_comp_enqueue(MMIOOp *mmio_op) void mmio_comp_enqueue(MMIOOp *mmio_op) {
{
#ifdef COORD_DEBUG #ifdef COORD_DEBUG
std::cout << main_time << " enqueuing MMIO comp " << mmio_op << std::cout << main_time << " enqueuing MMIO comp " << mmio_op << std::endl;
std::endl;
#endif #endif
PCIOp *op = new PCIOp; PCIOp *op = new PCIOp;
op->mmio_op = mmio_op; op->mmio_op = mmio_op;
op->type = PCIOp::OP_RWCOMP; op->type = PCIOp::OP_RWCOMP;
op->ready = true; op->ready = true;
queue.push_back(op); queue.push_back(op);
process(); process();
} }
}; };
#endif // COORD_H_ #endif // COORD_H_
...@@ -22,27 +22,26 @@ ...@@ -22,27 +22,26 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <iostream>
#include <deque>
#include <set>
#include <signal.h> #include <signal.h>
#include <verilated.h> #include <verilated.h>
#include <deque>
#include <iostream>
#include <set>
#ifdef TRACE_ENABLED #ifdef TRACE_ENABLED
#include <verilated_vcd_c.h> #include <verilated_vcd_c.h>
#endif #endif
extern "C" { extern "C" {
#include <simbricks/nicif/nicsim.h> #include <simbricks/nicif/nicsim.h>
} }
#include "sims/nic/corundum/obj_dir/Vinterface.h"
#include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/corundum.h"
#include "sims/nic/corundum/coord.h" #include "sims/nic/corundum/coord.h"
#include "sims/nic/corundum/corundum.h"
#include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/dma.h" #include "sims/nic/corundum/dma.h"
#include "sims/nic/corundum/mem.h" #include "sims/nic/corundum/mem.h"
#include "sims/nic/corundum/obj_dir/Vinterface.h"
struct DMAOp; struct DMAOp;
...@@ -51,354 +50,337 @@ static uint64_t sync_period = 500 * 1000ULL; // 500ns ...@@ -51,354 +50,337 @@ static uint64_t sync_period = 500 * 1000ULL; // 500ns
static uint64_t pci_latency = 500 * 1000ULL; // 500ns static uint64_t pci_latency = 500 * 1000ULL; // 500ns
static uint64_t eth_latency = 500 * 1000ULL; // 500ns static uint64_t eth_latency = 500 * 1000ULL; // 500ns
static volatile int exiting = 0; static volatile int exiting = 0;
uint64_t main_time = 0; uint64_t main_time = 0;
static struct nicsim_params nsparams; static struct nicsim_params nsparams;
#ifdef TRACE_ENABLED #ifdef TRACE_ENABLED
static VerilatedVcdC* trace; static VerilatedVcdC *trace;
#endif #endif
static volatile union cosim_pcie_proto_d2h *d2h_alloc(void); static volatile union cosim_pcie_proto_d2h *d2h_alloc(void);
static void sigint_handler(int dummy) {
static void sigint_handler(int dummy) exiting = 1;
{
exiting = 1;
} }
static void sigusr1_handler(int dummy) static void sigusr1_handler(int dummy) {
{ fprintf(stderr, "main_time = %lu\n", main_time);
fprintf(stderr, "main_time = %lu\n", main_time);
} }
double sc_time_stamp() double sc_time_stamp() {
{ return main_time;
return main_time;
} }
static void reset_inputs(Vinterface *top) static void reset_inputs(Vinterface *top) {
{ top->clk = 0;
top->clk = 0; top->rst = 0;
top->rst = 0; top->m_axis_ctrl_dma_read_desc_ready = 0;
top->m_axis_ctrl_dma_read_desc_ready = 0; top->s_axis_ctrl_dma_read_desc_status_tag = 0;
top->s_axis_ctrl_dma_read_desc_status_tag = 0; top->s_axis_ctrl_dma_read_desc_status_valid = 0;
top->s_axis_ctrl_dma_read_desc_status_valid = 0; top->m_axis_ctrl_dma_write_desc_ready = 0;
top->m_axis_ctrl_dma_write_desc_ready = 0; top->s_axis_ctrl_dma_write_desc_status_tag = 0;
top->s_axis_ctrl_dma_write_desc_status_tag = 0; top->s_axis_ctrl_dma_write_desc_status_valid = 0;
top->s_axis_ctrl_dma_write_desc_status_valid = 0; top->m_axis_data_dma_read_desc_ready = 0;
top->m_axis_data_dma_read_desc_ready = 0; top->s_axis_data_dma_read_desc_status_tag = 0;
top->s_axis_data_dma_read_desc_status_tag = 0; top->s_axis_data_dma_read_desc_status_valid = 0;
top->s_axis_data_dma_read_desc_status_valid = 0; top->m_axis_data_dma_write_desc_ready = 0;
top->m_axis_data_dma_write_desc_ready = 0; top->s_axis_data_dma_write_desc_status_tag = 0;
top->s_axis_data_dma_write_desc_status_tag = 0; top->s_axis_data_dma_write_desc_status_valid = 0;
top->s_axis_data_dma_write_desc_status_valid = 0; top->s_axil_awaddr = 0;
top->s_axil_awaddr = 0; top->s_axil_awprot = 0;
top->s_axil_awprot = 0; top->s_axil_awvalid = 0;
top->s_axil_awvalid = 0; top->s_axil_wdata = 0;
top->s_axil_wdata = 0; top->s_axil_wstrb = 0;
top->s_axil_wstrb = 0; top->s_axil_wvalid = 0;
top->s_axil_wvalid = 0; top->s_axil_bready = 0;
top->s_axil_bready = 0; top->s_axil_araddr = 0;
top->s_axil_araddr = 0; top->s_axil_arprot = 0;
top->s_axil_arprot = 0; top->s_axil_arvalid = 0;
top->s_axil_arvalid = 0; top->s_axil_rready = 0;
top->s_axil_rready = 0; top->m_axil_csr_awready = 0;
top->m_axil_csr_awready = 0; top->m_axil_csr_wready = 0;
top->m_axil_csr_wready = 0; top->m_axil_csr_bresp = 0;
top->m_axil_csr_bresp = 0; top->m_axil_csr_bvalid = 0;
top->m_axil_csr_bvalid = 0; top->m_axil_csr_arready = 0;
top->m_axil_csr_arready = 0; top->m_axil_csr_rdata = 0;
top->m_axil_csr_rdata = 0; top->m_axil_csr_rresp = 0;
top->m_axil_csr_rresp = 0; top->m_axil_csr_rvalid = 0;
top->m_axil_csr_rvalid = 0; top->ctrl_dma_ram_wr_cmd_sel = 0;
top->ctrl_dma_ram_wr_cmd_sel = 0; // top->ctrl_dma_ram_wr_cmd_be = 0;
// top->ctrl_dma_ram_wr_cmd_be = 0; // top->ctrl_dma_ram_wr_cmd_addr = 0;
// top->ctrl_dma_ram_wr_cmd_addr = 0; top->ctrl_dma_ram_wr_cmd_valid = 0;
top->ctrl_dma_ram_wr_cmd_valid = 0; top->ctrl_dma_ram_rd_cmd_sel = 0;
top->ctrl_dma_ram_rd_cmd_sel = 0; // top->ctrl_dma_ram_rd_cmd_addr = 0;
// top->ctrl_dma_ram_rd_cmd_addr = 0; top->ctrl_dma_ram_rd_cmd_valid = 0;
top->ctrl_dma_ram_rd_cmd_valid = 0; top->ctrl_dma_ram_rd_resp_ready = 0;
top->ctrl_dma_ram_rd_resp_ready = 0; top->data_dma_ram_wr_cmd_sel = 0;
top->data_dma_ram_wr_cmd_sel = 0; // top->data_dma_ram_wr_cmd_be = 0;
// top->data_dma_ram_wr_cmd_be = 0; // top->data_dma_ram_wr_cmd_addr = 0;
// top->data_dma_ram_wr_cmd_addr = 0; top->data_dma_ram_wr_cmd_valid = 0;
top->data_dma_ram_wr_cmd_valid = 0; top->data_dma_ram_rd_cmd_sel = 0;
top->data_dma_ram_rd_cmd_sel = 0; // top->data_dma_ram_rd_cmd_addr = 0;
// top->data_dma_ram_rd_cmd_addr = 0; top->data_dma_ram_rd_cmd_valid = 0;
top->data_dma_ram_rd_cmd_valid = 0; top->data_dma_ram_rd_resp_ready = 0;
top->data_dma_ram_rd_resp_ready = 0; top->tx_axis_tready = 0;
top->tx_axis_tready = 0; top->s_axis_tx_ptp_ts_valid = 0;
top->s_axis_tx_ptp_ts_valid = 0; top->rx_axis_tkeep = 0;
top->rx_axis_tkeep = 0; top->rx_axis_tvalid = 0;
top->rx_axis_tvalid = 0; top->rx_axis_tlast = 0;
top->rx_axis_tlast = 0; top->rx_axis_tuser = 0;
top->rx_axis_tuser = 0; top->s_axis_rx_ptp_ts_valid = 0;
top->s_axis_rx_ptp_ts_valid = 0; top->ptp_ts_step = 0;
top->ptp_ts_step = 0;
} }
static void report_output(const char *label, uint64_t val) static void report_output(const char *label, uint64_t val) {
{ if (val == 0)
if (val == 0) return;
return;
std::cout << " " << label << " = " << val << std::endl; std::cout << " " << label << " = " << val << std::endl;
} }
static void report_outputs(Vinterface *top) static void report_outputs(Vinterface *top) {
{ report_output("m_axis_ctrl_dma_read_desc_dma_addr",
report_output("m_axis_ctrl_dma_read_desc_dma_addr", top->m_axis_ctrl_dma_read_desc_dma_addr);
top->m_axis_ctrl_dma_read_desc_dma_addr); report_output("m_axis_ctrl_dma_read_desc_ram_sel",
report_output("m_axis_ctrl_dma_read_desc_ram_sel", top->m_axis_ctrl_dma_read_desc_ram_sel);
top->m_axis_ctrl_dma_read_desc_ram_sel); report_output("m_axis_ctrl_dma_read_desc_ram_addr",
report_output("m_axis_ctrl_dma_read_desc_ram_addr", top->m_axis_ctrl_dma_read_desc_ram_addr);
top->m_axis_ctrl_dma_read_desc_ram_addr); report_output("m_axis_ctrl_dma_read_desc_len",
report_output("m_axis_ctrl_dma_read_desc_len", top->m_axis_ctrl_dma_read_desc_len);
top->m_axis_ctrl_dma_read_desc_len); report_output("m_axis_ctrl_dma_read_desc_tag",
report_output("m_axis_ctrl_dma_read_desc_tag", top->m_axis_ctrl_dma_read_desc_tag);
top->m_axis_ctrl_dma_read_desc_tag); report_output("m_axis_ctrl_dma_read_desc_valid",
report_output("m_axis_ctrl_dma_read_desc_valid", top->m_axis_ctrl_dma_read_desc_valid);
top->m_axis_ctrl_dma_read_desc_valid); report_output("m_axis_ctrl_dma_write_desc_dma_addr",
report_output("m_axis_ctrl_dma_write_desc_dma_addr", top->m_axis_ctrl_dma_write_desc_dma_addr);
top->m_axis_ctrl_dma_write_desc_dma_addr); report_output("m_axis_ctrl_dma_write_desc_ram_sel",
report_output("m_axis_ctrl_dma_write_desc_ram_sel", top->m_axis_ctrl_dma_write_desc_ram_sel);
top->m_axis_ctrl_dma_write_desc_ram_sel); report_output("m_axis_ctrl_dma_write_desc_ram_addr",
report_output("m_axis_ctrl_dma_write_desc_ram_addr", top->m_axis_ctrl_dma_write_desc_ram_addr);
top->m_axis_ctrl_dma_write_desc_ram_addr); report_output("m_axis_ctrl_dma_write_desc_len",
report_output("m_axis_ctrl_dma_write_desc_len", top->m_axis_ctrl_dma_write_desc_len);
top->m_axis_ctrl_dma_write_desc_len); report_output("m_axis_ctrl_dma_write_desc_tag",
report_output("m_axis_ctrl_dma_write_desc_tag", top->m_axis_ctrl_dma_write_desc_tag);
top->m_axis_ctrl_dma_write_desc_tag); report_output("m_axis_ctrl_dma_write_desc_valid",
report_output("m_axis_ctrl_dma_write_desc_valid", top->m_axis_ctrl_dma_write_desc_valid);
top->m_axis_ctrl_dma_write_desc_valid); report_output("m_axis_data_dma_read_desc_dma_addr",
report_output("m_axis_data_dma_read_desc_dma_addr", top->m_axis_data_dma_read_desc_dma_addr);
top->m_axis_data_dma_read_desc_dma_addr); report_output("m_axis_data_dma_read_desc_ram_sel",
report_output("m_axis_data_dma_read_desc_ram_sel", top->m_axis_data_dma_read_desc_ram_sel);
top->m_axis_data_dma_read_desc_ram_sel); report_output("m_axis_data_dma_read_desc_ram_addr",
report_output("m_axis_data_dma_read_desc_ram_addr", top->m_axis_data_dma_read_desc_ram_addr);
top->m_axis_data_dma_read_desc_ram_addr); report_output("m_axis_data_dma_read_desc_len",
report_output("m_axis_data_dma_read_desc_len", top->m_axis_data_dma_read_desc_len);
top->m_axis_data_dma_read_desc_len); report_output("m_axis_data_dma_read_desc_tag",
report_output("m_axis_data_dma_read_desc_tag", top->m_axis_data_dma_read_desc_tag);
top->m_axis_data_dma_read_desc_tag); report_output("m_axis_data_dma_read_desc_valid",
report_output("m_axis_data_dma_read_desc_valid", top->m_axis_data_dma_read_desc_valid);
top->m_axis_data_dma_read_desc_valid); report_output("m_axis_data_dma_write_desc_dma_addr",
report_output("m_axis_data_dma_write_desc_dma_addr", top->m_axis_data_dma_write_desc_dma_addr);
top->m_axis_data_dma_write_desc_dma_addr); report_output("m_axis_data_dma_write_desc_ram_sel",
report_output("m_axis_data_dma_write_desc_ram_sel", top->m_axis_data_dma_write_desc_ram_sel);
top->m_axis_data_dma_write_desc_ram_sel); report_output("m_axis_data_dma_write_desc_ram_addr",
report_output("m_axis_data_dma_write_desc_ram_addr", top->m_axis_data_dma_write_desc_ram_addr);
top->m_axis_data_dma_write_desc_ram_addr); report_output("m_axis_data_dma_write_desc_len",
report_output("m_axis_data_dma_write_desc_len", top->m_axis_data_dma_write_desc_len);
top->m_axis_data_dma_write_desc_len); report_output("m_axis_data_dma_write_desc_tag",
report_output("m_axis_data_dma_write_desc_tag", top->m_axis_data_dma_write_desc_tag);
top->m_axis_data_dma_write_desc_tag); report_output("m_axis_data_dma_write_desc_valid",
report_output("m_axis_data_dma_write_desc_valid", top->m_axis_data_dma_write_desc_valid);
top->m_axis_data_dma_write_desc_valid); report_output("s_axil_awready", top->s_axil_awready);
report_output("s_axil_awready", top->s_axil_awready); report_output("s_axil_wready", top->s_axil_wready);
report_output("s_axil_wready", top->s_axil_wready); report_output("s_axil_bresp", top->s_axil_bresp);
report_output("s_axil_bresp", top->s_axil_bresp); report_output("s_axil_bvalid", top->s_axil_bvalid);
report_output("s_axil_bvalid", top->s_axil_bvalid); report_output("s_axil_arready", top->s_axil_arready);
report_output("s_axil_arready", top->s_axil_arready); report_output("s_axil_rdata", top->s_axil_rdata);
report_output("s_axil_rdata", top->s_axil_rdata); report_output("s_axil_rresp", top->s_axil_rresp);
report_output("s_axil_rresp", top->s_axil_rresp); report_output("s_axil_rvalid", top->s_axil_rvalid);
report_output("s_axil_rvalid", top->s_axil_rvalid); report_output("m_axil_csr_awaddr", top->m_axil_csr_awaddr);
report_output("m_axil_csr_awaddr", top->m_axil_csr_awaddr); report_output("m_axil_csr_awprot", top->m_axil_csr_awprot);
report_output("m_axil_csr_awprot", top->m_axil_csr_awprot); report_output("m_axil_csr_awvalid", top->m_axil_csr_awvalid);
report_output("m_axil_csr_awvalid", top->m_axil_csr_awvalid); report_output("m_axil_csr_wdata", top->m_axil_csr_wdata);
report_output("m_axil_csr_wdata", top->m_axil_csr_wdata); report_output("m_axil_csr_wstrb", top->m_axil_csr_wstrb);
report_output("m_axil_csr_wstrb", top->m_axil_csr_wstrb); report_output("m_axil_csr_wvalid", top->m_axil_csr_wvalid);
report_output("m_axil_csr_wvalid", top->m_axil_csr_wvalid); report_output("m_axil_csr_bready", top->m_axil_csr_bready);
report_output("m_axil_csr_bready", top->m_axil_csr_bready); report_output("m_axil_csr_araddr", top->m_axil_csr_araddr);
report_output("m_axil_csr_araddr", top->m_axil_csr_araddr); report_output("m_axil_csr_arprot", top->m_axil_csr_arprot);
report_output("m_axil_csr_arprot", top->m_axil_csr_arprot); report_output("m_axil_csr_arvalid", top->m_axil_csr_arvalid);
report_output("m_axil_csr_arvalid", top->m_axil_csr_arvalid); report_output("m_axil_csr_rready", top->m_axil_csr_rready);
report_output("m_axil_csr_rready", top->m_axil_csr_rready); report_output("ctrl_dma_ram_wr_cmd_ready", top->ctrl_dma_ram_wr_cmd_ready);
report_output("ctrl_dma_ram_wr_cmd_ready", top->ctrl_dma_ram_wr_cmd_ready); report_output("ctrl_dma_ram_rd_cmd_ready", top->ctrl_dma_ram_rd_cmd_ready);
report_output("ctrl_dma_ram_rd_cmd_ready", top->ctrl_dma_ram_rd_cmd_ready); report_output("ctrl_dma_ram_rd_resp_valid", top->ctrl_dma_ram_rd_resp_valid);
report_output("ctrl_dma_ram_rd_resp_valid", report_output("data_dma_ram_wr_cmd_ready", top->data_dma_ram_wr_cmd_ready);
top->ctrl_dma_ram_rd_resp_valid); report_output("data_dma_ram_rd_cmd_ready", top->data_dma_ram_rd_cmd_ready);
report_output("data_dma_ram_wr_cmd_ready", top->data_dma_ram_wr_cmd_ready); report_output("data_dma_ram_rd_resp_valid", top->data_dma_ram_rd_resp_valid);
report_output("data_dma_ram_rd_cmd_ready", top->data_dma_ram_rd_cmd_ready); report_output("tx_axis_tkeep", top->tx_axis_tkeep);
report_output("data_dma_ram_rd_resp_valid", report_output("tx_axis_tvalid", top->tx_axis_tvalid);
top->data_dma_ram_rd_resp_valid); report_output("tx_axis_tlast", top->tx_axis_tlast);
report_output("tx_axis_tkeep", top->tx_axis_tkeep); report_output("tx_axis_tuser", top->tx_axis_tuser);
report_output("tx_axis_tvalid", top->tx_axis_tvalid); report_output("s_axis_tx_ptp_ts_ready", top->s_axis_tx_ptp_ts_ready);
report_output("tx_axis_tlast", top->tx_axis_tlast); report_output("rx_axis_tready", top->rx_axis_tready);
report_output("tx_axis_tuser", top->tx_axis_tuser); report_output("s_axis_rx_ptp_ts_ready", top->s_axis_rx_ptp_ts_ready);
report_output("s_axis_tx_ptp_ts_ready", top->s_axis_tx_ptp_ts_ready); report_output("msi_irq", top->msi_irq);
report_output("rx_axis_tready", top->rx_axis_tready);
report_output("s_axis_rx_ptp_ts_ready", top->s_axis_rx_ptp_ts_ready);
report_output("msi_irq", top->msi_irq);
} }
struct MMIOOp { struct MMIOOp {
uint64_t id; uint64_t id;
uint64_t addr; uint64_t addr;
uint64_t value; uint64_t value;
size_t len; size_t len;
bool isWrite; bool isWrite;
}; };
class MMIOInterface { class MMIOInterface {
protected: protected:
enum OpState { enum OpState {
AddrIssued, AddrIssued,
AddrAcked, AddrAcked,
AddrDone, AddrDone,
}; };
Vinterface &top; Vinterface &top;
PCICoordinator &coord; PCICoordinator &coord;
std::deque<MMIOOp *> queue; std::deque<MMIOOp *> queue;
MMIOOp *rCur, *wCur; MMIOOp *rCur, *wCur;
enum OpState rState, wState; enum OpState rState, wState;
public: public:
MMIOInterface(Vinterface &top_, PCICoordinator &coord_) MMIOInterface(Vinterface &top_, PCICoordinator &coord_)
: top(top_), coord(coord_), rCur(0), wCur(0) : top(top_), coord(coord_), rCur(0), wCur(0) {
{ }
}
void step() {
void step() if (rCur) {
{ /* work on active read operation */
if (rCur) {
/* work on active read operation */ if (rState == AddrIssued && top.s_axil_arready) {
/* read handshake is complete */
if (rState == AddrIssued && top.s_axil_arready) { top.s_axil_arvalid = 0;
/* read handshake is complete */ rState = AddrAcked;
top.s_axil_arvalid = 0; }
rState = AddrAcked; if (rState == AddrAcked && top.s_axil_rvalid) {
} /* read data received */
if (rState == AddrAcked && top.s_axil_rvalid) { top.s_axil_rready = 0;
/* read data received */ rCur->value = top.s_axil_rdata;
top.s_axil_rready = 0; coord.mmio_comp_enqueue(rCur);
rCur->value = top.s_axil_rdata;
coord.mmio_comp_enqueue(rCur);
#ifdef MMIO_DEBUG #ifdef MMIO_DEBUG
std::cout << main_time << " MMIO: completed AXI read op=" << std::cout << main_time << " MMIO: completed AXI read op=" << rCur
rCur << " val=" << rCur->value << std::endl; << " val=" << rCur->value << std::endl;
#endif #endif
rCur = 0; rCur = 0;
} }
} else if (wCur) { } else if (wCur) {
/* work on active write operation */ /* work on active write operation */
if (wState == AddrIssued && top.s_axil_awready) { if (wState == AddrIssued && top.s_axil_awready) {
/* write addr handshake is complete */ /* write addr handshake is complete */
top.s_axil_awvalid = 0; top.s_axil_awvalid = 0;
wState = AddrAcked; wState = AddrAcked;
} }
if (wState == AddrAcked && top.s_axil_wready) { if (wState == AddrAcked && top.s_axil_wready) {
/* write data handshake is complete */ /* write data handshake is complete */
top.s_axil_wvalid = 0; top.s_axil_wvalid = 0;
top.s_axil_bready = 1; top.s_axil_bready = 1;
wState = AddrDone; wState = AddrDone;
} }
if (wState == AddrDone && top.s_axil_bvalid) { if (wState == AddrDone && top.s_axil_bvalid) {
/* write complete */ /* write complete */
top.s_axil_bready = 0; top.s_axil_bready = 0;
// TODO(antoinek): check top.s_axil_bresp // TODO(antoinek): check top.s_axil_bresp
#ifdef MMIO_DEBUG #ifdef MMIO_DEBUG
std::cout << main_time << " MMIO: completed AXI write op=" std::cout << main_time << " MMIO: completed AXI write op=" << wCur
<< wCur << std::endl; << std::endl;
#endif #endif
coord.mmio_comp_enqueue(wCur); coord.mmio_comp_enqueue(wCur);
wCur = 0; wCur = 0;
} }
} else if (/*!top.clk &&*/ !queue.empty()) { } else if (/*!top.clk &&*/ !queue.empty()) {
/* issue new operation */ /* issue new operation */
MMIOOp *op = queue.front(); MMIOOp *op = queue.front();
queue.pop_front(); queue.pop_front();
if (!op->isWrite) { if (!op->isWrite) {
/* issue new read */ /* issue new read */
rCur = op; rCur = op;
rState = AddrIssued; rState = AddrIssued;
top.s_axil_araddr = rCur->addr; top.s_axil_araddr = rCur->addr;
top.s_axil_arprot = 0x0; top.s_axil_arprot = 0x0;
top.s_axil_arvalid = 1; top.s_axil_arvalid = 1;
top.s_axil_rready = 1; top.s_axil_rready = 1;
} else { } else {
/* issue new write */ /* issue new write */
wCur = op; wCur = op;
wState = AddrIssued; wState = AddrIssued;
top.s_axil_awaddr = wCur->addr; top.s_axil_awaddr = wCur->addr;
top.s_axil_awprot = 0x0; top.s_axil_awprot = 0x0;
top.s_axil_awvalid = 1; top.s_axil_awvalid = 1;
top.s_axil_wdata = wCur->value; top.s_axil_wdata = wCur->value;
top.s_axil_wstrb = 0xf; top.s_axil_wstrb = 0xf;
top.s_axil_wvalid = 1; top.s_axil_wvalid = 1;
} }
} }
} }
void issueRead(uint64_t id, uint64_t addr, size_t len) void issueRead(uint64_t id, uint64_t addr, size_t len) {
{ MMIOOp *op = new MMIOOp;
MMIOOp *op = new MMIOOp;
#ifdef MMIO_DEBUG #ifdef MMIO_DEBUG
std::cout << main_time << " MMIO: read id=" << id << " addr=" << std::cout << main_time << " MMIO: read id=" << id << " addr=" << std::hex
std::hex << addr << " len=" << len << " op=" << op << std::endl; << addr << " len=" << len << " op=" << op << std::endl;
#endif #endif
op->id = id; op->id = id;
op->addr = addr; op->addr = addr;
op->len = len; op->len = len;
op->isWrite = false; op->isWrite = false;
queue.push_back(op); queue.push_back(op);
} }
void issueWrite(uint64_t id, uint64_t addr, size_t len, uint64_t val) {
void issueWrite(uint64_t id, uint64_t addr, size_t len, uint64_t val) MMIOOp *op = new MMIOOp;
{
MMIOOp *op = new MMIOOp;
#ifdef MMIO_DEBUG #ifdef MMIO_DEBUG
std::cout << main_time << " MMIO: write id=" << id << " addr=" << std::cout << main_time << " MMIO: write id=" << id << " addr=" << std::hex
std::hex << addr << " len=" << len << " val=" << val << " op=" << addr << " len=" << len << " val=" << val << " op=" << op
<< op << std::endl; << std::endl;
#endif #endif
op->id = id; op->id = id;
op->addr = addr; op->addr = addr;
op->len = len; op->len = len;
op->value = val; op->value = val;
op->isWrite = true; op->isWrite = true;
queue.push_back(op); queue.push_back(op);
} }
}; };
void pci_rwcomp_issue(MMIOOp *op) void pci_rwcomp_issue(MMIOOp *op) {
{ volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc(); volatile struct cosim_pcie_proto_d2h_readcomp *rc;
volatile struct cosim_pcie_proto_d2h_readcomp *rc; volatile struct cosim_pcie_proto_d2h_writecomp *wc;
volatile struct cosim_pcie_proto_d2h_writecomp *wc;
if (!msg) if (!msg)
throw "completion alloc failed"; throw "completion alloc failed";
if (op->isWrite) { if (op->isWrite) {
wc = &msg->writecomp; wc = &msg->writecomp;
wc->req_id = op->id; wc->req_id = op->id;
// WMB(); // WMB();
wc->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP | wc->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} else { } else {
rc = &msg->readcomp; rc = &msg->readcomp;
memcpy((void *) rc->data, &op->value, op->len); memcpy((void *)rc->data, &op->value, op->len);
rc->req_id = op->id; rc->req_id = op->id;
// WMB(); // WMB();
rc->own_type = COSIM_PCIE_PROTO_D2H_MSG_READCOMP | rc->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_READCOMP | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} }
delete op; delete op;
} }
#if 0 #if 0
...@@ -446,49 +428,46 @@ class MemAccessor { ...@@ -446,49 +428,46 @@ class MemAccessor {
std::set<DMAOp *> pci_dma_pending; std::set<DMAOp *> pci_dma_pending;
void pci_dma_issue(DMAOp *op) void pci_dma_issue(DMAOp *op) {
{ volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc(); uint8_t ty;
uint8_t ty;
if (!msg) if (!msg)
throw "completion alloc failed"; throw "completion alloc failed";
if (op->write) { if (op->write) {
volatile struct cosim_pcie_proto_d2h_write *write = &msg->write; volatile struct cosim_pcie_proto_d2h_write *write = &msg->write;
write->req_id = (uintptr_t) op; write->req_id = (uintptr_t)op;
write->offset = op->dma_addr; write->offset = op->dma_addr;
write->len = op->len; write->len = op->len;
// TODO(antoinek): check DMA length // TODO(antoinek): check DMA length
memcpy((void *) write->data, op->data, op->len); memcpy((void *)write->data, op->data, op->len);
// WMB(); // WMB();
write->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITE | write->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_WRITE | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} else { } else {
volatile struct cosim_pcie_proto_d2h_read *read = &msg->read; volatile struct cosim_pcie_proto_d2h_read *read = &msg->read;
read->req_id = (uintptr_t) op; read->req_id = (uintptr_t)op;
read->offset = op->dma_addr; read->offset = op->dma_addr;
read->len = op->len; read->len = op->len;
// WMB();
read->own_type = COSIM_PCIE_PROTO_D2H_MSG_READ |
COSIM_PCIE_PROTO_D2H_OWN_HOST;
}
pci_dma_pending.insert(op); // WMB();
} read->own_type =
COSIM_PCIE_PROTO_D2H_MSG_READ | COSIM_PCIE_PROTO_D2H_OWN_HOST;
}
pci_dma_pending.insert(op);
}
static void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc) static void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc) {
{ DMAOp *op = (DMAOp *)(uintptr_t)rc->req_id;
DMAOp *op = (DMAOp *) (uintptr_t) rc->req_id; if (pci_dma_pending.find(op) == pci_dma_pending.end())
if (pci_dma_pending.find(op) == pci_dma_pending.end()) throw "unexpected completion";
throw "unexpected completion"; pci_dma_pending.erase(op);
pci_dma_pending.erase(op);
memcpy(op->data, (void *) rc->data, op->len); memcpy(op->data, (void *)rc->data, op->len);
#if 0 #if 0
std::cerr << "dma read comp: "; std::cerr << "dma read comp: ";
...@@ -497,335 +476,322 @@ static void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc) ...@@ -497,335 +476,322 @@ static void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc)
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
op->engine->pci_op_complete(op);
op->engine->pci_op_complete(op);
} }
static void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc) static void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc) {
{ DMAOp *op = (DMAOp *)(uintptr_t)wc->req_id;
DMAOp *op = (DMAOp *) (uintptr_t) wc->req_id; if (pci_dma_pending.find(op) == pci_dma_pending.end())
if (pci_dma_pending.find(op) == pci_dma_pending.end()) throw "unexpected completion";
throw "unexpected completion"; pci_dma_pending.erase(op);
pci_dma_pending.erase(op);
op->engine->pci_op_complete(op); op->engine->pci_op_complete(op);
} }
static uint64_t csr_read(uint64_t off) static uint64_t csr_read(uint64_t off) {
{ switch (off) {
switch (off) { case 0x00:
case 0x00: return 32; /* firmware id */ return 32; /* firmware id */
case 0x04: return 1; /* firmware version */ case 0x04:
case 0x08: return 0x43215678; /* board id */ return 1; /* firmware version */
case 0x0c: return 0x1; /* board version */ case 0x08:
case 0x10: return 1; /* phc count */ return 0x43215678; /* board id */
case 0x14: return 0x200; /* phc offset */ case 0x0c:
case 0x18: return 0x80; /* phc stride */ return 0x1; /* board version */
case 0x20: return 1; /* if_count */ case 0x10:
case 0x24: return 0x80000; /* if stride */ return 1; /* phc count */
case 0x2c: return 0x80000; /* if csr offset */ case 0x14:
case 0x200: return 0x1; /* phc features */ return 0x200; /* phc offset */
default: case 0x18:
std::cerr << "csr_read(" << off << ") unimplemented" << std::endl; return 0x80; /* phc stride */
return 0; case 0x20:
} return 1; /* if_count */
case 0x24:
return 0x80000; /* if stride */
case 0x2c:
return 0x80000; /* if csr offset */
case 0x200:
return 0x1; /* phc features */
default:
std::cerr << "csr_read(" << off << ") unimplemented" << std::endl;
return 0;
}
} }
static void csr_write(uint64_t off, uint64_t val) static void csr_write(uint64_t off, uint64_t val) {
{
} }
static void h2d_read(MMIOInterface &mmio, static void h2d_read(MMIOInterface &mmio,
volatile struct cosim_pcie_proto_h2d_read *read) volatile struct cosim_pcie_proto_h2d_read *read) {
{ // std::cout << "got read " << read->offset << std::endl;
// std::cout << "got read " << read->offset << std::endl; if (read->offset < 0x80000) {
if (read->offset < 0x80000) { volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc(); volatile struct cosim_pcie_proto_d2h_readcomp *rc;
volatile struct cosim_pcie_proto_d2h_readcomp *rc;
if (!msg)
if (!msg) throw "completion alloc failed";
throw "completion alloc failed";
rc = &msg->readcomp;
rc = &msg->readcomp; memset((void *)rc->data, 0, read->len);
memset((void *) rc->data, 0, read->len); uint64_t val = csr_read(read->offset);
uint64_t val = csr_read(read->offset); memcpy((void *)rc->data, &val, read->len);
memcpy((void *) rc->data, &val, read->len); rc->req_id = read->req_id;
rc->req_id = read->req_id;
// WMB();
// WMB(); rc->own_type =
rc->own_type = COSIM_PCIE_PROTO_D2H_MSG_READCOMP | COSIM_PCIE_PROTO_D2H_MSG_READCOMP | COSIM_PCIE_PROTO_D2H_OWN_HOST;
COSIM_PCIE_PROTO_D2H_OWN_HOST; } else {
} else { /*printf("read(bar=%u, off=%lu, len=%u) = %lu\n", read->bar, read->offset,
/*printf("read(bar=%u, off=%lu, len=%u) = %lu\n", read->bar, read->offset, read->len, val);*/
read->len, val);*/ mmio.issueRead(read->req_id, read->offset, read->len);
mmio.issueRead(read->req_id, read->offset, read->len); }
}
} }
static void h2d_write(MMIOInterface &mmio, static void h2d_write(MMIOInterface &mmio,
volatile struct cosim_pcie_proto_h2d_write *write) volatile struct cosim_pcie_proto_h2d_write *write) {
{ uint64_t val = 0;
uint64_t val = 0;
memcpy(&val, (void *) write->data, write->len); memcpy(&val, (void *)write->data, write->len);
// std::cout << "got write " << write->offset << " = " << val << std::endl; // std::cout << "got write " << write->offset << " = " << val << std::endl;
if (write->offset < 0x80000) { if (write->offset < 0x80000) {
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc(); volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile struct cosim_pcie_proto_d2h_writecomp *wc; volatile struct cosim_pcie_proto_d2h_writecomp *wc;
if (!msg) if (!msg)
throw "completion alloc failed"; throw "completion alloc failed";
csr_write(write->offset, val); csr_write(write->offset, val);
wc = &msg->writecomp; wc = &msg->writecomp;
wc->req_id = write->req_id; wc->req_id = write->req_id;
// WMB(); // WMB();
wc->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP | wc->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} else { } else {
mmio.issueWrite(write->req_id, write->offset, write->len, val); mmio.issueWrite(write->req_id, write->offset, write->len, val);
} }
} }
static void poll_h2d(MMIOInterface &mmio) static void poll_h2d(MMIOInterface &mmio) {
{ volatile union cosim_pcie_proto_h2d *msg =
volatile union cosim_pcie_proto_h2d *msg = nicif_h2d_poll(&nsparams, main_time);
nicif_h2d_poll(&nsparams, main_time); uint8_t t;
uint8_t t;
if (msg == NULL) if (msg == NULL)
return; return;
t = msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK; t = msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK;
// std::cerr << "poll_h2d: polled type=" << (int) t << std::endl; // std::cerr << "poll_h2d: polled type=" << (int) t << std::endl;
switch (t) { switch (t) {
case COSIM_PCIE_PROTO_H2D_MSG_READ: case COSIM_PCIE_PROTO_H2D_MSG_READ:
h2d_read(mmio, &msg->read); h2d_read(mmio, &msg->read);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_WRITE: case COSIM_PCIE_PROTO_H2D_MSG_WRITE:
h2d_write(mmio, &msg->write); h2d_write(mmio, &msg->write);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_READCOMP: case COSIM_PCIE_PROTO_H2D_MSG_READCOMP:
h2d_readcomp(&msg->readcomp); h2d_readcomp(&msg->readcomp);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_WRITECOMP: case COSIM_PCIE_PROTO_H2D_MSG_WRITECOMP:
h2d_writecomp(&msg->writecomp); h2d_writecomp(&msg->writecomp);
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_DEVCTRL: case COSIM_PCIE_PROTO_H2D_MSG_DEVCTRL:
break; break;
case COSIM_PCIE_PROTO_H2D_MSG_SYNC: case COSIM_PCIE_PROTO_H2D_MSG_SYNC:
break; break;
default: default:
std::cerr << "poll_h2d: unsupported type=" << t << std::endl; std::cerr << "poll_h2d: unsupported type=" << t << std::endl;
} }
nicif_h2d_done(msg); nicif_h2d_done(msg);
nicif_h2d_next(); nicif_h2d_next();
}; }
static volatile union cosim_pcie_proto_d2h *d2h_alloc(void) static volatile union cosim_pcie_proto_d2h *d2h_alloc(void) {
{ return nicsim_d2h_alloc(&nsparams, main_time);
return nicsim_d2h_alloc(&nsparams, main_time);
} }
class EthernetTx { class EthernetTx {
protected: protected:
Vinterface &top; Vinterface &top;
uint8_t packet_buf[2048]; uint8_t packet_buf[2048];
size_t packet_len; size_t packet_len;
public: public:
EthernetTx(Vinterface &top_) EthernetTx(Vinterface &top_) : top(top_), packet_len(0) {
: top(top_), packet_len(0) }
{
}
void packet_done() void packet_done() {
{ volatile union cosim_eth_proto_d2n *msg =
volatile union cosim_eth_proto_d2n *msg = nicsim_d2n_alloc(&nsparams, main_time);
nicsim_d2n_alloc(&nsparams, main_time); volatile struct cosim_eth_proto_d2n_send *send;
volatile struct cosim_eth_proto_d2n_send *send;
if (!msg) if (!msg)
throw "completion alloc failed"; throw "completion alloc failed";
send = &msg->send; send = &msg->send;
memcpy((void *) send->data, packet_buf, packet_len); memcpy((void *)send->data, packet_buf, packet_len);
send->len = packet_len; send->len = packet_len;
send->timestamp = main_time + eth_latency; send->timestamp = main_time + eth_latency;
// WMB(); // WMB();
send->own_type = COSIM_ETH_PROTO_D2N_MSG_SEND | send->own_type = COSIM_ETH_PROTO_D2N_MSG_SEND | COSIM_ETH_PROTO_D2N_OWN_NET;
COSIM_ETH_PROTO_D2N_OWN_NET;
#ifdef ETH_DEBUG #ifdef ETH_DEBUG
std::cerr << main_time << " EthernetTx: packet len=" << std::hex << std::cerr << main_time << " EthernetTx: packet len=" << std::hex
packet_len << " "; << packet_len << " ";
for (size_t i = 0; i < packet_len; i++) { for (size_t i = 0; i < packet_len; i++) {
std::cerr << (unsigned) packet_buf[i] << " "; std::cerr << (unsigned)packet_buf[i] << " ";
} }
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
} }
void step() void step() {
{ top.tx_axis_tready = 1;
top.tx_axis_tready = 1;
if (top.tx_axis_tvalid) {
/* iterate over all 8 bytes */
for (size_t i = 0; i < 8; i++) {
if ((top.tx_axis_tkeep & (1 << i)) != 0) {
assert(packet_len < 2048);
packet_buf[packet_len++] =
(top.tx_axis_tdata >> (i * 8));
}
}
if (top.tx_axis_tlast) { if (top.tx_axis_tvalid) {
packet_done(); /* iterate over all 8 bytes */
packet_len = 0; for (size_t i = 0; i < 8; i++) {
} if ((top.tx_axis_tkeep & (1 << i)) != 0) {
} assert(packet_len < 2048);
packet_buf[packet_len++] = (top.tx_axis_tdata >> (i * 8));
} }
}
if (top.tx_axis_tlast) {
packet_done();
packet_len = 0;
}
}
}
}; };
class EthernetRx { class EthernetRx {
protected: protected:
Vinterface &top; Vinterface &top;
static const size_t FIFO_SIZE = 32; static const size_t FIFO_SIZE = 32;
uint8_t fifo_bufs[FIFO_SIZE][2048]; uint8_t fifo_bufs[FIFO_SIZE][2048];
size_t fifo_lens[FIFO_SIZE]; size_t fifo_lens[FIFO_SIZE];
size_t fifo_pos_rd; size_t fifo_pos_rd;
size_t fifo_pos_wr; size_t fifo_pos_wr;
size_t packet_off;
size_t packet_off;
public:
public: EthernetRx(Vinterface &top_)
EthernetRx(Vinterface &top_) : top(top_), fifo_pos_rd(0), fifo_pos_wr(0), packet_off(0) {
: top(top_), fifo_pos_rd(0), fifo_pos_wr(0), packet_off(0) for (size_t i = 0; i < FIFO_SIZE; i++) fifo_lens[i] = 0;
{ }
for (size_t i = 0; i < FIFO_SIZE; i++)
fifo_lens[i] = 0; void packet_received(const void *data, size_t len) {
} if (fifo_lens[fifo_pos_wr] != 0) {
std::cerr << "EthernetRx: dropping packet" << std::endl;
void packet_received(const void *data, size_t len) return;
{ }
if (fifo_lens[fifo_pos_wr] != 0) {
std::cerr << "EthernetRx: dropping packet" << std::endl;
return;
}
memcpy(fifo_bufs[fifo_pos_wr], data, len); memcpy(fifo_bufs[fifo_pos_wr], data, len);
fifo_lens[fifo_pos_wr] = len; fifo_lens[fifo_pos_wr] = len;
#ifdef ETH_DEBUG #ifdef ETH_DEBUG
std::cout << main_time << " rx into " << fifo_pos_wr << std::endl; std::cout << main_time << " rx into " << fifo_pos_wr << std::endl;
std::cerr << main_time << " EthernetRx: packet len=" << std::hex << std::cerr << main_time << " EthernetRx: packet len=" << std::hex << len
len << " "; << " ";
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
std::cerr << (unsigned) fifo_bufs[fifo_pos_wr][i] << " "; std::cerr << (unsigned)fifo_bufs[fifo_pos_wr][i] << " ";
} }
std::cerr << std::endl; std::cerr << std::endl;
#endif #endif
fifo_pos_wr = (fifo_pos_wr + 1) % FIFO_SIZE; fifo_pos_wr = (fifo_pos_wr + 1) % FIFO_SIZE;
} }
void step() void step() {
{ if (fifo_lens[fifo_pos_rd] != 0) {
if (fifo_lens[fifo_pos_rd] != 0) { // we have data to send
// we have data to send if (packet_off != 0 && !top.rx_axis_tready) {
if (packet_off != 0 && !top.rx_axis_tready) { // no ready signal, can't advance
// no ready signal, can't advance std::cerr << "eth rx: no ready" << std::endl;
std::cerr << "eth rx: no ready" << std::endl; } else if (packet_off == fifo_lens[fifo_pos_rd]) {
} else if (packet_off == fifo_lens[fifo_pos_rd]) { // done with packet
// done with packet
#ifdef ETH_DEBUG #ifdef ETH_DEBUG
std::cerr << main_time << " EthernetRx: finished packet" << std::cerr << main_time << " EthernetRx: finished packet" << std::endl;
std::endl;
#endif #endif
top.rx_axis_tvalid = 0; top.rx_axis_tvalid = 0;
top.rx_axis_tlast = 0; top.rx_axis_tlast = 0;
packet_off = 0; packet_off = 0;
fifo_lens[fifo_pos_rd] = 0; fifo_lens[fifo_pos_rd] = 0;
fifo_pos_rd = (fifo_pos_rd + 1) % FIFO_SIZE; fifo_pos_rd = (fifo_pos_rd + 1) % FIFO_SIZE;
} else { } else {
// put out more packet data // put out more packet data
#ifdef ETH_DEBUG #ifdef ETH_DEBUG
std::cerr << main_time << " EthernetRx: push flit " << std::cerr << main_time << " EthernetRx: push flit " << packet_off
packet_off << std::endl; << std::endl;
if (packet_off == 0) if (packet_off == 0)
std::cout << "rx from " << fifo_pos_rd << std::endl; std::cout << "rx from " << fifo_pos_rd << std::endl;
#endif #endif
top.rx_axis_tkeep = 0; top.rx_axis_tkeep = 0;
top.rx_axis_tdata = 0; top.rx_axis_tdata = 0;
size_t i; size_t i;
for (i = 0; i < 8 && packet_off < fifo_lens[fifo_pos_rd]; for (i = 0; i < 8 && packet_off < fifo_lens[fifo_pos_rd]; i++) {
i++) { top.rx_axis_tdata |= ((uint64_t)fifo_bufs[fifo_pos_rd][packet_off])
top.rx_axis_tdata |= << (i * 8);
((uint64_t) fifo_bufs[fifo_pos_rd][packet_off]) << top.rx_axis_tkeep |= (1 << i);
(i * 8); packet_off++;
top.rx_axis_tkeep |= (1 << i);
packet_off++;
}
top.rx_axis_tvalid = 1;
top.rx_axis_tlast = (packet_off == fifo_lens[fifo_pos_rd]);
}
// trace->dump(main_time);
} else {
// no data
top.rx_axis_tvalid = 0;
top.rx_axis_tlast = 0;
}
} }
top.rx_axis_tvalid = 1;
top.rx_axis_tlast = (packet_off == fifo_lens[fifo_pos_rd]);
}
// trace->dump(main_time);
} else {
// no data
top.rx_axis_tvalid = 0;
top.rx_axis_tlast = 0;
}
}
}; };
static void n2d_recv(EthernetRx &rx, static void n2d_recv(EthernetRx &rx,
volatile struct cosim_eth_proto_n2d_recv *recv) volatile struct cosim_eth_proto_n2d_recv *recv) {
{ rx.packet_received((const void *)recv->data, recv->len);
rx.packet_received((const void *) recv->data, recv->len);
} }
static void poll_n2d(EthernetRx &rx) static void poll_n2d(EthernetRx &rx) {
{ volatile union cosim_eth_proto_n2d *msg =
volatile union cosim_eth_proto_n2d *msg = nicif_n2d_poll(&nsparams, main_time);
nicif_n2d_poll(&nsparams, main_time); uint8_t t;
uint8_t t;
if (msg == NULL) if (msg == NULL)
return; return;
t = msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK; t = msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK;
switch (t) { switch (t) {
case COSIM_ETH_PROTO_N2D_MSG_RECV: case COSIM_ETH_PROTO_N2D_MSG_RECV:
n2d_recv(rx, &msg->recv); n2d_recv(rx, &msg->recv);
break; break;
case COSIM_ETH_PROTO_N2D_MSG_SYNC: case COSIM_ETH_PROTO_N2D_MSG_SYNC:
break; break;
default: default:
std::cerr << "poll_n2d: unsupported type=" << t << std::endl; std::cerr << "poll_n2d: unsupported type=" << t << std::endl;
} }
nicif_n2d_done(msg); nicif_n2d_done(msg);
nicif_n2d_next(); nicif_n2d_next();
} }
#if 0 #if 0
...@@ -903,272 +869,252 @@ class PCICoordinator { ...@@ -903,272 +869,252 @@ class PCICoordinator {
}; };
#endif #endif
void pci_msi_issue(uint8_t vec) void pci_msi_issue(uint8_t vec) {
{ volatile union cosim_pcie_proto_d2h *msg = d2h_alloc();
volatile union cosim_pcie_proto_d2h *msg = d2h_alloc(); volatile struct cosim_pcie_proto_d2h_interrupt *intr;
volatile struct cosim_pcie_proto_d2h_interrupt *intr;
#ifdef MSI_DEBUG #ifdef MSI_DEBUG
std::cerr << main_time << " MSI interrupt vec=" << (int) vec << std::endl; std::cerr << main_time << " MSI interrupt vec=" << (int)vec << std::endl;
#endif #endif
intr = &msg->interrupt; intr = &msg->interrupt;
intr->vector = vec; intr->vector = vec;
intr->inttype = COSIM_PCIE_PROTO_INT_MSI; intr->inttype = COSIM_PCIE_PROTO_INT_MSI;
// WMB(); // WMB();
intr->own_type = COSIM_PCIE_PROTO_D2H_MSG_INTERRUPT | intr->own_type =
COSIM_PCIE_PROTO_D2H_OWN_HOST; COSIM_PCIE_PROTO_D2H_MSG_INTERRUPT | COSIM_PCIE_PROTO_D2H_OWN_HOST;
} }
static void msi_step(Vinterface &top, PCICoordinator &coord) {
static void msi_step(Vinterface &top, PCICoordinator &coord) if (!top.msi_irq)
{ return;
if (!top.msi_irq)
return;
#ifdef MSI_DEBUG #ifdef MSI_DEBUG
std::cerr << main_time << " msi_step: MSI interrupt raw vec=" << std::cerr << main_time
(int) top.msi_irq << std::endl; << " msi_step: MSI interrupt raw vec=" << (int)top.msi_irq
<< std::endl;
#endif #endif
for (size_t i = 0; i < 32; i++) { for (size_t i = 0; i < 32; i++) {
if (!((1ULL << i) & top.msi_irq)) if (!((1ULL << i) & top.msi_irq))
continue; continue;
coord.msi_enqueue(i); coord.msi_enqueue(i);
} }
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{ char *vargs[2] = {argv[0], NULL};
char *vargs[2] = { argv[0], NULL }; Verilated::commandArgs(1, vargs);
Verilated::commandArgs(1, vargs); int sync_mode = SYNC_MODES;
int sync_mode = SYNC_MODES;
#ifdef TRACE_ENABLED #ifdef TRACE_ENABLED
Verilated::traceEverOn(true); Verilated::traceEverOn(true);
#endif #endif
if (argc < 4 && argc > 10) { if (argc < 4 && argc > 10) {
fprintf(stderr, "Usage: corundum_verilator PCI-SOCKET ETH-SOCKET " fprintf(stderr,
"SHM [SYNC-MODE] [START-TICK] [SYNC-PERIOD] [PCI-LATENCY] " "Usage: corundum_verilator PCI-SOCKET ETH-SOCKET "
"[ETH-LATENCY] [CLOCK-FREQ-MHZ]\n"); "SHM [SYNC-MODE] [START-TICK] [SYNC-PERIOD] [PCI-LATENCY] "
return EXIT_FAILURE; "[ETH-LATENCY] [CLOCK-FREQ-MHZ]\n");
} return EXIT_FAILURE;
if (argc >= 5) }
sync_mode = strtol(argv[4], NULL, 0); if (argc >= 5)
if (argc >= 6) sync_mode = strtol(argv[4], NULL, 0);
main_time = strtoull(argv[5], NULL, 0); if (argc >= 6)
if (argc >= 7) main_time = strtoull(argv[5], NULL, 0);
sync_period = strtoull(argv[6], NULL, 0) * 1000ULL; if (argc >= 7)
if (argc >= 8) sync_period = strtoull(argv[6], NULL, 0) * 1000ULL;
pci_latency = strtoull(argv[7], NULL, 0) * 1000ULL; if (argc >= 8)
if (argc >= 9) pci_latency = strtoull(argv[7], NULL, 0) * 1000ULL;
eth_latency = strtoull(argv[8], NULL, 0) * 1000ULL; if (argc >= 9)
if (argc >= 10) eth_latency = strtoull(argv[8], NULL, 0) * 1000ULL;
clock_period = 1000000ULL / strtoull(argv[9], NULL, 0); if (argc >= 10)
clock_period = 1000000ULL / strtoull(argv[9], NULL, 0);
struct cosim_pcie_proto_dev_intro di;
memset(&di, 0, sizeof(di)); struct cosim_pcie_proto_dev_intro di;
memset(&di, 0, sizeof(di));
di.bars[0].len = 1 << 24;
di.bars[0].flags = COSIM_PCIE_PROTO_BAR_64; di.bars[0].len = 1 << 24;
di.bars[0].flags = COSIM_PCIE_PROTO_BAR_64;
di.pci_vendor_id = 0x5543;
di.pci_device_id = 0x1001; di.pci_vendor_id = 0x5543;
di.pci_class = 0x02; di.pci_device_id = 0x1001;
di.pci_subclass = 0x00; di.pci_class = 0x02;
di.pci_revision = 0x00; di.pci_subclass = 0x00;
di.pci_msi_nvecs = 32; di.pci_revision = 0x00;
di.pci_msi_nvecs = 32;
nsparams.sync_pci = 1;
nsparams.sync_eth = 1; nsparams.sync_pci = 1;
nsparams.pci_socket_path = argv[1]; nsparams.sync_eth = 1;
nsparams.eth_socket_path = argv[2]; nsparams.pci_socket_path = argv[1];
nsparams.shm_path = argv[3]; nsparams.eth_socket_path = argv[2];
nsparams.pci_latency = pci_latency; nsparams.shm_path = argv[3];
nsparams.eth_latency = eth_latency; nsparams.pci_latency = pci_latency;
nsparams.sync_delay = sync_period; nsparams.eth_latency = eth_latency;
assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER); nsparams.sync_delay = sync_period;
nsparams.sync_mode = sync_mode; assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER);
nsparams.sync_mode = sync_mode;
if (nicsim_init(&nsparams, &di)) {
return EXIT_FAILURE; if (nicsim_init(&nsparams, &di)) {
} return EXIT_FAILURE;
std::cout << "sync_pci=" << nsparams.sync_pci << }
" sync_eth=" << nsparams.sync_eth << std::endl; std::cout << "sync_pci=" << nsparams.sync_pci
<< " sync_eth=" << nsparams.sync_eth << std::endl;
signal(SIGINT, sigint_handler);
signal(SIGUSR1, sigusr1_handler); signal(SIGINT, sigint_handler);
signal(SIGUSR1, sigusr1_handler);
Vinterface *top = new Vinterface; Vinterface *top = new Vinterface;
#ifdef TRACE_ENABLED #ifdef TRACE_ENABLED
trace = new VerilatedVcdC; trace = new VerilatedVcdC;
top->trace(trace, 99); top->trace(trace, 99);
trace->open("debug.vcd"); trace->open("debug.vcd");
#endif #endif
MemWritePort p_mem_write_ctrl_dma( MemWritePort p_mem_write_ctrl_dma(
top->ctrl_dma_ram_wr_cmd_sel, top->ctrl_dma_ram_wr_cmd_sel, top->ctrl_dma_ram_wr_cmd_be,
top->ctrl_dma_ram_wr_cmd_be, top->ctrl_dma_ram_wr_cmd_addr, top->ctrl_dma_ram_wr_cmd_data,
top->ctrl_dma_ram_wr_cmd_addr, top->ctrl_dma_ram_wr_cmd_valid, top->ctrl_dma_ram_wr_cmd_ready);
top->ctrl_dma_ram_wr_cmd_data, MemReadPort p_mem_read_ctrl_dma(
top->ctrl_dma_ram_wr_cmd_valid, top->ctrl_dma_ram_rd_cmd_sel, top->ctrl_dma_ram_rd_cmd_addr,
top->ctrl_dma_ram_wr_cmd_ready); top->ctrl_dma_ram_rd_cmd_valid, top->ctrl_dma_ram_rd_resp_ready,
MemReadPort p_mem_read_ctrl_dma( top->ctrl_dma_ram_rd_resp_data, top->ctrl_dma_ram_rd_cmd_ready,
top->ctrl_dma_ram_rd_cmd_sel, top->ctrl_dma_ram_rd_resp_valid);
top->ctrl_dma_ram_rd_cmd_addr, MemWritePort p_mem_write_data_dma(
top->ctrl_dma_ram_rd_cmd_valid, top->data_dma_ram_wr_cmd_sel, top->data_dma_ram_wr_cmd_be,
top->ctrl_dma_ram_rd_resp_ready, top->data_dma_ram_wr_cmd_addr, top->data_dma_ram_wr_cmd_data,
top->ctrl_dma_ram_rd_resp_data, top->data_dma_ram_wr_cmd_valid, top->data_dma_ram_wr_cmd_ready);
top->ctrl_dma_ram_rd_cmd_ready, MemReadPort p_mem_read_data_dma(
top->ctrl_dma_ram_rd_resp_valid); top->data_dma_ram_rd_cmd_sel, top->data_dma_ram_rd_cmd_addr,
MemWritePort p_mem_write_data_dma( top->data_dma_ram_rd_cmd_valid, top->data_dma_ram_rd_resp_ready,
top->data_dma_ram_wr_cmd_sel, top->data_dma_ram_rd_resp_data, top->data_dma_ram_rd_cmd_ready,
top->data_dma_ram_wr_cmd_be, top->data_dma_ram_rd_resp_valid);
top->data_dma_ram_wr_cmd_addr,
top->data_dma_ram_wr_cmd_data, DMAPorts p_dma_read_ctrl(top->m_axis_ctrl_dma_read_desc_dma_addr,
top->data_dma_ram_wr_cmd_valid, top->m_axis_ctrl_dma_read_desc_ram_sel,
top->data_dma_ram_wr_cmd_ready); top->m_axis_ctrl_dma_read_desc_ram_addr,
MemReadPort p_mem_read_data_dma( top->m_axis_ctrl_dma_read_desc_len,
top->data_dma_ram_rd_cmd_sel, top->m_axis_ctrl_dma_read_desc_tag,
top->data_dma_ram_rd_cmd_addr, top->m_axis_ctrl_dma_read_desc_valid,
top->data_dma_ram_rd_cmd_valid, top->m_axis_ctrl_dma_read_desc_ready,
top->data_dma_ram_rd_resp_ready, top->s_axis_ctrl_dma_read_desc_status_tag,
top->data_dma_ram_rd_resp_data, top->s_axis_ctrl_dma_read_desc_status_valid);
top->data_dma_ram_rd_cmd_ready, DMAPorts p_dma_write_ctrl(top->m_axis_ctrl_dma_write_desc_dma_addr,
top->data_dma_ram_rd_resp_valid); top->m_axis_ctrl_dma_write_desc_ram_sel,
top->m_axis_ctrl_dma_write_desc_ram_addr,
DMAPorts p_dma_read_ctrl( top->m_axis_ctrl_dma_write_desc_len,
top->m_axis_ctrl_dma_read_desc_dma_addr, top->m_axis_ctrl_dma_write_desc_tag,
top->m_axis_ctrl_dma_read_desc_ram_sel, top->m_axis_ctrl_dma_write_desc_valid,
top->m_axis_ctrl_dma_read_desc_ram_addr, top->m_axis_ctrl_dma_write_desc_ready,
top->m_axis_ctrl_dma_read_desc_len, top->s_axis_ctrl_dma_write_desc_status_tag,
top->m_axis_ctrl_dma_read_desc_tag, top->s_axis_ctrl_dma_write_desc_status_valid);
top->m_axis_ctrl_dma_read_desc_valid, DMAPorts p_dma_read_data(top->m_axis_data_dma_read_desc_dma_addr,
top->m_axis_ctrl_dma_read_desc_ready, top->m_axis_data_dma_read_desc_ram_sel,
top->s_axis_ctrl_dma_read_desc_status_tag, top->m_axis_data_dma_read_desc_ram_addr,
top->s_axis_ctrl_dma_read_desc_status_valid); top->m_axis_data_dma_read_desc_len,
DMAPorts p_dma_write_ctrl( top->m_axis_data_dma_read_desc_tag,
top->m_axis_ctrl_dma_write_desc_dma_addr, top->m_axis_data_dma_read_desc_valid,
top->m_axis_ctrl_dma_write_desc_ram_sel, top->m_axis_data_dma_read_desc_ready,
top->m_axis_ctrl_dma_write_desc_ram_addr, top->s_axis_data_dma_read_desc_status_tag,
top->m_axis_ctrl_dma_write_desc_len, top->s_axis_data_dma_read_desc_status_valid);
top->m_axis_ctrl_dma_write_desc_tag, DMAPorts p_dma_write_data(top->m_axis_data_dma_write_desc_dma_addr,
top->m_axis_ctrl_dma_write_desc_valid, top->m_axis_data_dma_write_desc_ram_sel,
top->m_axis_ctrl_dma_write_desc_ready, top->m_axis_data_dma_write_desc_ram_addr,
top->s_axis_ctrl_dma_write_desc_status_tag, top->m_axis_data_dma_write_desc_len,
top->s_axis_ctrl_dma_write_desc_status_valid); top->m_axis_data_dma_write_desc_tag,
DMAPorts p_dma_read_data( top->m_axis_data_dma_write_desc_valid,
top->m_axis_data_dma_read_desc_dma_addr, top->m_axis_data_dma_write_desc_ready,
top->m_axis_data_dma_read_desc_ram_sel, top->s_axis_data_dma_write_desc_status_tag,
top->m_axis_data_dma_read_desc_ram_addr, top->s_axis_data_dma_write_desc_status_valid);
top->m_axis_data_dma_read_desc_len,
top->m_axis_data_dma_read_desc_tag, // PCICoordinator pci_coord;
top->m_axis_data_dma_read_desc_valid, PCICoordinator pci_coord_mmio;
top->m_axis_data_dma_read_desc_ready, PCICoordinator pci_coord_msi;
top->s_axis_data_dma_read_desc_status_tag, PCICoordinator pci_coord_rc;
top->s_axis_data_dma_read_desc_status_valid); PCICoordinator pci_coord_wc;
DMAPorts p_dma_write_data( PCICoordinator pci_coord_rd;
top->m_axis_data_dma_write_desc_dma_addr, PCICoordinator pci_coord_wd;
top->m_axis_data_dma_write_desc_ram_sel, MMIOInterface mmio(*top, pci_coord_mmio);
top->m_axis_data_dma_write_desc_ram_addr,
top->m_axis_data_dma_write_desc_len, MemWriter mem_control_writer(p_mem_write_ctrl_dma);
top->m_axis_data_dma_write_desc_tag, MemReader mem_control_reader(p_mem_read_ctrl_dma);
top->m_axis_data_dma_write_desc_valid, MemWriter mem_data_writer(p_mem_write_data_dma);
top->m_axis_data_dma_write_desc_ready, MemReader mem_data_reader(p_mem_read_data_dma);
top->s_axis_data_dma_write_desc_status_tag,
top->s_axis_data_dma_write_desc_status_valid); DMAReader dma_read_ctrl("read ctrl", p_dma_read_ctrl, mem_control_writer,
pci_coord_rc);
// PCICoordinator pci_coord; DMAWriter dma_write_ctrl("write ctrl", p_dma_write_ctrl, mem_control_reader,
PCICoordinator pci_coord_mmio; pci_coord_wc);
PCICoordinator pci_coord_msi; DMAReader dma_read_data("read data", p_dma_read_data, mem_data_writer,
PCICoordinator pci_coord_rc; pci_coord_rd);
PCICoordinator pci_coord_wc; DMAWriter dma_write_data("write data", p_dma_write_data, mem_data_reader,
PCICoordinator pci_coord_rd; pci_coord_wd);
PCICoordinator pci_coord_wd;
MMIOInterface mmio(*top, pci_coord_mmio); EthernetTx tx(*top);
EthernetRx rx(*top);
MemWriter mem_control_writer(p_mem_write_ctrl_dma);
MemReader mem_control_reader(p_mem_read_ctrl_dma); reset_inputs(top);
MemWriter mem_data_writer(p_mem_write_data_dma); top->rst = 1;
MemReader mem_data_reader(p_mem_read_data_dma); top->eval();
DMAReader dma_read_ctrl("read ctrl", p_dma_read_ctrl, mem_control_writer, /* raising edge */
pci_coord_rc); top->clk = !top->clk;
DMAWriter dma_write_ctrl("write ctrl", p_dma_write_ctrl, mem_control_reader, top->eval();
pci_coord_wc);
DMAReader dma_read_data("read data", p_dma_read_data, mem_data_writer, top->rst = 0;
pci_coord_rd);
DMAWriter dma_write_data("write data", p_dma_write_data, mem_data_reader, while (!exiting) {
pci_coord_wd); while (nicsim_sync(&nsparams, main_time)) {
std::cerr << "warn: nicsim_sync failed (t=" << main_time << ")"
EthernetTx tx(*top); << std::endl;
EthernetRx rx(*top); }
nicsim_advance_epoch(&nsparams, main_time);
reset_inputs(top);
top->rst = 1;
top->eval();
/* raising edge */ do {
poll_h2d(mmio);
poll_n2d(rx);
} while ((nsparams.sync_pci || nsparams.sync_eth) &&
nicsim_next_timestamp(&nsparams) <= main_time && !exiting);
/* falling edge */
top->clk = !top->clk; top->clk = !top->clk;
main_time += clock_period / 2;
top->eval(); top->eval();
top->rst = 0; mmio.step();
while (!exiting) {
while (nicsim_sync(&nsparams, main_time)) {
std::cerr << "warn: nicsim_sync failed (t=" << main_time << ")" <<
std::endl;
}
nicsim_advance_epoch(&nsparams, main_time);
do {
poll_h2d(mmio);
poll_n2d(rx);
} while ((nsparams.sync_pci || nsparams.sync_eth) &&
nicsim_next_timestamp(&nsparams) <= main_time && !exiting);
/* falling edge */
top->clk = !top->clk;
main_time += clock_period / 2;
top->eval();
mmio.step(); dma_read_ctrl.step();
dma_write_ctrl.step();
dma_read_data.step();
dma_write_data.step();
dma_read_ctrl.step(); mem_control_writer.step();
dma_write_ctrl.step(); mem_control_reader.step();
dma_read_data.step(); mem_data_writer.step();
dma_write_data.step(); mem_data_reader.step();
mem_control_writer.step(); tx.step();
mem_control_reader.step(); rx.step();
mem_data_writer.step();
mem_data_reader.step();
tx.step(); msi_step(*top, pci_coord_msi);
rx.step();
msi_step(*top, pci_coord_msi); /* raising edge */
top->clk = !top->clk;
/* raising edge */ main_time += clock_period / 2;
top->clk = !top->clk;
main_time += clock_period / 2;
// top->s_axis_tx_ptp_ts_96 = main_time; // top->s_axis_tx_ptp_ts_96 = main_time;
top->s_axis_tx_ptp_ts_valid = 1; top->s_axis_tx_ptp_ts_valid = 1;
top->s_axis_rx_ptp_ts_valid = 1; top->s_axis_rx_ptp_ts_valid = 1;
top->eval(); top->eval();
} }
report_outputs(top); report_outputs(top);
std::cout << std::endl << std::endl << "main_time:" << main_time << std::cout << std::endl << std::endl << "main_time:" << main_time << std::endl;
std::endl;
#ifdef TRACE_ENABLED #ifdef TRACE_ENABLED
trace->dump(main_time + 1); trace->dump(main_time + 1);
trace->close(); trace->close();
#endif #endif
top->final(); top->final();
delete top; delete top;
return 0; return 0;
} }
...@@ -22,126 +22,117 @@ ...@@ -22,126 +22,117 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "sims/nic/corundum/dma.h"
#include <iostream> #include <iostream>
#include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/corundum.h" #include "sims/nic/corundum/corundum.h"
#include "sims/nic/corundum/dma.h" #include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/mem.h" #include "sims/nic/corundum/mem.h"
void DMAReader::step() {
void DMAReader::step() p.dma_ready = 1;
{ if (p.dma_valid) {
p.dma_ready = 1; DMAOp *op = new DMAOp;
if (p.dma_valid) { op->engine = this;
DMAOp *op = new DMAOp; op->dma_addr = p.dma_addr;
op->engine = this; op->ram_sel = p.dma_ram_sel;
op->dma_addr = p.dma_addr; op->ram_addr = p.dma_ram_addr;
op->ram_sel = p.dma_ram_sel; op->len = p.dma_len;
op->ram_addr = p.dma_ram_addr; op->tag = p.dma_tag;
op->len = p.dma_len; op->write = false;
op->tag = p.dma_tag; pending.insert(op);
op->write = false;
pending.insert(op);
#ifdef DMA_DEBUG #ifdef DMA_DEBUG
std::cout << main_time << " dma[" << label << "] op " << std::hex << std::cout << main_time << " dma[" << label << "] op " << std::hex
op->dma_addr << " -> " << op->ram_sel << ":" << op->ram_addr << << op->dma_addr << " -> " << op->ram_sel << ":" << op->ram_addr
" len=" << op->len << " tag=" << (int) op->tag << std::endl; << " len=" << op->len << " tag=" << (int)op->tag << std::endl;
#endif #endif
coord.dma_register(op, true); coord.dma_register(op, true);
} }
p.dma_status_valid = 0; p.dma_status_valid = 0;
if (!completed.empty()) { if (!completed.empty()) {
DMAOp *op = completed.front(); DMAOp *op = completed.front();
completed.pop_front(); completed.pop_front();
// std::cout << "dma[" << label << "] status complete " << op->dma_addr // std::cout << "dma[" << label << "] status complete " << op->dma_addr
// << std::endl; // << std::endl;
p.dma_status_valid = 1; p.dma_status_valid = 1;
p.dma_status_tag = op->tag; p.dma_status_tag = op->tag;
pending.erase(op); pending.erase(op);
delete op; delete op;
} }
} }
void DMAReader::pci_op_complete(DMAOp *op) void DMAReader::pci_op_complete(DMAOp *op) {
{ mw.op_issue(op);
mw.op_issue(op);
} }
void DMAReader::mem_op_complete(DMAOp *op) void DMAReader::mem_op_complete(DMAOp *op) {
{ completed.push_back(op);
completed.push_back(op); // std::cout << "dma[" << label << "] mem complete " << op->dma_addr <<
// std::cout << "dma[" << label << "] mem complete " << op->dma_addr << // std::endl;
// std::endl;
} }
void DMAWriter::step() {
p.dma_ready = 1;
void DMAWriter::step() if (p.dma_valid) {
{ DMAOp *op = new DMAOp;
p.dma_ready = 1; op->engine = this;
if (p.dma_valid) { op->dma_addr = p.dma_addr;
DMAOp *op = new DMAOp; op->ram_sel = p.dma_ram_sel;
op->engine = this; op->ram_addr = p.dma_ram_addr;
op->dma_addr = p.dma_addr; op->len = p.dma_len;
op->ram_sel = p.dma_ram_sel; op->tag = p.dma_tag;
op->ram_addr = p.dma_ram_addr; op->write = true;
op->len = p.dma_len; pending.insert(op);
op->tag = p.dma_tag;
op->write = true;
pending.insert(op);
#ifdef DMA_DEBUG #ifdef DMA_DEBUG
std::cout << main_time << " dma write [" << label << "] op " << std::cout << main_time << " dma write [" << label << "] op " << std::hex
std::hex << op->dma_addr << " -> " << op->ram_sel << ":" << << op->dma_addr << " -> " << op->ram_sel << ":" << op->ram_addr
op->ram_addr << " len=" << op->len << " tag=" << (int) op->tag << " len=" << op->len << " tag=" << (int)op->tag << std::endl;
<< std::endl;
#endif #endif
coord.dma_register(op, false); coord.dma_register(op, false);
mr.op_issue(op); mr.op_issue(op);
} }
p.dma_status_valid = 0; p.dma_status_valid = 0;
if (!completed.empty()) { if (!completed.empty()) {
DMAOp *op = completed.front(); DMAOp *op = completed.front();
completed.pop_front(); completed.pop_front();
#ifdef DMA_DEBUG #ifdef DMA_DEBUG
std::cout << main_time << " dma write [" << label << std::cout << main_time << " dma write [" << label << "] status complete "
"] status complete " << op->dma_addr << std::endl; << op->dma_addr << std::endl;
#endif #endif
p.dma_status_valid = 1; p.dma_status_valid = 1;
p.dma_status_tag = op->tag; p.dma_status_tag = op->tag;
pending.erase(op); pending.erase(op);
// coord.msi_enqueue(0); // coord.msi_enqueue(0);
delete op; delete op;
} }
} }
void DMAWriter::pci_op_complete(DMAOp *op) void DMAWriter::pci_op_complete(DMAOp *op) {
{
#ifdef DMA_DEBUG #ifdef DMA_DEBUG
std::cout << main_time << " dma write [" << label << "] pci complete " << std::cout << main_time << " dma write [" << label << "] pci complete "
op->dma_addr << std::endl; << op->dma_addr << std::endl;
#endif #endif
completed.push_back(op); completed.push_back(op);
} }
void DMAWriter::mem_op_complete(DMAOp *op) void DMAWriter::mem_op_complete(DMAOp *op) {
{
#ifdef DMA_DEBUG #ifdef DMA_DEBUG
std::cout << main_time << " dma write [" << label << "] mem complete " << std::cout << main_time << " dma write [" << label << "] mem complete "
op->dma_addr << ": "; << op->dma_addr << ": ";
for (size_t i = 0; i < op->len; i++) for (size_t i = 0; i < op->len; i++)
std::cout << (unsigned) op->data[i] << " "; std::cout << (unsigned)op->data[i] << " ";
std::cout << std::endl; std::cout << std::endl;
#endif #endif
coord.dma_mark_ready(op); coord.dma_mark_ready(op);
} }
...@@ -25,15 +25,14 @@ ...@@ -25,15 +25,14 @@
#ifndef DMA_H_ #ifndef DMA_H_
#define DMA_H_ #define DMA_H_
#include <set>
#include <deque>
#include <verilated.h> #include <verilated.h>
#include "sims/nic/corundum/obj_dir/Vinterface.h" #include <deque>
#include <set>
#include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/coord.h" #include "sims/nic/corundum/coord.h"
#include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/obj_dir/Vinterface.h"
#define MAX_DMA_LEN 2048 #define MAX_DMA_LEN 2048
...@@ -42,95 +41,93 @@ class MemWriter; ...@@ -42,95 +41,93 @@ class MemWriter;
class MemReader; class MemReader;
struct DMAPorts { struct DMAPorts {
/* inputs to DMA engine */ /* inputs to DMA engine */
vluint64_t &dma_addr; vluint64_t &dma_addr;
vluint8_t &dma_ram_sel; vluint8_t &dma_ram_sel;
vluint32_t &dma_ram_addr; vluint32_t &dma_ram_addr;
vluint16_t &dma_len; vluint16_t &dma_len;
vluint8_t &dma_tag; vluint8_t &dma_tag;
vluint8_t &dma_valid; vluint8_t &dma_valid;
/* outputs of DMA engine */ /* outputs of DMA engine */
vluint8_t &dma_ready; vluint8_t &dma_ready;
vluint8_t &dma_status_tag; vluint8_t &dma_status_tag;
vluint8_t &dma_status_valid; vluint8_t &dma_status_valid;
DMAPorts(vluint64_t &dma_addr_, vluint8_t &dma_ram_sel_,
DMAPorts(vluint64_t &dma_addr_, vluint8_t &dma_ram_sel_, vluint32_t &dma_ram_addr_, vluint16_t &dma_len_, vluint8_t &dma_tag_,
vluint32_t &dma_ram_addr_, vluint16_t &dma_len_, vluint8_t &dma_valid_, vluint8_t &dma_ready_,
vluint8_t &dma_tag_, vluint8_t &dma_valid_, vluint8_t &dma_status_tag_, vluint8_t &dma_status_valid_)
vluint8_t &dma_ready_, vluint8_t &dma_status_tag_, : dma_addr(dma_addr_),
vluint8_t &dma_status_valid_) dma_ram_sel(dma_ram_sel_),
: dma_addr(dma_addr_), dma_ram_sel(dma_ram_sel_), dma_ram_addr(dma_ram_addr_),
dma_ram_addr(dma_ram_addr_), dma_len(dma_len_), dma_len(dma_len_),
dma_tag(dma_tag_), dma_valid(dma_valid_), dma_tag(dma_tag_),
dma_ready(dma_ready_), dma_status_tag(dma_status_tag_), dma_valid(dma_valid_),
dma_status_valid(dma_status_valid_) dma_ready(dma_ready_),
{ dma_status_tag(dma_status_tag_),
} dma_status_valid(dma_status_valid_) {
}
}; };
struct DMAOp { struct DMAOp {
DMAEngine *engine; DMAEngine *engine;
uint64_t dma_addr; uint64_t dma_addr;
size_t len; size_t len;
uint64_t ram_addr; uint64_t ram_addr;
bool write; bool write;
uint8_t ram_sel; uint8_t ram_sel;
uint8_t tag; uint8_t tag;
uint8_t data[MAX_DMA_LEN]; uint8_t data[MAX_DMA_LEN];
}; };
class DMAEngine { class DMAEngine {
protected: protected:
DMAPorts &p; DMAPorts &p;
PCICoordinator &coord; PCICoordinator &coord;
DMAEngine(DMAPorts &p_, PCICoordinator &coord_) DMAEngine(DMAPorts &p_, PCICoordinator &coord_) : p(p_), coord(coord_) {
: p(p_), coord(coord_) { } }
public: public:
virtual void pci_op_complete(DMAOp *op) = 0; virtual void pci_op_complete(DMAOp *op) = 0;
virtual void mem_op_complete(DMAOp *op) = 0; virtual void mem_op_complete(DMAOp *op) = 0;
}; };
class DMAReader : public DMAEngine { class DMAReader : public DMAEngine {
protected: protected:
std::set<DMAOp *> pending; std::set<DMAOp *> pending;
std::deque<DMAOp *> completed; std::deque<DMAOp *> completed;
const char *label; const char *label;
MemWriter &mw; MemWriter &mw;
public: public:
DMAReader(const char *label_, DMAPorts &p_, MemWriter &mw_, DMAReader(const char *label_, DMAPorts &p_, MemWriter &mw_,
PCICoordinator &coord_) PCICoordinator &coord_)
: DMAEngine(p_, coord_), label(label_), mw(mw_) : DMAEngine(p_, coord_), label(label_), mw(mw_) {
{ }
}
virtual void pci_op_complete(DMAOp *op);
virtual void pci_op_complete(DMAOp *op); virtual void mem_op_complete(DMAOp *op);
virtual void mem_op_complete(DMAOp *op); void step();
void step();
}; };
class DMAWriter : public DMAEngine { class DMAWriter : public DMAEngine {
protected: protected:
std::set<DMAOp *> pending; std::set<DMAOp *> pending;
std::deque<DMAOp *> completed; std::deque<DMAOp *> completed;
const char *label; const char *label;
MemReader &mr; MemReader &mr;
public: public:
DMAWriter(const char *label_, DMAPorts &p_, MemReader &mr_, DMAWriter(const char *label_, DMAPorts &p_, MemReader &mr_,
PCICoordinator &coord_) PCICoordinator &coord_)
: DMAEngine(p_, coord_), label(label_), mr(mr_) : DMAEngine(p_, coord_), label(label_), mr(mr_) {
{ }
}
virtual void pci_op_complete(DMAOp *op);
virtual void pci_op_complete(DMAOp *op); virtual void mem_op_complete(DMAOp *op);
virtual void mem_op_complete(DMAOp *op); void step();
void step();
}; };
#endif // DMA_H_ #endif // DMA_H_
...@@ -22,10 +22,11 @@ ...@@ -22,10 +22,11 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include "sims/nic/corundum/mem.h"
#include <iostream> #include <iostream>
#include "sims/nic/corundum/debug.h" #include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/mem.h"
#include "sims/nic/corundum/dma.h" #include "sims/nic/corundum/dma.h"
/* /*
...@@ -40,173 +41,163 @@ ...@@ -40,173 +41,163 @@
#define SEG_COUNT 8 #define SEG_COUNT 8
#define SEG_WIDTH (DATA_WIDTH / SEG_COUNT) #define SEG_WIDTH (DATA_WIDTH / SEG_COUNT)
void MemWriter::step() void MemWriter::step() {
{ if (cur && p.mem_ready && ((p.mem_ready & p.mem_valid) == p.mem_valid)) {
if (cur && p.mem_ready &&
((p.mem_ready & p.mem_valid) == p.mem_valid))
{
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
std::cerr << "completed write to: " << cur->ram_addr << std::endl; std::cerr << "completed write to: " << cur->ram_addr << std::endl;
#endif #endif
p.mem_valid = 0; p.mem_valid = 0;
p.mem_be[0] = p.mem_be[1] = p.mem_be[2] = p.mem_be[3] = 0; p.mem_be[0] = p.mem_be[1] = p.mem_be[2] = p.mem_be[3] = 0;
if (cur_off == cur->len) { if (cur_off == cur->len) {
/* operation is done */ /* operation is done */
pending.pop_front(); pending.pop_front();
cur->engine->mem_op_complete(cur); cur->engine->mem_op_complete(cur);
cur_off = 0; cur_off = 0;
} else { } else {
/* operation is not done yet, we'll pick it back up */ /* operation is not done yet, we'll pick it back up */
} }
cur = 0; cur = 0;
} else if (!cur && !pending.empty()) { } else if (!cur && !pending.empty()) {
cur = pending.front(); cur = pending.front();
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
std::cerr << "issuing write to " << cur->ram_addr << std::endl; std::cerr << "issuing write to " << cur->ram_addr << std::endl;
#endif #endif
size_t data_byte_width = DATA_WIDTH / 8; size_t data_byte_width = DATA_WIDTH / 8;
size_t data_offset = (cur->ram_addr + cur_off) % data_byte_width; size_t data_offset = (cur->ram_addr + cur_off) % data_byte_width;
/* first reset everything */ /* first reset everything */
p.mem_sel = 0; p.mem_sel = 0;
p.mem_addr[0] = p.mem_addr[1] = p.mem_addr[2] = 0; p.mem_addr[0] = p.mem_addr[1] = p.mem_addr[2] = 0;
p.mem_be[0] = p.mem_be[1] = p.mem_be[2] = p.mem_be[3] = 0; p.mem_be[0] = p.mem_be[1] = p.mem_be[2] = p.mem_be[3] = 0;
p.mem_valid = 0; p.mem_valid = 0;
for (size_t i = 0; i < data_byte_width / 4; i++) for (size_t i = 0; i < data_byte_width / 4; i++) p.mem_data[i] = 0;
p.mem_data[i] = 0;
/* put data bytes in the right places */
size_t off = data_offset;
/* put data bytes in the right places */ size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset
size_t off = data_offset; ? data_byte_width - data_offset
size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset ? : cur->len - cur_off);
data_byte_width - data_offset : cur->len - cur_off); for (size_t i = 0; i < cur_len; i++, off++) {
for (size_t i = 0; i < cur_len; i++, off++) { size_t byte_off = off % 4;
size_t byte_off = off % 4; p.mem_data[off / 4] |=
p.mem_data[off / 4] |= (((uint32_t) cur->data[cur_off + i]) << (((uint32_t)cur->data[cur_off + i]) << (byte_off * 8));
(byte_off * 8)); p.mem_be[off / 32] |= (1 << (off % 32));
p.mem_be[off / 32] |= (1 << (off % 32)); p.mem_valid |= (1 << (off / (SEG_WIDTH / 8)));
p.mem_valid |= (1 << (off / (SEG_WIDTH / 8)));
}
uint64_t seg_addr = (cur->ram_addr + cur_off) / data_byte_width;
size_t seg_addr_bits = 12;
// iterate over the address bit by bit
for (size_t i = 0; i < seg_addr_bits; i++) {
uint32_t bit = ((seg_addr >> i) & 0x1);
// iterate over the segments
for (size_t j = 0; j < SEG_COUNT; j++) {
size_t dst_bit = j * seg_addr_bits + i;
p.mem_addr[dst_bit / 32] |= (bit << (dst_bit % 32));
}
}
cur_off += cur_len;
} }
uint64_t seg_addr = (cur->ram_addr + cur_off) / data_byte_width;
size_t seg_addr_bits = 12;
// iterate over the address bit by bit
for (size_t i = 0; i < seg_addr_bits; i++) {
uint32_t bit = ((seg_addr >> i) & 0x1);
// iterate over the segments
for (size_t j = 0; j < SEG_COUNT; j++) {
size_t dst_bit = j * seg_addr_bits + i;
p.mem_addr[dst_bit / 32] |= (bit << (dst_bit % 32));
}
}
cur_off += cur_len;
}
} }
void MemWriter::op_issue(DMAOp *op) void MemWriter::op_issue(DMAOp *op) {
{
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
std::cerr << "enqueued write to " << op->ram_addr << std::endl; std::cerr << "enqueued write to " << op->ram_addr << std::endl;
#endif #endif
pending.push_back(op); pending.push_back(op);
} }
void MemReader::step() {
size_t data_byte_width = DATA_WIDTH / 8;
if (cur && p.mem_resvalid &&
((p.mem_resvalid & p.mem_valid) == p.mem_valid)) {
void MemReader::step()
{
size_t data_byte_width = DATA_WIDTH / 8;
if (cur && p.mem_resvalid &&
((p.mem_resvalid & p.mem_valid) == p.mem_valid)) {
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
std::cerr << "completed read from: " << std::hex << cur->ram_addr << std::cerr << "completed read from: " << std::hex << cur->ram_addr
std::endl; << std::endl;
std::cerr << " reval = " << (unsigned) p.mem_resvalid << std::endl; std::cerr << " reval = " << (unsigned)p.mem_resvalid << std::endl;
#endif #endif
p.mem_valid = 0; p.mem_valid = 0;
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
for (size_t i = 0; i < 32; i++) for (size_t i = 0; i < 32; i++)
std::cerr << " val = " << p.mem_data[i] << std::endl; std::cerr << " val = " << p.mem_data[i] << std::endl;
#endif #endif
size_t off = (cur->ram_addr + cur_off) % data_byte_width; size_t off = (cur->ram_addr + cur_off) % data_byte_width;
size_t cur_len = (cur->len - cur_off > data_byte_width - off ? size_t cur_len =
data_byte_width - off : cur->len - cur_off); (cur->len - cur_off > data_byte_width - off ? data_byte_width - off
for (size_t i = 0; i < cur_len; i++, off++) { : cur->len - cur_off);
size_t byte_off = (off % 4); for (size_t i = 0; i < cur_len; i++, off++) {
cur->data[cur_off + i] = (p.mem_data[off / 4] >> (byte_off * 8)) & size_t byte_off = (off % 4);
0xff; cur->data[cur_off + i] = (p.mem_data[off / 4] >> (byte_off * 8)) & 0xff;
} }
cur_off += cur_len; cur_off += cur_len;
if (cur_off == cur->len) { if (cur_off == cur->len) {
/* operation is done */ /* operation is done */
pending.pop_front(); pending.pop_front();
cur->engine->mem_op_complete(cur); cur->engine->mem_op_complete(cur);
cur_off = 0; cur_off = 0;
} else { } else {
/* operation is not done yet, we'll pick it back up */ /* operation is not done yet, we'll pick it back up */
} }
cur = 0; cur = 0;
} else if (!cur && !pending.empty()) { } else if (!cur && !pending.empty()) {
cur = pending.front(); cur = pending.front();
size_t data_offset = (cur->ram_addr + cur_off) % data_byte_width; size_t data_offset = (cur->ram_addr + cur_off) % data_byte_width;
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
std::cerr << "issuing op=" << cur << " read from " << std::hex << std::cerr << "issuing op=" << cur << " read from " << std::hex
cur->ram_addr << std::endl; << cur->ram_addr << std::endl;
std::cerr << " off=" << data_offset << std::endl; std::cerr << " off=" << data_offset << std::endl;
#endif #endif
/* first reset everything */ /* first reset everything */
p.mem_sel = 0; p.mem_sel = 0;
p.mem_addr[0] = p.mem_addr[1] = p.mem_addr[2] = 0; p.mem_addr[0] = p.mem_addr[1] = p.mem_addr[2] = 0;
p.mem_valid = 0x0; p.mem_valid = 0x0;
/* put data bytes in the right places */
/* put data bytes in the right places */ size_t off = data_offset;
size_t off = data_offset; size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset
size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset ? ? data_byte_width - data_offset
data_byte_width - data_offset : cur->len - cur_off); : cur->len - cur_off);
for (size_t i = 0; i < cur_len; i++, off++) { for (size_t i = 0; i < cur_len; i++, off++) {
p.mem_valid |= (1 << (off / (SEG_WIDTH / 8))); p.mem_valid |= (1 << (off / (SEG_WIDTH / 8)));
} }
// p.mem_resready = p.mem_valid; // p.mem_resready = p.mem_valid;
p.mem_resready = 0xff; p.mem_resready = 0xff;
uint64_t seg_addr = (cur->ram_addr + cur_off) / data_byte_width; uint64_t seg_addr = (cur->ram_addr + cur_off) / data_byte_width;
size_t seg_addr_bits = 12; size_t seg_addr_bits = 12;
// iterate over the address bit by bit // iterate over the address bit by bit
for (size_t i = 0; i < seg_addr_bits; i++) { for (size_t i = 0; i < seg_addr_bits; i++) {
uint32_t bit = ((seg_addr >> i) & 0x1); uint32_t bit = ((seg_addr >> i) & 0x1);
// iterate over the segments // iterate over the segments
for (size_t j = 0; j < SEG_COUNT; j++) { for (size_t j = 0; j < SEG_COUNT; j++) {
size_t dst_bit = j * seg_addr_bits + i; size_t dst_bit = j * seg_addr_bits + i;
p.mem_addr[dst_bit / 32] |= (bit << (dst_bit % 32)); p.mem_addr[dst_bit / 32] |= (bit << (dst_bit % 32));
} }
} }
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
for (size_t i = 0; i < 3; i++) for (size_t i = 0; i < 3; i++)
std::cerr << " addr = " << p.mem_addr[i] << std::endl; std::cerr << " addr = " << p.mem_addr[i] << std::endl;
std::cerr << " mem_valid = " << (unsigned) p.mem_valid << std::endl; std::cerr << " mem_valid = " << (unsigned)p.mem_valid << std::endl;
#endif #endif
} }
} }
void MemReader::op_issue(DMAOp *op) void MemReader::op_issue(DMAOp *op) {
{
#ifdef MEM_DEBUG #ifdef MEM_DEBUG
std::cerr << "enqueued read from " << op->ram_addr << std::endl; std::cerr << "enqueued read from " << op->ram_addr << std::endl;
#endif #endif
pending.push_back(op); pending.push_back(op);
} }
...@@ -25,91 +25,93 @@ ...@@ -25,91 +25,93 @@
#ifndef MEM_H_ #ifndef MEM_H_
#define MEM_H_ #define MEM_H_
#include <deque>
#include <verilated.h> #include <verilated.h>
#include <deque>
#include "sims/nic/corundum/obj_dir/Vinterface.h" #include "sims/nic/corundum/obj_dir/Vinterface.h"
class DMAOp; class DMAOp;
struct MemReadPort { struct MemReadPort {
/* outputs to memory */ /* outputs to memory */
vluint8_t &mem_sel; vluint8_t &mem_sel;
vluint32_t (&mem_addr)[3]; vluint32_t (&mem_addr)[3];
vluint8_t &mem_valid; vluint8_t &mem_valid;
vluint8_t &mem_resready; vluint8_t &mem_resready;
/* inputs from memory */ /* inputs from memory */
vluint32_t (&mem_data)[32]; vluint32_t (&mem_data)[32];
vluint8_t &mem_ready; vluint8_t &mem_ready;
vluint8_t &mem_resvalid; /* for read only */ vluint8_t &mem_resvalid; /* for read only */
MemReadPort(vluint8_t &mem_sel_, vluint32_t (&mem_addr_)[3], MemReadPort(vluint8_t &mem_sel_, vluint32_t (&mem_addr_)[3],
vluint8_t &mem_valid_, vluint8_t &mem_resready_, vluint8_t &mem_valid_, vluint8_t &mem_resready_,
vluint32_t (&mem_data_)[32], vluint8_t &mem_ready_, vluint32_t (&mem_data_)[32], vluint8_t &mem_ready_,
vluint8_t &mem_resvalid_) vluint8_t &mem_resvalid_)
: mem_sel(mem_sel_), mem_addr(mem_addr_), mem_valid(mem_valid_), : mem_sel(mem_sel_),
mem_resready(mem_resready_), mem_data(mem_data_), mem_ready(mem_ready_), mem_addr(mem_addr_),
mem_resvalid(mem_resvalid_) mem_valid(mem_valid_),
{ mem_resready(mem_resready_),
} mem_data(mem_data_),
mem_ready(mem_ready_),
mem_resvalid(mem_resvalid_) {
}
}; };
struct MemWritePort { struct MemWritePort {
/* outputs to memory */ /* outputs to memory */
vluint8_t &mem_sel; vluint8_t &mem_sel;
vluint32_t (&mem_be)[4]; /* for write only */ vluint32_t (&mem_be)[4]; /* for write only */
vluint32_t (&mem_addr)[3]; vluint32_t (&mem_addr)[3];
vluint32_t (&mem_data)[32]; vluint32_t (&mem_data)[32];
vluint8_t &mem_valid; vluint8_t &mem_valid;
/* inputs from memory */ /* inputs from memory */
vluint8_t &mem_ready; vluint8_t &mem_ready;
MemWritePort(vluint8_t &mem_sel_, vluint32_t (&mem_be_)[4], MemWritePort(vluint8_t &mem_sel_, vluint32_t (&mem_be_)[4],
vluint32_t (&mem_addr_)[3], vluint32_t (&mem_data_)[32], vluint32_t (&mem_addr_)[3], vluint32_t (&mem_data_)[32],
vluint8_t &mem_valid_, vluint8_t &mem_ready_) vluint8_t &mem_valid_, vluint8_t &mem_ready_)
: mem_sel(mem_sel_), mem_be(mem_be_), mem_addr(mem_addr_), : mem_sel(mem_sel_),
mem_data(mem_data_), mem_valid(mem_valid_), mem_ready(mem_ready_) mem_be(mem_be_),
{ mem_addr(mem_addr_),
} mem_data(mem_data_),
mem_valid(mem_valid_),
mem_ready(mem_ready_) {
}
}; };
class MemReader { class MemReader {
protected: protected:
MemReadPort &p; MemReadPort &p;
std::deque<DMAOp *> pending; std::deque<DMAOp *> pending;
DMAOp *cur; DMAOp *cur;
size_t cur_off; size_t cur_off;
public: public:
MemReader(MemReadPort &p_) MemReader(MemReadPort &p_) : p(p_), cur(0), cur_off(0) {
: p(p_), cur(0), cur_off(0) }
{
}
void step(); void step();
void op_issue(DMAOp *op); void op_issue(DMAOp *op);
}; };
class MemWriter { class MemWriter {
protected: protected:
MemWritePort &p; MemWritePort &p;
std::deque<DMAOp *> pending; std::deque<DMAOp *> pending;
DMAOp *cur; DMAOp *cur;
size_t cur_off; size_t cur_off;
public: public:
MemWriter(MemWritePort &p_) MemWriter(MemWritePort &p_) : p(p_), cur(0), cur_off(0) {
: p(p_), cur(0), cur_off(0) }
{
}
void step(); void step();
void op_issue(DMAOp *op); void op_issue(DMAOp *op);
}; };
#endif // MEM_H_ #endif // MEM_H_
...@@ -22,798 +22,697 @@ ...@@ -22,798 +22,697 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#include <stdlib.h> #include "sims/nic/corundum_bm/corundum_bm.h"
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <unistd.h> #include <unistd.h>
#include <signal.h>
#include <cassert>
#include "sims/nic/corundum_bm/corundum_bm.h" #include <cassert>
static nicbm::Runner *runner; static nicbm::Runner *runner;
namespace corundum { namespace corundum {
DescRing::DescRing() DescRing::DescRing()
: _dmaAddr(0), _sizeLog(0), _size(0), _sizeMask(0), : _dmaAddr(0),
_index(0), _headPtr(0), _tailPtr(0), _sizeLog(0),
_currHead(0), _currTail(0), active(false), armed(false) _size(0),
{ _sizeMask(0),
_index(0),
_headPtr(0),
_tailPtr(0),
_currHead(0),
_currTail(0),
active(false),
armed(false) {
} }
DescRing::~DescRing() DescRing::~DescRing() {
{
} }
addr_t DescRing::dmaAddr() {
addr_t return this->_dmaAddr;
DescRing::dmaAddr()
{
return this->_dmaAddr;
} }
size_t size_t DescRing::sizeLog() {
DescRing::sizeLog() return this->_sizeLog;
{
return this->_sizeLog;
} }
unsigned unsigned DescRing::index() {
DescRing::index() return this->_index;
{
return this->_index;
} }
ptr_t ptr_t DescRing::headPtr() {
DescRing::headPtr() return this->_headPtr;
{
return this->_headPtr;
} }
ptr_t ptr_t DescRing::tailPtr() {
DescRing::tailPtr() return this->_tailPtr;
{
return this->_tailPtr;
} }
void void DescRing::setDMALower(uint32_t addr) {
DescRing::setDMALower(uint32_t addr) this->_dmaAddr &= 0xFFFFFFFF00000000;
{ this->_dmaAddr |= (addr_t)addr;
this->_dmaAddr &= 0xFFFFFFFF00000000;
this->_dmaAddr |= (addr_t)addr;
} }
void void DescRing::setDMAUpper(uint32_t addr) {
DescRing::setDMAUpper(uint32_t addr) this->_dmaAddr &= 0xFFFFFFFF;
{ this->_dmaAddr |= ((addr_t)addr << 32);
this->_dmaAddr &= 0xFFFFFFFF;
this->_dmaAddr |= ((addr_t)addr << 32);
} }
void void DescRing::setSizeLog(size_t size_log) {
DescRing::setSizeLog(size_t size_log) if (size_log & QUEUE_ACTIVE_MASK) {
{ this->active = true;
if (size_log & QUEUE_ACTIVE_MASK) { } else {
this->active = true; this->active = false;
} else { }
this->active = false;
}
this->_sizeLog = size_log & 0xFF; this->_sizeLog = size_log & 0xFF;
this->_size = 1 << this->_sizeLog; this->_size = 1 << this->_sizeLog;
this->_sizeMask = this->_size - 1; this->_sizeMask = this->_size - 1;
this->cplDma.resize(this->_size, false); this->cplDma.resize(this->_size, false);
} }
void void DescRing::setIndex(unsigned index) {
DescRing::setIndex(unsigned index) assert(!(index & QUEUE_CONT_MASK));
{ if (index & QUEUE_ARM_MASK) {
assert(!(index & QUEUE_CONT_MASK)); this->armed = true;
if (index & QUEUE_ARM_MASK) { }
this->armed = true; this->_index = index & 0xFF;
}
this->_index = index & 0xFF;
} }
void void DescRing::setHeadPtr(ptr_t ptr) {
DescRing::setHeadPtr(ptr_t ptr) this->_headPtr = ptr;
{
this->_headPtr = ptr;
} }
void void DescRing::setTailPtr(ptr_t ptr) {
DescRing::setTailPtr(ptr_t ptr) this->_tailPtr = ptr;
{
this->_tailPtr = ptr;
} }
bool bool DescRing::empty() {
DescRing::empty() return (this->_headPtr == this->_currTail);
{
return (this->_headPtr == this->_currTail);
} }
bool bool DescRing::full() {
DescRing::full() return (this->_currHead - this->_tailPtr >= this->_size);
{
return (this->_currHead - this->_tailPtr >= this->_size);
} }
bool DescRing::updatePtr(ptr_t ptr, bool head) {
ptr_t curr_ptr = head ? this->_headPtr : this->_tailPtr;
if (ptr != curr_ptr) {
// out of order completion
this->cplDma[ptr & this->_sizeMask] = true;
return false;
}
/* Safe to update the pointer. Also check if any DMA is completed
* out-of-order in front of us.
*/
curr_ptr = ptr & this->_sizeMask;
bool do {
DescRing::updatePtr(ptr_t ptr, bool head) if (head) {
{ this->_headPtr++;
ptr_t curr_ptr = head ? this->_headPtr : this->_tailPtr; } else {
if (ptr != curr_ptr) { this->_tailPtr++;
// out of order completion
this->cplDma[ptr & this->_sizeMask] = true;
return false;
} }
/* Safe to update the pointer. Also check if any DMA is completed this->cplDma[curr_ptr] = false;
* out-of-order in front of us. curr_ptr = (curr_ptr + 1) & this->_sizeMask;
*/ } while (this->cplDma.at(curr_ptr));
curr_ptr = ptr & this->_sizeMask; return true;
do {
if (head) {
this->_headPtr++;
} else {
this->_tailPtr++;
}
this->cplDma[curr_ptr] = false;
curr_ptr = (curr_ptr + 1) & this->_sizeMask;
} while (this->cplDma.at(curr_ptr));
return true;
} }
EventRing::EventRing() EventRing::EventRing() {
{
} }
EventRing::~EventRing() EventRing::~EventRing() {
{
} }
void void EventRing::dmaDone(DMAOp *op) {
EventRing::dmaDone(DMAOp *op) assert(op->write);
{ switch (op->type) {
assert(op->write);
switch (op->type) {
case DMA_TYPE_EVENT: case DMA_TYPE_EVENT:
if (updatePtr((ptr_t)op->tag, true)) { if (updatePtr((ptr_t)op->tag, true)) {
runner->msi_issue(0); runner->msi_issue(0);
} }
delete op; delete op;
break; break;
default: default:
fprintf(stderr, "Unknown DMA type %u\n", op->type); fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort(); abort();
} }
} }
void void EventRing::issueEvent(unsigned type, unsigned source) {
EventRing::issueEvent(unsigned type, unsigned source) assert(type == EVENT_TYPE_TX_CPL || type == EVENT_TYPE_RX_CPL);
{ if (this->armed) {
assert(type == EVENT_TYPE_TX_CPL || type == EVENT_TYPE_RX_CPL); if (full()) {
if (this->armed) { fprintf(stderr, "Event ring is rull\n");
if (full()) { return;
fprintf(stderr, "Event ring is rull\n");
return;
}
addr_t dma_addr = this->_dmaAddr + (this->_currHead & this->_sizeMask) *
EVENT_SIZE;
/* Issue DMA write */
DMAOp *op = new DMAOp;
op->type = DMA_TYPE_EVENT;
op->dma_addr = dma_addr;
op->len = EVENT_SIZE;
op->ring = this;
op->tag = this->_currHead;
op->write = true;
Event *event = (Event *)op->data;
memset(event, 0, sizeof(Event));
event->type = type;
event->source = source;
runner->issue_dma(*op);
this->_currHead++;
this->armed = false;
} }
addr_t dma_addr =
this->_dmaAddr + (this->_currHead & this->_sizeMask) * EVENT_SIZE;
/* Issue DMA write */
DMAOp *op = new DMAOp;
op->type = DMA_TYPE_EVENT;
op->dma_addr = dma_addr;
op->len = EVENT_SIZE;
op->ring = this;
op->tag = this->_currHead;
op->write = true;
Event *event = (Event *)op->data;
memset(event, 0, sizeof(Event));
event->type = type;
event->source = source;
runner->issue_dma(*op);
this->_currHead++;
this->armed = false;
}
} }
CplRing::CplRing(EventRing *eventRing) CplRing::CplRing(EventRing *eventRing) : eventRing(eventRing) {
: eventRing(eventRing)
{
} }
CplRing::~CplRing() CplRing::~CplRing() {
{
} }
void void CplRing::dmaDone(DMAOp *op) {
CplRing::dmaDone(DMAOp *op) assert(op->write);
{ switch (op->type) {
assert(op->write);
switch (op->type) {
case DMA_TYPE_TX_CPL: case DMA_TYPE_TX_CPL:
case DMA_TYPE_RX_CPL: { case DMA_TYPE_RX_CPL: {
if (updatePtr((ptr_t)op->tag, true)) { if (updatePtr((ptr_t)op->tag, true)) {
unsigned type = op->type == DMA_TYPE_TX_CPL ? EVENT_TYPE_TX_CPL : unsigned type =
EVENT_TYPE_RX_CPL; op->type == DMA_TYPE_TX_CPL ? EVENT_TYPE_TX_CPL : EVENT_TYPE_RX_CPL;
this->eventRing->issueEvent(type, 0); this->eventRing->issueEvent(type, 0);
} }
delete op; delete op;
break; break;
} }
default: default:
fprintf(stderr, "Unknown DMA type %u\n", op->type); fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort(); abort();
} }
}
void CplRing::complete(unsigned index, size_t len, bool tx) {
CplData data;
data.index = index;
data.len = len;
data.tx = tx;
this->pending.push_back(data);
while (!full() && !this->pending.empty()) {
CplData &data = this->pending.front();
addr_t dma_addr =
this->_dmaAddr + (this->_currHead & this->_sizeMask) * CPL_SIZE;
/* Issue DMA write */
DMAOp *op = new DMAOp;
op->type = data.tx ? DMA_TYPE_TX_CPL : DMA_TYPE_RX_CPL;
op->dma_addr = dma_addr;
op->len = CPL_SIZE;
op->ring = this;
op->tag = this->_currHead;
op->write = true;
Cpl *cpl = (Cpl *)op->data;
memset(cpl, 0, sizeof(Cpl));
cpl->index = data.index;
cpl->len = data.len;
this->pending.pop_front();
runner->issue_dma(*op);
this->_currHead++;
}
} }
void TxRing::TxRing(CplRing *cplRing) : txCplRing(cplRing) {
CplRing::complete(unsigned index, size_t len, bool tx)
{
CplData data;
data.index = index;
data.len = len;
data.tx = tx;
this->pending.push_back(data);
while (!full() && !this->pending.empty()) {
CplData &data = this->pending.front();
addr_t dma_addr = this->_dmaAddr + (this->_currHead & this->_sizeMask) *
CPL_SIZE;
/* Issue DMA write */
DMAOp *op = new DMAOp;
op->type = data.tx ? DMA_TYPE_TX_CPL : DMA_TYPE_RX_CPL;
op->dma_addr = dma_addr;
op->len = CPL_SIZE;
op->ring = this;
op->tag = this->_currHead;
op->write = true;
Cpl *cpl = (Cpl *)op->data;
memset(cpl, 0, sizeof(Cpl));
cpl->index = data.index;
cpl->len = data.len;
this->pending.pop_front();
runner->issue_dma(*op);
this->_currHead++;
}
} }
TxRing::TxRing(CplRing *cplRing) TxRing::~TxRing() {
: txCplRing(cplRing) }
{
} void TxRing::setHeadPtr(ptr_t ptr) {
DescRing::setHeadPtr(ptr);
TxRing::~TxRing() while (this->_currTail != this->_headPtr) {
{ unsigned index = this->_currTail & this->_sizeMask;
} addr_t dma_addr = this->_dmaAddr + index * DESC_SIZE;
/* Issue DMA read */
void DMAOp *op = new DMAOp;
TxRing::setHeadPtr(ptr_t ptr) op->type = DMA_TYPE_DESC;
{ op->dma_addr = dma_addr;
DescRing::setHeadPtr(ptr); op->len = DESC_SIZE;
while (this->_currTail != this->_headPtr) { op->ring = this;
unsigned index = this->_currTail & this->_sizeMask; op->tag = this->_currTail;
addr_t dma_addr = this->_dmaAddr + index * DESC_SIZE; op->write = false;
/* Issue DMA read */ runner->issue_dma(*op);
DMAOp *op = new DMAOp; this->_currTail++;
op->type = DMA_TYPE_DESC; }
op->dma_addr = dma_addr;
op->len = DESC_SIZE;
op->ring = this;
op->tag = this->_currTail;
op->write = false;
runner->issue_dma(*op);
this->_currTail++;
}
} }
void void TxRing::dmaDone(DMAOp *op) {
TxRing::dmaDone(DMAOp *op) switch (op->type) {
{
switch (op->type) {
case DMA_TYPE_DESC: { case DMA_TYPE_DESC: {
assert(!op->write); assert(!op->write);
Desc *desc = (Desc *)op->data; Desc *desc = (Desc *)op->data;
op->type = DMA_TYPE_MEM; op->type = DMA_TYPE_MEM;
op->dma_addr = desc->addr; op->dma_addr = desc->addr;
op->len = desc->len; op->len = desc->len;
op->write = false; op->write = false;
runner->issue_dma(*op); runner->issue_dma(*op);
break; break;
} }
case DMA_TYPE_MEM: case DMA_TYPE_MEM:
assert(!op->write); assert(!op->write);
runner->eth_send(op->data, op->len); runner->eth_send(op->data, op->len);
updatePtr((ptr_t)op->tag, false); updatePtr((ptr_t)op->tag, false);
this->txCplRing->complete(op->tag, op->len, true); this->txCplRing->complete(op->tag, op->len, true);
delete op; delete op;
break; break;
default: default:
fprintf(stderr, "Unknown DMA type %u\n", op->type); fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort(); abort();
} }
} }
RxRing::RxRing(CplRing *cplRing) RxRing::RxRing(CplRing *cplRing) : rxCplRing(cplRing) {
: rxCplRing(cplRing)
{
} }
RxRing::~RxRing() RxRing::~RxRing() {
{
} }
void void RxRing::dmaDone(DMAOp *op) {
RxRing::dmaDone(DMAOp *op) switch (op->type) {
{
switch (op->type) {
case DMA_TYPE_DESC: { case DMA_TYPE_DESC: {
assert(!op->write); assert(!op->write);
Desc *desc = (Desc *)op->data; Desc *desc = (Desc *)op->data;
op->type = DMA_TYPE_MEM; op->type = DMA_TYPE_MEM;
op->dma_addr = desc->addr; op->dma_addr = desc->addr;
op->len = op->rx_data->len; op->len = op->rx_data->len;
memcpy((void *)op->data, (void *)op->rx_data->data, op->len); memcpy((void *)op->data, (void *)op->rx_data->data, op->len);
delete op->rx_data; delete op->rx_data;
op->write = true; op->write = true;
runner->issue_dma(*op); runner->issue_dma(*op);
break; break;
} }
case DMA_TYPE_MEM: case DMA_TYPE_MEM:
assert(op->write); assert(op->write);
updatePtr((ptr_t)op->tag, false); updatePtr((ptr_t)op->tag, false);
this->rxCplRing->complete(op->tag, op->len, false); this->rxCplRing->complete(op->tag, op->len, false);
delete op; delete op;
break; break;
default: default:
fprintf(stderr, "Unknown DMA type %u\n", op->type); fprintf(stderr, "Unknown DMA type %u\n", op->type);
abort(); abort();
} }
} }
void void RxRing::rx(RxData *rx_data) {
RxRing::rx(RxData *rx_data) if (empty()) {
{ delete rx_data;
if (empty()) { return;
delete rx_data; }
return; addr_t dma_addr =
} this->_dmaAddr + (this->_currTail & this->_sizeMask) * DESC_SIZE;
addr_t dma_addr = this->_dmaAddr + (this->_currTail & this->_sizeMask) * /* Issue DMA read */
DESC_SIZE; DMAOp *op = new DMAOp;
/* Issue DMA read */ op->type = DMA_TYPE_DESC;
DMAOp *op = new DMAOp; op->dma_addr = dma_addr;
op->type = DMA_TYPE_DESC; op->len = DESC_SIZE;
op->dma_addr = dma_addr; op->ring = this;
op->len = DESC_SIZE; op->rx_data = rx_data;
op->ring = this; op->tag = this->_currTail;
op->rx_data = rx_data; op->write = false;
op->tag = this->_currTail; runner->issue_dma(*op);
op->write = false; this->_currTail++;
runner->issue_dma(*op);
this->_currTail++;
} }
Port::Port() Port::Port()
: _id(0), _features(0), _mtu(0), : _id(0),
_schedCount(0), _schedOffset(0), _schedStride(0), _features(0),
_schedType(0), _rssMask(0), _schedEnable(false), _mtu(0),
_queueEnable(false) _schedCount(0),
{ _schedOffset(0),
_schedStride(0),
_schedType(0),
_rssMask(0),
_schedEnable(false),
_queueEnable(false) {
} }
Port::~Port() Port::~Port() {
{
} }
unsigned unsigned Port::id() {
Port::id() return this->_id;
{
return this->_id;
} }
unsigned unsigned Port::features() {
Port::features() return this->_features;
{
return this->_features;
} }
size_t size_t Port::mtu() {
Port::mtu() return this->_mtu;
{
return this->_mtu;
} }
size_t size_t Port::schedCount() {
Port::schedCount() return this->_schedCount;
{
return this->_schedCount;
} }
addr_t addr_t Port::schedOffset() {
Port::schedOffset() return this->_schedOffset;
{
return this->_schedOffset;
} }
addr_t addr_t Port::schedStride() {
Port::schedStride() return this->_schedStride;
{
return this->_schedStride;
} }
unsigned unsigned Port::schedType() {
Port::schedType() return this->_schedType;
{
return this->_schedType;
} }
unsigned Port::rssMask() {
unsigned return this->_rssMask;
Port::rssMask()
{
return this->_rssMask;
} }
void void Port::setId(unsigned id) {
Port::setId(unsigned id) this->_id = id;
{
this->_id = id;
} }
void void Port::setFeatures(unsigned features) {
Port::setFeatures(unsigned features) this->_features =
{ features & (IF_FEATURE_RSS | IF_FEATURE_PTP_TS | IF_FEATURE_TX_CSUM |
this->_features = features & (IF_FEATURE_RSS | IF_FEATURE_RX_CSUM | IF_FEATURE_RX_HASH);
IF_FEATURE_PTP_TS |
IF_FEATURE_TX_CSUM |
IF_FEATURE_RX_CSUM |
IF_FEATURE_RX_HASH);
} }
void void Port::setMtu(size_t mtu) {
Port::setMtu(size_t mtu) this->_mtu = mtu;
{
this->_mtu = mtu;
} }
void void Port::setSchedCount(size_t count) {
Port::setSchedCount(size_t count) this->_schedCount = count;
{
this->_schedCount = count;
} }
void void Port::setSchedOffset(addr_t offset) {
Port::setSchedOffset(addr_t offset) this->_schedOffset = offset;
{
this->_schedOffset = offset;
} }
void void Port::setSchedStride(addr_t stride) {
Port::setSchedStride(addr_t stride) this->_schedStride = stride;
{
this->_schedStride = stride;
} }
void void Port::setSchedType(unsigned type) {
Port::setSchedType(unsigned type) this->_schedType = type;
{
this->_schedType = type;
} }
void void Port::setRssMask(unsigned mask) {
Port::setRssMask(unsigned mask) this->_rssMask = mask;
{
this->_rssMask = mask;
} }
void void Port::schedEnable() {
Port::schedEnable() this->_schedEnable = true;
{
this->_schedEnable = true;
} }
void void Port::schedDisable() {
Port::schedDisable() this->_schedEnable = false;
{
this->_schedEnable = false;
} }
void void Port::queueEnable() {
Port::queueEnable() this->_queueEnable = true;
{
this->_queueEnable = true;
} }
void void Port::queueDisable() {
Port::queueDisable() this->_queueEnable = false;
{
this->_queueEnable = false;
} }
Corundum::Corundum() Corundum::Corundum()
: txCplRing(&this->eventRing), rxCplRing(&this->eventRing), : txCplRing(&this->eventRing),
txRing(&this->txCplRing), rxRing(&this->rxCplRing), features(0) rxCplRing(&this->eventRing),
{ txRing(&this->txCplRing),
this->port.setId(0); rxRing(&this->rxCplRing),
this->port.setFeatures(this->features); features(0) {
this->port.setMtu(2048); this->port.setId(0);
this->port.setSchedCount(1); this->port.setFeatures(this->features);
this->port.setSchedOffset(0x100000); this->port.setMtu(2048);
this->port.setSchedStride(0x100000); this->port.setSchedCount(1);
this->port.setSchedType(0); this->port.setSchedOffset(0x100000);
this->port.setRssMask(0); this->port.setSchedStride(0x100000);
this->port.schedDisable(); this->port.setSchedType(0);
} this->port.setRssMask(0);
this->port.schedDisable();
Corundum::~Corundum() }
{
} Corundum::~Corundum() {
}
reg_t
Corundum::reg_read(uint8_t bar, addr_t addr) reg_t Corundum::reg_read(uint8_t bar, addr_t addr) {
{ switch (addr) {
switch (addr) { case REG_FW_ID:
case REG_FW_ID: return 32;
return 32; case REG_FW_VER:
case REG_FW_VER: return 1;
return 1; case REG_BOARD_ID:
case REG_BOARD_ID: return 0x43215678;
return 0x43215678; case REG_BOARD_VER:
case REG_BOARD_VER: return 1;
return 1; case REG_PHC_COUNT:
case REG_PHC_COUNT: return 1;
return 1; case REG_PHC_OFFSET:
case REG_PHC_OFFSET: return 0x200;
return 0x200; case REG_PHC_STRIDE:
case REG_PHC_STRIDE: return 0x80;
return 0x80; case REG_IF_COUNT:
case REG_IF_COUNT: return 1;
return 1; case REG_IF_STRIDE:
case REG_IF_STRIDE: return 0x80000;
return 0x80000; case REG_IF_CSR_OFFSET:
case REG_IF_CSR_OFFSET: return 0x80000;
return 0x80000; case PHC_REG_FEATURES:
case PHC_REG_FEATURES: return 0x1;
return 0x1; case PHC_REG_PTP_CUR_SEC_L:
case PHC_REG_PTP_CUR_SEC_L: return 0x0;
return 0x0; case PHC_REG_PTP_CUR_SEC_H:
case PHC_REG_PTP_CUR_SEC_H: return 0x0;
return 0x0; case IF_REG_IF_ID:
case IF_REG_IF_ID: return 0;
return 0; case IF_REG_IF_FEATURES:
case IF_REG_IF_FEATURES: return this->features;
return this->features; case IF_REG_EVENT_QUEUE_COUNT:
case IF_REG_EVENT_QUEUE_COUNT: return 1;
return 1; case IF_REG_EVENT_QUEUE_OFFSET:
case IF_REG_EVENT_QUEUE_OFFSET: return 0x100000;
return 0x100000; case IF_REG_TX_QUEUE_COUNT:
case IF_REG_TX_QUEUE_COUNT: return 1;
return 1; case IF_REG_TX_QUEUE_OFFSET:
case IF_REG_TX_QUEUE_OFFSET: return 0x200000;
return 0x200000; case IF_REG_TX_CPL_QUEUE_COUNT:
case IF_REG_TX_CPL_QUEUE_COUNT: return 1;
return 1; case IF_REG_TX_CPL_QUEUE_OFFSET:
case IF_REG_TX_CPL_QUEUE_OFFSET: return 0x400000;
return 0x400000; case IF_REG_RX_QUEUE_COUNT:
case IF_REG_RX_QUEUE_COUNT: return 1;
return 1; case IF_REG_RX_QUEUE_OFFSET:
case IF_REG_RX_QUEUE_OFFSET: return 0x600000;
return 0x600000; case IF_REG_RX_CPL_QUEUE_COUNT:
case IF_REG_RX_CPL_QUEUE_COUNT: return 1;
return 1; case IF_REG_RX_CPL_QUEUE_OFFSET:
case IF_REG_RX_CPL_QUEUE_OFFSET: return 0x700000;
return 0x700000; case IF_REG_PORT_COUNT:
case IF_REG_PORT_COUNT: return 1;
return 1; case IF_REG_PORT_OFFSET:
case IF_REG_PORT_OFFSET: return 0x800000;
return 0x800000; case IF_REG_PORT_STRIDE:
case IF_REG_PORT_STRIDE: return 0x200000;
return 0x200000; case EVENT_QUEUE_HEAD_PTR_REG:
case EVENT_QUEUE_HEAD_PTR_REG: return this->eventRing.headPtr();
return this->eventRing.headPtr(); case TX_QUEUE_ACTIVE_LOG_SIZE_REG:
case TX_QUEUE_ACTIVE_LOG_SIZE_REG: return this->txRing.sizeLog();
return this->txRing.sizeLog(); case TX_QUEUE_TAIL_PTR_REG:
case TX_QUEUE_TAIL_PTR_REG: return this->txRing.tailPtr();
return this->txRing.tailPtr(); case TX_CPL_QUEUE_HEAD_PTR_REG:
case TX_CPL_QUEUE_HEAD_PTR_REG: return this->txCplRing.headPtr();
return this->txCplRing.headPtr(); case RX_QUEUE_TAIL_PTR_REG:
case RX_QUEUE_TAIL_PTR_REG: return this->rxRing.tailPtr();
return this->rxRing.tailPtr(); case RX_CPL_QUEUE_HEAD_PTR_REG:
case RX_CPL_QUEUE_HEAD_PTR_REG: return this->rxCplRing.headPtr();
return this->rxCplRing.headPtr(); case PORT_REG_PORT_ID:
case PORT_REG_PORT_ID: return this->port.id();
return this->port.id(); case PORT_REG_PORT_FEATURES:
case PORT_REG_PORT_FEATURES: return this->port.features();
return this->port.features(); case PORT_REG_PORT_MTU:
case PORT_REG_PORT_MTU: return this->port.mtu();
return this->port.mtu(); case PORT_REG_SCHED_COUNT:
case PORT_REG_SCHED_COUNT: return this->port.schedCount();
return this->port.schedCount(); case PORT_REG_SCHED_OFFSET:
case PORT_REG_SCHED_OFFSET: return this->port.schedOffset();
return this->port.schedOffset(); case PORT_REG_SCHED_STRIDE:
case PORT_REG_SCHED_STRIDE: return this->port.schedStride();
return this->port.schedStride(); case PORT_REG_SCHED_TYPE:
case PORT_REG_SCHED_TYPE: return this->port.schedType();
return this->port.schedType(); default:
default: fprintf(stderr, "Unknown register read %lx\n", addr);
fprintf(stderr, "Unknown register read %lx\n", addr); abort();
abort(); }
} }
}
void Corundum::reg_write(uint8_t bar, uint64_t addr, reg_t val) {
void switch (addr) {
Corundum::reg_write(uint8_t bar, uint64_t addr, reg_t val) case REG_FW_ID:
{ case REG_FW_VER:
switch (addr) { case REG_BOARD_ID:
case REG_FW_ID: case REG_BOARD_VER:
case REG_FW_VER: case REG_PHC_COUNT:
case REG_BOARD_ID: case REG_PHC_OFFSET:
case REG_BOARD_VER: case REG_PHC_STRIDE:
case REG_PHC_COUNT: case REG_IF_COUNT:
case REG_PHC_OFFSET: case REG_IF_STRIDE:
case REG_PHC_STRIDE: case REG_IF_CSR_OFFSET:
case REG_IF_COUNT: case PHC_REG_FEATURES:
case REG_IF_STRIDE: case PHC_REG_PTP_SET_FNS:
case REG_IF_CSR_OFFSET: case PHC_REG_PTP_SET_NS:
case PHC_REG_FEATURES: case PHC_REG_PTP_SET_SEC_L:
case PHC_REG_PTP_SET_FNS: case PHC_REG_PTP_SET_SEC_H:
case PHC_REG_PTP_SET_NS: break;
case PHC_REG_PTP_SET_SEC_L: case EVENT_QUEUE_BASE_ADDR_REG:
case PHC_REG_PTP_SET_SEC_H: this->eventRing.setDMALower(val);
break; break;
case EVENT_QUEUE_BASE_ADDR_REG: case EVENT_QUEUE_BASE_ADDR_REG + 4:
this->eventRing.setDMALower(val); this->eventRing.setDMAUpper(val);
break; break;
case EVENT_QUEUE_BASE_ADDR_REG + 4: case EVENT_QUEUE_ACTIVE_LOG_SIZE_REG:
this->eventRing.setDMAUpper(val); this->eventRing.setSizeLog(val);
break; break;
case EVENT_QUEUE_ACTIVE_LOG_SIZE_REG: case EVENT_QUEUE_INTERRUPT_INDEX_REG:
this->eventRing.setSizeLog(val); this->eventRing.setIndex(val);
break; break;
case EVENT_QUEUE_INTERRUPT_INDEX_REG: case EVENT_QUEUE_HEAD_PTR_REG:
this->eventRing.setIndex(val); this->eventRing.setHeadPtr(val);
break; break;
case EVENT_QUEUE_HEAD_PTR_REG: case EVENT_QUEUE_TAIL_PTR_REG:
this->eventRing.setHeadPtr(val); this->eventRing.setTailPtr(val);
break; break;
case EVENT_QUEUE_TAIL_PTR_REG: case TX_QUEUE_BASE_ADDR_REG:
this->eventRing.setTailPtr(val); this->txRing.setDMALower(val);
break; break;
case TX_QUEUE_BASE_ADDR_REG: case TX_QUEUE_BASE_ADDR_REG + 4:
this->txRing.setDMALower(val); this->txRing.setDMAUpper(val);
break; break;
case TX_QUEUE_BASE_ADDR_REG + 4: case TX_QUEUE_ACTIVE_LOG_SIZE_REG:
this->txRing.setDMAUpper(val); this->txRing.setSizeLog(val);
break; break;
case TX_QUEUE_ACTIVE_LOG_SIZE_REG: case TX_QUEUE_CPL_QUEUE_INDEX_REG:
this->txRing.setSizeLog(val); this->txRing.setIndex(val);
break; break;
case TX_QUEUE_CPL_QUEUE_INDEX_REG: case TX_QUEUE_HEAD_PTR_REG:
this->txRing.setIndex(val); this->txRing.setHeadPtr(val);
break; break;
case TX_QUEUE_HEAD_PTR_REG: case TX_QUEUE_TAIL_PTR_REG:
this->txRing.setHeadPtr(val); this->txRing.setTailPtr(val);
break; break;
case TX_QUEUE_TAIL_PTR_REG: case TX_CPL_QUEUE_BASE_ADDR_REG:
this->txRing.setTailPtr(val); this->txCplRing.setDMALower(val);
break; break;
case TX_CPL_QUEUE_BASE_ADDR_REG: case TX_CPL_QUEUE_BASE_ADDR_REG + 4:
this->txCplRing.setDMALower(val); this->txCplRing.setDMAUpper(val);
break; break;
case TX_CPL_QUEUE_BASE_ADDR_REG + 4: case TX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG:
this->txCplRing.setDMAUpper(val); this->txCplRing.setSizeLog(val);
break; break;
case TX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG: case TX_CPL_QUEUE_INTERRUPT_INDEX_REG:
this->txCplRing.setSizeLog(val); this->txCplRing.setIndex(val);
break; break;
case TX_CPL_QUEUE_INTERRUPT_INDEX_REG: case TX_CPL_QUEUE_HEAD_PTR_REG:
this->txCplRing.setIndex(val); this->txCplRing.setHeadPtr(val);
break; break;
case TX_CPL_QUEUE_HEAD_PTR_REG: case TX_CPL_QUEUE_TAIL_PTR_REG:
this->txCplRing.setHeadPtr(val); this->txCplRing.setTailPtr(val);
break; break;
case TX_CPL_QUEUE_TAIL_PTR_REG: case RX_QUEUE_BASE_ADDR_REG:
this->txCplRing.setTailPtr(val); this->rxRing.setDMALower(val);
break; break;
case RX_QUEUE_BASE_ADDR_REG: case RX_QUEUE_BASE_ADDR_REG + 4:
this->rxRing.setDMALower(val); this->rxRing.setDMAUpper(val);
break; break;
case RX_QUEUE_BASE_ADDR_REG + 4: case RX_QUEUE_ACTIVE_LOG_SIZE_REG:
this->rxRing.setDMAUpper(val); this->rxRing.setSizeLog(val);
break; break;
case RX_QUEUE_ACTIVE_LOG_SIZE_REG: case RX_QUEUE_CPL_QUEUE_INDEX_REG:
this->rxRing.setSizeLog(val); this->rxRing.setIndex(val);
break; break;
case RX_QUEUE_CPL_QUEUE_INDEX_REG: case RX_QUEUE_HEAD_PTR_REG:
this->rxRing.setIndex(val); this->rxRing.setHeadPtr(val);
break; break;
case RX_QUEUE_HEAD_PTR_REG: case RX_QUEUE_TAIL_PTR_REG:
this->rxRing.setHeadPtr(val); this->rxRing.setTailPtr(val);
break; break;
case RX_QUEUE_TAIL_PTR_REG: case RX_CPL_QUEUE_BASE_ADDR_REG:
this->rxRing.setTailPtr(val); this->rxCplRing.setDMALower(val);
break; break;
case RX_CPL_QUEUE_BASE_ADDR_REG: case RX_CPL_QUEUE_BASE_ADDR_REG + 4:
this->rxCplRing.setDMALower(val); this->rxCplRing.setDMAUpper(val);
break; break;
case RX_CPL_QUEUE_BASE_ADDR_REG + 4: case RX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG:
this->rxCplRing.setDMAUpper(val); this->rxCplRing.setSizeLog(val);
break; break;
case RX_CPL_QUEUE_ACTIVE_LOG_SIZE_REG: case RX_CPL_QUEUE_INTERRUPT_INDEX_REG:
this->rxCplRing.setSizeLog(val); this->rxCplRing.setIndex(val);
break; break;
case RX_CPL_QUEUE_INTERRUPT_INDEX_REG: case RX_CPL_QUEUE_HEAD_PTR_REG:
this->rxCplRing.setIndex(val); this->rxCplRing.setHeadPtr(val);
break; break;
case RX_CPL_QUEUE_HEAD_PTR_REG: case RX_CPL_QUEUE_TAIL_PTR_REG:
this->rxCplRing.setHeadPtr(val); this->rxCplRing.setTailPtr(val);
break; break;
case RX_CPL_QUEUE_TAIL_PTR_REG: case PORT_REG_SCHED_ENABLE:
this->rxCplRing.setTailPtr(val); if (val) {
break; this->port.schedEnable();
case PORT_REG_SCHED_ENABLE: } else {
if (val) { this->port.schedDisable();
this->port.schedEnable(); }
} else { break;
this->port.schedDisable(); case PORT_REG_RSS_MASK:
} this->port.setRssMask(val);
break; break;
case PORT_REG_RSS_MASK: case PORT_QUEUE_ENABLE:
this->port.setRssMask(val); if (val) {
break; this->port.queueEnable();
case PORT_QUEUE_ENABLE: } else {
if (val) { this->port.queueDisable();
this->port.queueEnable(); }
} else { break;
this->port.queueDisable(); default:
} fprintf(stderr, "Unknown register write %lx\n", addr);
break; abort();
default: }
fprintf(stderr, "Unknown register write %lx\n", addr);
abort();
}
} }
void void Corundum::setup_intro(struct cosim_pcie_proto_dev_intro &di) {
Corundum::setup_intro(struct cosim_pcie_proto_dev_intro &di) di.bars[0].len = 1 << 24;
{ di.bars[0].flags = COSIM_PCIE_PROTO_BAR_64;
di.bars[0].len = 1 << 24; di.pci_vendor_id = 0x5543;
di.bars[0].flags = COSIM_PCIE_PROTO_BAR_64; di.pci_device_id = 0x1001;
di.pci_vendor_id = 0x5543; di.pci_class = 0x02;
di.pci_device_id = 0x1001; di.pci_subclass = 0x00;
di.pci_class = 0x02; di.pci_revision = 0x00;
di.pci_subclass = 0x00; di.pci_msi_nvecs = 32;
di.pci_revision = 0x00;
di.pci_msi_nvecs = 32;
} }
void void Corundum::dma_complete(nicbm::DMAOp &op) {
Corundum::dma_complete(nicbm::DMAOp &op) DMAOp *op_ = reinterpret_cast<DMAOp *>(&op);
{ op_->ring->dmaDone(op_);
DMAOp *op_ = reinterpret_cast<DMAOp *>(&op);
op_->ring->dmaDone(op_);
} }
void void Corundum::eth_rx(uint8_t port, const void *data, size_t len) {
Corundum::eth_rx(uint8_t port, const void *data, size_t len) RxData *rx_data = new RxData;
{ memcpy((void *)rx_data->data, data, len);
RxData *rx_data = new RxData; rx_data->len = len;
memcpy((void *)rx_data->data, data, len); rxRing.rx(rx_data);
rx_data->len = len;
rxRing.rx(rx_data);
} }
} // namespace corundum } // namespace corundum
using namespace corundum; int main(int argc, char *argv[]) {
corundum::Corundum dev;
int main(int argc, char *argv[]) runner = new nicbm::Runner(dev);
{ return runner->runMain(argc, argv);
Corundum dev;
runner = new nicbm::Runner(dev);
return runner->runMain(argc, argv);
} }
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment