Skip to content

Commit

Permalink
Gray Binary Converter (intel#54)
Browse files Browse the repository at this point in the history
  • Loading branch information
quekyj authored Feb 29, 2024
1 parent 1d96e0f commit 20d897a
Show file tree
Hide file tree
Showing 4 changed files with 301 additions and 0 deletions.
35 changes: 35 additions & 0 deletions doc/components/binary_gray.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Binary Gray

ROHD HCL provides a module to perform conversion on binary to gray and gray to binary.

## Binary-to-Gray

A fundamental digital logic operation known as binary to gray code conversion is employed in many different applications, notably in digital communication and signal processing systems. Gray code is a binary numbering system that is useful for minimizing communication channel faults because adjacent values only differ in one bit. This conversion algorithm converts a binary value into its equivalent Gray code representation from the input binary value. Each bit in the binary input is XORed with the bit before it to produce the Gray code. In order to reduce errors during signal transmission or processing, the transition between consecutive values must be as smooth as feasible in applications like rotary encoders, error correction, and circuit design.

The `BinaryToGrayConverter` module in ROHD-HCL accept a single input `binary` to be converted to gray of type `Logic`. The output value can be access via the getter `grayCode`.

An example is shown below to convert binary to gray code.

```dart
final binaryInput = Logic(name: 'binaryInput', width: 3)..put(bin('111'));
final binToGray = BinaryToGrayConverter(binaryInput);
await binToGray.build();
print(binToGray.grayCode.value.toString(includeWidth: false)); // output: 100
```

## Gray-to-Binary

The conversion of gray to binary code is an essential process in digital logic and communication systems. A binary numbering system called gray code is appropriate for use in applications where error reduction is crucial because adjacent values only differ by one bit. This conversion algorithm converts a Gray code value into its corresponding binary representation from the input. This is accomplished by computing the equivalent binary bit by XOR operations with the preceding bit after examining each bit in the Gray code, starting with the least significant bit. In many different domains, such as rotary encoders, digital signal processing, and error correction systems, it is necessary to extract precise binary representations from Gray code inputs. These applications include Gray to Binary Code Conversion.

The `GrayToBinary` module in ROHD-HCL accept a single input `gray` to be converted to binary of type `Logic`. The output value can be access via the getter `binaryVal`.

An example is shown below to convert gray code to binary value.

```dart
final graycode = Logic(name: 'grayCode', width: 3)..put(bin('100'));
final grayToBin = GrayToBinaryConverter(graycode);
await grayToBin.build();
print(grayToBin.binaryVal.value.toString(includeWidth: false)); // output: 111
```
1 change: 1 addition & 0 deletions lib/rohd_hcl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

export 'src/adder.dart';
export 'src/arbiters/arbiters.dart';
export 'src/binary_gray.dart';
export 'src/carry_save_mutiplier.dart';
export 'src/component_config/component_config.dart';
export 'src/count.dart';
Expand Down
143 changes: 143 additions & 0 deletions lib/src/binary_gray.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// binary_gray.dart
// A converter that can transform binary values into Gray code values or Gray
// code values into binary values.
//
// 2023 October 5
// Author: Yao Jing Quek <yao.jing.quek@intel.com>

import 'package:rohd/rohd.dart';

/// A module for converting binary values to Gray code representation.
///
/// The [BinaryToGrayConverter] class represents a module that takes a binary
/// value as input and produces the equivalent Gray code representation as
/// output. It internally uses the [binaryToGray] function for the
/// conversion.
class BinaryToGrayConverter extends Module {
/// The Gray code representation output of the converter.
///
/// This [Logic] value represents the Gray code representation of the binary
/// input provided to the converter. It can be accessed using
/// the [gray] getter.
Logic get gray => output('gray');

/// Creates a [BinaryToGrayConverter] instance with the specified binary
/// input.
///
/// The [binary] parameter is the binary input that you want to convert
/// to Gray code. The width of the input [binary] determines the width
/// of the Gray code output.
BinaryToGrayConverter(Logic binary) {
final inputWidth = binary.width;
binary = addInput('binary', binary, width: inputWidth);
final grayVal = addOutput('gray', width: inputWidth);

Combinational([
Case(
binary,
[
for (var i = 0; i < (1 << inputWidth); i++)
CaseItem(Const(i, width: inputWidth), [
grayVal <
Const(binaryToGray(LogicValue.ofInt(i, inputWidth)),
width: inputWidth)
])
],
conditionalType: ConditionalType.unique)
]);
}

/// Converts a binary value represented by [binary] to Gray code.
///
/// Given a [binary] value, this function return [LogicValue]
/// representing the equivalent Gray code.
///
/// For each bit in the [binary] input, starting from the least significant
/// bit (index 0), the function calculates the corresponding Gray code bit
/// based on XOR operation with the previous bit. The resulting Gray code
/// bits are returned.
///
/// Returns [LogicValue] representing the Gray code.
static LogicValue binaryToGray(LogicValue binary) {
final reverseBit = binary.reversed;
final binList = reverseBit.toList().asMap().entries.map((entry) {
final currentBit = entry.value;
final idx = entry.key;
if (idx == 0) {
return currentBit;
} else {
final previousIndex = reverseBit[idx - 1];
return currentBit ^ previousIndex;
}
}).toList();
return binList.swizzle();
}
}

/// A module for converting Gray code to binary representation.
///
/// The [GrayToBinaryConverter] class represents a module that takes a Gray
/// code value as input and produces the equivalent binary representation as
/// output. It internally uses the [grayToBinary] function for the
/// conversion
class GrayToBinaryConverter extends Module {
/// The binary representation output of the converter.
///
/// This [Logic] value represents the binary representation of the Gray code
/// input provided to the converter. It can be accessed using the [binary]
/// getter.
Logic get binary => output('binary');

/// Creates a [GrayToBinaryConverter] instance with the specified Gray code
/// input.
///
/// The [gray] parameter is the Gray code input that you want to convert to
/// binary. The width of the input [gray] determines the width of the binary
/// output.
GrayToBinaryConverter(Logic gray) {
final inputWidth = gray.width;
gray = addInput('gray', gray, width: inputWidth);
final binaryVal = addOutput('binary', width: inputWidth);

Combinational([
Case(
gray,
[
for (var i = 0; i < (1 << inputWidth); i++)
CaseItem(Const(i, width: inputWidth), [
binaryVal <
Const(grayToBinary(LogicValue.ofInt(i, inputWidth)),
width: inputWidth),
]),
],
conditionalType: ConditionalType.unique),
]);
}

/// Converts a Gray code value represented by [gray] to binary.
///
/// Given a [gray] value, this function return [LogicValue]
/// representing the equivalent binary representation.
///
/// For each bit in the [gray] input, starting from the least significant bit
/// (index 0), the function calculates the corresponding binary bit based
/// on XOR operation with the previous binary bit.
///
/// Return [LogicValue] representing the binary representation.
static LogicValue grayToBinary(LogicValue gray) {
final reverseGray = gray.reversed;
final grayList = reverseGray.toList();
var previousBit = LogicValue.zero;

final binaryList = grayList.map((currentBit) {
final binaryBit = currentBit ^ previousBit;
previousBit = binaryBit;
return binaryBit;
}).toList();

return binaryList.swizzle();
}
}
122 changes: 122 additions & 0 deletions test/binary_gray_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright (C) 2023 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// binary_gray_test.dart
// Tests for binary to gray and gray to binary conversion.
//
// 2023 October 5
// Author: Yao Jing Quek <yao.jing.quek@intel.com>
//

import 'dart:math';

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:test/test.dart';

Future<void> main() async {
group('binary to gray code', () {
test('should return 100 if binary is 111 and width is 3.', () async {
final binaryInput = Logic(name: 'binaryInput', width: 3)..put(bin('111'));
final binToGray = BinaryToGrayConverter(binaryInput);
await binToGray.build();

expect(binToGray.gray.value.toString(includeWidth: false), '100');
});

test('should return 0 if binary is 0 and width is 1.', () async {
final binaryInput = Logic(name: 'binaryInput')..put(bin('0'));
final binToGray = BinaryToGrayConverter(binaryInput);
await binToGray.build();

expect(binToGray.gray.value.toInt(), 0);
});

test('should return 1 if binary is 1 and width is 1.', () async {
final binaryInput = Logic(name: 'binaryInput')..put(bin('1'));
final binToGray = BinaryToGrayConverter(binaryInput);
await binToGray.build();

expect(binToGray.gray.value.toInt(), 1);
});

test('should return 111110 if binary is 101011 and width is 6.', () async {
final binaryInput = Logic(name: 'binaryInput', width: 6)
..put(bin('101011'));
final binToGray = BinaryToGrayConverter(binaryInput);
await binToGray.build();

expect(binToGray.gray.value.toString(includeWidth: false), '111110');
});
});

group('gray code to binary', () {
test('should return 101 if gray code is 111 and width is 3.', () async {
final graycode = Logic(name: 'grayCode', width: 3)..put(bin('111'));
final grayToBin = GrayToBinaryConverter(graycode);
await grayToBin.build();

expect(grayToBin.binary.value.toString(includeWidth: false), '101');
});

test('should return 0 if gray code is 0 and width is 1.', () async {
final grayCode = Logic(name: 'grayCode')..put(bin('0'));
final grayToBin = GrayToBinaryConverter(grayCode);
await grayToBin.build();

expect(grayToBin.binary.value.toInt(), 0);
});

test('should return 1 if gray code is 1 and width is 1.', () async {
final grayCode = Logic(name: 'grayCode')..put(bin('1'));
final grayToBin = GrayToBinaryConverter(grayCode);
await grayToBin.build();

expect(grayToBin.binary.value.toInt(), 1);
});

test('should return 101011 if gray code is 111110 and width is 6.',
() async {
final grayCode = Logic(name: 'grayCode', width: 6)..put(bin('111110'));
final grayToBin = GrayToBinaryConverter(grayCode);
await grayToBin.build();

expect(grayToBin.binary.value.toString(includeWidth: false), '101011');
});

test(
'sequential values should differ in just one bit in integer and bigInt'
' bit range.', () async {
Future<void> checkBitDiff({required int width}) async {
for (var i = 0; i < pow(2, width) - 1; i++) {
final binaryInput1 = Logic(name: 'binaryInputSeq1', width: width)
..put(bin(i.toRadixString(2)));
final binaryInput2 = Logic(name: 'binaryInputSeq2', width: width)
..put(bin((i + 1).toRadixString(2)));

final binToGray1 = BinaryToGrayConverter(binaryInput1);
final binToGray2 = BinaryToGrayConverter(binaryInput2);

await binToGray1.build();
await binToGray2.build();

final gray1 = binToGray1.gray.value;
final gray2 = binToGray2.gray.value;

var diff = gray1 ^ gray2;

var setBits = 0;
while (diff.toInt() != 0) {
setBits++;
diff &= diff - 1;
}

expect(setBits, 1);
}
}

await checkBitDiff(width: 64);
await checkBitDiff(width: 100);
});
});
}

0 comments on commit 20d897a

Please sign in to comment.