Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[minor] Add generic intrinsic expressions/statements. #204

Merged
merged 10 commits into from
Apr 18, 2024
1 change: 1 addition & 0 deletions revision-history.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ revisionHistory:
- Restore flow description.
- Update intrinsic module example to use a real intrinsic.
- Restore id and info in printf grammar, add to verif commands.
- Add intrinsic expressions and statements.
abi:
- Add ABI for public modules and filelist output.
- Changed ABI for group and ref generated files.
Expand Down
71 changes: 67 additions & 4 deletions spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -227,9 +227,11 @@ endmodule

## Implementation Defined Modules (Intrinsics)

Intrinsics ([@sec:intrinsics]) can be expressed as intrinsic modules but this is deprecated.

Intrinsic modules are modules which represent implementation-defined, compiler-provided functionality.
Intrinsics generally are used for functionality which requires knowledge of the implementation or circuit not available to a library writer.
What intrinsics are supported by an implementation is defined by the implementation.
Which intrinsics are supported by an implementation is defined by the implementation.
The particular intrinsic represented by an intrinsic module is encoded in *intrinsic*.
The name of the intmodule is only used to identify a specific instance.
An implementation shall type-check all ports and parameters.
Expand Down Expand Up @@ -2386,6 +2388,12 @@ circuit Foo:
;; snippetend
```

## Intrinsic Statements

Intrinsics may be used as statements.
If the intrinsic has a return type, it is unused.
See [@sec:intrinsics].

# Layer Blocks

The `layerblock`{.firrtl} keyword declares a *layer block* and associates it with a layer.
Expand Down Expand Up @@ -2899,8 +2907,9 @@ for creating literal property type expressions,
for referencing a circuit component,
for statically and dynamically accessing a nested element within a component,
for creating multiplexers,
for performing primitive operations, and
for reading a remote reference to a probe.
for performing primitive operations,
for reading a remote reference to a probe, and
for intrinsics ([@sec:intrinsics]).

## Constant Integer Expressions

Expand Down Expand Up @@ -3278,6 +3287,52 @@ Within a memory declaration, all port names must be unique.

Any modifications to names must preserve the uniqueness of names within a namespace.

# Intrinsics

Intrinsics are expressions and statements which represent implementation-defined, compiler-provided functionality.

Intrinsics generally are used for functionality which requires knowledge of the implementation or circuit not available to a library writer.
Which intrinsics are supported by an implementation is defined by the implementation.

Intrinsics first specify the intrinsic: the name of the intrinsic, any parameters, and return type if applicable.
Any inputs to the intrinsic follow.
An implementation shall type-check the specification and all operands.

Below are some examples of intrinsics.
These are for demonstration and their meaning or validity is determined by the implementation.

The following shows an intrinsic expression for the intrinsic named "circt_ltl_delay" with two parameters, returns `UInt<1>`{.firrtl}, and has one operand.

``` .firrtl
FIRRTL version 4.0.0
circuit Foo :
;; snippetbegin
public module Foo :
input in : UInt<1>

node d = intrinsic(circt_ltl_delay<delay = 1, length = 0> : UInt<1>, in)
;; snippetend
```

The following has an intrinsic statement with an intrinsic expression as its operand.
The statement is for the intrinsic named "circt_verif_assert".
The expression is for the intrinsic named "circt_isX" which returns a `UInt<1>`{.firrtl} and takes an operand.

``` .firrtl
FIRRTL version 4.0.0
circuit Foo :
;; snippetbegin
public module Foo :
input data : UInt<5>

intrinsic(circt_verif_assert, intrinsic(circt_isX: UInt<1>, data))
;; snippetend
```

Operands and the return type of intrinsics must be passive and ground or aggregate types.
dtzSiFive marked this conversation as resolved.
Show resolved Hide resolved
When used as an expression, the intrinsic must have a return type.
The types of intrinsic module parameters may only be literal integers or string literals.

# Annotations

Annotations encode arbitrary metadata and associate it with zero or more targets ([@sec:targets]) in a FIRRTL circuit.
Expand Down Expand Up @@ -4236,6 +4291,7 @@ command =
| "force_initial" , "(" , expr_probe , "," , expr , ")"
| "release" , "(" , expr , "," , expr , "," , expr_probe , ")"
| "release_initial" , "(" , expr_probe , ")"
| expr_intrinsic , [ info ]
| "printf" , "(" ,
expr , "," ,
expr , "," ,
Expand Down Expand Up @@ -4297,7 +4353,8 @@ expr =
| expr_enum
| expr_mux
| expr_read
| expr_primop ;
| expr_primop
| expr_intrinsic ;

expr_reference = reference ;
expr_lit = ( "UInt" | "SInt" ) , [ width ] , "(" , ( int | rint ) , ")" ;
Expand All @@ -4315,6 +4372,12 @@ property_expr = reference_static | property_literal_expr | property_expr_primop
property_expr_primop = property_primop_2expr ;
expr_primop = primop_2expr | primop_1expr | primop_1expr1int | primop_1expr2int ;

expr_intrinsic = "intrinsic", "(" , id ,
[ "<" "parameter" , id , "=" , ( int | string_dq ) ,
{ "," , "parameter" , id , "=" , ( int | string_dq ) } , ">" ] ,
[ ":" , type ] ,
{ "," , expr } , ")"

(* Types *)
type = ( [ "const" ] , type_hardware ) | type_probe ;

Expand Down
Loading