CIRCT  19.0.0git
LowerSeqFIFO.cpp
Go to the documentation of this file.
1 //===- LowerSeqFIFO.cpp - seq.fifo lowering -------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "PassDetails.h"
11 #include "circt/Dialect/SV/SVOps.h"
15 #include "mlir/Transforms/DialectConversion.h"
16 #include "llvm/ADT/TypeSwitch.h"
17 
18 using namespace circt;
19 using namespace seq;
20 
21 namespace {
22 
23 struct FIFOLowering : public OpConversionPattern<seq::FIFOOp> {
24 public:
25  using OpConversionPattern::OpConversionPattern;
26 
27  LogicalResult
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();
34  BackedgeBuilder bb(rewriter, loc);
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);
41 
42  // ====== Some constants ======
43  Value countTcFull =
44  rewriter.create<hw::ConstantOp>(loc, countType, depth - 1);
45  Value countTc1 = rewriter.create<hw::ConstantOp>(loc, countType, 1);
46  Value countTc0 = rewriter.create<hw::ConstantOp>(loc, countType, 0);
47  Value ptrTc1 = rewriter.create<hw::ConstantOp>(loc, ptrType, 1);
48 
49  // ====== Hardware units ======
50  Value count = rewriter.create<seq::CompRegOp>(
51  loc, nextCount, clk, rst,
52  rewriter.create<hw::ConstantOp>(loc, countType, 0), "fifo_count");
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);
56  Value rdAddr = rewriter.create<seq::CompRegOp>(
57  loc, rdAddrNext, clk, rst,
58  rewriter.create<hw::ConstantOp>(loc, ptrType, 0), "fifo_rd_addr");
59  Value wrAddr = rewriter.create<seq::CompRegOp>(
60  loc, wrAddrNext, clk, rst,
61  rewriter.create<hw::ConstantOp>(loc, ptrType, 0), "fifo_wr_addr");
62 
63  Value readData = rewriter.create<seq::ReadPortOp>(
64  loc, hlmem, llvm::SmallVector<Value>{rdAddr}, adaptor.getRdEn(),
65  /*latency*/ 0);
66  rewriter.create<seq::WritePortOp>(loc, hlmem,
67  llvm::SmallVector<Value>{wrAddr},
68  adaptor.getInput(), adaptor.getWrEn(),
69  /*latency*/ 1);
70 
71  // ====== some more constants =====
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"));
78 
79  // ====== Next-state count ======
80  auto notRdEn = comb::createOrFoldNot(loc, adaptor.getRdEn(), rewriter);
81  auto notWrEn = comb::createOrFoldNot(loc, adaptor.getWrEn(), rewriter);
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);
87 
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,
92  // keep value
93  count,
94  // increment
95  addCountTc1);
96  auto countEqTc0 = rewriter.create<comb::ICmpOp>(
97  loc, comb::ICmpPredicate::eq, count, countTc0);
98  auto subCountTc1 = rewriter.create<comb::SubOp>(loc, count, countTc1);
99 
100  Value rdEnNext = rewriter.create<comb::MuxOp>(loc, countEqTc0,
101  // keep value
102  count,
103  // decrement
104  subCountTc1);
105 
106  auto nextInnerMux =
107  rewriter.create<comb::MuxOp>(loc, rdEnAndNotWrEn, rdEnNext, count);
108  auto nextMux = rewriter.create<comb::MuxOp>(loc, wrEnAndNotRdEn, wrEnNext,
109  nextInnerMux);
110  nextCount.setValue(rewriter.create<comb::MuxOp>(
111  loc, rdEnNandWrEn, /*keep value*/ count, nextMux));
112  static_cast<Value>(nextCount).getDefiningOp()->setAttr(
113  "sv.namehint", rewriter.getStringAttr("fifo_count_next"));
114 
115  // ====== Read/write pointers ======
116  Value wrAndNotFull = rewriter.create<comb::AndOp>(
117  loc, adaptor.getWrEn(), comb::createOrFoldNot(loc, fifoFull, rewriter));
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)
122  .getDefiningOp()
123  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_wr_addr_next"));
124 
125  auto notFifoEmpty = comb::createOrFoldNot(loc, fifoEmpty, rewriter);
126  Value rdAndNotEmpty =
127  rewriter.create<comb::AndOp>(loc, adaptor.getRdEn(), notFifoEmpty);
128  auto addRdAddrPtrTc1 = rewriter.create<comb::AddOp>(loc, rdAddr, ptrTc1);
129  rdAddrNext.setValue(rewriter.create<comb::MuxOp>(loc, rdAndNotEmpty,
130  addRdAddrPtrTc1, rdAddr));
131  static_cast<Value>(rdAddrNext)
132  .getDefiningOp()
133  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_rd_addr_next"));
134 
135  // ====== Result values ======
136  llvm::SmallVector<Value> results;
137 
138  // Data
139  results.push_back(readData);
140  // Full
141  results.push_back(fifoFull);
142  // Empty
143  results.push_back(fifoEmpty);
144 
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())
150  .getDefiningOp()
151  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_almost_full"));
152  }
153 
154  if (auto almostEmpty = mem.getAlmostEmptyThreshold()) {
155  results.push_back(rewriter.create<comb::ICmpOp>(
156  loc, comb::ICmpPredicate::ule, count,
157  rewriter.create<hw::ConstantOp>(loc, countType,
158  almostEmpty.value())));
159  static_cast<Value>(results.back())
160  .getDefiningOp()
161  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_almost_empty"));
162  }
163 
164  rewriter.replaceOp(mem, results);
165  return success();
166  }
167 };
168 
169 #define GEN_PASS_DEF_LOWERSEQFIFO
170 #include "circt/Dialect/Seq/SeqPasses.h.inc"
171 
172 struct LowerSeqFIFOPass : public impl::LowerSeqFIFOBase<LowerSeqFIFOPass> {
173  void runOnOperation() override;
174 };
175 
176 } // namespace
177 
178 void LowerSeqFIFOPass::runOnOperation() {
179  MLIRContext &ctxt = getContext();
180  ConversionTarget target(ctxt);
181 
182  // Lowering patterns must lower away all HLMem-related operations.
183  target.addIllegalOp<seq::FIFOOp>();
184  target.addLegalDialect<seq::SeqDialect, hw::HWDialect, comb::CombDialect>();
185  RewritePatternSet patterns(&ctxt);
186  patterns.add<FIFOLowering>(&ctxt);
187 
188  if (failed(
189  applyPartialConversion(getOperation(), target, std::move(patterns))))
190  signalPassFailure();
191 }
192 
193 std::unique_ptr<Pass> circt::seq::createLowerSeqFIFOPass() {
194  return std::make_unique<LowerSeqFIFOPass>();
195 }
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)
Definition: hw.py:393
Value createOrFoldNot(Location loc, Value value, OpBuilder &builder, bool twoState=false)
Create a `‘Not’' gate on a value.
Definition: CombOps.cpp:48
std::unique_ptr< mlir::Pass > createLowerSeqFIFOPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: seq.py:1