CIRCT 24.0.0git
Loading...
Searching...
No Matches
ESIPasses.cpp
Go to the documentation of this file.
1//===- ESIPasses.cpp - Common code for ESI passes ---------------*- C++ -*-===//
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"
10
13#include "circt/Support/LLVM.h"
14
15#include "mlir/IR/SymbolTable.h"
16#include "mlir/Pass/Pass.h"
17#include "mlir/Transforms/DialectConversion.h"
18
19using namespace circt;
20using namespace circt::esi;
21using namespace circt::esi::detail;
22using namespace circt::hw;
23
25 std::string typeID;
26 llvm::raw_string_ostream(typeID) << t;
27 return StringAttr::get(t.getContext(), typeID);
28}
29
31 if (auto ch = dyn_cast<ChannelType>(t))
32 t = ch.getInner();
33 if (auto win = dyn_cast<WindowType>(t))
34 t = win.getLoweredType();
35 return hw::getBitWidth(t);
36}
37
38//===----------------------------------------------------------------------===//
39// ESI custom op builder.
40//===----------------------------------------------------------------------===//
41
43 : ImplicitLocOpBuilder(UnknownLoc::get(top->getContext()), top),
44 a(StringAttr::get(getContext(), "a")),
45 aValid(StringAttr::get(getContext(), "a_valid")),
46 aReady(StringAttr::get(getContext(), "a_ready")),
47 x(StringAttr::get(getContext(), "x")),
48 xValid(StringAttr::get(getContext(), "x_valid")),
49 xReady(StringAttr::get(getContext(), "x_ready")),
50 dataOutValid(StringAttr::get(getContext(), "DataOutValid")),
51 dataOutReady(StringAttr::get(getContext(), "DataOutReady")),
52 dataOut(StringAttr::get(getContext(), "DataOut")),
53 dataInValid(StringAttr::get(getContext(), "DataInValid")),
54 dataInReady(StringAttr::get(getContext(), "DataInReady")),
55 dataIn(StringAttr::get(getContext(), "DataIn")),
56 clk(StringAttr::get(getContext(), "clk")),
57 rst(StringAttr::get(getContext(), "rst")),
58 width(StringAttr::get(getContext(), "WIDTH")),
59 dataDelay(StringAttr::get(getContext(), "DATA_DELAY")) {
60
61 auto regions = top->getRegions();
62 if (regions.empty()) {
63 top->emitError("ESI HW Builder needs a region to insert HW.");
64 }
65 auto &region = regions.front();
66 if (!region.empty())
67 setInsertionPoint(&region.front(), region.front().begin());
68}
69
70static StringAttr constructUniqueSymbol(Operation *tableOp,
71 StringRef proposedNameRef) {
72 SmallString<64> proposedName = proposedNameRef;
73
74 // Normalize the type name.
75 for (char &ch : proposedName) {
76 if (isalpha(ch) || isdigit(ch) || ch == '_')
77 continue;
78 ch = '_';
79 }
80
81 // Make sure that this symbol isn't taken. If it is, append a number and try
82 // again.
83 size_t baseLength = proposedName.size();
84 size_t tries = 0;
85 while (SymbolTable::lookupSymbolIn(tableOp, proposedName)) {
86 proposedName.resize(baseLength);
87 proposedName.append(llvm::utostr(++tries));
88 }
89
90 return StringAttr::get(tableOp->getContext(), proposedName);
91}
92
93/// Return a parameter list for the stage module with the specified values.
94ArrayAttr ESIHWBuilder::getStageParameterList(Attribute widthValue,
95 Attribute dataDelayValue) {
96 auto type = IntegerType::get(width.getContext(), 32, IntegerType::Unsigned);
97 return ArrayAttr::get(
98 width.getContext(),
99 {ParamDeclAttr::get(width.getContext(), width, type, widthValue),
100 ParamDeclAttr::get(width.getContext(), dataDelay, type,
101 dataDelayValue)});
102}
103
104/// Write an 'ExternModuleOp' to use a hand-coded SystemVerilog module. Said
105/// module implements pipeline stage, adding 1 cycle latency. This particular
106/// implementation is double-buffered and fully pipelines the reverse-flow ready
107/// signal.
108HWModuleExternOp ESIHWBuilder::declareStage(Operation *symTable,
109 PipelineStageOp stage) {
110 Type dataType = stage.innerType();
111 HWModuleExternOp &stageMod = declaredStage[dataType];
112 if (stageMod)
113 return stageMod;
114
115 // Since this module has parameterized widths on the a input and x output,
116 // give the extern declation a None type since nothing else makes sense.
117 // Will be refining this when we decide how to better handle parameterized
118 // types and ops.
119 size_t argn = 0;
120 size_t resn = 0;
121 llvm::SmallVector<PortInfo> ports = {
123 {{rst, getI1Type(), ModulePort::Direction::Input}, argn++}};
124
125 ports.push_back({{a, dataType, ModulePort::Direction::Input}, argn++});
126 ports.push_back(
127 {{aValid, getI1Type(), ModulePort::Direction::Input}, argn++});
128 ports.push_back(
129 {{aReady, getI1Type(), ModulePort::Direction::Output}, resn++});
130 ports.push_back({{x, dataType, ModulePort::Direction::Output}, resn++});
131
132 ports.push_back(
133 {{xValid, getI1Type(), ModulePort::Direction::Output}, resn++});
134 ports.push_back(
135 {{xReady, getI1Type(), ModulePort::Direction::Input}, argn++});
136
137 stageMod = HWModuleExternOp::create(
138 *this, constructUniqueSymbol(symTable, "ESI_PipelineStage"), ports,
139 "ESI_PipelineStage", getStageParameterList({}, {}));
140 return stageMod;
141}
142
143/// Write an 'ExternModuleOp' to use a hand-coded SystemVerilog module. Said
144/// module contains a bi-directional Cosimulation DPI interface with valid/ready
145/// semantics.
146HWModuleExternOp
150
151 SmallVector<Attribute, 8> params;
152 params.push_back(
153 ParamDeclAttr::get("ENDPOINT_ID", NoneType::get(getContext())));
154 params.push_back(
155 ParamDeclAttr::get("TO_HOST_TYPE_ID", NoneType::get(getContext())));
156 params.push_back(ParamDeclAttr::get("TO_HOST_SIZE_BITS", getI32Type()));
157
158 auto dataInType = hw::IntType::get(hw::ParamDeclRefAttr::get(
159 StringAttr::get(getContext(), "TO_HOST_SIZE_BITS"),
160 getIntegerType(32, false)));
161 PortInfo ports[] = {
163 {{rst, getI1Type(), ModulePort::Direction::Input}, 1},
164 {{dataInValid, getI1Type(), ModulePort::Direction::Input}, 2},
165 {{dataInReady, getI1Type(), ModulePort::Direction::Output}, 3},
166 {{dataIn, dataInType, ModulePort::Direction::Input}, 4}};
167
168 declaredCosimEndpointToHostModule = HWModuleExternOp::create(
169 *this, constructUniqueSymbol(symTable, "Cosim_Endpoint_ToHost"), ports,
170 "Cosim_Endpoint_ToHost", ArrayAttr::get(getContext(), params));
172}
173
174HWModuleExternOp
178
179 SmallVector<Attribute, 8> params;
180 params.push_back(
181 ParamDeclAttr::get("ENDPOINT_ID", NoneType::get(getContext())));
182 params.push_back(
183 ParamDeclAttr::get("FROM_HOST_TYPE_ID", NoneType::get(getContext())));
184 params.push_back(ParamDeclAttr::get("FROM_HOST_SIZE_BITS", getI32Type()));
185
186 auto dataInType = hw::IntType::get(hw::ParamDeclRefAttr::get(
187 StringAttr::get(getContext(), "FROM_HOST_SIZE_BITS"),
188 getIntegerType(32, false)));
189 PortInfo ports[] = {
191 {{rst, getI1Type(), ModulePort::Direction::Input}, 1},
192 {{dataOutValid, getI1Type(), ModulePort::Direction::Output}, 2},
193 {{dataOutReady, getI1Type(), ModulePort::Direction::Input}, 3},
194 {{dataOut, dataInType, ModulePort::Direction::Output}, 4}};
195
196 declaredCosimEndpointFromHostModule = HWModuleExternOp::create(
197 *this, constructUniqueSymbol(symTable, "Cosim_Endpoint_FromHost"), ports,
198 "Cosim_Endpoint_FromHost", ArrayAttr::get(getContext(), params));
200}
201
202Type ESIHWBuilder::getClockType() { return seq::ClockType::get(getContext()); }
203
static void registerPasses()
static StringAttr constructUniqueSymbol(Operation *tableOp, StringRef proposedNameRef)
Definition ESIPasses.cpp:70
#define isalpha(x)
Definition FIRLexer.cpp:27
#define isdigit(x)
Definition FIRLexer.cpp:26
if(parseOptionalKeywordOrOptionalString(parser, result.rawName, found)) return failure()
hw::HWModuleExternOp declareCosimEndpointFromHostModule(Operation *symTable)
std::optional< hw::HWModuleExternOp > declaredCosimEndpointToHostModule
Definition PassDetails.h:79
hw::HWModuleExternOp declareCosimEndpointToHostModule(Operation *symTable)
Write an 'ExternModuleOp' to use a hand-coded SystemVerilog module.
ArrayAttr getStageParameterList(Attribute widthValue, Attribute dataDelayValue)
Get the parameter list for the stage module.
Definition ESIPasses.cpp:94
std::optional< hw::HWModuleExternOp > declaredCosimEndpointFromHostModule
Definition PassDetails.h:80
llvm::DenseMap< Type, hw::HWModuleExternOp > declaredStage
Definition PassDetails.h:81
hw::HWModuleExternOp declareStage(Operation *symTable, PipelineStageOp)
Write an 'ExternModuleOp' to use a hand-coded SystemVerilog module.
uint64_t getWidth(Type t)
Definition ESIPasses.cpp:30
StringAttr getTypeID(Type t)
Definition ESIPasses.cpp:24
void registerESIPasses()
int64_t getBitWidth(mlir::Type type)
Return the hardware bit width of a type.
Definition HWTypes.cpp:122
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
This holds the name, type, direction of a module's ports.