diff --git a/mibuild/sim/ethernet_tb.cpp b/mibuild/sim/ethernet_tb.cpp new file mode 100644 index 000000000..084cf1359 --- /dev/null +++ b/mibuild/sim/ethernet_tb.cpp @@ -0,0 +1,296 @@ +// 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 + +#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; +} + +/* ios */ + +/* Terminal functions */ +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; + } +} + +/* 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 */ + +unsigned char eth_txbuffer[1532]; +unsigned char eth_rxbuffer[1532]; +int eth_txbuffer_len = 0; +int eth_rxbuffer_len = 0; +int eth_rxbuffer_pos = 0; + +struct eth_device +{ + char *dev; + char *tap; + int fd; +}; + +void eth_open(struct eth_device *eth) +{ + + struct ifreq ifr; + eth->fd = open (eth->dev, O_RDWR); + if(eth->fd < 0) { + fprintf (stderr, " Could not open dev %s\n", eth->dev); + return; + } + + memset (&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_TAP | IFF_NO_PI; + strncpy (ifr.ifr_name, eth->tap, IFNAMSIZ); + + if (ioctl (eth->fd, TUNSETIFF, (void *) &ifr) < 0) { + fprintf (stderr, " Could not set %s\n", eth->tap); + close(eth->fd); + } + return; +} + +int eth_close(struct eth_device *eth) +{ + if (eth->fd < 0) + close(eth->fd); +} + +void eth_write_tap( + struct eth_device *eth, + unsigned char *buf, + unsigned long int length) +{ + write (eth->fd, buf, length); +} + +int eth_read_tap ( + struct eth_device *eth, + unsigned char *buf) +{ + + struct pollfd fds[1]; + int n; + int length; + + fds[0].fd = eth->fd; + fds[0].events = POLLIN; + + n = poll(fds, 1, 0); + if ((n > 0) && ((fds[0].revents & POLLIN) == POLLIN)) { + length = read(eth->fd, buf, 1532); + } else { + length = 0; + } + return length; +} + +Vdut* dut; +VerilatedVcdC* tfp; + +#define MAX_LEN 2048 + +struct sim { + bool run; + + unsigned int tick; + clock_t start; + clock_t end; + float speed; + + char txbuffer[MAX_LEN]; + char rxbuffer[MAX_LEN]; + + char rx_serial_stb; + char rx_serial_data; + char rx_serial_presented; +}; + +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; +} + +#ifdef ETH_SOURCE_STB +int eth_last_source_stb = 0; + +int ethernet_service(struct eth_device *eth) { + /* fpga --> tap */ + ETH_SOURCE_ACK = 1; + if(ETH_SOURCE_STB == 1) { + eth_txbuffer[eth_txbuffer_len] = ETH_SOURCE_DATA; + eth_txbuffer_len++; + } else { + if (eth_last_source_stb) { + eth_write_tap(eth, eth_txbuffer, eth_txbuffer_len-1); // XXX FIXME software or gateware? + eth_txbuffer_len = 0; + } + } + eth_last_source_stb = ETH_SOURCE_STB; + + /* tap --> fpga */ + if (eth_rxbuffer_len == 0) { + ETH_SINK_STB = 0; + eth_rxbuffer_pos = 0; + eth_rxbuffer_len = eth_read_tap(eth, eth_rxbuffer); + } else { + if (eth_rxbuffer_pos < MAX(eth_rxbuffer_len, 60)) { + ETH_SINK_STB = 1; + ETH_SINK_DATA = eth_rxbuffer[eth_rxbuffer_pos]; + eth_rxbuffer_pos++; + } else { + ETH_SINK_STB = 0; + eth_rxbuffer_len = 0; + memset(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) +{ + 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); + + struct eth_device eth; + char dev[] = "/dev/net/tap0"; + char tap[] = "tap0"; + eth.dev = dev; + eth.tap = tap; + eth_open(ð); + + s.run = true; + while(s.run) { + sim_tick(&s); + if (SYS_CLK) { + if (console_service(&s) != 0) + s.run = false; +#ifdef ETH_SOURCE_STB + ethernet_service(ð); +#endif + } + } + s.end = clock(); + + tfp->close(); + + exit(0); +} diff --git a/mibuild/sim/server.py b/mibuild/sim/server.py deleted file mode 100644 index 87981fca1..000000000 --- a/mibuild/sim/server.py +++ /dev/null @@ -1,129 +0,0 @@ -# This file is Copyright (c) 2015 Florent Kermarrec -# License: BSD - -import socket -import os -import pty -import time -import threading -import subprocess -import struct -import fcntl - -messages= { - "EXIT": 0, - "ACK": 1, - "ERROR": 2, - "UART": 3, - "ETHERNET": 4 -} - -class PacketTooLarge(Exception): - pass - -class VerilatorServer: - def __init__(self, sockaddr="/tmp/simsocket"): - self.sockaddr = sockaddr - self.socket = socket.socket(socket.AF_UNIX, socket.SOCK_SEQPACKET) - self._cleanup_file() - self.socket.bind(self.sockaddr) - self.socket.listen(1) - - master, slave = pty.openpty() - self.serial = master - self.serial_name = os.ttyname(slave) - - os.system("openvpn --mktun --dev tap0") - os.system("ip link set tap0 up") - os.system("ip addr add 192.169.0.14/24 dev tap0") - os.system("iface tap0 inet") - os.system("mknod /dev/net/tap c 10 200") - os.system("chmod 600 /dev/net/tap") - - - self.ack = False - - self._print_banner() - - def _print_banner(self): - print("Mibuild simulation server") - print("sockaddr: {}".format(self.sockaddr)) - print("serial: {}".format(self.serial_name)) - - def _cleanup_file(self): - try: - os.remove(self.sockaddr) - except OSError: - pass - - def accept(self): - self.conn, addr = self.socket.accept() - - def send(self, packet): - self.conn.send(packet) - - def recv(self): - maxlen = 2048 - packet = self.conn.recv(maxlen) - if len(packet) < 1: - return None - if len(packet) >= maxlen: - raise PacketTooLarge - return packet - - def close(self): - if hasattr(self, "conn"): - self.conn.shutdown(socket.SHUT_RDWR) - self.conn.close() - if hasattr(self, "socket"): - self.socket.shutdown(socket.SHUT_RDWR) - self.socket.close() - os.system("openvpn --rmtun --dev tap0") - os.system("rm -f /dev/net/tap") - self._cleanup_file() - -# XXX proof of concept -server = VerilatorServer() -server.accept() -print("Connection accepted") - -TUNSETIFF = 0x400454ca -IFF_TAP = 0x0002 -IFF_NO_PI = 0x1000 - -def read(): - while True: - packet = server.recv() - if packet is not None: - if packet[0] == messages["UART"]: - c = bytes(chr(packet[1]).encode('utf-8')) - os.write(server.serial, c) - elif packet[0] == messages["ETHERNET"]: - tap = os.open("/dev/net/tun", os.O_RDWR) - fcntl.ioctl(tap, TUNSETIFF, struct.pack("16sH", b"tap0", IFF_TAP | IFF_NO_PI)) - os.write(tap, packet[1+8:-4]) - os.close(tap) - elif packet[0] == messages["ACK"]: - server.ack = True - -def write(): - while True: - for c in list(os.read(server.serial, 100)): - packet = [messages["UART"], c] - server.send(bytes(packet)) - while not server.ack: - pass - server.ack = False - -readthread = threading.Thread(target=read, daemon=True) -readthread.start() - -writethread = threading.Thread(target=write, daemon=True) -writethread.start() - -try: - while True: - time.sleep(1) -except KeyboardInterrupt: - server.close() - diff --git a/mibuild/sim/server_tb.cpp b/mibuild/sim/server_tb.cpp deleted file mode 100644 index 8563eebfd..000000000 --- a/mibuild/sim/server_tb.cpp +++ /dev/null @@ -1,236 +0,0 @@ -// This file is Copyright (c) 2015 Florent Kermarrec -// License: BSD - -#include - -#include "Vdut.h" -#include "verilated.h" -#include "verilated_vcd_c.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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; -} - -Vdut* dut; -VerilatedVcdC* tfp; - -/* ios */ - -#define MAX_LEN 2048 - -enum { - MESSAGE_EXIT = 0, - MESSAGE_ACK, - MESSAGE_ERROR, - MESSAGE_UART, - MESSAGE_ETH -}; - -struct sim { - int socket; - bool run; - - unsigned int tick; - clock_t start; - clock_t end; - float speed; - - char txbuffer[MAX_LEN]; - char rxbuffer[MAX_LEN]; - - char rx_serial_stb; - char rx_serial_data; - char rx_serial_presented; -}; - -unsigned char eth_txbuffer[1532]; -unsigned char eth_rxbuffer[1532]; -int eth_txbuffer_len = 0; -int eth_rxbuffer_len = 0; -int eth_rxbuffer_pos = 0; - -int sim_connect(struct sim *s, const char *sockaddr) -{ - struct sockaddr_un addr; - - s->socket = socket(AF_UNIX, SOCK_SEQPACKET, 0); - if(s->socket < 0) { - return -1; - } - - addr.sun_family = AF_UNIX; - strcpy(addr.sun_path, sockaddr); - if(connect(s->socket, (struct sockaddr *)&addr, sizeof(addr)) != 0) { - close(s->socket); - return -1; - } - - return 0; -} - -int sim_send(struct sim *s, char *buffer, int len) -{ - send(s->socket, s->txbuffer, len, 0); - return 0; -} - -void sim_receive_process(struct sim *s, char * buffer, int len) { - int i; - switch(buffer[0]) { - case MESSAGE_EXIT: - s->run = false; - break; - case MESSAGE_UART: - i = 0; - for(i=0; irx_serial_stb = 1; - s->rx_serial_data = buffer[i+1]; - while (s->rx_serial_presented == 0); - s->rx_serial_presented = 0; - } - s->rx_serial_stb = 0; - break; - default: - break; - } -} - -void *sim_receive(void *s_void) -{ - struct sim *s = (sim *) s_void; - int rxlen; - while(1) - { - rxlen = recv(s->socket, s->rxbuffer, MAX_LEN, 0); - if (rxlen > 0) - sim_receive_process(s, s->rxbuffer, rxlen); - s->txbuffer[0] = MESSAGE_ACK; - sim_send(s, s->txbuffer, 1); - } -} - -void sim_destroy(struct sim *s) -{ - close(s->socket); - free(s); -} - -int console_service(struct sim *s) -{ - /* fpga --> console */ - SERIAL_SOURCE_ACK = 1; - if(SERIAL_SOURCE_STB == 1) { - s->txbuffer[0] = MESSAGE_UART; - s->txbuffer[1] = SERIAL_SOURCE_DATA; - sim_send(s, s->txbuffer, 2); - } - - /* console --> fpga */ - SERIAL_SINK_STB = s->rx_serial_stb; - SERIAL_SINK_DATA = s->rx_serial_data; - if (SERIAL_SINK_STB & SERIAL_SINK_ACK) - s->rx_serial_presented = s->rx_serial_stb; - - return 0; -} - -#ifdef ETH_SOURCE_STB -int eth_last_source_stb = 0; - -int ethernet_service(struct sim *s) { - /* fpga --> ethernet tap */ - ETH_SOURCE_ACK = 1; - if(ETH_SOURCE_STB == 1) { - eth_txbuffer[eth_txbuffer_len] = ETH_SOURCE_DATA; - eth_txbuffer_len++; - } else { - if (eth_last_source_stb) { - s->txbuffer[0] = MESSAGE_ETH; - memcpy(s->txbuffer+1, eth_txbuffer, eth_txbuffer_len); - sim_send(s, s->txbuffer, eth_txbuffer_len+1); - eth_txbuffer_len = 0; - } - } - eth_last_source_stb = ETH_SOURCE_STB; -} -#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) -{ - 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); - sim_connect(&s, "/tmp/simsocket"); - - pthread_t sim_receive_thread; - - pthread_create(&sim_receive_thread, NULL, sim_receive, &s); - - s.run = true; - while(s.run) { - sim_tick(&s); - if (SYS_CLK) { - if (console_service(&s) != 0) - s.run = false; -#ifdef ETH_SOURCE_STB - ethernet_service(&s); -#endif - } - } - s.end = clock(); - - tfp->close(); - pthread_cancel(sim_receive_thread); - sim_destroy(&s); - - exit(0); -}