Skip to content

Commit dd3f43d

Browse files
authored
Logic.assignSubset for partial assignments to Logic (#502)
1 parent 6474134 commit dd3f43d

File tree

5 files changed

+195
-32
lines changed

5 files changed

+195
-32
lines changed

doc/user_guide/_docs/A04-assignment.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,29 @@
22
title: "Assignment"
33
permalink: /docs/assignment/
44
excerpt: "Assignment"
5-
last_modified_at: 2022-12-06
5+
last_modified_at: 2024-08-02
66
toc: true
77
---
88

99
To assign one signal to the value of another signal, use the `<=` operator. This is a hardware synthesizable assignment connecting two wires together.
1010

1111
```dart
1212
var a = Logic(), b = Logic();
13-
// assign a to always have the same value as b
13+
14+
// assign `a` to always have the same value as `b`
1415
a <= b;
1516
```
17+
18+
It is also possible to do a partial assignment to a signal using `assignSubset`.
19+
20+
```dart
21+
var a = Logic(width: 3), b = Logic(width: 2);
22+
23+
// assign the bottom two bits of `a` to have the same value as `b`
24+
a.assignSubset(b.elements);
25+
26+
// assign the upper bit (index 2) of `a` to be 0
27+
a.assignSubset([Const(0)], 2);
28+
```
29+
30+
If you're assigning groups of bits that are already collected as a single `Logic`, consider using a [`swizzle`](https://intel.github.io/rohd-website/docs/bus-range-swizzling/).

lib/src/signals/logic.dart

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -826,4 +826,39 @@ class Logic {
826826

827827
return selected;
828828
}
829+
830+
/// If [assignSubset] has been used on this signal, a reference to the
831+
/// [LogicArray] that is usd to drive `this`.
832+
LogicArray? _subsetDriver;
833+
834+
/// Performs an assignment operation on a portion this signal to be driven by
835+
/// [updatedSubset]. Each index of [updatedSubset] will be assigned to drive
836+
/// the corresponding index, plus [start], of this signal.
837+
///
838+
/// Each of the elements of [updatedSubset] must have the same [width] as the
839+
/// corresponding member of [elements] of this signal.
840+
///
841+
/// Example:
842+
/// ```dart
843+
/// // assign elements 2 and 3 of receiverLogic to sig1 and sig2, respectively
844+
/// receiverLogic.assignSubset([sig1, sig2], start: 2);
845+
/// ```
846+
void assignSubset(List<Logic> updatedSubset, {int start = 0}) {
847+
if (updatedSubset.length > width - start) {
848+
throw SignalWidthMismatchException.forWidthOverflow(
849+
updatedSubset.length, width - start);
850+
}
851+
852+
if (_subsetDriver == null) {
853+
_subsetDriver = (isNet ? LogicArray.net : LogicArray.new)(
854+
[width],
855+
1,
856+
name: '${name}_subset',
857+
naming: Naming.unnamed,
858+
);
859+
this <= _subsetDriver!;
860+
}
861+
862+
_subsetDriver!.assignSubset(updatedSubset, start: start);
863+
}
829864
}

lib/src/signals/logic_array.dart

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -234,33 +234,4 @@ class LogicArray extends LogicStructure {
234234
naming: Naming.mergeable,
235235
);
236236
}
237-
238-
/// Perform Assign operation on a Logic subset or slice
239-
///
240-
/// Assigns part of this LogicArray with a given [updatedSubset] of type
241-
/// [List<Logic>]. The update is performed from a given [start] position
242-
/// to the length of the [updatedSubset].
243-
///
244-
/// Example:
245-
/// ```dart
246-
/// LogicArray sampleLogic;
247-
/// // Note: updatedSubset.length < (sampleLogic.length - start)
248-
/// List<Logic> updatedSubset;
249-
/// // Assign part of sampleLogic as [updatedSubset]
250-
/// sampleLogic.assignSubset(updatedSubset); // start = 0 by default
251-
/// // assign updated subset to sampleLogic[10:10+updatedSubset.length]
252-
/// sampleLogic.assignSubset(updatedSubset, 10);
253-
/// ```
254-
///
255-
void assignSubset(List<Logic> updatedSubset, {int start = 0}) {
256-
if (updatedSubset.length > elements.length - start) {
257-
throw SignalWidthMismatchException.forWidthOverflow(
258-
updatedSubset.length, elements.length - start);
259-
}
260-
261-
// Assign Logic array from `start` index to `start+updatedSubset.length`
262-
for (var i = 0; i < updatedSubset.length; i++) {
263-
elements[start + i] <= updatedSubset[i];
264-
}
265-
}
266237
}

lib/src/signals/logic_structure.dart

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,19 @@ class LogicStructure implements Logic {
364364
return newWithSet;
365365
}
366366

367+
@override
368+
void assignSubset(List<Logic> updatedSubset, {int start = 0}) {
369+
if (updatedSubset.length > elements.length - start) {
370+
throw SignalWidthMismatchException.forWidthOverflow(
371+
updatedSubset.length, elements.length - start);
372+
}
373+
374+
// Assign Logic array from `start` index to `start+updatedSubset.length`
375+
for (var i = 0; i < updatedSubset.length; i++) {
376+
elements[start + i] <= updatedSubset[i];
377+
}
378+
}
379+
367380
@override
368381
Logic operator ~() => ~packed;
369382

