17 #include "mlir/Pass/Pass.h"
18 #include "mlir/Transforms/DialectConversion.h"
19 #include "llvm/ADT/TypeSwitch.h"
23 #define GEN_PASS_DEF_LOWERSEQHLMEM
24 #include "circt/Dialect/Seq/SeqPasses.h.inc"
28 using namespace circt;
33 struct SimpleBehavioralMemoryLowering
39 using OpConversionPattern::OpConversionPattern;
42 matchAndRewrite(seq::HLMemOp mem, OpAdaptor adaptor,
43 ConversionPatternRewriter &rewriter)
const final {
46 auto memType = mem.getMemType();
47 if (memType.getShape().size() != 1)
48 return rewriter.notifyMatchFailure(
49 mem,
"only unidimensional memories are supported");
50 auto size = memType.getShape()[0];
53 llvm::SmallVector<seq::ReadPortOp> readOps;
54 llvm::SmallVector<seq::WritePortOp> writeOps;
55 for (
auto *user : mem.getHandle().getUsers()) {
56 auto res = llvm::TypeSwitch<Operation *, LogicalResult>(user)
57 .Case([&](seq::ReadPortOp op) {
58 readOps.push_back(op);
61 .Case([&](seq::WritePortOp op) {
62 writeOps.push_back(op);
65 .Default([&](Operation *op) {
return failure(); });
67 return rewriter.notifyMatchFailure(user,
"unsupported port type");
70 auto clk = mem.getClk();
71 auto rst = mem.getRst();
72 auto memName = mem.getName();
75 hw::UnpackedArrayType memArrType =
78 rewriter.create<
sv::RegOp>(mem.getLoc(), memArrType, mem.getNameAttr())
89 llvm::SmallVector<WriteTuple> writeTuples;
90 for (
auto writeOp : writeOps) {
91 if (writeOp.getLatency() != 1)
92 return rewriter.notifyMatchFailure(
93 writeOp,
"only supports write ports with latency == 1");
94 auto addr = writeOp.getAddresses()[0];
95 auto data = writeOp.getInData();
96 auto en = writeOp.getWrEn();
97 writeTuples.push_back({writeOp.getLoc(),
addr,
data,
en});
98 rewriter.eraseOp(writeOp);
101 auto hwClk = rewriter.create<seq::FromClockOp>(
clk.getLoc(),
clk);
102 rewriter.create<sv::AlwaysFFOp>(
103 mem.getLoc(), sv::EventControl::AtPosEdge, hwClk,
104 sv::ResetType::SyncReset, sv::EventControl::AtPosEdge, rst, [&] {
105 for (
auto [loc, address,
data,
en] : writeTuples) {
106 Value a = address, d =
data;
109 rewriter.create<sv::IfOp>(loc,
en, [&] {
111 rewriter.create<sv::ArrayIndexInOutOp>(l, svMem, a);
112 rewriter.create<sv::PAssignOp>(l, memLoc, d);
123 for (
auto [ri, readOp] : llvm::enumerate(readOps)) {
124 rewriter.setInsertionPointAfter(readOp);
125 auto loc = readOp.getLoc();
127 auto readAddress = readOp.getAddresses()[0];
128 unsigned latency = readOp.getLatency();
129 unsigned addressDelayCycles = latency - 1;
132 for (
unsigned i = 0; i < addressDelayCycles; ++i) {
134 loc, readAddress,
clk,
135 rewriter.getStringAttr(memName +
"_rdaddr" + std::to_string(ri) +
136 "_dly" + std::to_string(i)));
142 rewriter.create<sv::ArrayIndexInOutOp>(loc, svMem, readAddress);
148 rewriter.getStringAttr(memName +
"_rd" + std::to_string(ri) +
151 rewriter.replaceOp(readOp, {readData});
154 rewriter.eraseOp(mem);
158 struct LowerSeqHLMemPass
159 :
public circt::seq::impl::LowerSeqHLMemBase<LowerSeqHLMemPass> {
160 void runOnOperation()
override;
165 void LowerSeqHLMemPass::runOnOperation() {
168 MLIRContext &
ctxt = getContext();
169 ConversionTarget target(
ctxt);
172 target.addIllegalOp<seq::HLMemOp, seq::ReadPortOp, seq::WritePortOp>();
173 target.addLegalDialect<sv::SVDialect, seq::SeqDialect>();
177 if (failed(applyPartialConversion(top, target, std::move(
patterns))))
182 return std::make_unique<LowerSeqHLMemPass>();
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createLowerSeqHLMemPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.