diff --git a/.gitignore b/.gitignore index 9c392f7..354e3c7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ docs html +_NVC_LIB *~ script/* !script/ghdl_run_all.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ec5f6b..8381a2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,21 +5,27 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.3.0] - 2023-10-13 + +### Added + - nw_codec: Hamming encoder/decoder, odd/even parity function + - nw_util: Pointer type to t_slv_arr + ## [1.2.1] - 2023-06-26 ### Fixed - - ARP documentation + - nw_ethernet: ARP documentation - Deployment to gh-pages ## [1.2.0] - 2023-05-31 ### Added - - USB library + - nw_usb: USB library ## [1.1.0] - 2023-02-25 ### Added - - Bit-stuffing codec + - nw_codec: Bit-stuffing codec ## [1.0.0] - 2023-02-20 diff --git a/readme.md b/README.md similarity index 92% rename from readme.md rename to README.md index e146d87..4c5c597 100644 --- a/readme.md +++ b/README.md @@ -5,7 +5,7 @@ ![GitHub top language](https://img.shields.io/github/languages/top/geddy11/netwiz?style=plastic) ## Intro -NetWiz is a stand-alone VHDL library for network protocol packet generation and manipulation. NetWiz offers a stateless and functional **[API](https://geddy11.github.io/netwiz/functions_func.html)**. +NetWiz is a stand-alone VHDL library for network protocol packet generation and manipulation. NetWiz offers a stateless and functional [**API**](https://geddy11.github.io/netwiz/functions_func.html). NetWiz requires VHDL 2008 and is designed for test bench use only, synthesis is not supported. NetWiz is licensed under the MIT license. @@ -18,6 +18,7 @@ Netwiz consists of several libraries. Libraries not related to a specific networ * [nw_cobs](@ref nw_cobs): Consistent Overhead Byte Stuffing * [nw_bitstuff](@ref nw_bstuff): Bit stuffing * [nw_base](@ref nw_base): Base64/32/16 codec + * [nw_hamming](@ref nw_hamming): Hamming encoding/decoding * nw_pcap: * [nw_pcap](@ref nw_pcap): Read network packets from PCAP/PCAPNG files (produced by Wireshark, tcmpdump et.al.) * nw_util: @@ -48,5 +49,5 @@ Netwiz consists of several libraries. Libraries not related to a specific networ Additional protocol libraries are expected to be added in the future. ## Documentation - The NetWiz API is **[documented here](https://geddy11.github.io/netwiz/)**. + The NetWiz API is [**documented here**](https://geddy11.github.io/netwiz/). diff --git a/nw_codec/src/nw_codec_context.vhd b/nw_codec/src/nw_codec_context.vhd index 742140a..b930618 100644 --- a/nw_codec/src/nw_codec_context.vhd +++ b/nw_codec/src/nw_codec_context.vhd @@ -37,4 +37,5 @@ context nw_codec_context is use nw_codec.nw_cobs_pkg.all; use nw_codec.nw_base_pkg.all; use nw_codec.nw_bitstuff_pkg.all; + use nw_codec.nw_hamming_pkg.all; end context nw_codec_context; diff --git a/nw_codec/src/nw_hamming_pkg.vhd b/nw_codec/src/nw_hamming_pkg.vhd new file mode 100644 index 0000000..6b57a28 --- /dev/null +++ b/nw_codec/src/nw_hamming_pkg.vhd @@ -0,0 +1,517 @@ +------------------------------------------------------------------------------- +-- Title : Network Wizard Hamming Codec +-- Project : netwiz +-- GitHub : https://github.com/geddy11/netwiz +-- Standard : VHDL'08 +------------------------------------------------------------------------------- +-- Description: +--!\file +--!\brief Hamming codec functions +------------------------------------------------------------------------------- +-- MIT License +-- +-- Copyright (c) 2023 Geir Drange +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +-- WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +-- IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------- +--! @cond libraries +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; + +library nw_adapt; +use nw_adapt.nw_adaptations_pkg.all; +library nw_util; +context nw_util.nw_util_context; +--! @endcond + +--! \page nw_hamming Hamming codec +--! \tableofcontents +--! \section hamming Hamming codec +--! This library provides functions for Hamming encoding and decoding of data arrays of any width/size. +--! Supports single error correction/double error detection (SECDED). +--! +--! \subsection hamming__subsec1 Functionality +--! \li Perform Hamming encoding +--! \li Perform Hamming decoding +--! \li Perform parity calculation (odd/even) +--! +--! The number of parity bits (r) for a data word of length n is given by the equation: 2^r ≥ r + n + 1. +--! The output of the encoder is non-systematic: Position of the parity bits are given by 2^p, p ∈ [0, r). +--! The decoder expects the parity bits of the encoded data to be positioned as above. +--! +--! \n More details in \ref nw_hamming_pkg +--! \subsection hamming_subsec2 Example use +--! Include the libraries: +--! ~~~ +--! library nw_codec; +--! context nw_codec.nw_codec_context; +--! ~~~ +--! Example 1: Encode/decode 32bit data array without extra parity bit. +--! ~~~ +--! v_ewidth := f_hamming_enc_width(data_array_32bit, false); -- determine word width of encoded array +--! v_enc_data := new t_slv_arr(0 to data_array_32bit'length - 1)(v_ewidth - 1 downto 0); -- allocate array +--! v_enc_data := f_hamming_enc(data_array_32bit, false); -- encode data +--! ... +--! v_dwidth := f_hamming_dec_width(v_enc_data, false); -- determine width of decoded data (32bit + 1 status bit) +--! v_dec_data := new t_slv_arr(0 to data_array_32bit'length - 1)(v_dwidth - 1 downto 0); -- allocate array +--! v_dec_data := f_hamming_dec(v_enc_data, false); -- decode data (MSB holds error status) +--! ~~~ +--! Example 2: Encode/decode 128bit data array with extra parity bit (SECDED). +--! ~~~ +--! v_ewidth := f_hamming_enc_width(data_array_128bit, true); -- determine word width of encoded array +--! v_enc_data := new t_slv_arr(0 to data_array_128bit'length - 1)(v_ewidth - 1 downto 0); -- allocate array +--! v_enc_data := f_hamming_enc(data_array_128bit, true); -- encode data +--! ... +--! v_dwidth := f_hamming_dec_width(v_enc_data, true); -- determine width of decoded data (128bit + 2 status bits) +--! v_dec_data := new t_slv_arr(0 to data_array_128bit'length - 1)(v_dwidth - 1 downto 0); -- allocate array +--! v_dec_data := f_hamming_dec(v_enc_data, true); -- decode data (two MSBs hold error status) +--! ~~~ +--! See further examples in the test bench nw_codec_tb.vhd. +package nw_hamming_pkg is + + ------------------------------------------------------------------------------- + -- Functions + ------------------------------------------------------------------------------- + function f_calc_parity(data : std_logic_vector; + even_parity : boolean := true) return std_logic; + + function f_calc_parity(data : t_slv_arr; + even_parity : boolean := true) return t_slv_arr; + + impure function f_hamming_enc(data : t_slv_arr; + extra_parity : boolean := false) return t_slv_arr; + + impure function f_hamming_enc(data : t_slv_arr; + extra_parity : boolean := false) return t_slv_arr_ptr; + + function f_hamming_enc_width(data : t_slv_arr; + extra_parity : boolean := false) return natural; + + impure function f_hamming_dec(data : t_slv_arr; + extra_parity : boolean := false) return t_slv_arr; + + impure function f_hamming_dec(data : t_slv_arr; + extra_parity : boolean := false) return t_slv_arr_ptr; + + function f_hamming_dec_width(data : t_slv_arr; + extra_parity : boolean := false) return natural; + +end package nw_hamming_pkg; + +package body nw_hamming_pkg is + + ------------------------------------------------------------------------------- + -- Calculate number of parity bits during encoding (internal) + ------------------------------------------------------------------------------- + function f_calc_num_bits(data : t_slv_arr) + return integer is + variable v_r : integer := 0; + variable v_m : integer; + begin + v_m := data(data'low)'length; + while 2**v_r < v_m + v_r + 1 loop + v_r := v_r + 1; + end loop; + + return v_r; + end function f_calc_num_bits; + + ------------------------------------------------------------------------------- + -- Calculate number of parity bits for decoding (internal) + ------------------------------------------------------------------------------- + function f_calc_num_bits_dec(data_len : integer) + return integer is + variable v_r : integer := 0; + variable v_m : integer := 0; + begin + while v_r + v_m /= data_len loop + v_m := v_m + 1; + while 2**v_r < v_m + v_r + 1 loop + v_r := v_r + 1; + end loop; + end loop; + + return v_r; + end function f_calc_num_bits_dec; + + ------------------------------------------------------------------------------- + -- Calculate hamming parity bits, data word is non-systematic (internal) + ------------------------------------------------------------------------------- + function f_calc_hamming_bits(data : std_logic_vector; + parity_bits : integer; + extra_parity : boolean := false) + return std_logic_vector is + variable v_par : std_logic_vector(parity_bits - 1 downto 0) := (others => '0'); + variable v_parity : integer; + variable v_dwidth : integer := data'length; + variable v_2pj : unsigned(30 downto 0); + begin + if extra_parity then + v_dwidth := v_dwidth - 1; + end if; + -- calculate hamming parity bits + for j in 0 to parity_bits - 1 loop + v_parity := 0; + for k in 2**j - 1 to v_dwidth - 1 loop + v_2pj := to_unsigned(2**j, 31); + if (to_unsigned(k+1, 31) and v_2pj) = v_2pj then + if data(k) = '1' then + v_parity := v_parity + 1; + end if; + end if; + end loop; + if v_parity mod 2 = 1 then + v_par(j) := '1'; + end if; + end loop; + + return v_par; + end function f_calc_hamming_bits; + + ------------------------------------------------------------------------------- + --! \brief Calculate parity + --! \param data Data vector + --! \param even_parity True = Use even parity (default), false = use odd parity + --! \return Parity bit + --! + --! Calculate parity (even or odd) of a logic vector. + --! + --! **Example use** + --! ~~~ + --! parity := f_calc_parity("0010101111101"); + --! ~~~ + ------------------------------------------------------------------------------- + function f_calc_parity(data : std_logic_vector; + even_parity : boolean := true) + return std_logic is + begin + if even_parity then + return xor data; + else + return xnor data; + end if; + end function f_calc_parity; + + ------------------------------------------------------------------------------- + --! \brief Calculate parity + --! \param data Data array + --! \param even_parity True = Use even parity (default), false = use odd parity + --! \return Parity bit array + --! + --! Calculate parity (even or odd) of a logic vector array. Returns a one-bit array of parity. + --! + --! **Example use** + --! ~~~ + --! parity_array := f_calc_parity(data_array); + --! ~~~ + ------------------------------------------------------------------------------- + function f_calc_parity(data : t_slv_arr; + even_parity : boolean := true) + return t_slv_arr is + variable v_ret : t_slv_arr(0 to data'length - 1)(0 downto 0); + variable v_idx : integer := 0; + begin + assert data'ascending report "f_calc_parity: data array must be ascending" severity C_SEVERITY; + for i in data'low to data'high loop + if even_parity then + v_ret(v_idx)(0) := xor data(i); + else + v_ret(v_idx)(0) := xnor data(i); + end if; + v_idx := v_idx + 1; + end loop; + return v_ret; + end function f_calc_parity; + + ------------------------------------------------------------------------------- + --! \brief Encode data array + --! \param data Data array + --! \param extra_parity Add extra parity bit (default=false) + --! \return Encoded data array pointer + --! + --! Encode data with a Hamming encoder. The returned pointer should be deallocated after use to avoid memory leaks. + --! The encoded data is non-systematic (data and parity bits mixed). + --! + --! **Example use** + --! ~~~ + --! encoded_data_ptr := f_hamming_enc(data); + --! ~~~ + ------------------------------------------------------------------------------- + impure function f_hamming_enc(data : t_slv_arr; + extra_parity : boolean := false) + return t_slv_arr_ptr is + variable v_r : integer; + variable v_m : integer := data(data'low)'length; + variable v_rtot : integer; + variable v_res : t_slv_arr_ptr; + variable v_par : std_logic_vector(data(data'low)'length downto 0); + variable v_didx : integer; + variable v_pidx : integer; + variable v_parity : integer; + variable v_2pj : unsigned(30 downto 0); + begin + assert data'ascending report "f_hamming_enc: data array must be ascending" severity C_SEVERITY; + assert data(data'low)'ascending = false report "f_hamming_enc: input data bits must be descending" severity C_SEVERITY; + -- calculate number of parity bits + v_r := f_calc_num_bits(data); + -- allocate output array + v_rtot := v_m + v_r; + if extra_parity then + v_rtot := v_rtot + 1; + end if; + v_res := new t_slv_arr(data'low to data'high)(v_rtot - 1 downto 0); + -- encode data + for i in data'range loop + -- put data in right positions + v_didx := 0; + v_pidx := 0; + for j in 0 to v_m + v_r - 1 loop + if j + 1 = 2**v_pidx then -- parity bit position + v_res(i)(j) := '0'; + v_pidx := v_pidx + 1; + else + v_res(i)(j) := data(i)(v_didx); + v_didx := v_didx + 1; + end if; + end loop; + -- calculate parity bits + v_par(v_r - 1 downto 0) := f_calc_hamming_bits(v_res(i), v_r, extra_parity); + for j in 0 to v_r - 1 loop + v_res(i)(2**j - 1) := v_par(j); + end loop; + -- extra parity bit + if extra_parity then + v_res(i)(v_rtot - 1) := f_calc_parity(v_res(i)(v_rtot - 2 downto 0), true); + end if; + end loop; + + return v_res; + end function f_hamming_enc; + + ------------------------------------------------------------------------------- + --! \brief Encode data array + --! \param data Data array + --! \param extra_parity Add extra parity bit (default=false) + --! \return Encoded data array + --! + --! Encode data with a Hamming encoder. Same as above, but returns a data array instead of pointer. + --! + --! **Example use** + --! ~~~ + --! encoded_data := f_hamming_enc(data, true); + --! ~~~ + ------------------------------------------------------------------------------- + impure function f_hamming_enc(data : t_slv_arr; + extra_parity : boolean := false) + return t_slv_arr is + variable v_ptr : t_slv_arr_ptr; + begin + v_ptr := f_hamming_enc(data, extra_parity); + + return v_ptr.all; + end function f_hamming_enc; + + ------------------------------------------------------------------------------- + --! \brief Get encoded data width + --! \param data Data array + --! \param extra_parity Add extra parity bit (default=false) + --! \return Encoded data array width + --! + --! Get encoded data width. The encoded data width is the sum of data bits in input data and the number of parity bits required. + --! + --! **Example use** + --! ~~~ + --! edata_width := f_hamming_enc_width(data); + --! ~~~ + ------------------------------------------------------------------------------- + function f_hamming_enc_width(data : t_slv_arr; + extra_parity : boolean := false) + return natural is + variable v_r : natural; + variable v_m : integer := data(data'low)'length; + begin + -- calculate number of parity bits + v_r := f_calc_num_bits(data); + if extra_parity then + v_r := v_r + 1; + end if; + + return v_r + v_m; + end function f_hamming_enc_width; + + ------------------------------------------------------------------------------- + --! \brief Decode data array + --! \param data Encoded data array + --! \param extra_parity Has extra parity bit (default=false) + --! \return Pointer to decoded data array with status + --! + --! Decode data with a Hamming decoder. The returned pointer should be deallocated after use to avoid memory leaks. + --! If input data does not have extra parity bit, single errors will be corrected, and one extra status bit is added + --! to decoded data to indicate positions where correction has been made. + --! If input data have extra parity bit, two errors can be detected and one error corrected. This is indicated with two status bits, + --! the first indicates single error correction, and the last double error detection. + --! + --! **Example use** + --! ~~~ + --! decoded_data_ptr := f_hamming_dec(data, true); + --! decoded_data := decoded_data_ptr.all; + --! v_statpos := decoded_data(0)'high; + --! for i in decoded_data'range loop + --! if decoded_data(i)(v_statpos) = '1' then -- double error detected + --! ... + --! elsif decoded_data(i)(v_statpos - 1) = '1' then -- sigle error corrected + --! ... + --! end if; + --! end loop; + --! -- deallocate the array when finished + --! deallocate(decoded_data_ptr); + --! ~~~ + ------------------------------------------------------------------------------- + impure function f_hamming_dec(data : t_slv_arr; + extra_parity : boolean := false) + return t_slv_arr_ptr is + variable v_r : integer; + variable v_n : integer; + variable v_rs : integer; + variable v_m : integer := data(data'low)'length; + variable v_par : std_logic_vector(v_m downto 0); + variable v_dec : t_slv_arr_ptr; + variable v_didx : integer; + variable v_pidx : integer; + variable v_syn : integer; + variable v_data : std_logic_vector(v_m - 1 downto 0); + variable v_eparity : std_logic; + variable v_end : integer := 1; + begin + assert data'ascending report "f_hamming_dec: data array must be ascending" severity C_SEVERITY; + assert data(data'low)'ascending = false report "f_hamming_dec: input data bits must be descending" severity C_SEVERITY; + + -- determine the width of the decoded data array with status bits + v_rs := f_hamming_dec_width(data, extra_parity); + -- determin how many hamming parity bits were used + v_r := f_calc_num_bits_dec(v_m); + -- determine original data width + v_n := v_m - f_calc_num_bits_dec(v_m); + if extra_parity then + v_n := v_n - 1; + end if; + -- allocate data array for decoded data + v_dec := new t_slv_arr(data'low to data'high)(v_rs - 1 downto 0); + -- decode data + for i in data'range loop + v_data := data(i); + -- calculate hamming parity bits + v_par(v_r - 1 downto 0) := f_calc_hamming_bits(v_data, v_r, extra_parity); + -- check parity and correct if possible + v_dec(i)(v_rs - 1) := '0'; + v_syn := to_integer(unsigned(v_par(v_r - 1 downto 0))); -- syndrome + + if extra_parity then + v_end := 2; + v_dec(i)(v_rs - 2) := '0'; + v_eparity := f_calc_parity(v_data); + if v_syn > 0 then + if v_eparity = '0' then -- double error detected + v_dec(i)(v_rs - 1) := '1'; + elsif v_syn <= v_m - 1 then -- single bit error can be corrected + v_dec(i)(v_rs - 2) := '1'; + v_data(v_syn - 1) := not v_data(v_syn - 1); + end if; + end if; + else + if v_syn > 0 then -- error detected + v_dec(i)(v_rs - 1) := '1'; + if v_syn <= v_m then -- single bit error can be corrected + v_data(v_syn - 1) := not v_data(v_syn - 1); + end if; + end if; + end if; + -- extract data vector + v_didx := 0; + v_pidx := 0; + for j in 0 to v_m - v_end loop + if j + 1 = 2**v_pidx then -- parity bit position + v_pidx := v_pidx + 1; + else + v_dec(i)(v_didx) := v_data(j); + v_didx := v_didx + 1; + end if; + end loop; + end loop; + + return v_dec; + end function f_hamming_dec; + + ------------------------------------------------------------------------------- + --! \brief Decode data array + --! \param data Encoded data array + --! \param extra_parity Has extra parity bit (default=false) + --! \return Decoded data array with status + --! + --! Decode data with a Hamming decoder. Same as above, but returns a data array instead of pointer. + --! + --! **Example use** + --! ~~~ + --! decoded_data := f_hamming_dec(data, true); + --! ~~~ + ------------------------------------------------------------------------------- + impure function f_hamming_dec(data : t_slv_arr; + extra_parity : boolean := false) + return t_slv_arr is + variable v_ptr : t_slv_arr_ptr; + begin + v_ptr := f_hamming_dec(data, extra_parity); + + return v_ptr.all; + end function f_hamming_dec; + + ------------------------------------------------------------------------------- + --! \brief Get decoded data width + --! \param data Encoded data array + --! \param extra_parity Use extra parity bit (default=false) + --! \return Width of decoded data including status bits + --! + --! Get decoded data width, which is the original data width plus one or two status bits. + --! + --! **Example use** + --! ~~~ + --! data_width := f_hamming_dec_width(data, true); + --! ~~~ + ------------------------------------------------------------------------------- + function f_hamming_dec_width(data : t_slv_arr; + extra_parity : boolean := false) + return natural is + variable v_r : natural; + variable v_m : integer; + variable v_org : integer := data(data'low)'length; + begin + -- calculate number of parity bits that was used to encode data + if extra_parity then + v_r := f_calc_num_bits_dec(v_org - 1); + else + v_r := f_calc_num_bits_dec(v_org); + end if; + -- calculate size of decoded array (including extra status bit(s)) + v_m := v_org - v_r + 1; + + return v_m; + end function f_hamming_dec_width; + + +end package body nw_hamming_pkg; diff --git a/nw_codec/src/nw_sl_codec_pkg.vhd b/nw_codec/src/nw_sl_codec_pkg.vhd index f2c7f58..a4beada 100644 --- a/nw_codec/src/nw_sl_codec_pkg.vhd +++ b/nw_codec/src/nw_sl_codec_pkg.vhd @@ -53,6 +53,7 @@ context nw_util.nw_util_context; --! \li \subpage nw_cobs --! \li \subpage nw_base --! \li \subpage nw_bstuff +--! \li \subpage nw_hamming --! --! \n More details in \ref nw_sl_codec_pkg --! \subsection sl_codec_subsec2 Example use diff --git a/nw_codec/tb/nw_codec_tb.vhd b/nw_codec/tb/nw_codec_tb.vhd index 308af31..caca2bf 100644 --- a/nw_codec/tb/nw_codec_tb.vhd +++ b/nw_codec/tb/nw_codec_tb.vhd @@ -64,7 +64,8 @@ architecture behav of nw_codec_tb is (word => x"e", code => (others => "0010110")), (word => x"f", code => (others => "1111111"))); - constant C_TEST1 : t_slv_arr(0 to 10)(7 downto 0) := (x"01", x"01", x"01", x"05", x"01", x"01", x"01", x"01", x"01", x"01", x"01"); + constant C_TEST1 : t_slv_arr(0 to 10)(7 downto 0) := (x"01", x"01", x"01", x"05", x"01", x"01", x"01", x"01", x"01", x"01", x"01"); + constant C_TEST5_3 : t_slv_arr(0 to 15)(7 downto 0) := (x"00", x"87", x"99", x"1e", x"aa", x"2d", x"33", x"b4", x"4b", x"cc", x"d2", x"55", x"e1", x"66", x"78", x"ff"); begin @@ -87,11 +88,25 @@ begin variable v_data_1bit : t_slv_arr(0 to 255)(0 downto 0); variable v_data4 : t_slv_arr(0 to 15)(7 downto 0) := (x"00", x"67", x"7e", x"80", x"7d", x"7e", x"fe", x"7d", x"45", x"5e", x"5d", x"7d", x"5d", x"ac", x"e1", x"01"); - variable v_dec3 : t_slv_arr(0 to 15)(7 downto 0); + variable v_dec3 : t_slv_arr(0 to 15)(7 downto 0); + variable v_ptr : t_slv_arr_ptr; + variable v_data4enc : t_slv_arr(0 to 15)(11 downto 0); + variable v_data4dec : t_slv_arr(0 to 15)(8 downto 0); + variable v_h74 : t_slv_arr(0 to 0)(6 downto 0); + variable v_h84 : t_slv_arr(0 to 0)(7 downto 0); + variable v_tmp : t_slv_arr(0 to 0)(3 downto 0); + + variable v_par : t_slv_arr(0 to 15)(3 downto 0); + variable v_tmp2 : std_logic_vector(11 downto 0); + variable v_pass : boolean; + variable v_data_17bit : t_slv_arr(0 to 31)(16 downto 0); + variable v_data_23bit : t_slv_arr(0 to 31)(22 downto 0); + variable v_data_19bit : t_slv_arr(0 to 31)(18 downto 0); begin wait for 0.747 ns; + ------------------------------------------------------------------------------- -- nw_sl_codec_pkg functions ------------------------------------------------------------------------------- @@ -274,6 +289,113 @@ begin assert v_dec3(0 to 15) = v_data4(0 to 15) report "Test 4.3 failed" severity failure; + ------------------------------------------------------------------------------- + -- nw_hamming_pkg functions + ------------------------------------------------------------------------------- + msg("Part 5: Verify nw_hamming_pkg functions"); + + v_elen := f_hamming_enc_width(v_data4, false); + assert v_elen = 12 + report "Test 5.1 failed" severity failure; + + v_data4enc := f_hamming_enc(v_data4, false); + v_ptr := f_hamming_enc(v_data4, false); + assert v_data4enc = v_ptr.all + report "Test 5.2 failed" severity failure; + + -- in long TBs with many calls to f_hamming_enc(), deallocate is recommended to avoind memory leakage + deallocate(v_ptr); + + for i in 0 to 15 loop + v_tmp(0) := std_logic_vector(to_unsigned(i, 4)); + v_h74 := f_hamming_enc(v_tmp, false); + assert v_h74(0) = C_TEST5_3(i)(6 downto 0) + report "Test 5.3a failed" severity failure; + + v_h84 := f_hamming_enc(v_tmp, true); + assert v_h84(0) = C_TEST5_3(i) + report "Test 5.3b failed" severity failure; + wait for 1 ns; + end loop; + + v_dlen := f_hamming_dec_width(v_h74, false); + assert v_dlen = 5 + report "Test 5.4a failed" severity failure; + + v_dlen := f_hamming_dec_width(C_TEST5_3, true); + assert v_dlen = 6 + report "Test 5.4b failed" severity failure; + + wait for 5.42 ns; + + -- insert single bit errors in array with no extra parity bit + for i in 0 to 11 loop + v_data4enc(i)(i) := not v_data4enc(i)(i); + end loop; + v_data4dec := f_hamming_dec(v_data4enc, false); + v_pass := true; + for i in 0 to 15 loop + if i < 12 then -- check parity status bit + if v_data4dec(i)(8) = '0' then + v_pass := false; + end if; + else + if v_data4dec(i)(8) = '1' then + v_pass := false; + end if; + end if; + if v_data4dec(i)(7 downto 0) /= v_data4(i) then + v_pass := false; + end if; + end loop; + assert v_pass + report "Test 5.5 failed" severity failure; + + -- insert double bit errors in array with extra parity bit + v_data_17bit := f_gen_prbs(C_POLY_X17_X14_1, 17, 32, C_MSB_FIRST, "11111111111111111"); -- random data + v_elen := f_hamming_enc_width(v_data_17bit, true); + assert v_elen = 23 + report "Test 5.5 failed" severity failure; + + v_data_23bit := f_hamming_enc(v_data_17bit, true); -- encode + v_dlen := f_hamming_dec_width(v_data_23bit, true); + assert v_dlen = 19 + report "Test 5.6 failed" severity failure; + + for i in 0 to 21 loop -- double errors + v_data_23bit(i)(i) := not v_data_23bit(i)(i); + v_data_23bit(i)(i+1) := not v_data_23bit(i)(i+1); + end loop; + for i in 23 to 31 loop -- single errors + v_data_23bit(i)(i - 20) := not v_data_23bit(i)(i - 20); + end loop; + + v_data_19bit := f_hamming_dec(v_data_23bit, true); -- decode + v_pass := true; + for i in 0 to 31 loop + if i < 22 then -- double errors + if v_data_19bit(i)(18 downto 17) /= "10" then + v_pass := false; + end if; + elsif i = 22 then -- no error + if v_data_19bit(i)(18 downto 17) /= "00" then + v_pass := false; + end if; + if v_data_17bit(i) /= v_data_19bit(i)(16 downto 0) then + v_pass := false; + end if; + else -- single errors + if v_data_19bit(i)(18 downto 17) /= "01" then + v_pass := false; + end if; + if v_data_17bit(i) /= v_data_19bit(i)(16 downto 0) then + v_pass := false; + end if; + end if; + end loop; + assert v_pass + report "Test 5.7 failed" severity failure; + wait for 100 ns; -- Finish the simulation msg("All tests are pass!"); diff --git a/nw_util/src/nw_types_pkg.vhd b/nw_util/src/nw_types_pkg.vhd index 0da3137..245a366 100644 --- a/nw_util/src/nw_types_pkg.vhd +++ b/nw_util/src/nw_types_pkg.vhd @@ -42,6 +42,7 @@ package nw_types_pkg is -- Types ------------------------------------------------------------------------------- type t_slv_arr is array (natural range <>) of std_logic_vector; --! Array of std_logic_vector is the primary data type + type t_slv_arr_ptr is access t_slv_arr; --! Pointer to t_slv_arr type t_unsigned_arr is array (natural range <>) of unsigned; --! Array of unsigned end package nw_types_pkg; diff --git a/script/ghdl_run_all.sh b/script/ghdl_run_all.sh index 4107856..1ae1083 100644 --- a/script/ghdl_run_all.sh +++ b/script/ghdl_run_all.sh @@ -80,6 +80,7 @@ ghdl -a --std=08 -frelaxed-rules --work=nw_codec ../nw_codec/src/nw_sl_codec_pkg ghdl -a --std=08 -frelaxed-rules --work=nw_codec ../nw_codec/src/nw_cobs_pkg.vhd ghdl -a --std=08 -frelaxed-rules --work=nw_codec ../nw_codec/src/nw_base_pkg.vhd ghdl -a --std=08 -frelaxed-rules --work=nw_codec ../nw_codec/src/nw_bitstuff_pkg.vhd +ghdl -a --std=08 -frelaxed-rules --work=nw_codec ../nw_codec/src/nw_hamming_pkg.vhd ghdl -a --std=08 -frelaxed-rules --work=nw_codec ../nw_codec/src/nw_codec_context.vhd ghdl -a --std=08 -frelaxed-rules --work=work ../nw_codec/tb/nw_codec_tb.vhd ghdl -e --std=08 -frelaxed-rules --work=work nw_codec_tb diff --git a/script/modelsim_run_all.do b/script/modelsim_run_all.do index 086804d..b81dacc 100644 --- a/script/modelsim_run_all.do +++ b/script/modelsim_run_all.do @@ -87,6 +87,7 @@ vcom -2008 -quiet -work ./nw_codec ../nw_codec/src/nw_sl_codec_pkg.vhd vcom -2008 -quiet -work ./nw_codec ../nw_codec/src/nw_cobs_pkg.vhd vcom -2008 -quiet -work ./nw_codec ../nw_codec/src/nw_base_pkg.vhd vcom -2008 -quiet -work ./nw_codec ../nw_codec/src/nw_bitstuff_pkg.vhd +vcom -2008 -quiet -work ./nw_codec ../nw_codec/src/nw_hamming_pkg.vhd vcom -2008 -quiet -work ./nw_codec ../nw_codec/src/nw_codec_context.vhd vcom -2008 -quiet -work ./work ../nw_codec/tb/nw_codec_tb.vhd vsim -quiet -c nw_codec_tb -do "onerror {quit -code 1}; run -all"