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"
26 using namespace circt;
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));
51 Value countTcFull = rewriter.create<
hw::ConstantOp>(loc, countType, depth);
60 loc, nextCount,
clk, rst,
62 seq::HLMemOp hlmem = rewriter.create<seq::HLMemOp>(
63 loc,
clk, rst,
"fifo_mem",
64 llvm::SmallVector<int64_t>{
static_cast<int64_t
>(depth)}, eltType);
66 loc, rdAddrNext,
clk, rst,
69 loc, wrAddrNext,
clk, rst,
72 Value readData = rewriter.create<seq::ReadPortOp>(
73 loc, hlmem, llvm::SmallVector<Value>{rdAddr}, adaptor.getRdEn(),
75 rewriter.create<seq::WritePortOp>(loc, hlmem,
76 llvm::SmallVector<Value>{wrAddr},
77 adaptor.getInput(), adaptor.getWrEn(),
81 comb::ICmpOp fifoFull = rewriter.create<comb::ICmpOp>(
82 loc, comb::ICmpPredicate::eq, count, countTcFull);
83 fifoFull->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_full"));
84 comb::ICmpOp fifoEmpty = rewriter.create<comb::ICmpOp>(
85 loc, comb::ICmpPredicate::eq, count, countTc0);
86 fifoEmpty->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_empty"));
91 Value rdEnNandWrEn = rewriter.create<
comb::AndOp>(loc, notRdEn, notWrEn);
92 Value rdEnAndNotWrEn =
93 rewriter.create<
comb::AndOp>(loc, adaptor.getRdEn(), notWrEn);
94 Value wrEnAndNotRdEn =
95 rewriter.create<
comb::AndOp>(loc, adaptor.getWrEn(), notRdEn);
97 auto countEqTcFull = rewriter.create<comb::ICmpOp>(
98 loc, comb::ICmpPredicate::eq, count, countTcFull);
99 auto addCountTc1 = rewriter.create<
comb::AddOp>(loc, count, countTc1);
100 Value wrEnNext = rewriter.create<
comb::MuxOp>(loc, countEqTcFull,
105 auto countEqTc0 = rewriter.create<comb::ICmpOp>(
106 loc, comb::ICmpPredicate::eq, count, countTc0);
107 auto subCountTc1 = rewriter.create<
comb::SubOp>(loc, count, countTc1);
109 Value rdEnNext = rewriter.create<
comb::MuxOp>(loc, countEqTc0,
116 rewriter.create<
comb::MuxOp>(loc, rdEnAndNotWrEn, rdEnNext, count);
117 auto nextMux = rewriter.create<
comb::MuxOp>(loc, wrEnAndNotRdEn, wrEnNext,
120 loc, rdEnNandWrEn, count, nextMux));
121 static_cast<Value
>(nextCount).getDefiningOp()->setAttr(
122 "sv.namehint", rewriter.getStringAttr(
"fifo_count_next"));
127 auto addWrAddrPtrTc1 = rewriter.create<
comb::AddOp>(loc, wrAddr, ptrTc1);
129 auto wrAddrNextNoRollover = rewriter.create<
comb::MuxOp>(
130 loc, wrAndNotFull, addWrAddrPtrTc1, wrAddr);
131 auto isMaxAddrWr = rewriter.create<comb::ICmpOp>(
132 loc, comb::ICmpPredicate::eq, wrAddrNextNoRollover, ptrTcFull);
134 wrAddrNextNoRollover));
135 static_cast<Value
>(wrAddrNext)
137 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_wr_addr_next"));
140 Value rdAndNotEmpty =
141 rewriter.create<
comb::AndOp>(loc, adaptor.getRdEn(), notFifoEmpty);
142 auto addRdAddrPtrTc1 = rewriter.create<
comb::AddOp>(loc, rdAddr, ptrTc1);
143 auto rdAddrNextNoRollover = rewriter.create<
comb::MuxOp>(
144 loc, rdAndNotEmpty, addRdAddrPtrTc1, rdAddr);
145 auto isMaxAddrRd = rewriter.create<comb::ICmpOp>(
146 loc, comb::ICmpPredicate::eq, rdAddrNextNoRollover, ptrTcFull);
148 rdAddrNextNoRollover));
149 static_cast<Value
>(rdAddrNext)
151 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_rd_addr_next"));
154 llvm::SmallVector<Value> results;
157 results.push_back(readData);
159 results.push_back(fifoFull);
161 results.push_back(fifoEmpty);
163 if (
auto almostFull = mem.getAlmostFullThreshold()) {
164 results.push_back(rewriter.create<comb::ICmpOp>(
165 loc, comb::ICmpPredicate::uge, count,
166 rewriter.create<
hw::ConstantOp>(loc, countType, almostFull.value())));
167 static_cast<Value
>(results.back())
169 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_full"));
172 if (
auto almostEmpty = mem.getAlmostEmptyThreshold()) {
173 results.push_back(rewriter.create<comb::ICmpOp>(
174 loc, comb::ICmpPredicate::ule, count,
176 almostEmpty.value())));
177 static_cast<Value
>(results.back())
179 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_empty"));
183 Value clkI1 = rewriter.create<seq::FromClockOp>(loc,
clk);
185 loc, rewriter.create<
comb::AndOp>(loc, adaptor.getRdEn(), fifoEmpty),
187 rewriter.create<verif::ClockedAssertOp>(
188 loc, notEmptyAndRden, verif::ClockEdge::Pos, clkI1, Value(),
189 rewriter.getStringAttr(
"FIFO empty when read enabled"));
191 loc, rewriter.create<
comb::AndOp>(loc, adaptor.getWrEn(), fifoFull),
193 rewriter.create<verif::ClockedAssertOp>(
194 loc, notFullAndWren, verif::ClockEdge::Pos, clkI1,
196 rewriter.getStringAttr(
"FIFO full when write enabled"));
198 rewriter.replaceOp(mem, results);
203 struct LowerSeqFIFOPass
204 :
public circt::seq::impl::LowerSeqFIFOBase<LowerSeqFIFOPass> {
205 void runOnOperation()
override;
210 void LowerSeqFIFOPass::runOnOperation() {
211 MLIRContext &
ctxt = getContext();
212 ConversionTarget target(
ctxt);
215 target.addIllegalOp<seq::FIFOOp>();
216 target.addLegalDialect<seq::SeqDialect, hw::HWDialect, comb::CombDialect,
217 verif::VerifDialect>();
222 applyPartialConversion(getOperation(), target, std::move(
patterns))))
227 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)
def create(data_type, value)
Value createOrFoldNot(Location loc, Value value, OpBuilder &builder, bool twoState=false)
Create a `‘Not’' gate on a value.
std::unique_ptr< mlir::Pass > createLowerSeqFIFOPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.