mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
mibuild: initial Verilator support
This commit is contained in:
parent
8f81ae6826
commit
382ca374c3
4 changed files with 300 additions and 0 deletions
31
mibuild/platforms/sim.py
Normal file
31
mibuild/platforms/sim.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
from mibuild.generic_platform import *
|
||||||
|
from mibuild.crg import SimpleCRG
|
||||||
|
from mibuild.sim.verilator import VerilatorPlatform
|
||||||
|
|
||||||
|
class SimPins(Pins):
|
||||||
|
def __init__(self, n):
|
||||||
|
Pins.__init__(self, "s "*n)
|
||||||
|
|
||||||
|
_io = [
|
||||||
|
("sys_clk", 0, SimPins(1)),
|
||||||
|
("sys_rst", 0, SimPins(1)),
|
||||||
|
("serial", 0,
|
||||||
|
Subsignal("source_stb", SimPins(1)),
|
||||||
|
Subsignal("source_ack", SimPins(1)),
|
||||||
|
Subsignal("source_data", SimPins(8)),
|
||||||
|
|
||||||
|
Subsignal("sink_stb", SimPins(1)),
|
||||||
|
Subsignal("sink_ack", SimPins(1)),
|
||||||
|
Subsignal("sink_data", SimPins(8)),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
class Platform(VerilatorPlatform):
|
||||||
|
is_sim = True
|
||||||
|
default_clk_name = "sys_clk"
|
||||||
|
default_clk_period = 1000 # on modern computers simulate at ~ 1MHz
|
||||||
|
def __init__(self):
|
||||||
|
VerilatorPlatform.__init__(self, "SIM", _io)
|
||||||
|
|
||||||
|
def do_finalize(self, fragment):
|
||||||
|
pass
|
0
mibuild/sim/__init__.py
Normal file
0
mibuild/sim/__init__.py
Normal file
158
mibuild/sim/dut_tb.cpp
Normal file
158
mibuild/sim/dut_tb.cpp
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
// 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/select.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <termios.h>
|
||||||
|
|
||||||
|
int trace = 0;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vluint64_t main_time = 0;
|
||||||
|
double sc_time_stamp () {
|
||||||
|
return main_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vdut* dut;
|
||||||
|
VerilatedVcdC* tfp;
|
||||||
|
unsigned int tick;
|
||||||
|
|
||||||
|
/* ios */
|
||||||
|
/* ios */
|
||||||
|
|
||||||
|
int console_service() {
|
||||||
|
/* 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 (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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim_tick() {
|
||||||
|
SYS_CLK = tick%2;
|
||||||
|
dut->eval();
|
||||||
|
if (trace)
|
||||||
|
tfp->dump(tick);
|
||||||
|
tick++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sim_init() {
|
||||||
|
int i;
|
||||||
|
tick = 0;
|
||||||
|
#ifdef SYS_RST
|
||||||
|
SYS_RST = 1;
|
||||||
|
SYS_CLK = 0;
|
||||||
|
for (i=0; i<8; i++)
|
||||||
|
sim_tick();
|
||||||
|
SYS_RST = 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv, char **env) {
|
||||||
|
|
||||||
|
clock_t start;
|
||||||
|
clock_t end;
|
||||||
|
float speed;
|
||||||
|
|
||||||
|
set_conio_terminal_mode();
|
||||||
|
|
||||||
|
Verilated::commandArgs(argc, argv);
|
||||||
|
dut = new Vdut;
|
||||||
|
|
||||||
|
Verilated::traceEverOn(true);
|
||||||
|
tfp = new VerilatedVcdC;
|
||||||
|
dut->trace(tfp, 99);
|
||||||
|
tfp->open("dut.vcd");
|
||||||
|
|
||||||
|
start = clock();
|
||||||
|
sim_init();
|
||||||
|
bool run = true;
|
||||||
|
while(run) {
|
||||||
|
sim_tick();
|
||||||
|
if (SYS_CLK) {
|
||||||
|
if (console_service() != 0)
|
||||||
|
run = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end = clock();
|
||||||
|
|
||||||
|
speed = (tick/2)/((end-start)/CLOCKS_PER_SEC);
|
||||||
|
|
||||||
|
printf("averate speed: %3.3f MHz\n\r", speed/1000000);
|
||||||
|
|
||||||
|
tfp->close();
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
111
mibuild/sim/verilator.py
Normal file
111
mibuild/sim/verilator.py
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
# This file is Copyright (c) 2015 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||||
|
# License: BSD
|
||||||
|
|
||||||
|
import os, subprocess
|
||||||
|
|
||||||
|
from migen.fhdl.std import *
|
||||||
|
from migen.fhdl.structure import _Fragment
|
||||||
|
from mibuild.generic_platform import *
|
||||||
|
|
||||||
|
def _build_tb(platform, template):
|
||||||
|
|
||||||
|
def io_name(ressource, subsignal=None):
|
||||||
|
res = platform.lookup_request(ressource)
|
||||||
|
if subsignal is not None:
|
||||||
|
res = getattr(res, subsignal)
|
||||||
|
return platform.vns.get_name(res)
|
||||||
|
|
||||||
|
ios = """
|
||||||
|
#define SYS_CLK dut->{sys_clk}
|
||||||
|
|
||||||
|
#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(
|
||||||
|
sys_clk=io_name("sys_clk"),
|
||||||
|
|
||||||
|
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"),
|
||||||
|
)
|
||||||
|
|
||||||
|
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, build_name, include_paths, verilator_root_path, template_file, trace):
|
||||||
|
include = ""
|
||||||
|
for path in include_paths:
|
||||||
|
include += "-I"+path+" "
|
||||||
|
|
||||||
|
build_script_contents = """# Autogenerated by mibuild
|
||||||
|
rm -rf obj_dir/
|
||||||
|
verilator {disable_warnings} -O3 --cc dut.v --exe dut_tb.cpp {trace} {include}
|
||||||
|
make -j -C obj_dir/ -f Vdut.mk Vdut VERILATOR_ROOT={verilator_root}
|
||||||
|
|
||||||
|
""".format(verilator_root= os.path.join("../../", verilator_root_path), # XXX
|
||||||
|
disable_warnings="-Wno-lint -Wno-INITIALDLY",
|
||||||
|
trace="-trace" if trace else "",
|
||||||
|
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, os.path.join("../", template_file)) # XXX
|
||||||
|
r = subprocess.call(["bash", build_script_file])
|
||||||
|
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 VerilatorPlatform(GenericPlatform):
|
||||||
|
# XXX fix template / verilator_path
|
||||||
|
def build(self, soc, build_dir="build", build_name="top", run=True, trace=True,
|
||||||
|
template_file="../migen/mibuild/sim/dut_tb.cpp",
|
||||||
|
verilator_root_path="../verilator"):
|
||||||
|
tools.mkdir_noerror(build_dir)
|
||||||
|
os.chdir(build_dir)
|
||||||
|
|
||||||
|
self.soc = soc
|
||||||
|
fragment = soc.get_fragment()
|
||||||
|
self.finalize(fragment)
|
||||||
|
v_src, vns = self.get_verilog(fragment)
|
||||||
|
named_sc, named_pc = self.resolve_signals(vns)
|
||||||
|
self.vns = vns
|
||||||
|
v_file = "dut.v"
|
||||||
|
tools.write_to_file(v_file, v_src)
|
||||||
|
|
||||||
|
include_paths = []
|
||||||
|
for source in self.sources:
|
||||||
|
path = os.path.dirname(source[0]).replace("\\", "\/")
|
||||||
|
if path not in include_paths:
|
||||||
|
include_paths.append(path)
|
||||||
|
include_paths += self.verilog_include_paths
|
||||||
|
_build_sim(self, build_name, include_paths, verilator_root_path, template_file, trace)
|
||||||
|
|
||||||
|
if run:
|
||||||
|
_run_sim(build_name)
|
||||||
|
|
||||||
|
os.chdir("..")
|
Loading…
Reference in a new issue