-
Notifications
You must be signed in to change notification settings - Fork 317
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
[Arcilator] Allow running verif.simulation ops #8233
base: main
Are you sure you want to change the base?
Conversation
8a3a802
to
5a66259
Compare
%failure = seq.compreg %6, %clock reset %init, %false : i1 | ||
%6 = comb.or %failure, %5 : i1 | ||
|
||
// Print some statistics about the test. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice use of DPI!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really cool work! 😎
getOperation().getLoc(), builder.getStringAttr("exit"), | ||
builder.getFunctionType({builder.getI32Type()}, {})); | ||
SymbolTable::setSymbolVisibility(func, SymbolTable::Visibility::Private); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we need to check the type of the existing function in the else case?
|
||
SmallVector<StringAttr> symbols; | ||
getOperation().walk([&](verif::SimulationOp op) { | ||
auto *symbolTableOp = SymbolTable::getNearestSymbolTable(op); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a need to have verif.simulation
nested in arbitrary ops or could we require builtin.module
as parent to simplify this?
auto *symbolTableOp = SymbolTable::getNearestSymbolTable(op); | ||
assert(symbolTableOp); | ||
if (symbolTableOp == getOperation()) | ||
symbols.push_back(op.getSymNameAttr()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are you collecting the symbols here but never using them?
auto &funcBody = funcOp.getBody().emplaceBlock(); | ||
builder.setInsertionPointToEnd(&funcBody); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Super-nit: builder
has a method createBlock
that does this in one line
auto &instBody = instOp.getBody().emplaceBlock(); | ||
auto instArg = instBody.addArgument(instType, op.getLoc()); | ||
builder.setInsertionPointToEnd(&instBody); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
builder.create<SimSetInputOp>(op.getLoc(), instArg, clockName, lowOp); | ||
builder.create<SimSetInputOp>(op.getLoc(), instArg, initName, trueOp); | ||
builder.create<SimStepOp>(op.getLoc(), instArg); | ||
builder.create<SimSetInputOp>(op.getLoc(), instArg, clockName, highOp); | ||
builder.create<SimStepOp>(op.getLoc(), instArg); | ||
builder.create<SimSetInputOp>(op.getLoc(), instArg, clockName, lowOp); | ||
builder.create<SimSetInputOp>(op.getLoc(), instArg, initName, falseOp); | ||
builder.create<SimStepOp>(op.getLoc(), instArg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: might be worth storing the location in a temporary
// Compute `exit_code | (exit_code != 0)` as a way of guaranteeing that | ||
// the exit code will be non-zero even if bits are truncated by the operating | ||
// system. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Smart way to deal with the fact that exit typically ANDs with 0xFF. Maybe worth mentioning in the simulation op documentation that on non-zero exit code the least significant bit is always set? But I guess also not really, because we are very vague about that anyway.
// CHECK: arc.sim.set_input [[A]], "clock" = [[C0]] | ||
// CHECK: arc.sim.set_input [[A]], "init" = [[I1]] | ||
// CHECK: arc.sim.step [[A]] | ||
// CHECK: arc.sim.set_input [[A]], "clock" = [[C1]] | ||
// CHECK: arc.sim.step [[A]] | ||
// CHECK: arc.sim.set_input [[A]], "clock" = [[C0]] | ||
// CHECK: arc.sim.set_input [[A]], "init" = [[I0]] | ||
// CHECK: arc.sim.step [[A]] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the simulation op description didn't mention that done is not checked when init=1. Which, of course, makes sense, but might be worth mentioning.
|
||
#include "circt/Dialect/Arc/ArcOps.h" | ||
#include "circt/Dialect/Arc/ArcPasses.h" | ||
#include "circt/Dialect/Comb/CombOps.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused?
%0 = comb.add %count, %c1_i19 : i19 | ||
|
||
// Generate inputs to the adder. | ||
%1, %2 = func.call @generateAdderInputs(%count) : (i19) -> (i42, i42) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strictly speaking this would need to be a module instantiation since the region describes hardware, right? And the function would need to use comb instead of arith.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's a good point. This happens to survive the Arcilator pipeline unharmed. A DPI call would probably fit better here, to reflect what you would type up in some SV input.
2ab5136
to
d99eb7a
Compare
5a66259
to
bdf9e04
Compare
Add the `LowerVerifSimulations` pass to the Arc dialect. This pass converts any `verif.simulation` ops in the input into a test harness module and a `func.func` that instantiates the module and applies the necessary stimulus to it using `arc.sim.*` ops. Also add the pass to the arcilator pipeline. This allows the user to run any `verif.simulation` ops in the input design by specifying the `--run --jit-entry=<simulation-name>` command line options. We may want to streamline this in the future. Also add an integration test which verifies an adder circuit and prints the simulation results.
bdf9e04
to
588a431
Compare
Add the
LowerVerifSimulations
pass to the Arc dialect. This pass converts anyverif.simulation
ops in the input into a test harness module and afunc.func
that instantiates the module and applies the necessary stimulus to it usingarc.sim.*
ops.Also add the pass to the arcilator pipeline. This allows the user to run any
verif.simulation
ops in the input design by specifying the--run --jit-entry=<simulation-name>
command line options. We may want to streamline this in the future.Also add an integration test which verifies an adder circuit and prints the simulation results.