firesim/target-design/switch/shmemport.h

193 lines
5.0 KiB
C++

#ifndef __SHMEMPORT_H
#define __SHMEMPORT_H
#include <errno.h>
class ShmemPort : public BasePort {
public:
ShmemPort(int portNo, char *shmemportname, bool uplink);
void tick();
void tick_pre();
void send();
void recv();
private:
uint8_t *recvbufs[2];
uint8_t *sendbufs[2];
int currentround = 0;
};
ShmemPort::ShmemPort(int portNo, char *shmemportname, bool uplink)
: BasePort(portNo, !uplink) {
#define SHMEM_EXTRABYTES 1
#define SHMEM_NAME_SIZE 120
// create shared memory regions
char name[SHMEM_NAME_SIZE];
int shmemfd;
char *recvdirection;
char *senddirection;
int ftresult;
int shm_flags;
if (uplink) {
// uplink should not truncate on SHM_OPEN
shm_flags = O_RDWR /*| O_CREAT*/;
} else {
shm_flags = O_RDWR | O_CREAT | O_TRUNC;
}
if (uplink) {
fprintf(stdout, "Uplink Port\n");
recvdirection = "stn";
senddirection = "nts";
} else {
fprintf(stdout, "Downlink Port\n");
recvdirection = "nts";
senddirection = "stn";
}
for (int j = 0; j < 2; j++) {
int namelen;
if (shmemportname) {
fprintf(stdout, "Using non-slot-id associated shmemportname:\n");
namelen = snprintf(name,
SHMEM_NAME_SIZE,
"/port_%s%s_%d",
recvdirection,
shmemportname,
j);
if (namelen >= SHMEM_NAME_SIZE) {
fprintf(stderr,
"shmem port name /port_%s%s_%d too large\n",
recvdirection,
shmemportname,
j);
}
} else {
fprintf(stdout, "Using slot-id associated shmemportname:\n");
snprintf(
name, SHMEM_NAME_SIZE, "/port_%s%d_%d", recvdirection, _portNo, j);
}
fprintf(stdout, "opening/creating shmem region\n%s\n", name);
shmemfd = shm_open(name, shm_flags, S_IRWXU);
while (shmemfd == -1) {
perror("shm_open failed");
if (uplink) {
fprintf(stdout, "retrying in 1s...\n");
sleep(1);
shmemfd = shm_open(name, shm_flags, S_IRWXU);
} else {
abort();
}
}
if (!uplink) {
ftresult = ftruncate(shmemfd, BUFSIZE_BYTES + SHMEM_EXTRABYTES);
if (ftresult == -1) {
perror("ftruncate failed");
abort();
}
}
recvbufs[j] = (uint8_t *)mmap(NULL,
BUFSIZE_BYTES + SHMEM_EXTRABYTES,
PROT_READ | PROT_WRITE,
MAP_SHARED,
shmemfd,
0);
if (recvbufs[j] == MAP_FAILED) {
perror("mmap failed");
abort();
}
if (!uplink) {
memset(recvbufs[j], 0, BUFSIZE_BYTES + SHMEM_EXTRABYTES);
}
if (shmemportname) {
fprintf(stdout, "Using non-slot-id associated shmemportname:\n");
sprintf(name, "/port_%s%s_%d", senddirection, shmemportname, j);
} else {
fprintf(stdout, "Using slot-id associated shmemportname:\n");
sprintf(name, "/port_%s%d_%d", senddirection, _portNo, j);
}
fprintf(stdout, "opening/creating shmem region\n%s\n", name);
shmemfd = shm_open(name, shm_flags, S_IRWXU);
while (shmemfd == -1) {
perror("shm_open failed");
if (uplink) {
fprintf(stdout, "retrying in 1s...\n");
sleep(1);
shmemfd = shm_open(name, shm_flags, S_IRWXU);
} else {
abort();
}
}
if (!uplink) {
ftresult = ftruncate(shmemfd, BUFSIZE_BYTES + SHMEM_EXTRABYTES);
if (ftresult == -1) {
perror("ftruncate failed");
abort();
}
}
sendbufs[j] = (uint8_t *)mmap(NULL,
BUFSIZE_BYTES + SHMEM_EXTRABYTES,
PROT_READ | PROT_WRITE,
MAP_SHARED,
shmemfd,
0);
if (sendbufs[j] == MAP_FAILED) {
perror("mmap failed");
abort();
}
if (!uplink) {
memset(sendbufs[j], 0, BUFSIZE_BYTES + SHMEM_EXTRABYTES);
}
}
// setup "current" bufs. tick will swap for shmem passing
current_input_buf = recvbufs[0];
current_output_buf = sendbufs[0];
}
void ShmemPort::send() {
if (((uint64_t *)current_output_buf)[0] == 0xDEADBEEFDEADBEEFL) {
// if compress flag is set, clear it, this port type doesn't care
// (and in fact, we're writing too much, so stuff later will get confused)
((uint64_t *)current_output_buf)[0] = 0L;
}
// mark flag to initiate "send"
current_output_buf[BUFSIZE_BYTES] = 1;
}
void ShmemPort::recv() {
volatile uint8_t *polladdr = current_input_buf + BUFSIZE_BYTES;
while (*polladdr == 0) {
;
} // poll
}
void ShmemPort::tick_pre() {
currentround = (currentround + 1) % 2;
current_output_buf = sendbufs[currentround];
}
void ShmemPort::tick() {
// zero out recv buf flag for next iter
current_input_buf[BUFSIZE_BYTES] = 0;
// swap buf pointers
current_input_buf = recvbufs[currentround];
}
#endif // __SSHMEMPORT_H