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"
31using 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 = SCModuleOp::create(rewriter, 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 = SCFuncOp::create(rewriter, module.getLoc(),
74 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 MethodOp::create(rewriter, 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 SensitiveOp::create(rewriter, 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) {
102 auto inputRead = SignalReadOp::create(rewriter, scFunc.getLoc(),
103 scModule.getArgument(i))
105 auto converted = typeConverter->materializeSourceConversion(
106 rewriter, scModule.getLoc(), portsLocal[i].type, inputRead);
107 scFuncBody.getArgument(0).replaceAllUsesWith(converted);
108 scFuncBody.eraseArgument(0);
112 rewriter.eraseOp(module);
114 SmallVector<Value> outPorts;
115 for (
auto val : scModule.getArguments()) {
116 if (isa<OutputType>(val.getType()))
117 outPorts.push_back(val);
120 rewriter.setInsertionPoint(outputOp);
121 for (
auto args : llvm::zip(outPorts, outputOp->getOperands())) {
122 Value portValue = std::get<0>(args);
123 auto converted = typeConverter->materializeTargetConversion(
126 SignalWriteOp::create(rewriter, outputOp->getLoc(), portValue, converted);
130 outputOp->dropAllReferences();
131 rewriter.eraseOp(outputOp);
142 using OpConversionPattern::OpConversionPattern;
145 template <
typename PortTy>
147 collectPortInfo(ValueRange ports, ArrayAttr portNames,
148 SmallVector<systemc::ModuleType::PortInfo> &portInfo)
const {
149 for (
auto inPort :
llvm::zip(ports, portNames)) {
150 Type ty = std::get<0>(inPort).getType();
151 systemc::ModuleType::PortInfo
info;
153 if (isa<hw::InOutType>(ty))
156 info.type = typeConverter->convertType(PortTy::get(ty));
157 info.name = cast<StringAttr>(std::get<1>(inPort));
158 portInfo.push_back(info);
166 matchAndRewrite(InstanceOp instanceOp, OpAdaptor adaptor,
167 ConversionPatternRewriter &rewriter)
const override {
170 auto scModule = instanceOp->getParentOfType<SCModuleOp>();
172 return rewriter.notifyMatchFailure(instanceOp,
173 "parent was not an SCModuleOp");
176 auto ctor = scModule.getOrCreateCtor();
177 OpBuilder stateBuilder(ctor);
178 OpBuilder initBuilder = OpBuilder::atBlockEnd(ctor.getBodyBlock());
182 SmallVector<systemc::ModuleType::PortInfo> portInfo;
183 if (failed(collectPortInfo<InputType>(adaptor.getInputs(),
184 adaptor.getArgNames(), portInfo)) ||
185 failed(collectPortInfo<OutputType>(instanceOp->getResults(),
186 adaptor.getResultNames(), portInfo)))
187 return instanceOp->emitOpError(
"inout ports not supported");
189 Location loc = instanceOp->getLoc();
190 auto instanceName = instanceOp.getInstanceNameAttr();
191 auto instModuleName = instanceOp.getModuleNameAttr();
194 auto instDecl = InstanceDeclOp::create(stateBuilder, loc, instanceName,
195 instModuleName, portInfo);
198 for (
size_t i = 0, numInputs = adaptor.getInputs().size(); i < numInputs;
200 Value input = adaptor.getInputs()[i];
201 auto portId = rewriter.getIndexAttr(i);
202 StringAttr signalName = rewriter.getStringAttr(
203 instanceName.getValue() +
"_" + portInfo[i].name.getValue());
205 if (
auto readOp = input.getDefiningOp<SignalReadOp>()) {
208 BindPortOp::create(initBuilder, loc, instDecl, portId,
215 Value channel = SignalOp::create(stateBuilder, loc, sigType, signalName);
216 BindPortOp::create(initBuilder, loc, instDecl, portId, channel);
217 SignalWriteOp::create(rewriter, loc, channel, input);
221 for (
size_t i = 0, numOutputs = instanceOp->getNumResults(); i < numOutputs;
223 size_t numInputs = adaptor.getInputs().size();
224 Value output = instanceOp->getResult(i);
225 auto portId = rewriter.getIndexAttr(i + numInputs);
226 StringAttr signalName =
227 rewriter.getStringAttr(instanceName.getValue() +
"_" +
228 portInfo[i + numInputs].name.getValue());
230 if (output.hasOneUse()) {
231 if (
auto writeOp = dyn_cast<SignalWriteOp>(*output.user_begin())) {
238 BindPortOp::create(initBuilder, loc, instDecl, portId,
248 Value channel = SignalOp::create(stateBuilder, loc, sigType, signalName);
249 BindPortOp::create(initBuilder, loc, instDecl, portId, channel);
250 auto instOut = SignalReadOp::create(rewriter, loc, channel);
251 output.replaceAllUsesWith(instOut);
254 rewriter.eraseOp(instanceOp);
266 target.addIllegalDialect<HWDialect>();
267 target.addLegalDialect<mlir::BuiltinDialect>();
268 target.addLegalDialect<systemc::SystemCDialect>();
269 target.addLegalDialect<comb::CombDialect>();
270 target.addLegalDialect<emitc::EmitCDialect>();
275 TypeConverter &typeConverter) {
276 patterns.add<ConvertHWModule, ConvertInstance>(typeConverter,
281 converter.addConversion([](Type type) {
return type; });
282 converter.addConversion([&](SignalType type) {
283 return SignalType::get(converter.convertType(type.getBaseType()));
285 converter.addConversion([&](InputType type) {
286 return InputType::get(converter.convertType(type.getBaseType()));
288 converter.addConversion([&](systemc::InOutType type) {
289 return systemc::InOutType::get(converter.convertType(type.getBaseType()));
291 converter.addConversion([&](OutputType type) {
292 return OutputType::get(converter.convertType(type.getBaseType()));
294 converter.addConversion([](IntegerType type) -> Type {
295 auto bw = type.getIntOrFloatBitWidth();
303 return UIntType::get(type.getContext(), bw);
316 converter.addSourceMaterialization(
317 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
318 assert(values.size() == 1);
319 auto op = ConvertOp::create(builder, loc, type, values[0]);
320 return op.getResult();
323 converter.addTargetMaterialization(
324 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
325 assert(values.size() == 1);
326 auto op = ConvertOp::create(builder, loc, type, values[0]);
327 return op.getResult();
336struct HWToSystemCPass
337 :
public circt::impl::ConvertHWToSystemCBase<HWToSystemCPass> {
338 void runOnOperation()
override;
344 return std::make_unique<HWToSystemCPass>();
348void HWToSystemCPass::runOnOperation() {
349 MLIRContext &context = getContext();
350 ModuleOp
module = getOperation();
354 OpBuilder builder(module.getRegion());
355 emitc::IncludeOp::create(builder, module->getLoc(),
"systemc.h",
true);
357 ConversionTarget target(context);
358 TypeConverter typeConverter;
359 RewritePatternSet
patterns(&context);
364 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)
static BigIntType get(MLIRContext *context, unsigned width)
static BigUIntType get(MLIRContext *context, unsigned width)
static BitVectorType get(MLIRContext *context, unsigned width)
static IntType get(MLIRContext *context, unsigned width)
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.