mirror of
https://github.com/Nuand/bladeRF-wiphy.git
synced 2024-12-29 18:19:10 +00:00
159 lines
5.5 KiB
VHDL
159 lines
5.5 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 work ;
|
|
use work.wlan_p.all ;
|
|
|
|
entity wlan_channel_inverter is
|
|
port (
|
|
clock : in std_logic ;
|
|
reset : in std_logic ;
|
|
|
|
first : in std_logic ;
|
|
last : in std_logic ;
|
|
|
|
in_channel : in wlan_sample_t ;
|
|
in_reference : in wlan_sample_t ;
|
|
|
|
out_inverted : out wlan_sample_t ;
|
|
done : out std_logic
|
|
) ;
|
|
end entity ;
|
|
|
|
architecture arch of wlan_channel_inverter is
|
|
|
|
-- Sequence is either -1, 0 or 1, so no need to store extra precision
|
|
type seq_lut_t is array(natural range <>) of integer range -1 to 1 ;
|
|
|
|
-- Convert from real type to LUT type
|
|
function create_long_seq_lut return seq_lut_t is
|
|
variable rv : seq_lut_t(LONG_SEQ_FREQ'range) ;
|
|
begin
|
|
for i in rv'range loop
|
|
rv(i) := integer(LONG_SEQ_FREQ(i).re) ;
|
|
end loop ;
|
|
return rv ;
|
|
end function ;
|
|
|
|
constant LONG_SEQ_LUT : seq_lut_t := create_long_seq_lut ;
|
|
|
|
-- TODO: Make this a feedback signal
|
|
signal snr_bias : unsigned(15 downto 0) := to_unsigned( 1, 16 ) ;
|
|
|
|
signal ref_x_conjh_i : signed(31 downto 0) ;
|
|
signal ref_x_conjh_q : signed(31 downto 0) ;
|
|
signal ref_x_conjh_valid : std_logic ;
|
|
|
|
signal magsq : unsigned(31 downto 0) ;
|
|
signal magsq_valid : std_logic ;
|
|
|
|
signal last_reg : std_logic ;
|
|
|
|
signal div_i : signed(31 downto 0) ;
|
|
signal div_q : signed(31 downto 0) ;
|
|
signal div_valid : std_logic ;
|
|
signal div_done : std_logic ;
|
|
|
|
begin
|
|
|
|
-- Incoming channel is in the frequency domain, H(t),
|
|
-- with the reference signal, T2(t). The inversion of this
|
|
-- is to then take T2(t) * H*(t) / ( |H(t)|^2 + NSR )
|
|
calc_ref_x_conjh : process(clock, reset)
|
|
variable count : natural range 0 to LONG_SEQ_FREQ'high := 0 ;
|
|
begin
|
|
if( reset = '1' ) then
|
|
count := 0 ;
|
|
ref_x_conjh_i <= (others =>'0') ;
|
|
ref_x_conjh_q <= (others =>'0') ;
|
|
ref_x_conjh_valid <= '0' ;
|
|
last_reg <= '0' ;
|
|
elsif( rising_edge(clock) ) then
|
|
last_reg <= last ;
|
|
ref_x_conjh_valid <= in_channel.valid ;
|
|
ref_x_conjh_i <= in_channel.i*in_reference.i + in_channel.q*in_reference.q ;
|
|
ref_x_conjh_q <= in_channel.i*in_reference.q - in_channel.q*in_reference.i ;
|
|
if( in_channel.valid = '1' ) then
|
|
if( first = '1' ) then
|
|
count := 1 ;
|
|
else
|
|
if( count < LONG_SEQ_LUT'high ) then
|
|
count := count + 1 ;
|
|
else
|
|
assert last = '1'
|
|
report "Last not high when expected for channel estimate"
|
|
severity error ;
|
|
count := 0 ;
|
|
end if ;
|
|
end if ;
|
|
end if ;
|
|
end if ;
|
|
end process ;
|
|
|
|
calc_magsq : process(clock, reset)
|
|
variable sample : wlan_sample_t := ( (others =>'0'), (others =>'0'), '0' );
|
|
begin
|
|
if( reset = '1' ) then
|
|
magsq <= (others =>'0') ;
|
|
magsq_valid <= '0' ;
|
|
sample := ( (others =>'0'), (others =>'0'), '0' ) ;
|
|
elsif( rising_edge(clock) ) then
|
|
magsq_valid <= in_channel.valid ;
|
|
if( in_channel.valid = '1' ) then
|
|
sample.i := resize(in_channel.i,sample.i'length) ;
|
|
sample.q := resize(in_channel.q,sample.q'length) ;
|
|
magsq <= resize(shift_right(unsigned(std_logic_vector(in_channel.i*in_channel.i + in_channel.q*in_channel.q)),12),magsq'length)+snr_bias ;
|
|
end if ;
|
|
end if ;
|
|
end process ;
|
|
|
|
-- Divide each value
|
|
U_div : entity work.wlan_divide
|
|
generic map (
|
|
SAMPLE_WIDTH => ref_x_conjh_i'length,
|
|
DENOM_WIDTH => magsq'length,
|
|
NUM_PIPELINE => magsq'length
|
|
) port map (
|
|
clock => clock,
|
|
reset => reset,
|
|
|
|
in_i => ref_x_conjh_i,
|
|
in_q => ref_x_conjh_q,
|
|
in_denom => magsq,
|
|
in_valid => magsq_valid,
|
|
in_done => last_reg,
|
|
|
|
out_i => div_i,
|
|
out_q => div_q,
|
|
out_valid => div_valid,
|
|
out_done => div_done
|
|
) ;
|
|
|
|
-- Outputs
|
|
out_inverted.i <= resize(div_i,out_inverted.i'length) ;
|
|
out_inverted.q <= resize(div_q,out_inverted.q'length) ;
|
|
out_inverted.valid <= div_valid ;
|
|
done <= div_done ;
|
|
|
|
end architecture ;
|
|
|