diff --git a/libraries/base/common/hdllib.cfg b/libraries/base/common/hdllib.cfg
index 507266e0ecca3abf8a42762d4ac1ba85ce4a7258..6a8deef3b0251bc4dc8d5a8401c9b93e470c8ff9 100644
--- a/libraries/base/common/hdllib.cfg
+++ b/libraries/base/common/hdllib.cfg
@@ -197,6 +197,7 @@ test_bench_files =
     tb/vhdl/tb_mms_common_variable_delay.vhd
     
     tb/vhdl/tb_tb_resize.vhd
+    tb/vhdl/tb_tb_round.vhd
     tb/vhdl/tb_tb_common_add_sub.vhd
     tb/vhdl/tb_tb_common_adder_tree.vhd
     tb/vhdl/tb_tb_common_fanout_tree.vhd
@@ -220,7 +221,7 @@ regression_test_vhdl =
     tb/vhdl/tb_common_transpose_symbol.vhd
     tb/vhdl/tb_common_variable_delay.vhd
     tb/vhdl/tb_tb_resize.vhd
-    #tb/vhdl/tb_round.vhd           -- has no self verification yet
+    tb/vhdl/tb_tb_round.vhd
     tb/vhdl/tb_requantize.vhd
     tb/vhdl/tb_common_to_sreal.vhd
     tb/vhdl/tb_common_pulse_delay.vhd
diff --git a/libraries/base/common/src/vhdl/common_pkg.vhd b/libraries/base/common/src/vhdl/common_pkg.vhd
index cf03d8a7b2723ad19b51505269d471b2eb01b8c4..58e8b511359f7c00e7788c636eff2713d2edf18c 100644
--- a/libraries/base/common/src/vhdl/common_pkg.vhd
+++ b/libraries/base/common/src/vhdl/common_pkg.vhd
@@ -464,12 +464,12 @@ PACKAGE common_pkg IS
   FUNCTION truncate_or_resize_uvec( vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- when b=TRUE then truncate to width w, else resize to width w
   FUNCTION truncate_or_resize_svec( vec : STD_LOGIC_VECTOR; b : BOOLEAN; w : NATURAL) RETURN STD_LOGIC_VECTOR;  -- idem for signed values
   
-  FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n, and clip to avoid wrap
-  FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n
-  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem but round up to +infinity (s_round_up = u_round)
-  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- idem but round up to +infinity (s_round_up = u_round)
-  FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
-  FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                 RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
+  FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip       : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n, and clip to avoid wrap
+  FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                       RETURN STD_LOGIC_VECTOR;  -- remove n LSBits from vec by rounding away from 0, so result has width vec'LENGTH-n
+  FUNCTION s_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip, even : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem but round half to even for signed
+  FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip       : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
+  FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL)                       RETURN STD_LOGIC_VECTOR;  -- idem round up for unsigned values
+  FUNCTION u_round(   vec : STD_LOGIC_VECTOR; n : NATURAL; clip, even : BOOLEAN) RETURN STD_LOGIC_VECTOR;  -- idem but round half to even for unsigned
 
   FUNCTION u_to_s(u : NATURAL; w : NATURAL) RETURN INTEGER;   -- interpret w bit unsigned u as w bit   signed, and remove any MSbits
   FUNCTION s_to_u(s : INTEGER; w : NATURAL) RETURN NATURAL;   -- interpret w bit   signed s as w bit unsigned, and remove any MSbits
@@ -2313,16 +2313,62 @@ PACKAGE BODY common_pkg IS
     RETURN v_res;
   END;
   
-  
-  -- Functions s_round, s_round_up and u_round:
+  -------------------------------------------------------------------------------------------------
+  -- Rounding schemes:
+  -------------------------------------------------------------------------------------------------
+  --
+  -- From https://en.wikipedia.org/wiki/Rounding it follows that there are three main
+  -- categories for rounding to integer:
+  --
+  -- 1) Direct rounding to integer :
+  --    . down           : y = floor(x), is truncate of LSbits
+  --    . up             : y = ceil(x),
+  --    . towards zero   : y = truncate(x) = int(x), is truncate of fraction, is keep the integer part
+  --                         = sgn(x) floor(|x|) = floor(x) when x >= 0, else ceil(x)
+  --    . away from zero : y = sgn(x) ceil(|x|) = ceil(x) when x >= 0, else floor(x)
+  -- 2) Rounding to nearest integer :
+  --    . half down           : y = ceil(x - 0.5),
+  --    . half up             : y = floor(x + 0.5),
+  --    . half towards zero   : y = sgn(x) ceil(|x| - 0.5) = ceil(x - 0.5) when x >= 0, else floor(x + 0.5)
+  --    . half away from zero : y = sgn(x) floor(|x| + 0.5) = floor(x + 0.5) when x >= 0, else ceil(x - 0.5)
+  --    . round half to even : rounds to the nearest even integer when fraction = 0.5 else use
+  --      either floor(x + 0.5) or ceil(x - 0.5), because they are equivalent then. This avoid
+  --      DC bias and bias towards or away from zero.
+  --
+  -- 3) Randomized rounding to an integer : round to nearest when fraction != 0.5, round up or
+  --    down when fraction = 0.5. This avoid DC bias and bias towards or away from zero:
+  --    . alternate tie breaking : alternately select round up or round down when fraction = 0.5
+  --        else either floor(x + 0.5) or ceil(x - 0.5), because they are equivalent then.
+  --    . random tie breaking : idem as alternate tie breaking, but use random selection.
+  --    . stochastic rounding : round up or down with a probability that depends on proximity.
+  --      This avoids DC bias when the input is not random, e.g. when the input has a constant
+  --      fraction > 0. For DSP with ADC related data with sufficient dynamic range this does
+  --      not occur.
+  --
+  --  The advantage of round half to even, over round with tie breaking is, that for tie
+  --  breaking an external signal is needed to hold the alternate or random selector state,
+  --  whereas for round half to even the current input signal itself determines the
+  --  selection. Hence round half to even can be fully implemented in a function, whereas
+  --  a function for round using tie breaking requires an external state to manage the
+  --  selection.
+  --
+  --  * Half up introduces +DC bias when fraction 0.5 occurs.
+  --  * Half away from zero is also used by round() in VHDL math_real, Matlab, Python, TCL.
+  --  * Half away avoids DC bias, but does introduce bias away from zero, which can show
+  --    as a up bias in power values because (negative)**2 > 0 and (positive)**2 > 0.
+  --
+  -- Functions s_round() and u_round():
   --
+  -- . u_round() supports half up (= half away) and half even.
+  -- . s_round() supports half away and half even.
   -- . The returned output width is input width - n.
   -- . If n=0 then the return value is the same as the input value so only
   --   wires (NOP, no operation).
   -- . Both have the same implementation but different c_max and c_clip values.
   -- . Round up for unsigned so +2.5 becomes 3
-  -- . Round away from zero for signed so round up for positive and round down for negative, so +2.5 becomes 3 and -2.5 becomes -3.
-  -- . Round away from zero is also used by round() in Matlab, Python, TCL
+  -- . Round away from zero for signed so round up for positive and round down for negative,
+  --   so +2.5 becomes 3 and -2.5 becomes -3.
+  -- . Round away from zero is also used by round() in VHDL math_real, Matlab, Python, TCL
   -- . Rounding up implies adding 0.5 and then truncation, use clip = TRUE to
   --   clip the potential overflow due to adding 0.5 to +max.
   -- . For negative values overflow due to rounding can not occur, because c_half-1 >= 0 for n>0
@@ -2332,73 +2378,79 @@ PACKAGE BODY common_pkg IS
   --   maximum product is -8*-8=+64 <= 127-8, so wrapping due to rounding
   --   overflow will never occur.
 
-  FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
-    -- Use SIGNED to avoid NATURAL (32 bit range) overflow error
-    CONSTANT c_in_w  : NATURAL := vec'LENGTH;
-    CONSTANT c_out_w : NATURAL := vec'LENGTH - n;
-    CONSTANT c_one   : SIGNED(c_in_w-1 DOWNTO 0) := TO_SIGNED(1, c_in_w);
-    CONSTANT c_half  : SIGNED(c_in_w-1 DOWNTO 0) := SHIFT_LEFT(c_one, n-1);                            -- = 2**(n-1)
-    CONSTANT c_max   : SIGNED(c_in_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_in_w-2 DOWNTO 0)) - c_half;  -- = 2**(c_in_w-1)-1 - c_half  
-    CONSTANT c_clip  : SIGNED(c_out_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_out_w-2 DOWNTO 0));         -- = 2**(c_out_w-1)-1
-    VARIABLE v_in    : SIGNED(c_in_w-1 DOWNTO 0);
-    VARIABLE v_out   : SIGNED(c_out_w-1 DOWNTO 0);
+  FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip, even : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
+    -- # Round half away from zero when even = FALSE, else round half to even.
+    -- # Round half to even algorithm:
+    -- #                vec: -3.5  -2.5  -1.5  -0.5  0.5  1.5  2.5  3.5
+    -- #   floor(vec + 0.5)  -4    -3    -2    -1    1    2    3    4
+    -- #   round even        -4    -2    -2     0    0    2    2    4
+    -- #   round even clip   -4    -2    -2     0    0    2    2    3, clip to c_clip = 3 when c_out_w = 3
+    -- Use SIGNED instead of NATURAL for c_half to avoid INTEGER (32 bit range) overflow error
+    CONSTANT c_in_w     : NATURAL := vec'LENGTH;
+    CONSTANT c_out_w    : NATURAL := vec'LENGTH - n;
+    CONSTANT c_one      : SIGNED(c_in_w-1 DOWNTO 0) := TO_SIGNED(1, c_in_w);
+    CONSTANT c_half     : SIGNED(c_in_w-1 DOWNTO 0) := SHIFT_LEFT(c_one, n-1);                            -- = 2**(n-1)
+    CONSTANT c_max      : SIGNED(c_in_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_in_w-2 DOWNTO 0)) - c_half;  -- = 2**(c_in_w-1)-1 - c_half
+    -- When c_out_w = 1, then c_clip = 0, because a 1 bit signed value is -1 or 0
+    CONSTANT c_clip     : SIGNED(c_out_w-1 DOWNTO 0) := SIGNED('0' & c_slv1(c_out_w-2 DOWNTO 0));         -- = 2**(c_out_w-1)-1
+    VARIABLE v_in       : SIGNED(c_in_w-1 DOWNTO 0);
+    CONSTANT u_half     : UNSIGNED(n-1 DOWNTO 0) := UNSIGNED(STD_LOGIC_VECTOR(c_half(n-1 DOWNTO 0)));     -- convert to UNSIGNED to compare with u_fraction
+    VARIABLE u_fraction : UNSIGNED(n-1 DOWNTO 0);
+    VARIABLE v_out      : SIGNED(c_out_w-1 DOWNTO 0);
   BEGIN
     v_in := SIGNED(vec);
     IF n > 0 THEN
       IF clip = TRUE AND v_in > c_max THEN
