mirror of https://github.com/llvm/circt.git
[Moore] Add evenOp to handle event controls. (#7154)
This commit is contained in:
parent
11fb804813
commit
f26f534d60
|
@ -323,6 +323,65 @@ def NonBlockingAssignOp : AssignOpBase<"nonblocking_assign"> {
|
|||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Statements
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
def None: I32EnumAttrCase<"None", 0, "none">;
|
||||
/// Transit from 0 to x/z/1, and from x/z to 1.
|
||||
def PosEdge: I32EnumAttrCase<"PosEdge", 1, "posedge">;
|
||||
/// Transit from 1 to x/z/0, and from x/z to 0.
|
||||
def NegEdge: I32EnumAttrCase<"NegEdge", 2, "negedge">;
|
||||
/// Include the negedge and posedge.
|
||||
def BothEdges: I32EnumAttrCase<"BothEdges", 3, "edge">;
|
||||
|
||||
def EdgeAtrr: I32EnumAttr<"Edge", "Edge kind",
|
||||
[None, PosEdge, NegEdge, BothEdges]>{
|
||||
let cppNamespace = "circt::moore";
|
||||
}
|
||||
|
||||
def EventOp : MooreOp<"wait_event", [
|
||||
HasParent<"ProcedureOp">
|
||||
]> {
|
||||
let summary = "Detecting posedge and negedge";
|
||||
let description = [{
|
||||
It is introduced by the symbol `@`, and it allows statement execution to
|
||||
be delayed until the occurrence of some simulation event occurring in a
|
||||
procedure executing concurrently with this procedure.
|
||||
|
||||
For the implicit event control(`@(*)`), there are two situations that are
|
||||
not automatically added to event expression:
|
||||
1. Identifiers that only appear in wait or event expressions.
|
||||
```
|
||||
always @(*) begin // equivalent to @(b)
|
||||
@(n) kid = b; // n is not added to @(*)
|
||||
end
|
||||
```
|
||||
2. Identifiers that only appear as a hierarchical_variable_identifier
|
||||
in the variable_lvalue of the left-hand side of assignments.
|
||||
```
|
||||
always @(*) begin
|
||||
a = b + c; // a is not added to @(*)
|
||||
end
|
||||
```
|
||||
|
||||
Example:
|
||||
```
|
||||
@(a, b, c) // none
|
||||
@(posedge clk) // positive edge
|
||||
@(negedge clk) // negative edge
|
||||
@(edge clk) // both edge
|
||||
@(*) // implicit event control
|
||||
```
|
||||
See IEEE 1800-2017 § 9.4.2 "Event control".
|
||||
}];
|
||||
let arguments = (ins EdgeAtrr:$edge, UnpackedType:$input);
|
||||
let results = (outs);
|
||||
let assemblyFormat = [{
|
||||
$edge $input attr-dict `:` type($input)
|
||||
}];
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Expressions
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -34,6 +34,7 @@ add_circt_translation_library(CIRCTImportVerilog
|
|||
Statements.cpp
|
||||
Structure.cpp
|
||||
Types.cpp
|
||||
TimingControls.cpp
|
||||
|
||||
DEPENDS
|
||||
slang_slang
|
||||
|
|
|
@ -79,6 +79,10 @@ struct Context {
|
|||
Value convertRvalueExpression(const slang::ast::Expression &expr);
|
||||
Value convertLvalueExpression(const slang::ast::Expression &expr);
|
||||
|
||||
// Convert a slang timing control into an MLIR timing control.
|
||||
LogicalResult
|
||||
convertTimingControl(const slang::ast::TimingControl &timingControl);
|
||||
|
||||
mlir::ModuleOp intoModuleOp;
|
||||
const slang::SourceManager &sourceManager;
|
||||
SmallDenseMap<slang::BufferID, StringRef> &bufferFilePaths;
|
||||
|
|
|
@ -302,8 +302,12 @@ struct StmtVisitor {
|
|||
return success();
|
||||
}
|
||||
|
||||
// Ignore timing control for now.
|
||||
// Handle timing control.
|
||||
LogicalResult visit(const slang::ast::TimedStatement &stmt) {
|
||||
if (failed(context.convertTimingControl(stmt.timing)))
|
||||
return failure();
|
||||
if (failed(context.convertStatement(stmt.stmt)))
|
||||
return failure();
|
||||
return success();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
//===- TimingControl.cpp - Slang timing control conversion ----------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ImportVerilogInternals.h"
|
||||
#include "slang/ast/TimingControl.h"
|
||||
using namespace circt;
|
||||
using namespace ImportVerilog;
|
||||
namespace {
|
||||
struct TimingCtrlVisitor {
|
||||
Context &context;
|
||||
Location loc;
|
||||
OpBuilder &builder;
|
||||
|
||||
TimingCtrlVisitor(Context &context, Location loc)
|
||||
: context(context), loc(loc), builder(context.builder) {}
|
||||
|
||||
LogicalResult visit(const slang::ast::SignalEventControl &ctrl) {
|
||||
// TODO: When updating slang to the latest version, we will handle
|
||||
// "iffCondition".
|
||||
auto loc = context.convertLocation(ctrl.sourceRange.start());
|
||||
auto input = context.convertRvalueExpression(ctrl.expr);
|
||||
builder.create<moore::EventOp>(loc, static_cast<moore::Edge>(ctrl.edge),
|
||||
input);
|
||||
return success();
|
||||
}
|
||||
|
||||
LogicalResult visit(const slang::ast::ImplicitEventControl &ctrl) {
|
||||
return success();
|
||||
}
|
||||
|
||||
LogicalResult visit(const slang::ast::EventListControl &ctrl) {
|
||||
for (auto *event : ctrl.as<slang::ast::EventListControl>().events) {
|
||||
if (failed(context.convertTimingControl(*event)))
|
||||
return failure();
|
||||
}
|
||||
return success();
|
||||
}
|
||||
|
||||
/// Emit an error for all other timing controls.
|
||||
template <typename T>
|
||||
LogicalResult visit(T &&node) {
|
||||
mlir::emitError(loc, "unspported timing control: ")
|
||||
<< slang::ast::toString(node.kind);
|
||||
return failure();
|
||||
}
|
||||
|
||||
LogicalResult visitInvalid(const slang::ast::TimingControl &ctrl) {
|
||||
mlir::emitError(loc, "invalid timing control");
|
||||
return failure();
|
||||
}
|
||||
};
|
||||
} // namespace
|
||||
|
||||
LogicalResult
|
||||
Context::convertTimingControl(const slang::ast::TimingControl &timingControl) {
|
||||
auto loc = convertLocation(timingControl.sourceRange.start());
|
||||
TimingCtrlVisitor visitor{*this, loc};
|
||||
return timingControl.visit(visitor);
|
||||
}
|
|
@ -1161,3 +1161,50 @@ module MultiPorts(
|
|||
// CHECK: [[C1_READ:%.+]] = moore.read %c1
|
||||
// CHECK: moore.output [[V1_READ]], [[C1_READ]]
|
||||
endmodule
|
||||
|
||||
// CHECK-LABEL: moore.module @EventControl(in %clk : !moore.l1)
|
||||
module EventControl(input clk);
|
||||
// CHECK: %clk_0 = moore.net name "clk" wire : <l1>
|
||||
|
||||
int a1, a2, b, c;
|
||||
|
||||
// CHECK: moore.procedure always
|
||||
// CHECK: [[CLK_READ:%.+]] = moore.read %clk_0 : l1
|
||||
// CHECK: moore.wait_event posedge [[CLK_READ]] : l1
|
||||
always @(posedge clk) begin end;
|
||||
|
||||
// CHECK: moore.procedure always
|
||||
// CHECK: [[CLK_READ:%.+]] = moore.read %clk_0 : l1
|
||||
// CHECK: moore.wait_event negedge [[CLK_READ]] : l1
|
||||
always @(negedge clk) begin end;
|
||||
|
||||
// CHECK: moore.procedure always
|
||||
// CHECK: [[CLK_READ:%.+]] = moore.read %clk_0 : l1
|
||||
// CHECK: moore.wait_event edge [[CLK_READ]] : l1
|
||||
always @(edge clk) begin end;
|
||||
|
||||
// CHECK: moore.procedure always {
|
||||
// CHECK: [[B_READ:%.+]] = moore.read %b : i32
|
||||
// CHECK: moore.wait_event none [[B_READ]] : i32
|
||||
// CHECK: [[C_READ:%.+]] = moore.read %c : i32
|
||||
// CHECK: moore.wait_event none [[C_READ]] : i32
|
||||
always @(b, c) begin
|
||||
// CHECK: [[B_READ:%.+]] = moore.read %b : i32
|
||||
// CHECK: [[C_READ:%.+]] = moore.read %c : i32
|
||||
// CHECK: [[ADD:%.+]] = moore.add [[B_READ]], [[C_READ]] : i32
|
||||
// CHECK: moore.blocking_assign %a1, [[ADD]] : i32
|
||||
a1 = b + c;
|
||||
end;
|
||||
|
||||
// CHECK: moore.procedure always
|
||||
always @(*) begin
|
||||
// CHECK: [[B_READ:%.+]] = moore.read %b : i32
|
||||
// CHECK: [[C_READ:%.+]] = moore.read %c : i32
|
||||
// CHECK: [[ADD:%.+]] = moore.add [[B_READ]], [[C_READ]] : i32
|
||||
// CHECK: moore.blocking_assign %a2, [[ADD]] : i32
|
||||
a2 = b + c;
|
||||
end
|
||||
|
||||
// CHECK: moore.assign %clk_0, %clk : l1
|
||||
// CHECK: moore.output
|
||||
endmodule
|
||||
|
|
Loading…
Reference in New Issue