@@ -586,4 +599,10 @@ class LogicStructure implements Logic {
586599

587600
@override
588601
List<Logic> get _srcConnections => throw UnsupportedError('Unnecessary');
602+
603+
@override
604+
LogicArray? get _subsetDriver => throw UnsupportedError('Unnecessary');
605+
606+
@override
607+
set _subsetDriver(LogicArray? _) => throw UnsupportedError('Unnecessary');
589608
}

test/assignment_test.dart

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (C) 2021-2023 Intel Corporation
1+
// Copyright (C) 2021-2024 Intel Corporation
22
// SPDX-License-Identifier: BSD-3-Clause
33
//
44
// assignment_test.dart
@@ -25,7 +25,58 @@ class ExampleModule extends Module {
2525
Logic get out => output('out');
2626
}
2727

28+
class LogicSubsetModule extends Module {
29+
LogicSubsetModule(int offset, int resultWidth, Logic subset) {
30+
subset = addInput('subset', subset, width: subset.width);
31+
32+
addOutput('result', width: resultWidth)
33+
.assignSubset(subset.elements, start: offset);
34+
}
35+
}
36+
37+
class MyStruct extends LogicStructure {
38+
final Logic smaller;
39+
final Logic big;
40+
41+
factory MyStruct() => MyStruct._(
42+
Logic(name: 'smaller'),
43+
Logic(name: 'big', width: 8),
44+
);
45+
46+
MyStruct._(this.smaller, this.big) : super([smaller, big], name: 'myStruct');
47+
48+
@override
49+
LogicStructure clone({String? name}) => MyStruct();
50+
}
51+
52+
class LogicStructSubsetModule extends Module {
53+
LogicStructSubsetModule(Logic smaller, Logic big) {
54+
smaller = addInput('smaller', smaller);
55+
big = addInput('big', big, width: 8);
56+
57+
final struct = MyStruct()..assignSubset([smaller, big]);
58+
59+
addOutput('result', width: struct.width) <= struct;
60+
}
61+
}
62+
63+
class LogicNetSubsetModule extends Module {
64+
LogicNetSubsetModule(int offset1, int offset2, LogicNet subset1,
65+
LogicNet subset2, LogicNet result) {
66+
subset1 = addInOut('subset1', subset1, width: subset1.width);
67+
subset2 = addInOut('subset2', subset2, width: subset2.width);
68+
69+
result = addInOut('result', result, width: result.width)
70+
..assignSubset(subset1.elements, start: offset1)
71+
..assignSubset(subset2.elements, start: offset2);
72+
}
73+
}
74+
2875
void main() {
76+
tearDown(() async {
77+
await Simulator.reset();
78+
});
79+
2980
// From https://github.com/intel/rohd/issues/159
3081
// Thank you to @chykon for reporting!
3182
test('const comb assignment', () async {
@@ -43,4 +94,76 @@ void main() {
4394
);
4495
expect(simResult, equals(true));
4596
});
97+
98+
group('assign subset', () {
99+
group('logic', () {
100+
test('single bit', () async {
101+
final mod = LogicSubsetModule(3, 8, Logic());
102+
await mod.build();
103+
104+
final vectors = [
105+
Vector({'subset': bin('1')},
106+
{'result': LogicValue.ofString('zzzz1zzz')}),
107+
];
108+
109+
await SimCompare.checkFunctionalVector(mod, vectors);
110+
SimCompare.checkIverilogVector(mod, vectors);
111+
});
112+
113+
test('multiple bits', () async {
114+
final mod = LogicSubsetModule(2, 8, Logic(width: 4));
115+
await mod.build();
116+
117+
final vectors = [
118+
Vector({'subset': bin('0110')},
119+
{'result': LogicValue.ofString('zz0110zz')}),
120+
];
121+
122+
await SimCompare.checkFunctionalVector(mod, vectors);
123+
SimCompare.checkIverilogVector(mod, vectors);
124+
});
125+
126+
test('width mismatch fails', () {
127+
expect(() => Logic(width: 8).assignSubset([Logic(width: 4)]),
128+
throwsA(isA<SignalWidthMismatchException>()));
129+
});
130+
131+
test('out of bounds fails', () {
132+
expect(() => Logic(width: 8).assignSubset([Logic(), Logic()], start: 7),
133+
throwsA(isA<SignalWidthMismatchException>()));
134+
});
135+
});
136+
137+
test('logic structure', () async {
138+
final mod = LogicStructSubsetModule(Logic(), Logic(width: 8));
139+
await mod.build();
140+
141+
final vectors = [
142+
Vector(
143+
{'smaller': bin('1'), 'big': bin('1010')}, {'result': bin('10101')})
144+
];
145+
146+
await SimCompare.checkFunctionalVector(mod, vectors);
147+
SimCompare.checkIverilogVector(mod, vectors);
148+
});
149+
150+
test('logic net is multi-assignable', () async {
151+
final mod = LogicNetSubsetModule(
152+
2,
153+
4,
154+
LogicNet(width: 4),
155+
LogicNet(width: 4),
156+
LogicNet(width: 8),
157+
);
158+
await mod.build();
159+
160+
final vectors = [
161+
Vector({'subset1': bin('0000'), 'subset2': bin('1111')},
162+
{'result': LogicValue.ofString('11xx00zz')}),
163+
];
164+
165+
await SimCompare.checkFunctionalVector(mod, vectors);
166+
SimCompare.checkIverilogVector(mod, vectors);
167+
});
168+
});
46169
}

0 commit comments

Comments
 (0)