-        v_out := c_clip;                                              -- Round clip to maximum positive to avoid wrap to negative
+        v_out := c_clip;  -- Round clip to maximum positive to avoid wrap to negative
       ELSE
-        IF vec(vec'HIGH)='0' THEN
-          v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half + 0, n), c_out_w);  -- Round up for positive
+        IF even = FALSE THEN
+          -- Round half away
+          IF vec(vec'HIGH)='0' THEN
+            v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half + 0, n), c_out_w);  -- Round half up for positive
+          ELSE
+            v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half - 1, n), c_out_w);  -- Round half down for negative
+          END IF;
         ELSE
-          v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half - 1, n), c_out_w);  -- Round down for negative
+          -- Round half to even
+          v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half, n), c_out_w);  -- Round to nearest using floor(vec + 0.5)
+          u_fraction := UNSIGNED(vec(n-1 DOWNTO 0));
+          IF u_fraction = u_half AND v_out(0) = '1' THEN  -- Round half to even, so when odd subtract 1
+            v_out := v_out - 1;                           -- to make v_out even
+          END IF;
         END IF;
       END IF;
     ELSE
-      v_out := RESIZE_NUM(v_in, c_out_w);                             -- NOP
+      v_out := RESIZE_NUM(v_in, c_out_w);  -- NOP
     END IF;
     RETURN STD_LOGIC_VECTOR(v_out);
   END;
 
-  FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
   BEGIN
-    RETURN s_round(vec, n, FALSE);  -- no round clip
+    RETURN s_round(vec, n, clip, FALSE);  -- no round half to even
   END;
-  
-  -- An alternative is to always round up, also for negative numbers (i.e. s_round_up = u_round).
-  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
+
+  FUNCTION s_round(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
   BEGIN
-    RETURN u_round(vec, n, clip);
+    RETURN s_round(vec, n, FALSE);  -- no round clip
   END;
   
-  FUNCTION s_round_up(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
+  -- for unsigned round half away and round half up are equivalent
+  FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip, even : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
+    CONSTANT c_in_w     : NATURAL := vec'LENGTH;
+    CONSTANT c_out_w    : NATURAL := vec'LENGTH - n;
+    VARIABLE in_vec     : STD_LOGIC_VECTOR(c_in_w DOWNTO 0);
+    VARIABLE out_vec    : STD_LOGIC_VECTOR(c_out_w DOWNTO 0);
   BEGIN
-    RETURN u_round(vec, n, FALSE);  -- no round clip
+    -- Convert unsigned to positive signed and back to be able to reuse s_round()
+    in_vec := '0' & vec;
+    out_vec := s_round(in_vec, n, clip, even);
+    RETURN out_vec(c_out_w-1 DOWNTO 0);
   END;
-  
-  -- Unsigned numbers are round up (almost same as s_round, but without the else on negative vec)
-  FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN ) RETURN STD_LOGIC_VECTOR IS
-    -- Use UNSIGNED to avoid NATURAL (32 bit range) overflow error
-    CONSTANT c_in_w  : NATURAL := vec'LENGTH;
-    CONSTANT c_out_w : NATURAL := vec'LENGTH - n;
-    CONSTANT c_one   : UNSIGNED(c_in_w-1 DOWNTO 0) := TO_UNSIGNED(1, c_in_w);
-    CONSTANT c_half  : UNSIGNED(c_in_w-1 DOWNTO 0) := SHIFT_LEFT(c_one, n-1);                        -- = 2**(n-1)
-    CONSTANT c_max   : UNSIGNED(c_in_w-1 DOWNTO 0) := UNSIGNED(c_slv1(c_in_w-1 DOWNTO 0)) - c_half;  -- = 2**c_in_w-1 - c_half  
-    CONSTANT c_clip  : UNSIGNED(c_out_w-1 DOWNTO 0) := UNSIGNED(c_slv1(c_out_w-1 DOWNTO 0));         -- = 2**c_out_w-1
-    VARIABLE v_in    : UNSIGNED(c_in_w-1 DOWNTO 0);
-    VARIABLE v_out   : UNSIGNED(c_out_w-1 DOWNTO 0);
+
+  FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL; clip : BOOLEAN) RETURN STD_LOGIC_VECTOR IS
   BEGIN
-    v_in := UNSIGNED(vec);
-    IF n > 0 THEN
-      IF clip = TRUE AND v_in > c_max THEN
-        v_out := c_clip;                                              -- Round clip to +max to avoid wrap to 0
-      ELSE
-        v_out := RESIZE_NUM(SHIFT_RIGHT(v_in + c_half, n), c_out_w);  -- Round up
-      END IF;
-    ELSE
-      v_out := RESIZE_NUM(v_in, c_out_w);                             -- NOP
-    END IF;
-    RETURN STD_LOGIC_VECTOR(v_out);
+    RETURN u_round(vec, n, clip, FALSE);  -- no round half to even
   END;
 
   FUNCTION u_round(vec : STD_LOGIC_VECTOR; n : NATURAL) RETURN STD_LOGIC_VECTOR IS
diff --git a/libraries/base/common/src/vhdl/common_requantize.vhd b/libraries/base/common/src/vhdl/common_requantize.vhd
index 06f6836d6792ddd01a48feaa9607f51346dcfa22..cd704a27386792c8c272453232a1d58e996f5ce3 100644
--- a/libraries/base/common/src/vhdl/common_requantize.vhd
+++ b/libraries/base/common/src/vhdl/common_requantize.vhd
@@ -57,9 +57,10 @@ ENTITY common_requantize IS
     g_lsb_w               : INTEGER := 4;         -- when > 0, number of LSbits to remove from in_dat
                                                   -- when < 0, number of LSBits to insert as a gain before resize to out_dat'LENGTH
                                                   -- when 0 then no effect
-    g_lsb_round           : BOOLEAN := TRUE;      -- when true ROUND else TRUNCATE the input LSbits
-    g_lsb_round_clip      : BOOLEAN := FALSE;     -- when true round clip to +max to avoid wrapping to output -min (signed) or 0 (unsigned) due to rounding
-    g_msb_clip            : BOOLEAN := TRUE;      -- when true CLIP else WRAP the input MSbits
+    g_lsb_round           : BOOLEAN := TRUE;      -- when TRUE round else truncate the input LSbits
+    g_lsb_round_clip      : BOOLEAN := FALSE;     -- when TRUE round clip to +max to avoid wrapping to output -min (signed) or 0 (unsigned) due to rounding
+    g_lsb_round_even      : BOOLEAN := FALSE;     -- when TRUE round to even, else round away from zero
+    g_msb_clip            : BOOLEAN := TRUE;      -- when TRUE CLIP else WRAP the input MSbits
     g_msb_clip_symmetric  : BOOLEAN := FALSE;     -- when TRUE clip signed symmetric to +c_smax and -c_smax, else to +c_smax and c_smin_symm
                                                   -- for wrapping when g_msb_clip=FALSE the g_msb_clip_symmetric is ignored, so signed wrapping is done asymmetric
     g_gain_w              : NATURAL := 0;         -- do not use, must be 0, use negative g_lsb_w instead
@@ -101,6 +102,7 @@ BEGIN
     g_representation  => g_representation,
     g_round           => g_lsb_round,
     g_round_clip      => g_lsb_round_clip,
+    g_round_even      => g_lsb_round_even,
     g_pipeline_input  => 0,
     g_pipeline_output => g_pipeline_remove_lsb,
     g_in_dat_w        => g_in_dat_w,
diff --git a/libraries/base/common/src/vhdl/common_round.vhd b/libraries/base/common/src/vhdl/common_round.vhd
index 60e57c440b271976ebefd5241621c91c279ea651..65ccff8133905b359036ed56b3a98c50060579c1 100644
--- a/libraries/base/common/src/vhdl/common_round.vhd
+++ b/libraries/base/common/src/vhdl/common_round.vhd
@@ -36,12 +36,14 @@ ENTITY common_round IS
   --
   -- If the input comes from a product and is rounded to the input width then g_round_clip can safely be FALSE, because e.g. for unsigned
   -- 4b*4b=8b->4b the maximum product is 15*15=225 <= 255-8, so wrapping will never occur.
