18 #include "mlir/Transforms/DialectConversion.h"
19 #include "llvm/ADT/TypeSwitch.h"
21 using namespace circt;
26 struct SimpleBehavioralMemoryLowering
32 using OpConversionPattern::OpConversionPattern;
35 matchAndRewrite(seq::HLMemOp mem, OpAdaptor adaptor,
36 ConversionPatternRewriter &rewriter)
const final {
39 auto memType = mem.getMemType();
40 if (memType.getShape().size() != 1)
41 return rewriter.notifyMatchFailure(
42 mem,
"only unidimensional memories are supported");
43 auto size = memType.getShape()[0];
46 llvm::SmallVector<seq::ReadPortOp> readOps;
47 llvm::SmallVector<seq::WritePortOp> writeOps;
48 for (
auto *user : mem.getHandle().getUsers()) {
49 auto res = llvm::TypeSwitch<Operation *, LogicalResult>(user)
50 .Case([&](seq::ReadPortOp op) {
51 readOps.push_back(op);
54 .Case([&](seq::WritePortOp op) {
55 writeOps.push_back(op);
58 .Default([&](Operation *op) {
return failure(); });
60 return rewriter.notifyMatchFailure(user,
"unsupported port type");
63 auto clk = mem.getClk();
64 auto rst = mem.getRst();
65 auto memName = mem.getName();
68 hw::UnpackedArrayType memArrType =
71 rewriter.create<
sv::RegOp>(mem.getLoc(), memArrType, mem.getNameAttr())
82 llvm::SmallVector<WriteTuple> writeTuples;
83 for (
auto writeOp : writeOps) {
84 if (writeOp.getLatency() != 1)
85 return rewriter.notifyMatchFailure(
86 writeOp,
"only supports write ports with latency == 1");
87 auto addr = writeOp.getAddresses()[0];
88 auto data = writeOp.getInData();
89 auto en = writeOp.getWrEn();
90 writeTuples.push_back({writeOp.getLoc(), addr, data, en});
91 rewriter.eraseOp(writeOp);
94 auto hwClk = rewriter.create<seq::FromClockOp>(
clk.getLoc(),
clk);
95 rewriter.create<sv::AlwaysFFOp>(
96 mem.getLoc(), sv::EventControl::AtPosEdge, hwClk, ResetType::SyncReset,
97 sv::EventControl::AtPosEdge, rst, [&] {
98 for (
auto [loc, address, data, en] : writeTuples) {
99 Value a = address, d =
data;
102 rewriter.create<sv::IfOp>(loc,
en, [&] {
104 rewriter.create<sv::ArrayIndexInOutOp>(l, svMem, a);
105 rewriter.create<sv::PAssignOp>(l, memLoc, d);
116 for (
auto [ri, readOp] : llvm::enumerate(readOps)) {
117 rewriter.setInsertionPointAfter(readOp);
118 auto loc = readOp.getLoc();
120 auto readAddress = readOp.getAddresses()[0];
121 unsigned latency = readOp.getLatency();
122 unsigned addressDelayCycles = latency - 1;
125 for (
unsigned i = 0; i < addressDelayCycles; ++i) {
127 loc, readAddress,
clk,
128 rewriter.getStringAttr(memName +
"_rdaddr" + std::to_string(ri) +
129 "_dly" + std::to_string(i)));
135 rewriter.create<sv::ArrayIndexInOutOp>(loc, svMem, readAddress);
141 rewriter.getStringAttr(memName +
"_rd" + std::to_string(ri) +
144 rewriter.replaceOp(readOp, {readData});
147 rewriter.eraseOp(mem);
152 #define GEN_PASS_DEF_LOWERSEQHLMEM
153 #include "circt/Dialect/Seq/SeqPasses.h.inc"
155 struct LowerSeqHLMemPass :
public impl::LowerSeqHLMemBase<LowerSeqHLMemPass> {
156 void runOnOperation()
override;
161 void LowerSeqHLMemPass::runOnOperation() {
164 MLIRContext &ctxt = getContext();
165 ConversionTarget target(ctxt);
168 target.addIllegalOp<seq::HLMemOp, seq::ReadPortOp, seq::WritePortOp>();
169 target.addLegalDialect<sv::SVDialect, seq::SeqDialect>();
171 patterns.add<SimpleBehavioralMemoryLowering>(&ctxt);
173 if (failed(applyPartialConversion(top, target, std::move(
patterns))))
178 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()
This file defines an intermediate representation for circuits acting as an abstraction for constraint...