17 #include "mlir/Dialect/EmitC/IR/EmitC.h"
18 #include "mlir/IR/BuiltinDialect.h"
19 #include "mlir/Pass/Pass.h"
20 #include "mlir/Transforms/DialectConversion.h"
21 #include "llvm/ADT/TypeSwitch.h"
24 #define GEN_PASS_DEF_CONVERTHWTOSYSTEMC
25 #include "circt/Conversion/Passes.h.inc"
29 using namespace circt;
31 using namespace systemc;
44 using OpConversionPattern::OpConversionPattern;
47 matchAndRewrite(
HWModuleOp module, OpAdaptor adaptor,
48 ConversionPatternRewriter &rewriter)
const override {
50 if (!module.getParameters().empty())
51 return emitError(module->getLoc(),
"module parameters not supported yet");
53 auto ports = module.getPortList();
54 if (llvm::any_of(ports, [](
auto &port) {
return port.isInOut(); }))
55 return emitError(module->getLoc(),
"inout arguments not supported yet");
58 for (
size_t i = 0; i < ports.size(); ++i)
59 ports[i].type = typeConverter->convertType(ports[i].type);
61 auto scModule = rewriter.create<SCModuleOp>(module.getLoc(),
62 module.getNameAttr(), ports);
63 auto *outputOp = module.getBodyBlock()->getTerminator();
64 scModule.setVisibility(module.getVisibility());
66 auto portAttrs = module.getAllPortAttrs();
67 if (!portAttrs.empty())
68 scModule.setAllArgAttrs(portAttrs);
72 rewriter.setInsertionPointToStart(scModule.getBodyBlock());
73 auto scFunc = rewriter.create<SCFuncOp>(
74 module.getLoc(), rewriter.getStringAttr(
"innerLogic"));
80 scFunc.getBodyBlock()->erase();
81 Region &scFuncBody = scFunc.getBody();
82 rewriter.inlineRegionBefore(module.getBody(), scFuncBody, scFuncBody.end());
85 rewriter.setInsertionPointToStart(
86 scModule.getOrCreateCtor().getBodyBlock());
87 rewriter.create<MethodOp>(scModule.getLoc(), scFunc.getHandle());
90 SmallVector<Value> sensitivityValues(
91 llvm::make_filter_range(scModule.getArguments(), [](BlockArgument arg) {
92 return !isa<OutputType>(arg.getType());
94 if (!sensitivityValues.empty())
95 rewriter.create<SensitiveOp>(scModule.getLoc(), sensitivityValues);
99 rewriter.setInsertionPointToStart(scFunc.getBodyBlock());
100 auto portsLocal = module.getPortList();
101 for (
size_t i = 0, e = scFunc.getRegion().getNumArguments(); i < e; ++i) {
104 .create<SignalReadOp>(scFunc.getLoc(), scModule.getArgument(i))
106 auto converted = typeConverter->materializeSourceConversion(
107 rewriter, scModule.getLoc(), portsLocal[i].type, inputRead);
108 scFuncBody.getArgument(0).replaceAllUsesWith(converted);
109 scFuncBody.eraseArgument(0);
113 rewriter.eraseOp(module);
115 SmallVector<Value> outPorts;
116 for (
auto val : scModule.getArguments()) {
117 if (isa<OutputType>(val.getType()))
118 outPorts.push_back(val);
121 rewriter.setInsertionPoint(outputOp);
122 for (
auto args : llvm::zip(outPorts, outputOp->getOperands())) {
123 Value portValue = std::get<0>(args);
124 auto converted = typeConverter->materializeTargetConversion(
127 rewriter.create<SignalWriteOp>(outputOp->getLoc(), portValue, converted);
131 outputOp->dropAllReferences();
132 rewriter.eraseOp(outputOp);
143 using OpConversionPattern::OpConversionPattern;
146 template <
typename PortTy>
148 collectPortInfo(ValueRange ports, ArrayAttr portNames,
149 SmallVector<systemc::ModuleType::PortInfo> &portInfo)
const {
150 for (
auto inPort : llvm::zip(ports, portNames)) {
151 Type ty = std::get<0>(inPort).getType();
152 systemc::ModuleType::PortInfo info;
154 if (isa<hw::InOutType>(ty))
157 info.type = typeConverter->convertType(
PortTy::get(ty));
158 info.name = cast<StringAttr>(std::get<1>(inPort));
159 portInfo.push_back(info);
167 matchAndRewrite(InstanceOp instanceOp, OpAdaptor adaptor,
168 ConversionPatternRewriter &rewriter)
const override {
171 auto scModule = instanceOp->getParentOfType<SCModuleOp>();
173 return rewriter.notifyMatchFailure(instanceOp,
174 "parent was not an SCModuleOp");
177 auto ctor = scModule.getOrCreateCtor();
178 OpBuilder stateBuilder(ctor);
179 OpBuilder initBuilder = OpBuilder::atBlockEnd(ctor.getBodyBlock());
183 SmallVector<systemc::ModuleType::PortInfo> portInfo;
184 if (failed(collectPortInfo<InputType>(adaptor.getInputs(),
185 adaptor.getArgNames(), portInfo)) ||
186 failed(collectPortInfo<OutputType>(instanceOp->getResults(),
187 adaptor.getResultNames(), portInfo)))
188 return instanceOp->emitOpError(
"inout ports not supported");
190 Location loc = instanceOp->getLoc();
191 auto instanceName = instanceOp.getInstanceNameAttr();
192 auto instModuleName = instanceOp.getModuleNameAttr();
195 auto instDecl = stateBuilder.create<InstanceDeclOp>(
196 loc, instanceName, instModuleName, portInfo);
199 for (
size_t i = 0, numInputs = adaptor.getInputs().size(); i < numInputs;
201 Value input = adaptor.getInputs()[i];
202 auto portId = rewriter.getIndexAttr(i);
203 StringAttr signalName = rewriter.getStringAttr(
204 instanceName.getValue() +
"_" + portInfo[i].name.getValue());
206 if (
auto readOp = input.getDefiningOp<SignalReadOp>()) {
209 initBuilder.create<BindPortOp>(loc, instDecl, portId,
216 Value channel = stateBuilder.create<SignalOp>(loc, sigType, signalName);
217 initBuilder.create<BindPortOp>(loc, instDecl, portId, channel);
218 rewriter.create<SignalWriteOp>(loc, channel, input);
222 for (
size_t i = 0, numOutputs = instanceOp->getNumResults(); i < numOutputs;
224 size_t numInputs = adaptor.getInputs().size();
225 Value output = instanceOp->getResult(i);
226 auto portId = rewriter.getIndexAttr(i + numInputs);
227 StringAttr signalName =
228 rewriter.getStringAttr(instanceName.getValue() +
"_" +
229 portInfo[i + numInputs].name.getValue());
231 if (output.hasOneUse()) {
232 if (
auto writeOp = dyn_cast<SignalWriteOp>(*output.user_begin())) {
239 initBuilder.create<BindPortOp>(loc, instDecl, portId,
249 Value channel = stateBuilder.create<SignalOp>(loc, sigType, signalName);
250 initBuilder.create<BindPortOp>(loc, instDecl, portId, channel);
251 auto instOut = rewriter.create<SignalReadOp>(loc, channel);
252 output.replaceAllUsesWith(instOut);
255 rewriter.eraseOp(instanceOp);
267 target.addIllegalDialect<HWDialect>();
268 target.addLegalDialect<mlir::BuiltinDialect>();
269 target.addLegalDialect<systemc::SystemCDialect>();
270 target.addLegalDialect<comb::CombDialect>();
271 target.addLegalDialect<emitc::EmitCDialect>();
276 TypeConverter &typeConverter) {
277 patterns.add<ConvertHWModule, ConvertInstance>(typeConverter,
282 converter.addConversion([](Type type) {
return type; });
283 converter.addConversion([&](SignalType type) {
286 converter.addConversion([&](InputType type) {
292 converter.addConversion([&](OutputType type) {
295 converter.addConversion([](IntegerType type) -> Type {
296 auto bw = type.getIntOrFloatBitWidth();
317 converter.addSourceMaterialization(
318 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
319 assert(values.size() == 1);
320 auto op = builder.create<ConvertOp>(loc, type, values[0]);
321 return op.getResult();
324 converter.addTargetMaterialization(
325 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
326 assert(values.size() == 1);
327 auto op = builder.create<ConvertOp>(loc, type, values[0]);
328 return op.getResult();
337 struct HWToSystemCPass
338 :
public circt::impl::ConvertHWToSystemCBase<HWToSystemCPass> {
339 void runOnOperation()
override;
345 return std::make_unique<HWToSystemCPass>();
349 void HWToSystemCPass::runOnOperation() {
350 MLIRContext &context = getContext();
351 ModuleOp module = getOperation();
355 OpBuilder builder(module.getRegion());
356 builder.create<emitc::IncludeOp>(module->getLoc(),
"systemc.h",
true);
358 ConversionTarget target(context);
359 TypeConverter typeConverter;
360 RewritePatternSet
patterns(&context);
365 if (failed(applyFullConversion(module, target, std::move(
patterns))))
assert(baseType &&"element must be base type")
static void populateLegality(ConversionTarget &target)
static void populateOpConversion(RewritePatternSet &patterns, TypeConverter &typeConverter)
static void populateTypeConversion(TypeConverter &converter)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
circt::hw::InOutType InOutType
Type getSignalBaseType(Type type)
Get the type wrapped by a signal or port (in, inout, out) type.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
std::unique_ptr< mlir::OperationPass< mlir::ModuleOp > > createConvertHWToSystemCPass()
Create a HW to SystemC dialects conversion pass.