Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into mingzhe-structCreate
Browse files Browse the repository at this point in the history
  • Loading branch information
mingzheTerapines committed Aug 22, 2024
2 parents 0729f70 + eef76ca commit 3b1e302
Show file tree
Hide file tree
Showing 292 changed files with 10,952 additions and 3,507 deletions.
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,13 @@ if(CIRCT_SLANG_FRONTEND_ENABLED)
# harder than it ought to be.
set_property(
GLOBAL APPEND PROPERTY CIRCT_EXPORTS slang_slang unordered_dense fmt)

# Disable the installation of headers coming from third-party libraries. We
# won't use those APIs directly. Just make them static libraries for the sake
# of running slang normally.
set_target_properties(fmt PROPERTIES PUBLIC_HEADER "")
set_target_properties(unordered_dense PROPERTIES PUBLIC_HEADER "")

install(TARGETS slang_slang unordered_dense fmt EXPORT CIRCTTargets)
else()
find_package(slang 3.0 REQUIRED)
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

# ⚡️ "CIRCT" / Circuit IR Compilers and Tools

"CIRCT" stands for "Circuit IR Compilers and Tools". One might also interpret
"CIRCT" stands for "Circuit Intermediate Representations (IR) Compilers and Tools". One might also interpret
it as the recursively as "CIRCT IR Compiler and Tools". The T can be
selectively expanded as Tool, Translator, Team, Technology, Target, Tree, Type,
... we're ok with the ambiguity.
Expand Down
49 changes: 49 additions & 0 deletions docs/Dialects/FIRRTL/FIRRTLAnnotations.md
Original file line number Diff line number Diff line change
Expand Up @@ -474,8 +474,55 @@ Example:
}
```

### FullResetAnnotation

| Property | Type | Description |
| ---------- | ------ | ------------- |
| class | string | `circt.FullAsyncResetAnnotation` |
| target | string | Reference target |
| resetType | string | "async" or "sync" |


The target must be a signal that is a reset. The type of the signal must be (or inferred
to be) the same as the reset type specified in the annotation.

Indicates that all reset-less registers which are children of the module containing
the target will have the reset targeted attached, with a reset value of 0.

The module containing the target of this annotation is not allowed to reside in multiple
hierarchies.

Example:
```json
{
"class": "circt.FullResetAnnotation",
"target": "~Foo|Bar/d:Baz>reset",
"resetType": "async"
}
```

### ExcludeFromFullResetAnnotation

| Property | Type | Description |
| ---------- | ------ | ------------- |
| class | string | `circt.ExcludeFromFullResetAnnotation` |
| target | string | Reference target |

This annotation indicates that the target moudle should be excluded from the
FullResetAnnotation of a parent module.

Example:
```json
{
"class": "circt.IgnoreFullAsyncResetAnnotation",
"target": "~Foo|Bar/d:Baz"
}
```

### FullAsyncResetAnnotation

**Deprecated, use FullResetAnnotation**

| Property | Type | Description |
| ---------- | ------ | ------------- |
| class | string | `sifive.enterprise.firrtl.FullAsyncResetAnnotation` |
Expand All @@ -500,6 +547,8 @@ Example:

### IgnoreFullAsyncResetAnnotation

**Deprecated, use ExcludeFromFullResetAnnotation**

| Property | Type | Description |
| ---------- | ------ | ------------- |
| class | string | `sifive.enterprise.firrtl.IgnoreFullAsyncResetAnnotation` |
Expand Down
6 changes: 4 additions & 2 deletions docs/Dialects/FIRRTL/FIRRTLIntrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ Function Declaration:

Types:
* Operand and result types must be passive.
* Aggregate types are lowered into corresponding verilog aggregate.
* A vector is lowered to an unpacked open array type, e.g. `a: Vec<4, UInt<8>>` to `byte a []`.
* A bundle is lowered to a packed struct.
* Integer types are lowered into into 2-state types.
* Small integer types (< 64 bit) must be compatible to C-types and arguments are passed by values. Users are required to use specific integer types for small integers shown in the table below. Large integers are lowered to `bit` and passed by a reference.

Expand All @@ -267,12 +268,13 @@ Types:

Example SV output:
```firrtl
node result = intrinsic(circt_dpi_call<isClocked = 1, functionName="dpi_func"> : UInt<64>, clock, enable, uint_8_value, uint_32_value)
node result = intrinsic(circt_dpi_call<isClocked = 1, functionName="dpi_func"> : UInt<64>, clock, enable, uint_8_value, uint_32_value, uint_8_vector)
```
```verilog
import "DPI-C" function void dpi_func(
input byte in_0,
int in_1,
byte in_2[],
output longint out_0
);
Expand Down
4 changes: 4 additions & 0 deletions docs/Dialects/FIRRTL/_index.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ page](https://github.com/freechipsproject/firrtl).

[include "Dialects/FIRRTLExpressionOps.md"]

## Operation Definitions -- Intrinsics

[include "Dialects/FIRRTLIntrinsicOps.md"]

## Type Definitions

[include "Dialects/FIRRTLTypes.md"]
Expand Down
15 changes: 7 additions & 8 deletions docs/Dialects/HWArith/RationaleHWArith.md
Original file line number Diff line number Diff line change
Expand Up @@ -483,19 +483,18 @@ can be simplified to:
%4 = hwarith.icmp lt %0, %1 : si3, ui5
```

Note that the result of the comparison is *always* of type `ui1`, regardless of
the operands. So if the `i1` type is needed, the result must be cast
accordingly.
Note that the result of the comparison is *always* of type `i1` since the
logical result is a boolean, which doesn't have signedness semantics.

#### Overview

| | LHS type | RHS type | Comparison type | Result type |
| - | :------- | :------- | :--------------------------------------- | :---------- |
|(U)| `ui<a>` | `ui<b>` | `ui<r>`, *r* = max(*a*, *b*) | `ui1` |
|(S)| `si<a>` | `si<b>` | `si<r>`, *r* = max(*a*, *b*) | `ui1` |
|(M)| `ui<a>` | `si<b>` | `si<r>`, *r* = *a* + 1 **if** *a**b* | `ui1` |
| | | | `si<r>`, *r* = *b* **if** *a* < *b* | `ui1` |
|(M)| `si<a>` | `ui<b>` | Same as `ui<b> si<a>` | `ui1` |
|(U)| `ui<a>` | `ui<b>` | `ui<r>`, *r* = max(*a*, *b*) | `i1` |
|(S)| `si<a>` | `si<b>` | `si<r>`, *r* = max(*a*, *b*) | `i1` |
|(M)| `ui<a>` | `si<b>` | `si<r>`, *r* = *a* + 1 **if** *a**b* | `i1` |
| | | | `si<r>`, *r* = *b* **if** *a* < *b* | `i1` |
|(M)| `si<a>` | `ui<b>` | Same as `ui<b> si<a>` | `i1` |

#### Examples
```mlir
Expand Down
3 changes: 3 additions & 0 deletions docs/VerilogGeneration.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,9 @@ The current set of "lint warnings fix" Lowering Options is:
collisions with Verilog keywords insensitively. E.g., this will treat a
variable called `WIRE` as a collision with the keyword and rename it to
`WIRE_0` (or similar). When set to `false`, then `WIRE` will not be renamed.
* `fixUpEmptyModules` (default=`false`). If true, then add a dummy wire to
empty modules since some vendor tools consider empty modules as a blackbox and
raise synthesis errors.

## Recommended `LoweringOptions` by Target

Expand Down
11 changes: 7 additions & 4 deletions frontends/PyCDE/integration_test/esi_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pycde
from pycde import (AppID, Clock, Module, Reset, modparams, generator)
from pycde.bsp import cosim
from pycde.common import Constant
from pycde.constructs import Reg, Wire
from pycde.esi import FuncService, MMIO, MMIOReadWriteCmdType
from pycde.types import (Bits, Channel, UInt)
Expand All @@ -15,21 +16,23 @@
import sys


class LoopbackInOutAdd7(Module):
class LoopbackInOutAdd(Module):
"""Loopback the request from the host, adding 7 to the first 15 bits."""
clk = Clock()
rst = Reset()

add_amt = Constant(UInt(16), 11)

@generator
def construct(ports):
loopback = Wire(Channel(UInt(16)))
args = FuncService.get_call_chans(AppID("loopback_add7"),
args = FuncService.get_call_chans(AppID("add"),
arg_type=UInt(24),
result=loopback)

ready = Wire(Bits(1))
data, valid = args.unwrap(ready)
plus7 = data + 7
plus7 = data + LoopbackInOutAdd.add_amt.value
data_chan, data_ready = loopback.type.wrap(plus7.as_uint(16), valid)
data_chan_buffered = data_chan.buffer(ports.clk, ports.rst, 5)
ready.assign(data_ready)
Expand Down Expand Up @@ -96,7 +99,7 @@ class Top(Module):

@generator
def construct(ports):
LoopbackInOutAdd7(clk=ports.clk, rst=ports.rst)
LoopbackInOutAdd(clk=ports.clk, rst=ports.rst, appid=AppID("loopback"))
for i in range(4, 18, 5):
MMIOClient(i)()
MMIOReadWriteClient(clk=ports.clk, rst=ports.rst)
Expand Down
9 changes: 7 additions & 2 deletions frontends/PyCDE/integration_test/test_software/esi_ram.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from multiprocessing import dummy
import time
from typing import cast
import esiaccel as esi
Expand Down Expand Up @@ -26,8 +27,12 @@
# assert len(m.type_table) == len(m_alt.type_table)

info = m.module_infos
assert len(info) == 3
assert info[1].name == "Dummy"
dummy_info = None
for i in info:
if i.name == "Dummy":
dummy_info = i
break
assert dummy_info is not None


def read(addr: int) -> bytearray:
Expand Down
16 changes: 12 additions & 4 deletions frontends/PyCDE/integration_test/test_software/esi_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,21 @@ def read_offset_check(i: int, add_amt: int):
print(m.type_table)

d = acc.build_accelerator()

recv = d.ports[esi.AppID("loopback_add7")].read_port("result")
loopback = d.children[esi.AppID("loopback")]
recv = loopback.ports[esi.AppID("add")].read_port("result")
recv.connect()

send = d.ports[esi.AppID("loopback_add7")].write_port("arg")
send = loopback.ports[esi.AppID("add")].write_port("arg")
send.connect()

loopback_info = None
for mod_info in m.module_infos:
if mod_info.name == "LoopbackInOutAdd":
loopback_info = mod_info
break
assert loopback_info is not None
add_amt = mod_info.constants["add_amt"].value

################################################################################
# Loopback add 7 tests
################################################################################
Expand All @@ -85,6 +93,6 @@ def read_offset_check(i: int, add_amt: int):

print(f"data: {data}")
print(f"resp: {resp}")
assert resp == data + 7
assert resp == data + add_amt

print("PASS")
17 changes: 17 additions & 0 deletions frontends/PyCDE/src/pycde/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,23 @@ def __repr__(self) -> str:
return f"{self.name}[{self.index}]"


class Constant:
"""A constant value associated with a module. Gets added to the ESI system
manifest so it is accessible at runtime.
Example usage:
```
def ExampleModule(Module):
const_name = Constant(UInt(16), 42)
```
"""

def __init__(self, type: Type, value: object):
self.type = type
self.value = value


class _PyProxy:
"""Parent class for a Python object which has a corresponding IR op (i.e. a
proxy class)."""
Expand Down
21 changes: 18 additions & 3 deletions frontends/PyCDE/src/pycde/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
from dataclasses import dataclass
from typing import Any, List, Optional, Set, Tuple, Dict

from .common import (AppID, Clock, Input, ModuleDecl, Output, PortError,
_PyProxy, Reset)
from .support import (get_user_loc, _obj_to_attribute, create_type_string,
from .common import (AppID, Clock, Constant, Input, ModuleDecl, Output,
PortError, _PyProxy, Reset)
from .support import (get_user_loc, _obj_to_attribute, obj_to_typed_attribute,
create_const_zero)
from .signals import ClockSignal, Signal, _FromCirctValue
from .types import ClockType, Type, _FromCirctType
Expand Down Expand Up @@ -237,6 +237,7 @@ def scan_cls(self):
clock_ports = set()
reset_ports = set()
generators = {}
constants = {}
num_inputs = 0
num_outputs = 0
for attr_name, attr in self.cls_dct.items():
Expand Down Expand Up @@ -273,11 +274,14 @@ def scan_cls(self):
ports.append(attr)
elif isinstance(attr, Generator):
generators[attr_name] = attr
elif isinstance(attr, Constant):
constants[attr_name] = attr

self.ports = ports
self.clocks = clock_ports
self.resets = reset_ports
self.generators = generators
self.constants = constants

def create_port_proxy(self) -> PortProxyBase:
"""Create a proxy class for generators to use in order to access module
Expand Down Expand Up @@ -475,6 +479,17 @@ def create_op(self, sys, symbol):
else:
self.add_metadata(sys, symbol, None)

# If there are associated constants, add them to the manifest.
if len(self.constants) > 0:
constants_dict: Dict[str, ir.Attribute] = {}
for name, constant in self.constants.items():
constant_attr = obj_to_typed_attribute(constant.value, constant.type)
constants_dict[name] = constant_attr
with ir.InsertionPoint(sys.mod.body):
from .dialects.esi import esi
esi.SymbolConstantsOp(symbolRef=ir.FlatSymbolRefAttr.get(symbol),
constants=ir.DictAttr.get(constants_dict))

if len(self.generators) > 0:
if hasattr(self, "parameters") and self.parameters is not None:
self.attributes["pycde.parameters"] = self.parameters
Expand Down
13 changes: 13 additions & 0 deletions frontends/PyCDE/src/pycde/support.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
from __future__ import annotations

from .circt import support
from .circt import ir

from typing import TYPE_CHECKING
if TYPE_CHECKING:
from .types import Type

import os


Expand Down Expand Up @@ -43,6 +49,13 @@ def _obj_to_attribute(obj) -> ir.Attribute:
"This is required for parameters.")


def obj_to_typed_attribute(obj: object, type: Type) -> ir.Attribute:
from .types import BitVectorType
if isinstance(type, BitVectorType):
return ir.IntegerAttr.get(type._type, obj)
raise ValueError(f"Type '{type}' conversion to attribute not supported yet.")


__dir__ = os.path.dirname(__file__)
_local_files = set([os.path.join(__dir__, x) for x in os.listdir(__dir__)])
_hidden_filenames = set(["functools.py"])
Expand Down
5 changes: 4 additions & 1 deletion frontends/PyCDE/test/test_esi.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from pycde import (Clock, Input, InputChannel, Output, OutputChannel, Module,
Reset, generator, types)
from pycde import esi
from pycde.common import AppID, RecvBundle, SendBundle
from pycde.common import AppID, Constant, RecvBundle, SendBundle
from pycde.constructs import Wire
from pycde.esi import MMIO
from pycde.module import Metadata
Expand Down Expand Up @@ -36,6 +36,7 @@ class HostComms:


# CHECK: esi.manifest.sym @LoopbackInOutTop name "LoopbackInOut" {{.*}}version "0.1" {bar = "baz", foo = 1 : i64}
# CHECK: esi.manifest.constants @LoopbackInOutTop {c1 = 54 : ui8}


# CHECK-LABEL: hw.module @LoopbackInOutTop(in %clk : !seq.clock, in %rst : i1)
Expand All @@ -59,6 +60,8 @@ class LoopbackInOutTop(Module):
},
)

c1 = Constant(UInt(8), 54)

@generator
def construct(self):
# Use Cosim to implement the 'HostComms' service.
Expand Down
1 change: 1 addition & 0 deletions include/circt-c/Dialect/HW.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ MLIR_CAPI_EXPORTED MlirStringRef hwTypeAliasTypeGetScope(MlirType typeAlias);

MLIR_CAPI_EXPORTED bool hwAttrIsAInnerSymAttr(MlirAttribute);
MLIR_CAPI_EXPORTED MlirAttribute hwInnerSymAttrGet(MlirAttribute symName);
MLIR_CAPI_EXPORTED MlirAttribute hwInnerSymAttrGetEmpty(MlirContext ctx);
MLIR_CAPI_EXPORTED MlirAttribute hwInnerSymAttrGetSymName(MlirAttribute);

MLIR_CAPI_EXPORTED bool hwAttrIsAInnerRefAttr(MlirAttribute);
Expand Down
Loading

0 comments on commit 3b1e302

Please sign in to comment.