CIRCT  20.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 
10 #include "circt/Dialect/SV/SVOps.h"
14 #include "mlir/Pass/Pass.h"
15 #include "mlir/Transforms/DialectConversion.h"
16 #include "llvm/ADT/TypeSwitch.h"
17 
18 namespace circt {
19 namespace seq {
20 #define GEN_PASS_DEF_LOWERSEQFIFO
21 #include "circt/Dialect/Seq/SeqPasses.h.inc"
22 } // namespace seq
23 } // namespace circt
24 
25 using namespace circt;
26 using namespace seq;
27 
28 namespace {
29 
30 struct FIFOLowering : public OpConversionPattern<seq::FIFOOp> {
31 public:
32  using OpConversionPattern::OpConversionPattern;
33 
34  LogicalResult
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();
41  BackedgeBuilder bb(rewriter, loc);
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));
45  Backedge rdAddrNext = bb.get(ptrType);
46  Backedge wrAddrNext = bb.get(ptrType);
47  Backedge nextCount = bb.get(countType);
48 
49  // ====== Some constants ======
50  Value countTcFull =
51  rewriter.create<hw::ConstantOp>(loc, countType, depth - 1);
52  Value countTc1 = rewriter.create<hw::ConstantOp>(loc, countType, 1);
53  Value countTc0 = rewriter.create<hw::ConstantOp>(loc, countType, 0);
54  Value ptrTc1 = rewriter.create<hw::ConstantOp>(loc, ptrType, 1);
55 
56  // ====== Hardware units ======
57  Value count = rewriter.create<seq::CompRegOp>(
58  loc, nextCount, clk, rst,
59  rewriter.create<hw::ConstantOp>(loc, countType, 0), "fifo_count");
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);
63  Value rdAddr = rewriter.create<seq::CompRegOp>(
64  loc, rdAddrNext, clk, rst,
65  rewriter.create<hw::ConstantOp>(loc, ptrType, 0), "fifo_rd_addr");
66  Value wrAddr = rewriter.create<seq::CompRegOp>(
67  loc, wrAddrNext, clk, rst,
68  rewriter.create<hw::ConstantOp>(loc, ptrType, 0), "fifo_wr_addr");
69 
70  Value readData = rewriter.create<seq::ReadPortOp>(
71  loc, hlmem, llvm::SmallVector<Value>{rdAddr}, adaptor.getRdEn(),
72  mem.getRdLatency());
73  rewriter.create<seq::WritePortOp>(loc, hlmem,
74  llvm::SmallVector<Value>{wrAddr},
75  adaptor.getInput(), adaptor.getWrEn(),
76  /*latency*/ 1);
77 
78  // ====== some more constants =====
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"));
85 
86  // ====== Next-state count ======
87  auto notRdEn = comb::createOrFoldNot(loc, adaptor.getRdEn(), rewriter);
88  auto notWrEn = comb::createOrFoldNot(loc, adaptor.getWrEn(), rewriter);
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);
94 
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,
99  // keep value
100  count,
101  // increment
102  addCountTc1);
103  auto countEqTc0 = rewriter.create<comb::ICmpOp>(
104  loc, comb::ICmpPredicate::eq, count, countTc0);
105  auto subCountTc1 = rewriter.create<comb::SubOp>(loc, count, countTc1);
106 
107  Value rdEnNext = rewriter.create<comb::MuxOp>(loc, countEqTc0,
108  // keep value
109  count,
110  // decrement
111  subCountTc1);
112 
113  auto nextInnerMux =
114  rewriter.create<comb::MuxOp>(loc, rdEnAndNotWrEn, rdEnNext, count);
115  auto nextMux = rewriter.create<comb::MuxOp>(loc, wrEnAndNotRdEn, wrEnNext,
116  nextInnerMux);
117  nextCount.setValue(rewriter.create<comb::MuxOp>(
118  loc, rdEnNandWrEn, /*keep value*/ count, nextMux));
119  static_cast<Value>(nextCount).getDefiningOp()->setAttr(
120  "sv.namehint", rewriter.getStringAttr("fifo_count_next"));
121 
122  // ====== Read/write pointers ======
123  Value wrAndNotFull = rewriter.create<comb::AndOp>(
124  loc, adaptor.getWrEn(), comb::createOrFoldNot(loc, fifoFull, rewriter));
125  auto addWrAddrPtrTc1 = rewriter.create<comb::AddOp>(loc, wrAddr, ptrTc1);
126  wrAddrNext.setValue(rewriter.create<comb::MuxOp>(loc, wrAndNotFull,
127  addWrAddrPtrTc1, wrAddr));
128  static_cast<Value>(wrAddrNext)
129  .getDefiningOp()
130  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_wr_addr_next"));
131 
132  auto notFifoEmpty = comb::createOrFoldNot(loc, fifoEmpty, rewriter);
133  Value rdAndNotEmpty =
134  rewriter.create<comb::AndOp>(loc, adaptor.getRdEn(), notFifoEmpty);
135  auto addRdAddrPtrTc1 = rewriter.create<comb::AddOp>(loc, rdAddr, ptrTc1);
136  rdAddrNext.setValue(rewriter.create<comb::MuxOp>(loc, rdAndNotEmpty,
137  addRdAddrPtrTc1, rdAddr));
138  static_cast<Value>(rdAddrNext)
139  .getDefiningOp()
140  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_rd_addr_next"));
141 
142  // ====== Result values ======
143  llvm::SmallVector<Value> results;
144 
145  // Data
146  results.push_back(readData);
147  // Full
148  results.push_back(fifoFull);
149  // Empty
150  results.push_back(fifoEmpty);
151 
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())
157  .getDefiningOp()
158  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_almost_full"));
159  }
160 
161  if (auto almostEmpty = mem.getAlmostEmptyThreshold()) {
162  results.push_back(rewriter.create<comb::ICmpOp>(
163  loc, comb::ICmpPredicate::ule, count,
164  rewriter.create<hw::ConstantOp>(loc, countType,
165  almostEmpty.value())));
166  static_cast<Value>(results.back())
167  .getDefiningOp()
168  ->setAttr("sv.namehint", rewriter.getStringAttr("fifo_almost_empty"));
169  }
170 
171  rewriter.replaceOp(mem, results);
172  return success();
173  }
174 };
175 
176 struct LowerSeqFIFOPass
177  : public circt::seq::impl::LowerSeqFIFOBase<LowerSeqFIFOPass> {
178  void runOnOperation() override;
179 };
180 
181 } // namespace
182 
183 void LowerSeqFIFOPass::runOnOperation() {
184  MLIRContext &ctxt = getContext();
185  ConversionTarget target(ctxt);
186 
187  // Lowering patterns must lower away all HLMem-related operations.
188  target.addIllegalOp<seq::FIFOOp>();
189  target.addLegalDialect<seq::SeqDialect, hw::HWDialect, comb::CombDialect>();
190  RewritePatternSet patterns(&ctxt);
191  patterns.add<FIFOLowering>(&ctxt);
192 
193  if (failed(
194  applyPartialConversion(getOperation(), target, std::move(patterns))))
195  signalPassFailure();
196 }
197 
198 std::unique_ptr<Pass> circt::seq::createLowerSeqFIFOPass() {
199  return std::make_unique<LowerSeqFIFOPass>();
200 }
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)
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