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(rewriter).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");
177 auto ctor = scModule.getOrCreateCtor(rewriter);
178 OpBuilder::InsertPoint stateInsertPt(ctor->getBlock(),
179 Block::iterator(ctor.getOperation()));
180 OpBuilder::InsertPoint initInsertPt(ctor.getBodyBlock(),
181 ctor.getBodyBlock()->end());
185 SmallVector<systemc::ModuleType::PortInfo> portInfo;
186 if (failed(collectPortInfo<InputType>(adaptor.getInputs(),
187 adaptor.getArgNames(), portInfo)) ||
188 failed(collectPortInfo<OutputType>(instanceOp->getResults(),
189 adaptor.getResultNames(), portInfo)))
190 return instanceOp->emitOpError(
"inout ports not supported");
192 Location loc = instanceOp->getLoc();
193 auto instanceName = instanceOp.getInstanceNameAttr();
194 auto instModuleName = instanceOp.getModuleNameAttr();
197 rewriter.restoreInsertionPoint(stateInsertPt);
198 auto instDecl = InstanceDeclOp::create(rewriter, loc, instanceName,
199 instModuleName, portInfo);
202 for (
size_t i = 0, numInputs = adaptor.getInputs().size(); i < numInputs;
204 Value input = adaptor.getInputs()[i];
205 auto portId = rewriter.getIndexAttr(i);
206 StringAttr signalName = rewriter.getStringAttr(
207 instanceName.getValue() +
"_" + portInfo[i].name.getValue());
209 if (
auto readOp = input.getDefiningOp<SignalReadOp>()) {
212 rewriter.restoreInsertionPoint(initInsertPt);
213 BindPortOp::create(rewriter, loc, instDecl, portId, readOp.getInput());
219 rewriter.restoreInsertionPoint(stateInsertPt);
220 Value channel = SignalOp::create(rewriter, loc, sigType, signalName);
221 rewriter.restoreInsertionPoint(initInsertPt);
222 BindPortOp::create(rewriter, loc, instDecl, portId, channel);
223 rewriter.setInsertionPoint(instanceOp);
224 SignalWriteOp::create(rewriter, loc, channel, input);
228 for (
size_t i = 0, numOutputs = instanceOp->getNumResults(); i < numOutputs;
230 size_t numInputs = adaptor.getInputs().size();
231 Value output = instanceOp->getResult(i);
232 auto portId = rewriter.getIndexAttr(i + numInputs);
233 StringAttr signalName =
234 rewriter.getStringAttr(instanceName.getValue() +
"_" +
235 portInfo[i + numInputs].name.getValue());
237 if (output.hasOneUse()) {
238 if (
auto writeOp = dyn_cast<SignalWriteOp>(*output.user_begin())) {
245 rewriter.restoreInsertionPoint(initInsertPt);
246 BindPortOp::create(rewriter, loc, instDecl, portId,
256 rewriter.restoreInsertionPoint(stateInsertPt);
257 Value channel = SignalOp::create(rewriter, loc, sigType, signalName);
258 rewriter.restoreInsertionPoint(initInsertPt);
259 BindPortOp::create(rewriter, loc, instDecl, portId, channel);
260 rewriter.setInsertionPoint(instanceOp);
261 auto instOut = SignalReadOp::create(rewriter, loc, channel);
262 output.replaceAllUsesWith(instOut);
265 rewriter.eraseOp(instanceOp);
277 target.addIllegalDialect<HWDialect>();
278 target.addLegalDialect<mlir::BuiltinDialect>();
279 target.addLegalDialect<systemc::SystemCDialect>();
280 target.addLegalDialect<comb::CombDialect>();
281 target.addLegalDialect<emitc::EmitCDialect>();
286 TypeConverter &typeConverter) {
287 patterns.add<ConvertHWModule, ConvertInstance>(typeConverter,
292 converter.addConversion([](Type type) {
return type; });
293 converter.addConversion([&](SignalType type) {
294 return SignalType::get(converter.convertType(type.getBaseType()));
296 converter.addConversion([&](InputType type) {
297 return InputType::get(converter.convertType(type.getBaseType()));
299 converter.addConversion([&](systemc::InOutType type) {
300 return systemc::InOutType::get(converter.convertType(type.getBaseType()));
302 converter.addConversion([&](OutputType type) {
303 return OutputType::get(converter.convertType(type.getBaseType()));
305 converter.addConversion([](IntegerType type) -> Type {
306 auto bw = type.getIntOrFloatBitWidth();
314 return UIntType::get(type.getContext(), bw);
327 converter.addSourceMaterialization(
328 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
329 assert(values.size() == 1);
330 auto op = ConvertOp::create(builder, loc, type, values[0]);
331 return op.getResult();
334 converter.addTargetMaterialization(
335 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
336 assert(values.size() == 1);
337 auto op = ConvertOp::create(builder, loc, type, values[0]);
338 return op.getResult();
347struct HWToSystemCPass
348 :
public circt::impl::ConvertHWToSystemCBase<HWToSystemCPass> {
349 void runOnOperation()
override;
355 return std::make_unique<HWToSystemCPass>();
359void HWToSystemCPass::runOnOperation() {
360 MLIRContext &
context = getContext();
361 ModuleOp
module = getOperation();
365 OpBuilder builder(module.getRegion());
366 emitc::IncludeOp::create(builder, module->getLoc(),
"systemc.h",
true);
368 ConversionTarget target(
context);
369 TypeConverter typeConverter;
375 if (failed(applyFullConversion(module, target, std::move(
patterns))))
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
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.