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"
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) {
57 return emitError(module->getLoc(),
"inout arguments not supported yet");
60 for (
size_t i = 0; i < ports.size(); ++i)
61 ports[i].type = typeConverter->convertType(ports[i].type);
63 auto scModule = SCModuleOp::create(rewriter, module.getLoc(),
64 module.getNameAttr(), ports);
65 auto *outputOp =
module.getBodyBlock()->getTerminator();
66 scModule.setVisibility(module.getVisibility());
68 auto portAttrs =
module.getAllPortAttrs();
69 if (!portAttrs.empty())
70 scModule.setAllArgAttrs(portAttrs);
74 rewriter.setInsertionPointToStart(scModule.getBodyBlock());
75 auto scFunc = SCFuncOp::create(rewriter, module.getLoc(),
76 rewriter.getStringAttr(
"innerLogic"));
82 scFunc.getBodyBlock()->erase();
83 Region &scFuncBody = scFunc.getBody();
84 rewriter.inlineRegionBefore(module.getBody(), scFuncBody, scFuncBody.end());
87 rewriter.setInsertionPointToStart(
88 scModule.getOrCreateCtor(rewriter).getBodyBlock());
89 MethodOp::create(rewriter, scModule.getLoc(), scFunc.getHandle());
92 SmallVector<Value> sensitivityValues(
93 llvm::make_filter_range(scModule.getArguments(), [](BlockArgument arg) {
94 return !isa<OutputType>(arg.getType());
96 if (!sensitivityValues.empty())
97 SensitiveOp::create(rewriter, scModule.getLoc(), sensitivityValues);
101 rewriter.setInsertionPointToStart(scFunc.getBodyBlock());
102 auto portsLocal =
module.getPortList();
103 for (
size_t i = 0, e = scFunc.getRegion().getNumArguments(); i < e; ++i) {
104 auto inputRead = SignalReadOp::create(rewriter, scFunc.getLoc(),
105 scModule.getArgument(i))
107 auto converted = typeConverter->materializeSourceConversion(
108 rewriter, scModule.getLoc(), portsLocal[i].type, inputRead);
109 scFuncBody.getArgument(0).replaceAllUsesWith(converted);
110 scFuncBody.eraseArgument(0);
114 rewriter.eraseOp(module);
116 SmallVector<Value> outPorts;
117 for (
auto val : scModule.getArguments()) {
118 if (isa<OutputType>(val.getType()))
119 outPorts.push_back(val);
122 rewriter.setInsertionPoint(outputOp);
123 for (
auto args : llvm::zip(outPorts, outputOp->getOperands())) {
124 Value portValue = std::get<0>(args);
125 auto converted = typeConverter->materializeTargetConversion(
128 SignalWriteOp::create(rewriter, outputOp->getLoc(), portValue, converted);
132 outputOp->dropAllReferences();
133 rewriter.eraseOp(outputOp);
144 using OpConversionPattern::OpConversionPattern;
147 template <
typename PortTy>
149 collectPortInfo(ValueRange ports, ArrayAttr portNames,
150 SmallVector<systemc::ModuleType::PortInfo> &portInfo)
const {
151 for (
auto inPort : llvm::zip(ports, portNames)) {
152 Type ty = std::get<0>(inPort).getType();
153 systemc::ModuleType::PortInfo
info;
155 if (isa<hw::InOutType>(ty))
158 info.type = typeConverter->convertType(PortTy::get(ty));
159 info.name = cast<StringAttr>(std::get<1>(inPort));
160 portInfo.push_back(info);
168 matchAndRewrite(InstanceOp instanceOp, OpAdaptor adaptor,
169 ConversionPatternRewriter &rewriter)
const override {
172 auto scModule = instanceOp->getParentOfType<SCModuleOp>();
174 return rewriter.notifyMatchFailure(instanceOp,
175 "parent was not an SCModuleOp");
179 auto ctor = scModule.getOrCreateCtor(rewriter);
180 OpBuilder::InsertPoint stateInsertPt(ctor->getBlock(),
181 Block::iterator(ctor.getOperation()));
182 OpBuilder::InsertPoint initInsertPt(ctor.getBodyBlock(),
183 ctor.getBodyBlock()->end());
187 SmallVector<systemc::ModuleType::PortInfo> portInfo;
188 if (failed(collectPortInfo<InputType>(adaptor.getInputs(),
189 adaptor.getArgNames(), portInfo)) ||
190 failed(collectPortInfo<OutputType>(instanceOp->getResults(),
191 adaptor.getResultNames(), portInfo)))
192 return instanceOp->emitOpError(
"inout ports not supported");
194 Location loc = instanceOp->getLoc();
195 auto instanceName = instanceOp.getInstanceNameAttr();
196 auto instModuleName = instanceOp.getModuleNameAttr();
199 rewriter.restoreInsertionPoint(stateInsertPt);
200 auto instDecl = InstanceDeclOp::create(rewriter, loc, instanceName,
201 instModuleName, portInfo);
204 for (
size_t i = 0, numInputs = adaptor.getInputs().size(); i < numInputs;
206 Value input = adaptor.getInputs()[i];
207 auto portId = rewriter.getIndexAttr(i);
208 StringAttr signalName = rewriter.getStringAttr(
209 instanceName.getValue() +
"_" + portInfo[i].name.getValue());
211 if (
auto readOp = input.getDefiningOp<SignalReadOp>()) {
214 rewriter.restoreInsertionPoint(initInsertPt);
215 BindPortOp::create(rewriter, loc, instDecl, portId, readOp.getInput());
221 rewriter.restoreInsertionPoint(stateInsertPt);
222 Value channel = SignalOp::create(rewriter, loc, sigType, signalName);
223 rewriter.restoreInsertionPoint(initInsertPt);
224 BindPortOp::create(rewriter, loc, instDecl, portId, channel);
225 rewriter.setInsertionPoint(instanceOp);
226 SignalWriteOp::create(rewriter, loc, channel, input);
230 for (
size_t i = 0, numOutputs = instanceOp->getNumResults(); i < numOutputs;
232 size_t numInputs = adaptor.getInputs().size();
233 Value output = instanceOp->getResult(i);
234 auto portId = rewriter.getIndexAttr(i + numInputs);
235 StringAttr signalName =
236 rewriter.getStringAttr(instanceName.getValue() +
"_" +
237 portInfo[i + numInputs].name.getValue());
239 if (output.hasOneUse()) {
240 if (
auto writeOp = dyn_cast<SignalWriteOp>(*output.user_begin())) {
247 rewriter.restoreInsertionPoint(initInsertPt);
248 BindPortOp::create(rewriter, loc, instDecl, portId,
258 rewriter.restoreInsertionPoint(stateInsertPt);
259 Value channel = SignalOp::create(rewriter, loc, sigType, signalName);
260 rewriter.restoreInsertionPoint(initInsertPt);
261 BindPortOp::create(rewriter, loc, instDecl, portId, channel);
262 rewriter.setInsertionPoint(instanceOp);
263 auto instOut = SignalReadOp::create(rewriter, loc, channel);
264 output.replaceAllUsesWith(instOut);
267 rewriter.eraseOp(instanceOp);
279 target.addIllegalDialect<HWDialect>();
280 target.addLegalDialect<mlir::BuiltinDialect>();
281 target.addLegalDialect<systemc::SystemCDialect>();
282 target.addLegalDialect<comb::CombDialect>();
283 target.addLegalDialect<emitc::EmitCDialect>();
288 TypeConverter &typeConverter) {
289 patterns.add<ConvertHWModule, ConvertInstance>(typeConverter,
294 converter.addConversion([](Type type) {
return type; });
295 converter.addConversion([&](SignalType type) {
296 return SignalType::get(converter.convertType(type.getBaseType()));
298 converter.addConversion([&](InputType type) {
299 return InputType::get(converter.convertType(type.getBaseType()));
301 converter.addConversion([&](systemc::InOutType type) {
302 return systemc::InOutType::get(converter.convertType(type.getBaseType()));
304 converter.addConversion([&](OutputType type) {
305 return OutputType::get(converter.convertType(type.getBaseType()));
307 converter.addConversion([](IntegerType type) -> Type {
308 auto bw = type.getIntOrFloatBitWidth();
329 converter.addSourceMaterialization(
330 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
331 assert(values.size() == 1);
332 auto op = ConvertOp::create(builder, loc, type, values[0]);
333 return op.getResult();
336 converter.addTargetMaterialization(
337 [](OpBuilder &builder, Type type, ValueRange values, Location loc) {
338 assert(values.size() == 1);
339 auto op = ConvertOp::create(builder, loc, type, values[0]);
340 return op.getResult();
349struct HWToSystemCPass
350 :
public circt::impl::ConvertHWToSystemCBase<HWToSystemCPass> {
351 void runOnOperation()
override;
357 return std::make_unique<HWToSystemCPass>();
361void HWToSystemCPass::runOnOperation() {
362 MLIRContext &
context = getContext();
363 ModuleOp module = getOperation();
367 OpBuilder builder(module.getRegion());
368 emitc::IncludeOp::create(builder, module->getLoc(),
"systemc.h",
true);
371 TypeConverter typeConverter;
377 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)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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)
static UIntType 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.