Skip to content

Commit

Permalink
Add bit-stuffing codec library.
Browse files Browse the repository at this point in the history
  • Loading branch information
geddy11 committed Feb 25, 2023
1 parent 607b131 commit a7b2ddc
Show file tree
Hide file tree
Showing 7 changed files with 323 additions and 15 deletions.
281 changes: 281 additions & 0 deletions nw_codec/src/nw_bitstuff_pkg.vhd
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
-------------------------------------------------------------------------------
-- Title : Network Wizard Bit Stuffing
-- Project : netwiz
-- GitHub : https://github.com/geddy11/netwiz
-- Standard : VHDL'08
-------------------------------------------------------------------------------
-- Description:
--!\file
--!\brief Bit stuffing 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_bstuff Bit stuffing
--! \tableofcontents
--! \section bitstuff Bit Stuffing
--! This library provides functions for bit stuffing.
--!
--! \subsection bstuff_subsec1 Functionality
--! \li Perform bit-stuffing encoding and decoding of 1bit arrays.
--!
--! The bit-stuffing algorithm inserts an extra bit if a sequence of bits with the same value is longer than a specified threshold.
--!
--! \n More details in \ref nw_bitstuff_pkg
--! \subsection bstuff_subsec2 Example use
--! Include the libraries:
--! ~~~
--! library nw_codec;
--! context nw_codec.nw_codec_context;
--! ~~~
--! Example: HDLC-style bit-stuffing. Assume we have a HDLC frame in the variable \c v_data (8bit format). A zero-bit shall be inserted after each sequence of 5 one's.
--! The 8-bit frame is converted to 1-bit with f_repack().
--! ~~~
--! v_len := f_bitstuff_enc_len(f_repack(v_data, 1), 5); -- get length of encoded data (v_data is here 8bit, and is repacked to 1bit)
--! v_encoded(0 to v_len - 1) := f_bitstuff_enc(f_repack(v_data, 1), 5); -- encode
--! ~~~
--! Add FEC (0x7e) before and after the bit-stuffed HDLC frame:
--! ~~~
--! v_encoded(0 to v_len + 15) := f_concat("01111110", f_concat(v_encoded, "01111110")); -- add FEC before and after data frame
--! ~~~
--! Decoding of a bit-stuffed frame:
--! ~~~
--! v_dlen := f_bitstuff_dec_len(v_encoded(0 to v_len - 1)); -- get length of decoded data
--! v_decoded(0 to v_dlen - 1) := f_bitstuff_dec(v_encoded(0 to v_len - 1));
--! ~~~
--! See further examples in the test bench nw_codec_tb.vhd.
package nw_bitstuff_pkg is

