38 using ModuleMemories = SmallVector<std::pair<FirMemConfig, FirMemOp>, 0>;
39 SmallVector<ModuleMemories> memories(modules.size());
41 mlir::parallelFor(
context, 0, modules.size(), [&](
auto idx) {
44 HWModuleOp(modules[idx]).walk([&](seq::FirMemOp op) {
45 memories[idx].push_back({collectMemory(op), op});
50 MapVector<FirMemConfig, SmallVector<FirMemOp, 1>> grouped;
51 for (
auto [module, moduleMemories] :
llvm::zip(modules, memories))
52 for (auto [summary, memOp] : moduleMemories)
53 grouped[summary].push_back(memOp);
75 cfg.
depth = op.getType().getDepth();
78 cfg.
maskBits = op.getType().getMaskWidth().value_or(1);
81 if (
auto init = op.getInitAttr()) {
87 if (
auto prefix = op.getPrefixAttr())
88 cfg.
prefix = prefix.getValue();
95 for (
auto *user : op->getUsers()) {
96 if (isa<FirMemReadOp>(user))
98 else if (isa<FirMemWriteOp>(user))
100 else if (isa<FirMemReadWriteOp>(user))
105 if (isa<FirMemWriteOp, FirMemReadWriteOp>(user)) {
108 clockValues.insert({clock, clockValues.size()}).first->second);
145 ArrayRef<seq::FirMemOp> memOps) {
151 for (
auto memOp : memOps) {
152 auto parent = memOp->getParentOfType<
HWModuleOp>();
158 builder.setInsertionPoint(insertPt);
166 StringRef baseName =
"";
167 bool firstFound =
false;
168 for (
auto memOp : memOps) {
169 if (
auto memName = memOp.getName()) {
176 for (; idx < memName->size() && idx < baseName.size(); ++idx)
177 if ((*memName)[idx] != baseName[idx])
179 baseName = baseName.take_front(idx);
182 baseName = baseName.rtrim(
'_');
184 SmallString<32> nameBuffer;
186 if (!baseName.empty()) {
187 nameBuffer += baseName;
195 LLVM_DEBUG(llvm::dbgs() <<
"Creating " << name <<
" for " << mem.
depth
196 <<
" x " << mem.
dataWidth <<
" memory\n");
199 SmallVector<hw::PortInfo> ports;
202 Type clkType = ClockType::get(
context);
203 Type bitType = IntegerType::get(
context, 1);
204 Type dataType = IntegerType::get(
context, std::max((
size_t)1, mem.
dataWidth));
207 IntegerType::get(
context, std::max(1U, llvm::Log2_64_Ceil(mem.
depth)));
211 auto addInput = [&](StringRef prefix,
size_t idx, StringRef suffix,
213 ports.push_back({{builder.getStringAttr(prefix + Twine(idx) + suffix), type,
214 ModulePort::Direction::Input},
219 size_t outputIdx = 0;
220 auto addOutput = [&](StringRef prefix,
size_t idx, StringRef suffix,
222 ports.push_back({{builder.getStringAttr(prefix + Twine(idx) + suffix), type,
223 ModulePort::Direction::Output},
228 auto addCommonPorts = [&](StringRef prefix,
size_t idx) {
229 addInput(prefix, idx,
"_addr", addrType);
230 addInput(prefix, idx,
"_en", bitType);
231 addInput(prefix, idx,
"_clk", clkType);
236 addCommonPorts(
"R", i);
237 addOutput(
"R", i,
"_data", dataType);
242 addCommonPorts(
"RW", i);
243 addInput(
"RW", i,
"_wmode", bitType);
244 addInput(
"RW", i,
"_wdata", dataType);
245 addOutput(
"RW", i,
"_rdata", dataType);
247 addInput(
"RW", i,
"_wmask", maskType);
252 addCommonPorts(
"W", i);
253 addInput(
"W", i,
"_data", dataType);
255 addInput(
"W", i,
"_mask", maskType);
260 auto genAttr = [&](StringRef name, Attribute attr) {
261 return builder.getNamedAttr(name, attr);
263 auto genAttrUI32 = [&](StringRef name, uint32_t value) {
264 return genAttr(name, builder.getUI32IntegerAttr(value));
266 NamedAttribute genAttrs[] = {
267 genAttr(
"depth", builder.getI64IntegerAttr(mem.
depth)),
275 genAttr(
"readUnderWrite",
277 genAttr(
"writeUnderWrite",
279 genAttr(
"writeClockIDs", builder.getI32ArrayAttr(mem.
writeClockIDs)),
280 genAttr(
"initFilename", builder.getStringAttr(mem.
initFilename)),
281 genAttr(
"initIsBinary", builder.getBoolAttr(mem.
initIsBinary)),
282 genAttr(
"initIsInline", builder.getBoolAttr(mem.
initIsInline))};
286 Location loc = FirMemOp(memOps.front()).getLoc();
287 if (memOps.size() > 1) {
288 SmallVector<Location> locs;
289 for (
auto memOp : memOps)
290 locs.push_back(memOp.getLoc());
291 loc = FusedLoc::get(
context, locs);
296 hw::HWModuleGeneratedOp::create(builder, loc, schemaSymRef, name, ports,
297 StringRef{}, ArrayAttr{}, genAttrs);
299 genOp->setAttr(
"output_file", mem.
outputFile);
308 ArrayRef<std::tuple<FirMemConfig *, HWModuleGeneratedOp, FirMemOp>> mems) {
309 LLVM_DEBUG(llvm::dbgs() <<
"Lowering " << mems.size() <<
" memories in "
310 << module.getName() <<
"\n");
312 DenseMap<unsigned, Value> constOneOps;
313 auto constOne = [&](
unsigned width = 1) {
314 auto it = constOneOps.try_emplace(width, Value{});
316 auto builder = OpBuilder::atBlockBegin(module.getBodyBlock());
318 builder, module.getLoc(), builder.getIntegerType(width), 1);
320 return it.first->second;
322 auto valueOrOne = [&](Value value,
unsigned width = 1) {
323 return value ? value : constOne(width);
326 for (
auto [config, genOp, memOp] : mems) {
327 LLVM_DEBUG(llvm::dbgs() <<
"- Lowering " << memOp.getName() <<
"\n");
328 SmallVector<Value> inputs;
329 SmallVector<Value> outputs;
331 auto addInput = [&](Value value) { inputs.push_back(value); };
332 auto addOutput = [&](Value value) { outputs.push_back(value); };
335 for (
auto *op : memOp->getUsers()) {
336 auto port = dyn_cast<FirMemReadOp>(op);
339 addInput(port.getAddress());
340 addInput(valueOrOne(port.getEnable()));
341 addInput(port.getClk());
342 addOutput(port.getData());
346 for (
auto *op : memOp->getUsers()) {
347 auto port = dyn_cast<FirMemReadWriteOp>(op);
350 addInput(port.getAddress());
351 addInput(valueOrOne(port.getEnable()));
352 addInput(port.getClk());
353 addInput(port.getMode());
354 addInput(port.getWriteData());
355 addOutput(port.getReadData());
356 if (config->maskBits > 1)
357 addInput(valueOrOne(port.getMask(), config->maskBits));
361 for (
auto *op : memOp->getUsers()) {
362 auto port = dyn_cast<FirMemWriteOp>(op);
365 addInput(port.getAddress());
366 addInput(valueOrOne(port.getEnable()));
367 addInput(port.getClk());
368 addInput(port.getData());
369 if (config->maskBits > 1)
370 addInput(valueOrOne(port.getMask(), config->maskBits));
374 StringRef memName =
"mem";
375 if (
auto name = memOp.getName(); name && !name->empty())
377 ImplicitLocOpBuilder builder(memOp.getLoc(), memOp);
378 auto instOp = hw::InstanceOp::create(
379 builder, genOp, builder.getStringAttr(memName +
"_ext"), inputs,
380 ArrayAttr{}, memOp.getInnerSymAttr());
381 for (
auto [oldOutput, newOutput] : llvm::zip(outputs, instOp.getResults()))
382 oldOutput.replaceAllUsesWith(newOutput);
385 auto defaultAttrNames = memOp.getAttributeNames();
386 for (
auto namedAttr : memOp->getAttrs())
387 if (!llvm::is_contained(defaultAttrNames, namedAttr.getName()))
388 instOp->setAttr(namedAttr.getName(), namedAttr.getValue());
391 for (
auto *user : llvm::make_early_inc_range(memOp->getUsers()))