ofRadixString static method
Create a LogicValue from a length/radix-encoded string of the following format:
<length><format><value-string>.
<length> is the binary digit length of the LogicValue to be
constructed.
<format>s supported are 'b,'q,'o,'d,'h supporting radixes as follows:
- 'b: binary (radix 2)
- 'q: quaternary (radix 4)
- 'o: octal (radix 8)
- 'd: decimal (radix 10)
- 'h: hexadecimal (radix 16)
<value-string> contains space-separated digits corresponding to the
radix format. Space-separation is for ease of reading and is often
in chunks of 4 digits.
If the format of then length/radix-encoded string is not completely parsed a LogicValueConstructionException will be thrown. This can be caused by illegal characters in the string or too long of a value string.
Strings created by toRadixString are parsed by ofRadixString.
If the LogicValue width is not encoded as round number of radix characters, the leading character must be small enough to be encoded in the remaining width:
- 9'h1aa
- 10'h2aa
- 11'h4aa
- 12'haa
Implementation
static LogicValue ofRadixString(String valueString, {String sepChar = '_'}) {
if (radixStringChars.contains(sepChar)) {
throw LogicValueConstructionException('separation character invalid');
}
if (RegExp(r'^\d+').firstMatch(valueString) != null) {
final formatStr =
RegExp("^(\\d+)'([bqodh])([0-9aAbBcCdDeEfFzZxX<>$sepChar]*)")
.firstMatch(valueString);
if (formatStr != null) {
if (valueString.length != formatStr.group(0)!.length) {
throw LogicValueConstructionException('radix string stopped '
'parsing at character position ${formatStr.group(0)!.length}');
}
final specifiedLength = int.parse(formatStr.group(1)!);
final compressedStr = formatStr.group(3)!.replaceAll(sepChar, '');
// Extract radix
final radixString = formatStr.group(2)!;
final radix = switch (radixString) {
'b' => 2,
'q' => 4,
'o' => 8,
'd' => 10,
'h' => 16,
_ => throw LogicValueConstructionException(
'Unsupported radix: $radixString'),
};
final span = (math.log(radix) / math.log(2)).ceil();
final reversedStr = _reverse(compressedStr);
// Find any binary expansions, then extend to the span
final binaries = RegExp('>[^<>]*<').allMatches(reversedStr).indexed;
// At this point, binaryLength has the binary bit count for binaries
// Remove and store expansions of binary fields '<[x0z1]*>.
final fullBinaries = RegExp('>[^<>]*<');
final bitExpandLocs = fullBinaries.allMatches(reversedStr).indexed;
final numExpanded = bitExpandLocs.length;
final numChars = reversedStr.length - numExpanded * (span + 1);
final binaryLength = (binaries.isEmpty
? 0
: binaries
.map<int>((j) => j.$2.group(0)!.length - 2)
.reduce((a, b) => a + b)) +
(numChars - numExpanded) * span;
// is the binary length shorter than it appears
final int shorter;
if ((binaries.isNotEmpty) && compressedStr[0] == '<') {
final binGroup = _reverse(binaries.last.$2.group(0)!);
final binaryChunk = binGroup.substring(1, binGroup.length - 1);
var cnt = 0;
while (cnt < binaryChunk.length - 1 && binaryChunk[cnt++] == '0') {}
shorter = cnt - 1;
} else {
if (compressedStr.isNotEmpty) {
final leadChar = compressedStr[0];
if (RegExp('[xXzZ]').hasMatch(leadChar)) {
shorter = span - 1;
} else {
shorter = span -
BigInt.parse(leadChar, radix: radix).toRadixString(2).length;
}
} else {
shorter = 0;
}
}
if ((radix != 10) & (binaryLength - shorter > specifiedLength)) {
throw LogicValueConstructionException(
'ofRadixString: cannot represent '
'$compressedStr in $specifiedLength');
}
final noBinariesStr = reversedStr.replaceAll(fullBinaries, '0');
final xLocations = RegExp('x|X')
.allMatches(noBinariesStr)
.indexed
.map((m) => List.generate(span, (s) => m.$2.start * span + s))
.expand((xe) => xe);
final zLocations = RegExp('z|Z')
.allMatches(noBinariesStr)
.indexed
.map((m) => List.generate(span, (s) => m.$2.start * span + s))
.expand((ze) => ze);
final BigInt intValue;
if (noBinariesStr.isNotEmpty) {
intValue = BigInt.parse(
_reverse(noBinariesStr.replaceAll(RegExp('[xXzZ]'), '0')),
radix: radix)
.toUnsigned(specifiedLength);
} else {
intValue = BigInt.zero;
}
final logicValList = List<LogicValue>.from(
LogicValue.ofString(intValue.toRadixString(2))
.zeroExtend(specifiedLength)
.toList());
// Put all the X and Z's back into the list
for (final x in xLocations) {
if (x < specifiedLength) {
logicValList[x] = LogicValue.x;
}
}
for (final z in zLocations) {
if (z < specifiedLength) {
logicValList[z] = LogicValue.z;
}
}
// Now add back the bitfield expansions stored earlier
var lastPos = 0;
var lastCpos = 0;
for (final i in bitExpandLocs) {
var len = i.$2.group(0)!.length;
if (i.$1 == bitExpandLocs.last.$1) {
final revBitChars = i.$2.group(0)!;
while (len > 1 && revBitChars[len - 2] == '0') {
len--;
}
}
final bitChars = i.$2.group(0)!.substring(1, len - 1);
var pos = 0;
if (i.$1 > 0) {
final nonExpChars = i.$2.start - lastCpos - span - 2;
pos = lastPos + span + span * nonExpChars;
} else {
final nonExpChars = i.$2.start - lastCpos;
pos = lastPos + span * nonExpChars;
}
for (var bitPos = 0; bitPos < len - 2; bitPos++) {
logicValList[pos + bitPos] = switch (bitChars[bitPos]) {
'0' => LogicValue.zero,
'1' => LogicValue.one,
'x' => LogicValue.x,
_ => LogicValue.z
};
}
lastCpos = i.$2.start;
lastPos = pos;
}
return logicValList.rswizzle();
}
}
throw LogicValueConstructionException(
'Invalid LogicValue string $valueString');
}