diff --git a/lib/src/logic.dart b/lib/src/logic.dart index 50c9d50c3..453344b1e 100644 --- a/lib/src/logic.dart +++ b/lib/src/logic.dart @@ -449,15 +449,53 @@ class Logic { } /// Accesses the [index]th bit of this signal. + /// + /// Negative/Positive index values are allowed. (The negative indexing starts from the end=[width]-1) + /// -([width]) <= [index] < [width] + /// + /// ```dart + /// Logic nextVal = addOutput('nextVal', width: width); + /// // Example: val = 0xce, val.width = 8, bin(0xce) = "0b11001110" + /// // Positive Indexing + /// nextVal <= val[3]; // output: 1 + /// + /// // Negative Indexing + /// nextVal <= val[-5]; // output: 1, also val[3] == val[-5] + /// + /// // Error cases + /// nextVal <= val[-9]; // Error!: allowed values [-8, 7] + /// nextVal <= val[8]; // Error!: allowed values [-8, 7] + /// ``` + /// Logic operator [](int index) => slice(index, index); /// Accesses a subset of this signal from [startIndex] to [endIndex], /// both inclusive. /// - /// If [endIndex] is less than [startIndex], the returned value will be - /// reversed relative to the original signal. - Logic slice(int endIndex, int startIndex) => - BusSubset(this, startIndex, endIndex).subset; + /// If [endIndex] comes before the [startIndex] on position, the returned + /// value will be reversed relative to the original signal. + /// Negative/Positive index values are allowed. (The negative indexing starts from where the array ends) + /// + /// ```dart + /// Logic nextVal = addOutput('nextVal', width: width); + /// // Example: val = 0xce, val.width = 8, bin(0xce) = "0b11001110" + /// // Negative Slicing + /// nextVal <= val.slice(val.width - 1, -3); // = val.slice(7,5) & output: 0b110, where the output.width=3 + /// + /// // Positive Slicing + /// nextVal <= val.slice(5, 0); // = val.slice(-3, -8) & output: 0b001110, where the output.width=6 + /// ``` + /// + Logic slice(int endIndex, int startIndex) { + // Given start and end index, if either of them are seen to be -ve index + // value(s) then convert them to a +ve index value(s) + final modifiedStartIndex = + (startIndex < 0) ? width + startIndex : startIndex; + final modifiedEndIndex = (endIndex < 0) ? width + endIndex : endIndex; + + // Create a new bus subset + return BusSubset(this, modifiedStartIndex, modifiedEndIndex).subset; + } /// Returns a version of this [Logic] with the bit order reversed. Logic get reversed => slice(0, width - 1); @@ -465,24 +503,36 @@ class Logic { /// Returns a subset [Logic]. It is inclusive of [startIndex], exclusive of /// [endIndex]. /// - /// [startIndex] must be less than [endIndex]. If [startIndex] and [endIndex] - /// are equal, then a zero-width signal is returned. + /// The [startIndex] must come before the [endIndex]. If [startIndex] and + /// [endIndex] are equal, then a zero-width signal is returned. + /// Negative/Positive index values are allowed. (The negative indexing starts from where the array ends) + /// + /// ```dart + /// Logic nextVal = addOutput('nextVal', width: width); + /// // Example: val = 0xce, val.width = 8, bin(0xce) = "0b11001110" + /// // Negative getRange + /// nextVal <= val.getRange(-3, val.width); // = val.getRange(5,8) & output: 0b110, where the output.width=3 + /// + /// // Positive getRange + /// nextVal <= val.getRange(0, 6); // = val.slice(0, -2) & output: 0b001110, where the output.width=6 + /// ``` + /// Logic getRange(int startIndex, int endIndex) { - if (endIndex < startIndex) { - throw Exception( - 'End ($endIndex) cannot be less than start ($startIndex).'); - } - if (endIndex > width) { - throw Exception('End ($endIndex) must be less than width ($width).'); - } - if (startIndex < 0) { - throw Exception( - 'Start ($startIndex) must be greater than or equal to 0.'); - } if (endIndex == startIndex) { return Const(0, width: 0); } - return slice(endIndex - 1, startIndex); + + // Given start and end index, if either of them are seen to be -ve index + // value(s) then conver them to a +ve index value(s) + final modifiedStartIndex = + (startIndex < 0) ? width + startIndex : startIndex; + final modifiedEndIndex = (endIndex < 0) ? width + endIndex : endIndex; + if (modifiedEndIndex < modifiedStartIndex) { + throw Exception( + 'End $modifiedEndIndex(=$endIndex) cannot be less than start' + ' $modifiedStartIndex(=$startIndex).'); + } + return slice(modifiedEndIndex - 1, modifiedStartIndex); } /// Returns a new [Logic] with width [newWidth] where new bits added are zeros diff --git a/lib/src/modules/bus.dart b/lib/src/modules/bus.dart index b24393f5e..c8be6c200 100644 --- a/lib/src/modules/bus.dart +++ b/lib/src/modules/bus.dart @@ -38,13 +38,18 @@ class BusSubset extends Module with InlineSystemVerilog { BusSubset(Logic bus, this.startIndex, this.endIndex, {String name = 'bussubset'}) : super(name: name) { + // If a converted index value is still -ve then it's an Index out of bounds + // on a Logic Bus if (startIndex < 0 || endIndex < 0) { - throw Exception('Cannot access negative indices!' - ' Indices $startIndex and/or $endIndex are invalid.'); + throw Exception( + 'Start ($startIndex) and End ($endIndex) must be greater than or ' + 'equal to 0.'); } + // If the +ve indices are more than Logic bus width, Index out of bounds if (endIndex > bus.width - 1 || startIndex > bus.width - 1) { - throw Exception('Index out of bounds, indices $startIndex and' - ' $endIndex must be less than width-1'); + throw Exception( + 'Index out of bounds, indices $startIndex and $endIndex must be less' + ' than ${bus.width}'); } // original name can't be unpreferred because you cannot do a bit slice diff --git a/lib/src/utilities/simcompare.dart b/lib/src/utilities/simcompare.dart index 4afee1946..48e9b6085 100644 --- a/lib/src/utilities/simcompare.dart +++ b/lib/src/utilities/simcompare.dart @@ -204,7 +204,7 @@ abstract class SimCompare { Directory(dir).createSync(recursive: true); File(tmpTestFile).writeAsStringSync(testbench); final compileResult = Process.runSync('iverilog', - ['-g2012', tmpTestFile, '-o', tmpOutput] + iverilogExtraArgs); + ['-g2012', '-o', tmpOutput, ...iverilogExtraArgs, tmpTestFile]); bool printIfContentsAndCheckError(dynamic output) { if (output.toString().isNotEmpty) { print(output); diff --git a/lib/src/values/logic_value.dart b/lib/src/values/logic_value.dart index 4acd9058d..8d8c22629 100644 --- a/lib/src/values/logic_value.dart +++ b/lib/src/values/logic_value.dart @@ -298,12 +298,28 @@ abstract class LogicValue { } /// Returns the `i`th bit of this [LogicValue] + /// + /// The [index] provided can be positive or negative. For positive [index], + /// the indexing is performed from front of the LogicValue. + /// For negative [index], the indexing started from last index and + /// goes to front. + /// Note: the [index] value must follow, -[width] <= [index] < [width] + /// + /// ```dart + /// LogicValue.ofString('1111')[2]; // == LogicValue.one + /// LogicValue.ofString('0111')[-1]; // == LogicValue.zero + /// LogicValue.ofString('0100')[-2]; // == LogicValue.one + /// LogicValue.ofString('0101')[-5]; // Error - out of range + /// LogicValue.ofString('0101')[10]; // Error - out of range + /// ``` + /// LogicValue operator [](int index) { - if (index >= width || index < 0) { + final modifiedIndex = (index < 0) ? width + index : index; + if (modifiedIndex >= width || modifiedIndex < 0) { throw IndexError(index, this, 'LogicValueIndexOutOfRange', - 'Index out of range: $index.', width); + 'Index out of range: $modifiedIndex(=$index).', width); } - return _getIndex(index); + return _getIndex(modifiedIndex); } /// Returns the `i`th bit of this [LogicValue]. Performs no boundary checks. @@ -316,21 +332,39 @@ abstract class LogicValue { /// Returns a subset [LogicValue]. It is inclusive of [startIndex], exclusive /// of [endIndex]. /// - /// [startIndex] must be less than [endIndex]. If [startIndex] and [endIndex] - /// are equal, then a zero-width value is returned. + /// [startIndex] must come before the [endIndex] on position. If [startIndex] + /// and [endIndex] are equal, then a zero-width value is returned. + /// Negative/Positive index values are allowed. (The negative indexing starts from the end=[width]-1) + /// + /// ```dart [TODO] + /// LogicValue.ofString('0101').getRange(0, 2); // == LogicValue.ofString('01') + /// LogicValue.ofString('0101').getRange(1, -2); // == LogicValue.zero + /// LogicValue.ofString('0101').getRange(-3, 4); // == LogicValue.ofString('010') + /// LogicValue.ofString('0101').getRange(-1, -2); // Error - negative end index and start > end - error! start must be less than end + /// LogicValue.ofString('0101').getRange(2, 1); // Error - bad inputs start > end + /// LogicValue.ofString('0101').getRange(0, 7); // Error - bad inputs end > length-1 + /// ``` + /// LogicValue getRange(int startIndex, int endIndex) { - if (endIndex < startIndex) { + final modifiedStartIndex = + (startIndex < 0) ? width + startIndex : startIndex; + final modifiedEndIndex = (endIndex < 0) ? width + endIndex : endIndex; + if (modifiedEndIndex < modifiedStartIndex) { throw Exception( - 'End ($endIndex) cannot be less than start ($startIndex).'); + 'End $modifiedEndIndex(=$endIndex) cannot be less than start ' + '$modifiedStartIndex(=$startIndex).'); } - if (endIndex > width) { - throw Exception('End ($endIndex) must be less than width ($width).'); + if (modifiedEndIndex > width) { + throw Exception( + 'End $modifiedEndIndex(=$endIndex) must be less than width' + ' ($width).'); } - if (startIndex < 0) { + if (modifiedStartIndex < 0) { throw Exception( - 'Start ($startIndex) must be greater than or equal to 0.'); + 'Start $modifiedStartIndex(=$startIndex) must be greater than or ' + 'equal to 0.'); } - return _getRange(startIndex, endIndex); + return _getRange(modifiedStartIndex, modifiedEndIndex); } /// Returns a subset [LogicValue]. It is inclusive of [start], exclusive of @@ -344,11 +378,22 @@ abstract class LogicValue { /// /// If [endIndex] is less than [startIndex], the returned value will be /// reversed relative to the original value. + /// + /// ```dart [TODO] + /// LogicValue.ofString('xz01').slice(2, 1); // == LogicValue.ofString('z0') + /// LogicValue.ofString('xz01').slice(-2, -3); // == LogicValue.ofString('z0') + /// LogicValue.ofString('xz01').slice(1, 3); // == LogicValue.ofString('0zx') + /// LogicValue.ofString('xz01').slice(-3, -1); // == LogicValue.ofString('0zx') + /// LogicValue.ofString('xz01').slice(-2, -2); // == LogicValue.ofString('z') + /// ``` LogicValue slice(int endIndex, int startIndex) { - if (startIndex <= endIndex) { - return getRange(startIndex, endIndex + 1); + final modifiedStartIndex = + (startIndex < 0) ? width + startIndex : startIndex; + final modifiedEndIndex = (endIndex < 0) ? width + endIndex : endIndex; + if (modifiedStartIndex <= modifiedEndIndex) { + return getRange(modifiedStartIndex, modifiedEndIndex + 1); } else { - return getRange(endIndex, startIndex + 1).reversed; + return getRange(modifiedEndIndex, modifiedStartIndex + 1).reversed; } } diff --git a/test/bus_test.dart b/test/bus_test.dart index bb5d1b596..4709ec041 100644 --- a/test/bus_test.dart +++ b/test/bus_test.dart @@ -12,17 +12,46 @@ import 'package:rohd/src/utilities/simcompare.dart'; import 'package:test/test.dart'; class BusTestModule extends Module { + // --- Getters --- Logic get aBar => output('a_bar'); Logic get aAndB => output('a_and_b'); - Logic get aShrunk => output('a_shrunk'); - Logic get aRSliced => output('a_rsliced'); - Logic get aReversed => output('a_reversed'); - Logic get aRange => output('a_range'); Logic get aBJoined => output('a_b_joined'); Logic get a1 => output('a1'); Logic get aPlusB => output('a_plus_b'); + // Getters for Logic subset test variables + Logic get aReversed => output('a_reversed'); + // --- Getters for Slicing + Logic get aShrunk1 => output('a_shrunk1'); + Logic get aShrunk2 => output('a_shrunk2'); + Logic get aShrunk3 => output('a_shrunk3'); + Logic get aNegShrunk1 => output('a_neg_shrunk1'); + Logic get aNegShrunk2 => output('a_neg_shrunk2'); + Logic get aNegShrunk3 => output('a_neg_shrunk3'); + // --- Getters for Reverse Slicing + Logic get aRSliced1 => output('a_rsliced1'); + Logic get aRSliced2 => output('a_rsliced2'); + Logic get aRSliced3 => output('a_rsliced3'); + Logic get aRNegativeSliced1 => output('a_r_neg_sliced1'); + Logic get aRNegativeSliced2 => output('a_r_neg_sliced2'); + Logic get aRNegativeSliced3 => output('a_r_neg_sliced3'); + // --- Getters for getRange + Logic get aRange1 => output('a_range1'); + Logic get aRange2 => output('a_range2'); + Logic get aRange3 => output('a_range3'); + Logic get aNegativeRange1 => output('a_neg_range1'); + Logic get aNegativeRange2 => output('a_neg_range2'); + Logic get aNegativeRange3 => output('a_neg_range3'); + // --- Getters for operator[] + Logic get aOperatorIndexing1 => output('a_operator_indexing1'); + Logic get aOperatorIndexing2 => output('a_operator_indexing2'); + Logic get aOperatorIndexing3 => output('a_operator_indexing3'); + Logic get aOperatorNegIndexing1 => output('a_operator_neg_indexing1'); + Logic get aOperatorNegIndexing2 => output('a_operator_neg_indexing2'); + Logic get aOperatorNegIndexing3 => output('a_operator_neg_indexing3'); + BusTestModule(Logic a, Logic b) : super(name: 'bustestmodule') { + // --- Declaration --- if (a.width != b.width) { throw Exception('a and b must be same width, but found "$a" and "$b".'); } @@ -34,26 +63,86 @@ class BusTestModule extends Module { final aBar = addOutput('a_bar', width: a.width); final aAndB = addOutput('a_and_b', width: a.width); - final aShrunk = addOutput('a_shrunk', width: 3); - final aRSliced = addOutput('a_rsliced', width: 5); - final aReversed = addOutput('a_reversed', width: a.width); - final aRange = addOutput('a_range', width: 3); + final aBJoined = addOutput('a_b_joined', width: a.width + b.width); final aPlusB = addOutput('a_plus_b', width: a.width); final a1 = addOutput('a1'); final expressionBitSelect = addOutput('expression_bit_select', width: 4); + // Logic Reverse value + final aReversed = addOutput('a_reversed', width: a.width); + // Slicing with Positive Indices + final aShrunk1 = addOutput('a_shrunk1', width: 3); + final aShrunk2 = addOutput('a_shrunk2', width: 2); + final aShrunk3 = addOutput('a_shrunk3'); + // Slicing with negative indices + final aNegativeShrunk1 = addOutput('a_neg_shrunk1', width: 3); + final aNegativeShrunk2 = addOutput('a_neg_shrunk2', width: 2); + final aNegativeShrunk3 = addOutput('a_neg_shrunk3'); + // Slicing and reversing the value + final aRSliced1 = addOutput('a_rsliced1', width: 5); + final aRSliced2 = addOutput('a_rsliced2', width: 2); + final aRSliced3 = addOutput('a_rsliced3'); + // Slicing and reversing the value via negative indices + final aRNegativeSliced1 = addOutput('a_r_neg_sliced1', width: 5); + final aRNegativeSliced2 = addOutput('a_r_neg_sliced2', width: 2); + final aRNegativeSliced3 = addOutput('a_r_neg_sliced3'); + // Getting the range of consecutive values over the Logic (subset) + final aRange1 = addOutput('a_range1', width: 3); + final aRange2 = addOutput('a_range2', width: 2); + final aRange3 = addOutput('a_range3'); + final aNegativeRange1 = addOutput('a_neg_range1', width: 3); + final aNegativeRange2 = addOutput('a_neg_range2', width: 2); + final aNegativeRange3 = addOutput('a_neg_range3'); + // Operator Indexing with positive index value + final aOperatorIndexing1 = addOutput('a_operator_indexing1'); + final aOperatorIndexing2 = addOutput('a_operator_indexing2'); + final aOperatorIndexing3 = addOutput('a_operator_indexing3'); + // Operator Indexing with negative index value + final aOperatorNegIndexing1 = addOutput('a_operator_neg_indexing1'); + final aOperatorNegIndexing2 = addOutput('a_operator_neg_indexing2'); + final aOperatorNegIndexing3 = addOutput('a_operator_neg_indexing3'); + + // --- Assignments --- aBar <= ~a; aAndB <= a & b; - aShrunk <= a.slice(2, 0); - aRSliced <= a.slice(3, 7); - aReversed <= a.reversed; - aRange <= a.getRange(5, 8); aBJoined <= [b, a].swizzle(); a1 <= a[1]; aPlusB <= a + b; + + // Logic Subset functionality + aShrunk1 <= a.slice(2, 0); + aShrunk2 <= a.slice(1, 0); + aShrunk3 <= a.slice(0, 0); + aNegativeShrunk1 <= a.slice(-6, 0); + aNegativeShrunk2 <= a.slice(-7, 0); + aNegativeShrunk3 <= a.slice(-8, 0); + + aRSliced1 <= a.slice(3, 7); + aRSliced2 <= a.slice(6, 7); + aRSliced3 <= a.slice(7, 7); + aRNegativeSliced1 <= a.slice(-5, -1); + aRNegativeSliced2 <= a.slice(-2, -1); + aRNegativeSliced3 <= a.slice(-1, -1); + + aRange1 <= a.getRange(5, 8); + aRange2 <= a.getRange(6, 8); + aRange3 <= a.getRange(7, 8); + aNegativeRange1 <= a.getRange(-3, 8); // NOTE: endIndex value is exclusive + aNegativeRange2 <= a.getRange(-2, 8); + aNegativeRange3 <= a.getRange(-1, 8); + + aOperatorIndexing1 <= a[0]; + aOperatorIndexing2 <= a[a.width - 1]; + aOperatorIndexing3 <= a[4]; + aOperatorNegIndexing1 <= a[-a.width]; + aOperatorNegIndexing2 <= a[-1]; + aOperatorNegIndexing3 <= a[-2]; + + aReversed <= a.reversed; + expressionBitSelect <= - [aBJoined, aShrunk, aRange, aRSliced, aPlusB].swizzle().slice(3, 0); + [aBJoined, aShrunk1, aRange1, aRSliced1, aPlusB].swizzle().slice(3, 0); } } @@ -103,7 +192,7 @@ void main() { final a = Logic(width: 8); final b = Logic(width: 8); final gtm = BusTestModule(a, b); - final out = gtm.aShrunk; + final out = gtm.aShrunk1; await gtm.build(); a.put(0); expect(out.value.toInt(), equals(0)); @@ -113,6 +202,31 @@ void main() { expect(out.value.toInt(), equals(5)); }); + test('Operator Indexing', () async { + final a = Logic(width: 8); + final b = Logic(width: 8); + final gtm = BusTestModule(a, b); + final out1 = gtm.aOperatorIndexing1; + final out2 = gtm.aOperatorIndexing2; + final out3 = gtm.aOperatorIndexing3; + final out4 = gtm.aOperatorNegIndexing1; + final out5 = gtm.aOperatorNegIndexing2; + final out6 = gtm.aOperatorNegIndexing3; + await gtm.build(); + a.put(bin('11111110')); + expect(out1.value.toInt(), equals(0)); + a.put(bin('10000000')); + expect(out2.value.toInt(), equals(bin('1'))); + a.put(bin('11101111')); + expect(out3.value.toInt(), equals(bin('0'))); + a.put(bin('11111110')); + expect(out4.value.toInt(), equals(0)); + a.put(bin('10000000')); + expect(out5.value.toInt(), equals(bin('1'))); + a.put(bin('10111111')); + expect(out6.value.toInt(), equals(bin('0'))); + }); + test('Bus swizzle', () async { final a = Logic(width: 8); final b = Logic(width: 8); @@ -143,12 +257,42 @@ void main() { 'b': 8, 'a_bar': 8, 'a_and_b': 8, - 'a_shrunk': 3, - 'a_rsliced': 5, - 'a_reversed': 8, - 'a_range': 3, 'a_b_joined': 16, 'a_plus_b': 8, + + // Slicing + 'a_shrunk1': 3, + 'a_shrunk2': 2, + 'a_shrunk3': 1, + 'a_neg_shrunk1': 3, + 'a_neg_shrunk2': 2, + 'a_neg_shrunk3': 1, + // Reverse Slicing + 'a_rsliced1': 5, + 'a_rsliced2': 2, + 'a_rsliced3': 1, + 'a_r_neg_sliced1': 5, + 'a_r_neg_sliced2': 2, + 'a_r_neg_sliced3': 1, + + // getRange + 'a_range1': 3, + 'a_range2': 2, + 'a_range3': 1, + 'a_neg_range1': 3, + 'a_neg_range2': 2, + 'a_neg_range3': 1, + + // operator[] + 'a_operator_indexing1': 1, + 'a_operator_indexing2': 1, + 'a_operator_indexing3': 1, + 'a_operator_neg_indexing1': 1, + 'a_operator_neg_indexing2': 1, + 'a_operator_neg_indexing3': 1, + + // Logic bus value Reversed + 'a_reversed': 8, 'expression_bit_select': 4, }; test('NotGate bus', () async { @@ -177,6 +321,26 @@ void main() { Vector({'a': 1, 'b': 1}, {'a_and_b': 1}), Vector({'a': 0xff, 'b': 0xaa}, {'a_and_b': 0xaa}), ]; + + await SimCompare.checkFunctionalVector(gtm, vectors); + final simResult = SimCompare.iverilogVector( + gtm.generateSynth(), gtm.runtimeType.toString(), vectors, + signalToWidthMap: signalToWidthMap); + expect(simResult, equals(true)); + }); + + test('Operator indexing', () async { + final gtm = BusTestModule(Logic(width: 8), Logic(width: 8)); + await gtm.build(); + final vectors = [ + Vector({'a': bin('11111110')}, {'a_operator_indexing1': 0}), + Vector({'a': bin('10000000')}, {'a_operator_indexing2': 1}), + Vector({'a': bin('11101111')}, {'a_operator_indexing3': 0}), + Vector({'a': bin('11111110')}, {'a_operator_neg_indexing1': 0}), + Vector({'a': bin('10000000')}, {'a_operator_neg_indexing2': 1}), + Vector({'a': bin('10111111')}, {'a_operator_neg_indexing3': 0}), + ]; + await SimCompare.checkFunctionalVector(gtm, vectors); final simResult = SimCompare.iverilogVector( gtm.generateSynth(), gtm.runtimeType.toString(), vectors, @@ -188,9 +352,33 @@ void main() { final gtm = BusTestModule(Logic(width: 8), Logic(width: 8)); await gtm.build(); final vectors = [ - Vector({'a': 0}, {'a_shrunk': 0}), - Vector({'a': 0xff}, {'a_shrunk': bin('111')}), - Vector({'a': 0xf5}, {'a_shrunk': 5}), + // Positive Indexing + // Test set 1 + Vector({'a': 0}, {'a_shrunk1': 0}), + Vector({'a': 0xfa}, {'a_shrunk1': bin('010')}), + Vector({'a': 0xab}, {'a_shrunk1': 3}), + // Test set 2 + Vector({'a': 0}, {'a_shrunk2': 0}), + Vector({'a': 0xec}, {'a_shrunk2': bin('00')}), + Vector({'a': 0xfa}, {'a_shrunk2': 2}), + // Test set 3 + Vector({'a': 0}, {'a_shrunk3': 0}), + Vector({'a': 0xff}, {'a_shrunk3': bin('1')}), + Vector({'a': 0xba}, {'a_shrunk3': 0}), + + // Negative Indexing + // Test set 1 + Vector({'a': 0}, {'a_neg_shrunk1': 0}), + Vector({'a': 0xfa}, {'a_neg_shrunk1': bin('010')}), + Vector({'a': 0xab}, {'a_neg_shrunk1': 3}), + // Test set 2 + Vector({'a': 0}, {'a_neg_shrunk2': 0}), + Vector({'a': 0xec}, {'a_neg_shrunk2': bin('00')}), + Vector({'a': 0xfa}, {'a_neg_shrunk2': 2}), + // Test set 3 + Vector({'a': 0}, {'a_neg_shrunk3': 0}), + Vector({'a': 0xff}, {'a_neg_shrunk3': bin('1')}), + Vector({'a': 0xba}, {'a_neg_shrunk3': 0}) ]; await SimCompare.checkFunctionalVector(gtm, vectors); final simResult = SimCompare.iverilogVector( @@ -203,9 +391,33 @@ void main() { final gtm = BusTestModule(Logic(width: 8), Logic(width: 8)); await gtm.build(); final vectors = [ - Vector({'a': 0}, {'a_rsliced': 0}), - Vector({'a': 0xff}, {'a_rsliced': bin('11111')}), - Vector({'a': 0xf5}, {'a_rsliced': 0xf}), + // Positive Indexing + // Test set 1 + Vector({'a': 0}, {'a_rsliced1': 0}), + Vector({'a': 0xac}, {'a_rsliced1': bin('10101')}), + Vector({'a': 0xf5}, {'a_rsliced1': 0xf}), + // Test set 2 + Vector({'a': 0}, {'a_rsliced2': 0}), + Vector({'a': 0xab}, {'a_rsliced2': bin('01')}), + Vector({'a': 0xac}, {'a_rsliced2': 1}), + // Test set 3 + Vector({'a': 0}, {'a_rsliced3': 0}), + Vector({'a': 0xaf}, {'a_rsliced3': bin('1')}), + Vector({'a': 0xaf}, {'a_rsliced3': 1}), + + // Negative Indexing + // Test set 1 + Vector({'a': 0}, {'a_r_neg_sliced1': 0}), + Vector({'a': 0xac}, {'a_r_neg_sliced1': bin('10101')}), + Vector({'a': 0xf5}, {'a_r_neg_sliced1': 0xf}), + // Test set 2 + Vector({'a': 0}, {'a_r_neg_sliced2': 0}), + Vector({'a': 0xab}, {'a_r_neg_sliced2': bin('01')}), + Vector({'a': 0xac}, {'a_r_neg_sliced2': 1}), + // Test set 3 + Vector({'a': 0}, {'a_r_neg_sliced3': 0}), + Vector({'a': 0xaf}, {'a_r_neg_sliced3': bin('1')}), + Vector({'a': 0xaf}, {'a_r_neg_sliced3': 1}) ]; await SimCompare.checkFunctionalVector(gtm, vectors); final simResult = SimCompare.iverilogVector( @@ -233,9 +445,33 @@ void main() { final gtm = BusTestModule(Logic(width: 8), Logic(width: 8)); await gtm.build(); final vectors = [ - Vector({'a': 0}, {'a_range': 0}), - Vector({'a': 0xff}, {'a_range': 7}), - Vector({'a': bin('10100101')}, {'a_range': bin('101')}), + // Positive Indexing + // Test set 1 + Vector({'a': 0}, {'a_range1': 0}), + Vector({'a': 0xaf}, {'a_range1': 5}), + Vector({'a': bin('11000101')}, {'a_range1': bin('110')}), + // Test set 2 + Vector({'a': 0}, {'a_range2': 0}), + Vector({'a': 0xaf}, {'a_range2': 2}), + Vector({'a': bin('10111111')}, {'a_range2': bin('10')}), + // Test set 3 + Vector({'a': 0}, {'a_range3': 0}), + Vector({'a': 0x80}, {'a_range3': 1}), + Vector({'a': bin('10000000')}, {'a_range3': bin('1')}), + + // Negative Indexing + // Test set 1 + Vector({'a': 0}, {'a_neg_range1': 0}), + Vector({'a': 0xaf}, {'a_neg_range1': 5}), + Vector({'a': bin('11000101')}, {'a_neg_range1': bin('110')}), + // Test set 2 + Vector({'a': 0}, {'a_neg_range2': 0}), + Vector({'a': 0xaf}, {'a_neg_range2': 2}), + Vector({'a': bin('10111111')}, {'a_neg_range2': bin('10')}), + // Test set 3 + Vector({'a': 0}, {'a_neg_range3': 0}), + Vector({'a': 0x80}, {'a_neg_range3': 1}), + Vector({'a': bin('10000000')}, {'a_neg_range3': bin('1')}), ]; await SimCompare.checkFunctionalVector(gtm, vectors); final simResult = SimCompare.iverilogVector( diff --git a/test/logic_value_test.dart b/test/logic_value_test.dart index 0e8ae6bcb..36d2a44c7 100644 --- a/test/logic_value_test.dart +++ b/test/logic_value_test.dart @@ -318,9 +318,17 @@ void main() { () => LogicValue.ofString('0101')[10], throwsA(isA())); expect( - // index - negative - () => LogicValue.ofString('0101')[-1], + // index - out of range + () => LogicValue.ofString('0101')[-5], throwsA(isA())); + expect( + // index - negative + LogicValue.ofString('0111')[-1], + equals(LogicValue.zero)); + expect( + // index - negative + LogicValue.ofString('0100')[-2], + equals(LogicValue.one)); expect( // reversed LogicValue.ofString('0101').reversed, @@ -330,9 +338,22 @@ void main() { LogicValue.ofString('0101').getRange(0, 2), equals(LogicValue.ofString('01'))); expect( - // getRange - bad inputs start < 0 - () => LogicValue.ofString('0101').getRange(-2, 1), + // getRange - negative end index and start < end + LogicValue.ofString('0101').getRange(1, -2), + LogicValue.zero); + expect( + // getRange - negative end index and start < end + LogicValue.ofString('0101').getRange(-3, 4), + equals(LogicValue.ofString('010'))); + expect( + // getRange - negative end index and start > end - error! start must + // be less than end + () => LogicValue.ofString('0101').getRange(-1, -2), throwsA(isA())); + expect( + // getRange - same index results zero width value + LogicValue.ofString('0101').getRange(-1, -1), + LogicValue.ofString('')); expect( // getRange - bad inputs start > end () => LogicValue.ofString('0101').getRange(2, 1), @@ -343,8 +364,14 @@ void main() { throwsA(isA())); expect(LogicValue.ofString('xz01').slice(2, 1), equals(LogicValue.ofString('z0'))); + expect(LogicValue.ofString('xz01').slice(-2, -3), + equals(LogicValue.ofString('z0'))); expect(LogicValue.ofString('xz01').slice(1, 3), equals(LogicValue.ofString('0zx'))); + expect(LogicValue.ofString('xz01').slice(-3, -1), + equals(LogicValue.ofString('0zx'))); + expect(LogicValue.ofString('xz01').slice(-2, -2), + equals(LogicValue.ofString('z'))); expect( // isValid - valid LogicValue.ofString('0101').isValid,