61 using ModuleMemories = SmallVector<std::pair<FirMemConfig, FirMemOp>, 0>;
62 SmallVector<ModuleMemories> memories(modules.size());
64 mlir::parallelFor(
context, 0, modules.size(), [&](
auto idx) {
67 HWModuleOp(modules[idx]).walk([&](seq::FirMemOp op) {
68 memories[idx].push_back({collectMemory(op), op});
74 for (
auto [module, moduleMemories] :
llvm::zip(modules, memories))
75 for (auto [summary, memOp] : moduleMemories)
76 grouped[summary].push_back(memOp);
98 cfg.
depth = op.getType().getDepth();
101 cfg.
maskBits = op.getType().getMaskWidth().value_or(1);
104 if (
auto init = op.getInitAttr()) {
110 if (
auto prefix = op.getPrefixAttr())
111 cfg.
prefix = prefix.getValue();
118 for (
auto *user : op->getUsers()) {
119 if (isa<FirMemReadOp>(user))
121 else if (isa<FirMemWriteOp>(user))
123 else if (isa<FirMemReadWriteOp>(user))
128 if (isa<FirMemWriteOp, FirMemReadWriteOp>(user)) {
131 clockValues.insert({clock, clockValues.size()}).first->second);
168 ArrayRef<seq::FirMemOp> memOps) {
174 for (
auto memOp : memOps) {
175 auto parent = memOp->getParentOfType<
HWModuleOp>();
181 builder.setInsertionPoint(insertPt);
189 StringRef baseName =
"";
190 bool firstFound =
false;
191 for (
auto memOp : memOps) {
192 if (
auto memName = memOp.getName()) {
199 for (; idx < memName->size() && idx < baseName.size(); ++idx)
200 if ((*memName)[idx] != baseName[idx])
202 baseName = baseName.take_front(idx);
205 baseName = baseName.rtrim(
'_');
207 SmallString<32> nameBuffer;
209 if (!baseName.empty()) {
210 nameBuffer += baseName;
216 auto name = builder.getStringAttr(
globalNamespace.newName(nameBuffer));
218 LLVM_DEBUG(llvm::dbgs() <<
"Creating " << name <<
" for " << mem.
depth
219 <<
" x " << mem.
dataWidth <<
" memory\n");
222 SmallVector<hw::PortInfo> ports;
225 Type clkType = ClockType::get(
context);
226 Type bitType = IntegerType::get(
context, 1);
227 Type dataType = IntegerType::get(
context, std::max((
size_t)1, mem.
dataWidth));
230 IntegerType::get(
context, std::max(1U, llvm::Log2_64_Ceil(mem.
depth)));
234 auto addInput = [&](StringRef prefix,
size_t idx, StringRef suffix,
236 ports.push_back({{builder.getStringAttr(prefix + Twine(idx) + suffix), type,
237 ModulePort::Direction::Input},
242 size_t outputIdx = 0;
243 auto addOutput = [&](StringRef prefix,
size_t idx, StringRef suffix,
245 ports.push_back({{builder.getStringAttr(prefix + Twine(idx) + suffix), type,
246 ModulePort::Direction::Output},
251 auto addCommonPorts = [&](StringRef prefix,
size_t idx) {
252 addInput(prefix, idx,
"_addr", addrType);
253 addInput(prefix, idx,
"_en", bitType);
254 addInput(prefix, idx,
"_clk", clkType);
259 addCommonPorts(
"R", i);
260 addOutput(
"R", i,
"_data", dataType);
265 addCommonPorts(
"RW", i);
266 addInput(
"RW", i,
"_wmode", bitType);
267 addInput(
"RW", i,
"_wdata", dataType);
268 addOutput(
"RW", i,
"_rdata", dataType);
270 addInput(
"RW", i,
"_wmask", maskType);
275 addCommonPorts(
"W", i);
276 addInput(
"W", i,
"_data", dataType);
278 addInput(
"W", i,
"_mask", maskType);
283 auto genAttr = [&](StringRef name, Attribute attr) {
284 return builder.getNamedAttr(name, attr);
286 auto genAttrUI32 = [&](StringRef name, uint32_t value) {
287 return genAttr(name, builder.getUI32IntegerAttr(value));
289 NamedAttribute genAttrs[] = {
290 genAttr(
"depth", builder.getI64IntegerAttr(mem.
depth)),
298 genAttr(
"readUnderWrite",
300 genAttr(
"writeUnderWrite",
302 genAttr(
"writeClockIDs", builder.getI32ArrayAttr(mem.
writeClockIDs)),
303 genAttr(
"initFilename", builder.getStringAttr(mem.
initFilename)),
304 genAttr(
"initIsBinary", builder.getBoolAttr(mem.
initIsBinary)),
305 genAttr(
"initIsInline", builder.getBoolAttr(mem.
initIsInline))};
309 Location loc = FirMemOp(memOps.front()).getLoc();
310 if (memOps.size() > 1) {
311 SmallVector<Location> locs;
312 for (
auto memOp : memOps)
313 locs.push_back(memOp.getLoc());
314 loc = FusedLoc::get(
context, locs);
319 hw::HWModuleGeneratedOp::create(builder, loc, schemaSymRef, name, ports,
320 StringRef{}, ArrayAttr{}, genAttrs);
324 genOp->setAttr(
"output_file", outputFile);
333 ArrayRef<std::tuple<FirMemConfig *, HWModuleGeneratedOp, FirMemOp>> mems) {
334 LLVM_DEBUG(llvm::dbgs() <<
"Lowering " << mems.size() <<
" memories in "
335 << module.getName() <<
"\n");
337 DenseMap<unsigned, Value> constOneOps;
338 auto constOne = [&](
unsigned width = 1) {
339 auto it = constOneOps.try_emplace(width, Value{});
341 auto builder = OpBuilder::atBlockBegin(module.getBodyBlock());
343 APInt::getAllOnes(width));
345 return it.first->second;
347 auto valueOrOne = [&](Value value,
unsigned width = 1) {
348 return value ? value : constOne(width);
351 for (
auto [config, genOp, memOp] : mems) {
352 LLVM_DEBUG(llvm::dbgs() <<
"- Lowering " << memOp.getName() <<
"\n");
353 SmallVector<Value> inputs;
354 SmallVector<Value> outputs;
356 auto addInput = [&](Value value) { inputs.push_back(value); };
357 auto addOutput = [&](Value value) { outputs.push_back(value); };
360 for (
auto *op : memOp->getUsers()) {
361 auto port = dyn_cast<FirMemReadOp>(op);
364 addInput(port.getAddress());
365 addInput(valueOrOne(port.getEnable()));
366 addInput(port.getClk());
367 addOutput(port.getData());
371 for (
auto *op : memOp->getUsers()) {
372 auto port = dyn_cast<FirMemReadWriteOp>(op);
375 addInput(port.getAddress());
376 addInput(valueOrOne(port.getEnable()));
377 addInput(port.getClk());
378 addInput(port.getMode());
379 addInput(port.getWriteData());
380 addOutput(port.getReadData());
381 if (config->maskBits > 1)
382 addInput(valueOrOne(port.getMask(), config->maskBits));
386 for (
auto *op : memOp->getUsers()) {
387 auto port = dyn_cast<FirMemWriteOp>(op);
390 addInput(port.getAddress());
391 addInput(valueOrOne(port.getEnable()));
392 addInput(port.getClk());
393 addInput(port.getData());
394 if (config->maskBits > 1)
395 addInput(valueOrOne(port.getMask(), config->maskBits));
399 StringRef memName =
"mem";
400 if (
auto name = memOp.getName(); name && !name->empty())
402 ImplicitLocOpBuilder builder(memOp.getLoc(), memOp);
403 auto instOp = hw::InstanceOp::create(
404 builder, genOp, builder.getStringAttr(memName +
"_ext"), inputs,
405 ArrayAttr{}, memOp.getInnerSymAttr());
406 for (
auto [oldOutput, newOutput] : llvm::zip(outputs, instOp.getResults()))
407 oldOutput.replaceAllUsesWith(newOutput);
410 auto defaultAttrNames = memOp.getAttributeNames();
411 for (
auto namedAttr : memOp->getAttrs())
412 if (!llvm::is_contained(defaultAttrNames, namedAttr.getName()))
413 instOp->setAttr(namedAttr.getName(), namedAttr.getValue());
416 for (
auto *user : llvm::make_early_inc_range(memOp->getUsers()))