15 #include "mlir/Transforms/DialectConversion.h"
16 #include "llvm/ADT/TypeSwitch.h"
18 using namespace circt;
25 using OpConversionPattern::OpConversionPattern;
28 matchAndRewrite(seq::FIFOOp mem, OpAdaptor adaptor,
29 ConversionPatternRewriter &rewriter)
const final {
30 Type eltType = adaptor.getInput().getType();
31 Value
clk = adaptor.getClk();
32 Value rst = adaptor.getRst();
33 Location loc = mem.getLoc();
35 size_t depth = mem.getDepth();
36 Type countType = rewriter.getIntegerType(llvm::Log2_64_Ceil(depth + 1));
37 Type ptrType = rewriter.getIntegerType(llvm::Log2_64_Ceil(depth));
38 Backedge rdAddrNext = bb.get(ptrType);
39 Backedge wrAddrNext = bb.get(ptrType);
40 Backedge nextCount = bb.get(countType);
51 loc, nextCount,
clk, rst,
53 seq::HLMemOp hlmem = rewriter.create<seq::HLMemOp>(
54 loc,
clk, rst,
"fifo_mem",
55 llvm::SmallVector<int64_t>{
static_cast<int64_t
>(depth)}, eltType);
57 loc, rdAddrNext,
clk, rst,
60 loc, wrAddrNext,
clk, rst,
63 Value readData = rewriter.create<seq::ReadPortOp>(
64 loc, hlmem, llvm::SmallVector<Value>{rdAddr}, adaptor.getRdEn(),
66 rewriter.create<seq::WritePortOp>(loc, hlmem,
67 llvm::SmallVector<Value>{wrAddr},
68 adaptor.getInput(), adaptor.getWrEn(),
72 comb::ICmpOp fifoFull = rewriter.create<comb::ICmpOp>(
73 loc, comb::ICmpPredicate::eq, count, countTcFull);
74 fifoFull->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_full"));
75 comb::ICmpOp fifoEmpty = rewriter.create<comb::ICmpOp>(
76 loc, comb::ICmpPredicate::eq, count, countTc0);
77 fifoEmpty->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_empty"));
82 Value rdEnNandWrEn = rewriter.create<
comb::AndOp>(loc, notRdEn, notWrEn);
83 Value rdEnAndNotWrEn =
84 rewriter.create<
comb::AndOp>(loc, adaptor.getRdEn(), notWrEn);
85 Value wrEnAndNotRdEn =
86 rewriter.create<
comb::AndOp>(loc, adaptor.getWrEn(), notRdEn);
88 auto countEqTcFull = rewriter.create<comb::ICmpOp>(
89 loc, comb::ICmpPredicate::eq, count, countTcFull);
90 auto addCountTc1 = rewriter.create<
comb::AddOp>(loc, count, countTc1);
91 Value wrEnNext = rewriter.create<
comb::MuxOp>(loc, countEqTcFull,
96 auto countEqTc0 = rewriter.create<comb::ICmpOp>(
97 loc, comb::ICmpPredicate::eq, count, countTc0);
98 auto subCountTc1 = rewriter.create<
comb::SubOp>(loc, count, countTc1);
100 Value rdEnNext = rewriter.create<
comb::MuxOp>(loc, countEqTc0,
107 rewriter.create<
comb::MuxOp>(loc, rdEnAndNotWrEn, rdEnNext, count);
108 auto nextMux = rewriter.create<
comb::MuxOp>(loc, wrEnAndNotRdEn, wrEnNext,
111 loc, rdEnNandWrEn, count, nextMux));
112 static_cast<Value
>(nextCount).getDefiningOp()->setAttr(
113 "sv.namehint", rewriter.getStringAttr(
"fifo_count_next"));
118 auto addWrAddrPtrTc1 = rewriter.create<
comb::AddOp>(loc, wrAddr, ptrTc1);
119 wrAddrNext.setValue(rewriter.create<
comb::MuxOp>(loc, wrAndNotFull,
120 addWrAddrPtrTc1, wrAddr));
121 static_cast<Value
>(wrAddrNext)
123 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_wr_addr_next"));
126 Value rdAndNotEmpty =
127 rewriter.create<
comb::AndOp>(loc, adaptor.getRdEn(), notFifoEmpty);
128 auto addRdAddrPtrTc1 = rewriter.create<
comb::AddOp>(loc, rdAddr, ptrTc1);
130 addRdAddrPtrTc1, rdAddr));
131 static_cast<Value
>(rdAddrNext)
133 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_rd_addr_next"));
136 llvm::SmallVector<Value> results;
139 results.push_back(readData);
141 results.push_back(fifoFull);
143 results.push_back(fifoEmpty);
145 if (
auto almostFull = mem.getAlmostFullThreshold()) {
146 results.push_back(rewriter.create<comb::ICmpOp>(
147 loc, comb::ICmpPredicate::uge, count,
148 rewriter.create<
hw::ConstantOp>(loc, countType, almostFull.value())));
149 static_cast<Value
>(results.back())
151 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_full"));
154 if (
auto almostEmpty = mem.getAlmostEmptyThreshold()) {
155 results.push_back(rewriter.create<comb::ICmpOp>(
156 loc, comb::ICmpPredicate::ule, count,
158 almostEmpty.value())));
159 static_cast<Value
>(results.back())
161 ->setAttr(
"sv.namehint", rewriter.getStringAttr(
"fifo_almost_empty"));
164 rewriter.replaceOp(mem, results);
169 #define GEN_PASS_DEF_LOWERSEQFIFO
170 #include "circt/Dialect/Seq/SeqPasses.h.inc"
172 struct LowerSeqFIFOPass :
public impl::LowerSeqFIFOBase<LowerSeqFIFOPass> {
173 void runOnOperation()
override;
178 void LowerSeqFIFOPass::runOnOperation() {
179 MLIRContext &ctxt = getContext();
180 ConversionTarget target(ctxt);
183 target.addIllegalOp<seq::FIFOOp>();
184 target.addLegalDialect<seq::SeqDialect, hw::HWDialect, comb::CombDialect>();
189 applyPartialConversion(getOperation(), target, std::move(
patterns))))
194 return std::make_unique<LowerSeqFIFOPass>();
Instantiate one of these and use it to build typed backedges.
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()
This file defines an intermediate representation for circuits acting as an abstraction for constraint...