-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
248 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,10 +8,10 @@ | |
// Author: Max Korbel <[email protected]> | ||
|
||
import 'dart:async'; | ||
import 'dart:collection'; | ||
import 'dart:convert'; | ||
import 'dart:io'; | ||
|
||
import 'package:collection/collection.dart'; | ||
import 'package:logging/logging.dart'; | ||
import 'package:rohd/rohd.dart'; | ||
// ignore: implementation_imports | ||
|
@@ -258,11 +258,27 @@ mixin Cosim on ExternalSystemVerilogModule { | |
Future<void> _sendInput(Logic inputSignal, LogicValue newValue) async { | ||
assert( | ||
inputSignal.parentModule! == this, 'Signal should be in this Cosim.'); | ||
await _socketLock.synchronized(() async { | ||
_send('DRIVE:' | ||
'${_cosimSignalName(inputSignal)}:' | ||
'${newValue.toString(includeWidth: false)}'); | ||
}); | ||
|
||
if (inputSignal is LogicArray && inputSignal.numUnpackedDimensions > 0) { | ||
var idx = 0; | ||
for (final element in inputSignal.flattenedUnpacked) { | ||
await _socketLock.synchronized(() async { | ||
_send('DRIVE:' | ||
'${_cosimSignalName(inputSignal)}[$idx]:' | ||
'${newValue.getRange( | ||
idx * element.width, | ||
idx * element.width + element.width, | ||
).toString(includeWidth: false)}'); | ||
}); | ||
idx++; | ||
} | ||
} else { | ||
await _socketLock.synchronized(() async { | ||
_send('DRIVE:' | ||
'${_cosimSignalName(inputSignal)}:' | ||
'${newValue.toString(includeWidth: false)}'); | ||
}); | ||
} | ||
} | ||
|
||
/// Transmits all input values to cosim. | ||
|
@@ -300,13 +316,27 @@ mixin Cosim on ExternalSystemVerilogModule { | |
final signalNameSplit = event.signalName!.split('.'); | ||
final registreeName = signalNameSplit[0]; | ||
final portName = signalNameSplit[1]; | ||
|
||
if (!_registrees.containsKey(registreeName)) { | ||
throw Exception('Did not find registered module named "$registreeName",' | ||
' but received a message from the cosim process attempting to' | ||
' drive this signal: "${event.signalName}"'); | ||
} | ||
// ignore: unnecessary_null_checks | ||
_registrees[registreeName]!.output(portName).put(event.signalValue!); | ||
|
||
// handle case where there was an unpacked array (should end with ']') | ||
if (portName.endsWith(']')) { | ||
final splitPortName = portName.split(RegExp(r'[\[\]]')); | ||
final arrayName = splitPortName[0]; | ||
final arrayIndex = int.parse(splitPortName[1]); | ||
(_registrees[registreeName]!.output(arrayName) as LogicArray) | ||
.flattenedUnpacked | ||
.toList()[arrayIndex] | ||
// ignore: unnecessary_null_checks | ||
.put(event.signalValue!); | ||
} else { | ||
// ignore: unnecessary_null_checks | ||
_registrees[registreeName]!.output(portName).put(event.signalValue!); | ||
} | ||
}); | ||
|
||
_receivedStream | ||
|
@@ -545,12 +575,22 @@ async def setup_connections(dut, connector : rohd_connector.RohdConnector): | |
// no need to listen to 0-bit signals, they probably don't even exist | ||
continue; | ||
} | ||
// ignore: missing_whitespace_between_adjacent_strings | ||
pythonFileContents.write(' cocotb.start_soon(' | ||
'connector.listen_to_signal(' | ||
"'${registree._cosimSignalName(outputLogic)}'," | ||
' $cocoTbHier.$outputName' | ||
'))\n'); | ||
if (outputLogic is LogicArray && | ||
outputLogic.numUnpackedDimensions > 0) { | ||
for (var i = 0; i < outputLogic.flattenedUnpackedCount; i++) { | ||
pythonFileContents.write(' cocotb.start_soon( ' | ||
'connector.listen_to_signal(' | ||
"'${registree._cosimSignalName(outputLogic)}[$i]'," | ||
' $cocoTbHier.$outputName[$i] ' | ||
'))\n'); | ||
} | ||
} else { | ||
pythonFileContents.write(' cocotb.start_soon( ' | ||
'connector.listen_to_signal(' | ||
"'${registree._cosimSignalName(outputLogic)}'," | ||
' $cocoTbHier.$outputName ' | ||
'))\n'); | ||
} | ||
} | ||
for (final inputEntry in registree.inputs.entries) { | ||
final inputName = inputEntry.key; | ||
|
@@ -559,9 +599,18 @@ async def setup_connections(dut, connector : rohd_connector.RohdConnector): | |
// no need to drive 0-bit signals, they probably don't even exist | ||
continue; | ||
} | ||
pythonFileContents.write( | ||
" nameToSignalMap['${registree._cosimSignalName(inputLogic)}'] " | ||
'= $cocoTbHier.$inputName\n'); | ||
|
||
if (inputLogic is LogicArray && inputLogic.numUnpackedDimensions > 0) { | ||
for (var i = 0; i < inputLogic.flattenedUnpackedCount; i++) { | ||
pythonFileContents.write(' nameToSignalMap[ ' | ||
"'${registree._cosimSignalName(inputLogic)}[$i]' ] " | ||
'= $cocoTbHier.$inputName[$i]\n'); | ||
} | ||
} else { | ||
pythonFileContents.write(' nameToSignalMap[ ' | ||
"'${registree._cosimSignalName(inputLogic)}' ] " | ||
'= $cocoTbHier.$inputName\n'); | ||
} | ||
} | ||
} | ||
pythonFileContents | ||
|
@@ -572,3 +621,19 @@ async def setup_connections(dut, connector : rohd_connector.RohdConnector): | |
File('$directory/__init__.py').writeAsStringSync(''); | ||
} | ||
} | ||
|
||
extension on LogicArray { | ||
/// Returns all unpacked dimensions as a flattened iterable. | ||
Iterable<Logic> get flattenedUnpacked { | ||
Iterable<Logic> flattenedElements = elements; | ||
for (var i = 0; i < numUnpackedDimensions - 1; i++) { | ||
flattenedElements = flattenedElements.map((e) => e.elements).flattened; | ||
} | ||
return flattenedElements; | ||
} | ||
|
||
/// Returns the number of elements in [flattenedUnpacked]. | ||
int get flattenedUnpackedCount => numUnpackedDimensions == 0 | ||
? 0 | ||
: dimensions.getRange(0, numUnpackedDimensions).fold(1, (a, b) => a * b); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
// Copyright (C) 2023 Intel Corporation | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// array_test.dart | ||
// Tests for array functionality | ||
// | ||
// 2023 November 28 | ||
// Author: Max Korbel <[email protected]> | ||
|
||
import 'package:rohd/rohd.dart'; | ||
import 'package:rohd/src/utilities/simcompare.dart'; | ||
import 'package:rohd_cosim/rohd_cosim.dart'; | ||
import 'package:test/test.dart'; | ||
|
||
import 'cosim_test_infra.dart'; | ||
|
||
class CosimArrayMod extends ExternalSystemVerilogModule with Cosim { | ||
LogicArray get b => output('b') as LogicArray; | ||
|
||
@override | ||
List<String> get verilogSources => ['../../test/cosim_array.sv']; | ||
|
||
CosimArrayMod( | ||
Logic a, { | ||
super.name = 'arraymod', | ||
int numUnpackedDimensions = 0, | ||
}) : assert(numUnpackedDimensions >= 0 && numUnpackedDimensions <= 2, | ||
'only supports 0,1,2'), | ||
super(definitionName: 'my_cosim_array_2p${numUnpackedDimensions}u') { | ||
final dimensions = [ | ||
if (numUnpackedDimensions >= 2) 5, | ||
if (numUnpackedDimensions >= 1) 4, | ||
3, | ||
]; | ||
|
||
addInputArray('a', a, | ||
dimensions: dimensions, | ||
elementWidth: 2, | ||
numUnpackedDimensions: numUnpackedDimensions); | ||
addOutputArray('b', | ||
dimensions: dimensions, | ||
elementWidth: 2, | ||
numUnpackedDimensions: numUnpackedDimensions); | ||
} | ||
} | ||
|
||
Future<void> main() async { | ||
tearDown(() async { | ||
await Simulator.reset(); | ||
await Cosim.reset(); | ||
}); | ||
|
||
group('cosim array', () { | ||
List<Vector> walkingOnes(int width) { | ||
final vectors = <Vector>[]; | ||
for (var i = 0; i < width; i++) { | ||
final shiftedOne = LogicValue.ofInt(1, width) << i; | ||
vectors.add(Vector({'a': shiftedOne}, {'b': shiftedOne})); | ||
} | ||
return vectors; | ||
} | ||
|
||
test('2 packed, 0 unpacked', () async { | ||
final mod = CosimArrayMod(Logic(width: 6)); | ||
await mod.build(); | ||
|
||
const dirName = 'simple_array_2p0u'; | ||
|
||
await CosimTestingInfrastructure.connectCosim(dirName); | ||
|
||
final vectors = [ | ||
Vector({'a': 0}, {'b': 0}), | ||
Vector({'a': LogicValue.ofString('01xz10')}, | ||
{'b': LogicValue.ofString('01xz10')}), | ||
...walkingOnes(6) | ||
]; | ||
await SimCompare.checkFunctionalVector(mod, vectors); | ||
|
||
await CosimTestingInfrastructure.cleanupCosim(dirName); | ||
}); | ||
|
||
test('2 packed, 1 unpacked', () async { | ||
final mod = CosimArrayMod(Logic(width: 6 * 4), numUnpackedDimensions: 1); | ||
await mod.build(); | ||
|
||
const dirName = 'simple_array_2p1u'; | ||
|
||
await CosimTestingInfrastructure.connectCosim(dirName); | ||
|
||
final vectors = [ | ||
Vector({'a': 0}, {'b': 0}), | ||
Vector({'a': LogicValue.ofString('01xz10' * 4)}, | ||
{'b': LogicValue.ofString('01xz10' * 4)}), | ||
...walkingOnes(24), | ||
]; | ||
|
||
await SimCompare.checkFunctionalVector(mod, vectors); | ||
|
||
await CosimTestingInfrastructure.cleanupCosim(dirName); | ||
}); | ||
|
||
test('2 packed, 2 unpacked', () async { | ||
final mod = | ||
CosimArrayMod(Logic(width: 6 * 4 * 5), numUnpackedDimensions: 2); | ||
await mod.build(); | ||
|
||
const dirName = 'simple_array_2p2u'; | ||
|
||
await CosimTestingInfrastructure.connectCosim(dirName); | ||
|
||
final vectors = [ | ||
Vector({'a': 0}, {'b': 0}), | ||
Vector({'a': LogicValue.ofString('01xz10' * 4 * 5)}, | ||
{'b': LogicValue.ofString('01xz10' * 4 * 5)}), | ||
...walkingOnes(120), | ||
]; | ||
await SimCompare.checkFunctionalVector(mod, vectors); | ||
|
||
await CosimTestingInfrastructure.cleanupCosim(dirName); | ||
}); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Copyright (C) 2023 Intel Corporation | ||
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// cosim_array.sv | ||
// A simple SystemVerilog module for testing cosimulation with arrays. | ||
// | ||
// 2022 | ||
// Author: Max Korbel <[email protected]> | ||
|
||
// 2 packed, 2 unpacked | ||
module my_cosim_array_2p2u( | ||
input logic[2:0][1:0] a [4:0][3:0], | ||
output logic[2:0][1:0] b [4:0][3:0] | ||
); | ||
|
||
assign b = a; | ||
|
||
endmodule | ||
|
||
// 2 packed, 1 unpacked | ||
module my_cosim_array_2p1u( | ||
input logic[2:0][1:0] a [3:0], | ||
output logic[2:0][1:0] b [3:0] | ||
); | ||
|
||
assign b = a; | ||
|
||
endmodule | ||
|
||
// 2 packed, 0 unpacked | ||
module my_cosim_array_2p0u( | ||
input logic[2:0][1:0] a, | ||
output logic[2:0][1:0] b | ||
); | ||
|
||
assign b = a; | ||
|
||
endmodule |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,7 +2,7 @@ | |
// SPDX-License-Identifier: BSD-3-Clause | ||
// | ||
// cosim_bus.sv | ||
// A simple SystemVerilog module for testing cosimulation. | ||
// A simple SystemVerilog module for testing cosimulation with busses. | ||
// | ||
// 2022 | ||
// Author: Max Korbel <[email protected]> | ||
|