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

LogicStructure and LogicArray #375

Merged
merged 76 commits into from
Jun 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
f4e9d55
initial structure for logic structures, and refactoring logicvalue.of
mkorbel1 May 1, 2023
a8949f1
mostly implemented, untested
mkorbel1 May 1, 2023
e7c215e
fix some tests, allow put to truncate or extend
mkorbel1 May 1, 2023
cf5d9cd
started moving files around, started logic array
mkorbel1 May 2, 2023
8cc4e50
fix comment
mkorbel1 May 2, 2023
2a2b5fe
first tests for logic array passing
mkorbel1 May 2, 2023
9310430
make element access easier
mkorbel1 May 2, 2023
3a7943a
initial module creationg with arrays
mkorbel1 May 2, 2023
2cd66d1
simpler generated verilog works sorta
mkorbel1 May 2, 2023
5976e08
almost got right assignments in passthrough, but extra non-existent i…
mkorbel1 May 3, 2023
2780328
first correct sv generated for simple passthrough
mkorbel1 May 3, 2023
c4e0ac7
got 2d passthrough working
mkorbel1 May 3, 2023
32fde74
got 3d passthrough working
mkorbel1 May 3, 2023
4569e17
got sv test passing, fix order of dims bug
mkorbel1 May 3, 2023
457a3b0
got it working for up through 3 dims
mkorbel1 May 3, 2023
7bbe227
add test for 4d
mkorbel1 May 3, 2023
0acbb01
packing and unpacking works
mkorbel1 May 3, 2023
1f4fc58
regroup tests
mkorbel1 May 3, 2023
9996105
got intermediate arrays instantiating
mkorbel1 May 4, 2023
a805276
got test working with pack and unpack in sv
mkorbel1 May 4, 2023
7698623
more tests with rearranging
mkorbel1 May 4, 2023
fa4b465
fix empty array test and teardown
mkorbel1 May 4, 2023
1d946e0
add unpacked arrays, but simcompare needs fixing
mkorbel1 May 4, 2023
2a9ed8f
got unpacked test working, but not with iverilog
mkorbel1 May 5, 2023
a9dbef1
test unpacked, but no sv sims
mkorbel1 May 5, 2023
56ba4d3
add more unpacked tests, no sv sim
mkorbel1 May 5, 2023
682579f
sv check for intermediate unpacked
mkorbel1 May 5, 2023
d653922
tests for name collisions with arrays
mkorbel1 May 5, 2023
4b12d7d
got array-based instantiation working
mkorbel1 May 5, 2023
9332224
all hier tests passing
mkorbel1 May 5, 2023
410cb4f
add LogicArray.of
mkorbel1 May 5, 2023
12f8477
add range fix and hier dimension fix
mkorbel1 May 5, 2023
83b5e0e
logicvalue of improvements, and structure test starting
mkorbel1 May 10, 2023
369309d
some more progress and todos
mkorbel1 May 19, 2023
681661e
add test for constant assignment, not passing
mkorbel1 May 26, 2023
40ea8e0
fix bug with constant assignment with bus subset and array
mkorbel1 May 26, 2023
6bd6bed
tested struct ports
mkorbel1 May 26, 2023
0c7dc99
fancy struct inverter
mkorbel1 May 26, 2023
12dbab9
reorganize signals directory
mkorbel1 May 26, 2023
44e6d06
move array and struct into the signals lib
mkorbel1 May 26, 2023
d9dce82
get rid of rootstructure stuff, not needed
mkorbel1 May 30, 2023
4aba127
remove arrayLocationFromRoot
mkorbel1 May 30, 2023
b65f68b
make arrayIndex privately settable
mkorbel1 May 30, 2023
ad97344
adjust parentstructure
mkorbel1 May 30, 2023
0b05ff1
move srcConnections to only exist in module
mkorbel1 May 30, 2023
8a327a1
test sub array
mkorbel1 May 30, 2023
ae57d58
empty multi-dim
mkorbel1 May 30, 2023
6925e9f
test input and output ports with arrays and normal logics
mkorbel1 May 30, 2023
65bff6c
some paranoia about swizzle testing
mkorbel1 May 30, 2023
6cfa91a
make it so that oven_fsm is not generated all the time
mkorbel1 May 30, 2023
f4eb858
add description to conditionalgroup
mkorbel1 May 30, 2023
a32c712
Merge branch 'main' of github.com:intel/rohd into logicstructs
mkorbel1 May 30, 2023
4bede12
resolve merge issues and fix tmp file thing
mkorbel1 May 30, 2023
421632f
added logic array ports
mkorbel1 May 31, 2023
57586d2
got conditional assignments tested and working
mkorbel1 May 31, 2023
ac9d3e8
test array of single bit like a bus
mkorbel1 May 31, 2023
ee929b1
arrays as expressions
mkorbel1 May 31, 2023
493d872
test with interfaces
mkorbel1 Jun 1, 2023
6378b3b
some cleanup of conditionalgroup
mkorbel1 Jun 1, 2023
e44580f
cleanup based on api design changes for arrays
mkorbel1 Jun 1, 2023
2bb7eeb
Improved error checking for construction of arrays
mkorbel1 Jun 1, 2023
c7f18de
test that unpacked dims get passed correctly
mkorbel1 Jun 1, 2023
b29620f
cleanup and improve checks on structure construction
mkorbel1 Jun 1, 2023
47290d6
add test for fix on #254 with put vs const in sv gen
mkorbel1 Jun 1, 2023
5990ea5
more cleanup
mkorbel1 Jun 1, 2023
6d36f14
got slice and getrange working nicely with arrays
mkorbel1 Jun 2, 2023
cc0cb44
get withset working nicely
mkorbel1 Jun 2, 2023
090fb65
fix up shorthands for structures
mkorbel1 Jun 5, 2023
84937bd
test cloning for structures
mkorbel1 Jun 5, 2023
81afac5
fix withset for structures
mkorbel1 Jun 5, 2023
8745fce
test inject and some sim actions with arrays
mkorbel1 Jun 5, 2023
d91f23f
fix bug with negative 64bit constants, and test indexing of structs
mkorbel1 Jun 5, 2023
ac85127
test elements on basic logic
mkorbel1 Jun 5, 2023
5c4b056
cleanup and doc comments
mkorbel1 Jun 5, 2023
ad368b5
Added documentation for struct and array
mkorbel1 Jun 5, 2023
ba97525
some cleanup
mkorbel1 Jun 5, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ Combinational([
c < 0,
d < 1,
],
conditionalType: ConditionalType.Unique
conditionalType: ConditionalType.unique
),
CaseZ([b,a].swizzle(),[
CaseItem(Const(LogicValue.ofString('z1')), [
Expand All @@ -496,7 +496,7 @@ Combinational([
], defaultItem: [
e < 0,
],
conditionalType: ConditionalType.Priority
conditionalType: ConditionalType.priority
)
]);
```
Expand Down
2 changes: 1 addition & 1 deletion benchmark/logic_value_of_benchmark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class LogicValueOfBenchmark extends BenchmarkBase {

@override
void run() {
LogicValue.of(toOf);
LogicValue.ofIterable(toOf);
}
}

Expand Down
44 changes: 44 additions & 0 deletions doc/user_guide/_docs/logic-arrays.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
---
title: "Logic Arrays"
permalink: /docs/logic-arrays/
last_modified_at: 2022-6-5
toc: true
---

A `LogicArray` is a type of `LogicStructure` that mirrors multi-dimensional arrays in hardware languages like SystemVerilog. In ROHD, the `LogicArray` type inherits a lot of functionality from `LogicStructure`, so it can behave like a `Logic` where it makes sense or be individually referenced in other places.

`LogicArray`s can be constructed easily using the constructor:

```dart
// A 1D array with ten 8-bit elements.
LogicArray([10], 8);

// A 4x3 2D array, with four arrays, each with three 2-bit elements.
LogicArray([4, 3], 2, name: 'array4x3');

// A 5x5x5 3D array, with 125 total elements, each 128 bits.
LogicArray([5, 5, 5], 128);
```

As long as the total width of a `LogicArray` and another type of `Logic` (including `Logic`, `LogicStructure`, and another `LogicArray`) are the same, assignments and bitwise operations will work in per-element order. This means you can assign two `LogicArray`s of different dimensions to each other as long as the total width matches.

## Unpacked arrays

In SystemVerilog, there is a concept of "packed" vs. "unpacked" arrays which have different use cases and capabilities. In ROHD, all arrays act the same and you get the best of both worlds. You can indicate when constructing a `LogicArray` that some number of the dimensions should be "unpacked" as a hint to `Synthesizer`s. Marking an array with a non-zero `numUnpackedDimensions`, for example, will make that many of the dimensions "unpacked" in generated SystemVerilog signal declarations.

```dart
// A 4x3 2D array, with four arrays, each with three 2-bit elements.
// The first dimension (4) will be unpacked.
LogicArray(
[4, 3],
2,
name: 'array4x3w1unpacked',
numUnpackedDimensions: 1,
);
```

## Array ports

You can declare ports of `Module`s as being arrays (including with some dimensions "unpacked") using `addInputArray` and `addOutputArray`. Note that these do _not_ automatically do validation that the dimensions, element width, number of unpacked dimensions, etc. are equal between the port and the original signal. As long as the overall width matches, the assignment will be clean.

Array ports in generated SystemVerilog will match dimensions (including unpacked) as specified when the port is created.
68 changes: 68 additions & 0 deletions doc/user_guide/_docs/logic-structures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
---
title: "Logic Structures"
permalink: /docs/logic-structures/
last_modified_at: 2022-6-5
toc: true
---

A `LogicStructure` is a useful way to group or bundle related `Logic` signals together. They operate in a similar way to "`packed` `structs`" in SystemVerilog, or a `class` containing multiple `Logic`s in ROHD, but with some important differences.

**`LogicStructure`s will _not_ convert to `struct`s in generated SystemVerilog.** They are purely a way to deal with signals during generation time in ROHD.

**`LogicStructure`s can be used anywhere a `Logic` can be**. This means you can assign one structure to another structure, or inter-assign between normal signals and structures. As long as the overall width matches, the assignment will work. The order of assignment of bits is based on the order of the `elements` in the structure.

**Elements within a `LogicStructure` can be individually assigned.** This is a notable difference from individual bits of a plain `Logic` where you'd have to use something like `withSet` to effectively modify bits within a signal.

`LogicArray`s are a type of `LogicStructure` and thus inherit these behavioral traits.

## Using `LogicStructure` to group signals

The simplest way to use a `LogicStructure` is to just use its constructor, which requires a collection of `Logic`s.

For example, if you wanted to bundle together a `ready` and a `valid` signal together into one structure, you could do this:

```dart
final rvStruct = LogicStructure([Logic(name: 'ready'), Logic(name: 'valid')]);
```

You could now assign this like any other `Logic` all together:

```dart
Logic ready, valid;
rvStruct <= [ready, valid].rswizzle();
```

Or you can assign individual `elements`:

```dart
rvStruct.elements[0] <= ready;
rvStruct.elements[1] <= valid;
```

## Making your own structure

Referencing elements by index is often not ideal for named signals. We can do better by building our own structure that inherits from `LogicStructure`.

```dart
class ReadyValidStruct extends LogicStructure {
final Logic ready;
final Logic valid;

factory ReadyValidStruct() => MyStruct._(
Logic(name: 'ready'),
Logic(name: 'valid'),
);

ReadyValidStruct._(this.ready, this.valid)
: super([ready, valid], name: 'readyValid');

@override
LogicStructure clone({String? name}) => ReadyValidStruct();
}
```

Here we've built a class that has `ready` and `valid` as fields, so we can reference those instead of by element index. We use some tricks with `factory`s to make this easier to work with.

We override the `clone` function so that we can make a duplicate structure of the same type.

There's a lot more that can be done with a custom class like this, but this is a good start. There are places where it may even make sense to prefer a custom `LogicStructure` to an `Interface`.
2 changes: 1 addition & 1 deletion example/fir_filter.dart
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class FirFilter extends Module {
],
orElse: [out < 0] +
// Set all 'z' to zero.
List<ConditionalAssign>.generate(depth, (index) => z[index] < 0))
List<Conditional>.generate(depth, (index) => z[index] < 0))
]);
}
}
Expand Down
4 changes: 3 additions & 1 deletion example/oven_fsm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,9 @@ Future<void> main({bool noPrint = false}) async {
//
// Check on https://mermaid.js.org/intro/ to view the diagram generated.
// If you are using vscode, you can download the mermaid extension.
oven.ovenStateMachine.generateDiagram(outputPath: 'oven_fsm.md');
if (!noPrint) {
oven.ovenStateMachine.generateDiagram(outputPath: 'oven_fsm.md');
}

// Before we can simulate or generate code with the counter, we need
// to build it.
Expand Down
2 changes: 1 addition & 1 deletion lib/rohd.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@

export 'src/external.dart';
export 'src/interface.dart';
export 'src/logic.dart';
export 'src/module.dart';
export 'src/modules/modules.dart';
export 'src/signals/signals.dart';
export 'src/simulator.dart';
export 'src/state_machine.dart';
export 'src/swizzle.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/collections/iterable_removable_queue.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ class IterableRemovableQueue<T> {
/// Adds a new item to the end of the queue.
void add(T item) {
final newElement = _IterableRemovableElement<T>(item);
if (_first == null) {
if (isEmpty) {
_first = newElement;
_last = _first;
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class SignalRedrivenException extends RohdException {
/// with default error [message].
///
/// Creates a [SignalRedrivenException] with an optional error [message].
SignalRedrivenException(String signals,
SignalRedrivenException(Iterable<Logic> signals,
[String message = 'Sequential drove the same signal(s) multiple times: '])
: super(message + signals);
: super(message + signals.toString());
}
21 changes: 21 additions & 0 deletions lib/src/exceptions/logic/logic_construction_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// logic_construction_exception.dart
// An exception thrown when a logical signal fails to construct.
//
// 2023 June 1
// Author: Max Korbel <max.korbel@intel.com>

import 'package:rohd/rohd.dart';
import 'package:rohd/src/exceptions/rohd_exception.dart';

/// An exception that thrown when a [Logic] is connecting to itself.
class LogicConstructionException extends RohdException {
/// A message describing why the construction failed.
final String reason;

/// Creates an exception when a [Logic] is trying to connect itself.
LogicConstructionException(this.reason)
: super('Failed to construct signal: $reason');
}
2 changes: 2 additions & 0 deletions lib/src/exceptions/logic/logic_exceptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,7 @@
/// SPDX-License-Identifier: BSD-3-Clause

export 'invalid_multiplier_exception.dart';
export 'logic_construction_exception.dart';
export 'put_exception.dart';
export 'self_connecting_logic_exception.dart';
export 'signal_width_mismatch_exception.dart';
21 changes: 21 additions & 0 deletions lib/src/exceptions/logic/signal_width_mismatch_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// port_width_mismatch_exception.dart
// Definition for exception when a signal has the wrong width.
//
// 2023 June 2
// Author: Max Korbel <max.korbel@intel.com>

import 'package:rohd/rohd.dart';
import 'package:rohd/src/exceptions/rohd_exception.dart';

/// An [Exception] thrown when a signal has the wrong width.
class SignalWidthMismatchException extends RohdException {
/// Constructs a new [Exception] for when a signal has the wrong width.
SignalWidthMismatchException(Logic signal, int expectedWidth,
{String additionalMessage = ''})
: super('Signal ${signal.name} has the wrong width.'
' Expected $expectedWidth but found ${signal.width}.'
' $additionalMessage');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// logic_value_construction_exception.dart
// An exception that thrown when a signal failes to `put`.
//
// 2023 May 1
// Author: Max Korbel <max.korbel@intel.com>

import 'package:rohd/rohd.dart';
import 'package:rohd/src/exceptions/rohd_exception.dart';

/// An exception that thrown when a [LogicValue] cannot be properly constructed.
class LogicValueConstructionException extends RohdException {
/// Creates an exception for when a construction of a `LogicValue` fails.
LogicValueConstructionException(String message)
: super('Failed to construct `LogicValue`: $message');
}
5 changes: 3 additions & 2 deletions lib/src/exceptions/logic_value/logic_value_exceptions.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
/// Copyright (C) 2023 Intel Corporation
/// SPDX-License-Identifier: BSD-3-Clause
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'invalid_truncation_exception.dart';
export 'logic_value_construction_exception.dart';
6 changes: 4 additions & 2 deletions lib/src/exceptions/module/port_width_mismatch_exception.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import 'package:rohd/src/exceptions/rohd_exception.dart';
/// An [Exception] thrown when a port has the wrong width.
class PortWidthMismatchException extends RohdException {
/// Constructs a new [Exception] for when a port has the wrong width.
PortWidthMismatchException(Logic port, int expectedWidth)
PortWidthMismatchException(Logic port, int expectedWidth,
{String additionalMessage = ''})
: super('Port ${port.name} has the wrong width.'
' Expected $expectedWidth but found ${port.width}.');
' Expected $expectedWidth but found ${port.width}.'
' $additionalMessage');

/// Constructs a new [Exception] for when two ports should have been the
/// same width, but were not.
Expand Down
12 changes: 0 additions & 12 deletions lib/src/interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,6 @@ import 'package:collection/collection.dart';
import 'package:meta/meta.dart';

import 'package:rohd/rohd.dart';
import 'package:rohd/src/exceptions/name/name_exceptions.dart';
import 'package:rohd/src/utilities/sanitizer.dart';

/// An extension of [Logic] useful for [Interface] definitions.
class Port extends Logic {
/// Constructs a [Logic] intended to be used for ports in an [Interface].
Port(String name, [int width = 1]) : super(name: name, width: width) {
if (!Sanitizer.isSanitary(name)) {
throw InvalidPortNameException(name);
}
}
}

/// Represents a logical interface to a [Module].
///
Expand Down
Loading