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

[RFC][Sim] Add triggered simulation procedures #7676

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/circt/Dialect/Sim/SimOps.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
#include "mlir/IR/SymbolTable.h"

#include "circt/Dialect/HW/HWOpInterfaces.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/Seq/SeqDialect.h"
#include "circt/Dialect/Seq/SeqTypes.h"
#include "circt/Dialect/Sim/SimDialect.h"
#include "circt/Dialect/Sim/SimTypes.h"
#include "circt/Support/BuilderUtils.h"
#include "mlir/Interfaces/CallInterfaces.h"
#include "mlir/Interfaces/FunctionInterfaces.h"
#include "mlir/Interfaces/InferTypeOpInterface.h"

#define GET_OP_CLASSES
#include "circt/Dialect/Sim/Sim.h.inc"
Expand Down
128 changes: 122 additions & 6 deletions include/circt/Dialect/Sim/SimOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,13 @@

include "mlir/Interfaces/SideEffectInterfaces.td"
include "mlir/Interfaces/FunctionInterfaces.td"
include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/IR/BuiltinAttributes.td"
include "mlir/IR/RegionKindInterface.td"
include "circt/Dialect/Sim/SimDialect.td"
include "circt/Dialect/Sim/SimTypes.td"
include "circt/Dialect/Seq/SeqTypes.td"
include "circt/Dialect/HW/HWEnums.td"
include "circt/Dialect/HW/HWOpInterfaces.td"
include "circt/Dialect/HW/HWTypes.td"

Expand Down Expand Up @@ -319,12 +323,6 @@ def FormatStringConcatOp : SimOp<"fmt.concat", [Pure]> {
/// and flattening continues without recursing into the cycle.
LogicalResult getFlattenedInputs(llvm::SmallVectorImpl<Value> &flatOperands);
}];

let builders = [
OpBuilder<(ins "mlir::ValueRange":$inputs), [{
return build($_builder, $_state, circt::sim::FormatStringType::get($_builder.getContext()), inputs);
}]>
];
}

