Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for LogicValue operation bugs related to size, sign, math, and comparison #319

Merged
merged 13 commits into from
Sep 18, 2023
Merged
7 changes: 4 additions & 3 deletions lib/src/values/big_logic_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ class _BigLogicValue extends LogicValue {
static final Map<int, BigInt> _masksOfWidth = {};
static BigInt _maskOfWidth(int width) {
if (!_masksOfWidth.containsKey(width)) {
_masksOfWidth[width] = (BigInt.one << width) - BigInt.one;
_masksOfWidth[width] =
((BigInt.one << width) - BigInt.one).toUnsigned(width);
}
return _masksOfWidth[width]!;
}
Expand All @@ -60,8 +61,8 @@ class _BigLogicValue extends LogicValue {
: assert(width > LogicValue._INT_BITS,
'_BigLogicValue should only be used for large values'),
super._(width) {
_value = _mask & value;
_invalid = _mask & invalid;
_value = (_mask & value).toUnsigned(width);
_invalid = (_mask & invalid).toUnsigned(width);

assert(
allowInefficientRepresentation ||
Expand Down
26 changes: 19 additions & 7 deletions lib/src/values/logic_value.dart
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ typedef LogicValues = LogicValue;
///
/// Each bit of [LogicValue] can be represented as a [LogicValue]
/// of `0`, `1`, `x` (contention), or `z` (floating).
/// LogicValue is unsigned
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
@immutable
abstract class LogicValue implements Comparable<LogicValue> {
/// The number of bits in an int.
Expand Down Expand Up @@ -881,7 +882,7 @@ abstract class LogicValue implements Comparable<LogicValue> {
}
if (this is BigInt ||
this is _BigLogicValue ||
(this is _FilledLogicValue && width >= _INT_BITS)) {
(this is _FilledLogicValue && width > _INT_BITS)) {
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
final a = toBigInt();
return LogicValue.ofBigInt(op(a, width) as BigInt, width);
} else {
Expand Down Expand Up @@ -925,12 +926,12 @@ abstract class LogicValue implements Comparable<LogicValue> {
return LogicValue.filled(other.width, LogicValue.x);
}

if (this is _BigLogicValue || other is BigInt || other is _BigLogicValue) {
if (width > _INT_BITS || (other is LogicValue && other.width > _INT_BITS)) {
final a = toBigInt();
final b = other is BigInt
? other
: other is int
? BigInt.from(other)
? BigInt.from(other).toUnsigned(_INT_BITS)
: other is LogicValue
? other.toBigInt()
: throw Exception(
Expand Down Expand Up @@ -1040,19 +1041,30 @@ abstract class LogicValue implements Comparable<LogicValue> {

dynamic a;
dynamic b;
if (this is _BigLogicValue || other is BigInt || other is _BigLogicValue) {
if (width > _INT_BITS || (other is LogicValue && other.width > _INT_BITS)) {
a = toBigInt();
b = other is BigInt
? other
: other is int
? BigInt.from(other)
? BigInt.from(other).toUnsigned(_INT_BITS)
: other is LogicValue
? other.toBigInt()
: throw Exception(
'Unexpected big type: ${other.runtimeType}.');
} else {
a = toInt();
b = other is int ? other : (other as LogicValue).toInt();
if (width < _INT_BITS) {
a = toInt();
b = other is int ? other : (other as LogicValue).toInt();
} else {
// Here we now know: width == _INT_BITS
final ai = toInt();
final bi = other is int ? other : (other as LogicValue).toInt();
if ((ai < 0) || (bi < 0)) {
final abig = LogicValue.ofBigInt(BigInt.from(ai), _INT_BITS + 1);
final bbig = LogicValue.ofBigInt(BigInt.from(bi), _INT_BITS + 1);
return abig._doCompare(bbig, op);
}
}
}
return op(a, b) ? LogicValue.one : LogicValue.zero;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/src/values/small_logic_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class _SmallLogicValue extends LogicValue {
bool get isFloating => (_invalid == _mask) && (_value == _mask);

@override
BigInt toBigInt() => BigInt.from(toInt());
BigInt toBigInt() => BigInt.from(toInt()).toUnsigned(width);

@override
int toInt() {
Expand Down
149 changes: 149 additions & 0 deletions test/big_logic_value_test.dart
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import 'package:rohd/rohd.dart';
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
import 'package:test/test.dart';

void main() {
test('crash compare', () {
final input = Const(BigInt.from(2).pow(128), width: 129);
final output = Logic();
Combinational([
If.block([
Iff(input.getRange(0, 128) > BigInt.from(0),
[output < Const(1, width: 1)]),
Else([output < Const(0, width: 1)]),
])
]);
});
test('bad compare', () {
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
const i = 64;
final input = Const(BigInt.from(1) << (i - 1), width: i);
final output = Logic();
Combinational([
If.block([
Iff(input > BigInt.from(0), [output < Const(1, width: 1)]),
Else([output < Const(0, width: 1)]),
])
]);
final b = ~input.eq(0);
expect(output.value, equals(b.value));
});
test('big value test', () {
expect(
LogicValue.ofBigInt(BigInt.zero, 128) +
LogicValue.ofBigInt(BigInt.zero, 128),
LogicValue.ofInt(0, 128));
});
group('values test', () {
for (final len in [63, 64, 65, 66, 67]) {
final sslv = LogicValue.ofInt(4, len); // small Int hold Big
final bslv = LogicValue.ofInt(-0xFFFF, len); // 18446744073709486081
final fslv = LogicValue.ofInt(-2, len); // 18446744073709551614

final sblv = LogicValue.ofBigInt(BigInt.from(4), len);
final bblv = LogicValue.ofBigInt(BigInt.from(-0xFFFF), len);
final fblv = LogicValue.ofBigInt(BigInt.from(-2), len);

test('small Int storage len=$len', () {
expect(sslv < bslv, LogicValue.one);
expect(bslv < sslv, LogicValue.zero);
expect(sslv > bslv, LogicValue.zero);
expect(bslv > sslv, LogicValue.one);

expect(sslv < fslv, LogicValue.one);
expect(fslv < sslv, LogicValue.zero);
expect(sslv > fslv, LogicValue.zero);
expect(fslv > sslv, LogicValue.one);

expect(bslv < fslv, LogicValue.one);
expect(fslv < bslv, LogicValue.zero);
expect(bslv > fslv, LogicValue.zero);
expect(fslv > bslv, LogicValue.one);
});
test('big Int storage len=$len', () {
expect(sblv < bblv, LogicValue.one);
expect(bblv < sblv, LogicValue.zero);
expect(sblv > bblv, LogicValue.zero);
expect(bblv > sblv, LogicValue.one);

expect(sblv < fblv, LogicValue.one);
expect(fblv < sblv, LogicValue.zero);
expect(sblv > fblv, LogicValue.zero);
expect(fblv > sblv, LogicValue.one);

expect(bblv < fblv, LogicValue.one);
expect(fblv < bblv, LogicValue.zero);
expect(bblv > fblv, LogicValue.zero);
expect(fblv > bblv, LogicValue.one);
});
test('big math len=$len', () {
expect(sslv + fslv, LogicValue.ofInt(2, len));
expect(sslv - fslv, LogicValue.ofInt(6, len));
expect(fslv - sslv, LogicValue.ofInt(-6, len));

expect(sslv * fslv, LogicValue.ofInt(-8, len));

expect(sslv + fslv, LogicValue.ofBigInt(BigInt.from(2), len));
expect(sslv - fslv, LogicValue.ofBigInt(BigInt.from(6), len));
expect(fslv - sslv, LogicValue.ofBigInt(BigInt.from(-6), len));

expect(fslv * sslv, LogicValue.ofBigInt(BigInt.from(-8), len));

expect(sblv + fblv, LogicValue.ofInt(2, len));
expect(sblv - fblv, LogicValue.ofInt(6, len));
expect(fblv - sblv, LogicValue.ofInt(-6, len));

expect(sblv * fblv, LogicValue.ofInt(-8, len));

expect(sblv + fblv, LogicValue.ofBigInt(BigInt.from(2), len));
expect(sblv - fblv, LogicValue.ofBigInt(BigInt.from(6), len));
expect(fblv - sblv, LogicValue.ofBigInt(BigInt.from(-6), len));

expect(fblv * sblv, LogicValue.ofBigInt(BigInt.from(-8), len));
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
});
test('division test len=$len', () {
final negsfour = LogicValue.ofInt(-4, len);
final negbfour = LogicValue.ofBigInt(BigInt.from(-4), len);
final two = LogicValue.ofBigInt(BigInt.from(2), len);
expect(negsfour / two, LogicValue.ofInt(-4, len) >>> 1);
expect(negbfour / two, LogicValue.ofBigInt(BigInt.from(-4), len) >>> 1);
});
test('modulo test len=$len', () {
final negsfive = LogicValue.ofInt(-5, len);
final negbfive = LogicValue.ofBigInt(BigInt.from(-5), len);
final two = LogicValue.ofBigInt(BigInt.from(2), len);
expect(negsfive % two, LogicValue.ofInt(1, len));
expect(negbfive % two, LogicValue.ofBigInt(BigInt.from(1), len));
});
test('clog test len=$len', () {
final negnum = LogicValue.ofInt(-1, len);
expect(negnum.clog2(), LogicValue.ofInt(len, len));
for (final l in [1, 2, 3]) {
expect((negnum >>> l).clog2(), LogicValue.ofInt(len - l, len));
}
for (final l in [len - 5, len - 4, len - 3, len - 2]) {
final bignum = LogicValue.ofBigInt(BigInt.from(1) << l, len);
expect(bignum.clog2(), LogicValue.ofInt(l, len));
if (len < 64) {
final smallnum = LogicValue.ofInt(1 << l, len);
expect(smallnum.clog2(), LogicValue.ofInt(l, len));
}
}
for (final l in [len - 5, len - 4, len - 3]) {
final bignum = LogicValue.ofBigInt(BigInt.from(2) << l, len);
expect(bignum.clog2().toBigInt(), BigInt.from(l + 1));
if (len < 64) {
final smallnum = LogicValue.ofInt(2 << l, len);
expect(smallnum.clog2(), LogicValue.ofInt(l + 1, len));
}
}
for (final l in [len - 5, len - 4, len - 3]) {
final bignum = LogicValue.ofBigInt(BigInt.from(3) << l, len);
expect(bignum.clog2(), LogicValue.ofInt(l + 2, len));
if (len < 64) {
final smallnum = LogicValue.ofInt(3 << l, len);
expect(smallnum.clog2(), LogicValue.ofInt(l + 2, len));
}
}
});
}
mkorbel1 marked this conversation as resolved.
Show resolved Hide resolved
});
}