From bf4106e2e15518e6e9af9137246fb66797586bbc Mon Sep 17 00:00:00 2001 From: Josh Kimmel Date: Thu, 21 Nov 2024 13:04:55 -0800 Subject: [PATCH] [MultiCycleDivider] Patch of prior bug fix to properly support unsigned division (#141) * Fixing bug in Divider and updating tests and documentation accordingly. --- doc/components/divider.md | 10 +++++++--- lib/src/arithmetic/divider.dart | 7 ++----- test/arithmetic/divider_test.dart | 9 ++++++++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/doc/components/divider.md b/doc/components/divider.md index a2ebb689c..d2b564495 100644 --- a/doc/components/divider.md +++ b/doc/components/divider.md @@ -1,13 +1,13 @@ # Divider -ROHD HCL provides an integer divider module to get the dividend of numerator and denominator operands. The divider implementation is not pipelined and has a maximum latency of the bit width of the operands. +ROHD HCL provides an integer divider module to get the quotient and the remainder of dividend and divisor operands. The divider implementation is not pipelined and has a minimum latency of 3 cycles. The maximum latency is dependent on the width of the operands (upper bound of `O(WIDTH**2)`). Note that latency increases exponentially as the absolute difference between the dividend and the divisor increases (worst case: largest possible dividend and divisor of 1). ## Interface The inputs to the divider module are: * `clock` => clock for synchronous logic -* `reset` => reset for synchronous logic (active high) +* `reset` => reset for synchronous logic (active high, synchronous to `clock`) * `dividend` => the numerator operand * `divisor` => the denominator operand * `isSigned` => should the operands of the division be treated as signed integers @@ -30,7 +30,7 @@ To initiate a new request, it is expected that the requestor drive `validIn` to When the division is complete, the module will assert the `validOut` signal along with the numerical values of `quotient` and `remainder` representing the division result and the signal `divZero` to indicate whether or not a division by zero occurred. The module will hold these signal values until `readyOut` is driven high by the integrating environment. The integrating environment must assume that `quotient` and `remainder` are meaningless if `divZero` is asserted. -### Mathematical Properties +## Mathematical Properties For the division, implicit rounding towards 0 is always performed. I.e., a negative quotient will always be rounded up if the dividend is not evenly divisible by the divisor. Note that this behavior is not uniform across all programming languages (for example, Python rounds towards negative infinity). @@ -65,3 +65,7 @@ if (divIntf.validOut.value.toBool()) { } ``` + +## Future Considerations + +In the future, an optimization might be added in which the `remainder` output is optional and controlled by a build time constructor parameter. If the remainder does not need to be computed, the implementation's upper bound latency can be significantly improved (`O(WIDTH**2)` => `O(WIDTH)`). diff --git a/lib/src/arithmetic/divider.dart b/lib/src/arithmetic/divider.dart index c3016eee2..a15a1e918 100644 --- a/lib/src/arithmetic/divider.dart +++ b/lib/src/arithmetic/divider.dart @@ -258,10 +258,7 @@ class MultiCycleDivider extends Module { orElse: [ tmpDifference < (aBuf - tmpShift), // move to accumulate if tmpDifference <= 0 - If( - ~tmpShift.or() | - tmpDifference[dataWidth - 1] | - ~tmpDifference.or(), + If(~tmpShift.or() | tmpDifference[-1] | ~tmpDifference.or(), then: [nextState < _MultiCycleDividerState.accumulate], orElse: [nextState < _MultiCycleDividerState.process]) ]) @@ -375,7 +372,7 @@ class MultiCycleDivider extends Module { currentState.eq(_MultiCycleDividerState .process), // didn't exceed a_buf, so count as success [ - If(~tmpDifference[dataWidth - 1], then: [ + If(~tmpDifference[-1], then: [ lastSuccess < (Const(1, width: dataWidth + 1) << currIndex), // capture 2^i diff --git a/test/arithmetic/divider_test.dart b/test/arithmetic/divider_test.dart index 6574b1bfb..b98a60553 100644 --- a/test/arithmetic/divider_test.dart +++ b/test/arithmetic/divider_test.dart @@ -406,7 +406,14 @@ class MultiCycleDividerBasicSequence extends Sequence { mDivisor: 0, mValidIn: true, mIsSigned: true, - mReadyOut: true)); // divide by 0 + mReadyOut: true)) // divide by 0 + // long latency division + ..add(MultiCycleDividerInputSeqItem( + mDividend: 0xffffffec, + mDivisor: 0x6, + mValidIn: true, + mIsSigned: false, + mReadyOut: true)); } }