Skip to content

Commit 71a0700

Browse files
authored
Enhance LogicValue.toRadixString to enable fixed-width output (#583)
1 parent 9467fda commit 71a0700

File tree

3 files changed

+55
-18
lines changed

3 files changed

+55
-18
lines changed

doc/user_guide/_docs/A02-logical_signals.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ x.value.toInt()
3737
x.value.toBigInt()
3838
3939
// constructing a LogicValue a handful of different ways
40-
LogicValue.ofRadixString("31'h5761 F87A"); // 0x5761F87A
40+
LogicValue.ofRadixString("31'h5761_F87A"); // 0x5761F87A
4141
LogicValue.ofString('0101xz01'); // 0b0101xz01
4242
LogicValue.of([LogicValue.one, LogicValue.zero]); // 0b10
4343
[LogicValue.z, LogicValue.x].swizzle(); // 0bzx

lib/src/values/logic_value.dart

Lines changed: 39 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -632,8 +632,11 @@ abstract class LogicValue implements Comparable<LogicValue> {
632632
/// - [chunkSize] = default: `61'h2_9ebc_5f06_5bf7`
633633
/// - [chunkSize] = 10: `61'h29e_bc5f065bf7`
634634
///
635-
/// Leading 0s are omitted in the output string:
635+
/// [leadingZeros] defaults to false, so leading 0s are omitted in
636+
/// the output string:
636637
/// - `25'h1`
638+
/// otherwise if [leadingZeros] is set to true then the output string is:
639+
/// - `25'h000_0001`
637640
///
638641
/// When a [LogicValue] has 'x' or 'z' bits, then the radix characters those
639642
/// bits overlap will be expanded into binary form with '<' '>' bracketing
@@ -648,7 +651,10 @@ abstract class LogicValue implements Comparable<LogicValue> {
648651
/// - `9'bz_zzzz_zzzz = 9'hZZZ`
649652
///
650653
String toRadixString(
651-
{int radix = 2, int chunkSize = 4, String sepChar = '_'}) {
654+
{int radix = 2,
655+
int chunkSize = 4,
656+
bool leadingZeros = false,
657+
String sepChar = '_'}) {
652658
if (radixStringChars.contains(sepChar)) {
653659
throw LogicValueConversionException('separation character invalid');
654660
}
@@ -661,22 +667,33 @@ abstract class LogicValue implements Comparable<LogicValue> {
661667
_ => throw LogicValueConversionException('Unsupported radix: $radix')
662668
};
663669
final String reversedStr;
664-
if (isValid) {
665-
final radixString =
666-
toBigInt().toUnsigned(width).toRadixString(radix).toUpperCase();
667-
reversedStr = _reverse(radixString);
668-
} else if (radix == 10) {
669-
final span = (width * math.log(2) / math.log(radix)).floor();
670-
if (toRadixString().contains(RegExp('[xX]'))) {
671-
reversedStr = 'X' * span;
670+
if (radix == 10) {
671+
if (isValid) {
672+
var radixString =
673+
toBigInt().toUnsigned(width).toRadixString(radix).toUpperCase();
674+
if (leadingZeros) {
675+
final span =
676+
math.max(1, (width * math.log(2) / math.log(radix)).floor());
677+
for (var i = radixString.length; i < (width / span).ceil(); i++) {
678+
radixString = '0$radixString';
679+
}
680+
}
681+
reversedStr = _reverse(radixString);
672682
} else {
673-
reversedStr = 'Z' * span;
683+
final span =
684+
math.max(1, (width * math.log(2) / math.log(radix)).floor());
685+
if (toRadixString().contains(RegExp('[xX]'))) {
686+
reversedStr = 'X' * span;
687+
} else {
688+
reversedStr = 'Z' * span;
689+
}
674690
}
675691
} else {
676692
final span = (math.log(radix) / math.log(2)).ceil();
677693
final extendedStr =
678694
LogicValue.of(this, width: span * (width / span).ceil());
679695
final buf = StringBuffer();
696+
var haveLeadingZeros = true;
680697
for (var i = (extendedStr.width ~/ span) - 1; i >= 0; i--) {
681698
final binaryChunk = extendedStr.slice((i + 1) * span - 1, i * span);
682699
var chunkString = binaryChunk.toString(includeWidth: false);
@@ -695,10 +712,17 @@ abstract class LogicValue implements Comparable<LogicValue> {
695712
else
696713
binaryChunk.toBigInt().toUnsigned(span).toRadixString(radix)
697714
].first;
715+
if (s != '0') {
716+
haveLeadingZeros = false;
717+
}
718+
if ((s == '0') & !leadingZeros & haveLeadingZeros) {
719+
continue;
720+
}
698721
buf.write(_reverse(s));
699722
}
700723
reversedStr = _reverse(buf.toString());
701724
}
725+
702726
final spaceString = _reverse(reversedStr
703727
.replaceAllMapped(
704728
RegExp('((>(.){$chunkSize}<)|([a-zA-Z0-9])){$chunkSize}'),
@@ -739,10 +763,10 @@ abstract class LogicValue implements Comparable<LogicValue> {
739763
/// If the LogicValue width is not encoded as round number of radix
740764
/// characters, the leading character must be small enough to be encoded
741765
/// in the remaining width:
742-
/// - 9'h1AA
743-
/// - 10'h2AA
744-
/// - 11'h4AA
745-
/// - 12'hAAA
766+
/// - 9'h1aa
767+
/// - 10'h2aa
768+
/// - 11'h4aa
769+
/// - 12'haa
746770
static LogicValue ofRadixString(String valueString, {String sepChar = '_'}) {
747771
if (radixStringChars.contains(sepChar)) {
748772
throw LogicValueConstructionException('separation character invalid');

test/logic_value_test.dart

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2057,6 +2057,15 @@ void main() {
20572057
LogicValue.ofRadixString(lv.toRadixString(radix: i)), equals(lv));
20582058
}
20592059
});
2060+
test('radixString roundTrip with leading zeros', () {
2061+
final lv = LogicValue.ofBigInt(BigInt.from(737481838713847), 61);
2062+
for (final i in [2, 4, 8, 10, 16]) {
2063+
expect(
2064+
LogicValue.ofRadixString(
2065+
lv.toRadixString(radix: i, leadingZeros: true)),
2066+
equals(lv));
2067+
}
2068+
});
20602069
test('radixString binary expansion', () {
20612070
final lv = LogicValue.ofRadixString("12'b10z111011z00");
20622071
expect(lv.toRadixString(radix: 16), equals("12'h<10z1>d<1z00>"));
@@ -2069,10 +2078,15 @@ void main() {
20692078
test('radixString leading zero', () {
20702079
final lv = LogicValue.ofRadixString("10'b00_0010_0111");
20712080
expect(lv.toRadixString(), equals("10'b10_0111"));
2081+
expect(lv.toRadixString(leadingZeros: true), equals("10'b00_0010_0111"));
20722082
expect(lv.toRadixString(radix: 4), equals("10'q213"));
20732083
expect(lv.toRadixString(radix: 8), equals("10'o47"));
20742084
expect(lv.toRadixString(radix: 10), equals("10'd39"));
2085+
expect(
2086+
lv.toRadixString(radix: 10, leadingZeros: true), equals("10'd0039"));
20752087
expect(lv.toRadixString(radix: 16), equals("10'h27"));
2088+
expect(
2089+
lv.toRadixString(radix: 16, leadingZeros: true), equals("10'h027"));
20762090
for (final i in [2, 4, 8, 10, 16]) {
20772091
expect(
20782092
LogicValue.ofRadixString(lv.toRadixString(radix: i)), equals(lv));
@@ -2164,7 +2178,7 @@ void main() {
21642178
expect(lv.toRadixString(radix: 4), equals("10'q2_2213"));
21652179
expect(lv.toRadixString(radix: 8), equals("10'o1247"));
21662180
expect(lv.toRadixString(radix: 10), equals("10'd679"));
2167-
expect(lv.toRadixString(radix: 16), equals("10'h2A7"));
2181+
expect(lv.toRadixString(radix: 16), equals("10'h2a7"));
21682182
for (final i in [2, 4, 8, 10, 16]) {
21692183
expect(
21702184
LogicValue.ofRadixString(lv.toRadixString(radix: i)), equals(lv));
@@ -2178,7 +2192,6 @@ void main() {
21782192
for (var setWidth = 1; setWidth < 12; setWidth++) {
21792193
for (var iterations = 0; iterations < 10; iterations++) {
21802194
final ii = random.nextInt((1 << (setWidth + 1)) - 1);
2181-
21822195
for (var pos = 0; pos < inL.width - setWidth; pos++) {
21832196
final l = Logic(width: width);
21842197
l <= inL.withSet(pos, Const(ii, width: setWidth));

0 commit comments

Comments
 (0)