mibuild/sim: remove server and interact with tap directly in cpp tb. for now: - need to create tap manually: 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 - ARP request/reply OK - TFTP request OK - need to be tested with TFTP server. - need clean up
This commit is contained in:
parent
3e84c66ba9
commit
e82b540a96
|
@ -0,0 +1,296 @@
|
||||||
|
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
// License: BSD
|
||||||
|
#include "Vdut.h"
|
||||||
|
#include "verilated.h"
|
||||||
|
#include "verilated_vcd_c.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <termios.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
|
||||||
|
#include <linux/if.h>
|
||||||
|
#include <linux/if_tun.h>
|
||||||
|
|
||||||
|
#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);
|
||||||
|
}
|
|
@ -1,129 +0,0 @@
|
||||||
# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
||||||
# 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()
|
|
||||||
|
|
|
@ -1,236 +0,0 @@
|
||||||
// This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
|
|
||||||
// License: BSD
|
|
||||||
|
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
#include "Vdut.h"
|
|
||||||
#include "verilated.h"
|
|
||||||
#include "verilated_vcd_c.h"
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/select.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
#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; i<len-1; i++) {
|
|
||||||
s->rx_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);
|
|
||||||
}
|
|
Loading…
Reference in New Issue