24 #include "mlir/IR/Builders.h"
25 #include "mlir/Tools/mlir-translate/Translation.h"
26 #include "llvm/ADT/StringSet.h"
27 #include "llvm/ADT/TypeSwitch.h"
28 #include "llvm/Support/raw_ostream.h"
30 using namespace circt;
34 TclEmitter::TclEmitter(mlir::ModuleOp topLevel)
35 : topLevel(topLevel), populated(false) {}
42 for (
auto symOp :
topLevel.getOps<mlir::SymbolOpInterface>())
43 if (
auto name = symOp.getNameAttr())
55 for (
auto tclOp : hier.getOps<DynInstDataOpInterface>()) {
57 "Referenced mod does does not match");
58 tclOps.push_back(tclOp);
64 for (
auto tclOp :
topLevel.getOps<DynInstDataOpInterface>()) {
66 assert(mod &&
"Must be able to resolve top module");
83 struct TclOutputState {
84 TclOutputState(
TclEmitter &emitter, llvm::raw_ostream &os)
85 : os(os), emitter(emitter) {}
87 llvm::raw_ostream &os;
88 llvm::raw_ostream &indent() {
94 SmallVector<Attribute> symbolRefs;
96 void emit(PhysLocationAttr);
97 LogicalResult emitLocationAssignment(UnaryDynInstDataOpInterface refOp,
99 std::optional<StringRef> subpath);
101 LogicalResult emit(PDPhysRegionOp region);
103 LogicalResult emit(PDRegPhysLocationOp);
104 LogicalResult emit(DynamicInstanceVerbatimAttrOp attr);
105 LogicalResult emit(PDMulticycleOp op);
107 void emitPath(hw::HierPathOp ref, std::optional<StringRef> subpath);
108 void emitInnerRefPart(hw::InnerRefAttr innerRef);
112 HierPathOp getRefOp(UnaryDynInstDataOpInterface op) {
113 return getRefOp(op.getLoc(), op.getPathSym());
118 HierPathOp getRefOp(Location loc, FlatSymbolRefAttr pathSym) {
119 auto ref = dyn_cast_or_null<hw::HierPathOp>(emitter.getDefinition(pathSym));
121 emitter.usedRef(ref);
123 emitError(loc,
"could not find hw.hierpath named ") << pathSym;
129 void TclOutputState::emitInnerRefPart(hw::InnerRefAttr innerRef) {
132 os <<
"{{" << symbolRefs.size() <<
"}}";
135 symbolRefs.push_back(innerRef);
138 void TclOutputState::emitPath(hw::HierPathOp ref,
139 std::optional<StringRef> subpath) {
140 os <<
"{{" << symbolRefs.size() <<
":|}}";
146 void TclOutputState::emit(PhysLocationAttr pla) {
151 switch (pla.getPrimitiveType().getValue()) {
152 case PrimitiveType::M20K:
156 case PrimitiveType::DSP:
160 case PrimitiveType::FF:
167 os <<
"_X" << pla.getX() <<
"_Y" << pla.getY() <<
"_" << numCharacter
175 TclOutputState::emitLocationAssignment(UnaryDynInstDataOpInterface refOp,
176 PhysLocationAttr loc,
177 std::optional<StringRef> subpath) {
178 indent() <<
"set_location_assignment ";
182 os <<
" -to $parent|";
183 emitPath(getRefOp(refOp), subpath);
189 if (failed(emitLocationAssignment(loc, loc.getLoc(), loc.getSubPath())))
195 LogicalResult TclOutputState::emit(PDRegPhysLocationOp locs) {
196 ArrayRef<PhysLocationAttr> locArr = locs.getLocs().getLocs();
197 for (
size_t i = 0, e = locArr.size(); i < e; ++i) {
198 PhysLocationAttr pla = locArr[i];
201 if (failed(emitLocationAssignment(locs, pla, {})))
203 os <<
"[" << i <<
"]\n";
208 LogicalResult TclOutputState::emit(PDMulticycleOp op) {
209 indent() <<
"set_multicycle_path ";
211 os <<
"-setup " << op.getCycles() <<
" ";
212 os <<
"-from [get_registers {$parent|";
213 emitPath(getRefOp(op.getLoc(), op.getSourceAttr()), std::nullopt);
215 os <<
"-to [get_registers {$parent|";
216 emitPath(getRefOp(op.getLoc(), op.getDestAttr()), std::nullopt);
223 LogicalResult TclOutputState::emit(DynamicInstanceVerbatimAttrOp attr) {
224 HierPathOp ref = getRefOp(attr);
225 indent() <<
"set_instance_assignment -name " << attr.getName() <<
" "
229 os <<
" -to $parent|";
230 emitPath(ref, attr.getSubPath());
240 LogicalResult TclOutputState::emit(PDPhysRegionOp region) {
241 HierPathOp ref = getRefOp(region);
243 auto physicalRegion = dyn_cast_or_null<DeclPhysicalRegionOp>(
244 emitter.getDefinition(region.getPhysRegionRefAttr()));
246 return region.emitOpError(
247 "could not find physical region declaration named ")
248 << region.getPhysRegionRefAttr();
251 indent() <<
"set_instance_assignment -name PLACE_REGION \"";
252 auto physicalBounds =
253 physicalRegion.getBounds().getAsRange<PhysicalBoundsAttr>();
256 [&](PhysicalBoundsAttr bounds) {
257 os <<
'X' << bounds.getXMin() <<
' ';
258 os <<
'Y' << bounds.getYMin() <<
' ';
259 os <<
'X' << bounds.getXMax() <<
' ';
260 os <<
'Y' << bounds.getYMax();
265 os <<
" -to $parent|";
266 emitPath(ref, region.getSubPath());
270 indent() <<
"set_instance_assignment -name RESERVE_PLACE_REGION OFF";
271 os <<
" -to $parent|";
272 emitPath(ref, region.getSubPath());
276 indent() <<
"set_instance_assignment -name CORE_ONLY_PLACE_REGION ON";
277 os <<
" -to $parent|";
278 emitPath(ref, region.getSubPath());
282 indent() <<
"set_instance_assignment -name REGION_NAME ";
283 os << physicalRegion.getName();
284 os <<
" -to $parent|";
285 emitPath(ref, region.getSubPath());
299 llvm::raw_string_ostream os(s);
300 TclOutputState state(*
this, os);
305 StringAttr instName = tclOpsForInstancesKV.first;
306 os <<
"proc {{" << state.symbolRefs.size() <<
"}}";
308 os <<
'_' << instName.getValue();
309 os <<
"_config { parent } {\n";
313 LogicalResult ret = success();
314 const auto &tclOpsForMod = tclOpsForInstancesKV.second;
315 for (Operation *tclOp : tclOpsForMod) {
317 TypeSwitch<Operation *, LogicalResult>(tclOp)
319 .Case([&](PDRegPhysLocationOp op) {
return state.emit(op); })
320 .Case([&](PDPhysRegionOp op) {
return state.emit(op); })
321 .Case([&](PDMulticycleOp op) {
return state.emit(op); })
322 .Case([&](DynamicInstanceVerbatimAttrOp op) {
323 return state.emit(op);
325 .Default([](Operation *op) {
326 return op->emitOpError(
"could not determine how to output tcl");
335 OpBuilder
builder = OpBuilder::atBlockEnd(hwMod->getBlock());
336 auto verbatim =
builder.create<sv::VerbatimOp>(
337 builder.getUnknownLoc(), os.str(), ValueRange{},
338 builder.getArrayAttr(state.symbolRefs));
341 if (!outputFile.empty()) {
342 auto outputFileAttr =
343 OutputFileAttr::getFromFilename(
builder.getContext(), outputFile);
344 verbatim->setAttr(
"output_file", outputFileAttr);
assert(baseType &&"element must be base type")
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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...