Skip to content

Commit

Permalink
mibuild: initial Verilator support
Browse files Browse the repository at this point in the history
  • Loading branch information
enjoy-digital committed Mar 1, 2015
1 parent 8f81ae6 commit 382ca37
Show file tree
Hide file tree
Showing 4 changed files with 300 additions and 0 deletions.
31 changes: 31 additions & 0 deletions mibuild/platforms/sim.py
@@ -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
Empty file added mibuild/sim/__init__.py
Empty file.
158 changes: 158 additions & 0 deletions mibuild/sim/dut_tb.cpp
@@ -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 changes: 111 additions & 0 deletions mibuild/sim/verilator.py
@@ -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}

This comment has been minimized.

Copy link
@sbourdeauducq

sbourdeauducq Mar 2, 2015

Member

Why do you need to set VERILATOR_ROOT? It fails here with:
Vdut.mk:59: ../../../verilator/include/verilated.mk: No such file or directory
Removing it fixes the problem.

This comment has been minimized.

Copy link
@enjoy-digital

enjoy-digital Mar 2, 2015

Author Contributor

Thanks, removed!

""".format(verilator_root= os.path.join("../../", verilator_root_path), # XXX
disable_warnings="-Wno-lint -Wno-INITIALDLY",

This comment has been minimized.

Copy link
@sbourdeauducq

sbourdeauducq Mar 2, 2015

Member

What about using -Wno-fatal instead of or in addition to disabling some warnings?

You are not disabling all warnings anyway, so some code (like mor1kx) still causes the simulation to fail without -Wno-fatal.

This comment has been minimized.

Copy link
@enjoy-digital

enjoy-digital Mar 2, 2015

Author Contributor

Done, I've added a verbose parameter to hide all those warnings (you can enable them with -Ob verbose True)

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("..")

0 comments on commit 382ca37

Please sign in to comment.