18 #include "mlir/IR/BuiltinTypes.h"
19 #include "mlir/IR/OperationSupport.h"
20 #include "mlir/IR/PatternMatch.h"
21 #include "llvm/ADT/TypeSwitch.h"
23 using namespace circt;
24 using namespace calyx;
30 APInt apNumStates(64, numStates);
31 size_t log2 = apNumStates.ceilLogBase2();
32 return log2 > 1 ? log2 : 1;
38 void dispatch(Operation *op, ComponentOp component) {
39 TypeSwitch<Operation *>(op)
40 .template Case<SeqOp, EnableOp>(
41 [&](
auto opNode) { visit(opNode, component); })
43 op->emitError() <<
"Operation '" << op->getName()
44 <<
"' not supported for control compilation";
49 void visit(SeqOp seqOp, ComponentOp &component);
50 void visit(EnableOp, ComponentOp &) {
65 auto wires = component.getWiresOp();
66 Block *wiresBody = wires.getBodyBlock();
68 auto &seqOps =
seq.getBodyBlock()->getOperations();
69 if (!llvm::all_of(seqOps, [](
auto &&op) {
return isa<EnableOp>(op); })) {
70 seq.emitOpError(
"should only contain EnableOps in this pass.");
78 OpBuilder
builder(component->getRegion(0));
81 Value fsmIn = fsmRegister.getIn();
82 Value fsmWriteEn = fsmRegister.getWriteEn();
83 Value fsmOut = fsmRegister.getOut();
85 builder.setInsertionPointToStart(wiresBody);
89 builder.setInsertionPointToEnd(wiresBody);
91 builder.create<GroupOp>(wires->getLoc(),
builder.getStringAttr(
"seq"));
94 auto &symTable = am.getChildAnalysis<SymbolTable>(wires);
95 symTable.insert(seqGroup);
98 SmallVector<Attribute, 8> compiledGroups;
100 seq.walk([&](EnableOp enable) {
101 StringRef groupName = enable.getGroupName();
102 compiledGroups.push_back(
104 auto groupOp = symTable.lookup<GroupOp>(groupName);
106 builder.setInsertionPoint(groupOp);
108 fsmBitWidth, fsmIndex);
112 auto guard = groupOp.getDoneOp().getGuard();
113 Value source = groupOp.getDoneOp().getSrc();
114 auto doneOpValue = !guard ? source
116 wires->getLoc(), guard, source,
false);
123 builder.create<comb::ICmpOp>(wires->getLoc(), comb::ICmpPredicate::eq,
124 fsmOut, fsmCurrentState,
false);
131 builder.setInsertionPoint(seqGroup);
132 auto groupDoneGuard =
136 auto goOp = groupOp.getGoOp();
137 assert(goOp &&
"The Go Insertion pass should be run before this.");
138 goOp->setOperands({oneConstant, groupGoGuard});
142 fsmBitWidth, fsmIndex + 1);
143 builder.setInsertionPointToEnd(seqGroup.getBodyBlock());
144 builder.create<AssignOp>(wires->getLoc(), fsmIn, fsmNextState,
146 builder.create<AssignOp>(wires->getLoc(), fsmWriteEn, oneConstant,
154 builder.setInsertionPoint(seqGroup);
155 auto isFinalState =
builder.create<comb::ICmpOp>(
156 wires->getLoc(), comb::ICmpPredicate::eq, fsmOut, fsmNextState,
false);
159 builder.setInsertionPointToEnd(seqGroup.getBodyBlock());
160 builder.create<GroupDoneOp>(seqGroup->getLoc(), oneConstant, isFinalState);
164 builder.setInsertionPointToEnd(wiresBody);
167 builder.create<AssignOp>(wires->getLoc(), fsmIn, zeroConstant, isFinalState);
168 builder.create<AssignOp>(wires->getLoc(), fsmWriteEn, oneConstant,
174 seq->getLoc(), seqGroup.getSymName(),
182 struct CompileControlPass :
public CompileControlBase<CompileControlPass> {
183 void runOnOperation()
override;
188 void CompileControlPass::runOnOperation() {
189 ComponentOp component = getOperation();
191 component.getControlOp().walk(
192 [&](Operation *op) { compileControlVisitor.dispatch(op, component); });
196 component.getWiresOp().walk([&](UndefinedOp op) { op->erase(); });
200 return std::make_unique<CompileControlPass>();
assert(baseType &&"element must be base type")
static size_t getNecessaryBitWidth(size_t numStates)
Given some number of states, returns the necessary bit width TODO(Calyx): Probably a better built-in ...
void visit(EnableOp, ComponentOp &)
CompileControlVisitor(AnalysisManager am)
void visit(SeqOp seqOp, ComponentOp &component)
Generates a latency-insensitive FSM to realize a sequential operation.
void dispatch(Operation *op, ComponentOp component)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createCompileControlPass()
hw::ConstantOp createConstant(Location loc, OpBuilder &builder, ComponentOp component, size_t width, size_t value)
A helper function to create constants in the HW dialect.
calyx::RegisterOp createRegister(Location loc, OpBuilder &builder, ComponentOp component, size_t width, Twine prefix)
Creates a RegisterOp, with input and output port bit widths defined by width.
Value createOrFoldNot(Location loc, Value value, OpBuilder &builder, bool twoState=false)
Create a `‘Not’' gate on a value.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...