mirror of
https://github.com/Nuand/bladeRF-wiphy.git
synced 2025-03-10 22:43:53 +00:00
940 lines
37 KiB
VHDL
940 lines
37 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_tx_p.all ;
|
|
use wlan.wlan_rx_p.all ;
|
|
|
|
library nuand;
|
|
use nuand.fifo_readwrite_p.all;
|
|
|
|
library altera_mf ;
|
|
use altera_mf.altera_mf_components.all ;
|
|
|
|
entity wlan_top is
|
|
port (
|
|
rx_clock : in std_logic ;
|
|
rx_reset : in std_logic ;
|
|
rx_enable : in std_logic ;
|
|
|
|
tx_clock : in std_logic ;
|
|
tx_reset : in std_logic ;
|
|
tx_enable : in std_logic ;
|
|
|
|
config_reg : in std_logic_vector(31 downto 0 ) ;
|
|
|
|
packet_en : in std_logic ;
|
|
|
|
tx_packet_control : in packet_control_t ;
|
|
tx_packet_empty : in std_logic ;
|
|
tx_packet_ready : out std_logic ;
|
|
|
|
rx_packet_control : out packet_control_t ;
|
|
rx_packet_ready : in std_logic ;
|
|
|
|
rx_fifo_usedw : in std_logic_vector(11 downto 0);
|
|
rx_fifo_write : out std_logic ;
|
|
rx_fifo_full : in std_logic ;
|
|
rx_fifo_data : out std_logic_vector(31 downto 0) ;
|
|
|
|
tx_fifo_usedw : in std_logic_vector(11 downto 0);
|
|
tx_fifo_read : buffer std_logic ;
|
|
tx_fifo_empty : in std_logic ;
|
|
tx_fifo_data : in std_logic_vector(31 downto 0) ;
|
|
|
|
gain_inc_req : out std_logic ;
|
|
gain_dec_req : out std_logic ;
|
|
gain_rst_req : out std_logic ;
|
|
gain_ack : in std_logic ;
|
|
gain_nack : in std_logic ;
|
|
gain_lock : in std_logic ;
|
|
gain_max : in std_logic ;
|
|
|
|
tx_ota_req : out std_logic ;
|
|
tx_ota_ack : in std_logic ;
|
|
|
|
out_i : buffer signed(15 downto 0) ;
|
|
out_q : buffer signed(15 downto 0) ;
|
|
out_valid : buffer std_logic ;
|
|
wlan_tx_ota : buffer std_logic ;
|
|
|
|
in_i : in signed(15 downto 0) ;
|
|
in_q : in signed(15 downto 0) ;
|
|
in_valid : in std_logic
|
|
|
|
) ;
|
|
end entity ;
|
|
|
|
architecture arch of wlan_top is
|
|
|
|
type fsm_tx_t is (IDLE, WAIT_FOR_SOP, READ_HEADER, READ_VECTOR, VALID_VECTOR,
|
|
READ_PAYLOAD, READ_BLANKS, VALID_ACK, SEND_ACK, WAIT_TO_TX, WAIT_TO_ACK,
|
|
WAIT_FOR_ACK, WAIT_TO_RETRY_TX, VALID_RETRY_VECTOR,
|
|
READ_RETRY_FIFO, NO_ACK_RECEIVED, GOOD_ACK_RECEIVED, WRITE_ACK_TO_FIFO);
|
|
type fsm_rx_t is (IDLE, TX_ACK_HEADER, TX_ACK_WRITE, READ_VECTOR,
|
|
WAIT_TO_WRITE_HEADER, WRITE_HEADER, WRITE_PAYLOAD,
|
|
PAD_ZERO);
|
|
|
|
type state_rx_t is record
|
|
fsm : fsm_rx_t;
|
|
header : std_logic_vector(127 downto 0) ;
|
|
length : natural range 0 to 4096 ;
|
|
byte_index : natural range 0 to 3 ;
|
|
written_bytes : natural range 0 to 65536 ;
|
|
written_words : natural range 0 to 4096 ;
|
|
fifo_write : std_logic ;
|
|
rx_word : std_logic_vector(31 downto 0) ;
|
|
read_payload : std_logic ;
|
|
packet_control : packet_control_t ;
|
|
fifo_tx_ack_rreq : std_logic ;
|
|
end record;
|
|
|
|
type state_tx_t is record
|
|
fsm : fsm_tx_t ;
|
|
header : std_logic_vector(127 downto 0) ;
|
|
byte_index : natural range 0 to 3 ;
|
|
read_bytes : natural range 0 to 65536 ;
|
|
read_words : natural range 0 to 4096 ;
|
|
fifo_read : std_logic ;
|
|
tx_word : std_logic_vector(31 downto 0) ;
|
|
ready_for_packet : std_logic ;
|
|
|
|
tx_ack_required : std_logic ;
|
|
tx_ack_attempt : natural range 0 to 10;
|
|
tx_ack_timeout : natural range 0 to 25000;
|
|
tx_ack_fifo_rst : std_logic ;
|
|
tx_ack_fifo_write : std_logic ;
|
|
tx_packet_header : std_logic_vector(87 downto 0) ;
|
|
|
|
tx_packet_flags : std_logic_vector(15 downto 0) ;
|
|
tx_packet_cookie : std_logic_vector(31 downto 0) ;
|
|
|
|
fifo_tx_ack_wreq : std_logic ;
|
|
fifo_tx_ack_data : std_logic_vector( 63 downto 0 ) ;
|
|
|
|
timer : natural range 0 to 20000 ;
|
|
tx_vector : wlan_tx_vector_t ;
|
|
tx_vector_valid : std_logic ;
|
|
in_ack : std_logic ;
|
|
in_wait_for_ack : std_logic ;
|
|
|
|
tx_ota_req : std_logic ;
|
|
end record;
|
|
|
|
function datarate_to_lv( x : wlan_datarate_t ) return std_logic_vector is
|
|
variable rv : std_logic_vector(3 downto 0) ;
|
|
begin
|
|
case x is
|
|
when WLAN_RATE_6 => rv := x"0" ;
|
|
when WLAN_RATE_9 => rv := x"1" ;
|
|
when WLAN_RATE_12 => rv := x"2" ;
|
|
when WLAN_RATE_18 => rv := x"3" ;
|
|
when WLAN_RATE_24 => rv := x"4" ;
|
|
when WLAN_RATE_36 => rv := x"5" ;
|
|
when WLAN_RATE_48 => rv := x"6" ;
|
|
when WLAN_RATE_54 => rv := x"7" ;
|
|
when others => rv := x"0" ;
|
|
end case ;
|
|
return rv ;
|
|
end function ;
|
|
|
|
function bandwidth_to_lv( x : wlan_bandwidth_t ) return std_logic_vector is
|
|
variable rv : std_logic_vector(3 downto 0) ;
|
|
begin
|
|
case x is
|
|
when WLAN_BW_5 => rv := x"0" ;
|
|
when WLAN_BW_10 => rv := x"1" ;
|
|
when WLAN_BW_20 => rv := x"2" ;
|
|
when others => rv := x"0" ;
|
|
end case ;
|
|
return rv ;
|
|
end function ;
|
|
|
|
signal tx_vector : wlan_tx_vector_t ;
|
|
signal tx_vector_valid : std_logic ;
|
|
signal tx_status : wlan_tx_status_t ;
|
|
signal tx_status_valid : std_logic ;
|
|
signal tx_wlan_fifo_re : std_logic ;
|
|
signal tx_wlan_fifo_data : std_logic_vector(7 downto 0) ;
|
|
signal tx_wlan_fifo_empty : std_logic ;
|
|
signal bb : wlan_sample_t ;
|
|
signal done : std_Logic ;
|
|
signal scaled_out_i : signed(11 downto 0);
|
|
signal scaled_out_q : signed(11 downto 0);
|
|
|
|
function NULL_RX_STATE return state_rx_t is
|
|
variable rv : state_rx_t;
|
|
begin
|
|
rv.fsm := IDLE ;
|
|
rv.header := (others => '0' ) ;
|
|
rv.length := 0 ;
|
|
rv.byte_index := 0 ;
|
|
rv.written_words := 0 ;
|
|
rv.written_bytes := 0 ;
|
|
rv.fifo_write := '0' ;
|
|
rv.rx_word := (others => '0' ) ;
|
|
rv.read_payload := '0' ;
|
|
rv.fifo_tx_ack_rreq := '0';
|
|
return rv ;
|
|
end function ;
|
|
|
|
function NULL_TX_STATE return state_tx_t is
|
|
variable rv : state_tx_t;
|
|
begin
|
|
rv.fsm := IDLE ;
|
|
rv.read_words := 0 ;
|
|
rv.read_bytes := 0 ;
|
|
rv.header := (others => '0' ) ;
|
|
rv.tx_word := (others => '0' ) ;
|
|
|
|
rv.ready_for_packet := '0' ;
|
|
|
|
rv.tx_ack_required := '0' ;
|
|
rv.tx_ack_attempt := 3;
|
|
rv.tx_ack_timeout := 2500;
|
|
rv.tx_ack_fifo_rst := '0';
|
|
rv.tx_ack_fifo_write := '0';
|
|
rv.tx_packet_header := ( others => '0' );
|
|
|
|
rv.tx_packet_flags := ( others => '0' ) ;
|
|
rv.tx_packet_cookie := ( others => '0' ) ;
|
|
|
|
rv.fifo_tx_ack_wreq := '0' ;
|
|
rv.fifo_tx_ack_data := ( others => '0' ) ;
|
|
|
|
rv.timer := 0 ;
|
|
rv.byte_index := 0 ;
|
|
rv.fifo_read := '0' ;
|
|
rv.tx_vector_valid := '0' ;
|
|
rv.in_ack := '0' ;
|
|
rv.in_wait_for_ack := '0' ;
|
|
|
|
rv.tx_ota_req := '0' ;
|
|
return rv ;
|
|
end function ;
|
|
|
|
signal current_tx_state, future_tx_state : state_tx_t ;
|
|
signal current_rx_state, future_rx_state : state_rx_t ;
|
|
attribute keep: boolean;
|
|
attribute noprune: boolean;
|
|
attribute preserve: boolean;
|
|
|
|
attribute keep of tx_vector : signal is true;
|
|
attribute noprune of tx_vector : signal is true;
|
|
attribute preserve of tx_vector : signal is true;
|
|
|
|
attribute keep of done : signal is true;
|
|
attribute noprune of done : signal is true;
|
|
attribute preserve of done : signal is true;
|
|
|
|
attribute keep of current_tx_state : signal is true;
|
|
attribute noprune of current_tx_state : signal is true;
|
|
attribute preserve of current_tx_state : signal is true;
|
|
|
|
signal rx_end_of_packet : std_logic ;
|
|
signal rx_status : wlan_rx_status_t ;
|
|
signal rx_status_valid : std_logic ;
|
|
signal rx_vector : wlan_rx_vector_t ;
|
|
signal rx_vector_valid : std_logic ;
|
|
|
|
signal rx_data : std_logic_vector( 7 downto 0 ) ;
|
|
signal rx_data_valid : std_logic ;
|
|
signal rx_data_read : std_logic ;
|
|
|
|
signal ack_mac : std_logic_vector( 47 downto 0 ) ;
|
|
signal ack_valid : std_logic ;
|
|
|
|
signal tx_idle : std_logic ;
|
|
signal tx_difs_ready : std_logic ;
|
|
signal tx_sifs_ready : std_logic ;
|
|
|
|
signal tx_ack_ready : std_logic ;
|
|
signal tx_ack_re : std_logic ;
|
|
signal tx_ack_data : std_logic_vector( 7 downto 0 ) ;
|
|
|
|
signal rx_block : std_logic ;
|
|
signal rx_quiet : std_logic ;
|
|
|
|
signal tx_req : std_logic ;
|
|
|
|
signal ack_timer_val : unsigned( 15 downto 0 );
|
|
|
|
signal tx_retry_fifo_q : std_logic_vector( 7 downto 0 ) ;
|
|
signal tx_retry_fifo_rst : std_logic ;
|
|
signal tx_retry_fifo_empty : std_logic ;
|
|
signal tx_retry_fifo_usedw : std_logic_vector( 10 downto 0 ) ;
|
|
|
|
signal fifo_tx_ack_wfull : std_logic ;
|
|
|
|
signal fifo_tx_ack_q : std_logic_vector( 63 downto 0 ) ;
|
|
signal fifo_tx_ack_rempty : std_logic ;
|
|
|
|
signal tx_retry_fifo_data : std_logic_vector( 7 downto 0 ) ;
|
|
signal tx_retry_fifo_write : std_logic ;
|
|
signal tx_retry_fifo_read : std_logic ;
|
|
|
|
signal acked_packet : std_logic ;
|
|
begin
|
|
rx_block <= wlan_tx_ota;
|
|
--rx_block <= '0';
|
|
|
|
tx_req <= '1' when ( tx_packet_empty = '0' ) else '0' ;
|
|
U_dcf : entity work.wlan_dcf
|
|
port map (
|
|
rx_clock => rx_clock,
|
|
rx_reset => rx_reset,
|
|
rx_enable => rx_enable,
|
|
|
|
rand_lsb => in_i(0),
|
|
rand_valid => in_valid,
|
|
|
|
rx_quiet => rx_quiet,
|
|
|
|
rx_block => open,
|
|
|
|
tx_clock => tx_clock,
|
|
tx_reset => tx_reset,
|
|
tx_enable => tx_enable,
|
|
|
|
tx_req => tx_req,
|
|
tx_idle => not wlan_tx_ota,
|
|
|
|
tx_sifs_ready => tx_sifs_ready,
|
|
tx_difs_ready => tx_difs_ready
|
|
) ;
|
|
|
|
U_ack_gen : entity work.wlan_ack_generator
|
|
port map (
|
|
wclock => rx_clock,
|
|
wreset => rx_reset,
|
|
|
|
ack_mac => ack_mac,
|
|
ack_valid => ack_valid,
|
|
|
|
rclock => tx_clock,
|
|
rreset => tx_reset,
|
|
|
|
fifo_data => tx_ack_data,
|
|
fifo_re => tx_ack_re,
|
|
done_tx => done,
|
|
|
|
ack_ready => tx_ack_ready
|
|
) ;
|
|
|
|
U_wlan_rx : entity work.wlan_rx
|
|
port map (
|
|
clock40m => rx_clock,
|
|
reset40m => rx_reset,
|
|
|
|
bb_i => in_i,
|
|
bb_q => in_q,
|
|
bb_valid => in_valid,
|
|
|
|
equalized_i => open,
|
|
equalized_q => open,
|
|
equalized_valid => open,
|
|
|
|
gain_inc_req => gain_inc_req,
|
|
gain_dec_req => gain_dec_req,
|
|
gain_rst_req => gain_rst_req,
|
|
gain_ack => gain_ack,
|
|
gain_nack => gain_nack,
|
|
gain_lock => gain_lock,
|
|
gain_max => gain_max,
|
|
|
|
ack_mac => ack_mac,
|
|
ack_valid => ack_valid,
|
|
|
|
acked_packet => acked_packet,
|
|
|
|
rx_quiet => rx_quiet,
|
|
rx_block => rx_block,
|
|
|
|
rx_end_of_packet => rx_end_of_packet,
|
|
rx_status => rx_status,
|
|
rx_status_valid => rx_status_valid,
|
|
|
|
rx_vector => rx_vector,
|
|
rx_vector_valid => rx_vector_valid,
|
|
|
|
rx_data_req => current_rx_state.read_payload,
|
|
rx_data => rx_data,
|
|
rx_data_valid => rx_data_valid,
|
|
|
|
mse => open,
|
|
mse_valid => open
|
|
) ;
|
|
|
|
U_wlan_tx : entity work.wlan_tx
|
|
port map (
|
|
clock => tx_clock,
|
|
reset => tx_reset,
|
|
|
|
tx_vector => tx_vector,
|
|
tx_vector_valid => tx_vector_valid,
|
|
|
|
tx_status => tx_status,
|
|
tx_status_valid => tx_status_valid,
|
|
|
|
fifo_re => tx_wlan_fifo_re,
|
|
fifo_data => tx_wlan_fifo_data,
|
|
fifo_empty => tx_wlan_fifo_empty,
|
|
|
|
bb => bb,
|
|
done => done
|
|
) ;
|
|
|
|
wlan_tx_ota <= '1' when ( tx_ota_ack = '1' and current_tx_state.tx_ota_req = '1' ) else '0';
|
|
|
|
tx_idle <= '1' when (current_tx_state.fsm /= IDLE) else '0' ;
|
|
|
|
scaled_out_i <= to_signed( to_integer(bb.i/2 - bb.i/8 - bb.i/16), 12 ) ;
|
|
out_i <= scaled_out_i(11) & scaled_out_i(11) & scaled_out_i(11) & scaled_out_i(11) & scaled_out_i;
|
|
scaled_out_q <= to_signed( to_integer(bb.q/2 - bb.q/8 - bb.q/16), 12 ) ;
|
|
out_q <= scaled_out_q(11) & scaled_out_q(11) & scaled_out_q(11) & scaled_out_q(11) & scaled_out_q;
|
|
out_valid <= bb.valid;
|
|
|
|
rx_fifo_data <= current_rx_state.rx_word ;
|
|
rx_fifo_write <= current_rx_state.fifo_write ;
|
|
|
|
rx_packet_control.pkt_core_id <= ( others => '0' ) ;
|
|
rx_packet_control.pkt_flags <= ( others => '0' ) ;
|
|
rx_packet_control.pkt_sop <= current_rx_state.packet_control.pkt_sop ;
|
|
rx_packet_control.pkt_eop <= current_rx_state.packet_control.pkt_eop ;
|
|
rx_packet_control.data <= current_rx_state.rx_word ;
|
|
rx_packet_control.data_valid <= current_rx_state.fifo_write ;
|
|
|
|
rx_state_comb : process(all)
|
|
variable written_bytes : natural range 0 to 4096;
|
|
begin
|
|
future_rx_state <= current_rx_state;
|
|
future_rx_state.fifo_write <= '0' ;
|
|
future_rx_state.read_payload <= '0' ;
|
|
|
|
future_rx_state.fifo_tx_ack_rreq <= '0' ;
|
|
|
|
future_rx_state.packet_control.pkt_sop <= '0' ;
|
|
future_rx_state.packet_control.pkt_eop <= '0' ;
|
|
|
|
case current_rx_state.fsm is
|
|
|
|
when IDLE =>
|
|
if( fifo_tx_ack_rempty = '0' ) then
|
|
future_rx_state.fsm <= TX_ACK_HEADER;
|
|
end if;
|
|
|
|
if( rx_vector_valid = '1' ) then
|
|
future_rx_state.fsm <= READ_VECTOR ;
|
|
future_rx_state.header <= ( others => '0' ) ;
|
|
future_rx_state.rx_word <= ( others => '0' ) ;
|
|
end if ;
|
|
|
|
when TX_ACK_HEADER =>
|
|
future_rx_state.header(63 downto 0) <= fifo_tx_ack_q ;
|
|
future_rx_state.written_words <= 0 ;
|
|
if( rx_packet_ready = '1' ) then
|
|
future_rx_state.fifo_tx_ack_rreq <= '1' ;
|
|
future_rx_state.fsm <= TX_ACK_WRITE ;
|
|
end if;
|
|
|
|
when TX_ACK_WRITE =>
|
|
future_rx_state.rx_word <= current_rx_state.header(31 downto 0);
|
|
future_rx_state.header <= x"00000000" & current_rx_state.header(127 downto 32);
|
|
|
|
future_rx_state.fifo_write <= '1' ;
|
|
|
|
future_rx_state.written_words <= current_rx_state.written_words + 1 ;
|
|
if( current_rx_state.written_words = 0 ) then
|
|
future_rx_state.packet_control.pkt_sop <= '1' ;
|
|
elsif( current_rx_state.written_words = 3 ) then
|
|
future_rx_state.packet_control.pkt_eop <= '1' ;
|
|
future_rx_state.fsm <= IDLE;
|
|
end if;
|
|
|
|
when READ_VECTOR =>
|
|
future_rx_state.length <= rx_vector.length - 2 ; -- 2 for SERVICE, and 4 for FCS
|
|
future_rx_state.header(23 downto 0 ) <= x"0" & bandwidth_to_lv(rx_vector.bandwidth) & x"0001";
|
|
future_rx_state.header(31 downto 24) <= x"0" & datarate_to_lv(rx_vector.datarate);
|
|
future_rx_state.header(47 downto 32) <= std_logic_vector(to_unsigned(rx_vector.length - 2, 16));
|
|
future_rx_state.header(127 downto 48) <= ( others => '0' );
|
|
if( rx_packet_ready = '1' ) then
|
|
future_rx_state.fsm <= WRITE_HEADER ;
|
|
else
|
|
future_rx_state.fsm <= WAIT_TO_WRITE_HEADER ;
|
|
end if;
|
|
future_rx_state.byte_index <= 0 ;
|
|
|
|
when WAIT_TO_WRITE_HEADER =>
|
|
if( rx_packet_ready = '1' ) then
|
|
future_rx_state.fsm <= WRITE_HEADER ;
|
|
end if;
|
|
|
|
when WRITE_HEADER =>
|
|
future_rx_state.rx_word <= current_rx_state.header(31 downto 0);
|
|
if( current_rx_state.byte_index = 0 ) then
|
|
future_rx_state.packet_control.pkt_sop <= '1' ;
|
|
end if;
|
|
future_rx_state.fifo_write <= '1' ;
|
|
|
|
future_rx_state.header <= x"00000000" & current_rx_state.header(127 downto 32);
|
|
|
|
if( current_rx_state.byte_index = 3 ) then
|
|
future_rx_state.byte_index <= 0 ;
|
|
future_rx_state.written_words <= 4 ;
|
|
future_rx_state.written_bytes <= 1 ;
|
|
future_rx_state.fsm <= WRITE_PAYLOAD ;
|
|
else
|
|
future_rx_state.byte_index <= current_rx_state.byte_index + 1 ;
|
|
end if ;
|
|
|
|
when WRITE_PAYLOAD =>
|
|
future_rx_state.read_payload <= '1' ;
|
|
if( rx_data_valid = '1' ) then
|
|
if( current_rx_state.byte_index = 3 ) then
|
|
future_rx_state.rx_word(31 downto 24) <= rx_data ;
|
|
elsif( current_rx_state.byte_index = 2 ) then
|
|
future_rx_state.rx_word(23 downto 16) <= rx_data ;
|
|
elsif( current_rx_state.byte_index = 1 ) then
|
|
future_rx_state.rx_word(15 downto 8) <= rx_data ;
|
|
elsif( current_rx_state.byte_index = 0 ) then
|
|
future_rx_state.rx_word(7 downto 0) <= rx_data ;
|
|
end if ;
|
|
future_rx_state.written_bytes <= current_rx_state.written_bytes + 1 ;
|
|
|
|
if( current_rx_state.byte_index = 3 ) then
|
|
future_rx_state.fifo_write <= '1' ;
|
|
future_rx_state.written_words <= current_rx_state.written_words + 1 ;
|
|
if( current_rx_state.written_bytes = current_rx_state.length ) then
|
|
future_rx_state.packet_control.pkt_eop <= '1' ;
|
|
end if;
|
|
future_rx_state.byte_index <= 0 ;
|
|
else
|
|
future_rx_state.byte_index <= current_rx_state.byte_index + 1 ;
|
|
end if ;
|
|
end if ;
|
|
if( rx_end_of_packet = '1' or current_rx_state.length <= current_rx_state.written_bytes ) then
|
|
future_rx_state.fsm <= PAD_ZERO ;
|
|
end if ;
|
|
|
|
when PAD_ZERO =>
|
|
if( current_rx_state.byte_index = 3 ) then
|
|
future_rx_state.rx_word(31 downto 24) <= x"00" ;
|
|
elsif( current_rx_state.byte_index = 2 ) then
|
|
future_rx_state.rx_word(31 downto 16) <= x"0000" ;
|
|
elsif( current_rx_state.byte_index = 1 ) then
|
|
future_rx_state.rx_word(31 downto 8) <= x"000000" ;
|
|
elsif( current_rx_state.byte_index = 0 ) then
|
|
future_rx_state.rx_word(31 downto 0) <= ( others => '0' ) ;
|
|
end if ;
|
|
|
|
future_rx_state.fsm <= IDLE ;
|
|
|
|
if( current_rx_state.byte_index /= 0 ) then
|
|
future_rx_state.packet_control.pkt_eop <= '1' ;
|
|
future_rx_state.fifo_write <= '1' ;
|
|
end if ;
|
|
|
|
end case ;
|
|
end process ;
|
|
|
|
process( rx_clock, rx_reset )
|
|
begin
|
|
if( rx_reset = '1' ) then
|
|
current_rx_state <= NULL_RX_STATE ;
|
|
elsif( rising_edge(rx_clock) ) then
|
|
current_rx_state <= future_rx_state ;
|
|
end if ;
|
|
end process ;
|
|
|
|
|
|
tx_packet_ready <= '1' when ( current_tx_state.fifo_read = '1' or current_tx_state.ready_for_packet = '1' ) else '0' ;
|
|
|
|
tx_vector_valid <= current_tx_state.tx_vector_valid ;
|
|
tx_vector <= current_tx_state.tx_vector ;
|
|
tx_ota_req <= current_tx_state.tx_ota_req ;
|
|
ack_timer_val <= unsigned(config_reg(15 downto 0));
|
|
|
|
tx_state_comb : process(all)
|
|
begin
|
|
future_tx_state <= current_tx_state;
|
|
|
|
case current_tx_state.fsm is
|
|
when SEND_ACK =>
|
|
tx_wlan_fifo_data <= tx_ack_data ;
|
|
tx_retry_fifo_read <= '0';
|
|
tx_ack_re <= tx_wlan_fifo_re ;
|
|
when READ_RETRY_FIFO =>
|
|
if( current_tx_state.read_bytes = 1 ) then
|
|
tx_wlan_fifo_data <= tx_retry_fifo_q or x"08";
|
|
else
|
|
tx_wlan_fifo_data <= tx_retry_fifo_q;
|
|
end if;
|
|
tx_retry_fifo_read <= tx_wlan_fifo_re;
|
|
tx_ack_re <= '0' ;
|
|
when others =>
|
|
case current_tx_state.byte_index is
|
|
when 0 => tx_wlan_fifo_data <= current_tx_state.tx_word( 7 downto 0) ;
|
|
when 1 => tx_wlan_fifo_data <= current_tx_state.tx_word(15 downto 8) ;
|
|
when 2 => tx_wlan_fifo_data <= current_tx_state.tx_word(23 downto 16) ;
|
|
when 3 => tx_wlan_fifo_data <= current_tx_state.tx_word(31 downto 24) ;
|
|
end case;
|
|
tx_retry_fifo_read <= '0';
|
|
tx_ack_re <= '0' ;
|
|
end case ;
|
|
|
|
if( current_tx_state.fsm = READ_RETRY_FIFO or current_tx_state.fsm = READ_PAYLOAD) then
|
|
tx_retry_fifo_write <= tx_wlan_fifo_re;
|
|
else
|
|
tx_retry_fifo_write <= '0';
|
|
end if;
|
|
|
|
future_tx_state.fifo_read <= '0';
|
|
future_tx_state.tx_vector_valid <= '0';
|
|
future_tx_state.ready_for_packet <= '0';
|
|
|
|
future_tx_state.tx_ack_fifo_rst <= '0';
|
|
future_tx_state.tx_ack_fifo_write <= '0';
|
|
|
|
future_tx_state.fifo_tx_ack_wreq <= '0' ;
|
|
|
|
case current_tx_state.fsm is
|
|
|
|
when IDLE =>
|
|
if( tx_ack_ready = '1' ) then
|
|
future_tx_state.timer <= 5; --to_integer(ack_timer_val) ;
|
|
|
|
future_tx_state.fsm <= WAIT_TO_ACK ;
|
|
|
|
elsif( tx_difs_ready = '1' and tx_packet_empty = '0' ) then
|
|
future_tx_state.timer <= 400 ; -- move back to 2500
|
|
future_tx_state.tx_ota_req <= '1' ;
|
|
|
|
future_tx_state.fsm <= WAIT_TO_TX ;
|
|
|
|
future_tx_state.read_words <= 0 ;
|
|
else
|
|
future_tx_state <= NULL_TX_STATE;
|
|
end if;
|
|
|
|
when WAIT_TO_ACK =>
|
|
future_tx_state.in_ack <= '1' ;
|
|
|
|
future_tx_state.tx_vector.datarate <= WLAN_RATE_6 ;
|
|
future_tx_state.tx_vector.bandwidth <= WLAN_BW_20 ;
|
|
future_tx_state.tx_vector.length <= 10 ;
|
|
if( current_tx_state.timer = 0 ) then
|
|
future_tx_state.timer <= 20 ; -- move back to 2500
|
|
future_tx_state.tx_ota_req <= '1' ;
|
|
future_tx_state.fsm <= WAIT_TO_TX ;
|
|
else
|
|
future_tx_state.timer <= current_tx_state.timer - 1 ;
|
|
end if ;
|
|
|
|
when WAIT_TO_TX =>
|
|
if( current_tx_state.timer = 0 ) then
|
|
if( tx_ota_ack = '1' ) then
|
|
if( current_tx_state.in_ack = '1' ) then
|
|
future_tx_state.fsm <= VALID_ACK;
|
|
else
|
|
future_tx_state.ready_for_packet <= '1';
|
|
future_tx_state.fsm <= WAIT_FOR_SOP;
|
|
end if ;
|
|
end if ;
|
|
else
|
|
future_tx_state.timer <= current_tx_state.timer - 1 ;
|
|
end if ;
|
|
|
|
when VALID_ACK =>
|
|
future_tx_state.fsm <= SEND_ACK ;
|
|
future_tx_state.tx_vector_valid <= '1' ;
|
|
|
|
when SEND_ACK =>
|
|
if( done = '1' ) then
|
|
if( current_tx_state.in_wait_for_ack = '1' ) then
|
|
future_tx_state.fsm <= WAIT_FOR_ACK;
|
|
else
|
|
future_tx_state.fsm <= IDLE;
|
|
end if;
|
|
future_tx_state.in_ack <= '0' ;
|
|
future_tx_state.tx_ota_req <= '0' ;
|
|
end if ;
|
|
|
|
when WAIT_FOR_SOP =>
|
|
if( tx_packet_control.pkt_sop = '1' ) then
|
|
future_tx_state.header <= tx_packet_control.data & current_tx_state.header(127 downto 32) ;
|
|
future_tx_state.read_words <= current_tx_state.read_words + 1;
|
|
|
|
future_tx_state.ready_for_packet <= '0';
|
|
future_tx_state.fsm <= READ_HEADER;
|
|
else
|
|
future_tx_state.ready_for_packet <= '1';
|
|
end if;
|
|
|
|
when READ_HEADER =>
|
|
if( current_tx_state.read_words <= 2 ) then
|
|
future_tx_state.fifo_read <= '1';
|
|
else
|
|
future_tx_state.fifo_read <= '0';
|
|
end if;
|
|
|
|
if( tx_packet_control.data_valid = '1' ) then
|
|
future_tx_state.header <= tx_packet_control.data & current_tx_state.header(127 downto 32) ;
|
|
future_tx_state.read_words <= current_tx_state.read_words + 1;
|
|
if( current_tx_state.read_words = 2 ) then
|
|
future_tx_state.fifo_read <= '0';
|
|
end if;
|
|
end if ;
|
|
|
|
if( current_tx_state.read_words >= 3 ) then
|
|
future_tx_state.fsm <= READ_VECTOR ;
|
|
end if ;
|
|
|
|
when READ_VECTOR =>
|
|
future_tx_state.fsm <= VALID_VECTOR ;
|
|
future_tx_state.tx_vector.length <= to_integer(signed(current_tx_state.header(79 downto 64))) ;
|
|
-- no ack <= current_tx_state.header(31 downto 16) (3rd and 4th bytes, currently reserverd)
|
|
-- cookie <= current_tx_state.header(127 downto 96)
|
|
future_tx_state.tx_packet_flags <= current_tx_state.header(31 downto 16);
|
|
future_tx_state.tx_packet_cookie <= current_tx_state.header(127 downto 96);
|
|
|
|
case current_tx_state.header(47 downto 32) is
|
|
when x"0000" => future_tx_state.tx_vector.datarate <= WLAN_RATE_6 ;
|
|
when x"0001" => future_tx_state.tx_vector.datarate <= WLAN_RATE_9 ;
|
|
when x"0002" => future_tx_state.tx_vector.datarate <= WLAN_RATE_12 ;
|
|
when x"0003" => future_tx_state.tx_vector.datarate <= WLAN_RATE_18 ;
|
|
when x"0004" => future_tx_state.tx_vector.datarate <= WLAN_RATE_24 ;
|
|
when x"0005" => future_tx_state.tx_vector.datarate <= WLAN_RATE_36 ;
|
|
when x"0006" => future_tx_state.tx_vector.datarate <= WLAN_RATE_48 ;
|
|
when x"0007" => future_tx_state.tx_vector.datarate <= WLAN_RATE_54 ;
|
|
when others => future_tx_state.tx_vector.datarate <= WLAN_RATE_6 ;
|
|
end case;
|
|
|
|
case current_tx_state.header(63 downto 48) is
|
|
when x"0000" => future_tx_state.tx_vector.bandwidth <= WLAN_BW_5 ;
|
|
when x"0001" => future_tx_state.tx_vector.bandwidth <= WLAN_BW_10 ;
|
|
when x"0002" => future_tx_state.tx_vector.bandwidth <= WLAN_BW_20 ;
|
|
when others => future_tx_state.tx_vector.bandwidth <= WLAN_BW_5 ;
|
|
end case;
|
|
|
|
when VALID_VECTOR =>
|
|
future_tx_state.tx_word <= tx_packet_control.data ;
|
|
|
|
future_tx_state.fifo_read <= '1';
|
|
future_tx_state.read_words <= current_tx_state.read_words + 1;
|
|
|
|
future_tx_state.tx_vector_valid <= '1' ;
|
|
future_tx_state.fsm <= READ_PAYLOAD ;
|
|
|
|
future_tx_state.tx_ack_fifo_rst <= '1';
|
|
|
|
future_tx_state.read_bytes <= 1;
|
|
|
|
when READ_PAYLOAD =>
|
|
--if( tx_packet_control.pkt_eop = '1' ) then
|
|
-- future_tx_state.fsm <= FINISH_PACKET;
|
|
--end if;
|
|
if( tx_wlan_fifo_re = '1') then
|
|
|
|
-- figure out TX packet's ACK requirements
|
|
if( current_tx_state.read_bytes <= 10 ) then
|
|
future_tx_state.tx_packet_header <=
|
|
current_tx_state.tx_packet_header(79 downto 0) & tx_wlan_fifo_data ;
|
|
end if;
|
|
if( current_tx_state.read_bytes = 11 ) then
|
|
if( current_tx_state.tx_packet_header(75 downto 74) = "01" or
|
|
current_tx_state.tx_packet_header(47 downto 0) = x"FFFFFFFFFFFF" ) then
|
|
future_tx_state.tx_ack_required <= '0';
|
|
else
|
|
future_tx_state.tx_ack_required <= '1';
|
|
future_tx_state.tx_ack_attempt <= 1;
|
|
future_tx_state.tx_ack_timeout <= 0;
|
|
end if;
|
|
end if;
|
|
|
|
future_tx_state.read_bytes <= current_tx_state.read_bytes + 1 ;
|
|
|
|
if (current_tx_state.byte_index = 3) then
|
|
future_tx_state.fifo_read <= '1';
|
|
future_tx_state.read_words <= current_tx_state.read_words + 1;
|
|
|
|
future_tx_state.tx_word <= tx_packet_control.data ;
|
|
future_tx_state.byte_index <= 0;
|
|
else
|
|
future_tx_state.byte_index <= current_tx_state.byte_index + 1 ;
|
|
end if;
|
|
end if;
|
|
if( done = '1' ) then
|
|
future_tx_state.tx_ota_req <= '0' ;
|
|
if( current_tx_state.tx_ack_required = '1' ) then
|
|
future_tx_state.tx_ack_timeout <= 0;
|
|
future_tx_state.fsm <= WAIT_FOR_ACK;
|
|
else
|
|
future_tx_state <= NULL_TX_STATE ;
|
|
end if;
|
|
end if;
|
|
|
|
when WAIT_FOR_ACK =>
|
|
future_tx_state.in_wait_for_ack <= '1' ;
|
|
|
|
if( acked_packet = '1' ) then
|
|
future_tx_state.fsm <= GOOD_ACK_RECEIVED ;
|
|
future_tx_state.in_wait_for_ack <= '0' ;
|
|
end if;
|
|
|
|
if( current_tx_state.tx_ack_timeout = 2500) then
|
|
if( current_tx_state.tx_ack_attempt = 0) then
|
|
future_tx_state.fsm <= NO_ACK_RECEIVED;
|
|
else
|
|
if( tx_ack_ready = '1' ) then
|
|
future_tx_state.fsm <= WAIT_TO_ACK;
|
|
elsif( tx_difs_ready = '1' ) then
|
|
future_tx_state.in_wait_for_ack <= '0' ;
|
|
future_tx_state.fsm <= WAIT_TO_RETRY_TX;
|
|
future_tx_state.timer <= 2500 ;
|
|
future_tx_state.tx_ota_req <= '1' ;
|
|
end if;
|
|
end if;
|
|
else
|
|
future_tx_state.tx_ack_timeout <= current_tx_state.tx_ack_timeout + 1;
|
|
end if;
|
|
|
|
when WAIT_TO_RETRY_TX =>
|
|
if( current_tx_state.timer = 0 ) then
|
|
if( tx_ota_ack = '1' ) then
|
|
future_tx_state.fsm <= VALID_RETRY_VECTOR;
|
|
end if;
|
|
else
|
|
future_tx_state.timer <= current_tx_state.timer - 1 ;
|
|
end if ;
|
|
|
|
when VALID_RETRY_VECTOR =>
|
|
future_tx_state.tx_ack_attempt <= current_tx_state.tx_ack_attempt - 1;
|
|
case current_tx_state.tx_vector.datarate is
|
|
when WLAN_RATE_9 => future_tx_state.tx_vector.datarate <= WLAN_RATE_6;
|
|
when WLAN_RATE_12 => future_tx_state.tx_vector.datarate <= WLAN_RATE_9;
|
|
when WLAN_RATE_18 => future_tx_state.tx_vector.datarate <= WLAN_RATE_12;
|
|
when WLAN_RATE_24 => future_tx_state.tx_vector.datarate <= WLAN_RATE_18;
|
|
when WLAN_RATE_36 => future_tx_state.tx_vector.datarate <= WLAN_RATE_24;
|
|
when WLAN_RATE_48 => future_tx_state.tx_vector.datarate <= WLAN_RATE_36;
|
|
when WLAN_RATE_54 => future_tx_state.tx_vector.datarate <= WLAN_RATE_48;
|
|
when others => future_tx_state.tx_vector.datarate <= WLAN_RATE_6;
|
|
end case;
|
|
future_tx_state.tx_vector_valid <= '1' ;
|
|
future_tx_state.fsm <= READ_RETRY_FIFO;
|
|
future_tx_state.read_bytes <= 0;
|
|
|
|
when READ_RETRY_FIFO =>
|
|
if( tx_wlan_fifo_re = '1') then
|
|
future_tx_state.read_bytes <= current_tx_state.read_bytes + 1;
|
|
end if;
|
|
if( done = '1' ) then
|
|
future_tx_state.tx_ota_req <= '0' ;
|
|
future_tx_state.tx_ack_timeout <= 0;
|
|
future_tx_state.fsm <= WAIT_FOR_ACK;
|
|
end if;
|
|
|
|
when GOOD_ACK_RECEIVED =>
|
|
future_tx_state.fifo_tx_ack_data(15 downto 0 ) <= x"0002" ;
|
|
future_tx_state.fifo_tx_ack_data(23 downto 16) <= x"0" & bandwidth_to_lv(current_tx_state.tx_vector.bandwidth) ;
|
|
future_tx_state.fifo_tx_ack_data(31 downto 24) <= x"0" & datarate_to_lv(current_tx_state.tx_vector.datarate) ;
|
|
future_tx_state.fifo_tx_ack_data(63 downto 32) <= current_tx_state.tx_packet_cookie;
|
|
if( fifo_tx_ack_wfull = '0' ) then
|
|
future_tx_state.fifo_tx_ack_wreq <= '1' ;
|
|
future_tx_state.fsm <= WRITE_ACK_TO_FIFO;
|
|
end if;
|
|
when NO_ACK_RECEIVED =>
|
|
future_tx_state.fifo_tx_ack_data(15 downto 0 ) <= x"0003" ;
|
|
future_tx_state.fifo_tx_ack_data(23 downto 16) <= x"0" & bandwidth_to_lv(current_tx_state.tx_vector.bandwidth) ;
|
|
future_tx_state.fifo_tx_ack_data(31 downto 24) <= x"0" & datarate_to_lv(current_tx_state.tx_vector.datarate) ;
|
|
future_tx_state.fifo_tx_ack_data(63 downto 32) <= current_tx_state.tx_packet_cookie;
|
|
if( fifo_tx_ack_wfull = '0' ) then
|
|
future_tx_state.fifo_tx_ack_wreq <= '1' ;
|
|
future_tx_state.fsm <= WRITE_ACK_TO_FIFO;
|
|
end if;
|
|
|
|
when WRITE_ACK_TO_FIFO =>
|
|
future_tx_state <= NULL_TX_STATE;
|
|
|
|
when others =>
|
|
future_tx_state <= NULL_TX_STATE;
|
|
end case;
|
|
end process ;
|
|
|
|
U_fifo_tx_retry : scfifo
|
|
generic map (
|
|
lpm_width => 8,
|
|
lpm_widthu => 11,
|
|
lpm_numwords => 1600,
|
|
lpm_showahead => "ON"
|
|
) port map (
|
|
clock => tx_clock,
|
|
aclr => tx_reset,
|
|
sclr => tx_retry_fifo_rst,
|
|
data => tx_wlan_fifo_data,
|
|
wrreq => tx_retry_fifo_write,
|
|
rdreq => tx_retry_fifo_read,
|
|
q => tx_retry_fifo_q,
|
|
full => open,
|
|
empty => tx_retry_fifo_empty,
|
|
usedw => tx_retry_fifo_usedw
|
|
) ;
|
|
tx_retry_fifo_rst <= current_tx_state.tx_ack_fifo_rst;
|
|
|
|
process( tx_clock, tx_reset )
|
|
begin
|
|
if( tx_reset = '1' ) then
|
|
current_tx_state <= NULL_TX_STATE ;
|
|
elsif( rising_edge(tx_clock) ) then
|
|
current_tx_state <= future_tx_state ;
|
|
end if ;
|
|
end process ;
|
|
|
|
U_fifo_tx_ack: dcfifo
|
|
generic map (
|
|
lpm_width => 64,
|
|
lpm_widthu => 3,
|
|
lpm_numwords => 8,
|
|
lpm_showahead => "ON"
|
|
)
|
|
port map (
|
|
aclr => tx_reset,
|
|
|
|
wrclk => tx_clock,
|
|
wrreq => current_tx_state.fifo_tx_ack_wreq,
|
|
data => current_tx_state.fifo_tx_ack_data,
|
|
|
|
wrfull => fifo_tx_ack_wfull,
|
|
wrempty => open,
|
|
wrusedw => open,
|
|
|
|
rdclk => rx_clock,
|
|
rdreq => current_rx_state.fifo_tx_ack_rreq,
|
|
q => fifo_tx_ack_q,
|
|
|
|
rdfull => open,
|
|
rdempty => fifo_tx_ack_rempty,
|
|
rdusedw => open
|
|
) ;
|
|
end architecture ;
|
|
|