mirror of https://github.com/llvm/circt.git
[ImportVerilog] Add option to lower always @* as always_comb (#8271)
Add the `--always-at-star-as-comb` option to circt-verilog and add a corresponding option to ImportVerilog. When this option is set, detect `always @*` in the Verilog AST and lower it as a `always_comb`. This is a common pattern in synthesizers and simulators, since the traiditonal `always @*` in Verilog does not accurately describe the behaviour of combinational logic. Enable this option by default, which seems to be a common behaviour among existing tools.
This commit is contained in:
parent
3f0aa622f0
commit
d02a452a23
|
@ -49,6 +49,9 @@ struct ImportVerilogOptions {
|
|||
/// Generate debug information in the form of debug dialect ops in the IR.
|
||||
bool debugInfo = false;
|
||||
|
||||
/// Interpret `always @(*)` as `always_comb`.
|
||||
bool lowerAlwaysAtStarAsComb = true;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Include paths
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
|
|
@ -505,19 +505,34 @@ struct ModuleVisitor : public BaseVisitor {
|
|||
}
|
||||
|
||||
// Handle procedures.
|
||||
LogicalResult visit(const slang::ast::ProceduralBlockSymbol &procNode) {
|
||||
auto procOp = builder.create<moore::ProcedureOp>(
|
||||
loc, convertProcedureKind(procNode.procedureKind));
|
||||
LogicalResult convertProcedure(moore::ProcedureKind kind,
|
||||
const slang::ast::Statement &body) {
|
||||
auto procOp = builder.create<moore::ProcedureOp>(loc, kind);
|
||||
OpBuilder::InsertionGuard guard(builder);
|
||||
builder.setInsertionPointToEnd(&procOp.getBody().emplaceBlock());
|
||||
Context::ValueSymbolScope scope(context.valueSymbols);
|
||||
if (failed(context.convertStatement(procNode.getBody())))
|
||||
if (failed(context.convertStatement(body)))
|
||||
return failure();
|
||||
if (builder.getBlock())
|
||||
builder.create<moore::ReturnOp>(loc);
|
||||
return success();
|
||||
}
|
||||
|
||||
LogicalResult visit(const slang::ast::ProceduralBlockSymbol &procNode) {
|
||||
// Detect `always @(*) <stmt>` and convert to `always_comb <stmt>` if
|
||||
// requested by the user.
|
||||
if (context.options.lowerAlwaysAtStarAsComb) {
|
||||
auto *stmt = procNode.getBody().as_if<slang::ast::TimedStatement>();
|
||||
if (procNode.procedureKind == slang::ast::ProceduralBlockKind::Always &&
|
||||
stmt &&
|
||||
stmt->timing.kind == slang::ast::TimingControlKind::ImplicitEvent)
|
||||
return convertProcedure(moore::ProcedureKind::AlwaysComb, stmt->stmt);
|
||||
}
|
||||
|
||||
return convertProcedure(convertProcedureKind(procNode.procedureKind),
|
||||
procNode.getBody());
|
||||
}
|
||||
|
||||
// Handle generate block.
|
||||
LogicalResult visit(const slang::ast::GenerateBlockSymbol &genNode) {
|
||||
if (!genNode.isUninstantiated) {
|
||||
|
|
|
@ -132,37 +132,6 @@ module Basic;
|
|||
bit [0:0] b1;
|
||||
bit b2 = b1;
|
||||
|
||||
// CHECK: moore.procedure initial {
|
||||
// CHECK: }
|
||||
initial;
|
||||
|
||||
// CHECK: moore.procedure final {
|
||||
// CHECK: }
|
||||
final begin end
|
||||
|
||||
// CHECK: moore.procedure always {
|
||||
// CHECK: %x = moore.variable
|
||||
// CHECK: %y = moore.variable
|
||||
// CHECK: }
|
||||
always begin
|
||||
int x;
|
||||
begin
|
||||
int y;
|
||||
end
|
||||
end
|
||||
|
||||
// CHECK: moore.procedure always_comb {
|
||||
// CHECK: }
|
||||
always_comb begin end
|
||||
|
||||
// CHECK: moore.procedure always_latch {
|
||||
// CHECK: }
|
||||
always_latch begin end
|
||||
|
||||
// CHECK: moore.procedure always_ff {
|
||||
// CHECK: }
|
||||
always_ff @* begin end
|
||||
|
||||
// CHECK: [[TMP1:%.+]] = moore.read %v2
|
||||
// CHECK: moore.assign %v1, [[TMP1]] : i32
|
||||
assign v1 = v2;
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
// RUN: circt-verilog --parse-only --always-at-star-as-comb=0 %s | FileCheck %s --check-prefixes=CHECK,CHECK-STAR
|
||||
// RUN: circt-verilog --parse-only --always-at-star-as-comb=1 %s | FileCheck %s --check-prefixes=CHECK,CHECK-COMB
|
||||
// REQUIRES: slang
|
||||
|
||||
// Internal issue in Slang v3 about jump depending on uninitialised value.
|
||||
// UNSUPPORTED: valgrind
|
||||
|
||||
// CHECK-LABEL: moore.module @Foo()
|
||||
module Foo;
|
||||
// CHECK: moore.procedure initial {
|
||||
// CHECK-NEXT: func.call @foo
|
||||
// CHECK-NEXT: moore.return
|
||||
// CHECK-NEXT: }
|
||||
initial foo();
|
||||
|
||||
// CHECK: moore.procedure final {
|
||||
// CHECK-NEXT: func.call @foo
|
||||
// CHECK-NEXT: moore.return
|
||||
// CHECK-NEXT: }
|
||||
final foo();
|
||||
|
||||
// CHECK: moore.procedure always {
|
||||
// CHECK-NEXT: func.call @foo
|
||||
// CHECK-NEXT: moore.return
|
||||
// CHECK-NEXT: }
|
||||
always foo();
|
||||
|
||||
// CHECK: moore.procedure always_comb {
|
||||
// CHECK-NEXT: func.call @foo
|
||||
// CHECK-NEXT: moore.return
|
||||
// CHECK-NEXT: }
|
||||
always_comb foo();
|
||||
|
||||
// CHECK: moore.procedure always_latch {
|
||||
// CHECK-NEXT: func.call @foo
|
||||
// CHECK-NEXT: moore.return
|
||||
// CHECK-NEXT: }
|
||||
always_latch foo();
|
||||
|
||||
// CHECK: moore.procedure always_ff {
|
||||
// CHECK-NEXT: moore.wait_event {
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: func.call @foo
|
||||
// CHECK-NEXT: moore.return
|
||||
// CHECK-NEXT: }
|
||||
always_ff @* foo();
|
||||
|
||||
// CHECK-STAR: moore.procedure always {
|
||||
// CHECK-STAR-NEXT: moore.wait_event {
|
||||
// CHECK-STAR-NEXT: }
|
||||
// CHECK-STAR-NEXT: func.call @foo
|
||||
// CHECK-STAR-NEXT: moore.return
|
||||
// CHECK-STAR-NEXT: }
|
||||
// CHECK-COMB: moore.procedure always_comb {
|
||||
// CHECK-COMB-NEXT: func.call @foo
|
||||
// CHECK-COMB-NEXT: moore.return
|
||||
// CHECK-COMB-NEXT: }
|
||||
always @* foo();
|
||||
endmodule
|
||||
|
||||
function void foo();
|
||||
endfunction
|
|
@ -117,6 +117,11 @@ struct CLOptions {
|
|||
cl::opt<bool> debugInfo{"g", cl::desc("Generate debug information"),
|
||||
cl::cat(cat)};
|
||||
|
||||
cl::opt<bool> lowerAlwaysAtStarAsComb{
|
||||
"always-at-star-as-comb",
|
||||
cl::desc("Interpret `always @(*)` as `always_comb`"), cl::init(true),
|
||||
cl::cat(cat)};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Include paths
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -357,6 +362,7 @@ static LogicalResult executeWithSources(MLIRContext *context,
|
|||
else if (opts.loweringMode == LoweringMode::OnlyParse)
|
||||
options.mode = ImportVerilogOptions::Mode::OnlyParse;
|
||||
options.debugInfo = opts.debugInfo;
|
||||
options.lowerAlwaysAtStarAsComb = opts.lowerAlwaysAtStarAsComb;
|
||||
|
||||
options.includeDirs = opts.includeDirs;
|
||||
options.includeSystemDirs = opts.includeSystemDirs;
|
||||
|
|
Loading…
Reference in New Issue