This PR extends compreg's powerOnValue operand to be able to capture more complicated initialization such as firreg's randomized initialization or DPI calls. This change should make register initialization more modular and a step forward towards https://github.com/llvm/circt/issues/7213.
While ASICs might not have explicit initial values, they are crucial for simulation
and FPGA implementation. FPGA designs often require constant initial values, while
simulation allows for more complex initialization using expressions like function calls
`$random`, `$readmem`, and `$fopen`.
seq.compreg has a (optional) powerOn operand that is lowered into inlined assignment in SV which allows users to initialize registers with user-specified values. However this representation is not sufficient for initialization with function calls.
In order to represent various kinds of initialization, `seq.initial` op and `!seq.immutable` type
are introduced. The `seq.initial` operation produces values with types wrapped in `!seq.immutable`.
The `!seq.immutable` type wrapper prevents initial values from depending on time-variant values.
Stateful operations typically require corresponding initial values with the `!seq.immutable` type.
This ensures that the initial state of the operation is well-defined and independent of time-variant factors.
Example Input:
```mlir
%r_init, %u_init = seq.initial {
%rand = sv.macro.ref.se @RANDOM() : () -> i32
%c0_i32 = hw.constant 0 : i32
seq.yield %rand, %c0_i32 : i32, i32
} : !seq.immutable<i32>, !seq.immutable<i32>
%r = seq.compreg %i, %clk initial %r_init : i32
%u = seq.compreg %i, %clk initial %u_init : i32
```
Output Verilog:
```verilog
reg [31:0] r;
initial
r = `RANDOM;
reg [31:0] u = 32'h0;
```
Align CIRCT with the finalized layer ABI [[1]]. This changes the file
name of the bind file used to enable a layer. This specifically switches
from using underscore as a delimiter to a hyphen. This avoids a problem
where a circuit that contained modules or layers whose names contained
underscores could result in multiple layer enable files that had, by the
ABI, the exact same name.
[1]: https://github.com/chipsalliance/firrtl-spec/pull/233
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This adds a pass to check for illegal instantiation of a module with
layers underneath a layer. This is a situation that leads to
bind-unde-bind when emitted to Verilog, which is illegal. This does not
differentiate between inline layers and bind layers, although
theoretically this is only a problem for bind layers. This does not
create errors on extmodules, as we have no way of knowing whether they
contain a layer or not, and we don't want false positives.
Stop emitting external modules entirely in single file emission and drop
the creation of "extern_modules.sv" in split file emission. This is done
because it creates problems/confusion for Verilog generation flows which
are trying to hide the existence of some modules. E.g., the existence of
"extern_modules.sv" will leak what external modules were instantiated
under a FIRRTL layerblock.
Alternatively, this could be revived by creating these files by respecting
the output file attributes on external modules such that each significant
directory got such a file.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
`FreezePaths` pass may sometimes need to be invoked before `ExportVerilog`.
This change removes the dependency of the pass on the `hw.verilogName`
attribute, and adds an optional get operation name function, that can be
invoked if the verilog name is absent.
This enables any tool to invoke it earlier by providing an appropriate
name-getter function.
But as is expected, the names used to freeze the paths, may not match the
verilog names. This should be used with caution, only when the path will not
be used and its okay to be incorrect.
Currently, `AcceleratorConnection` implementations only have one "official" teardown entry point, being their destructors. However, this makes implementations susceptible to destructor race conditions, due to the various things that may be concurrently executing in implementation-owned resources.
To provide users with more control during teardown, mark `AcceleratorConnection::disconnect` as virtual, allowing implementations to tear things down before destruction.
Co-authored-by: Morten Borup Petersen <mpetersen@microsoft.com>
Fix a performance issue in the `LayerMerge` pass. Apparently, repeated
use of `inlineBlockBefore` with a forward walk can be a performance issue.
Fix this, by reversing the iteration order.
h/t @youngar for algorithmic suggestions.
Fixes#7551.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Remove vestigial code in BlackBoxReader related to tracking the "priority"
of different directories. This was made unused in an earlier commit that
switched to an LCA computation for where black box files should be placed.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Change how the output directory is computed for external modules with
black box annotations. Previously, this relied on a "precedence" of
predefined directories. Now, this trivially computes the LCA of the
directories for all output directories for a black box annotation with the
same name field.
This _does not_ replicate the old behavior. Instead, users are expected
to rework their output directory structure to align with this algorithm.
E.g., it is no longer possible to make the tesbench a sibling directory of
the main output directory and have blackboxes that are instantiated by
both the testbench and the design to be put in the design---instead a user
should nest the testbench directory _under_ the main output directory.
The omnibus test case has been necessarily updated to show how the above
nesting.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add a utility, makeCommonPrefix, copied from AssignOutputDirs. This is
useful for computing the LCA of two directories.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Reorder the FIRRTL pass pipeline so that Chisel blackboxes (represented by
a `firrtl.extmodule` and one of two blackbox annotations) will be assigned
an output directory based on their instantiation location.
Fixes#7538.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Change the `AssignOutputDirs` pass to add `hw::output_file` attributes on
external modules in the same way that these attributes are added to normal
modules. While this has no effect on an external module which has no
implementation, this fixes a bug where the external module _does_ have an
implementation that the compiler will later resolve.
This is specifically done to make output directories compose correctly
with Chisel inline blackboxes where the body of the external module is in
an annotation and is supposed to be written to a file.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add the standard debug header/footer to the `BlackBoxReader` pass. This
is entirely cosmetic.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Add some basic debugging information to the AssignOutputDirs pass. This
indicates that the pass is running and what modules are having their
output directories updated.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Skip values defined by `ConstantLike` ops when collecting the list of
values to observe in `llhd.wait` ops. Constants will never cause an
`llhd.wait` to resume execution since they never change value.
There is a canonicalization for `exract(c, shl(1, x))` to `x == c` but this
canonicalization introduces a bunch of comparision to constants. This harms
PPA when bitwidth is large (e.g. 16 bit shift introduce 2^16 icmp op). To prevent
such regressions this commit imposes restriction regarding the number of uses
for shift.
Start of static C++ header file generation. Just integer constants for now. Can work off of any manifest and will even connect to a live accelerator and read the manifest from there.
Generates a `types.h` file and one per module listed in the manifest. Inside the module header file, generates one class per module and adds the constants to that class. Puts _everything_ in a namespace specified by the user as `system_name`.
Combine two tests of LowerLayers end-to-end behavior into a single
`-split-input-file` test. This is done to add more tests to this file in
the future.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
Greatly reduces IR size generated in presence of many repeat
constants as commonly occurs in practice due to the data-like
nature of classes / properties.
Same tricky as done for FIRRTL integer constants,
use single cache/code for both.
This is necessary to lower the moore dialect's always_comb and always_latch without introducing helper signals. It also allows for more mem2reg at the LLHD level.
This changes emission style for unpacked array declaration. Verilator doesn't support initialization assignments for unpacked arrays, e.g:
```verilog
wire w[1:0] = '{0, 0};
```
This PR checks the value type and prevents inlining. Ideally it is more desirable to improve verilator but for now I want to avoid inlining unpacked arrays to declaration since it's just a tiny readability optimization.
Fix https://github.com/llvm/circt/issues/6363.
Fix a bug in the `SpecializeLayers` pass where sibling layers would not be
enabled/disabled correctly if an earlier sibling layer was also
enabled/disabled.
Fixes#7525.
Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
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>
Make the `llhd.sig` op use the same naming pattern as HW wires, Moore
variables, Seq registers, and a handful of other operations in CIRCT.
These all use the `custom<ImplicitSSAName>` parser to provide uniform
handling of optional names.
Make the signal name optional to align with other ops.
Rename the class to `SignalOp` for clarity.
PathInfo stores a pointer to an Operation, which was problematic
because that Operation may be deleted in updateInstanceInModule. The
test case added in this patch would lead to a use-after-free.
This pointer was only really used for a few things, which can be
handled differently to avoid needing to consider Operation lifetimes.
One use was the operator bool implementation, to check if a PathInfo is
empty. In the one place this was used, an equivalent check is to query
the PathInfoTable, and check if the key was not in the table.
Another use was adding the Operation's location in error messages and
notes. We can safely store a Location directly for these messages.
The final use was to do an isa check while determining the target
kind. This is where the use in the use-after-free would manifest. For
this, we do the isa check early, and store the result in a bool.
In summary, we are able to simplify the data in PathInfo in order to
avoid hanging on to an Operation pointer and needing to worry about
its lifetime.
This removes a verifier that checks that modules do not instantiate
themsselves. This will be covered by a new diagnostic pass which can
handle indirect recursion as well. This instance verifier goes a bit
beyond what we normally check in verifiers, as it must reach upward to
find the owning module to compare against its target module, and we
normally try to check only local operation properties in verifiers.
This changes how nested layers are specified when using --enable-layers
or --disable-layers. Previously a nested layer was specified with
`A::B`, and now it follows the syntax in the FIRRTL spec for layers,
which is `A.B`.
The goal of this PR is to add a new set of inline formal test ops to FIRRTL:
```firrtl
FIRRTL version 4.0.0
circuit Foo:
public module Foo:
input data : UInt<32>
input c : UInt<1>
output out : UInt<32>
;; Foo body
module FooTest:
;; example test
inst foo of Foo
;; symbolic input -- maps to input in btor2
input s_foo_c : UInt<1>
input s_foo_data : UInt<32>
;; feed the symbolic inputs to the instance
connect foo.c, s_foo_c
connect foo.data, s_foo_data
;; example assertion that uses the symbolic inputs and outputs
intrinsic(circt_verif_assert, intrinsic(
circt_ltl_implication : UInt<1>, s_foo_c, eq(foo.out, s_foo_data))
)
formal testFormal of FooTest, bound = 20
```
These new ops will then be lowered to the existing `verif.formal` op in a future PR.
For each layer, we emit a bindfile. Each bindfile has a header consisting of an
include guard, and an `include for each parent layer's bindfile. To emit the
bindfile's headers, we walk the layer declarations, and keep track of a stack
of parent layers, which we use to emit the `includes.
Unfortunately, a bug in the stack management code means that we forget to
unwind the stack of parent layers, when the curent layer has no parents. This
caused us to emit an include from one layer to the previous layer, when the
previous layer had any children.
This PR fixes the stack unwind loop to correctly clear the stack, when the
current layer has no parents.
List concatenation is implemented by first ensuring all the sub-lists
are evaluated, and then appending the elements of each sub-list into
the final ListValue that represents the concatenation of the lists.
* Fix n^2 behavior with canonicalizeIdempotentInputs.
Add arbitrary "depth" check to bound the search.
* Don't allow flattening or idempotent to search into operations
defined in other blocks.
* Support removing duplicates even when operands come from other
blocks. (or(x, y, x) -> or(x, x) regardless of their origin).
* Don't walk into operations with different two-state-ness in the
idempotent operand canonicalizer.
* When creating new operation in idempotent canonicalizer,
create it with matching two-state-ness.
Add tests for functional changes above.