Skip to content

Commit

Permalink
[SV] Introduce a new SV dialect with operations that provide access to
Browse files Browse the repository at this point in the history
if/ifdef/always @ posedge, fwrite, and macro expressions.

This is still very simple and early on, but is a reasonable starting
point to expand the capabilities for the verilog printer.
  • Loading branch information
lattner committed Aug 15, 2020
1 parent 9ab7d66 commit 485f6ce
Show file tree
Hide file tree
Showing 17 changed files with 393 additions and 3 deletions.
1 change: 1 addition & 0 deletions include/circt/Dialect/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ add_subdirectory(FIRRTL)
add_subdirectory(Handshake)
add_subdirectory(LLHD)
add_subdirectory(RTL)
add_subdirectory(SV)
add_subdirectory(StaticLogic)
5 changes: 5 additions & 0 deletions include/circt/Dialect/SV/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
add_mlir_dialect(SV sv)

set(LLVM_TARGET_DEFINITIONS SV.td)


27 changes: 27 additions & 0 deletions include/circt/Dialect/SV/Dialect.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===- SV/IR/Dialect.h - SV dialect declaration -----------------*- C++ -*-===//
//
// This file defines an SV MLIR dialect.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_SV_DIALECT_H
#define CIRCT_DIALECT_SV_DIALECT_H

#include "mlir/IR/Dialect.h"

namespace circt {
namespace sv {
using namespace mlir;

class SVDialect : public Dialect {
public:
explicit SVDialect(MLIRContext *context);
~SVDialect();

static StringRef getDialectNamespace() { return "sv"; }
};

} // namespace sv
} // namespace circt

#endif // CIRCT_DIALECT_SV_DIALECT_H
24 changes: 24 additions & 0 deletions include/circt/Dialect/SV/Expressions.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===- Expressions.td - SV expression ops ------------------*- tablegen -*-===//
//
// This describes the ops for SystemVerilog expressions.
//
//===----------------------------------------------------------------------===//

def TextualValueOp : SVOp<"textual_value", [NoSideEffect]> {
let summary = "Expression that expands to a value given SystemVerilog text";
let description = [{
This operation produces a typed value expressed by a string of
SystemVerilog. This can be used to access macros and other values that are
only sensible as Verilog text.

The text string is expected to have the highest precedence, so it should
be parenthesized if it isn't a single token.
}];

let arguments = (ins StrAttr:$string);
let results = (outs AnySignlessInteger:$result);

let assemblyFormat = [{
$string attr-dict `:` type($result)
}];
}
23 changes: 23 additions & 0 deletions include/circt/Dialect/SV/Ops.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===- SV/Ops.h - Declare SV dialect operations -----------------*- C++ -*-===//
//
// This file declares the operation classes for the SV dialect.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_SV_OPS_H
#define CIRCT_DIALECT_SV_OPS_H

#include "circt/Dialect/SV/Dialect.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/Interfaces/SideEffectInterfaces.h"

namespace circt {
namespace sv {

#define GET_OP_CLASSES
#include "circt/Dialect/SV/SV.h.inc"

} // namespace sv
} // namespace circt

#endif // CIRCT_DIALECT_SV_OPS_H
32 changes: 32 additions & 0 deletions include/circt/Dialect/SV/SV.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//===- SV.td - SystemVerilog dialect definition ------------*- tablegen -*-===//
//
// This is the top level file for the SV dialect.
//
//===----------------------------------------------------------------------===//

#ifndef SV_TD
#define SV_TD

include "mlir/IR/OpBase.td"
include "mlir/Interfaces/SideEffectInterfaces.td"

def SVDialect : Dialect {
let name = "sv";

let summary = "Types and operations for SV dialect";
let description = [{
This dialect defines the `sv` dialect, which represents various
SystemVerilog-specific constructs in an AST-like representation.
}];

let cppNamespace = "sv";
}

// Base class for the operation in this dialect.
class SVOp<string mnemonic, list<OpTrait> traits = []> :
Op<SVDialect, mnemonic, traits>;

include "Expressions.td"
include "Statements.td"

#endif // SV_TD
84 changes: 84 additions & 0 deletions include/circt/Dialect/SV/Statements.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//===- Statements.td - SV statements ops -------------------*- tablegen -*-===//
//
// This describes the ops for System Verilog statements.
//
//===----------------------------------------------------------------------===//

class HasCustomParserPrinter {
code printer = [{ return ::print$cppClass(p, *this); }];
code parser = [{ return ::parse$cppClass(parser, result); }];
}

def HasRegionTerminator : SingleBlockImplicitTerminator<"YieldOp">;

//===----------------------------------------------------------------------===//
// Control flow like-operations
//===----------------------------------------------------------------------===//

def IfDefOp : SVOp<"ifdef", [HasRegionTerminator]>, HasCustomParserPrinter {
let summary = "'ifdef MACRO' block";

let description = [{
This operation is an #ifdef block, or an #ifndef block if `string` starts
with a `!` character.
}];

let regions = (region SizedRegion<1>:$body);
let arguments = (ins StrAttr:$cond);
let results = (outs);

// TODO: ODS doesn't support parsing/printing regions yet :-(
// let assemblyFormat = [{ $clock attr-dict $body }];*/
}

def IfOp : SVOp<"if", [HasRegionTerminator]>,
HasCustomParserPrinter {
let summary = "'if (cond)' block";

let regions = (region SizedRegion<1>:$body);
let arguments = (ins I1:$cond);
let results = (outs);

// TODO: ODS doesn't support parsing/printing regions yet :-(
//let assemblyFormat = [{ $cond attr-dict $body }];
}

// TODO: This should be generalized, e.g. with an enum to specify the edge
// trigger behavior.
def AlwaysAtPosEdgeOp : SVOp<"alwaysat_posedge", [HasRegionTerminator]>,
HasCustomParserPrinter {
let summary = "'always @(posedge ...)'' block";

let regions = (region SizedRegion<1>:$body);
let arguments = (ins I1:$clock);
let results = (outs);

// TODO: ODS doesn't support parsing/printing regions yet :-(
//let assemblyFormat = [{ $clock attr-dict $body }];
}

//===----------------------------------------------------------------------===//
// Other Statements
//===----------------------------------------------------------------------===//

def YieldOp
: SVOp<"yield", [NoSideEffect, Terminator,
ParentOneOf<["IfDefOp, IfOp", "AlwaysAtPosEdgeOp"]>]> {
let summary = "terminator for control-flow operation regions";
let arguments = (ins);

let assemblyFormat = [{attr-dict}];
}

// TODO: This needs to model the file descriptor to write on as well as the
// arguments.
def FWriteOp : SVOp<"fwrite", []> {
let summary = "'$fwrite' statement";

let arguments = (ins StrAttr:$string);
let results = (outs);

let assemblyFormat = [{
$string attr-dict
}];
}
1 change: 1 addition & 0 deletions lib/Dialect/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ add_subdirectory(FIRRTL)
add_subdirectory(Handshake)
add_subdirectory(LLHD)
add_subdirectory(RTL)
add_subdirectory(SV)
add_subdirectory(StaticLogic)
17 changes: 17 additions & 0 deletions lib/Dialect/SV/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
file(GLOB globbed *.cpp)
add_mlir_dialect_library(MLIRSV
${globbed}

ADDITIONAL_HEADER_DIRS
${CIRCT_MAIN_INCLUDE_DIR}/circt/Dialect/SV

DEPENDS
MLIRSVIncGen

LINK_COMPONENTS
Support

LINK_LIBS PUBLIC
)

add_dependencies(mlir-headers MLIRSVIncGen)
25 changes: 25 additions & 0 deletions lib/Dialect/SV/Dialect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===- Dialect.cpp - Implement the SV dialect -----------------------------===//
//
//===----------------------------------------------------------------------===//

#include "circt/Dialect/SV/Dialect.h"
#include "circt/Dialect/SV/Ops.h"

using namespace circt;
using namespace sv;

//===----------------------------------------------------------------------===//
// Dialect specification.
//===----------------------------------------------------------------------===//

SVDialect::SVDialect(MLIRContext *context)
: Dialect(getDialectNamespace(), context) {

// Register operations.
addOperations<
#define GET_OP_LIST
#include "circt/Dialect/SV/SV.cpp.inc"
>();
}

SVDialect::~SVDialect() {}
98 changes: 98 additions & 0 deletions lib/Dialect/SV/Ops.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
//===- Ops.cpp - Implement the SV operations ------------------------------===//
//
//===----------------------------------------------------------------------===//

#include "circt/Dialect/SV/Ops.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/StandardTypes.h"

using namespace circt;
using namespace sv;

//===----------------------------------------------------------------------===//
// Control flow like-operations
//===----------------------------------------------------------------------===//

//===----------------------------------------------------------------------===//
// IfDefOp

static ParseResult parseIfDefOp(OpAsmParser &parser, OperationState &result) {
StringAttr cond;
Region *body = result.addRegion();
if (parser.parseAttribute(cond, "cond", result.attributes) ||
parser.parseRegion(*body, llvm::None, llvm::None) ||
parser.parseOptionalAttrDict(result.attributes))
return failure();

IfDefOp::ensureTerminator(*body, parser.getBuilder(), result.location);
return success();
}

static void printIfDefOp(OpAsmPrinter &p, IfDefOp op) {
p << op.getOperationName() << ' ';
p.printAttribute(op.condAttr());
p.printRegion(op.body(),
/*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/false);
p.printOptionalAttrDict(op.getAttrs(), {"cond"});
}

//===----------------------------------------------------------------------===//
// IfOp

static ParseResult parseIfOp(OpAsmParser &parser, OperationState &result) {
OpAsmParser::OperandType cond;
Region *body = result.addRegion();
if (parser.parseOperand(cond) ||
parser.resolveOperand(cond, parser.getBuilder().getI1Type(),
result.operands) ||
parser.parseRegion(*body, llvm::None, llvm::None) ||
parser.parseOptionalAttrDict(result.attributes))
return failure();

IfOp::ensureTerminator(*body, parser.getBuilder(), result.location);
return success();
}

static void printIfOp(OpAsmPrinter &p, IfOp op) {
p << op.getOperationName() << ' ' << op.cond();
p.printRegion(op.body(),
/*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/false);
p.printOptionalAttrDict(op.getAttrs());
}

//===----------------------------------------------------------------------===//
// AlwaysAtPosEdgeOp

static ParseResult parseAlwaysAtPosEdgeOp(OpAsmParser &parser,
OperationState &result) {
OpAsmParser::OperandType clock;
Region *body = result.addRegion();
if (parser.parseOperand(clock) ||
parser.resolveOperand(clock, parser.getBuilder().getI1Type(),
result.operands) ||
parser.parseRegion(*body, llvm::None, llvm::None) ||
parser.parseOptionalAttrDict(result.attributes))
return failure();

AlwaysAtPosEdgeOp::ensureTerminator(*body, parser.getBuilder(),
result.location);
return success();
}

static void printAlwaysAtPosEdgeOp(OpAsmPrinter &p, AlwaysAtPosEdgeOp op) {
p << op.getOperationName() << ' ' << op.clock();
p.printRegion(op.body(),
/*printEntryBlockArgs=*/false,
/*printBlockTerminators=*/false);
p.printOptionalAttrDict(op.getAttrs());
}

//===----------------------------------------------------------------------===//
// TableGen generated logic.
//===----------------------------------------------------------------------===//

// Provide the autogenerated implementation guts for the Op classes.
#define GET_OP_CLASSES
#include "circt/Dialect/SV/SV.cpp.inc"
1 change: 1 addition & 0 deletions lib/EmitVerilog/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ add_mlir_library(CIRCTEmitVerilog
LINK_LIBS PUBLIC
MLIRFIRRTL
MLIRRTL
MLIRSV
)
Loading

0 comments on commit 485f6ce

Please sign in to comment.