Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Experimental][export-smv] Introduce the export-smv tool #67

Open
wants to merge 24 commits into
base: main
Choose a base branch
from

Conversation

Jiahui17
Copy link
Contributor

@Jiahui17 Jiahui17 commented Feb 29, 2024

This PR introduces the export-smv tool, which converts a handshake-level IR to the nuXmv input format, .smv (https://nuxmv.fbk.eu/).

This allows us to run model-checking on an abstracted dataflow circuit model.

Example use:

{ exp-export-smv handshake_export.mlir --timing-models=data/components.json;
cat data/components.smv } > model.smv

Prepare the following nuXmv batch script, commands.cmd

set verbose_level 2; set pp_list cpp; set counter_examples 0; set dynamic_reorder 1;
set on_failure_script_quits;
set reorder_method sift; set enable_sexp2bdd_caching 0; set bdd_static_order_heuristics basic;
set cone_of_influence; set use_coi_size_sorting 1;
read_model -i model.smv;
flatten_hierarchy; encode_variables; build_flat_model;
build_model -f; check_invar -s forward;
show_property -o property.rpt;
time; quit

And we can launch a verification run by using nuXmv -int commands.cmd

The current implementation prints a netlist and a library of units in the SMV format to stdout.

Since this language does not support parametrized instantiation, we generate one implementation for each parametrization of a unit, e.g., it generates one implementation for 2-output, 3-output, and 4-output eager fork.

@Jiahui17 Jiahui17 changed the title [Experimental][export-smv] Introduce exp-export-smv tool [Experimental][export-smv] Introduce the export-smv tool Feb 29, 2024
Copy link
Member

@lucas-rami lucas-rami left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the contribution! I left a couple of super minor comments.

Operation *dst = oprd.getOwner();

// Locate value in source results and destination operands
const size_t resIdx = findIndexInRange(src->getResults(), val);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you are sure that val is the result of an operation you can just do

const size_t resIdx = cast<OpResult>(val).getResultNumber();


// Locate value in source results and destination operands
const size_t resIdx = findIndexInRange(src->getResults(), val);
const size_t argIdx = findIndexInRange(dst->getOperands(), val);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can just do

const size_t argIdx = oprd.getOperandNumber();

StringRef unitName = getUniqueName(op);

os << "VAR " << unitName << " : ";
if (failed(getUnitType(op, os, timingDB))) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary brackets


for (auto [idx, arg] : llvm::enumerate(op->getOperands())) {
os << unitName << "_dataIn" << idx << ", " << unitName << "_pValid" << idx;
if (idx < op->getNumOperands() - 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary brackets


for (auto [idx, arg] : llvm::enumerate(op->getResults())) {
os << unitName << "_nReady" << idx;
if (idx < op->getNumResults() - 1) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary brackets

return success();
}

LogicalResult getOperatorImpl(unsigned numInputs, unsigned lat,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

None of the for's in this function need brackets

os << "DEFINE valid0 := b" << slots - (transp) << ".valid0; \n";
os << "DEFINE ready0 := b0.ready0; \n";
if (transp) {
assert(std::size(data) == slots);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we use the size() method on vectors across the repository instead of std::size

assert(nOutputs >= 2 && "received a fork with 0 or 1 output ports!");
// interface
os << "\nMODULE fork_1_" << nOutputs << "(dataIn0, pValid0, ";
for (unsigned i = 0; i < nOutputs - 1; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary brackets

}
os << "nReady" << nOutputs - 1 << ")\n";
os << "forkStop := ";
for (unsigned i = 0; i < nOutputs - 1; i++) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: unnecessary brackets

"this file"),
cl::init("data/components.json"), cl::cat(mainCategory));

static size_t findIndexInRange(ValueRange range, Value val) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer needed after changes proposed below

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants