Skip to content

Commit

Permalink
[ESI][Runtime] Add a utility wrap a command with a cosim (llvm#6579)
Browse files Browse the repository at this point in the history
The 'esi-cosim' script starts a simulation, waits for it to start, then
executes the 'inner' command. When the specified command exits, it kills
the simulation. Very helpful for debugging designs via ESI cosimulation.

Only supports Verilator currently.
  • Loading branch information
teqdruid authored Jan 15, 2024
1 parent 05d0886 commit 7c59a2e
Show file tree
Hide file tree
Showing 8 changed files with 410 additions and 5 deletions.
2 changes: 1 addition & 1 deletion frontends/PyCDE/integration_test/esi_ram.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# RUN: rm -rf %t
# RUN: mkdir %t && cd %t
# RUN: %PYTHON% %s %t 2>&1
# RUN: esi-cosim-runner.py --tmpdir %t --exec %S/test_software/esi_ram.py `ls %t/hw/*.sv | grep -v driver.sv`
# RUN: esi-cosim.py -- %PYTHON% %S/test_software/esi_ram.py cosim env

import pycde
from pycde import (AppID, Clock, Input, Module, generator)
Expand Down
2 changes: 1 addition & 1 deletion frontends/PyCDE/integration_test/esi_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# RUN: rm -rf %t
# RUN: mkdir %t && cd %t
# RUN: %PYTHON% %s %t 2>&1
# RUN: esi-cosim-runner.py --tmpdir %t --exec %S/test_software/esi_test.py `ls %t/hw/*.sv | grep -v driver.sv`
# RUN: esi-cosim.py -- %PYTHON% %S/test_software/esi_test.py cosim env

import pycde
from pycde import (AppID, Clock, Input, Module, generator)
Expand Down
7 changes: 7 additions & 0 deletions frontends/PyCDE/integration_test/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@

llvm_config.use_default_substitutions()

llvm_config.with_environment('LIBRARY_PATH', [config.llvm_lib_dir],
append_path=True)
llvm_config.with_environment('LD_LIBRARY_PATH', [config.llvm_lib_dir],
append_path=True)

# Set the timeout, if requested.
if config.timeout is not None and config.timeout != "":
lit_config.maxIndividualTestTime = int(config.timeout)
Expand Down Expand Up @@ -151,6 +156,8 @@
llvm_config.with_environment('PYTHONPATH',
[f"{config.esi_runtime_path}/python/"],
append_path=True)
tools.append("esi-cosim.py")
tool_dirs.append(f"{config.esi_runtime_path}/cosim")

# Enable ESI cosim tests if they have been built.
if config.esi_cosim_path != "":
Expand Down
4 changes: 2 additions & 2 deletions frontends/PyCDE/src/bsp/cosim.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def CosimBSP(user_module):
"""Wrap and return a cosimulation 'board support package' containing
'user_module'"""

class top(Module):
class ESI_Cosim_Top(Module):
clk = Clock()
rst = Input(types.int(1))

Expand All @@ -35,4 +35,4 @@ def build(ports):

System.current().add_packaging_step(esi.package)

return top
return ESI_Cosim_Top
1 change: 1 addition & 0 deletions lib/Dialect/ESI/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ set(ESI_RUNTIME_SRCS
runtime/cosim/Cosim_Manifest.sv
runtime/cosim/Cosim_Endpoint.sv
runtime/cosim/CosimDpi.capnp
runtime/cosim/esi-cosim.py
runtime/python/esi/__init__.py
runtime/python/esi/accelerator.py
runtime/python/esi/esiCppAccel.cpp
Expand Down
110 changes: 110 additions & 0 deletions lib/Dialect/ESI/runtime/cosim/driver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//===- driver.cpp - ESI Verilator software driver -------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// A fairly standard, boilerplate Verilator C++ simulation driver. Assumes the
// top level exposes just two signals: 'clk' and 'rst'.
//
//===----------------------------------------------------------------------===//

#ifndef TOP_MODULE
#define TOP_MODULE ESI_Cosim_Top
#endif // TOP_MODULE

// Macro black magic to get the header file name and class name from the
// TOP_MODULE macro. Need to disable formatting for this section, as
// clang-format messes it up by inserting spaces.

// clang-format off
#define STRINGIFY_MACRO(x) STR(x)
#define STR(x) #x
#define EXPAND(x)x
#define CONCAT3(n1, n2, n3) STRINGIFY_MACRO(EXPAND(n1)EXPAND(n2)EXPAND(n3))
#define TOKENPASTE(x, y) x ## y
#define CLASSNAME(x, y) TOKENPASTE(x, y)

#include CONCAT3(V,TOP_MODULE,.h)
// clang-format on

#include "verilated_vcd_c.h"

#include "signal.h"
#include <iostream>

vluint64_t timeStamp;

// Stop the simulation gracefully on ctrl-c.
volatile bool stopSimulation = false;
void handle_sigint(int) { stopSimulation = true; }

// Called by $time in Verilog.
double sc_time_stamp() { return timeStamp; }

int main(int argc, char **argv) {
// Register graceful exit handler.
signal(SIGINT, handle_sigint);

Verilated::commandArgs(argc, argv);

// Construct the simulated module's C++ model.
auto &dut = *new CLASSNAME(V, TOP_MODULE)();
char *waveformFile = getenv("SAVE_WAVE");

VerilatedVcdC *tfp = nullptr;
if (waveformFile) {
#ifdef TRACE
tfp = new VerilatedVcdC();
Verilated::traceEverOn(true);
dut.trace(tfp, 99); // Trace 99 levels of hierarchy
tfp->open(waveformFile);
std::cout << "[driver] Writing trace to " << waveformFile << std::endl;
#else
std::cout
<< "[driver] Warning: waveform file specified, but not a debug build"
<< std::endl;
#endif
}

std::cout << "[driver] Starting simulation" << std::endl;

// TODO: Add max speed (cycles per second) option for small, interactive
// simulations to reduce waveform for debugging. Should this be a command line
// option or configurable over the cosim interface?

// Reset.
dut.rst = 1;
dut.clk = 0;

// TODO: Support ESI reset handshake in the future.
// Run for a few cycles with reset held.
for (timeStamp = 0; timeStamp < 8 && !Verilated::gotFinish(); timeStamp++) {
dut.eval();
dut.clk = !dut.clk;
if (tfp)
tfp->dump(timeStamp);
}

// Take simulation out of reset.
dut.rst = 0;

// Run for the specified number of cycles out of reset.
for (; !Verilated::gotFinish() && !stopSimulation; timeStamp++) {
dut.eval();
dut.clk = !dut.clk;
if (tfp)
tfp->dump(timeStamp);
}

// Tell the simulator that we're going to exit. This flushes the output(s) and
// frees whatever memory may have been allocated.
dut.final();
if (tfp)
tfp->close();

std::cout << "[driver] Ending simulation at tick #" << timeStamp << std::endl;
return 0;
}
Loading

0 comments on commit 7c59a2e

Please sign in to comment.