From 447896fb55b14585362b166b8413a3c2c42cf922 Mon Sep 17 00:00:00 2001 From: Geir Date: Wed, 20 Sep 2023 20:25:54 +0200 Subject: [PATCH 1/5] Hamming encoder --- nw_codec/src/nw_codec_context.vhd | 1 + nw_codec/src/nw_hamming_pkg.vhd | 293 ++++++++++++++++++++++++++++++ nw_codec/src/nw_sl_codec_pkg.vhd | 5 - nw_codec/tb/nw_codec_tb.vhd | 33 ++++ nw_util/src/nw_types_pkg.vhd | 1 + readme.md | 5 +- script/ghdl_run_all.sh | 1 + script/modelsim_run_all.do | 1 + 8 files changed, 333 insertions(+), 7 deletions(-) create mode 100644 nw_codec/src/nw_hamming_pkg.vhd 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..5bba0d5 --- /dev/null +++ b/nw_codec/src/nw_hamming_pkg.vhd @@ -0,0 +1,293 @@ +------------------------------------------------------------------------------- +-- 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 Codec library +--! \tableofcontents +--! \section codec Hamming codec +--! This library provides functions for Hamming encoding and decoding. +--! 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. +--! Position of the parity bits are given by 2^p, p ∈ [0, r). +--! +--! \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: +--! +--! 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; + + function f_hamming_enc(data : t_slv_arr; + extra_parity: boolean := False) return t_slv_arr; + + 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; + + -- function f_sl_dec(data : t_slv_arr; + -- codec : t_codec) return t_slv_arr; + + -- function f_sl_dec_len (data : t_slv_arr; + -- codec : t_codec) return natural; + +end package nw_hamming_pkg; + +package body nw_hamming_pkg is + + ------------------------------------------------------------------------------- + -- Calculate number of parity bits (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; + + ------------------------------------------------------------------------------- + --! \brief Caclulate 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 Caclulate 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 + --! \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. + --! + --! **Example use** + --! ~~~ + --! encoded_data_ptr := f_hamming_enc(data, true); + --! ~~~ + ------------------------------------------------------------------------------- + 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_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 words 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); + -- process data + for i in data'range loop + -- put data in right positions + v_didx := 0; + v_pidx := 0; + for j in 0 to v_rtot - 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 + for j in 0 to v_r - 1 loop + v_parity := 0; + for k in 2**j to v_rtot - 1 loop + v_2pj := to_unsigned(2**j, 31); + if (to_unsigned(k+1, 31) and v_2pj) = v_2pj then + if v_res(i)(k) = '1' then + v_parity := v_parity + 1; + end if; + end if; + end loop; + if v_parity mod 2 = 1 then + v_res(i)(2**j - 1) := '1'; + end if; + 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 + --! \param data Data array + --! \param extra_parity Add extra parity bit (default=false) + --! \return Encoded data array + --! + --! Encode data with a Hamming encoder. + --! + --! **Example use** + --! ~~~ + --! encoded_data := f_hamming_enc(data, true); + --! ~~~ + ------------------------------------------------------------------------------- + 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 + --! + --! Get encoded data with. + --! + --! **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; + + +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..30d5adf 100644 --- a/nw_codec/src/nw_sl_codec_pkg.vhd +++ b/nw_codec/src/nw_sl_codec_pkg.vhd @@ -49,11 +49,6 @@ context nw_util.nw_util_context; --! \li Perform data word stuffing (replace specific words with an escape sequence) --! \li Encode data words from lookup table --! ---! Other libraries in Codec are: ---! \li \subpage nw_cobs ---! \li \subpage nw_base ---! \li \subpage nw_bstuff ---! --! \n More details in \ref nw_sl_codec_pkg --! \subsection sl_codec_subsec2 Example use --! Include the libraries: diff --git a/nw_codec/tb/nw_codec_tb.vhd b/nw_codec/tb/nw_codec_tb.vhd index 308af31..c85ce7d 100644 --- a/nw_codec/tb/nw_codec_tb.vhd +++ b/nw_codec/tb/nw_codec_tb.vhd @@ -65,6 +65,7 @@ architecture behav of nw_codec_tb is (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_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 @@ -88,10 +89,42 @@ begin 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_ptr : t_slv_arr_ptr; + variable v_data4enc: t_slv_arr(0 to 15)(11 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); + + begin wait for 0.747 ns; + ------------------------------------------------------------------------------- + -- 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; + + 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; + ------------------------------------------------------------------------------- -- nw_sl_codec_pkg functions ------------------------------------------------------------------------------- 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/readme.md b/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/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" From 4b3cd58235cc515b298c30e1730ab261a1384f24 Mon Sep 17 00:00:00 2001 From: Geir Date: Fri, 13 Oct 2023 18:26:33 +0200 Subject: [PATCH 2/5] Hamming encoder finished. --- .gitignore | 1 + CHANGELOG.md | 12 +- Doxyfile | 3 +- readme.md => README.md | 0 nw_codec/src/nw_hamming_pkg.vhd | 403 +++++++++++++++++++++++-------- nw_codec/src/nw_sl_codec_pkg.vhd | 6 + nw_codec/tb/nw_codec_tb.vhd | 161 +++++++++--- 7 files changed, 446 insertions(+), 140 deletions(-) rename readme.md => README.md (100%) 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..72a408c 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] - + +### 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/Doxyfile b/Doxyfile index e3be6cd..6ca45ff 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1019,7 +1019,8 @@ RECURSIVE = YES # run. EXCLUDE = docs \ - html + html \ + CHANGELOG.md # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/readme.md b/README.md similarity index 100% rename from readme.md rename to README.md diff --git a/nw_codec/src/nw_hamming_pkg.vhd b/nw_codec/src/nw_hamming_pkg.vhd index 5bba0d5..9e3b9d6 100644 --- a/nw_codec/src/nw_hamming_pkg.vhd +++ b/nw_codec/src/nw_hamming_pkg.vhd @@ -40,11 +40,11 @@ library nw_util; context nw_util.nw_util_context; --! @endcond ---! \page nw_hamming Codec library +--! \page nw_hamming Hamming codec --! \tableofcontents ---! \section codec Hamming codec ---! This library provides functions for Hamming encoding and decoding. ---! Single error correction/double error detection (SECDED) +--! \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 @@ -52,7 +52,8 @@ context nw_util.nw_util_context; --! \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. ---! Position of the parity bits are given by 2^p, p ∈ [0, r). +--! 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 @@ -69,49 +70,104 @@ 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 : 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; + function f_calc_parity(data : t_slv_arr; + even_parity : boolean := true) return t_slv_arr; - function f_hamming_enc(data : t_slv_arr; - extra_parity: boolean := False) return t_slv_arr; + function f_hamming_enc(data : t_slv_arr; + extra_parity : boolean := false) return t_slv_arr; - function f_hamming_enc(data : t_slv_arr; - extra_parity: boolean := False) return t_slv_arr_ptr; + 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; + function f_hamming_enc_width(data : t_slv_arr; + extra_parity : boolean := false) return natural; - -- function f_sl_dec(data : t_slv_arr; - -- codec : t_codec) return t_slv_arr; + function f_hamming_dec(data : t_slv_arr; + extra_parity : boolean := false) return t_slv_arr; - -- function f_sl_dec_len (data : t_slv_arr; - -- codec : t_codec) return natural; + 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 (internal) + -- Calculate number of parity bits during encoding (internal) ------------------------------------------------------------------------------- - function f_calc_num_bits(data : t_slv_arr) + 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; + 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; + 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 Caclulate parity + --! \brief Calculate parity --! \param data Data vector --! \param even_parity True = Use even parity (default), false = use odd parity --! \return Parity bit @@ -123,19 +179,19 @@ package body nw_hamming_pkg is --! parity := f_calc_parity("0010101111101"); --! ~~~ ------------------------------------------------------------------------------- - function f_calc_parity(data: std_logic_vector; - even_parity: boolean := true) + 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; + begin + if even_parity then + return xor data; + else + return xnor data; + end if; + end function f_calc_parity; ------------------------------------------------------------------------------- - --! \brief Caclulate parity + --! \brief Calculate parity --! \param data Data array --! \param even_parity True = Use even parity (default), false = use odd parity --! \return Parity bit array @@ -147,26 +203,26 @@ package body nw_hamming_pkg is --! parity_array := f_calc_parity(data_array); --! ~~~ ------------------------------------------------------------------------------- - function f_calc_parity(data: t_slv_arr; - even_parity: boolean := true) + 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; + 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 + --! \brief Encode data array --! \param data Data array --! \param extra_parity Add extra parity bit (default=false) --! \return Encoded data array pointer @@ -178,68 +234,59 @@ package body nw_hamming_pkg is --! encoded_data_ptr := f_hamming_enc(data, true); --! ~~~ ------------------------------------------------------------------------------- - function f_hamming_enc(data : t_slv_arr; - extra_parity: boolean := False) + 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_didx : integer; - variable v_pidx : integer; - variable v_parity : integer; - variable v_2pj: unsigned(30 downto 0); + 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 words must be descending" 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); + 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); - -- process data + -- 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_rtot - 1 loop - if j + 1 = 2**v_pidx then -- parity bit position + 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; + v_pidx := v_pidx + 1; else v_res(i)(j) := data(i)(v_didx); - v_didx := v_didx + 1; + 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_parity := 0; - for k in 2**j to v_rtot - 1 loop - v_2pj := to_unsigned(2**j, 31); - if (to_unsigned(k+1, 31) and v_2pj) = v_2pj then - if v_res(i)(k) = '1' then - v_parity := v_parity + 1; - end if; - end if; - end loop; - if v_parity mod 2 = 1 then - v_res(i)(2**j - 1) := '1'; - end if; + 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 + --! \brief Encode data array --! \param data Data array --! \param extra_parity Add extra parity bit (default=false) --! \return Encoded data array @@ -251,37 +298,37 @@ package body nw_hamming_pkg is --! encoded_data := f_hamming_enc(data, true); --! ~~~ ------------------------------------------------------------------------------- - function f_hamming_enc(data : t_slv_arr; - extra_parity: boolean := False) + 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); + 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; + 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 + --! \return Encoded data array width --! - --! Get encoded data with. + --! Get encoded data width. --! --! **Example use** --! ~~~ --! edata_width := f_hamming_enc_width(data); --! ~~~ ------------------------------------------------------------------------------- - function f_hamming_enc_width(data : t_slv_arr; - extra_parity: boolean := False) + 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; + 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); + v_r := f_calc_num_bits(data); if extra_parity then v_r := v_r + 1; end if; @@ -289,5 +336,161 @@ package body nw_hamming_pkg is 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); + --! ~~~ + ------------------------------------------------------------------------------- + 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. + --! + --! **Example use** + --! ~~~ + --! decoded_data := f_hamming_dec(data, true); + --! ~~~ + ------------------------------------------------------------------------------- + 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. + --! + --! **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 30d5adf..a4beada 100644 --- a/nw_codec/src/nw_sl_codec_pkg.vhd +++ b/nw_codec/src/nw_sl_codec_pkg.vhd @@ -49,6 +49,12 @@ context nw_util.nw_util_context; --! \li Perform data word stuffing (replace specific words with an escape sequence) --! \li Encode data words from lookup table --! +--! Other libraries in Codec are: +--! \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 --! Include the libraries: diff --git a/nw_codec/tb/nw_codec_tb.vhd b/nw_codec/tb/nw_codec_tb.vhd index c85ce7d..e314ad0 100644 --- a/nw_codec/tb/nw_codec_tb.vhd +++ b/nw_codec/tb/nw_codec_tb.vhd @@ -64,8 +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_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"); + 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 @@ -86,44 +86,26 @@ begin variable v_init : std_logic_vector(31 downto 0) := x"ffffffff"; variable v_str : string(1 to 16); 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_ptr : t_slv_arr_ptr; - variable v_data4enc: t_slv_arr(0 to 15)(11 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_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_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_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; - - 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; ------------------------------------------------------------------------------- -- nw_sl_codec_pkg functions @@ -307,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!"); From 731c257b148c900300ee25b57ded2e4301fdc943 Mon Sep 17 00:00:00 2001 From: Geir Date: Fri, 13 Oct 2023 19:14:45 +0200 Subject: [PATCH 3/5] Add documentation. Closes #23 --- CHANGELOG.md | 2 +- Doxyfile | 3 +-- nw_codec/src/nw_hamming_pkg.vhd | 35 ++++++++++++++++++++++++++------- nw_codec/tb/nw_codec_tb.vhd | 4 ++-- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72a408c..8381a2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ 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] - +## [1.3.0] - 2023-10-13 ### Added - nw_codec: Hamming encoder/decoder, odd/even parity function diff --git a/Doxyfile b/Doxyfile index 6ca45ff..e3be6cd 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1019,8 +1019,7 @@ RECURSIVE = YES # run. EXCLUDE = docs \ - html \ - CHANGELOG.md + html # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded diff --git a/nw_codec/src/nw_hamming_pkg.vhd b/nw_codec/src/nw_hamming_pkg.vhd index 9e3b9d6..a22bbf1 100644 --- a/nw_codec/src/nw_hamming_pkg.vhd +++ b/nw_codec/src/nw_hamming_pkg.vhd @@ -62,8 +62,26 @@ context nw_util.nw_util_context; --! library nw_codec; --! context nw_codec.nw_codec_context; --! ~~~ ---! Example 1: ---! +--! 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 @@ -228,10 +246,11 @@ package body nw_hamming_pkg is --! \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, true); + --! encoded_data_ptr := f_hamming_enc(data); --! ~~~ ------------------------------------------------------------------------------- function f_hamming_enc(data : t_slv_arr; @@ -291,7 +310,7 @@ package body nw_hamming_pkg is --! \param extra_parity Add extra parity bit (default=false) --! \return Encoded data array --! - --! Encode data with a Hamming encoder. + --! Encode data with a Hamming encoder. Same as above, but returns a data array instead of pointer. --! --! **Example use** --! ~~~ @@ -314,7 +333,7 @@ package body nw_hamming_pkg is --! \param extra_parity Add extra parity bit (default=false) --! \return Encoded data array width --! - --! Get encoded data 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** --! ~~~ @@ -355,7 +374,9 @@ package body nw_hamming_pkg is --! 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 @@ -443,7 +464,7 @@ package body nw_hamming_pkg is --! \param extra_parity Has extra parity bit (default=false) --! \return Decoded data array with status --! - --! Decode data with a Hamming decoder. + --! Decode data with a Hamming decoder. Same as above, but returns a data array instead of pointer. --! --! **Example use** --! ~~~ @@ -466,7 +487,7 @@ package body nw_hamming_pkg is --! \param extra_parity Use extra parity bit (default=false) --! \return Width of decoded data including status bits --! - --! Get decoded data width. + --! Get decoded data width, which is the original data width plus one or two status bits. --! --! **Example use** --! ~~~ diff --git a/nw_codec/tb/nw_codec_tb.vhd b/nw_codec/tb/nw_codec_tb.vhd index e314ad0..caca2bf 100644 --- a/nw_codec/tb/nw_codec_tb.vhd +++ b/nw_codec/tb/nw_codec_tb.vhd @@ -86,8 +86,8 @@ begin variable v_init : std_logic_vector(31 downto 0) := x"ffffffff"; variable v_str : string(1 to 16); 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_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_ptr : t_slv_arr_ptr; variable v_data4enc : t_slv_arr(0 to 15)(11 downto 0); From 7a8049deb287ad7e8862bf8e64a910d53b7fafc6 Mon Sep 17 00:00:00 2001 From: Geir Date: Fri, 13 Oct 2023 19:23:18 +0200 Subject: [PATCH 4/5] Define impure functions returning pointer. --- nw_codec/src/nw_hamming_pkg.vhd | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nw_codec/src/nw_hamming_pkg.vhd b/nw_codec/src/nw_hamming_pkg.vhd index a22bbf1..d3dc0c7 100644 --- a/nw_codec/src/nw_hamming_pkg.vhd +++ b/nw_codec/src/nw_hamming_pkg.vhd @@ -97,8 +97,8 @@ package nw_hamming_pkg is function f_hamming_enc(data : t_slv_arr; extra_parity : boolean := false) return t_slv_arr; - function f_hamming_enc(data : t_slv_arr; - extra_parity : boolean := false) return t_slv_arr_ptr; + 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; @@ -106,8 +106,8 @@ package nw_hamming_pkg is function f_hamming_dec(data : t_slv_arr; extra_parity : boolean := false) return t_slv_arr; - function f_hamming_dec(data : t_slv_arr; - extra_parity : boolean := false) return t_slv_arr_ptr; + 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; @@ -253,8 +253,8 @@ package body nw_hamming_pkg is --! encoded_data_ptr := f_hamming_enc(data); --! ~~~ ------------------------------------------------------------------------------- - function f_hamming_enc(data : t_slv_arr; - extra_parity : boolean := false) + 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; @@ -383,8 +383,8 @@ package body nw_hamming_pkg is --! deallocate(decoded_data_ptr); --! ~~~ ------------------------------------------------------------------------------- - function f_hamming_dec(data : t_slv_arr; - extra_parity : boolean := false) + 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; From 08a16b484689f3208ad893df55da135cbb711560 Mon Sep 17 00:00:00 2001 From: Geir Date: Fri, 13 Oct 2023 19:25:22 +0200 Subject: [PATCH 5/5] Define more impure functions. --- nw_codec/src/nw_hamming_pkg.vhd | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nw_codec/src/nw_hamming_pkg.vhd b/nw_codec/src/nw_hamming_pkg.vhd index d3dc0c7..6b57a28 100644 --- a/nw_codec/src/nw_hamming_pkg.vhd +++ b/nw_codec/src/nw_hamming_pkg.vhd @@ -94,8 +94,8 @@ package nw_hamming_pkg is function f_calc_parity(data : t_slv_arr; even_parity : boolean := true) return t_slv_arr; - 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; impure function f_hamming_enc(data : t_slv_arr; extra_parity : boolean := false) return t_slv_arr_ptr; @@ -103,8 +103,8 @@ package nw_hamming_pkg is function f_hamming_enc_width(data : t_slv_arr; extra_parity : boolean := false) return natural; - 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; impure function f_hamming_dec(data : t_slv_arr; extra_parity : boolean := false) return t_slv_arr_ptr; @@ -317,8 +317,8 @@ package body nw_hamming_pkg is --! encoded_data := f_hamming_enc(data, true); --! ~~~ ------------------------------------------------------------------------------- - function f_hamming_enc(data : t_slv_arr; - extra_parity : boolean := false) + 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 @@ -471,8 +471,8 @@ package body nw_hamming_pkg is --! decoded_data := f_hamming_dec(data, true); --! ~~~ ------------------------------------------------------------------------------- - function f_hamming_dec(data : t_slv_arr; - extra_parity : boolean := false) + 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