Skip to content

Commit

Permalink
Serialization (#92)
Browse files Browse the repository at this point in the history
  • Loading branch information
desmonddak authored Sep 19, 2024
1 parent b731bd8 commit 22f6154
Show file tree
Hide file tree
Showing 6 changed files with 617 additions and 0 deletions.
11 changes: 11 additions & 0 deletions doc/components/serialization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Serialization / Deserialization

ROHD-HCL implements a `Serializer` and `Deserializer` set of components that enable converting wide structures to a serialized narrow stream of data and vice-versa.

## Serializer

The `Serializer` is a module that accepts a wider `LogicArray` `deserialized` for input data and optionally a `Logic` `readyIn` to allow for pausing serialization. While `readyIn` is high, the `Serializer` sequentially outputs chunks of data on the Logic `serialized` output until the entire `LogicArray` `deserialized` has been transferred to the output. At that point the `Serializer` raises Logic `done`. This process will continue until the Logic `readyIn` is lowered, allowing for back-to-back transfers of wide data over the Logic `serialized` stream. The number of serialization steps in the current transfer is available in Logic `count`. Lowering `readyIn` will pause the transfer and raising it will continue from where it paused.

## Deserializer

The `Deserializer` is a module that accepts a `Logic` `serialized` stream over a pre-defined `length` number of clocks. It outputs a `LogicArray` `deserialized` of the same length of Logic words that match the width of Logic `serialized`. Deserialization runs while Logic `enable` is high, and Logic `validOut` is emitted when deserialization is complete. This process will continue when Logic `enable` is high, allowing for back-to-back deserialization transfers of a narrow stream of data into wider (`length`) `LogicArray`s during `length` number of serialization steps (clocks while `enable` is high) for each transfer. The number of serialization steps in the current transfer is available in Logic `count`. Lowering `enable` will pause the transfer and raising it will continue from where it paused.
1 change: 1 addition & 0 deletions lib/rohd_hcl.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export 'src/interfaces/interfaces.dart';
export 'src/memory/memories.dart';
export 'src/models/models.dart';
export 'src/rotate.dart';
export 'src/serialization/serialization.dart';
export 'src/shift_register.dart';
export 'src/sort.dart';
export 'src/summation/summation.dart';
Expand Down
70 changes: 70 additions & 0 deletions lib/src/serialization/deserializer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// deserializer.dart
// A deserialization block, deserializing narrow input data onto a wide channel.
//
// 2024 August 27
// Author: desmond Kirkpatrick <[email protected]>

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

/// [Deserializer] aggregates data from a serialized stream.
class Deserializer extends Module {
/// Aggregated data output.
LogicArray get deserialized => output('deserialized') as LogicArray;

/// Length of aggregate to deserialize.
final int length;

/// [done] emitted when the last element is committed to [deserialized].
/// The timing is that you can latch [deserialized] when [done] is high.
Logic get done => output('done');

/// Return the current count of elements that have been serialized out.
Logic get count => output('count');

/// Build a Deserializer that takes serialized input [serialized]
/// and aggregates it into one wide output [deserialized] of length [length].
///
/// Updates one element per clock while [enable] (if connected) is high,
/// emitting [done] when completing the filling of wide output `LogicArray`
/// [deserialized].
Deserializer(Logic serialized, this.length,
{required Logic clk,
required Logic reset,
Logic? enable,
super.name = 'deserializer'}) {
clk = addInput('clk', clk);
reset = addInput('reset', reset);
if (enable != null) {
enable = addInput('enable', enable);
}
serialized = (serialized is LogicArray)
? addInputArray('serialized', serialized,
dimensions: serialized.dimensions,
elementWidth: serialized.elementWidth)
: addInput('serialized', serialized, width: serialized.width);
final cnt = Counter.simple(
clk: clk, reset: reset, enable: enable, maxValue: length - 1);
addOutput('count', width: cnt.width) <= cnt.count;
addOutput('done') <= cnt.overflowed;
addOutputArray('deserialized',
dimensions: (serialized is LogicArray)
? ([length, ...serialized.dimensions])
: [length],
elementWidth: (serialized is LogicArray)
? serialized.elementWidth
: serialized.width)
.elements
.forEachIndexed((i, d) =>
d <=
flop(
clk,
reset: reset,
en: (enable ?? Const(1)) & count.eq(i),
serialized));
}
}
5 changes: 5 additions & 0 deletions lib/src/serialization/serialization.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

export 'deserializer.dart';
export 'serializer.dart';
91 changes: 91 additions & 0 deletions lib/src/serialization/serializer.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (C) 2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// serializer.dart
// A serialization block, serializing wide input data onto a narrower channel.
//
// 2024 August 27
// Author: desmond Kirkpatrick <[email protected]>

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

/// Serializes wide aggregated data onto a narrower serialization stream.
class Serializer extends Module {
/// Serialized output, one data item per clock.
Logic get serialized => output('serialized');

/// Return [done] = true when we have processed `deserialized`completely.
/// [done] is asserted with the final element being serialized so that
/// at the next clock edge, you have [done] with the last element latched at
/// the same time.
Logic get done => output('done');

/// The number of current serialization steps completed in the
/// transfer is [count].
Logic get count => output('count');

/// Build a Serializer that takes the array [deserialized] and sequences it
/// onto the [serialized] output.
///
/// Delivers one element per clock while [enable]
/// is high (if connected). If [flopInput] is true, the
/// [Serializer] is configured to latch the input data and hold it until
/// [done] is asserted after the full `LogicArray` [deserialized] is
/// transferred. This will delay the serialized output by one cycle.
Serializer(LogicArray deserialized,
{required Logic clk,
required Logic reset,
Logic? enable,
bool flopInput = false,
super.name = 'serializer'}) {
clk = addInput('clk', clk);
reset = addInput('reset', reset);
if (enable != null) {
enable = addInput('enable', enable);
}
deserialized = addInputArray('deserialized', deserialized,
dimensions: deserialized.dimensions,
elementWidth: deserialized.elementWidth);

addOutput('count', width: log2Ceil(deserialized.dimensions[0]));
addOutput('done');

final reducedDimensions = List<int>.from(deserialized.dimensions)
..removeAt(0);
if (deserialized.dimensions.length > 1) {
addOutputArray('serialized',
dimensions: reducedDimensions,
elementWidth: deserialized.elementWidth);
} else {
addOutput('serialized', width: deserialized.elementWidth);
}

final cnt = Counter.simple(
clk: clk,
reset: reset,
enable: enable,
maxValue: deserialized.elements.length - 1);

final latchInput = (enable ?? Const(1)) & ~cnt.count.or();
count <=
(flopInput
? flop(clk, reset: reset, en: enable, cnt.count)
: cnt.count);

final dataOutput =
LogicArray(deserialized.dimensions, deserialized.elementWidth);
for (var i = 0; i < deserialized.elements.length; i++) {
dataOutput.elements[i] <=
(flopInput
? flop(
clk, reset: reset, en: latchInput, deserialized.elements[i])
: deserialized.elements[i]);
}
serialized <= dataOutput.elements.selectIndex(count);
done <=
(flopInput
? flop(clk, reset: reset, en: enable, cnt.equalsMax)
: cnt.equalsMax);
}
}
Loading

0 comments on commit 22f6154

Please sign in to comment.