// This file is Copyright (c) 2015 Florent Kermarrec // License: BSD #include "Vdut.h" #include "verilated.h" #include "verilated_vcd_c.h" #include #include #include #include #include #include #include #include #include #include #include /* ios */ #ifdef SERIAL_SOURCE_STB #define WITH_SERIAL #endif #ifdef ETH_SOURCE_STB #define WITH_ETH #endif #define MAX(a,b) (((a)>(b))?(a):(b)) #define MIN(a,b) (((a)<(b))?(a):(b)) int trace = 0; vluint64_t main_time = 0; double sc_time_stamp() { return main_time; } /* Sim struct */ struct sim { bool run; unsigned int tick; clock_t start; clock_t end; float speed; #ifdef WITH_SERIAL_PTY char serial_dev[64]; int serial_fd; unsigned char serial_rx_data; unsigned char serial_tx_data; #endif #ifdef WITH_ETH const char *eth_dev; const char *eth_tap; int eth_fd; unsigned char eth_txbuffer[2048]; unsigned char eth_rxbuffer[2048]; int eth_txbuffer_len; int eth_rxbuffer_len; int eth_rxbuffer_pos; int eth_last_source_stb; #endif }; /* Serial functions */ #ifndef WITH_SERIAL_PTY struct termios orig_termios; void reset_terminal_mode(void) { tcsetattr(0, TCSANOW, &orig_termios); } void set_conio_terminal_mode(void) { struct termios new_termios; /* take two copies - one for now, one for later */ tcgetattr(0, &orig_termios); memcpy(&new_termios, &orig_termios, sizeof(new_termios)); /* register cleanup handler, and set the new terminal mode */ atexit(reset_terminal_mode); cfmakeraw(&new_termios); tcsetattr(0, TCSANOW, &new_termios); } int kbhit(void) { struct timeval tv = { 0L, 0L }; fd_set fds; FD_ZERO(&fds); FD_SET(0, &fds); return select(1, &fds, NULL, NULL, &tv); } int getch(void) { int r; unsigned char c; if((r = read(0, &c, sizeof(c))) < 0) { return r; } else { return c; } } #endif /* Ethernet functions */ /* create tap: openvpn --mktun --dev tap0 ifconfig tap0 192.168.0.14 up mknod /dev/net/tap0 c 10 200 delete tap: openvpn --rmtun --dev tap0 */ #ifdef WITH_ETH void eth_init(struct sim *s, const char *dev, const char*tap) { s->eth_txbuffer_len = 0; s->eth_rxbuffer_len = 0; s->eth_rxbuffer_pos = 0; s->eth_last_source_stb = 0; s->eth_dev = dev; s->eth_tap = tap; } void eth_open(struct sim *s) { struct ifreq ifr; s->eth_fd = open (s->eth_dev, O_RDWR); if(s->eth_fd < 0) { fprintf(stderr, " Could not open dev %s\n", s->eth_dev); return; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TAP | IFF_NO_PI; strncpy(ifr.ifr_name, s->eth_tap, IFNAMSIZ); if(ioctl(s->eth_fd, TUNSETIFF, (void *) &ifr) < 0) { fprintf(stderr, " Could not set %s\n", s->eth_tap); close(s->eth_fd); } return; } int eth_close(struct sim *s) { if(s->eth_fd < 0) close(s->eth_fd); } void eth_write(struct sim *s, unsigned char *buf, int len) { write(s->eth_fd, buf, len); } int eth_read(struct sim *s, unsigned char *buf) { struct pollfd fds[1]; int n; int len; fds[0].fd = s->eth_fd; fds[0].events = POLLIN; n = poll(fds, 1, 0); if((n > 0) && ((fds[0].revents & POLLIN) == POLLIN)) { len = read(s->eth_fd, buf, 1532); } else { len = 0; } return len; } #endif Vdut* dut; VerilatedVcdC* tfp; #ifndef WITH_SERIAL_PTY int console_service(struct sim *s) { /* fpga --> console */ SERIAL_SOURCE_ACK = 1; if(SERIAL_SOURCE_STB == 1) { if(SERIAL_SOURCE_DATA == '\n') putchar('\r'); putchar(SERIAL_SOURCE_DATA); fflush(stdout); } /* console --> fpga */ SERIAL_SINK_STB = 0; if(s->tick%(1000) == 0) { if(kbhit()) { char c = getch(); if(c == 27 && !kbhit()) { printf("\r\n"); return -1; } else { SERIAL_SINK_STB = 1; SERIAL_SINK_DATA = c; } } } return 0; } #else void console_init(struct sim *s) { FILE *f; f = fopen("/tmp/simserial","r"); fscanf(f, "%[^\n]", s->serial_dev); fclose(f); return; } void console_open(struct sim *s) { s->serial_fd = open(s->serial_dev, O_RDWR); if(s->serial_fd < 0) { fprintf(stderr, " Could not open dev %s\n", s->serial_dev); return; } return; } int console_close(struct sim *s) { if(s->serial_fd < 0) close(s->serial_fd); } void console_write(struct sim *s, unsigned char *buf, int len) { write(s->serial_fd, buf, len); } int console_read(struct sim *s, unsigned char *buf) { struct pollfd fds[1]; int n; int len; fds[0].fd = s->serial_fd; fds[0].events = POLLIN; n = poll(fds, 1, 0); if((n > 0) && ((fds[0].revents & POLLIN) == POLLIN)) { len = read(s->serial_fd, buf, 1); } else { len = 0; } return len; } int console_service(struct sim *s) { /* fpga --> console */ SERIAL_SOURCE_ACK = 1; if(SERIAL_SOURCE_STB == 1) { s->serial_tx_data = SERIAL_SOURCE_DATA; console_write(s, &(s->serial_tx_data), 1); } /* console --> fpga */ SERIAL_SINK_STB = 0; if(console_read(s, &(s->serial_rx_data))) { SERIAL_SINK_STB = 1; SERIAL_SINK_DATA = s->serial_rx_data; } return 0; } #endif #ifdef WITH_ETH int ethernet_service(struct sim *s) { /* fpga --> tap */ ETH_SOURCE_ACK = 1; if(ETH_SOURCE_STB == 1) { s->eth_txbuffer[s->eth_txbuffer_len] = ETH_SOURCE_DATA; s->eth_txbuffer_len++; } else { if(s->eth_last_source_stb) { eth_write(s, s->eth_txbuffer, s->eth_txbuffer_len); s->eth_txbuffer_len = 0; } } s->eth_last_source_stb = ETH_SOURCE_STB; /* tap --> fpga */ if(s->eth_rxbuffer_len == 0) { ETH_SINK_STB = 0; s->eth_rxbuffer_pos = 0; s->eth_rxbuffer_len = eth_read(s, s->eth_rxbuffer); } else { if(s->eth_rxbuffer_pos < MAX(s->eth_rxbuffer_len, 60)) { ETH_SINK_STB = 1; ETH_SINK_DATA = s->eth_rxbuffer[s->eth_rxbuffer_pos]; s->eth_rxbuffer_pos++; } else { ETH_SINK_STB = 0; s->eth_rxbuffer_len = 0; memset(s->eth_rxbuffer, 0, 1532); } } } #endif void sim_tick(struct sim *s) { SYS_CLK = s->tick%2; dut->eval(); if(trace) tfp->dump(s->tick); s->tick++; } void sim_init(struct sim *s) { int i; s->tick = 0; #ifdef SYS_RST SYS_RST = 1; SYS_CLK = 0; for (i=0; i<8; i++) sim_tick(s); SYS_RST = 0; #endif s->start = clock(); } int main(int argc, char **argv, char **env) { float speed; #ifndef WITH_SERIAL_PTY set_conio_terminal_mode(); #endif Verilated::commandArgs(argc, argv); dut = new Vdut; Verilated::traceEverOn(true); tfp = new VerilatedVcdC; dut->trace(tfp, 99); tfp->open("dut.vcd"); struct sim s; sim_init(&s); #ifdef WITH_SERIAL_PTY console_init(&s); console_open(&s); #endif #ifdef WITH_ETH eth_init(&s, "/dev/net/tap0", "tap0"); // XXX get this from /tmp/simethernet eth_open(&s); #endif s.run = true; while(s.run) { sim_tick(&s); if(SYS_CLK) { #ifdef WITH_SERIAL if(console_service(&s) != 0) s.run = false; #endif #ifdef WITH_ETH ethernet_service(&s); #endif } } s.end = clock(); speed = (s.tick/2)/((s.end-s.start)/CLOCKS_PER_SEC); printf("average speed: %3.3f MHz\n\r", speed/1000000); tfp->close(); #ifdef WITH_SERIAL_PTY console_close(&s); #endif #ifdef WITH_ETH eth_close(&s); #endif exit(0); }