Skip to content

Commit

Permalink
Fixes and improvements related to shifts (#412)
Browse files Browse the repository at this point in the history
  • Loading branch information
mkorbel1 authored Sep 19, 2023
1 parent 2ef187e commit b7612ba
Show file tree
Hide file tree
Showing 14 changed files with 806 additions and 226 deletions.
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 <max.korbel@intel.com

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

0 comments on commit b7612ba

Please sign in to comment.