Skip to content

Commit

Permalink
RTL to have one array-array assignment instead of bit blasted assignm…
Browse files Browse the repository at this point in the history
…ents (#487)
  • Loading branch information
sshankar4 authored Jun 13, 2024
1 parent b1331ae commit 9cad7eb
Show file tree
Hide file tree
Showing 2 changed files with 165 additions and 1 deletion.
57 changes: 56 additions & 1 deletion lib/src/synthesizers/systemverilog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -882,6 +882,7 @@ class _SynthModuleDefinition {
}

// The order of these is important!
_collapseArrays();
_collapseAssignments();
_assignSubmodulePortMapping();
_replaceNetConnections();
Expand Down Expand Up @@ -1103,6 +1104,59 @@ class _SynthModuleDefinition {
}
}

/// Merges bit blasted array assignments into one single assignment when
/// it's full array-full array assignment
void _collapseArrays() {
final boringArrayPairs = <(_SynthLogic, _SynthLogic)>[];

var prevAssignmentCount = 0;
while (prevAssignmentCount != assignments.length) {
final reducedAssignments = <_SynthAssignment>[];

final groupedAssignments =
<(_SynthLogic, _SynthLogic), List<_SynthAssignment>>{};

for (final assignment in assignments) {
final src = assignment.src;
final dst = assignment.dst;

if (src is _SynthLogicArrayElement && dst is _SynthLogicArrayElement) {
final srcArray = src.parentArray;
final dstArray = dst.parentArray;

assert(srcArray.logics.length == 1, 'should be 1');
assert(dstArray.logics.length == 1, 'should be 1');

if (srcArray.logics.first.elements.length !=
dstArray.logics.first.elements.length ||
boringArrayPairs.contains((srcArray, dstArray))) {
reducedAssignments.add(assignment);
} else {
groupedAssignments[(srcArray, dstArray)] ??= [];
groupedAssignments[(srcArray, dstArray)]!.add(assignment);
}
} else {
reducedAssignments.add(assignment);
}
}

for (final MapEntry(key: (srcArray, dstArray), value: arrAssignments)
in groupedAssignments.entries) {
if (arrAssignments.length == srcArray.logics.first.elements.length) {
reducedAssignments.add(_SynthAssignment(srcArray, dstArray));
} else {
reducedAssignments.addAll(arrAssignments);
boringArrayPairs.add((srcArray, dstArray));
}
}

prevAssignmentCount = assignments.length;
assignments
..clear()
..addAll(reducedAssignments);
}
}

/// Collapses assignments that don't need to remain present.
void _collapseAssignments() {
// there might be more assign statements than necessary, so let's ditch them
Expand Down Expand Up @@ -1183,7 +1237,8 @@ class _SynthLogicArrayElement extends _SynthLogic {

@override
String get name {
final n = '${parentArray.name}[${logic.arrayIndex!}]';
final parentArrayname = parentArray.replacement?.name ?? parentArray.name;
final n = '$parentArrayname[${logic.arrayIndex!}]';
assert(
Sanitizer.isSanitary(
n.substring(0, n.contains('[') ? n.indexOf('[') : null)),
Expand Down
109 changes: 109 additions & 0 deletions test/array_collapsing_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// array_collapsing_test.dart
// Tests for array collapsing
//
// 2024 June 5
// Author: Shankar Sharma <[email protected]>

import 'package:rohd/rohd.dart';
import 'package:rohd/src/utilities/simcompare.dart';
import 'package:test/test.dart';

class ArrayModule extends Module {
ArrayModule(LogicArray a) {
final inpA = addInputArray('a', a, dimensions: a.dimensions);
addOutputArray('b', dimensions: a.dimensions) <= inpA;

final inoutA = addInOutArray('c', a, dimensions: a.dimensions);
addOutputArray('d', dimensions: [a.dimensions.last]) <=
inoutA.elements.first;
}
}

class ArrayModuleWithNetIntermediates extends Module {
ArrayModuleWithNetIntermediates(LogicArray a, LogicArray b) {
a = addInOutArray('a', a,
dimensions: a.dimensions,
elementWidth: a.elementWidth,
numUnpackedDimensions: a.numUnpackedDimensions);

final intermediate = LogicArray.net(
a.dimensions,
a.elementWidth,
name: 'intermediate',
naming: Naming.reserved,
);

b = addInOutArray('b', b,
dimensions: a.dimensions,
elementWidth: a.elementWidth,
numUnpackedDimensions: a.numUnpackedDimensions);

intermediate <= a;
b <= intermediate;
}
}

void main() {
tearDown(() async {
await Simulator.reset();
});
test('array nets with intermediate collapse', () async {
final mod = ArrayModuleWithNetIntermediates(
LogicArray([3, 3], 1), LogicArray([3, 3], 1));
await mod.build();

final sv = mod.generateSynth();
expect(sv,
contains('net_connect #(.WIDTH(9)) net_connect (intermediate, a);'));
expect(sv,
contains('net_connect #(.WIDTH(9)) net_connect_0 (b, intermediate);'));

final vectors = [
Vector({'a': 0}, {'b': 0}),
Vector({'a': 123}, {'b': 123}),
];
await SimCompare.checkFunctionalVector(mod, vectors);
SimCompare.checkIverilogVector(mod, vectors);
});

test('array nets with intermediate collapse with unpacked', () async {
final mod = ArrayModuleWithNetIntermediates(
LogicArray([3, 3], 1, numUnpackedDimensions: 2),
LogicArray([3, 3], 1, numUnpackedDimensions: 2));
await mod.build();

final sv = mod.generateSynth();
expect(sv,
contains('net_connect #(.WIDTH(9)) net_connect (intermediate, a);'));
expect(sv,
contains('net_connect #(.WIDTH(9)) net_connect_0 (b, intermediate);'));

final vectors = [
Vector({'a': 0}, {'b': 0}),
Vector({'a': 123}, {'b': 123}),
];
await SimCompare.checkFunctionalVector(mod, vectors);
});

test('collapse test 2d', () async {
final mod = ArrayModule(LogicArray([4, 4], 1));
await mod.build();

final sv = mod.generateSynth();

expect(sv, contains('assign d = c[0];'));
expect(sv, contains('assign b = a;'));

final vectors = [
Vector({'a': 0}, {'b': 0}),
Vector({'a': 123}, {'b': 123}),
Vector({'c': 6}, {'d': 6}),
];

await SimCompare.checkFunctionalVector(mod, vectors);
SimCompare.checkIverilogVector(mod, vectors);
});
}

0 comments on commit 9cad7eb

Please sign in to comment.