+  -- When g_round = FALSE then truncate (= remove) the LSbits and then g_round_clip and g_round_even are dont care.
   -- 
 
   GENERIC (
     g_representation  : STRING  := "SIGNED";  -- SIGNED (round +-0.5 away from zero to +- infinity) or UNSIGNED rounding (round 0.5 up to + inifinity)
     g_round           : BOOLEAN := TRUE;      -- when TRUE round the input, else truncate the input
     g_round_clip      : BOOLEAN := FALSE;     -- when TRUE clip rounded input >= +max to avoid wrapping to output -min (signed) or 0 (unsigned)
+    g_round_even      : BOOLEAN := FALSE;     -- when TRUE round to even, else round away from zero
     g_pipeline_input  : NATURAL := 0;         -- >= 0
     g_pipeline_output : NATURAL := 1;         -- >= 0, use g_pipeline_input=0 and g_pipeline_output=0 for combinatorial output
     g_in_dat_w        : NATURAL := 36;
@@ -90,10 +92,10 @@ BEGIN
   -- Decrease to out_dat width by c_remove_w number of LSbits
   -- . rounding
   gen_s : IF c_remove_w>0 AND g_round=TRUE AND g_representation="SIGNED" GENERATE
-    res_dat <= s_round(reg_dat, c_remove_w, g_round_clip);
+    res_dat <= s_round(reg_dat, c_remove_w, g_round_clip, g_round_even);
   END GENERATE;
   gen_u : IF c_remove_w>0 AND g_round=TRUE AND g_representation="UNSIGNED" GENERATE
-    res_dat <= u_round(reg_dat, c_remove_w, g_round_clip);
+    res_dat <= u_round(reg_dat, c_remove_w, g_round_clip, g_round_even);
   END GENERATE;
   -- . truncating
   gen_t : IF c_remove_w>0 AND g_round=FALSE GENERATE
diff --git a/libraries/base/common/tb/vhdl/tb_resize.vhd b/libraries/base/common/tb/vhdl/tb_resize.vhd
index cc7a8044e92be04fddd7b4c433025a100b1026d9..d791044e3125e5c4f13239186837d98f4092c43a 100644
--- a/libraries/base/common/tb/vhdl/tb_resize.vhd
+++ b/libraries/base/common/tb/vhdl/tb_resize.vhd
@@ -19,11 +19,7 @@
 --
 -------------------------------------------------------------------------------
 
-LIBRARY IEEE;
-USE IEEE.STD_LOGIC_1164.ALL;
-USE IEEE.NUMERIC_STD.ALL;
-USE work.common_pkg.ALL;
-
+-- Author: E. Kooistra 2009, updated in 2021
 -- Purpose: Test bench for common_resize.vhd and for RESIZE_NUM() from
 --          common_pkg.vhd
 -- Usage:
@@ -37,6 +33,11 @@ USE work.common_pkg.ALL;
 -- . Observe reg_dat with respect to out_sdat, out_sovr for signed
 -- . Observe reg_dat with respect to out_udat, out_uovr for unsigned
 
+LIBRARY IEEE;
+USE IEEE.STD_LOGIC_1164.ALL;
+USE IEEE.NUMERIC_STD.ALL;
+USE work.common_pkg.ALL;
+
 ENTITY tb_resize IS
   GENERIC (
     -- Supported for RESIZE_NUM() and common_resize.vhd
diff --git a/libraries/base/common/tb/vhdl/tb_round.vhd b/libraries/base/common/tb/vhdl/tb_round.vhd
index 65ca3d57e96bb25b01a5303ac3716af10c03591a..68d5cd7b2694a5068fc50849b5d92604575db26d 100644
--- a/libraries/base/common/tb/vhdl/tb_round.vhd
+++ b/libraries/base/common/tb/vhdl/tb_round.vhd
@@ -19,186 +19,613 @@
 --
 -------------------------------------------------------------------------------
 
+-- Author: E. Kooistra 2009, updated in 2021 using common_round_tb.py
+-- Purpose: Test bench for common_round.vhd
+-- Description:
+--   The signal names in this VHDL tb are the same as in the document [1] and
+--   in the Python tb [2].
+--   The verification uses expected results that were obtained and copied
+--   from [2]. The tb_tb_round.vhd tries different settings for w and r.
+--
+-- References:
+-- [1] https://support.astron.nl/confluence/display/L2M/L4+SDPFW+Decision%3A+Number+representation%2C+resizing+and+rounding
+-- [2] common_round_tb.py
+-- Usage:
+-- > as 5
+--   and manually set the signed data output signals to radix decimal
+-- > run -a
+
 LIBRARY IEEE;
 USE IEEE.STD_LOGIC_1164.ALL;
 USE IEEE.NUMERIC_STD.ALL;
 USE work.common_pkg.ALL;
 
--- Purpose: Test bench for common_round.vhd
--- Usage:
--- > do wave_round.do
--- > run 500 ns
--- . Observe reg_dat with respect to out_sdat_no_rc   for signed   round without clipping of rounding overflow
--- . Observe reg_dat with respect to out_sdat_with_rc for signed   round with    clipping of rounding overflow
--- . Observe reg_dat with respect to out_udat for         unsigned round
--- . Observe reg_dat with respect to out_tdat for         truncation
-
 ENTITY tb_round IS
+  GENERIC (
+    g_in_dat_w        : NATURAL := 4;  -- w = g_in_dat_w, in [2]
+    g_out_dat_w       : NATURAL := 1   -- r = g_in_dat_w - g_out_dat_w, in [2]
+  );
 END tb_round;
 
 ARCHITECTURE tb OF tb_round IS
 
   CONSTANT clk_period   : TIME    := 10 ns;
   
-  CONSTANT c_pipeline_input  : NATURAL := 0;
-  CONSTANT c_pipeline_output : NATURAL := 0;
-  CONSTANT c_pipeline        : NATURAL := c_pipeline_input + c_pipeline_output;
-  
-  --CONSTANT c_round_clip   : BOOLEAN := TRUE;
-  CONSTANT c_round_clip   : BOOLEAN := FALSE;
-  CONSTANT c_in_dat_w     : NATURAL := 5;
-  CONSTANT c_out_dat_w    : NATURAL := 3;
-  CONSTANT c_round_w      : NATURAL := c_in_dat_w - c_out_dat_w;
+  CONSTANT c_pipeline_input   : NATURAL := 0;
+  CONSTANT c_pipeline_output  : NATURAL := 0;
+  CONSTANT c_pipeline         : NATURAL := c_pipeline_input + c_pipeline_output;
   
-  SIGNAL in_val           : STD_LOGIC;
-  SIGNAL in_dat           : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
-  SIGNAL in_vec           : STD_LOGIC_VECTOR(c_in_dat_w   DOWNTO 0);
-  SIGNAL reg_vec          : STD_LOGIC_VECTOR(c_in_dat_w   DOWNTO 0);
-  SIGNAL reg_val          : STD_LOGIC;
-  SIGNAL reg_dat          : STD_LOGIC_VECTOR(c_in_dat_w-1 DOWNTO 0);
+  CONSTANT c_round_w          : INTEGER := g_in_dat_w - g_out_dat_w;
   
-  SIGNAL out_sdat_no_rc   : STD_LOGIC_VECTOR(c_out_dat_w-1 DOWNTO 0);
-  SIGNAL out_sdat_with_rc : STD_LOGIC_VECTOR(c_out_dat_w-1 DOWNTO 0);
-  SIGNAL out_udat         : STD_LOGIC_VECTOR(c_out_dat_w-1 DOWNTO 0);
-  SIGNAL out_tdat         : STD_LOGIC_VECTOR(c_out_dat_w-1 DOWNTO 0);  -- truncate
-  
-  SIGNAL tb_end           : STD_LOGIC := '0';
-  SIGNAL clk              : STD_LOGIC := '1';
-  SIGNAL rst              : STD_LOGIC := '1';
+  -- Expected rounded results from [2] for w = g_in_dat_w = 4 and r = c_round_w = 1
+  CONSTANT c_exp_w4_r1_sreal_fixed_point             : t_real_arr(0 TO 15)    := (-4.0, -3.5, -3.0, -2.5, -2.0, -1.5, -1.0, -0.5, 0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5);
+  CONSTANT c_exp_w4_r1_signed_truncate               : t_integer_arr(0 TO 15) := (-4,   -4,   -3,   -3,   -2,   -2,   -1,   -1,   0,   0,   1,   1,   2,   2,   3,   3);
+  CONSTANT c_exp_w4_r1_signed_round_half_away        : t_integer_arr(0 TO 15) := (-4,   -4,   -3,   -3,   -2,   -2,   -1,   -1,   0,   1,   1,   2,   2,   3,   3,  -4);
+  CONSTANT c_exp_w4_r1_signed_round_half_away_clip   : t_integer_arr(0 TO 15) := (-4,   -4,   -3,   -3,   -2,   -2,   -1,   -1,   0,   1,   1,   2,   2,   3,   3,   3);
+  CONSTANT c_exp_w4_r1_signed_round_half_even        : t_integer_arr(0 TO 15) := (-4,   -4,   -3,   -2,   -2,   -2,   -1,    0,   0,   0,   1,   2,   2,   2,   3,  -4);
+  CONSTANT c_exp_w4_r1_signed_round_half_even_clip   : t_integer_arr(0 TO 15) := (-4,   -4,   -3,   -2,   -2,   -2,   -1,    0,   0,   0,   1,   2,   2,   2,   3,   3);
+
+  CONSTANT c_exp_w4_r1_unsigned_fixed_point          : t_real_arr(0 TO 15)    := (0.0, 0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0, 5.5, 6.0, 6.5, 7.0, 7.5);
+  CONSTANT c_exp_w4_r1_unsigned_truncate             : t_natural_arr(0 TO 15) := (0,   0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7);
+  CONSTANT c_exp_w4_r1_unsigned_round_half_up        : t_natural_arr(0 TO 15) := (0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   0);
+  CONSTANT c_exp_w4_r1_unsigned_round_half_up_clip   : t_natural_arr(0 TO 15) := (0,   1,   1,   2,   2,   3,   3,   4,   4,   5,   5,   6,   6,   7,   7,   7);
+  CONSTANT c_exp_w4_r1_unsigned_round_half_even      : t_natural_arr(0 TO 15) := (0,   0,   1,   2,   2,   2,   3,   4,   4,   4,   5,   6,   6,   6,   7,   0);
+  CONSTANT c_exp_w4_r1_unsigned_round_half_even_clip : t_natural_arr(0 TO 15) := (0,   0,   1,   2,   2,   2,   3,   4,   4,   4,   5,   6,   6,   6,   7,   7);
+
+  -- Expected rounded results from [2] for w = g_in_dat_w = 4 and r = c_round_w = 2
+  CONSTANT c_exp_w4_r2_sreal_fixed_point           : t_real_arr(0 TO 15)    := (-2.0, -1.75, -1.5, -1.25, -1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75);
+  CONSTANT c_exp_w4_r2_signed_truncate             : t_integer_arr(0 TO 15) := (-2,   -2,    -2,   -2,    -1,   -1,    -1,   -1,    0,   0,    0,   0,    1,   1,    1,   1);
+  CONSTANT c_exp_w4_r2_signed_round_half_away      : t_integer_arr(0 TO 15) := (-2,   -2,    -2,   -1,    -1,   -1,    -1,    0,    0,   0,    1,   1,    1,   1,   -2,  -2);
+  CONSTANT c_exp_w4_r2_signed_round_half_away_clip : t_integer_arr(0 TO 15) := (-2,   -2,    -2,   -1,    -1,   -1,    -1,    0,    0,   0,    1,   1,    1,   1,    1,   1);
+  CONSTANT c_exp_w4_r2_signed_round_half_even      : t_integer_arr(0 TO 15) := (-2,   -2,    -2,   -1,    -1,   -1,     0,    0,    0,   0,    0,   1,    1,   1,   -2,  -2);
+  CONSTANT c_exp_w4_r2_signed_round_half_even_clip : t_integer_arr(0 TO 15) := (-2,   -2,    -2,   -1,    -1,   -1,     0,    0,    0,   0,    0,   1,    1,   1,    1,   1);
+
+  CONSTANT c_exp_w4_r2_unsigned_fixed_point          : t_real_arr(0 TO 15)    := (0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75);
+  CONSTANT c_exp_w4_r2_unsigned_truncate             : t_natural_arr(0 TO 15) := (0,   0,    0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3);
+  CONSTANT c_exp_w4_r2_unsigned_round_half_up        : t_natural_arr(0 TO 15) := (0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3,    0,   0);
+  CONSTANT c_exp_w4_r2_unsigned_round_half_up_clip   : t_natural_arr(0 TO 15) := (0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3,    3,   3);
+  CONSTANT c_exp_w4_r2_unsigned_round_half_even      : t_natural_arr(0 TO 15) := (0,   0,    0,   1,    1,   1,    2,   2,    2,   2,    2,   3,    3,   3,    0,   0);
+  CONSTANT c_exp_w4_r2_unsigned_round_half_even_clip : t_natural_arr(0 TO 15) := (0,   0,    0,   1,    1,   1,    2,   2,    2,   2,    2,   3,    3,   3,    3,   3);
+
+  -- Expected rounded results from [2] for w = g_in_dat_w = 4 and r = c_round_w = 3
+  CONSTANT c_exp_w4_r3_sreal_fixed_point           : t_real_arr(0 TO 15)    := (-1.0, -0.875, -0.75, -0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875);
+  CONSTANT c_exp_w4_r3_signed_truncate             : t_integer_arr(0 TO 15) := (-1,   -1,     -1,    -1,     -1,   -1,     -1,    -1,     0,   0,     0,    0,     0,   0,     0,    0);
+  CONSTANT c_exp_w4_r3_signed_round_half_away      : t_integer_arr(0 TO 15) := (-1,   -1,     -1,    -1,     -1,    0,      0,     0,     0,   0,     0,    0,    -1,  -1,    -1,   -1);
+  CONSTANT c_exp_w4_r3_signed_round_half_away_clip : t_integer_arr(0 TO 15) := (-1,   -1,     -1,    -1,     -1,    0,      0,     0,     0,   0,     0,    0,     0,   0,     0,    0);
+  CONSTANT c_exp_w4_r3_signed_round_half_even      : t_integer_arr(0 TO 15) := (-1,   -1,     -1,    -1,      0,    0,      0,     0,     0,   0,     0,    0,     0,  -1,    -1,   -1);
+  CONSTANT c_exp_w4_r3_signed_round_half_even_clip : t_integer_arr(0 TO 15) := (-1,   -1,     -1,    -1,      0,    0,      0,     0,     0,   0,     0,    0,     0,   0,     0,    0);
+
+  CONSTANT c_exp_w4_r3_unsigned_fixed_point          : t_real_arr(0 TO 15)    := (0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875);
+  CONSTANT c_exp_w4_r3_unsigned_truncate             : t_natural_arr(0 TO 15) := (0,   0,     0,    0,     0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1);
+  CONSTANT c_exp_w4_r3_unsigned_round_half_up        : t_natural_arr(0 TO 15) := (0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1,     0,   0,     0,    0);
+  CONSTANT c_exp_w4_r3_unsigned_round_half_up_clip   : t_natural_arr(0 TO 15) := (0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1,     1,   1,     1,    1);
+  CONSTANT c_exp_w4_r3_unsigned_round_half_even      : t_natural_arr(0 TO 15) := (0,   0,     0,    0,     0,   1,     1,    1,     1,   1,     1,    1,     0,   0,     0,    0);
+  CONSTANT c_exp_w4_r3_unsigned_round_half_even_clip : t_natural_arr(0 TO 15) := (0,   0,     0,    0,     0,   1,     1,    1,     1,   1,     1,    1,     1,   1,     1,    1);
+
+  -- Expected rounded results from [2] for w = g_in_dat_w = 5 and r = c_round_w = 2
+  CONSTANT c_exp_w5_r2_sreal_fixed_point             : t_real_arr(0 TO 31)    := (-4.0, -3.75, -3.5, -3.25, -3.0, -2.75, -2.5, -2.25, -2.0, -1.75, -1.5, -1.25, -1.0, -0.75, -0.5, -0.25, 0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75);
+  CONSTANT c_exp_w5_r2_signed_truncate               : t_integer_arr(0 TO 31) := (-4,   -4,    -4,   -4,    -3,   -3,    -3,   -3,    -2,   -2,    -2,   -2,    -1,   -1,    -1,   -1,    0,   0,    0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3);
+  CONSTANT c_exp_w5_r2_signed_round_half_away        : t_integer_arr(0 TO 31) := (-4,   -4,    -4,   -3,    -3,   -3,    -3,   -2,    -2,   -2,    -2,   -1,    -1,   -1,    -1,    0,    0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3,   -4,  -4);
+  CONSTANT c_exp_w5_r2_signed_round_half_away_clip   : t_integer_arr(0 TO 31) := (-4,   -4,    -4,   -3,    -3,   -3,    -3,   -2,    -2,   -2,    -2,   -1,    -1,   -1,    -1,    0,    0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3,    3,   3);
+  CONSTANT c_exp_w5_r2_signed_round_half_even        : t_integer_arr(0 TO 31) := (-4,   -4,    -4,   -3,    -3,   -3,    -2,   -2,    -2,   -2,    -2,   -1,    -1,   -1,     0,    0,    0,   0,    0,   1,    1,   1,    2,   2,    2,   2,    2,   3,    3,   3,   -4,  -4);
+  CONSTANT c_exp_w5_r2_signed_round_half_even_clip   : t_integer_arr(0 TO 31) := (-4,   -4,    -4,   -3,    -3,   -3,    -2,   -2,    -2,   -2,    -2,   -1,    -1,   -1,     0,    0,    0,   0,    0,   1,    1,   1,    2,   2,    2,   2,    2,   3,    3,   3,    3,   3);
+
+  CONSTANT c_exp_w5_r2_unsigned_fixed_point          : t_real_arr(0 TO 31)    := (0.0, 0.25, 0.5, 0.75, 1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0, 3.25, 3.5, 3.75, 4.0, 4.25, 4.5, 4.75, 5.0, 5.25, 5.5, 5.75, 6.0, 6.25, 6.5, 6.75, 7.0, 7.25, 7.5, 7.75);
+  CONSTANT c_exp_w5_r2_unsigned_truncate             : t_natural_arr(0 TO 31) := (0,   0,    0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3,    4,   4,    4,   4,    5,   5,    5,   5,    6,   6,    6,   6,    7,   7,    7,   7);
+  CONSTANT c_exp_w5_r2_unsigned_round_half_up        : t_natural_arr(0 TO 31) := (0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3,    4,   4,    4,   4,    5,   5,    5,   5,    6,   6,    6,   6,    7,   7,    7,   7,    0,   0);
+  CONSTANT c_exp_w5_r2_unsigned_round_half_up_clip   : t_natural_arr(0 TO 31) := (0,   0,    1,   1,    1,   1,    2,   2,    2,   2,    3,   3,    3,   3,    4,   4,    4,   4,    5,   5,    5,   5,    6,   6,    6,   6,    7,   7,    7,   7,    7,   7);
+  CONSTANT c_exp_w5_r2_unsigned_round_half_even      : t_natural_arr(0 TO 31) := (0,   0,    0,   1,    1,   1,    2,   2,    2,   2,    2,   3,    3,   3,    4,   4,    4,   4,    4,   5,    5,   5,    6,   6,    6,   6,    6,   7,    7,   7,    0,   0);
+  CONSTANT c_exp_w5_r2_unsigned_round_half_even_clip : t_natural_arr(0 TO 31) := (0,   0,    0,   1,    1,   1,    2,   2,    2,   2,    2,   3,    3,   3,    4,   4,    4,   4,    4,   5,    5,   5,    6,   6,    6,   6,    6,   7,    7,   7,    7,   7);
+
+  -- Expected rounded results from [2] for w = g_in_dat_w = 5 and r = c_round_w = 3
+  CONSTANT c_exp_w5_r3_sreal_fixed_point           : t_real_arr(0 TO 31)    := (-2.0, -1.875, -1.75, -1.625, -1.5, -1.375, -1.25, -1.125, -1.0, -0.875, -0.75, -0.625, -0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875);
+  CONSTANT c_exp_w5_r3_signed_truncate             : t_integer_arr(0 TO 31) := (-2,   -2,     -2,    -2,     -2,   -2,     -2,    -2,     -1,   -1,     -1,    -1,     -1,   -1,     -1,    -1,     0,   0,     0,    0,     0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1);
+  CONSTANT c_exp_w5_r3_signed_round_half_away      : t_integer_arr(0 TO 31) := (-2,   -2,     -2,    -2,     -2,   -1,     -1,    -1,     -1,   -1,     -1,    -1,     -1,    0,      0,     0,     0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1,    -2,  -2,    -2,   -2);
+  CONSTANT c_exp_w5_r3_signed_round_half_away_clip : t_integer_arr(0 TO 31) := (-2,   -2,     -2,    -2,     -2,   -1,     -1,    -1,     -1,   -1,     -1,    -1,     -1,    0,      0,     0,     0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1,     1,   1,     1,    1);
+  CONSTANT c_exp_w5_r3_signed_round_half_even      : t_integer_arr(0 TO 31) := (-2,   -2,     -2,    -2,     -2,   -1,     -1,    -1,     -1,   -1,     -1,    -1,      0,    0,      0,     0,     0,   0,     0,    0,     0,   1,     1,    1,     1,   1,     1,    1,    -2,  -2,    -2,   -2);
+  CONSTANT c_exp_w5_r3_signed_round_half_even_clip : t_integer_arr(0 TO 31) := (-2,   -2,     -2,    -2,     -2,   -1,     -1,    -1,     -1,   -1,     -1,    -1,      0,    0,      0,     0,     0,   0,     0,    0,     0,   1,     1,    1,     1,   1,     1,    1,     1,   1,     1,    1);
+
+  CONSTANT c_exp_w5_r3_unsigned_fixed_point          : t_real_arr(0 TO 31)    := (0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0, 1.125, 1.25, 1.375, 1.5, 1.625, 1.75, 1.875, 2.0, 2.125, 2.25, 2.375, 2.5, 2.625, 2.75, 2.875, 3.0, 3.125, 3.25, 3.375, 3.5, 3.625, 3.75, 3.875);
+  CONSTANT c_exp_w5_r3_unsigned_truncate             : t_natural_arr(0 TO 31) := (0,   0,     0,    0,     0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1,     2,   2,     2,    2,     2,   2,     2,    2,     3,   3,     3,    3,     3,   3,     3,    3);
+  CONSTANT c_exp_w5_r3_unsigned_round_half_up        : t_natural_arr(0 TO 31) := (0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1,     2,   2,     2,    2,     2,   2,     2,    2,     3,   3,     3,    3,     3,   3,     3,    3,     0,   0,     0,    0);
+  CONSTANT c_exp_w5_r3_unsigned_round_half_up_clip   : t_natural_arr(0 TO 31) := (0,   0,     0,    0,     1,   1,     1,    1,     1,   1,     1,    1,     2,   2,     2,    2,     2,   2,     2,    2,     3,   3,     3,    3,     3,   3,     3,    3,     3,   3,     3,    3);
+  CONSTANT c_exp_w5_r3_unsigned_round_half_even      : t_natural_arr(0 TO 31) := (0,   0,     0,    0,     0,   1,     1,    1,     1,   1,     1,    1,     2,   2,     2,    2,     2,   2,     2,    2,     2,   3,     3,    3,     3,   3,     3,    3,     0,   0,     0,    0);
+  CONSTANT c_exp_w5_r3_unsigned_round_half_even_clip : t_natural_arr(0 TO 31) := (0,   0,     0,    0,     0,   1,     1,    1,     1,   1,     1,    1,     2,   2,     2,    2,     2,   2,     2,    2,     2,   3,     3,    3,     3,   3,     3,    3,     3,   3,     3,    3);
+
+  SIGNAL tb_end               : STD_LOGIC := '0';
+  SIGNAL clk                  : STD_LOGIC := '1';
+
+  -- Input data
+  SIGNAL in_val               : STD_LOGIC;
+  SIGNAL in_dat               : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+  SIGNAL reg_val              : STD_LOGIC;
+  SIGNAL reg_dat              : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+
+  -- Signed output data
+  -- . view as radix decimal in Wave window
+  SIGNAL fs_signed_integer                : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+  SIGNAL fs_signed_truncate               : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_signed_round_half_away        : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_signed_round_half_away_clip   : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_signed_round_half_even        : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_signed_round_half_even_clip   : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+
+  SIGNAL S_w4                                    : NATURAL;  -- lookup index for signed
+  SIGNAL exp_w4_r1_signed_truncate               : INTEGER;
+  SIGNAL exp_w4_r1_signed_round_half_away        : INTEGER;
+  SIGNAL exp_w4_r1_signed_round_half_away_clip   : INTEGER;
+  SIGNAL exp_w4_r1_signed_round_half_even        : INTEGER;
+  SIGNAL exp_w4_r1_signed_round_half_even_clip   : INTEGER;
+
+  SIGNAL exp_w4_r2_signed_truncate               : INTEGER;
+  SIGNAL exp_w4_r2_signed_round_half_away        : INTEGER;
+  SIGNAL exp_w4_r2_signed_round_half_away_clip   : INTEGER;
+  SIGNAL exp_w4_r2_signed_round_half_even        : INTEGER;
+  SIGNAL exp_w4_r2_signed_round_half_even_clip   : INTEGER;
+
+  SIGNAL exp_w4_r3_signed_truncate               : INTEGER;
+  SIGNAL exp_w4_r3_signed_round_half_away        : INTEGER;
+  SIGNAL exp_w4_r3_signed_round_half_away_clip   : INTEGER;
+  SIGNAL exp_w4_r3_signed_round_half_even        : INTEGER;
+  SIGNAL exp_w4_r3_signed_round_half_even_clip   : INTEGER;
+
+  SIGNAL S_w5                                    : NATURAL;  -- lookup index for signed
+  SIGNAL exp_w5_r2_signed_truncate               : INTEGER;
+  SIGNAL exp_w5_r2_signed_round_half_away        : INTEGER;
+  SIGNAL exp_w5_r2_signed_round_half_away_clip   : INTEGER;
+  SIGNAL exp_w5_r2_signed_round_half_even        : INTEGER;
+  SIGNAL exp_w5_r2_signed_round_half_even_clip   : INTEGER;
+
+  SIGNAL exp_w5_r3_signed_truncate               : INTEGER;
+  SIGNAL exp_w5_r3_signed_round_half_away        : INTEGER;
+  SIGNAL exp_w5_r3_signed_round_half_away_clip   : INTEGER;
+  SIGNAL exp_w5_r3_signed_round_half_even        : INTEGER;
+  SIGNAL exp_w5_r3_signed_round_half_even_clip   : INTEGER;
+
+  -- . show as real in Wave window
+  SIGNAL fs_sreal_fixed_point             : REAL := 0.0;
+  SIGNAL fs_sreal_truncate                : REAL := 0.0;
+  SIGNAL fs_sreal_round_half_away         : REAL := 0.0;
+  SIGNAL fs_sreal_round_half_away_clip    : REAL := 0.0;
+  SIGNAL fs_sreal_round_half_even         : REAL := 0.0;
+  SIGNAL fs_sreal_round_half_even_clip    : REAL := 0.0;
+
+  -- Unsigned output data
+  -- . view as radix unsigned in Wave window
+  SIGNAL fs_unsigned_integer              : STD_LOGIC_VECTOR(g_in_dat_w-1 DOWNTO 0);
+  SIGNAL fs_unsigned_truncate             : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_unsigned_round_half_up        : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_unsigned_round_half_up_clip   : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_unsigned_round_half_even      : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+  SIGNAL fs_unsigned_round_half_even_clip : STD_LOGIC_VECTOR(g_out_dat_w-1 DOWNTO 0);
+
+  SIGNAL U_w4                                    : NATURAL;  -- lookup index for unsigned
+  SIGNAL exp_w4_r1_unsigned_truncate             : INTEGER;
+  SIGNAL exp_w4_r1_unsigned_round_half_up        : INTEGER;
+  SIGNAL exp_w4_r1_unsigned_round_half_up_clip   : INTEGER;
+  SIGNAL exp_w4_r1_unsigned_round_half_even      : INTEGER;
+  SIGNAL exp_w4_r1_unsigned_round_half_even_clip : INTEGER;
+
+  SIGNAL exp_w4_r2_unsigned_truncate             : INTEGER;
+  SIGNAL exp_w4_r2_unsigned_round_half_up        : INTEGER;
+  SIGNAL exp_w4_r2_unsigned_round_half_up_clip   : INTEGER;
+  SIGNAL exp_w4_r2_unsigned_round_half_even      : INTEGER;
+  SIGNAL exp_w4_r2_unsigned_round_half_even_clip : INTEGER;
+
+  SIGNAL exp_w4_r3_unsigned_truncate             : INTEGER;
+  SIGNAL exp_w4_r3_unsigned_round_half_up        : INTEGER;
+  SIGNAL exp_w4_r3_unsigned_round_half_up_clip   : INTEGER;
+  SIGNAL exp_w4_r3_unsigned_round_half_even      : INTEGER;
+  SIGNAL exp_w4_r3_unsigned_round_half_even_clip : INTEGER;
+
+  SIGNAL U_w5                                    : NATURAL;  -- lookup index for unsigned
+  SIGNAL exp_w5_r2_unsigned_truncate             : INTEGER;
+  SIGNAL exp_w5_r2_unsigned_round_half_up        : INTEGER;
+  SIGNAL exp_w5_r2_unsigned_round_half_up_clip   : INTEGER;
+  SIGNAL exp_w5_r2_unsigned_round_half_even      : INTEGER;
+  SIGNAL exp_w5_r2_unsigned_round_half_even_clip : INTEGER;
+
+  SIGNAL exp_w5_r3_unsigned_truncate             : INTEGER;
+  SIGNAL exp_w5_r3_unsigned_round_half_up        : INTEGER;
+  SIGNAL exp_w5_r3_unsigned_round_half_up_clip   : INTEGER;
+  SIGNAL exp_w5_r3_unsigned_round_half_even      : INTEGER;
+  SIGNAL exp_w5_r3_unsigned_round_half_even_clip : INTEGER;
+
+  -- . show as real in Wave window
+  SIGNAL fs_ureal_fixed_point             : REAL := 0.0;
+  SIGNAL fs_ureal_truncate                : REAL := 0.0;
+  SIGNAL fs_ureal_round_half_up           : REAL := 0.0;
+  SIGNAL fs_ureal_round_half_up_clip      : REAL := 0.0;
+  SIGNAL fs_ureal_round_half_even         : REAL := 0.0;
+  SIGNAL fs_ureal_round_half_even_clip    : REAL := 0.0;
 
-  CONSTANT c_init         : STD_LOGIC_VECTOR(in_dat'RANGE) := (OTHERS=>'0');
-  
 BEGIN
 
   -- Stimuli
   clk <= NOT clk OR tb_end AFTER clk_period/2;
-  rst <= '1', '0' AFTER 3*clk_period;
   
-  -- Testbench end
-  p_tb_end : PROCESS
-    VARIABLE v_dat : STD_LOGIC_VECTOR(in_dat'RANGE);
+  p_stimuli : PROCESS
   BEGIN
-    tb_end <= '0';
-    WAIT UNTIL in_val='1';
-    WAIT UNTIL rising_edge(clk);
-    v_dat := in_dat;              -- keep first in_dat 
-    WAIT UNTIL rising_edge(clk);
-    WAIT UNTIL v_dat=in_dat;      -- wait until all incrementing in_dat values have been applied at least once
-    WAIT UNTIL rising_edge(clk);
-    WAIT UNTIL rising_edge(clk);
+    in_val <= '0';
+    in_dat <= (OTHERS=>'0');
+    FOR I IN 0 TO 3 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
+    in_val <= '1';
     WAIT UNTIL rising_edge(clk);
+    FOR I IN 0 TO 2**g_in_dat_w - 1 LOOP
+      in_dat <= INCR_UVEC(in_dat, 1);
+      WAIT UNTIL rising_edge(clk);
+    END LOOP;
+    in_val <= '0';
+    in_dat <= (OTHERS=>'0');
+    FOR I IN 0 TO 3 LOOP WAIT UNTIL rising_edge(clk); END LOOP;
     tb_end <= '1';
     WAIT;
   END PROCESS;
+
+  -- Delay input as much as DUT output, assume c_pipeline = 0
+  reg_val <= in_val;
+  reg_dat <= in_dat;
   
-  p_clk : PROCESS (rst, clk)
-  BEGIN
-    IF rst='1' THEN
-      in_val      <= '0';
-      in_dat      <= c_init;
-    ELSIF rising_edge(clk) THEN
-      in_val      <= '1';
-      in_dat      <= STD_LOGIC_VECTOR(SIGNED(in_dat)+1);
-    END IF;
-  END PROCESS;
-  
-  -- Delay input as much as DUT output
-  in_vec <= in_val & in_dat;
-  
-  u_pipe : ENTITY work.common_pipeline
+  fs_signed_integer <= reg_dat;
+  fs_unsigned_integer <= reg_dat;
+
+  -----------------------------------------------------------------------------
+  -- SIGNED DUTs
+  -----------------------------------------------------------------------------
+
+  s_truncate : ENTITY work.common_round
   GENERIC MAP (
-    g_representation => "SIGNED",
-    g_pipeline       => c_pipeline,
-    g_in_dat_w       => c_in_dat_w+1,
-    g_out_dat_w      => c_in_dat_w+1
+    g_representation  => "SIGNED",
+    g_round           => FALSE,
+    g_round_clip      => FALSE,
+    g_pipeline_input  => c_pipeline_input,
+    g_pipeline_output => c_pipeline_output,
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
   )
   PORT MAP (
-    clk     => clk,
-    in_dat  => in_vec,
-    out_dat => reg_vec
+    clk            => clk,
+    in_dat         => in_dat,
+    out_dat        => fs_signed_truncate
   );
-  
-  reg_val <= reg_vec(c_in_dat_w);
-  reg_dat <= reg_vec(c_in_dat_w-1 DOWNTO 0);
-  
-  -- DUT for "SIGNED" round without clipping of rounding overflow
-  u_s_round : ENTITY work.common_round
+
+  s_round_half_away : ENTITY work.common_round
   GENERIC MAP (
     g_representation  => "SIGNED",
     g_round           => TRUE,
     g_round_clip      => FALSE,
     g_pipeline_input  => c_pipeline_input,
     g_pipeline_output => c_pipeline_output,
-    g_in_dat_w        => c_in_dat_w,
-    g_out_dat_w       => c_out_dat_w
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
   )
   PORT MAP (
     clk            => clk,
-    clken          => '1',
     in_dat         => in_dat,
-    out_dat        => out_sdat_no_rc
+    out_dat        => fs_signed_round_half_away
   );
 
-  -- DUT for "SIGNED" round with clipping of rounding overflow
-  u_s_round_rc : ENTITY work.common_round
+  s_round_half_away_clip : ENTITY work.common_round
   GENERIC MAP (
     g_representation  => "SIGNED",
     g_round           => TRUE,
     g_round_clip      => TRUE,
     g_pipeline_input  => c_pipeline_input,
     g_pipeline_output => c_pipeline_output,
-    g_in_dat_w        => c_in_dat_w,
-    g_out_dat_w       => c_out_dat_w
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
   )
   PORT MAP (
     clk            => clk,
-    clken          => '1',
     in_dat         => in_dat,
-    out_dat        => out_sdat_with_rc
+    out_dat        => fs_signed_round_half_away_clip
   );
   
-  -- DUT for "UNSIGNED" round
-  u_u_round : ENTITY work.common_round
+  s_round_half_even : ENTITY work.common_round
   GENERIC MAP (
-    g_representation  => "UNSIGNED",
+    g_representation  => "SIGNED",
     g_round           => TRUE,
-    g_round_clip      => c_round_clip,
+    g_round_clip      => FALSE,
+    g_round_even      => TRUE,
     g_pipeline_input  => c_pipeline_input,
     g_pipeline_output => c_pipeline_output,
-    g_in_dat_w        => c_in_dat_w,
-    g_out_dat_w       => c_out_dat_w
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
   )
   PORT MAP (
     clk            => clk,
-    clken          => '1',
     in_dat         => in_dat,
-    out_dat        => out_udat
+    out_dat        => fs_signed_round_half_even
   );
-  
+
+  s_round_half_even_clip : ENTITY work.common_round
+  GENERIC MAP (
+    g_representation  => "SIGNED",
+    g_round           => TRUE,
+    g_round_clip      => TRUE,
+    g_round_even      => TRUE,
+    g_pipeline_input  => c_pipeline_input,
+    g_pipeline_output => c_pipeline_output,
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
+  )
+  PORT MAP (
+    clk            => clk,
+    in_dat         => in_dat,
+    out_dat        => fs_signed_round_half_even_clip
+  );
+
+
+  -----------------------------------------------------------------------------
+  -- UNSIGNED DUTs
+  -----------------------------------------------------------------------------
+
   -- DUT for truncate
   u_truncate : ENTITY work.common_round
   GENERIC MAP (
     g_representation  => "UNSIGNED",
     g_round           => FALSE,
-    g_round_clip      => c_round_clip,
+    g_round_clip      => FALSE,
     g_pipeline_input  => c_pipeline_input,
     g_pipeline_output => c_pipeline_output,
-    g_in_dat_w        => c_in_dat_w,
-    g_out_dat_w       => c_out_dat_w
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
   )
   PORT MAP (
     clk            => clk,
-    clken          => '1',
     in_dat         => in_dat,
-    out_dat        => out_tdat
+    out_dat        => fs_unsigned_truncate
+  );
+
+  u_round_half_up : ENTITY work.common_round
+  GENERIC MAP (
+    g_representation  => "UNSIGNED",
+    g_round           => TRUE,
+    g_round_clip      => FALSE,
+    g_pipeline_input  => c_pipeline_input,
+    g_pipeline_output => c_pipeline_output,
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
+  )
+  PORT MAP (
+    clk            => clk,
+    in_dat         => in_dat,
+    out_dat        => fs_unsigned_round_half_up
   );
   
-  
+  u_round_half_up_clip : ENTITY work.common_round
+  GENERIC MAP (
+    g_representation  => "UNSIGNED",
+    g_round           => TRUE,
+    g_round_clip      => TRUE,
+    g_pipeline_input  => c_pipeline_input,
+    g_pipeline_output => c_pipeline_output,
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
+  )
+  PORT MAP (
+    clk            => clk,
+    in_dat         => in_dat,
+    out_dat        => fs_unsigned_round_half_up_clip
+  );
+
+  u_round_half_even : ENTITY work.common_round
+  GENERIC MAP (
+    g_representation  => "UNSIGNED",
+    g_round           => TRUE,
+    g_round_clip      => FALSE,
+    g_round_even      => TRUE,
+    g_pipeline_input  => c_pipeline_input,
+    g_pipeline_output => c_pipeline_output,
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
+  )
+  PORT MAP (
+    clk            => clk,
+    in_dat         => in_dat,
+    out_dat        => fs_unsigned_round_half_even
+  );
+
+  u_round_half_even_clip : ENTITY work.common_round
+  GENERIC MAP (
+    g_representation  => "UNSIGNED",
+    g_round           => TRUE,
+    g_round_clip      => TRUE,
+    g_round_even      => TRUE,
+    g_pipeline_input  => c_pipeline_input,
+    g_pipeline_output => c_pipeline_output,
+    g_in_dat_w        => g_in_dat_w,
+    g_out_dat_w       => g_out_dat_w
+  )
+  PORT MAP (
+    clk            => clk,
+    in_dat         => in_dat,
+    out_dat        => fs_unsigned_round_half_even_clip
+  );
+
+  -- Observe fixed point SLV values as REAL
+  -- . signed
+  fs_sreal_fixed_point          <= TO_SREAL(fs_signed_integer, c_round_w);
+  fs_sreal_truncate             <= TO_SREAL(fs_signed_truncate, 0);
+  fs_sreal_round_half_away      <= TO_SREAL(fs_signed_round_half_away, 0);
+  fs_sreal_round_half_away_clip <= TO_SREAL(fs_signed_round_half_away_clip, 0);
+  fs_sreal_round_half_even      <= TO_SREAL(fs_signed_round_half_even, 0);
+  fs_sreal_round_half_even_clip <= TO_SREAL(fs_signed_round_half_even_clip, 0);
+
+  -- . unsigned
+  fs_ureal_fixed_point          <= TO_UREAL(fs_unsigned_integer, c_round_w);
+  fs_ureal_truncate             <= TO_UREAL(fs_unsigned_truncate, 0);
+  fs_ureal_round_half_up        <= TO_UREAL(fs_unsigned_round_half_up, 0);
+  fs_ureal_round_half_up_clip   <= TO_UREAL(fs_unsigned_round_half_up_clip, 0);
+  fs_ureal_round_half_even      <= TO_UREAL(fs_unsigned_round_half_even, 0);
+  fs_ureal_round_half_even_clip <= TO_UREAL(fs_unsigned_round_half_even_clip, 0);
+
+  -- Expected rounded values
+  -- . w = 4
+  S_w4 <= (TO_UINT(in_dat) + 8) MOD 16;  -- 2**4 = 16
+  U_w4 <= TO_UINT(in_dat) MOD 16;
+
+  -- . w = 4, r = 1
+  exp_w4_r1_signed_truncate             <= c_exp_w4_r1_signed_truncate(S_w4);
+  exp_w4_r1_signed_round_half_away      <= c_exp_w4_r1_signed_round_half_away(S_w4);
+  exp_w4_r1_signed_round_half_away_clip <= c_exp_w4_r1_signed_round_half_away_clip(S_w4);
+  exp_w4_r1_signed_round_half_even      <= c_exp_w4_r1_signed_round_half_even(S_w4);
+  exp_w4_r1_signed_round_half_even_clip <= c_exp_w4_r1_signed_round_half_even_clip(S_w4);
+
+  exp_w4_r1_unsigned_truncate             <= c_exp_w4_r1_unsigned_truncate(U_w4);
+  exp_w4_r1_unsigned_round_half_up        <= c_exp_w4_r1_unsigned_round_half_up(U_w4);
+  exp_w4_r1_unsigned_round_half_up_clip   <= c_exp_w4_r1_unsigned_round_half_up_clip(U_w4);
+  exp_w4_r1_unsigned_round_half_even      <= c_exp_w4_r1_unsigned_round_half_even(U_w4);
+  exp_w4_r1_unsigned_round_half_even_clip <= c_exp_w4_r1_unsigned_round_half_even_clip(U_w4);
+
+  -- . w = 4, r = 2
+  exp_w4_r2_signed_truncate             <= c_exp_w4_r2_signed_truncate(S_w4);
+  exp_w4_r2_signed_round_half_away      <= c_exp_w4_r2_signed_round_half_away(S_w4);
+  exp_w4_r2_signed_round_half_away_clip <= c_exp_w4_r2_signed_round_half_away_clip(S_w4);
+  exp_w4_r2_signed_round_half_even      <= c_exp_w4_r2_signed_round_half_even(S_w4);
+  exp_w4_r2_signed_round_half_even_clip <= c_exp_w4_r2_signed_round_half_even_clip(S_w4);
+
+  exp_w4_r2_unsigned_truncate             <= c_exp_w4_r2_unsigned_truncate(U_w4);
+  exp_w4_r2_unsigned_round_half_up        <= c_exp_w4_r2_unsigned_round_half_up(U_w4);
+  exp_w4_r2_unsigned_round_half_up_clip   <= c_exp_w4_r2_unsigned_round_half_up_clip(U_w4);
+  exp_w4_r2_unsigned_round_half_even      <= c_exp_w4_r2_unsigned_round_half_even(U_w4);
+  exp_w4_r2_unsigned_round_half_even_clip <= c_exp_w4_r2_unsigned_round_half_even_clip(U_w4);
+
+  -- . w = 4, r = 3
+  exp_w4_r3_signed_truncate             <= c_exp_w4_r3_signed_truncate(S_w4);
+  exp_w4_r3_signed_round_half_away      <= c_exp_w4_r3_signed_round_half_away(S_w4);
+  exp_w4_r3_signed_round_half_away_clip <= c_exp_w4_r3_signed_round_half_away_clip(S_w4);
+  exp_w4_r3_signed_round_half_even      <= c_exp_w4_r3_signed_round_half_even(S_w4);
+  exp_w4_r3_signed_round_half_even_clip <= c_exp_w4_r3_signed_round_half_even_clip(S_w4);
+
+  exp_w4_r3_unsigned_truncate             <= c_exp_w4_r3_unsigned_truncate(U_w4);
+  exp_w4_r3_unsigned_round_half_up        <= c_exp_w4_r3_unsigned_round_half_up(U_w4);
+  exp_w4_r3_unsigned_round_half_up_clip   <= c_exp_w4_r3_unsigned_round_half_up_clip(U_w4);
+  exp_w4_r3_unsigned_round_half_even      <= c_exp_w4_r3_unsigned_round_half_even(U_w4);
+  exp_w4_r3_unsigned_round_half_even_clip <= c_exp_w4_r3_unsigned_round_half_even_clip(U_w4);
+
+  -- . w = 5
+  S_w5 <= (TO_UINT(in_dat) + 16) MOD 32;  -- 2**5 = 32
+  U_w5 <= TO_UINT(in_dat) MOD 32;
+
+  -- . w = 5, r = 2
+  exp_w5_r2_signed_truncate             <= c_exp_w5_r2_signed_truncate(S_w5);
+  exp_w5_r2_signed_round_half_away      <= c_exp_w5_r2_signed_round_half_away(S_w5);
+  exp_w5_r2_signed_round_half_away_clip <= c_exp_w5_r2_signed_round_half_away_clip(S_w5);
+  exp_w5_r2_signed_round_half_even      <= c_exp_w5_r2_signed_round_half_even(S_w5);
+  exp_w5_r2_signed_round_half_even_clip <= c_exp_w5_r2_signed_round_half_even_clip(S_w5);
+
+  exp_w5_r2_unsigned_truncate             <= c_exp_w5_r2_unsigned_truncate(U_w5);
+  exp_w5_r2_unsigned_round_half_up        <= c_exp_w5_r2_unsigned_round_half_up(U_w5);
+  exp_w5_r2_unsigned_round_half_up_clip   <= c_exp_w5_r2_unsigned_round_half_up_clip(U_w5);
+  exp_w5_r2_unsigned_round_half_even      <= c_exp_w5_r2_unsigned_round_half_even(U_w5);
+  exp_w5_r2_unsigned_round_half_even_clip <= c_exp_w5_r2_unsigned_round_half_even_clip(U_w5);
+
+  -- . w = 5, r = 3
+  exp_w5_r3_signed_truncate             <= c_exp_w5_r3_signed_truncate(S_w5);
+  exp_w5_r3_signed_round_half_away      <= c_exp_w5_r3_signed_round_half_away(S_w5);
+  exp_w5_r3_signed_round_half_away_clip <= c_exp_w5_r3_signed_round_half_away_clip(S_w5);
+  exp_w5_r3_signed_round_half_even      <= c_exp_w5_r3_signed_round_half_even(S_w5);
+  exp_w5_r3_signed_round_half_even_clip <= c_exp_w5_r3_signed_round_half_even_clip(S_w5);
+
+  exp_w5_r3_unsigned_truncate             <= c_exp_w5_r3_unsigned_truncate(U_w5);
+  exp_w5_r3_unsigned_round_half_up        <= c_exp_w5_r3_unsigned_round_half_up(U_w5);
+  exp_w5_r3_unsigned_round_half_up_clip   <= c_exp_w5_r3_unsigned_round_half_up_clip(U_w5);
+  exp_w5_r3_unsigned_round_half_even      <= c_exp_w5_r3_unsigned_round_half_even(U_w5);
+  exp_w5_r3_unsigned_round_half_even_clip <= c_exp_w5_r3_unsigned_round_half_even_clip(U_w5);
+
   -- Verification
   p_verify : PROCESS
   BEGIN
     WAIT UNTIL rising_edge(clk);
     IF reg_val = '1' THEN
+      IF c_round_w <= 0 THEN
+        -- Without rounding the expected value is same as input value
+        -- . signed
+        ASSERT SIGNED(fs_signed_truncate            ) = SIGNED(reg_dat) REPORT "Wrong wired fs_signed_truncate" SEVERITY ERROR;
+        ASSERT SIGNED(fs_signed_round_half_away     ) = SIGNED(reg_dat) REPORT "Wrong wired fs_signed_round_half_away" SEVERITY ERROR;
+        ASSERT SIGNED(fs_signed_round_half_away_clip) = SIGNED(reg_dat) REPORT "Wrong wired fs_signed_round_half_away_clip" SEVERITY ERROR;
+        ASSERT SIGNED(fs_signed_round_half_even     ) = SIGNED(reg_dat) REPORT "Wrong wired fs_signed_round_half_even" SEVERITY ERROR;
+        ASSERT SIGNED(fs_signed_round_half_even_clip) = SIGNED(reg_dat) REPORT "Wrong wired fs_signed_round_half_even_clip"    SEVERITY ERROR;
+        -- . unsigned
+        ASSERT UNSIGNED(fs_unsigned_truncate            ) = UNSIGNED(reg_dat) REPORT "Wrong wired fs_unsigned_truncate" SEVERITY ERROR;
+        ASSERT UNSIGNED(fs_unsigned_round_half_up       ) = UNSIGNED(reg_dat) REPORT "Wrong wired fs_unsigned_round_half_up" SEVERITY ERROR;
+        ASSERT UNSIGNED(fs_unsigned_round_half_up_clip  ) = UNSIGNED(reg_dat) REPORT "Wrong wired fs_unsigned_round_half_up_clip" SEVERITY ERROR;
+        ASSERT UNSIGNED(fs_unsigned_round_half_even     ) = UNSIGNED(reg_dat) REPORT "Wrong wired fs_unsigned_round_half_even" SEVERITY ERROR;
+        ASSERT UNSIGNED(fs_unsigned_round_half_even_clip) = UNSIGNED(reg_dat) REPORT "Wrong wired fs_unsigned_round_half_even_clip" SEVERITY ERROR;
+      ELSE
+        -- With rounding then compare with expected list of values from common_round_tb.py
+        IF g_in_dat_w = 4 AND c_round_w = 1 THEN
+          -- . signed
+          ASSERT SIGNED(fs_signed_truncate            ) = exp_w4_r1_signed_truncate             REPORT "Wrong exp_w4_r1_signed_truncate" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away     ) = exp_w4_r1_signed_round_half_away      REPORT "Wrong exp_w4_r1_signed_round_half_away" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away_clip) = exp_w4_r1_signed_round_half_away_clip REPORT "Wrong exp_w4_r1_signed_round_half_away_clip" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even     ) = exp_w4_r1_signed_round_half_even      REPORT "Wrong exp_w4_r1_signed_round_half_even" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even_clip) = exp_w4_r1_signed_round_half_even_clip REPORT "Wrong exp_w4_r1_signed_round_half_even_clip" SEVERITY ERROR;
+          -- . unsigned
+          ASSERT UNSIGNED(fs_unsigned_truncate            ) = exp_w4_r1_unsigned_truncate             REPORT "Wrong exp_w4_r1_unsigned_truncate" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up       ) = exp_w4_r1_unsigned_round_half_up        REPORT "Wrong exp_w4_r1_unsigned_round_half_up" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up_clip  ) = exp_w4_r1_unsigned_round_half_up_clip   REPORT "Wrong exp_w4_r1_unsigned_round_half_up_clip" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even     ) = exp_w4_r1_unsigned_round_half_even      REPORT "Wrong exp_w4_r1_unsigned_round_half_even" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even_clip) = exp_w4_r1_unsigned_round_half_even_clip REPORT "Wrong exp_w4_r1_unsigned_round_half_even_clip" SEVERITY ERROR;
+        END IF;
+        IF g_in_dat_w = 4 AND c_round_w = 2 THEN
+          -- . signed
+          ASSERT SIGNED(fs_signed_truncate            ) = exp_w4_r2_signed_truncate             REPORT "Wrong exp_w4_r2_signed_truncate" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away     ) = exp_w4_r2_signed_round_half_away      REPORT "Wrong exp_w4_r2_signed_round_half_away" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away_clip) = exp_w4_r2_signed_round_half_away_clip REPORT "Wrong exp_w4_r2_signed_round_half_away_clip" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even     ) = exp_w4_r2_signed_round_half_even      REPORT "Wrong exp_w4_r2_signed_round_half_even" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even_clip) = exp_w4_r2_signed_round_half_even_clip REPORT "Wrong exp_w4_r2_signed_round_half_even_clip" SEVERITY ERROR;
+          -- . unsigned
+          ASSERT UNSIGNED(fs_unsigned_truncate            ) = exp_w4_r2_unsigned_truncate             REPORT "Wrong exp_w4_r2_unsigned_truncate" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up       ) = exp_w4_r2_unsigned_round_half_up        REPORT "Wrong exp_w4_r2_unsigned_round_half_up" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up_clip  ) = exp_w4_r2_unsigned_round_half_up_clip   REPORT "Wrong exp_w4_r2_unsigned_round_half_up_clip" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even     ) = exp_w4_r2_unsigned_round_half_even      REPORT "Wrong exp_w4_r2_unsigned_round_half_even" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even_clip) = exp_w4_r2_unsigned_round_half_even_clip REPORT "Wrong exp_w4_r2_unsigned_round_half_even_clip" SEVERITY ERROR;
+        END IF;
+        IF g_in_dat_w = 4 AND c_round_w = 3 THEN
+          -- . signed
+          ASSERT SIGNED(fs_signed_truncate            ) = exp_w4_r3_signed_truncate             REPORT "Wrong exp_w4_r3_signed_truncate" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away     ) = exp_w4_r3_signed_round_half_away      REPORT "Wrong exp_w4_r3_signed_round_half_away" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away_clip) = exp_w4_r3_signed_round_half_away_clip REPORT "Wrong exp_w4_r3_signed_round_half_away_clip" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even     ) = exp_w4_r3_signed_round_half_even      REPORT "Wrong exp_w4_r3_signed_round_half_even" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even_clip) = exp_w4_r3_signed_round_half_even_clip REPORT "Wrong exp_w4_r3_signed_round_half_even_clip" SEVERITY ERROR;
+          -- . unsigned
+          ASSERT UNSIGNED(fs_unsigned_truncate            ) = exp_w4_r3_unsigned_truncate             REPORT "Wrong exp_w4_r3_unsigned_truncate" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up       ) = exp_w4_r3_unsigned_round_half_up        REPORT "Wrong exp_w4_r3_unsigned_round_half_up" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up_clip  ) = exp_w4_r3_unsigned_round_half_up_clip   REPORT "Wrong exp_w4_r3_unsigned_round_half_up_clip" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even     ) = exp_w4_r3_unsigned_round_half_even      REPORT "Wrong exp_w4_r3_unsigned_round_half_even" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even_clip) = exp_w4_r3_unsigned_round_half_even_clip REPORT "Wrong exp_w4_r3_unsigned_round_half_even_clip" SEVERITY ERROR;
+        END IF;
+        IF g_in_dat_w = 5 AND c_round_w = 2 THEN
+          -- . signed
+          ASSERT SIGNED(fs_signed_truncate            ) = exp_w5_r2_signed_truncate             REPORT "Wrong exp_w5_r2_signed_truncate" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away     ) = exp_w5_r2_signed_round_half_away      REPORT "Wrong exp_w5_r2_signed_round_half_away" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away_clip) = exp_w5_r2_signed_round_half_away_clip REPORT "Wrong exp_w5_r2_signed_round_half_away_clip" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even     ) = exp_w5_r2_signed_round_half_even      REPORT "Wrong exp_w5_r2_signed_round_half_even" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even_clip) = exp_w5_r2_signed_round_half_even_clip REPORT "Wrong exp_w5_r2_signed_round_half_even_clip" SEVERITY ERROR;
+          -- . unsigned
+          ASSERT UNSIGNED(fs_unsigned_truncate            ) = exp_w5_r2_unsigned_truncate             REPORT "Wrong exp_w5_r2_unsigned_truncate" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up       ) = exp_w5_r2_unsigned_round_half_up        REPORT "Wrong exp_w5_r2_unsigned_round_half_up" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up_clip  ) = exp_w5_r2_unsigned_round_half_up_clip   REPORT "Wrong exp_w5_r2_unsigned_round_half_up_clip" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even     ) = exp_w5_r2_unsigned_round_half_even      REPORT "Wrong exp_w5_r2_unsigned_round_half_even" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even_clip) = exp_w5_r2_unsigned_round_half_even_clip REPORT "Wrong exp_w5_r2_unsigned_round_half_even_clip" SEVERITY ERROR;
+        END IF;
+        IF g_in_dat_w = 5 AND c_round_w = 3 THEN
+          -- . signed
+          ASSERT SIGNED(fs_signed_truncate            ) = exp_w5_r3_signed_truncate             REPORT "Wrong exp_w5_r3_signed_truncate" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away     ) = exp_w5_r3_signed_round_half_away      REPORT "Wrong exp_w5_r3_signed_round_half_away" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_away_clip) = exp_w5_r3_signed_round_half_away_clip REPORT "Wrong exp_w5_r3_signed_round_half_away_clip" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even     ) = exp_w5_r3_signed_round_half_even      REPORT "Wrong exp_w5_r3_signed_round_half_even" SEVERITY ERROR;
+          ASSERT SIGNED(fs_signed_round_half_even_clip) = exp_w5_r3_signed_round_half_even_clip REPORT "Wrong exp_w5_r3_signed_round_half_even_clip" SEVERITY ERROR;
+          -- . unsigned
+          ASSERT UNSIGNED(fs_unsigned_truncate            ) = exp_w5_r3_unsigned_truncate             REPORT "Wrong exp_w5_r3_unsigned_truncate" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up       ) = exp_w5_r3_unsigned_round_half_up        REPORT "Wrong exp_w5_r3_unsigned_round_half_up" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_up_clip  ) = exp_w5_r3_unsigned_round_half_up_clip   REPORT "Wrong exp_w5_r3_unsigned_round_half_up_clip" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even     ) = exp_w5_r3_unsigned_round_half_even      REPORT "Wrong exp_w5_r3_unsigned_round_half_even" SEVERITY ERROR;
+          ASSERT UNSIGNED(fs_unsigned_round_half_even_clip) = exp_w5_r3_unsigned_round_half_even_clip REPORT "Wrong exp_w5_r3_unsigned_round_half_even_clip" SEVERITY ERROR;
+        END IF;
+      END IF;
     END IF;
   END PROCESS;
 
