14 #include "mlir/Pass/Pass.h"
15 #include "mlir/Transforms/DialectConversion.h"
16 #include "llvm/ADT/TypeSwitch.h"
20 #define GEN_PASS_DEF_LOWERSEQFIFO
21 #include "circt/Dialect/Seq/SeqPasses.h.inc"
25 using namespace circt;
32 using OpConversionPattern::OpConversionPattern;
35 matchAndRewrite(seq::FIFOOp mem, OpAdaptor adaptor,
36 ConversionPatternRewriter &rewriter)
const final {
37 Type eltType = adaptor.getInput().getType();
38 Value
clk = adaptor.getClk();
39 Value rst = adaptor.getRst();
40 Location loc = mem.getLoc();
42 size_t depth = mem.getDepth();
43 Type countType = rewriter.getIntegerType(llvm::Log2_64_Ceil(depth + 1));
44 Type ptrType = rewriter.getIntegerType(llvm::Log2_64_Ceil(depth));
58 loc, nextCount,
clk, rst,
60 seq::HLMemOp hlmem = rewriter.create<seq::HLMemOp>(
61 loc,
clk, rst,
"fifo_mem",
62 llvm::SmallVector<int64_t>{
static_cast<int64_t
>(depth)}, eltType);
64 loc, rdAddrNext,
clk, rst,
67 loc, wrAddrNext,
clk, rst,
70 Value readData = rewriter.create<seq::ReadPortOp>(
71 loc, hlmem, llvm::SmallVector<Value>{rdAddr}, adaptor.getRdEn(),
73 rewriter.create<seq::WritePortOp>(loc, hlmem,
74 llvm::SmallVector<Value>{wrAddr},
75 adaptor.getInput(), adaptor.getWrEn(),
79 comb::ICmpOp fifoFull = rewriter.create<comb::ICmpOp>(
80 loc, comb::ICmpPredicate::eq, count, countTcFull);
81 fifoFull->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_full"));
82 comb::ICmpOp fifoEmpty = rewriter.create<comb::ICmpOp>(
83 loc, comb::ICmpPredicate::eq, count, countTc0);
84 fifoEmpty->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_empty"));
89 Value rdEnNandWrEn = rewriter.create<
comb::AndOp>(loc, notRdEn, notWrEn);
90 Value rdEnAndNotWrEn =
91 rewriter.create<
comb::AndOp>(loc, adaptor.getRdEn(), notWrEn);
92 Value wrEnAndNotRdEn =
93 rewriter.create<
comb::AndOp>(loc, adaptor.getWrEn(), notRdEn);
95 auto countEqTcFull = rewriter.create<comb::ICmpOp>(
96 loc, comb::ICmpPredicate::eq, count, countTcFull);
97 auto addCountTc1 = rewriter.create<
comb::AddOp>(loc, count, countTc1);
98 Value wrEnNext = rewriter.create<
comb::MuxOp>(loc, countEqTcFull,
103 auto countEqTc0 = rewriter.create<comb::ICmpOp>(
104 loc, comb::ICmpPredicate::eq, count, countTc0);
105 auto subCountTc1 = rewriter.create<
comb::SubOp>(loc, count, countTc1);
107 Value rdEnNext = rewriter.create<
comb::MuxOp>(loc, countEqTc0,
114 rewriter.create<
comb::MuxOp>(loc, rdEnAndNotWrEn, rdEnNext, count);
115 auto nextMux = rewriter.create<
comb::MuxOp>(loc, wrEnAndNotRdEn, wrEnNext,
118 loc, rdEnNandWrEn, count, nextMux));
119 static_cast<Value
>(nextCount).getDefiningOp()->setAttr(
120 "sv.namehint", rewriter.getStringAttr(
"fifo_count_next"));
125 auto addWrAddrPtrTc1 = rewriter.create<
comb::AddOp>(loc, wrAddr, ptrTc1);
127 addWrAddrPtrTc1, wrAddr));
128 static_cast<Value
>(wrAddrNext)
130 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_wr_addr_next"));
133 Value rdAndNotEmpty =
134 rewriter.create<
comb::AndOp>(loc, adaptor.getRdEn(), notFifoEmpty);
135 auto addRdAddrPtrTc1 = rewriter.create<
comb::AddOp>(loc, rdAddr, ptrTc1);
137 addRdAddrPtrTc1, rdAddr));
138 static_cast<Value
>(rdAddrNext)
140 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_rd_addr_next"));
143 llvm::SmallVector<Value> results;
146 results.push_back(readData);
148 results.push_back(fifoFull);
150 results.push_back(fifoEmpty);
152 if (
auto almostFull = mem.getAlmostFullThreshold()) {
153 results.push_back(rewriter.create<comb::ICmpOp>(
154 loc, comb::ICmpPredicate::uge, count,
155 rewriter.create<
hw::ConstantOp>(loc, countType, almostFull.value())));
156 static_cast<Value
>(results.back())
158 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_full"));
161 if (
auto almostEmpty = mem.getAlmostEmptyThreshold()) {
162 results.push_back(rewriter.create<comb::ICmpOp>(
163 loc, comb::ICmpPredicate::ule, count,
165 almostEmpty.value())));
166 static_cast<Value
>(results.back())
168 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_empty"));
171 rewriter.replaceOp(mem, results);
176 struct LowerSeqFIFOPass
177 :
public circt::seq::impl::LowerSeqFIFOBase<LowerSeqFIFOPass> {
178 void runOnOperation()
override;
183 void LowerSeqFIFOPass::runOnOperation() {
184 MLIRContext &
ctxt = getContext();
185 ConversionTarget target(
ctxt);
188 target.addIllegalOp<seq::FIFOOp>();
189 target.addLegalDialect<seq::SeqDialect, hw::HWDialect, comb::CombDialect>();
194 applyPartialConversion(getOperation(), target, std::move(
patterns))))
199 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.