-------------------------------------------------------------------------------
-- Functions
-------------------------------------------------------------------------------
function f_bitstuff_enc(data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1') return t_slv_arr;

function f_bitstuff_enc_len (data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1') return natural;

function f_bitstuff_dec(data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1') return t_slv_arr;

function f_bitstuff_dec_len (data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1') return natural;

end package nw_bitstuff_pkg;

package body nw_bitstuff_pkg is

-------------------------------------------------------------------------------
-- Encode data (internal)
-------------------------------------------------------------------------------
function f_bitstuff_enc(data : t_slv_arr;
run_length : positive;
run_type : std_logic;
get_length : boolean := false)
return t_slv_arr is
variable v_data : t_slv_arr(0 to 2 * data'length)(0 downto 0);
variable v_len : natural := 0;
variable v_cnt : natural := 0;
variable v_length : t_slv_arr(0 to 0)(30 downto 0);
begin
assert data'ascending report "f_bitstuff_enc: data array must be ascending" severity C_SEVERITY;
assert data(data'low)'length = 1 report "f_bitstuff_enc: data must be 1bit" severity C_SEVERITY;
assert run_length > 1 report "f_bitstuff_enc: run_length must be > 1" severity C_SEVERITY;

for i in data'low to data'high loop
v_data(v_len) := data(i);
v_len := v_len + 1;
if data(i)(0) = run_type then
v_cnt := v_cnt + 1;
if v_cnt = run_length then
v_data(v_len)(0) := not run_type;
v_len := v_len + 1;
v_cnt := 0;
end if;
else
v_cnt := 0;
end if;
end loop;
if get_length then
v_length(0) := std_logic_vector(to_unsigned(v_len, 31));
return v_length;
else
return v_data(0 to v_len - 1);
end if;
end function f_bitstuff_enc;

-------------------------------------------------------------------------------
--! \brief Encode data
--! \param data Data array (1bit)
--! \param run_length Maximum run length before stuff bit is inserted
--! \param run_type Run-length value (default '1')
--! \return Encoded data
--!
--! Encode data with bit-stuffing. If a sequence of bits with value run_type longer than run_length is enconutered, a stuff bit of inverse value is inserted.
--!
--! **Example use**
--! ~~~
--! encoded_data := f_bitstuff_enc(data_1bit, 5);
--! ~~~
-------------------------------------------------------------------------------
function f_bitstuff_enc(data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1')
return t_slv_arr is
begin
return f_bitstuff_enc(data, run_length, run_type, false);
end function f_bitstuff_enc;

-------------------------------------------------------------------------------
--! \brief Get encoded data length
--! \param data Data array (1bit)
--! \param run_length Maximum run length before stuff bit is inserted
--! \param run_type Run-length value (default '1')
--! \return Encoded data length
--!
--! Get length of encoded data after applying bit stuffing.
--!
--! **Example use**
--! ~~~
--! v_len := f_bitstuff_enc_len(data_1bit, 5);
--! ~~~
-------------------------------------------------------------------------------
function f_bitstuff_enc_len(data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1')
return natural is
variable v_length : t_slv_arr(0 to 0)(30 downto 0);
begin
v_length := f_bitstuff_enc(data, run_length, run_type, true);
return to_integer(unsigned(v_length(0)));
end function f_bitstuff_enc_len;

-------------------------------------------------------------------------------
-- Decode data (internal)
-------------------------------------------------------------------------------
function f_bitstuff_dec(data : t_slv_arr;
run_length : positive;
run_type : std_logic;
get_length : boolean := false)
return t_slv_arr is
variable v_data : t_slv_arr(0 to data'length)(0 downto 0);
variable v_len : natural := 0;
variable v_cnt : natural := 0;
variable v_skip : boolean := false;
variable v_length : t_slv_arr(0 to 0)(30 downto 0);
begin
assert data'ascending report "f_bitstuff_dec: data array must be ascending" severity C_SEVERITY;
assert data(data'low)'length = 1 report "f_bitstuff_dec: data must be 1bit" severity C_SEVERITY;
assert run_length > 1 report "f_bitstuff_dec: run_length must be > 1" severity C_SEVERITY;

for i in data'low to data'high loop
if data(i)(0) = run_type then
v_cnt := v_cnt + 1;
else
v_cnt := 0;
end if;
if not v_skip then
if v_cnt < run_length then
v_data(v_len) := data(i);
v_len := v_len + 1;
v_skip := false;
elsif v_cnt = run_length then
v_data(v_len) := data(i);
v_len := v_len + 1;
v_skip := true;
v_cnt := 0;
end if;
else
v_cnt := 0;
v_skip := false;
end if;
end loop;
if get_length then
v_length(0) := std_logic_vector(to_unsigned(v_len, 31));
return v_length;
else
return v_data(0 to v_len - 1);
end if;
end function f_bitstuff_dec;

-------------------------------------------------------------------------------
--! \brief Decode data
--! \param data Data array (1bit)
--! \param run_length Maximum run length before stuff bit is inserted
--! \param run_type Run-length value (default '1')
--! \return Decoded data
--!
--! Decode bit-stuffed data. Remove bits inserted by the encoding process.
--!
--! **Example use**
--! ~~~
--! decoded_data := f_bitstuff_dec(data_1bit, 5);
--! ~~~
-------------------------------------------------------------------------------
function f_bitstuff_dec(data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1')
return t_slv_arr is
begin
return f_bitstuff_dec(data, run_length, run_type, false);
end function f_bitstuff_dec;

-------------------------------------------------------------------------------
--! \brief Get decoded data length
--! \param data Data array (1bit)
--! \param run_length Maximum run length before stuff bit is inserted
--! \param run_type Run-length value (default '1')
--! \return Decoded data length
--!
--! Get length of decoded data after bit stuffing is removed.
--!
--! **Example use**
--! ~~~
--! v_len := f_bitstuff_dec_len(data_1bit, 5);
--! ~~~
-------------------------------------------------------------------------------
function f_bitstuff_dec_len(data : t_slv_arr;
run_length : positive;
run_type : std_logic := '1')
return natural is
variable v_length : t_slv_arr(0 to 0)(30 downto 0);
begin
v_length := f_bitstuff_dec(data, run_length, run_type, true);
return to_integer(unsigned(v_length(0)));
end function f_bitstuff_dec_len;


end package body nw_bitstuff_pkg;
1 change: 1 addition & 0 deletions nw_codec/src/nw_codec_context.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,5 @@ context nw_codec_context is
use nw_codec.nw_sl_codec_pkg.all;
use nw_codec.nw_cobs_pkg.all;
use nw_codec.nw_base_pkg.all;
use nw_codec.nw_bitstuff_pkg.all;
end context nw_codec_context;
1 change: 1 addition & 0 deletions nw_codec/src/nw_sl_codec_pkg.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ context nw_util.nw_util_context;
--! 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
Expand Down
50 changes: 36 additions & 14 deletions nw_codec/tb/nw_codec_tb.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,23 @@ begin
p_main : process
variable v_data : 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_data2 : t_slv_arr(0 to 8)(3 downto 0) := (x"e", x"1", x"6", x"f", x"0", x"b", x"3", x"c", x"2");
variable v_enc2 : t_slv_arr(0 to 8)(6 downto 0);
variable v_elen : natural;
variable v_dlen : natural;
variable v_enc : t_slv_arr(0 to 31)(7 downto 0);
variable v_dec : t_slv_arr(0 to 31)(7 downto 0);
variable v_dec2 : t_slv_arr(0 to 8)(3 downto 0);
variable v_data3 : t_slv_arr(0 to 767)(7 downto 0);
variable v_raw : t_slv_arr(0 to 1023)(7 downto 0);
variable v_cobs_enc : t_slv_arr(0 to 1023)(7 downto 0);
variable v_cobs_dec : t_slv_arr(0 to 1023)(7 downto 0);
variable v_init : std_logic_vector(31 downto 0) := x"ffffffff";
variable v_str : string(1 to 16);

variable v_data2 : t_slv_arr(0 to 8)(3 downto 0) := (x"e", x"1", x"6", x"f", x"0", x"b", x"3", x"c", x"2");
variable v_enc2 : t_slv_arr(0 to 8)(6 downto 0);
variable v_elen : natural;
variable v_dlen : natural;
variable v_enc : t_slv_arr(0 to 31)(7 downto 0);
variable v_dec : t_slv_arr(0 to 31)(7 downto 0);
variable v_dec2 : t_slv_arr(0 to 8)(3 downto 0);
variable v_data3 : t_slv_arr(0 to 767)(7 downto 0);
variable v_raw : t_slv_arr(0 to 1023)(7 downto 0);
variable v_cobs_enc : t_slv_arr(0 to 1023)(7 downto 0);
variable v_cobs_dec : t_slv_arr(0 to 1023)(7 downto 0);
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);

begin
wait for 0.747 ns;
Expand Down Expand Up @@ -252,6 +255,25 @@ begin
assert v_dlen = 15
report "Test 3.34 failed" severity failure;

-------------------------------------------------------------------------------
-- nw_bitstuff_pkg functions
-------------------------------------------------------------------------------
msg("Part 4: Verify nw_bitstuff_pkg functions");

v_elen := f_bitstuff_enc_len(f_repack(v_data4, 1), 5);
assert v_elen = 134
report "Test 4.1 failed" severity failure;

v_data_1bit(0 to v_elen - 1) := f_bitstuff_enc(f_repack(v_data4, 1), 5);

v_dlen := f_bitstuff_dec_len(v_data_1bit(0 to v_elen - 1), 5);
assert v_dlen = 128
report "Test 4.2 failed" severity failure;

v_dec3 := f_repack(f_bitstuff_dec(v_data_1bit(0 to v_elen - 1), 5), 8);
assert v_dec3(0 to 15) = v_data4(0 to 15)
report "Test 4.3 failed" severity failure;

wait for 100 ns;
-- Finish the simulation
msg("All tests are pass!");
Expand Down
3 changes: 2 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/).
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.

Expand All @@ -16,6 +16,7 @@ Netwiz consists of several libraries. Libraries not related to a specific networ
* nw_codec:
* [nw_sl_codec](@ref nw_sl_codec): Stateless generic codec
* [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_pcap:
* [nw_pcap](@ref nw_pcap): Read network packets from PCAP/PCAPNG files (produced by Wireshark, tcmpdump et.al.)
Expand Down
1 change: 1 addition & 0 deletions script/ghdl_run_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ echo -e "\nTesting nw_codec"
ghdl -a --std=08 -frelaxed-rules --work=nw_codec ../nw_codec/src/nw_sl_codec_pkg.vhd
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_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
Expand Down
1 change: 1 addition & 0 deletions script/modelsim_run_all.do
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ vlib nw_codec
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_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"
Expand Down

0 comments on commit a7b2ddc

Please sign in to comment.