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"
35TclEmitter::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");
84struct 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;
130void TclOutputState::emitInnerRefPart(hw::InnerRefAttr innerRef) {
133 os <<
"{{" << symbolRefs.size() <<
"}}";
136 symbolRefs.push_back(innerRef);
139void TclOutputState::emitPath(hw::HierPathOp ref,
140 std::optional<StringRef> subpath) {
141 os <<
"{{" << symbolRefs.size() <<
":|}}";
142 symbolRefs.push_back(FlatSymbolRefAttr::get(ref));
147void TclOutputState::emit(PhysLocationAttr pla) {
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
176TclOutputState::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())))
196LogicalResult TclOutputState::emit(PDRegPhysLocationOp locs) {
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";
209LogicalResult TclOutputState::emit(PDMulticycleOp op) {
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);
224LogicalResult TclOutputState::emit(DynamicInstanceVerbatimAttrOp attr) {
225 HierPathOp ref = getRefOp(attr);
226 indent() <<
"set_instance_assignment -name " << attr.getName() <<
" "
230 os <<
" -to $parent|";
231 emitPath(ref, attr.getSubPath());
241LogicalResult TclOutputState::emit(PDPhysRegionOp region) {
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";
311 state.symbolRefs.push_back(SymbolRefAttr::get(hwMod));
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(
337 UnknownLoc::get(hwMod->getContext()), hwMod->getBlock());
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")
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)
mlir::Operation * getDefinition(mlir::Attribute attr) const override
Lookup a definition for 'symbol' in the cache.
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.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.