diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c9fcb6cc8..b5b15ff89 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -57,6 +57,7 @@ jobs: make clean make emu NO_DIFF=1 EMU_TRACE=1 ./build/emu -b 0 -e 100 -i ./ready-to-run/microbench.bin --dump-wave -C 10000 + ./build/emu -b 0 -e 100 -i ./ready-to-run/microbench.bin --dump-wave-full -C 10000 - name: Simulation with No Diff run: | @@ -95,6 +96,7 @@ jobs: make clean make emu EMU_TRACE=1 ./build/emu -b 10 -e 12 -i ./ready-to-run/microbench.bin --dump-wave --diff ./ready-to-run/riscv64-nemu-interpreter-so + ./build/emu -b 10 -e 12 -i ./ready-to-run/microbench.bin --dump-wave-full --diff ./ready-to-run/riscv64-nemu-interpreter-so - name: Difftest with two threads run: | diff --git a/src/test/csrc/verilator/emu.cpp b/src/test/csrc/verilator/emu.cpp index 089912b97..51b4b0c96 100644 --- a/src/test/csrc/verilator/emu.cpp +++ b/src/test/csrc/verilator/emu.cpp @@ -87,6 +87,7 @@ static inline void print_help(const char *file) { printf(" --load-snapshot=PATH load snapshot from PATH\n"); printf(" --no-snapshot disable saving snapshots\n"); printf(" --dump-wave dump waveform when log is enabled\n"); + printf(" --dump-wave-full dump full waveform when log is enabled\n"); printf(" --dump-ref-trace dump REF trace when log is enabled\n"); printf(" --dump-commit-trace dump commit trace when log is enabled\n"); #ifdef ENABLE_CHISEL_DB @@ -143,6 +144,7 @@ inline EmuArgs parse_args(int argc, const char *argv[]) { { "dump-footprints", 1, NULL, 0 }, { "as-footprints", 0, NULL, 0 }, { "dump-linearized", 1, NULL, 0 }, + { "dump-wave-full", 0, NULL, 0 }, { "seed", 1, NULL, 's' }, { "max-cycles", 1, NULL, 'C' }, { "fork-interval", 1, NULL, 'X' }, @@ -213,6 +215,7 @@ inline EmuArgs parse_args(int argc, const char *argv[]) { case 19: args.footprints_name = optarg; continue; case 20: args.image_as_footprints = true; continue; case 21: args.linearized_name = optarg; continue; + case 22: args.enable_waveform = true; args.enable_waveform_full = true; continue; } // fall through default: @@ -264,6 +267,8 @@ inline EmuArgs parse_args(int argc, const char *argv[]) { exit(0); } + args.enable_waveform = args.enable_waveform && !args.enable_fork; + #ifdef ENABLE_IPC char *ipc_image = (char *)malloc(255); char *ipc_file = (char *)malloc(255); @@ -317,6 +322,25 @@ Emulator::Emulator(int argc, const char *argv[]): // init flash init_flash(args.flash_bin); +#if VM_TRACE == 1 + if (args.enable_waveform) { + Verilated::traceEverOn(true); // Verilator must compute traced signals +#ifdef ENABLE_FST + tfp = new VerilatedFstC; +#else + tfp = new VerilatedVcdC; +#endif + dut_ptr->trace(tfp, 99); // Trace 99 levels of hierarchy + if (args.wave_path != NULL) { + tfp->open(args.wave_path); + } + else { + time_t now = time(NULL); + tfp->open(waveform_filename(now)); // Open the dump file + } + } +#endif + // init core reset_ncycles(10); @@ -348,26 +372,6 @@ Emulator::Emulator(int argc, const char *argv[]): init_db(args.dump_db, (args.select_db != NULL), args.select_db); #endif -#if VM_TRACE == 1 - enable_waveform = args.enable_waveform && !args.enable_fork; - if (enable_waveform) { - Verilated::traceEverOn(true); // Verilator must compute traced signals -#ifdef ENABLE_FST - tfp = new VerilatedFstC; -#else - tfp = new VerilatedVcdC; -#endif - dut_ptr->trace(tfp, 99); // Trace 99 levels of hierarchy - if (args.wave_path != NULL) { - tfp->open(args.wave_path); - } - else { - time_t now = time(NULL); - tfp->open(waveform_filename(now)); // Open the dump file - } - } -#endif - #ifdef VM_SAVABLE snapshot_slot = new VerilatedSaveMem[2]; if (args.snapshot_path != NULL) { @@ -440,7 +444,7 @@ Emulator::Emulator(int argc, const char *argv[]): Emulator::~Emulator() { // Simulation ends here, do clean up & display jobs #if VM_TRACE == 1 - if (enable_waveform) tfp->close(); + if (args.enable_waveform) tfp->close(); #endif #if VM_COVERAGE == 1 @@ -528,16 +532,30 @@ inline void Emulator::reset_ncycles(size_t cycles) { #ifdef COVERAGE_PORT_RESET dut_ptr->coverage_reset = dut_ptr->reset; #endif // COVERAGE_PORT_RESET - dut_ptr->clock = 0; + dut_ptr->clock = 1; #ifdef COVERAGE_PORT_CLOCK dut_ptr->coverage_clock = dut_ptr->clock; #endif // COVERAGE_PORT_CLOCK dut_ptr->eval(); - dut_ptr->clock = 1; + +#if VM_TRACE == 1 + if (args.enable_waveform && args.enable_waveform_full && args.log_begin == 0) { + tfp->dump(2 * i); + } +#endif + + dut_ptr->clock = 0; #ifdef COVERAGE_PORT_CLOCK dut_ptr->coverage_clock = dut_ptr->clock; #endif // COVERAGE_PORT_CLOCK dut_ptr->eval(); + +#if VM_TRACE == 1 + if (args.enable_waveform && args.enable_waveform_full && args.log_begin == 0) { + tfp->dump(2 * i + 1); + } +#endif + dut_ptr->reset = 0; #ifdef COVERAGE_PORT_RESET dut_ptr->coverage_reset = dut_ptr->reset; @@ -550,35 +568,32 @@ inline void Emulator::single_cycle() { goto end_single_cycle; } - dut_ptr->clock = 0; + dut_ptr->clock = 1; #ifdef COVERAGE_PORT_CLOCK dut_ptr->coverage_clock = dut_ptr->clock; #endif // COVERAGE_PORT_CLOCK dut_ptr->eval(); #if VM_TRACE == 1 - if (enable_waveform) { + if (args.enable_waveform) { #ifndef CONFIG_NO_DIFFTEST - auto trap = difftest[0]->get_trap_event(); - uint64_t cycle = trap->cycleCnt; - uint64_t begin = dut_ptr->io_logCtrl_log_begin; - uint64_t end = dut_ptr->io_logCtrl_log_end; - bool in_range = (begin <= cycle) && (cycle <= end); + uint64_t cycle = difftest[0]->get_trap_event()->cycleCnt; #else - bool in_range = true; - static uint64_t cycle = 0; + static uint64_t cycle = -1UL; cycle++; #endif - if (in_range || force_dump_wave) { tfp->dump(cycle); } + bool in_range = (args.log_begin <= cycle) && (cycle <= args.log_end); + if (in_range || force_dump_wave) { + if (args.enable_waveform_full) { + tfp->dump(20 + 2*cycle); + } + else { + tfp->dump(cycle); + } + } } #endif - dut_ptr->clock = 1; -#ifdef COVERAGE_PORT_CLOCK - dut_ptr->coverage_clock = dut_ptr->clock; -#endif // COVERAGE_PORT_CLOCK - dut_ptr->eval(); - #ifdef WITH_DRAMSIM3 dramsim3_step(); #endif @@ -592,6 +607,27 @@ inline void Emulator::single_cycle() { dut_ptr->io_uart_in_ch = uart_getc(); } + dut_ptr->clock = 0; +#ifdef COVERAGE_PORT_CLOCK + dut_ptr->coverage_clock = dut_ptr->clock; +#endif // COVERAGE_PORT_CLOCK + dut_ptr->eval(); + +#if VM_TRACE == 1 + if (args.enable_waveform && args.enable_waveform_full) { +#ifndef CONFIG_NO_DIFFTEST + uint64_t cycle = difftest[0]->get_trap_event()->cycleCnt; +#else + static uint64_t cycle = -1UL; + cycle++; +#endif + bool in_range = (args.log_begin <= cycle) && (cycle <= args.log_end); + if (in_range || force_dump_wave) { + tfp->dump(21 + 2*cycle); + } + } +#endif + end_single_cycle: #ifndef CONFIG_NO_DIFFTEST if (args.trace_name) { @@ -1068,7 +1104,7 @@ void Emulator::fork_child_init() { tfp->open(cycle_wavefile(cycles, now)); // override output range config, force dump wave force_dump_wave = true; - enable_waveform = true; + args.enable_waveform = true; #endif #ifndef CONFIG_NO_DIFFTEST #ifdef ENABLE_SIMULATOR_DEBUG_INFO diff --git a/src/test/csrc/verilator/emu.h b/src/test/csrc/verilator/emu.h index c513c0f6a..a28912a98 100644 --- a/src/test/csrc/verilator/emu.h +++ b/src/test/csrc/verilator/emu.h @@ -64,6 +64,7 @@ struct EmuArgs { const char *footprints_name = nullptr; const char *linearized_name = nullptr; bool enable_waveform = false; + bool enable_waveform_full = false; bool enable_ref_trace = false; bool enable_commit_trace = false; bool enable_snapshot = true; @@ -98,7 +99,6 @@ class Emulator final : public DUT { #else VerilatedVcdC* tfp; #endif - bool enable_waveform; bool force_dump_wave = false; #ifdef VM_SAVABLE VerilatedSaveMem *snapshot_slot = nullptr;