mirror of
https://github.com/Nuand/bladeRF-wiphy.git
synced 2025-01-29 15:43:59 +00:00
Add traceback based soft decision Viterbi decoder implementation
This commit is contained in:
parent
45fda6959a
commit
cbcc2c1951
85
fpga/ip/nuand/viterbi_decoder/vhdl/branch_compare.vhd
Normal file
85
fpga/ip/nuand/viterbi_decoder/vhdl/branch_compare.vhd
Normal file
@ -0,0 +1,85 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.viterbi_p.all;
|
||||
|
||||
entity branch_compare is
|
||||
generic(
|
||||
RESET_ACTIVE : boolean := false;
|
||||
REG_UNCODED : boolean := false
|
||||
);
|
||||
port(
|
||||
clock : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
bm_a : in unsigned(15 downto 0);
|
||||
bm_b : in unsigned(15 downto 0);
|
||||
bm_valid : in std_logic;
|
||||
|
||||
path_in_a : in path_t;
|
||||
path_in_b : in path_t;
|
||||
|
||||
branch : in branch_inputs_t;
|
||||
path_out : out path_t;
|
||||
|
||||
win : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of branch_compare is
|
||||
begin
|
||||
|
||||
process(reset, clock)
|
||||
variable cost_a, cost_b : unsigned(path_in_a.cost'range);
|
||||
begin
|
||||
if (reset = '1') then
|
||||
path_out <= NULL_PATH_RST(RESET_ACTIVE);
|
||||
win <= '0';
|
||||
elsif (rising_edge(clock)) then
|
||||
if (bm_valid = '1') then
|
||||
cost_a := path_in_a.cost + bm_a;
|
||||
cost_b := path_in_b.cost + bm_b;
|
||||
|
||||
if ((path_in_a.cost = (path_in_a.cost'range => '1')) and
|
||||
(path_in_b.cost = (path_in_b.cost'range => '1'))) then
|
||||
win <= '0';
|
||||
path_out.cost <= ( others => '1' );
|
||||
elsif (path_in_a.cost = (path_in_a.cost'range => '1')) then
|
||||
win <= '1';
|
||||
path_out.cost <= cost_b;
|
||||
elsif (path_in_b.cost = (path_in_b.cost'range => '1')) then
|
||||
win <= '0';
|
||||
path_out.cost <= cost_a;
|
||||
else
|
||||
if (cost_b < cost_a) then
|
||||
win <= '1';
|
||||
path_out.cost <= cost_b;
|
||||
else
|
||||
win <= '0';
|
||||
path_out.cost <= cost_a;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end architecture;
|
56
fpga/ip/nuand/viterbi_decoder/vhdl/comp2.vhd
Normal file
56
fpga/ip/nuand/viterbi_decoder/vhdl/comp2.vhd
Normal file
@ -0,0 +1,56 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.viterbi_p.all;
|
||||
|
||||
entity comp2 is
|
||||
port(
|
||||
clock : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
path_name_a : in path_name_t;
|
||||
path_name_b : in path_name_t;
|
||||
path_valid : in std_logic;
|
||||
|
||||
path_name_out : out path_name_t
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of comp2 is
|
||||
begin
|
||||
process(clock, reset)
|
||||
begin
|
||||
if (reset = '1') then
|
||||
path_name_out.name <= (others => '0');
|
||||
path_name_out.path <= NULL_PATH_T;
|
||||
elsif (rising_edge(clock)) then
|
||||
if (path_valid = '1') then
|
||||
if (path_name_b.path.cost < path_name_a.path.cost) then
|
||||
path_name_out <= path_name_b;
|
||||
else
|
||||
path_name_out <= path_name_a;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end architecture;
|
87
fpga/ip/nuand/viterbi_decoder/vhdl/r2_comparator.vhd
Normal file
87
fpga/ip/nuand/viterbi_decoder/vhdl/r2_comparator.vhd
Normal file
@ -0,0 +1,87 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.viterbi_p.all;
|
||||
|
||||
entity r2_comparator is
|
||||
generic(
|
||||
NUM_PATHS : in natural := 64;
|
||||
STATE_BITS : in natural := 6
|
||||
);
|
||||
port(
|
||||
clock : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
paths : in path_arr_t(NUM_PATHS-1 downto 0);
|
||||
path_valid : in std_logic;
|
||||
|
||||
label_out : out unsigned(STATE_BITS-1 downto 0);
|
||||
valid_out : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of r2_comparator is
|
||||
type path_name_arr_arr_t is array(natural range <>) of path_name_arr_t(NUM_PATHS-1 downto 0);
|
||||
|
||||
signal r2_matrix : path_name_arr_arr_t(STATE_BITS downto 0);
|
||||
|
||||
signal valid_out_r : std_logic_vector(STATE_BITS - 1 downto 1);
|
||||
begin
|
||||
gen_init_path: for i in paths'range generate
|
||||
r2_matrix(0)(i).path <= paths(i);
|
||||
r2_matrix(0)(i).name <= to_unsigned(i, 6);
|
||||
end generate;
|
||||
|
||||
process(clock, reset)
|
||||
begin
|
||||
if (reset = '1') then
|
||||
valid_out_r <= ( others => '0' );
|
||||
valid_out <= '0';
|
||||
elsif (rising_edge(clock)) then
|
||||
if (path_valid = '1') then
|
||||
valid_out_r <= path_valid & valid_out_r(valid_out_r'high downto 2);
|
||||
valid_out <= valid_out_r(1);
|
||||
else
|
||||
valid_out <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
gen_cs: for cs_i in 1 to STATE_BITS generate
|
||||
gen_rs: for rs_i in 0 to NUM_PATHS/(2**cs_i)-1 generate
|
||||
U_comp2 : entity work.comp2
|
||||
port map(
|
||||
clock => clock,
|
||||
reset => reset,
|
||||
|
||||
path_name_a => r2_matrix(cs_i-1)(rs_i * 2),
|
||||
path_name_b => r2_matrix(cs_i-1)(rs_i * 2 + 1),
|
||||
path_valid => path_valid,
|
||||
path_name_out => r2_matrix(cs_i)(rs_i)
|
||||
);
|
||||
end generate;
|
||||
end generate;
|
||||
|
||||
label_out <= r2_matrix(r2_matrix'high)(0).name;
|
||||
|
||||
end architecture;
|
9
fpga/ip/nuand/viterbi_decoder/vhdl/tb/compile.do
Normal file
9
fpga/ip/nuand/viterbi_decoder/vhdl/tb/compile.do
Normal file
@ -0,0 +1,9 @@
|
||||
vcom -work work -2008 ../viterbi_p.vhd
|
||||
vcom -work work -2008 ../tracer.vhd
|
||||
vcom -work work -2008 ../comp2.vhd
|
||||
vcom -work work -2008 ../r2_comparator.vhd
|
||||
vcom -work work -2008 ../branch_compare.vhd
|
||||
vcom -work work -2008 ../traceback.vhd
|
||||
vcom -work work -2008 ../viterbi_decoder.vhd
|
||||
vcom -work work -2008 viterbi_decoder_tb.vhd
|
||||
vcom -work work -2008 r2_comparator_tb.vhd
|
69
fpga/ip/nuand/viterbi_decoder/vhdl/tb/r2_comparator_tb.vhd
Normal file
69
fpga/ip/nuand/viterbi_decoder/vhdl/tb/r2_comparator_tb.vhd
Normal file
@ -0,0 +1,69 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.viterbi_p.all;
|
||||
|
||||
entity r2_comparator_tb is
|
||||
end entity;
|
||||
|
||||
architecture behv of r2_comparator_tb is
|
||||
signal clock : std_logic := '0';
|
||||
signal reset : std_logic;
|
||||
signal valid : std_logic;
|
||||
signal paths : path_arr_t(63 downto 0);
|
||||
|
||||
begin
|
||||
clock <= not clock after 10 ns;
|
||||
reset <= '1', '0' after 100 ns;
|
||||
valid <= '0', '1' after 198 ns, '0' after 548 ns;
|
||||
|
||||
process
|
||||
variable i : integer;
|
||||
variable t_cost : integer;
|
||||
begin
|
||||
for i in paths'range loop
|
||||
if (i = 51) then
|
||||
t_cost := 10;
|
||||
else
|
||||
t_cost := 100 + i;
|
||||
end if;
|
||||
paths(i).cost <= to_unsigned(t_cost, paths(i).cost'high + 1);
|
||||
paths(i).active <= '0';
|
||||
end loop;
|
||||
wait;
|
||||
end process;
|
||||
|
||||
|
||||
U_uut: entity work.r2_comparator
|
||||
port map(
|
||||
clock => clock,
|
||||
reset => reset,
|
||||
|
||||
paths => paths,
|
||||
path_valid => valid,
|
||||
|
||||
label_out => open,
|
||||
valid_out => open
|
||||
);
|
||||
end architecture;
|
||||
|
189
fpga/ip/nuand/viterbi_decoder/vhdl/tb/viterbi_decoder_tb.vhd
Normal file
189
fpga/ip/nuand/viterbi_decoder/vhdl/tb/viterbi_decoder_tb.vhd
Normal file
@ -0,0 +1,189 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
entity viterbi_decoder_tb is
|
||||
end entity;
|
||||
|
||||
architecture behv of viterbi_decoder_tb is
|
||||
signal clock : std_logic := '0';
|
||||
signal reset : std_logic;
|
||||
|
||||
type int_arr_t is array(natural range <>) of integer;
|
||||
constant recv : int_arr_t(0 to 47) := (
|
||||
-125, -122, -126, 127, 120, -127,
|
||||
-126, -128, -126, 127, 124, -127,
|
||||
118, -127, 122, -127, -120, -125,
|
||||
-123, 127, -117, -125, -124, -127,
|
||||
-127, -127, 122, -127, 127, 119,
|
||||
-127, 119, 127, -122, 128, -120,
|
||||
127, 127, 127, 124, 122, 127,
|
||||
127, 119, 122, 125, 126, 121);
|
||||
|
||||
|
||||
|
||||
type LUT_sl is array(natural range <>) of std_logic;
|
||||
constant LUT : LUT_sl := ( '1', '1', '1', '0',
|
||||
'0', '1', '0', '1',
|
||||
'0', '1', '1', '0',
|
||||
'0', '1', '1', '1',
|
||||
'0', '1', '1', '0',
|
||||
'0', '0', '1', '0',
|
||||
'0', '0', '0', '0',
|
||||
'0', '1', '0', '1',
|
||||
'0', '1', '1', '0',
|
||||
'0', '1', '1', '1',
|
||||
'0', '1', '1', '0',
|
||||
'0', '0', '1', '0',
|
||||
'0', '0', '0', '0',
|
||||
'0', '1', '0', '1',
|
||||
'0', '1', '1', '0',
|
||||
'0', '1', '1', '1',
|
||||
'0', '1', '1', '0',
|
||||
'0', '0', '1', '0',
|
||||
'0', '0', '0', '0',
|
||||
'1', '1', '1', '1',
|
||||
'1', '1', '1', '1',
|
||||
'1', '1', '1', '1',
|
||||
'1', '1', '1', '1'
|
||||
);
|
||||
|
||||
--signal t_state : std_logic_vector(6 downto 0);
|
||||
|
||||
signal t_valid : std_logic := '0';
|
||||
signal t_bit_a, t_bit_b : std_logic_vector(7 downto 0) := ( others => '0' );
|
||||
signal t_erasure : std_logic_vector(1 downto 0) := ( others => '0' );
|
||||
|
||||
|
||||
function generate_out_bit(code : std_logic_vector(6 downto 0); state : std_logic_vector(6 downto 0); in_bit : std_logic)
|
||||
return std_logic
|
||||
is
|
||||
variable ret : std_logic;
|
||||
variable i : natural;
|
||||
begin
|
||||
ret := '0';
|
||||
for i in 0 to code'high loop
|
||||
if(code(i) = '1') then
|
||||
if(i = code'high) then
|
||||
ret := ret xor in_bit;
|
||||
else
|
||||
ret := ret xor state(code'high-1-i);
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
return ret;
|
||||
end function;
|
||||
|
||||
constant G_A : integer := 91;
|
||||
constant G_B : integer := 121;
|
||||
constant K : integer := 7;
|
||||
|
||||
function G_A_VEC_GEN return std_logic_vector is
|
||||
begin
|
||||
return std_logic_vector(to_unsigned(G_A, K));
|
||||
end function;
|
||||
|
||||
function G_B_VEC_GEN return std_logic_vector is
|
||||
begin
|
||||
return std_logic_vector(to_unsigned(G_B, K));
|
||||
end function;
|
||||
|
||||
constant G_A_VEC : std_logic_vector(K-1 downto 0) := G_A_VEC_GEN;
|
||||
constant G_B_VEC : std_logic_vector(K-1 downto 0) := G_B_VEC_GEN;
|
||||
|
||||
begin
|
||||
clock <= not clock after 10 ns;
|
||||
reset <= '1', '0' after 100 ns, '1' after 5 us, '0' after 6 us;
|
||||
|
||||
process
|
||||
variable state : std_logic_vector(6 downto 0) := ( others => '0' );
|
||||
variable b_a, b_b : std_logic;
|
||||
variable idx : integer := 0;
|
||||
begin
|
||||
wait for 500 ns;
|
||||
for iz in 0 to 23 loop
|
||||
for i in 0 to 23 loop
|
||||
wait until rising_edge(clock);
|
||||
t_valid <= '1';
|
||||
t_bit_a <= not(std_logic_vector(127 + to_signed(recv(2*i), t_bit_a'high +1)));
|
||||
t_bit_b <= not(std_logic_vector(127 + to_signed(recv(2*i+1), t_bit_b'high +1)));
|
||||
--if (recv(i*2) < 0) then
|
||||
-- t_bit_a <= ( others => '1' );
|
||||
--else
|
||||
-- t_bit_a <= ( others => '0' );
|
||||
--end if;
|
||||
--if (recv(i*2+1) < 0) then
|
||||
-- t_bit_b <= ( others => '1' );
|
||||
--else
|
||||
-- t_bit_b <= ( others => '0' );
|
||||
--end if;
|
||||
end loop;
|
||||
t_erasure <= ( others => '1' );
|
||||
wait until reset = '1';
|
||||
t_valid <= '0';
|
||||
wait for 30 us;
|
||||
end loop;
|
||||
--for i in LUT'range loop
|
||||
-- wait until rising_edge(clock);
|
||||
-- b_a := generate_out_bit(G_A_VEC, state, LUT(idx));
|
||||
-- b_b := generate_out_bit(G_B_VEC, state, LUT(idx));
|
||||
-- t_bit_a <= ( others => b_a );
|
||||
-- t_bit_b <= ( others => b_b );
|
||||
-- t_valid <= '1';
|
||||
-- state := state(5 downto 0) & LUT(idx);
|
||||
-- wait until rising_edge(clock);
|
||||
-- t_valid <= '0';
|
||||
|
||||
-- idx := idx + 1;
|
||||
-- if (idx > 90) then
|
||||
-- t_bit_a <= ( others => '0' );
|
||||
-- t_bit_b <= ( others => '0' );
|
||||
-- for i in 0 to 900 loop
|
||||
-- t_valid <= '1';
|
||||
-- wait until rising_edge(clock);
|
||||
-- t_valid <= '0';
|
||||
-- if (i = 10 or i = 50) then
|
||||
-- wait for 10 us;
|
||||
-- end if;
|
||||
-- wait until rising_edge(clock);
|
||||
-- end loop;
|
||||
-- t_valid <= '0';
|
||||
-- wait;
|
||||
-- end if;
|
||||
|
||||
|
||||
--end loop;
|
||||
end process;
|
||||
|
||||
U_uut: entity work.viterbi_decoder
|
||||
port map(
|
||||
clock => clock,
|
||||
reset => reset,
|
||||
|
||||
in_a => t_bit_a,
|
||||
in_b => t_bit_b,
|
||||
erasure => (others => '0'),
|
||||
bsd_valid => t_valid,
|
||||
|
||||
out_bit => open,
|
||||
out_valid => open
|
||||
);
|
||||
end architecture;
|
112
fpga/ip/nuand/viterbi_decoder/vhdl/tb/wave.do
Normal file
112
fpga/ip/nuand/viterbi_decoder/vhdl/tb/wave.do
Normal file
@ -0,0 +1,112 @@
|
||||
onerror {resume}
|
||||
quietly WaveActivateNextPane {} 0
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/G_A
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/G_A_VEC
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/G_B
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/G_B_VEC
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/K
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/TB_LEN
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/acs_reg
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/acs_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/best_idx
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/bm
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/bm_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/bsd_in
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/bsd_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/clock
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/erasure
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/in_a
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/in_b
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/lut
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/out_bit
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/out_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/paths
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/reset
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/NUM_PATHS
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/STATE_BITS
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/clock
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/label_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/path_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/paths
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/r2_matrix
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/reset
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/valid_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_r2_comp/valid_out_r
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/NUM_STATES
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/STATE_BITS
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/TB_LEN
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/acs_reg
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/acs_valid
|
||||
add wave -noupdate -radix unsigned /viterbi_decoder_tb/U_uut/U_traceback/best_idx
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/best_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/bit_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/clock
|
||||
add wave -noupdate -expand /viterbi_decoder_tb/U_uut/U_traceback/current
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/future
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/reset
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/trace_state
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/trace_state_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/NUM_STATES
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/STATE_BITS
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/acs_reg
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/acs_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/clock
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/reset
|
||||
add wave -noupdate -radix unsigned /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/state_in
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/state_valid
|
||||
add wave -noupdate -radix unsigned /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/state_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(0)/U_tracer/valid_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/NUM_STATES
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/STATE_BITS
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/TB_LEN
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/acs_reg
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/acs_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/best_idx
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/best_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/bit_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/valid_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/clock
|
||||
add wave -noupdate -expand /viterbi_decoder_tb/U_uut/U_traceback/current
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/future
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/reset
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/trace_state
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/trace_state_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/valid_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/acs_reg
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/acs_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/clock
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/NUM_STATES
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/reset
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/STATE_BITS
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/state_in
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/state_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/state_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(1)/U_tracer/valid_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/acs_reg
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/acs_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/clock
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/NUM_STATES
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/reset
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/STATE_BITS
|
||||
add wave -noupdate -radix unsigned /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/state_in
|
||||
add wave -noupdate -radix unsigned /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/state_out
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/state_valid
|
||||
add wave -noupdate /viterbi_decoder_tb/U_uut/U_traceback/gen_tracers(19)/U_tracer/valid_out
|
||||
TreeUpdate [SetDefaultTree]
|
||||
WaveRestoreCursors {{Cursor 1} {3754327 ps} 0}
|
||||
quietly wave cursor active 1
|
||||
configure wave -namecolwidth 518
|
||||
configure wave -valuecolwidth 100
|
||||
configure wave -justifyvalue left
|
||||
configure wave -signalnamewidth 0
|
||||
configure wave -snapdistance 10
|
||||
configure wave -datasetprefix 0
|
||||
configure wave -rowmargin 4
|
||||
configure wave -childrowmargin 2
|
||||
configure wave -gridoffset 0
|
||||
configure wave -gridperiod 1
|
||||
configure wave -griddelta 40
|
||||
configure wave -timeline 0
|
||||
configure wave -timelineunits ps
|
||||
update
|
||||
WaveRestoreZoom {0 ps} {52500 ns}
|
155
fpga/ip/nuand/viterbi_decoder/vhdl/traceback.vhd
Normal file
155
fpga/ip/nuand/viterbi_decoder/vhdl/traceback.vhd
Normal file
@ -0,0 +1,155 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.viterbi_p.all;
|
||||
|
||||
entity traceback is
|
||||
generic(
|
||||
STATE_BITS : in integer;
|
||||
NUM_STATES : in integer;
|
||||
TB_LEN : in integer
|
||||
);
|
||||
port(
|
||||
clock : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
acs_reg : in std_logic_vector(NUM_STATES-1 downto 0);
|
||||
acs_valid : in std_logic;
|
||||
|
||||
best_idx : in unsigned(STATE_BITS-1 downto 0);
|
||||
best_valid : in std_logic;
|
||||
|
||||
bit_out : out std_logic;
|
||||
valid_out : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of traceback is
|
||||
type history_t is array(7 + TB_LEN*2 downto 0) of std_logic_vector(NUM_STATES-1 downto 0);
|
||||
|
||||
type fsm_t is (IDLE, START_TRACER);
|
||||
|
||||
type state_t is record
|
||||
fsm : fsm_t;
|
||||
loaded : std_logic;
|
||||
history : history_t;
|
||||
acs_count : natural range 0 to TB_LEN+STATE_BITS*2;
|
||||
acs_enough : std_logic;
|
||||
bit_out : std_logic;
|
||||
valid_out : std_logic;
|
||||
end record;
|
||||
|
||||
function NULL_STATE_T return state_t is
|
||||
variable ret : state_t;
|
||||
begin
|
||||
ret.fsm := IDLE;
|
||||
ret.loaded := '0';
|
||||
for i in ret.history'range loop
|
||||
ret.history(i) := ( others => '0' );
|
||||
end loop;
|
||||
ret.acs_count := 0;
|
||||
ret.acs_enough := '0';
|
||||
ret.bit_out := '0';
|
||||
ret.valid_out := '0';
|
||||
return(ret);
|
||||
end function;
|
||||
|
||||
signal current, future : state_t := NULL_STATE_T;
|
||||
|
||||
type trace_state_t is array(TB_LEN downto 0) of unsigned(STATE_BITS-1 downto 0);
|
||||
|
||||
signal trace_state : trace_state_t;
|
||||
signal trace_state_valid : std_logic_vector(TB_LEN downto 0);
|
||||
begin
|
||||
sync : process(clock, reset)
|
||||
begin
|
||||
if (reset = '1') then
|
||||
current <= NULL_STATE_T;
|
||||
elsif (rising_edge(clock)) then
|
||||
current <= future;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
trace_state(0) <= best_idx;
|
||||
trace_state_valid(0) <= current.acs_enough;
|
||||
|
||||
gen_tracers: for i in 0 to TB_LEN-1 generate
|
||||
U_tracer: entity work.tracer
|
||||
generic map(
|
||||
STATE_BITS => STATE_BITS,
|
||||
NUM_STATES => NUM_STATES
|
||||
)
|
||||
port map(
|
||||
clock => clock,
|
||||
reset => reset,
|
||||
|
||||
state_in => trace_state(i),
|
||||
state_valid => trace_state_valid(i),
|
||||
acs_reg => current.history(6 + 2 * i),
|
||||
acs_valid => acs_valid,
|
||||
|
||||
state_out => trace_state(i+1),
|
||||
valid_out => trace_state_valid(i+1)
|
||||
);
|
||||
end generate;
|
||||
|
||||
|
||||
bit_out <= current.bit_out;
|
||||
valid_out <= current.valid_out;
|
||||
|
||||
comb : process(all)
|
||||
begin
|
||||
future <= current;
|
||||
|
||||
future.bit_out <= '0';
|
||||
future.valid_out <= '0';
|
||||
|
||||
if (acs_valid = '1') then
|
||||
if (current.acs_enough = '0') then
|
||||
if (current.acs_count = TB_LEN + 6 + 5) then
|
||||
future.acs_enough <= '1';
|
||||
else
|
||||
future.acs_count <= current.acs_count + 1;
|
||||
end if;
|
||||
end if;
|
||||
future.history <= current.history(current.history'high-1 downto 0) & acs_reg;
|
||||
end if;
|
||||
|
||||
case current.fsm is
|
||||
when IDLE =>
|
||||
if (current.acs_enough = '1' and acs_valid = '1') then
|
||||
future.fsm <= START_TRACER;
|
||||
end if;
|
||||
when START_TRACER =>
|
||||
if (acs_valid = '1') then
|
||||
-- the bit that is about to be shifted out is actually the uncoded bit
|
||||
-- the new bit that is shifted in is from the current branch, the historical ACS reg basically determines the LSB of the new state
|
||||
future.bit_out <= trace_state(TB_LEN)(5);
|
||||
future.valid_out <= trace_state_valid(TB_LEN);
|
||||
end if;
|
||||
when others =>
|
||||
future <= NULL_STATE_T;
|
||||
end case;
|
||||
end process;
|
||||
|
||||
end architecture;
|
61
fpga/ip/nuand/viterbi_decoder/vhdl/tracer.vhd
Normal file
61
fpga/ip/nuand/viterbi_decoder/vhdl/tracer.vhd
Normal file
@ -0,0 +1,61 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.viterbi_p.all;
|
||||
|
||||
entity tracer is
|
||||
generic(
|
||||
STATE_BITS : in integer;
|
||||
NUM_STATES : in integer
|
||||
);
|
||||
port(
|
||||
clock : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
state_in : in unsigned(STATE_BITS-1 downto 0);
|
||||
state_valid : in std_logic;
|
||||
acs_reg : in std_logic_vector(NUM_STATES-1 downto 0);
|
||||
acs_valid : in std_logic;
|
||||
|
||||
state_out : out unsigned(STATE_BITS-1 downto 0);
|
||||
valid_out : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of tracer is
|
||||
begin
|
||||
process(clock, reset)
|
||||
variable s_bit : std_logic;
|
||||
begin
|
||||
if (reset='1') then
|
||||
state_out <= ( others => '0' );
|
||||
valid_out <= '0';
|
||||
elsif (rising_edge(clock)) then
|
||||
s_bit := acs_reg(to_integer(state_in));
|
||||
if (acs_valid = '1') then
|
||||
state_out <= s_bit & state_in(state_in'high downto 1);
|
||||
valid_out <= state_valid;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end architecture;
|
311
fpga/ip/nuand/viterbi_decoder/vhdl/viterbi_decoder.vhd
Normal file
311
fpga/ip/nuand/viterbi_decoder/vhdl/viterbi_decoder.vhd
Normal file
@ -0,0 +1,311 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
library work;
|
||||
use work.viterbi_p.all;
|
||||
|
||||
entity viterbi_decoder is
|
||||
generic(
|
||||
K : in natural := 7;
|
||||
G_A : in natural := 91;
|
||||
G_B : in natural := 121;
|
||||
TB_LEN : in natural := 42
|
||||
);
|
||||
port(
|
||||
clock : in std_logic;
|
||||
reset : in std_logic;
|
||||
|
||||
in_a : in std_logic_vector(7 downto 0);
|
||||
in_b : in std_logic_vector(7 downto 0);
|
||||
erasure : in std_logic_vector(1 downto 0);
|
||||
bsd_valid : in std_logic;
|
||||
|
||||
out_bit : out std_logic;
|
||||
out_valid : out std_logic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture arch of viterbi_decoder is
|
||||
function STATE_BITS return natural is
|
||||
begin
|
||||
return K-1;
|
||||
end function;
|
||||
|
||||
function NUM_STATES return natural is
|
||||
begin
|
||||
return (2**STATE_BITS);
|
||||
end function;
|
||||
|
||||
|
||||
function G_A_VEC_GEN return std_logic_vector is
|
||||
begin
|
||||
return std_logic_vector(to_unsigned(G_A, K));
|
||||
end function;
|
||||
|
||||
function G_B_VEC_GEN return std_logic_vector is
|
||||
begin
|
||||
return std_logic_vector(to_unsigned(G_B, K));
|
||||
end function;
|
||||
|
||||
constant G_A_VEC : std_logic_vector(K-1 downto 0) := G_A_VEC_GEN;
|
||||
constant G_B_VEC : std_logic_vector(K-1 downto 0) := G_B_VEC_GEN;
|
||||
|
||||
type branch_lut_t is array(NUM_STATES-1 downto 0) of branch_inputs_t;
|
||||
|
||||
function generate_out_bit(code : std_logic_vector(K-1 downto 0); state : std_logic_vector(STATE_BITS-1 downto 0); in_bit : std_logic)
|
||||
return std_logic
|
||||
is
|
||||
variable ret : std_logic;
|
||||
variable i : natural;
|
||||
begin
|
||||
ret := '0';
|
||||
for i in 0 to code'high loop
|
||||
if(code(i) = '1') then
|
||||
if(i = code'high) then
|
||||
ret := ret xor in_bit;
|
||||
else
|
||||
ret := ret xor state(code'high-1-i);
|
||||
end if;
|
||||
end if;
|
||||
end loop;
|
||||
return ret;
|
||||
end function;
|
||||
|
||||
function generate_next_state(state : std_logic_vector(STATE_BITS-1 downto 0); in_bit : std_logic)
|
||||
return std_logic_vector is
|
||||
begin
|
||||
return state(state'high - 1 downto 0) & in_bit;
|
||||
end function;
|
||||
|
||||
-- if the convolution encoder's initial state is 0, some states are
|
||||
-- "impossible" at least for K-1 bits
|
||||
function is_state_active( t_idx : integer ; state : integer ) return boolean is
|
||||
begin
|
||||
if (t_idx < 0) then
|
||||
return true;
|
||||
end if;
|
||||
return ( (state) <= (2**t_idx - 1) );
|
||||
end function;
|
||||
|
||||
|
||||
-- cast std_logic vector to integer
|
||||
function sl_to_integer( x : std_logic ) return integer is
|
||||
begin
|
||||
if (x = '1') then
|
||||
return 1;
|
||||
end if;
|
||||
return 0;
|
||||
end function;
|
||||
|
||||
function gen_branch_t( i : integer ; in_bit : std_logic ) return branch_t is
|
||||
variable t_state_slv : std_logic_vector(STATE_BITS-1 downto 0);
|
||||
variable next_state_slv : std_logic_vector(STATE_BITS-1 downto 0);
|
||||
variable t_bit_a : std_logic;
|
||||
variable t_bit_b : std_logic;
|
||||
variable t_bit_slv : std_logic_vector(1 downto 0);
|
||||
variable ret : branch_t;
|
||||
begin
|
||||
t_state_slv := std_logic_vector(to_unsigned(i, STATE_BITS));
|
||||
|
||||
t_bit_a := generate_out_bit(G_A_VEC, t_state_slv, in_bit);
|
||||
t_bit_b := generate_out_bit(G_B_VEC, t_state_slv, in_bit);
|
||||
next_state_slv := t_state_slv(t_state_slv'high-1 downto 0) & in_bit;
|
||||
|
||||
ret.set := true;
|
||||
ret.start_state := i;
|
||||
ret.u_bit := in_bit;
|
||||
ret.bit_a := t_bit_a;
|
||||
ret.bit_b := t_bit_b;
|
||||
ret.bit_s := t_state_slv(t_state_slv'high);
|
||||
t_bit_slv := t_bit_b & t_bit_a;
|
||||
ret.bm_idx := to_integer(unsigned(t_bit_slv));
|
||||
ret.prev_state := i;
|
||||
ret.next_state := to_integer(unsigned(next_state_slv));
|
||||
--report "S[" & integer'image(i) & "] -- bit=" & to_string(in_bit) &
|
||||
-- " coded=" & to_string(t_bit_a) & "," & to_string(t_bit_b) &
|
||||
-- " -- D[" & integer'image(to_integer(unsigned(next_state_slv))) & "]";
|
||||
return ret;
|
||||
end function;
|
||||
|
||||
function generate_branch_table return branch_lut_t is
|
||||
variable tmp_branch : branch_t;
|
||||
variable ret : branch_lut_t;
|
||||
begin
|
||||
for i in 0 to NUM_STATES-1 loop
|
||||
ret(i)(0).set := false;
|
||||
ret(i)(1).set := false;
|
||||
end loop;
|
||||
|
||||
for i in 0 to NUM_STATES-1 loop
|
||||
|
||||
-- uncoded bit is 0?
|
||||
tmp_branch := gen_branch_t(i, '0');
|
||||
if (ret(tmp_branch.next_state)(sl_to_integer(tmp_branch.bit_s)).set) then
|
||||
report "ERROR BUILDING BRANCH TABLE, INPUTS MUST BE UNIQUE" severity error;
|
||||
end if;
|
||||
ret(tmp_branch.next_state)(sl_to_integer(tmp_branch.bit_s)) := tmp_branch;
|
||||
|
||||
|
||||
-- uncoded bit is 1?
|
||||
tmp_branch := gen_branch_t(i, '1');
|
||||
if (ret(tmp_branch.next_state)(sl_to_integer(tmp_branch.bit_s)).set) then
|
||||
report "ERROR BUILDING BRANCH TABLE, INPUTS MUST BE UNIQUE" severity error;
|
||||
end if;
|
||||
ret(tmp_branch.next_state)(sl_to_integer(tmp_branch.bit_s)) := tmp_branch;
|
||||
|
||||
end loop;
|
||||
return ret;
|
||||
end function;
|
||||
|
||||
|
||||
--function NULL_EDGE is return edge_t
|
||||
|
||||
constant lut : branch_lut_t := generate_branch_table;
|
||||
|
||||
signal bsd_in : bsd_t(1 downto 0);
|
||||
|
||||
|
||||
signal paths : path_arr_t(NUM_STATES-1 downto 0);
|
||||
|
||||
signal bm : bm_t(3 downto 0);
|
||||
signal bm_valid : std_logic;
|
||||
|
||||
function single_bit_loss_function(received : unsigned; expected : std_logic) return unsigned is
|
||||
variable expanded : unsigned(received'range);
|
||||
begin
|
||||
if (expected = '0') then
|
||||
return(received);
|
||||
end if;
|
||||
|
||||
expanded := (others => '1');
|
||||
return expanded - received;
|
||||
end function;
|
||||
|
||||
function loss_function(received_bsd : bsd_t ; expected : unsigned ; erasure : std_logic_vector) return unsigned is
|
||||
variable loss : unsigned(15 downto 0);
|
||||
begin
|
||||
loss := ( others => '0' );
|
||||
|
||||
for i in received_bsd'range loop
|
||||
if (erasure(i) = '0') then
|
||||
loss := loss + single_bit_loss_function(received_bsd(i), expected(i));
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return loss;
|
||||
end function;
|
||||
|
||||
signal acs_reg : std_logic_vector(NUM_STATES-1 downto 0);
|
||||
|
||||
signal acs_valid : std_logic;
|
||||
|
||||
signal best_idx : unsigned(STATE_BITS-1 downto 0);
|
||||
begin
|
||||
|
||||
bsd_in(0) <= unsigned(in_a);
|
||||
bsd_in(1) <= unsigned(in_b);
|
||||
|
||||
process(clock, reset)
|
||||
begin
|
||||
if (reset = '1') then
|
||||
for i in bm'range loop
|
||||
bm(i) <= ( others => '0' );
|
||||
end loop;
|
||||
bm_valid <= '0';
|
||||
elsif (rising_edge(clock)) then
|
||||
if (bsd_valid = '1') then
|
||||
bm_valid <= '1';
|
||||
for i in bm'range loop
|
||||
bm(i) <= loss_function(bsd_in, to_unsigned(i,2), erasure);
|
||||
end loop;
|
||||
else
|
||||
bm_valid <= '0';
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
gen_bm_loop: for t_state in 0 to (NUM_STATES-1) generate
|
||||
gen_bc: entity work.branch_compare
|
||||
generic map(
|
||||
RESET_ACTIVE => (t_state = 0)
|
||||
)
|
||||
port map(
|
||||
clock => clock,
|
||||
reset => reset,
|
||||
|
||||
bm_a => bm(lut(t_state)(0).bm_idx),
|
||||
bm_b => bm(lut(t_state)(1).bm_idx),
|
||||
bm_valid => bm_valid,
|
||||
|
||||
path_in_a => paths(lut(t_state)(0).prev_state),
|
||||
path_in_b => paths(lut(t_state)(1).prev_state),
|
||||
|
||||
branch => lut(t_state),
|
||||
|
||||
path_out => paths(t_state),
|
||||
|
||||
win => acs_reg(t_state)
|
||||
);
|
||||
end generate;
|
||||
|
||||
process(clock, reset)
|
||||
begin
|
||||
if (reset = '1') then
|
||||
acs_valid <= '0';
|
||||
elsif (rising_edge(clock)) then
|
||||
acs_valid <= bm_valid;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
U_r2_comp: entity work.r2_comparator
|
||||
port map(
|
||||
clock => clock,
|
||||
reset => reset,
|
||||
|
||||
paths => paths,
|
||||
path_valid => acs_valid,
|
||||
|
||||
label_out => best_idx
|
||||
);
|
||||
|
||||
|
||||
U_traceback: entity work.traceback
|
||||
generic map(
|
||||
STATE_BITS => STATE_BITS,
|
||||
NUM_STATES => NUM_STATES,
|
||||
TB_LEN => TB_LEN
|
||||
)
|
||||
port map(
|
||||
clock => clock,
|
||||
reset => reset,
|
||||
|
||||
acs_reg => acs_reg,
|
||||
acs_valid => acs_valid,
|
||||
|
||||
best_idx => best_idx,
|
||||
best_valid => '0',
|
||||
|
||||
bit_out => out_bit,
|
||||
valid_out => out_valid
|
||||
);
|
||||
|
||||
end architecture;
|
85
fpga/ip/nuand/viterbi_decoder/vhdl/viterbi_p.vhd
Normal file
85
fpga/ip/nuand/viterbi_decoder/vhdl/viterbi_p.vhd
Normal file
@ -0,0 +1,85 @@
|
||||
-- This file is part of bladeRF-wiphy.
|
||||
--
|
||||
-- Copyright (C) 2021 Nuand, LLC.
|
||||
--
|
||||
-- This program is free software; you can redistribute it and/or modify
|
||||
-- it under the terms of the GNU General Public License as published by
|
||||
-- the Free Software Foundation; either version 2 of the License, or
|
||||
-- (at your option) any later version.
|
||||
--
|
||||
-- This program is distributed in the hope that it will be useful,
|
||||
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
-- GNU General Public License for more details.
|
||||
--
|
||||
-- You should have received a copy of the GNU General Public License along
|
||||
-- with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
-- 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
|
||||
package viterbi_p is
|
||||
type path_t is record
|
||||
--- path metric stuff
|
||||
cost : unsigned(23 downto 0);
|
||||
active : std_logic;
|
||||
end record;
|
||||
type path_arr_t is array(natural range <>) of path_t;
|
||||
|
||||
type path_name_t is record
|
||||
path : path_t;
|
||||
name : unsigned(5 downto 0);
|
||||
end record;
|
||||
|
||||
type path_name_arr_t is array(natural range <>) of path_name_t;
|
||||
|
||||
|
||||
type branch_t is record
|
||||
-- starting conditions
|
||||
start_state : natural;
|
||||
u_bit : std_logic;
|
||||
|
||||
-- internal state keeping
|
||||
bit_s : std_logic;
|
||||
set : boolean;
|
||||
|
||||
-- output
|
||||
bit_a : std_logic;
|
||||
bit_b : std_logic;
|
||||
bm_idx : integer;
|
||||
|
||||
-- final state
|
||||
prev_state : integer;
|
||||
next_state : integer;
|
||||
end record;
|
||||
|
||||
type branch_inputs_t is array(1 downto 0) of branch_t;
|
||||
|
||||
type bsd_t is array(natural range <>) of unsigned(7 downto 0);
|
||||
|
||||
type bm_t is array(natural range <>) of unsigned(15 downto 0);
|
||||
|
||||
function NULL_PATH_RST(init_state : boolean) return path_t;
|
||||
function NULL_PATH_T return path_t;
|
||||
end package;
|
||||
|
||||
package body viterbi_p is
|
||||
function NULL_PATH_RST(init_state : boolean) return path_t is
|
||||
variable ret : path_t;
|
||||
begin
|
||||
if (init_state) then
|
||||
ret.cost := ( others => '0' );
|
||||
else
|
||||
ret.cost := ( others => '1' );
|
||||
end if;
|
||||
ret.active := '0';
|
||||
return ret;
|
||||
end function;
|
||||
|
||||
function NULL_PATH_T return path_t is
|
||||
begin
|
||||
return NULL_PATH_RST(false);
|
||||
end function;
|
||||
end package body;
|
Loading…
x
Reference in New Issue
Block a user