mirror of https://github.com/llvm/circt.git
[SV] Add basic Visitor and EmitVerilog support for InterfaceOps. (#298)
This commit is contained in:
parent
3eef7df131
commit
38150d7706
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
||||
|
|
Loading…
Reference in New Issue