Commit Graph

22 Commits

Author SHA1 Message Date
Jacques Pienaar 7f1c3399e4
Update to new builder format. (#8785)
Basically did

set(CMAKE_CXX_CLANG_TIDY local/clang-tidy -checks=-*,llvm-use-new-mlir-op-builder -fix)

and then fixed cases where temporary OpBuilders were used (as passed in
by reference now).
2025-07-26 04:55:06 -07:00
Michael 9088c29f4b
[ImportVerilog] Add full_case attribute support (#8762)
This patch adds support of `(* full_case *)` attribute in case 
statements [1], which says that all possible case items have been 
covered and no default clause is needed.

[1]: http://www1.pldworld.com/@xilinx/html/technote/TOOL/MANUAL/21i_doc/data/fndtn/ver/ver7_4.htm
2025-07-22 10:46:16 -07:00
Fabian Schuiki e636298d73
[ImportVerilog] Detect and fixup two-state-exhaustive case statements (#8628)
Case statements often occur in the following form in real-world Verilog:

```
module Foo(input logic [1:0] a, output logic [3:0] z);
  always_comb begin
    case (a)
      2'd0: z = 4'b0001;
      2'd1: z = 4'b0010;
      2'd2: z = 4'b0100;
      2'd3: z = 4'b1000;
    endcase
  end
endmodule
```

The intention being that the case statement exhaustively covers all
possible `a` input values, and assigns a corresponding `z` output value.
This case statement _is_ exhaustive assuming two-state logic. However,
the Verilog `logic` type is four-state, where the bits in `a` can also
have the value X and Z. If `a` contains X or Z, none of the case
statements would execute and `z` would not be assigned, essentially
creating a latch.

In practice, logic synthesizers fold X and Z values to 0 or 1 however
they see fit, often in an attempt to minimize logic. For this case
statement the obvious assumption is that the input is two-state and the
match is exhaustive. This does not work in simulation, though.

This commit makes ImportVerilog detect if a case statement is exhaustive
assuming two-state logic. If it is, the last case item is treated as the
default, being executed regardless of its case value. As a result, the
above example generates a CFG where all possible paths through the case
statement assign the output `z`. This then ensures that the case
statement can be lowered to properly in circt-verilog, without
generating conditional drives or latches.

The core dialects of CIRCT currently don't represent X and Z well, and
most of ImportVerilog and the circt-verilog pipeline assumes all values
are two-state. Once we add X and Z handling to the core dialects, we
will have to revisit this behavior and make it opt-out.

Fixes #8626.
2025-07-01 08:52:00 -07:00
Tobias Wölfel b6b1ced097
[ImportVerilog] Add support for concurrent assertions (#8559)
Initial setup for handling SystemVerilog Assertions by adding
AssertionExpr class and integrating LTL dialect. This enables the
foundation for converting SVA expressions to LTL.

Handle concurrent assertion statements by inserting Verif operations
assert and assume operations.
Use `AssertionExpr` to parse the expression.

Add a helper function to convert values to MLIR i1 type for LTL operations.
The function validates that moore::IntType inputs are 1-bit wide and creates
a ConversionOp to handle the conversion from SystemVerilog logic types.

SystemVerilog assertions evaluate expressions to Boolean values where only
'true' results in true, with 'unknown' and 'high impedance' values both
evaluating to false.

This conversion is needed for LTL operations, which only work with i1
types.

Add support for simple assertion expressions. Simple assertions consist 
of an expression, handled by 'Expression.h', and an optional repetition.
Add conversion of the expression type to i1, which is the required input
value of LTL operations.

Add additional timing visitor to add LTL clock operation.
2025-06-19 09:54:21 -07:00
chenbo f11e9d1f47
[ImportVerilog] Add foreach statement support. (#8017)
Add for loop statement support, due to the lack of dyn array support, currently static-length array is supported.
2025-01-17 15:24:45 +08:00
Fabian Schuiki 224bc57c2c
[ImportVerilog] Add $display/$write/$info/$warning/$error/$fatal (#7642)
Add support for the `$display`, `$write`, `$info`, `$warning`, `$error`,
and `$fatal` system tasks.

These tasks are pretty complicated since they involve string formatting.
Verilog has quite a few format specifiers and very strange rules for
them. Luckily, Slang contains a handy utility that parses format strings
and delegates handling of arguments and intermittent pieces of text to
callbacks.

I've decided to follow the same IR design as the printing op
in the Sim dialect: each format specifier is turned into a dedicated op
that captures all relevant format options, plus additional literals for
the text in between interpolated values, and concatenate everything into
a single `!moore.format_string`. (Shoutout to @fzi-hielscher for
trailblazing the nice design for `sim.print`!) This is handled in a new
`FormatStrings.cpp` file inside of ImportVerilog.

The actual system tasks are mapped to new `moore.builtin.display` and
`moore.builtin.severity` ops. These handle only the printing of the
message in question, plus potential error bookkeeping. The `$fatal`
system task creates additional `moore.builtin.finish_message` and
`moore.builtin.finish` ops to represent its implicit call to `$finish`.

The implementation also handles the strange `$displayb`, `$displayo`,
`$displayh`, `$writeb`, `$writeo`, and `$writeh` flavors of the tasks,
where the suffix indicates the default format to use for arguments that
are not covered by a format string literal. SystemVerilog is weird.

Thanks @hailongSun2000 for your prior work on this!

Co-authored-by: Hailong Sun <hailong.sun@terapines.com>
2024-09-27 12:30:50 -07:00
Fabian Schuiki d42d00e6ee
[ImportVerilog] Add support for $stop/$finish/$exit (#7634)
Add support for the simulation control system tasks `$stop`, `$finish`,
and `$exit`. Also add corresponding ops to the Moore dialect that handle
the orthogonal pieces of functionality represented by these tasks.
2024-09-26 22:06:24 -07:00
Hailong Sun d5314f79fe
[Moore] Add assert, assume, and conver ops. (#7589)
These immediate assertion ops borrow from the SV dialect.
2024-09-20 10:42:30 +08:00
Fabian Schuiki d71e6e30c3
[Moore] Improve WaitEventOp, lower to LLHD (#7518)
Rework the `moore.wait_event` op to be able to accurately model the
semantics of SystemVerilog's `@...` event control statements. The op now
has a body region which is executed to detect a relevant change in one
or more interesting values. A new `moore.detect_event` op serves as the
mechanism to encode whether a posedge, negedge, both, or any change at
all on a value should be detected as an event.

Based on this new `moore.wait_event` op we can properly convert most of
the event control statements in `ImportVerilog` to a corresponding MLIR
op. Delay control like `#1ns` is not handled yet.

In the MooreToCore conversion this new op allows us to properly generate
`llhd.wait` operations at the right place that suspend process execution
until an interesting event has occurred. This now also allows us to
support almost all SystemVerilog processes in the lowering. The only
missing ones are `always_comb` and `always_latch` which require an
implicit `llhd.wait` to be inserted. @maerhart has a version of that
lowering almost ready though.

This commit also adds an `llhd.final` op in order to be able to lower
`final` procedures.

Fixes #7482.

Co-authored-by: Martin Erhart <maerhart@outlook.com>
2024-08-16 13:14:12 -07:00
Fabian Schuiki 5cc69bd6b1
[ImportVerilog] Switch from SCF to CF dialect for control flow (#7432)
Instead of using the SCF dialect and its `scf.if` and `scf.while`
operations for control flow, switch over to the CF dialect and its
`cf.br` and `cf.cond_br`. This allows us to support SystemVerilog's
`continue`, `break`, and `return` statements which don't map well to the
Structured Control Flow dialect.
2024-08-05 17:10:19 -07:00
Fabian Schuiki 0b72b19b8d
[ImportVerilog] Support for loop variables (#7393)
Add support for variables declared inside the for loop initializer,
such as `for (int x = 0; ...)`. This is pretty straightforward, since
Slang already creates corresponding variable declaration AST nodes in
the surrounding scope. The only change needed is removing an error
diagnostic.
2024-07-27 14:05:23 -07:00
Fabian Schuiki 1345859484
[ImportVerilog] Add basic function support (#7349)
Add basic support for function definitions and calls to such functions.

Input function arguments are currently passed into the function by
value, while output, inout, ref, and const ref arguments are passed by
reference at the moment. Later on we may want to be more faithful to the
SV spec and make output and inout arguments also pass by value.

Calls to void functions are slightly strange in that they don't really
have a result value, but the `convertExpression` function really wants
a valid `Value` to return. To work around this, these calls generate an
additional `!moore.void` value using `unrealized_conversion_cast`, which
gets deleted again by the statement conversion code.
2024-07-22 11:31:28 -07:00
Hailong Sun a75fd479c5
[ImportVerilog] Fix the segmentation fault caused by the case statement. (#7295)
Because the return of 'convertRvalueExpression()' can return '{}'. For example, when we handle the 'x'/'z' value, it will emit an error and return '{}', so we must estimate whether the return of 'convertRvalueExpression()' is '{}'. Otherwise, it will cause a segmentation fault.
2024-07-10 13:51:59 +08:00
Hailong Sun f26f534d60
[Moore] Add evenOp to handle event controls. (#7154) 2024-06-14 09:05:33 +08:00
Hailong Sun 69085ea0e5
[Moore] Tweak Variable and ReadLValue ops. (#7095)
[Moore] Modify the tests related to the RefType.

Add a wrapper type(moore::RefType) to work for VariableOp/NetOp, ReadOp, and AssignOpBase, and it can wrap any SystemVerilog types. We added RefType in order to introduce Mem2Reg into moore to eliminate the local temporary variables. Meanwhile, we added a new op named moore.extract_ref which is the copy of moore.extract that explicitly works on the ref type. And moore.concat_ref is the copy of moore.concat. Later, we will tweak union/struct ops like moore.struct_create in order to support the ref type.

moore.variable/moore.net will return a result with ref<T>, it's similar to memref.alloca.

Change moore::ReadLValueOp to moore::ReadOp, it's similar to memref.load. Initially, we need moore.read_lvalue only to service for assigmen operations(like +=, *=, etc). However, moore. read is not only for assignment operations but also to take a value with RefType(ref) and return the current value with the nested type(T). For example, a = b + c, moore.read will take b and c(both are ref<T>), and then return a value with the nested type(T).

We think the MooreLValueType and VariableDeclOp(52a71a6) that had been removed eventually found their proper site.

We also divide convertExpression() into convertLvalueExpression() for the LHS of assignments and convertRvalueExpression() for the RHS of assignments. The former will return a value with RefType like ref<i32>, but the latter returns a value without RefType like i32.

Co-authored-by: Fabian Schuiki <fschuiki@iis.ee.ethz.ch>
2024-06-07 11:08:17 +08:00
Fabian Schuiki dd68e3c6f4
[ImportVerilog] Fix expression errors not being propagated
Fix a subtle issue in ImportVerilog's statement converter, where a call
to `convertExpression` returning a null value would not properly be
mapped to a `failure()` result.

The original line was `success(<value>)`, which apparently still returns
success even with a null value. Changing this to `failure(!<value>)`
fixes the issue.

While at it, remove all error test cases that simply check for Slang
frontend errors. These things are already tested in Slang. ImportVerilog
should only test for the errors it generates itself.
2024-05-31 09:45:01 -07:00
Fabian Schuiki 6a2b628129
[Moore] Make simple bit vectors a proper MLIR type (#7011)
The core type most SystemVerilog expressions are interested in and
operate on is a "simple bit vector type". These are individual integer
atoms like `bit` or `logic`, integral types like `int`, or packed arrays
with a single dimension and an integer atom inner type, like
`bit [42:0]`. So in a nutshell, simple bit vector types are MLIR's `i42`
in the two-valued (`bit`) case, or the four-valued equivalent (`logic`).

Up until this point, the Moore dialect reflected this pattern by
providing and `IntType` for the integer atoms like `bit` and `int`, and
using the `PackedRangeDim` for single dimension vectors of `bit`. A
`SimpleBitVectorType` helper struct would then summarize the _actual_
bit vector that was expressed by the packed range and integer atom. This
makes working with the types in TableGen files very annoying, since the
thing you are actually interested in -- the simple bit vector -- is not
a propery MLIR type, but more like a helper struct on the side.

This commit rips out the existing `IntType` and its composition with a
packed array dimension, and replaces it with a proper simple bit vector
type that is actually an MLIR type. As a result, SystemVerilog types
like `int unsigned`, `bit [42:0]`, `reg`, `logic signed [31:0]`, or
`integer` are all translated into the same MLIR type. This new simple
bit vector MLIR type retains the `IntType` name, and prints as
`!moore.i42` or `!moore.l42`, depending on whether it is a two-valued or
four-valued integer. Single `bit` and `logic` atoms become `i1` and `l1`
respectively.

This makes the Moore type system a lot easier to work with and removes
a lot of unnecessary noise. Operations can now simply use
`llvm::isa<IntType>` to check if a value is a simple bit vector.
2024-05-09 15:52:20 -07:00
Hailong Sun 06cb84a83e
[ImportVerilog] Fix unknown name caused by local variables. (#6995) 2024-05-08 09:53:24 +08:00
angel e2b0f3230b [ImportVerilog] Add case statement. 2024-04-22 10:00:32 +08:00
Fabian Schuiki 002fe7ca6d
[ImportVerilog] Add if and loop statements (#6831)
Extend the `ImportVerilog` conversion to support `if` statements and
`for`, `repeat`, `while`, `do ... while`, and `forever` loops. Lower
them to `scf.if` and `scf.while` ops for now. In the future, since
Verilog has `break`, `continue`, and `return` statements, we may have to
switch to a different dialect or defined these ops in the Moore dialect.

Co-authored-by: Hailong Sun <hailong.sun@terapines.com>
Co-authored-by: ShiZuoye <albertethon@163.com>
Co-authored-by: hunterzju <hunter_ht@zju.edu.cn>
Co-authored-by: Anqi Yu <anqi.yu@terapines.com>
2024-03-20 09:37:22 -07:00
Fabian Schuiki 5c9fb8f3a7
[ImportVerilog] Add assignment statements (#6773)
Add continuous, blocking, and non-blocking assignments to the Moore
dialect. These represent the corresponding constructs in SystemVerilog.

Add a `ScopedHashTable` to the ImportVerilog conversion context and add
variable declarations to it. This allows expression conversion to
resolve name expressions to the MLIR value that was generated for the
corresponding declaration. The Slang AST node pointer itself is used as
a lookup key, since the AST already has all names resolved.

Add a basic expression handling mechanism to the ImportVerilog
conversion. A new `convertExpression` entry point calls an `ExprVisitor`
to convert expression nodes in the Slang AST to the corresponding MLIR
operations. This currently only supports name expressions, which simply
looks up the converted MLIR value for whatever the name was resolved to,
and blocking and non-blocking assignments.

Extend the module conversion to properly handle continuous assignments
at the module level.

Thanks @albertethon, @hailongSun2000, and @angelzzzzz for the help to
get this started.

Co-authored-by: ShiZuoye <albertethon@163.com>
Co-authored-by: Hailong Sun <hailong.sun@terapines.com>
Co-authored-by: Anqi Yu <anqi.yu@terapines.com>
2024-03-02 20:55:36 -08:00
Fabian Schuiki 0749166b43
[ImportVerilog] Convert initial/always/final procedures (#6766)
Add the `moore.procedure` operation to represent `initial`, `final`,
`always`, `always_comb`, `always_latch`, and `always_ff` procedures.
Extend the ImportVerilog conversion to map the corresponding Slang AST
nodes to these new operations.

These procedures expect a valid body statement or statement block. In
order to write basic tests, and in preparation for statement conversion
in the future, add the `Statements.cpp` file with a `StmtVisitor` that
handles the conversion of Verilog statements to MLIR ops. A new
`convertStatement` function on the conversion context acts as entry
point to convert statements, similar to `convertModule*` or
`convertType`. We only support a few basic statements as of now, mainly
stray semicolons, nested blocks, and variable declarations. This commit
explicitly does not handle variable lifetime yet, which is a topic for
a future refinement PR.

Thanks @hailongSun2000 for doing the heavy lifting here and getting this
going.

Co-authored-by: Hailong Sun <hailong.sun@terapines.com>
2024-02-29 09:10:07 -08:00