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

Reformat closer to google style

parent eb125a88
......@@ -22,183 +22,174 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <unistd.h>
#include <simbricks/netif/netsim.h>
#include "lib/simbricks/netif/internal.h"
static uint64_t current_epoch = 0;
int netsim_init(struct netsim_interface *nsif,
const char *eth_socket_path, int *sync_eth)
{
struct cosim_eth_proto_dev_intro di;
struct cosim_eth_proto_net_intro ni;
int cfd, shm_fd;
void *p;
if ((cfd = uxsocket_connect(eth_socket_path)) < 0) {
return -1;
}
memset(&ni, 0, sizeof(ni));
if (*sync_eth)
ni.flags |= COSIM_ETH_PROTO_FLAGS_NI_SYNC;
if (send(cfd, &ni, sizeof(ni), 0) != sizeof(ni)) {
perror("sending net intro failed");
return -1;
}
if (uxsocket_recv(cfd, &di, sizeof(di), &shm_fd)) {
return -1;
}
if ((p = shm_map(shm_fd)) == NULL) {
return -1;
}
close(shm_fd);
if ((di.flags & COSIM_ETH_PROTO_FLAGS_DI_SYNC) == 0) {
*sync_eth = 0;
nsif->sync = 0;
} else {
nsif->sync = *sync_eth;
}
nsif->d2n_queue = (uint8_t *) p + di.d2n_offset;
nsif->n2d_queue = (uint8_t *) p + di.n2d_offset;
nsif->d2n_elen = di.d2n_elen;
nsif->n2d_elen = di.n2d_elen;
nsif->d2n_enum = di.d2n_nentries;
nsif->n2d_enum = di.n2d_nentries;
nsif->d2n_pos = nsif->n2d_pos = 0;
nsif->d2n_timestamp = nsif->n2d_timestamp = 0;
return 0;
int netsim_init(struct netsim_interface *nsif, const char *eth_socket_path,
int *sync_eth) {
struct cosim_eth_proto_dev_intro di;
struct cosim_eth_proto_net_intro ni;
int cfd, shm_fd;
void *p;
if ((cfd = uxsocket_connect(eth_socket_path)) < 0) {
return -1;
}
memset(&ni, 0, sizeof(ni));
if (*sync_eth)
ni.flags |= COSIM_ETH_PROTO_FLAGS_NI_SYNC;
if (send(cfd, &ni, sizeof(ni), 0) != sizeof(ni)) {
perror("sending net intro failed");
return -1;
}
if (uxsocket_recv(cfd, &di, sizeof(di), &shm_fd)) {
return -1;
}
if ((p = shm_map(shm_fd)) == NULL) {
return -1;
}
close(shm_fd);
if ((di.flags & COSIM_ETH_PROTO_FLAGS_DI_SYNC) == 0) {
*sync_eth = 0;
nsif->sync = 0;
} else {
nsif->sync = *sync_eth;
}
nsif->d2n_queue = (uint8_t *)p + di.d2n_offset;
nsif->n2d_queue = (uint8_t *)p + di.n2d_offset;
nsif->d2n_elen = di.d2n_elen;
nsif->n2d_elen = di.n2d_elen;
nsif->d2n_enum = di.d2n_nentries;
nsif->n2d_enum = di.n2d_nentries;
nsif->d2n_pos = nsif->n2d_pos = 0;
nsif->d2n_timestamp = nsif->n2d_timestamp = 0;
return 0;
}
void netsim_cleanup(struct netsim_interface *nsif)
{
fprintf(stderr, "netsim_cleanup: TODO\n");
abort();
void netsim_cleanup(struct netsim_interface *nsif) {
fprintf(stderr, "netsim_cleanup: TODO\n");
abort();
}
volatile union cosim_eth_proto_d2n *netsim_d2n_poll(
struct netsim_interface *nsif, uint64_t timestamp)
{
volatile union cosim_eth_proto_d2n *msg =
(volatile union cosim_eth_proto_d2n *)
(nsif->d2n_queue + nsif->d2n_pos * nsif->d2n_elen);
/* message not ready */
if ((msg->dummy.own_type & COSIM_ETH_PROTO_D2N_OWN_MASK) !=
COSIM_ETH_PROTO_D2N_OWN_NET)
return NULL;
/* if in sync mode, wait till message is ready */
nsif->d2n_timestamp = msg->dummy.timestamp;
if (nsif->sync && nsif->d2n_timestamp > timestamp)
return NULL;
nsif->d2n_pos = (nsif->d2n_pos + 1) % nsif->d2n_enum;
return msg;
struct netsim_interface *nsif, uint64_t timestamp) {
volatile union cosim_eth_proto_d2n *msg =
(volatile union cosim_eth_proto_d2n *)(nsif->d2n_queue +
nsif->d2n_pos * nsif->d2n_elen);
/* message not ready */
if ((msg->dummy.own_type & COSIM_ETH_PROTO_D2N_OWN_MASK) !=
COSIM_ETH_PROTO_D2N_OWN_NET)
return NULL;
/* if in sync mode, wait till message is ready */
nsif->d2n_timestamp = msg->dummy.timestamp;
if (nsif->sync && nsif->d2n_timestamp > timestamp)
return NULL;
nsif->d2n_pos = (nsif->d2n_pos + 1) % nsif->d2n_enum;
return msg;
}
void netsim_d2n_done(struct netsim_interface *nsif,
volatile union cosim_eth_proto_d2n *msg)
{
msg->dummy.own_type = (msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK)
| COSIM_ETH_PROTO_D2N_OWN_DEV;
volatile union cosim_eth_proto_d2n *msg) {
msg->dummy.own_type = (msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK) |
COSIM_ETH_PROTO_D2N_OWN_DEV;
}
volatile union cosim_eth_proto_n2d *netsim_n2d_alloc(
struct netsim_interface *nsif, uint64_t timestamp,
uint64_t latency)
{
volatile union cosim_eth_proto_n2d *msg =
(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)
{
return NULL;
}
struct netsim_interface *nsif, uint64_t timestamp, uint64_t latency) {
volatile union cosim_eth_proto_n2d *msg =
(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) {
return NULL;
}
msg->dummy.timestamp = timestamp + latency;
nsif->n2d_timestamp = timestamp;
msg->dummy.timestamp = timestamp + latency;
nsif->n2d_timestamp = timestamp;
nsif->n2d_pos = (nsif->n2d_pos + 1) % nsif->n2d_enum;
return msg;
nsif->n2d_pos = (nsif->n2d_pos + 1) % nsif->n2d_enum;
return msg;
}
int netsim_n2d_sync(struct netsim_interface *nsif, uint64_t timestamp,
uint64_t latency, uint64_t sync_delay, int sync_mode)
{
volatile union cosim_eth_proto_n2d *msg;
volatile struct cosim_eth_proto_n2d_sync *sync;
int do_sync;
uint64_t latency, uint64_t sync_delay, int sync_mode) {
volatile union cosim_eth_proto_n2d *msg;
volatile struct cosim_eth_proto_n2d_sync *sync;
int do_sync;
if (!nsif->sync)
return 0;
if (!nsif->sync)
return 0;
switch (sync_mode) {
switch (sync_mode) {
case SYNC_MODES:
do_sync = nsif->n2d_timestamp == 0 ||
timestamp - nsif->n2d_timestamp >= sync_delay;
break;
do_sync = nsif->n2d_timestamp == 0 ||
timestamp - nsif->n2d_timestamp >= sync_delay;
break;
case SYNC_BARRIER:
do_sync = current_epoch == 0 ||
timestamp - current_epoch >= sync_delay;
break;
do_sync = current_epoch == 0 || timestamp - current_epoch >= sync_delay;
break;
default:
fprintf(stderr, "unsupported sync mode=%u\n", sync_mode);
return 0;
}
fprintf(stderr, "unsupported sync mode=%u\n", sync_mode);
return 0;
}
if (!do_sync) {
return 0;
}
if (!do_sync) {
return 0;
}
msg = netsim_n2d_alloc(nsif, timestamp, latency);
if (msg == NULL)
return -1;
msg = netsim_n2d_alloc(nsif, timestamp, latency);
if (msg == NULL)
return -1;
sync = &msg->sync;
// WMB();
sync->own_type = COSIM_ETH_PROTO_N2D_MSG_SYNC | COSIM_ETH_PROTO_N2D_OWN_DEV;
sync = &msg->sync;
// WMB();
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,
int sync_mode)
{
if (sync_mode == SYNC_BARRIER) {
if (timestamp - current_epoch >= sync_delay) {
current_epoch = timestamp;
}
int sync_mode) {
if (sync_mode == SYNC_BARRIER) {
if (timestamp - current_epoch >= sync_delay) {
current_epoch = timestamp;
}
}
}
uint64_t netsim_advance_time(uint64_t timestamp, uint64_t sync_delay,
int sync_mode)
{
switch (sync_mode) {
int sync_mode) {
switch (sync_mode) {
case SYNC_MODES:
return timestamp;
return timestamp;
case SYNC_BARRIER:
return timestamp < current_epoch + sync_delay ?
timestamp : current_epoch + sync_delay;
return timestamp < current_epoch + sync_delay
? timestamp
: current_epoch + sync_delay;
default:
fprintf(stderr, "unsupported sync mode=%u\n", sync_mode);
return timestamp;
}
fprintf(stderr, "unsupported sync mode=%u\n", sync_mode);
return timestamp;
}
}
......@@ -27,48 +27,47 @@
#include <stddef.h>
#include <stdint.h>
#include <simbricks/proto/network.h>
#define SYNC_MODES 0
#define SYNC_BARRIER 1
struct netsim_interface {
uint8_t *d2n_queue;
size_t d2n_pos;
size_t d2n_elen;
size_t d2n_enum;
uint64_t d2n_timestamp;
uint8_t *d2n_queue;
size_t d2n_pos;
size_t d2n_elen;
size_t d2n_enum;
uint64_t d2n_timestamp;
uint8_t *n2d_queue;
size_t n2d_pos;
size_t n2d_elen;
size_t n2d_enum;
uint64_t n2d_timestamp;
uint8_t *n2d_queue;
size_t n2d_pos;
size_t n2d_elen;
size_t n2d_enum;
uint64_t n2d_timestamp;
int sync;
int sync;
};
int netsim_init(struct netsim_interface *nsif,
const char *eth_socket_path, int *sync_eth);
int netsim_init(struct netsim_interface *nsif, const char *eth_socket_path,
int *sync_eth);
void netsim_cleanup(struct netsim_interface *nsif);
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,
volatile union cosim_eth_proto_d2n *msg);
static inline uint64_t netsim_d2n_timestamp(struct netsim_interface *nsif)
{
return nsif->d2n_timestamp;
volatile union cosim_eth_proto_d2n *msg);
static inline uint64_t netsim_d2n_timestamp(struct netsim_interface *nsif) {
return nsif->d2n_timestamp;
}
volatile union cosim_eth_proto_n2d *netsim_n2d_alloc(
struct netsim_interface *nsif, uint64_t timestamp,
uint64_t latency);
struct netsim_interface *nsif, uint64_t timestamp, uint64_t latency);
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,
int sync_mode);
int sync_mode);
uint64_t netsim_advance_time(uint64_t timestamp, uint64_t sync_delay,
int sync_mode);
int sync_mode);
#endif // SIMBRICKS_NETIF_NETSIM_H_
......@@ -24,96 +24,93 @@
#include <fcntl.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <unistd.h>
#include "lib/simbricks/netif/internal.h"
int uxsocket_connect(const char *path)
{
int fd;
struct sockaddr_un saun;
int uxsocket_connect(const char *path) {
int fd;
struct sockaddr_un saun;
/* prepare and connect socket */
memset(&saun, 0, sizeof(saun));
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, path);
/* prepare and connect socket */
memset(&saun, 0, sizeof(saun));
saun.sun_family = AF_UNIX;
strcpy(saun.sun_path, path);
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket failed");
return -1;
}
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("socket failed");
return -1;
}
if (connect(fd, (struct sockaddr *) &saun, sizeof(saun)) != 0) {
perror("connect failed");
return -1;
}
if (connect(fd, (struct sockaddr *)&saun, sizeof(saun)) != 0) {
perror("connect failed");
return -1;
}
return fd;
return fd;
}
int uxsocket_recv(int fd, void *data, size_t len, int *pfd)
{
int *ppfd;
ssize_t ret;
struct cmsghdr *cmsg;
union {
char buf[CMSG_SPACE(sizeof(int))];
struct cmsghdr align;
} u;
struct iovec iov = {
.iov_base = data,
.iov_len = len,
};
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = u.buf,
.msg_controllen = sizeof(u.buf),
.msg_flags = 0,
};
int uxsocket_recv(int fd, void *data, size_t len, int *pfd) {
int *ppfd;
ssize_t ret;
struct cmsghdr *cmsg;
union {
char buf[CMSG_SPACE(sizeof(int))];
struct cmsghdr align;
} u;
struct iovec iov = {
.iov_base = data,
.iov_len = len,
};
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = u.buf,
.msg_controllen = sizeof(u.buf),
.msg_flags = 0,
};
if ((ret = recvmsg(fd, &msg, 0)) != (ssize_t) len) {
perror("recvmsg failed");
return -1;
}
if ((ret = recvmsg(fd, &msg, 0)) != (ssize_t)len) {
perror("recvmsg failed");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
ppfd = (int *) CMSG_DATA(cmsg);
if (msg.msg_controllen <= 0 || cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
fprintf(stderr, "accessing ancillary data failed\n");
return -1;
}
cmsg = CMSG_FIRSTHDR(&msg);
ppfd = (int *)CMSG_DATA(cmsg);
if (msg.msg_controllen <= 0 || cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
fprintf(stderr, "accessing ancillary data failed\n");
return -1;
}
*pfd = *ppfd;
return 0;
*pfd = *ppfd;
return 0;
}
void *shm_map(int shm_fd)
{
void *p;
struct stat statbuf;
void *shm_map(int shm_fd) {
void *p;
struct stat statbuf;
if (fstat(shm_fd, &statbuf) != 0) {
perror("shm_map: fstat failed");
return NULL;
}
if (fstat(shm_fd, &statbuf) != 0) {
perror("shm_map: fstat failed");
return NULL;
}
p = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd,
0);
if (p == MAP_FAILED) {
perror("shm_map: mmap failed");
return NULL;
}
p = mmap(NULL, statbuf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd,
0);
if (p == MAP_FAILED) {
perror("shm_map: mmap failed");
return NULL;
}
return p;
return p;
}
This diff is collapsed.
......@@ -27,10 +27,11 @@
#include <cassert>
#include <cstring>
#include <set>
#include <deque>
#include <set>
extern "C" {
#include <simbricks/nicif/nicsim.h>
#include <simbricks/nicif/nicsim.h>
}
namespace nicbm {
......@@ -38,21 +39,22 @@ namespace nicbm {
static const size_t MAX_DMA_LEN = 2048;
class DMAOp {
public:
virtual ~DMAOp() { }
bool write;
uint64_t dma_addr;
size_t len;
void *data;
public:
virtual ~DMAOp() {
}
bool write;
uint64_t dma_addr;
size_t len;
void *data;
};
class TimedEvent {
public:
virtual ~TimedEvent() { }
uint64_t time;
public:
virtual ~TimedEvent() {
}
uint64_t time;
};
/**
* 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
......@@ -60,111 +62,107 @@ class TimedEvent {
* device as needed.
* */
class Runner {
public:
class Device {
protected:
bool int_intx_en;
bool int_msi_en;
bool int_msix_en;
public:
/**
* Initialize device specific parameters (pci dev/vendor id,
* BARs etc. in intro struct.
*/
virtual void setup_intro(struct cosim_pcie_proto_dev_intro &di)
= 0;
/**
* execute a register read from `bar`:`addr` of length `len`.
* Should store result in `dest`.
*/
virtual void reg_read(uint8_t bar, uint64_t addr, void *dest,
size_t len) = 0;
/**
* execute a register write to `bar`:`addr` of length `len`,
* with the data in `src`.
*/
virtual void reg_write(uint8_t bar, uint64_t addr,
const void *src, size_t len) = 0;
/**
* the previously issued DMA operation `op` completed.
*/
virtual void dma_complete(DMAOp &op) = 0;
/**
* A packet has arrived on the wire, of length `len` with
* payload `data`.
*/
virtual void eth_rx(uint8_t port, const void *data, size_t len)
= 0;
/**
* A timed event is due.
*/
virtual void timed_event(TimedEvent &ev);
/**
* Device control update
*/
virtual void devctrl_update(
struct cosim_pcie_proto_h2d_devctrl &devctrl);
};
protected:
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;
uint64_t mac_addr;
struct nicsim_params nsparams;
struct cosim_pcie_proto_dev_intro dintro;
volatile union cosim_pcie_proto_d2h *d2h_alloc(void);
volatile union cosim_eth_proto_d2n *d2n_alloc(void);
void h2d_read(volatile struct cosim_pcie_proto_h2d_read *read);
void h2d_write(volatile struct cosim_pcie_proto_h2d_write *write);
void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc);
void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc);
void h2d_devctrl(volatile struct cosim_pcie_proto_h2d_devctrl *dc);
void poll_h2d();
void eth_recv(volatile struct cosim_eth_proto_n2d_recv *recv);
void poll_n2d();
bool event_next(uint64_t &retval);
void event_trigger();
void dma_do(DMAOp &op);
void dma_trigger();
public:
Runner(Device &dev_);
/** Run the simulation */
int runMain(int argc, char *argv[]);
/* these three are for `Runner::Device`. */
void issue_dma(DMAOp &op);
void msi_issue(uint8_t vec);
void msix_issue(uint8_t vec);
void eth_send(const void *data, size_t len);
void event_schedule(TimedEvent &evt);
void event_cancel(TimedEvent &evt);
uint64_t time_ps() const;
uint64_t get_mac_addr() const;
public:
class Device {
protected:
bool int_intx_en;
bool int_msi_en;
bool int_msix_en;
public:
/**
* Initialize device specific parameters (pci dev/vendor id,
* BARs etc. in intro struct.
*/
virtual void setup_intro(struct cosim_pcie_proto_dev_intro &di) = 0;
/**
* execute a register read from `bar`:`addr` of length `len`.
* Should store result in `dest`.
*/
virtual void reg_read(uint8_t bar, uint64_t addr, void *dest,
size_t len) = 0;
/**
* execute a register write to `bar`:`addr` of length `len`,
* with the data in `src`.
*/
virtual void reg_write(uint8_t bar, uint64_t addr, const void *src,
size_t len) = 0;
/**
* the previously issued DMA operation `op` completed.
*/
virtual void dma_complete(DMAOp &op) = 0;
/**
* A packet has arrived on the wire, of length `len` with
* payload `data`.
*/
virtual void eth_rx(uint8_t port, const void *data, size_t len) = 0;
/**
* A timed event is due.
*/
virtual void timed_event(TimedEvent &ev);
/**
* Device control update
*/
virtual void devctrl_update(struct cosim_pcie_proto_h2d_devctrl &devctrl);
};
protected:
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;
uint64_t mac_addr;
struct nicsim_params nsparams;
struct cosim_pcie_proto_dev_intro dintro;
volatile union cosim_pcie_proto_d2h *d2h_alloc(void);
volatile union cosim_eth_proto_d2n *d2n_alloc(void);
void h2d_read(volatile struct cosim_pcie_proto_h2d_read *read);
void h2d_write(volatile struct cosim_pcie_proto_h2d_write *write);
void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc);
void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc);
void h2d_devctrl(volatile struct cosim_pcie_proto_h2d_devctrl *dc);
void poll_h2d();
void eth_recv(volatile struct cosim_eth_proto_n2d_recv *recv);
void poll_n2d();
bool event_next(uint64_t &retval);
void event_trigger();
void dma_do(DMAOp &op);
void dma_trigger();
public:
Runner(Device &dev_);
/** Run the simulation */
int runMain(int argc, char *argv[]);
/* these three are for `Runner::Device`. */
void issue_dma(DMAOp &op);
void msi_issue(uint8_t vec);
void msix_issue(uint8_t vec);
void eth_send(const void *data, size_t len);
void event_schedule(TimedEvent &evt);
void event_cancel(TimedEvent &evt);
uint64_t time_ps() const;
uint64_t get_mac_addr() const;
};
/**
......@@ -172,26 +170,23 @@ class Runner {
*/
template <class TReg = uint32_t>
class SimpleDevice : public Runner::Device {
public:
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_read(uint8_t bar, uint64_t addr, void *dest,
size_t len)
{
assert(len == sizeof(TReg));
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)
{
assert(len == sizeof(TReg));
TReg r;
memcpy(&r, src, sizeof(r));
reg_write(bar, addr, r);
}
public:
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_read(uint8_t bar, uint64_t addr, void *dest, size_t len) {
assert(len == sizeof(TReg));
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) {
assert(len == sizeof(TReg));
TReg r;
memcpy(&r, src, sizeof(r));
reg_write(bar, addr, r);
}
};
} // namespace nicbm
......
This diff is collapsed.
......@@ -25,28 +25,28 @@
#ifndef SIMBRICKS_NICIF_NICSIM_H_
#define SIMBRICKS_NICIF_NICSIM_H_
#include <simbricks/proto/pcie.h>
#include <simbricks/proto/network.h>
#include <simbricks/proto/pcie.h>
#define SYNC_MODES 0 // ModES style synchronization
#define SYNC_BARRIER 1 // Global barrier style synchronization
struct nicsim_params {
const char *pci_socket_path;
const char *eth_socket_path;
const char *shm_path;
const char *pci_socket_path;
const char *eth_socket_path;
const char *shm_path;
uint64_t pci_latency;
uint64_t eth_latency;
uint64_t sync_delay;
uint64_t pci_latency;
uint64_t eth_latency;
uint64_t sync_delay;
int sync_pci;
int sync_eth;
int sync_mode;
int sync_pci;
int sync_eth;
int sync_mode;
};
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);
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);
uint64_t nicsim_next_timestamp(struct nicsim_params *params);
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_next(void);
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(
struct nicsim_params *params, uint64_t timestamp);
volatile union cosim_eth_proto_n2d *nicif_n2d_poll(struct nicsim_params *params,
uint64_t timestamp);
void nicif_n2d_done(volatile union cosim_eth_proto_n2d *msg);
void nicif_n2d_next(void);
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_
......@@ -24,116 +24,112 @@
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include "lib/simbricks/nicif/internal.h"
int uxsocket_init(const char *path)
{
int fd;
struct sockaddr_un saun;
int uxsocket_init(const char *path) {
int fd;
struct sockaddr_un saun;
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("uxsocket_init: socket failed");
goto error_exit;
}
if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
perror("uxsocket_init: socket failed");
goto error_exit;
}
memset(&saun, 0, sizeof(saun));
saun.sun_family = AF_UNIX;
memcpy(saun.sun_path, path, strlen(path));
if (bind(fd, (struct sockaddr *) &saun, sizeof(saun))) {
perror("uxsocket_init: bind failed");
goto error_close;
}
memset(&saun, 0, sizeof(saun));
saun.sun_family = AF_UNIX;
memcpy(saun.sun_path, path, strlen(path));
if (bind(fd, (struct sockaddr *)&saun, sizeof(saun))) {
perror("uxsocket_init: bind failed");
goto error_close;
}
if (listen(fd, 5)) {
perror("uxsocket_init: listen failed");
goto error_close;
}
if (listen(fd, 5)) {
perror("uxsocket_init: listen failed");
goto error_close;
}
return fd;
return fd;
error_close:
close(fd);
close(fd);
error_exit:
return -1;
return -1;
}
int uxsocket_send(int connfd, void *data, size_t len, int fd)
{
ssize_t tx;
struct iovec iov = {
.iov_base = data,
.iov_len = len,
};
union {
char buf[CMSG_SPACE(sizeof(int))];
struct cmsghdr align;
} u;
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = u.buf,
.msg_controllen = 0,
.msg_flags = 0,
};
struct cmsghdr *cmsg = &u.align;
if (fd >= 0) {
msg.msg_controllen = sizeof(u.buf);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*(int *) CMSG_DATA(cmsg) = fd;
}
if ((tx = sendmsg(connfd, &msg, 0)) != (ssize_t) len) {
fprintf(stderr, "tx == %zd\n", tx);
return -1;
}
return 0;
int uxsocket_send(int connfd, void *data, size_t len, int fd) {
ssize_t tx;
struct iovec iov = {
.iov_base = data,
.iov_len = len,
};
union {
char buf[CMSG_SPACE(sizeof(int))];
struct cmsghdr align;
} u;
struct msghdr msg = {
.msg_name = NULL,
.msg_namelen = 0,
.msg_iov = &iov,
.msg_iovlen = 1,
.msg_control = u.buf,
.msg_controllen = 0,
.msg_flags = 0,
};
struct cmsghdr *cmsg = &u.align;
if (fd >= 0) {
msg.msg_controllen = sizeof(u.buf);
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
cmsg->cmsg_len = CMSG_LEN(sizeof(int));
*(int *)CMSG_DATA(cmsg) = fd;
}
if ((tx = sendmsg(connfd, &msg, 0)) != (ssize_t)len) {
fprintf(stderr, "tx == %zd\n", tx);
return -1;
}
return 0;
}
int shm_create(const char *path, size_t size, void **addr)
{
int fd;
void *p;
int shm_create(const char *path, size_t size, void **addr) {
int fd;
void *p;
if ((fd = open(path, O_CREAT | O_RDWR, 0666)) == -1) {
perror("util_create_shmsiszed: open failed");
goto error_out;
}
if (ftruncate(fd, size) != 0) {
perror("util_create_shmsiszed: ftruncate failed");
goto error_remove;
}
if ((fd = open(path, O_CREAT | O_RDWR, 0666)) == -1) {
perror("util_create_shmsiszed: open failed");
goto error_out;
}
if (ftruncate(fd, size) != 0) {
perror("util_create_shmsiszed: ftruncate failed");
goto error_remove;
}
if ((p = mmap(NULL, size, PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_POPULATE, fd, 0)) == (void *) -1)
{
perror("util_create_shmsiszed: mmap failed");
goto error_remove;
}
if ((p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
fd, 0)) == (void *)-1) {
perror("util_create_shmsiszed: mmap failed");
goto error_remove;
}
memset(p, 0, size);
memset(p, 0, size);
*addr = p;
return fd;
*addr = p;
return fd;
error_remove:
close(fd);
unlink(path);
close(fd);
unlink(path);
error_out:
return -1;
return -1;
}
......@@ -38,34 +38,32 @@
* memory file descriptor attached.
*/
struct cosim_eth_proto_dev_intro {
/** flags: see COSIM_ETH_PROTO_FLAGS_DI_* */
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));
/** flags: see COSIM_ETH_PROTO_FLAGS_DI_* */
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));
#define COSIM_ETH_PROTO_FLAGS_NI_SYNC (1 << 0)
/** welcome message sent by network to device */
struct cosim_eth_proto_net_intro {
/** flags: see COSIM_ETH_PROTO_FLAGS_IN_* */
/** flags: see COSIM_ETH_PROTO_FLAGS_IN_* */
uint64_t flags;
} __attribute__((packed));
/******************************************************************************/
/* Messages on in-memory device to network channel */
......@@ -82,36 +80,35 @@ struct cosim_eth_proto_net_intro {
#define COSIM_ETH_PROTO_D2N_MSG_SEND 0x2
struct cosim_eth_proto_d2n_dummy {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_d2n_sync {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_d2n_send {
uint16_t len;
uint8_t port;
uint8_t pad[45];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
uint16_t len;
uint8_t port;
uint8_t pad[45];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
} __attribute__((packed));
union cosim_eth_proto_d2n {
struct cosim_eth_proto_d2n_dummy dummy;
struct cosim_eth_proto_d2n_sync sync;
struct cosim_eth_proto_d2n_send send;
struct cosim_eth_proto_d2n_dummy dummy;
struct cosim_eth_proto_d2n_sync sync;
struct cosim_eth_proto_d2n_send send;
};
/******************************************************************************/
/* Messages on in-memory network to device channel */
......@@ -126,33 +123,33 @@ union cosim_eth_proto_d2n {
#define COSIM_ETH_PROTO_N2D_MSG_RECV 0x2
struct cosim_eth_proto_n2d_dummy {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_n2d_sync {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
struct cosim_eth_proto_n2d_recv {
uint16_t len;
uint8_t port;
uint8_t pad[45];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
uint16_t len;
uint8_t port;
uint8_t pad[45];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
};
union cosim_eth_proto_n2d {
struct cosim_eth_proto_n2d_dummy dummy;
struct cosim_eth_proto_n2d_sync sync;
struct cosim_eth_proto_n2d_recv recv;
struct cosim_eth_proto_n2d_dummy dummy;
struct cosim_eth_proto_n2d_sync sync;
struct cosim_eth_proto_n2d_recv recv;
};
#endif // SIMBRICKS_PROTO_NETWORK_H_
......@@ -55,69 +55,67 @@
* memory file descriptor attached.
*/
struct cosim_pcie_proto_dev_intro {
/** flags: see COSIM_PCIE_PROTO_FLAGS_DI_* */
uint64_t flags;
/** flags: see COSIM_PCIE_PROTO_FLAGS_DI_* */
uint64_t flags;
/** offset of the device-to-host queue in shared memory region */
uint64_t d2h_offset;
/** size of an entry in the device-to-host queue in bytes */
uint64_t d2h_elen;
/** total device-to-host queue length in #entries */
uint64_t d2h_nentries;
/** offset of the host-to-device queue in shared memory region */
uint64_t h2d_offset;
/** size of an entry in the host-to-device queue in bytes */
uint64_t h2d_elen;
/** total host-to-device queue length in #entries */
uint64_t h2d_nentries;
/** information for each BAR exposed by the device */
struct {
/** length of the bar in bytes (len = 0 indicates unused bar) */
uint64_t len;
/** flags (see COSIM_PCIE_PROTO_BAR_*) */
uint64_t flags;
} __attribute__((packed)) bars[COSIM_PCIE_PROTO_NBARS];
/** PCI vendor id */
uint16_t pci_vendor_id;
/** PCI device id */
uint16_t pci_device_id;
/* PCI class */
uint8_t pci_class;
/* PCI subclass */
uint8_t pci_subclass;
/* PCI revision */
uint8_t pci_revision;
/* PCI number of MSI vectors */
uint8_t pci_msi_nvecs;
/* PCI number of MSI-X vectors */
uint16_t pci_msix_nvecs;
/* BAR number for MSI-X table */
uint8_t pci_msix_table_bar;
/* BAR number for MSI-X PBA */
uint8_t pci_msix_pba_bar;
/* Offset for MSI-X table */
uint32_t pci_msix_table_offset;
/* Offset for MSI-X PBA */
uint32_t pci_msix_pba_offset;
/* MSI-X capability offset */
uint16_t psi_msix_cap_offset;
/** offset of the device-to-host queue in shared memory region */
uint64_t d2h_offset;
/** size of an entry in the device-to-host queue in bytes */
uint64_t d2h_elen;
/** total device-to-host queue length in #entries */
uint64_t d2h_nentries;
/** offset of the host-to-device queue in shared memory region */
uint64_t h2d_offset;
/** size of an entry in the host-to-device queue in bytes */
uint64_t h2d_elen;
/** total host-to-device queue length in #entries */
uint64_t h2d_nentries;
/** information for each BAR exposed by the device */
struct {
/** length of the bar in bytes (len = 0 indicates unused bar) */
uint64_t len;
/** flags (see COSIM_PCIE_PROTO_BAR_*) */
uint64_t flags;
} __attribute__((packed)) bars[COSIM_PCIE_PROTO_NBARS];
/** PCI vendor id */
uint16_t pci_vendor_id;
/** PCI device id */
uint16_t pci_device_id;
/* PCI class */
uint8_t pci_class;
/* PCI subclass */
uint8_t pci_subclass;
/* PCI revision */
uint8_t pci_revision;
/* PCI number of MSI vectors */
uint8_t pci_msi_nvecs;
/* PCI number of MSI-X vectors */
uint16_t pci_msix_nvecs;
/* BAR number for MSI-X table */
uint8_t pci_msix_table_bar;
/* BAR number for MSI-X PBA */
uint8_t pci_msix_pba_bar;
/* Offset for MSI-X table */
uint32_t pci_msix_table_offset;
/* Offset for MSI-X PBA */
uint32_t pci_msix_pba_offset;
/* MSI-X capability offset */
uint16_t psi_msix_cap_offset;
} __attribute__((packed));
#define COSIM_PCIE_PROTO_FLAGS_HI_SYNC (1 << 0)
/** welcome message sent by host to device */
struct cosim_pcie_proto_host_intro {
/** flags: see COSIM_PCIE_PROTO_FLAGS_HI_* */
/** flags: see COSIM_PCIE_PROTO_FLAGS_HI_* */
uint64_t flags;
} __attribute__((packed));
/******************************************************************************/
/* Messages on in-memory device to host channel */
......@@ -138,41 +136,41 @@ struct cosim_pcie_proto_host_intro {
#define COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP 0x6
struct cosim_pcie_proto_d2h_dummy {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_dummy);
struct cosim_pcie_proto_d2h_sync {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_sync);
struct cosim_pcie_proto_d2h_read {
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t pad[30];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t pad[30];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_read);
struct cosim_pcie_proto_d2h_write {
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t pad[30];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t pad[30];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
} __attribute__((packed));
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
struct cosim_pcie_proto_d2h_interrupt {
uint16_t vector;
uint8_t inttype;
uint8_t pad[45];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint16_t vector;
uint8_t inttype;
uint8_t pad[45];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_interrupt);
struct cosim_pcie_proto_d2h_readcomp {
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_readcomp);
struct cosim_pcie_proto_d2h_writecomp {
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_d2h_writecomp);
union cosim_pcie_proto_d2h {
struct cosim_pcie_proto_d2h_dummy dummy;
struct cosim_pcie_proto_d2h_sync sync;
struct cosim_pcie_proto_d2h_read read;
struct cosim_pcie_proto_d2h_write write;
struct cosim_pcie_proto_d2h_interrupt interrupt;
struct cosim_pcie_proto_d2h_readcomp readcomp;
struct cosim_pcie_proto_d2h_writecomp writecomp;
struct cosim_pcie_proto_d2h_dummy dummy;
struct cosim_pcie_proto_d2h_sync sync;
struct cosim_pcie_proto_d2h_read read;
struct cosim_pcie_proto_d2h_write write;
struct cosim_pcie_proto_d2h_interrupt interrupt;
struct cosim_pcie_proto_d2h_readcomp readcomp;
struct cosim_pcie_proto_d2h_writecomp writecomp;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_d2h);
/******************************************************************************/
/* Messages on in-memory host to device channel */
......@@ -240,62 +237,62 @@ COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_d2h);
#define COSIM_PCIE_PROTO_H2D_MSG_DEVCTRL 0x7
struct cosim_pcie_proto_h2d_dummy {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_dummy);
struct cosim_pcie_proto_h2d_sync {
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t pad[48];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_sync);
struct cosim_pcie_proto_h2d_read {
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t bar;
uint8_t pad[29];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t bar;
uint8_t pad[29];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_read);
struct cosim_pcie_proto_h2d_write {
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t bar;
uint8_t pad[29];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
uint64_t req_id;
uint64_t offset;
uint16_t len;
uint8_t bar;
uint8_t pad[29];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_write);
struct cosim_pcie_proto_h2d_readcomp {
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint8_t data[];
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_readcomp);
struct cosim_pcie_proto_h2d_writecomp {
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint64_t req_id;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
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_MSIX_EN (1 << 2)
struct cosim_pcie_proto_h2d_devctrl {
uint64_t flags;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
uint64_t flags;
uint8_t pad[40];
uint64_t timestamp;
uint8_t pad_[7];
uint8_t own_type;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(struct cosim_pcie_proto_h2d_devctrl);
union cosim_pcie_proto_h2d {
struct cosim_pcie_proto_h2d_dummy dummy;
struct cosim_pcie_proto_h2d_sync sync;
struct cosim_pcie_proto_h2d_read read;
struct cosim_pcie_proto_h2d_write write;
struct cosim_pcie_proto_h2d_readcomp readcomp;
struct cosim_pcie_proto_h2d_writecomp writecomp;
struct cosim_pcie_proto_h2d_devctrl devctrl;
struct cosim_pcie_proto_h2d_dummy dummy;
struct cosim_pcie_proto_h2d_sync sync;
struct cosim_pcie_proto_h2d_read read;
struct cosim_pcie_proto_h2d_write write;
struct cosim_pcie_proto_h2d_readcomp readcomp;
struct cosim_pcie_proto_h2d_writecomp writecomp;
struct cosim_pcie_proto_h2d_devctrl devctrl;
} __attribute__((packed));
COSIM_PCI_MSG_SZCHECK(union cosim_pcie_proto_h2d);
......
......@@ -22,15 +22,16 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <unistd.h>
#include <cassert>
#include <climits>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <csignal>
#include <climits>
#include <cstring>
#include <unistd.h>
#include <vector>
#include <unordered_map>
#include <cassert>
#include <vector>
extern "C" {
#include <simbricks/netif/netsim.h>
......@@ -41,31 +42,30 @@ static uint64_t eth_latency = (500 * 1000ULL); // 500ns
/* MAC address type */
struct MAC {
const volatile uint8_t *data;
const volatile uint8_t *data;
MAC(const volatile uint8_t *data)
: data(data) {}
MAC(const volatile uint8_t *data) : data(data) {
}
bool operator==(const MAC &other) const {
for (int i = 0; i < 6; i++) {
if (data[i] != other.data[i]) {
return false;
}
}
return true;
bool operator==(const MAC &other) const {
for (int i = 0; i < 6; i++) {
if (data[i] != other.data[i]) {
return false;
}
}
return true;
}
};
namespace std {
template <>
struct hash<MAC>
{
size_t operator()(const MAC &m) const {
struct hash<MAC> {
size_t operator()(const MAC &m) const {
size_t res = 0;
for (int i = 0; i < 6; i++) {
res = (res << 4) | (res ^ m.data[i]);
res = (res << 4) | (res ^ m.data[i]);
}
return res;
}
}
};
} // namespace std
......@@ -77,149 +77,145 @@ static const MAC bcast_addr(bcast);
static std::vector<struct netsim_interface> nsifs;
static std::unordered_map<MAC, int> mac_table;
static void sigint_handler(int dummy)
{
exiting = 1;
static void sigint_handler(int dummy) {
exiting = 1;
}
static void forward_pkt(volatile struct cosim_eth_proto_d2n_send *tx, int port)
{
volatile union cosim_eth_proto_n2d *msg_to;
msg_to = netsim_n2d_alloc(&nsifs[port], cur_ts, eth_latency);
if (msg_to != NULL) {
volatile struct cosim_eth_proto_n2d_recv *rx;
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, "forward_pkt: dropping packet\n");
}
static void forward_pkt(volatile struct cosim_eth_proto_d2n_send *tx,
int port) {
volatile union cosim_eth_proto_n2d *msg_to;
msg_to = netsim_n2d_alloc(&nsifs[port], cur_ts, eth_latency);
if (msg_to != NULL) {
volatile struct cosim_eth_proto_n2d_recv *rx;
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, "forward_pkt: dropping packet\n");
}
}
static void switch_pkt(struct netsim_interface *nsif, int iport)
{
volatile union cosim_eth_proto_d2n *msg_from = netsim_d2n_poll(nsif,
cur_ts);
if (msg_from == NULL) {
return;
static void switch_pkt(struct netsim_interface *nsif, int iport) {
volatile union cosim_eth_proto_d2n *msg_from = netsim_d2n_poll(nsif, cur_ts);
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;
}
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
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) {
// L2 forwarding
if (mac_table.count(dst) > 0) {
int eport = mac_table.at(dst);
forward_pkt(tx, eport);
} else {
fprintf(stderr, "switch_pkt: unsupported type=%u\n", type);
abort();
// Broadcast
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 c;
int bad_option = 0;
int sync_mode = SYNC_MODES;
// Parse command line argument
while ((c = getopt(argc, argv, "s:S:E:m:")) != -1 && !bad_option) {
switch (c) {
case 's': {
struct netsim_interface nsif;
int sync = 1;
if (netsim_init(&nsif, optarg, &sync) != 0) {
fprintf(stderr, "connecting to %s failed\n", optarg);
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;
int main(int argc, char *argv[]) {
int c;
int bad_option = 0;
int sync_mode = SYNC_MODES;
// Parse command line argument
while ((c = getopt(argc, argv, "s:S:E:m:")) != -1 && !bad_option) {
switch (c) {
case 's': {
struct netsim_interface nsif;
int sync = 1;
if (netsim_init(&nsif, optarg, &sync) != 0) {
fprintf(stderr, "connecting to %s failed\n", optarg);
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;
}
if (nsifs.empty() || bad_option) {
fprintf(stderr, "Usage: net_switch [-S SYNC-PERIOD] [-E ETH-LATENCY] "
"-s SOCKET-A [-s SOCKET-B ...]\n");
return EXIT_FAILURE;
}
if (nsifs.empty() || bad_option) {
fprintf(stderr,
"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();
}
}
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);
// 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);
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);
}
}
return 0;
return 0;
}
......@@ -23,15 +23,15 @@
*/
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <pthread.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <simbricks/netif/netsim.h>
......@@ -40,119 +40,113 @@
static struct netsim_interface nsif;
static int tap_fd;
static int tap_open(const char *name)
{
struct ifreq ifr;
int fd;
static int tap_open(const char *name) {
struct ifreq ifr;
int fd;
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
perror("tap_open: open failed");
return -1;
}
if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
perror("tap_open: open failed");
return -1;
}
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy(ifr.ifr_name, name, IFNAMSIZ);
memset(&ifr, 0, sizeof(ifr));
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
strncpy(ifr.ifr_name, name, IFNAMSIZ);
if (ioctl(fd, TUNSETIFF, &ifr) != 0) {
perror("tap_open: ioctl failed");
close(fd);
return -1;
}
if (ioctl(fd, TUNSETIFF, &ifr) != 0) {
perror("tap_open: ioctl failed");
close(fd);
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
printf("sent packet: len=%u\n", s->len);
printf("sent packet: len=%u\n", s->len);
#endif
if (write(tap_fd, (void *) s->data, s->len) != (ssize_t) s->len) {
perror("d2n_send: send failed");
}
if (write(tap_fd, (void *)s->data, s->len) != (ssize_t)s->len) {
perror("d2n_send: send failed");
}
}
static void poll_d2n(void)
{
volatile union cosim_eth_proto_d2n *msg = netsim_d2n_poll(&nsif, 0);
uint8_t type;
static void poll_d2n(void) {
volatile union cosim_eth_proto_d2n *msg = netsim_d2n_poll(&nsif, 0);
uint8_t type;
/* message not ready */
if (msg == NULL)
return;
/* message not ready */
if (msg == NULL)
return;
type = msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK;
switch (type) {
case COSIM_ETH_PROTO_D2N_MSG_SEND:
d2n_send(&msg->send);
break;
type = msg->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK;
switch (type) {
case COSIM_ETH_PROTO_D2N_MSG_SEND:
d2n_send(&msg->send);
break;
default:
fprintf(stderr, "poll_d2n: unsupported type=%u\n", type);
}
default:
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)
{
volatile union cosim_eth_proto_n2d *msg;
volatile struct cosim_eth_proto_n2d_recv *rx;
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
static void *rx_handler(void *arg) {
volatile union cosim_eth_proto_n2d *msg;
volatile struct cosim_eth_proto_n2d_recv *rx;
ssize_t len;
// WMB();
rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV |
COSIM_ETH_PROTO_N2D_OWN_DEV;
}
}
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;
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;
sync = 0;
if (netsim_init(&nsif, argv[2], &sync) != 0) {
close(tap_fd);
return -1;
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
pthread_t worker;
if (pthread_create(&worker, NULL, rx_handler, NULL) != 0) {
return EXIT_FAILURE;
}
// WMB();
rx->own_type = COSIM_ETH_PROTO_N2D_MSG_RECV | COSIM_ETH_PROTO_N2D_OWN_DEV;
}
}
printf("start polling\n");
while (1) {
poll_d2n();
}
return 0;
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;
}
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 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <assert.h>
#include <fcntl.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <pcap/pcap.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/mman.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>
......@@ -44,147 +44,141 @@ static uint64_t cur_ts;
static int exiting = 0;
static pcap_dumper_t *dumpfile = NULL;
static void sigint_handler(int dummy)
{
exiting = 1;
static void sigint_handler(int dummy) {
exiting = 1;
}
static void sigusr1_handler(int dummy)
{
fprintf(stderr, "main_time = %lu\n", cur_ts);
static void sigusr1_handler(int dummy) {
fprintf(stderr, "main_time = %lu\n", cur_ts);
}
static void move_pkt(struct netsim_interface *from, struct netsim_interface *to)
{
volatile union cosim_eth_proto_d2n *msg_from =
netsim_d2n_poll(from, cur_ts);
volatile union cosim_eth_proto_n2d *msg_to;
volatile struct cosim_eth_proto_d2n_send *tx;
volatile struct cosim_eth_proto_n2d_recv *rx;
struct pcap_pkthdr ph;
uint8_t type;
if (msg_from == NULL)
return;
type = msg_from->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK;
if (type == COSIM_ETH_PROTO_D2N_MSG_SEND) {
tx = &msg_from->send;
// log to pcap file if initialized
if (dumpfile) {
memset(&ph, 0, sizeof(ph));
ph.ts.tv_sec = cur_ts / 1000000000000ULL;
ph.ts.tv_usec = (cur_ts % 1000000000000ULL) / 1000ULL;
ph.caplen = tx->len;
ph.len = tx->len;
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();
static void move_pkt(struct netsim_interface *from,
struct netsim_interface *to) {
volatile union cosim_eth_proto_d2n *msg_from = netsim_d2n_poll(from, cur_ts);
volatile union cosim_eth_proto_n2d *msg_to;
volatile struct cosim_eth_proto_d2n_send *tx;
volatile struct cosim_eth_proto_n2d_recv *rx;
struct pcap_pkthdr ph;
uint8_t type;
if (msg_from == NULL)
return;
type = msg_from->dummy.own_type & COSIM_ETH_PROTO_D2N_MSG_MASK;
if (type == COSIM_ETH_PROTO_D2N_MSG_SEND) {
tx = &msg_from->send;
// log to pcap file if initialized
if (dumpfile) {
memset(&ph, 0, sizeof(ph));
ph.ts.tv_sec = cur_ts / 1000000000000ULL;
ph.ts.tv_usec = (cur_ts % 1000000000000ULL) / 1000ULL;
ph.caplen = tx->len;
ph.len = tx->len;
pcap_dump((unsigned char *)dumpfile, &ph, (unsigned char *)tx->data);
}
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[])
{
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;
// 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();
}
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;
}
netsim_d2n_done(from, msg_from);
}
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);
sync_a = sync_b = 1;
if (netsim_init(&nsif_a, argv[1], &sync_a) != 0) {
return -1;
dumpfile = pcap_dump_open(pc, argv[6]);
}
assert(sync_mode == SYNC_MODES || sync_mode == SYNC_BARRIER);
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) {
return -1;
if (netsim_n2d_sync(&nsif_b, cur_ts, eth_latency, sync_period, sync_mode) !=
0) {
fprintf(stderr, "netsim_n2d_sync(nsif_a) failed\n");
abort();
}
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_n2d_sync(&nsif_b, cur_ts, eth_latency, sync_period,
sync_mode) != 0) {
fprintf(stderr, "netsim_n2d_sync(nsif_a) failed\n");
abort();
}
netsim_advance_epoch(cur_ts, sync_period, sync_mode);
do {
move_pkt(&nsif_a, &nsif_b);
move_pkt(&nsif_b, &nsif_a);
ts_a = netsim_d2n_timestamp(&nsif_a);
ts_b = netsim_d2n_timestamp(&nsif_b);
} while (!exiting &&
((sync_a && ts_a <= cur_ts) ||
(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;
netsim_advance_epoch(cur_ts, sync_period, sync_mode);
do {
move_pkt(&nsif_a, &nsif_b);
move_pkt(&nsif_b, &nsif_a);
ts_a = netsim_d2n_timestamp(&nsif_a);
ts_b = netsim_d2n_timestamp(&nsif_b);
} while (!exiting &&
((sync_a && ts_a <= cur_ts) || (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 @@
#define COORD_H_
#include <deque>
#include <map>
#include <iostream>
#include <map>
#include "sims/nic/corundum/debug.h"
......@@ -39,116 +39,107 @@ void pci_msi_issue(uint8_t vec);
void pci_rwcomp_issue(MMIOOp *op);
class PCICoordinator {
protected:
struct PCIOp {
union {
DMAOp *dma_op;
MMIOOp *mmio_op;
uint32_t msi_vec;
};
enum {
OP_DMA,
OP_MSI,
OP_RWCOMP,
} type;
bool ready;
};
std::deque<PCIOp *> queue;
std::map<DMAOp *, PCIOp *> dmamap;
void process()
{
PCIOp *op;
while (!queue.empty()) {
op = queue.front();
if (!op->ready)
break;
queue.pop_front();
if (op->type == PCIOp::OP_MSI) {
protected:
struct PCIOp {
union {
DMAOp *dma_op;
MMIOOp *mmio_op;
uint32_t msi_vec;
};
enum {
OP_DMA,
OP_MSI,
OP_RWCOMP,
} type;
bool ready;
};
std::deque<PCIOp *> queue;
std::map<DMAOp *, PCIOp *> dmamap;
void process() {
PCIOp *op;
while (!queue.empty()) {
op = queue.front();
if (!op->ready)
break;
queue.pop_front();
if (op->type == PCIOp::OP_MSI) {
#ifdef COORD_DEBUG
std::cout << main_time << " issuing msi " << op->msi_vec <<
std::endl;
std::cout << main_time << " issuing msi " << op->msi_vec << std::endl;
#endif
pci_msi_issue(op->msi_vec);
} else if (op->type == PCIOp::OP_DMA) {
pci_msi_issue(op->msi_vec);
} else if (op->type == PCIOp::OP_DMA) {
#ifdef COORD_DEBUG
std::cout << main_time << " issuing dma " << op->dma_op <<
std::endl;
std::cout << main_time << " issuing dma " << op->dma_op << std::endl;
#endif
pci_dma_issue(op->dma_op);
dmamap.erase(op->dma_op);
} else if (op->type == PCIOp::OP_RWCOMP) {
pci_dma_issue(op->dma_op);
dmamap.erase(op->dma_op);
} else if (op->type == PCIOp::OP_RWCOMP) {
#ifdef COORD_DEBUG
std::cout << main_time << " issuing mmio " << op->mmio_op <<
std::endl;
std::cout << main_time << " issuing mmio " << op->mmio_op << std::endl;
#endif
pci_rwcomp_issue(op->mmio_op);
} else {
throw "unknown type";
}
delete op;
}
}
public:
void dma_register(DMAOp *dma_op, bool ready)
{
pci_rwcomp_issue(op->mmio_op);
} else {
throw "unknown type";
}
delete op;
}
}
public:
void dma_register(DMAOp *dma_op, bool ready) {
#ifdef COORD_DEBUG
std::cout << main_time << " registering dma op " << dma_op << " "
<< ready << std::endl;
std::cout << main_time << " registering dma op " << dma_op << " " << ready
<< std::endl;
#endif
PCIOp *op = new PCIOp;
op->dma_op = dma_op;
op->type = PCIOp::OP_DMA;
op->ready = ready;
PCIOp *op = new PCIOp;
op->dma_op = dma_op;
op->type = PCIOp::OP_DMA;
op->ready = ready;
queue.push_back(op);
dmamap[dma_op] = op;
queue.push_back(op);
dmamap[dma_op] = op;
process();
}
process();
}
void dma_mark_ready(DMAOp *op)
{
void dma_mark_ready(DMAOp *op) {
#ifdef COORD_DEBUG
std::cout << main_time << " readying dma op " << op << std::endl;
std::cout << main_time << " readying dma op " << op << std::endl;
#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
std::cout << main_time << " enqueuing MSI " << vec << std::endl;
std::cout << main_time << " enqueuing MSI " << vec << std::endl;
#endif
PCIOp *op = new PCIOp;
op->msi_vec = vec;
op->type = PCIOp::OP_MSI;
op->ready = true;
queue.push_back(op);
PCIOp *op = new PCIOp;
op->msi_vec = vec;
op->type = PCIOp::OP_MSI;
op->ready = true;
queue.push_back(op);
process();
}
process();
}
void mmio_comp_enqueue(MMIOOp *mmio_op)
{
void mmio_comp_enqueue(MMIOOp *mmio_op) {
#ifdef COORD_DEBUG
std::cout << main_time << " enqueuing MMIO comp " << mmio_op <<
std::endl;
std::cout << main_time << " enqueuing MMIO comp " << mmio_op << std::endl;
#endif
PCIOp *op = new PCIOp;
op->mmio_op = mmio_op;
op->type = PCIOp::OP_RWCOMP;
op->ready = true;
queue.push_back(op);
process();
}
PCIOp *op = new PCIOp;
op->mmio_op = mmio_op;
op->type = PCIOp::OP_RWCOMP;
op->ready = true;
queue.push_back(op);
process();
}
};
#endif // COORD_H_
This diff is collapsed.
......@@ -22,126 +22,117 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sims/nic/corundum/dma.h"
#include <iostream>
#include "sims/nic/corundum/debug.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"
void DMAReader::step()
{
p.dma_ready = 1;
if (p.dma_valid) {
DMAOp *op = new DMAOp;
op->engine = this;
op->dma_addr = p.dma_addr;
op->ram_sel = p.dma_ram_sel;
op->ram_addr = p.dma_ram_addr;
op->len = p.dma_len;
op->tag = p.dma_tag;
op->write = false;
pending.insert(op);
void DMAReader::step() {
p.dma_ready = 1;
if (p.dma_valid) {
DMAOp *op = new DMAOp;
op->engine = this;
op->dma_addr = p.dma_addr;
op->ram_sel = p.dma_ram_sel;
op->ram_addr = p.dma_ram_addr;
op->len = p.dma_len;
op->tag = p.dma_tag;
op->write = false;
pending.insert(op);
#ifdef DMA_DEBUG
std::cout << main_time << " dma[" << label << "] op " << std::hex <<
op->dma_addr << " -> " << op->ram_sel << ":" << op->ram_addr <<
" len=" << op->len << " tag=" << (int) op->tag << std::endl;
std::cout << main_time << " dma[" << label << "] op " << std::hex
<< op->dma_addr << " -> " << op->ram_sel << ":" << op->ram_addr
<< " len=" << op->len << " tag=" << (int)op->tag << std::endl;
#endif
coord.dma_register(op, true);
}
coord.dma_register(op, true);
}
p.dma_status_valid = 0;
if (!completed.empty()) {
DMAOp *op = completed.front();
completed.pop_front();
p.dma_status_valid = 0;
if (!completed.empty()) {
DMAOp *op = completed.front();
completed.pop_front();
// std::cout << "dma[" << label << "] status complete " << op->dma_addr
// << std::endl;
// std::cout << "dma[" << label << "] status complete " << op->dma_addr
// << std::endl;
p.dma_status_valid = 1;
p.dma_status_tag = op->tag;
pending.erase(op);
delete op;
}
p.dma_status_valid = 1;
p.dma_status_tag = op->tag;
pending.erase(op);
delete op;
}
}
void DMAReader::pci_op_complete(DMAOp *op)
{
mw.op_issue(op);
void DMAReader::pci_op_complete(DMAOp *op) {
mw.op_issue(op);
}
void DMAReader::mem_op_complete(DMAOp *op)
{
completed.push_back(op);
// std::cout << "dma[" << label << "] mem complete " << op->dma_addr <<
// std::endl;
void DMAReader::mem_op_complete(DMAOp *op) {
completed.push_back(op);
// std::cout << "dma[" << label << "] mem complete " << op->dma_addr <<
// std::endl;
}
void DMAWriter::step()
{
p.dma_ready = 1;
if (p.dma_valid) {
DMAOp *op = new DMAOp;
op->engine = this;
op->dma_addr = p.dma_addr;
op->ram_sel = p.dma_ram_sel;
op->ram_addr = p.dma_ram_addr;
op->len = p.dma_len;
op->tag = p.dma_tag;
op->write = true;
pending.insert(op);
void DMAWriter::step() {
p.dma_ready = 1;
if (p.dma_valid) {
DMAOp *op = new DMAOp;
op->engine = this;
op->dma_addr = p.dma_addr;
op->ram_sel = p.dma_ram_sel;
op->ram_addr = p.dma_ram_addr;
op->len = p.dma_len;
op->tag = p.dma_tag;
op->write = true;
pending.insert(op);
#ifdef DMA_DEBUG
std::cout << main_time << " dma write [" << label << "] op " <<
std::hex << op->dma_addr << " -> " << op->ram_sel << ":" <<
op->ram_addr << " len=" << op->len << " tag=" << (int) op->tag
<< std::endl;
std::cout << main_time << " dma write [" << label << "] op " << std::hex
<< op->dma_addr << " -> " << op->ram_sel << ":" << op->ram_addr
<< " len=" << op->len << " tag=" << (int)op->tag << std::endl;
#endif
coord.dma_register(op, false);
mr.op_issue(op);
}
coord.dma_register(op, false);
mr.op_issue(op);
}
p.dma_status_valid = 0;
if (!completed.empty()) {
DMAOp *op = completed.front();
completed.pop_front();
p.dma_status_valid = 0;
if (!completed.empty()) {
DMAOp *op = completed.front();
completed.pop_front();
#ifdef DMA_DEBUG
std::cout << main_time << " dma write [" << label <<
"] status complete " << op->dma_addr << std::endl;
std::cout << main_time << " dma write [" << label << "] status complete "
<< op->dma_addr << std::endl;
#endif
p.dma_status_valid = 1;
p.dma_status_tag = op->tag;
pending.erase(op);
// coord.msi_enqueue(0);
delete op;
}
p.dma_status_valid = 1;
p.dma_status_tag = op->tag;
pending.erase(op);
// coord.msi_enqueue(0);
delete op;
}
}
void DMAWriter::pci_op_complete(DMAOp *op)
{
void DMAWriter::pci_op_complete(DMAOp *op) {
#ifdef DMA_DEBUG
std::cout << main_time << " dma write [" << label << "] pci complete " <<
op->dma_addr << std::endl;
std::cout << main_time << " dma write [" << label << "] pci complete "
<< op->dma_addr << std::endl;
#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
std::cout << main_time << " dma write [" << label << "] mem complete " <<
op->dma_addr << ": ";
for (size_t i = 0; i < op->len; i++)
std::cout << (unsigned) op->data[i] << " ";
std::cout << std::endl;
std::cout << main_time << " dma write [" << label << "] mem complete "
<< op->dma_addr << ": ";
for (size_t i = 0; i < op->len; i++)
std::cout << (unsigned)op->data[i] << " ";
std::cout << std::endl;
#endif
coord.dma_mark_ready(op);
coord.dma_mark_ready(op);
}
......@@ -25,15 +25,14 @@
#ifndef DMA_H_
#define DMA_H_
#include <set>
#include <deque>
#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/debug.h"
#include "sims/nic/corundum/obj_dir/Vinterface.h"
#define MAX_DMA_LEN 2048
......@@ -42,95 +41,93 @@ class MemWriter;
class MemReader;
struct DMAPorts {
/* inputs to DMA engine */
vluint64_t &dma_addr;
vluint8_t &dma_ram_sel;
vluint32_t &dma_ram_addr;
vluint16_t &dma_len;
vluint8_t &dma_tag;
vluint8_t &dma_valid;
/* outputs of DMA engine */
vluint8_t &dma_ready;
vluint8_t &dma_status_tag;
vluint8_t &dma_status_valid;
DMAPorts(vluint64_t &dma_addr_, vluint8_t &dma_ram_sel_,
vluint32_t &dma_ram_addr_, vluint16_t &dma_len_,
vluint8_t &dma_tag_, vluint8_t &dma_valid_,
vluint8_t &dma_ready_, vluint8_t &dma_status_tag_,
vluint8_t &dma_status_valid_)
: dma_addr(dma_addr_), dma_ram_sel(dma_ram_sel_),
dma_ram_addr(dma_ram_addr_), dma_len(dma_len_),
dma_tag(dma_tag_), dma_valid(dma_valid_),
dma_ready(dma_ready_), dma_status_tag(dma_status_tag_),
dma_status_valid(dma_status_valid_)
{
}
/* inputs to DMA engine */
vluint64_t &dma_addr;
vluint8_t &dma_ram_sel;
vluint32_t &dma_ram_addr;
vluint16_t &dma_len;
vluint8_t &dma_tag;
vluint8_t &dma_valid;
/* outputs of DMA engine */
vluint8_t &dma_ready;
vluint8_t &dma_status_tag;
vluint8_t &dma_status_valid;
DMAPorts(vluint64_t &dma_addr_, vluint8_t &dma_ram_sel_,
vluint32_t &dma_ram_addr_, vluint16_t &dma_len_, vluint8_t &dma_tag_,
vluint8_t &dma_valid_, vluint8_t &dma_ready_,
vluint8_t &dma_status_tag_, vluint8_t &dma_status_valid_)
: dma_addr(dma_addr_),
dma_ram_sel(dma_ram_sel_),
dma_ram_addr(dma_ram_addr_),
dma_len(dma_len_),
dma_tag(dma_tag_),
dma_valid(dma_valid_),
dma_ready(dma_ready_),
dma_status_tag(dma_status_tag_),
dma_status_valid(dma_status_valid_) {
}
};
struct DMAOp {
DMAEngine *engine;
uint64_t dma_addr;
size_t len;
uint64_t ram_addr;
bool write;
uint8_t ram_sel;
uint8_t tag;
uint8_t data[MAX_DMA_LEN];
DMAEngine *engine;
uint64_t dma_addr;
size_t len;
uint64_t ram_addr;
bool write;
uint8_t ram_sel;
uint8_t tag;
uint8_t data[MAX_DMA_LEN];
};
class DMAEngine {
protected:
DMAPorts &p;
PCICoordinator &coord;
protected:
DMAPorts &p;
PCICoordinator &coord;
DMAEngine(DMAPorts &p_, PCICoordinator &coord_)
: p(p_), coord(coord_) { }
DMAEngine(DMAPorts &p_, PCICoordinator &coord_) : p(p_), coord(coord_) {
}
public:
virtual void pci_op_complete(DMAOp *op) = 0;
virtual void mem_op_complete(DMAOp *op) = 0;
public:
virtual void pci_op_complete(DMAOp *op) = 0;
virtual void mem_op_complete(DMAOp *op) = 0;
};
class DMAReader : public DMAEngine {
protected:
std::set<DMAOp *> pending;
std::deque<DMAOp *> completed;
const char *label;
MemWriter &mw;
public:
DMAReader(const char *label_, DMAPorts &p_, MemWriter &mw_,
PCICoordinator &coord_)
: DMAEngine(p_, coord_), label(label_), mw(mw_)
{
}
virtual void pci_op_complete(DMAOp *op);
virtual void mem_op_complete(DMAOp *op);
void step();
protected:
std::set<DMAOp *> pending;
std::deque<DMAOp *> completed;
const char *label;
MemWriter &mw;
public:
DMAReader(const char *label_, DMAPorts &p_, MemWriter &mw_,
PCICoordinator &coord_)
: DMAEngine(p_, coord_), label(label_), mw(mw_) {
}
virtual void pci_op_complete(DMAOp *op);
virtual void mem_op_complete(DMAOp *op);
void step();
};
class DMAWriter : public DMAEngine {
protected:
std::set<DMAOp *> pending;
std::deque<DMAOp *> completed;
const char *label;
MemReader &mr;
public:
DMAWriter(const char *label_, DMAPorts &p_, MemReader &mr_,
PCICoordinator &coord_)
: DMAEngine(p_, coord_), label(label_), mr(mr_)
{
}
virtual void pci_op_complete(DMAOp *op);
virtual void mem_op_complete(DMAOp *op);
void step();
protected:
std::set<DMAOp *> pending;
std::deque<DMAOp *> completed;
const char *label;
MemReader &mr;
public:
DMAWriter(const char *label_, DMAPorts &p_, MemReader &mr_,
PCICoordinator &coord_)
: DMAEngine(p_, coord_), label(label_), mr(mr_) {
}
virtual void pci_op_complete(DMAOp *op);
virtual void mem_op_complete(DMAOp *op);
void step();
};
#endif // DMA_H_
......@@ -22,10 +22,11 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include "sims/nic/corundum/mem.h"
#include <iostream>
#include "sims/nic/corundum/debug.h"
#include "sims/nic/corundum/mem.h"
#include "sims/nic/corundum/dma.h"
/*
......@@ -40,173 +41,163 @@
#define SEG_COUNT 8
#define SEG_WIDTH (DATA_WIDTH / SEG_COUNT)
void MemWriter::step()
{
if (cur && p.mem_ready &&
((p.mem_ready & p.mem_valid) == p.mem_valid))
{
void MemWriter::step() {
if (cur && p.mem_ready && ((p.mem_ready & p.mem_valid) == p.mem_valid)) {
#ifdef MEM_DEBUG
std::cerr << "completed write to: " << cur->ram_addr << std::endl;
std::cerr << "completed write to: " << cur->ram_addr << std::endl;
#endif
p.mem_valid = 0;
p.mem_be[0] = p.mem_be[1] = p.mem_be[2] = p.mem_be[3] = 0;
if (cur_off == cur->len) {
/* operation is done */
pending.pop_front();
cur->engine->mem_op_complete(cur);
cur_off = 0;
} else {
/* operation is not done yet, we'll pick it back up */
}
cur = 0;
} else if (!cur && !pending.empty()) {
cur = pending.front();
p.mem_valid = 0;
p.mem_be[0] = p.mem_be[1] = p.mem_be[2] = p.mem_be[3] = 0;
if (cur_off == cur->len) {
/* operation is done */
pending.pop_front();
cur->engine->mem_op_complete(cur);
cur_off = 0;
} else {
/* operation is not done yet, we'll pick it back up */
}
cur = 0;
} else if (!cur && !pending.empty()) {
cur = pending.front();
#ifdef MEM_DEBUG
std::cerr << "issuing write to " << cur->ram_addr << std::endl;
std::cerr << "issuing write to " << cur->ram_addr << std::endl;
#endif
size_t data_byte_width = DATA_WIDTH / 8;
size_t data_offset = (cur->ram_addr + cur_off) % data_byte_width;
/* first reset everything */
p.mem_sel = 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_valid = 0;
for (size_t i = 0; i < data_byte_width / 4; i++)
p.mem_data[i] = 0;
/* put data bytes in the right places */
size_t off = data_offset;
size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset ?
data_byte_width - data_offset : cur->len - cur_off);
for (size_t i = 0; i < cur_len; i++, off++) {
size_t byte_off = off % 4;
p.mem_data[off / 4] |= (((uint32_t) cur->data[cur_off + i]) <<
(byte_off * 8));
p.mem_be[off / 32] |= (1 << (off % 32));
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;
size_t data_byte_width = DATA_WIDTH / 8;
size_t data_offset = (cur->ram_addr + cur_off) % data_byte_width;
/* first reset everything */
p.mem_sel = 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_valid = 0;
for (size_t i = 0; i < data_byte_width / 4; i++) p.mem_data[i] = 0;
/* put data bytes in the right places */
size_t off = data_offset;
size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset
? data_byte_width - data_offset
: cur->len - cur_off);
for (size_t i = 0; i < cur_len; i++, off++) {
size_t byte_off = off % 4;
p.mem_data[off / 4] |=
(((uint32_t)cur->data[cur_off + i]) << (byte_off * 8));
p.mem_be[off / 32] |= (1 << (off % 32));
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;
}
}
void MemWriter::op_issue(DMAOp *op)
{
void MemWriter::op_issue(DMAOp *op) {
#ifdef MEM_DEBUG
std::cerr << "enqueued write to " << op->ram_addr << std::endl;
std::cerr << "enqueued write to " << op->ram_addr << std::endl;
#endif
pending.push_back(op);
pending.push_back(op);
}
void MemReader::step() {
size_t data_byte_width = DATA_WIDTH / 8;
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)) {
if (cur && p.mem_resvalid &&
((p.mem_resvalid & p.mem_valid) == p.mem_valid)) {
#ifdef MEM_DEBUG
std::cerr << "completed read from: " << std::hex << cur->ram_addr <<
std::endl;
std::cerr << " reval = " << (unsigned) p.mem_resvalid << std::endl;
std::cerr << "completed read from: " << std::hex << cur->ram_addr
<< std::endl;
std::cerr << " reval = " << (unsigned)p.mem_resvalid << std::endl;
#endif
p.mem_valid = 0;
p.mem_valid = 0;
#ifdef MEM_DEBUG
for (size_t i = 0; i < 32; i++)
std::cerr << " val = " << p.mem_data[i] << std::endl;
for (size_t i = 0; i < 32; i++)
std::cerr << " val = " << p.mem_data[i] << std::endl;
#endif
size_t off = (cur->ram_addr + cur_off) % data_byte_width;
size_t cur_len = (cur->len - cur_off > data_byte_width - off ?
data_byte_width - off : cur->len - cur_off);
for (size_t i = 0; i < cur_len; i++, off++) {
size_t byte_off = (off % 4);
cur->data[cur_off + i] = (p.mem_data[off / 4] >> (byte_off * 8)) &
0xff;
}
cur_off += cur_len;
if (cur_off == cur->len) {
/* operation is done */
pending.pop_front();
cur->engine->mem_op_complete(cur);
cur_off = 0;
} else {
/* operation is not done yet, we'll pick it back up */
}
cur = 0;
} else if (!cur && !pending.empty()) {
cur = pending.front();
size_t data_offset = (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 ? data_byte_width - off
: cur->len - cur_off);
for (size_t i = 0; i < cur_len; i++, off++) {
size_t byte_off = (off % 4);
cur->data[cur_off + i] = (p.mem_data[off / 4] >> (byte_off * 8)) & 0xff;
}
cur_off += cur_len;
if (cur_off == cur->len) {
/* operation is done */
pending.pop_front();
cur->engine->mem_op_complete(cur);
cur_off = 0;
} else {
/* operation is not done yet, we'll pick it back up */
}
cur = 0;
} else if (!cur && !pending.empty()) {
cur = pending.front();
size_t data_offset = (cur->ram_addr + cur_off) % data_byte_width;
#ifdef MEM_DEBUG
std::cerr << "issuing op=" << cur << " read from " << std::hex <<
cur->ram_addr << std::endl;
std::cerr << " off=" << data_offset << std::endl;
std::cerr << "issuing op=" << cur << " read from " << std::hex
<< cur->ram_addr << std::endl;
std::cerr << " off=" << data_offset << std::endl;
#endif
/* first reset everything */
p.mem_sel = 0;
p.mem_addr[0] = p.mem_addr[1] = p.mem_addr[2] = 0;
p.mem_valid = 0x0;
/* put data bytes in the right places */
size_t off = data_offset;
size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset ?
data_byte_width - data_offset : cur->len - cur_off);
for (size_t i = 0; i < cur_len; i++, off++) {
p.mem_valid |= (1 << (off / (SEG_WIDTH / 8)));
}
// p.mem_resready = p.mem_valid;
p.mem_resready = 0xff;
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));
}
}
/* first reset everything */
p.mem_sel = 0;
p.mem_addr[0] = p.mem_addr[1] = p.mem_addr[2] = 0;
p.mem_valid = 0x0;
/* put data bytes in the right places */
size_t off = data_offset;
size_t cur_len = (cur->len - cur_off > data_byte_width - data_offset
? data_byte_width - data_offset
: cur->len - cur_off);
for (size_t i = 0; i < cur_len; i++, off++) {
p.mem_valid |= (1 << (off / (SEG_WIDTH / 8)));
}
// p.mem_resready = p.mem_valid;
p.mem_resready = 0xff;
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));
}
}
#ifdef MEM_DEBUG
for (size_t i = 0; i < 3; i++)
std::cerr << " addr = " << p.mem_addr[i] << std::endl;
std::cerr << " mem_valid = " << (unsigned) p.mem_valid << std::endl;
for (size_t i = 0; i < 3; i++)
std::cerr << " addr = " << p.mem_addr[i] << std::endl;
std::cerr << " mem_valid = " << (unsigned)p.mem_valid << std::endl;
#endif
}
}
}
void MemReader::op_issue(DMAOp *op)
{
void MemReader::op_issue(DMAOp *op) {
#ifdef MEM_DEBUG
std::cerr << "enqueued read from " << op->ram_addr << std::endl;
std::cerr << "enqueued read from " << op->ram_addr << std::endl;
#endif
pending.push_back(op);
pending.push_back(op);
}
This diff is collapsed.
This diff is collapsed.
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