[SV] Add basic Visitor and EmitVerilog support for InterfaceOps. (#298)

This commit is contained in:
mikeurbach 2020-12-03 15:32:49 -07:00 committed by GitHub
parent 3eef7df131
commit 38150d7706
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 0 deletions

View File

@ -40,6 +40,10 @@ def InterfaceOp : SVOp<"interface",
let assemblyFormat = [{
attr-dict $sym_name $body
}];
let extraClassDeclaration = [{
Block *getBodyBlock() { return &body().front(); }
}];
}
// For now, IntegerType is a placeholder for future SV dialect types

View File

@ -25,6 +25,8 @@ public:
IfDefOp, IfOp, AlwaysAtPosEdgeOp,
// Other Statements.
YieldOp, FWriteOp, FatalOp, FinishOp,
// Type declarations.
InterfaceOp, InterfaceSignalOp, InterfaceModportOp,
// Verification statements.
AssertOp, AssumeOp, CoverOp>(
[&](auto expr) -> ResultType {
@ -66,6 +68,11 @@ public:
HANDLE(FatalOp, Unhandled);
HANDLE(FinishOp, Unhandled);
// Type declarations.
HANDLE(InterfaceOp, Unhandled);
HANDLE(InterfaceSignalOp, Unhandled);
HANDLE(InterfaceModportOp, Unhandled);
// Verification statements.
HANDLE(AssertOp, Unhandled);
HANDLE(AssumeOp, Unhandled);

View File

@ -15,6 +15,7 @@
#include "mlir/IR/Module.h"
#include "mlir/IR/StandardTypes.h"
#include "mlir/Translation.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/Support/raw_ostream.h"
@ -318,6 +319,9 @@ public:
void emitDecl(RegOp op);
void emitDecl(MemOp op);
void emitDecl(RegInitOp op);
void emitDecl(sv::InterfaceOp op);
void emitDecl(sv::InterfaceSignalOp op);
void emitDecl(sv::InterfaceModportOp op);
void emitOperation(Operation *op);
void collectNamesEmitDecls(Block &block);
@ -1950,6 +1954,40 @@ void ModuleEmitter::emitDecl(MemOp op) {
}
}
void ModuleEmitter::emitDecl(sv::InterfaceOp op) {
os << "interface " << op.sym_name() << ";\n";
addIndent();
for (auto &op : op.getBodyBlock()->without_terminator())
emitOperation(&op);
reduceIndent();
os << "endinterface\n\n";
}
void ModuleEmitter::emitDecl(sv::InterfaceSignalOp op) {
indent() << "logic ";
auto type = op.type();
if (getBitWidthOrSentinel(type) != 1) {
emitTypePaddedToWidth(type, 0, op);
os << ' ';
}
os << op.sym_name() << ";\n";
}
void ModuleEmitter::emitDecl(sv::InterfaceModportOp op) {
indent() << "modport " << op.sym_name() << '(';
llvm::interleaveComma(op.ports(), os, [&](const Attribute &portAttr) {
auto port = portAttr.cast<sv::ModportStructAttr>();
os << port.direction().getValue() << ' ' << port.signal().getValue();
});
os << ");\n";
}
//===----------------------------------------------------------------------===//
// Module Driver
//===----------------------------------------------------------------------===//
@ -2290,6 +2328,12 @@ void ModuleEmitter::emitOperation(Operation *op) {
bool visitSV(sv::AssertOp op) { return emitter.emitStatement(op), true; }
bool visitSV(sv::AssumeOp op) { return emitter.emitStatement(op), true; }
bool visitSV(sv::CoverOp op) { return emitter.emitStatement(op), true; }
bool visitSV(sv::InterfaceSignalOp op) {
return emitter.emitDecl(op), true;
}
bool visitSV(sv::InterfaceModportOp op) {
return emitter.emitDecl(op), true;
}
bool visitUnhandledSV(Operation *op) { return false; }
bool visitInvalidSV(Operation *op) { return false; }
@ -2771,6 +2815,9 @@ void CircuitEmitter::emitCircuit(CircuitOp circuit) {
} else if (auto module = dyn_cast<rtl::RTLExternModuleOp>(op)) {
ModuleEmitter(state).emitRTLExternModule(module);
continue;
} else if (auto interface = dyn_cast<sv::InterfaceOp>(op)) {
ModuleEmitter(state).emitDecl(interface);
continue;
}
// Ignore the done terminator at the end of the circuit.
@ -2790,6 +2837,8 @@ void CircuitEmitter::emitMLIRModule(ModuleOp module) {
ModuleEmitter(state).emitRTLModule(module);
else if (auto module = dyn_cast<rtl::RTLExternModuleOp>(op))
ModuleEmitter(state).emitRTLExternModule(module);
else if (auto interface = dyn_cast<sv::InterfaceOp>(op))
ModuleEmitter(state).emitDecl(interface);
else if (!isa<ModuleTerminatorOp>(op))
op.emitError("unknown operation");
}

View File

@ -1,6 +1,34 @@
// RUN: circt-translate %s -emit-verilog -verify-diagnostics | FileCheck %s --strict-whitespace
// CHECK-LABEL: interface myinterface;
// CHECK: logic [31:0] data;
// CHECK: modport input_port(input data);
// CHECK: modport output_port(output data);
// CHECK: endinterface
// CHECK-EMPTY:
sv.interface @myinterface {
sv.interface.signal @data : i32
sv.interface.modport @input_port ("input" @data)
sv.interface.modport @output_port ("output" @data)
}
firrtl.circuit "M1" {
// CHECK-LABEL: interface handshake_example;
// CHECK: logic [31:0] data;
// CHECK: logic valid;
// CHECK: logic ready;
// CHECK: modport dataflow_in(input data, input valid, output ready);
// CHECK: modport dataflow_out(output data, output valid, input ready);
// CHECK: endinterface
// CHECK-EMPTY:
sv.interface @handshake_example {
sv.interface.signal @data : i32
sv.interface.signal @valid : i1
sv.interface.signal @ready : i1
sv.interface.modport @dataflow_in ("input" @data, "input" @valid, "output" @ready)
sv.interface.modport @dataflow_out ("output" @data, "output" @valid, "input" @ready)
}
// CHECK-LABEL: module M1(
firrtl.module @M1(%clock : i1, %cond : i1, %val : i8) {