13#include "mlir/Pass/Pass.h"
14#include "mlir/Transforms/DialectConversion.h"
15#include "llvm/ADT/TypeSwitch.h"
19#define GEN_PASS_DEF_UNROLLMEMORYLATENCIES
20#include "circt/Dialect/Seq/SeqPasses.h.inc"
28struct UnrollMemoryLatenciesPass
29 :
public circt::seq::impl::UnrollMemoryLatenciesBase<
30 UnrollMemoryLatenciesPass> {
31 void runOnOperation()
override;
36 void delayAddresses(OpBuilder &builder, Location loc, Value
clk, Value ce,
37 MutableOperandRange addrs, IntegerAttr delayAttr)
const {
39 builder.setInsertionPoint(addrs.getOwner());
44 for (
auto &
addr : addrs)
46 addr.set(seq::ShiftRegOp::create(builder, loc, delayAttr,
addr.get(),
clk,
47 ce, {}, {}, {}, {}, {}));
53 void hlMemOpWritePortUnrolling(seq::WritePortOp &op,
54 OpBuilder &builder)
const {
57 IntegerAttr latencyAttr = op.getLatencyAttr();
58 IntegerAttr delayAttr =
59 IntegerAttr::get(latencyAttr.getType(), latencyAttr.getInt() - 1);
60 IntegerAttr oneAttr = IntegerAttr::get(latencyAttr.getType(), 1);
63 OpOperand &
data = op.getInDataMutable();
64 OpOperand &wrEn = op.getWrEnMutable();
65 MutableOperandRange addrs = op.getAddressesMutable();
66 Value
clk = op.getMemory().getDefiningOp()->getOperand(0);
68 builder.setInsertionPointAfter(op);
72 builder.getI1Type(), 1);
75 delayAddresses(builder, op.getLoc(), clk, ce, addrs, delayAttr);
78 data.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayAttr,
79 data.get(), clk, ce, {}, {}, {}, {}, {}));
82 wrEn.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayAttr,
83 wrEn.get(), clk, ce, {}, {}, {}, {}, {}));
86 op.setLatencyAttr(oneAttr);
92 void hlMemOpReadPortUnrolling(seq::ReadPortOp &op, OpBuilder &builder)
const {
94 IntegerAttr latencyAttr = op.getLatencyAttr();
95 IntegerAttr zeroAttr = IntegerAttr::get(latencyAttr.getType(), 0);
98 MutableOperandRange addrs = op.getAddressesMutable();
99 MutableOperandRange rdEn = op.getRdEnMutable();
100 Value
clk = op.getMemory().getDefiningOp()->getOperand(0);
102 builder.setInsertionPointAfter(op);
106 builder.getI1Type(), 1);
109 delayAddresses(builder, op.getLoc(), clk, ce, addrs, latencyAttr);
112 for (
auto &rden : rdEn)
113 rden.set(seq::ShiftRegOp::create(builder, op.getLoc(), latencyAttr,
114 rden.get(), clk, ce, {}, {}, {}, {},
117 op.setLatencyAttr(zeroAttr);
127 void unrollFirMemWritePort(seq::FirMemWriteOp &op, IntegerAttr delayAttr,
128 Value ce, OpBuilder &builder)
const {
131 OpOperand &
addr = op.getAddressMutable();
132 OpOperand &
data = op.getDataMutable();
133 MutableOperandRange ens = op.getEnableMutable();
134 Value
clk = op.getClk();
137 data.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayAttr,
138 data.get(), clk, ce, {}, {}, {}, {}, {}));
140 addr.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayAttr,
141 addr.get(), clk, ce, {}, {}, {}, {}, {}));
144 en.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayAttr,
en.get(),
145 clk, ce, {}, {}, {}, {}, {}));
149 void unrollFirMemReadPort(seq::FirMemReadOp &op, IntegerAttr delayRdAttr,
150 Value ce, OpBuilder &builder)
const {
152 OpOperand &
addr = op.getAddressMutable();
153 MutableOperandRange ens = op.getEnableMutable();
154 Value
clk = op.getClk();
156 addr.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayRdAttr,
157 addr.get(), clk, ce, {}, {}, {}, {}, {}));
160 en.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayRdAttr,
161 en.get(), clk, ce, {}, {}, {}, {}, {}));
167 void unrollFirMemReadWritePort(seq::FirMemReadWriteOp &op,
168 IntegerAttr delayWrAttr,
169 IntegerAttr delayRdAttr, Value ce,
170 OpBuilder &builder)
const {
172 OpOperand &
addr = op.getAddressMutable();
173 OpOperand &
data = op.getWriteDataMutable();
174 OpOperand &mode = op.getModeMutable();
175 MutableOperandRange ens = op.getEnableMutable();
176 Value
clk = op.getClk();
180 auto delayedReadAddr =
181 seq::ShiftRegOp::create(builder, op.getLoc(), delayRdAttr,
addr.get(),
182 clk, ce, {}, {}, {}, {}, {});
184 auto delayedWriteAddr =
185 seq::ShiftRegOp::create(builder, op.getLoc(), delayWrAttr,
addr.get(),
186 clk, ce, {}, {}, {}, {}, {});
190 data.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayWrAttr,
191 data.get(), clk, ce, {}, {}, {}, {}, {}));
202 seq::ShiftRegOp::create(builder, op.getLoc(), delayWrAttr, mode.get(),
203 clk, ce, {}, {}, {}, {}, {});
206 seq::ShiftRegOp::create(builder, op.getLoc(), delayRdAttr, mode.get(),
207 clk, ce, {}, {}, {}, {}, {});
211 auto selectMode = comb::MuxOp::create(
212 builder, op.getLoc(),
213 delayWrAttr.getInt() < delayRdAttr.getInt() ? delayedModeWr
215 delayedModeWr, delayedModeRd);
216 mode.set(selectMode);
219 addr.set(comb::MuxOp::create(builder, op.getLoc(), selectMode,
220 delayedWriteAddr, delayedReadAddr));
224 en.set(seq::ShiftRegOp::create(builder, op.getLoc(), delayWrAttr,
225 en.get(), clk, ce, {}, {}, {}, {}, {}));
228 void firMemOpUnrolling(seq::FirMemOp &mem, OpBuilder &builder)
const {
231 IntegerAttr wrLatency = mem.getWriteLatencyAttr();
232 IntegerAttr rdLatency = mem.getReadLatencyAttr();
233 IntegerAttr delayRdAttr = builder.getI64IntegerAttr(rdLatency.getInt());
234 IntegerAttr delayWrAttr = builder.getI64IntegerAttr(wrLatency.getInt() - 1);
235 IntegerAttr zeroAttr = builder.getI32IntegerAttr(0);
236 IntegerAttr oneAttr = builder.getI32IntegerAttr(1);
238 builder.setInsertionPointAfter(mem);
242 builder.getI1Type(), 1);
245 for (
auto *user : mem->getUsers()) {
247 TypeSwitch<Operation *, void>(user)
248 .Case<seq::FirMemWriteOp>([&](
auto port) {
249 unrollFirMemWritePort(port, delayWrAttr, ce, builder);
251 .Case<seq::FirMemReadOp>([&](
auto port) {
252 unrollFirMemReadPort(port, delayRdAttr, ce, builder);
254 .Case<seq::FirMemReadWriteOp>([&](
auto port) {
255 unrollFirMemReadWritePort(port, delayWrAttr, delayRdAttr, ce,
258 .Default([](
auto) { });
262 mem.setReadLatencyAttr(zeroAttr);
263 mem.setWriteLatencyAttr(oneAttr);
269void UnrollMemoryLatenciesPass::runOnOperation() {
270 auto top = getOperation();
271 OpBuilder builder(top);
274 top->walk([&](Operation *op) {
275 TypeSwitch<Operation *>(op)
276 .Case<seq::WritePortOp>(
277 [&](
auto &wrop) { hlMemOpWritePortUnrolling(wrop, builder); })
278 .Case<seq::ReadPortOp>(
279 [&](
auto &rdop) { hlMemOpReadPortUnrolling(rdop, builder); })
280 .Case<seq::FirMemOp>(
281 [&](
auto &firmem) { firMemOpUnrolling(firmem, builder); })
282 .Default([](
auto) {});
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.