Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
71 changes: 71 additions & 0 deletions lib/src/arithmetic/floating_point/floating_point_fft.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Copyright (C) 2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

import 'package:rohd/rohd.dart';

// class FFT extends Module {
// LogicArray get out => output('out') as LogicArray;
//
// FFT(Logic en, Logic clk, Logic reset, LogicArray input, {super.name = 'fft'})
// : assert(input.dimensions.length == 1) {
// final int length = input.dimensions[0];
// if ((length & (~(length - 1))) != length) {
// assert(false);
// }
// final int log2Length = log2Ceil(length);
//
// input = addInputArray(
// 'input_array',
// input,
// dimensions: input.dimensions, // it seems like these are needed
// elementWidth: input.elementWidth,
// numUnpackedDimensions: input.numUnpackedDimensions,
// );
//
// List<LogicArray> stageArrays = List.generate(
// log2Length + 1,
// (stage) => LogicArray(
// input.dimensions,
// input.elementWidth,
// name: 'stage${stage}Array',
// numUnpackedDimensions: input.numUnpackedDimensions,
// ),
// );
//
// LogicArray out = addOutputArray(
// 'out',
// dimensions: input.dimensions,
// elementWidth: input.elementWidth,
// numUnpackedDimensions: input.numUnpackedDimensions,
// );
// out <= stageArrays[log2Length];
//
// List<List<Conditional> Function(PipelineStageInfo)> fftStages = [];
//
// fftStages.add((p) => [stageArrays[0] < BitReverse(input).out]);
//
// for (var s = 1; s <= log2Length; s++) {
// final m = 1 << s;
// final mShift = log2Ceil(m);
//
// Counter i = Counter(en, reset, clk, width: log2Length - 1);
//
// Logic k = (i.val >> (mShift - 1)) << mShift;
// Logic j = (i.val & Const((m >> 1) - 1, width: i.width));
// }
//
// // ReadyValidPipeline()
//
// // for s = 1 to log(n) do
// // m ← 2s
// // ωm ← exp(−2πi/m)
// // for k = 0 to n-1 by m do
// // ω ← 1
// // for j = 0 to m/2 – 1 do
// // t ← ω A[k + j + m/2]
// // u ← A[k + j]
// // A[k + j] ← u + t
// // A[k + j + m/2] ← u – t
// // ω ← ω ωm
// }
// }
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// Copyright (C) 2024-2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

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

class ComplexFloatingPoint extends LogicStructure {
final FloatingPoint realPart;

final FloatingPoint imaginaryPart;

static String _nameJoin(String? structName, String signalName) {
if (structName == null) {
return signalName;
}
return '${structName}_$signalName';
}

ComplexFloatingPoint({
required int exponentWidth,
required int mantissaWidth,
String? name,
}) : this._internal(
realPart: FloatingPoint(
exponentWidth: exponentWidth,
mantissaWidth: mantissaWidth,
name: _nameJoin(name, 're'),
),
imaginaryPart: FloatingPoint(
exponentWidth: exponentWidth,
mantissaWidth: mantissaWidth,
name: _nameJoin(name, 'im'),
),
name: name,
);

ComplexFloatingPoint._internal(
{required this.realPart, required this.imaginaryPart, super.name})
: assert(realPart.exponent.width == imaginaryPart.exponent.width),
assert(realPart.mantissa.width == imaginaryPart.mantissa.width),
super([realPart, imaginaryPart]);

@mustBeOverridden
@override
ComplexFloatingPoint clone({String? name}) => ComplexFloatingPoint(
exponentWidth: realPart.exponent.width,
mantissaWidth: realPart.mantissa.width,
name: name,
);

ComplexFloatingPoint adder(ComplexFloatingPoint other) =>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not override operator + and *?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to hide the fact that it's expensive

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the names of the functions seem unintuitive to me, maybe plus and times or addedTo and multipliedBy or something?

if we wanted to stay more consistent with other parts of the library, these could be their own components (classes, modules) e.g. ComplexFloatingPointMultiplier, perhaps with an argument that allows you to choose your own FloatingPointMultiplier implementation for the internals.

ComplexFloatingPoint._internal(
realPart: FloatingPointAdderSinglePath(realPart, other.realPart).sum,
imaginaryPart:
FloatingPointAdderSinglePath(imaginaryPart, other.imaginaryPart)
.sum,
name: _nameJoin(name, "adder"));

ComplexFloatingPoint multiplier(ComplexFloatingPoint other) {
// use only 3 multipliers: https://mathworld.wolfram.com/ComplexMultiplication.html
final ac = FloatingPointMultiplierSimple(realPart, other.realPart).product;
final bd = FloatingPointMultiplierSimple(imaginaryPart, other.imaginaryPart)
.product;
final abcd = FloatingPointMultiplierSimple(
FloatingPointAdderSinglePath(realPart, imaginaryPart).sum,
FloatingPointAdderSinglePath(other.realPart, other.imaginaryPart)
.sum)
.product;

return ComplexFloatingPoint._internal(
realPart: FloatingPointAdderSinglePath(ac, bd.negated()).sum,
imaginaryPart: FloatingPointAdderSinglePath(abcd,
FloatingPointAdderSinglePath(ac.negated(), bd.negated()).sum)
.sum,
name: _nameJoin(name, "multiplier"));
}

ComplexFloatingPoint negated() => ComplexFloatingPoint._internal(
realPart: realPart.negated(),
imaginaryPart: imaginaryPart.negated(),
name: _nameJoin(name, "negated"));
}
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,12 @@ class FloatingPoint extends LogicStructure {
}
}

