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 and improvements related to shifts #412

Merged
merged 7 commits into from
Sep 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/src/exceptions/exceptions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ export './module/module_exceptions.dart';
export './name/name_exceptions.dart';
export './sim_compare/sim_compare_exceptions.dart';
export 'rohd_exception.dart';
export 'unsupported_type_exception.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ class ValueWidthMismatchException extends RohdException {
/// Creates an exception when two [LogicValue] considered for the operation
/// are of different width.
ValueWidthMismatchException(LogicValue a, LogicValue b)
: super('Width Mismatch ${a.width} & ${b.width}: '
'LogicValue must be of same width');
: super('Width mismatch between $a (${a.width}) & $b (${b.width}): '
'LogicValues must be of same width for this operation.');
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class NonSupportedTypeException extends RohdException {
/// with default error [message].
///
/// Creates a [NonSupportedTypeException] with an optional error [message].
NonSupportedTypeException(String vector,
NonSupportedTypeException(dynamic vector,
[String message = 'The runtimetype of expected vector is unsupported: '])
: super(message + vector.runtimeType.toString());
: super('$message $vector (${vector.runtimeType})');
}
18 changes: 18 additions & 0 deletions lib/src/exceptions/unsupported_type_exception.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// unsupported_type_exception.dart
// An exception that is thrown when an unsupported type is used.
//
// 2023 September 14
// Author: Max Korbel <[email protected]

import 'package:rohd/src/exceptions/rohd_exception.dart';

/// An exception that is thrown when an unsupported type is used.
class UnsupportedTypeException extends RohdException {
/// Creates an exception when an unsupported type is used.
UnsupportedTypeException(dynamic value, List<Type> supportedTypes)
: super('Unsupported type ${value.runtimeType} used ($value).'
' Supported types are ${supportedTypes.join(',')}');
}
2 changes: 1 addition & 1 deletion lib/src/modules/gates.dart
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ class _ShiftGate extends Module with InlineSystemVerilog {
: super(name: name) {
final shiftAmountLogic = shiftAmount is Logic
? shiftAmount
: Const(shiftAmount, width: in_.width);
: Const(LogicValue.ofInferWidth(shiftAmount));

_inName = Module.unpreferredName('in_${in_.name}');
_shiftAmountName =
Expand Down
36 changes: 26 additions & 10 deletions lib/src/utilities/simcompare.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,15 +47,22 @@ class Vector {
/// the [inputValues].
static String _errorCheckString(String sigName, dynamic expected,
LogicValue expectedVal, String inputValues) {
final expectedHexStr = expected is int
? '0x${expected.toRadixString(16)}'
: expected.toString();
final expectedValStr = expectedVal.toString();
if (expected is! int && expected is! LogicValue && expected is! BigInt) {
throw NonSupportedTypeException(expected);
}

if (expected is! int && expected is! LogicValue) {
throw Exception(
'Support for ${expected.runtimeType} is not supported (yet?).');
String expectedHexStr;
if (expected is int) {
expectedHexStr =
BigInt.from(expected).toUnsigned(expectedVal.width).toRadixString(16);
} else if (expected is BigInt) {
expectedHexStr = expected.toUnsigned(expectedVal.width).toRadixString(16);
} else {
expectedHexStr = expected.toString();
}
expectedHexStr = '0x$expectedHexStr';

final expectedValStr = expectedVal.toString();

return 'if($sigName !== $expectedValStr) '
'\$error(\$sformatf("Expected $sigName=$expectedHexStr,'
Expand All @@ -80,7 +87,11 @@ class Vector {
}
return arrAssigns.toString();
} else {
return '$signalName = ${inputValues[signalName]};';
var assignmentValue = inputValues[signalName];
if (assignmentValue is BigInt) {
assignmentValue = LogicValue.of(assignmentValue, width: signal.width);
}
return '$signalName = $assignmentValue;';
}
}).join('\n');

Expand Down Expand Up @@ -151,7 +162,12 @@ abstract class SimCompare {
' expected $o to be $value, but it was ${o.value}.';
if (value is int) {
expect(o.value.isValid, isTrue, reason: errorReason);
expect(o.value.toInt(), equals(value), reason: errorReason);
expect(o.value.toBigInt(),
equals(BigInt.from(value).toUnsigned(o.width)),
reason: errorReason);
} else if (value is BigInt) {
expect(o.value.isValid, isTrue, reason: errorReason);
expect(o.value.toBigInt(), equals(value), reason: errorReason);
} else if (value is LogicValue) {
if (o.width > 1 &&
(value == LogicValue.x || value == LogicValue.z)) {
Expand All @@ -162,7 +178,7 @@ abstract class SimCompare {
expect(o.value, equals(value), reason: errorReason);
}
} else {
throw NonSupportedTypeException(value.runtimeType.toString());
throw NonSupportedTypeException(value);
}
}
}).catchError(
Expand Down
57 changes: 35 additions & 22 deletions lib/src/values/big_logic_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class _BigLogicValue extends LogicValue {
late final BigInt _invalid;

BigInt get _mask => _maskOfWidth(width);
static final Map<int, BigInt> _masksOfWidth = {};
static final Map<int, BigInt> _masksOfWidth = HashMap();
static BigInt _maskOfWidth(int width) {
if (!_masksOfWidth.containsKey(width)) {
_masksOfWidth[width] =
Expand Down Expand Up @@ -121,15 +121,22 @@ class _BigLogicValue extends LogicValue {
@override
BigInt toBigInt() {
if (_invalid.sign != 0) {
throw Exception('Cannot convert invalid LogicValue to BigInt: $this');
throw InvalidValueOperationException(this, 'toBigInt');
}
return _value;
}

@override
int toInt() =>
throw Exception('LogicValue width $width is too long to convert to int.'
int toInt() {
final bigInt = toBigInt();
if (bigInt.isValidInt) {
return bigInt.toIntUnsigned(LogicValue._INT_BITS);
} else {
throw InvalidTruncationException(
'LogicValue $this is too long to convert to int.'
' Use toBigInt() instead.');
}
}

@override
LogicValue operator ~() => LogicValue._bigLogicValueOrFilled(
Expand Down Expand Up @@ -197,28 +204,34 @@ class _BigLogicValue extends LogicValue {
}

@override
LogicValue _shiftLeft(int shamt) => !isValid
? _FilledLogicValue(_LogicValueEnum.x, width)
: LogicValue._bigLogicValueOrFilled(
(_value << shamt) & _mask, (_invalid << shamt) & _mask, width);
LogicValue _shiftLeft(int shamt) => LogicValue._bigLogicValueOrFilled(
(_value << shamt) & _mask, (_invalid << shamt) & _mask, width);

@override
LogicValue _shiftRight(int shamt) => !isValid
? _FilledLogicValue(_LogicValueEnum.x, width)
: LogicValue._bigLogicValueOrFilled(
_value >> shamt, _invalid >> shamt, width);
LogicValue _shiftRight(int shamt) => LogicValue._bigLogicValueOrFilled(
// we can just use >> because these are unsigned
_value >> shamt,
_invalid >> shamt,
width);

@override
LogicValue _shiftArithmeticRight(int shamt) => !isValid
? _FilledLogicValue(_LogicValueEnum.x, width)
: LogicValue._bigLogicValueOrFilled(
(_value |
(this[width - 1] == LogicValue.one
? ((_mask >> (width - shamt)) << (width - shamt))
: BigInt.zero)) >>
shamt,
_invalid >> shamt,
width);
LogicValue _shiftArithmeticRight(int shamt) {
shamt;

var value = (_value.toSigned(width) >> shamt).toUnsigned(width);
var invalid = (_invalid.toSigned(width) >> shamt).toUnsigned(width);

// if uppermost bit is invalid, then turn the shifted bits into X's
if (!this[-1].isValid) {
// for affected bits of value: zero out value
value &= _mask >> shamt;

// for affected bits of invalid: make sure they are high
invalid |= ~_mask >> shamt;
}

return LogicValue._bigLogicValueOrFilled(value, invalid, width);
}

@override
BigInt get _bigIntInvalid => _invalid;
Expand Down
39 changes: 19 additions & 20 deletions lib/src/values/filled_logic_value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,7 @@ class _FilledLogicValue extends LogicValue {
int get _hashCode => _value.hashCode;

@override
bool get isValid =>
!(_value == _LogicValueEnum.x || _value == _LogicValueEnum.z);
bool get isValid => _value.isValid;

@override
bool get isFloating => _value == _LogicValueEnum.z;
Expand All @@ -86,21 +85,24 @@ class _FilledLogicValue extends LogicValue {
} else if (_value == _LogicValueEnum.zero) {
return BigInt.zero;
}
throw Exception('Cannot convert invalid value "$_value" to BigInt.');
throw InvalidValueOperationException(this, 'toBigInt');
}

@override
int toInt() {
if (width > LogicValue._INT_BITS) {
throw Exception('LogicValue width $width is too long to convert to int.'
if (_value == _LogicValueEnum.zero) {
return 0;
} else if (!isValid) {
throw InvalidValueOperationException(this, 'toInt');
} else if (width > LogicValue._INT_BITS) {
throw InvalidTruncationException(
'LogicValue $this is too long to convert to int.'
' Use toBigInt() instead.');
}
if (_value == _LogicValueEnum.one) {
} else if (_value == _LogicValueEnum.one) {
return _SmallLogicValue._maskOfWidth(width);
} else if (_value == _LogicValueEnum.zero) {
return 0;
}
throw Exception('Cannot convert invalid value "$_value" to an int.');

throw InvalidValueOperationException(this, 'toInt');
}

@override
Expand Down Expand Up @@ -289,10 +291,6 @@ class _FilledLogicValue extends LogicValue {
return this;
}

if (shamt >= width) {
return _FilledLogicValue(_LogicValueEnum.zero, width);
}

return [
getRange(0, width - shamt),
_FilledLogicValue(_LogicValueEnum.zero, shamt),
Expand All @@ -305,18 +303,19 @@ class _FilledLogicValue extends LogicValue {
return this;
}

if (shamt >= width) {
return _FilledLogicValue(_LogicValueEnum.zero, width);
}

return [
_FilledLogicValue(_LogicValueEnum.zero, shamt),
getRange(shamt, width),
_getRange(shamt, width),
].swizzle();
}

@override
LogicValue _shiftArithmeticRight(int shamt) => this;
LogicValue _shiftArithmeticRight(int shamt) => _value != _LogicValueEnum.z
? this
: [
_FilledLogicValue(_LogicValueEnum.x, shamt),
_getRange(shamt, width),
].swizzle();

@override
BigInt get _bigIntInvalid =>
Expand Down
Loading