diff --git a/essent b/essent index 438a699..c0b916e 160000 --- a/essent +++ b/essent @@ -1 +1 @@ -Subproject commit 438a699609bc189e5af0224eb3bf70c427a6c1a0 +Subproject commit c0b916ea5258045505fd915de63bfea660e23ba8 diff --git a/waveform-demo/riscv-mini/Makefile b/waveform-demo/riscv-mini/Makefile new file mode 100644 index 0000000..bcee364 --- /dev/null +++ b/waveform-demo/riscv-mini/Makefile @@ -0,0 +1,37 @@ +# Run Rocket Chip to get .fir (FIRRTL) file of design +generated_dir = $(abspath riscv-mini/generated-src) +fir_filename = Tile.fir +fir_path = $(abspath $(fir_filename)) + +Tile.h: $(fir_filename) + cd ../../essent; sbt 'run -O3 $(fir_path)' + +withVCD: $(fir_filename) + cd ../../essent; sbt 'run -O3 -withVCD $(fir_path)' + +withFST: $(fir_filename) + cd ../../essent; sbt 'run -O3 -withFST $(fir_path)' + +CXXFLAGS = -O3 -std=c++11 +INCLUDES = -I../../firrtl-sig + +top: top.cc mm.cc mm.h Tile.h + $(CXX) $(CXXFLAGS) $(INCLUDES) top.cc mm.cc -o top + +top_withVCD: top.cc mm.cc mm.h withVCD + $(CXX) $(CXXFLAGS) $(INCLUDES) top.cc mm.cc -o top_vcd + +top_withFST: top.cc mm.cc mm.h withFST + $(CXX) $(CXXFLAGS) $(INCLUDES) top.cc mm.cc -o top_fst + +.PHONY: clean +clean: + rm -rf $(fir_filename) Tile.h top VTile test-* + +VTile: riscv-mini/README.md + cd riscv-mini; make verilator + cp riscv-mini/VTile . + +.PHONY: test +test: top VTile + ./test.sh diff --git a/waveform-demo/riscv-mini/mm.cc b/waveform-demo/riscv-mini/mm.cc new file mode 120000 index 0000000..747e4d7 --- /dev/null +++ b/waveform-demo/riscv-mini/mm.cc @@ -0,0 +1 @@ +../../riscv-mini/mm.cc \ No newline at end of file diff --git a/waveform-demo/riscv-mini/mm.h b/waveform-demo/riscv-mini/mm.h new file mode 120000 index 0000000..d30d814 --- /dev/null +++ b/waveform-demo/riscv-mini/mm.h @@ -0,0 +1 @@ +../../riscv-mini/mm.h \ No newline at end of file diff --git a/waveform-demo/riscv-mini/riscv-mini b/waveform-demo/riscv-mini/riscv-mini new file mode 120000 index 0000000..90afba3 --- /dev/null +++ b/waveform-demo/riscv-mini/riscv-mini @@ -0,0 +1 @@ +../../riscv-mini/riscv-mini/ \ No newline at end of file diff --git a/waveform-demo/riscv-mini/top.cc b/waveform-demo/riscv-mini/top.cc new file mode 100644 index 0000000..3a37763 --- /dev/null +++ b/waveform-demo/riscv-mini/top.cc @@ -0,0 +1,109 @@ +#include +#include + +#include "mm.h" +#include "uint.h" +#include "Tile.h" + +// Adapted from riscv-mini/src/main/cc/top.cc + +using namespace std; + +static uint64_t trace_count = 0; +static uint64_t main_time = 0; +Tile *top; +mm_magic_t* mem; + + +void tick(bool verbose, bool done_reset) { + main_time++; + + top->io_nasti_aw_ready = UInt<1>(mem->aw_ready()); + top->io_nasti_ar_ready = UInt<1>(mem->ar_ready()); + top->io_nasti_w_ready = UInt<1>(mem->w_ready()); + top->io_nasti_b_valid = UInt<1>(mem->b_valid()); + top->io_nasti_b_bits_id = UInt<5>(mem->b_id()); + top->io_nasti_b_bits_resp = UInt<2>(mem->b_resp()); + top->io_nasti_r_valid = UInt<1>(mem->r_valid()); + top->io_nasti_r_bits_id = UInt<5>(mem->r_id()); + top->io_nasti_r_bits_resp = UInt<2>(mem->r_resp()); + top->io_nasti_r_bits_last = UInt<1>(mem->r_last()); + memcpy(&top->io_nasti_r_bits_data, mem->r_data(), 8); + + top->eval(true, verbose, done_reset); + mem->tick( + top->reset, + top->io_nasti_ar_valid, + top->io_nasti_ar_bits_addr.as_single_word(), + top->io_nasti_ar_bits_id.as_single_word(), + top->io_nasti_ar_bits_size.as_single_word(), + top->io_nasti_ar_bits_len.as_single_word(), + top->io_nasti_aw_valid, + top->io_nasti_aw_bits_addr.as_single_word(), + top->io_nasti_aw_bits_id.as_single_word(), + top->io_nasti_aw_bits_size.as_single_word(), + top->io_nasti_aw_bits_len.as_single_word(), + top->io_nasti_w_valid, + top->io_nasti_w_bits_strb.as_single_word(), + &top->io_nasti_w_bits_data, + top->io_nasti_w_bits_last, + top->io_nasti_r_ready, + top->io_nasti_b_ready + ); + main_time++; +} + + +int main(int argc, char** argv) { + uint64_t timeout = 10000000L; + top = new Tile; + mem = new mm_magic_t(1L << 32, 8); + //cout << "Enabling waves..." << endl; + load_mem(mem->get_data(), (const char*)(argv[1])); + + // reset + top->reset = UInt<1>(1); + top->io_host_fromhost_bits = UInt<32>(0); + top->io_host_fromhost_valid = UInt<1>(0); + top->genWaveHeader(); + // cout << "Starting simulation!" << endl; + for (size_t i = 0; i < 5 ; i++) { + tick(true, false); + } + top->reset = UInt<1>(0); + + // actual sim + top->io_host_fromhost_bits = UInt<32>(0); + top->io_host_fromhost_valid = UInt<1>(0); + do { + tick(true,true); + } while(!top->io_host_tohost.as_single_word() && main_time < timeout); + + int retcode = top->io_host_tohost.as_single_word() >> 1; + + // run 10 cycles past termination + // FUTURE: small off-by-1 hack in detecting termination + for (size_t i = 0 ; i < 9 ; i++) { + tick(true, true); + } + + // note: don't know why riscv-mini /10 (instead of /2), but same for testing + if (main_time >= timeout) { + cerr << "Simulation terminated by timeout at time " << main_time + << " (cycle " << main_time / 10 << ")"<< endl; + return -1; + } else { + cerr << "Simulation completed at time " << main_time + << " (cycle " << main_time / 10 << ")"<< endl; + if (retcode) { + cerr << "TOHOST = " << retcode << endl; + } + } + + delete top; + delete mem; + + //cout << "Finishing simulation!\n"; + + return 0; +} diff --git a/waveform-demo/rocket16/Makefile b/waveform-demo/rocket16/Makefile new file mode 100644 index 0000000..1bd072a --- /dev/null +++ b/waveform-demo/rocket16/Makefile @@ -0,0 +1,39 @@ +FIR_PATH = $(shell pwd)/TestHarness.DefaultConfig.1609.fir + +CXXFLAGS = -O3 -std=c++11 +CLANG_FLAGS = -fno-slp-vectorize -fbracket-depth=1024 + +UNAME_OS := $(shell uname -s) +ifeq ($(UNAME_OS),Darwin) + CXXFLAGS += $(CLANG_FLAGS) +endif + +ifeq ($(ALL_ON),1) + CXXFLAGS += -DALL_ON +endif + +INCLUDES = -Iriscv/include -I../../firrtl-sig + +LIBS = -Lriscv/lib -Wl,-rpath,riscv/lib -lfesvr -lpthread + +riscv_dir := $(shell pwd)/riscv + +riscv/lib/libfesvr.so: + git submodule update --init riscv-fesvr + cd riscv-fesvr; git checkout `cat ../fesvr.commit` + patch riscv-fesvr/fesvr/dtm.cc ../riscv-fesvr.patch + mkdir $(riscv_dir) + cd riscv-fesvr; mkdir build; cd build; ../configure --prefix=$(riscv_dir) --target=riscv64-unknown-elf; make install + +withVCD_TestHarness.h: + cd ../../essent; sbt 'run -O3 -withVCD $(FIR_PATH)' + +withFST_TestHarness.h: + cd ../../essent; sbt 'run -O3 -withFST $(FIR_PATH)' + +withVCD_emulator: emulator.cc withVCD_TestHarness.h riscv/lib/libfesvr.so + $(CXX) $(CXXFLAGS) $(INCLUDES) emulator.cc -o emulator_vcd $(LIBS) + +withFST_emulator: emulator.cc withFST_TestHarness.h riscv/lib/libfesvr.so + $(CXX) $(CXXFLAGS) $(INCLUDES) emulator.cc -o emulator_fst $(LIBS) + diff --git a/waveform-demo/rocket16/TestHarness.DefaultConfig.1609.fir b/waveform-demo/rocket16/TestHarness.DefaultConfig.1609.fir new file mode 120000 index 0000000..58eafa8 --- /dev/null +++ b/waveform-demo/rocket16/TestHarness.DefaultConfig.1609.fir @@ -0,0 +1 @@ +../../rocket16/TestHarness.DefaultConfig.1609.fir \ No newline at end of file diff --git a/waveform-demo/rocket16/emulator.cc b/waveform-demo/rocket16/emulator.cc new file mode 100644 index 0000000..2492b3a --- /dev/null +++ b/waveform-demo/rocket16/emulator.cc @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "TestHarness.h" + +dtm_t* dtm; +static uint64_t trace_count = 0; + +void handle_sigterm(int sig) { + dtm->stop(); +} + +void tick_dtm(TestHarness *tile, bool done_reset) { + // PRINT_SIG(tile->SimDTM_1.debug_req_ready); + // PRINT_SIG(tile->SimDTM_1.debug_resp_valid); + // PRINT_SIG(tile->SimDTM_1.debug_resp_bits_resp); + // PRINT_SIG(tile->SimDTM_1.debug_resp_bits_data); + if (done_reset) { + dtm_t::resp resp_bits; + resp_bits.resp = tile->SimDTM_1.debug_resp_bits_resp.as_single_word(); + resp_bits.data = tile->SimDTM_1.debug_resp_bits_data.as_single_word(); + + dtm->tick(tile->SimDTM_1.debug_req_ready.as_single_word(), + tile->SimDTM_1.debug_resp_valid.as_single_word(), + resp_bits); + + tile->SimDTM_1.debug_resp_ready = UInt<1>(dtm->resp_ready()); + tile->SimDTM_1.debug_req_valid = UInt<1>(dtm->req_valid()); + tile->SimDTM_1.debug_req_bits_addr = UInt<5>(dtm->req_bits().addr); + tile->SimDTM_1.debug_req_bits_op = UInt<2>(dtm->req_bits().op); + tile->SimDTM_1.debug_req_bits_data = UInt<34>(dtm->req_bits().data); + + tile->SimDTM_1.exit = UInt<32>(dtm->done() ? (dtm->exit_code() << 1 | 1) : 0); + } else { + tile->SimDTM_1.debug_req_valid = UInt<1>(0); + tile->SimDTM_1.debug_resp_ready = UInt<1>(0); + tile->SimDTM_1.exit = UInt<32>(0); + } + // PRINT_SIG(tile->SimDTM_1.debug_req_valid); + // PRINT_SIG(tile->SimDTM_1.debug_req_bits_addr); + // PRINT_SIG(tile->SimDTM_1.debug_req_bits_op); + // PRINT_SIG(tile->SimDTM_1.debug_req_bits_data); + // PRINT_SIG(tile->SimDTM_1.debug_resp_ready); +} + +int main(int argc, char** argv) { + unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); + uint64_t max_cycles = -1; + uint64_t start = 0; + int ret = 0; + bool print_cycles = false; + bool verbose = false; + bool done_reset = false; + + for (int i = 1; i < argc; i++) { + std::string arg = argv[i]; + if (arg.substr(0, 2) == "-s") + random_seed = atoi(argv[i]+2); + else if (arg == "+verbose") + verbose = true; + else if (arg.substr(0, 12) == "+max-cycles=") + max_cycles = atoll(argv[i]+12); + else if (arg.substr(0, 7) == "+start=") + start = atoll(argv[i]+7); + else if (arg.substr(0, 12) == "+cycle-count") + print_cycles = true; + } + + srand(random_seed); + srand48(random_seed); + + TestHarness *tile = new TestHarness; + + dtm = new dtm_t(std::vector(argv + 1, argv + argc)); + + signal(SIGTERM, handle_sigterm); + tile->genWaveHeader(); + tile->reset = UInt<1>(1); + tick_dtm(tile, done_reset); + tile->eval(false, verbose, done_reset); + // reset for several cycles to handle pipelined reset + for (int i = 0; i < 10; i++) { + tile->eval(true, verbose, done_reset); + tick_dtm(tile, done_reset); + } + tile->reset = UInt<1>(0); + tile->eval(false, verbose, done_reset); + tick_dtm(tile, done_reset); + done_reset = true; + + while (!dtm->done() && !tile->io_success && trace_count < max_cycles) { + tile->eval(true, verbose, done_reset); + tick_dtm(tile, done_reset); + trace_count++; + } + + if (dtm->exit_code()) { + fprintf(stderr, "*** FAILED *** (code = %d, seed %d) after %" PRIu64 " cycles\n", dtm->exit_code(), random_seed, trace_count); + ret = dtm->exit_code(); + } else if (trace_count == max_cycles) { + fprintf(stderr, "*** FAILED *** (timeout, seed %d) after %" PRIu64 " cycles\n", random_seed, trace_count); + ret = 2; + } else if (verbose || print_cycles) { + fprintf(stderr, "Completed after %" PRIu64 " cycles\n", trace_count); + } + + delete tile; + delete dtm; + + return ret; +} diff --git a/waveform-demo/rocket16/riscv b/waveform-demo/rocket16/riscv new file mode 120000 index 0000000..e769704 --- /dev/null +++ b/waveform-demo/rocket16/riscv @@ -0,0 +1 @@ +../../rocket16/riscv \ No newline at end of file diff --git a/waveform-demo/rocket16/riscv-fesvr b/waveform-demo/rocket16/riscv-fesvr new file mode 120000 index 0000000..67820f1 --- /dev/null +++ b/waveform-demo/rocket16/riscv-fesvr @@ -0,0 +1 @@ +../../rocket16/riscv-fesvr \ No newline at end of file diff --git a/waveform/vcd_comp.py b/waveform/vcd_comp.py new file mode 100644 index 0000000..bedf38b --- /dev/null +++ b/waveform/vcd_comp.py @@ -0,0 +1,145 @@ +import collections +import sys + +#first argument must be verilator vcd and second argument is ESSENT VCD +vcdFile1 = sys.argv[1] +vcdFile2 = sys.argv[2] +is_ver1 = sys.argv[3] +is_ver2 = sys.argv[4] + +with open(vcdFile1,'r') as f1, open(vcdFile2,'r') as f2: + vcd1 = f1.readlines() + vcd2 = f2.readlines() + +vcd1_header = [] +vcd2_header = [] + +for line in vcd1: + if "$enddefinitions $end" in line: + break + else: + vcd1_header.append(line) + +for line2 in vcd2: + if "$enddefinitions $end" in line2: + break + else: + vcd2_header.append(line2) + +vcd1_mod = [] +vcd2_mod = [] + +#modules check +for i in vcd1_header: + if "scope module" in i: + mod_name = i[i.find("module ") + 7:i.find(" $end")] + vcd1_mod.append(mod_name) + +for i in vcd2_header: + if "scope module" in i: + mod_name = i[i.find("module ") + 7:i.find(" $end")] + vcd2_mod.append(mod_name) + +if is_ver1 == "True": + print("First vcd is Verilator's VCD") + vcd1_mod.remove("TOP") + +if is_ver2 == "True": + print("Second vcd is Verilator's VCD") + vcd2_mod.remove("TOP") + +if collections.Counter(vcd1_mod) == collections.Counter(vcd2_mod): + print ("The modules are the same in both vcds") +else: + print ("The modules are not the same in both vcds") + print("Modules present in essent , not in verilator") + extra_vcd2_mod = list(set(vcd2_mod) - set(vcd1_mod)) + print(extra_vcd2_mod) + print("Modules present in verilator , not in essent") + extra_vcd1_mod = list(set(vcd1_mod) - set(vcd2_mod)) + print(extra_vcd1_mod) + +#store the signals whole name from the Tile or Top most module of vcd file +# key - signal name , value - identifier code +vcd1_signal = {} +temp_hier = [] +for line in vcd1_header: + if "scope module" in line: + mod_name = line[line.find("module ") + 7:line.find(" $end")] + temp_hier.append(mod_name) + temp_hier.append("$") + elif "upscope" in line: + temp_hier.pop(-1) + temp_hier.pop(-1) + elif "wire" in line: + if ("wire 128" in line) | ("wire 256" in line) | ("wired 512" in line): + temp = line[line.find("wire") + 9:line.find("$end")] + else : + temp = line[line.find("wire") + 8:line.find("$end")] + iden_code = temp[0:temp.find(" ")] + temp1 = temp[temp.find(" ") + 1:] + signal_name = temp1[:temp1.find(" ")] + key = ''.join(map(str,temp_hier)) + signal_name + if is_ver1 == "True": + up_key = key.replace('TOP$','') + key = up_key + vcd1_signal[key] = iden_code + +#print(vcd1_signal) + +vcd2_signal = {} +temp_hier = [] +for line in vcd2_header: + if "scope module" in line: + mod_name = line[line.find("module ") + 7:line.find(" $end")] + temp_hier.append(mod_name) + temp_hier.append("$") + elif "upscope" in line: + temp_hier.pop(-1) + temp_hier.pop(-1) + elif "wire" in line: + if ("wire 128" in line) | ("wire 256" in line) | ("wired 512" in line): + temp = line[line.find("wire") + 9:line.find("$end")] + else : + temp = line[line.find("wire") + 8:line.find("$end")] + iden_code = temp[0:temp.find(" ")] + temp1 = temp[temp.find(" ") + 1:] + signal_name = temp1[:temp1.find(" ")] + key = ''.join(map(str,temp_hier)) + signal_name + if is_ver2 == "True": + up_key = key.replace('TOP$','') + key = up_key + vcd2_signal[key] = iden_code + +#print(vcd2_signal) + +#compare between the signals between two vcd input files +diff_signals1_2 = set(vcd1_signal) - set(vcd2_signal) +print("Signals which are present in 1st input vcd, not present in 2nd input vcd") +print(diff_signals1_2) + +diff_signals2_1 = set(vcd2_signal) - set(vcd1_signal) +print("Signals which are present in 2nd input vcd, not present in 1st input vcd") +print(diff_signals2_1) + + +start_cycle = 0 +vcd1_signal_value = {} +for i in vcd1: + if start_cycle == 1: + if "b" in i: + iden_code = i[i.find(" ") +1:-1] + value = i[1:i.find(" ")] + vcd1_signal_value[iden_code] = value + else: + iden_code = i[1:-1] + value = i[0] + vcd1_signal_value[iden_code] = value + if i.startswith('#'): + if start_cycle == 1: + start_cycle = 0 + break + else: + start_cycle = 1 + cycle_count = i[1] +