mirror of
https://github.com/Nuand/bladeRF-wiphy.git
synced 2024-12-18 13:26:48 +00:00
Initial commit
This commit is contained in:
commit
3e751f3e37
339
LICENSE
Normal file
339
LICENSE
Normal 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
109
fpga/common/wlan_files.tcl
Normal 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
201
fpga/ip/nuand/cordic.vhd
Normal 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
97
fpga/ip/nuand/nco.vhd
Normal 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
75
fpga/modelsim/wlan.do
Normal 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
26
fpga/quartus/wlan.qip
Normal 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
|
||||
}
|
||||
|
65
fpga/vhdl/clock_sync_logic.vhd
Normal file
65
fpga/vhdl/clock_sync_logic.vhd
Normal 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 ;
|
60
fpga/vhdl/clock_sync_logic_vector.vhd
Normal file
60
fpga/vhdl/clock_sync_logic_vector.vhd
Normal 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 ;
|
58
fpga/vhdl/clock_sync_params.vhd
Normal file
58
fpga/vhdl/clock_sync_params.vhd
Normal 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 ;
|
70
fpga/vhdl/tb/wlan_ack_generator_tb.vhd
Normal file
70
fpga/vhdl/tb/wlan_ack_generator_tb.vhd
Normal 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 ;
|
114
fpga/vhdl/tb/wlan_acquisition_tb.vhd
Normal file
114
fpga/vhdl/tb/wlan_acquisition_tb.vhd
Normal 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 ;
|
||||
|
118
fpga/vhdl/tb/wlan_bsd_tb.vhd
Normal file
118
fpga/vhdl/tb/wlan_bsd_tb.vhd
Normal 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 ;
|
||||
|
202
fpga/vhdl/tb/wlan_channel_inverter_tb.vhd
Normal file
202
fpga/vhdl/tb/wlan_channel_inverter_tb.vhd
Normal 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 ;
|
||||
|
95
fpga/vhdl/tb/wlan_clock_tb.vhd
Normal file
95
fpga/vhdl/tb/wlan_clock_tb.vhd
Normal 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 ;
|
57
fpga/vhdl/tb/wlan_dsss_plcp_crc_tb.vhd
Normal file
57
fpga/vhdl/tb/wlan_dsss_plcp_crc_tb.vhd
Normal 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 ;
|
55
fpga/vhdl/tb/wlan_interleaver_tb.vhd
Normal file
55
fpga/vhdl/tb/wlan_interleaver_tb.vhd
Normal 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 ;
|
||||
|
121
fpga/vhdl/tb/wlan_lfsr_tb.vhd
Normal file
121
fpga/vhdl/tb/wlan_lfsr_tb.vhd
Normal 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 ;
|
||||
|
112
fpga/vhdl/tb/wlan_modulator_tb.vhd
Normal file
112
fpga/vhdl/tb/wlan_modulator_tb.vhd
Normal 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 ;
|
||||
|
76
fpga/vhdl/tb/wlan_peak_finder_tb.vhd
Normal file
76
fpga/vhdl/tb/wlan_peak_finder_tb.vhd
Normal 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
188
fpga/vhdl/tb/wlan_rx_tb.vhd
Normal 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 ;
|
||||
|
92
fpga/vhdl/tb/wlan_sample_loader.vhd
Normal file
92
fpga/vhdl/tb/wlan_sample_loader.vhd
Normal 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 ;
|
||||
|
80
fpga/vhdl/tb/wlan_sample_saver.vhd
Normal file
80
fpga/vhdl/tb/wlan_sample_saver.vhd
Normal 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 ;
|
||||
|
160
fpga/vhdl/tb/wlan_symbol_shaper_tb.vhd
Normal file
160
fpga/vhdl/tb/wlan_symbol_shaper_tb.vhd
Normal 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 ;
|
||||
|
207
fpga/vhdl/tb/wlan_tables_p.vhd
Normal file
207
fpga/vhdl/tb/wlan_tables_p.vhd
Normal 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
37
fpga/vhdl/tb/wlan_tb.vhd
Normal 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 ;
|
||||
|
221
fpga/vhdl/tb/wlan_top_tb.vhd
Normal file
221
fpga/vhdl/tb/wlan_top_tb.vhd
Normal 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 ;
|
||||
|
72
fpga/vhdl/tb/wlan_tx_long_tb.vhd
Normal file
72
fpga/vhdl/tb/wlan_tx_long_tb.vhd
Normal 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 ;
|
||||
|
70
fpga/vhdl/tb/wlan_tx_short_tb.vhd
Normal file
70
fpga/vhdl/tb/wlan_tx_short_tb.vhd
Normal 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
178
fpga/vhdl/tb/wlan_tx_tb.vhd
Normal 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 ;
|
||||
|
187
fpga/vhdl/tb/wlan_viterbi_encoder_tb.vhd
Normal file
187
fpga/vhdl/tb/wlan_viterbi_encoder_tb.vhd
Normal 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 ;
|
||||
|
203
fpga/vhdl/tb/wlan_viterbi_tb.vhd
Normal file
203
fpga/vhdl/tb/wlan_viterbi_tb.vhd
Normal 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 ;
|
163
fpga/vhdl/wlan_ack_generator.vhd
Normal file
163
fpga/vhdl/wlan_ack_generator.vhd
Normal 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 ;
|
||||
|
256
fpga/vhdl/wlan_acquisition.vhd
Normal file
256
fpga/vhdl/wlan_acquisition.vhd
Normal 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
221
fpga/vhdl/wlan_agc.vhd
Normal 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
298
fpga/vhdl/wlan_agc_drv.vhd
Normal 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
182
fpga/vhdl/wlan_bsd.vhd
Normal 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 ;
|
||||
|
75
fpga/vhdl/wlan_cfo_correction.vhd
Normal file
75
fpga/vhdl/wlan_cfo_correction.vhd
Normal 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 ;
|
150
fpga/vhdl/wlan_cfo_estimate.vhd
Normal file
150
fpga/vhdl/wlan_cfo_estimate.vhd
Normal 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 ;
|
158
fpga/vhdl/wlan_channel_inverter.vhd
Normal file
158
fpga/vhdl/wlan_channel_inverter.vhd
Normal 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
149
fpga/vhdl/wlan_clamper.vhd
Normal 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 ;
|
||||
|
92
fpga/vhdl/wlan_correlator.vhd
Normal file
92
fpga/vhdl/wlan_correlator.vhd
Normal 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
91
fpga/vhdl/wlan_crc.vhd
Normal 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
134
fpga/vhdl/wlan_csma.vhd
Normal 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
194
fpga/vhdl/wlan_dcf.vhd
Normal 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 ;
|
||||
|
||||
|
75
fpga/vhdl/wlan_deinterleaver.vhd
Normal file
75
fpga/vhdl/wlan_deinterleaver.vhd
Normal 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 ;
|
||||
|
71
fpga/vhdl/wlan_delay_correlator.vhd
Normal file
71
fpga/vhdl/wlan_delay_correlator.vhd
Normal 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 ;
|
||||
|
243
fpga/vhdl/wlan_demodulator.vhd
Normal file
243
fpga/vhdl/wlan_demodulator.vhd
Normal 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 ;
|
||||
|
||||
|
226
fpga/vhdl/wlan_depuncturer.vhd
Normal file
226
fpga/vhdl/wlan_depuncturer.vhd
Normal 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 ;
|
||||
|
||||
|
233
fpga/vhdl/wlan_descrambler.vhd
Normal file
233
fpga/vhdl/wlan_descrambler.vhd
Normal 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
106
fpga/vhdl/wlan_divide.vhd
Normal 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 ;
|
132
fpga/vhdl/wlan_dsss_demodulator.vhd
Normal file
132
fpga/vhdl/wlan_dsss_demodulator.vhd
Normal 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 ;
|
97
fpga/vhdl/wlan_dsss_despreader.vhd
Normal file
97
fpga/vhdl/wlan_dsss_despreader.vhd
Normal 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 ;
|
143
fpga/vhdl/wlan_dsss_p_norm.vhd
Normal file
143
fpga/vhdl/wlan_dsss_p_norm.vhd
Normal 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 ;
|
193
fpga/vhdl/wlan_dsss_peak_finder.vhd
Normal file
193
fpga/vhdl/wlan_dsss_peak_finder.vhd
Normal 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 ;
|
70
fpga/vhdl/wlan_dsss_plcp_crc.vhd
Normal file
70
fpga/vhdl/wlan_dsss_plcp_crc.vhd
Normal 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
140
fpga/vhdl/wlan_dsss_rx.vhd
Normal 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 ;
|
81
fpga/vhdl/wlan_dsss_rx_controller.vhd
Normal file
81
fpga/vhdl/wlan_dsss_rx_controller.vhd
Normal 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 ;
|
271
fpga/vhdl/wlan_dsss_rx_framer.vhd
Normal file
271
fpga/vhdl/wlan_dsss_rx_framer.vhd
Normal 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
440
fpga/vhdl/wlan_encoder.vhd
Normal 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 ;
|
||||
|
332
fpga/vhdl/wlan_equalizer.vhd
Normal file
332
fpga/vhdl/wlan_equalizer.vhd
Normal 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
302
fpga/vhdl/wlan_fft64.vhd
Normal 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
334
fpga/vhdl/wlan_framer.vhd
Normal 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
164
fpga/vhdl/wlan_ifft64.vhd
Normal 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 ;
|
||||
|
62
fpga/vhdl/wlan_interleaver.vhd
Normal file
62
fpga/vhdl/wlan_interleaver.vhd
Normal 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 ;
|
||||
|
133
fpga/vhdl/wlan_interleaver_p.vhd
Normal file
133
fpga/vhdl/wlan_interleaver_p.vhd
Normal 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
79
fpga/vhdl/wlan_lfsr.vhd
Normal 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 ;
|
||||
|
343
fpga/vhdl/wlan_modulator.vhd
Normal file
343
fpga/vhdl/wlan_modulator.vhd
Normal 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
275
fpga/vhdl/wlan_p.vhd
Normal 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
144
fpga/vhdl/wlan_p_norm.vhd
Normal 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 ;
|
76
fpga/vhdl/wlan_peak_finder.vhd
Normal file
76
fpga/vhdl/wlan_peak_finder.vhd
Normal 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 ;
|
||||
|
343
fpga/vhdl/wlan_phase_correction.vhd
Normal file
343
fpga/vhdl/wlan_phase_correction.vhd
Normal 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
816
fpga/vhdl/wlan_rx.vhd
Normal 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 ;
|
||||
|
228
fpga/vhdl/wlan_rx_controller.vhd
Normal file
228
fpga/vhdl/wlan_rx_controller.vhd
Normal 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 ;
|
422
fpga/vhdl/wlan_rx_framer.vhd
Normal file
422
fpga/vhdl/wlan_rx_framer.vhd
Normal 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
84
fpga/vhdl/wlan_rx_p.vhd
Normal 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 ;
|
323
fpga/vhdl/wlan_rx_packet_buffer.vhd
Normal file
323
fpga/vhdl/wlan_rx_packet_buffer.vhd
Normal 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 ;
|
||||
|
125
fpga/vhdl/wlan_sample_buffer.vhd
Normal file
125
fpga/vhdl/wlan_sample_buffer.vhd
Normal 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 ;
|
||||
|
218
fpga/vhdl/wlan_scrambler.vhd
Normal file
218
fpga/vhdl/wlan_scrambler.vhd
Normal 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 ;
|
||||
|
229
fpga/vhdl/wlan_symbol_shaper.vhd
Normal file
229
fpga/vhdl/wlan_symbol_shaper.vhd
Normal 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
939
fpga/vhdl/wlan_top.vhd
Normal 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
339
fpga/vhdl/wlan_tx.vhd
Normal 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 ;
|
||||
|
233
fpga/vhdl/wlan_tx_controller.vhd
Normal file
233
fpga/vhdl/wlan_tx_controller.vhd
Normal 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
135
fpga/vhdl/wlan_tx_long.vhd
Normal 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
82
fpga/vhdl/wlan_tx_p.vhd
Normal 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
118
fpga/vhdl/wlan_tx_short.vhd
Normal 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 ;
|
||||
|
155
fpga/vhdl/wlan_viterbi_decoder.vhd
Normal file
155
fpga/vhdl/wlan_viterbi_decoder.vhd
Normal 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 ;
|
||||
|
83
fpga/vhdl/wlan_viterbi_encoder.vhd
Normal file
83
fpga/vhdl/wlan_viterbi_encoder.vhd
Normal 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
49
matlab/util.m
Normal 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
108
matlab/wlan_rx.m
Normal 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
|
Loading…
Reference in New Issue
Block a user