def PrintFormattedOp : SimOp<"print"> {
Expand Down Expand Up @@ -365,4 +363,122 @@ def PrintFormattedProcOp : SimOp<"proc.print"> {
let assemblyFormat = "$input attr-dict";
}

// --- Trigger Ops ---

def OnEdgeOp : SimOp<"on_edge", [
Pure,
DeclareOpInterfaceMethods<InferTypeOpInterface, ["inferReturnTypes"]>
]> {
let summary = "Invoke a trigger on a clock edge event.";
let arguments = (ins ClockType:$clock, EventControlAttr:$event);
let results = (outs EdgeTriggerType:$result);
let assemblyFormat = "$event $clock attr-dict";
}

def OnInitOp : SimOp<"on_init", [Pure]> {
let summary = "Invoke a trigger at the start of simulation.";
let results = (outs InitTriggerType:$result);
let assemblyFormat = "attr-dict";
}

def TriggerSequenceOp : SimOp<"trigger_sequence", [
DeclareOpInterfaceMethods<InferTypeOpInterface, ["inferReturnTypes"]>
]> {
let summary = "Derive a sequence of triggers from a parent trigger.";
let description = [{
Creates a series of sequenced triggers.
The first resulting trigger is invoked when the parent trigger is invoked.
The subsequent triggers are invoked after all preceeding triggers
have completed. The operation completes after all result triggers have
completed.
}];
let arguments = (ins AnyTriggerType:$parent, UI32Attr:$length);
let results = (outs Variadic<AnyTriggerType>:$triggers);
let assemblyFormat =
"$parent `,` $length attr-dict `:` qualified(type($parent))";
let hasFolder = true;
let hasCanonicalizeMethod = true;
let hasVerifier = true;
}

def YieldSeqOp : SimOp<"yield_seq",[
Terminator, HasParent<"circt::sim::TriggeredOp">
]> {
let summary = [{Yield results form a triggerd region with 'seq'
(i.e. register-like) semantics."}];
let description = [{
Terminates a triggered region and produces the given list of values.
The results only become visible after all triggers and register updates
occuring on the same event as the parent operation have completed.
E.g., the following snippet produces a counter that increments on every
rising edge of '%clk':
```
%posedge = sim.on_edge posedge %clk
%counter = sim.triggered (%counter) on %posedge tieoff [0 : i8] {
^bb0(%arg0: i8):
%cst1 = hw.constant 1 : i8
%inc = comb.add bin %arg0, %cst1 : i8
sim.yield_seq %inc : i8
} : (i8) -> (i8)
```
}];
let arguments = (ins Variadic<AnyType>:$inputs);
let assemblyFormat = "($inputs^ `:` qualified(type($inputs)))? attr-dict";
let builders = [OpBuilder<(ins), "build($_builder, $_state, {});">];
}

def TriggeredOp : SimOp<"triggered", [
AttrSizedOperandSegments,
IsolatedFromAbove,
RegionKindInterface,
RecursiveMemoryEffects,
RecursivelySpeculatable,
SingleBlockImplicitTerminator<"sim::YieldSeqOp">,
HasParent<"circt::hw::HWModuleOp">
]> {
let summary = [{
Defines a procedure invoked on a given trigger and condition.
}];
let description = [{
Creates a procedural region which is invoked on a given trigger.
The optional condition allows the execution of the body to be skipped, if
the condition evaluates to `false` at the time when the trigger's
root event occurs.
The body region must complete without 'consuming' simulation time. It
may not run indefinitely or wait for any simulation event. It is allowed to
have side-effects and produce results.
For every result a 'tieoff' constant must be provided. It specifies the
respective result's value before the body is first invoked.
For non-simulation flows the results are replaced by their tie-off values.
}];
let arguments = (ins AnyTriggerType:$trigger,
Optional<I1>:$condition,
Variadic<AnyType>:$inputs,
OptionalAttr<TypedArrayAttrBase<
TypedAttrInterface, "Tie-off constants">>:$tieoffs
);
let results = (outs Variadic<AnyType>);
let regions = (region SizedRegion<1>:$body);

let assemblyFormat = [{
` ` `(` $inputs `)`
`on` ` ` `(` $trigger `:` qualified(type($trigger)) `)`
(`if` $condition^)?
(`tieoff` $tieoffs^)? attr-dict-with-keyword
$body
`:` functional-type($inputs, results)
}];

let extraClassDeclaration = [{
// Implement RegionKindInterface.
static RegionKind getRegionKind(unsigned index) {
return RegionKind::SSACFG;
}
}];

let hasVerifier = true;
let hasFolder = true;
let hasCanonicalizeMethod = true;
}

#endif // CIRCT_DIALECT_SIM_SIMOPS_TD
2 changes: 2 additions & 0 deletions include/circt/Dialect/Sim/SimTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Types.h"

#include "circt/Dialect/HW/HWEnums.h"

#define GET_TYPEDEF_CLASSES
#include "circt/Dialect/Sim/SimTypes.h.inc"

Expand Down
15 changes: 15 additions & 0 deletions include/circt/Dialect/Sim/SimTypes.td
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,19 @@ def FormatStringType : SimTypeDef<"FormatString"> {
}];
}


def EdgeTriggerType : SimTypeDef<"EdgeTrigger"> {
let summary = "Trigger derived from an edge event.";
let parameters = (ins "::circt::hw::EventControl":$edgeEvent);
let mnemonic = "trigger.edge";
let assemblyFormat = "`<` $edgeEvent `>`";
}

def InitTriggerType : SimTypeDef<"InitTrigger"> {
let summary = "Trigger derived from the simulation start event.";
let mnemonic = "trigger.init";
}

def AnyTriggerType : AnyTypeOf<[EdgeTriggerType, InitTriggerType]>;

#endif // CIRCT_DIALECT_SIM_SIMTYPES_TD
7 changes: 7 additions & 0 deletions lib/Dialect/Sim/SimDialect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//

#include "circt/Dialect/Sim/SimDialect.h"
#include "circt/Dialect/HW/HWDialect.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/Sim/SimOps.h"
#include "mlir/IR/Builders.h"
Expand Down Expand Up @@ -40,6 +41,12 @@ Operation *SimDialect::materializeConstant(::mlir::OpBuilder &builder,
::mlir::Type type,
::mlir::Location loc) {

// Delegate non 'sim' types to the HW dialect materializer.
if (!isa<SimDialect>(type.getDialect()))
return builder.getContext()
->getLoadedDialect<hw::HWDialect>()
->materializeConstant(builder, value, type, loc);

if (auto fmtStrType = llvm::dyn_cast<FormatStringType>(type))
return builder.create<FormatLitOp>(loc, fmtStrType,
llvm::cast<StringAttr>(value));
Expand Down
Loading
Loading