Commit 160cf5f5 authored by Sebastien Bourdeauducq's avatar Sebastien Bourdeauducq
Browse files

build: remove sim (needs refactoring as per my email from Nov 12 2015)

parent 988cbd3d
from migen.build.sim.platform import SimPlatform
sim_special_overrides = {}
// 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>
/* 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);
}
from migen.build.generic_platform import GenericPlatform
from migen.build.sim import common, verilator
class SimPlatform(GenericPlatform):
def __init__(self, *args, toolchain="verilator", **kwargs):
GenericPlatform.__init__(self, *args, **kwargs)
if toolchain == "verilator":
self.toolchain = verilator.SimVerilatorToolchain()
else:
raise ValueError("Unknown toolchain")
def get_verilog(self, *args, special_overrides=dict(), **kwargs):
so = dict(common.sim_special_overrides)
so.update(special_overrides)
return GenericPlatform.get_verilog(self, *args, special_overrides=so, **kwargs)
def build(self, *args, **kwargs):
return self.toolchain.build(self, *args, **kwargs)
# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
# License: BSD
import os
import subprocess
from migen.fhdl.structure import _Fragment
from migen.build import tools
from migen.build.generic_platform import *
def _build_tb(platform, vns, serial, template):
def io_name(resource, subsignal=None):
res = platform.lookup_request(resource)
if subsignal is not None:
res = getattr(res, subsignal)
return vns.get_name(res)
ios = """
#define SYS_CLK dut->{sys_clk}
""".format(sys_clk=io_name("sys_clk"))
if serial == "pty":
ios += "#define WITH_SERIAL_PTY"
elif serial == "console":
pass
else:
raise ValueError
try:
ios += """
#define SERIAL_SOURCE_STB dut->{serial_source_stb}
#define SERIAL_SOURCE_ACK dut->{serial_source_ack}
#define SERIAL_SOURCE_DATA dut->{serial_source_data}
#define SERIAL_SINK_STB dut->{serial_sink_stb}
#define SERIAL_SINK_ACK dut->{serial_sink_ack}
#define SERIAL_SINK_DATA dut->{serial_sink_data}
""".format(
serial_source_stb=io_name("serial", "source_stb"),
serial_source_ack=io_name("serial", "source_ack"),
serial_source_data=io_name("serial", "source_data"),
serial_sink_stb=io_name("serial", "sink_stb"),
serial_sink_ack=io_name("serial", "sink_ack"),
serial_sink_data=io_name("serial", "sink_data"),
)
except:
pass
try:
ios += """
#define ETH_SOURCE_STB dut->{eth_source_stb}
#define ETH_SOURCE_ACK dut->{eth_source_ack}
#define ETH_SOURCE_DATA dut->{eth_source_data}
#define ETH_SINK_STB dut->{eth_sink_stb}
#define ETH_SINK_ACK dut->{eth_sink_ack}
#define ETH_SINK_DATA dut->{eth_sink_data}
""".format(
eth_source_stb=io_name("eth", "source_stb"),
eth_source_ack=io_name("eth", "source_ack"),
eth_source_data=io_name("eth", "source_data"),
eth_sink_stb=io_name("eth", "sink_stb"),
eth_sink_ack=io_name("eth", "sink_ack"),
eth_sink_data=io_name("eth", "sink_data"),
)
except:
pass
content = ""
f = open(template, "r")
done = False
for l in f:
content += l
if "/* ios */" in l and not done:
content += ios
done = True
f.close()
tools.write_to_file("dut_tb.cpp", content)
def _build_sim(platform, vns, build_name, include_paths, sim_path, serial, verbose):
include = ""
for path in include_paths:
include += "-I"+path+" "
build_script_contents = """# Autogenerated by Migen
rm -rf obj_dir/
verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp -LDFLAGS "-lpthread" -trace {include}
make -j -C obj_dir/ -f Vdut.mk Vdut
""".format(
disable_warnings="-Wno-fatal",
include=include)
build_script_file = "build_" + build_name + ".sh"
tools.write_to_file(build_script_file, build_script_contents, force_unix=True)
_build_tb(platform, vns, serial, os.path.join("..", sim_path, "dut_tb.cpp"))
if verbose:
r = subprocess.call(["bash", build_script_file])
else:
r = subprocess.call(["bash", build_script_file], stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
if r != 0:
raise OSError("Subprocess failed")
def _run_sim(build_name):
run_script_contents = """obj_dir/Vdut
"""
run_script_file = "run_" + build_name + ".sh"
tools.write_to_file(run_script_file, run_script_contents, force_unix=True)
r = subprocess.call(["bash", run_script_file])
if r != 0:
raise OSError("Subprocess failed")
class SimVerilatorToolchain:
# XXX fir sim_path
def build(self, platform, fragment, build_dir="build", build_name="top",
sim_path="../migen/migen/build/sim/", serial="console",
run=True, verbose=False):
tools.mkdir_noerror(build_dir)
os.chdir(build_dir)
if not isinstance(fragment, _Fragment):
fragment = fragment.get_fragment()
platform.finalize(fragment)
v_output = platform.get_verilog(fragment)
named_sc, named_pc = platform.resolve_signals(v_output.ns)
v_output.write("dut.v")
include_paths = []
for source in platform.sources:
path = os.path.dirname(source[0]).replace("\\", "\/")
if path not in include_paths:
include_paths.append(path)
include_paths += platform.verilog_include_paths
_build_sim(platform, v_output.ns, build_name, include_paths, sim_path, serial, verbose)
if run:
_run_sim(build_name)
os.chdir("..")
return v_output.ns
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