diff --git a/libraries/base/common/tb/vhdl/tb_tb_round.vhd b/libraries/base/common/tb/vhdl/tb_tb_round.vhd
new file mode 100644
index 0000000000000000000000000000000000000000..40efae340b378080d4043ea10edc83e227440f95
--- /dev/null
+++ b/libraries/base/common/tb/vhdl/tb_tb_round.vhd
@@ -0,0 +1,42 @@
+-- --------------------------------------------------------------------------
+-- Copyright 2021
+-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
+-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
+--
+-- Licensed under the Apache License, Version 2.0 (the "License");
+-- you may not use this file except in compliance with the License.
+-- You may obtain a copy of the License at
+--
+-- http://www.apache.org/licenses/LICENSE-2.0
+--
+-- Unless required by applicable law or agreed to in writing, software
+-- distributed under the License is distributed on an "AS IS" BASIS,
+-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+-- See the License for the specific language governing permissions and
+-- limitations under the License.
+-- --------------------------------------------------------------------------
+--
+-- Author: E. Kooistra, 4 nov 2021
+-- Purpose: Multi tb for common_round.vhd and s_round(), u_round() in common_pkg.vhd
+
+LIBRARY IEEE;
+USE IEEE.std_logic_1164.ALL;
+
+ENTITY tb_tb_round IS
+END tb_tb_round;
+
+ARCHITECTURE tb OF tb_tb_round IS
+  SIGNAL tb_end : STD_LOGIC := '0';  -- declare tb_end to avoid 'No objects found' error on 'when -label tb_end'
+BEGIN
+  -- -- Supported for RESIZE_NUM() and common_round.vhd
+  -- g_in_dat_w        : NATURAL := 5;
+  -- g_out_dat_w       : NATURAL := 3
+
+  u_extend      : ENTITY work.tb_round GENERIC MAP (5, 6);
+  u_wires       : ENTITY work.tb_round GENERIC MAP (5, 5);
+  u_round_w4_r1 : ENTITY work.tb_round GENERIC MAP (4, 3);  -- -r = 4 - 3 = 1
+  u_round_w4_r2 : ENTITY work.tb_round GENERIC MAP (4, 2);  -- -r = 4 - 2 = 2
+  u_round_w4_r3 : ENTITY work.tb_round GENERIC MAP (4, 1);  -- -r = 4 - 1 = 3
+  u_round_w5_r2 : ENTITY work.tb_round GENERIC MAP (5, 3);  -- -r = 5 - 3 = 2
+  u_round_w5_r3 : ENTITY work.tb_round GENERIC MAP (5, 2);  -- -r = 5 - 2 = 3
+END tb;
diff --git a/libraries/base/dp/src/vhdl/dp_requantize.vhd b/libraries/base/dp/src/vhdl/dp_requantize.vhd
index 1ae2ca974821c6bc4319b9e74a5d6ff3fc5b3fc9..31d63241e128df435401ce5e9a9bba5a41adf732 100644
--- a/libraries/base/dp/src/vhdl/dp_requantize.vhd
+++ b/libraries/base/dp/src/vhdl/dp_requantize.vhd
@@ -34,14 +34,15 @@ USE common_lib.common_pkg.ALL;
 
 ENTITY dp_requantize IS
   GENERIC (               
-    g_complex             : BOOLEAN := TRUE;      -- when true, the re and im field are processed, when false, the data field is processed
+    g_complex             : BOOLEAN := TRUE;      -- when TRUE, the re and im field are processed, when false, the data field is processed
     g_representation      : STRING  := "SIGNED";  -- SIGNED (round +-0.5 away from zero to +- infinity) or UNSIGNED rounding (round 0.5 up to + inifinity)         
     g_lsb_w               : INTEGER := 4;         -- when > 0, number of LSbits to remove from in_dat
                                                   -- when < 0, number of LSBits to insert as a gain before resize to out_dat'LENGTH
                                                   -- when 0 then no effect
-    g_lsb_round           : BOOLEAN := TRUE;      -- when true ROUND else TRUNCATE the input LSbits                                                                
-    g_lsb_round_clip      : BOOLEAN := FALSE;     -- when true round clip to +max to avoid wrapping to output -min (signed) or 0 (unsigned) due to rounding        
-    g_msb_clip            : BOOLEAN := TRUE;      -- when true CLIP else WRAP the input MSbits                                                                     
+    g_lsb_round           : BOOLEAN := TRUE;      -- when TRUE round else truncate the input LSbits
+    g_lsb_round_clip      : BOOLEAN := FALSE;     -- when TRUE round clip to +max to avoid wrapping to output -min (signed) or 0 (unsigned) due to rounding
+    g_lsb_round_even      : BOOLEAN := FALSE;     -- when TRUE round to even, else round away from zero
+    g_msb_clip            : BOOLEAN := TRUE;      -- when TRUE CLIP else WRAP the input MSbits
     g_msb_clip_symmetric  : BOOLEAN := FALSE;     -- when TRUE clip signed symmetric to +c_smax and -c_smax, else to +c_smax and c_smin_symm                       
                                                   -- for wrapping when g_msb_clip=FALSE the g_msb_clip_symmetric is ignored, so signed wrapping is done asymmetric 
     g_gain_w              : NATURAL := 0;         -- do not use, must be 0, use negative g_lsb_w instead
@@ -88,7 +89,8 @@ BEGIN
       g_representation      => g_representation,      
       g_lsb_w               => g_lsb_w,               
       g_lsb_round           => g_lsb_round,           
-      g_lsb_round_clip      => g_lsb_round_clip,      
+      g_lsb_round_clip      => g_lsb_round_clip,
+      g_lsb_round_even      => g_lsb_round_even,
       g_msb_clip            => g_msb_clip,            
       g_msb_clip_symmetric  => g_msb_clip_symmetric,
       g_pipeline_remove_lsb => g_pipeline_remove_lsb, 
@@ -113,7 +115,8 @@ BEGIN
       g_representation      => g_representation,     
       g_lsb_w               => g_lsb_w,              
       g_lsb_round           => g_lsb_round,          
-      g_lsb_round_clip      => g_lsb_round_clip,     
+      g_lsb_round_clip      => g_lsb_round_clip,
+      g_lsb_round_even      => g_lsb_round_even,
       g_msb_clip            => g_msb_clip,           
       g_msb_clip_symmetric  => g_msb_clip_symmetric, 
       g_pipeline_remove_lsb => g_pipeline_remove_lsb,
@@ -133,7 +136,8 @@ BEGIN
       g_representation      => g_representation,      
       g_lsb_w               => g_lsb_w,               
       g_lsb_round           => g_lsb_round,           
-      g_lsb_round_clip      => g_lsb_round_clip,      
+      g_lsb_round_clip      => g_lsb_round_clip,
+      g_lsb_round_even      => g_lsb_round_even,
       g_msb_clip            => g_msb_clip,            
       g_msb_clip_symmetric  => g_msb_clip_symmetric,  
       g_pipeline_remove_lsb => g_pipeline_remove_lsb,