FloatingPoint negated() => FloatingPoint._(
~sign,
exponent.clone()..gets(exponent),
mantissa.clone()..gets(mantissa),
_explicitJBit);

/// Construct a FloatingPoint that represents infinity.
factory FloatingPoint.inf(
{required int exponentWidth,
Expand Down
44 changes: 44 additions & 0 deletions lib/src/bit_reversal.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (C) 2021-2024 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause

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

int bitReverse(int value, int bits) {
var reversed = 0;
for (var i = 0; i < bits; i++) {
reversed <<= 1;
reversed |= value & 1;
value >>= 1;
}
return reversed;
}

class BitReversal extends Module {
LogicArray get out => output('out') as LogicArray;

BitReversal(LogicArray input, {super.name = 'bit_reversal'})
: assert(input.dimensions.length == 1, 'Can only bit reverse 1D arrays') {
input = addInputArray(
'input_array',
input,
dimensions: input.dimensions, // it seems like these are needed
elementWidth: input.elementWidth,
numUnpackedDimensions: input.numUnpackedDimensions,
);

final out = addOutputArray(
'out',
dimensions: input.dimensions,
elementWidth: input.elementWidth,
numUnpackedDimensions: input.numUnpackedDimensions,
);

final length = input.dimensions[0];
final bits = log2Ceil(length);

for (var i = 0; i < length; i++) {
out.elements[bitReverse(i, bits)] <= input.elements[i];
}
}
}
65 changes: 65 additions & 0 deletions test/arithmetic/floating_point/copmlex_floating_point_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (C) 2025 Intel Corporation
// SPDX-License-Identifier: BSD-3-Clause
//
// floating_point_test.dart
// Tests of Floating Point basic types
//
// 2024 April 1
// Authors:
// Max Korbel <[email protected]>
// Desmond A Kirkpatrick <[email protected]

import 'package:rohd/rohd.dart';
import 'package:rohd_hcl/rohd_hcl.dart';
import 'package:rohd_hcl/src/arithmetic/signals/floating_point_logics/complex_floating_point_logic.dart';
import 'package:test/test.dart';

ComplexFloatingPoint newComplex(double real, double imaginary) {
final realFP = FloatingPoint64();
final imaginaryFP = FloatingPoint64();

final realFPValue = FloatingPoint64Value.populator().ofDouble(real);
final imaginaryFPValue = FloatingPoint64Value.populator().ofDouble(imaginary);

realFP.put(realFPValue);
imaginaryFP.put(imaginaryFPValue);

final complex = ComplexFloatingPoint(
exponentWidth: realFP.exponent.width,
mantissaWidth: realFP.mantissa.width);
complex.realPart <= realFP;
complex.imaginaryPart <= imaginaryFP;

return complex;
}

void main() {
tearDown(() async {
await Simulator.reset();
});

test('complex constructor', () {
final complex = newComplex(1.23, 3.45);

expect(complex.realPart.floatingPointValue.toDouble(), 1.23);
expect(complex.imaginaryPart.floatingPointValue.toDouble(), 3.45);
});

test('complex addition', () {
final a = newComplex(1.0, 0.0);
final b = newComplex(0.0, -1.0);
final c = a.adder(b);

expect(c.realPart.floatingPointValue.toDouble(), 1.0);
expect(b.imaginaryPart.floatingPointValue.toDouble(), -1.0);
});

test('complex multiplication', () {
final a = newComplex(1.0, 2.0);
final b = newComplex(-3.0, -4.0);
final c = a.multiplier(b);

expect(c.realPart.floatingPointValue.toDouble(), 5.0);
expect(c.imaginaryPart.floatingPointValue.toDouble(), -10.0);
});
}
Loading