14 #include "../PassDetail.h"
18 #include "mlir/Dialect/EmitC/IR/EmitC.h"
19 #include "mlir/IR/BuiltinDialect.h"
20 #include "mlir/Transforms/DialectConversion.h"
21 #include "llvm/ADT/TypeSwitch.h"
24 using namespace circt;
26 using namespace systemc;
39 using OpConversionPattern::OpConversionPattern;
42 matchAndRewrite(HWModuleOp module, OpAdaptor adaptor,
43 ConversionPatternRewriter &rewriter)
const override {
45 if (!module.getParameters().empty())
46 return emitError(module->getLoc(),
"module parameters not supported yet");
48 auto ports = module.getPortList();
49 if (llvm::any_of(ports, [](
auto &port) {
return port.isInOut(); }))
50 return emitError(module->getLoc(),
"inout arguments not supported yet");
53 for (
size_t i = 0; i < ports.size(); ++i)
54 ports.at(i).type = typeConverter->convertType(ports.at(i).type);
56 auto scModule = rewriter.create<SCModuleOp>(module.getLoc(),
57 module.getNameAttr(), ports);
58 auto *outputOp = module.getBodyBlock()->getTerminator();
59 scModule.setVisibility(module.getVisibility());
61 auto portAttrs = module.getAllPortAttrs();
62 scModule.setAllArgAttrs(portAttrs);
66 rewriter.setInsertionPointToStart(scModule.getBodyBlock());
67 auto scFunc = rewriter.create<SCFuncOp>(
68 module.getLoc(), rewriter.getStringAttr(
"innerLogic"));
74 scFunc.getBodyBlock()->erase();
75 Region &scFuncBody = scFunc.getBody();
76 rewriter.inlineRegionBefore(module.getBody(), scFuncBody, scFuncBody.end());
79 rewriter.setInsertionPointToStart(
80 scModule.getOrCreateCtor().getBodyBlock());
81 rewriter.create<MethodOp>(scModule.getLoc(), scFunc.getHandle());
84 SmallVector<Value> sensitivityValues(
85 llvm::make_filter_range(scModule.getArguments(), [](BlockArgument arg) {
86 return !arg.getType().isa<OutputType>();
88 if (!sensitivityValues.empty())
89 rewriter.create<SensitiveOp>(scModule.getLoc(), sensitivityValues);
93 rewriter.setInsertionPointToStart(scFunc.getBodyBlock());
94 auto portsLocal = module.getPortList();
95 for (
size_t i = 0, e = scFunc.getRegion().getNumArguments(); i < e; ++i) {
98 .create<SignalReadOp>(scFunc.getLoc(), scModule.getArgument(i))
100 auto converted = typeConverter->materializeSourceConversion(
101 rewriter, scModule.getLoc(), portsLocal.at(i).type, inputRead);
102 scFuncBody.getArgument(0).replaceAllUsesWith(converted);
103 scFuncBody.eraseArgument(0);
107 rewriter.eraseOp(module);
109 SmallVector<Value> outPorts;
110 for (
auto val : scModule.getArguments()) {
111 if (val.getType().isa<OutputType>())
112 outPorts.push_back(val);
115 rewriter.setInsertionPoint(outputOp);
116 for (
auto args : llvm::zip(outPorts, outputOp->getOperands())) {
117 Value portValue = std::get<0>(args);
118 auto converted = typeConverter->materializeTargetConversion(
121 rewriter.create<SignalWriteOp>(outputOp->getLoc(), portValue, converted);
125 outputOp->dropAllReferences();
126 rewriter.eraseOp(outputOp);
137 using OpConversionPattern::OpConversionPattern;
140 template <
typename PortTy>
142 collectPortInfo(ValueRange ports, ArrayAttr portNames,
143 SmallVector<systemc::ModuleType::PortInfo> &portInfo)
const {
144 for (
auto inPort : llvm::zip(ports, portNames)) {
145 Type ty = std::get<0>(inPort).getType();
146 systemc::ModuleType::PortInfo info;
151 info.type = typeConverter->convertType(
PortTy::get(ty));
152 info.name = std::get<1>(inPort).cast<StringAttr>();
153 portInfo.push_back(info);
161 matchAndRewrite(InstanceOp instanceOp, OpAdaptor adaptor,
162 ConversionPatternRewriter &rewriter)
const override {
165 auto scModule = instanceOp->getParentOfType<SCModuleOp>();
167 return rewriter.notifyMatchFailure(instanceOp,
168 "parent was not an SCModuleOp");
171 auto ctor = scModule.getOrCreateCtor();
172 OpBuilder stateBuilder(ctor);
173 OpBuilder initBuilder = OpBuilder::atBlockEnd(ctor.getBodyBlock());
177 SmallVector<systemc::ModuleType::PortInfo> portInfo;
178 if (failed(collectPortInfo<InputType>(adaptor.getInputs(),
179 adaptor.getArgNames(), portInfo)) ||
180 failed(collectPortInfo<OutputType>(instanceOp->getResults(),
181 adaptor.getResultNames(), portInfo)))
182 return instanceOp->emitOpError(
"inout ports not supported");
184 Location loc = instanceOp->getLoc();
185 auto instanceName = instanceOp.getInstanceNameAttr();
186 auto instModuleName = instanceOp.getModuleNameAttr();
189 auto instDecl = stateBuilder.create<InstanceDeclOp>(
190 loc, instanceName, instModuleName, portInfo);
193 for (
size_t i = 0, numInputs = adaptor.getInputs().size(); i < numInputs;
195 Value input = adaptor.getInputs()[i];
196 auto portId = rewriter.getIndexAttr(i);
197 StringAttr signalName = rewriter.getStringAttr(
198 instanceName.getValue() +
"_" + portInfo[i].name.getValue());
200 if (
auto readOp = input.getDefiningOp<SignalReadOp>()) {
203 initBuilder.create<BindPortOp>(loc, instDecl, portId,
210 Value channel = stateBuilder.create<SignalOp>(loc, sigType, signalName);
211 initBuilder.create<BindPortOp>(loc, instDecl, portId, channel);
212 rewriter.create<SignalWriteOp>(loc, channel, input);
216 for (
size_t i = 0, numOutputs = instanceOp->getNumResults(); i < numOutputs;
218 size_t numInputs = adaptor.getInputs().size();
219 Value output = instanceOp->getResult(i);
220 auto portId = rewriter.getIndexAttr(i + numInputs);
221 StringAttr signalName =
222 rewriter.getStringAttr(instanceName.getValue() +
"_" +
223 portInfo[i + numInputs].name.getValue());
225 if (output.hasOneUse()) {
226 if (
auto writeOp = dyn_cast<SignalWriteOp>(*output.user_begin())) {
233 initBuilder.create<BindPortOp>(loc, instDecl, portId,
243 Value channel = stateBuilder.create<SignalOp>(loc, sigType, signalName);
244 initBuilder.create<BindPortOp>(loc, instDecl, portId, channel);
245 auto instOut = rewriter.create<SignalReadOp>(loc, channel);
246 output.replaceAllUsesWith(instOut);
249 rewriter.eraseOp(instanceOp);
261 target.addIllegalDialect<HWDialect>();
262 target.addLegalDialect<mlir::BuiltinDialect>();
263 target.addLegalDialect<systemc::SystemCDialect>();
264 target.addLegalDialect<comb::CombDialect>();
265 target.addLegalDialect<emitc::EmitCDialect>();
266 target.addLegalOp<hw::ConstantOp>();
270 TypeConverter &typeConverter) {
271 patterns.add<ConvertHWModule, ConvertInstance>(typeConverter,
276 converter.addConversion([](Type type) {
return type; });
277 converter.addConversion([&](SignalType type) {
280 converter.addConversion([&](InputType type) {
286 converter.addConversion([&](OutputType type) {
289 converter.addConversion([](IntegerType type) -> Type {
290 auto bw = type.getIntOrFloatBitWidth();
311 converter.addSourceMaterialization(
312 [](OpBuilder &
builder, Type type, ValueRange values, Location loc) {
313 assert(values.size() == 1);
314 auto op =
builder.create<ConvertOp>(loc, type, values[0]);
315 return op.getResult();
318 converter.addTargetMaterialization(
319 [](OpBuilder &
builder, Type type, ValueRange values, Location loc) {
320 assert(values.size() == 1);
321 auto op =
builder.create<ConvertOp>(loc, type, values[0]);
322 return op.getResult();
331 struct HWToSystemCPass :
public ConvertHWToSystemCBase<HWToSystemCPass> {
332 void runOnOperation()
override;
338 return std::make_unique<HWToSystemCPass>();
342 void HWToSystemCPass::runOnOperation() {
343 MLIRContext &context = getContext();
344 ModuleOp module = getOperation();
348 OpBuilder
builder(module.getRegion());
349 builder.create<emitc::IncludeOp>(module->getLoc(),
"systemc.h",
true);
351 ConversionTarget target(context);
352 TypeConverter typeConverter;
353 RewritePatternSet
patterns(&context);
358 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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
std::unique_ptr< mlir::OperationPass< mlir::ModuleOp > > createConvertHWToSystemCPass()
Create a HW to SystemC dialects conversion pass.