Initial commit

This commit is contained in:
Nuand 2020-12-30 23:11:59 -08:00
commit 3e751f3e37
89 changed files with 15702 additions and 0 deletions

339
LICENSE Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
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.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

109
fpga/common/wlan_files.tcl Normal file
View File

@ -0,0 +1,109 @@
if { $modelsim == 1 } {
if { [info exists wlan_path ] } {
set here $wlan_path
} else {
set here ""
}
} else {
set here $::quartus(qip_path)
}
set wlan_common [list \
[file normalize [ file join $here ../vhdl/wlan_p.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_tx_p.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_rx_p.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_interleaver_p.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_lfsr.vhd] ] \
[file normalize [ file join $here ../vhdl/clock_sync_logic.vhd] ] \
[file normalize [ file join $here ../vhdl/clock_sync_params.vhd] ] \
[file normalize [ file join $here ../vhdl/clock_sync_logic_vector.vhd] ] \
] ;
set wlan_synthesis_tx [list \
[file normalize [ file join $here ../vhdl/wlan_descrambler.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_viterbi_encoder.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_scrambler.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_crc.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_framer.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_encoder.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_modulator.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_interleaver.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_ifft64.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_tx_short.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_tx_long.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_tx_controller.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_sample_buffer.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_symbol_shaper.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_tx.vhd] ] \
] ;
set wlan_synthesis_rx [ list \
[file normalize [ file join $here ../ip/nuand/cordic.vhd] ] \
[file normalize [ file join $here ../ip/nuand/nco.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_agc.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_agc_drv.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dsss_despreader.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dsss_plcp_crc.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dsss_p_norm.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dsss_demodulator.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dsss_peak_finder.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dsss_rx_controller.vhd] ]\
[file normalize [ file join $here ../vhdl/wlan_dsss_rx_framer.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dsss_rx.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_divide.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_channel_inverter.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_clamper.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_crc.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_rx_packet_buffer.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_rx_framer.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_csma.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_bsd.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_clamper.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_viterbi_decoder.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_depuncturer.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_deinterleaver.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_phase_correction.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_demodulator.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_equalizer.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_fft64.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_rx_controller.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_cfo_correction.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_cfo_estimate.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_peak_finder.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_delay_correlator.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_correlator.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_p_norm.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_acquisition.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_rx.vhd] ] \
] ;
set wlan_synthesis_top [ list \
[file normalize [ file join $here ../vhdl/wlan_ack_generator.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_dcf.vhd] ] \
[file normalize [ file join $here ../vhdl/wlan_top.vhd] ] \
] ;
set wlan_sim [ list \
[file normalize [ file join $here ../vhdl/tb/wlan_clock_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_viterbi_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_dsss_plcp_crc_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_sample_loader.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_sample_saver.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_tables_p.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_peak_finder_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_symbol_shaper_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_viterbi_encoder_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_lfsr_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_modulator_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_interleaver_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_tx_short_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_tx_long_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_ack_generator_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_acquisition_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_tx_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_rx_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_top_tb.vhd] ] \
[file normalize [ file join $here ../vhdl/tb/wlan_channel_inverter_tb.vhd] ]\
[file normalize [ file join $here ../vhdl/tb/wlan_tb.vhd] ] \
] ;

201
fpga/ip/nuand/cordic.vhd Normal file
View File

@ -0,0 +1,201 @@
-- 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 ;
package cordic_p is
-- Vectoring mode forces outputs.y to 0
-- Rotation mode forces outputs.z to 0
type cordic_mode_t is (CORDIC_ROTATION, CORDIC_VECTORING) ;
-- TODO: Make this a generic package
type cordic_xyz_t is record
x : signed(15 downto 0) ;
y : signed(15 downto 0) ;
z : signed(15 downto 0) ;
valid : std_logic ;
end record ;
end package ; -- cordic_p
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
use ieee.math_real.all ;
library work ;
use work.cordic_p.all ;
entity cordic is
port (
clock : in std_logic ;
reset : in std_logic ;
mode : in cordic_mode_t ;
inputs : in cordic_xyz_t ;
normalized : out cordic_xyz_t ;
outputs : out cordic_xyz_t
) ;
end entity ; -- cordic
architecture arch of cordic is
-- TODO: Make this generic
constant NUM_STAGES : natural := 14 ;
-- TODO: Use the VHDL-2008 integer_vector
type integer_array_t is array(natural range <>) of integer ;
-- Each stage of the CORDIC is atan(2^(-i))
function calculate_cordic_table return integer_array_t is
variable rv : integer_array_t(0 to NUM_STAGES-1) := (others => 0) ;
begin
for i in 0 to rv'high loop
rv(i) := integer(round((2.0**NUM_STAGES)*arctan(2.0**(-i))/MATH_PI)) ;
end loop ;
return rv ;
end function ;
-- Constant array
constant K : integer_array_t := calculate_cordic_table ;
-- The array for CORDIC stages
type xyzs_t is array(0 to NUM_STAGES-1) of cordic_xyz_t ;
-- ALl the XYZ's for the CORDIC stages
signal xyzs : xyzs_t ;
signal nxyzs : xyzs_t ;
signal nflip : std_logic_vector(0 to NUM_STAGES-1) ;
begin
rotate : process(clock, reset)
begin
if( reset = '1' ) then
xyzs <= (others =>(x => (others =>'0'), y => (others =>'0'), z => (others =>'0'), valid => '0')) ;
nxyzs <= (others =>(x => (others =>'0'), y => (others =>'0'), z => (others =>'0'), valid => '0')) ;
nflip <= (others => '0') ;
elsif( rising_edge( clock ) ) then
-- First stage will rotate the vector to be within -pi/2 to pi/2
xyzs(0).valid <= inputs.valid ;
nxyzs(0).valid <= inputs.valid ;
if( inputs.valid = '1' ) then
case mode is
when CORDIC_ROTATION =>
-- Make sure we're only rotating -pi/2 to pi/2 and adjust accordingly
if( inputs.z > 2**(NUM_STAGES-1) ) then
xyzs(0).x <= -inputs.x ;
xyzs(0).y <= -inputs.y ;
xyzs(0).z <= inputs.z - 2**NUM_STAGES ;
elsif( inputs.z < -(2**(NUM_STAGES-1)) ) then
xyzs(0).x <= -inputs.x ;
xyzs(0).y <= -inputs.y ;
xyzs(0).z <= inputs.z + 2**NUM_STAGES ;
else
xyzs(0).x <= inputs.x ;
xyzs(0).y <= inputs.y ;
xyzs(0).z <= inputs.z ;
end if ;
when CORDIC_VECTORING =>
nxyzs(0).x <= to_signed(1243, nxyzs(0).x'length) ;
nxyzs(0).y <= (others => '0') ;
nflip(0) <= '1' ;
-- Make sure we're in the 1st or 4th quadrant only
if( inputs.x < 0 and inputs.y < 0 ) then
xyzs(0).x <= -inputs.x ;
xyzs(0).y <= -inputs.y ;
xyzs(0).z <= inputs.z - 2**(NUM_STAGES) ;
elsif( inputs.x < 0 ) then
xyzs(0).x <= -inputs.x ;
xyzs(0).y <= -inputs.y ;
xyzs(0).z <= inputs.z + 2**(NUM_STAGES) ;
else
xyzs(0).x <= inputs.x ;
xyzs(0).y <= inputs.y ;
xyzs(0).z <= inputs.z ;
nflip(0) <= '0' ;
end if ;
end case ;
end if ;
-- Run through all the other stages
for i in 0 to xyzs'high-1 loop
xyzs(i+1).valid <= xyzs(i).valid ;
nxyzs(i+1).valid <= nxyzs(i).valid ;
nflip(i+1) <= nflip(i) ;
if( xyzs(i).valid = '1' ) then
case mode is
when CORDIC_ROTATION =>
if( xyzs(i).z < 0 ) then
xyzs(i+1).x <= xyzs(i).x + shift_right(xyzs(i).y, i) ;
xyzs(i+1).y <= xyzs(i).y - shift_right(xyzs(i).x, i) ;
xyzs(i+1).z <= xyzs(i).z + K(i) ;
else
xyzs(i+1).x <= xyzs(i).x - shift_right(xyzs(i).y, i) ;
xyzs(i+1).y <= xyzs(i).y + shift_right(xyzs(i).x, i) ;
xyzs(i+1).z <= xyzs(i).z - K(i) ;
end if ;
when CORDIC_VECTORING =>
if( xyzs(i).y < 0 ) then
xyzs(i+1).x <= xyzs(i).x - shift_right(xyzs(i).y, i) ;
xyzs(i+1).y <= xyzs(i).y + shift_right(xyzs(i).x, i) ;
xyzs(i+1).z <= xyzs(i).z - K(i) ;
nxyzs(i+1).x <= nxyzs(i).x + shift_right(nxyzs(i).y, i) ;
nxyzs(i+1).y <= nxyzs(i).y - shift_right(nxyzs(i).x, i) ;
else
xyzs(i+1).x <= xyzs(i).x + shift_right(xyzs(i).y, i) ;
xyzs(i+1).y <= xyzs(i).y - shift_right(xyzs(i).x, i) ;
xyzs(i+1).z <= xyzs(i).z + K(i) ;
nxyzs(i+1).x <= nxyzs(i).x - shift_right(nxyzs(i).y, i) ;
nxyzs(i+1).y <= nxyzs(i).y + shift_right(nxyzs(i).x, i) ;
end if ;
end case ;
end if ;
end loop ;
-- Output stage
outputs <= xyzs(xyzs'high) ;
end if ;
end process ;
normalized_output : process(clock, reset)
begin
if( reset = '1' ) then
normalized <= (x => (others =>'0'), y => (others =>'0'), z => (others =>'0'), valid => '0') ;
elsif( rising_edge( clock ) ) then
normalized.valid <= '0' ;
if( nxyzs(nxyzs'high).valid = '1' ) then
if( nflip(nflip'high) = '1' ) then
normalized.x <= - nxyzs(nxyzs'high).x ;
normalized.y <= - nxyzs(nxyzs'high).y ;
else
normalized.x <= nxyzs(nxyzs'high).x ;
normalized.y <= nxyzs(nxyzs'high).y ;
end if ;
normalized.valid <= '1' ;
end if ;
end if ;
end process ;
end architecture ; -- arch

97
fpga/ip/nuand/nco.vhd Normal file
View File

@ -0,0 +1,97 @@
-- 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 ;
package nco_p is
type nco_input_t is record
dphase : signed(15 downto 0) ;
valid : std_logic ;
end record ;
type nco_output_t is record
re : signed(15 downto 0) ;
im : signed(15 downto 0) ;
valid : std_logic ;
end record ;
end package ; -- nco_p
library ieee ;
use ieee.std_logic_1164.all ;
use ieee.numeric_std.all ;
library work ;
use work.cordic_p.all ;
use work.nco_p.all ;
entity nco is
port (
clock : in std_logic ;
reset : in std_logic ;
inputs : in nco_input_t ;
outputs : out nco_output_t
) ;
end entity ; -- nco
architecture arch of nco is
signal phase : signed(15 downto 0) ;
signal cordic_inputs : cordic_xyz_t ;
signal cordic_outputs : cordic_xyz_t ;
begin
accumulate_phase : process(clock, reset)
variable temp : signed(15 downto 0) ;
begin
if( reset = '1' ) then
phase <= (others =>'0') ;
elsif( rising_edge( clock ) ) then
if( inputs.valid = '1' ) then
temp := phase + inputs.dphase ;
if( temp > 16384 ) then
temp := temp - 32768 ;
elsif( temp < -16384 ) then
temp := temp + 32768 ;
end if ;
phase <= temp ;
end if ;
end if ;
end process ;
cordic_inputs <= ( x => to_signed(1234,16), y => to_signed(0,16), z => phase, valid => inputs.valid ) ;
U_cordic : entity work.cordic
port map (
clock => clock,
reset => reset,
mode => CORDIC_ROTATION,
inputs => cordic_inputs,
outputs => cordic_outputs
) ;
outputs.re <= cordic_outputs.x ;
outputs.im <= cordic_outputs.y ;
outputs.valid <= cordic_outputs.valid ;
end architecture ; -- arch

75
fpga/modelsim/wlan.do Normal file
View File

@ -0,0 +1,75 @@
# Library
vlib wlan
if { ! [info exists wlan_path] } {
set wlan_path "."
}
set modelsim 1
vlib nuand
vcom -work nuand -2008 [file join $wlan_path ../../../bladeRF/hdl/fpga/ip/nuand/synthesis/fifo_readwrite_p.vhd ]
# altera ip simulation models
vlib fft64
set QSYS_SIMDIR [file normalize [ file join $wlan_path ../ip/altera/fft64/fft64/simulation/ ] ]
source [file normalize [ file join $wlan_path $QSYS_SIMDIR/mentor/msim_setup.tcl ] ]
dev_com
com
vmap fft64 libraries/fft_ii_0/
vlog -work fft64 [ file join $wlan_path ../ip/altera/fft64/fft64/simulation/fft64.v ]
set hexfiles [glob [file join $wlan_path "../ip/altera/fft64/fft64/simulation/submodules/*.hex"] ]
foreach f $hexfiles {
file copy -force $f .
}
vlib viterbi_decoder
set QSYS_SIMDIR [file normalize [ file join $wlan_path ../ip/altera/viterbi_decoder/viterbi_decoder/simulation/ ] ]
source [file normalize [ file join $wlan_path $QSYS_SIMDIR/mentor/msim_setup.tcl ] ]
dev_com
com
vmap viterbi_decoder libraries/viterbi_ii_0/
vlog -work viterbi_decoder [ file join $wlan_path ../ip/altera/viterbi_decoder/viterbi_decoder/simulation/viterbi_decoder.v ]
vlog -work viterbi_decoder [ file join $wlan_path ../ip/altera/viterbi_decoder/viterbi_decoder/simulation/submodules/viterbi_decoder_viterbi_ii_0.v ]
vlib wlan_pll
vlog -work wlan_pll [ file join $wlan_path ../ip/altera/wlan_pll/wlan_pll/wlan_pll.v ]
source [file normalize [ file join $wlan_path ../common/wlan_files.tcl ] ]
# Common packages
foreach f $wlan_common {
vcom -work wlan -2008 $f
}
# TX Synthesis
foreach f $wlan_synthesis_tx {
vcom -work wlan -2008 $f
}
# RX Synthesis
foreach f $wlan_synthesis_rx {
vcom -work wlan -2008 $f
}
# Top Level Synthesis
foreach f $wlan_synthesis_top {
vcom -work wlan -2008 $f
}
# Simulation
foreach f $wlan_sim {
vcom -work wlan -2008 $f
}
proc wlan_sim_entity { entity } {
vsim -t ps -L work -L work_lib -L fft_ii_0 -L altera_ver -L lpm_ver -L sgate_ver -L altera_mf_ver -L wlan -L fft64 -L viterbi_decoder -L altera_lnsim_ver $entity
}
alias tb_wlan_rx {
wlan_sim_entity wlan_rx_tb
}

26
fpga/quartus/wlan.qip Normal file
View File

@ -0,0 +1,26 @@
# Altera FFT IP
set_global_assignment -name QIP_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/fft64/fft64/synthesis/fft64.qip"]
set_global_assignment -name QIP_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/viterbi_decoder/viterbi_decoder/synthesis/viterbi_decoder.qip"]
set_global_assignment -library "wlan_pll" -name VERILOG_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/wlan_pll/wlan_pll/wlan_pll.v"]
set_global_assignment -library "wlan_pll" -name QIP_FILE [file normalize "../../../../../bladeRF-wiphy/fpga/ip/altera/wlan_pll/wlan_pll/wlan_pll.qip"]
set modelsim 0
# Nuand WLAN IP files
source [file normalize [file join $::quartus(qip_path) ../common/wlan_files.tcl]]
foreach f $wlan_common {
set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008
}
foreach f $wlan_synthesis_tx {
set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008
}
foreach f $wlan_synthesis_rx {
set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008
}
foreach f $wlan_synthesis_top {
set_global_assignment -library "wlan" -name VHDL_FILE [file normalize [file join $::quartus(qip_path) $f]] -hdl_version VHDL_2008
}

View File

@ -0,0 +1,65 @@
-- 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_rx_p.all ;
entity clock_sync_logic is
port (
from_signal : in std_logic ;
to_clock : in std_logic ;
to_reset : in std_logic ;
to_signal : out std_logic
) ;
end entity;
architecture arch of clock_sync_logic is
signal t_sig_r : std_logic ;
signal t_sig_rr : std_logic ;
attribute ALTERA_ATTRIBUTE : string;
attribute ALTERA_ATTRIBUTE of arch: architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers *clock_sync_logic|*_r* ] "" ";
begin
process(all)
begin
if( to_reset = '1' ) then
t_sig_rr <= '0' ;
t_sig_r <= '0' ;
to_signal <= '0' ;
elsif( rising_edge( to_clock ) ) then
t_sig_r <= from_signal ;
t_sig_rr <= t_sig_r ;
if( t_sig_rr = '0' and t_sig_r = '1' ) then
to_signal <= '1' ;
else
to_signal <= '0' ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,60 @@
-- 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_rx_p.all ;
entity clock_sync_logic_vector is
generic (
LEN : integer := 8
) ;
port (
from_signal : in std_logic_vector(LEN-1 downto 0) ;
to_clock : in std_logic ;
to_reset : in std_logic ;
to_signal : out std_logic_vector(LEN-1 downto 0)
) ;
end entity;
architecture arch of clock_sync_logic_vector is
signal t_sig_r : std_logic_vector(LEN-1 downto 0) ;
attribute ALTERA_ATTRIBUTE : string;
attribute ALTERA_ATTRIBUTE of arch: architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers *clock_sync_logic_vector|*_r* ] "" ";
begin
process(all)
begin
if( to_reset = '1' ) then
t_sig_r <= ( others => '0' ) ;
to_signal <= ( others => '0' ) ;
elsif( rising_edge( to_clock ) ) then
t_sig_r <= from_signal ;
to_signal <= t_sig_r ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,58 @@
-- 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_rx_p.all ;
entity clock_sync_params is
port (
from_signal : in wlan_rx_params_t ;
to_clock : in std_logic ;
to_reset : in std_logic ;
to_signal : out wlan_rx_params_t
) ;
end entity;
architecture arch of clock_sync_params is
signal t_sig_r : wlan_rx_params_t ;
attribute ALTERA_ATTRIBUTE : string;
attribute ALTERA_ATTRIBUTE of arch: architecture is "-name SDC_STATEMENT ""set_false_path -to [get_registers *clock_sync_params|*_r* ] "" ";
begin
process(all)
begin
if( to_reset = '1' ) then
t_sig_r <= NULL_PARAMS ;
to_signal <= NULL_PARAMS ;
elsif( rising_edge( to_clock ) ) then
t_sig_r <= from_signal ;
to_signal <= t_sig_r ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,70 @@
-- 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_rx_p.all ;
entity wlan_ack_generator_tb is
end entity ;
architecture arch of wlan_ack_generator_tb is
signal wclock : std_logic := '1' ;
signal wreset : std_logic := '1' ;
signal rclock : std_logic := '1' ;
signal rreset : std_logic := '1' ;
signal ack_valid : std_logic := '0' ;
signal fifo_re : std_logic := '0' ;
begin
wclock <= not wclock after 5 ns ;
wreset <= '1', '0' after 55 ns ;
rclock <= not rclock after 6 ns ;
rreset <= '1', '0' after 55 ns ;
ack_valid <= '0', '1' after 72 ns, '0' after 82 ns ;
fifo_re <= '0', '1' after 400 ns, '0' after 412 ns ;
U_ack_gen : entity wlan.wlan_ack_generator
port map (
wclock => wclock,
wreset => wreset,
ack_mac => x"1234567890ab",
ack_valid => ack_valid,
rclock => rclock,
rreset => rreset,
fifo_data => open,
fifo_re => fifo_re,
done_tx => '1',
ack_ready => open
) ;
end architecture ;

View File

@ -0,0 +1,114 @@
-- 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 ;
use ieee.math_real.all ;
library wlan ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
library wlan;
entity wlan_acquisition_tb is
end entity ;
architecture arch of wlan_acquisition_tb is
signal clock : std_logic := '0' ;
signal sample : wlan_sample_t ;
signal fopen : std_logic;
signal reset : std_logic;
signal i_sum : signed(63 downto 0);
signal q_sum : signed(63 downto 0);
signal sum : signed(127 downto 0);
signal acquired_packet : std_logic ;
signal p_mag : signed(23 downto 0) ;
type SAMPLE_ARRAY is array (integer range <>) of wlan_sample_t;
signal samples : SAMPLE_ARRAY(0 to 159);
begin
clock <= not clock after 10 ns;
reset <= '1', '0' after 50 ns ;
fopen <= '0', '1' after 100 ns;
U_sample_loader: entity wlan.wlan_sample_loader
generic map (
FILENAME => "tx"
) port map (
clock => clock,
fopen => fopen,
sample => sample
);
U_csma : entity wlan.wlan_csma
port map (
clock => clock,
reset => reset,
in_sample => sample,
quiet => open
) ;
U_acquisition : entity wlan.wlan_acquisition
port map (
clock => clock,
reset => reset,
in_sample => sample,
acquired => acquired_packet,
p_mag => p_mag,
quiet => '0',
burst => '0',
out_sample => open
);
tb : process(clock)
variable tsum : signed(127 downto 0);
variable isum : signed(63 downto 0);
variable qsum : signed(63 downto 0);
begin
if( rising_edge( clock ) ) then
if( sample.valid = '1' ) then
for i in 0 to samples'high - 1 loop
samples(i+1) <= samples(i);
end loop ;
samples(0) <= sample;
isum := (others => '0');
qsum := (others => '0');
for i in 0 to 79 loop
isum := isum + samples(i).i * samples(i + 80).i + samples(i).q * samples(i + 80).q;
qsum := qsum - samples(i).i * samples(i + 80).q + samples(i).q * samples(i + 80).i;
end loop ;
i_sum <= isum;
q_sum <= qsum;
tsum := isum * isum + qsum * qsum;
sum <= tsum;
end if;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,118 @@
-- 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 ;
entity wlan_bsd_tb is
end entity ;
architecture arch of wlan_bsd_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal init : std_logic := '0' ;
signal modulation : wlan_modulation_t := WLAN_BPSK ;
signal data : std_logic_vector(287 downto 0) := (others =>'0') ;
signal data_valid : std_logic := '0' ;
signal mod_start : std_logic ;
signal mod_end : std_logic ;
signal mod_sample : wlan_sample_t ;
signal bsds : wlan_bsds_t ;
procedure nop( signal clock : in std_logic ; count : in natural ) is
begin
for i in 1 to count loop
wait until rising_edge(clock) ;
end loop ;
end procedure ;
begin
clock <= not clock after 1 ns ;
U_modulator : entity work.wlan_modulator
port map (
clock => clock,
reset => reset,
init => init,
data => data,
modulation => modulation,
in_valid => data_valid,
ifft_ready => '1',
symbol_start => mod_start,
symbol_end => mod_end,
symbol_sample => mod_sample
) ;
U_bsd : entity work.wlan_bsd
port map (
clock => clock,
reset => reset,
modulation => modulation,
in_sample => mod_sample,
bsds => bsds
) ;
tb : process
begin
reset <= '1' ;
nop( clock, 10 ) ;
reset <= '0' ;
nop( clock, 10 ) ;
init <= '1' ;
nop( clock, 1 ) ;
init <= '0' ;
nop( clock, 1 ) ;
-- Run through modulations and populate data
for m in 0 to wlan_modulation_t'pos(WLAN_64QAM) loop
modulation <= wlan_modulation_t'val(m) ;
data <= (others =>'0') ;
data_valid <= '1' ;
nop( clock, 1 ) ;
data_valid <= '0' ;
wait until rising_edge(clock) and mod_start = '1' ;
wait until rising_edge(clock) and mod_end = '1' ;
nop( clock, 10 ) ;
end loop ;
nop( clock, 100 ) ;
report "-- End of Simulation --" severity failure ;
end process ;
end architecture ;

View File

@ -0,0 +1,202 @@
-- 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 ;
use ieee.math_real.all ;
use ieee.math_complex.all ;
library work ;
use work.wlan_p.all ;
entity wlan_channel_inverter_tb is
end entity ;
architecture arch of wlan_channel_inverter_tb is
constant TAVG : complex_array_t := (
( 4.0, 2.0),
( 5736.0, 2073.0),
( -5700.0, -1798.0),
( -5569.0, -1564.0),
( 5389.0, 1404.0),
( 5180.0, 1331.0),
( -4986.0, -1341.0),
( 4837.0, 1414.0),
( -4750.0, -1520.0),
( 4742.0, 1628.0),
( -4780.0, -1702.0),
( -4854.0, -1728.0),
( -4923.0, -1696.0),
( -4965.0, -1620.0),
( -4964.0, -1522.0),
( 4909.0, 1427.0),
( 4818.0, 1362.0),
( -4710.0, -1344.0),
( -4600.0, -1372.0),
( 4533.0, 1441.0),
( -4515.0, -1527.0),
( 4532.0, 1595.0),
( -4609.0, -1631.0),
( 4684.0, 1605.0),
( 4753.0, 1521.0),
( 4773.0, 1388.0),
( 4717.0, 1230.0),
( 1.0, 0.0),
( 4.0, 1.0),
( -1.0, 0.0),
( 4.0, 1.0),
( 1.0, 0.0),
( 2.0, 1.0),
( 0.0, 0.0),
( 1.0, 1.0),
( -1.0, -1.0),
( 1.0, 0.0),
( 1.0, 1.0),
( 4206.0, 2466.0),
( 4354.0, 2392.0),
( -4440.0, -2287.0),
( -4446.0, -2177.0),
( 4406.0, 2102.0),
( 4336.0, 2079.0),
( -4268.0, -2110.0),
( 4222.0, 2185.0),
( -4227.0, -2285.0),
( 4283.0, 2381.0),
( 4373.0, 2445.0),
( 4480.0, 2462.0),
( 4586.0, 2433.0),
( 4660.0, 2367.0),
( 4682.0, 2282.0),
( -4654.0, -2210.0),
( -4590.0, -2179.0),
( 4500.0, 2200.0),
( 4438.0, 2286.0),
( -4423.0, -2422.0),
( 4474.0, 2578.0),
( -4602.0, -2721.0),
( 4801.0, 2816.0),
( 5040.0, 2830.0),
( 5300.0, 2758.0),
( 5523.0, 2591.0)
) ;
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal first : std_logic := '0' ;
signal last : std_logic := '0' ;
signal channel : wlan_sample_t := (i => (others =>'0'), q => (others =>'0'), valid => '0') ;
signal reference : wlan_sample_t := (i => (others =>'0'), q => (others =>'0'), valid => '0') ;
signal inverted : wlan_sample_t ;
signal done : std_logic ;
procedure nop( signal clock : in std_logic ; x : natural ) is
begin
for i in 1 to x loop
wait until rising_edge(clock) ;
end loop ;
end procedure ;
begin
clock <= not clock after 1 ns ;
U_channel_inverter : entity work.wlan_channel_inverter
port map (
clock => clock,
reset => reset,
first => first,
last => last,
in_channel => channel,
in_reference => reference,
out_inverted => inverted,
done => done
) ;
tb : process
begin
reset <= '1' ;
nop( clock, 10 ) ;
reset <= '0' ;
nop( clock, 10 ) ;
for i in TAVG'range loop
reference.i <= to_signed(integer(LONG_SEQ_FREQ(i).re*4096.0), reference.i'length) ;
reference.q <= to_signed(integer(LONG_SEQ_FREQ(i).im*4096.0), reference.q'length) ;
channel.i <= to_signed(integer(TAVG(i).re), channel.i'length) ;
channel.q <= to_signed(integer(TAVG(i).im), channel.q'length) ;
channel.valid <= '1' ;
if( i = 0 ) then
first <= '1' ;
else
first <= '0' ;
end if ;
if( i = TAVG'high ) then
last <= '1' ;
else
last <= '0' ;
end if ;
nop( clock, 1 ) ;
end loop ;
last <= '0' ;
channel.valid <= '0' ;
wait until rising_edge(clock) and done = '1' ;
nop( clock, 100 ) ;
report "-- End of Simulation --" severity failure ;
end process ;
equalize : process
variable expected : complex := (0.0, 0.0) ;
variable finished : boolean := false ;
variable cinverted : complex := (0.0, 0.0);
variable idx : natural range TAVG'range := 0 ;
variable error_squared : real := 0.0 ;
variable equalized : complex := (0.0, 0.0) ;
begin
while finished = false loop
wait until rising_edge(clock) and inverted.valid = '1' ;
cinverted.re := real(to_integer(inverted.i)) ;
cinverted.im := real(to_integer(inverted.q)) ;
cinverted := cinverted ;
equalized := (TAVG(idx) * cinverted) / 4096.0 ;
expected := LONG_SEQ_FREQ(idx) * 4096.0 ;
error_squared := (expected.re - equalized.re) * (expected.re - equalized.re) +
(expected.im - equalized.im) * (expected.im - equalized.im) +
1.0e-100;
if( done = '1' ) then
finished := true ;
else
idx := idx + 1 ;
end if ;
end loop ;
wait ;
end process ;
end architecture ;

View File

@ -0,0 +1,95 @@
-- 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 ;
library altera_mf ;
use altera_mf.altera_mf_components.all ;
library wlan_pll ;
entity wlan_clock_tb is
end entity ;
architecture arch of wlan_clock_tb is
signal wclock : std_logic := '1' ;
signal wreset : std_logic := '1' ;
signal wdata : unsigned(7 downto 0) := ( others => '0' ) ;
signal wvalid : std_logic := '1' ;
signal wfull : std_logic := '1' ;
signal rclock : std_logic := '1' ;
signal rreset : std_logic := '1' ;
signal rempty : std_logic := '1' ;
signal rdata : std_logic_vector(7 downto 0) := ( others => '0' ) ;
signal ack_valid : std_logic := '0' ;
signal fifo_re : std_logic := '0' ;
signal alt : std_logic := '0' ;
begin
wclock <= not wclock after 20 ns;
rclock <= not rclock after 10 ns;
process(wclock)
begin
if( rising_edge( wclock ) ) then
alt <= not alt;
if (alt = '0' ) then
wdata <= wdata + 1;
end if;
end if;
end process;
U_rx_data_dc_fifo: dcfifo
generic map (
lpm_width => 8,
lpm_widthu => 6,
lpm_numwords => 32,
lpm_showahead => "ON"
)
port map (
wrclk => wclock,
wrreq => alt and not wfull,
data => std_logic_vector(wdata),
wrfull => wfull,
wrempty => open,
wrusedw => open,
rdclk => rclock,
rdreq => not rempty,
q => rdata,
rdfull => open,
rdempty => rempty,
rdusedw => open
) ;
end architecture ;

View File

@ -0,0 +1,57 @@
-- 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_rx_p.all ;
entity wlan_dsss_plcp_crc_tb is
end entity ;
architecture arch of wlan_dsss_plcp_crc_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal in_data : std_logic := '1' ;
begin
clock <= not clock after 5 ns ;
reset <= '1', '0' after 55 ns ;
in_data <= '0',
'1' after 65 ns,
'0' after 75 ns,
'1' after 85 ns,
'0' after 95 ns;
U_plcp_crc : entity wlan.wlan_dsss_plcp_crc
port map (
clock => clock,
reset => reset,
in_data => in_data,
in_valid => '1',
crc => open
) ;
end architecture ;

View File

@ -0,0 +1,55 @@
-- 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 ;
use work.wlan_interleaver_p.all ;
library std ;
use std.textio.all ;
entity wlan_interleaver_tb is
end entity ;
architecture arch of wlan_interleaver_tb is
procedure print( table : integer_array_t ; n : natural ) is
begin
for i in 0 to n-1 loop
write(output, integer'image(i) & " -> " & integer'image(table(i)) & CR ) ;
end loop ;
end procedure ;
begin
tb : process
variable l : line ;
begin
write( output, "-- BPSK Table --" & CR ) ;
print( WLAN_INTERLEAVER_BPSK, 48 ) ;
wait ;
end process ;
end architecture ;

View File

@ -0,0 +1,121 @@
-- 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 ;
use work.wlan_tables_p.all ;
entity wlan_lfsr_tb is
end entity ;
architecture arch of wlan_lfsr_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal init : unsigned(6 downto 0) := (others =>'1') ;
signal init_valid : std_logic := '0' ;
signal advance : std_logic := '0' ;
signal data : std_logic_vector(7 downto 0) ;
signal data_valid : std_logic ;
function reverse(x : in std_logic_vector) return std_logic_vector is
variable rv : std_logic_vector(x'range) ;
begin
for i in x'range loop
rv(rv'high-i) := x(i) ;
end loop ;
return rv ;
end function ;
begin
clock <= not clock after 0.5 ns ;
U_lfsr : entity work.wlan_lfsr
generic map (
WIDTH => data'length
) port map (
clock => clock,
reset => reset,
init => init,
init_valid => init_valid,
advance => advance,
data => data,
data_valid => data_valid
) ;
tb : process
begin
nop( clock, 100 ) ;
reset <= '0' ;
nop( clock, 100 ) ;
init <= "1011101" ; -- L-14 from standard
init_valid <= '1' ;
nop( clock, 1 ) ;
init_valid <= '0' ;
nop( clock, 100 ) ;
for i in TABLE_L_13'range loop
advance <= '1' ;
nop( clock, 1 ) ;
end loop ;
advance <= '0' ;
nop( clock, 100 ) ;
report "-- End of Simulation --" severity failure ;
end process ;
verification : process
variable indata : std_logic_vector(data'range) ;
variable result : std_logic_vector(data'range) ;
variable rev_result : std_logic_vector(data'range) ;
begin
result := (others =>'0') ;
indata := (others =>'0') ;
rev_result := (others =>'0') ;
for i in 0 to TABLE_L_15'high loop
wait until rising_edge(clock) and data_valid = '1' ;
indata := std_logic_vector(to_unsigned(TABLE_L_13(i),data'length));
result := data xor indata ;
-- Location of tail bits that have to be 0 going into Viterbi Encoder
if( i = 102 ) then
result(5 downto 0) := (others =>'0') ;
end if ;
rev_result := reverse(result) ;
assert rev_result = std_logic_vector(to_unsigned(TABLE_L_15(i),result'length))
report "Incorrect scrambling sequence at index " & integer'image(i)
severity error ;
end loop ;
wait ;
end process ;
end architecture ;

View File

@ -0,0 +1,112 @@
-- 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 ;
use work.wlan_tables_p.all ;
entity wlan_modulator_tb is
end entity ;
architecture arch of wlan_modulator_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal init : std_logic := '0' ;
signal data : std_logic_vector(287 downto 0) := TABLE_L_19 ;
signal modulation : wlan_modulation_t := WLAN_16QAM ;
signal in_valid : std_logic := '0' ;
signal symbol_start : std_logic ;
signal symbol_end : std_logic ;
signal symbol_sample : wlan_sample_t ;
signal ifft_sample : wlan_sample_t ;
signal ifft_valid_cp : std_logic ;
signal ifft_done : std_logic ;
begin
clock <= not clock after (0.5 sec / 40.0e6) ;
U_modulator : entity work.wlan_modulator
port map (
clock => clock,
reset => reset,
init => init,
data => data,
modulation => modulation,
in_valid => in_valid,
ifft_ready => '1',
symbol_start => symbol_start,
symbol_end => symbol_end,
symbol_sample => symbol_sample
) ;
U_ifft : entity work.wlan_ifft64
port map (
clock => clock,
reset => reset,
symbol_start => symbol_start,
symbol_end => symbol_end,
in_sample => symbol_sample,
out_sample => ifft_sample,
out_valid_cp => ifft_valid_cp,
done => ifft_done
) ;
tb : process
begin
reset <= '1' ;
nop( clock, 100 ) ;
reset <= '0' ;
nop( clock, 100 ) ;
init <= '1' ;
nop( clock, 1 ) ;
init <= '0' ;
nop( clock, 10 ) ;
for i in 1 to 10 loop
in_valid <= '1' ;
nop( clock, 1 ) ;
in_valid <= '0' ;
nop( clock, 1 ) ;
wait until rising_edge(clock) and symbol_end = '1' ;
nop( clock, 1 ) ;
end loop ;
nop( clock, 1000 ) ;
report "-- End of Simulation --" severity failure ;
end process ;
end architecture ;

View File

@ -0,0 +1,76 @@
-- 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 ;
use work.wlan_tables_p.all ;
entity wlan_peak_finder_tb is
end entity ;
architecture arch of wlan_peak_finder_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal init : unsigned(6 downto 0) := (others =>'1') ;
signal init_valid : std_logic := '0' ;
signal advance : std_logic := '0' ;
signal data : std_logic_vector(7 downto 0) ;
signal data_valid : std_logic ;
signal sample : unsigned( 127 downto 0 ) ;
signal inc : std_logic := '1';
begin
clock <= not clock after 0.5 ns ;
reset <= '1', '0' after 10 ns;
U_peak_finder : entity work.wlan_peak_finder
port map (
clock => clock,
reset => reset,
sample => sample,
sample_valid=> '1',
peak => open
) ;
process(clock)
begin
if( reset = '1' ) then
sample <= (others => '0') ;
elsif( rising_edge( clock ) ) then
if( inc = '1' ) then
sample <= sample + 1 ;
if (sample = 45) then
inc <= '0';
end if;
else
sample <= sample - 1 ;
end if;
end if;
end process;
end architecture ;

188
fpga/vhdl/tb/wlan_rx_tb.vhd Normal file
View File

@ -0,0 +1,188 @@
-- 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 ;
use ieee.math_real.all ;
library wlan ;
use wlan.wlan_p.all ;
use work.nco_p.all ;
use wlan.wlan_rx_p.all ;
library wlan;
entity wlan_rx_tb is
end entity ;
architecture arch of wlan_rx_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal sample : wlan_sample_t ;
signal sample_r : wlan_sample_t ;
signal eq : wlan_sample_t ;
signal fopen : std_logic;
signal i_sum : signed(63 downto 0);
signal q_sum : signed(63 downto 0);
signal sum : signed(127 downto 0);
type SAMPLE_ARRAY is array (integer range <>) of wlan_sample_t;
signal samples : SAMPLE_ARRAY(0 to 159);
signal gain_inc_req : std_logic ;
signal gain_dec_req : std_logic ;
signal gain_rst_req : std_logic ;
signal gain_ack : std_logic ;
signal gain_nack : std_logic ;
signal gain_lock : std_logic := '0' ;
signal gain_max : std_logic ;
signal nco_inputs : nco_input_t ;
signal nco_outputs : nco_output_t ;
signal nco_en : std_logic ;
begin
sample_r.valid <= sample.valid;
sample_r.i <= resize(shift_right(sample.i * nco_outputs.re - sample.q * nco_outputs.im, 11), 16);
sample_r.q <= resize(shift_right(sample.i * nco_outputs.im + sample.q * nco_outputs.re, 11), 16);
nco_inputs <= ( dphase => to_signed(-15, 16), valid => sample.valid) ;
U_nco : entity work.nco
port map (
clock => clock,
reset => reset,
inputs => nco_inputs,
outputs => nco_outputs
) ;
clock <= not clock after 12.5 ns;
reset <= '1', '0' after 100 ns ;
fopen <= '0', '1' after 100 ns;
U_sample_loader: entity wlan.wlan_sample_loader
port map (
clock => clock,
fopen => fopen,
sample => sample
);
gain_ack <= '0' ;
gain_max <= '1' ;
gain_nack <= '1' ;
-- U_agc : entity wlan.wlan_agc_drv
-- port map (
-- clock => clock,
-- reset => reset,
--
-- enable => '1',
-- 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_high => gain_max,
-- gain_mid => open,
-- gain_low => open,
--
-- sclk => open,
-- miso => '0',
-- mosi => open,
-- cs_n => open
-- ) ;
U_rx : entity wlan.wlan_rx
port map (
clock40m => clock,
reset40m => reset,
bb_i => sample.i,
bb_q => sample.q,
bb_valid => sample.valid,
equalized_i => eq.i,
equalized_q => eq.q,
equalized_valid => eq.valid,
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,
rx_block => '0',
rx_data_req => '1',
rx_data => open,
rx_data_valid => open,
rx_end_of_packet=> open,
rx_status => open,
rx_status_valid => open,
rx_vector => open,
rx_vector_valid => open,
mse => open,
mse_valid => open
);
process(clock)
variable tsum : signed(127 downto 0);
variable isum : signed(63 downto 0);
variable qsum : signed(63 downto 0);
begin
if( rising_edge( clock ) ) then
if( sample.valid = '1' ) then
for i in 0 to samples'high - 1 loop
samples(i+1) <= samples(i);
end loop ;
samples(0) <= sample;
isum := (others => '0');
qsum := (others => '0');
for i in 0 to 79 loop
isum := isum + samples(i).i * samples(i + 80).i + samples(i).q * samples(i + 80).q;
qsum := qsum - samples(i).i * samples(i + 80).q + samples(i).q * samples(i + 80).i;
end loop ;
i_sum <= isum;
q_sum <= qsum;
tsum := isum * isum + qsum * qsum;
sum <= tsum;
end if;
end if ;
end process ;
U_sample_saver : entity work.wlan_sample_saver
generic map (
FILENAME => "eq"
) port map (
clock => clock,
fopen => '1',
sample => eq,
done => '0'
) ;
end architecture ;

View File

@ -0,0 +1,92 @@
-- 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 std ;
use std.textio.all ;
library wlan ;
use wlan.wlan_p.all ;
entity wlan_sample_loader is
generic (
FILENAME : string := "tx"
) ;
port (
clock : in std_logic ;
fopen : in std_logic ;
sample : out wlan_sample_t ;
ad_ctrl : out std_logic_vector( 7 downto 0 )
) ;
end entity ;
architecture arch of wlan_sample_loader is
begin
save : process
file f : text ;
variable l : line ;
variable li : integer ;
variable comma : character ;
variable status : file_open_status ;
variable fcount : natural := 0 ;
variable scount : natural := 0 ;
function fname( b : string ; count : natural ) return string is
begin
return b & "-" & integer'image(count) & ".csv" ;
end function ;
begin
wait until rising_edge(clock) and fopen = '1' ;
file_open(status, f, fname( FILENAME, fcount ), read_mode) ;
assert status = OPEN_OK
report "Could not open file: " & fname( FILENAME, fcount )
severity failure ;
scount := 0 ;
while true loop
sample.valid <= '0';
wait until rising_edge(clock) ;
readline( f, l );
read( l, li );
sample.i <= to_signed(li, sample.i'length);
read( l, comma );
read( l, li );
sample.q <= to_signed(li, sample.q'length);
sample.valid <= '1';
read( l, comma );
read( l, li );
ad_ctrl <= std_logic_vector(to_signed(li, ad_ctrl'length));
wait until rising_edge(clock) ;
scount := scount + 1 ;
if( endfile( f ) ) then
file_close( f ) ;
write( output, "Read " & integer'image(scount) & " samples from " & fname( FILENAME, fcount ) & CR ) ;
fcount := fcount + 1 ;
exit ;
end if ;
end loop ;
end process ;
end architecture ;

View File

@ -0,0 +1,80 @@
-- 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 std ;
use std.textio.all ;
library work ;
use work.wlan_p.all ;
entity wlan_sample_saver is
generic (
FILENAME : string := "samples"
) ;
port (
clock : in std_logic ;
fopen : in std_logic ;
sample : in wlan_sample_t ;
done : in std_logic
) ;
end entity ;
architecture arch of wlan_sample_saver is
begin
save : process
file f : text ;
variable l : line ;
variable status : file_open_status ;
variable fcount : natural := 0 ;
variable scount : natural := 0 ;
function fname( b : string ; count : natural ) return string is
begin
return b & "-" & integer'image(count) & ".csv" ;
end function ;
begin
wait until rising_edge(clock) and fopen = '1' ;
file_open(status, f, fname( FILENAME, fcount ), write_mode) ;
assert status = OPEN_OK
report "Could not open file: " & fname( FILENAME, fcount )
severity failure ;
scount := 0 ;
while true loop
wait until rising_edge(clock) and sample.valid = '1' ;
write( l, to_integer(sample.i) ) ;
write( l, ',' ) ;
write( l, to_integer(sample.q) ) ;
writeline( f, l ) ;
flush( f ) ;
scount := scount + 1 ;
if( done = '1' ) then
file_close( f ) ;
write( output, "Wrote " & integer'image(scount) & " samples to " & fname( FILENAME, fcount ) & CR ) ;
fcount := fcount + 1 ;
exit ;
end if ;
end loop ;
end process ;
end architecture ;

View File

@ -0,0 +1,160 @@
-- 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_symbol_shaper_tb is
end entity ;
architecture arch of wlan_symbol_shaper_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal cp_i : signed(15 downto 0) := (others =>'0') ;
signal cp_q : signed(15 downto 0) := (others =>'0') ;
signal cp_re : std_logic ;
signal cp_empty : std_logic := '1' ;
signal sample_i : signed(15 downto 0) := (others =>'0') ;
signal sample_q : signed(15 downto 0) := (others =>'0') ;
signal sample_re : std_logic ;
signal sample_empty : std_logic := '1' ;
signal out_sample : wlan_sample_t ;
signal done : std_logic ;
begin
clock <= not clock after (0.5 / 40.0e6) * 1 sec ;
U_shaper : entity work.wlan_symbol_shaper
port map (
clock => clock,
reset => reset,
cp_i => cp_i,
cp_q => cp_q,
cp_re => cp_re,
cp_empty => cp_empty,
sample_i => sample_i,
sample_q => sample_q,
sample_re => sample_re,
sample_empty => sample_empty,
out_sample => out_sample,
done => done
) ;
tb : process
begin
reset <= '1' ;
nop(clock, 100) ;
reset <= '0' ;
nop(clock, 100) ;
nop(clock,10000) ;
report "-- End of Simulation --" severity failure ;
end process ;
emulate_cp : process
variable count : natural := 1 ;
begin
wait until rising_edge(clock) and reset = '0' ;
nop(clock, 100) ;
cp_empty <= '0' ;
-- Long sequence CP
cp_i <= to_signed(1, cp_i'length) ;
cp_q <= to_signed(1, cp_q'length) ;
for i in 1 to 32 loop
wait until rising_edge(clock) and cp_re = '1' ;
end loop ;
-- 10 data symbols
for i in 1 to 10 loop
cp_i <= cp_i + 1 ;
cp_q <= cp_q + 1 ;
for i in 1 to 16 loop
wait until rising_edge(clock) and cp_re = '1' ;
end loop ;
end loop ;
-- 11th data symbol is the last
cp_i <= cp_i + 1 ;
cp_q <= cp_q + 1 ;
for i in 1 to 15 loop
wait until rising_edge(clock) and cp_re = '1' ;
end loop ;
cp_empty <= '1' ;
wait until rising_edge(clock) and cp_re = '1' ;
nop(clock, 100) ;
wait ;
end process ;
emulate_sample : process
variable count : natural := 0 ;
begin
wait until rising_edge(clock) and reset = '0' ;
nop(clock, 100) ;
-- Short sequence
count := 160 ;
sample_empty <= '0' ;
sample_i <= to_signed(0, sample_i'length) ;
sample_q <= to_signed(0, sample_q'length) ;
for i in 1 to 160 loop
wait until rising_edge(clock) and sample_re = '1' ;
end loop ;
-- Long sequence
sample_i <= sample_i + 1 ;
sample_q <= sample_q + 1 ;
for i in 1 to 128 loop
wait until rising_edge(clock) and sample_re = '1' ;
end loop ;
-- 10 data symbols
for i in 1 to 10 loop
sample_i <= sample_i + 1 ;
sample_q <= sample_q + 1 ;
for i in 1 to 64 loop
wait until rising_edge(clock) and sample_re = '1' ;
end loop ;
end loop ;
-- 11th symbol is the last one
sample_i <= sample_i + 1 ;
sample_q <= sample_q + 1 ;
for i in 1 to 63 loop
wait until rising_edge(clock) and sample_re = '1' ;
end loop ;
sample_empty <= '1' ;
wait until rising_edge(clock) and sample_re = '1' ;
nop(clock, 100) ;
wait ;
end process ;
end architecture ;

View File

@ -0,0 +1,207 @@
-- 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 ;
library work ;
use work.wlan_p.all ;
package wlan_tables_p is
-- Table L-1: MAC PDU Data
constant TABLE_L_1 : integer_array_t := (
16#04#, 16#02#, 16#00#, 16#2E#, 16#00#,
16#60#, 16#08#, 16#CD#, 16#37#, 16#A6#,
16#00#, 16#20#, 16#D6#, 16#01#, 16#3C#,
16#F1#, 16#00#, 16#60#, 16#08#, 16#AD#,
16#3B#, 16#AF#, 16#00#, 16#00#, 16#4A#,
16#6F#, 16#79#, 16#2C#, 16#20#, 16#62#,
16#72#, 16#69#, 16#67#, 16#68#, 16#74#,
16#20#, 16#73#, 16#70#, 16#61#, 16#72#,
16#6B#, 16#20#, 16#6F#, 16#66#, 16#20#,
16#64#, 16#69#, 16#76#, 16#69#, 16#6E#,
16#69#, 16#74#, 16#79#, 16#2C#, 16#0A#,
16#44#, 16#61#, 16#75#, 16#67#, 16#68#,
16#74#, 16#65#, 16#72#, 16#20#, 16#6F#,
16#66#, 16#20#, 16#45#, 16#6C#, 16#79#,
16#73#, 16#69#, 16#75#, 16#6D#, 16#2C#,
16#0A#, 16#46#, 16#69#, 16#72#, 16#65#,
16#2D#, 16#69#, 16#6E#, 16#73#, 16#69#,
16#72#, 16#65#, 16#64#, 16#20#, 16#77#,
16#65#, 16#20#, 16#74#, 16#72#, 16#65#,
16#61#
) ;
-- bladeRF Beacon Frame
constant BEACON_FRAME : integer_array_t := (
16#80#, 16#00#, 16#00#, 16#00#, 16#ff#, 16#ff#, 16#ff#, 16#ff#, 16#ff#, 16#ff#, 16#02#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#,
16#02#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#dd#, 16#70#, 16#1b#, 16#1e#, 16#78#, 16#01#, 16#05#, 16#00#,
16#64#, 16#00#, 16#01#, 16#04#, 16#00#, 16#10#, 16#62#, 16#6c#, 16#61#, 16#64#, 16#65#, 16#52#, 16#46#, 16#77#, 16#6c#, 16#61#,
16#6e#, 16#5f#, 16#53#, 16#53#, 16#49#, 16#44#, 16#01#, 16#08#, 16#82#, 16#84#, 16#8b#, 16#96#, 16#0c#, 16#12#, 16#18#, 16#24#,
16#03#, 16#01#, 16#01#, 16#05#, 16#04#, 16#01#, 16#02#, 16#00#, 16#00#, 16#2a#, 16#01#, 16#04#, 16#32#, 16#04#, 16#30#, 16#48#,
16#60#, 16#6c#, 16#7f#, 16#08#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#00#, 16#40#, 16#dd#, 16#18#, 16#00#, 16#50#,
16#f2#, 16#02#, 16#01#, 16#01#, 16#00#, 16#00#, 16#03#, 16#a4#, 16#00#, 16#00#, 16#27#, 16#a4#, 16#00#, 16#00#, 16#42#, 16#43#,
16#5e#, 16#00#, 16#62#, 16#32#, 16#2f#, 16#00#, 16#ee#, 16#f7#, 16#d7#, 16#6b#
) ;
constant MIND_FRAME : integer_array_t := (
16#88#, 16#02#, 16#3c#, 16#00#,
16#90#, 16#b6#, 16#86#, 16#e8#,
16#e2#, 16#2f#, 16#00#, 16#1c#,
16#f0#, 16#c5#, 16#e6#, 16#4d#,
16#00#, 16#1c#, 16#f0#, 16#c5#,
16#e6#, 16#4d#, 16#70#, 16#0b#,
16#00#, 16#00#, 16#aa#, 16#aa#,
16#36#, 16#37#
) ;
-- Table L-13: Pre-scrambled data
constant TABLE_L_13 : integer_array_t := (
16#00#, 16#00#, 16#04#,
16#02#, 16#00#, 16#2e#,
16#00#, 16#60#, 16#08#,
16#cd#, 16#37#, 16#a6#,
16#00#, 16#20#, 16#d6#,
16#01#, 16#3c#, 16#f1#,
16#00#, 16#60#, 16#08#,
16#ad#, 16#3b#, 16#af#,
16#00#, 16#00#, 16#4a#,
16#6f#, 16#79#, 16#2c#,
16#20#, 16#62#, 16#72#,
16#69#, 16#67#, 16#68#,
16#74#, 16#20#, 16#73#,
16#70#, 16#61#, 16#72#,
16#6b#, 16#20#, 16#6f#,
16#66#, 16#20#, 16#64#,
16#69#, 16#76#, 16#69#,
16#6e#, 16#69#, 16#74#,
16#79#, 16#2c#, 16#0a#,
16#44#, 16#61#, 16#75#,
16#67#, 16#68#, 16#74#,
16#65#, 16#72#, 16#20#,
16#6f#, 16#66#, 16#20#,
16#45#, 16#6c#, 16#79#,
16#73#, 16#69#, 16#75#,
16#6d#, 16#2c#, 16#0a#,
16#46#, 16#69#, 16#72#,
16#65#, 16#2d#, 16#69#,
16#6e#, 16#73#, 16#69#,
16#72#, 16#65#, 16#64#,
16#20#, 16#77#, 16#65#,
16#20#, 16#74#, 16#72#,
16#65#, 16#61#, 16#67#,
16#33#, 16#21#, 16#b6#,
16#00#, 16#00#, 16#00#,
16#00#, 16#00#, 16#00#
) ;
-- Post-scrambled data
constant TABLE_L_15 : integer_array_t := (
16#6c#, 16#19#, 16#89#,
16#8f#, 16#68#, 16#21#,
16#f4#, 16#a5#, 16#61#,
16#4f#, 16#d7#, 16#ae#,
16#24#, 16#0c#, 16#f3#,
16#3a#, 16#e4#, 16#bc#,
16#53#, 16#98#, 16#c0#,
16#1e#, 16#35#, 16#b3#,
16#e3#, 16#f8#, 16#25#,
16#60#, 16#d6#, 16#25#,
16#35#, 16#33#, 16#fe#,
16#f0#, 16#41#, 16#2b#,
16#8f#, 16#53#, 16#1c#,
16#83#, 16#41#, 16#be#,
16#39#, 16#28#, 16#66#,
16#44#, 16#66#, 16#cd#,
16#f6#, 16#a3#, 16#d8#,
16#0d#, 16#d4#, 16#81#,
16#3b#, 16#2f#, 16#df#,
16#c3#, 16#58#, 16#f7#,
16#c6#, 16#52#, 16#eb#,
16#70#, 16#8f#, 16#9e#,
16#6a#, 16#90#, 16#81#,
16#fd#, 16#7c#, 16#a9#,
16#d1#, 16#55#, 16#12#,
16#04#, 16#74#, 16#d9#,
16#e9#, 16#3b#, 16#cd#,
16#93#, 16#8d#, 16#7b#,
16#7c#, 16#70#, 16#02#,
16#20#, 16#99#, 16#a1#,
16#7d#, 16#8a#, 16#27#,
16#17#, 16#39#, 16#15#,
16#a0#, 16#ec#, 16#95#,
16#16#, 16#91#, 16#10#,
16#00#, 16#dc#, 16#7f#,
16#0e#, 16#f2#, 16#c9#
) ;
-- Post Viterbi Encoded (R=3/4) data
constant TABLE_L_16 : integer_array_t := (
16#2b#, 16#08#, 16#a1#, 16#f0#,
16#9d#, 16#b5#, 16#9a#, 16#1d#,
16#4a#, 16#fb#, 16#e8#, 16#c2#,
16#8f#, 16#c0#, 16#c8#, 16#73#,
16#c0#, 16#43#, 16#e0#, 16#19#,
16#e0#, 16#d3#, 16#eb#, 16#b2#,
16#af#, 16#98#, 16#fd#, 16#59#,
16#0f#, 16#8b#, 16#69#, 16#66#,
16#0c#, 16#aa#, 16#d9#, 16#10#,
16#56#, 16#8b#, 16#a6#, 16#40#,
16#64#, 16#b3#, 16#21#, 16#9e#,
16#8e#, 16#91#, 16#c1#, 16#05#,
16#b7#, 16#b7#, 16#c5#, 16#d8#,
16#80#, 16#2f#, 16#a2#, 16#dd#,
16#6f#, 16#2b#, 16#97#, 16#61#,
16#d9#, 16#dd#, 16#0d#, 16#12#,
16#76#, 16#27#, 16#02#, 16#4c#,
16#92#, 16#bc#, 16#12#, 16#4b#,
16#6a#, 16#f7#, 16#70#, 16#23#,
16#27#, 16#8e#, 16#01#, 16#b4#,
16#d6#, 16#c3#, 16#6a#, 16#60#,
16#4d#, 16#4b#, 16#cb#, 16#51#,
16#9c#, 16#b0#, 16#80#, 16#eb#,
16#89#, 16#34#, 16#14#, 16#40#,
16#6c#, 16#9e#, 16#2c#, 16#51#,
16#4b#, 16#7c#, 16#69#, 16#11#,
16#15#, 16#86#, 16#fd#, 16#be#,
16#5e#, 16#f9#, 16#be#, 16#28#,
16#ef#, 16#ca#, 16#55#, 16#03#,
16#fd#, 16#26#, 16#91#, 16#3b#,
16#95#, 16#ec#, 16#5b#, 16#23#,
16#99#, 16#5f#, 16#28#, 16#3e#,
16#d4#, 16#e9#, 16#f7#, 16#b8#,
16#13#, 16#75#, 16#8e#, 16#f2#,
16#a0#, 16#1b#, 16#6c#, 16#e9#,
16#07#, 16#5d#, 16#b0#, 16#bf#
) ;
-- Table L-19: Data to be modulated
constant TABLE_L_19 : std_logic_vector(287 downto 0) :=
x"00000000" & -- 287 downto 256
x"00000000" & -- 255 downto 224
x"00000000" & -- 223 downto 192
x"B6CDB000" & -- 191 downto 160
x"C219D6D8" & -- 159 downto 128
x"96AF1C76" & -- 127 downto 96
x"48B85908" & -- 95 downto 64
x"88FD00CE" & -- 63 downto 32
x"23F70FEE" ; -- 32 downto 0
end package ;

37
fpga/vhdl/tb/wlan_tb.vhd Normal file
View File

@ -0,0 +1,37 @@
-- 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 ;
use ieee.math_real.all ;
library work ;
use work.wlan_p.all ;
use work.wlan_rx_p.all ;
use work.wlan_tx_p.all ;
entity wlan_tb is
end entity ;
architecture arch of wlan_tb is
begin
end architecture ;

View File

@ -0,0 +1,221 @@
-- 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 ;
use ieee.math_real.all ;
library work ;
use work.wlan_p.all ;
use work.wlan_tables_p.all ;
use work.wlan_tx_p.all ;
library nuand;
use nuand.fifo_readwrite_p.all;
entity wlan_top_tb is
end entity ;
architecture arch of wlan_top_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal rx_enable : std_logic := '1' ;
signal tx_enable : std_logic := '0' ;
signal rx_i : signed(15 downto 0) := (others =>'0') ;
signal rx_q : signed(15 downto 0) := (others =>'0') ;
signal rx_valid : std_logic := '0' ;
signal tx_fifo_usedw : std_logic_vector(11 downto 0) := x"000";
signal tx_fifo_read : std_logic := '1';
signal tx_fifo_empty : std_logic := '0';
signal tx_fifo_data : std_logic_vector(31 downto 0);
signal rx_fifo_usedw : std_logic_vector(11 downto 0 ) := x"000";
signal rx_fifo_write : std_logic ;
signal rx_fifo_full : std_logic := '0' ;
signal rx_fifo_data : std_logic_vector(31 downto 0);
signal gain_inc_req : std_logic ;
signal gain_dec_req : std_logic ;
signal gain_rst_req : std_logic ;
signal gain_ack : std_logic ;
signal gain_nack : std_logic ;
signal gain_lock : std_logic ;
signal gain_max : std_logic ;
constant TEST_FRAME : integer_array_t := (
16#00070007#,
16#00020000#,
16#00000010#,
16#00000000#,
16#04030201#,
16#08070605#,
16#0C0B0A09#,
16#100F0E0D#,
16#12345678#,
16#00000000#,
16#00080008#,
16#00020000#,
16#00000010#,
16#00000000#,
16#04030201#,
16#08070605#,
16#0C0B0A09#,
16#100F0E0D#,
16#00000000#,
16#00000000#,
16#00090009#,
16#00020000#,
16#00000010#,
16#00000000#,
16#04030201#,
16#08070605#,
16#0C0B0A09#,
16#100F0E0D#,
16#00000000#,
16#00000000#
) ;
signal sample : wlan_sample_t ;
signal eq : wlan_sample_t ;
signal fopen : std_logic;
signal tx_packet_control : packet_control_t ;
signal tx_packet_empty : std_logic ;
signal tx_packet_ready : std_logic ;
signal rx_packet_control : packet_control_t ;
signal rx_packet_ready : std_logic ;
begin
rx_packet_ready <= '1' ;
tx_packet_control.pkt_sop <= '0' ;
tx_packet_control.pkt_eop <= '0' ;
tx_packet_control.data_valid <= '0';
tx_packet_control.data <= ( others => '0' );
U_sample_loader: entity work.wlan_sample_loader
port map (
clock => clock,
fopen => fopen,
sample => sample
);
-- Actual 40MHz clock
clock <= not clock after 12.5 ns;
reset <= '1', '0' after 100 ns ;
fopen <= '0', '1' after 100 ns;
process(all)
variable idx : integer := 0;
begin
tx_fifo_data <= std_logic_vector(to_unsigned(TEST_FRAME(idx), 32));
if( rising_edge(clock) ) then
if( tx_fifo_read = '1' ) then
idx := idx + 1;
end if;
end if;
end process;
U_wlan_top : entity work.wlan_top
port map (
rx_clock => clock,
rx_reset => reset,
rx_enable => rx_enable,
tx_clock => clock,
tx_reset => reset,
tx_enable => tx_enable,
config_reg => x"00000000",
packet_en => '1',
tx_packet_control => tx_packet_control,
tx_packet_empty => tx_packet_empty,
tx_packet_ready => tx_packet_ready,
rx_packet_control => rx_packet_control,
rx_packet_ready => rx_packet_ready,
tx_fifo_usedw => tx_fifo_usedw,
tx_fifo_read => tx_fifo_read,
tx_fifo_empty => tx_fifo_empty,
tx_fifo_data => tx_fifo_data,
rx_fifo_usedw => rx_fifo_usedw,
rx_fifo_write => rx_fifo_write,
rx_fifo_full => rx_fifo_full,
rx_fifo_data => rx_fifo_data,
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,
tx_ota_req => open,
tx_ota_ack => '1',
out_i => open,
out_q => open,
out_valid => open,
in_i => sample.i,
in_q => sample.q,
in_valid => sample.valid
) ;
gain_ack <= '1' ;
gain_lock <= '0' ;
-- U_agc : entity work.wlan_agc_drv
-- port map (
-- clock => clock,
-- reset => reset,
--
-- enable => '1',
-- 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_high => gain_max,
-- gain_mid => open,
-- gain_low => open,
--
-- sclk => open,
-- miso => '0',
-- mosi => open,
-- cs_n => open
-- ) ;
end architecture ;

View File

@ -0,0 +1,72 @@
-- 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 ;
use work.wlan_tx_p.all ;
entity wlan_tx_long_tb is
end entity ;
architecture arch of wlan_tx_long_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal start : std_logic := '0' ;
signal done : std_logic ;
signal sample : wlan_sample_t ;
signal valid_cp : std_logic ;
begin
clock <= not clock after 1 ns ;
U_tx_long : entity work.wlan_tx_long
port map (
clock => clock,
reset => reset,
start => start,
done => done,
out_sample => sample,
out_valid_cp => valid_cp
) ;
tb : process
begin
reset <= '1' ;
nop(clock, 100) ;
reset <= '0' ;
nop(clock, 100) ;
start <= '1' ;
nop(clock, 1) ;
start <= '0' ;
nop(clock, 1) ;
nop(clock, 1000 ) ;
report "-- End of Simulation --" severity failure ;
end process ;
end architecture ;

View File

@ -0,0 +1,70 @@
-- 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 ;
use work.wlan_tx_p.all ;
entity wlan_tx_short_tb is
end entity ;
architecture arch of wlan_tx_short_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal start : std_logic := '0' ;
signal done : std_logic ;
signal sample : wlan_sample_t ;
begin
clock <= not clock after 1 ns ;
U_tx_short : entity work.wlan_tx_short
port map (
clock => clock,
reset => reset,
start => start,
done => done,
out_sample => sample
) ;
tb : process
begin
reset <= '1' ;
nop(clock, 100) ;
reset <= '0' ;
nop(clock, 100) ;
start <= '1' ;
nop(clock, 1) ;
start <= '0' ;
nop(clock, 1) ;
nop(clock, 1000 ) ;
report "-- End of Simulation --" severity failure ;
end process ;
end architecture ;

178
fpga/vhdl/tb/wlan_tx_tb.vhd Normal file
View File

@ -0,0 +1,178 @@
-- 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 ;
use ieee.math_real.all ;
library work ;
use work.wlan_p.all ;
use work.wlan_tables_p.all ;
use work.wlan_tx_p.all ;
library std ;
use std.textio.all ;
entity wlan_tx_tb is
end entity ;
architecture arch of wlan_tx_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal tx_vector : wlan_tx_vector_t ;
signal tx_vector_valid : std_logic := '0' ;
signal tx_status : wlan_tx_status_t ;
signal tx_status_valid : std_logic ;
signal fifo_re : std_logic ;
signal fifo_data : std_logic_vector(7 downto 0) := (others =>'0') ;
signal fifo_empty : std_logic := '0' ;
signal fifo_reset : std_logic := '0' ;
signal bb : wlan_sample_t ;
signal bb_scaled : wlan_sample_t ;
signal done : std_logic ;
type wlan_tx_vectors_t is array(natural range <>) of wlan_tx_vector_t ;
constant VECTORS : wlan_tx_vectors_t := (
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_6),
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_9),
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_12),
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_18),
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_24),
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_36),
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_48),
(length => TABLE_L_1'length, bandwidth => WLAN_BW_20, datarate => WLAN_RATE_54)
) ;
function "/"( L : wlan_sample_t ; R : real ) return wlan_sample_t is
variable rv : wlan_sample_t := L ;
begin
rv.i := to_signed(integer(real(to_integer(L.i))/R),rv.i'length) ;
rv.q := to_signed(integer(real(to_integer(L.q))/R),rv.q'length) ;
return rv ;
end function ;
begin
-- Actual 40MHz clock
clock <= not clock after (0.5/40.0e6) * 1 sec ;
fifo : process(clock, reset, fifo_reset)
variable index : natural range TABLE_L_1'range := TABLE_L_1'low ;
begin
if( reset = '1' or fifo_reset = '1' ) then
index := TABLE_L_1'low ;
fifo_empty <= '0' ;
fifo_data <= std_logic_vector(to_unsigned(TABLE_L_1(index),fifo_data'length)) ;
elsif( rising_edge(clock) ) then
fifo_empty <= '0' ;
if( fifo_re = '1' ) then
if( index < TABLE_L_1'high ) then
index := index + 1 ;
end if ;
end if ;
fifo_data <= std_logic_vector(to_unsigned(TABLE_L_1(index),fifo_data'length)) ;
if( index = TABLE_L_1'high ) then
fifo_empty <= '1' ;
end if ;
end if ;
end process ;
U_wlan_tx : entity work.wlan_tx
port map (
clock => clock,
reset => reset,
tx_vector => tx_vector,
tx_vector_valid => tx_vector_valid,
tx_status => tx_status,
tx_status_valid => tx_status_valid,
fifo_re => fifo_re,
fifo_data => fifo_data,
fifo_empty => fifo_empty,
bb => bb,
done => done
) ;
tb : process
variable clock_count : natural ;
begin
reset <= '1' ;
nop( clock, 100 ) ;
reset <= '0' ;
nop( clock, 100 ) ;
-- Setup for a transmission
for i in VECTORS'range loop
clock_count := 10_000 ;
tx_vector <= VECTORS(i) ;
-- Kick it off
tx_vector_valid <= '1' ;
nop( clock, 1 ) ;
tx_vector_valid <= '0' ;
-- Wait for a while or until we've timed out
inner : while true loop
wait until rising_edge(clock) ;
if done = '1' then
write( output, "Continuing on..." & CR ) ;
exit inner ;
else
if( clock_count = 0 ) then
report "Never finished - exiting early"
severity failure ;
else
clock_count := clock_count - 1 ;
end if ;
end if ;
end loop ;
fifo_reset <= '1' ;
nop( clock, 1 ) ;
fifo_reset <= '0' ;
nop( clock, 100 ) ;
end loop ;
-- Done
report "-- End of Simulation --" severity failure ;
end process ;
bb_scaled <= bb ;
U_sample_saver : entity work.wlan_sample_saver
generic map (
FILENAME => "tx"
) port map (
clock => clock,
fopen => tx_vector_valid,
sample => bb_scaled,
done => done
) ;
end architecture ;

View File

@ -0,0 +1,187 @@
-- 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 ;
use work.wlan_tables_p.all ;
entity wlan_viterbi_encoder_tb is
end entity ;
architecture arch of wlan_viterbi_encoder_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal init : std_logic := '0' ;
signal in_data : std_logic_vector(7 downto 0) := (others =>'0') ;
signal in_valid : std_logic := '0' ;
signal in_done : std_logic := '0' ;
signal out_a : std_logic_vector(7 downto 0) ;
signal out_b : std_logic_vector(7 downto 0) ;
signal out_done : std_logic ;
signal out_valid : std_logic ;
signal r34 : std_logic_vector(11 downto 0) ;
function reverse( x : in integer ; len : in positive ) return std_logic_vector is
constant val : unsigned(len-1 downto 0) := to_unsigned(x,len) ;
variable rv : unsigned(len-1 downto 0) ;
begin
for i in val'range loop
rv(val'high-i) := val(i) ;
end loop ;
return std_logic_vector(rv) ;
end ;
begin
-- 40 MHz clock rate
clock <= not clock after (0.5 / 40.0e6) * 1 sec ;
U_encoder : entity work.wlan_viterbi_encoder
generic map (
WIDTH => in_data'length
) port map (
clock => clock,
reset => reset,
init => init,
in_data => in_data,
in_valid => in_valid,
in_done => in_done,
out_a => out_a,
out_b => out_b,
out_done => out_done,
out_valid => out_valid
) ;
tb : process
begin
reset <= '1' ;
nop( clock, 100 ) ;
reset <= '0' ;
nop( clock, 100 ) ;
for x in 1 to 2 loop
init <= '1' ;
nop( clock, 1 ) ;
init <= '0' ;
nop( clock, 1 ) ;
for i in TABLE_L_15'range loop
in_data <= reverse(TABLE_L_15(i), in_data'length) ;
in_valid <= '1' ;
if( i = TABLE_L_15'high ) then
in_done <= '1' ;
end if ;
nop( clock, 1 ) ;
end loop ;
in_valid <= '0' ;
in_done <= '0' ;
nop( clock, 100 ) ;
end loop ;
report "-- End of Simulation --" severity failure ;
end process ;
-- R=3/4 verification
verify : process
variable idx : natural range 0 to TABLE_L_16'length ;
variable downcount : natural range 0 to 8 ;
variable accum : std_logic_vector(7 downto 0) ;
type puncture_t is (AB, A, B) ;
variable puncture : puncture_t ;
variable check : std_logic_vector(7 downto 0) ;
begin
idx := 0 ;
accum := (others =>'0') ;
puncture := AB ;
check := (others =>'0') ;
downcount := 8 ;
while idx < TABLE_L_16'length loop
wait until rising_edge(clock) and out_valid = '1' ;
-- Need to consume A and B and, after 8 bits accumulated, check index
for i in 0 to out_a'high loop
case puncture is
when AB =>
accum := accum(6 downto 0) & out_a(i) ;
downcount := downcount - 1 ;
if( downcount = 0 ) then
-- Verify
check := std_logic_vector(to_unsigned(TABLE_L_16(idx),check'length)) ;
assert check = accum
report "Incorrect Viterbi Encoding @ " & integer'image(idx)
severity error ;
downcount := 8 ;
idx := idx + 1 ;
end if ;
accum := accum(6 downto 0) & out_b(i) ;
downcount := downcount - 1 ;
if( downcount = 0 ) then
-- Verify
check := std_logic_vector(to_unsigned(TABLE_L_16(idx),check'length)) ;
assert check = accum
report "Incorrect Viterbi Encoding @ " & integer'image(idx)
severity error ;
downcount := 8 ;
idx := idx + 1 ;
end if ;
puncture := A ;
when A =>
accum := accum(6 downto 0) & out_a(i) ;
downcount := downcount - 1 ;
if( downcount = 0 ) then
-- Verify
check := std_logic_vector(to_unsigned(TABLE_L_16(idx),check'length)) ;
assert check = accum
report "Incorrect Viterbi Encoding @ " & integer'image(idx)
severity error ;
downcount := 8 ;
idx := idx + 1 ;
end if ;
puncture := B ;
when B =>
accum := accum(6 downto 0) & out_b(i) ;
downcount := downcount - 1 ;
if( downcount = 0 ) then
-- Verify
check := std_logic_vector(to_unsigned(TABLE_L_16(idx),check'length)) ;
assert check = accum
report "Incorrect Viterbi Encoding @ " & integer'image(idx)
severity error ;
downcount := 8 ;
idx := idx + 1 ;
end if ;
puncture := AB ;
end case ;
end loop ;
end loop ;
wait ;
end process ;
end architecture ;

View File

@ -0,0 +1,203 @@
-- 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_rx_p.all ;
library viterbi_decoder ;
entity wlan_viterbi_tb is
end entity ;
architecture arch of wlan_viterbi_tb is
signal clock : std_logic := '1' ;
signal reset : std_logic := '1' ;
signal lfsr_init : std_logic := '0' ;
signal lfsr_advance : std_logic := '0' ;
signal lfsr_data : std_logic_vector(0 downto 0) ;
signal lfsr_valid : std_logic ;
signal in_bit : std_logic_vector(0 downto 0) := (others =>'0') ;
signal in_done : std_logic := '0' ;
signal in_valid : std_logic := '0' ;
signal enc_init : std_logic := '0' ;
signal enc_a : std_logic_vector(0 downto 0) ;
signal enc_b : std_logic_vector(0 downto 0) ;
signal enc_done : std_logic ;
signal enc_valid : std_logic ;
signal soft_a : signed(7 downto 0) ;
signal soft_b : signed(7 downto 0) ;
signal soft_valid : std_logic ;
signal dec_bit : std_logic ;
signal dec_valid : std_logic ;
signal verify_prime : std_logic ;
signal verify_advance : std_logic ;
signal verify_data : std_logic_vector(0 downto 0) ;
signal verify_valid : std_logic ;
procedure nop( signal clock : in std_logic ; count : natural ) is
begin
for i in 1 to count loop
wait until rising_edge(clock) ;
end loop ;
end procedure ;
constant LFSR_INIT_VAL : unsigned(6 downto 0) := "0101010" ;
signal params : wlan_rx_params_t := NULL_PARAMS ;
signal params_valid : std_logic := '0' ;
begin
clock <= not clock after 1 ns ;
U_lfsr : entity wlan.wlan_lfsr
generic map (
WIDTH => 1
) port map (
clock => clock,
reset => reset,
init => LFSR_INIT_VAL,
init_valid => lfsr_init,
advance => lfsr_advance,
data => lfsr_data,
data_valid => lfsr_valid
) ;
in_bit <= lfsr_data ;
in_valid <= lfsr_valid ;
U_encoder : entity wlan.wlan_viterbi_encoder
generic map (
WIDTH => 1
) port map (
clock => clock,
reset => reset,
init => enc_init,
in_data => in_bit,
in_valid => in_valid,
in_done => in_done,
out_a => enc_a,
out_b => enc_b,
out_done => enc_done,
out_valid => enc_valid
) ;
U_decoder : entity wlan.wlan_viterbi_decoder
port map (
clock => clock,
reset => reset,
init => '0',
in_soft_a => soft_a,
in_soft_b => soft_b,
in_erasure => "00",
in_valid => soft_valid,
params => params,
params_valid => params_valid,
out_dec_bit => dec_bit,
out_dec_valid => dec_valid
) ;
soft_a <= to_signed(15,soft_a'length) when enc_a(0) = '0' else to_signed(-15,soft_a'length) ;
soft_b <= to_signed(15,soft_b'length) when enc_b(0) = '0' else to_signed(-15,soft_b'length) ;
soft_valid <= enc_valid ;
tb : process
begin
reset <= '1' ;
nop( clock, 100 ) ;
reset <= '0' ;
nop( clock, 100 ) ;
enc_init <= '1' ;
lfsr_init <= '1' ;
nop( clock, 1 ) ;
enc_init <= '0' ;
lfsr_init <= '0' ;
nop( clock, 10 ) ;
params.num_decoded_bits <= 10000 ;
params_valid <= '1' ;
nop( clock, 1 ) ;
params_valid <= '0' ;
nop( clock, 100 ) ;
for i in 1 to 10000 loop
lfsr_advance <= '1' ;
wait until rising_edge(clock) ;
end loop ;
nop( clock, 10000 ) ;
report "-- End of Simulation --" severity failure ;
end process ;
U_verify : entity wlan.wlan_lfsr
generic map (
WIDTH => 1
) port map (
clock => clock,
reset => reset,
init => LFSR_INIT_VAL,
init_valid => lfsr_init,
advance => verify_advance,
data => verify_data,
data_valid => verify_valid
) ;
verify_advance <= dec_valid or verify_prime ;
verify : process
begin
verify_prime <= '0' ;
wait until rising_edge(clock) and lfsr_init = '1' ;
nop( clock, 10 ) ;
verify_prime <= '1' ;
nop( clock, 1 ) ;
verify_prime <= '0' ;
while true loop
wait until rising_edge(clock) and dec_valid = '1' ;
assert (dec_bit = verify_data(0))
report "Verification mismatch"
severity error ;
end loop ;
end process ;
end architecture ;

View File

@ -0,0 +1,163 @@
-- 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 altera_mf ;
use altera_mf.altera_mf_components.all ;
entity wlan_ack_generator is
port (
wclock : in std_logic ;
wreset : in std_logic ;
ack_mac : in std_logic_vector( 47 downto 0 );
ack_valid : in std_logic ;
rclock : in std_logic ;
rreset : in std_logic ;
fifo_data : out std_logic_vector( 7 downto 0 );
fifo_re : in std_logic ;
done_tx : in std_logic ;
ack_ready : out std_logic
) ;
end entity ;
architecture arch of wlan_ack_generator is
signal wfull : std_logic ;
signal rempty : std_logic ;
signal rread : std_logic ;
type fsm_t is (IDLE, READ, DONE);
type state_t is record
fsm : fsm_t;
payload : std_logic_vector( 79 downto 0 );
rread : std_logic ;
byte_idx : natural range 0 to 10 ;
end record ;
signal current_state : state_t;
signal future_state : state_t;
function NULL_STATE return state_t is
variable rv : state_t;
begin
rv.fsm := IDLE ;
rv.payload := (others => '0' ) ;
rv.rread := '0' ;
rv.byte_idx := 0 ;
return rv ;
end function ;
signal mac_address : std_logic_vector( 47 downto 0 );
begin
U_mac_dc_fifo: dcfifo
generic map (
lpm_width => 48,
lpm_widthu => 4,
lpm_numwords => 16,
lpm_showahead => "ON"
)
port map (
aclr => wreset or rreset,
wrclk => wclock,
wrreq => ack_valid and not wfull,
data => ack_mac,
wrfull => wfull,
wrempty => open,
wrusedw => open,
rdclk => rclock,
rdreq => rread,
q => mac_address,
rdfull => open,
rdempty => rempty,
rdusedw => open
) ;
ack_ready <= not rempty;
fifo_data <= current_state.payload(79 downto 72);
rread <= current_state.rread;
process(all)
begin
future_state <= current_state ;
future_state.rread <= '0';
case current_state.fsm is
when IDLE =>
future_state.payload <= x"D400" & x"0000" & mac_address;
if( fifo_re = '1' and rempty = '0' ) then
future_state.fsm <= READ ;
future_state.byte_idx <= 0 ;
future_state.rread <= '1' ;
future_state.payload <= current_state.payload(71 downto 0) & x"00";
else
future_state.payload <= x"D400" & x"0000" & mac_address;
end if;
when READ =>
if( fifo_re = '1' ) then
future_state.byte_idx <= current_state.byte_idx + 1;
future_state.payload <= current_state.payload(71 downto 0) & x"00";
if( current_state.byte_idx = 9 ) then
future_state.fsm <= DONE ;
end if;
end if;
when DONE =>
if (done_tx = '1') then
future_state.fsm <= IDLE ;
end if ;
future_state.byte_idx <= 0 ;
when others =>
future_state <= NULL_STATE ;
end case;
end process;
process(rclock, rreset)
begin
if( rreset = '1' ) then
current_state <= NULL_STATE ;
elsif( rising_edge( rclock ) ) then
current_state <= future_state ;
end if;
end process;
end architecture ;

View File

@ -0,0 +1,256 @@
-- 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_acquisition is
port (
clock : in std_logic ;
reset : in std_logic ;
in_sample : in wlan_sample_t ;
quiet : in std_logic ;
burst : in std_logic ;
acquired : out std_logic ;
p_mag : buffer signed( 23 downto 0 ) ;
out_sample : out wlan_sample_t
) ;
end entity;
architecture arch of wlan_acquisition is
type sample_history_t is array (natural range 31 downto 0 ) of wlan_sample_t ;
signal sample_history : sample_history_t ;
signal sample_counter : unsigned( 9 downto 0 );
signal power_accum : unsigned( 31 downto 0 ) ;
signal ptemp : unsigned( 31 downto 0 ) ;
signal itemp : signed( 31 downto 0 ) ;
signal qtemp : signed( 31 downto 0 ) ;
signal i_accum : signed( 31 downto 0 ) ;
signal q_accum : signed( 31 downto 0 ) ;
signal accum_valid : std_logic ;
signal i_sum : signed( 31 downto 0 ) ;
signal q_sum : signed( 31 downto 0 ) ;
signal div_i_power : signed( 31 downto 0 ) ;
signal div_q_power : signed( 31 downto 0 ) ;
signal div_power_valid : std_logic ;
signal div_i_power_r : signed( 31 downto 0 ) ;
signal div_q_power_r : signed( 31 downto 0 ) ;
signal div_power_valid_r : std_logic ;
signal div_i_squared : unsigned( 31 downto 0 ) ;
signal div_q_squared : unsigned( 31 downto 0 ) ;
signal div_squared_valid : std_logic ;
signal div : unsigned( 31 downto 0 ) ;
signal burst_counter : unsigned( 31 downto 0 ) ;
signal div_valid : std_logic ;
signal p_valid : std_logic ;
signal iq_valid : std_logic ;
signal max : unsigned( 31 downto 0 ) ;
signal max_counter : unsigned( 7 downto 0 ) ;
signal min : unsigned( 31 downto 0 ) ;
signal min_found : std_logic ;
signal peak_found : std_logic ;
signal p_sample : wlan_sample_t ;
signal peak_match : std_logic ;
signal first_peak : std_logic ;
begin
process( clock )
begin
if( reset = '1' ) then
burst_counter <= ( others => '0' );
elsif( rising_edge( clock ) ) then
if( in_sample.valid = '1' ) then
if( burst = '1' ) then
burst_counter <= burst_counter + 1 ;
else
burst_counter <= ( others => '0' ) ;
end if;
end if;
end if ;
end process ;
process( clock )
begin
if( reset = '1' ) then
sample_counter <= ( others => '0' ) ;
power_accum <= ( others => '0' ) ;
i_accum <= ( others => '0' ) ;
q_accum <= ( others => '0' ) ;
elsif( rising_edge( clock ) ) then
accum_valid <= '0' ;
if( burst = '0' or quiet = '1' ) then
sample_counter <= ( others => '0' ) ;
power_accum <= ( others => '0' ) ;
i_accum <= ( others => '0' ) ;
q_accum <= ( others => '0' ) ;
iq_valid <= '0';
p_valid <= '0';
elsif( in_sample.valid = '1' and sample_counter < 650 ) then
sample_counter <= sample_counter + 1 ;
for i in 0 to sample_history'high - 1 loop
sample_history( i + 1 ) <= sample_history( i ) ;
end loop ;
sample_history(0).i <= in_sample.i ;
sample_history(0).q <= - in_sample.q ;
ptemp <= unsigned((resize(in_sample.i * in_sample.i + in_sample.q * in_sample.q, 32))) ;
p_valid <= '1';
if( p_valid = '1') then
power_accum <= power_accum + ptemp ;-- unsigned((resize(in_sample.i * in_sample.i + in_sample.q * in_sample.q, 32))) ;
end if;
if( sample_counter > 30 ) then
i_sum <= resize(sample_history(14).i + sample_history(30).i, 32);
q_sum <= resize(sample_history(14).q + sample_history(30).q, 32);
end if ;
if( sample_counter > 31 ) then
iq_valid <= '1';
itemp <= signed(resize(shift_right(i_sum * in_sample.i - q_sum * in_sample.q, 6), 32));
qtemp <= signed(resize(shift_right(i_sum * in_sample.q + q_sum * in_sample.i, 6), 32));
if( iq_valid = '1' ) then
i_accum <= i_accum + itemp;
q_accum <= q_accum + qtemp;
accum_valid <= '1' ;
end if;
end if ;
end if ;
end if ;
end process ;
process( clock )
begin
if( reset = '1' ) then
div_power_valid_r <= '0' ;
div_i_power_r <= ( others => '0' ) ;
div_q_power_r <= ( others => '0' ) ;
elsif( rising_edge( clock ) ) then
div_power_valid_r <= div_power_valid ;
div_i_power_r <= div_i_power ;
div_q_power_r <= div_q_power ;
end if ;
end process ;
process( clock )
begin
if( reset = '1' ) then
max <= ( others => '0' ) ;
max_counter <= ( others => '0' ) ;
peak_found <= '0' ;
elsif( rising_edge( clock ) ) then
div_squared_valid <= '0' ;
div_valid <= '0' ;
if( quiet = '1' ) then
max <= ( others => '0' ) ;
max_counter <= ( others => '0' ) ;
peak_found <= '0' ;
else
if( div_power_valid_r = '1' ) then
div_i_squared <= unsigned(resize(div_i_power_r * div_i_power_r, 32)) ;
div_q_squared <= unsigned(resize(div_q_power_r * div_q_power_r, 32)) ;
div_squared_valid <= '1' ;
end if ;
if( div_squared_valid = '1' ) then
div <= unsigned(resize(div_i_squared + div_q_squared, 32)) ;
div_valid <= '1';
end if ;
if( div_valid = '1' ) then
if( div > max ) then
max <= div ;
max_counter <= to_unsigned(31, max_counter'length) ;
else
if( max_counter = 0 ) then
peak_found <= '1' ;
min <= div ;
else
max_counter <= max_counter - 1 ;
end if ;
end if ;
end if ;
end if ;
end if ;
end process ;
U_power_div : entity work.wlan_divide
generic map (
SAMPLE_WIDTH => 32,
DENOM_WIDTH => 32,
NUM_PIPELINE => 32
) port map (
clock => clock,
reset => reset,
in_i => resize(shift_left(i_accum, 8), 32),
in_q => resize(shift_left(q_accum, 8), 32),
in_denom => resize(shift_right(power_accum, 12), 32),
in_valid => accum_valid,
in_done => '0',
out_i => div_i_power,
out_q => div_q_power,
out_valid => div_power_valid,
out_done => open
) ;
process(all)
begin
if( burst_counter > 192 and burst_counter < 254 ) then
acquired <= peak_found ; --and peak_match and first_peak;
else
acquired <= '0';
end if;
end process ;
U_p_norm : entity wlan.wlan_p_norm
port map (
clock => clock,
reset => reset,
quiet => quiet,
sample => in_sample,
p_normed => p_sample,
p_mag => p_mag
);
out_sample <= in_sample;
end architecture ;

221
fpga/vhdl/wlan_agc.vhd Normal file
View File

@ -0,0 +1,221 @@
-- 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 ;
use ieee.math_real.all ;
entity wlan_agc is
port (
-- 40MHz clock and async asserted, sync deasserted reset
clock : in std_logic ;
reset : in std_logic ;
agc_hold_req : in std_logic ;
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_max : in std_logic ;
rst_gains : out std_logic ;
burst : out std_logic ;
sample_i : in signed(15 downto 0 ) ;
sample_q : in signed(15 downto 0 ) ;
sample_valid : in std_logic
) ;
end entity ;
architecture arch of wlan_agc is
type wlan_sample_t is record
i : signed(15 downto 0) ;
q : signed(15 downto 0) ;
valid : std_logic ;
end record ;
signal iir : signed( 31 downto 0 ) ;
signal ptemp : signed( 31 downto 0 ) ;
signal burst_cnt: signed( 7 downto 0 ) ;
function run_iir( x : signed( 31 downto 0); y : signed ( 31 downto 0) )
return signed
is
variable amrea : signed(31 downto 0) ;
begin
amrea := resize( x - shift_right(x, 6) + shift_right(y, 6), 32 );
return amrea;
end;
type fsm_t is (IDLE, SETTLE, ATTACK, WAIT_GAIN_ACK, WAIT_GAIN_ACK_1, HOLD) ;
type state_t is record
fsm : fsm_t ;
inc_req : std_logic ;
dec_req : std_logic ;
rst_req : std_logic ;
timer : unsigned( 10 downto 0 ) ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.inc_req := '0' ;
rv.dec_req := '0' ;
rv.rst_req := '0' ;
rv.timer := ( others => '0' );
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal sample, sample_out : wlan_sample_t ;
begin
sample.i <= sample_i;
sample.q <= sample_q;
sample.valid <= sample_valid;
gain_inc_req <= current.inc_req ;
gain_dec_req <= current.dec_req ;
gain_rst_req <= current.rst_req ;
process( clock )
begin
if( reset = '1' ) then
rst_gains <= '0' ;
burst <= '0' ;
elsif( rising_edge( clock )) then
if( ( gain_max = '1' and iir < 4200 ) or current.fsm = SETTLE ) then
rst_gains <= '1' ;
else
rst_gains <= '0' ;
end if ;
if( gain_max = '0' or iir > 150000 ) then
burst <= '1' ;
burst_cnt <= to_signed(18, burst_cnt'length) ;
else
if( ptemp > 300000 ) then
burst <= '1' ;
burst_cnt <= to_signed(6, burst_cnt'length) ;
else
if( burst_cnt > 0 ) then
burst <= '1' ;
burst_cnt <= burst_cnt - 1 ;
else
burst <= '0' ;
end if ;
end if ;
end if ;
end if ;
end process ;
process( clock )
begin
if( reset = '1' ) then
iir <= ( others => '0' ) ;
ptemp <= (others => '0' ) ;
elsif( rising_edge( clock )) then
if( current.timer = 18 ) then
iir <= ptemp ;
elsif( sample.valid = '1') then
ptemp <= sample.i * sample.i + sample.q * sample.q ;
iir <= run_iir(iir, ptemp) ;
end if ;
end if ;
end process ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.inc_req <= '0' ;
future.dec_req <= '0' ;
future.rst_req <= '0' ;
case current.fsm is
when IDLE =>
future.fsm <= SETTLE ;
when SETTLE =>
if( current.timer > 32 ) then -- 50 looks good 70 is overkill
future.timer <= ( others => '0' ) ;
future.fsm <= ATTACK ;
else
if( current.timer < 400 ) then
future.timer <= current.timer + 1 ;
end if ;
end if ;
when ATTACK =>
if( rst_gains = '1' ) then
future.timer <= ( others => '0' ) ;
elsif( current.timer < 1000 ) then
future.timer <= current.timer + 1 ;
end if ;
if( agc_hold_req = '1' ) then
future.fsm <= HOLD ;
else
-- 405000, -48dBm to enter mid, -28dBm to enter low
if( current.timer < 24 and iir > 485000 ) then --335000
-- I = Q = sqrt(2048*2048/10)=657, IIR = I^2 + Q^2= 845000
future.fsm <= WAIT_GAIN_ACK ;
future.dec_req <= '1' ;
elsif( current.timer > 300 and iir < 1000 ) then
--elsif( iir < 5000 ) then
-- I = Q = 50, IIR = I^2 + Q^2= 5000
future.inc_req <= '1' ;
future.fsm <= WAIT_GAIN_ACK ;
end if ;
end if ;
when WAIT_GAIN_ACK =>
future.fsm <= WAIT_GAIN_ACK_1 ;
when WAIT_GAIN_ACK_1 =>
if( gain_ack = '1' ) then
future.fsm <= SETTLE ;
future.timer <= ( others => '0' ) ;
end if ;
if( gain_nack = '1' ) then
future.fsm <= ATTACK ;
end if ;
when HOLD =>
if( iir < 5000 ) then
-- I = Q = 50, IIR = I^2 + Q^2= 5000
future.rst_req <= '1' ;
future.fsm <= WAIT_GAIN_ACK ;
end if ;
end case ;
end process ;
end architecture ;

298
fpga/vhdl/wlan_agc_drv.vhd Normal file
View File

@ -0,0 +1,298 @@
-- 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 ;
use ieee.math_real.all ;
entity wlan_agc_drv is
port (
-- 80 MHz clock and async asserted, sync deasserted reset
clock : in std_logic ;
reset : in std_logic ;
enable : in std_logic ;
gain_inc_req : in std_logic ;
gain_dec_req : in std_logic ;
gain_rst_req : in std_logic ;
gain_ack : out std_logic ;
gain_nack : out std_logic ;
gain_high : out std_logic ;
gain_mid : out std_logic ;
gain_low : out std_logic ;
-- Arbiter
arbiter_req : out std_logic ;
arbiter_grant : in std_logic ;
arbiter_done : out std_logic ;
-- Misc
band_sel : in std_logic ;
-- Physical Interface
sclk : out std_logic ;
miso : in std_logic ;
mosi : out std_logic ;
cs_n : out std_logic
) ;
end entity ;
architecture arch of wlan_agc_drv is
type gain_state_t is ( UNSET_GAIN_STATE, HIGH_GAIN_STATE, MID_GAIN_STATE, LOW_GAIN_STATE ) ;
type lna_gain_t is ( LNA_MID_GAIN, LNA_MAX_GAIN ) ;
type rxvga1_gain_t is ( RXVGA1_MID_GAIN, RXVGA1_MAX_GAIN ) ;
type rxvga2_gain_t is ( RXVGA2_LOW_GAIN, RXVGA2_MID_GAIN ) ;
type fsm_t is ( INIT, IDLE, SPI_WRITE, SPI_WRITE_GRANTED, WRITE_RXVGA1, WRITE_RXVGA2,
UPDATE_GAINS, SPI_WAIT, SPI_WAIT_1 ) ;
type gain_t is record
lna_gain : lna_gain_t ;
rxvga1_gain : rxvga1_gain_t ;
rxvga2_gain : rxvga2_gain_t ;
end record ;
-- -82dBm - -52dBm
constant HIGH_GAIN : gain_t := (
lna_gain => LNA_MAX_GAIN, -- 6 dB (Max)
rxvga1_gain => RXVGA1_MAX_GAIN, -- 30 dB
rxvga2_gain => RXVGA2_MID_GAIN -- 15 dB
) ;
-- -52dBm - -30dBm
constant MID_GAIN : gain_t := (
lna_gain => LNA_MID_GAIN, -- 3 dB (Mid)
rxvga1_gain => RXVGA1_MAX_GAIN, -- 30 dB
rxvga2_gain => RXVGA2_LOW_GAIN -- 0 dB
) ;
-- -30dBm - -17dBm
constant LOW_GAIN : gain_t := (
lna_gain => LNA_MID_GAIN, -- 3 dB (Mid)
rxvga1_gain => RXVGA1_MID_GAIN, -- 12 dB
rxvga2_gain => RXVGA2_LOW_GAIN -- 0 dB
) ;
type state_t is record
fsm : fsm_t ;
nfsm : fsm_t ;
initializing : std_logic ;
ack : std_logic ;
nack : std_logic ;
gain_state : gain_state_t ;
current_gain : gain_t ;
future_gain : gain_t ;
arbiter_req : std_logic ;
arbiter_done : std_logic ;
gain_inc_req : std_logic ;
gain_dec_req : std_logic ;
gain_rst_req : std_logic ;
-- Avalon-MM Interface
mm_write : std_logic ;
mm_addr : std_logic_vector(7 downto 0) ;
mm_din : std_logic_vector(7 downto 0) ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := INIT ;
rv.nfsm := INIT ;
rv.initializing := '0' ;
rv.arbiter_req := '0' ;
rv.arbiter_done := '0' ;
rv.gain_inc_req := '0' ;
rv.gain_dec_req := '0' ;
rv.gain_rst_req := '0' ;
rv.gain_state := UNSET_GAIN_STATE ;
rv.mm_addr := ( others => '0' ) ;
rv.mm_din := ( others => '0' ) ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal mm_busy : std_logic ;
begin
arbiter_req <= current.arbiter_req ;
arbiter_done <= current.arbiter_done ;
gain_high <= '1' when current.gain_state = HIGH_GAIN_STATE else '0' ;
gain_mid <= '1' when current.gain_state = MID_GAIN_STATE else '0' ;
gain_low <= '1' when current.gain_state = LOW_GAIN_STATE else '0' ;
gain_ack <= current.ack ; --'1' when current.fsm = UPDATE_GAINS else '0' ;
gain_nack <= current.nack ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.mm_write <= '0' ;
future.ack <= '0' ;
future.nack <= '0' ;
future.arbiter_done <= '0' ;
future.arbiter_req <= '0' ;
future.gain_inc_req <= gain_inc_req ;
future.gain_dec_req <= gain_dec_req ;
future.gain_rst_req <= gain_rst_req ;
case current.fsm is
when INIT =>
future.nack <= '1' ;
if( enable = '1' ) then
future.nack <= '0' ;
future.gain_state <= HIGH_GAIN_STATE ;
future.future_gain <= HIGH_GAIN ;
future.initializing <= '1' ;
future.fsm <= SPI_WRITE ;
end if ;
when IDLE =>
if( current.gain_inc_req = '1' ) then
if( current.gain_state = LOW_GAIN_STATE ) then
future.gain_state <= MID_GAIN_STATE ;
future.future_gain <= MID_GAIN ;
future.fsm <= SPI_WRITE ;
elsif( current.gain_state = MID_GAIN_STATE ) then
future.gain_state <= HIGH_GAIN_STATE ;
future.future_gain <= HIGH_GAIN ;
future.fsm <= SPI_WRITE ;
else
future.nack <= '1' ;
-- we are already as high as can be
end if ;
end if ;
if( current.gain_dec_req = '1' ) then
if( current.gain_state = MID_GAIN_STATE ) then
future.gain_state <= LOW_GAIN_STATE ;
future.future_gain <= LOW_GAIN ;
future.fsm <= SPI_WRITE ;
elsif( current.gain_state = HIGH_GAIN_STATE ) then
future.gain_state <= MID_GAIN_STATE ;
future.future_gain <= MID_GAIN ;
future.fsm <= SPI_WRITE ;
else
future.nack <= '1' ;
-- we are already as low as can be
end if ;
end if ;
if( current.gain_rst_req = '1' ) then
future.gain_state <= HIGH_GAIN_STATE ;
future.future_gain <= HIGH_GAIN ;
end if ;
if( enable = '0' ) then
future.fsm <= INIT ;
end if ;
when SPI_WRITE =>
future.arbiter_req <= '1' ;
if( arbiter_grant = '1' ) then
future.fsm <= SPI_WRITE_GRANTED ;
end if ;
when SPI_WRITE_GRANTED =>
if( current.current_gain.lna_gain /= current.future_gain.lna_gain or
current.initializing = '1' ) then
future.mm_addr <= x"75" ;
if (current.future_gain.lna_gain = LNA_MAX_GAIN ) then
if (band_sel = '0' ) then
future.mm_din <= x"D0";
else
future.mm_din <= x"E0";
end if ;
elsif (current.future_gain.lna_gain = LNA_MID_GAIN ) then
if (band_sel = '0' ) then
future.mm_din <= x"90";
else
future.mm_din <= x"A0";
end if ;
end if ;
future.mm_write <= '1' ;
future.fsm <= SPI_WAIT ;
future.nfsm <= WRITE_RXVGA1 ;
else
future.fsm <= WRITE_RXVGA1 ;
end if ;
when WRITE_RXVGA1 =>
if( current.current_gain.rxvga1_gain /= current.future_gain.rxvga1_gain or
current.initializing = '1' ) then
future.mm_addr <= x"76" ;
if (current.future_gain.rxvga1_gain = RXVGA1_MAX_GAIN ) then
future.mm_din <= x"78" ;
elsif (current.future_gain.rxvga1_gain = RXVGA1_MID_GAIN ) then
future.mm_din <= x"46" ;
end if ;
future.mm_write <= '1' ;
future.fsm <= SPI_WAIT ;
future.nfsm <= WRITE_RXVGA2 ;
else
future.fsm <= WRITE_RXVGA2 ;
end if ;
when WRITE_RXVGA2 =>
if( current.current_gain.rxvga2_gain /= current.future_gain.rxvga2_gain or
current.initializing = '1' ) then
future.mm_addr <= x"65" ;
if (current.future_gain.rxvga2_gain = RXVGA2_MID_GAIN ) then
future.mm_din <= x"05" ;
elsif (current.future_gain.rxvga2_gain = RXVGA2_LOW_GAIN ) then
future.mm_din <= x"00" ;
end if ;
future.mm_write <= '1' ;
future.fsm <= SPI_WAIT ;
future.nfsm <= UPDATE_GAINS ;
else
future.fsm <= UPDATE_GAINS ;
end if ;
when UPDATE_GAINS =>
future.ack <= '1' ;
future.initializing <= '0' ;
future.current_gain <= current.future_gain ;
future.arbiter_done <= '1' ;
future.fsm <= IDLE ;
when SPI_WAIT =>
future.fsm <= SPI_WAIT_1 ;
when SPI_WAIT_1 =>
if( mm_busy = '0' ) then
future.fsm <= current.nfsm ;
end if ;
end case ;
end process ;
end architecture ;

182
fpga/vhdl/wlan_bsd.vhd Normal file
View File

@ -0,0 +1,182 @@
-- 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 work.wlan_rx_p.all ;
entity wlan_bsd is
port (
clock : in std_logic ;
reset : in std_logic ;
modulation : in wlan_modulation_t ;
in_sample : in wlan_sample_t ;
out_sample : out wlan_sample_t ;
bsds : out wlan_bsds_t
) ;
end entity ;
architecture arch of wlan_bsd is
-- Expected to be nominally +/- 4096, so shift and clamp to +/-15
-- TODO: Move this to being LLR instead of euclidean distance?
function compress(x : in signed(15 downto 0)) return signed is
variable rv : signed(bsds.bsds(0)'range) ;
begin
if( x > 4095 ) then
rv := to_signed(2**rv'high-1, rv'length) ;
elsif( x < -4095 ) then
rv := to_signed(-(2**rv'high-1), rv'length) ;
else
rv := resize(shift_right(x,5),rv'length) ;
end if ;
return rv ;
end function ;
begin
calculate_bsd : process(clock, reset)
begin
if( reset = '1' ) then
for i in bsds.bsds'range loop
bsds.bsds(i) <= (others =>'0') ;
end loop ;
out_sample.valid <= '0' ;
bsds.valid <= '0' ;
elsif(rising_edge(clock)) then
out_sample <= in_sample ;
bsds.valid <= in_sample.valid ;
if( in_sample.valid = '1' ) then
-- Please check Figure 18-10 from WLAN standard for decisions
-- made here.
-- Note that downstream, the Viterbi decoder wants positive values
-- to represent probabilities that a '0' was transmitted, and negative
-- values to represent probabilities that a '1' was transmitted.
--
-- Therefore, the following is true of the BSD calculator:
--
-- +15 Most likely a 0
-- ...
-- +4 Soft likeliness of a 0
-- ...
-- 0 Neither a 0 or a 1
-- ...
-- -4 Soft likeliness of a 1
-- ...
-- -15 Most likely a 1
--
case modulation is
when WLAN_BPSK =>
-- b0
-- Decision region is the Y axis, 0 is negative,
-- and 1 is positive
bsds.bsds(0) <= compress(-in_sample.i) ;
-- b1, b2, b3, b4, b5 not transmitted
for i in 1 to 5 loop
bsds.bsds(i) <= (others =>'0') ;
end loop ;
when WLAN_QPSK =>
-- b0
-- Decision region is the Y axis, 0 is negative,
-- and 1 is positive
bsds.bsds(0) <= compress(-in_sample.i) ;
-- b1
-- Decision region is the X axis, 0 is negative,
-- and 1 is positive
bsds.bsds(1) <= compress(-in_sample.q) ;
-- b2, b3, b4, b5 not transmitted
for i in 2 to 5 loop
bsds.bsds(i) <= (others =>'0') ;
end loop ;
when WLAN_16QAM =>
-- b0
-- Decision region is the Y axis, 0 is negative,
-- and 1 is positive
bsds.bsds(0) <= compress(-in_sample.i) ;
-- b1
-- Decision region is the Y axis, -2 < x < 2 is 1,
-- and 0 is outside of that region
bsds.bsds(1) <= compress(abs(in_sample.i)-2590) ;
-- b2
-- Decision region is the X axis, 0 is negative,
-- and 1 is positive
bsds.bsds(2) <= compress(-in_sample.q) ;
-- b3
-- Decision region is the X axis, -2 < y < 2 is 1,
-- and 0 is outside of that region
bsds.bsds(3) <= compress(abs(in_sample.q)-2590) ;
-- b4 and b5 not transmitted
for i in 4 to 5 loop
bsds.bsds(i) <= (others =>'0') ;
end loop ;
when WLAN_64QAM =>
-- b0
-- Decision region is the Y axis, 0 is negative
-- and 1 is positive
bsds.bsds(0) <= compress(-in_sample.i) ;
-- b1
-- Decision region is the Y axis, -4 < x < 4 is 1,
-- and 0 is outside of that region
bsds.bsds(1) <= compress(abs(in_sample.i)-2528) ;
-- b2
-- Decision region is the Y axis, -6 < x < -2 or 2 < x < 6 is 0,
-- and 1 is outside of that region
bsds.bsds(2) <= compress(abs(abs(in_sample.i)-2528)-2528/2) ;
-- b3
-- Decision region is the X axis, 0 is negative
-- and 1 is positive
bsds.bsds(3) <= compress(-in_sample.q) ;
-- b4
-- Decision region is the X axis, -4 < y < 4 is 1,
-- and 0 is outside of that region
bsds.bsds(4) <= compress(abs(in_sample.q)-2528) ;
-- b5
-- Decision region is the X axis, -6 < y < -2 or 2 < y < 6 is 0,
-- and 1 is outside of that region
bsds.bsds(5) <= compress(abs(abs(in_sample.q)-2528)-2528/2) ;
when others =>
end case ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,75 @@
-- 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 ;
use ieee.math_real.all ;
library wlan ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
use wlan.cordic_p.all ;
use wlan.nco_p.all ;
entity wlan_cfo_correction is
port (
clock : in std_logic ;
reset : in std_logic ;
dphase : in signed( 15 downto 0 ) ;
dphase_valid : in std_logic ;
p_mag : in signed( 23 downto 0 ) ;
p_mag_valid : in std_logic ;
in_sample : in wlan_sample_t ;
out_sample : out wlan_sample_t
) ;
end entity;
architecture arch of wlan_cfo_correction is
signal nco_inputs : nco_input_t ;
signal nco_outputs : nco_output_t ;
begin
U_nco : entity work.nco
port map (
clock => clock,
reset => reset,
inputs => nco_inputs,
outputs => nco_outputs
) ;
process( clock )
begin
if( rising_edge( clock ) ) then
nco_inputs.valid <= in_sample.valid ;
out_sample.valid <= in_sample.valid ;
if( in_sample.valid = '1' ) then
if( p_mag_valid = '0' ) then
out_sample.i <= in_sample.i ;
out_sample.q <= in_sample.q ;
else
out_sample.i <= resize( shift_right( in_sample.i * p_mag , 15 ), 16 ) ;
out_sample.q <= resize( shift_right( in_sample.q * p_mag , 15 ), 16 ) ;
end if ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,150 @@
-- 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 ;
use ieee.math_real.all ;
library wlan ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
use wlan.cordic_p.all ;
entity wlan_cfo_estimate is
generic (
DELAY : integer := 64 ;
MOVING_WINDOW : integer := 64
) ;
port (
clock : in std_logic ;
reset : in std_logic ;
in_sample : in wlan_sample_t ;
atan_average : out signed( 31 downto 0 ) ;
out_sample : out wlan_sample_t
) ;
end entity;
architecture arch of wlan_cfo_estimate is
-- I need a sample history, correlation history, atan history
-- history helps insert new correlation history
-- correlation history helps when averaging atan2 values of corelation history
type wlan_sample_history_t is array( natural range 0 to DELAY - 1 ) of wlan_sample_t ;
signal wlan_sample_history : wlan_sample_history_t ;
type wlan_corr_t is record
i : signed(31 downto 0) ;
q : signed(31 downto 0) ;
end record ;
type wlan_correlation_history_t is array( natural range 0 to DELAY - 1 ) of wlan_corr_t ;
signal wlan_correlation_history : wlan_correlation_history_t ;
type wlan_atan_history_t is array( natural range 0 to MOVING_WINDOW - 1 ) of signed(15 downto 0) ;
signal wlan_atan_history : wlan_atan_history_t ;
signal cordic_inputs : cordic_xyz_t ;
signal cordic_outputs : cordic_xyz_t ;
signal sum : signed( 31 downto 0 ) ;
begin
-- save sample history
process( clock )
begin
if( reset = '1' ) then
for x in wlan_sample_history'range loop
wlan_sample_history(x).i <= ( others => '0' ) ;
wlan_sample_history(x).q <= ( others => '0' ) ;
end loop ;
elsif( rising_edge( clock ) ) then
if( in_sample.valid = '1' ) then
for i in 0 to wlan_sample_history'high - 1 loop
wlan_sample_history( i + 1 ) <= wlan_sample_history( i ) ;
end loop ;
wlan_sample_history(0) <= in_sample ;
end if ;
end if ;
end process ;
-- perform delay correlation on samples 64 samples apart
process( clock )
variable isum : signed( 31 downto 0 ) ;
variable qsum : signed( 31 downto 0 ) ;
begin
if( reset = '1' ) then
wlan_correlation_history <= ( others => ( i => ( others => '0'), q => ( others => '0' ) ) ) ;
elsif( rising_edge( clock ) ) then
if( in_sample.valid = '1' ) then
for i in 0 to wlan_correlation_history'high - 1 loop
wlan_correlation_history( i + 1 ) <= wlan_correlation_history( i ) ;
end loop ;
isum := in_sample.i * wlan_sample_history(DELAY - 1).i + in_sample.q * wlan_sample_history(DELAY - 1).q ;
qsum := resize( -1 * in_sample.i * wlan_sample_history(DELAY - 1).q +
in_sample.q * wlan_sample_history(DELAY - 1).i, 32) ;
wlan_correlation_history(0).i <= isum ;
wlan_correlation_history(0).q <= qsum ;
end if ;
end if ;
end process ;
-- take atan2() of delay correlator using CORDIC
cordic_inputs <= ( x => resize(shift_right(wlan_correlation_history(0).i, 7), 16),
y => resize(shift_right(wlan_correlation_history(0).q, 7), 16),
z => (others => '0'),
valid => in_sample.valid ) ;
U_cordic : entity work.cordic
port map (
clock => clock,
reset => reset,
mode => CORDIC_VECTORING,
inputs => cordic_inputs,
outputs => cordic_outputs
) ;
-- save atan2 history
process( clock )
begin
if( reset = '1' ) then
wlan_atan_history <= ( others => ( others => '0' ) ) ;
sum <= ( others => '0' );
elsif( rising_edge( clock ) ) then
if ( cordic_outputs.valid = '1' ) then
for i in 0 to wlan_atan_history'high - 1 loop
wlan_atan_history( i + 1 ) <= wlan_atan_history( i ) ;
end loop ;
wlan_atan_history(0) <= cordic_outputs.z ;
sum <= sum + cordic_outputs.z - wlan_atan_history(MOVING_WINDOW - 1);
end if ;
end if ;
end process ;
-- perform atan2 average
process( clock )
begin
if( rising_edge( clock ) ) then
atan_average <= shift_right( sum, integer(ceil(log2(real(MOVING_WINDOW)))) ) ;
end if ;
end process ;
out_sample <= in_sample ;
end architecture ;

View File

@ -0,0 +1,158 @@
-- 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 ;

149
fpga/vhdl/wlan_clamper.vhd Normal file
View File

@ -0,0 +1,149 @@
-- 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 ;
use work.wlan_rx_p.all ;
entity wlan_clamper is
port (
clock : in std_logic ;
reset : in std_logic ;
in_mod : in wlan_modulation_t ;
in_ssd : in wlan_sample_t;
out_ssd : out wlan_sample_t ;
out_clamped : out wlan_sample_t ;
out_error : out unsigned(31 downto 0)
) ;
end entity ;
architecture arch of wlan_clamper is
begin
clamp : process(clock, reset)
variable symbol : wlan_sample_t ;
begin
if( reset = '1' ) then
out_ssd <= ( (others =>'0'), (others =>'0'), '0' ) ;
out_clamped <= ( (others =>'0'), (others =>'0'), '0' ) ;
out_error <= (others =>'0') ;
symbol := ( (others =>'0'), (others =>'0'), '0' ) ;
elsif( rising_edge(clock) ) then
out_ssd <= in_ssd ;
if( in_ssd.valid = '1' ) then
case in_mod is
when WLAN_BPSK =>
symbol.q := (others =>'0') ;
if( in_ssd.i < 0 ) then
symbol.i := to_signed( -4096, symbol.i'length ) ;
else
symbol.i := to_signed( 4096, symbol.i'length ) ;
end if ;
when WLAN_QPSK =>
if( in_ssd.i < 0 ) then
symbol.i := to_signed( -2896, symbol.i'length ) ;
else
symbol.i := to_signed( 2896, symbol.i'length ) ;
end if ;
if( in_ssd.q < 0 ) then
symbol.q := to_signed( -2896, symbol.q'length ) ;
else
symbol.q := to_signed( 2896, symbol.q'length ) ;
end if ;
when WLAN_16QAM =>
-- I
if( in_ssd.i < 0 ) then
if( in_ssd.i < -2590 ) then
symbol.i := to_signed( -3886, symbol.i'length ) ;
else
symbol.i := to_signed( -1295, symbol.i'length ) ;
end if ;
else
if( in_ssd.i > 2590 ) then
symbol.i := to_signed( 3886, symbol.i'length ) ;
else
symbol.i := to_signed( 1295, symbol.i'length ) ;
end if ;
end if ;
-- Q
if( in_ssd.q < 0 ) then
if( in_ssd.q < -2590 ) then
symbol.q := to_signed( -3886, symbol.q'length ) ;
else
symbol.q := to_signed( -1295, symbol.q'length ) ;
end if ;
else
if( in_ssd.q > 2590 ) then
symbol.q := to_signed( 3886, symbol.q'length ) ;
else
symbol.q := to_signed( 1295, symbol.q'length ) ;
end if ;
end if ;
when WLAN_64QAM =>
-- I
case to_integer(in_ssd.i) is
when -32768 to -3792 => symbol.i := to_signed(-4424, symbol.i'length ) ;
when -3791 to -2528 => symbol.i := to_signed(-3160, symbol.i'length ) ;
when -2527 to -1264 => symbol.i := to_signed(-1896, symbol.i'length ) ;
when -1263 to -1 => symbol.i := to_signed( -632, symbol.i'length ) ;
when 0 to 1263 => symbol.i := to_signed( 632, symbol.i'length ) ;
when 1264 to 2527 => symbol.i := to_signed( 1896, symbol.i'length ) ;
when 2528 to 3791 => symbol.i := to_signed( 3160, symbol.i'length ) ;
when 3792 to 32767 => symbol.i := to_signed( 4424, symbol.i'length ) ;
when others => symbol.i := (others =>'0') ;
end case ;
-- Q
case to_integer(in_ssd.q) is
when -32768 to -3792 => symbol.q := to_signed(-4424, symbol.q'length ) ;
when -3791 to -2528 => symbol.q := to_signed(-3160, symbol.q'length ) ;
when -2527 to -1264 => symbol.q := to_signed(-1896, symbol.q'length ) ;
when -1263 to -1 => symbol.q := to_signed( -632, symbol.q'length ) ;
when 0 to 1263 => symbol.q := to_signed( 632, symbol.q'length ) ;
when 1264 to 2527 => symbol.q := to_signed( 1896, symbol.q'length ) ;
when 2528 to 3791 => symbol.q := to_signed( 3160, symbol.q'length ) ;
when 3792 to 32767 => symbol.q := to_signed( 4424, symbol.q'length ) ;
when others => symbol.q := (others =>'0') ;
end case ;
when others =>
end case ;
end if ;
-- TODO: Check to see if this is too much logic and needs to be pipelined
-- out_error <= unsigned(std_logic_vector(((symbol.i - in_ssd.i)*(symbol.i - in_ssd.i)) +
-- (symbol.q - in_ssd.q)*(symbol.q - in_ssd.q))) ;
out_clamped.i <= symbol.i ;
out_clamped.q <= symbol.q ;
out_clamped.valid <= in_ssd.valid ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,92 @@
-- 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_correlator is
port (
clock : in std_logic ;
reset : in std_logic ;
sample : in wlan_sample_t ;
value : out signed( 31 downto 0 )
) ;
end entity ;
architecture arch of wlan_correlator is
constant preamble : sample_array_t( 15 downto 0 ) := (
(valid => '1', i => to_signed( 269, 16), q => to_signed( 269, 16)),
(valid => '1', i => to_signed(-775, 16), q => to_signed( 14, 16)),
(valid => '1', i => to_signed( -79, 16), q => to_signed(-460, 16)),
(valid => '1', i => to_signed( 835, 16), q => to_signed( -74, 16)),
(valid => '1', i => to_signed( 538, 16), q => to_signed( 0, 16)),
(valid => '1', i => to_signed( 835, 16), q => to_signed( -74, 16)),
(valid => '1', i => to_signed( -79, 16), q => to_signed(-460, 16)),
(valid => '1', i => to_signed(-775, 16), q => to_signed( 14, 16)),
(valid => '1', i => to_signed( 269, 16), q => to_signed( 269, 16)),
(valid => '1', i => to_signed( 14, 16), q => to_signed(-775, 16)),
(valid => '1', i => to_signed(-460, 16), q => to_signed( -79, 16)),
(valid => '1', i => to_signed( -74, 16), q => to_signed( 835, 16)),
(valid => '1', i => to_signed( 0, 16), q => to_signed( 538, 16)),
(valid => '1', i => to_signed( -74, 16), q => to_signed( 835, 16)),
(valid => '1', i => to_signed(-460, 16), q => to_signed( -79, 16)),
(valid => '1', i => to_signed( 14, 16), q => to_signed(-775, 16))
);
type correlator_result_t is record
i : signed(15 downto 0) ;
q : signed(15 downto 0) ;
valid : std_logic ;
end record ;
type eq_array_t is array(natural range <>) of correlator_result_t ;
signal accum : eq_array_t(15 downto 0);
begin
process( clock )
variable isum : signed( 100 downto 0 ) ;
variable qsum : signed( 100 downto 0 ) ;
begin
if( reset = '1' ) then
value <= ( others => '0' ) ;
elsif( rising_edge( clock ) ) then
if( sample.valid = '1' ) then
for i in accum'range loop
if i = accum'high then
accum(i).i <= resize(shift_right(preamble(i).i*sample.i + preamble(i).q*sample.q, 14),16);
accum(i).q <= resize(shift_right(- preamble(i).q*sample.i + preamble(i).i*sample.q, 14),16);
else
accum(i).i <= resize(accum(i+1).i + shift_right(preamble(i).i*sample.i + preamble(i).q*sample.q, 14),16);
accum(i).q <= resize(accum(i+1).q + shift_right(- preamble(i).q*sample.i + preamble(i).i*sample.q, 14),16);
end if;
end loop;
value <= resize(accum(0).i * accum(0).i + accum(0).q * accum(0).q,32);
end if ;
end if ;
end process ;
end architecture ;

91
fpga/vhdl/wlan_crc.vhd Normal file
View File

@ -0,0 +1,91 @@
-- 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 ;
entity wlan_crc is
port (
clock : in std_logic ;
reset : in std_logic ;
in_data : in std_logic_vector(7 downto 0) ;
in_valid : in std_logic ;
crc : out std_logic_vector(31 downto 0)
) ;
end entity ;
architecture arch of wlan_crc is
signal crc_next : std_logic_vector(31 downto 0);
begin
process( reset, clock )
begin
if( reset = '1' ) then
crc_next <= ( others => '1' ) ;
elsif( rising_edge( clock ) ) then
if (in_valid = '1' ) then
crc_next(0) <= crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(1) <= crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(2) <= crc_next(26) xor in_data(5) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(3) <= crc_next(27) xor in_data(4) xor crc_next(26) xor in_data(5) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6);
crc_next(4) <= crc_next(28) xor in_data(3) xor crc_next(27) xor in_data(4) xor crc_next(26) xor in_data(5) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(5) <= crc_next(29) xor in_data(2) xor crc_next(28) xor in_data(3) xor crc_next(27) xor in_data(4) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(6) <= crc_next(30) xor in_data(1) xor crc_next(29) xor in_data(2) xor crc_next(28) xor in_data(3) xor crc_next(26) xor in_data(5) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6);
crc_next(7) <= crc_next(31) xor in_data(0) xor crc_next(30) xor in_data(1) xor crc_next(29) xor in_data(2) xor crc_next(27) xor in_data(4) xor crc_next(26) xor in_data(5) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(8) <= crc_next(0) xor crc_next(31) xor in_data(0) xor crc_next(30) xor in_data(1) xor crc_next(28) xor in_data(3) xor crc_next(27) xor in_data(4) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(9) <= crc_next(1) xor crc_next(31) xor in_data(0) xor crc_next(29) xor in_data(2) xor crc_next(28) xor in_data(3) xor crc_next(26) xor in_data(5) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6);
crc_next(10) <= crc_next(2) xor crc_next(30) xor in_data(1) xor crc_next(29) xor in_data(2) xor crc_next(27) xor in_data(4) xor crc_next(26) xor in_data(5) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(11) <= crc_next(3) xor crc_next(31) xor in_data(0) xor crc_next(30) xor in_data(1) xor crc_next(28) xor in_data(3) xor crc_next(27) xor in_data(4) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(12) <= crc_next(4) xor crc_next(31) xor in_data(0) xor crc_next(29) xor in_data(2) xor crc_next(28) xor in_data(3) xor crc_next(26) xor in_data(5) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(13) <= crc_next(5) xor crc_next(30) xor in_data(1) xor crc_next(29) xor in_data(2) xor crc_next(27) xor in_data(4) xor crc_next(26) xor in_data(5) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6);
crc_next(14) <= crc_next(6) xor crc_next(31) xor in_data(0) xor crc_next(30) xor in_data(1) xor crc_next(28) xor in_data(3) xor crc_next(27) xor in_data(4) xor crc_next(26) xor in_data(5);
crc_next(15) <= crc_next(7) xor crc_next(31) xor in_data(0) xor crc_next(29) xor in_data(2) xor crc_next(28) xor in_data(3) xor crc_next(27) xor in_data(4);
crc_next(16) <= crc_next(8) xor crc_next(30) xor in_data(1) xor crc_next(29) xor in_data(2) xor crc_next(28) xor in_data(3) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(17) <= crc_next(9) xor crc_next(31) xor in_data(0) xor crc_next(30) xor in_data(1) xor crc_next(29) xor in_data(2) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6);
crc_next(18) <= crc_next(10) xor crc_next(31) xor in_data(0) xor crc_next(30) xor in_data(1) xor crc_next(26) xor in_data(5);
crc_next(19) <= crc_next(11) xor crc_next(31) xor in_data(0) xor crc_next(27) xor in_data(4);
crc_next(20) <= crc_next(12) xor crc_next(28) xor in_data(3);
crc_next(21) <= crc_next(13) xor crc_next(29) xor in_data(2);
crc_next(22) <= crc_next(14) xor crc_next(30) xor in_data(1) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(23) <= crc_next(15) xor crc_next(31) xor in_data(0) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(24) <= crc_next(16) xor crc_next(26) xor in_data(5) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6);
crc_next(25) <= crc_next(17) xor crc_next(27) xor in_data(4) xor crc_next(26) xor in_data(5);
crc_next(26) <= crc_next(18) xor crc_next(28) xor in_data(3) xor crc_next(27) xor in_data(4) xor crc_next(24) xor crc_next(30) xor in_data(1) xor in_data(7);
crc_next(27) <= crc_next(19) xor crc_next(29) xor in_data(2) xor crc_next(28) xor in_data(3) xor crc_next(25) xor crc_next(31) xor in_data(0) xor in_data(6);
crc_next(28) <= crc_next(20) xor crc_next(30) xor in_data(1) xor crc_next(29) xor in_data(2) xor crc_next(26) xor in_data(5);
crc_next(29) <= crc_next(21) xor crc_next(31) xor in_data(0) xor crc_next(30) xor in_data(1) xor crc_next(27) xor in_data(4);
crc_next(30) <= crc_next(22) xor crc_next(31) xor in_data(0) xor crc_next(28) xor in_data(3);
crc_next(31) <= crc_next(23) xor crc_next(29) xor in_data(2);
end if;
end if;
end process;
process(crc_next)
begin
for i in 0 to 31 loop
crc(i) <= crc_next(31 - i) xor '1';
end loop;
end process;
end architecture ;

134
fpga/vhdl/wlan_csma.vhd Normal file
View File

@ -0,0 +1,134 @@
-- 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_csma is
port (
clock : in std_logic ;
reset : in std_logic ;
in_sample : in wlan_sample_t ;
quiet : out std_logic
) ;
end entity ;
architecture arch of wlan_csma is
type fsm_t is (IDLE, CAPTURE_PHY_NOISE, CSMA) ;
type unsigned_array_t is array (natural range 0 to 79) of unsigned( 31 downto 0 ) ;
type state_t is record
fsm : fsm_t ;
quiet : std_logic ;
timer : unsigned( 23 downto 0 ) ;
powersum : unsigned( 31 downto 0 ) ;
min_phy_noise : unsigned( 31 downto 0 ) ;
history : unsigned_array_t ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.timer := ( others => '0' ) ;
rv.min_phy_noise := ( others => '1' ) ;
rv.powersum := ( others => '0' ) ;
for i in rv.history'range loop
rv.history(i) := ( others => '0' ) ;
end loop ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
begin
quiet <= current.quiet ;
sync : process( clock )
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge( clock ) ) then
current <= future ;
end if ;
end process ;
comb: process(all)
begin
future <= current ;
case current.fsm is
when IDLE =>
future.fsm <= CAPTURE_PHY_NOISE ;
future.quiet <= '0' ;
when CAPTURE_PHY_NOISE =>
future.quiet <= '0' ;
--if( current.timer > 100000 ) then
if( current.timer > 110 ) then
future.fsm <= CSMA ;
future.powersum <= ( others => '0' ) ;
for i in future.history'range loop
future.history(i) <= ( others => '0' ) ;
end loop ;
future.timer <= ( others => '0' ) ;
end if ;
if( in_sample.valid = '1' ) then
future.timer <= current.timer + 1 ;
for i in 0 to current.history'high - 1 loop
future.history( i + 1 ) <= current.history( i ) ;
end loop ;
future.history(0) <= unsigned(resize(in_sample.i * in_sample.i + in_sample.q * in_sample.q, 32 ));
future.powersum <= current.powersum + current.history(0)
- current.history(79);
if( current.timer > 100 ) then
if( current.powersum < current.min_phy_noise ) then
future.min_phy_noise <= current.powersum ;
end if ;
end if ;
end if ;
when CSMA =>
if( in_sample.valid = '1' ) then
for i in 0 to current.history'high - 1 loop
future.history( i + 1 ) <= current.history( i ) ;
end loop ;
future.history(0) <= unsigned(resize(in_sample.i * in_sample.i + in_sample.q * in_sample.q, 32 ));
future.powersum <= current.powersum + current.history(0)
- current.history(9);
if( current.timer > 20 ) then
if( (current.min_phy_noise / 8 ) * 4 > current.powersum ) then
future.quiet <= '1' ;
else
future.quiet <= '0' ;
end if ;
else
future.timer <= current.timer + 1 ;
end if ;
end if ;
end case ;
end process ;
end architecture ;

194
fpga/vhdl/wlan_dcf.vhd Normal file
View File

@ -0,0 +1,194 @@
-- 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 ;
entity wlan_dcf is
port (
rx_clock : in std_logic ;
rx_reset : in std_logic ;
rx_enable : in std_logic ;
rand_lsb : in std_logic ;
rand_valid : in std_logic ;
rx_quiet : in std_logic ;
rx_block : out std_logic ;
tx_clock : in std_logic ;
tx_reset : in std_logic ;
tx_enable : in std_logic ;
tx_req : in std_logic ;
tx_idle : in std_logic ;
tx_sifs_ready : out std_logic ;
tx_difs_ready : out std_logic
) ;
end entity ;
architecture arch of wlan_dcf is
type fsm_t is (IDLE, CAPTURE_CW, LOOK_FOR_SILENCE, WAIT_END_TX ) ;
type state_t is record
fsm : fsm_t;
timer : unsigned( 15 downto 0 ) ;
rand : std_logic_vector( 7 downto 0 ) ;
cw_mask : std_logic_vector( 7 downto 0 ) ;
cw_timer : unsigned( 15 downto 0 ) ;
rx_block : std_logic ;
difs : std_logic ;
sifs : std_logic ;
end record;
function NULL_STATE return state_t is
variable rv : state_t;
begin
rv.fsm := IDLE ;
rv.timer := (others => '0' ) ;
rv.rand := (others => '0' ) ;
rv.cw_mask := (others => '0' ) ;
rv.cw_timer := (others => '0' ) ;
rv.rx_block := '0' ;
rv.difs := '0' ;
rv.sifs := '0' ;
return rv ;
end function ;
signal current : state_t ;
signal future : state_t ;
signal rx_quiet_r : std_logic_vector( 3 downto 0 );
signal rand_lsb_r : std_logic_vector( 3 downto 0 );
signal rand_valid_r : std_logic_vector( 3 downto 0 );
signal rx_block_r : std_logic_vector( 3 downto 0 );
begin
tx_sifs_ready <= current.sifs ;
tx_difs_ready <= current.difs ;
rx_block <= rx_block_r(0) ;
process( rx_clock, rx_reset )
begin
if( rx_reset = '1' ) then
rx_block_r <= ( others => '0' ) ;
elsif( rising_edge(rx_clock) ) then
rx_block_r <= current.rx_block & rx_block_r( 3 downto 1 ) ;
end if ;
end process ;
process( tx_clock, tx_reset )
begin
if( tx_reset = '1' ) then
rx_quiet_r <= ( others => '0' ) ;
rand_lsb_r <= ( others => '0' ) ;
rand_valid_r <= ( others => '0' ) ;
current <= NULL_STATE ;
elsif( rising_edge(rx_clock) ) then
rx_quiet_r <= rx_quiet & rx_quiet_r( 3 downto 1 ) ;
rand_lsb_r <= rand_lsb & rand_lsb_r( 3 downto 1 ) ;
rand_valid_r <= rand_valid & rand_valid_r( 3 downto 1 ) ;
current <= future ;
end if ;
end process ;
state_comb : process(all)
begin
future <= current;
future.rand <= rand_lsb_r(0) & current.rand( 7 downto 1 ) ;
future.rx_block <= '0' ;
case current.fsm is
when IDLE =>
future.fsm <= CAPTURE_CW ;
when CAPTURE_CW =>
future.sifs <= '0' ;
future.difs <= '0' ;
future.timer <= ( others => '0' ) ;
future.cw_timer <= 360 + to_unsigned(to_integer(unsigned(current.cw_mask and current.rand)) * 180, 16) ;
future.fsm <= LOOK_FOR_SILENCE ;
when LOOK_FOR_SILENCE =>
--if( rand_valid_r(0) = '1' ) then
if( true ) then
if( rx_quiet_r(0) = '1' ) then
if ( current.timer <= current.cw_timer ) then
future.timer <= current.timer + 1 ;
end if ;
if( current.timer = current.cw_timer ) then
future.cw_mask <= ( others => '0' ) ;
future.difs <= '1' ;
future.sifs <= '1' ;
end if ;
else
if( ( current.timer < current.cw_timer ) and tx_req = '1' ) then
future.cw_mask <= '1' & current.cw_mask( 7 downto 1 ) ;
end if ;
future.fsm <= IDLE ;
future.sifs <= '0' ;
future.difs <= '0' ;
end if ;
if( current.timer >= 40 ) then
future.sifs <= '1' ;
end if ;
end if ;
if( tx_idle = '0' ) then
future.fsm <= WAIT_END_TX ;
future.sifs <= '0' ;
future.difs <= '0' ;
future.rx_block <= '1' ;
end if ;
when WAIT_END_TX =>
future.rx_block <= '1' ;
if( tx_idle = '1' ) then
future.fsm <= CAPTURE_CW ;
future.rx_block <= '0' ;
end if ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,75 @@
-- 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 ;
use work.wlan_interleaver_p.all ;
entity wlan_deinterleaver is
port (
clock : in std_logic ;
reset : in std_logic ;
modulation : in wlan_modulation_t ;
data : in bsd_array_t(287 downto 0) ;
in_valid : in std_logic ;
depuncturer_empty : in std_logic ;
deinterleaved_mod : out wlan_modulation_t ;
deinterleaved : out bsd_array_t(287 downto 0) ;
deinterleaved_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_deinterleaver is
signal data_new : std_logic ;
signal data_r : bsd_array_t(287 downto 0) ;
begin
permute_bits : process(clock, reset)
begin
if( reset = '1' ) then
deinterleaved <= (others =>(others =>'0')) ;
deinterleaved_mod <= WLAN_BPSK ;
deinterleaved_valid <= '0' ;
data_new <= '0' ;
elsif( rising_edge(clock) ) then
deinterleaved_valid <= '0' ;
if( in_valid = '1' ) then
data_r <= data ;
data_new <= '1' ;
end if;
if( depuncturer_empty = '1' and data_new = '1' ) then
data_new <= '0' ;
deinterleaved_valid <= '1' ;
deinterleaved <= deinterleave(modulation, data) ;
if( modulation = WLAN_BPSK ) then
deinterleaved( 287 downto 48 ) <= (others =>(others => '0' )) ;
end if ;
deinterleaved_mod <= modulation ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,71 @@
-- 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_delay_correlator is
generic (
SAMPLE_DELTA : integer
) ;
port (
clock : in std_logic ;
reset : in std_logic ;
sample : in wlan_sample_t ;
value : out signed( 127 downto 0 )
) ;
end entity ;
architecture arch of wlan_delay_correlator is
signal samples : sample_array_t( 0 to SAMPLE_DELTA * 2 - 1 ) ;
begin
process( clock )
variable isum : signed( 63 downto 0 ) ;
variable qsum : signed( 63 downto 0 ) ;
begin
if( rising_edge( clock ) ) then
if( sample.valid = '1' ) then
for i in 0 to samples'high - 1 loop
samples(i+1) <= samples(i) ;
end loop ;
samples(0) <= sample ;
isum := (others => '0') ;
qsum := (others => '0') ;
for i in 0 to SAMPLE_DELTA - 1 loop
isum := isum + samples(i).i * samples(i + SAMPLE_DELTA).i +
samples(i).q * samples(i + SAMPLE_DELTA).q ;
qsum := qsum - samples(i).i * samples(i + SAMPLE_DELTA).q +
samples(i).q * samples(i + SAMPLE_DELTA).i ;
end loop ;
value <= isum * isum + qsum * qsum ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,243 @@
-- 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 ;
use ieee.math_real.all ;
use ieee.math_complex.all ;
library work ;
use work.wlan_p.all ;
use work.wlan_interleaver_p.all ;
use work.wlan_rx_p.all ;
entity wlan_demodulator is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
params : in wlan_rx_params_t ;
params_valid : in std_logic ;
in_sample : in wlan_sample_t ;
in_done : in std_logic ;
dfe_sample : out wlan_sample_t ;
out_mod : out wlan_modulation_t ;
out_data : out bsd_array_t( 287 downto 0 ) ;
out_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_demodulator is
type fsm_t is (IDLE, DEMODULATING) ;
type bsd_fsm_t is (IDLE, DEMODULATING) ;
type state_t is record
fsm : fsm_t ;
bsds : bsd_array_t(287 downto 0) ;
index : natural range 0 to 70 ;
modulation : wlan_modulation_t ;
dfe : wlan_sample_t ;
valid : std_logic ;
pilot_polarity : std_logic ;
lfsr_advance : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.bsds := (others =>( others => '0' )) ;
rv.index := 0 ;
rv.modulation := WLAN_BPSK ;
rv.valid := '0' ;
rv.pilot_polarity := '1' ;
rv.lfsr_advance := '0' ;
return rv ;
end function ;
-- TODO: Add in the pilot polarity LFSR
function reorder_bsds( x : bsd_array_t(287 downto 0) ; modulation : wlan_modulation_t ) return bsd_array_t is
variable rv : bsd_array_t(287 downto 0) ;
begin
rv := ( others => (others => '0' ) );
-- Positions 24 -> 47 come first (positive frequencies)
-- Positions 0 -> 23 are reversed and come afterwards (negative frequencies)
case modulation is
when WLAN_BPSK =>
rv(24*1-1 downto 0) := x(48*1-1 downto 24*1) ;
rv(48*1-1 downto 24*1) := x(24*1-1 downto 0) ;
when WLAN_QPSK =>
rv(24*2-1 downto 0) := x(48*2-1 downto 24*2) ;
rv(48*2-1 downto 24*2) := x(24*2-1 downto 0) ;
when WLAN_16QAM =>
rv(24*4-1 downto 0) := x(48*4-1 downto 24*4) ;
rv(48*4-1 downto 24*4) := x(24*4-1 downto 0) ;
when WLAN_64QAM =>
rv(24*6-1 downto 0) := x(48*6-1 downto 24*6) ;
rv(48*6-1 downto 24*6) := x(24*6-1 downto 0) ;
when others =>
end case ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal out_sample : wlan_sample_t ;
signal clamped : wlan_sample_t ;
signal lfsr_data : std_logic_vector( 0 downto 0 ) ;
signal lfsr_advance : std_logic ;
signal bsdd_bsds : wlan_bsds_t ;
begin
dfe_sample.i <= resize( shift_left(clamped.i, 0), 16 ) ;
dfe_sample.q <= resize( shift_left(clamped.q, 0), 16 ) ;
dfe_sample.valid <= '0' ; --clamped.valid ;
u_bsd : entity work.wlan_bsd
port map(
clock => clock,
reset => reset,
modulation => params.modulation,
in_sample => in_sample,
out_sample => out_sample,
bsds => bsdd_bsds
);
u_clampler : entity work.wlan_clamper
port map(
clock => clock,
reset => reset,
in_mod => params.modulation,
in_ssd => in_sample,
out_ssd => open,
out_clamped => clamped,
out_error => open
);
lfsr_advance <= current.lfsr_advance ;
U_lfsr : entity work.wlan_lfsr
generic map (
WIDTH => lfsr_data'length
) port map (
clock => clock,
reset => reset,
init => (others =>'1'),
init_valid => init,
advance => lfsr_advance,
data => lfsr_data,
data_valid => open
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
if( current.fsm /= IDLE and init = '1' ) then
current <= NULL_STATE ;
else
current <= future ;
end if ;
end if ;
end process ;
out_mod <= current.modulation ;
out_data <= current.bsds ;
out_valid <= current.valid ;
comb : process(all)
variable tmp_bsds : bsd_array_t(287 downto 0) ;
begin
future <= current ;
future.valid <= '0' ;
future.lfsr_advance <= '0' ;
if( params_valid = '1' ) then
future.modulation <= params.modulation ;
end if ;
future.pilot_polarity <= lfsr_data(0);
case current.fsm is
when IDLE =>
future.modulation <= WLAN_BPSK ;
future.fsm <= DEMODULATING ;
when DEMODULATING =>
if( bsdd_bsds.valid = '1' ) then
case current.index is
-- Check for DC null
when 0 =>
-- Check for outside nulls
when 27 to 37 =>
-- Check for 3 positive pilots
when 7|43|57 =>
-- Check for 1 negative pilot
when 21 =>
-- Otherwise data
when others =>
case current.modulation is
when WLAN_BPSK =>
future.bsds <= current.bsds(287 downto 48) & bsdd_bsds.bsds(0) & current.bsds(47 downto 1);
when WLAN_QPSK =>
future.bsds <= current.bsds(287 downto 96) & bsdd_bsds.bsds(1 downto 0) & current.bsds(95 downto 2);
when WLAN_16QAM =>
future.bsds <= current.bsds(287 downto 192) & bsdd_bsds.bsds(3 downto 0) & current.bsds(191 downto 4);
when WLAN_64QAM =>
future.bsds <= bsdd_bsds.bsds( 5 downto 0) & current.bsds(287 downto 6);
when others =>
end case ;
end case ;
-- Check if we've reached a full symbol length
if( current.index < 64 ) then
future.index <= current.index + 1 ;
end if ;
end if ;
if( current.index = 64) then
future.lfsr_advance <= '1' ;
future.index <= 0 ;
future.bsds <= reorder_bsds(current.bsds, current.modulation) ;
future.valid <= '1' ;
end if ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,226 @@
-- 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 ;
use work.wlan_interleaver_p.all ;
use work.wlan_rx_p.all ;
entity wlan_depuncturer is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
modulation : in wlan_modulation_t ;
data : in bsd_array_t(287 downto 0) ;
in_valid : in std_logic ;
params : in wlan_rx_params_t ;
params_valid : in std_logic ;
end_zero_pad : in std_logic ;
empty : out std_logic ;
out_soft_a : out signed(7 downto 0) ;
out_soft_b : out signed(7 downto 0) ;
out_erasure : out std_logic_vector(1 downto 0) ;
out_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_depuncturer is
signal bit_count : unsigned( 11 downto 0 ) ;
type puncture_3_4_t is (STATE_A, STATE_B, STATE_C) ;
type fsm_t is (IDLE, WAIT_FOR_DATA, DEPUNCTURING, ZEROS) ;
type state_t is record
fsm : fsm_t ;
bit_count : unsigned( 13 downto 0 ) ;
n_cbps : natural range 0 to 288 ;
num_symbols : natural range 0 to 1366 ;
-- bit_count_saved : unsigned( 13 downto 0 ) ;
decoded_bits : natural range 0 to 12000 ;
bit_index : natural range 0 to 12000 ;
n_dbps : natural range 24 to 216 ;
data : bsd_array_t( 287 downto 0 ) ;
soft_a : signed( 7 downto 0 ) ;
soft_b : signed( 7 downto 0 ) ;
erasure : std_logic_vector( 1 downto 0 ) ;
soft_valid : std_logic ;
params : wlan_rx_params_t ;
datarate : wlan_datarate_t ;
p_3_4 : puncture_3_4_t ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.bit_count := to_unsigned( 0, rv.bit_count'length ) ;
rv.n_cbps := 48 ;
-- rv.bit_count_saved := to_unsigned( 0, rv.bit_count_saved'length ) ;
rv.decoded_bits := 0 ;
rv.bit_index := 0 ;
rv.n_dbps := 24 ;
rv.data := ( others => (others => '0' ) ) ;
rv.soft_a := ( others => '0' ) ;
rv.soft_b := ( others => '0' ) ;
rv.erasure := ( others => '0' ) ;
rv.soft_valid := '0' ;
rv.datarate := WLAN_RATE_6 ;
rv.p_3_4 := STATE_A ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
begin
empty <= '0' when ( current.fsm = DEPUNCTURING ) else '1' ;
out_soft_a <= current.soft_a ;
out_soft_b <= current.soft_b ;
out_erasure <= current.erasure ;
out_valid <= current.soft_valid ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
if( init = '1' ) then
current <= NULL_STATE ;
else
current <= future ;
end if ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.soft_valid <= '0' ;
case current.fsm is
when IDLE =>
if( params_valid = '1' ) then
-- future.bit_count <= current.bit_count_saved ;
future.decoded_bits <= params.num_data_symbols ;
future.bit_index <= 0 ;
future.n_dbps <= params.n_dbps ;
future.datarate <= params.datarate;
future.n_cbps <= params.n_dbps ;
future.fsm <= WAIT_FOR_DATA ;
else
future <= NULL_STATE ;
end if ;
when WAIT_FOR_DATA =>
if( in_valid = '1' ) then
future.data <= data ;
future.fsm <= DEPUNCTURING ;
future.bit_index <= current.bit_index + 1 ;
future.bit_count <= to_unsigned( current.n_cbps - 1, future.bit_count'length ) ;
end if ;
when DEPUNCTURING =>
if( current.bit_count = 0 ) then
if( current.bit_index >= current.decoded_bits ) then
future.fsm <= ZEROS ;
else
future.fsm <= WAIT_FOR_DATA ;
end if ;
else
future.bit_index <= current.bit_index + 1 ;
future.bit_count <= current.bit_count - 1 ;
end if;
-- r=1/2
if( current.datarate = WLAN_RATE_6 or current.datarate = WLAN_RATE_12 or
current.datarate = WLAN_RATE_24 ) then
future.soft_a <= current.data(0);
future.soft_b <= current.data(1);
future.erasure <= "00";
future.data <= current.data(1 downto 0) & current.data( 287 downto 2 );
future.soft_valid <= '1' ;
end if ;
-- r=3/4
if( current.datarate = WLAN_RATE_9 or current.datarate = WLAN_RATE_18 or
current.datarate = WLAN_RATE_36 or current.datarate = WLAN_RATE_54 ) then
if( current.p_3_4 = STATE_A ) then
future.soft_a <= current.data(0);
future.soft_b <= current.data(1);
future.erasure <= "00";
future.p_3_4 <= STATE_B;
future.data <= current.data(1 downto 0) & current.data( 287 downto 2 );
elsif( current.p_3_4 = STATE_B ) then
future.soft_a <= current.data(0);
future.soft_b <= (others => '0');
future.erasure <= "01";
future.p_3_4 <= STATE_C;
future.data <= current.data(0) & current.data( 287 downto 1 );
elsif( current.p_3_4 = STATE_C ) then
future.soft_a <= (others => '0');
future.soft_b <= current.data(0);
future.erasure <= "10";
future.p_3_4 <= STATE_A;
future.data <= current.data(0) & current.data( 287 downto 1 );
end if;
future.soft_valid <= '1' ;
end if ;
-- r=2/3
if( current.datarate = WLAN_RATE_48 ) then
if( current.p_3_4 = STATE_A ) then
future.soft_a <= current.data(0);
future.soft_b <= current.data(1);
future.erasure <= "00";
future.p_3_4 <= STATE_B;
future.data <= current.data(1 downto 0) & current.data( 287 downto 2 );
elsif( current.p_3_4 = STATE_B ) then
future.soft_a <= current.data(0);
future.soft_b <= (others => '0');
future.erasure <= "01";
future.p_3_4 <= STATE_A;
future.data <= current.data(0) & current.data( 287 downto 1 );
end if ;
future.soft_valid <= '1' ;
end if ;
when ZEROS =>
if( end_zero_pad = '1' ) then
future.fsm <= IDLE ;
end if ;
future.soft_a <= ( others => '0' ) ;
future.soft_b <= ( others => '0' ) ;
future.erasure <= ( others => '1' ) ;
future.soft_valid <= '1' ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,233 @@
-- 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_rx_p.all ;
use work.wlan_p.all ;
entity wlan_descrambler is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
params : in wlan_rx_params_t ;
params_valid : in std_logic ;
bypass : in std_logic ;
in_data : in std_logic ;
in_valid : in std_logic ;
out_data : out std_logic_vector(7 downto 0) ;
out_valid : out std_logic ;
out_done : out std_logic
) ;
end entity ;
architecture arch of wlan_descrambler is
signal lfsr_advance : std_logic ;
signal lfsr_data : std_logic_vector(out_data'range) ;
signal lfsr_valid : std_logic ;
type fsm_t is (CAPTURE_BITS, CAPTURED_BYTE, INIT_SCRAMBLER, INIT_SCRAMBLER_2, INIT_SCRAMBLER_3, DESCRAMBLE_DATA) ;
type state_t is record
fsm : fsm_t ;
bits : std_logic_vector(7 downto 0) ;
bits_valid : std_logic ;
data : std_logic_vector(7 downto 0) ;
data_valid : std_logic ;
done : std_logic ;
lfsr_initialized : std_logic ;
lfsr_init_val : unsigned( 6 downto 0 ) ;
lfsr_init : std_logic ;
service_bytes : natural range 0 to 2 ;
bit_index : natural range 0 to 7 ;
symbol_bytes_left : natural range 0 to 27 ;
bytes_per_symbol : natural range 3 to 27 ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := CAPTURE_BITS ;
rv.bits := (others =>'0') ;
rv.bits_valid := '0' ;
rv.data := (others =>'0') ;
rv.data_valid := '0' ;
rv.done := '0' ;
rv.lfsr_initialized := '0' ;
rv.service_bytes := 2 ;
rv.bit_index := 0 ;
rv.symbol_bytes_left := 3 ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
function reverse(x : std_logic_vector) return std_logic_vector is
variable rv : std_logic_vector(x'range) ;
begin
for i in x'range loop
rv(x'high-i) := x(i) ;
end loop ;
return rv ;
end function ;
signal data_reversed : std_logic_vector(7 downto 0) ;
constant descrambler_table : integer_array_t(0 to 127) := (
0, 73, 36, 109, 18, 91, 54, 127,
9, 64, 45, 100, 27, 82, 63, 118,
77, 4, 105, 32, 95, 22, 123, 50,
68, 13, 96, 41, 86, 31, 114, 59,
38, 111, 2, 75, 52, 125, 16, 89,
47, 102, 11, 66, 61, 116, 25, 80,
107, 34, 79, 6, 121, 48, 93, 20,
98, 43, 70, 15, 112, 57, 84, 29,
19, 90, 55, 126, 1, 72, 37, 108,
26, 83, 62, 119, 8, 65, 44, 101,
94, 23, 122, 51, 76, 5, 104, 33,
87, 30, 115, 58, 69, 12, 97, 40,
53, 124, 17, 88, 39, 110, 3, 74,
60, 117, 24, 81, 46, 103, 10, 67,
120, 49, 92, 21, 106, 35, 78, 7,
113, 56, 85, 28, 99, 42, 71, 14
) ;
begin
data_reversed <= reverse(current.data) ;
out_data <= current.data ;
out_valid <= current.data_valid ;
out_done <= current.done ;
U_lfsr : entity work.wlan_lfsr
generic map (
WIDTH => out_data'length
) port map (
clock => clock,
reset => reset,
init => current.lfsr_init_val,
init_valid => current.lfsr_init,
advance => lfsr_advance,
data => lfsr_data,
data_valid => lfsr_valid
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
if( init = '1' ) then
current <= NULL_STATE ;
else
current <= future ;
end if ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.bits_valid <= '0' ;
future.data_valid <= '0' ;
future.done <= '0' ;
lfsr_advance <= '0' ;
future.lfsr_init <= '0' ;
if( in_valid = '1') then
future.bits <= current.bits(6 downto 0) & in_data ;
if( current.bit_index = 7 ) then
future.bit_index <= 0 ;
future.bits_valid <= '1' ;
else
future.bit_index <= current.bit_index + 1;
end if ;
end if ;
case current.fsm is
when CAPTURE_BITS =>
if( params_valid = '1' ) then
future.service_bytes <= 2 ;
end if ;
if( current.bits_valid = '1') then
future.data <= current.bits ;
future.fsm <= CAPTURED_BYTE ;
end if ;
when CAPTURED_BYTE =>
if( bypass = '1' ) then
future.data <= reverse( current.data ) ;
future.data_valid <= '1' ;
future.fsm <= CAPTURE_BITS ;
else
if( current.service_bytes = 0 ) then
future.data <= reverse( current.data ) ;
future.fsm <= DESCRAMBLE_DATA ;
else
future.fsm <= INIT_SCRAMBLER ;
future.service_bytes <= current.service_bytes - 1 ;
end if ;
end if ;
when INIT_SCRAMBLER =>
if( current.service_bytes = 1 ) then
future.lfsr_init_val <= unsigned(reverse(std_logic_vector(to_unsigned(descrambler_table(to_integer(unsigned(current.data(7 downto 1)))), 7 ) )));
future.lfsr_init <= '1' ;
future.fsm <= INIT_SCRAMBLER_2 ;
else
lfsr_advance <= '1' ;
future.fsm <= CAPTURE_BITS ;
end if ;
when INIT_SCRAMBLER_2 =>
future.fsm <= INIT_SCRAMBLER_3 ;
when INIT_SCRAMBLER_3 =>
lfsr_advance <= '1' ;
future.fsm <= CAPTURE_BITS ;
when DESCRAMBLE_DATA =>
lfsr_advance <= '1' ;
future.data <= current.data xor lfsr_data ;
future.data_valid <= '1' ;
future.fsm <= CAPTURE_BITS ;
when others =>
future.fsm <= CAPTURE_BITS ;
end case ;
end process ;
end architecture ;

106
fpga/vhdl/wlan_divide.vhd Normal file
View File

@ -0,0 +1,106 @@
-- 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 lpm ;
use lpm.lpm_components.all ;
entity wlan_divide is
generic (
SAMPLE_WIDTH : natural ;
DENOM_WIDTH : natural ;
NUM_PIPELINE : natural
) ;
port (
clock : in std_logic ;
reset : in std_logic ;
in_i : in signed(SAMPLE_WIDTH-1 downto 0) ;
in_q : in signed(SAMPLE_WIDTH-1 downto 0) ;
in_denom : in unsigned(DENOM_WIDTH-1 downto 0) ;
in_valid : in std_logic ;
in_done : in std_logic ;
out_i : out signed(SAMPLE_WIDTH-1 downto 0) ;
out_q : out signed(SAMPLE_WIDTH-1 downto 0) ;
out_valid : out std_logic ;
out_done : out std_logic
) ;
end entity ;
architecture altera of wlan_divide is
signal done : std_logic_vector(NUM_PIPELINE-1 downto 0) ;
signal valid : std_logic_vector(NUM_PIPELINE-1 downto 0) ;
begin
register_valids_and_done : process(clock, reset)
begin
if( reset = '1' ) then
done <= (others =>'0') ;
valid <= (others =>'0') ;
elsif( rising_edge(clock) ) then
done <= done(done'high-1 downto 0) & in_done ;
valid <= valid(valid'high-1 downto 0) & in_valid ;
end if ;
end process ;
out_done <= done(done'high) ;
out_valid <= valid(valid'high) ;
div_i : lpm_divide
generic map (
lpm_nrepresentation => "SIGNED",
lpm_drepresentation => "UNSIGNED",
lpm_hint => "LPM_REMAINDERPOSITIVE=TRUE",
lpm_pipeline => NUM_PIPELINE,
lpm_type => "LPM_DIVIDE",
lpm_widthd => DENOM_WIDTH,
lpm_widthn => SAMPLE_WIDTH
) port map (
clock => clock,
aclr => reset,
numer => std_logic_vector(in_i),
denom => std_logic_vector(in_denom),
remain => open,
signed(quotient) => out_i
) ;
div_q : lpm_divide
generic map (
lpm_nrepresentation => "SIGNED",
lpm_drepresentation => "UNSIGNED",
lpm_hint => "LPM_REMAINDERPOSITIVE=TRUE",
lpm_pipeline => NUM_PIPELINE,
lpm_type => "LPM_DIVIDE",
lpm_widthd => DENOM_WIDTH,
lpm_widthn => SAMPLE_WIDTH
) port map (
clock => clock,
aclr => reset,
numer => std_logic_vector(in_q),
denom => std_logic_vector(in_denom),
remain => open,
signed(quotient) => out_q
) ;
end architecture ;

View File

@ -0,0 +1,132 @@
-- 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_dsss_demodulator is
port (
clock : in std_logic ;
reset : in std_logic ;
modulation : in wlan_modulation_t ;
in_bin_idx : in natural ;
despread : in wlan_sample_t ;
out_bin_idx : out natural ;
out_bits : out std_logic_vector( 1 downto 0 ) ;
out_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_dsss_demodulator is
signal history : sample_array_t( 19 downto 0 );
signal res_i : signed( 19 downto 0 ) ;
signal a_i, a_q, b_i, b_q : signed(15 downto 0) ;
signal res_q : signed( 19 downto 0 ) ;
signal res_valid : std_logic ;
signal coded_bits : std_logic_vector( 1 downto 0 ) ;
signal coded_valid : std_logic ;
signal coded_idx : natural ;
signal decoded_bits : std_logic_vector( 19 downto 0 ) ;
signal demod_bits : std_logic_vector( 19 downto 0 ) ;
type bit_history_t is array(0 to 20) of std_logic_vector(7 downto 0) ;
signal bit_history : bit_history_t ;
begin
-- demodulate bits
process( clock )
variable wtf : signed (19 downto 0 );
begin
if( reset = '1' ) then
history <= ( others => NULL_SAMPLE ) ;
coded_bits <= ( others => '0' ) ;
coded_valid <= '0' ;
coded_idx <= 0 ;
demod_bits <= ( others => '0' ) ;
elsif( rising_edge( clock ) ) then
coded_valid <= '0' ;
if( despread.valid = '1' ) then
for i in 0 to history'high - 1 loop
history(i+1) <= history(i) ;
end loop ;
history(0) <= despread ;
if( modulation = WLAN_DBPSK ) then
coded_idx <= in_bin_idx ;
a_i <= despread.i;
a_q <= history(19).i;
b_i <= despread.q;
b_q <= history(19).q;
wtf := resize((shift_right(despread.i * history(19).i,4) + shift_right(despread.q * history(19).q,4)), 20);
res_i <= wtf;
if( wtf < 0 ) then
demod_bits(in_bin_idx) <= '1' ;
coded_bits(0) <= '1' ;
else
demod_bits(in_bin_idx) <= '0' ;
coded_bits(0) <= '0' ;
end if ;
coded_valid <= '1' ;
end if ;
end if ;
end if ;
end process ;
-- descramble decoded bits
process( clock )
begin
if( reset = '1' ) then
out_bin_idx <= 0 ;
out_bits <= ( others => '0' ) ;
out_valid <= '0' ;
bit_history <= ( others => ( others => '0' ) ) ;
decoded_bits<= ( others => '0' ) ;
elsif( rising_edge( clock ) ) then
out_valid <= '0' ;
if( coded_valid = '1' ) then
if( modulation = WLAN_DBPSK ) then
-- save per bin descrambler register
bit_history(coded_idx) <= bit_history(coded_idx)(6 downto 0) & coded_bits(0) ;
-- descramble bit
out_bits(0) <= coded_bits(0) xor bit_history(coded_idx)(3) xor bit_history(coded_idx)(6) ;
decoded_bits(coded_idx) <= coded_bits(0) xor bit_history(coded_idx)(3) xor bit_history(coded_idx)(6) ;
out_bin_idx <= coded_idx ;
out_valid <= '1' ;
end if ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,97 @@
-- 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_dsss_despreader is
port (
clock : in std_logic ;
reset : in std_logic ;
sample : in wlan_sample_t ;
despread : out wlan_sample_t
) ;
end entity ;
architecture arch of wlan_dsss_despreader is
constant preamble : sample_array_t( 19 downto 0 ) := (
(valid => '1', i => to_signed( 128, 16), q => to_signed( 128, 16)),
(valid => '1', i => to_signed( -14, 16), q => to_signed( -14, 16)),
(valid => '1', i => to_signed(-135, 16), q => to_signed(-135, 16)),
(valid => '1', i => to_signed( -20, 16), q => to_signed( -20, 16)),
(valid => '1', i => to_signed( 197, 16), q => to_signed( 197, 16)),
(valid => '1', i => to_signed( 210, 16), q => to_signed( 210, 16)),
(valid => '1', i => to_signed( 1, 16), q => to_signed( 1, 16)),
(valid => '1', i => to_signed(-135, 16), q => to_signed(-135, 16)),
(valid => '1', i => to_signed( -34, 16), q => to_signed( -34, 16)),
(valid => '1', i => to_signed( 120, 16), q => to_signed( 120, 16)),
(valid => '1', i => to_signed( 147, 16), q => to_signed( 147, 16)),
(valid => '1', i => to_signed( 128, 16), q => to_signed( 128, 16)),
(valid => '1', i => to_signed( 148, 16), q => to_signed( 148, 16)),
(valid => '1', i => to_signed( 102, 16), q => to_signed( 102, 16)),
(valid => '1', i => to_signed( -54, 16), q => to_signed( -54, 16)),
(valid => '1', i => to_signed(-159, 16), q => to_signed(-159, 16)),
(valid => '1', i => to_signed(-142, 16), q => to_signed(-142, 16)),
(valid => '1', i => to_signed(-119, 16), q => to_signed(-119, 16)),
(valid => '1', i => to_signed(-130, 16), q => to_signed(-130, 16)),
(valid => '1', i => to_signed( -86, 16), q => to_signed( -86, 16))
);
type despreader_result_t is record
i : signed(15 downto 0) ;
q : signed(15 downto 0) ;
valid : std_logic ;
end record ;
type eq_array_t is array(natural range <>) of despreader_result_t ;
signal accum : eq_array_t(19 downto 0);
begin
process( clock )
begin
if( reset = '1' ) then
elsif( rising_edge( clock ) ) then
despread.valid <= '0' ;
if( sample.valid = '1' ) then
for i in accum'range loop
if i = accum'high then
accum(i).i <= resize(shift_right(preamble(i).i*sample.i, 9), 16);
accum(i).q <= resize(shift_right(preamble(i).q*sample.q, 9), 16);
accum(i).valid <= '1';
else
accum(i).i <= resize(accum(i+1).i + shift_right(preamble(i).i*sample.i, 9), 16);
accum(i).q <= resize(accum(i+1).q + shift_right(preamble(i).q*sample.q, 9), 16);
accum(i).valid <= accum(i+1).valid;
end if;
end loop;
despread.i <= accum(0).i ;
despread.q <= accum(0).q ;
despread.valid <= accum(0).valid ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,143 @@
-- 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 ;
use ieee.math_real.all ;
library wlan ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
entity wlan_dsss_p_norm is
port (
-- 40MHz clock and async asserted, sync deasserted reset
clock : in std_logic ;
reset : in std_logic ;
in_sample : in wlan_sample_t ;
p_normed : out wlan_sample_t
) ;
end entity ;
architecture arch of wlan_dsss_p_norm is
signal pow_set : signed( 31 downto 0 ) ;
signal iir : signed( 31 downto 0 ) ;
signal dat : signed( 31 downto 0 ) ;
signal log2 : unsigned ( 8 downto 0 ) ;
signal ptemp : signed( 31 downto 0 ) ;
signal p_mag : signed( 23 downto 0 ) ;
signal timer : unsigned( 8 downto 0 ) ;
signal second_blip : std_logic ;
type unsigned_array_t is array (natural range 0 to 511) of signed( 23 downto 0 ) ;
function calc_lut return unsigned_array_t is
variable rv : unsigned_array_t ;
variable i : real ;
variable two : real ;
begin
for x in rv'range loop
i := ( 24.0 - (real(x) / 16.0) ) / 2.0 + 12.0; -- i is in log2
report integer'image(x) & " LUT " & real'image(i);
two := 2 ** i ;
if (real(two) > 5.7e5) then
two := 5.7e5;
end if;
rv(x) := to_signed(integer(round(two)), 24) ;
end loop ;
return rv ;
end;
constant mult_lut : unsigned_array_t := calc_lut;
function log2x( x : signed( 31 downto 0) )
return unsigned is
variable bits : unsigned( 8 downto 0 ) ;
begin
bits := (others => '0') ;
for i in x'range loop
if (x(i) = '1') then
bits(8 downto 4) := to_unsigned(i, 5) ;
if (real(i) < 4.0) then
bits(3 downto 4 - i) := unsigned(x(i - 1 downto 0)) ;
else
bits(3 downto 0) := unsigned(x(i - 1 downto i - 4)) ;
end if;
exit ;
end if ;
end loop ;
return bits ;
end log2x ;
function run_iir( x : signed( 31 downto 0); y : signed ( 31 downto 0) )
return signed
is
variable ret : signed(31 downto 0) ;
begin
ret := resize( x - shift_right(x, 4) + shift_right(y, 4), 32 );
return ret;
end;
begin
process( clock )
variable gain_req : std_logic ;
begin
if( reset = '1' ) then
iir <= ( others => '0' ) ;
ptemp <= ( others => '0' ) ;
p_mag <= ( others => '0' ) ;
timer <= ( others => '0' ) ;
pow_set <= ( others => '0' ) ;
second_blip <= '0' ;
elsif( rising_edge( clock )) then
p_mag <= signed(resize(mult_lut(to_integer(log2x(pow_set))), 24)) ;
p_normed.valid <= '0' ;
if (in_sample.valid = '1') then
ptemp <= in_sample.i * in_sample.i + in_sample.q * in_sample.q ;
iir <= run_iir(iir, ptemp) ;
gain_req := '0' ;
if( iir*2 < pow_set or iir > pow_set*2 ) then
gain_req := '1' ;
end if ;
if( timer = 59 ) then
timer <= ( others => '0' ) ;
if( gain_req = '1' ) then
second_blip <= '1' ;
end if ;
else
timer <= timer + 1 ;
end if;
if( second_blip = '1' ) then
if( gain_req = '1' ) then
pow_set <= iir ;
end if ;
second_blip <= '0' ;
end if ;
p_normed.i <= resize(shift_right(in_sample.i * p_mag, 16), 16) ;
p_normed.q <= resize(shift_right(in_sample.q * p_mag, 16), 16) ;
p_normed.valid <= '1' ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,193 @@
-- 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_dsss_peak_finder is
generic (
SAMPLE_WINDOW : integer := 20
) ;
port (
clock : in std_logic ;
reset : in std_logic ;
despread : in wlan_sample_t ;
bin_idx : in natural ;
out_mode_bin : out natural
) ;
end entity ;
architecture arch of wlan_dsss_peak_finder is
type peak_index_t is record
idx : unsigned(4 downto 0) ;
valid : std_logic ;
end record ;
type peak_index_array_t is array(0 to SAMPLE_WINDOW-1) of peak_index_t ;
type peak_array_t is array(0 to SAMPLE_WINDOW-1) of unsigned(4 downto 0) ;
type histo_comparison_t is array(0 to SAMPLE_WINDOW-1) of std_logic_vector(0 to SAMPLE_WINDOW-1) ;
-- which bin had the peak over the past SAMPLE_WINDOW symbols
signal peak_index : peak_index_array_t ;
-- histogram of how many peaks each bin has had over the past SAMPLE_WINDOW symbols
signal peak_histo : peak_array_t ;
signal max_bin_idx : natural ;
signal max_bin_val : unsigned( 31 downto 0 ) ;
signal max_bin_valid : std_logic ;
signal c_pow : unsigned( 31 downto 0 ) ;
signal c_pow_valid : std_logic ;
signal histo_update : std_logic ;
signal histo_comparisons : histo_comparison_t ;
signal diff_complete : std_logic ;
begin
-- calculate correlation peak
process( clock )
begin
if( reset = '1' ) then
c_pow <= ( others => '0' ) ;
c_pow_valid <= '0' ;
elsif( rising_edge( clock ) ) then
if( despread.valid = '1' ) then
c_pow <= unsigned(resize(shift_right(despread.i * despread.i + despread.q * despread.q, 5), 32)) ;
c_pow_valid <= despread.valid ;
end if ;
end if ;
end process ;
-- find peak bin in the current symbol. In RAKE terms this is the strongest finger
process( clock )
begin
if( reset = '1' ) then
max_bin_val <= ( others => '0') ;
max_bin_idx <= 0 ;
max_bin_valid <= '0' ;
elsif( rising_edge( clock ) ) then
max_bin_valid <= '0' ;
if( c_pow_valid = '1' ) then
if( max_bin_val < c_pow or bin_idx = 0) then
max_bin_val <= c_pow ;
max_bin_idx <= bin_idx ;
end if ;
if( bin_idx = 19 ) then
max_bin_valid <= '1' ;
end if ;
end if ;
end if ;
end process ;
-- update histogram
process( clock )
variable last_index : integer ;
begin
if( reset = '1' ) then
peak_index <= ( others => ( idx => ( others => '0' ), valid => '0' ) );
peak_histo <= ( others => ( others => '0' ) );
histo_update <= '0' ;
elsif( rising_edge( clock ) ) then
histo_update <= '0' ;
if( max_bin_valid = '1' ) then
for i in 0 to peak_index'high - 1 loop
peak_index(i+1) <= peak_index(i);
end loop ;
peak_index(0).idx <= to_unsigned(max_bin_idx, 5) ;
peak_index(0).valid <= '1' ;
histo_update <= '1' ;
if( peak_index(peak_index'high).valid = '1' ) then
if( peak_index(peak_index'high).idx /= max_bin_idx ) then
last_index := to_integer(peak_index(peak_index'high).idx);
peak_histo(last_index)<= peak_histo(last_index) - 1 ;
peak_histo(max_bin_idx) <= peak_histo(max_bin_idx) + 1 ;
else
histo_update <= '0' ;
end if ;
else
peak_histo(max_bin_idx) <= peak_histo(max_bin_idx) + 1 ;
end if ;
end if ;
end if ;
end process ;
-- find histogram peak by performing (n)*(n-1)/2 comparisons
process( clock )
begin
if( reset = '1' ) then
histo_comparisons <= ( others => ( others => '0' ) ) ;
elsif(rising_edge( clock ) ) then
diff_complete <= '0' ;
if( histo_update = '1' ) then
-- comparsing against oneself can be optimzed out
for ii in histo_comparisons'range loop
histo_comparisons(ii)(ii) <= '1' ;
end loop ;
for ii in 1 to histo_comparisons'high loop
for ij in 0 to ii-1 loop
if( peak_histo(ii) < peak_histo(ij) ) then
histo_comparisons(ii)(ij) <= '0' ;
histo_comparisons(ij)(ii) <= '1' ;
else
histo_comparisons(ii)(ij) <= '1' ;
histo_comparisons(ij)(ii) <= '0' ;
end if ;
end loop ;
end loop ;
diff_complete <= '1' ;
end if ;
end if ;
end process ;
-- bin that has all '1's in its comparison calculation is the mode
process( clock )
begin
if( reset = '1' ) then
out_mode_bin <= 0;
elsif( rising_edge( clock ) ) then
if( diff_complete = '1' ) then
for ii in histo_comparisons'range loop
if( histo_comparisons(ii) = x"FFFFF" ) then
out_mode_bin <= ii ;
end if ;
end loop ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,70 @@
-- 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 ;
entity wlan_dsss_plcp_crc is
port (
clock : in std_logic ;
reset : in std_logic ;
in_data : in std_logic ;
in_valid : in std_logic ;
crc : out std_logic_vector(15 downto 0)
) ;
end entity ;
architecture arch of wlan_dsss_plcp_crc is
signal crc_next : std_logic_vector(15 downto 0);
begin
process( reset, clock )
begin
if( reset = '1' ) then
crc_next <= ( others => '1' ) ;
elsif( rising_edge( clock ) ) then
if (in_valid = '1' ) then
crc_next(15) <= crc_next(14);
crc_next(14) <= crc_next(13);
crc_next(13) <= crc_next(12);
crc_next(12) <= crc_next(11) xor crc_next(15) xor in_data;
crc_next(11) <= crc_next(10);
crc_next(10) <= crc_next(9);
crc_next(9) <= crc_next(8);
crc_next(8) <= crc_next(7);
crc_next(7) <= crc_next(6);
crc_next(6) <= crc_next(5);
crc_next(5) <= crc_next(4) xor crc_next(15) xor in_data;
crc_next(4) <= crc_next(3);
crc_next(3) <= crc_next(2);
crc_next(2) <= crc_next(1);
crc_next(1) <= crc_next(0);
crc_next(0) <= crc_next(15) xor in_data ;
end if;
end if;
end process;
crc <= crc_next xor x"FFFF";
end architecture ;

140
fpga/vhdl/wlan_dsss_rx.vhd Normal file
View File

@ -0,0 +1,140 @@
-- 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.nco_p.all ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
library altera_mf ;
use altera_mf.altera_mf_components.all ;
library wlan_pll ;
entity wlan_dsss_rx is
port (
-- 40MHz clock and async asserted, sync deasserted reset
clock : in std_logic ;
reset : in std_logic ;
-- Baseband input signals
sample : in wlan_sample_t ;
params : out wlan_rx_params_t ;
params_valid : out std_logic ;
data : out std_logic_vector( 7 downto 0 ) ;
data_valid : out std_logic ;
framer_done : out std_logic ;
crc_correct : out std_logic
) ;
end entity ;
architecture arch of wlan_dsss_rx is
signal despread : wlan_sample_t ;
signal p_norm_sample : wlan_sample_t ;
signal modulation : wlan_modulation_t ;
signal bin_idx : natural range 0 to 20 ;
signal mode_bin : natural range 0 to 20 ;
signal demod_bits : std_logic_vector( 1 downto 0 ) ;
signal demod_idx : natural range 0 to 20 ;
signal demod_valid : std_logic ;
begin
U_dsss_rx_controller : entity work.wlan_dsss_rx_controller
port map (
clock => clock,
reset => reset,
in_sample => sample,
modulation => modulation,
out_bin_idx => bin_idx
) ;
U_dsss_p_norm : entity work.wlan_dsss_p_norm
port map (
clock => clock,
reset => reset,
in_sample => sample,
p_normed => p_norm_sample
) ;
U_dsss_despreader : entity work.wlan_dsss_despreader
port map (
clock => clock,
reset => reset,
sample => p_norm_sample,
despread => despread
) ;
U_dsss_peak_finder : entity work.wlan_dsss_peak_finder
port map (
clock => clock,
reset => reset,
despread => despread,
bin_idx => bin_idx,
out_mode_bin => mode_bin
) ;
U_dsss_demodulator : entity work.wlan_dsss_demodulator
port map (
clock => clock,
reset => reset,
modulation => modulation,
in_bin_idx => bin_idx,
despread => despread,
out_bin_idx => demod_idx,
out_bits => demod_bits,
out_valid => demod_valid
) ;
U_dsss_rx_framer : entity work.wlan_dsss_rx_framer
port map (
clock => clock,
reset => reset,
mode_bin => mode_bin,
demod_idx => demod_idx,
demod_bits => demod_bits,
demod_valid => demod_valid,
params => params,
params_valid => params_valid,
data => data,
data_valid => data_valid,
framer_done => framer_done,
crc_correct => crc_correct
) ;
end architecture ;

View File

@ -0,0 +1,81 @@
-- 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_dsss_rx_controller is
port (
clock : in std_logic ;
reset : in std_logic ;
in_sample : in wlan_sample_t ;
modulation : out wlan_modulation_t;
out_bin_idx : out natural
) ;
end entity;
architecture arch of wlan_dsss_rx_controller is
type fsm_t is (IDLE) ;
type state_t is record
fsm : fsm_t ;
bin_idx : natural range 0 to 20 ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.bin_idx := 0 ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
begin
out_bin_idx <= current.bin_idx ;
modulation <= WLAN_DBPSK ;
sync : process( clock )
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge( clock ) ) then
current <= future ;
end if ;
end process ;
comb: process(all)
begin
future <= current ;
if( in_sample.valid = '1' ) then
if( current.bin_idx = 19 ) then
future.bin_idx <= 0 ;
else
future.bin_idx <= current.bin_idx + 1 ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,271 @@
-- 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_dsss_rx_framer is
port (
clock : in std_logic ;
reset : in std_logic ;
mode_bin : in natural ;
demod_idx : in natural ;
demod_bits : in std_logic_vector( 1 downto 0 ) ;
demod_valid : in std_logic ;
params : out wlan_rx_params_t ;
params_valid : out std_logic ;
data : out std_logic_vector( 7 downto 0 ) ;
data_valid : out std_logic ;
framer_done : out std_logic ;
crc_correct : out std_logic
) ;
end entity ;
architecture arch of wlan_dsss_rx_framer is
type counter_t is array(0 to 19) of unsigned(4 downto 0) ;
type fsm_t is (ACQUIRING, SEARCH_FOR_SFD, CAPTURE_PLCP, VERIFY_PLCP_CRC, CAPTURE_PAYLOAD, VERIFY_FCS, COMMIT_PKT) ;
type state_t is record
fsm : fsm_t ;
mode_bin : natural range 0 to 20 ;
sfd_attempt : natural range 0 to 120 ;
byte_ready : std_logic ;
byte_count : natural range 0 to 1200 ;
pkt_len : natural range 0 to 1200 ;
payload_len : natural range 0 to 1200 ;
fcs : std_logic_vector( 31 downto 0 ) ;
bit_count : natural range 0 to 60 ;
recv_reg : std_logic_vector( 47 downto 0 ) ;
consecutive_ones : counter_t ;
plcp_crc_bit : std_logic ;
plcp_crc_bit_valid : std_logic ;
plcp_crc_init : std_logic ;
params : wlan_rx_params_t ;
params_valid : std_logic ;
framer_done : std_logic ;
crc_correct : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := ACQUIRING ;
rv.mode_bin := 0 ;
rv.sfd_attempt := 0 ;
rv.byte_ready := '0' ;
rv.byte_count := 0 ;
rv.pkt_len := 0 ;
rv.payload_len := 0 ;
rv.fcs := ( others => '0' ) ;
rv.bit_count := 0 ;
rv.recv_reg := ( others => '0' ) ;
rv.consecutive_ones := ( others => ( others => '0' ) ) ;
rv.plcp_crc_bit := '0' ;
rv.plcp_crc_bit_valid := '0' ;
rv.plcp_crc_init := '0' ;
rv.params_valid := '0' ;
rv.params.packet_valid := '0' ;
rv.framer_done := '0' ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal plcp_crc : std_logic_vector( 15 downto 0 ) ;
signal plcp_crc_endian : std_logic_vector( 15 downto 0 ) ;
signal calculated_fcs : std_logic_vector( 31 downto 0 ) ;
begin
crc_correct <= current.crc_correct ;
framer_done <= current.framer_done ;
data <= current.recv_reg( 7 downto 0 ) ;
data_valid <= current.byte_ready ;
params_valid <= current.params_valid ;
params <= current.params;
U_plcp_crc : entity wlan.wlan_dsss_plcp_crc
port map (
clock => clock,
reset => reset or current.plcp_crc_init,
in_data => current.plcp_crc_bit,
in_valid => current.plcp_crc_bit_valid,
crc => plcp_crc
) ;
U_crc : entity wlan.wlan_crc
port map (
clock => clock,
reset => reset or current.plcp_crc_init,
in_data => current.recv_reg( 7 downto 0 ),
in_valid => current.byte_ready,
crc => calculated_fcs
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process( clock )
begin
for i in 0 to 7 loop
plcp_crc_endian(i) <= plcp_crc(15 - i );
plcp_crc_endian(8+i) <= plcp_crc(7 - i );
end loop ;
future <= current ;
future.byte_ready <= '0' ;
future.plcp_crc_bit_valid <= '0' ;
future.plcp_crc_init <= '0' ;
future.params_valid <= '0' ;
future.params.packet_valid <= '0' ;
future.framer_done <= '0' ;
future.crc_correct <= '0' ;
case current.fsm is
when ACQUIRING =>
if( demod_valid = '1' ) then
if( demod_bits(0) = '1' ) then
if(future.consecutive_ones(demod_idx) = 27 ) then
future.consecutive_ones <= ( others => ( others => '0' ) ) ;
future.mode_bin <= mode_bin ;
future.sfd_attempt <= 0 ;
future.plcp_crc_init <= '1' ;
future.fsm <= SEARCH_FOR_SFD ;
else
future.consecutive_ones(demod_idx) <= current.consecutive_ones(demod_idx) + 1 ;
end if ;
else
future.consecutive_ones(demod_idx) <= ( others => '0' ) ;
end if ;
end if ;
when SEARCH_FOR_SFD =>
if( demod_valid = '1' ) then
if( demod_idx = current.mode_bin ) then
future.recv_reg(15 downto 0) <= demod_bits(0) & current.recv_reg(15 downto 1) ;
future.sfd_attempt <= current.sfd_attempt + 1 ;
end if;
end if;
if( current.recv_reg(15 downto 0) = x"F3A0" ) then
future.fsm <= CAPTURE_PLCP ;
future.bit_count <= 1 ;
elsif( current.sfd_attempt >= 130 ) then
future.fsm <= ACQUIRING ;
end if ;
when CAPTURE_PLCP =>
if( demod_valid = '1' and demod_idx = current.mode_bin ) then
if( current.bit_count <= 32 ) then
future.plcp_crc_bit <= demod_bits(0) ;
future.plcp_crc_bit_valid <= '1' ;
end if ;
future.recv_reg <= demod_bits(0) & current.recv_reg(47 downto 1) ;
if( current.bit_count = 48 ) then
future.fsm <= VERIFY_PLCP_CRC ;
end if ;
future.bit_count <= current.bit_count + 1 ;
end if ;
when VERIFY_PLCP_CRC =>
if( plcp_crc_endian = current.recv_reg(47 downto 32) ) then
future.fsm <= CAPTURE_PAYLOAD ;
future.byte_count <= 1 ;
future.pkt_len <= to_integer(unsigned(current.recv_reg(31 downto 19))) ;
future.payload_len <= to_integer(unsigned(current.recv_reg(31 downto 19))) - 4 ;
future.bit_count <= 1 ;
future.params_valid <= '1' ;
future.params.datarate <= WLAN_RATE_1 ;
future.params.length <= to_integer(unsigned(current.recv_reg(31 downto 19))) - 4 ;
else
future.fsm <= ACQUIRING ;
end if ;
future.recv_reg <= ( others => '0' ) ;
when CAPTURE_PAYLOAD =>
if( demod_valid = '1' and demod_idx = current.mode_bin ) then
future.recv_reg(7 downto 0) <= demod_bits(0) & current.recv_reg(7 downto 1) ;
if( current.bit_count = 8 ) then
future.bit_count <= 1 ;
if( current.byte_count > current.payload_len ) then
future.fcs <= demod_bits(0) & current.recv_reg(7 downto 1) & current.fcs(31 downto 8) ;
else
future.byte_ready <= '1' ;
end if ;
if( current.byte_count = current.pkt_len ) then
future.fsm <= VERIFY_FCS ;
else
future.byte_count <= current.byte_count + 1 ;
end if ;
else
future.bit_count <= current.bit_count + 1 ;
end if ;
end if ;
when VERIFY_FCS =>
future.framer_done <= '1' ;
if( current.fcs = calculated_fcs ) then
future.crc_correct <= '1' ;
future.fsm <= COMMIT_PKT ;
else
future.fsm <= ACQUIRING ;
end if ;
when COMMIT_PKT =>
future.fsm <= ACQUIRING ;
end case ;
end process ;
end architecture ;

440
fpga/vhdl/wlan_encoder.vhd Normal file
View File

@ -0,0 +1,440 @@
-- 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 ;
use work.wlan_tx_p.all ;
entity wlan_encoder is
port (
clock : in std_logic ;
reset : in std_logic ;
params : in wlan_tx_params_t ;
params_valid : in std_logic ;
pdu_start : in std_logic ;
pdu_end : in std_logic ;
scrambler : in std_logic_vector(7 downto 0) ;
scrambler_valid : in std_logic ;
scrambler_done : in std_logic ;
mod_data : out std_logic_vector(287 downto 0) ;
mod_type : out wlan_modulation_t ;
mod_valid : out std_logic ;
mod_end : in std_logic
) ;
end entity ;
architecture arch of wlan_encoder is
-- General scrambled/encoded data
type fsm_t is (IDLE, ENCODE_SIGNAL, ENCODE_DATA) ;
type puncture_state_t is (PUNCTURE_AB, PUNCTURE_A, PUNCTURE_B) ;
type state_t is record
fsm : fsm_t ;
mod_type : wlan_modulation_t ;
saved_coded : std_logic_vector(5 downto 0) ;
mod_data : std_logic_vector(287 downto 0) ;
mod_valid : std_logic ;
puncturing_nibble : std_logic ;
extra_byte : std_logic ;
bits_per_symbol : natural range 0 to 216 ;
bits_left : natural range 0 to 216 ;
puncture_state : puncture_state_t ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.mod_type := WLAN_BPSK ;
rv.saved_coded := (others =>'0') ;
rv.mod_data := (others =>'0') ;
rv.mod_valid := '0' ;
rv.puncturing_nibble := '0' ;
rv.extra_byte := '0' ;
rv.bits_per_symbol := 0 ;
rv.bits_left := 0 ;
rv.puncture_state := PUNCTURE_AB ;
return rv ;
end function ;
signal viterbi_init : std_logic ;
signal viterbi_a : std_logic_vector(7 downto 0) ;
signal viterbi_b : std_logic_vector(7 downto 0) ;
signal viterbi_done : std_logic ;
signal viterbi_valid : std_logic ;
signal current, future : state_t := NULL_STATE ;
function puncture_1_2( data : std_logic_vector ; a, b : std_logic_vector ; modulation : wlan_modulation_t ) return std_logic_vector is
variable rv : std_logic_vector(data'range) := data ;
variable punctured : std_logic_vector(15 downto 0) ;
begin
-- Interleave the values
for i in 0 to a'high loop
punctured(2*i) := a(i) ;
punctured(2*i+1) := b(i) ;
end loop ;
-- Insert them into the bits
case modulation is
when WLAN_BPSK =>
rv(47 downto 32) := punctured ;
rv(31 downto 0) := data(47 downto 16) ;
when WLAN_QPSK =>
rv(95 downto 80) := punctured ;
rv(79 downto 0) := data(95 downto 16) ;
when WLAN_16QAM =>
rv(191 downto 176) := punctured ;
rv(175 downto 0) := data(191 downto 16) ;
when WLAN_64QAM =>
rv(287 downto 272) := punctured ;
rv(271 downto 0) := data(287 downto 16) ;
when others =>
report "Not good" severity failure ;
end case ;
return rv ;
end function ;
function puncture_2_3( data : std_logic_vector ; a, b : std_logic_vector ; modulation : wlan_modulation_t ) return std_logic_vector is
variable rv : std_logic_vector(data'range) := data ;
variable punctured : std_logic_vector(11 downto 0) ;
begin
-- 2/3 puncturing pattern
punctured(0) := a(0) ;
punctured(1) := b(0) ;
punctured(2) := a(1) ;
punctured(3) := a(2) ;
punctured(4) := b(2) ;
punctured(5) := a(3) ;
punctured(6) := a(4) ;
punctured(7) := b(4) ;
punctured(8) := a(5) ;
punctured(9) := a(6) ;
punctured(10) := b(6) ;
punctured(11) := a(7) ;
case modulation is
when WLAN_BPSK =>
rv(47 downto 36) := punctured ;
rv(35 downto 0) := data(47 downto 12) ;
when WLAN_QPSK =>
rv(95 downto 84) := punctured ;
rv(83 downto 0) := data(95 downto 12) ;
when WLAN_16QAM =>
rv(191 downto 180) := punctured ;
rv(179 downto 0) := data(191 downto 12) ;
when WLAN_64QAM =>
rv(287 downto 276) := punctured ;
rv(275 downto 0) := data(287 downto 12) ;
when others =>
report "Not good again" severity failure ;
end case ;
return rv ;
end function ;
function puncture_3_4_ab( data : std_logic_vector ; a, b : std_logic_vector ; modulation : wlan_modulation_t ) return std_logic_vector is
variable rv : std_logic_vector(data'range) := data ;
variable punctured : std_logic_vector(10 downto 0) ;
begin
punctured(0) := a(0) ;
punctured(1) := b(0) ;
punctured(2) := a(1) ;
punctured(3) := b(2) ;
punctured(4) := a(3) ;
punctured(5) := b(3) ;
punctured(6) := a(4) ;
punctured(7) := b(5) ;
punctured(8) := a(6) ;
punctured(9) := b(6) ;
punctured(10) := a(7) ;
case modulation is
when WLAN_BPSK =>
rv(47 downto 37) := punctured ;
rv(36 downto 0) := data(47 downto 11) ;
when WLAN_QPSK =>
rv(95 downto 85) := punctured ;
rv(84 downto 0) := data(95 downto 11) ;
when WLAN_16QAM =>
rv(191 downto 181) := punctured ;
rv(180 downto 0) := data(191 downto 11) ;
when WLAN_64QAM =>
rv(287 downto 277) := punctured ;
rv(276 downto 0) := data(287 downto 11) ;
when others =>
report "Ugh, again" severity failure ;
end case ;
return rv ;
end function ;
function puncture_3_4_a( data : std_logic_vector ; a, b : std_logic_vector ; modulation : wlan_modulation_t ) return std_logic_vector is
variable rv : std_logic_vector(data'range) := data ;
variable punctured : std_logic_vector(9 downto 0) ;
begin
punctured(0) := a(0) ;
punctured(1) := b(1) ;
punctured(2) := a(2) ;
punctured(3) := b(2) ;
punctured(4) := a(3) ;
punctured(5) := b(4) ;
punctured(6) := a(5) ;
punctured(7) := b(5) ;
punctured(8) := a(6) ;
punctured(9) := b(7) ;
case modulation is
when WLAN_BPSK =>
rv(47 downto 38) := punctured ;
rv(37 downto 0) := data(47 downto 10) ;
when WLAN_QPSK =>
rv(95 downto 86) := punctured ;
rv(85 downto 0) := data(95 downto 10) ;
when WLAN_16QAM =>
rv(191 downto 182) := punctured ;
rv(181 downto 0) := data(191 downto 10) ;
when WLAN_64QAM =>
rv(287 downto 278) := punctured ;
rv(277 downto 0) := data(287 downto 10) ;
when others =>
report "Ugh, again" severity failure ;
end case ;
return rv ;
end function ;
function puncture_3_4_b( data : std_logic_vector ; a, b : std_logic_vector ; modulation : wlan_modulation_t ) return std_logic_vector is
variable rv : std_logic_vector(data'range) := data ;
variable punctured : std_logic_vector(10 downto 0) ;
begin
punctured(0) := b(0) ;
punctured(1) := a(1) ;
punctured(2) := b(1) ;
punctured(3) := a(2) ;
punctured(4) := b(3) ;
punctured(5) := a(4) ;
punctured(6) := b(4) ;
punctured(7) := a(5) ;
punctured(8) := b(6) ;
punctured(9) := a(7) ;
punctured(10) := b(7) ;
case modulation is
when WLAN_BPSK =>
rv(47 downto 37) := punctured ;
rv(36 downto 0) := data(47 downto 11) ;
when WLAN_QPSK =>
rv(95 downto 85) := punctured ;
rv(84 downto 0) := data(95 downto 11) ;
when WLAN_16QAM =>
rv(191 downto 181) := punctured ;
rv(180 downto 0) := data(191 downto 11) ;
when WLAN_64QAM =>
rv(287 downto 277) := punctured ;
rv(276 downto 0) := data(287 downto 11) ;
when others =>
report "Ugh, again" severity failure ;
end case ;
return rv ;
end function ;
function reverse(x : std_logic_vector) return std_logic_vector is
variable rv : std_logic_vector(x'range) ;
begin
for i in x'range loop
rv(x'high-i) := x(i) ;
end loop ;
return rv ;
end function ;
signal data_reversed : std_logic_vector(mod_data'range) ;
begin
mod_type <= current.mod_type ;
mod_data <= current.mod_data ;
mod_valid <= current.mod_valid ;
data_reversed <= reverse(current.mod_data) ;
U_viterbi_encoder : entity work.wlan_viterbi_encoder
generic map (
WIDTH => scrambler'length
) port map (
clock => clock,
reset => reset,
init => params_valid,
in_data => scrambler,
in_valid => scrambler_valid,
in_done => scrambler_done,
out_a => viterbi_a,
out_b => viterbi_b,
out_done => viterbi_done,
out_valid => viterbi_valid
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
variable tmp_data : std_logic_vector(287 downto 0) ;
begin
future <= current ;
future.mod_valid <= '0' ;
case current.fsm is
when IDLE =>
future.mod_data <= ( others => '0' );
if( params_valid = '1' ) then
future.fsm <= ENCODE_SIGNAL ;
future.mod_type <= WLAN_BPSK ;
future.bits_left <= 24-8 ;
future.bits_per_symbol <= params.n_dbps ;
future.puncture_state <= PUNCTURE_AB ;
if( params.datarate = WLAN_RATE_9) then
future.saved_coded <= ( others => '0' ) ;
future.puncturing_nibble <= '1' ;
future.extra_byte <= '1' ;
else
future.puncturing_nibble <= '0' ;
end if ;
end if ;
when ENCODE_SIGNAL =>
-- Encode 24 bits at R=1/2 with BPSK modulation, no scrambling
if( viterbi_valid = '1' ) then
future.mod_data <= puncture_1_2( current.mod_data, viterbi_a, viterbi_b, WLAN_BPSK ) ;
if( current.bits_left = 0 ) then
future.mod_valid <= '1' ;
future.fsm <= ENCODE_DATA ;
future.extra_byte <= '1' ;
if( current.puncturing_nibble = '1' and current.extra_byte = '1' ) then
future.bits_left <= current.bits_per_symbol ;
else
future.bits_left <= current.bits_per_symbol - 8 ;
end if ;
else
future.bits_left <= current.bits_left - 8 ;
end if ;
end if ;
when ENCODE_DATA =>
future.mod_type <= params.modulation ;
if( viterbi_valid = '1' ) then
case params.datarate is
when WLAN_RATE_6|WLAN_RATE_12|WLAN_RATE_24 =>
-- R=1/2
future.mod_data <= puncture_1_2(current.mod_data, viterbi_a, viterbi_b, params.modulation) ;
when WLAN_RATE_9 =>
case current.puncture_state is
when PUNCTURE_AB =>
tmp_data := puncture_3_4_ab(current.mod_data, viterbi_a, viterbi_b, WLAN_QPSK) ;
future.puncture_state <= PUNCTURE_B ;
when PUNCTURE_A =>
tmp_data := puncture_3_4_a(current.mod_data, viterbi_a, viterbi_b, WLAN_QPSK) ;
future.puncture_state <= PUNCTURE_AB ;
when PUNCTURE_B =>
tmp_data := puncture_3_4_b(current.mod_data, viterbi_a, viterbi_b, WLAN_QPSK) ;
future.puncture_state <= PUNCTURE_A ;
when others =>
report "Ahfkjhf" severity failure ;
end case ;
if( current.bits_left = 4) then
future.mod_valid <= '1' ;
-- at the last byte of stuff
if( current.extra_byte = '1' ) then
-- getting extra byte, so save it
-- made 54 bits, save top 6, send 48 bits
future.mod_data(47 downto 0) <= tmp_data(89 downto 42);
future.saved_coded <= tmp_data(95 downto 90);
else
-- made 42 bits
future.mod_data(47 downto 0) <= tmp_data(95 downto 54) & current.saved_coded;
end if ;
else
future.mod_data <= tmp_data ;
end if ;
when WLAN_RATE_18|WLAN_RATE_36|WLAN_RATE_54 =>
-- R=3/4
case current.puncture_state is
when PUNCTURE_AB =>
future.mod_data <= puncture_3_4_ab(current.mod_data, viterbi_a, viterbi_b, params.modulation) ;
future.puncture_state <= PUNCTURE_B ;
when PUNCTURE_A =>
future.mod_data <= puncture_3_4_a(current.mod_data, viterbi_a, viterbi_b, params.modulation) ;
future.puncture_state <= PUNCTURE_AB ;
when PUNCTURE_B =>
future.mod_data <= puncture_3_4_b(current.mod_data, viterbi_a, viterbi_b, params.modulation) ;
future.puncture_state <= PUNCTURE_A ;
when others =>
report "Ahfkjhf" severity failure ;
end case ;
when WLAN_RATE_48 =>
-- R=2/3
future.mod_data <= puncture_2_3(current.mod_data, viterbi_a, viterbi_b, params.modulation) ;
when others =>
report "Foff" severity failure ;
end case ;
if( current.bits_left = 0 or current.bits_left = 4) then
future.mod_valid <= '1' ;
if( current.puncturing_nibble = '1') then
if( current.extra_byte = '1' ) then
future.bits_left <= current.bits_per_symbol - 8 ;
else
future.bits_left <= current.bits_per_symbol ;
end if ;
future.extra_byte <= not current.extra_byte ;
else
future.bits_left <= current.bits_per_symbol - 8 ;
end if;
if( viterbi_done = '1' ) then
future.fsm <= IDLE ;
end if ;
else
if( current.bits_left = 4 ) then
-- BPSK R=3/4 here
future.bits_left <= 0 ;
else
future.bits_left <= current.bits_left - 8 ;
end if ;
end if ;
end if ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,332 @@
-- 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 ;

302
fpga/vhdl/wlan_fft64.vhd Normal file
View File

@ -0,0 +1,302 @@
-- 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 fft64;
library work ;
use work.wlan_p.all ;
use work.nco_p.all ;
use work.wlan_rx_p.all ;
library altera_mf ;
use altera_mf.altera_mf_components.all ;
entity wlan_fft64 is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
signal_dec : in std_logic ;
symbol_start : in std_logic ;
dphase : in signed( 15 downto 0 ) ;
in_sample : in wlan_sample_t ;
out_sample : out wlan_sample_t ;
done : out std_logic
) ;
end entity ;
architecture arch of wlan_fft64 is
signal sink_sop : std_logic ;
signal sink_sop_r : std_logic ;
signal sink_eop : std_logic ;
signal sink_eop_r : std_logic ;
signal sink_valid : std_logic ;
signal sink_ready : std_logic ;
signal sink_real : std_logic_vector(15 downto 0) ;
signal sink_imag : std_logic_vector(15 downto 0) ;
signal sink_error : std_logic_vector(1 downto 0) ;
signal source_sop : std_logic ;
signal source_eop : std_logic ;
signal source_valid : std_logic ;
signal source_ready : std_logic ;
signal source_real : std_logic_vector(22 downto 0) ;
signal source_imag : std_logic_vector(22 downto 0) ;
signal source_error : std_logic_vector(1 downto 0) ;
signal fft_sample : wlan_sample_t ;
signal samples : sample_array_t( 0 to 15 ) ;
signal fifo_input : std_logic_vector( 31 downto 0 ) ;
signal fifo_output : std_logic_vector( 31 downto 0 ) ;
signal fifo_usedw : std_logic_vector( 7 downto 0 ) ;
signal fifo_write : std_logic ;
signal fifo_read : std_logic ;
signal fifo_read_r : std_logic ;
signal fifo_full : std_logic ;
signal fifo_empty : std_logic ;
type fsm_writer_t is (W_IDLE, WRITE_IN);
type fsm_reader_t is (R_IDLE, START_CORDIC, READ_OUT, HOLD_OFF);
type state_t is record
wfsm : fsm_writer_t ;
wcount : unsigned( 9 downto 0 ) ;
rfsm : fsm_reader_t ;
rcount : unsigned( 9 downto 0 ) ;
sop : std_logic ;
eop : std_logic ;
read : std_logic ;
write : std_logic ;
signal_dec : std_logic ;
symbol_index: unsigned( 12 downto 0 ) ;
hold_off_cnt: natural range 0 to 100;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.wfsm := W_IDLE ;
rv.wcount := ( others => '0' ) ;
rv.rfsm := R_IDLE ;
rv.rcount := ( others => '0' ) ;
rv.sop := '0' ;
rv.eop := '0' ;
rv.read := '0' ;
rv.write := '0' ;
rv.signal_dec := '0' ;
rv.symbol_index := ( others => '0' ) ;
rv.hold_off_cnt := 0;
return rv ;
end function ;
signal current, future : state_t ;
signal nco_inputs : nco_input_t ;
signal nco_outputs : nco_output_t ;
signal nco_en : std_logic ;
signal corrected_i : signed( 15 downto 0 ) ;
signal corrected_q : signed( 15 downto 0 ) ;
begin
nco_en <= '1' when (current.rfsm = START_CORDIC or current.rfsm = READ_OUT) else '0';
nco_inputs <= ( dphase => dphase, valid => nco_en ) ;
U_nco : entity work.nco
port map (
clock => clock,
reset => reset or init,
inputs => nco_inputs,
outputs => nco_outputs
) ;
sync : process( clock )
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge( clock ) ) then
if( init = '1' ) then
current <= NULL_STATE ;
else
current <= future ;
end if ;
end if ;
end process ;
fifo_write <= '1' when ( ( symbol_start = '1' or current.wfsm = WRITE_IN ) and in_sample.valid = '1' ) else '0' ;
fifo_read <= '1' when ( current.rfsm = READ_OUT ) else '0' ;
comb: process(all)
begin
future <= current ;
if( init = '1' ) then
future.symbol_index <= ( others => '0' ) ;
end if ;
-- if( init = '1' ) then
-- future.signal_dec <= '0' ;
-- elsif( signal_dec = '1' ) then
-- future.signal_dec <= '1' ;
-- end if ;
case current.wfsm is
when W_IDLE =>
if( symbol_start = '1' ) then
future.wfsm <= WRITE_IN ;
future.wcount <= to_unsigned( 0, future.wcount'length ) ;
end if ;
when WRITE_IN =>
if( in_sample.valid = '1' ) then
future.wcount <= current.wcount + 1 ;
end if ;
if( current.wcount >= 64 ) then
future.wfsm <= W_IDLE ;
end if ;
end case ;
case current.rfsm is
when R_IDLE =>
if( unsigned( fifo_usedw ) >= 47 ) then
if( ( current.symbol_index = 2 and signal_dec = '1') or
current.symbol_index /= 2 ) then
future.rfsm <= START_CORDIC ;
future.rcount <= to_unsigned( 15, future.rcount'length ) ;
end if ;
end if ;
when START_CORDIC =>
if( current.rcount = 0 ) then
future.rcount <= to_unsigned( 64, future.rcount'length ) ;
future.symbol_index <= current.symbol_index + 1 ;
future.sop <= '1' ;
future.rfsm <= READ_OUT ;
else
future.rcount <= current.rcount - 1;
end if ;
when READ_OUT =>
future.sop <= '0' ;
future.eop <= '0' ;
if( unsigned( current.rcount ) = 2 ) then
future.eop <= '1' ;
end if ;
if( unsigned( current.rcount ) <= 1 ) then
future.hold_off_cnt <= 70 ;
future.rfsm <= HOLD_OFF ;
end if ;
future.rcount <= current.rcount - 1 ;
when HOLD_OFF =>
if( current.hold_off_cnt = 0 ) then
future.rfsm <= R_IDLE;
else
future.hold_off_cnt <= current.hold_off_cnt - 1;
end if;
end case ;
end process ;
U_fifo : scfifo
generic map (
lpm_width => fifo_input'length,
lpm_widthu => fifo_usedw'length,
lpm_numwords => 2**(fifo_usedw'length),
lpm_showahead => "ON"
) port map (
clock => clock,
aclr => reset,
sclr => init,
data => std_logic_vector( in_sample.i ) & std_logic_vector( in_sample.q ),
wrreq => fifo_write ,
rdreq => fifo_read,
q => fifo_output,
full => fifo_full,
empty => fifo_empty,
usedw => fifo_usedw
) ;
sink_sop <= current.sop ;
sink_eop <= current.eop ;
sink_real <= std_logic_vector(in_sample.i) ;
sink_imag <= std_logic_vector(in_sample.q) ;
sink_valid <= in_sample.valid ;
sink_error <= (others =>'0') ;
source_ready <= '1' ;
out_sample <= fft_sample ;
done <= '0' when reset = '1' else source_eop and source_valid when rising_edge(clock) ;
cfo_correction_stage : process(clock, reset)
begin
if( reset = '1' ) then
sink_sop_r <= '0' ;
sink_eop_r <= '0' ;
fifo_read_r <= '0' ;
elsif( rising_edge(clock) ) then
sink_sop_r <= sink_sop ;
sink_eop_r <= sink_eop ;
fifo_read_r <= fifo_read ;
corrected_i <= resize(shift_right(signed(fifo_output( 31 downto 16 )) * nco_outputs.re - signed(fifo_output( 15 downto 0 )) * nco_outputs.im, 11), 16);
corrected_q <= resize(shift_right(signed(fifo_output( 31 downto 16 )) * nco_outputs.im + signed(fifo_output( 15 downto 0 )) * nco_outputs.re, 11), 16);
end if ;
end process ;
U_fft64 : entity fft64.fft64
port map (
clk => clock,
reset_n => not(reset),
fftpts_in => std_logic_vector(to_unsigned(64,7)),
inverse => "0",
sink_sop => sink_sop_r,
sink_eop => sink_eop_r,
sink_valid => fifo_read_r,
sink_real => std_logic_vector(corrected_i),
sink_imag => std_logic_vector(corrected_q),
sink_error => sink_error,
source_ready => source_ready,
fftpts_out => open,
sink_ready => sink_ready,
source_error => source_error,
source_sop => source_sop,
source_eop => source_eop,
source_valid => source_valid,
source_real => source_real,
source_imag => source_imag
) ;
present_output : process(clock, reset)
begin
if( reset = '1' ) then
fft_sample <= NULL_SAMPLE ;
elsif( rising_edge(clock) ) then
fft_sample.valid <= source_valid ;
if( source_valid = '1' ) then
fft_sample.i <= signed(source_real(15 downto 0)) ;
fft_sample.q <= signed(source_imag(15 downto 0)) ;
end if ;
end if ;
end process ;
end architecture ;

334
fpga/vhdl/wlan_framer.vhd Normal file
View File

@ -0,0 +1,334 @@
-- 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 ;
library work ;
use work.wlan_p.all ;
use work.wlan_tx_p.all ;
entity wlan_framer is
port (
clock : in std_logic ;
reset : in std_logic ;
params : in wlan_tx_params_t ;
params_valid : in std_logic ;
encoder_start : in std_logic ;
fifo_data : in std_logic_vector(7 downto 0) ;
fifo_empty : in std_logic ;
fifo_re : out std_logic ;
buffer_room : in std_logic ;
mod_done : in std_logic ;
out_data : out std_logic_vector(7 downto 0) ;
out_valid : out std_logic ;
done : out std_logic
) ;
end entity ;
architecture arch of wlan_framer is
type fsm_t is (IDLE, FRAME_SIGNAL, WAIT_FOR_SIGNAL_MODULATED, FRAME_SERVICE, FRAME_DATA, WAIT_ZZ, WAIT_YY, WAIT_FOR_DATA_MODULATED, WAIT_FOR_BUFFER_ROOM) ;
type signal_field_t is record
rate : unsigned(3 downto 0) ;
length : unsigned(11 downto 0) ;
parity : std_logic ;
end record ;
function "xor"(x : std_logic_vector) return std_logic is
variable rv : std_logic := '0' ;
begin
for i in x'range loop
rv := x(i) xor rv ;
end loop ;
return rv ;
end function ;
function calculate_parity( x : signal_field_t ) return std_logic is
constant xx : std_logic_vector(15 downto 0) := std_logic_vector(x.rate & x.length) ;
constant rv : std_logic := "xor"(xx) ;
begin
return rv ;
end function ;
type state_t is record
fsm : fsm_t ;
signal_field : signal_field_t ;
signal_slv : unsigned(23 downto 0) ;
done : std_logic ;
bytes_left : natural range 0 to 4095 ;
symbol_bytes_left : natural range 0 to 27 ;
puncturing_nibble : std_logic ;
extra_byte : std_logic ;
symbol_bytes : natural range 0 to 27 ;
data : std_logic_vector(7 downto 0) ;
crc_data_valid : std_logic ;
data_valid : std_logic ;
fifo_re : std_logic ;
crc_reset : std_logic ;
crc_mux : std_logic ;
crc_index : natural range 0 to 8 ;
bad_index : natural range 0 to 80 ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.signal_field := ( (others =>'0'), (others =>'0'), '0' ) ;
rv.signal_slv := (others =>'0') ;
rv.done := '0' ;
rv.bytes_left := 0 ;
rv.puncturing_nibble := '0' ;
rv.extra_byte := '0' ;
rv.symbol_bytes := 0 ;
rv.symbol_bytes_left := 0 ;
rv.data := (others =>'0') ;
rv.crc_data_valid := '0' ;
rv.data_valid := '0' ;
rv.fifo_re := '0' ;
rv.crc_reset := '0' ;
rv.crc_mux := '0' ;
rv.crc_index := 0 ;
rv.bad_index := 0 ;
return rv ;
end function ;
function pack( x : signal_field_t ) return unsigned is
variable rv : unsigned(23 downto 0) ;
begin
rv(3 downto 0) := x.rate ;
rv(4) := '0' ;
rv(16 downto 5) := x.length ;
rv(17) := x.parity ;
rv(23 downto 18) := (others =>'0') ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal calculated_crc : std_logic_vector( 31 downto 0 ) ;
begin
fifo_re <= current.fifo_re ;
out_valid <= current.data_valid ;
done <= current.done ;
process(all)
begin
if( current.crc_mux = '1' ) then
case current.crc_index is
when 0 => out_data <= calculated_crc( 31 downto 24 ) ;
when 1 => out_data <= calculated_crc( 23 downto 16 ) ;
when 2 => out_data <= calculated_crc( 15 downto 8 ) ;
when 3 => out_data <= calculated_crc( 7 downto 0 ) ;
when others => out_data <= ( others => '0' ) ;
end case ;
else
out_data <= current.data ;
end if ;
end process ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
variable sf : signal_field_t ;
begin
sf := ( (others =>'0'), (others =>'0'), '0' ) ;
future <= current ;
future.done <= '0' ;
future.crc_data_valid <= '0' ;
future.data_valid <= '0' ;
future.fifo_re <= '0' ;
future.crc_reset <= '0' ;
case current.fsm is
when IDLE =>
future.crc_mux <= '0' ;
if( encoder_start = '1' ) then
future.fsm <= FRAME_SIGNAL ;
sf.length := to_unsigned( params.length, sf.length'length ) + 4 ;
case params.datarate is
-- Note table goes R4-R1 instead of R1-R4
when WLAN_RATE_6 => sf.rate := "1011" ;
when WLAN_RATE_9 => sf.rate := "1111" ;
when WLAN_RATE_12 => sf.rate := "1010" ;
when WLAN_RATE_18 => sf.rate := "1110" ;
when WLAN_RATE_24 => sf.rate := "1001" ;
when WLAN_RATE_36 => sf.rate := "1101" ;
when WLAN_RATE_48 => sf.rate := "1000" ;
when WLAN_RATE_54 => sf.rate := "1100" ;
when others => report "Error in datarate" severity failure ;
end case ;
sf.parity := calculate_parity( sf ) ;
future.signal_field <= sf ;
future.signal_slv <= pack(sf) ;
future.bytes_left <= 3-1 ;
future.symbol_bytes <= params.n_dbps/8 ;
future.symbol_bytes_left <= params.n_dbps/8 - 1;
future.crc_reset <= '1' ;
if( params.datarate = WLAN_RATE_9) then
future.puncturing_nibble <= '1' ;
future.extra_byte <= '1' ;
else
future.puncturing_nibble <= '0' ;
end if ;
end if ;
when FRAME_SIGNAL =>
-- SIGNAL field needs to be packed and sent out unscrambled
future.data <= std_logic_vector(current.signal_slv(7 downto 0)) ;
future.data_valid <= '1' ;
if( current.bytes_left = 0 ) then
future.fsm <= WAIT_FOR_SIGNAL_MODULATED ;
future.bytes_left <= 2-1 ;
else
future.signal_slv <= shift_right(current.signal_slv,8) ;
future.bytes_left <= current.bytes_left - 1 ;
end if ;
when WAIT_FOR_SIGNAL_MODULATED =>
if( mod_done = '1' ) then
future.fsm <= FRAME_SERVICE ;
future.bad_index <= 0;
end if ;
when WAIT_ZZ =>
if( current.bad_index = 70 ) then
future.fsm <= FRAME_SERVICE ;
else
future.bad_index <= current.bad_index + 1;
end if;
when FRAME_SERVICE =>
future.data <= (others =>'0') ;
future.data_valid <= '1' ;
if( current.bytes_left = 0 ) then
future.fifo_re <= '1' ;
future.fsm <= FRAME_DATA ;
future.bytes_left <= to_integer(current.signal_field.length) - 1 ;
if( current.puncturing_nibble = '1' and current.extra_byte = '1' ) then
future.symbol_bytes_left <= current.symbol_bytes - 2 ;
future.extra_byte <= '0' ;
else
future.symbol_bytes_left <= current.symbol_bytes - 2 - 1 ;
end if ;
else
future.bytes_left <= current.bytes_left - 1 ;
end if ;
when FRAME_DATA =>
future.data_valid <= '1' ;
if( current.bytes_left = 3 ) then
future.crc_index <= 3 ;
elsif( current.bytes_left < 3 ) then
future.crc_index <= current.crc_index - 1 ;
end if ;
if( current.bytes_left <= 3 ) then
future.crc_mux <= '1' ;
else
future.data <= fifo_data ;
future.crc_data_valid <= '1' ;
if( current.bytes_left > 4 ) then
future.fifo_re <= '1' ;
end if;
end if ;
if( current.bytes_left = 0 ) then
future.fsm <= IDLE ;
future.done <= '1' ;
else
if( current.symbol_bytes_left = 0 ) then
future.fifo_re <= '0' ;
future.fsm <= WAIT_FOR_DATA_MODULATED ;
else
future.symbol_bytes_left <= current.symbol_bytes_left - 1 ;
end if ;
future.bytes_left <= current.bytes_left - 1 ;
end if ;
when WAIT_FOR_DATA_MODULATED =>
if( mod_done = '1' ) then
if( current.puncturing_nibble = '1' ) then
if( current.extra_byte = '1' ) then
future.symbol_bytes_left <= current.symbol_bytes ;
else
future.symbol_bytes_left <= current.symbol_bytes - 1 ;
end if;
future.extra_byte <= not current.extra_byte ;
else
future.symbol_bytes_left <= current.symbol_bytes - 1 ;
end if;
if( buffer_room = '1' ) then
future.bad_index <= 0;
future.fsm <= FRAME_DATA ;
future.fifo_re <= '1' ;
else
future.fsm <= WAIT_FOR_BUFFER_ROOM ;
end if ;
end if ;
when WAIT_YY =>
if( current.bad_index = 32 ) then
future.fsm <= FRAME_DATA ;
future.fifo_re <= '1' ;
else
future.bad_index <= current.bad_index + 1;
end if;
when WAIT_FOR_BUFFER_ROOM =>
if( buffer_room = '1' ) then
future.fifo_re <= '1' ;
future.fsm <= FRAME_DATA ;
end if ;
when others =>
future.fsm <= IDLE ;
end case ;
end process ;
U_crc : entity wlan.wlan_crc
port map (
clock => clock,
reset => reset or current.crc_reset,
in_data => current.data,
in_valid => current.crc_data_valid,
crc => calculated_crc
) ;
end architecture ;

164
fpga/vhdl/wlan_ifft64.vhd Normal file
View File

@ -0,0 +1,164 @@
-- 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 fft64;
library work ;
use work.wlan_p.all ;
entity wlan_ifft64 is
port (
clock : in std_logic ;
reset : in std_logic ;
symbol_start : in std_logic ;
symbol_end : in std_logic ;
in_sample : in wlan_sample_t ;
out_sample : out wlan_sample_t ;
out_valid_cp : out std_logic ;
ifft_ready : out std_logic ;
done : out std_logic
) ;
end entity ;
architecture arch of wlan_ifft64 is
signal sink_sop : std_logic ;
signal sink_eop : std_logic ;
signal sink_valid : std_logic ;
signal sink_ready : std_logic ;
signal sink_real : std_logic_vector(15 downto 0) ;
signal sink_imag : std_logic_vector(15 downto 0) ;
signal sink_error : std_logic_vector(1 downto 0) ;
signal source_sop : std_logic ;
signal source_eop : std_logic ;
signal source_valid : std_logic ;
signal source_ready : std_logic ;
signal source_real : std_logic_vector(22 downto 0) ;
signal source_imag : std_logic_vector(22 downto 0) ;
signal source_error : std_logic_vector(1 downto 0) ;
signal cp_valid : std_logic ;
signal ifft_sample : wlan_sample_t ;
signal ready : std_logic ;
signal inflight : natural range 0 to 5 ;
signal cooldown : natural range 0 to 200 ;
begin
sink_sop <= symbol_start ;
sink_eop <= symbol_end ;
sink_real <= std_logic_vector(in_sample.i) ;
sink_imag <= std_logic_vector(in_sample.q) ;
sink_valid <= in_sample.valid ;
sink_error <= (others =>'0') ;
source_ready <= '1' ;
out_sample <= ifft_sample ;
out_valid_cp <= cp_valid ;
done <= '0' when reset = '1' else source_eop and source_valid when rising_edge(clock) ;
ifft_ready <= '0' when ( source_eop = '1' or ready = '0' or inflight >= 2 or cooldown > 0) else '1' ;
U_ifft64 : entity fft64.fft64
port map (
clk => clock,
reset_n => not(reset),
fftpts_in => std_logic_vector(to_unsigned(64,7)),
inverse => "1",
sink_sop => sink_sop,
sink_eop => sink_eop,
sink_valid => sink_valid,
sink_real => sink_real,
sink_imag => sink_imag,
sink_error => sink_error,
source_ready => source_ready,
fftpts_out => open,
sink_ready => sink_ready,
source_error => source_error,
source_sop => source_sop,
source_eop => source_eop,
source_valid => source_valid,
source_real => source_real,
source_imag => source_imag
) ;
present_output : process(clock, reset)
variable cp_down : natural range 0 to 48 ;
begin
if( reset = '1' ) then
cp_down := 47 ;
cp_valid <= '0' ;
ready <= '1' ;
ifft_sample <= NULL_SAMPLE ;
inflight <= 0;
cooldown <= 0;
elsif( rising_edge(clock) ) then
ifft_sample.valid <= source_valid ;
cp_valid <= '0' ;
if( source_valid = '1' and source_sop = '1' ) then
ready <= '0';
elsif( source_eop = '1' ) then
ready <= '1';
end if;
if( sink_valid = '1' and sink_sop = '1' ) then
cooldown <= 128;
-- increment, unless source is also outputting
if( source_valid = '1' and source_sop = '1' ) then
inflight <= inflight;
else
inflight <= inflight + 1;
end if ;
elsif( source_valid = '1' and source_sop = '1' ) then
if( sink_valid = '1' and sink_sop = '1' ) then
cooldown <= 128;
end if;
inflight <= inflight - 1;
else
if( cooldown > 0 ) then
cooldown <= cooldown - 1;
end if;
end if ;
if( source_valid = '1' ) then
ifft_sample.i <= resize(shift_right(signed(source_real)+8,4),ifft_sample.i'length) ;
ifft_sample.q <= resize(shift_right(signed(source_imag)+8,4),ifft_sample.q'length) ;
if( cp_down = 0 ) then
cp_valid <= '1' ;
end if ;
if( source_sop = '1' ) then
cp_down := 47 ;
elsif( source_eop = '1' ) then
cp_down := 47 ;
elsif( cp_down > 0 ) then
cp_down := cp_down - 1 ;
end if ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,62 @@
-- 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 ;
use work.wlan_interleaver_p.all ;
entity wlan_interleaver is
port (
clock : in std_logic ;
reset : in std_logic ;
modulation : in wlan_modulation_t ;
data : in std_logic_vector(287 downto 0) ;
in_valid : in std_logic ;
interleaved : out std_logic_vector(287 downto 0) ;
interleaved_mod : out wlan_modulation_t ;
interleaved_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_interleaver is
begin
permute_bits : process(clock, reset)
begin
if( reset = '1' ) then
interleaved <= (others =>'0') ;
interleaved_mod <= WLAN_BPSK ;
interleaved_valid <= '0' ;
elsif( rising_edge(clock) ) then
interleaved_valid <= in_valid ;
if( in_valid = '1' ) then
interleaved <= interleave(modulation, data) ;
interleaved_mod <= modulation ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,133 @@
-- 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.math_real.all ;
library work ;
use work.wlan_p.all ;
package wlan_interleaver_p is
-- Deferred initialization in package body after function definition
constant WLAN_INTERLEAVER_BPSK : integer_array_t ;
constant WLAN_INTERLEAVER_QPSK : integer_array_t ;
constant WLAN_INTERLEAVER_16QAM : integer_array_t ;
constant WLAN_INTERLEAVER_64QAM : integer_array_t ;
-- Interleaving occurs on bits
function interleave( modulation : wlan_modulation_t ; x : std_logic_vector(287 downto 0) ) return std_logic_vector ;
-- Deinterleaving occurs on bit soft decisions
function deinterleave( modulation : wlan_modulation_t ; x : bsd_array_t(287 downto 0) ) return bsd_array_t ;
end package ;
package body wlan_interleaver_p is
function get_table( modulation : wlan_modulation_t ) return integer_array_t is
begin
case modulation is
when WLAN_BPSK => return WLAN_INTERLEAVER_BPSK ;
when WLAN_QPSK => return WLAN_INTERLEAVER_QPSK ;
when WLAN_16QAM => return WLAN_INTERLEAVER_16QAM ;
when WLAN_64QAM => return WLAN_INTERLEAVER_64QAM ;
when others => return WLAN_INTERLEAVER_BPSK ;
end case ;
report "get_table: Could not figure out modulation" severity failure ;
end function ;
function interleave( modulation : wlan_modulation_t ; x : std_logic_vector(287 downto 0) ) return std_logic_vector is
variable t : integer_array_t(0 to 287) ;
variable y : std_logic_vector(287 downto 0) := (others =>'-') ;
begin
t := get_table( modulation ) ;
for i in t'range loop
-- 0 only happens for the 0 entry, so stop there
if( i > 0 and t(i) = 0 ) then
exit ;
else
y(t(i)) := x(i) ;
end if ;
end loop ;
return y ;
end function ;
function deinterleave( modulation : wlan_modulation_t ; x : bsd_array_t(287 downto 0) ) return bsd_array_t is
variable t : integer_array_t(0 to 287) ;
variable y : bsd_array_t(287 downto 0) ;
begin
y := (others => (others => '0' )) ;
t := get_table( modulation ) ;
for i in t'range loop
-- Stop at the next 0 entry
if( i > 0 and t(i) = 0 ) then
exit ;
else
y(i) := x(t(i)) ;
end if ;
end loop ;
return y ;
end function ;
function calculate_interleaver_table( modulation : wlan_modulation_t ) return integer_array_t is
variable n_cbps : natural ;
variable n_bpsc : natural ;
variable i : natural ;
variable j : natural ;
variable s : natural ;
variable rv : integer_array_t(0 to 287) := (others => 0) ;
begin
case modulation is
when WLAN_BPSK =>
n_bpsc := 1 ;
n_cbps := 48 ;
s := 1 ;
when WLAN_QPSK =>
n_bpsc := 2 ;
n_cbps := 96 ;
s := 1 ;
when WLAN_16QAM =>
n_bpsc := 4 ;
n_cbps := 192 ;
s := 2 ;
when WLAN_64QAM =>
n_bpsc := 6 ;
n_cbps := 288 ;
s := 3 ;
when others =>
end case ;
for k in 0 to n_cbps-1 loop
i := (n_cbps/16)*(k mod 16) + k/16 ;
j := s*integer(floor(real(i)/real(s))) + ((i + n_cbps - (16*i)/n_cbps) mod s) ;
rv(k) := j ;
end loop ;
return rv ;
end function ;
-- Deferred initialization of table
constant WLAN_INTERLEAVER_BPSK : integer_array_t := calculate_interleaver_table( WLAN_BPSK ) ;
constant WLAN_INTERLEAVER_QPSK : integer_array_t := calculate_interleaver_table( WLAN_QPSK ) ;
constant WLAN_INTERLEAVER_16QAM : integer_array_t := calculate_interleaver_table( WLAN_16QAM ) ;
constant WLAN_INTERLEAVER_64QAM : integer_array_t := calculate_interleaver_table( WLAN_64QAM ) ;
end package body ;

79
fpga/vhdl/wlan_lfsr.vhd Normal file
View File

@ -0,0 +1,79 @@
-- 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 ;
entity wlan_lfsr is
generic (
WIDTH : positive := 8
) ;
port (
clock : in std_logic ;
reset : in std_logic ;
init : in unsigned(6 downto 0) ;
init_valid : in std_logic ;
advance : in std_logic ;
data : out std_logic_vector(WIDTH-1 downto 0) ;
data_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_lfsr is
signal state : unsigned(6 downto 0) := (others =>'0') ;
begin
lfsr : process(clock, reset)
variable tempstate : unsigned(6 downto 0) := (others =>'0') ;
begin
if( reset = '1' ) then
state <= (others =>'0') ;
data <= (others =>'0') ;
data_valid <= '0' ;
tempstate := (others =>'0') ;
elsif( rising_edge(clock) ) then
data_valid <= '0' ;
if( init_valid = '1' ) then
tempstate := init ;
-- Initialize output to the first word, like a look-ahead FIFO
for i in 0 to data'high loop
tempstate := tempstate(5 downto 0) & (tempstate(6) xor tempstate(3)) ;
data(i) <= tempstate(0) ;
end loop ;
state <= tempstate ;
else
data_valid <= advance ;
if( advance = '1' ) then
tempstate := state ;
for i in 0 to data'high loop
tempstate := tempstate(5 downto 0) & (tempstate(6) xor tempstate(3)) ;
data(i) <= tempstate(0) ;
end loop ;
state <= tempstate ;
end if ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,343 @@
-- 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 ;
use ieee.math_real.all ;
use ieee.math_complex.all ;
library work ;
use work.wlan_p.all ;
entity wlan_modulator is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
data : in std_logic_vector(287 downto 0) ;
modulation : in wlan_modulation_t ;
in_valid : in std_logic ;
ifft_ready : in std_logic ;
symbol_start : out std_logic ;
symbol_end : out std_logic ;
symbol_sample : out wlan_sample_t
) ;
end entity ;
architecture arch of wlan_modulator is
function to_sample( x : complex ) return wlan_sample_t is
variable rv : wlan_sample_t ;
begin
rv.i := to_signed(integer(round(4096.0*x.re)), rv.i'length) ;
rv.q := to_signed(integer(round(4096.0*x.im)), rv.q'length) ;
rv.valid := '1' ;
return rv ;
end function ;
-- Table 18-8
function make_bpsk_table return sample_array_t is
variable rv : sample_array_t(1 downto 0) ;
begin
rv(0) := to_sample( (-1.0, 0.0) ) ;
rv(1) := to_sample( ( 1.0, 0.0) ) ;
return rv ;
end function ;
-- Table 18-9
function make_qpsk_table return sample_array_t is
constant SCALE : real := 1.0/sqrt(2.0) ;
variable rv : sample_array_t(3 downto 0) ;
begin
rv(0) := to_sample( (SCALE*(-1.0), SCALE*(-1.0)) ) ;
rv(1) := to_sample( (SCALE*( 1.0), SCALE*(-1.0)) ) ;
rv(2) := to_sample( (SCALE*(-1.0), SCALE*( 1.0)) ) ;
rv(3) := to_sample( (SCALE*( 1.0), SCALE*( 1.0)) ) ;
return rv ;
end function ;
-- Table 18-10
function make_16qam_table return sample_array_t is
constant SCALE : real := 1.0/sqrt(10.0) ;
variable bits : unsigned(3 downto 0) ;
variable sample : complex ;
variable rv : sample_array_t(15 downto 0) ;
begin
for i in rv'range loop
bits := to_unsigned(i,bits'length) ;
-- I bits
case bits(1 downto 0) is
when "00" => sample.re := SCALE*(-3.0) ;
when "01" => sample.re := SCALE*( 3.0) ;
when "10" => sample.re := SCALE*(-1.0) ;
when "11" => sample.re := SCALE*( 1.0) ;
when others => report "Weird" severity failure ;
end case ;
-- Q bits
case bits(3 downto 2) is
when "00" => sample.im := SCALE*(-3.0) ;
when "01" => sample.im := SCALE*( 3.0) ;
when "10" => sample.im := SCALE*(-1.0) ;
when "11" => sample.im := SCALE*( 1.0) ;
when others => report "Ack" severity failure ;
end case ;
rv(i) := to_sample( sample ) ;
end loop ;
return rv ;
end function ;
-- Table 18-11
function make_64qam_table return sample_array_t is
constant SCALE : real := 1.0/sqrt(42.0) ;
variable bits : unsigned(5 downto 0) ;
variable sample : complex ;
variable rv : sample_array_t(63 downto 0) ;
begin
for i in rv'range loop
bits := to_unsigned(i, bits'length) ;
-- I bits
case bits(2 downto 0) is
when "000" => sample.re := SCALE*(-7.0) ;
when "001" => sample.re := SCALE*( 7.0) ;
when "010" => sample.re := SCALE*(-1.0) ;
when "011" => sample.re := SCALE*( 1.0) ;
when "100" => sample.re := SCALE*(-5.0) ;
when "101" => sample.re := SCALE*( 5.0) ;
when "110" => sample.re := SCALE*(-3.0) ;
when "111" => sample.re := SCALE*( 3.0) ;
when others => report "Ugh!" severity failure ;
end case ;
-- Q bits
case bits(5 downto 3) is
when "000" => sample.im := SCALE*(-7.0) ;
when "001" => sample.im := SCALE*( 7.0) ;
when "010" => sample.im := SCALE*(-1.0) ;
when "011" => sample.im := SCALE*( 1.0) ;
when "100" => sample.im := SCALE*(-5.0) ;
when "101" => sample.im := SCALE*( 5.0) ;
when "110" => sample.im := SCALE*(-3.0) ;
when "111" => sample.im := SCALE*( 3.0) ;
when others => report "Blah" severity failure ;
end case ;
rv(i) := to_sample( sample ) ;
end loop ;
return rv ;
end function ;
-- Modulation tables
constant MOD_BPSK : sample_array_t := make_bpsk_table ;
constant MOD_QPSK : sample_array_t := make_qpsk_table ;
constant MOD_16QAM : sample_array_t := make_16qam_table ;
constant MOD_64QAM : sample_array_t := make_64qam_table ;
type fsm_t is (IDLE, WAIT_IFFT_READY, MODULATING) ;
type state_t is record
fsm : fsm_t ;
data : unsigned(287 downto 0) ;
byt : natural range 0 to 630 ;
index : natural range 0 to 63 ;
modulation : wlan_modulation_t ;
symbol : wlan_sample_t ;
symbol_start : std_logic ;
symbol_end : std_logic ;
pilot_polarity : std_logic ;
lfsr_advance : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.data := (others =>'0') ;
rv.byt := 0 ;
rv.index := 0 ;
rv.modulation := WLAN_BPSK ;
rv.symbol := NULL_SAMPLE ;
rv.symbol_start := '0' ;
rv.symbol_end := '0' ;
rv.pilot_polarity := '1' ;
rv.lfsr_advance := '0' ;
return rv ;
end function ;
function reorder_data( x : std_logic_vector(287 downto 0) ; modulation : wlan_modulation_t ) return unsigned is
variable rv : std_logic_vector(287 downto 0) ;
begin
-- Swap locations of positive and negative frequencies in the vector
case modulation is
when WLAN_BPSK =>
rv(24*1-1 downto 0) := x(48*1-1 downto 24*1) ;
rv(48*1-1 downto 24*1) := x(24*1-1 downto 0) ;
when WLAN_QPSK =>
rv(24*2-1 downto 0) := x(48*2-1 downto 24*2) ;
rv(48*2-1 downto 24*2) := x(24*2-1 downto 0) ;
when WLAN_16QAM =>
rv(24*4-1 downto 0) := x(48*4-1 downto 24*4) ;
rv(48*4-1 downto 24*4) := x(24*4-1 downto 0) ;
when WLAN_64QAM =>
rv(24*6-1 downto 0) := x(48*6-1 downto 24*6) ;
rv(48*6-1 downto 24*6) := x(24*6-1 downto 0) ;
when others =>
end case ;
return unsigned(rv) ;
end function ;
signal lfsr_advance : std_logic ;
signal lfsr_data : std_logic_vector(0 downto 0) ;
signal current, future : state_t := NULL_STATE ;
begin
symbol_start <= current.symbol_start ;
symbol_end <= current.symbol_end ;
symbol_sample <= current.symbol ;
lfsr_advance <= current.lfsr_advance ;
U_lfsr : entity work.wlan_lfsr
generic map (
WIDTH => lfsr_data'length
) port map (
clock => clock,
reset => reset,
init => (others =>'1'),
init_valid => init,
advance => lfsr_advance,
data => lfsr_data,
data_valid => open
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.lfsr_advance <= '0' ;
future.symbol.valid <= '0' ;
future.symbol_start <= '0' ;
future.symbol_end <= '0' ;
future.pilot_polarity <= lfsr_data(0) ;
case current.fsm is
when IDLE =>
future.symbol <= NULL_SAMPLE ;
future.symbol_start <= '0' ;
future.symbol_end <= '0' ;
if( init = '1' ) then
-- Reset the pilot polarity LFSR here
end if ;
if( in_valid = '1' ) then
future.modulation <= modulation ;
future.data <= reorder_data(data, modulation) ;
if( ifft_ready = '1' ) then
future.fsm <= MODULATING ;
else
future.fsm <= WAIT_IFFT_READY ;
end if;
end if ;
when WAIT_IFFT_READY =>
if( ifft_ready = '1' ) then
future.fsm <= MODULATING ;
end if;
when MODULATING =>
future.symbol_start <= '0' ;
future.symbol_end <= '0' ;
case current.index is
-- Check for DC null
when 0 =>
future.symbol <= NULL_SAMPLE ;
future.symbol.valid <= '1' ;
future.symbol_start <= '1' ;
-- Check for outside nulls
when 27 to 37 =>
future.symbol <= NULL_SAMPLE ;
future.symbol.valid <= '1' ;
-- Check for 3 positive pilots
when 7|43|57 =>
if( current.pilot_polarity = '1' ) then
future.symbol <= MOD_BPSK(0) ;
else
future.symbol <= MOD_BPSK(1) ;
end if ;
-- Check for 1 negative pilot
when 21 =>
if( current.pilot_polarity = '1' ) then
future.symbol <= MOD_BPSK(1) ;
else
future.symbol <= MOD_BPSK(0) ;
end if ;
-- Otherwise data
when others =>
case current.modulation is
when WLAN_BPSK =>
future.symbol <= MOD_BPSK(to_integer(current.data(0 downto 0))) ;
future.data <= shift_right(current.data,1) ;
when WLAN_QPSK =>
future.symbol <= MOD_QPSK(to_integer(current.data(1 downto 0))) ;
future.data <= shift_right(current.data,2) ;
when WLAN_16QAM =>
future.symbol <= MOD_16QAM(to_integer(current.data(3 downto 0))) ;
future.data <= shift_right(current.data,4) ;
when WLAN_64QAM =>
future.symbol <= MOD_64QAM(to_integer(current.data(5 downto 0))) ;
future.data <= shift_right(current.data,6) ;
when others =>
end case ;
end case ;
-- Check if we've reached a full symbol length
if( current.index < 63 ) then
future.index <= current.index + 1 ;
else
future.lfsr_advance <= '1' ;
future.symbol_end <= '1' ;
future.byt <= current.byt + 1;
future.index <= 0 ;
future.fsm <= IDLE ;
end if ;
end case ;
end process ;
end architecture ;

275
fpga/vhdl/wlan_p.vhd Normal file
View File

@ -0,0 +1,275 @@
-- 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 ;
use ieee.math_real.all ;
use ieee.math_complex.all ;
package wlan_p is
-- Convenience types
type wlan_sample_t is record
i : signed(15 downto 0) ;
q : signed(15 downto 0) ;
valid : std_logic ;
end record ;
type wlan_equalizer_sample_t is record
i : signed(22 downto 0) ;
q : signed(22 downto 0) ;
valid : std_logic ;
end record ;
type integer_array_t is array(natural range <>) of integer ;
type real_array_t is array(natural range <>) of real ;
type complex_array_t is array(natural range <>) of complex ;
type sample_array_t is array(natural range <>) of wlan_sample_t ;
type bsd_array_t is array(natural range <>) of signed(7 downto 0) ;
-- Bit soft decisions
type wlan_bsds_t is record
bsds : bsd_array_t(5 downto 0) ;
valid : std_logic ;
end record ;
-- Datarate selection
type wlan_datarate_t is (
WLAN_RATE_1, WLAN_RATE_2, WLAN_RATE_5_5, WLAN_RATE_11,
WLAN_RATE_6, WLAN_RATE_9, WLAN_RATE_12, WLAN_RATE_18,
WLAN_RATE_24, WLAN_RATE_36, WLAN_RATE_48, WLAN_RATE_54
) ;
type wlan_modulation_t is (
WLAN_DBPSK, WLAN_DQPSK, WLAN_BPSK, WLAN_QPSK, WLAN_16QAM, WLAN_64QAM
) ;
-- Bandwidth selection
type wlan_bandwidth_t is (
WLAN_BW_5, WLAN_BW_10, WLAN_BW_20
) ;
procedure nop( signal clock : in std_logic ; count : natural ) ;
function NULL_SAMPLE return wlan_sample_t ;
function NULL_EQ_SAMPLE return wlan_equalizer_sample_t ;
-- FFT has bin 0 as DC
constant SHORT_SEQ_FREQ : complex_array_t(0 to 63) := (
4 => (-1.472, -1.472),
8 => (-1.472, -1.472),
12 => ( 1.472, 1.472),
16 => ( 1.472, 1.472),
20 => ( 1.472, 1.472),
24 => ( 1.472, 1.472),
40 => ( 1.472, 1.472),
44 => (-1.472, -1.472),
48 => ( 1.472, 1.472),
52 => (-1.472, -1.472),
56 => (-1.472, -1.472),
60 => ( 1.472, 1.472),
others => ( 0.000, 0.000)
) ;
-- Short sequence in time truncated to the repetition point at 16 samples
constant SHORT_SEQ_TIME : complex_array_t := (
( 0.04600, 0.04600),
(-0.13245, 0.00234),
(-0.01347, -0.07853),
( 0.14276, -0.01265),
( 0.09200, 0.00000),
( 0.14276, -0.01265),
(-0.01347, -0.07853),
(-0.13245, 0.00234),
( 0.04600, 0.04600),
( 0.00234, -0.13245),
(-0.07853, -0.01347),
(-0.01265, 0.14276),
( 0.00000, 0.09200),
(-0.01265, 0.14276),
(-0.07853, -0.01347),
( 0.00234, -0.13245)
) ;
constant LONG_SEQ_FREQ : complex_array_t := (
( 0.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 0.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
(-1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0),
( 1.0, 0.0)
) ;
constant LONG_SEQ_TIME : complex_array_t := (
( 0.15625, 0.00000),
(-0.00512, -0.12033),
( 0.03975, -0.11116),
( 0.09683, 0.08280),
( 0.02111, 0.02789),
( 0.05982, -0.08771),
(-0.11513, -0.05518),
(-0.03832, -0.10617),
( 0.09754, -0.02589),
( 0.05334, 0.00408),
( 0.00099, -0.11500),
(-0.13680, -0.04738),
( 0.02448, -0.05853),
( 0.05867, -0.01494),
(-0.02248, 0.16066),
( 0.11924, -0.00410),
( 0.06250, -0.06250),
( 0.03692, 0.09834),
(-0.05721, 0.03930),
(-0.13126, 0.06523),
( 0.08222, 0.09236),
( 0.06956, 0.01412),
(-0.06031, 0.08129),
(-0.05646, -0.02180),
(-0.03504, -0.15089),
(-0.12189, -0.01657),
(-0.12732, -0.02050),
( 0.07507, -0.07404),
(-0.00281, 0.05377),
(-0.09189, 0.11513),
( 0.09172, 0.10587),
( 0.01228, 0.09760),
(-0.15625, 0.00000),
( 0.01228, -0.09760),
( 0.09172, -0.10587),
(-0.09189, -0.11513),
(-0.00281, -0.05377),
( 0.07507, 0.07404),
(-0.12732, 0.02050),
(-0.12189, 0.01657),
(-0.03504, 0.15089),
(-0.05646, 0.02180),
(-0.06031, -0.08129),
( 0.06956, -0.01412),
( 0.08222, -0.09236),
(-0.13126, -0.06523),
(-0.05721, -0.03930),
( 0.03692, -0.09834),
( 0.06250, 0.06250),
( 0.11924, 0.00410),
(-0.02248, -0.16066),
( 0.05867, 0.01494),
( 0.02448, 0.05853),
(-0.13680, 0.04738),
( 0.00099, 0.11500),
( 0.05334, -0.00408),
( 0.09754, 0.02589),
(-0.03832, 0.10617),
(-0.11513, 0.05518),
( 0.05982, 0.08771),
( 0.02111, -0.02789),
( 0.09683, -0.08280),
( 0.03975, 0.11116),
(-0.00512, 0.12033)
) ;
end package ;
package body wlan_p is
procedure nop( signal clock : in std_logic ; count : natural ) is
begin
for i in 1 to count loop
wait until rising_edge(clock) ;
end loop ;
end procedure ;
function NULL_SAMPLE return wlan_sample_t is
begin
return (
i => (others =>'0'),
q => (others =>'0'),
valid => '0'
) ;
end function ;
function NULL_EQ_SAMPLE return wlan_equalizer_sample_t is
begin
return (
i => (others =>'0'),
q => (others =>'0'),
valid => '0'
) ;
end function ;
end package body ;

144
fpga/vhdl/wlan_p_norm.vhd Normal file
View File

@ -0,0 +1,144 @@
-- 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 ;
use ieee.math_real.all ;
library wlan ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
entity wlan_p_norm is
port (
-- 40MHz clock and async asserted, sync deasserted reset
clock : in std_logic ;
reset : in std_logic ;
quiet : in std_logic ;
sample : in wlan_sample_t ;
p_normed : out wlan_sample_t ;
p_mag : out signed( 23 downto 0 )
) ;
end entity ;
architecture arch of wlan_p_norm is
signal iir : signed( 31 downto 0 ) ;
signal saved_iir: signed( 31 downto 0 ) ;
signal dat : signed( 31 downto 0 ) ;
signal log2 : unsigned ( 8 downto 0 ) ;
signal ptemp : signed( 31 downto 0 ) ;
signal timer : unsigned( 8 downto 0 ) ;
type unsigned_array_t is array (natural range 0 to 511) of signed( 23 downto 0 ) ;
function calc_lut return unsigned_array_t is
variable rv : unsigned_array_t ;
variable i : real ;
variable two : real ;
begin
for x in rv'range loop
i := ( 24.0 - (real(x) / 16.0) ) / 2.0 + 12.0; -- i is in log2
report integer'image(x) & " LUT " & real'image(i);
-- if (i > 5.0) then
-- i := 5.0;
-- end if;
two := 2 ** i ;
if (real(two) > 5.7e5) then
two := 5.7e5;
end if;
report integer'image(x) & " pow " & real'image(two);
rv(x) := to_signed(integer(round(two)), 24) ;
end loop ;
return rv ;
end;
constant mult_lut : unsigned_array_t := calc_lut;
function log2x( x : signed( 31 downto 0) )
return unsigned is
variable bits : unsigned( 8 downto 0 ) ;
begin
bits := (others => '0') ;
for i in x'range loop
if (x(i) = '1') then
bits(8 downto 4) := to_unsigned(i, 5) ;
if (real(i) < 4.0) then
bits(3 downto 4 - i) := unsigned(x(i - 1 downto 0)) ;
else
bits(3 downto 0) := unsigned(x(i - 1 downto i - 4)) ;
end if;
-- bits(3 downto 0) <=
exit ;
end if ;
end loop ;
return bits ;
end log2x ;
function run_iir( x : signed( 31 downto 0); y : signed ( 31 downto 0) )
return signed
is
variable amrea : signed(31 downto 0) ;
begin
amrea := resize( x - shift_right(x, 6) + shift_right(y, 6), 32 );
return amrea;
end;
begin
process( clock )
variable t : signed( 31 downto 0 ) ;
begin
if( reset = '1' ) then
iir <= ( others => '0' ) ;
saved_iir <= ( others => '0' ) ;
ptemp <= ( others => '0' ) ;
timer <= ( others => '0' ) ;
p_mag <= ( others => '0' ) ;
elsif( rising_edge( clock )) then
if( quiet = '1' ) then
ptemp <= ( others => '0' ) ;
timer <= ( others => '0' ) ;
else
if( timer < 200 ) then
timer <= timer + 1 ;
end if ;
if( timer = 18 ) then
iir <= ptemp;
end if ;
if( timer = 30 ) then
saved_iir <= iir ;
end if ;
end if ;
if (sample.valid = '1') then
ptemp <= sample.i * sample.i + sample.q * sample.q ;
iir <= run_iir(iir, ptemp) ;
p_normed.i <= resize(shift_right(sample.i * mult_lut(to_integer(log2x(saved_iir))) ,12),16);
p_normed.q <= resize(shift_right(sample.q * mult_lut(to_integer(log2x(saved_iir))) ,12),16);
p_mag <= signed(resize(mult_lut(to_integer(log2x(saved_iir))), 24));
--p_normed.q <= sample.q * mult_lut(log2x(t));
--dat <= log2x(t) * ;
log2 <= log2x(iir) ;
end if ;
if (timer < 30 ) then
p_normed.valid <= '0' ;
else
p_normed.valid <= sample.valid ;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,76 @@
-- 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_peak_finder is
generic (
SAMPLE_WINDOW : integer := 31
) ;
port (
clock : in std_logic ;
reset : in std_logic ;
sample : in unsigned(127 downto 0 ) ;
sample_valid : in std_logic;
peak : out std_logic
) ;
end entity ;
architecture arch of wlan_peak_finder is
type peak_array_t is array(0 to SAMPLE_WINDOW-1) of unsigned(sample'range) ;
signal samples : peak_array_t ;
begin
process( clock )
variable highest : std_logic;
begin
if( rising_edge( clock ) ) then
if( sample_valid = '1' ) then
for i in 0 to samples'high - 1 loop
samples(i+1) <= samples(i) ;
end loop ;
samples(0) <= sample ;
highest := '1';
for i in samples'range loop
if (i /= 15 and samples(i) > samples(15)) then
highest := '0';
end if;
end loop;
if (samples(15) < 300000000) then
highest := '0';
end if;
peak <= highest;
end if ;
end if ;
end process ;
end architecture ;

View File

@ -0,0 +1,343 @@
-- 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 ;
use ieee.math_real.all ;
use ieee.math_complex.all ;
library wlan ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
use wlan.cordic_p.all ;
library altera_mf ;
use altera_mf.altera_mf_components.all ;
entity wlan_phase_correction is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
in_sample : in wlan_sample_t ;
in_done : in std_logic ;
out_sample : out wlan_sample_t ;
out_done : out std_logic
) ;
end entity ;
architecture arch of wlan_phase_correction is
type fsm_writer_t is (IDLE, WRITE_SAMPLES) ;
type fsm_calculate_t is (IDLE, CAPTURE_CORDIC, CAPTURE_CORRECTION) ;
type fsm_reader_t is (IDLE, READ_SAMPLES) ;
type state_t is record
wfsm : fsm_writer_t ;
cfsm : fsm_calculate_t ;
rfsm : fsm_reader_t ;
windex : natural range 0 to 70 ;
rindex : natural range 0 to 70 ;
pilot_polarity : std_logic ;
lfsr_advance : std_logic ;
atan_sample : wlan_sample_t ;
atan_count : natural range 0 to 5 ;
atan_sum : signed( 31 downto 0 ) ;
atan_sum_valid : std_logic ;
norm_x_sum : signed( 31 downto 0 ) ;
norm_y_sum : signed( 31 downto 0 ) ;
phasor : wlan_sample_t ;
cordic_valid : std_logic_vector( 15 downto 0 ) ;
fifo_read : std_logic ;
clear_ready : std_logic ;
set_ready : std_logic ;
ready : std_logic ;
out_sample : wlan_sample_t ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.wfsm := IDLE ;
rv.cfsm := IDLE ;
rv.rfsm := IDLE ;
rv.rindex := 0 ;
rv.windex := 0 ;
rv.pilot_polarity := '1' ;
rv.lfsr_advance := '0' ;
rv.atan_count := 0 ;
rv.atan_sum := ( others => '0' ) ;
rv.norm_x_sum := ( others => '0' ) ;
rv.norm_y_sum := ( others => '0' ) ;
rv.cordic_valid := ( others => '0' ) ;
rv.fifo_read := '0' ;
rv.clear_ready := '0' ;
rv.set_ready := '0' ;
rv.ready := '0' ;
rv.out_sample.valid := '0' ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal lfsr_data : std_logic_vector( 0 downto 0 ) ;
signal lfsr_advance : std_logic ;
signal fifo_input : std_logic_vector( 31 downto 0 ) ;
signal fifo_output : std_logic_vector( 31 downto 0 ) ;
signal fifo_usedw : std_logic_vector( 7 downto 0 ) ;
signal fifo_write : std_logic ;
signal fifo_read : std_logic ;
signal fifo_read_r : std_logic ;
signal fifo_full : std_logic ;
signal fifo_empty : std_logic ;
signal cordic_inputs : cordic_xyz_t ;
signal cordic_outputs : cordic_xyz_t ;
signal cordic_normed : cordic_xyz_t ;
signal correction_inputs : cordic_xyz_t ;
signal correction_outputs : cordic_xyz_t ;
signal fifo_sample : wlan_sample_t ;
begin
out_sample <= current.out_sample ;
U_fifo : scfifo
generic map (
lpm_width => fifo_input'length,
lpm_widthu => fifo_usedw'length,
lpm_numwords => 2**(fifo_usedw'length),
lpm_showahead => "ON"
) port map (
clock => clock,
aclr => reset,
sclr => init,
data => std_logic_vector( in_sample.i ) & std_logic_vector( in_sample.q ),
wrreq => in_sample.valid,
rdreq => fifo_read,
q => fifo_output,
full => fifo_full,
empty => fifo_empty,
usedw => fifo_usedw
) ;
fifo_read <= current.fifo_read ;
fifo_sample.valid <= fifo_read ;
fifo_sample.i <= signed(fifo_output( 31 downto 16 )) ;
fifo_sample.q <= signed(fifo_output( 15 downto 0 )) ;
lfsr_advance <= current.lfsr_advance ;
U_lfsr : entity work.wlan_lfsr
generic map (
WIDTH => lfsr_data'length
) port map (
clock => clock,
reset => reset,
init => (others =>'1'),
init_valid => init,
advance => lfsr_advance,
data => lfsr_data,
data_valid => open
) ;
-- take atan2() of delay correlator using CORDIC
cordic_inputs <= ( x => resize(current.atan_sample.i, 16),
y => resize(current.atan_sample.q, 16),
z => (others => '0'),
valid => current.atan_sample.valid ) ;
U_cordic : entity work.cordic
port map (
clock => clock,
reset => reset,
mode => CORDIC_VECTORING,
inputs => cordic_inputs,
outputs => cordic_outputs,
normalized => cordic_normed
) ;
correction_inputs <= ( x => to_signed(1234,16), y => to_signed(0,16), z => resize(shift_right(current.atan_sum, 2), 16), valid => current.atan_sum_valid ) ;
U_correction_cordic : entity work.cordic
port map (
clock => clock,
reset => reset,
mode => CORDIC_ROTATION,
inputs => correction_inputs,
outputs => correction_outputs
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
if( init = '1' ) then
current <= NULL_STATE ;
else
current <= future ;
end if ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.out_sample.valid <= '0' ;
future.atan_sum_valid <= '0' ;
future.lfsr_advance <= '0' ;
future.fifo_read <= '0' ;
future.atan_sample.valid <= '0' ;
future.pilot_polarity <= lfsr_data(0);
future.cordic_valid <= current.atan_sample.valid & current.cordic_valid( 15 downto 1 ) ;
future.set_ready <= '0' ;
future.clear_ready <= '0' ;
if( current.set_ready = '1' ) then
future.ready <= '1' ;
elsif( current.clear_ready = '1' ) then
future.ready <= '0' ;
end if ;
case current.wfsm is
when IDLE =>
future.wfsm <= WRITE_SAMPLES ;
when WRITE_SAMPLES =>
if( in_sample.valid = '1' ) then
case current.windex is
-- Check for DC null
when 0 =>
-- Check for outside nulls
when 27 to 37 =>
-- Check for 3 positive pilots
when 7|43|57 =>
if( current.pilot_polarity = '1' ) then
future.atan_sample.i <= - in_sample.i ;
future.atan_sample.q <= - in_sample.q ;
future.atan_sample.valid <= in_sample.valid ;
else
future.atan_sample <= in_sample;
end if ;
-- Check for 1 negative pilot
when 21 =>
if( current.pilot_polarity = '1' ) then
future.atan_sample <= in_sample;
else
future.atan_sample.i <= - in_sample.i ;
future.atan_sample.q <= - in_sample.q ;
future.atan_sample.valid <= in_sample.valid ;
end if ;
-- Otherwise data
when others =>
end case ;
-- Check if we've reached a full symbol length
if( current.windex < 64 ) then
future.windex <= current.windex + 1 ;
end if ;
end if ;
if( current.windex = 64) then
future.lfsr_advance <= '1' ;
future.windex <= 0 ;
end if ;
end case ;
case current.cfsm is
when IDLE =>
future.cfsm <= CAPTURE_CORDIC ;
future.atan_sum <= ( others => '0' ) ;
future.norm_x_sum <= ( others => '0' ) ;
future.norm_y_sum <= ( others => '0' ) ;
future.atan_count <= 0 ;
when CAPTURE_CORDIC =>
if( cordic_normed.valid = '1' ) then
future.norm_x_sum <= current.norm_x_sum + cordic_normed.x ;
future.norm_y_sum <= current.norm_y_sum - cordic_normed.y ;
future.atan_count <= current.atan_count + 1 ;
if( current.atan_count = 3 ) then
future.cfsm <= CAPTURE_CORRECTION ;
end if ;
end if ;
when CAPTURE_CORRECTION =>
future.phasor.i <= resize(shift_right(current.norm_x_sum, 2), 16) ;
future.phasor.q <= resize(shift_right(current.norm_y_sum, 2), 16) ;
future.set_ready <= '1' ;
future.cfsm <= IDLE ;
end case ;
case current.rfsm is
when IDLE =>
if( current.ready = '1' ) then
future.clear_ready <= '1' ;
future.rindex <= 0 ;
future.rfsm <= READ_SAMPLES ;
end if ;
when READ_SAMPLES =>
if( fifo_empty = '0' ) then
future.rindex <= current.rindex + 1 ;
future.fifo_read <= '1' ;
if (current.rindex = 63 ) then
future.rfsm <= IDLE ;
end if ;
end if ;
end case ;
if( current.fifo_read = '1' ) then
future.out_sample.i <= resize(shift_right( current.phasor.i * fifo_sample.i - current.phasor.q * fifo_sample.q, 11 ), 16 ) ;
future.out_sample.q <= resize(shift_right( current.phasor.i * fifo_sample.q + current.phasor.q * fifo_sample.i, 11 ), 16 ) ;
future.out_sample.valid <= '1' ;
end if ;
end process ;
end architecture ;

816
fpga/vhdl/wlan_rx.vhd Normal file
View File

@ -0,0 +1,816 @@
-- 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.nco_p.all ;
use wlan.wlan_p.all ;
use wlan.wlan_rx_p.all ;
library altera_mf ;
use altera_mf.altera_mf_components.all ;
library wlan_pll ;
entity wlan_rx is
port (
-- 40MHz clock and async asserted, sync deasserted reset
clock40m : in std_logic ;
reset40m : in std_logic ;
-- Baseband input signals
bb_i : in signed(15 downto 0) ;
bb_q : in signed(15 downto 0) ;
bb_valid : in std_logic ;
equalized_i : out signed(15 downto 0) ;
equalized_q : out signed(15 downto 0) ;
equalized_valid : out std_logic ;
-- AGC control signal
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 ;
-- ACK signals
ack_mac : out std_logic_vector( 47 downto 0 ) ;
ack_valid : out std_logic ;
acked_packet : out std_logic ;
rx_quiet : out std_logic ;
rx_block : in std_logic ;
-- RX status signals
rx_end_of_packet: out std_logic ;
rx_status : out wlan_rx_status_t ;
rx_status_valid : out std_logic ;
rx_vector : out wlan_rx_vector_t ;
rx_vector_valid : out std_logic ;
rx_data_req : in std_logic ;
rx_data : out std_logic_vector( 7 downto 0 ) ;
rx_data_valid : out std_logic ;
mse : out unsigned(15 downto 0) ;
mse_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_rx is
signal rx_vector_rr : std_logic_vector( 3 downto 0 ) ;
signal rx_vector_r : std_logic_vector( 3 downto 0 ) ;
signal rx_end_of_packet_r : std_logic_vector( 3 downto 0 ) ;
signal params : wlan_rx_params_t ;
signal params_valid : std_logic ;
signal bb_sample : wlan_sample_t ;
signal bb_sample40 : wlan_sample_t ;
signal sample : wlan_sample_t ;
signal fft_sample : wlan_sample_t ;
signal dfe_sample : wlan_sample_t ;
signal eq_sample : wlan_sample_t ;
signal phase_corr_sample : wlan_sample_t ;
signal cfo_atan_average : signed( 31 downto 0 ) ;
signal cfo_est_sample : wlan_sample_t ;
signal p_mag : signed( 23 downto 0 ) ;
signal acquired_packet : std_logic ;
signal end_of_packet : std_logic ;
signal acquired_sample : wlan_sample_t ;
signal correction_dphase : signed( 15 downto 0 ) ;
signal correction_dphase_valid : std_logic ;
signal correction_p_mag : signed( 23 downto 0 ) ;
signal correction_p_mag_valid : std_logic ;
signal symbol_start : std_logic ;
signal fft_done : std_logic ;
signal eq_done : std_logic ;
signal phase_corr_done : std_logic ;
signal demod_modulation : wlan_modulation_t ;
signal demod_data : std_logic_vector( 287 downto 0 ) ;
signal demod_bsds : bsd_array_t(287 downto 0) ;
signal demod_valid : std_logic ;
signal deinter_modulation : wlan_modulation_t ;
signal deinter_data : std_logic_vector( 287 downto 0 ) ;
signal deinter_bsds : bsd_array_t(287 downto 0) ;
signal deinter_valid : std_logic ;
signal depunct_done : std_logic ;
signal depunct_empty : std_logic ;
signal depunct_soft_a : signed( 7 downto 0 ) ;
signal depunct_soft_b : signed( 7 downto 0 ) ;
signal depunct_erasure : std_logic_vector( 1 downto 0 ) ;
signal depunct_valid : std_logic ;
signal num_decoded_bits : unsigned( 13 downto 0 ) ;
signal num_decoded_bits_valid : std_logic ;
signal decoder_done : std_logic ;
signal rx_packet_init : std_logic ;
signal decoded_bit : std_logic;
signal decoded_valid : std_logic;
signal descrambled_data : std_logic_vector( 7 downto 0 ) ;
signal descrambled_valid : std_logic ;
signal descrambler_bypass : std_logic ;
signal signal_dec : std_logic ;
signal rx_framer_done : std_logic ;
-- Block Diagram of the modem
-- acquisition -> cfo est/removal -> equalizer -> demod -> depuncture -> fec -> framer
-- ^-----------------------------------------'
--
-- The equalizer can't move onward until there is the feedback from
-- the framer to understand the SIGNAL field, so FFT frames are buffered
-- until the actual payload size and length is known and at least seems
-- plausible.
signal clock : std_logic ;
signal bb_valid_80m : std_logic ;
signal bb_valid_r : std_logic ;
signal rst_gains : std_logic ;
signal burst : std_logic ;
signal framer_quiet_reset : std_logic ;
signal rx_data_rdempty : std_logic ;
signal crc_correct : std_logic ;
signal ack_valid_r : std_logic ;
signal ack_valid_rr80 : std_logic_vector( 3 downto 0 ) ;
signal ack_valid_rr : std_logic_vector( 3 downto 0 ) ;
signal acked_packet_r : std_logic ;
signal acked_packet_rr80 : std_logic_vector( 3 downto 0 ) ;
signal acked_packet_rr : std_logic_vector( 3 downto 0 ) ;
signal buf_params : wlan_rx_params_t ;
signal buf_params_valid : std_logic ;
signal buf_data : std_logic_vector( 7 downto 0 ) ;
signal buf_data_valid : std_logic ;
signal buf_end_of_packet : std_logic ;
signal dsss_params : wlan_rx_params_t ;
signal dsss_params_valid : std_logic ;
signal dsss_data : std_logic_vector( 7 downto 0 ) ;
signal dsss_data_valid : std_logic ;
signal dsss_framer_done : std_logic ;
signal dsss_crc_correct : std_logic ;
signal dsss_params_80m : wlan_rx_params_t ;
signal dsss_params_valid_80m : std_logic ;
signal dsss_data_80m : std_logic_vector( 7 downto 0 ) ;
signal dsss_data_valid_80m : std_logic ;
signal dsss_framer_done_80m : std_logic ;
signal dsss_crc_correct_80m : std_logic ;
component wlan_pll
port (
refclk : in std_logic;
rst : in std_logic;
outclk_0 : out std_logic;
locked : out std_logic
);
end component;
signal r_bb_i : signed(15 downto 0) ;
signal r_bb_q : signed(15 downto 0) ;
signal r_bb_valid : std_logic ;
signal wfull : std_logic ;
signal rempty : std_logic ;
signal fvalid : std_logic ;
signal fdata : std_logic_vector(31 downto 0) ;
signal f_bb_i : signed(15 downto 0) ;
signal f_bb_q : signed(15 downto 0) ;
signal rst_rr : std_logic_vector(2 downto 0);
signal reset : std_logic ;
begin
rx_quiet <= not burst ;
equalized_i <= phase_corr_sample.i( 15 downto 0 ) ;
equalized_q <= phase_corr_sample.q( 15 downto 0 ) ;
equalized_valid <= phase_corr_sample.valid;
process(all)
begin
if( rising_edge( clock ) ) then
rst_rr <= reset40m & rst_rr(rst_rr'high downto 1);
end if;
end process;
reset <= rst_rr(0);
U_rx_data_dc_fifo: dcfifo
generic map (
lpm_width => 32,
lpm_widthu => 5,
lpm_numwords => 32,
lpm_showahead => "ON"
)
port map (
aclr => reset,
wrclk => clock40m,
wrreq => bb_valid and not wfull,
data => std_logic_vector(bb_i) & std_logic_vector(bb_q),
wrfull => wfull,
wrempty => open,
wrusedw => open,
rdclk => clock,
rdreq => fvalid,
q => fdata,
rdfull => open,
rdempty => rempty,
rdusedw => open
) ;
fvalid <= not rempty;
f_bb_i <= signed(fdata(31 downto 16));
f_bb_q <= signed(fdata(15 downto 0));
process(clock40m, reset)
begin
if( reset = '1' ) then
r_bb_i <= ( others => '0' ) ;
r_bb_q <= ( others => '0' ) ;
r_bb_valid <= '0';
elsif( rising_edge( clock40m ) ) then
r_bb_i <= bb_i ;
r_bb_q <= bb_q ;
r_bb_valid <= bb_valid ;
end if;
end process;
process(clock, reset)
begin
if( reset = '1' ) then
bb_valid_r <= '0' ;
bb_valid_80m <= '0' ;
elsif( rising_edge( clock ) ) then
bb_valid_r <= r_bb_valid ;
if( r_bb_valid = '1' and bb_valid_r = '0' ) then
bb_valid_80m <= '1' ;
else
bb_valid_80m <= '0' ;
end if ;
end if ;
end process ;
U_80mhz_clock: component wlan_pll
port map (
refclk => clock40m,
rst => '0',
outclk_0 => clock,
locked => open
);
-- Input sample assignment
bb_sample.i <= f_bb_i;
bb_sample.q <= f_bb_q;
bb_sample.valid <= fvalid;
bb_sample40.i <= r_bb_i;
bb_sample40.q <= r_bb_q;
bb_sample40.valid <= r_bb_valid;
U_agc : entity work.wlan_agc
port map (
clock => clock40m,
reset => reset40m,
agc_hold_req => '0',
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_max => gain_max,
rst_gains => rst_gains,
burst => burst,
sample_i => bb_i,
sample_q => bb_q,
sample_valid => bb_valid
) ;
U_csma : entity wlan.wlan_csma
port map (
clock => clock,
reset => reset,
in_sample => acquired_sample,
quiet => open
) ;
U_dsss : entity wlan.wlan_dsss_rx
port map (
clock => clock40m,
reset => reset40m,
sample => bb_sample40,
params => dsss_params,
params_valid => dsss_params_valid,
data => dsss_data,
data_valid => dsss_data_valid,
framer_done => dsss_framer_done,
crc_correct => dsss_crc_correct
) ;
U_dsss_sync_params : entity wlan.clock_sync_params
port map (
from_signal => dsss_params,
to_clock => clock,
to_reset => reset,
to_signal => dsss_params_80m
) ;
U_dsss_sync_params_valid : entity wlan.clock_sync_logic
port map (
from_signal => dsss_params_valid,
to_clock => clock,
to_reset => reset,
to_signal => dsss_params_valid_80m
) ;
U_dsss_sync_data : entity wlan.clock_sync_logic_vector
port map (
from_signal => dsss_data,
to_clock => clock,
to_reset => reset,
to_signal => dsss_data_80m
) ;
U_dsss_sync_data_valid : entity wlan.clock_sync_logic
port map (
from_signal => dsss_data_valid,
to_clock => clock,
to_reset => reset,
to_signal => dsss_data_valid_80m
) ;
U_dsss_sync_framer_done : entity wlan.clock_sync_logic
port map (
from_signal => dsss_framer_done,
to_clock => clock,
to_reset => reset,
to_signal => dsss_framer_done_80m
) ;
U_dsss_sync_crc_correct : entity wlan.clock_sync_logic
port map (
from_signal => dsss_crc_correct,
to_clock => clock,
to_reset => reset,
to_signal => dsss_crc_correct_80m
) ;
U_acquisition : entity wlan.wlan_acquisition
port map (
clock => clock40m,
reset => reset40m,
acquired => acquired_packet,
p_mag => p_mag,
in_sample => bb_sample40,
quiet => not burst or gain_lock,
burst => burst,
out_sample => acquired_sample
);
U_cfo : entity wlan.wlan_cfo_estimate
port map (
clock => clock40m,
reset => reset40m,
in_sample => acquired_sample,
out_sample => cfo_est_sample,
atan_average => cfo_atan_average
) ;
U_cfo_correction : entity wlan.wlan_cfo_correction
port map (
clock => clock,
reset => reset,
dphase => correction_dphase,
dphase_valid => '0',
p_mag => correction_p_mag,
p_mag_valid => correction_p_mag_valid,
in_sample => bb_sample,
out_sample => sample
) ;
U_rx_controller : entity wlan.wlan_rx_controller
port map (
clock => clock,
reset => reset,
framer_quiet_reset => framer_quiet_reset,
params => params,
params_valid => params_valid,
rx_packet_init => rx_packet_init,
rx_quiet => not burst,
rx_framer_done => rx_framer_done,
sample_valid => sample.valid,
end_of_packet => end_of_packet,
-- acquistion
acquired => acquired_packet and not rx_block,
p_mag => p_mag,
-- CFO estimation
atan_average => resize( cfo_atan_average, 16 ),
-- CFO correction
c_dphase => correction_dphase,
c_dphase_valid => correction_dphase_valid,
c_p_mag => correction_p_mag,
c_p_mag_valid => correction_p_mag_valid,
-- FFT
symbol_start => symbol_start
) ;
U_fft: entity wlan.wlan_fft64
port map (
clock => clock,
reset => reset,
init => rx_packet_init,
signal_dec => signal_dec,
dphase => correction_dphase,
symbol_start => symbol_start,
in_sample => sample,
out_sample => fft_sample,
done => fft_done
) ;
-- Insert buffer here?
-- Equalizer need to know what modulation it's equalizin
U_eq: entity wlan.wlan_equalizer
port map (
clock => clock,
reset => reset,
init => rx_packet_init,
dfe_sample => dfe_sample,
in_sample => fft_sample,
in_done => fft_done,
out_sample => eq_sample,
out_done => eq_done
) ;
U_phase_correct: entity wlan.wlan_phase_correction
port map (
clock => clock,
reset => reset,
init => rx_packet_init,
in_sample => eq_sample,
in_done => eq_done,
out_sample => phase_corr_sample,
out_done => phase_corr_done
) ;
U_demod: entity wlan.wlan_demodulator
port map (
clock => clock,
reset => reset,
init => rx_packet_init,
params => params,
params_valid => params_valid,
in_sample => phase_corr_sample,
in_done => phase_corr_done,
dfe_sample => dfe_sample,
out_mod => demod_modulation,
-- FIXME: Change to output BSDs
out_data => demod_bsds,
out_valid => demod_valid
) ;
U_deinterleaver: entity wlan.wlan_deinterleaver
port map (
clock => clock,
reset => reset,
modulation => demod_modulation,
data => demod_bsds,
in_valid => demod_valid,
depuncturer_empty => depunct_empty,
deinterleaved_mod => deinter_modulation,
deinterleaved => deinter_bsds,
deinterleaved_valid => deinter_valid
) ;
U_depunct : entity wlan.wlan_depuncturer
port map (
clock => clock,
reset => reset,
init => rx_packet_init,
modulation => deinter_modulation,
data => deinter_bsds,
in_valid => deinter_valid,
params => params,
params_valid => params_valid,
end_zero_pad => decoder_done,
empty => depunct_empty,
out_soft_a => depunct_soft_a,
out_soft_b => depunct_soft_b,
out_erasure => depunct_erasure,
out_valid => depunct_valid
) ;
U_decoder : entity wlan.wlan_viterbi_decoder
port map (
clock => clock,
reset => reset,
init => rx_packet_init,
in_soft_a => depunct_soft_a,
in_soft_b => depunct_soft_b,
in_erasure => depunct_erasure,
in_valid => depunct_valid,
params => params,
params_valid => params_valid,
done => decoder_done,
out_dec_bit => decoded_bit,
out_dec_valid => decoded_valid
) ;
U_descrambler : entity wlan.wlan_descrambler
port map (
clock => clock,
reset => reset,
init => rx_packet_init,
params => params,
params_valid => params_valid,
bypass => descrambler_bypass,
in_data => decoded_bit,
in_valid => decoded_valid,
out_data => descrambled_data,
out_valid => descrambled_valid,
out_done => open
) ;
U_rx_sample_fifo: dcfifo
generic map (
lpm_width => 8,
lpm_widthu => 11,
lpm_numwords => 1600,
lpm_showahead => "ON"
)
port map (
aclr => reset,
wrclk => clock,
wrreq => buf_data_valid,
data => buf_data,
wrfull => open,
wrempty => open,
wrusedw => open,
rdclk => clock40m,
rdreq => (not rx_data_rdempty) and rx_data_req,
q => rx_data,
rdfull => open,
rdempty => rx_data_rdempty,
rdusedw => open
) ;
rx_data_valid <= (not rx_data_rdempty) and rx_data_req ;
rx_vector.length <= buf_params.length;
rx_vector.datarate <= buf_params.datarate;
rx_vector.bandwidth <= buf_params.bandwidth;
rx_vector_valid <= rx_vector_rr(0) ;
rx_end_of_packet <= rx_data_rdempty ;
process(all)
begin
if( reset = '1' ) then
rx_vector_r <= ( others => '0' ) ;
rx_end_of_packet_r <= ( others => '0' ) ;
elsif( rising_edge( clock ) ) then
if( buf_params_valid = '1' ) then
rx_vector_r <= ( others => '1' ) ;
else
rx_vector_r <= '0' & rx_vector_r(3 downto 1) ;
end if ;
if( buf_end_of_packet = '1' ) then
rx_end_of_packet_r <= ( others => '1' ) ;
else
rx_end_of_packet_r <= '0' & rx_end_of_packet_r(3 downto 1) ;
end if ;
end if ;
end process ;
process(all)
begin
if( reset = '1' ) then
rx_vector_rr <= ( others => '0' ) ;
acked_packet_rr <= ( others => '0' ) ;
elsif( rising_edge( clock40m ) ) then
rx_vector_rr <= rx_vector_r(0) & rx_vector_rr(3 downto 1) ;
ack_valid_rr <= ack_valid_rr80(0) & ack_valid_rr(3 downto 1) ;
if( ack_valid_rr(1 downto 0) = "10" ) then
ack_valid <= '1' ;
else
ack_valid <= '0' ;
end if ;
acked_packet_rr <= acked_packet_rr80(0) & acked_packet_rr(3 downto 1) ;
if( acked_packet_rr(1 downto 0) = "10" ) then
acked_packet <= '1' ;
else
acked_packet <= '0' ;
end if ;
end if ;
end process ;
process(all)
begin
if( reset = '1' ) then
ack_valid_rr80 <= ( others => '0' ) ;
acked_packet_rr80 <= (others => '0' ) ;
elsif( rising_edge( clock ) ) then
if( ack_valid_r = '1' ) then
ack_valid_rr80 <= ( others => '1' ) ;
else
ack_valid_rr80 <= '0' & ack_valid_rr80( 3 downto 1 ) ;
end if ;
if( acked_packet_r = '1' ) then
acked_packet_rr80 <= ( others => '1' ) ;
else
acked_packet_rr80 <= '0' & acked_packet_rr80( 3 downto 1 ) ;
end if ;
end if ;
end process ;
U_framer : entity wlan.wlan_rx_framer
port map (
clock => clock,
reset => reset,
framer_quiet_reset => framer_quiet_reset,
init => rx_packet_init,
bss_mac => x"70B3D57D8001",
ack_mac => ack_mac,
ack_valid => ack_valid_r,
acked_packet => acked_packet_r,
params => params,
params_valid => params_valid,
in_data => descrambled_data,
in_valid => descrambled_valid,
signal_dec => signal_dec,
descrambler_bypass => descrambler_bypass,
crc_correct => crc_correct,
depunct_done => depunct_done,
decoder_done => decoder_done,
framer_done => rx_framer_done
) ;
U_rx_packet_buffer : entity wlan.wlan_rx_packet_buffer
port map (
clock => clock,
reset => reset,
framer_quiet_reset => framer_quiet_reset,
framer_done => rx_framer_done,
crc_correct => crc_correct,
in_params => params,
in_params_valid => params_valid and signal_dec,
in_data => descrambled_data,
in_data_valid => descrambled_valid and signal_dec,
dsss_params => dsss_params_80m,
dsss_params_valid => dsss_params_valid_80m,
dsss_data => dsss_data_80m,
dsss_data_valid => dsss_data_valid_80m,
dsss_framer_done => dsss_framer_done_80m,
dsss_crc_correct => dsss_crc_correct_80m,
out_params => buf_params,
out_params_valid => buf_params_valid,
out_data => buf_data,
out_data_valid => buf_data_valid,
out_end_of_packet => buf_end_of_packet
) ;
end architecture ;

View File

@ -0,0 +1,228 @@
-- 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_rx_controller is
port (
clock : in std_logic ;
reset : in std_logic ;
framer_quiet_reset: out std_logic ;
params : in wlan_rx_params_t ;
params_valid : in std_logic ;
sample_valid : in std_logic ;
end_of_packet : out std_logic ;
rx_packet_init : out std_logic ;
rx_quiet : in std_logic ;
rx_framer_done : in std_logic ;
acquired : in std_logic ;
p_mag : in signed( 23 downto 0 ) ;
atan_average : in signed( 15 downto 0 ) ;
c_dphase : out signed( 15 downto 0 ) ;
c_dphase_valid : out std_logic ;
c_p_mag : out signed( 23 downto 0 ) ;
c_p_mag_valid : out std_logic ;
symbol_start : out std_logic
) ;
end entity;
architecture arch of wlan_rx_controller is
type fsm_t is (ACQUIRING, INIT_EQ, WAIT_FOR_CFO, DEC_SIGNAL, DEMOD, WAIT_EOP) ;
type state_t is record
fsm : fsm_t ;
pkt_time : unsigned( 23 downto 0 ) ;
sym_time : unsigned( 23 downto 0 ) ;
c_dphase : signed( 15 downto 0 ) ;
c_dphase_valid : std_logic ;
c_p_mag : signed( 23 downto 0 ) ;
c_p_mag_valid : std_logic ;
end_of_packet : std_logic ;
packet_init : std_logic ;
symbol_start : std_logic ;
decoded_bits : natural range 0 to 12000 ;
bit_index : natural range 0 to 12000 ;
n_dbps : natural range 24 to 216 ;
symbol_count : natural range 0 to 1366 ;
symbol_index : natural range 0 to 1366 ;
framer_reset : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := ACQUIRING ;
rv.pkt_time := ( others => '0' );
rv.c_dphase := ( others => '0' ) ;
rv.c_dphase_valid := '0' ;
rv.c_p_mag := ( others => '0' ) ;
rv.c_p_mag_valid := '0' ;
rv.end_of_packet := '0' ;
rv.packet_init := '0' ;
rv.symbol_start := '0' ;
rv.decoded_bits := 0 ;
rv.bit_index := 0 ;
rv.n_dbps := 24 ;
rv.symbol_count := 0 ;
rv.symbol_index := 0 ;
rv.framer_reset := '1' ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
begin
rx_packet_init <= current.packet_init ;
c_dphase <= current.c_dphase ;
c_dphase_valid <= current.c_dphase_valid ;
c_p_mag <= current.c_p_mag ;
c_p_mag_valid <= current.c_p_mag_valid ;
symbol_start <= current.symbol_start ;
end_of_packet <= current.end_of_packet ;
framer_quiet_reset <= current.framer_reset ;
sync : process( clock )
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge( clock ) ) then
current <= future ;
end if ;
end process ;
comb: process(all)
begin
future <= current ;
future.symbol_start <= '0' ;
future.packet_init <= '0' ;
case current.fsm is
when ACQUIRING =>
if( acquired = '1' ) then
-- it takes the acquisition core 201 samples after the actual
-- start of packet until it asserts acquired
future.pkt_time <= to_unsigned( 212+1, future.pkt_time'length ) ;
future.c_p_mag <= p_mag ;
future.c_p_mag_valid <= '1' ;
future.fsm <= INIT_EQ ;
future.symbol_index <= 1 ;
future.symbol_count <= 0 ;
future.packet_init <= '1' ;
future.framer_reset <= '0' ;
else
future <= NULL_STATE ;
end if ;
when INIT_EQ =>
if( rx_quiet = '1' ) then
future.fsm <= ACQUIRING ;
end if ;
if( sample_valid = '1' ) then
future.pkt_time <= current.pkt_time + 1 ;
if( current.pkt_time = 256 ) then
future.symbol_start <= '1' ;
future.fsm <= WAIT_FOR_CFO ;
end if ;
end if ;
when WAIT_FOR_CFO =>
if( rx_quiet = '1' ) then
future.fsm <= ACQUIRING ;
end if ;
if( sample_valid = '1' ) then
future.pkt_time <= current.pkt_time + 1 ;
if( current.pkt_time > 300 ) then
future.c_dphase <= shift_right( - atan_average, 6 ) ;
future.c_dphase_valid <= '1' ;
future.sym_time <= to_unsigned(336, future.sym_time'length);
future.fsm <= DEC_SIGNAL ;
end if ;
end if ;
when DEC_SIGNAL =>
if( rx_quiet = '1' ) then
future.fsm <= ACQUIRING ;
future.end_of_packet <= '1' ;
end if ;
if( params_valid = '1' ) then
if( params.packet_valid = '1' ) then
future.decoded_bits <= params.num_data_symbols ;
future.n_dbps <= params.n_dbps ;
future.bit_index <= params.n_dbps ;
future.fsm <= DEMOD ;
else
future.fsm <= ACQUIRING ;
future.end_of_packet <= '1' ;
end if ;
end if ;
if( sample_valid = '1' ) then
future.pkt_time <= current.pkt_time + 1 ;
if( current.sym_time = current.pkt_time) then
future.sym_time <= current.sym_time + 80;
future.symbol_start <= '1' ;
end if ;
end if ;
when DEMOD =>
if( rx_quiet = '1' ) then
future.fsm <= ACQUIRING ;
future.end_of_packet <= '1' ;
elsif( sample_valid = '1' ) then
future.pkt_time <= current.pkt_time + 1 ;
if( current.pkt_time = current.sym_time ) then
future.sym_time <= current.sym_time + 80;
future.bit_index <= current.bit_index + current.n_dbps ;
future.symbol_start <= '1' ;
end if ;
if (current.bit_index >= current.decoded_bits ) then
future.sym_time <= to_unsigned(5000, future.sym_time'length);
future.fsm <= WAIT_EOP ;
end if ;
end if ;
when WAIT_EOP =>
if( rx_framer_done = '1' or current.sym_time = 0) then
future.fsm <= ACQUIRING ;
future.end_of_packet <= '1' ;
end if ;
future.sym_time <= current.sym_time - 1 ;
when others =>
future.fsm <= ACQUIRING ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,422 @@
-- 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_rx_framer is
port (
clock : in std_logic ;
reset : in std_logic ;
framer_quiet_reset : in std_logic ;
init : in std_logic ;
bss_mac : in std_logic_vector( 47 downto 0 ) ;
ack_mac : out std_logic_vector( 47 downto 0 ) ;
ack_valid : out std_logic ;
acked_packet : out std_logic ;
params : out wlan_rx_params_t ;
params_valid : out std_logic ;
in_data : in std_logic_vector( 7 downto 0 ) ;
in_valid : in std_logic ;
signal_dec : out std_logic ;
descrambler_bypass : out std_logic ;
crc_correct : out std_logic ;
depunct_done : in std_logic ;
decoder_done : in std_logic ;
framer_done : out std_logic
) ;
end entity;
architecture arch of wlan_rx_framer is
function calculate_params( x : wlan_rx_vector_t; service : boolean ) return wlan_rx_params_t is
variable rv : wlan_rx_params_t ;
begin
rv.packet_valid := '0' ;
rv.datarate := x.datarate ;
rv.length := x.length ;
rv.bandwidth := x.bandwidth ;
rv.lfsr_init := "1011101" ;
case x.datarate is
when WLAN_RATE_6 =>
-- BPSK R=1/2
rv.n_bpsc := 1 ;
rv.n_dbps := 24 ;
rv.n_cbps := 48 ;
rv.modulation := WLAN_BPSK ;
when WLAN_RATE_9 =>
-- BPSK R=3/4
rv.n_bpsc := 1 ;
rv.n_dbps := 36 ;
rv.n_cbps := 48 ;
rv.modulation := WLAN_BPSK ;
when WLAN_RATE_12 =>
-- QPSK R=1/2
rv.n_bpsc := 2 ;
rv.n_dbps := 48 ;
rv.n_cbps := 96 ;
rv.modulation := WLAN_QPSK ;
when WLAN_RATE_18 =>
-- QPSK R=3/4
rv.n_bpsc := 2 ;
rv.n_dbps := 72 ;
rv.n_cbps := 96 ;
rv.modulation := WLAN_QPSK ;
when WLAN_RATE_24 =>
-- 16-QAM R=1/2
rv.n_bpsc := 4 ;
rv.n_dbps := 96 ;
rv.n_cbps := 192 ;
rv.modulation := WLAN_16QAM ;
when WLAN_RATE_36 =>
-- 16-QAM R=3/4
rv.n_bpsc := 4 ;
rv.n_dbps := 144 ;
rv.n_cbps := 192 ;
rv.modulation := WLAN_16QAM ;
when WLAN_RATE_48 =>
-- 64-QAM R=2/3
rv.n_bpsc := 6 ;
rv.n_dbps := 192 ;
rv.n_cbps := 288 ;
rv.modulation := WLAN_64QAM ;
when WLAN_RATE_54 =>
-- 64-QAM R=3/4
rv.n_bpsc := 6 ;
rv.n_dbps := 216 ;
rv.n_cbps := 288;
rv.modulation := WLAN_64QAM ;
when others =>
report "Invalid params" severity failure ;
end case ;
case x.bandwidth is
when WLAN_BW_5 =>
null ;
when WLAN_BW_10 =>
null ;
when WLAN_BW_20 =>
null ;
when others =>
report "Invalid bandwidth" severity failure ;
end case ;
rv.num_decoded_bits := rv.length * 8 ;
if (service) then
rv.num_data_symbols := rv.num_decoded_bits;-- (16 + rv.num_decoded_bits + rv.n_dbps - 1) / rv.n_dbps ;
else
rv.num_data_symbols := rv.num_decoded_bits; --+ rv.n_dbps - 1) / rv.n_dbps ;
end if;
return rv ;
end function ;
type fsm_t is (IDLE, PRIME_DEPUNCT_FOR_SIGNAL, CAPTURE_SIGNAL, DECODE_PARITY, DECODE_SIGNAL, CAPTURE_DATA, DECODE_DATA, CAPTURE_CRC, COMPARE_CRC) ;
type state_t is record
fsm : fsm_t ;
bytes_captured : natural range 0 to 8 ;
decoded_signal : std_logic_vector( 23 downto 0) ;
signal_valid : std_logic ;
params : wlan_rx_params_t ;
params_valid : std_logic ;
num_coded_bits : unsigned( 13 downto 0 ) ;
num_coded_bits_valid : std_logic ;
num_decoded_bits : unsigned( 13 downto 0 ) ;
num_decoded_bits_valid : std_logic ;
num_bytes : natural range 0 to 4096 ;
length : natural range 0 to 4096 ;
packet_crc : std_logic_vector( 31 downto 0) ;
crc_correct : std_logic ;
done : std_logic ;
frame_control : std_logic_vector( 15 downto 0 ) ;
frame_duration : std_logic_vector( 15 downto 0 ) ;
a0 : std_logic_vector( 47 downto 0 ) ;
a1 : std_logic_vector( 47 downto 0 ) ;
a2 : std_logic_vector( 47 downto 0 ) ;
frame_id : std_logic_vector( 15 downto 0 ) ;
ack_mac : std_logic_vector( 47 downto 0 ) ;
ack_valid : std_logic ;
acked_packet : std_logic ;
parity_bit : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.bytes_captured := 0 ;
rv.decoded_signal := ( others => '0' ) ;
rv.signal_valid := '0' ;
rv.params_valid := '0' ;
rv.num_coded_bits := ( others => '0' ) ;
rv.num_coded_bits_valid := '0' ;
rv.num_decoded_bits := ( others => '0' ) ;
rv.num_decoded_bits_valid := '0' ;
rv.num_bytes := 0 ;
rv.length := 0 ;
rv.params.packet_valid := '0' ;
rv.packet_crc := ( others => '0' ) ;
rv.crc_correct := '0' ;
rv.done := '0' ;
rv.frame_control := ( others => '0' ) ;
rv.frame_duration := ( others => '0' ) ;
rv.a0 := ( others => '0' ) ;
rv.a1 := ( others => '0' ) ;
rv.a2 := ( others => '0' ) ;
rv.ack_valid := '0' ;
rv.acked_packet := '0' ;
rv.frame_id := ( others => '0' ) ;
rv.parity_bit := '0' ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal payload_data : std_logic ;
signal calculated_crc : std_logic_vector( 31 downto 0 ) ;
begin
payload_data <= '1' when (current.fsm = DECODE_DATA and (current.num_bytes <= current.length - 4 )) else '0' ;
signal_dec <= current.signal_valid ;
descrambler_bypass <= not(current.signal_valid);
params <= current.params ;
params_valid <= current.params_valid ;
framer_done <= current.done;
crc_correct <= current.crc_correct ;
ack_valid <= current.ack_valid ;
ack_mac <= current.ack_mac ;
acked_packet <= current.acked_packet;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
if( framer_quiet_reset = '1' ) then
current <= NULL_STATE ;
else
current <= future ;
end if ;
end if ;
end process ;
comb : process(all)
variable rx_vec : wlan_rx_vector_t ;
variable parity_bit : std_logic ;
begin
future <= current ;
future.crc_correct <= '0' ;
future.num_coded_bits_valid <= '0' ;
future.num_decoded_bits_valid <= '0' ;
future.params_valid <= '0' ;
future.ack_valid <= '0' ;
future.acked_packet <= '0' ;
case current.fsm is
when IDLE =>
future.signal_valid <= '0' ;
if( init = '1' ) then
future.fsm <= PRIME_DEPUNCT_FOR_SIGNAL ;
else
future <= NULL_STATE ;
end if ;
when PRIME_DEPUNCT_FOR_SIGNAL =>
rx_vec.datarate := WLAN_RATE_6 ;
rx_vec.length := 3 ;
future.params <= calculate_params( rx_vec, false );
future.params_valid <= '1' ;
future.fsm <= CAPTURE_SIGNAL ;
when CAPTURE_SIGNAL =>
if( in_valid = '1' ) then
future.bytes_captured <= current.bytes_captured + 1 ;
if ( current.bytes_captured = 2 ) then
future.fsm <= DECODE_PARITY ;
future.signal_valid <= '1' ;
end if ;
future.decoded_signal <= in_data & current.decoded_signal( 23 downto 8 ) ;
end if ;
when DECODE_PARITY =>
parity_bit := current.decoded_signal(0) ;
for i in 1 to 16 loop
parity_bit := parity_bit xor current.decoded_signal( i ) ;
end loop ;
future.parity_bit <= parity_bit;
future.fsm <= DECODE_SIGNAL ;
when DECODE_SIGNAL =>
if( current.parity_bit = current.decoded_signal(17) ) then
future.fsm <= DECODE_DATA ;
future.params.packet_valid <= '1' ;
rx_vec.datarate := WLAN_RATE_6 ;
if( current.decoded_signal( 3 downto 0 ) = "1011" ) then
rx_vec.datarate := WLAN_RATE_6 ;
elsif( current.decoded_signal( 3 downto 0 ) = "1111" ) then
rx_vec.datarate := WLAN_RATE_9 ;
elsif( current.decoded_signal( 3 downto 0 ) = "1010" ) then
rx_vec.datarate := WLAN_RATE_12 ;
elsif( current.decoded_signal( 3 downto 0 ) = "1110" ) then
rx_vec.datarate := WLAN_RATE_18 ;
elsif( current.decoded_signal( 3 downto 0 ) = "1001" ) then
rx_vec.datarate := WLAN_RATE_24 ;
elsif( current.decoded_signal( 3 downto 0 ) = "1101" ) then
rx_vec.datarate := WLAN_RATE_36 ;
elsif( current.decoded_signal( 3 downto 0 ) = "1000" ) then
rx_vec.datarate := WLAN_RATE_48 ;
elsif( current.decoded_signal( 3 downto 0 ) = "1100" ) then
rx_vec.datarate := WLAN_RATE_54 ;
else
rx_vec.datarate := WLAN_RATE_6 ;
report "Bad rate" severity warning ;
end if ;
-- length consist of the length field encoded in the SIGNAL field,
-- plus 2 bytes for the SERVICE field
rx_vec.length := to_integer( unsigned( current.decoded_signal( 16 downto 5 ) ) ) + 2 ;
if( rx_vec.length > 1600 ) then
future.fsm <= IDLE ;
else
future.length <= to_integer( unsigned( current.decoded_signal( 16 downto 5 ) ) ) ;
future.num_bytes <= 1 ;
future.params <= calculate_params( rx_vec, true );
future.params.packet_valid <= '1' ;
end if ;
else
future.fsm <= IDLE ;
future.params.packet_valid <= '0' ;
end if ;
future.params_valid <= '1' ;
when DECODE_DATA =>
if( in_valid = '1' ) then
future.num_bytes <= current.num_bytes + 1 ;
if( current.num_bytes >= (current.length - 4 ) ) then
future.num_bytes <= 0 ;
future.fsm <= CAPTURE_CRC ;
end if ;
if (current.num_bytes <= 2 ) then
future.frame_control <= current.frame_control( 7 downto 0 ) & in_data ;
end if ;
if (current.num_bytes > 2 and current.num_bytes <= 4 ) then
future.frame_id <= current.frame_id( 7 downto 0 ) & in_data ;
end if ;
if (current.num_bytes > 4 and current.num_bytes <= 10 ) then
future.a0 <= current.a0( 39 downto 0 ) & in_data ;
end if ;
if (current.num_bytes > 10 and current.num_bytes <= 16 ) then
future.a1 <= current.a1( 39 downto 0 ) & in_data ;
end if ;
if (current.num_bytes > 16 and current.num_bytes <= 22 ) then
future.a2 <= current.a2( 39 downto 0 ) & in_data ;
end if ;
if (current.num_bytes > 22 and current.num_bytes <= 24 ) then
future.frame_id <= current.frame_id( 7 downto 0 ) & in_data ;
end if ;
end if ;
when CAPTURE_CRC =>
if( in_valid = '1' ) then
future.num_bytes <= current.num_bytes + 1 ;
future.packet_crc <= in_data & current.packet_crc( 31 downto 8 ) ;
if( current.num_bytes = (4 - 1) ) then
future.fsm <= COMPARE_CRC ;
end if ;
end if ;
when COMPARE_CRC =>
if( current.packet_crc = calculated_crc ) then
future.crc_correct <= '1' ;
if( current.frame_control(11 downto 10) = "01" and current.frame_control(15 downto 12) = "1101" and current.a0 = bss_mac ) then
future.acked_packet <= '1' ;
end if;
if( current.frame_control(10) = '0' ) then
if( current.frame_control(1 downto 1) = "0" and current.a0 = bss_mac ) then
future.ack_mac <= current.a1 ;
future.ack_valid <= '1' ;
elsif(current.frame_control(1 downto 0) = "10" and current.a1 = bss_mac ) then
future.ack_mac <= current.a2 ;
future.ack_valid <= '1' ;
end if;
end if ;
end if ;
future.done <= '1' ;
future.fsm <= IDLE ;
when others =>
future <= NULL_STATE ;
end case ;
end process ;
U_crc : entity wlan.wlan_crc
port map (
clock => clock,
reset => reset or init,
in_data => in_data,
in_valid => in_valid and payload_data,
crc => calculated_crc
) ;
end architecture ;

84
fpga/vhdl/wlan_rx_p.vhd Normal file
View File

@ -0,0 +1,84 @@
-- 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 ;
use ieee.math_real.all ;
library work ;
use work.wlan_p.all ;
package wlan_rx_p is
type wlan_rx_status_t is (RX_IDLE, RX_ACTIVE, RX_FAULT_SIGNAL_INVALID, RX_FAULT_OVERFLOW) ;
type wlan_rx_vector_t is record
length : positive range 1 to 4095 ;
datarate : wlan_datarate_t ;
bandwidth : wlan_bandwidth_t ;
end record ;
type wlan_rx_params_t is record
n_bpsc : natural range 1 to 6 ;
n_cbps : natural range 48 to 288 ;
n_dbps : natural range 24 to 216 ;
bandwidth : wlan_bandwidth_t ;
modulation : wlan_modulation_t ;
datarate : wlan_datarate_t ;
length : natural range 1 to 4095 ;
lfsr_init : unsigned(6 downto 0) ;
num_data_symbols : natural range 1 to 12000 ;
num_padding_bits : natural range 0 to 287 ;
num_decoded_bits : natural range 0 to 32768 ;
packet_valid : std_logic ;
end record ;
function NULL_PARAMS return wlan_rx_params_t ;
function NULL_RX_VECTOR return wlan_rx_vector_t ;
end package ;
package body wlan_rx_p is
function NULL_PARAMS return wlan_rx_params_t is
variable rv : wlan_rx_params_t ;
begin
rv.n_bpsc := 1 ;
rv.n_cbps := 48 ;
rv.n_dbps := 24 ;
rv.bandwidth := WLAN_BW_20 ;
rv.modulation := WLAN_BPSK ;
rv.datarate := WLAN_RATE_6 ;
rv.length := 1 ;
rv.lfsr_init := (others =>'1') ;
rv.num_data_symbols := 1 ;
rv.num_padding_bits := 0 ;
return rv ;
end function ;
function NULL_RX_VECTOR return wlan_rx_vector_t is
variable rv : wlan_rx_vector_t ;
begin
rv.length := 1 ;
rv.datarate := WLAN_RATE_6 ;
rv.bandwidth := WLAN_BW_20 ;
return rv ;
end function ;
end package body ;

View File

@ -0,0 +1,323 @@
-- 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 ;
library altera_mf ;
use altera_mf.altera_mf_components.all ;
entity wlan_rx_packet_buffer is
port (
clock : in std_logic ;
reset : in std_logic ;
framer_quiet_reset : in std_logic ;
framer_done : in std_logic ;
crc_correct : in std_logic ;
in_params : in wlan_rx_params_t ;
in_params_valid : in std_logic ;
in_data : in std_logic_vector( 7 downto 0 ) ;
in_data_valid : in std_logic ;
dsss_framer_done : in std_logic ;
dsss_crc_correct : in std_logic ;
dsss_params : in wlan_rx_params_t ;
dsss_params_valid : in std_logic ;
dsss_data : in std_logic_vector( 7 downto 0 ) ;
dsss_data_valid : in std_logic ;
out_params : out wlan_rx_params_t ;
out_params_valid : out std_logic ;
out_data : out std_logic_vector( 7 downto 0 ) ;
out_data_valid : out std_logic ;
out_end_of_packet : out std_logic
) ;
end entity;
architecture arch of wlan_rx_packet_buffer is
type wfsm_t is (IDLE, WRITE_DATA, DUMP_BUFFER, COMMIT_BUFFER) ;
type rfsm_t is (IDLE, READ, CLEAR_BUFFER, EOP) ;
type state_t is record
wfsm : wfsm_t ;
rfsm : rfsm_t ;
read : std_logic ;
buf_a_writing : std_logic ;
buf_a_reading : std_logic ;
buf_a_ready : std_logic ;
buf_b_ready : std_logic ;
buf_a_reset : std_logic ;
buf_b_reset : std_logic ;
buf_a_clear : std_logic ;
buf_b_clear : std_logic ;
buf_a_params : wlan_rx_params_t ;
buf_b_params : wlan_rx_params_t ;
out_params : wlan_rx_params_t ;
out_params_valid : std_logic ;
out_end_of_packet : std_logic ;
timer : natural range 0 to 1600 ;
dsss_mode : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.wfsm := IDLE ;
rv.read := '0' ;
rv.buf_a_writing := '0' ;
rv.buf_a_reading := '0' ;
rv.buf_a_ready := '0' ;
rv.buf_b_ready := '0' ;
rv.buf_a_reset := '0' ;
rv.buf_b_reset := '0' ;
rv.buf_a_clear := '0' ;
rv.buf_b_clear := '0' ;
rv.out_params_valid := '0' ;
rv.out_end_of_packet := '0' ;
rv.timer := 0 ;
rv.dsss_mode := '0' ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
signal fifo_a_q : std_logic_vector( 7 downto 0 ) ;
signal fifo_a_empty : std_logic ;
signal fifo_a_usedw : std_logic_vector( 10 downto 0 ) ;
signal fifo_b_q : std_logic_vector( 7 downto 0 ) ;
signal fifo_b_empty : std_logic ;
signal fifo_b_usedw : std_logic_vector( 10 downto 0 ) ;
signal fifo_data : std_logic_vector( 7 downto 0 ) ;
signal fifo_wrreq_a : std_logic ;
signal fifo_wrreq_b : std_logic ;
begin
out_params <= current.out_params ;
out_params_valid <= current.out_params_valid ;
out_data <= fifo_a_q when current.buf_a_reading = '1' else fifo_b_q ;
out_data_valid <= current.read ;
out_end_of_packet <= current.out_end_of_packet ;
U_fifo_a : scfifo
generic map (
lpm_width => 8,
lpm_widthu => 11,
lpm_numwords => 1600,
lpm_showahead => "ON"
) port map (
clock => clock,
aclr => reset,
sclr => current.buf_a_reset or current.buf_a_clear,
data => fifo_data,
wrreq => fifo_wrreq_a,
rdreq => current.read and current.buf_a_reading,
q => fifo_a_q,
full => open,
empty => fifo_a_empty,
usedw => fifo_a_usedw
) ;
U_fifo_b : scfifo
generic map (
lpm_width => 8,
lpm_widthu => 11,
lpm_numwords => 1600,
lpm_showahead => "ON"
) port map (
clock => clock,
aclr => reset,
sclr => current.buf_b_reset or current.buf_b_clear,
data => fifo_data,
wrreq => fifo_wrreq_b,
rdreq => current.read and not current.buf_a_reading,
q => fifo_b_q,
full => open,
empty => fifo_b_empty,
usedw => fifo_b_usedw
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
if( current.dsss_mode = '1' ) then
fifo_data <= dsss_data ;
fifo_wrreq_a <= dsss_data_valid and current.buf_a_writing ;
fifo_wrreq_b <= dsss_data_valid and not current.buf_a_writing ;
else
fifo_data <= in_data ;
fifo_wrreq_a <= in_data_valid and current.buf_a_writing ;
fifo_wrreq_b <= in_data_valid and not current.buf_a_writing ;
end if ;
future <= current ;
future.buf_a_reset <= '0' ;
future.buf_b_reset <= '0' ;
case current.wfsm is
when IDLE =>
if( (framer_quiet_reset = '0' and in_params_valid = '1') or dsss_params_valid = '1' ) then
if( current.buf_a_writing = '1' ) then
if( dsss_params_valid = '1' ) then
future.buf_a_params <= dsss_params ;
else
future.buf_a_params <= in_params ;
end if ;
future.buf_a_ready <= '0' ;
else
if( dsss_params_valid = '1' ) then
future.buf_b_params <= dsss_params ;
else
future.buf_b_params <= in_params ;
end if ;
future.buf_b_ready <= '0' ;
end if ;
future.dsss_mode <= dsss_params_valid ;
future.wfsm <= WRITE_DATA ;
end if ;
when WRITE_DATA =>
if( current.dsss_mode = '0' ) then
if( framer_quiet_reset = '1' or ( framer_done = '1' and crc_correct = '0' ) ) then
future.wfsm <= DUMP_BUFFER ;
end if ;
if( framer_done = '1' and crc_correct = '1' ) then
future.wfsm <= COMMIT_BUFFER ;
end if ;
else
if( dsss_framer_done = '1' ) then
if ( dsss_crc_correct = '1' ) then
future.wfsm <= COMMIT_BUFFER ;
else
future.wfsm <= DUMP_BUFFER ;
end if ;
end if ;
end if ;
when DUMP_BUFFER =>
if( current.buf_a_writing = '1' ) then
future.buf_a_reset <= '1' ;
else
future.buf_b_reset <= '1' ;
end if ;
future.wfsm <= IDLE ;
when COMMIT_BUFFER =>
if( current.buf_a_writing = '1' ) then
future.buf_a_writing <= '0' ;
future.buf_a_ready <= '1' ;
else
future.buf_a_writing <= '1' ;
future.buf_b_ready <= '1' ;
end if ;
future.wfsm <= IDLE ;
end case ;
future.out_end_of_packet <= '0' ;
future.buf_a_clear <= '0' ;
future.buf_b_clear <= '0' ;
case current.rfsm is
when IDLE =>
if( current.buf_a_ready = '1' and fifo_a_empty = '0' ) then
future.out_params <= current.buf_a_params ;
future.out_params_valid <= '1' ;
future.buf_a_reading <= '1' ;
future.timer <= current.buf_a_params.length - 2 ;
future.rfsm <= READ ;
elsif( current.buf_b_ready = '1' and fifo_b_empty = '0' ) then
future.out_params <= current.buf_b_params ;
future.out_params_valid <= '1' ;
future.buf_a_reading <= '0' ;
future.timer <= current.buf_b_params.length - 2 ;
future.rfsm <= READ ;
end if ;
when READ =>
if( ( current.buf_a_reading = '1' and fifo_a_empty = '1' ) or
( current.buf_a_reading = '0' and fifo_b_empty = '1' ) or
current.timer = 0) then
future.read <= '0' ;
future.rfsm <= CLEAR_BUFFER ;
else
future.read <= '1' ;
future.timer <= current.timer - 1 ;
end if ;
when CLEAR_BUFFER =>
if( current.buf_a_reading = '1' ) then
future.buf_a_clear <= '1' ;
else
future.buf_b_clear <= '1' ;
end if ;
if( ( current.buf_a_reading = '1' and fifo_a_empty = '1' ) or
( current.buf_a_reading = '0' and fifo_b_empty = '1' ) ) then
future.rfsm <= EOP ;
end if ;
when EOP =>
future.out_end_of_packet <= '1' ;
future.out_params_valid <= '0' ;
future.rfsm <= IDLE ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,125 @@
-- 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 ;
library altera_mf ;
use altera_mf.altera_mf_components.all ;
entity wlan_sample_buffer is
port (
clock : in std_logic ;
reset : in std_logic ;
-- Status
room : out std_logic ;
-- Short sequence inputs
short : in wlan_sample_t ;
-- Long sequence inputs
long : in wlan_sample_t ;
-- Symbol IFFT inputs
symbol : in wlan_sample_t ;
-- Sample FIFO outputs
sample : out wlan_sample_t ;
sample_i : out signed(15 downto 0) ;
sample_q : out signed(15 downto 0) ;
sample_re : in std_logic ;
sample_empty : out std_logic
) ;
end entity ;
architecture arch of wlan_sample_buffer is
signal fifo_write : std_logic ;
signal fifo_read : std_logic ;
signal fifo_input : std_logic_vector(31 downto 0) ;
signal fifo_output : std_logic_vector(31 downto 0) ;
signal fifo_empty : std_logic ;
signal fifo_full : std_logic ;
signal fifo_usedw : std_logic_vector(9 downto 0) ;
signal mux_i : signed(15 downto 0) ;
signal mux_q : signed(15 downto 0) ;
begin
check_fifo : process(clock)
begin
if( rising_edge(clock) ) then
if( fifo_full = '1' and fifo_write = '1' ) then
report "Writing to a full FIFO"
severity error ;
end if ;
end if ;
end process ;
fifo_input <= std_logic_vector(mux_i) & std_logic_vector(mux_q) ;
fifo_write <= short.valid or long.valid or symbol.valid ;
fifo_read <= sample_re ;
sample_i <= signed(fifo_output(31 downto 16)) ;
sample_q <= signed(fifo_output(15 downto 0)) ;
sample_empty <= fifo_empty ;
mux_input : process(all)
begin
if( short.valid = '1' ) then
mux_i <= short.i ;
mux_q <= short.q ;
elsif( long.valid = '1' ) then
mux_i <= long.i ;
mux_q <= long.q ;
elsif( symbol.valid = '1' ) then
mux_i <= symbol.i ;
mux_q <= symbol.q ;
else
mux_i <= (others =>'0') ;
mux_q <= (others =>'0') ;
end if ;
end process ;
room <= '1' when unsigned(fifo_usedw) < 2**(fifo_usedw'length)-128 else '0' ;
U_fifo : scfifo
generic map (
lpm_width => fifo_input'length,
lpm_widthu => fifo_usedw'length,
lpm_numwords => 2**(fifo_usedw'length),
lpm_showahead => "ON"
) port map (
clock => clock,
aclr => reset,
data => fifo_input,
wrreq => fifo_write,
rdreq => fifo_read,
q => fifo_output,
full => fifo_full,
empty => fifo_empty,
usedw => fifo_usedw
) ;
end architecture ;

View File

@ -0,0 +1,218 @@
-- 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 ;
use work.wlan_tx_p.all ;
entity wlan_scrambler is
port (
clock : in std_logic ;
reset : in std_logic ;
params : wlan_tx_params_t ;
params_valid : in std_logic ;
in_data : in std_logic_vector(7 downto 0) ;
in_valid : in std_logic ;
in_done : in std_logic ;
out_data : out std_logic_vector(7 downto 0) ;
out_valid : out std_logic ;
done : out std_logic
) ;
end entity ;
architecture arch of wlan_scrambler is
signal lfsr_advance : std_logic ;
signal lfsr_data : std_logic_vector(in_data'range) ;
signal lfsr_valid : std_logic ;
type fsm_t is (IDLE, SKIP_SIGNAL_FIELD, SCRAMBLE_DATA, INSERT_TAIL_BITS, SCRAMBLE_PADDING) ;
type state_t is record
fsm : fsm_t ;
data : std_logic_vector(7 downto 0) ;
data_valid : std_logic ;
done : std_logic ;
symbol_bytes_left : natural range 0 to 27 ;
bytes_per_symbol : natural range 3 to 27 ;
puncturing_nibble : std_logic ;
extra_byte : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.data := (others =>'0') ;
rv.data_valid := '0' ;
rv.done := '0' ;
rv.symbol_bytes_left := 3 ;
rv.puncturing_nibble := '0' ;
rv.extra_byte := '0' ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
function reverse(x : std_logic_vector) return std_logic_vector is
variable rv : std_logic_vector(x'range) ;
begin
for i in x'range loop
rv(x'high-i) := x(i) ;
end loop ;
return rv ;
end function ;
signal data_reversed : std_logic_vector(7 downto 0) ;
begin
data_reversed <= reverse(current.data) ;
out_data <= current.data ;
out_valid <= current.data_valid ;
done <= current.done ;
U_lfsr : entity work.wlan_lfsr
generic map (
WIDTH => in_data'length
) port map (
clock => clock,
reset => reset,
init => params.lfsr_init,
init_valid => params_valid,
advance => lfsr_advance,
data => lfsr_data,
data_valid => lfsr_valid
) ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.data_valid <= '0' ;
future.done <= '0' ;
lfsr_advance <= '0' ;
case current.fsm is
when IDLE =>
if( params_valid = '1' ) then
future.fsm <= SKIP_SIGNAL_FIELD ;
future.symbol_bytes_left <= 3-1 ;
future.bytes_per_symbol <= params.n_dbps/8 ;
if( params.datarate = WLAN_RATE_9) then
future.puncturing_nibble <= '1' ;
future.extra_byte <= '1' ;
else
future.extra_byte <= '0' ;
future.puncturing_nibble <= '0' ;
end if ;
end if ;
when SKIP_SIGNAL_FIELD =>
if( in_valid = '1' ) then
future.data <= in_data ;
future.data_valid <= '1' ;
if( current.symbol_bytes_left = 0 ) then
future.fsm <= SCRAMBLE_DATA ;
if( current.puncturing_nibble = '1' ) then
if( current.extra_byte <= '1' ) then
future.symbol_bytes_left <= current.bytes_per_symbol ;
future.extra_byte <= '0' ;
else
future.symbol_bytes_left <= current.bytes_per_symbol - 1 ;
end if;
else
future.symbol_bytes_left <= current.bytes_per_symbol - 1 ;
end if;
else
future.symbol_bytes_left <= current.symbol_bytes_left - 1 ;
end if ;
end if ;
when SCRAMBLE_DATA =>
lfsr_advance <= in_valid ;
if( in_valid = '1' ) then
future.data <= in_data xor lfsr_data ;
future.data_valid <= '1' ;
--needs to keep track if it's going to read an extra nibble or if it's going to save one
if ( current.symbol_bytes_left = 0 ) then
if( current.extra_byte = '0' ) then
future.symbol_bytes_left <= current.bytes_per_symbol - 1 ;
else
future.symbol_bytes_left <= current.bytes_per_symbol ;
end if ;
if( current.puncturing_nibble = '1' ) then
future.extra_byte <= not current.extra_byte ;
end if ;
else
future.symbol_bytes_left <= current.symbol_bytes_left - 1 ;
end if ;
if( in_done = '1' ) then
future.fsm <= INSERT_TAIL_BITS ;
end if ;
end if ;
when INSERT_TAIL_BITS =>
lfsr_advance <= '1' ;
future.data <= (others =>'0') ;
future.data_valid <= '1' ;
if( current.symbol_bytes_left = 0 ) then
future.fsm <= IDLE ;
-- Last byte in the symbol so we're good!
future.done <= '1' ;
else
future.symbol_bytes_left <= current.symbol_bytes_left - 1 ;
future.fsm <= SCRAMBLE_PADDING ;
end if ;
when SCRAMBLE_PADDING =>
lfsr_advance <= '1' ;
future.data <= lfsr_data ;
future.data_valid <= '1' ;
if( current.symbol_bytes_left = 0 ) then
future.fsm <= IDLE ;
future.done <= '1' ;
else
future.symbol_bytes_left <= current.symbol_bytes_left - 1 ;
end if ;
when others =>
future.fsm <= IDLE ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,229 @@
-- 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_symbol_shaper is
port (
clock : in std_logic ;
reset : in std_logic ;
cp_i : in signed(15 downto 0) ;
cp_q : in signed(15 downto 0) ;
cp_re : out std_logic ;
cp_empty : in std_logic ;
sample_i : in signed(15 downto 0) ;
sample_q : in signed(15 downto 0) ;
sample_re : out std_logic ;
sample_empty : in std_logic ;
out_sample : out wlan_sample_t ;
done : out std_logic
) ;
end entity ;
architecture arch of wlan_symbol_shaper is
type fsm_t is (IDLE, SHORT_SEQUENCE, GI2, LONG_SEQUENCE, SIGNAL_GI, SIGNAL_SYMBOL, DATA_GI, DATA_SYMBOL, FINISH) ;
type state_t is record
fsm : fsm_t ;
enable : std_logic ;
sample : wlan_sample_t ;
sample_re : std_logic ;
cp_re : std_logic ;
downcount : natural range 0 to 160 ;
done : std_logic ;
end record ;
function init return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.enable := '0' ;
rv.sample := NULL_SAMPLE ;
rv.downcount := 160 ;
rv.sample_re := '0' ;
rv.cp_re := '0' ;
rv.done := '0' ;
return rv ;
end function ;
signal current, future : state_t := init ;
begin
out_sample <= current.sample ;
sample_re <= current.sample_re ;
cp_re <= current.cp_re ;
done <= current.done ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= init ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
-- Save all current state
future <= current ;
-- Reset valids
future.sample.valid <= '0' ;
future.sample_re <= '0' ;
future.cp_re <= '0' ;
future.done <= '0' ;
-- Get the FSM kicked off
case current.fsm is
when IDLE =>
future.downcount <= 160-1 ;
if( sample_empty = '0' ) then
future.fsm <= SHORT_SEQUENCE ;
end if ;
when others =>
null ;
end case ;
-- Advance the FSM once every other clock cycle
if( current.fsm /= IDLE ) then
future.enable <= not current.enable ;
end if ;
-- Meat and potatoes of the FSM which advances
-- once every other clock cycle
if current.enable = '1' then
case current.fsm is
when SHORT_SEQUENCE =>
future.sample.i <= sample_i ;
future.sample.q <= sample_q ;
future.sample.valid <= '1' ;
future.sample_re <= '1' ;
if( current.downcount = 0 ) then
future.downcount <= 32-1 ;
future.fsm <= GI2 ;
else
future.downcount <= current.downcount - 1 ;
end if ;
when GI2 =>
future.sample.i <= cp_i ;
future.sample.q <= cp_q ;
future.sample.valid <= '1' ;
future.cp_re <= '1' ;
if( current.downcount = 0 ) then
future.downcount <= 128-1 ;
future.fsm <= LONG_SEQUENCE ;
else
future.downcount <= current.downcount - 1 ;
end if ;
when LONG_SEQUENCE =>
future.sample.i <= sample_i ;
future.sample.q <= sample_q ;
future.sample.valid <= '1' ;
future.sample_re <= '1' ;
if( current.downcount = 0 ) then
future.downcount <= 16-1 ;
future.fsm <= SIGNAL_GI ;
else
future.downcount <= current.downcount - 1 ;
end if ;
when SIGNAL_GI =>
future.sample.i <= cp_i ;
future.sample.q <= cp_q ;
future.sample.valid <= '1' ;
future.cp_re <= '1' ;
if( current.downcount = 0 ) then
future.downcount <= 64-1 ;
future.fsm <= SIGNAL_SYMBOL ;
else
future.downcount <= current.downcount - 1 ;
end if ;
when SIGNAL_SYMBOL =>
future.sample.i <= sample_i ;
future.sample.q <= sample_q ;
future.sample.valid <= '1' ;
future.sample_re <= '1' ;
if( current.downcount = 0 ) then
future.downcount <= 16-1 ;
future.fsm <= DATA_GI ;
else
future.downcount <= current.downcount - 1 ;
end if ;
when DATA_GI =>
future.sample.i <= cp_i ;
future.sample.q <= cp_q ;
future.sample.valid <= '1' ;
future.cp_re <= '1' ;
if( current.downcount = 0 ) then
future.downcount <= 64-1 ;
future.fsm <= DATA_SYMBOL ;
else
future.downcount <= current.downcount - 1 ;
end if ;
when DATA_SYMBOL =>
future.sample.i <= sample_i ;
future.sample.q <= sample_q ;
future.sample.valid <= '1' ;
future.sample_re <= '1' ;
if( current.downcount = 0 ) then
if( sample_empty = '1' ) then
future.downcount <= 160-1 ;
future.fsm <= FINISH ;
else
if( cp_empty = '1' ) then
future.downcount <= 160-1 ;
future.fsm <= FINISH ;
else
future.downcount <= 16-1 ;
future.fsm <= DATA_GI ;
end if ;
end if ;
else
future.downcount <= current.downcount - 1 ;
end if ;
when FINISH =>
future.sample.i <= (others =>'0') ;
future.sample.q <= (others =>'0') ;
future.sample.valid <= '1' ;
future.done <= '1' ;
future.fsm <= IDLE ;
when others =>
null ;
end case ;
end if ;
end process ;
end architecture ;

939
fpga/vhdl/wlan_top.vhd Normal file
View File

@ -0,0 +1,939 @@
-- 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 ;

339
fpga/vhdl/wlan_tx.vhd Normal file
View File

@ -0,0 +1,339 @@
-- 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 ;
use work.wlan_tx_p.all ;
entity wlan_tx is
port (
-- 40MHz clock rate with async assert/sync deassert reset signal
clock : in std_logic ;
reset : in std_logic ;
-- Control word structure
tx_vector : in wlan_tx_vector_t ;
tx_vector_valid : in std_logic ;
-- Status signal
tx_status : out wlan_tx_status_t ;
tx_status_valid : out std_logic ;
-- Data FIFO interface
fifo_re : out std_logic ;
fifo_data : in std_logic_vector(7 downto 0) ;
fifo_empty : in std_logic ;
-- Baseband output signals
bb : out wlan_sample_t ;
done : out std_logic
) ;
end entity ;
architecture arch of wlan_tx is
-- Controller signals
signal params : wlan_tx_params_t ;
signal params_valid : std_logic ;
signal status : wlan_tx_status_t ;
signal status_valid : std_logic ;
-- Framer
signal framer_data : std_logic_vector(7 downto 0) ;
signal framer_valid : std_logic ;
signal framer_done : std_logic ;
-- Scrambler
signal scrambler_data : std_logic_vector(7 downto 0) ;
signal scrambler_valid : std_logic ;
signal scrambler_done : std_logic ;
-- Encoder signals
signal encoder_start : std_logic ;
signal encoder_done : std_logic ;
-- Short sequence data
signal short : wlan_sample_t ;
signal short_start : std_logic ;
signal short_done : std_logic ;
-- Long sequence data
signal long : wlan_sample_t ;
signal long_valid_cp : std_logic ;
signal long_start : std_logic ;
signal long_done : std_logic ;
-- Interlever
signal interleaver_mod : wlan_modulation_t ;
signal interleaver_data : std_logic_vector(287 downto 0) ;
signal interleaver_valid : std_logic ;
-- Modulated signal
signal mod_init : std_logic ;
signal mod_data : std_logic_vector(287 downto 0) ;
signal mod_type : wlan_modulation_t ;
signal mod_valid : std_logic ;
signal mod_sample : wlan_sample_t ;
signal mod_start : std_logic ;
signal mod_end : std_logic ;
-- IFFT signal
signal ifft_sample : wlan_sample_t ;
signal ifft_valid_cp : std_logic ;
signal ifft_ready : std_logic ;
-- Cyclic Prefix signal
signal cp_i : signed(15 downto 0) ;
signal cp_q : signed(15 downto 0) ;
signal cp_re : std_logic ;
signal cp_empty : std_logic ;
-- Sample signal
signal sample_i : signed(15 downto 0) ;
signal sample_q : signed(15 downto 0) ;
signal sample_re : std_logic ;
signal sample_empty : std_logic ;
signal sample_ready : std_logic ;
signal buffer_room : std_logic ;
-- Time series signal
signal out_sample : wlan_sample_t ;
-- End status signal
signal tx_done : std_logic ;
signal ifft_done : std_logic ;
begin
-- Configure TX based on TX vector
U_tx_controller : entity work.wlan_tx_controller
port map (
clock => clock,
reset => reset,
tx_vector => tx_vector,
tx_vector_valid => tx_vector_valid,
params => params,
params_valid => params_valid,
status => status,
status_valid => status_valid,
short_start => short_start,
short_done => short_done,
long_done => long_done,
encoder_start => encoder_start,
encoder_done => encoder_done,
mod_init => mod_init,
mod_end => mod_end,
tx_done => tx_done
) ;
U_framer : entity work.wlan_framer
port map (
clock => clock,
reset => reset,
params => params,
params_valid => params_valid,
encoder_start => encoder_start,
buffer_room => buffer_room,
fifo_data => fifo_data,
fifo_empty => fifo_empty,
fifo_re => fifo_re,
mod_done => mod_end,
out_data => framer_data,
out_valid => framer_valid,
done => framer_done
) ;
U_scrambler : entity work.wlan_scrambler
port map (
clock => clock,
reset => reset,
params => params,
params_valid => params_valid,
in_data => framer_data,
in_valid => framer_valid,
in_done => framer_done,
out_data => scrambler_data,
out_valid => scrambler_valid,
done => scrambler_done
) ;
U_encoder : entity work.wlan_encoder
port map (
clock => clock,
reset => reset,
params => params,
params_valid => params_valid,
pdu_start => encoder_start,
pdu_end => encoder_done,
scrambler => scrambler_data,
scrambler_valid => scrambler_valid,
scrambler_done => scrambler_done,
mod_data => mod_data,
mod_type => mod_type,
mod_valid => mod_valid,
mod_end => mod_end
) ;
-- Interleaver
U_interleaver : entity work.wlan_interleaver
port map (
clock => clock,
reset => reset,
modulation => mod_type,
data => mod_data,
in_valid => mod_valid,
interleaved => interleaver_data,
interleaved_mod => interleaver_mod,
interleaved_valid => interleaver_valid
) ;
-- Modulation
U_modulator : entity work.wlan_modulator
port map (
clock => clock,
reset => reset,
init => mod_init,
data => interleaver_data,
modulation => interleaver_mod,
in_valid => interleaver_valid,
ifft_ready => ifft_ready,
symbol_start => mod_start,
symbol_end => mod_end,
symbol_sample => mod_sample
) ;
-- IFFT
U_ifft64 : entity work.wlan_ifft64
port map (
clock => clock,
reset => reset,
symbol_start => mod_start,
symbol_end => mod_end,
in_sample => mod_sample,
out_sample => ifft_sample,
out_valid_cp => ifft_valid_cp,
ifft_ready => ifft_ready,
done => ifft_done
) ;
-- Short sequence insertion
U_short_sequence : entity work.wlan_tx_short
port map (
clock => clock,
reset => reset,
start => short_start,
done => short_done,
out_sample => short
) ;
-- Long sequence insertion
long_start <= short_done ;
U_long_sequence : entity work.wlan_tx_long
port map (
clock => clock,
reset => reset,
start => long_start,
done => long_done,
out_sample => long,
out_valid_cp => long_valid_cp
) ;
-- CP buffer (16 samples at a time)
U_cp_buffer : entity work.wlan_sample_buffer
port map (
clock => clock,
reset => reset or tx_vector_valid,
short => NULL_SAMPLE,
long => (long.i, long.q, long_valid_cp),
symbol => (ifft_sample.i, ifft_sample.q, ifft_valid_cp),
sample_i => cp_i,
sample_q => cp_q,
sample_re => cp_re,
sample_empty => cp_empty
) ;
-- Symbol buffer (64 samples at a time)
U_symbol_buffer : entity work.wlan_sample_buffer
port map (
clock => clock,
reset => reset or tx_vector_valid,
room => buffer_room,
short => short,
long => long,
symbol => ifft_sample,
sample_i => sample_i,
sample_q => sample_q,
sample_re => sample_re,
sample_empty => sample_empty
) ;
-- Apply temporal window and send out the door
U_symbol_shaper : entity work.wlan_symbol_shaper
port map (
clock => clock,
reset => reset,
cp_i => cp_i,
cp_q => cp_q,
cp_re => cp_re,
cp_empty => cp_empty,
sample_i => sample_i,
sample_q => sample_q,
sample_re => sample_re,
sample_empty => sample_empty,
out_sample => out_sample,
done => tx_done
) ;
-- Register the output
bb <= out_sample when rising_edge(clock) ;
done <= tx_done when rising_edge(clock) ;
end architecture ;

View File

@ -0,0 +1,233 @@
-- 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 ;
use work.wlan_tx_p.all ;
entity wlan_tx_controller is
port (
clock : in std_logic ;
reset : in std_logic ;
-- Control from the MAC
tx_vector : in wlan_tx_vector_t ;
tx_vector_valid : in std_logic ;
-- Caculated parameters
params : out wlan_tx_params_t ;
params_valid : out std_logic ;
-- TX status generation
status : out wlan_tx_status_t ;
status_valid : out std_logic ;
-- Encoder from MAC
encoder_start : out std_logic ;
encoder_done : in std_logic ;
-- Short preamble control and status
short_start : out std_logic ;
short_done : in std_logic ;
-- Long preamble control and status
long_done : in std_logic ;
-- Modulator control and status
mod_init : out std_logic ;
mod_end : in std_logic ;
-- TX done
tx_done : in std_logic
) ;
end entity ;
architecture arch of wlan_tx_controller is
type fsm_t is (IDLE, START_TRANSMISSION, START_ENCODING_DATA, WAIT_FOR_PREAMBLE_DONE, WAIT_FOR_TX_DONE) ;
type state_t is record
fsm : fsm_t ;
params : wlan_tx_params_t ;
params_valid : std_logic ;
short_start : std_logic ;
encoder_start : std_logic ;
mod_init : std_logic ;
status_valid : std_logic ;
end record ;
function calculate_params( x : wlan_tx_vector_t ) return wlan_tx_params_t is
variable rv : wlan_tx_params_t ;
begin
rv.datarate := x.datarate ;
rv.length := x.length ;
rv.lfsr_init := "1011101" ;
case x.datarate is
when WLAN_RATE_6 =>
-- BPSK R=1/2
rv.n_bpsc := 1 ;
rv.n_dbps := 24 ;
rv.n_cbps := 48 ;
rv.modulation := WLAN_BPSK ;
when WLAN_RATE_9 =>
-- BPSK R=3/4
rv.n_bpsc := 1 ;
rv.n_dbps := 36 ;
rv.n_cbps := 48 ;
rv.modulation := WLAN_BPSK ;
when WLAN_RATE_12 =>
-- QPSK R=1/2
rv.n_bpsc := 2 ;
rv.n_dbps := 48 ;
rv.n_cbps := 96 ;
rv.modulation := WLAN_QPSK ;
when WLAN_RATE_18 =>
-- QPSK R=3/4
rv.n_bpsc := 2 ;
rv.n_dbps := 72 ;
rv.n_cbps := 96 ;
rv.modulation := WLAN_QPSK ;
when WLAN_RATE_24 =>
-- 16-QAM R=1/2
rv.n_bpsc := 4 ;
rv.n_dbps := 96 ;
rv.n_cbps := 192 ;
rv.modulation := WLAN_16QAM ;
when WLAN_RATE_36 =>
-- 16-QAM R=3/4
rv.n_bpsc := 4 ;
rv.n_dbps := 144 ;
rv.n_cbps := 192 ;
rv.modulation := WLAN_16QAM ;
when WLAN_RATE_48 =>
-- 64-QAM R=2/3
rv.n_bpsc := 6 ;
rv.n_dbps := 192 ;
rv.n_cbps := 288 ;
rv.modulation := WLAN_64QAM ;
when WLAN_RATE_54 =>
-- 64-QAM R=3/4
rv.n_bpsc := 6 ;
rv.n_dbps := 216 ;
rv.n_cbps := 288;
rv.modulation := WLAN_64QAM ;
when others =>
report "Invalid params" severity failure ;
end case ;
case x.bandwidth is
when WLAN_BW_5 =>
null ;
when WLAN_BW_10 =>
null ;
when WLAN_BW_20 =>
null ;
when others =>
report "Invalid bandwidth" severity failure ;
end case ;
return rv ;
end function ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.params_valid := '0' ;
rv.short_start := '0' ;
rv.encoder_start := '0' ;
rv.mod_init := '0' ;
rv.status_valid := '0' ;
return rv ;
end function ;
signal current, future : state_t := NULL_STATE ;
begin
params <= current.params ;
params_valid <= current.params_valid ;
short_start <= current.short_start ;
encoder_start <= current.encoder_start ;
mod_init <= current.mod_init ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.params_valid <= '0' ;
future.short_start <= '0' ;
future.encoder_start <= '0' ;
future.mod_init <= '0' ;
future.status_valid <= '0' ;
case current.fsm is
when IDLE =>
future.params_valid <= tx_vector_valid ;
if( tx_vector_valid = '1' ) then
future.params <= calculate_params(tx_vector) ;
future.fsm <= START_TRANSMISSION ;
end if ;
when START_TRANSMISSION =>
future.short_start <= '1' ;
future.fsm <= START_ENCODING_DATA ;
when START_ENCODING_DATA =>
future.fsm <= WAIT_FOR_PREAMBLE_DONE ;
when WAIT_FOR_PREAMBLE_DONE =>
if( long_done = '1' ) then
future.fsm <= WAIT_FOR_TX_DONE ;
future.encoder_start <= '1' ;
future.mod_init <= '1' ;
end if ;
when WAIT_FOR_TX_DONE =>
if( tx_done = '1' ) then
future.fsm <= IDLE ;
end if ;
end case ;
end process ;
end architecture ;

135
fpga/vhdl/wlan_tx_long.vhd Normal file
View File

@ -0,0 +1,135 @@
-- 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 ;
use ieee.math_real.all ;
library work ;
use work.wlan_p.all ;
use work.wlan_tx_p.all ;
entity wlan_tx_long is
port (
clock : in std_logic ;
reset : in std_logic ;
start : in std_logic ;
done : out std_logic ;
out_sample : out wlan_sample_t ;
out_valid_cp : out std_logic
) ;
end entity ;
architecture arch of wlan_tx_long is
function create_long_sequence return sample_array_t is
variable rv : sample_array_t(LONG_SEQ_TIME'range) ;
begin
for i in rv'range loop
rv(i).i := to_signed(integer(round(LONG_SEQ_TIME(i).re*4096.0*4.0)),rv(i).i'length) ;
rv(i).q := to_signed(integer(round(LONG_SEQ_TIME(i).im*4096.0*4.0)),rv(i).q'length) ;
rv(i).valid := '1' ;
end loop;
return rv ;
end function ;
constant LONG_SEQ : sample_array_t := create_long_sequence ;
type fsm_t is (IDLE, CYCLIC_PREFIX, T_SEQ) ;
type state_t is record
fsm : fsm_t ;
repeat : natural range 1 to 2 ;
index : natural range LONG_SEQ'range ;
sample : wlan_sample_t ;
valid_cp : std_logic ;
done : std_logic ;
end record ;
constant NULL_STATE : state_t := (
fsm => IDLE,
repeat => 2,
index => 32,
sample => NULL_SAMPLE,
valid_cp => '0',
done => '0'
) ;
-- FSM state
signal current, future : state_t := NULL_STATE ;
begin
done <= current.done ;
out_sample <= current.sample ;
out_valid_cp <= current.valid_cp ;
seq : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
case current.fsm is
when IDLE =>
future <= NULL_STATE ;
if( start = '1' ) then
future.fsm <= CYCLIC_PREFIX ;
end if ;
when CYCLIC_PREFIX =>
future.sample <= LONG_SEQ(current.index) ;
future.valid_cp <= '1' ;
future.sample.valid <= '0' ;
if( current.index < LONG_SEQ'high ) then
future.index <= current.index + 1 ;
else
future.fsm <= T_SEQ ;
future.index <= 0 ;
end if ;
when T_SEQ =>
future.sample <= LONG_SEQ(current.index) ;
future.valid_cp <= '0' ;
if( current.index < LONG_SEQ'high ) then
future.index <= current.index + 1 ;
else
if( current.repeat = 1 ) then
future.fsm <= IDLE ;
future.done <= '1' ;
else
future.repeat <= current.repeat - 1 ;
future.index <= 0 ;
end if ;
end if ;
when others =>
future <= NULL_STATE ;
end case ;
end process ;
end architecture ;

82
fpga/vhdl/wlan_tx_p.vhd Normal file
View File

@ -0,0 +1,82 @@
-- 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 ;
use ieee.math_real.all ;
library work ;
use work.wlan_p.all ;
package wlan_tx_p is
type wlan_tx_vector_t is record
length : positive range 1 to 4095 ;
datarate : wlan_datarate_t ;
bandwidth : wlan_bandwidth_t ;
end record ;
type wlan_tx_params_t is record
n_bpsc : natural range 1 to 6 ;
n_cbps : natural range 48 to 288 ;
n_dbps : natural range 24 to 216 ;
modulation : wlan_modulation_t ;
datarate : wlan_datarate_t ;
length : natural range 1 to 4095 ;
lfsr_init : unsigned(6 downto 0) ;
num_decoded_bits : natural range 8 to 11224 ;
num_data_symbols : natural range 1 to 1366 ;
num_padding_bits : natural range 0 to 287 ;
end record ;
function NULL_PARAMS return wlan_tx_params_t ;
function NULL_TX_VECTOR return wlan_tx_vector_t ;
type wlan_tx_status_t is (TX_IDLE, TX_SHORT, TX_LONG, TX_DATA, TX_FAULT_NODATA, TX_FAULT_UNDERRUN) ;
end package ;
package body wlan_tx_p is
function NULL_PARAMS return wlan_tx_params_t is
variable rv : wlan_tx_params_t ;
begin
rv.n_bpsc := 1 ;
rv.n_cbps := 48 ;
rv.n_dbps := 24 ;
rv.modulation := WLAN_BPSK ;
rv.datarate := WLAN_RATE_6 ;
rv.length := 1 ;
rv.lfsr_init := (others =>'1') ;
rv.num_data_symbols := 0 ;
rv.num_data_symbols := 1 ;
rv.num_padding_bits := 0 ;
return rv ;
end function ;
function NULL_TX_VECTOR return wlan_tx_vector_t is
variable rv : wlan_tx_vector_t ;
begin
rv.length := 1 ;
rv.datarate := WLAN_RATE_6 ;
rv.bandwidth := WLAN_BW_20 ;
return rv ;
end function ;
end package body ;

118
fpga/vhdl/wlan_tx_short.vhd Normal file
View File

@ -0,0 +1,118 @@
-- 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 ;
use ieee.math_real.all ;
library work ;
use work.wlan_p.all ;
use work.wlan_tx_p.all ;
entity wlan_tx_short is
port (
clock : in std_logic ;
reset : in std_logic ;
start : in std_logic ;
done : out std_logic ;
out_sample : out wlan_sample_t
) ;
end entity ;
architecture arch of wlan_tx_short is
function create_short_sequence return sample_array_t is
variable rv : sample_array_t(SHORT_SEQ_TIME'range) ;
begin
for i in rv'range loop
rv(i).i := to_signed(integer(round(SHORT_SEQ_TIME(i).re*4.0*4096.0)),rv(i).i'length) ;
rv(i).q := to_signed(integer(round(SHORT_SEQ_TIME(i).im*4.0*4096.0)),rv(i).i'length) ;
rv(i).valid := '1' ;
end loop ;
return rv ;
end function ;
constant SHORT_SEQ : sample_array_t := create_short_sequence ;
type fsm_t is (IDLE, COUNTING) ;
type state_t is record
fsm : fsm_t ;
repeat : natural range 1 to 10 ;
index : natural range short_seq'range ;
sample : wlan_sample_t ;
done : std_logic ;
end record ;
constant NULL_STATE : state_t := (
fsm => IDLE,
repeat => 10,
index => 0,
sample => NULL_SAMPLE,
done => '0'
) ;
-- FSM state
signal current, future : state_t := NULL_STATE ;
begin
done <= current.done ;
out_sample <= current.sample ;
seq : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
current <= future ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
case current.fsm is
when IDLE =>
future <= NULL_STATE ;
if( start = '1' ) then
future.fsm <= COUNTING ;
end if ;
when COUNTING =>
future.sample <= short_seq(current.index) ;
if( current.index < short_seq'high ) then
future.index <= current.index + 1 ;
else
if( current.repeat = 1 ) then
future.fsm <= IDLE ;
future.done <= '1' ;
else
future.repeat <= current.repeat - 1 ;
future.index <= 0 ;
end if ;
end if ;
when others =>
future <= NULL_STATE ;
end case ;
end process ;
end architecture ;

View File

@ -0,0 +1,155 @@
-- 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 ;
library work ;
library viterbi_decoder ;
entity wlan_viterbi_decoder is
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
in_soft_a : in signed(7 downto 0) ;
in_soft_b : in signed(7 downto 0) ;
in_erasure : in std_logic_vector(1 downto 0) ;
in_valid : in std_logic ;
params : in wlan_rx_params_t ;
params_valid : in std_logic ;
done : out std_logic ;
out_dec_bit : out std_logic ;
out_dec_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_viterbi_decoder is
type fsm_t is (IDLE, DECODE, RESET_CORE ) ;
type state_t is record
fsm : fsm_t ;
num_decoded_bits : unsigned( 13 downto 0 ) ;
done : std_logic ;
end record ;
function NULL_STATE return state_t is
variable rv : state_t ;
begin
rv.fsm := IDLE ;
rv.num_decoded_bits := ( others => '0' );
rv.done := '0' ;
return rv ;
end function ;
signal sink_rdy : std_logic ;
signal sink_val : std_logic ;
signal source_rdy : std_logic ;
signal source_val : std_logic ;
signal rr : std_logic_vector(15 downto 0) ;
signal decbit : std_logic ;
signal normalizations : std_logic_vector(7 downto 0) ;
signal core_reset : std_logic ;
signal current, future : state_t := NULL_STATE ;
begin
done <= current.done ;
sync : process(clock, reset)
begin
if( reset = '1' ) then
current <= NULL_STATE ;
elsif( rising_edge(clock) ) then
if( init = '1' ) then
current <= NULL_STATE ;
else
current <= future ;
end if ;
end if ;
end process ;
comb : process(all)
begin
future <= current ;
future.done <= '0' ;
case current.fsm is
when IDLE =>
if( params_valid = '1' ) then
future.num_decoded_bits <= to_unsigned(params.num_decoded_bits - 1, future.num_decoded_bits'length ) ;
future.fsm <= DECODE ;
end if ;
when DECODE =>
if( source_val = '1' ) then
future.num_decoded_bits <= current.num_decoded_bits - 1;
end if ;
if( current.num_decoded_bits = 0 ) then
future.done <= '1' ;
future.fsm <= RESET_CORE ;
end if ;
when RESET_CORE =>
future.fsm <= IDLE ;
end case ;
end process ;
core_reset <= '1' when current.fsm = RESET_CORE or current.fsm = IDLE or reset = '1' else '0' ;
rr <= std_logic_vector(in_soft_a) & std_logic_vector(in_soft_b) ;
sink_val <= in_valid ;
U_altera_decoder : entity viterbi_decoder.viterbi_decoder
port map (
clk => clock,
reset => core_reset,
sink_val => sink_val,
sink_rdy => sink_rdy,
rr => rr,
eras_sym => in_erasure,
source_rdy => source_rdy,
source_val => source_val,
decbit => decbit,
normalizations => normalizations
) ;
out_dec_bit <= decbit ;
out_dec_valid <= source_val ;
source_rdy <= '1' ;
end architecture ;

View File

@ -0,0 +1,83 @@
-- 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 ;
entity wlan_viterbi_encoder is
generic (
WIDTH : positive := 4
) ;
port (
clock : in std_logic ;
reset : in std_logic ;
init : in std_logic ;
in_data : in std_logic_vector(WIDTH-1 downto 0) ;
in_valid : in std_logic ;
in_done : in std_logic ;
out_a : out std_logic_vector(WIDTH-1 downto 0) ;
out_b : out std_logic_vector(WIDTH-1 downto 0) ;
out_done : out std_logic ;
out_valid : out std_logic
) ;
end entity ;
architecture arch of wlan_viterbi_encoder is
signal state : unsigned(5 downto 0) := (others =>'0') ;
begin
encode : process(clock, reset)
variable tempstate : unsigned(state'range) := (others =>'0') ;
begin
if( reset = '1' ) then
state <= (others =>'0') ;
out_a <= (others =>'0') ;
out_b <= (others =>'0') ;
out_valid <= '0' ;
out_done <= '0' ;
tempstate := (others =>'0') ;
elsif( rising_edge(clock) ) then
out_valid <= '0' ;
out_done <= in_done ;
if( init = '1' ) then
state <= (others =>'0') ;
else
out_valid <= in_valid ;
if( in_valid = '1' ) then
tempstate := state ;
for i in 0 to in_data'high loop
out_a(i) <= tempstate(5) xor tempstate(4) xor tempstate(2) xor tempstate(1) xor in_data(i) ;
out_b(i) <= tempstate(5) xor tempstate(2) xor tempstate(1) xor tempstate(0) xor in_data(i) ;
tempstate := tempstate(4 downto 0) & in_data(i) ;
end loop ;
state <= tempstate ;
end if ;
end if ;
end if ;
end process ;
end architecture ;

49
matlab/util.m Normal file
View File

@ -0,0 +1,49 @@
% 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.
% Null OFDM symbol
null = zeros(64,1) ;
% Short preamble generation
SHORT_ONE = 1.472 + 1.472*1j ;
% Bins for positive and negative values
% NOTE: MATLAB has bin 1 as the DC bin, but standard uses
% bin 0 as DC, so we will define all bins here similar to the
% standard, and when indexing them, we will add the MATLAB offset.
SHORT_POS = [12, 16, 20, 24, 40, 48, 60] ;
SHORT_NEG = [4, 8, 44, 52, 56] ;
short_preamble.freq = zeros(64,1) ;
short_preamble.freq(SHORT_POS+1) = SHORT_ONE ;
short_preamble.freq(SHORT_NEG+1) = -SHORT_ONE ;
short_preamble.time = ifft(short_preamble.freq) ;
% Long preamble generation
LONG_ONE = 1 ;
% Bins for positive and negative values
LONG_POS = [1, 4, 5, 7, 9, 15, 16, 19, 21, 23, 24, 25, 26, 38, 39, 42, 43, 45, 47, 48, 49, 50, 51, 52, 55, 56, 58, 60, 61, 62, 63 ] ;
LONG_NEG = [2, 3, 6, 8, 10, 11, 12, 13, 14, 17, 18, 20, 22, 40, 41, 44, 46, 53, 54, 57, 59 ] ;
long_preamble.freq = zeros(64,1) ;
long_preamble.freq(LONG_POS+1) = LONG_ONE ;
long_preamble.freq(LONG_NEG+1) = -LONG_ONE ;
long_preamble.time = ifft(long_preamble.freq) ;

108
matlab/wlan_rx.m Normal file
View File

@ -0,0 +1,108 @@
% 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.
%% User Parameters
snr = 99 ;
%% Initialization
% Get common stuff, x is input signal
util
clear rx
idx = 1 ;
%% AWGN Channel with some phase offset
% TODO: Make this more interesting
%h = [1] ;
% h = [ randn+1j*randn 0 (randn+1j*randn)/2 0 (randn+1j*randn)/4 ];
h = [ 0.85 0.1 0 0.05 0 0.05 ] ;
% Add noise
noise = (randn(length(x),1) + randn(length(x),1)*1j) ;
sp = sum(abs(x).^2) ;
np = sum(abs(noise).^2) ;
% Scale noise based on signal and noise power
nl = sp / (10^(snr/10)) / np ;
noise = sqrt(nl).*noise ;
sp = sum(abs(x).^2) ;
np = sum(abs(noise).^2) ;
rx.actual_snr = 10*log10(sp/np) ;
% Finally add the noise
% NOTE: Channel impulse response does not have a group delay, so don't
% delay the input, just chop it off.
xn = conv(x,h) ; xn = xn(1:length(x)) ;
xn = xn + noise ;
% Add a phase rotation
xn = xn .* exp(1j*pi/8) ;
%% Acquisition
% Acquire
% TODO: Actually acquire here, but for now we know we just advance 160
% samples into the signal
rx.short = xn(idx:idx+160-1) ;
idx = idx + 160 ; % short sequence
%% Save off T1 and T2 after GI2
% Initialize frequency offset correction
idx = idx + 32 ; % GI2
rx.t1 = xn(idx:idx+64-1) ;
rx.T1 = fft(rx.t1) ;
rx.T1(rx.T1==0) = 1e-20 ;
idx = idx + 64 ; % T1
% Figure out initial equalizer taps
rx.t2 = xn(idx:idx+64-1) ;
rx.T2 = fft(rx.t2) ;
rx.T2(rx.T2==0) = 1e-20 ;
idx = idx + 64 ; % T2
%% Initialize Equalizer from average of T1 and T2
% Since T1 and T2 should be the same, we should be able to average the
% observed samples together and try to get rid of some noise.
rx.tavg = (rx.t1 + rx.t2)./2 ;
rx.TAVG = fft(rx.tavg) ;
%rx.TAVG = fft([ h, zeros(1,64-length(h))].') ;
% Equalizer is just the reference signal divided by received signal
rx.EQ = long_preamble.freq .* conj(rx.TAVG) ./ (abs(rx.TAVG).^2 + 10^(-snr/10)) ;
%% Extract SIGNAL frame
idx = idx + 16 ; % GI
rx.signal = xn(idx:idx+64-1) ;
rx.SIGNAL = fft(rx.signal) ;
rx.SIGNAL_EQ = rx.SIGNAL .* rx.EQ ;
idx = idx + 64 ;
%% Extract DATA frames
n = 1 ;
num_data_frames = floor((length(x) - idx)/80) ;
rx.data = zeros(num_data_frames, 64) ;
rx.DATA = zeros(num_data_frames, 64) ;
idx = idx + 16 ; % GI
while n <= num_data_frames
rx.data(n,:) = xn(idx:idx+64-1) ;
rx.DATA(n,:) = fft(rx.data(n,:)) ;
rx.DATA_EQ(n,:) = rx.DATA(n,:) .* rx.EQ.' ;
% Increment
n = n + 1 ;
idx = idx + 80 ;
end