bladeRF-wiphy/fpga/vhdl/wlan_equalizer.vhd
2020-12-30 23:19:51 -08:00

333 lines
12 KiB
VHDL

-- This file is part of bladeRF-wiphy.
--
-- Copyright (C) 2020 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 wlan ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
entity wlan_equalizer is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
dfe_sample : in wlan_sample_t ;
in_sample : in wlan_sample_t ;
in_done : in std_logic ;
out_sample : out wlan_sample_t ;
out_done : in std_logic
) ;
end entity;
architecture arch of wlan_equalizer is
type equalizer_coefficient is record
i : signed( 15 downto 0 ) ;
q : signed( 15 downto 0 ) ;
end record ;
type equalizer_coefficients_t is array (integer range <>) of equalizer_coefficient ;
constant T2 : integer_array_t( 0 to 63 ) := (
0, 1, -1, -1, 1, 1, -1, 1,
-1, 1, -1, -1, -1, -1, -1, 1,
1, -1, -1, 1, -1, 1, -1, 1,
1, 1, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 1,
-1, -1, 1, 1, -1, 1, -1, 1,
1, 1, 1, 1, 1, -1, -1, 1,
1, -1, 1, -1, 1, 1, 1, 1
);
type fsm_t is (IDLE, INITIAL_ESTIMATE, UPDATE_ESTIMATE) ;
type state_t is record
rfsm, wfsm : fsm_t ;
eq : equalizer_coefficients_t( 63 downto 0 ) ;
update_index : unsigned( 5 downto 0 ) ;
rupdate_index : unsigned( 5 downto 0 ) ;
eq_chan, eq_ref : wlan_sample_t ;
eq_first, eq_last : std_logic;
rcupdate_index : unsigned( 5 downto 0 ) ;
rcupdate_cur_eq_sample : wlan_sample_t ;
rcupdate_new_eq_sample : wlan_sample_t ;
rcupdate_result : wlan_sample_t ;
rcupdate_result_index : unsigned( 5 downto 0 ) ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
for x in rv.eq'range loop
rv.eq(x) := (others => (others => '0') ) ;
end loop ;
rv.eq_chan := NULL_SAMPLE ;
rv.eq_ref := NULL_SAMPLE ;
rv.eq_first := '0' ;
rv.eq_last := '0' ;
rv.update_index := ( others => '0' ) ;
rv.rfsm := IDLE ;
rv.wfsm := IDLE ;
rv.rupdate_index := ( others => '0' ) ;
rv.rcupdate_index := ( others => '0' ) ;
rv.rcupdate_cur_eq_sample := NULL_SAMPLE ;
rv.rcupdate_new_eq_sample := NULL_SAMPLE ;
rv.rcupdate_result := NULL_SAMPLE ;
rv.rcupdate_result_index := ( others => '0' ) ;
return rv ;
end function ;
signal equalizer : wlan_sample_t ;
signal last_sample : wlan_sample_t ;
signal last_sample_r : wlan_sample_t ;
signal last_sample_rr : wlan_sample_t ;
signal last_sample_rrr : wlan_sample_t ;
signal eq_sample : wlan_sample_t ;
signal bin_index : unsigned( 5 downto 0 ) ;
signal in_sample_r : wlan_sample_t ;
signal result_sample : wlan_sample_t ;
signal equalizer_coeff_sample : equalizer_coefficient ;
signal current, future : state_t := NULL_STATE ;
signal eq_chan, eq_ref, eq_out, eq_invd: wlan_sample_t ;
signal eq_first, eq_last, eq_inv_done : std_logic;
begin
eq_ref <= current.eq_ref;
eq_chan <= current.eq_chan;
eq_first <= current.eq_first;
eq_last <= current.eq_last;
eq_out.i <= shift_right(eq_invd.i, 2);
eq_out.q <= shift_right(eq_invd.q, 2);
u_chan_inverter: entity work.wlan_channel_inverter
port map (
clock => clock,
reset => reset,
first => eq_first,
last => eq_last,
in_channel => eq_chan,
in_reference => eq_ref,
out_inverted => eq_invd,
done => eq_inv_done
) ;
out_sample <= eq_sample ;
comb : process(all)
variable idx, ridx : integer ;
begin
future <= current ;
case current.wfsm is
when IDLE =>
future.wfsm <= INITIAL_ESTIMATE ;
when INITIAL_ESTIMATE =>
future.eq_first <= '0';
future.eq_last <= '0';
future.eq_chan.valid <= '0';
future.eq_ref.valid <= '0';
if( in_done = '1' ) then
future.wfsm <= UPDATE_ESTIMATE ;
future.update_index <= ( others => '0' ) ;
end if ;
if( in_sample.valid = '1' ) then
idx := to_integer( current.update_index ) ;
future.update_index <= current.update_index + 1 ;
future.eq_chan.i <= in_sample.i;
future.eq_chan.q <= in_sample.q;
future.eq_chan.valid <= in_sample.valid;
future.eq_ref.i <= to_signed(T2(idx) * 4096, 16);
future.eq_ref.q <= to_signed(0, 16);
if( idx = 0 ) then
future.eq_first <= '1' ;
else
future.eq_first <= '0' ;
end if ;
if( idx = 63 ) then
future.eq_last <= '1' ;
else
future.eq_last <= '0' ;
end if ;
end if ;
when UPDATE_ESTIMATE =>
future.eq_first <= '0';
future.eq_last <= '0';
future.eq_chan.valid <= '0';
future.eq_ref.valid <= '0';
if( dfe_sample.valid = '0' ) then
future.update_index <= ( others => '0' ) ;
end if ;
if( dfe_sample.valid = '1' ) then
idx := to_integer( current.update_index ) ;
future.update_index <= current.update_index + 1 ;
future.eq_chan.i <= last_sample.i;
future.eq_chan.q <= last_sample.q;
future.eq_chan.valid <= last_sample.valid;
future.eq_ref.i <= dfe_sample.i;
future.eq_ref.q <= dfe_sample.q;
future.eq_ref.valid <= dfe_sample.valid;
if( idx = 0 ) then
future.eq_first <= '1' ;
else
future.eq_first <= '0' ;
end if ;
if( idx = 63 ) then
future.eq_last <= '1' ;
else
future.eq_last <= '0' ;
end if ;
end if ;
if( init = '1' ) then
future.wfsm <= IDLE ;
end if;
end case ;
future.rcupdate_new_eq_sample.valid <= '0' ;
case current.rfsm is
when IDLE =>
future.rfsm <= INITIAL_ESTIMATE ;
when INITIAL_ESTIMATE =>
if( eq_inv_done = '1' ) then
future.rfsm <= UPDATE_ESTIMATE ;
end if ;
if( eq_invd.valid = '1' ) then
ridx := to_integer( current.rupdate_index ) ;
future.rupdate_index <= current.rupdate_index + 1 ;
future.eq(ridx).i <= resize(shift_right(eq_invd.i, 0), 16 ) ;
future.eq(ridx).q <= resize(shift_right(eq_invd.q, 0), 16 ) ;
end if;
when UPDATE_ESTIMATE =>
if( eq_invd.valid = '0' ) then
future.rupdate_index <= ( others => '0' ) ;
end if ;
if( eq_invd.valid = '1' ) then
ridx := to_integer( current.rupdate_index ) ;
future.rupdate_index <= current.rupdate_index + 1 ;
future.rcupdate_index <= to_unsigned(ridx, future.rcupdate_index'length);
future.rcupdate_cur_eq_sample.i <= current.eq(ridx).i ;
future.rcupdate_cur_eq_sample.q <= current.eq(ridx).q ;
future.rcupdate_new_eq_sample <= eq_invd ;
--future.eq(ridx).i <= current.eq(ridx).i / 2 + eq_invd.i / 2 ;
--future.eq(ridx).q <= current.eq(ridx).q / 2 + eq_invd.q / 2 ;
--future.eq(ridx).i <= eq_invd.i / 2 ;
--future.eq(ridx).q <= eq_invd.q / 2 ;
end if ;
if( init = '1' ) then
future.rfsm <= IDLE ;
end if;
end case ;
if( current.rcupdate_new_eq_sample.valid = '1' ) then
future.rcupdate_result_index <= current.rcupdate_index ;
future.rcupdate_result.i <= current.rcupdate_cur_eq_sample.i / 2 + current.rcupdate_new_eq_sample.i / 2 ;
future.rcupdate_result.q <= current.rcupdate_cur_eq_sample.q / 2 + current.rcupdate_new_eq_sample.q / 2 ;
future.rcupdate_result.valid <= '1' ;
else
future.rcupdate_result.valid <= '0' ;
end if ;
if( current.rcupdate_result.valid = '1' ) then
if( current.rcupdate_result_index /= 7 and current.rcupdate_result_index /= 21 and
current.rcupdate_result_index /= 43 and current.rcupdate_result_index /= 57 ) then
future.eq(to_integer(current.rcupdate_result_index)).i <= current.rcupdate_result.i ;
future.eq(to_integer(current.rcupdate_result_index)).q <= current.rcupdate_result.q ;
end if ;
end if ;
end process ;
process( clock )
variable idx : integer ;
begin
if( reset = '1' ) then
current <= NULL_STATE ;
in_sample_r <= NULL_SAMPLE ;
result_sample <= NULL_SAMPLE ;
elsif( rising_edge( clock ) ) then
last_sample_r <= in_sample ;
last_sample_rr <= last_sample_r ;
last_sample_rrr <= last_sample_rr ;
last_sample <= last_sample_rrr ;
in_sample_r.valid <= '0' ;
if( init = '1' ) then
current <= NULL_STATE ;
bin_index <= ( others => '0' ) ;
else
current <= future ;
end if ;
if( in_sample.valid = '1' ) then
if( current.rfsm = UPDATE_ESTIMATE ) then
--eq_sample.valid <= in_sample.valid ;
in_sample_r <= in_sample ;
idx := to_integer( bin_index ) ;
bin_index <= bin_index + 1 ;
equalizer_coeff_sample <= current.eq(idx);
--eq_sample.i <= resize(shift_right(in_sample.i * current.eq(idx).i - in_sample.q * current.eq(idx).q, 12), 16 ) ;
--eq_sample.q <= resize(shift_right(in_sample.i * current.eq(idx).q + in_sample.q * current.eq(idx).i, 12), 16 ) ;
--eq_sample.i <= in_sample.i;--resize(shift_right(in_sample.i * current.eq(idx).i - in_sample.q * current.eq(idx).q, 12), 16 ) ;
--eq_sample.q <= in_sample.q;--resize(shift_right(in_sample.i * current.eq(idx).q + in_sample.q * current.eq(idx).i, 12), 16 ) ;
end if ;
end if ;
if( in_sample_r.valid = '1' ) then
result_sample.i <= resize(shift_right(in_sample_r.i * equalizer_coeff_sample.i - in_sample_r.q * equalizer_coeff_sample.q, 12), 16 ) ;
result_sample.q <= resize(shift_right(in_sample_r.i * equalizer_coeff_sample.q + in_sample_r.q * equalizer_coeff_sample.i, 12), 16 ) ;
result_sample.valid <= '1' ;
else
result_sample.valid <= '0' ;
end if ;
eq_sample <= result_sample ;
end if ;
end process ;
end architecture ;