25 #include "mlir/IR/Builders.h"
26 #include "mlir/Tools/mlir-translate/Translation.h"
27 #include "llvm/ADT/StringSet.h"
28 #include "llvm/ADT/TypeSwitch.h"
29 #include "llvm/Support/raw_ostream.h"
31 using namespace circt;
35 TclEmitter::TclEmitter(mlir::ModuleOp topLevel)
36 : topLevel(topLevel), populated(false) {}
43 for (
auto symOp :
topLevel.getOps<mlir::SymbolOpInterface>())
44 if (
auto name = symOp.getNameAttr())
56 for (
auto tclOp : hier.getOps<DynInstDataOpInterface>()) {
58 "Referenced mod does does not match");
59 tclOps.push_back(tclOp);
65 for (
auto tclOp :
topLevel.getOps<DynInstDataOpInterface>()) {
67 assert(mod &&
"Must be able to resolve top module");
84 struct TclOutputState {
85 TclOutputState(
TclEmitter &emitter, llvm::raw_ostream &os)
86 : os(os), emitter(emitter) {}
88 llvm::raw_ostream &os;
89 llvm::raw_ostream &indent() {
95 SmallVector<Attribute> symbolRefs;
97 void emit(PhysLocationAttr);
98 LogicalResult emitLocationAssignment(UnaryDynInstDataOpInterface refOp,
100 std::optional<StringRef> subpath);
102 LogicalResult
emit(PDPhysRegionOp region);
104 LogicalResult
emit(PDRegPhysLocationOp);
105 LogicalResult
emit(DynamicInstanceVerbatimAttrOp attr);
106 LogicalResult
emit(PDMulticycleOp op);
108 void emitPath(hw::HierPathOp ref, std::optional<StringRef> subpath);
109 void emitInnerRefPart(hw::InnerRefAttr innerRef);
113 HierPathOp getRefOp(UnaryDynInstDataOpInterface op) {
114 return getRefOp(op.getLoc(), op.getPathSym());
119 HierPathOp getRefOp(Location loc, FlatSymbolRefAttr pathSym) {
120 auto ref = dyn_cast_or_null<hw::HierPathOp>(emitter.getDefinition(pathSym));
122 emitter.usedRef(ref);
124 emitError(loc,
"could not find hw.hierpath named ") << pathSym;
130 void TclOutputState::emitInnerRefPart(hw::InnerRefAttr innerRef) {
133 os <<
"{{" << symbolRefs.size() <<
"}}";
136 symbolRefs.push_back(innerRef);
139 void TclOutputState::emitPath(hw::HierPathOp ref,
140 std::optional<StringRef> subpath) {
141 os <<
"{{" << symbolRefs.size() <<
":|}}";
152 switch (pla.getPrimitiveType().getValue()) {
153 case PrimitiveType::M20K:
157 case PrimitiveType::DSP:
161 case PrimitiveType::FF:
168 os <<
"_X" << pla.getX() <<
"_Y" << pla.getY() <<
"_" << numCharacter
176 TclOutputState::emitLocationAssignment(UnaryDynInstDataOpInterface refOp,
177 PhysLocationAttr loc,
178 std::optional<StringRef> subpath) {
179 indent() <<
"set_location_assignment ";
183 os <<
" -to $parent|";
184 emitPath(getRefOp(refOp), subpath);
190 if (failed(emitLocationAssignment(loc, loc.getLoc(), loc.getSubPath())))
197 ArrayRef<PhysLocationAttr> locArr = locs.getLocs().getLocs();
198 for (
size_t i = 0, e = locArr.size(); i < e; ++i) {
199 PhysLocationAttr pla = locArr[i];
202 if (failed(emitLocationAssignment(locs, pla, {})))
204 os <<
"[" << i <<
"]\n";
210 indent() <<
"set_multicycle_path ";
212 os <<
"-setup " << op.getCycles() <<
" ";
213 os <<
"-from [get_registers {$parent|";
214 emitPath(getRefOp(op.getLoc(), op.getSourceAttr()), std::nullopt);
216 os <<
"-to [get_registers {$parent|";
217 emitPath(getRefOp(op.getLoc(), op.getDestAttr()), std::nullopt);
225 HierPathOp ref = getRefOp(attr);
226 indent() <<
"set_instance_assignment -name " << attr.getName() <<
" "
230 os <<
" -to $parent|";
231 emitPath(ref, attr.getSubPath());
242 HierPathOp ref = getRefOp(region);
244 auto physicalRegion = dyn_cast_or_null<DeclPhysicalRegionOp>(
245 emitter.getDefinition(region.getPhysRegionRefAttr()));
247 return region.emitOpError(
248 "could not find physical region declaration named ")
249 << region.getPhysRegionRefAttr();
252 indent() <<
"set_instance_assignment -name PLACE_REGION \"";
253 auto physicalBounds =
254 physicalRegion.getBounds().getAsRange<PhysicalBoundsAttr>();
257 [&](PhysicalBoundsAttr bounds) {
258 os <<
'X' << bounds.getXMin() <<
' ';
259 os <<
'Y' << bounds.getYMin() <<
' ';
260 os <<
'X' << bounds.getXMax() <<
' ';
261 os <<
'Y' << bounds.getYMax();
266 os <<
" -to $parent|";
267 emitPath(ref, region.getSubPath());
271 indent() <<
"set_instance_assignment -name RESERVE_PLACE_REGION OFF";
272 os <<
" -to $parent|";
273 emitPath(ref, region.getSubPath());
277 indent() <<
"set_instance_assignment -name CORE_ONLY_PLACE_REGION ON";
278 os <<
" -to $parent|";
279 emitPath(ref, region.getSubPath());
283 indent() <<
"set_instance_assignment -name REGION_NAME ";
284 os << physicalRegion.getName();
285 os <<
" -to $parent|";
286 emitPath(ref, region.getSubPath());
300 llvm::raw_string_ostream os(s);
301 TclOutputState state(*
this, os);
306 StringAttr instName = tclOpsForInstancesKV.first;
307 os <<
"proc {{" << state.symbolRefs.size() <<
"}}";
309 os <<
'_' << instName.getValue();
310 os <<
"_config { parent } {\n";
314 LogicalResult ret = success();
315 const auto &tclOpsForMod = tclOpsForInstancesKV.second;
316 for (Operation *tclOp : tclOpsForMod) {
318 TypeSwitch<Operation *, LogicalResult>(tclOp)
320 .Case([&](PDRegPhysLocationOp op) {
return state.emit(op); })
321 .Case([&](PDPhysRegionOp op) {
return state.emit(op); })
322 .Case([&](PDMulticycleOp op) {
return state.emit(op); })
323 .Case([&](DynamicInstanceVerbatimAttrOp op) {
324 return state.emit(op);
326 .Default([](Operation *op) {
327 return op->emitOpError(
"could not determine how to output tcl");
336 auto builder = ImplicitLocOpBuilder::atBlockEnd(
338 builder.create<emit::FileOp>(outputFile, [&] {
339 builder.create<sv::VerbatimOp>(os.str(), ValueRange{},
340 builder.getArrayAttr(state.symbolRefs));
assert(baseType &&"element must be base type")
static LogicalResult emit(SolverOp solver, const SMTEmissionOptions &options, mlir::raw_indented_ostream &stream)
Emit the SMT operations in the given 'solver' to the 'stream'.
mlir::Operation * getDefinition(mlir::Attribute attr) const override
Lookup a definition for 'symbol' in the cache.
void freeze()
Mark the cache as frozen, which allows it to be shared across threads.
void addDefinition(mlir::StringAttr modSymbol, mlir::StringAttr name, mlir::Operation *op, size_t port=~0ULL)
Instantiate for all Tcl emissions.
Operation * getDefinition(FlatSymbolRefAttr)
hw::HWSymbolCache topLevelSymbols
DenseMap< Operation *, llvm::MapVector< StringAttr, SmallVector< DynInstDataOpInterface, 0 > > > tclOpsForModInstance
Map Module operations to their top-level "instance" names.
LogicalResult emit(Operation *hwMod, StringRef outputFile)
Write out all the relevant tcl commands.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.