From d4e17c57e7cfc895ea927a4f40116f47849d619d Mon Sep 17 00:00:00 2001 From: Tristan Gingold Date: Sat, 14 Jan 2023 19:02:44 +0100 Subject: testsuite/gna: add a test for #664 --- .../gna/issue664/numeric_system_pkg-orig.vhdl | 404 +++++++++++++++++++++ testsuite/gna/issue664/numeric_system_pkg.vhdl | 404 +++++++++++++++++++++ testsuite/gna/issue664/quire_accumulator.vhdl | 82 +++++ testsuite/gna/issue664/quire_accumulator_tb.vhdl | 109 ++++++ testsuite/gna/issue664/reset_synchronizer.vhdl | 26 ++ testsuite/gna/issue664/tb_pkg.vhdl | 90 +++++ testsuite/gna/issue664/testsuite.sh | 23 ++ 7 files changed, 1138 insertions(+) create mode 100644 testsuite/gna/issue664/numeric_system_pkg-orig.vhdl create mode 100644 testsuite/gna/issue664/numeric_system_pkg.vhdl create mode 100644 testsuite/gna/issue664/quire_accumulator.vhdl create mode 100644 testsuite/gna/issue664/quire_accumulator_tb.vhdl create mode 100644 testsuite/gna/issue664/reset_synchronizer.vhdl create mode 100644 testsuite/gna/issue664/tb_pkg.vhdl create mode 100755 testsuite/gna/issue664/testsuite.sh diff --git a/testsuite/gna/issue664/numeric_system_pkg-orig.vhdl b/testsuite/gna/issue664/numeric_system_pkg-orig.vhdl new file mode 100644 index 000000000..f5513b32a --- /dev/null +++ b/testsuite/gna/issue664/numeric_system_pkg-orig.vhdl @@ -0,0 +1,404 @@ +------------------------------------------------------------------ +---- ---- +---- Content: Numeric System Package ---- +---- for Stillwater KPUs ---- +---- ---- +---- Author: E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +---- ---- +---- Copyright (C) 2017-2018 ---- +---- E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +--- +---- A posit is a tapered floating point representation. +---- To compute with posits, the regime and exponent fields +---- need to be consolidated. This process generates a triple +---- (sign, exponent, fraction) +---- These triples are the input values to the arithmetic units +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +--The numeric_system package defines the number system that the +--overall system will be using. We are unifying integers, floats, and posits +--by converting them to a (sign, scale, fraction) triple. +-- +--Each number system, that is, integer, float, posit, valid, will have +--a slightly different relationship between and bit sizes +--for scale and fraction. This pkg configures the root of that configuration. + +-- static constexpr size_t escale = size_t(1) << es; // 2^es +-- static constexpr size_t range = escale * (4 * nbits - 8); // dynamic range of the posit configuration +-- static constexpr size_t half_range = range >> 1; // position of the fixed point +-- static constexpr size_t radix_point = half_range; +-- // the upper is 1 bit bigger than the lower because maxpos^2 has that scale +-- static constexpr size_t upper_range = half_range + 1; // size of the upper accumulator +-- static constexpr size_t qbits = range + capacity; // size of the quire minus the sign bit: we are managing the sign explicitly + +package numeric_system_pkg is + + generic( + NBITS : positive := 8; -- number of bits to represent encoding + EBITS : natural := 0; -- number of bits to represent exponent + SBITS : positive := 5; -- number of bits to represent scale + FBITS : natural := 5; -- number of bits to represent the fraction + CBITS : natural := 10 -- number of bits to represent quire capacity + ); + + -- arithmetic property constants + constant GUARDBITS : natural := 3; + + impure function adder_width return positive; + impure function multiplier_width return positive; + impure function divider_width return positive; + impure function posit_dynamic_range return positive; + impure function quire_width return positive; + + -- derived entities + constant BITS_ADDER_OUT : positive := adder_width; + constant BITS_MULTIPLIER_OUT : positive := multiplier_width; + constant BITS_DIVIDER_OUT : positive := divider_width; + constant BITS_MAX_ARITH_OUT : positive := divider_width; + constant BITS_DYNAMIC_RANGE : positive := posit_dynamic_range; + constant BITS_QUIRE_WIDTH : positive := quire_width; + + -- posits that don't have fraction bits, still have a hidden bit + -- don't know what FBITS - 1 downto 0 evaluates to: possibly empty/null and thus trouble + + -- posit encoding is a 2's complement encoding with respect to relational operators + subtype posit_word is signed(NBITS - 1 downto 0); + -- scales are integers and operators on scale are add/sub + subtype scale_word is signed(SBITS - 1 downto 0); + -- fractions are unsigned binary values with radix at FBITS-1 + subtype fraction_word is unsigned(FBITS - 1 downto 0); + + -- ssf triple === (sign, scale, fraction) normal form + -- ssf triples are stored in the register file + type ssf_type is record + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + fraction : fraction_word; + end record; + + subtype add_significant_word is std_logic_vector(BITS_ADDER_OUT - 1 downto 0); + -- sss triple === (sign, scale, significant) output of an adder/subtractor + -- these records flow to the quire and the posit rounding stage + type sss_add_output_type is record + valid : std_logic; + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : add_significant_word; + end record; + + subtype mul_significant_word is std_logic_vector(BITS_MULTIPLIER_OUT - 1 downto 0); + -- sss triple === (sign, scale, signficant) output of a multiplier + -- these records flow to the quire and the posit rounding stage + type sss_mul_output_type is record + valid : std_logic; + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : mul_significant_word; + end record; + + subtype div_significant_word is std_logic_vector(BITS_DIVIDER_OUT - 1 downto 0); + -- sss triple === (sign, scale, signficant) output of a divider + -- these records flow to the quire and the posit rounding stage + type sss_div_output_type is record + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : div_significant_word; + end record; + + -- max sss triple that can come out of the arithmetic data path. + -- all smaller sss triples are right extended with '0's to unify + type sss_max_result_type is record + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : std_logic_vector(BITS_MAX_ARITH_OUT - 1 downto 0); + end record; + + -- input record to the ALU + type alu_input_type is record + opcode : std_logic_vector(2 downto 0); -- instruction to execute: add/sub, mul/div, recip, sqrt + operand_1 : ssf_type; + operand_2 : ssf_type; + operand_3 : ssf_type; + end record; + + type quire_cmd_type is (LOAD, STORE, CLEAR, NOP); -- ACCUMULATE is default: keeps to 2 bits + + -- are we managing the quire as a sign-magnitude or a 2's complement accumulator? + -- subtype quire_word is unsigned(BITS_QUIRE_WIDTH - 1 downto 0); + subtype quire_word is signed(BITS_QUIRE_WIDTH - 1 downto 0); + constant QUIRE_ZERO : quire_word := (others => '0'); + + type quire_in_type is record + cmd : quire_cmd_type; + d_in : quire_word; -- for quire load + end record; + + subtype quire_in_reg is ssf_type; -- adding a raw posit value out of the posit registers + subtype quire_in_add is sss_add_output_type; -- adding the result of a posit addition without rounding + subtype quire_in_mul is sss_mul_output_type; -- adding the result of a posit multiplication without rounding + + type quire_state_type is (QS_ZERO, QS_NEG, QS_POS, QS_OVERFLOW); + + type quire_out_type is record + state : quire_state_type; + q_out : quire_word; -- for quire store + end record; + + -- stringer for ssf tripslet + function ssf_to_string( + tag : String; + triplet : ssf_type + ) return String; + + -- compare two ssf triplets + function cmpSSF( + val : ssf_type; + ref : ssf_type + ) return boolean; + + -- report the configuration and the derived constants + procedure reportConfiguration; + +end package; + +package body numeric_system_pkg is + + impure function adder_width return positive is + constant fbits_value : positive := FBITS; + begin + return fbits_value + 2; + end function; + + impure function multiplier_width return positive is + constant fbits_value : positive := FBITS; + begin + return 2 * fbits_value + 1; + end function; + + impure function divider_width return positive is + constant fbits_value : positive := FBITS; + begin + return 2 * fbits_value + 3; + end function; + + impure function posit_dynamic_range return positive is + constant ebits_value : natural := EBITS; + constant nbits_value : positive := NBITS; + variable escale : positive := 1; + begin + escale := 2 ** ebits_value; + return escale * (4 * nbits_value - 8); + end function; + + impure function quire_width return positive is + constant ebits_value : natural := EBITS; + constant nbits_value : positive := NBITS; + constant cbits_value : positive := CBITS; + variable escale : positive := 1; + variable qw : positive := 1; + begin + escale := 2 ** ebits_value; + qw := escale * (4 * nbits_value - 8) + cbits_value; + return qw; + end function; + + procedure reportConfiguration is + begin + report "Configuration Parameters"; + report " NBITS = " & to_string(NBITS); + report " EBITS = " & to_string(EBITS); + report " SBITS = " & to_string(SBITS); + report " FBITS = " & to_string(FBITS); + report " CBITS = " & to_string(CBITS); + + report " GUARDBITS = " & to_string(GUARDBITS); + + report "Derived Constants"; + report " BITS_ADDER_OUT : " & to_string(BITS_ADDER_OUT); + report " BITS_MULTIPLIER_OUT : " & to_string(BITS_MULTIPLIER_OUT); + report " BITS_DIVIDER_OUT : " & to_string(BITS_DIVIDER_OUT); + report " BITS_MAX_ARITH_OUT : " & to_string(BITS_MAX_ARITH_OUT); + report " BITS_DYNAMIC_RANGE : " & to_string(BITS_DYNAMIC_RANGE); + report " BITS_QUIRE_WIDTH : " & to_string(BITS_QUIRE_WIDTH); + end procedure; + + function ssf_to_string( + tag : String; + triplet : ssf_type + ) return String is + begin + if triplet.isZero = '1' then + return tag & " = (zero)"; + elsif triplet.isNaR = '1' then + return tag & " = (NaR)"; + else + return tag & " = (" & to_string(triplet.sign) & "," & to_string(triplet.scale) & "," & to_string(triplet.fraction) & ")"; + end if; + end function; + + function cmpSSF( + val : ssf_type; + ref : ssf_type + ) return boolean is + begin + -- first check special cases + if val.isZero = '1' AND val.isZero = ref.isZero then + return true; + end if; + if val.isNaR = '1' AND val.isNaR = ref.isNaR then + return true; + end if; + -- no special case, so compare ssf values + if val.sign = ref.sign AND val.scale = ref.scale AND val.fraction = ref.fraction then + return true; + else + return false; + end if; + + end function; + +end package body numeric_system_pkg; + +------------------------------------------------------------------ +--- posit configuration --- +------------------------------------------------------------------ +-- configuration for a posit<5,1>@1.0 : [s] [rr] [e] [f] [ggg] +-- es = 1 -> useed = 2^2^1 = 4 +-- max k = nbits-2 = 3 -> 4^3 = 2^6 -> maxpos = 64 +-- fraction bits [h] [f] [ggg] -> 1 hidden bit, 1 fraction bit, 3 guard bits == 5 bits total +-- adder out: 5 + 1 = 6 + +-- configuration for a posit<8,0>@1.0 : [s] [rr] [] [fffff] [ggg] +-- es = 0 -> useed = 2^2^0 = 2 +-- max k = nbits-2 = 6 -> 2^6 -> maxpos = 64 -> scale is 6+1 bits +-- fraction bits [h] [ffff] [ggg] -> 1 hidden bit, 4 fraction bit, 3 guard bits == 8 bits total +-- adder out: 8 + 1 = 9 + +-- configuration for a posit<8,1>@1.0 : [s] [rr] [e] [ffff] [ggg] +-- es = 1 -> useed = 2^2^1 = 4 +-- max k = nbits-2 = 6 -> 4^6 = 2^12 -> maxpos = 4096 -> scale is 12+1 bits +-- fraction bits [h] [ffff] [ggg] -> 1 hidden bit, 4 fraction bit, 3 guard bits == 8 bits total +-- adder out: 8 + 1 = 9 + +------------------------------------------------------------------ +--- float configuration --- +------------------------------------------------------------------ +-- configuation for a 8-bit float : [s] [ee] [f ffff] [ggg] +-- nbits = 8, es = 2 +-- configuation for a 16-bit float : [s] [eeee e] [ff ffff ffff] [ggg] +-- nbits = 16, es = 5 +-- configuation for a 32-bit float : [s] [eeee eeee] [fff ffff ffff ffff ffff ffff] [ggg] +-- nbits = 32, es = 8 + +-- Standard posit configurations +-- posit< 8,0> useed scale 1 minpos scale -6 maxpos scale 6 +-- posit< 16,1> useed scale 2 minpos scale -28 maxpos scale 28 +-- posit< 32,2> useed scale 4 minpos scale -120 maxpos scale 120 +-- posit< 64,3> useed scale 8 minpos scale -496 maxpos scale 496 + +package p4e0 is new work.numeric_system_pkg + generic map( + NBITS => 4, -- 4 encoding bits + EBITS => 0, -- no exponent bits + SBITS => 3, -- posit<4,0> scale ranges from -2 to 2 + FBITS => 1, -- one fraction bit + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p5e0 is new work.numeric_system_pkg + generic map( + NBITS => 5, -- 5 encoding bits + EBITS => 0, -- no exponent bits + SBITS => 4, -- posit<5,0> scale ranges from -3 to 3 + FBITS => 2, -- 2 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p8e0 is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 0, -- no exponent bits + SBITS => 5, -- posit<8,0> scale ranges from -6 to 6 + FBITS => 5, -- 5 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p8e1 is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 1, -- 1 exponent bit + SBITS => 6, -- posit<8,1> scale ranges from -12 to 12 + FBITS => 4, -- 4 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p8e2 is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 2, -- 2 exponent bits + SBITS => 7, -- posit<8,2> scale ranges from -24 to 24 + FBITS => 3, -- 3 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p16e1 is new work.numeric_system_pkg + generic map( + NBITS => 16, -- 16 encoding bits + EBITS => 1, -- one exponent bit + SBITS => 7, -- posit<16,1> scale ranges from -28 to 28 + FBITS => 12, -- 12 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +-- posit< 8,0> useed scale 1 minpos scale -6 maxpos scale 6 +-- posit< 8,1> useed scale 2 minpos scale -12 maxpos scale 12 +-- posit< 8,2> useed scale 4 minpos scale -24 maxpos scale 24 +-- posit< 16,0> useed scale 1 minpos scale -14 maxpos scale 14 +-- posit< 16,1> useed scale 2 minpos scale -28 maxpos scale 28 +-- posit< 16,2> useed scale 4 minpos scale -56 maxpos scale 56 + +------------------------------------------------------------------ +---- ---- +---- Content: Data Path Configuration Package ---- +---- for Stillwater KPUs ---- +---- ---- +---- Author: E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +---- ---- +---- Copyright (C) 2017-2018 ---- +---- E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ + +-- generic configuration package name that we can use in the components +-- and can change here to create different configurations +package config_pkg is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 1, -- no exponent bits + SBITS => 5, -- posit<8,0> scale ranges from -6 to 6 + FBITS => 5, -- 5 fraction bits + CBITS => 8 -- 8 capacity bits for quire + ); + diff --git a/testsuite/gna/issue664/numeric_system_pkg.vhdl b/testsuite/gna/issue664/numeric_system_pkg.vhdl new file mode 100644 index 000000000..196da2442 --- /dev/null +++ b/testsuite/gna/issue664/numeric_system_pkg.vhdl @@ -0,0 +1,404 @@ +------------------------------------------------------------------ +---- ---- +---- Content: Numeric System Package ---- +---- for Stillwater KPUs ---- +---- ---- +---- Author: E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +---- ---- +---- Copyright (C) 2017-2018 ---- +---- E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +--- +---- A posit is a tapered floating point representation. +---- To compute with posits, the regime and exponent fields +---- need to be consolidated. This process generates a triple +---- (sign, exponent, fraction) +---- These triples are the input values to the arithmetic units +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +--The numeric_system package defines the number system that the +--overall system will be using. We are unifying integers, floats, and posits +--by converting them to a (sign, scale, fraction) triple. +-- +--Each number system, that is, integer, float, posit, valid, will have +--a slightly different relationship between and bit sizes +--for scale and fraction. This pkg configures the root of that configuration. + +-- static constexpr size_t escale = size_t(1) << es; // 2^es +-- static constexpr size_t range = escale * (4 * nbits - 8); // dynamic range of the posit configuration +-- static constexpr size_t half_range = range >> 1; // position of the fixed point +-- static constexpr size_t radix_point = half_range; +-- // the upper is 1 bit bigger than the lower because maxpos^2 has that scale +-- static constexpr size_t upper_range = half_range + 1; // size of the upper accumulator +-- static constexpr size_t qbits = range + capacity; // size of the quire minus the sign bit: we are managing the sign explicitly + +package numeric_system_pkg is + + generic( + NBITS : positive := 8; -- number of bits to represent encoding + EBITS : natural := 0; -- number of bits to represent exponent + SBITS : positive := 5; -- number of bits to represent scale + FBITS : natural := 5; -- number of bits to represent the fraction + CBITS : natural := 10 -- number of bits to represent quire capacity + ); + + -- arithmetic property constants + constant GUARDBITS : natural := 3; + + impure function adder_width return positive; + impure function multiplier_width return positive; + impure function divider_width return positive; + impure function posit_dynamic_range return positive; + impure function quire_width return positive; + + -- derived entities + constant BITS_ADDER_OUT : positive := FBITS + 2; + constant BITS_MULTIPLIER_OUT : positive := 2 * FBITS + 1; + constant BITS_DIVIDER_OUT : positive := 2 * FBITS + 3; + constant BITS_MAX_ARITH_OUT : positive := 2 * FBITS + 3; + constant BITS_DYNAMIC_RANGE : positive := (2**EBITS) * (4 * NBITS - 8); + constant BITS_QUIRE_WIDTH : positive := BITS_DYNAMIC_RANGE + CBITS; + + -- posits that don't have fraction bits, still have a hidden bit + -- don't know what FBITS - 1 downto 0 evaluates to: possibly empty/null and thus trouble + + -- posit encoding is a 2's complement encoding with respect to relational operators + subtype posit_word is signed(NBITS - 1 downto 0); + -- scales are integers and operators on scale are add/sub + subtype scale_word is signed(SBITS - 1 downto 0); + -- fractions are unsigned binary values with radix at FBITS-1 + subtype fraction_word is unsigned(FBITS - 1 downto 0); + + -- ssf triple === (sign, scale, fraction) normal form + -- ssf triples are stored in the register file + type ssf_type is record + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + fraction : fraction_word; + end record; + + subtype add_significant_word is std_logic_vector(BITS_ADDER_OUT - 1 downto 0); + -- sss triple === (sign, scale, significant) output of an adder/subtractor + -- these records flow to the quire and the posit rounding stage + type sss_add_output_type is record + valid : std_logic; + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : add_significant_word; + end record; + + subtype mul_significant_word is std_logic_vector(BITS_MULTIPLIER_OUT - 1 downto 0); + -- sss triple === (sign, scale, signficant) output of a multiplier + -- these records flow to the quire and the posit rounding stage + type sss_mul_output_type is record + valid : std_logic; + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : mul_significant_word; + end record; + + subtype div_significant_word is std_logic_vector(BITS_DIVIDER_OUT - 1 downto 0); + -- sss triple === (sign, scale, signficant) output of a divider + -- these records flow to the quire and the posit rounding stage + type sss_div_output_type is record + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : div_significant_word; + end record; + + -- max sss triple that can come out of the arithmetic data path. + -- all smaller sss triples are right extended with '0's to unify + type sss_max_result_type is record + isNaR : std_logic; -- encoding special case of Not a Real + isZero : std_logic; -- encoding special case of 0 + sign : std_logic; -- sign + scale : scale_word; -- scale of the posit: useed ^ k * 2^e + significant : std_logic_vector(BITS_MAX_ARITH_OUT - 1 downto 0); + end record; + + -- input record to the ALU + type alu_input_type is record + opcode : std_logic_vector(2 downto 0); -- instruction to execute: add/sub, mul/div, recip, sqrt + operand_1 : ssf_type; + operand_2 : ssf_type; + operand_3 : ssf_type; + end record; + + type quire_cmd_type is (LOAD, STORE, CLEAR, NOP); -- ACCUMULATE is default: keeps to 2 bits + + -- are we managing the quire as a sign-magnitude or a 2's complement accumulator? + -- subtype quire_word is unsigned(BITS_QUIRE_WIDTH - 1 downto 0); + subtype quire_word is signed(BITS_QUIRE_WIDTH - 1 downto 0); + constant QUIRE_ZERO : quire_word := (others => '0'); + + type quire_in_type is record + cmd : quire_cmd_type; + d_in : quire_word; -- for quire load + end record; + + subtype quire_in_reg is ssf_type; -- adding a raw posit value out of the posit registers + subtype quire_in_add is sss_add_output_type; -- adding the result of a posit addition without rounding + subtype quire_in_mul is sss_mul_output_type; -- adding the result of a posit multiplication without rounding + + type quire_state_type is (QS_ZERO, QS_NEG, QS_POS, QS_OVERFLOW); + + type quire_out_type is record + state : quire_state_type; + q_out : quire_word; -- for quire store + end record; + + -- stringer for ssf tripslet + function ssf_to_string( + tag : String; + triplet : ssf_type + ) return String; + + -- compare two ssf triplets + function cmpSSF( + val : ssf_type; + ref : ssf_type + ) return boolean; + + -- report the configuration and the derived constants + procedure reportConfiguration; + +end package; + +package body numeric_system_pkg is + + impure function adder_width return positive is + constant fbits_value : positive := FBITS; + begin + return fbits_value + 2; + end function; + + impure function multiplier_width return positive is + constant fbits_value : positive := FBITS; + begin + return 2 * fbits_value + 1; + end function; + + impure function divider_width return positive is + constant fbits_value : positive := FBITS; + begin + return 2 * fbits_value + 3; + end function; + + impure function posit_dynamic_range return positive is + constant ebits_value : natural := EBITS; + constant nbits_value : positive := NBITS; + variable escale : positive := 1; + begin + escale := 2 ** ebits_value; + return escale * (4 * nbits_value - 8); + end function; + + impure function quire_width return positive is + constant ebits_value : natural := EBITS; + constant nbits_value : positive := NBITS; + constant cbits_value : positive := CBITS; + variable escale : positive := 1; + variable qw : positive := 1; + begin + escale := 2 ** ebits_value; + qw := escale * (4 * nbits_value - 8) + cbits_value; + return qw; + end function; + + procedure reportConfiguration is + begin + report "Configuration Parameters"; + report " NBITS = " & to_string(NBITS); + report " EBITS = " & to_string(EBITS); + report " SBITS = " & to_string(SBITS); + report " FBITS = " & to_string(FBITS); + report " CBITS = " & to_string(CBITS); + + report " GUARDBITS = " & to_string(GUARDBITS); + + report "Derived Constants"; + report " BITS_ADDER_OUT : " & to_string(BITS_ADDER_OUT); + report " BITS_MULTIPLIER_OUT : " & to_string(BITS_MULTIPLIER_OUT); + report " BITS_DIVIDER_OUT : " & to_string(BITS_DIVIDER_OUT); + report " BITS_MAX_ARITH_OUT : " & to_string(BITS_MAX_ARITH_OUT); + report " BITS_DYNAMIC_RANGE : " & to_string(BITS_DYNAMIC_RANGE); + report " BITS_QUIRE_WIDTH : " & to_string(BITS_QUIRE_WIDTH); + end procedure; + + function ssf_to_string( + tag : String; + triplet : ssf_type + ) return String is + begin + if triplet.isZero = '1' then + return tag & " = (zero)"; + elsif triplet.isNaR = '1' then + return tag & " = (NaR)"; + else + return tag & " = (" & to_string(triplet.sign) & "," & to_string(triplet.scale) & "," & to_string(triplet.fraction) & ")"; + end if; + end function; + + function cmpSSF( + val : ssf_type; + ref : ssf_type + ) return boolean is + begin + -- first check special cases + if val.isZero = '1' AND val.isZero = ref.isZero then + return true; + end if; + if val.isNaR = '1' AND val.isNaR = ref.isNaR then + return true; + end if; + -- no special case, so compare ssf values + if val.sign = ref.sign AND val.scale = ref.scale AND val.fraction = ref.fraction then + return true; + else + return false; + end if; + + end function; + +end package body numeric_system_pkg; + +------------------------------------------------------------------ +--- posit configuration --- +------------------------------------------------------------------ +-- configuration for a posit<5,1>@1.0 : [s] [rr] [e] [f] [ggg] +-- es = 1 -> useed = 2^2^1 = 4 +-- max k = nbits-2 = 3 -> 4^3 = 2^6 -> maxpos = 64 +-- fraction bits [h] [f] [ggg] -> 1 hidden bit, 1 fraction bit, 3 guard bits == 5 bits total +-- adder out: 5 + 1 = 6 + +-- configuration for a posit<8,0>@1.0 : [s] [rr] [] [fffff] [ggg] +-- es = 0 -> useed = 2^2^0 = 2 +-- max k = nbits-2 = 6 -> 2^6 -> maxpos = 64 -> scale is 6+1 bits +-- fraction bits [h] [ffff] [ggg] -> 1 hidden bit, 4 fraction bit, 3 guard bits == 8 bits total +-- adder out: 8 + 1 = 9 + +-- configuration for a posit<8,1>@1.0 : [s] [rr] [e] [ffff] [ggg] +-- es = 1 -> useed = 2^2^1 = 4 +-- max k = nbits-2 = 6 -> 4^6 = 2^12 -> maxpos = 4096 -> scale is 12+1 bits +-- fraction bits [h] [ffff] [ggg] -> 1 hidden bit, 4 fraction bit, 3 guard bits == 8 bits total +-- adder out: 8 + 1 = 9 + +------------------------------------------------------------------ +--- float configuration --- +------------------------------------------------------------------ +-- configuation for a 8-bit float : [s] [ee] [f ffff] [ggg] +-- nbits = 8, es = 2 +-- configuation for a 16-bit float : [s] [eeee e] [ff ffff ffff] [ggg] +-- nbits = 16, es = 5 +-- configuation for a 32-bit float : [s] [eeee eeee] [fff ffff ffff ffff ffff ffff] [ggg] +-- nbits = 32, es = 8 + +-- Standard posit configurations +-- posit< 8,0> useed scale 1 minpos scale -6 maxpos scale 6 +-- posit< 16,1> useed scale 2 minpos scale -28 maxpos scale 28 +-- posit< 32,2> useed scale 4 minpos scale -120 maxpos scale 120 +-- posit< 64,3> useed scale 8 minpos scale -496 maxpos scale 496 + +package p4e0 is new work.numeric_system_pkg + generic map( + NBITS => 4, -- 4 encoding bits + EBITS => 0, -- no exponent bits + SBITS => 3, -- posit<4,0> scale ranges from -2 to 2 + FBITS => 1, -- one fraction bit + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p5e0 is new work.numeric_system_pkg + generic map( + NBITS => 5, -- 5 encoding bits + EBITS => 0, -- no exponent bits + SBITS => 4, -- posit<5,0> scale ranges from -3 to 3 + FBITS => 2, -- 2 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p8e0 is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 0, -- no exponent bits + SBITS => 5, -- posit<8,0> scale ranges from -6 to 6 + FBITS => 5, -- 5 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p8e1 is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 1, -- 1 exponent bit + SBITS => 6, -- posit<8,1> scale ranges from -12 to 12 + FBITS => 4, -- 4 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p8e2 is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 2, -- 2 exponent bits + SBITS => 7, -- posit<8,2> scale ranges from -24 to 24 + FBITS => 3, -- 3 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +package p16e1 is new work.numeric_system_pkg + generic map( + NBITS => 16, -- 16 encoding bits + EBITS => 1, -- one exponent bit + SBITS => 7, -- posit<16,1> scale ranges from -28 to 28 + FBITS => 12, -- 12 fraction bits + CBITS => 10 -- 10 capacity bits for the quire + ); + +-- posit< 8,0> useed scale 1 minpos scale -6 maxpos scale 6 +-- posit< 8,1> useed scale 2 minpos scale -12 maxpos scale 12 +-- posit< 8,2> useed scale 4 minpos scale -24 maxpos scale 24 +-- posit< 16,0> useed scale 1 minpos scale -14 maxpos scale 14 +-- posit< 16,1> useed scale 2 minpos scale -28 maxpos scale 28 +-- posit< 16,2> useed scale 4 minpos scale -56 maxpos scale 56 + +------------------------------------------------------------------ +---- ---- +---- Content: Data Path Configuration Package ---- +---- for Stillwater KPUs ---- +---- ---- +---- Author: E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +---- ---- +---- Copyright (C) 2017-2018 ---- +---- E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ + +-- generic configuration package name that we can use in the components +-- and can change here to create different configurations +package config_pkg is new work.numeric_system_pkg + generic map( + NBITS => 8, -- 8 encoding bits + EBITS => 1, -- no exponent bits + SBITS => 5, -- posit<8,0> scale ranges from -6 to 6 + FBITS => 5, -- 5 fraction bits + CBITS => 8 -- 8 capacity bits for quire + ); + diff --git a/testsuite/gna/issue664/quire_accumulator.vhdl b/testsuite/gna/issue664/quire_accumulator.vhdl new file mode 100644 index 000000000..0c1800c5b --- /dev/null +++ b/testsuite/gna/issue664/quire_accumulator.vhdl @@ -0,0 +1,82 @@ +------------------------------------------------------------------ +---- ---- +---- Content: Parameterized quire accumulator unit: ---- +---- quire accumulator for deferred rounding ctrl ---- +---- ---- +---- Author: E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +---- ---- +---- Copyright (C) 2017-2018 ---- +---- E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ + +---- A quire is a super accumulator that receives unrounded +---- results from the adder and/or multiplier and accumulates +---- the unrounded results enabling to user controlled rounding. + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.config_pkg.all; + +entity quire_accumulator is + port( + clk : in std_logic; + rst_n : in std_logic; + q_in : in quire_in_type; + reg : in quire_in_reg; -- output from register file + add : in quire_in_add; -- output from adder/subtractor + mul : in quire_in_mul; -- output from multiplier + q_out : out quire_out_type + ); +end entity; + +architecture behavior of quire_accumulator is + + signal r, r_in : quire_word; + +begin + COMBINATORIAL : process(rst_n, q_in) + variable v : quire_word := QUIRE_ZERO; + variable state : quire_state_type := QS_ZERO; + begin + v := r; -- default assignment + + if rst_n = '0' then + v := QUIRE_ZERO; + else + if q_in.cmd = LOAD then + v := q_in.d_in; + elsif q_in.cmd = CLEAR then + v := QUIRE_ZERO; + elsif q_in.cmd = NOP then + v := r; + end if; + + if v = QUIRE_ZERO then + state := QS_ZERO; + else + state := QS_POS; + end if; + end if; + + r_in <= v; + q_out.q_out <= r; + q_out.state <= state; + + end process; + + SEQUENTIAL : process(clk) + begin + if rising_edge(clk) then + r <= r_in; + end if; + end process; + +end architecture; diff --git a/testsuite/gna/issue664/quire_accumulator_tb.vhdl b/testsuite/gna/issue664/quire_accumulator_tb.vhdl new file mode 100644 index 000000000..30292cde5 --- /dev/null +++ b/testsuite/gna/issue664/quire_accumulator_tb.vhdl @@ -0,0 +1,109 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library work; +use work.config_pkg.all; +use work.reset_synchronizer; +--use work.quire_accumulator; + +entity quire_accumulator_tb is +end entity; + +architecture behavior of quire_accumulator_tb is + component reset_synchronizer + port( + clk : in std_logic; + async_rst_n : in std_logic; + rst_n : out std_logic + ); + end component reset_synchronizer; + + -- component quire_accumulator + -- port( + -- clk : in std_logic; + -- rst_n : in std_logic; + -- q_in : in quire_in_type; + -- reg : in quire_in_reg; + -- add : in quire_in_add; + -- mul : in quire_in_mul; + -- q_out : out quire_out_type + -- ); + -- end component quire_accumulator; + + signal clk : std_logic := '0'; + signal async_rst_n : std_logic := '0'; + signal rst_n : std_logic := '0'; + signal finished : std_logic := '0'; + + -- signal q_in : quire_in_type := (cmd => CLEAR, d_in => QUIRE_ZERO); + -- signal q_in_reg : quire_in_reg := ( + -- isNaR => '0', + -- isZero => '1', + -- sign => '0', + -- scale => (others => '0'), + -- fraction => (others => '0') + -- ); + -- signal q_in_add : quire_in_add := ( + -- valid => '0', + -- isNaR => '0', + -- isZero => '1', + -- sign => '0', + -- scale => (others => '0'), + -- significant => (others => '0') + -- ); + -- signal q_in_mul : quire_in_mul := ( + -- valid => '0', + -- isNaR => '0', + -- isZero => '1', + -- sign => '0', + -- scale => (others => '0'), + -- significant => (others => '0') + -- ); + + -- signal q_out : quire_out_type := ( + -- state => QS_ZERO, + -- q_out => QUIRE_ZERO + -- ); + signal q_out : quire_out_type; +begin + CLKGEN : process(clk, finished) + begin + clk <= not clk after 2500 ps when finished /= '1' else '0'; + end process; + + RESET_PULSE : process + begin + reportConfiguration; + + wait for 5 ns; + async_rst_n <= '1'; + wait; + end process; + + END_OF_SIM : process + begin + wait for 100 ns; + finished <= '1'; + wait; + end process; + + RESET_SYNC : reset_synchronizer + port map( + clk => clk, + async_rst_n => async_rst_n, + rst_n => rst_n + ); + + -- SUT_PROC : quire_accumulator + -- port map( + -- clk => clk, + -- rst_n => rst_n, + -- q_in => q_in, + -- reg => q_in_reg, + -- add => q_in_add, + -- mul => q_in_mul, + -- q_out => q_out + -- ); + +end architecture behavior; diff --git a/testsuite/gna/issue664/reset_synchronizer.vhdl b/testsuite/gna/issue664/reset_synchronizer.vhdl new file mode 100644 index 000000000..1384d5c8f --- /dev/null +++ b/testsuite/gna/issue664/reset_synchronizer.vhdl @@ -0,0 +1,26 @@ +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity reset_synchronizer is + port( + clk : in std_logic; + async_rst_n : in std_logic; + rst_n : out std_logic + ); +end entity reset_synchronizer; + +architecture behavior of reset_synchronizer is + signal r_ff1 : std_logic; +begin + SYNCHRONIZE : process(clk, async_rst_n) + begin + if async_rst_n = '0' then + r_ff1 <= '0'; + rst_n <= '0'; + elsif rising_edge(clk) then + r_ff1 <= '1'; + rst_n <= r_ff1; + end if; + end process; +end architecture; diff --git a/testsuite/gna/issue664/tb_pkg.vhdl b/testsuite/gna/issue664/tb_pkg.vhdl new file mode 100644 index 000000000..f7e59b998 --- /dev/null +++ b/testsuite/gna/issue664/tb_pkg.vhdl @@ -0,0 +1,90 @@ +------------------------------------------------------------------ +---- ---- +---- Content: testbench package ---- +---- ---- +---- Author: E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ +---- ---- +---- Copyright (C) 2017-2018 ---- +---- E. Theodore L. Omtzigt ---- +---- theo@stillwater-sc.com ---- +---- ---- +------------------------------------------------------------------ + +---- A posit is a tapered floating point representation. To compute +---- with posits, the regime and exponent fields need to be consolidated. +---- This process generates a triple (sign, exponent, significant). +---- These triples are the input values to the arithmetic units. + +library ieee; +use ieee.std_logic_1164.all; +use std.textio.all; + +package tb_pkg is + + -- Procedure for clock generation + procedure clk_gen(signal clk : out std_logic; constant FREQ : real); + -- How to use + --architecture sim of tb is + -- -- Clock frequency and signal + -- signal clk_166 : std_logic; + -- signal clk_125 : std_logic; + -- + --begin + -- + -- -- Clock generation with concurrent procedure call + -- clk_gen(clk_166, 166.667E6); -- 166.667 MHz clock + -- clk_gen(clk_125, 125.000E6); -- 125.000 MHz clock + -- + -- -- Time resolution show + -- assert FALSE report "Time resolution: " & time'image(time'succ(0 fs)) severity NOTE; + -- + --end architecture; + + --- trackError + function trackError( + condition : boolean; + message : String; + nrErrors : integer + ) return integer; + +end package; + +package body tb_pkg is + + -- Procedure for clock generation + procedure clk_gen(signal clk : out std_logic; constant FREQ : real) is + constant PERIOD : time := 1 sec / FREQ; -- Full period + constant HIGH_TIME : time := PERIOD / 2; -- High time + constant LOW_TIME : time := PERIOD - HIGH_TIME; -- Low time; always >= HIGH_TIME + begin + -- Check the arguments + assert (HIGH_TIME /= 0 fs) report "clk_plain: High time is zero; time resolution to large for frequency" severity FAILURE; + -- Generate a clock cycle + loop + clk <= '1'; + wait for HIGH_TIME; + clk <= '0'; + wait for LOW_TIME; + end loop; + end procedure; + + -- trackError + function trackError( + condition : boolean; + message : String; + nrErrors : integer) return integer is + variable runningCount : integer; + begin + assert (condition) report message; + if condition = FALSE then + runningCount := nrErrors + 1; + else + runningCount := nrErrors; + end if; + return runningCount; + end function; + +end package body; diff --git a/testsuite/gna/issue664/testsuite.sh b/testsuite/gna/issue664/testsuite.sh new file mode 100755 index 000000000..4b4aca623 --- /dev/null +++ b/testsuite/gna/issue664/testsuite.sh @@ -0,0 +1,23 @@ +#! /bin/sh + +. ../../testenv.sh + +export GHDL_STD_FLAGS=--std=08 +analyze tb_pkg.vhdl +analyze numeric_system_pkg.vhdl +analyze reset_synchronizer.vhdl +analyze quire_accumulator.vhdl +analyze quire_accumulator_tb.vhdl +elab quire_accumulator_tb + +simulate quire_accumulator_tb + +# if ghdl_has_feature quire_accumulator_tb ghw; then +# simulate quire_accumulator_tb --wave=w.ghw +# fi + +rm -f w.ghw +clean + +echo "Test successful" + -- cgit v1.2.3