15#include "mlir/Pass/Pass.h"
16#include "mlir/Transforms/DialectConversion.h"
17#include "llvm/ADT/TypeSwitch.h"
21#define GEN_PASS_DEF_LOWERSEQFIFO
22#include "circt/Dialect/Seq/SeqPasses.h.inc"
33 using OpConversionPattern::OpConversionPattern;
36 matchAndRewrite(seq::FIFOOp mem, OpAdaptor adaptor,
37 ConversionPatternRewriter &rewriter)
const final {
38 Location loc = mem.getLoc();
39 Type eltType = adaptor.getInput().getType();
40 Value
clk = adaptor.getClk();
41 Value rst = adaptor.getRst();
43 size_t depth = mem.getDepth();
44 Type countType = rewriter.getIntegerType(llvm::Log2_64_Ceil(depth + 1));
45 Type ptrType = rewriter.getIntegerType(llvm::Log2_64_Ceil(depth));
60 rewriter, loc, nextCount,
clk, rst,
62 seq::HLMemOp hlmem = seq::HLMemOp::create(
63 rewriter, loc,
clk, rst,
"fifo_mem",
64 llvm::SmallVector<int64_t>{
static_cast<int64_t
>(depth)}, eltType);
66 rewriter, loc, rdAddrNext,
clk, rst,
69 rewriter, loc, wrAddrNext,
clk, rst,
72 Value readData = seq::ReadPortOp::create(
73 rewriter, loc, hlmem, llvm::SmallVector<Value>{rdAddr},
74 adaptor.getRdEn(), mem.getRdLatency());
75 seq::WritePortOp::create(rewriter, loc, hlmem,
76 llvm::SmallVector<Value>{wrAddr},
77 adaptor.getInput(), adaptor.getWrEn(),
81 comb::ICmpOp fifoFull = comb::ICmpOp::create(
82 rewriter, loc, comb::ICmpPredicate::eq, count, countTcFull);
83 fifoFull->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_full"));
84 comb::ICmpOp fifoEmpty = comb::ICmpOp::create(
85 rewriter, loc, comb::ICmpPredicate::eq, count, countTc0);
86 fifoEmpty->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_empty"));
89 auto notRdEn = comb::createOrFoldNot(loc, adaptor.getRdEn(), rewriter);
90 auto notWrEn = comb::createOrFoldNot(loc, adaptor.getWrEn(), rewriter);
91 Value rdEnNandWrEn = comb::AndOp::create(rewriter, loc, notRdEn, notWrEn);
92 Value rdEnAndNotWrEn =
93 comb::AndOp::create(rewriter, loc, adaptor.getRdEn(), notWrEn);
94 Value wrEnAndNotRdEn =
95 comb::AndOp::create(rewriter, loc, adaptor.getWrEn(), notRdEn);
97 auto countEqTcFull = comb::ICmpOp::create(
98 rewriter, loc, comb::ICmpPredicate::eq, count, countTcFull);
99 auto addCountTc1 = comb::AddOp::create(rewriter, loc, count, countTc1);
100 Value wrEnNext = comb::MuxOp::create(rewriter, loc, countEqTcFull,
105 auto countEqTc0 = comb::ICmpOp::create(
106 rewriter, loc, comb::ICmpPredicate::eq, count, countTc0);
107 auto subCountTc1 = comb::SubOp::create(rewriter, loc, count, countTc1);
109 Value rdEnNext = comb::MuxOp::create(rewriter, loc, countEqTc0,
116 comb::MuxOp::create(rewriter, loc, rdEnAndNotWrEn, rdEnNext, count);
117 auto nextMux = comb::MuxOp::create(rewriter, loc, wrEnAndNotRdEn, wrEnNext,
119 nextCount.
setValue(comb::MuxOp::create(rewriter, loc, rdEnNandWrEn,
121 static_cast<Value
>(nextCount).getDefiningOp()->setAttr(
122 "sv.namehint", rewriter.getStringAttr(
"fifo_count_next"));
126 comb::AndOp::create(rewriter, loc, adaptor.getWrEn(),
127 comb::createOrFoldNot(loc, fifoFull, rewriter));
128 auto addWrAddrPtrTc1 = comb::AddOp::create(rewriter, loc, wrAddr, ptrTc1);
130 auto wrAddrNextNoRollover = comb::MuxOp::create(rewriter, loc, wrAndNotFull,
131 addWrAddrPtrTc1, wrAddr);
133 comb::ICmpOp::create(rewriter, loc, comb::ICmpPredicate::eq,
134 wrAddrNextNoRollover, ptrTcFull);
135 wrAddrNext.
setValue(comb::MuxOp::create(rewriter, loc, isMaxAddrWr, ptrTc0,
136 wrAddrNextNoRollover));
137 static_cast<Value
>(wrAddrNext)
139 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_wr_addr_next"));
141 auto notFifoEmpty = comb::createOrFoldNot(loc, fifoEmpty, rewriter);
142 Value rdAndNotEmpty =
143 comb::AndOp::create(rewriter, loc, adaptor.getRdEn(), notFifoEmpty);
144 auto addRdAddrPtrTc1 = comb::AddOp::create(rewriter, loc, rdAddr, ptrTc1);
145 auto rdAddrNextNoRollover = comb::MuxOp::create(
146 rewriter, loc, rdAndNotEmpty, addRdAddrPtrTc1, rdAddr);
148 comb::ICmpOp::create(rewriter, loc, comb::ICmpPredicate::eq,
149 rdAddrNextNoRollover, ptrTcFull);
150 rdAddrNext.
setValue(comb::MuxOp::create(rewriter, loc, isMaxAddrRd, ptrTc0,
151 rdAddrNextNoRollover));
152 static_cast<Value
>(rdAddrNext)
154 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_rd_addr_next"));
157 llvm::SmallVector<Value> results;
160 results.push_back(readData);
162 results.push_back(fifoFull);
164 results.push_back(fifoEmpty);
166 if (
auto almostFull = mem.getAlmostFullThreshold()) {
168 comb::ICmpOp::create(rewriter, loc, comb::ICmpPredicate::uge, count,
170 almostFull.value())));
171 static_cast<Value
>(results.back())
173 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_full"));
176 if (
auto almostEmpty = mem.getAlmostEmptyThreshold()) {
178 comb::ICmpOp::create(rewriter, loc, comb::ICmpPredicate::ule, count,
180 almostEmpty.value())));
181 static_cast<Value
>(results.back())
183 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_empty"));
187 Value clkI1 = seq::FromClockOp::create(rewriter, loc,
clk);
188 Value notEmptyAndRden = comb::createOrFoldNot(
189 loc, comb::AndOp::create(rewriter, loc, adaptor.getRdEn(), fifoEmpty),
191 verif::ClockedAssertOp::create(
192 rewriter, loc, notEmptyAndRden, verif::ClockEdge::Pos, clkI1,
194 rewriter.getStringAttr(
"FIFO empty when read enabled"));
195 Value notFullAndWren = comb::createOrFoldNot(
196 loc, comb::AndOp::create(rewriter, loc, adaptor.getWrEn(), fifoFull),
198 verif::ClockedAssertOp::create(
199 rewriter, loc, notFullAndWren, verif::ClockEdge::Pos, clkI1,
201 rewriter.getStringAttr(
"FIFO full when write enabled"));
203 rewriter.replaceOp(mem, results);
208struct LowerSeqFIFOPass
209 :
public circt::seq::impl::LowerSeqFIFOBase<LowerSeqFIFOPass> {
210 void runOnOperation()
override;
215void LowerSeqFIFOPass::runOnOperation() {
216 MLIRContext &
ctxt = getContext();
217 ConversionTarget target(ctxt);
220 target.addIllegalOp<seq::FIFOOp>();
221 target.addLegalDialect<seq::SeqDialect, hw::HWDialect, comb::CombDialect,
222 verif::VerifDialect>();
227 applyPartialConversion(getOperation(), target, std::move(
patterns))))
232 return std::make_unique<LowerSeqFIFOPass>();
Instantiate one of these and use it to build typed backedges.
Backedge get(mlir::Type resultType, mlir::LocationAttr optionalLoc={})
Create a typed backedge.
Backedge is a wrapper class around a Value.
void setValue(mlir::Value)
create(cls, result_type, reset=None, reset_value=None, name=None, sym_name=None, **kwargs)
std::unique_ptr< mlir::Pass > createLowerSeqFIFOPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.