diff --git a/libraries/base/common/src/vhdl/common_pkg.vhd b/libraries/base/common/src/vhdl/common_pkg.vhd index 4b7c0f4b718866c29995a2968116247b233103c2..cf03d8a7b2723ad19b51505269d471b2eb01b8c4 100644 --- a/libraries/base/common/src/vhdl/common_pkg.vhd +++ b/libraries/base/common/src/vhdl/common_pkg.vhd @@ -383,15 +383,38 @@ PACKAGE common_pkg IS FUNCTION TO_UREAL(uvec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL; -- convert unsigned fixed point slv of any length, and with resolution of 2**resolution_w, to REAL FUNCTION TO_SREAL(svec : STD_LOGIC_VECTOR; resolution_w : INTEGER) RETURN REAL; -- convert signed fixed point slv of any length, and with resolution of 2**resolution_w, to REAL --- The RESIZE for SIGNED in IEEE.NUMERIC_STD extends the sign bit or it keeps the sign bit and LS part. This + -- RESIZE_NUM() original description: + -- The RESIZE for SIGNED in IEEE.NUMERIC_STD extends the sign bit or it keeps the sign bit and LS part. This -- behaviour of preserving the sign bit is less suitable for DSP and not necessary in general. A more -- appropriate approach is to ignore the MSbit sign and just keep the LS part. For too large values this -- means that the result gets wrapped, but that is fine for default behaviour, because that is also what -- happens for RESIZE of UNSIGNED. Therefor this is what the RESIZE_NUM for SIGNED and the RESIZE_SVEC do - -- and better not use RESIZE for SIGNED anymore. When w keeps or increases the data width then the values - -- do not change (of course). When w reduces the data width then: - -- * RESIZE() wraps between -, 0 for negative and 0, + for positive, so it keeps the sign and w-1 LSbits - -- * RESIZE_NUM() removes MSbits, so it wraps from + to - and from - to +, and it keeps the w LSbits + -- and better not use RESIZE for SIGNED anymore. + -- + -- RESIZE_NUM() updated description (27 oct 2021): + -- The RESIZE() from IEEE.NUMERIC_STD keeps the sign bit and the w-1 LSbits, this results in a signal that + -- keeps the sign, but wraps between - and 0 for negative input, and that wraps between + and 0 for + -- positive input. + -- The RESIZE_NUM() from in this common_pkg.vhd simply keeps the w LSbits, so it wraps between - and +. + -- Hence RESIZE_NUM() works the same for SIGNED as for UNSIGNED. For an adder that sums multiple inputs, + -- it can be better to wrap over the entire -, + range, like RESIZE_NUM() does, because if the final adder + -- sum again fits in w bits, then any wrapping effects for intermediate sums will cancel in the end sum. + -- If the number of bit w is sufficient to have no resize overflow, then RESIZE() = RESIZE_NUM(). In an + -- application overflow should be avoided anyway, so then using either RESIZE() or RESIZE_NUM() is fine. + -- When w keeps or increases the data width then the values do not change (of course). When w reduces the + -- data width then overflow can occur in an application, so then use: + -- * RESIZE() to preserve the sign, + -- * RESIZE_NUM() to wrap similar for SIGNED as for UNSIGNED, + -- * common_resize.vhd to clip the overflow (and use symmetrical -, + clipping to avoid introducing DC bias). + -- The resize functions and component are verified by tb_tb_resize.vhd. + -- Conclusion: + -- 1) Keep original RESIZE_NUM(), so resize by selecting the w LSbits for both SIGNED and UNSIGNED. + -- 2) For applications without overflow RESIZE() = RESIZE_NUM() = common_resize. + -- 3) For applications with overflow choose to use RESIZE_NUM(), because it wraps similar for SIGNED as + -- for UNSIGNED (because both keep the w LSbits), instead of behaving differently for SIGNED like + -- RESIZE() does (keeping the MSbit and the w-1 LSbits). The wrapping of RESIZE_NUM() preserves the + -- capability of recovering from intermediate overflow in a summator, which can be beneficial for e.g. + -- a beamformer. FUNCTION RESIZE_NUM( u : UNSIGNED; w : NATURAL) RETURN UNSIGNED; -- left extend with '0' or keep LS part (same as RESIZE for UNSIGNED) FUNCTION RESIZE_NUM( s : SIGNED; w : NATURAL) RETURN SIGNED; -- extend sign bit or keep LS part FUNCTION RESIZE_UVEC(sl : STD_LOGIC; w : NATURAL) RETURN STD_LOGIC_VECTOR; -- left extend with '0' into slv