187 Commits

Author SHA1 Message Date
Kirill Zakharenko
2a89674c56 Bump version to 1.0.5 2015-11-23 15:09:10 +03:00
Josh Blum
77e9066bf8 fpga: updated 4x ddc image for spi work 2015-08-11 23:45:58 -07:00
Josh Blum
1e43f04790 Merge branch 'axi_shared_spi' 2015-08-11 17:04:51 -07:00
Kirill Zakharenko
cbff81745b debian: added firmware to package and umtrx_firmware script to handle it 2015-08-11 13:29:52 +03:00
Josh Blum
57d5ca4b51 fpga: simplify spi setting regs with generate loop 2015-07-29 19:21:28 -07:00
Josh Blum
b78ceeb9b1 fpga: connect both spi settings drivers 2015-07-29 01:59:54 -07:00
Josh Blum
fcd92d8f50 fpga: use axi stream spi core (still single dest) 2015-07-28 16:32:17 -07:00
Josh Blum
2727f62ab8 fpga: created axi stream controled spi core 2015-07-28 16:31:29 -07:00
Alexander Chemeris
75c3380ccf host: Fix getters in umtrx_property_tree.py. 2015-07-27 20:42:23 -04:00
Josh Blum
80e65f35cf host: disable umtrx_fifo_ctrl cache of spi config
This register can be modified by the firmware,
which invalidates the cached setting.
2015-07-24 00:50:35 -07:00
Kirill Zakharenko
f16599cfa9 debian: conflicts/replaces stanzas to replace renamed package
otherwise new packages will be installed alongside older one and we'll
get a file conflict
2015-07-23 03:00:19 +02:00
Alexander Chemeris
e6b82c85e6 debian: 1.0.4 release changelog. 2015-07-21 21:09:25 -04:00
Alexander Chemeris
8e5b9e8cba utils: Prettier output for umtrx_auto_calibration 2015-07-21 21:09:25 -04:00
Alexander Chemeris
fc9ecf7709 host: Fix a typo in the DC offset property tree setter. 2015-07-21 21:09:25 -04:00
Alexander Chemeris
913f19357b utils: Verify that calibration property has been set correctly.
Sometimes setting an LMS register fails if UmTRX has bad power supply. We want
to make sure we catch this situation and abort calibration.
2015-07-21 18:48:43 -04:00
Alexander Chemeris
d96cea8000 utils: Set default Rx gain to 50 instead of 100 in calibration utils.
A few commits ago we changed Rx gain to real dB instead of abstract values,
which changed the gain settings range - old 100 is about current 50.
2015-07-21 00:38:09 -04:00
Alexander Chemeris
c401071ea6 scripts: Fix a nasty typo in umtrx_auto_calibration.
We were executing each calibration comand twice, because $echo was not defined.
2015-07-20 22:43:01 -04:00
Josh Blum
b5b351e535 debian: split umtrx into module and runtime packages
* uhd-umtrx for uhd plugin module only (multi-arch lib dir)
* umtrx - runtime utility applications (depends on uhd-umtrx)

The idea is to support multi-arch installs by separating out the plugin module
(which can exist in a multi-arch install) from the /usr/bin/ executables.
It may also be useful for users to have a minimal install (plugin only).
2015-07-12 00:02:27 -07:00
Josh Blum
1cf16e57f7 host: fixed missing boost math include (boost 1.46)
usrp_cal_utils.hpp used boost round but did not include the header.
This caused a build error on ubuntu 12.04 LTS w/ boost boost 1.46
2015-07-10 14:30:39 -07:00
Alexander Chemeris
b78a96661a host: FIx SET handling for the property tree JSON API. 2015-07-05 19:30:13 -04:00
Alexander Chemeris
5452567fd9 host: There is no need to explicitely support coerce() in property_alias()
Coerce is called automatically inside of the set() of the original property.
2015-07-05 12:47:56 -04:00
Alexander Chemeris
47b3e1aaea host: Complete calculations for VSWR in Python utils + better sensors output. 2015-07-05 10:01:37 -04:00
Alexander Chemeris
1e042157be Merge branch 'status_monitor'
Implements a TCP server inside UHD which gives access to a device's property
tree through a JSON API.
2015-07-04 19:27:14 -04:00
Alexander Chemeris
4cb89755bb host: A Python library for the property tree API and sensors query utility. 2015-07-04 19:19:39 -04:00
Alexander Chemeris
efba897843 host: No need to explicitely insert EOL, it's already there. 2015-07-04 19:19:39 -04:00
Alexander Chemeris
35ccac9f54 host: Fix typo in a comment s/GET/SET/. 2015-07-04 19:19:39 -04:00
Josh Blum
963f3e90dc umtrx: remove sleep used for testing 2015-07-04 19:19:39 -04:00
Josh Blum
0e8abb2068 umtrx: generic JSON property tree service 2015-07-04 19:19:39 -04:00
Josh Blum
e069b6d39c umtrx: client handler thread to keep socket open 2015-07-04 19:19:39 -04:00
Josh Blum
28f423567b umtrx: changes to tcp query server
* tcp query server is on its own thread
* tcp query take full sensor path (simpler)
* select on client socket to wait for data
2015-07-04 19:19:39 -04:00
Josh Blum
67303bcbcc umtrx: mutex for i2c-based interfaces 2015-07-04 19:19:38 -04:00
Josh Blum
0fc60d2275 umtrx: sensor query support and comments 2015-07-04 19:19:38 -04:00
Josh Blum
ce5f31f713 umtrx: mutex for lms ctrl wrapper class 2015-07-04 19:19:38 -04:00
Josh Blum
802b24c565 umtrx: work on status monitor tcp server 2015-07-04 19:19:38 -04:00
Josh Blum
56c4174ad4 umtrx: skeleton for status monitor thread 2015-07-04 19:19:38 -04:00
Alexander Chemeris
0073096b27 Merge branch 'achemeris/divsw' 2015-07-04 19:14:26 -04:00
Alexander Chemeris
7727cd283c host: By default route each Rx channel to it's own antenna. 2015-07-04 19:14:10 -04:00
Alexander Chemeris
ff13c7d73a host: Add ability to set diversity switches position from UHD args.
Diviersity switch controls are also aliased RF frontends property subtrees now.
2015-07-04 19:12:34 -04:00
Alexander Chemeris
0bee662b81 host: Implement property_alias() function which creates an alias at the proprty tree. 2015-07-04 19:01:23 -04:00
Kirill Zakharenko
7b955574a5 minor debianization fixes: +x debian/rules, correct debian/source/format 2015-06-29 11:45:45 +03:00
Josh Blum
4b102f0c4c Merge branch 'debian' 2015-06-20 16:45:07 -07:00
Josh Blum
0d7b517923 debian: changelog entry for 1.0.3 release 2015-06-20 16:44:57 -07:00
Josh Blum
aec754eb07 umtrx: strip leading g from describe hash 2015-06-04 20:44:31 -04:00
Alexander Chemeris
756cb9a74c utils: Better documentation for umtrx_auto_calibration. 2015-06-03 13:51:32 -04:00
Alexander Chemeris
0b105893a4 Merge branch 'achemeris/iq_cal_work' implementing Tx IQ calibration. 2015-05-28 17:34:56 -04:00
Josh Blum
41b93944a0 fpga: move tx frontend mux between DSP and corrections module
On the RX side, the same mux is between the corrections and the DSP.
However, for TX, this was between the DAC and corrections module,
leading to the host code setting the wrong corrections when the
channel 0 was set to frontend mapping "B:0".

This fixes the issue with the tx iq calibration utility.
A new fpga image is checked in and compat minor bumped.
2015-05-28 17:33:00 -04:00
Alexander Chemeris
a872102cd9 host: Fix UHD args in the umtrx_auto_calibration. 2015-05-28 17:33:00 -04:00
Alexander Chemeris
89277c6e56 host: Add missing new line in the calibration utils output. 2015-05-28 17:32:59 -04:00
Alexander Chemeris
1773223b81 host: Improve console output for calibration utilities. 2015-05-28 17:32:59 -04:00
Alexander Chemeris
24527ece28 host: Use "fifo_ctrl_window=0" UHD param in the umtrx_auto_calibration. 2015-05-28 17:32:59 -04:00
Alexander Chemeris
7834aa4709 host: Better reporting at the end of umtrx_auto_calibration 2015-05-28 17:32:59 -04:00
Alexander Chemeris
f61d102791 host: Checking in umtrx_auto_calibration script.
The script is a shortcut to run UmTRX calibration for a selected band.
2015-05-28 17:32:59 -04:00
Alexander Chemeris
d8b282404b host: An attempt to get IQ balance caliration working with the 2nd channel.
The 2nd channel calibration still doesn't work, but I thought this code is
useful anyway to unify DC and IQ calibratoin code.
2015-05-28 17:30:32 -04:00
Alexander Chemeris
4cd94528aa host: Correctly store IQ balance calibration values. 2015-05-28 17:30:31 -04:00
Alexander Chemeris
fb59ec9bd2 host: Better default values for umtrx_cal_tx_iq_balance. 2015-05-28 17:30:31 -04:00
Alexander Chemeris
9577f31bfb host: Checking in umtrx_cal_tx_iq_balance utility. 2015-05-28 17:30:31 -04:00
Alexander Chemeris
df513b81e5 host: Move more generic functions to usrp_cal_utils.hpp 2015-05-28 17:30:31 -04:00
Josh Blum
471eedbb6a debian: first shot at umtrx debianization 2015-05-26 17:12:04 -07:00
Alexander Chemeris
10e758be8c host: Implement setting Rx VGA1 gain in real dBs. 2015-05-20 12:21:29 -04:00
Alexander Chemeris
9c20b295d5 host: Fix whitespaces. 2015-05-20 12:17:00 -04:00
Alexander Chemeris
14e58af929 host: Implement power control below the PA minimum output power using LMS VGA. 2015-05-18 02:06:05 -04:00
Alexander Chemeris
9a752069e7 host: Output all known PA types on startup. 2015-05-18 00:26:10 -04:00
Alexander Chemeris
283dae8214 host: Implement functions to list all known PA types. 2015-05-18 00:17:44 -04:00
Alexander Chemeris
df90e2b342 host: Replace 'pa_power_limit' param with 'pa_power_max_w' and 'pa_power_max_dbm'. 2015-05-18 00:16:31 -04:00
Alexander Chemeris
0b1c002f32 host: Add utils to read NMEA and GPS coordinates from UmTRX. 2015-05-16 01:10:39 -04:00
Alexander Chemeris
313488b2d3 host: Fix umtrx_cal_tx_dc_offset help output to mention UmTRX. 2015-05-09 22:35:55 -04:00
Alexander Chemeris
189828f29c Merge branch 'achemeris/pa_control' 2015-05-09 01:17:11 -04:00
Alexander Chemeris
f913c39c0c host: Checking in a full scale DCDC conversion table. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
84c5426fd8 host: Delay between DCDC setting and reading it back is not necessary when there is a PA installed. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
ac22360125 host: Enable DCDC converter before setting its value. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
6bf16b4e66 host: Give DCDC converter time to settle when we set PA output power. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
451cc221be host: UHD uses dB for gains, not Watts. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
73ab35d46c host: Implement case insensitive PA type comparison. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
a189138078 host: Better status message 2015-05-09 01:16:52 -04:00
Alexander Chemeris
2d83e6caed host: Output a status message when PA power is limited by a configuration parameter. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
9becc6bdf8 host: Implement PA output power limit parameter. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
a5cee8c757 host: Fix power_amp_impl::max_power() implementation. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
5001cb8f95 host: Fix crash and beautift code. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
1337b13d56 host: Move power amp code into a separate class. 2015-05-09 01:16:52 -04:00
Alexander Chemeris
93aaef643d Initial implementation of the power control for UmTRX+PA systems. 2015-05-09 01:16:52 -04:00
Josh Blum
a33b3e92e4 umtrx: support dirty version marker when tree is unclean 2015-05-07 20:54:22 -07:00
Josh Blum
08c05c5f1b umtrx: add fifo_ctrl_window argument to specify window size
This is for debugging issues with the fifo control on some systems which are seeing missing packets.
Running with --args="fifo_ctrl_window=0" will set the window size to nothing, which acks all outgoing packets ASAP.
2015-05-07 19:44:39 -07:00
Alexander Chemeris
000a874189 host: Update copyright for umtrx_cal_tx_dc_offset.cpp. 2015-05-07 20:11:06 -04:00
Alexander Chemeris
7b15bc857b Merge branch 'achemeris/dc_offset_work' 2015-05-07 20:07:08 -04:00
Alexander Chemeris
e14c900821 host: Use amplitude setting for Dc offset calibration.
If we want 0 amplitude, we can set this with the command line parameter.
2015-05-07 20:05:39 -04:00
Alexander Chemeris
271b8a045e host: Better algorithm for Dc offset compensation search. 2015-05-07 19:42:04 -04:00
Alexander Chemeris
30a4557825 host: Improvements in the dc_cal_t abstraction. 2015-05-07 19:11:59 -04:00
Alexander Chemeris
32f82d646b host: Actually test dc_i/q_stop values. 2015-05-07 19:02:11 -04:00
Alexander Chemeris
c3754d5048 host: Better abstraction for dc calibration routines. 2015-05-07 19:01:02 -04:00
Alexander Chemeris
052a817f30 host: More verbose logging about calibration files loading. 2015-05-07 18:00:55 -04:00
Alexander Chemeris
8e92e8ca43 host: Store calibration file in a new way. 2015-05-07 18:00:25 -04:00
Alexander Chemeris
e64d3d5940 host: Update automatic DC calibration utility.
This verion of the DC calibration utility delivers predictable calibration
results, almost as good as manual calibration with a spectrum analyzer.

New features include writing calibration to a file in a format supported
by the UHD, as well as single run with measurement output to stdout.
2015-05-07 17:35:35 -04:00
Alexander Chemeris
158077c504 host: Fix loading of DC offset calibration values from EEPROM. 2015-04-29 22:45:05 -04:00
Josh Blum
84ef0be96c Merge branch 'win_fixes' 2015-04-27 20:56:57 -07:00
Josh Blum
84330517e5 Merge branch 'version_info' 2015-04-27 20:56:41 -07:00
Josh Blum
72062b1466 Merge branch 'dc_offset_debug'
Conflicts:
	host/umtrx_impl.cpp
2015-04-27 20:54:59 -07:00
Josh Blum
453caf23e8 umtrx: updated binaries after bootloader work 2015-04-27 17:21:01 -07:00
Josh Blum
b671b8f8b1 umtrx: use portable sleeps from boost 2015-04-27 17:01:05 -07:00
Josh Blum
b98d250be2 umtrx: switch to portable stdint.h include 2015-04-27 17:00:30 -07:00
Josh Blum
bf366bb7ae umtrx: remove misused class declspec UHD_API 2015-04-27 16:59:09 -07:00
Josh Blum
624f089dcb umtrx: provided nan() function for MSVC 2012 2015-04-27 16:56:35 -07:00
Josh Blum
6af61a7cab umtrx: parse and print version info from git 2015-04-27 15:38:01 -07:00
Alexander Chemeris
99a409192e images: Remove _test_pa image. All its features are already in the master. 2015-04-27 16:25:44 -04:00
Alexander Chemeris
ce92a2f47a host: Fix PLL lock detection - only 0x00 value is correct according to the LMS6002d documentation. 2015-04-27 10:35:53 -04:00
Alexander Chemeris
cbb5815fe0 host: Make non-interface functions of lms6002d_ctrl_impl class protected for better abstraction. 2015-04-27 00:06:37 -04:00
Alexander Chemeris
108f250bf9 host: Fix debug output. 2015-04-27 00:06:09 -04:00
Alexander Chemeris
7e5cfac7af host: Implement lo_locked sensor to show whether LMS PLL is actually locked. 2015-04-27 00:05:04 -04:00
Alexander Chemeris
8b7cb405f1 zpu: Bump fw minor version for the bootloader behavior change. 2015-04-26 23:24:06 -04:00
Alexander Chemeris
6ded41c3fd zpu: Don't confuse users telling USRP2 is loading - it's UmTRX they have! 2015-04-26 23:19:22 -04:00
Alexander Chemeris
fd2493f8fe zpu: Do not attempt to load production ZPU firmware from safe FPGA image.
This is almost always a bad idea and can lead to weird issues if you have produciton
ZPU firmware which is incompatible with your safe FPGA image.
2015-04-26 23:09:47 -04:00
Josh Blum
e2ca1fef44 umtrx: modify boost sleep line for boost compatibility 2015-04-15 00:32:05 -07:00
Josh Blum
0e18fa9544 umtrx: added link with pthreads to build
Some boost versions may require this.
2015-04-15 00:27:05 -07:00
Josh Blum
46f1e0522d Merge branch 'umtrx_icp_fix' into umtrx_update 2015-04-14 16:59:49 -07:00
Alexander Chemeris
f601bc41cf Merge pull request #9 from zabbal/umtrx_update
net_burner: Use 'ip' instead of deprecated 'ifconfig' to enumerate interfaces under Linux.
2015-04-14 10:47:09 +03:00
Josh Blum
595446d536 Merge branch 'fw_githash' into umtrx_update 2015-04-12 21:39:17 -07:00
Josh Blum
1f2cdf5b51 umtrx: checkin new fw with compat bump and hash 2015-04-12 21:38:32 -07:00
Josh Blum
d2acd75eb7 umtrx: bump fw minor for githash addition 2015-04-12 21:32:36 -07:00
Josh Blum
12e613bec2 umtrx: store 4 byte git hash into fw 2015-04-07 21:34:38 -07:00
Josh Blum
efedd23e1f umtrx: spi is fast now, use sleeps for settling times 2015-04-07 17:56:07 -07:00
Alexander Chemeris
e94ffbc3a9 Host: By default set LMS Icp to 0.2mA.
This gives much better results for the GMSK modulation.
2015-04-07 13:38:35 -07:00
Josh Blum
711523fb5a Merge branch 'umtrx_gains' into umtrx_update 2015-04-06 12:32:21 -07:00
Alexander Chemeris
483e31af48 Host: Power down DC comparators in LMS to improve Rx linearity (as per FAQ). 2015-04-06 02:31:21 -07:00
Alexander Chemeris
2d5c88d624 Host: Update the LMS regusters initialization to follow FAQ 1.0r12. 2015-04-06 02:30:35 -07:00
Josh Blum
a837e84e89 umtrx: test both channels with umtrx_test_gains 2015-04-02 13:22:12 -07:00
Josh Blum
6468121e16 umtrx: removed Safety check in favor of clipping 2015-04-02 12:14:41 -07:00
Josh Blum
4d7a11c21a umtrx: fixes for gain distribution
* By listing TX VGA2 first lms6002d_ctrl.cpp, we can rely on UHD to distribute first to VGA2 (as specified by the comments).
* Added clipping to lms6002d.hpp, currently UHD has a rounding bug, and prior to the clipping off-by-1 error could shutoff the gain.
* Return the actual gain setting readback from spi registers for set_rx/tx_gain() routines in lms6002d_ctrl.cpp
* Added a test app in utils called umtrx_test_gains to check the gain ranges and distribution algorithm.
2015-04-02 05:55:26 -07:00
Alexander Chemeris
3a41a46824 Host: Enable separate controls for Tx VGA1 and VGA2 gains. 2015-04-02 04:11:55 -07:00
Josh Blum
0a3dd778d0 umtrx: slow down icap clock, this image resets reliably
Looks like icap clk from the pll is shared with the frontend clock.
So instead I opted to divide the icap clk down inside s6_icap_wb.v.
The image checked in reset reliably after many trials,
which is a good sign that this may be an acceptable fix.
2015-04-01 00:45:00 -07:00
Max
171e9b83da Use ip instead of deprecated ifconfig.
Signed-off-by: Max <max.suraev@fairwaves.co>
2015-03-27 12:21:56 +01:00
Josh Blum
f274d9da1c umtrx: remove multi-threading from stream converters 2015-03-25 10:23:25 -07:00
Josh Blum
ca17c9da65 zpu: move spi mask into spi.c 2015-03-24 01:00:05 -07:00
Josh Blum
35522afed1 zpu: fixed umtrx_init() lms_res typo 2015-03-24 00:28:42 -07:00
Josh Blum
924dcf8d8a umtrx: s2 slave unused, fix comment 2015-03-17 12:05:23 -07:00
Sergey Kostanbaev
db0d59f936 update fpga & zpu images 2015-03-12 21:01:44 +03:00
Sergey Kostanbaev
20178f16fd zpu: add watchdog timer for while( ... ); operations 2015-03-12 20:57:38 +03:00
Sergey Kostanbaev
6129113723 zpu: set UART debug port speed 115200 2015-03-12 20:37:07 +03:00
Sergey Kostanbaev
a37e4c74de fpga: fix DCSYNC clock to 541.66 kHz 2015-03-12 20:35:25 +03:00
Josh Blum
4e3edded07 umtrx: revert merge changes for debugging 2015-03-11 02:14:39 -07:00
Josh Blum
146ab25f66 Merge branch 'fairwaves/umtrx' into umtrx_update
Conflicts:
	host/lms6002d_ctrl.cpp
2015-03-06 17:04:42 -08:00
Sergey Kostanbaev
eb69bb2a78 Set pa_en1 & pa_en2 to "1" by default, add "pa_en1" & "pa_en2" EEPROM variables and UMTRX_PA_EN1 & UMTRX_PA_EN2 enviroment values to override defaults 2015-02-27 10:33:46 +03:00
Josh Blum
fc089a299e umtrx: max timeout for tx async handler flush 2015-02-25 16:37:16 -08:00
Ivan Kluchnikov
0509c7b35a Use CMAKE_INSTALL_PREFIX as dest dir for cpack 2015-02-23 14:32:43 +03:00
Sergey Kostanbaev
f74ff5610d Add --divsw1 and --divsw2 options to umtrx_pa_ctrl 2015-02-12 15:20:18 +03:00
Sergey Kostanbaev
d0e136fb74 Fix UmTRX v2.0 creation with phony sensors 2015-01-21 19:37:04 +03:00
Sergey Kostanbaev
a5b5322b54 Add UMTRX_PA_DCDC_R and UMTRX_PA_LOW enviroment variable to override current EEPROM values for pa_dcdc_r and pa_low 2015-01-13 00:03:03 +03:00
Sergey Kostanbaev
9745ae9bb9 Fix reading pa_dcdc_r from EEPROM 2015-01-12 23:52:48 +03:00
Sergey Kostanbaev
e692e854cb Fix typo 2014-12-26 17:18:10 +03:00
Sergey Kostanbaev
064b7bcf28 Add DCSYNC for DC/DC. Not tested since I don't have an oscilloscope. 2014-12-21 22:35:33 +03:00
Sergey Kostanbaev
13c76a80e7 Add FPGA image with PA control; not tested well!!! 2014-12-21 13:09:14 +03:00
Sergey Kostanbaev
e08b40758a Add PA control logic 2014-12-21 13:07:20 +03:00
Sergey Kostanbaev
90b619f4b9 Move temperature sensors to separate class; add power sensor ADCs and add abitily to autodetect hw revision 2014-11-23 23:20:49 +03:00
Josh Blum
34ac1cc22c umtrx: command line options for cal app 2014-11-05 14:47:35 -08:00
Josh Blum
3eb1fe8b46 umtrx: produce cal files from script 2014-11-05 14:25:25 -08:00
Josh Blum
ef99dbc9cb umtrx: added goodness plot, cleanup 2014-11-05 02:49:36 -08:00
Josh Blum
49921fe4ef umtrx: plot validation dc power using sparse corrections values 2014-11-05 00:21:31 -08:00
Josh Blum
04d08ea43b umtrx: umtrx_cal_tx_dc_offset in python for tweaks 2014-11-04 23:02:48 -08:00
Josh Blum
8a900aab52 Merge branch 'umtrx_update' into dc_offset_debug 2014-10-29 13:42:07 -04:00
Josh Blum
12fe73a6dd umtrx: fix register temperature sensor 2014-10-29 13:24:46 -04:00
Josh Blum
ca98bfda97 umtrx: move dc_offset plugin to bottom 2014-10-29 12:20:49 -04:00
Josh Blum
96829b2e5a umtrx: plugin lms dc offset into fe corrections tree 2014-10-29 12:14:54 -04:00
Josh Blum
418ec3dc67 umtrx: disable lms on shutdown device 2014-10-29 11:03:18 -04:00
Josh Blum
6a8624e36d umtrx: added temp sensors 2014-10-28 20:20:28 -04:00
Josh Blum
fee641af8b umtrx: copy in platform.hpp, which may be deleted from uhd 2014-10-28 15:18:07 -04:00
Josh Blum
197e2f01f9 umtrx: added net reset for fw/fpga boot 2014-10-27 20:21:26 -04:00
Josh Blum
1553c302e9 umtrx: 4DDC leds reversed 2014-10-27 17:32:04 -04:00
Josh Blum
1cac684df3 umtrx: update fpga images for led fix 2014-10-27 16:52:50 -04:00
Josh Blum
1873ed92fa umtrx: default rx ant RX1 2014-10-27 14:55:57 -04:00
Josh Blum
16eaf1182d umtrx: added debian package generator 2014-10-27 14:36:40 -04:00
Josh Blum
f3ad225294 umtrx: uninstall target for cmake build 2014-10-27 10:24:51 -04:00
Josh Blum
195da695ec umtrx: remap LEDS, regular and 4DDC cases -- needs test 2014-10-27 10:19:54 -04:00
Josh Blum
fc309a340f umtrx: deleted build for unused revision 2014-10-27 10:19:07 -04:00
Josh Blum
2b79a428c0 umtrx: updated fw memory map for register remap 2014-10-27 09:50:16 -04:00
Josh Blum
3741147c33 umtrx: move buffering + gateway to rx chain 2014-10-15 17:22:45 -07:00
Josh Blum
1bb4b3f9a3 umtrx: remap dsps, add rx buffering 2014-10-15 13:49:03 -07:00
Josh Blum
f592aa3738 umtrx: setup mutex for stream creation 2014-10-15 00:38:08 -07:00
Josh Blum
6410efde3c umtrx: defaults avoid error on getFreq without setting 2014-10-14 23:34:27 -07:00
Josh Blum
13901ed852 umtrx: fpga build for 4DDC and arbitrary DSP support 2014-10-14 21:51:25 -07:00
Josh Blum
909f35785e umtrx: added ifdef check for UHD API change 2014-10-08 11:56:25 -07:00
Ivan Kluchnikov
c08d216567 Host: Fix Tx VGA, VGA1 and VGA2 gains setting procedure.
We should use separate tree nodes for Tx VGA gain ("gains") and for Tx VGA1, VGA2 gains ("internal_gains").
2014-09-26 17:34:44 +04:00
Josh Blum
bffdc53167 umtrx: fix defaults for set_iq_balance 2014-09-20 16:50:59 -04:00
Josh Blum
2847334b62 umtrx: rx3 was default antenna in previous code 2014-09-20 16:41:45 -04:00
Josh Blum
9a6f088809 umtrx: increase spi divider
was seeing issue with reliability at startup
2014-09-20 16:40:54 -04:00
Alexander Chemeris
4fa97a15a2 Host: Power down DC comparators in LMS to improve Rx linearity (as per FAQ). 2014-04-19 23:39:56 +04:00
Alexander Chemeris
e852d78e19 Host: Update the LMS regusters initialization to follow FAQ 1.0r12. 2014-04-19 23:27:07 +04:00
Alexander Chemeris
53ff2d5bf4 Host: Whitespace fixes. 2014-04-19 22:58:10 +04:00
Alexander Chemeris
10d0a0594a Host: Enable separate controls for Tx VGA1 and VGA2 gains. 2014-04-19 18:12:01 +04:00
Alexander Chemeris
17b33b98a3 Host: By default set LMS Icp to 0.2mA.
This gives much better results for the GMSK modulation.
2014-04-18 20:49:33 +04:00
85 changed files with 5220 additions and 1742 deletions

30
debian/changelog vendored Normal file
View File

@@ -0,0 +1,30 @@
umtrx (1.0.5) trusty; urgency=low
* host: disable umtrx_fifo_ctrl cache of spi config
* host: Fix getters in umtrx_property_tree.py.
* debian: added firmware to package and umtrx_firmware script to handle it
* fpga: created axi stream controled spi core
* fpga: use axi stream spi core (still single dest)
* fpga: connect both spi settings drivers
* fpga: simplify spi setting regs with generate loop
* fpga: updated 4x ddc image for spi work
-- Kirill Zakharenko <earwin@gmail.com> Mon, 23 Nov 2015 15:51:56 +0300
umtrx (1.0.4) unstable; urgency=low
* Do not add 'g' to a git id when creating a version string.
* Proper debianization.
* Add ability to set diversity switches position from UHD args.
* By default route each Rx channel to it's own antenna.
* JSON API to question/control property tree of a running UHD app. Useful for querying sensors and for debugging purposes.
* Python utility to query VSWR from a running UHD app in real time using JSON API.
* Fix DC and IQ calibration utilities.
-- Alexander Chemeris <Alexander.Chemeris@fairwaves.co> Tue, 21 Jul 2015 18:51:56 -0400
umtrx (1.0.3) unstable; urgency=low
* Created debian control files for 1.0.3 release of umtrx
-- Josh Blum <josh@pothosware.com> Sat, 20 Jun 2015 16:31:24 -0700

1
debian/compat vendored Normal file
View File

@@ -0,0 +1 @@
9

33
debian/control vendored Normal file
View File

@@ -0,0 +1,33 @@
Source: umtrx
Section: libs
Priority: optional
Maintainer: Josh Blum <josh@pothosware.com>
Build-Depends:
debhelper (>= 9.0.0),
cmake (>= 2.8),
libboost-all-dev,
libuhd-dev (>= 3.7)
Standards-Version: 3.9.5
Homepage: http://umtrx.org/
Vcs-Git: https://github.com/fairwaves/UHD-Fairwaves.git
Vcs-Browser: https://github.com/fairwaves/UHD-Fairwaves
Package: umtrx
Section: libs
Architecture: any
Pre-Depends: multiarch-support, ${misc:Pre-Depends}
Depends: ${shlibs:Depends}, ${misc:Depends}, uhd-umtrx
Conflicts: umtrx-uhd
Replaces: umtrx-uhd
Recommends: python
Description: Fairwaves UmTRX driver - runtime utilities
The industrial grade dual-channel wide-band SDR transceiver.
Package: uhd-umtrx
Section: libs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Conflicts: umtrx-uhd
Replaces: umtrx-uhd
Description: Fairwaves UmTRX driver - UHD plugin module
The industrial grade dual-channel wide-band SDR transceiver.

12
debian/copyright vendored Normal file
View File

@@ -0,0 +1,12 @@
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: umtrx
Source: https://github.com/fairwaves/UHD-Fairwaves
Files: *
Copyright:
Copyright 2012-2015 Fairwaves LLC
Copyright 2010-2012 Ettus Research LLC
License: GPL-3
On Debian systems, the full text of the GNU General Public
License version 3 can be found in the file
`/usr/share/common-licenses/GPL-3'.

1
debian/docs vendored Normal file
View File

@@ -0,0 +1 @@
README

18
debian/rules vendored Executable file
View File

@@ -0,0 +1,18 @@
#!/usr/bin/make -f
# -*- makefile -*-
DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH)
export DEB_HOST_MULTIARCH
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# This has to be exported to make some magic below work.
export DH_OPTIONS
%:
dh $@ --buildsystem=cmake --parallel --sourcedirectory=host
override_dh_auto_configure:
dh_auto_configure -- -DLIB_SUFFIX="/$(DEB_HOST_MULTIARCH)"

1
debian/source/format vendored Normal file
View File

@@ -0,0 +1 @@
3.0 (native)

1
debian/uhd-umtrx.install vendored Normal file
View File

@@ -0,0 +1 @@
usr/lib/*/uhd/modules/

2
debian/umtrx.install vendored Normal file
View File

@@ -0,0 +1,2 @@
usr/bin
images/u2plus_umtrx_v2.bin images/umtrx_txrx_uhd.bin usr/share/umtrx/firmware

View File

@@ -58,5 +58,6 @@ gpio_atr.v \
user_settings.v \
settings_fifo_ctrl.v \
simple_spi_core.v \
axis_spi_core.v \
simple_i2c_core.v \
))

View File

@@ -0,0 +1,243 @@
//
// Copyright 2012 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>.
//
// Simple SPI core, the simplest, yet complete spi core I can think of
// Settings register controlled.
// 2 settings regs, control and data
// 1 32-bit readback and status signal
// Settings reg map:
//
// BASE+0 divider setting
// bits [15:0] spi clock divider
//
// BASE+1 configuration input
// bits [23:0] slave select, bit0 = slave0 enabled
// bits [29:24] num bits (1 through 32)
// bit [30] data input edge = in data bit latched on rising edge of clock
// bit [31] data output edge = out data bit latched on rising edge of clock
//
// BASE+2 input data
// Writing this register begins a spi transaction.
// Bits are latched out from bit 0.
// Therefore, load this register in reverse.
//
// Readback
// Bits are latched into bit 0.
// Therefore, data will be in-order.
module axis_spi_core
#(
//set to 1 for ILA
parameter DEBUG = 0,
//tdest width for number of core users
parameter DESTW = 1,
//width of serial enables (up to 24 is possible)
parameter WIDTH = 8,
//idle state of the spi clock
parameter CLK_IDLE = 0,
//idle state of the serial enables
parameter SEN_IDLE = 24'hffffff
)
(
//clock and synchronous reset
input clock, input reset,
//configuration settings bus
input [DESTW-1:0] CONFIG_tdest,
input [79:0] CONFIG_tdata,
input CONFIG_tvalid,
output CONFIG_tready,
//32-bit data readback
output reg [DESTW-1:0] READBACK_tdest,
output [31:0] READBACK_tdata,
output READBACK_tvalid,
input READBACK_tready,
//spi interface, slave selects, clock, data in, data out
output [WIDTH-1:0] sen,
output sclk,
output mosi,
input miso
);
//state
localparam WAIT_CONFIG = 0;
localparam PRE_IDLE = 1;
localparam CLK_REG = 2;
localparam CLK_INV = 3;
localparam POST_IDLE = 4;
localparam IDLE_SEN = 5;
localparam WAIT_READBACK = 6;
reg [2:0] state;
//configuration settings
reg [15:0] sclk_divider;
reg [23:0] slave_select;
reg [5:0] num_bits;
reg datain_edge, dataout_edge;
//output ready/valid signals
assign CONFIG_tready = (state == WAIT_CONFIG);
assign READBACK_tvalid = (state == WAIT_READBACK);
//serial clock either idles or is in one of two clock states
reg sclk_reg;
assign sclk = sclk_reg;
//serial enables either idle or enabled based on state
wire sen_is_idle = (state == WAIT_CONFIG) || (state == IDLE_SEN);
wire [23:0] sen24 = (sen_is_idle)? SEN_IDLE : (SEN_IDLE ^ slave_select);
reg [WIDTH-1:0] sen_reg;
always @(posedge clock) sen_reg <= sen24[WIDTH-1:0];
assign sen = sen_reg;
//data output shift register
reg [31:0] dataout_reg;
wire [31:0] dataout_next = {dataout_reg[30:0], 1'b0};
assign mosi = dataout_reg[31];
//data input shift register
reg [31:0] datain_reg;
wire [31:0] datain_next = {datain_reg[30:0], miso};
assign READBACK_tdata = datain_reg;
//counter for spi clock
reg [15:0] sclk_counter;
wire sclk_counter_done = (sclk_counter == sclk_divider);
wire [15:0] sclk_counter_next = (sclk_counter_done)? 0 : sclk_counter + 1;
//counter for latching bits miso/mosi
reg [6:0] bit_counter;
wire [6:0] bit_counter_next = bit_counter + 1;
wire bit_counter_done = (bit_counter_next == num_bits);
always @(posedge clock) begin
if (reset) begin
state <= WAIT_CONFIG;
sclk_reg <= CLK_IDLE;
end
else begin
case (state)
WAIT_CONFIG: begin
if (CONFIG_tvalid && CONFIG_tready) begin
state <= PRE_IDLE;
end
{sclk_divider, dataout_edge, datain_edge, num_bits, slave_select, dataout_reg} <= CONFIG_tdata;
READBACK_tdest <= CONFIG_tdest;
sclk_counter <= 0;
bit_counter <= 0;
sclk_reg <= CLK_IDLE;
end
PRE_IDLE: begin
if (sclk_counter_done) state <= CLK_REG;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
CLK_REG: begin
if (sclk_counter_done) begin
state <= CLK_INV;
if (datain_edge != CLK_IDLE) datain_reg <= datain_next;
if (dataout_edge != CLK_IDLE && bit_counter != 0) dataout_reg <= dataout_next;
sclk_reg <= ~CLK_IDLE; //transition to rising when CLK_IDLE == 0
end
sclk_counter <= sclk_counter_next;
end
CLK_INV: begin
if (sclk_counter_done) begin
state <= (bit_counter_done)? POST_IDLE : CLK_REG;
bit_counter <= bit_counter_next;
if (datain_edge == CLK_IDLE) datain_reg <= datain_next;
if (dataout_edge == CLK_IDLE && ~bit_counter_done) dataout_reg <= dataout_next;
sclk_reg <= CLK_IDLE; //transition to falling when CLK_IDLE == 0
end
sclk_counter <= sclk_counter_next;
end
POST_IDLE: begin
if (sclk_counter_done) state <= IDLE_SEN;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
IDLE_SEN: begin
if (sclk_counter_done) state <= WAIT_READBACK;
sclk_counter <= sclk_counter_next;
sclk_reg <= CLK_IDLE;
end
WAIT_READBACK: begin
if (READBACK_tready && READBACK_tvalid) begin
state <= WAIT_CONFIG;
end
end
default: state <= WAIT_CONFIG;
endcase //state
end
end
/*******************************************************************
* Debug
******************************************************************/
generate
if (DEBUG == 1) begin
wire [35:0] CONTROL0;
chipscope_icon chipscope_icon
(
.CONTROL0(CONTROL0)
);
wire [255:0] DATA;
wire [7:0] TRIG0;
chipscope_ila chipscope_ila
(
.CONTROL(CONTROL0),
.CLK(clock),
.DATA(DATA),
.TRIG0(TRIG0)
);
assign TRIG0 =
{
4'b0,
CONFIG_tvalid, CONFIG_tready,
READBACK_tvalid, READBACK_tready
};
assign DATA[79:0] = CONFIG_tdata;
assign DATA[111:80] = READBACK_tdata;
assign DATA[112] = CONFIG_tvalid;
assign DATA[113] = CONFIG_tready;
assign DATA[114] = READBACK_tvalid;
assign DATA[115] = READBACK_tready;
assign DATA[127:120] = state;
end
endgenerate
endmodule //axis_spi_core

View File

@@ -23,6 +23,8 @@ module s6_icap_wb
input cyc_i, input stb_i, input we_i, output reg ack_o,
input [31:0] dat_i, output reg[31:0] dat_o);//, output [31:0] debug_out);
reg slow_clk_icap;
always @(posedge clk_icap) slow_clk_icap <= ~slow_clk_icap;
wire BUSY, CE, WRITE;
wire[31:0] s1_dat_i;
@@ -36,7 +38,7 @@ module s6_icap_wb
fifo_xlnx_16x40_2clk icap_fifo
(.rst(reset),
.wr_clk(clk), .din(dat_i), .wr_en(we_i & stb_i & ~ack_o & ~full), .full(full),
.rd_clk(clk_icap), .dout(s1_dat_i), .rd_en(~empty), .empty(empty));
.rd_clk(slow_clk_icap), .dout(s1_dat_i), .rd_en(~empty), .empty(empty));
assign WRITE = empty;
assign CE = empty;
@@ -45,7 +47,7 @@ module s6_icap_wb
(.BUSY(BUSY), // Busy output
.O(s1_dat_o[15:0]), // 16-bit data output
.CE(CE), // Clock enable input
.CLK(clk_icap), // Clock input
.CLK(slow_clk_icap), // Clock input
.I(s1_dat_i[15:0]), // 16-bit data input
.WRITE(WRITE) // Write input
);

View File

@@ -124,20 +124,13 @@ module simple_gemac_wrapper
// TX FIFO Chain
wire tx_ll_sof, tx_ll_eof, tx_ll_src_rdy, tx_ll_dst_rdy;
wire [7:0] tx_ll_data;
wire [35:0] tx_f36_data_int0, tx_f36_data_int1, tx_f36_data_int2;
wire tx_f36_src_rdy_int0, tx_f36_dst_rdy_int0, tx_f36_src_rdy_int1, tx_f36_dst_rdy_int1, tx_f36_src_rdy_int2, tx_f36_dst_rdy_int2;
wire [35:0] tx_f36_data_int1, tx_f36_data_int2;
wire tx_f36_src_rdy_int1, tx_f36_dst_rdy_int1, tx_f36_src_rdy_int2, tx_f36_dst_rdy_int2;
axi_fifo_2clk #(.WIDTH(36), .SIZE(0)) tx_2clk_fifo
(.i_aclk(sys_clk), .i_tdata(tx_f36_data), .i_tvalid(tx_f36_src_rdy), .i_tready(tx_f36_dst_rdy),
.o_aclk(tx_clk), .o_tdata(tx_f36_data_int0), .o_tvalid(tx_f36_src_rdy_int0), .o_tready(tx_f36_dst_rdy_int0),
.reset(reset));
axi_packet_gate #(.WIDTH(36), .SIZE(TXFIFOSIZE)) fully_buffer_outgoing_eth_pkts
(
.clk(tx_clk), .reset(reset), .clear(0),
.i_tdata(tx_f36_data_int0), .i_tvalid(tx_f36_src_rdy_int0), .i_tready(tx_f36_dst_rdy_int0), .i_tlast(tx_f36_data_int0[33]), .i_terror(0),
.o_tdata(tx_f36_data_int1), .o_tvalid(tx_f36_src_rdy_int1), .o_tready(tx_f36_dst_rdy_int2), .o_tlast()
);
fifo_2clock_cascade #(.WIDTH(36), .SIZE(TXFIFOSIZE)) tx_2clk_fifo
(.wclk(sys_clk), .datain(tx_f36_data), .src_rdy_i(tx_f36_src_rdy), .dst_rdy_o(tx_f36_dst_rdy), .space(),
.rclk(tx_clk), .dataout(tx_f36_data_int1), .src_rdy_o(tx_f36_src_rdy_int1), .dst_rdy_i(tx_f36_dst_rdy_int1), .occupied(),
.arst(reset));
ethtx_realign ethtx_realign
(.clk(tx_clk), .reset(tx_reset), .clear(clear),

View File

@@ -81,7 +81,7 @@ SYNTHESIZE_PROPERTIES = \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
"Use Synchronous Set" Auto \
"Verilog Macros" "LVDS=1 | NO_SERDES=1 | UMTRX=1 | LMS602D_FRONTEND=1 | SPARTAN6=1 | LMS_DSP=1"
"Verilog Macros" "LVDS=1 | NO_SERDES=1 | UMTRX=1 | LMS602D_FRONTEND=1 | SPARTAN6=1 | LMS_DSP=1 | NUMDDC=2 | NUMDUC=2"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"

View File

@@ -5,8 +5,8 @@
##################################################
# Project Setup
##################################################
TOP_MODULE = u2plus_umtrx
BUILD_DIR = $(abspath build$(ISE)_UmTRX)
TOP_MODULE = u2plus_umtrx_v2
BUILD_DIR = $(abspath build$(ISE)_UmTRXv2_4DDC)
##################################################
# Include other makefiles
@@ -48,8 +48,20 @@ simulator "ISE Simulator (VHDL/Verilog)" \
TOP_SRCS = \
capture_ddrlvds.v \
umtrx_core.v \
u2plus_umtrx.v \
u2plus_umtrx.ucf
umtrx_tx_chain.v \
umtrx_rx_chain.v \
umtrx_router.v \
umtrx_packet_dispatcher.v \
coregen/chipscope_icon.v \
coregen/chipscope_icon.xco \
coregen/chipscope_ila.v \
coregen/chipscope_ila.xco \
coregen/fifo_short_2clk.v \
coregen/fifo_short_2clk.xco \
coregen/fifo_4k_2clk.v \
coregen/fifo_4k_2clk.xco \
u2plus_umtrx_v2.v \
u2plus_umtrx_v2.ucf
SOURCES = $(abspath $(TOP_SRCS)) $(FIFO_SRCS) \
$(CONTROL_LIB_SRCS) $(SDR_LIB_SRCS) $(SERDES_SRCS) \
@@ -69,7 +81,7 @@ SYNTHESIZE_PROPERTIES = \
"Use Clock Enable" Auto \
"Use Synchronous Reset" Auto \
"Use Synchronous Set" Auto \
"Verilog Macros" "LVDS=1 | NO_SERDES=1 | UMTRX=1 | LMS602D_FRONTEND=1 | SPARTAN6=1 | LMS_DSP=1"
"Verilog Macros" "LVDS=1 | NO_SERDES=1 | UMTRX=1 | LMS602D_FRONTEND=1 | SPARTAN6=1 | LMS_DSP=1 | NUMDDC=4 | NUMDUC=0"
TRANSLATE_PROPERTIES = \
"Macro Search Path" "$(shell pwd)/../../coregen/"

View File

@@ -1,5 +1,5 @@
defparam bootram.RAM0.INIT_00=256'h00000000_00000000_00000000_ddd80400_3a0b0b80_80eb940c_82700b0b_0b0b0b0b;
defparam bootram.RAM0.INIT_01=256'h00000000_00000000_00000000_800c0400_880c840c_80dea22d_88080b0b_80088408;
defparam bootram.RAM0.INIT_00=256'h00000000_00000000_00000000_dfcb0400_3a0b0b80_80eeb40c_82700b0b_0b0b0b0b;
defparam bootram.RAM0.INIT_01=256'h00000000_00000000_00000000_800c0400_880c840c_80e0952d_88080b0b_80088408;
defparam bootram.RAM0.INIT_02=256'h00000000_00000000_04000000_ffff0652_832b2a83_81058205_72830609_71fd0608;
defparam bootram.RAM0.INIT_03=256'h83a70400_0b0b0b0b_7383ffff_2b2b0906_05820583_83060981_83ffff73_71fd0608;
defparam bootram.RAM0.INIT_04=256'h00000000_00000000_53510400_070a8106_73097306_09060906_72057373_72098105;
@@ -18,431 +18,431 @@ defparam bootram.RAM0.INIT_10=256'h00000000_00000000_00000000_00000000_00000000_
defparam bootram.RAM0.INIT_11=256'h00000000_00000000_00000000_00000000_00000000_04000000_05055351_72720981;
defparam bootram.RAM0.INIT_12=256'h00000000_00000000_00000000_00000000_00000000_07535104_73730906_72097206;
defparam bootram.RAM0.INIT_13=256'h00000000_00000000_04000000_81ff0652_1010102a_81058305_72830609_71fc0608;
defparam bootram.RAM0.INIT_14=256'h00000000_00000000_88aa0400_060b0b0b_10100508_80738306_0b0b80eb_71fc0608;
defparam bootram.RAM0.INIT_15=256'h00000000_0c510400_0c840c80_80085688_f92d5050_0b0b80d4_88087575_80088408;
defparam bootram.RAM0.INIT_16=256'h00000000_0c510400_0c840c80_80085688_ab2d5050_0b0b80d6_88087575_80088408;
defparam bootram.RAM0.INIT_14=256'h00000000_00000000_88aa0400_060b0b0b_10100508_a0738306_0b0b80ee_71fc0608;
defparam bootram.RAM0.INIT_15=256'h00000000_0c510400_0c840c80_80085688_ec2d5050_0b0b80d6_88087575_80088408;
defparam bootram.RAM0.INIT_16=256'h00000000_0c510400_0c840c80_80085688_9e2d5050_0b0b80d8_88087575_80088408;
defparam bootram.RAM0.INIT_17=256'h04000000_07515151_05ff0506_73097274_70547106_8106ff05_0509060a_72097081;
defparam bootram.RAM0.INIT_18=256'h51040000_06075151_7405ff05_06730972_05705471_098106ff_0509060a_72097081;
defparam bootram.RAM0.INIT_19=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_05ff0504;
defparam bootram.RAM0.INIT_1A=256'h00000000_00000000_00000000_00000000_00000000_51040000_80eb900c_810b0b0b;
defparam bootram.RAM0.INIT_1A=256'h00000000_00000000_00000000_00000000_00000000_51040000_80eeb00c_810b0b0b;
defparam bootram.RAM0.INIT_1B=256'h00000000_00000000_00000000_00000000_00000000_00000000_04000000_71810552;
defparam bootram.RAM0.INIT_1C=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM0.INIT_1D=256'h00000000_00000000_00000000_00000000_00000000_04000000_10100552_02840572;
defparam bootram.RAM0.INIT_1E=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM0.INIT_1F=256'h00000000_00000000_00000000_00000000_00000000_020d0400_05715351_717105ff;
defparam bootram.RAM0.INIT_20=256'h10101010_10101010_10101010_10101010_10101010_10101010_d69f3f04_82813f80;
defparam bootram.RAM0.INIT_20=256'h10101010_10101010_10101010_10101010_10101010_10101010_d8923f04_82813f80;
defparam bootram.RAM0.INIT_21=256'hfc060c51_102b0772_83051010_06098105_ff067383_51047381_10101053_10101010;
defparam bootram.RAM0.INIT_22=256'h51535104_72ed3851_0a100a53_71105272_09720605_8106ff05_72728072_51043c04;
defparam bootram.RAM0.INIT_23=256'h800b80eb_f00c82a0_0b0b80eb_8380800b_822ebd38_80eb9408_802ea438_80eb9008;
defparam bootram.RAM0.INIT_24=256'h0b80ebf4_80808280_ebf00cf8_0b0b0b80_808080a4_f80c04f8_800b80eb_f40c8290;
defparam bootram.RAM0.INIT_25=256'h940b80eb_80c0a880_80ebf00c_8c0b0b0b_80c0a880_ebf80c04_84800b80_0cf88080;
defparam bootram.RAM0.INIT_26=256'h70085252_80eb9c08_5170a738_80ebfc33_04ff3d0d_80ebf80c_80ded40b_f40c0b0b;
defparam bootram.RAM0.INIT_27=256'hfc34833d_810b80eb_5270ee38_08700852_2d80eb9c_eb9c0c70_38841280_70802e94;
defparam bootram.RAM0.INIT_28=256'h38823d0d_09810685_800b802e_0b0b0b0b_802e8e38_80ebec08_3d0d0b0b_0d040480;
defparam bootram.RAM0.INIT_29=256'h0b81e088_80ce3881_0d685a79_0404ee3d_3f823d0d_0b0bf5d4_ebec510b_040b0b80;
defparam bootram.RAM0.INIT_2A=256'h7981e188_81e1800c_0c890a0b_7981e598_81e5940c_e48c0c79_880c7981_0c7981e4;
defparam bootram.RAM0.INIT_2B=256'h81e2cc0c_0c890a0b_7981e290_81e2880c_0c890a0b_7981e2c8_81e2c00c_0c890a0b;
defparam bootram.RAM0.INIT_2C=256'ha8953f89_0553425a_54973d84_08933d70_8238881a_8b6a2781_0c818839_7981e2d4;
defparam bootram.RAM0.INIT_2D=256'h7b34811c_5b5b7933_7b1d7f1d_3d415e5c_0b883d99_5b5f4080_0284057b_923f8008;
defparam bootram.RAM0.INIT_23=256'h800b80ef_900c82a0_0b0b80ef_8380800b_822ebd38_80eeb408_802ea438_80eeb008;
defparam bootram.RAM0.INIT_24=256'h0b80ef94_80808280_ef900cf8_0b0b0b80_808080a4_980c04f8_800b80ef_940c8290;
defparam bootram.RAM0.INIT_25=256'h940b80ef_80c0a880_80ef900c_8c0b0b0b_80c0a880_ef980c04_84800b80_0cf88080;
defparam bootram.RAM0.INIT_26=256'h70085252_80eebc08_5170a738_80ef9c33_04ff3d0d_80ef980c_80e0c40b_940c0b0b;
defparam bootram.RAM0.INIT_27=256'h9c34833d_810b80ef_5270ee38_08700852_2d80eebc_eebc0c70_38841280_70802e94;
defparam bootram.RAM0.INIT_28=256'h38823d0d_09810685_800b802e_0b0b0b0b_802e8e38_80ef8c08_3d0d0b0b_0d040480;
defparam bootram.RAM0.INIT_29=256'h0b81e088_80ce3881_0d685a79_0404ee3d_3f823d0d_0b0bf5d4_ef8c510b_040b0b80;
defparam bootram.RAM0.INIT_2A=256'h7981e180_81e0f80c_0c890a0b_7981e598_81e5940c_e48c0c79_880c7981_0c7981e4;
defparam bootram.RAM0.INIT_2B=256'h81e2e80c_0c890a0b_7981e2a0_81e2980c_0c890a0b_7981e1d0_81e1c80c_0c890a0b;
defparam bootram.RAM0.INIT_2C=256'ha9b43f89_0553425a_54973d84_08933d70_8238881a_8b6a2781_0c818839_7981e2f0;
defparam bootram.RAM0.INIT_2D=256'h7b34811c_5b5b7933_7b1d7f1d_3d415e5c_0b883d99_5b5f4080_0284057b_a83f8008;
defparam bootram.RAM0.INIT_2E=256'h7c26ed38_811c5c88_79337b34_7d055b5b_7b1d963d_901f5e5c_ef38800b_5c887c26;
defparam bootram.RAM0.INIT_2F=256'h611d5b5b_805c7b1e_7c26ef38_811c5c86_79337b34_601d5b5b_5e5c7b1d_800b881f;
defparam bootram.RAM0.INIT_30=256'h5a588379_84120859_3d0d686a_3d0d04ee_998b3f94_7c26ef38_811c5c86_79337b34;
defparam bootram.RAM0.INIT_31=256'hf55778a3_94833f80_80ded851_75538c52_802e8c38_2e943875_0856758c_279c3877;
defparam bootram.RAM0.INIT_32=256'h75922682_ff981756_8818085d_8c5ba05c_f03fa057_dfa85193_53a45280_268e3878;
defparam bootram.RAM0.INIT_33=256'h5c8c1808_983980da_08085e82_88a13f80_0480d55c_05567508_2980e198_ae387584;
defparam bootram.RAM0.INIT_34=256'h39921822_065f81f5_0883ffff_aab73f80_38828239_75822e91_812e8938_5e7d5675;
defparam bootram.RAM0.INIT_35=256'h1808538c_18335490_57765596_2e833884_577580f2_18335682_81eb3995_51aa853f;
defparam bootram.RAM0.INIT_36=256'h81b3398d_5f80d35c_fe3f8008_57765194_2e833881_57577577_0b971933_18085280;
defparam bootram.RAM0.INIT_37=256'h19538c19_3370548e_94398d18_3f80c95c_52568bb4_538c1933_953dea05_18337054;
defparam bootram.RAM0.INIT_38=256'h80c23875_56758526_1833ff05_80ff3994_05b50534_5c750284_c13f80c8_3352568c;
defparam bootram.RAM0.INIT_39=256'h0ca23992_90180877_225fa939_5fae3976_08047608_08585675_e4058c19_842980e1;
defparam bootram.RAM0.INIT_3A=256'h08710c56_80059019_842980ec_568e3976_05700840_2980ec80_9b397684_18227723;
defparam bootram.RAM0.INIT_30=256'h5a588379_84120859_3d0d686a_3d0d04ee_9aaa3f94_7c26ef38_811c5c86_79337b34;
defparam bootram.RAM0.INIT_31=256'hf55778a3_95983f80_80e0c851_75538c52_802e8c38_2e943875_0856758c_279c3877;
defparam bootram.RAM0.INIT_32=256'h75922682_ff981756_8818085d_8c5ba05c_853fa057_e1985195_53a45280_268e3878;
defparam bootram.RAM0.INIT_33=256'h5c8c1808_983980da_08085e82_88b73f80_0480d55c_05567508_2980e388_ae387584;
defparam bootram.RAM0.INIT_34=256'h39921822_065f81f5_0883ffff_abd63f80_38828239_75822e91_812e8938_5e7d5675;
defparam bootram.RAM0.INIT_35=256'h1808538c_18335490_57765596_2e833884_577580f2_18335682_81eb3995_51aba43f;
defparam bootram.RAM0.INIT_36=256'h81b3398d_5f80d35c_933f8008_57765196_2e833881_57577577_0b971933_18085280;
defparam bootram.RAM0.INIT_37=256'h19538c19_3370548e_94398d18_3f80c95c_52568bca_538c1933_953dea05_18337054;
defparam bootram.RAM0.INIT_38=256'h80c23875_56758526_1833ff05_80ff3994_05b50534_5c750284_983f80c8_3352568d;
defparam bootram.RAM0.INIT_39=256'h0ca23992_90180877_225fa939_5fae3976_08047608_08585675_d4058c19_842980e3;
defparam bootram.RAM0.INIT_3A=256'h08710c56_a0059019_842980ef_568e3976_05700840_2980efa0_9b397684_18227723;
defparam bootram.RAM0.INIT_3B=256'h3d790557_58771996_0b833d5a_dc055480_0855943d_cc5c8c18_39785e80_80d25cad;
defparam bootram.RAM0.INIT_3C=256'h5a587719_800b833d_3ddc0554_5ca45594_38a439a0_887826ed_34811858_57753377;
defparam bootram.RAM0.INIT_3D=256'h04fd3d0d_3f943d0d_805199fa_ed388380_58887826_77348118_57577533_963d7905;
defparam bootram.RAM0.INIT_3E=256'h52725186_80c05372_e82e8438_a0537387_802e9838_90f33f73_dff45254_75705380;
defparam bootram.RAM0.INIT_3F=256'h0d81fa3f_0d04fa3d_9a3f853d_52735186_a23f80c0_52735186_3f9039a0_ae3f9a87;
defparam bootram.RAM1.INIT_00=256'hec9c0caa_3f800b80_d05190a5_8c5280e0_5190ae3f_5280e0b0_87933f89_80e09451;
defparam bootram.RAM1.INIT_01=256'h518ef73f_da3f8008_86aa3f84_518edd3f_863f8008_82d63f84_3f84dd3f_ca3f83f4;
defparam bootram.RAM1.INIT_02=256'h08518cf0_80845280_84bd3f83_5193993f_73528008_5483e83f_ce3f8008_869e3f84;
defparam bootram.RAM1.INIT_03=256'h83808251_80c68252_5193d53f_52838084_df3f8ab2_80805193_8c935283_3f93a33f;
defparam bootram.RAM1.INIT_04=256'heb3f8008_fc05518c_bf3f883d_ab9a3fad_3f8fbd51_fb3f8cdb_809251a3_93ca3f83;
defparam bootram.RAM1.INIT_05=256'h80e0f452_ad388453_2e098106_7382fdee_05225555_7680088e_2e80c938_56800880;
defparam bootram.RAM1.INIT_06=256'h85823f73_548ddb3f_94167052_518eea3f_3880e0fc_3f80089a_5180cac9_80089005;
defparam bootram.RAM1.INIT_07=256'h84cb3f90_39fe3d0d_ea3fff9e_a3d03f8a_3f8bf83f_75519984_88397452_5183fd3f;
defparam bootram.RAM1.INIT_08=256'h89e13f84_3f82ac51_805183f7_9b3f9f52_52805184_86f23f9f_3f8aa23f_b23f85f6;
defparam bootram.RAM1.INIT_09=256'h5183d03f_3f905290_ac5189c7_83dd3f82_88528851_5189d43f_ea3f82ac_52845183;
defparam bootram.RAM1.INIT_0A=256'h80e45189_5183b43f_3f9f529c_e45189ab_83c13f80_9f528051_ba3f8253_82ac5189;
defparam bootram.RAM1.INIT_0B=256'h843d0d04_810b800c_5183983f_3f9f5281_9e5183bc_df389f52_53728025_9e3fff13;
defparam bootram.RAM1.INIT_0C=256'h86559054_3f750856_e45188e7_80760c80_5188f03f_585680e4_e0807008_fa3d0d81;
defparam bootram.RAM1.INIT_0D=256'h5281518f_88805382_86559054_518d8a3f_5280e1fc_aa3f8008_5281518f_88805381;
defparam bootram.RAM1.INIT_0E=256'h57578170_3d0d787a_3d0d04fa_0b800c88_a5d83f81_518cf23f_5280e298_923f8008;
defparam bootram.RAM1.INIT_0F=256'h2e833880_527181ff_80547133_802e8338_33525270_38721770_7276279e_56548053;
defparam bootram.RAM1.INIT_10=256'h0b80eca4_fe3d0d81_883d0d04_5170800c_2e833881_07517080_df397474_55811353;
defparam bootram.RAM1.INIT_11=256'hbd38810b_a4335574_3d0d80ec_3d0d04f9_c5bb3f84_eba45180_e2b85280_34865380;
defparam bootram.RAM1.INIT_12=256'h9d388652_5574802e_0881ff06_b4c03f80_5280d051_70545682_8654873d_80eca434;
defparam bootram.RAM1.INIT_13=256'ha40b800c_f03f80eb_a45180c4_755280eb_8d388653_ff065574_3f800881_7551fef3;
defparam bootram.RAM1.INIT_14=256'hb938810b_a0335574_3d0d80ec_a00c04fb_b40880eb_a03480e2_810b80ec_893d0d04;
defparam bootram.RAM1.INIT_15=256'h99388452_5574802e_0881ff06_b3e03f80_5280d051_fc05538c_8454873d_80eca034;
defparam bootram.RAM1.INIT_16=256'h873d0d04_a00b800c_a00c80eb_387580eb_06557486_800881ff_51fe903f_873dfc05;
defparam bootram.RAM1.INIT_17=256'h750880eb_802e8d38_ff065574_3f800881_d051b2a6_538c5280_56845475_fb3d0d77;
defparam bootram.RAM1.INIT_18=256'h06077080_80eca808_73750671_3d0d7309_3d0d0480_74800c87_80eca034_a00c810b;
defparam bootram.RAM1.INIT_19=256'h80ecac0c_08060770_7180ecac_09737506_803d0d73_823d0d04_e08c0c51_eca80c81;
defparam bootram.RAM1.INIT_1A=256'h843d0d04_3f72800c_805181c7_74705353_04fe3d0d_0481af3f_51823d0d_81e0980c;
defparam bootram.RAM1.INIT_1B=256'h5472802e_81ff0654_56743370_0d777956_0d04fb3d_b63f833d_52805181_ff3d0d8a;
defparam bootram.RAM1.INIT_1C=256'h73528051_04ff3d0d_0c873d0d_39800b80_81913fe5_53765255_7481ff06_90388115;
defparam bootram.RAM1.INIT_1D=256'h0c843d0d_3f800b80_725180e7_bd3f8a52_705253ff_0d747653_0d04fe3d_cd3f833d;
defparam bootram.RAM1.INIT_1E=256'h823d0d04_ebac1234_8f053380_0d725102_0d04803d_dd3f833d_73528051_04ff3d0d;
defparam bootram.RAM1.INIT_1F=256'h0d805380_0d04fe3d_5351833d_7022720c_80e2c005_80057510_a0298290_ff3d0d73;
defparam bootram.RAM1.INIT_20=256'h3d0d04fc_25e53884_13538273_51ce3f81_13335272_3f80ebb0_527251c6_ebac1333;
defparam bootram.RAM1.INIT_21=256'h8d527351_81068738_72812e09_ac143353_953880eb_2e098106_5654748a_3d0d7678;
defparam bootram.RAM1.INIT_22=256'h3d0d74a0_3d0d04fe_8c150c86_2ef83874_08537280_05548414_29829080_de3f73a0;
defparam bootram.RAM1.INIT_23=256'hff3d0d80_843d0d04_5372800c_38901208_70802e85_5252ff53_05881108_29829080;
defparam bootram.RAM1.INIT_24=256'h81a8880c_5181800b_81a8840c_0c70882a_0681a880_227081ff_0c80ebb8_0b81a888;
defparam bootram.RAM1.INIT_25=256'h90087086_863881a8_71802e81_53548151_97053355_78028805_fd3d0d76_833d0d04;
defparam bootram.RAM1.INIT_26=256'h0870812a_0c81a890_0b81a890_8c0c8190_810781a8_f1387210_51515170_2a708106;
defparam bootram.RAM1.INIT_27=256'h2eba3871_51517080_81325151_70810670_0870872a_3881a890_515170f1_70810651;
defparam bootram.RAM1.INIT_28=256'h06515151_812a7081_a8900870_a8900c81_a0517081_812e8338_80e85171_802eb138;
defparam bootram.RAM1.INIT_29=256'ha8900c70_80c00b81_81518839_1252cc39_055634ff_70747081_a88c0851_70f13881;
defparam bootram.RAM1.INIT_2A=256'h81065151_70862a70_81a89008_33555354_88059705_0d767802_0d04fd3d_800c853d;
defparam bootram.RAM1.INIT_2B=256'h90087081_900c81a8_517081a8_84388190_5171802e_8c0c81d0_721081a8_5170f138;
defparam bootram.RAM1.INIT_2C=256'h802e80cf_51515170_70813251_2a708106_90087087_f13881a8_51515170_2a708106;
defparam bootram.RAM1.INIT_2D=256'h81a89008_81a8900c_38905170_71812e83_0c80d051_3381a88c_80c53873_3871802e;
defparam bootram.RAM1.INIT_2E=256'h5170802e_32515151_81067081_70872a70_81a89008_5170f138_81065151_70812a70;
defparam bootram.RAM1.INIT_2F=256'h3d0d04fd_70800c85_900c8051_c00b81a8_518a3980_ffb73981_ff135354_8e388114;
defparam bootram.RAM1.INIT_30=256'h7127f138_5181cb8f_70733151_81b8ac08_b8ac0852_259b3881_80537274_3d0d7554;
defparam bootram.RAM1.INIT_31=256'h80840cff_0cef0b82_0b828080_880c81e0_ff0b8280_04ff3d0d_39853d0d_811353e2;
defparam bootram.RAM1.INIT_32=256'h3d0d04fb_25f13883_11517080_05540cff_cf727084_5287519d_0c80f6ec_0b82808c;
defparam bootram.RAM1.INIT_33=256'h06527180_55557476_0b80f6ec_52805381_71065851_82808c08_88087009_3d0d8280;
defparam bootram.RAM1.INIT_34=256'h25dc3887_55538773_15761057_39811384_808c0c8f_712d7482_51730852_2e8f3872;
defparam bootram.RAM1.INIT_35=256'h09828088_81722b70_75710c51_80f6ec05_38718429_7187269f_3d0d7352_3d0d04ff;
defparam bootram.RAM1.INIT_36=256'hc40c5281_700881e0_92052274_ff3d0d02_3d0d0404_53515283_8280880c_08707206;
defparam bootram.RAM1.INIT_37=256'hf338820b_5170802e_70840651_81b8a008_81e0c00c_3d0d810b_3d0d0480_e0c80c83;
defparam bootram.RAM1.INIT_38=256'h08757190_3881b8a0_72802e93_81065452_b8a00870_fe3d0d81_823d0d04_81e0c00c;
defparam bootram.RAM1.INIT_39=256'hf8db3fff_80e2cc51_802e8b38_06515271_812a7081_529a3971_53818080_2a710c53;
defparam bootram.RAM1.INIT_3A=256'h38818080_70802ef2_c0065151_a0087080_3d0d81b8_3d0d0480_71800c84_a63f7252;
defparam bootram.RAM1.INIT_3B=256'h70900651_81b8a008_e0c00c52_2b880781_05227090_3d0d028e_3d0d04ff_0b800c82;
defparam bootram.RAM1.INIT_3C=256'hba51f7ad_802e8638_54805372_fd3d0d75_833d0d04_81e0c00c_f338840b_5170802e;
defparam bootram.RAM1.INIT_3D=256'h33568211_0d778311_0d04fb3d_e638853d_53857327_a83f8113_335252ac_3f721470;
defparam bootram.RAM1.INIT_3E=256'h029005bb_7c7e6163_04f63d0d_3f873d0d_d05180ed_535680e2_33547033_33558111;
defparam bootram.RAM1.INIT_3F=256'h782d7630_7952ad51_802e8a38_258f3875_59577680_5b5f5d5b_709f2a51_05337030;
defparam bootram.RAM2.INIT_00=256'h51b4b53f_3f775276_0851ffbd_b49d3f80_77527651_78548053_94387955_57777726;
defparam bootram.RAM2.INIT_01=256'h04f73d0d_3f823d0d_3351f695_0d028b05_0d04803d_782d8c3d_dc053351_800880e2;
defparam bootram.RAM2.INIT_02=256'h81ff0656_81d13876_5775802e_81ff0657_58783370_a0ae5c5a_84055208_8c3d7070;
defparam bootram.RAM2.INIT_03=256'h7580e32e_f024a038_fb387580_80f02e80_33575975_38811970_810680db_75a52e09;
defparam bootram.RAM2.INIT_04=256'h80f52eac_818b3975_2e80c638_397580e4_9e388195_75802e81_e3248a38_b9387580;
defparam bootram.RAM2.INIT_05=256'h19831233_ec397784_2eba3880_397580f8_db3880f5_80f32e80_248b3875_387580f5;
defparam bootram.RAM2.INIT_06=256'h39778419_54805390_8055a0ae_08525956_77841971_2d80da39_52755179_52595680;
defparam bootram.RAM2.INIT_07=256'h54805390_8055a0ae_08525956_77841971_8a529239_ae548153_568055a0_71085259;
defparam bootram.RAM2.INIT_08=256'h81055833_80527670_802e8e38_76335675_08595956_77841971_d03f9e39_527551fd;
defparam bootram.RAM2.INIT_09=256'h0d81b8b4_0c04803d_0b81e5e4_3d0d048a_0b800c8b_fea33980_39811959_51792dec;
defparam bootram.RAM2.INIT_0A=256'h05337298_0288059b_3d0d797b_3d0d04fc_70ef3882_06515151_81327081_08708c2a;
defparam bootram.RAM2.INIT_0B=256'h5170802e_70810651_5272822a_71810a07_802e8638_56545570_81065555_2b7b0772;
defparam bootram.RAM2.INIT_0C=256'h73517380_81e5ec0c_e5e80c70_a93f7181_2b5151ff_75317971_0a0752a0_86387182;
defparam bootram.RAM2.INIT_0D=256'h53727427_54555580_0d76787a_0d04fc3d_800c863d_80085170_953f81b8_2e8938ff;
defparam bootram.RAM2.INIT_0E=256'hff067290_387183ff_70802e8d_71902a51_5351ee39_05811555_15702273_8f387210;
defparam bootram.RAM2.INIT_0F=256'h0880ecbc_f03f7670_ecb451b5_53755280_fd3d0d86_863d0d04_3971800c_2a0552ec;
defparam bootram.RAM2.INIT_10=256'h38833d0d_708025f3_ff125252_720c8812_52895180_0d80ecc4_0d04ff3d_0c54853d;
defparam bootram.RAM2.INIT_11=256'h52528972_81128812_742e8e38_70225472_ecc05252_53800b80_02960522_04fd3d0d;
defparam bootram.RAM2.INIT_12=256'h08802e89_56c73f80_ff065358_7a7183ff_fa3d0d78_853d0d04_5170800c_25ee3880;
defparam bootram.RAM2.INIT_13=256'h802e8f38_15555271_55730888_ecc05555_ecc40b80_39800880_84050cad_38768008;
defparam bootram.RAM2.INIT_14=256'h86705493_04f13d0d_0c883d0d_23768414_fa3f7573_25eb38a2_54558975_81158814;
defparam bootram.RAM2.INIT_15=256'h028405a2_b03f9080_dc0551b4_0552913d_53923d88_b4bf3f73_d6055254_3d53923d;
defparam bootram.RAM2.INIT_16=256'h052380c0_028405aa_23818080_800b8c3d_05a60523_23800284_800b8b3d_0523818a;
defparam bootram.RAM2.INIT_17=256'h80080284_51fdb73f_913de405_80538a52_685d665e_05ae0523_23800284_910b8d3d;
defparam bootram.RAM2.INIT_18=256'hbe0523ac_80028405_0b913d23_ba052380_22028405_3d23963d_983d2290_05ae0523;
defparam bootram.RAM2.INIT_19=256'h0b973d23_0d805b80_0d04e83d_d93f913d_840551a4_c0298298_05526980_53913dd4;
defparam bootram.RAM2.INIT_1A=256'h80f20522_b38f3f02_3df80551_ecb4529a_3f865380_0551b39d_529a3df2_86539b3d;
defparam bootram.RAM2.INIT_1B=256'ha13d0845_05436e44_c41143f0_800b9b3d_8008585a_e23f8008_e20523f7_02840580;
defparam bootram.RAM2.INIT_1C=256'h7508701a_3d568458_fc06408c_3d088305_3d085fa3_5d6e5ea1_59845c90_a33d0846;
defparam bootram.RAM2.INIT_1D=256'h83065473_2e9a3873_08547380_73760c75_75278438_565a5573_80713151_787c3190;
defparam bootram.RAM2.INIT_1E=256'h51a3ab3f_16085276_75085394_51efee3f_3880e2f8_73802e88_08830654_8c389416;
defparam bootram.RAM2.INIT_1F=256'h51f6e83f_5978822a_843880c0_3878bf26_8025ffac_19595777_570817ff_75708405;
defparam bootram.RAM2.INIT_20=256'hca052380_02840580_94055a79_3d237f1f_8a800b94_6e404081_ea3d0d6b_9a3d0d04;
defparam bootram.RAM2.INIT_21=256'h80d20523_80028405_79963d23_c080075a_05236980_840580ce_81808002_0b953d23;
defparam bootram.RAM2.INIT_22=256'hd2052391_02840580_08095a79_fae03f80_3d70525c_538a5293_46684780_80ecbc08;
defparam bootram.RAM2.INIT_23=256'h7a51f6b6_51f7c23f_3880e3a4_065a7992_800881ff_5e8ac83f_3d70535c_3d705398;
defparam bootram.RAM2.INIT_24=256'h1f5b5b79_5c7b1d7c_90805380_94557b54_586b575d_5a6d5960_a939027f_3feddd3f;
defparam bootram.RAM2.INIT_25=256'h3d238d3d_ae05228a_0d7f5802_0d04f73d_893f983d_26ef38fd_1c5c867c_337b3481;
defparam bootram.RAM2.INIT_26=256'h3df80553_5588548b_2377567e_8405a605_3d238002_1857768b_a2052388_22028405;
defparam bootram.RAM2.INIT_27=256'h0b8f3d34_b2052386_80028405_8e3d2390_3d0d810b_3d0d04ee_fe9e3f8b_91527d51;
defparam bootram.RAM2.INIT_28=256'hcc3feaf3_ec0551af_0852943d_3f865380_0523eaa3_028405b6_b5053481_84028405;
defparam bootram.RAM2.INIT_29=256'h3f800808_c93fead7_f60551b0_8052943d_bc3f8653_f20551af_0852943d_3f845380;
defparam bootram.RAM2.INIT_2A=256'hf01b337a_1c5a80e2_53805b7a_05549086_55943de4_5780569c_59805880_43025c80;
defparam bootram.RAM2.INIT_2B=256'h90862e09_225f5d7d_3d088e11_d93d0daa_943d0d04_38fbcb3f_867b26ef_34811b5b;
defparam bootram.RAM2.INIT_2C=256'ha03f86ee_e3d451f5_38795280_799b268d_f2055b5b_3d088429_38901dac_8106829d;
defparam bootram.RAM2.INIT_2D=256'h1b225a79_86d43884_2e098106_5a799080_38821b22_810686e2_79812e09_397a225a;
defparam bootram.RAM2.INIT_2E=256'h853fa81d_70524088_b9389e1d_09810686_5a79812e_38861b22_810686c6_8c842e09;
defparam bootram.RAM2.INIT_2F=256'h08868f38_80085c80_51acfe3f_3dffa805_ecbc52a9_43845380_fd3f8008_70525f87;
defparam bootram.RAM2.INIT_30=256'h23841b33_0580fe05_1b220284_a13d2382_dc3f7a22_527951ad_5380ecb4_a73d5a86;
defparam bootram.RAM2.INIT_31=256'h0551ada9_52a93de4_23865379_05818205_34820284_05818105_1b330284_a23d3485;
defparam bootram.RAM2.INIT_32=256'h8c3f7953_527a51ad_8653981d_818e055b_ad9b3f02_ea05525a_7f53aa3d_3f847054;
defparam bootram.RAM2.INIT_33=256'h587c575d_5a7c597c_f43f027c_527e51ac_5f86537a_803f9e3d_f40551ad_7f52a93d;
defparam bootram.RAM2.INIT_34=256'h993f84ee_26ef38f9_1c5c867c_337b3481_1d5b5b79_537b1d7f_dc05547d_9c55a93d;
defparam bootram.RAM2.INIT_35=256'hd1387988_09810684_5b60842e_8c2a435b_1d702270_84e43890_2e098106_397d9080;
defparam bootram.RAM2.INIT_36=256'h5e865380_84b4387e_ff065f7e_1b2280ff_84c03886_2e098106_515a7985_2a708f06;
defparam bootram.RAM2.INIT_37=256'haaf73f80_70535b5c_80ecbc54_901c6255_38815e7e_3f800883_1d51ab8d_e2f05282;
defparam bootram.RAM2.INIT_38=256'h22ec1140_1b33821c_84b83f89_529c1d51_8138881d_7b802e84_5c7d8738_08833881;
defparam bootram.RAM2.INIT_39=256'h5d42407d_8411225d_7a08a41f_388c1b08_810683de_7f912e09_2e81bb38_5d407f81;
defparam bootram.RAM2.INIT_3A=256'hf5c33f80_22535d5d_e41d821d_bd39ac1d_f1ef3f83_80e3f451_79537d52_7a2e8f38;
defparam bootram.RAM2.INIT_3B=256'haaeb3f9c_7d527951_5f5a8853_9a3d993d_3d237f49_387a2299_802e83a6_08428008;
defparam bootram.RAM2.INIT_3C=256'h51aaca3f_b4055279_53a93dff_23604788_1b22973d_aadf3f82_79527f51_3d408853;
defparam bootram.RAM2.INIT_3D=256'h811c5c88_79337b34_7c1f5b5b_5e5c7b1d_557e843d_3f7b567c_7d51aac1_88537952;
defparam bootram.RAM2.INIT_3E=256'h5a792d82_61840508_7b26ef38_811b5b88_84051c34_5a793302_805b7f1b_7c26ef38;
defparam bootram.RAM2.INIT_3F=256'h335a7983_9539811a_81bb3882_387d882e_7d832e8a_33405b42_08a41e70_ad398c1b;
defparam bootram.RAM3.INIT_00=256'h2251f481_81f4387c_2e098106_5e5c7991_8912335c_1d80c01e_81a238ac_2e098106;
defparam bootram.RAM3.INIT_01=256'h88537a52_9b3d5c5e_794b983d_229b3d23_1c085a7c_80fe388c_8008802e_3f800841;
defparam bootram.RAM3.INIT_02=256'h4d8853a9_9d3d2379_5a821d22_3f901c08_7f51a999_88537d52_3f963d40_7d51a9a5;
defparam bootram.RAM3.INIT_03=256'h1d7c1f5b_3d5e5c7b_7e557e84_f83f7e56_527d51a8_3f88537a_7a51a981_3dcc0552;
defparam bootram.RAM3.INIT_04=256'h887b26ef_34811b5b_0284051c_1b5a7933_38805b7f_887c26ef_34811c5c_5b79337b;
defparam bootram.RAM3.INIT_05=256'h02840580_953d347e_1d5d5d7e_39ac1de4_a03f80de_80e951e5_085a792d_38608405;
defparam bootram.RAM3.INIT_06=256'h53605294_d205237e_02840580_23861a22_1a22963d_ce052384_02840580_cd05347e;
defparam bootram.RAM3.INIT_07=256'hce05237b_02840580_08095a79_f1c03f80_2a527c51_08537b81_f1cc3f80_3d70525b;
defparam bootram.RAM3.INIT_08=256'h53727427_ed900855_0d800b80_0d04fc3d_f73fa93d_526151f5_547a537f_567c557d;
defparam bootram.RAM3.INIT_09=256'h39811353_3872518b_09810685_5170752e_088c1353_54565171_0880ed98_a4387670;
defparam bootram.RAM3.INIT_0A=256'h8025ba38_b93f8008_535755ff_0d777971_0d04fb3d_800c863d_38ff5170_737326e7;
defparam bootram.RAM3.INIT_0B=256'h940c5473_870680ed_94088111_8e3980ed_80ed900c_89388114_54738726_80ed9008;
defparam bootram.RAM3.INIT_0C=256'h80080554_39800810_9c145194_755280ed_51548653_ed98120c_2b760880_10147082;
defparam bootram.RAM3.INIT_0D=256'h54738008_fed83f80_3d0d7551_3d0d04fd_a6bb3f87_ed9c0551_73842980_86537552;
defparam bootram.RAM3.INIT_0E=256'h800c853d_3f815473_7651a691_ed9c0552_73842980_05548653_08108008_24993880;
defparam bootram.RAM3.INIT_0F=256'h33710780_72078316_3370882b_2b078214_982b7190_81123371_0d757033_0d04fd3d;
defparam bootram.RAM3.INIT_10=256'hffff068b_a8387383_56595776_80edf822_3d0d7d7f_3d0d04f9_56545285_0c525354;
defparam bootram.RAM3.INIT_11=256'h742380c0_05515476_2980edfc_29147090_d3387390_73832680_31525654_3d227072;
defparam bootram.RAM3.INIT_12=256'h3d527390_5488538a_74902915_8326ad38_57575474_22707231_ff068d3d_397383ff;
defparam bootram.RAM3.INIT_13=256'h1656ec39_e3a53f81_53547451_75177033_78279138_3f805675_0551a581_2980edfc;
defparam bootram.RAM3.INIT_14=256'h88140c80_23800b82_54548073_0b80edfc_edf82380_9a052280_fc3d0d02_893d0d04;
defparam bootram.RAM3.INIT_15=256'hd938863d_54837427_82901454_9b3f8114_740551ef_80edf822_0cb48b52_0b828c14;
defparam bootram.RAM3.INIT_16=256'h881a085b_be387582_51567581_32708106_847c2c81_edfc5a5c_0d800b80_0d04f43d;
defparam bootram.RAM3.INIT_17=256'hff06708a_38800881_ff2e80c5_ea3f8008_5b7b51e2_781a8805_2680d638_5d7981ff;
defparam bootram.RAM3.INIT_18=256'h777b7081_8338815d_5876802e_51595158_80250753_72802571_8d327030_32703072;
defparam bootram.RAM3.INIT_19=256'h38828819_7a27ffb1_1a5a81ff_8c1a0c81_0c800b82_0582881a_88190881_055d3482;
defparam bootram.RAM3.INIT_1A=256'h75802eab_38782256_8b7627bf_8c1b0c56_08811182_38828c19_d2387c91_08802e80;
defparam bootram.RAM3.INIT_1B=256'h887826ef_34811858_57753377_1a781a57_3d5b5877_54800b83_08558819_38828819;
defparam bootram.RAM3.INIT_1C=256'h5a5c837c_1c82901a_8c1a0c81_0c800b82_0b82881a_f2a83f80_227c0551_3880edf8;
defparam bootram.RAM3.INIT_1D=256'h06538452_54759fff_23855590_7580f78c_9e052256_fb3d0d02_8e3d0d04_27fea938;
defparam bootram.RAM3.INIT_1E=256'h06515153_812a7081_b0800870_fa3d0d81_22800c04_0480f78c_3f873d0d_8151eb8f;
defparam bootram.RAM3.INIT_1F=256'h81a43880_8c9abe26_9f145372_0ce7a0a3_0b81b080_84085481_bd3881b0_72802e81;
defparam bootram.RAM3.INIT_20=256'h52585153_ea807131_c00c98e5_2c7080eb_84057083_08317411_2980ebc0_ebc00888;
defparam bootram.RAM3.INIT_21=256'h70902b70_80f6bc22_ffb1f053_f0258538_3972ffb1_ce90538c_25873880_80ce9073;
defparam bootram.RAM3.INIT_22=256'hc0227090_732980f6_2b70902c_be227090_d00c80f6_167080f6_80f6d008_902c7529;
defparam bootram.RAM3.INIT_23=256'h5b565156_55535155_872c5257_73180570_80f6cc0c_902c297f_087f3171_2b80f6cc;
defparam bootram.RAM3.INIT_24=256'h065253fe_7083ffff_53908013_8438f081_72f08125_ff538a39_2586388f_548fff73;
defparam bootram.RAM3.INIT_25=256'h5480c073_f6bc7054_e3ed3f80_d0528151_fdfa3fb7_0d908051_0d04fd3d_873f883d;
defparam bootram.RAM3.INIT_26=256'h0b81b080_94150c81_150c800b_ea800b90_152398e5_82800b84_23907323_70820555;
defparam bootram.RAM3.INIT_27=256'h55741770_059d0557_3f800284_68519994_5780c052_883d7054_04ea3d0d_0c853d0d;
defparam bootram.RAM3.INIT_28=256'h09810685_7381992e_70335154_94387416_2e098106_387381aa_81ff2e9d_33515473;
defparam bootram.RAM3.INIT_29=256'h54548452_0d863d70_0d04f93d_800c983d_38805473_be7527d1_39811555_3881548b;
defparam bootram.RAM3.INIT_2A=256'h5574800c_06833881_752e0981_a43f8008_5273519e_5380e498_3f805584_795198c4;
defparam bootram.RAM3.INIT_2B=256'he49c5255_06705380_800881ff_3f8eed3f_3d0d9282_940c04fc_810b81e0_893d0d04;
defparam bootram.RAM3.INIT_2C=256'h81873974_80e4b451_54738838_81065151_708d2a70_81b8b408_518de33f_e5bb3f80;
defparam bootram.RAM3.INIT_2D=256'h3f81518d_9851dc85_9c3880e5_8008802e_51feb63f_3f98800a_ec51dc99_b73880e4;
defparam bootram.RAM3.INIT_2E=256'hfed83f80_8c800a51_51dbea3f_3f80e5d0_0a5183f9_74529880_51e0b83f_a93f82ac;
defparam bootram.RAM3.INIT_2F=256'he6a451db_978e3f80_8c800a51_80ffff52_83808053_51dbd63f_3880e5f8_08802ebd;
defparam bootram.RAM3.INIT_30=256'h83ab3f88_80528051_51dfe83f_b03f82ac_e6c851db_feda3f80_51dff83f_c03f82ac;
defparam bootram.RAM3.INIT_31=256'h2e843880_537387e8_0d7554a0_0c04fd3d_7180f6d4_863d0d04_51db9a3f_3980e784;
defparam bootram.RAM3.INIT_32=256'h7351722d_802e8538_d4085372_be3f80f6_527251d9_e3f33f72_80e7d051_c0537352;
defparam bootram.RAM3.INIT_33=256'h802e8538_d4085372_9a3f80f6_528051d9_a23f80c0_528051d9_fe3d0da0_853d0d04;
defparam bootram.RAM3.INIT_34=256'h81557180_06515354_862a7081_ff0b8008_518d983f_fc3d0d9a_843d0d04_8051722d;
defparam bootram.RAM3.INIT_35=256'h8a547180_80248a38_9b387182_7182802e_5580e454_86800653_820b8008_2e80ec38;
defparam bootram.RAM3.INIT_36=256'h3f71882a_85518ccb_3f800852_84518cd3_8338ff54_7184802e_3987e854_2e8e388a;
defparam bootram.RAM3.INIT_37=256'h52d99a3f_55535154_0c80e888_7080f6e0_e8c81133_06720780_8a2c7083_8c068008;
defparam bootram.RAM3.INIT_38=256'h74822ea6_80f6d80c_2e983874_80f6d808_d9b33f74_11085252_0680ebc4_71822b8c;
defparam bootram.RAM3.INIT_39=256'h8e387380_f6dc082e_96387380_2e098106_9e397482_38feb93f_098106a3_3874812e;
defparam bootram.RAM3.INIT_3A=256'h518bad3f_da3f8008_fd3d0dd5_863d0d04_518bd83f_fde83f99_9f3f7351_f6dc0cfe;
defparam bootram.RAM3.INIT_3B=256'h9c518bd8_81ae8052_518be13f_3f8d5298_99518bb7_80f6dc0c_d80cff0b_800b80f6;
defparam bootram.RAM3.INIT_3C=256'hbb3f8451_5484518b_9f067053_908007f4_9a3f8008_3f84518b_8451de9b_3fbd8852;
defparam bootram.RAM3.INIT_3D=256'h84800752_ee3f8008_3f80518a_a051e189_735280e8_38800853_80082e8d_8b853f73;
defparam bootram.RAM3.INIT_3E=256'h595683ff_81d00a07_7ed00a06_81d00a07_7cd00a06_04f63d0d_3f853d0d_80518b94;
defparam bootram.RAM3.INIT_3F=256'h51dc803f_99770c8a_8a3f81ab_0c8a51dc_923f7177_578a51dc_8072710c_ff5282c0;
defparam bootram.RAM4.INIT_00=256'hffff0670_e63f7583_0c7851db_81998677_80e1805a_51dbf43f_e6770c78_8a5982d4;
defparam bootram.RAM4.INIT_01=256'h90067483_07077310_88067173_0672812a_71832a84_71872a07_852a8206_81ff0670;
defparam bootram.RAM4.INIT_02=256'h07077a88_80067373_63067081_0677872b_852b80c0_81ff0676_73070770_2ba00671;
defparam bootram.RAM4.INIT_03=256'h74832ba0_73109006_71730707_812a8806_2a840672_2a077183_82067187_2a70852a;
defparam bootram.RAM4.INIT_04=256'h70882b7b_73730707_70818006_872b6d06_80c00677_0676852b_077081ff_06717307;
defparam bootram.RAM4.INIT_05=256'h575d5653_53515752_5b515852_57525a55_44525351_5151586b_ff066d0c_077083ff;
defparam bootram.RAM4.INIT_06=256'h077081ff_ff067073_902a7081_96800676_3f75902a_7851dab3_9981770c_dabd3f81;
defparam bootram.RAM4.INIT_07=256'h74832ba0_73109006_71730707_812a8806_2a840672_2a077183_82067187_0670852a;
defparam bootram.RAM4.INIT_08=256'h2a701090_ff067a88_2b077081_72077887_80c00670_0676852b_077081ff_06717307;
defparam bootram.RAM4.INIT_09=256'h5b515155_51566740_7407680c_83fe8006_0770882b_0772872b_80c00671_0671852b;
defparam bootram.RAM4.INIT_0A=256'h7783ffff_51d9a43f_85770c78_80568199_b23f81a1_515752d9_5a5a5751_53515852;
defparam bootram.RAM4.INIT_0B=256'h73109006_71730707_812a8806_2a840672_2a077183_82067187_0670852a_067081ff;
defparam bootram.RAM4.INIT_0C=256'h73730707_70818006_872b7f06_80c00677_0676852b_077081ff_06717307_74832ba0;
defparam bootram.RAM4.INIT_0D=256'h90067483_07077310_88067173_0672812a_71832a84_71872a07_852a8206_7a882a70;
defparam bootram.RAM4.INIT_0E=256'h07077088_80067373_69067081_0677872b_852b80c0_81ff0676_73070770_2ba00671;
defparam bootram.RAM4.INIT_0F=256'h5752575c_58525351_5a555b51_53515752_586b4452_6d0c5151_83ffff06_2b7b0770;
defparam bootram.RAM4.INIT_10=256'h7081ff06_0678902a_902a9680_d7ed3f77_770c7851_55819983_3f81c180_5653d7fb;
defparam bootram.RAM4.INIT_11=256'h07077310_88067173_0672812a_71832a84_71872a07_852a8206_81ff0670_70730770;
defparam bootram.RAM4.INIT_12=256'h80067373_61067081_0677872b_852b80c0_81ff0676_73070770_2ba00671_90067483;
defparam bootram.RAM4.INIT_13=256'h077083ff_70882b75_71730707_872b6606_80c00672_0671852b_2a701090_07077a88;
defparam bootram.RAM4.INIT_14=256'h99857078_52d6e43f_57515159_58525a5b_58525351_5a545b51_51526942_ff066a0c;
defparam bootram.RAM4.INIT_15=256'h51d6c03f_f0770c78_d6c93f80_770c7851_d6d13f71_770c7851_d6d93f80_0c795252;
defparam bootram.RAM4.INIT_16=256'h770c7851_d6a53f71_770c7851_d6ad3f71_770c7851_d6b53f71_0c795252_88807078;
defparam bootram.RAM4.INIT_17=256'h800c873d_3f863d22_d051839a_53805280_873dfc05_3d0d8254_3d0d04fb_d69d3f8c;
defparam bootram.RAM4.INIT_18=256'h82945280_90387753_77829326_08585957_3d088412_3d0880d7_3d0d80d5_0d04ffb2;
defparam bootram.RAM4.INIT_19=256'h080480c1_a4055675_842980e9_81a23875_56759626_39ff9f16_983f81ac_e8d851da;
defparam bootram.RAM4.INIT_1A=256'h39ff883f_c65c80fa_80085f80_5e8caa3f_a63f8008_818c398c_8008085e_5cced03f;
defparam bootram.RAM4.INIT_1B=256'h80c55c80_5189d33f_5280f790_538c1708_39901708_d65c80ea_ff065e80_800883ff;
defparam bootram.RAM4.INIT_1C=256'hb9399417_3980c25c_80c45cbe_802e8638_ff065675_3f800881_90518a98_d53980f7;
defparam bootram.RAM4.INIT_1D=256'h8c170851_90170852_fe800553_3980d03d_80d75ca6_5188ba3f_528c1708_53901708;
defparam bootram.RAM4.INIT_1E=256'hfdec0554_5580d03d_a05c8294_f83f8339_528051f7_80d35c80_d25c8f39_8bc63f80;
defparam bootram.RAM4.INIT_1F=256'h808251e1_26ec3883_18588878_33773481_05575775_80d23d79_5a587719_800b833d;
defparam bootram.RAM4.INIT_20=256'h7f5a5757_0d7a7c7f_f33ff83d_3fff5182_8051cf89_3d0d80ea_3d0d0480_b13f80d0;
defparam bootram.RAM4.INIT_21=256'h05a10534_58330284_76708105_738a3d34_81175754_25b73875_56548074_5874ff16;
defparam bootram.RAM4.INIT_22=256'h2e8538c1_a63f7380_548a51d3_0881ff06_d1f83f80_81ff0651_fc055277_82538a3d;
defparam bootram.RAM4.INIT_23=256'h3d348154_dc567588_56748338_335580de_0d02a305_0d04fa3d_800c8a3d_39815473;
defparam bootram.RAM4.INIT_24=256'h3d348153_ab053389_0d7c5702_0d04f93d_893f883d_80d051ff_5381f752_883dfc05;
defparam bootram.RAM4.INIT_25=256'h80772597_802e9e38_70565473_0881ff06_d1983f80_33705256_5202a705_893dfc05;
defparam bootram.RAM4.INIT_26=256'h893d0d04_5574800c_2e833881_56547380_81ff0670_db3f8008_527551cf_3876537b;
defparam bootram.RAM4.INIT_27=256'hde2e0981_56567480_0b883d33_ffa03f80_5280d051_055381f7_54883dfc_fa3d0d81;
defparam bootram.RAM4.INIT_28=256'hc0ac0c89_0ca60b81_0b81c080_940c80eb_990b81c0_883d0d04_5675800c_06833881;
defparam bootram.RAM4.INIT_29=256'ha00c81c0_820b81c0_c0980c51_70810781_2bbe8006_3d0d7288_b00c0480_b00b81c0;
defparam bootram.RAM4.INIT_2A=256'h882bbe80_803d0d72_823d0d04_a808800c_f13881c0_51515170_2a708106_a4087081;
defparam bootram.RAM4.INIT_2B=256'h81065151_70812a70_81c0a408_81c0a00c_9c0c840b_517381c0_81c0980c_06708107;
defparam bootram.RAM4.INIT_2C=256'h0652718a_91387583_55575771_72830655_0d787a7c_ff39fa3d_823d0d04_5170f138;
defparam bootram.RAM4.INIT_2D=256'h2b771177_94387382_55737527_822a7255_88f93f72_86388151_5271802e_38728306;
defparam bootram.RAM4.INIT_2E=256'hea8c1133_708f0680_7470842a_04fe3d0d_39883d0d_811454e9_0c525452_12700872;
defparam bootram.RAM4.INIT_2F=256'he0900870_803d0d82_843d0d04_53cada3f_8c113352_8f0680ea_cae73f72_54515353;
defparam bootram.RAM4.INIT_30=256'h80060780_ff067a8c_05337880_3d0d0293_3d0d04fe_70f13882_06515151_882a7081;
defparam bootram.RAM4.INIT_31=256'he0900c75_800c7182_387682e0_515170f1_70810651_0870882a_5382e090_c0800753;
defparam bootram.RAM4.INIT_32=256'h2a708106_90087088_963882e0_5172802e_e0900c72_82800782_e0980c71_81ff0682;
defparam bootram.RAM4.INIT_33=256'h80558854_e0940c88_0d810b82_0d04fc3d_800c843d_80085170_f13882e0_51515170;
defparam bootram.RAM4.INIT_34=256'hfef13f80_81528151_548a8053_88805590_04fc3d0d_3f863d0d_8051ff87_80538052;
defparam bootram.RAM4.INIT_35=256'h3d0d0480_fed53f86_81528051_88548653_0d888055_0d04fc3d_800c863d_0881ff06;
defparam bootram.RAM4.INIT_36=256'h802ef438_ff065170_3f800881_803d0deb_823d0d04_8106800c_80088132_3d0dca3f;
defparam bootram.RAM4.INIT_37=256'h75fe9b0a_8055a054_ffb43f88_9b38dd3f_75800826_5685923f_fb3d0d77_823d0d04;
defparam bootram.RAM4.INIT_38=256'hff115657_80cb3d08_80c93d08_ffba3d0d_873d0d04_51fe843f_53815280_069b0a07;
defparam bootram.RAM4.INIT_39=256'h52883d70_805381ff_81a73882_73800826_5484ce3f_b4387517_81ff2681_57805573;
defparam bootram.RAM4.INIT_3A=256'he0980c88_9f3f7482_fed43ffd_3ffefd3f_73518b99_cb3d0852_3f755380_52548cbe;
defparam bootram.RAM4.INIT_3B=256'h82e0900c_0c88a00b_0b82e098_e0800c81_c00a0782_c00a0680_900c76fe_800b82e0;
defparam bootram.RAM4.INIT_3C=256'h15700882_0c54fe84_0882e08c_fe801570_3d558f56_ef3f80c8_e0900cfc_8aa00b82;
defparam bootram.RAM4.INIT_3D=256'he0900c8a_88800b82_e0800c54_15700882_0c54fe8c_0882e084_fe881570_e0880c54;
defparam bootram.RAM4.INIT_3E=256'h5574800c_e0980c81_38800b82_8025ffbc_16565675_3fff1690_900cfcb0_800b82e0;
defparam bootram.RAM4.INIT_3F=256'h38815774_082680cb_80577380_56838a3f_12575a56_797b7d72_04f93d0d_80c83d0d;
defparam bootram.RAM5.INIT_00=256'h54775373_27833876_55577675_80743175_2ea23882_06547380_387581ff_802e80c3;
defparam bootram.RAM5.INIT_01=256'h38828054_807527e1_38745482_74802e8e_31575956_74197676_eb3f7316_527551fd;
defparam bootram.RAM5.INIT_02=256'h73135482_802e8d38_56545573_0d76787a_0d04fc3d_800c893d_3f815776_dc39fd8c;
defparam bootram.RAM5.INIT_03=256'h30707406_fa3f8008_0ca63981_160c8075_0c800b84_800b8816_74279038_9c3f8008;
defparam bootram.RAM5.INIT_04=256'h863d0d04_51fcc93f_88160c71_84160c71_760c7406_80083072_5281ec3f_ff165651;
defparam bootram.RAM5.INIT_05=256'h082e9438_14088415_38815388_71802e9f_06705452_800881ff_54fc983f_fd3d0d75;
defparam bootram.RAM5.INIT_06=256'h0d888055_0d04fc3d_800c853d_3f805372_0c51fc94_05708816_14088008_81b13f88;
defparam bootram.RAM5.INIT_07=256'h80f6e408_04fb3d0d_0c863d0d_800a0680_3f8008fe_8151faa3_0a538152_a05481f9;
defparam bootram.RAM5.INIT_08=256'h585154ce_80ea9c54_70567155_0881ff06_81ff0680_08882a70_38d43f80_557480c2;
defparam bootram.RAM5.INIT_09=256'hc4db3f9c_80eab451_802e8a38_81065473_2e933874_557380c0_2e833881_9c3f73a0;
defparam bootram.RAM5.INIT_0A=256'hf5a93f74_51cde23f_5280ead4_278d3874_55558274_e408ea11_e40c80f6_397580f6;
defparam bootram.RAM5.INIT_0B=256'h04fefa3f_082b800c_3f810b80_800c04f2_ebbe0533_3f800880_0d04ff91_800c873d;
defparam bootram.RAM5.INIT_0C=256'h0c8b0b82_0b82e090_980c8880_800b82e0_56f8e93f_f63d0d7d_2b800c04_810b8008;
defparam bootram.RAM5.INIT_0D=256'h900cf8b8_a80b82e0_e0900c8a_88a80b82_82e0980c_800c810b_882b82e0_e0840c7c;
defparam bootram.RAM5.INIT_0E=256'h82e08c08_0cf89d3f_0b82e090_900c8a80_800b82e0_80d33888_54737627_3f7e5580;
defparam bootram.RAM5.INIT_0F=256'h83387053_53707327_31525790_883d7675_e080085b_84085a82_085982e0_5882e088;
defparam bootram.RAM5.INIT_10=256'h39800b82_1454ffa9_52ec3972_57348112_75708105_17517033_27913871_80527173;
defparam bootram.RAM5.INIT_11=256'h0508528c_538c088c_fd3d0d80_08028c0c_f6da3f8c_3d0d7251_3d0d0480_e0980c8c;
defparam bootram.RAM5.INIT_12=256'h81538c08_0cfd3d0d_8c08028c_0d8c0c04_0c54853d_80087080_5182de3f_08880508;
defparam bootram.RAM5.INIT_13=256'h8c0cf93d_048c0802_3d0d8c0c_800c5485_3f800870_085182b9_8c088805_8c050852;
defparam bootram.RAM5.INIT_14=256'h800b8c08_0888050c_0508308c_388c0888_088025ab_8c088805_08fc050c_0d800b8c;
defparam bootram.RAM5.INIT_15=256'h088c0508_fc050c8c_05088c08_0c8c08f4_8c08f405_8838810b_08fc0508_f4050c8c;
defparam bootram.RAM5.INIT_16=256'h38810b8c_fc050888_050c8c08_0b8c08f0_8c050c80_08308c08_8c088c05_8025ab38;
defparam bootram.RAM5.INIT_17=256'h81a73f80_88050851_08528c08_8c088c05_050c8053_088c08fc_8c08f005_08f0050c;
defparam bootram.RAM5.INIT_18=256'h8c08f805_08f8050c_0508308c_388c08f8_08802e8c_8c08fc05_f8050c54_08708c08;
defparam bootram.RAM5.INIT_19=256'h88050880_050c8c08_0b8c08fc_fb3d0d80_08028c0c_8c0c048c_54893d0d_0870800c;
defparam bootram.RAM5.INIT_1A=256'h8c388c08_05088025_0c8c088c_8c08fc05_050c810b_308c0888_08880508_2593388c;
defparam bootram.RAM5.INIT_1B=256'h8c08f805_3f800870_050851ad_528c0888_088c0508_0c81538c_8c088c05_8c050830;
defparam bootram.RAM5.INIT_1C=256'h800c5487_f8050870_050c8c08_308c08f8_08f80508_2e8c388c_fc050880_0c548c08;
defparam bootram.RAM5.INIT_1D=256'h088c0508_f8050c8c_800b8c08_08fc050c_0d810b8c_8c0cfd3d_048c0802_3d0d8c0c;
defparam bootram.RAM5.INIT_1E=256'h088c0508_2499388c_088c0508_38800b8c_08802ea3_8c08fc05_0827ac38_8c088805;
defparam bootram.RAM5.INIT_1F=256'h388c088c_802e80c9_08fc0508_0cc9398c_8c08fc05_fc050810_050c8c08_108c088c;
defparam bootram.RAM5.INIT_20=256'hf805088c_050c8c08_318c0888_088c0508_8805088c_a1388c08_88050826_05088c08;
defparam bootram.RAM5.INIT_21=256'h2a8c088c_8c050881_050c8c08_2a8c08fc_fc050881_050c8c08_078c08f8_08fc0508;
defparam bootram.RAM5.INIT_22=256'h8c08f805_0c518d39_8c08f405_88050870_8f388c08_0508802e_398c0890_050cffaf;
defparam bootram.RAM5.INIT_23=256'h56528372_78777956_04fc3d0d_3d0d8c0c_08800c85_8c08f405_f4050c51_08708c08;
defparam bootram.RAM5.INIT_24=256'h72712e09_74335253_a0387433_5271ff2e_b038ff12_5170802e_74078306_278c3874;
defparam bootram.RAM5.INIT_25=256'h04747454_0c863d0d_38800b80_098106e2_5571ff2e_ff145455_81158115_8106bd38;
defparam bootram.RAM5.INIT_26=256'h55ffaf39_38707355_718326e9_14545451_118414fc_068f3884_082e0981_51700873;
defparam bootram.RAM5.INIT_27=256'h83065170_38727507_8f72278c_55555555_7670797b_04fc3d0d_0c863d0d_72713180;
defparam bootram.RAM5.INIT_28=256'hff2e0981_ff125271_81055634_54337470_72708105_ff2e9838_ff125271_802ea738;
defparam bootram.RAM5.INIT_29=256'h54087170_72708405_8405530c_54087170_72708405_0d047451_800c863d_06ea3874;
defparam bootram.RAM5.INIT_2A=256'hf0125271_8405530c_54087170_72708405_8405530c_54087170_72708405_8405530c;
defparam bootram.RAM5.INIT_2B=256'h387054ff_718326ed_0cfc1252_70840553_05540871_38727084_83722795_8f26c938;
defparam bootram.RAM5.INIT_2C=256'h802ea238_83065170_278a3874_53558372_05335755_028c059f_0d767971_8339fc3d;
defparam bootram.RAM5.INIT_2D=256'h0c863d0d_ef387480_2e098106_125271ff_055534ff_73737081_ff2e9338_ff125271;
defparam bootram.RAM5.INIT_2E=256'h71708405_05530c72_72717084_7227a538_5154518f_71902b07_2b750770_04747488;
defparam bootram.RAM5.INIT_2F=256'h38727170_83722790_8f26dd38_f0125271_8405530c_0c727170_70840553_530c7271;
defparam bootram.RAM5.INIT_30=256'h72802e80_54555552_787a7c70_39fa3d0d_7053ff90_8326f238_fc125271_8405530c;
defparam bootram.RAM5.INIT_31=256'h74712e09_74335651_b1387133_5372ff2e_d438ff13_70802e80_07830651_d9387174;
defparam bootram.RAM5.INIT_32=256'h555272ff_15ff1555_38811281_802e80fc_ff065170_87387081_72802e81_8106a938;
defparam bootram.RAM5.INIT_33=256'h0c883d0d_52527080_71713151_7581ff06_7081ff06_74335651_d1387133_2e098106;
defparam bootram.RAM5.INIT_34=256'h802eb138_fc135372_52ff9739_38747655_74082e88_88387108_55837327_04717457;
defparam bootram.RAM5.INIT_35=256'h55837327_15841757_709a3884_06515151_84828180_120670f8_f7fbfdff_74087009;
defparam bootram.RAM5.INIT_36=256'h0b80eb94_fd3d0d80_883d0d04_800b800c_52fedf39_38747655_76082ed0_d0387408;
defparam bootram.RAM5.INIT_37=256'hb1fc3f80_528151ff_3f80ebd8_3fffaa8c_0cffaaf0_7380f6e8_812e9e38_08545472;
defparam bootram.RAM5.INIT_38=256'h800851f6_ffb1df3f_d8528151_ef3f80eb_d33fffa9_e80cffaa_3f7280f6_0851f6a3;
defparam bootram.RAM5.INIT_39=256'h08525270_2dfc1270_2e913870_525270ff_fc057008_80ebe00b_39ff3d0d_863f00ff;
defparam bootram.RAM5.INIT_3A=256'h6f722069_21457272_00000040_04000000_ffaafe3f_3d0d0404_06f13883_ff2e0981;
defparam bootram.RAM5.INIT_3B=256'h70656374_3a204578_646c6572_2068616e_636b6574_6c207061_6e74726f_6e20636f;
defparam bootram.RAM5.INIT_3C=256'h62757420_25642c20_62657220_206e756d_6c697479_74696269_6f6d7061_65642063;
defparam bootram.RAM5.INIT_3D=256'h636b6574_6c207061_6e74726f_6e20636f_6f722069_21457272_25640a00_676f7420;
defparam bootram.RAM5.INIT_3E=256'h656e6774_6164206c_61796c6f_65642070_70656374_3a204578_646c6572_2068616e;
defparam bootram.RAM5.INIT_3F=256'h6b206368_206c696e_0a657468_0a000000_74202564_7420676f_2c206275_68202564;
defparam bootram.RAM6.INIT_00=256'h31302055_50204e32_0a555352_640a0000_203d2025_70656564_643a2073_616e6765;
defparam bootram.RAM6.INIT_01=256'h62696c69_70617469_20636f6d_46504741_720a0000_6f616465_6f6f746c_44502062;
defparam bootram.RAM6.INIT_02=256'h70617469_20636f6d_77617265_4669726d_640a0000_723a2025_756d6265_7479206e;
defparam bootram.RAM6.INIT_03=256'h476f7420_00000000_61646472_640a0000_723a2025_756d6265_7479206e_62696c69;
defparam bootram.RAM6.INIT_04=256'h000006df_000006f6_00000000_65743a20_7061636b_65727920_65636f76_69702072;
defparam bootram.RAM6.INIT_05=256'h0000078f_0000078f_0000078f_0000078f_0000078f_00000765_0000078f_0000078f;
defparam bootram.RAM6.INIT_06=256'h0000078f_0000078f_0000078f_0000078f_0000066d_0000078f_000006a7_00000713;
defparam bootram.RAM6.INIT_07=256'h4c4d5331_00000753_00000746_0000073f_00000738_00000733_0000072e_0000067a;
defparam bootram.RAM6.INIT_08=256'h20636869_4c4d5332_0a000000_30782578_6e203d20_7273696f_70207665_20636869;
defparam bootram.RAM6.INIT_09=256'h3fff0000_0050c285_c0a80a02_0a000000_30782578_6e203d20_7273696f_70207665;
defparam bootram.RAM6.INIT_0A=256'h30313233_2e256400_642e2564_25642e25_45000000_01c300e2_054a0387_15290a94;
defparam bootram.RAM6.INIT_0B=256'h5f706b74_73656e64_ffff0000_ffffffff_00000000_43444546_38394142_34353637;
defparam bootram.RAM6.INIT_0C=256'h72206275_6e642f6f_656e2061_6f66206c_656e7420_69676e6d_6420616c_3a206261;
defparam bootram.RAM6.INIT_0D=256'h74206361_6f206869_65642074_6661696c_6f6e3a20_636f6d6d_6e65745f_66000000;
defparam bootram.RAM6.INIT_0E=256'h6172703a_646c655f_0a68616e_00000000_666f7220_696e6720_6c6f6f6b_63686520;
defparam bootram.RAM6.INIT_0F=256'h6e736973_696e636f_55445020_0a000000_3d202564_697a6520_72642073_20776569;
defparam bootram.RAM6.INIT_10=256'h50726f64_0b0b0b0b_00000000_2025640a_3a202564_67746873_206c656e_74656e74;
defparam bootram.RAM6.INIT_11=256'h20555352_74696e67_53746172_640a0000_203d2025_6d616765_6f6e2069_75637469;
defparam bootram.RAM6.INIT_12=256'h66652066_67207361_6164696e_2e204c6f_6d6f6465_61666520_696e2073_50322b20;
defparam bootram.RAM6.INIT_13=256'h69642070_2076616c_20666f72_6b696e67_43686563_00000000_6172652e_69726d77;
defparam bootram.RAM6.INIT_14=256'h64207072_56616c69_2e2e2e00_6d616765_47412069_6e204650_6374696f_726f6475;
defparam bootram.RAM6.INIT_15=256'h7474656d_642e2041_666f756e_61676520_4120696d_20465047_74696f6e_6f647563;
defparam bootram.RAM6.INIT_16=256'h64756374_2070726f_616c6964_4e6f2076_742e0000_20626f6f_6720746f_7074696e;
defparam bootram.RAM6.INIT_17=256'h64207072_56616c69_2e0a0000_6f756e64_67652066_20696d61_46504741_696f6e20;
defparam bootram.RAM6.INIT_18=256'h64696e67_204c6f61_756e642e_6520666f_6d776172_20666972_74696f6e_6f647563;
defparam bootram.RAM6.INIT_19=256'h6e672069_61727469_2e205374_64696e67_206c6f61_73686564_46696e69_2e2e2e00;
defparam bootram.RAM6.INIT_1A=256'h61696e20_6f6d206d_6e206672_65747572_523a2052_4552524f_2e000000_6d616765;
defparam bootram.RAM6.INIT_1B=256'h61707065_65722068_206e6576_6f756c64_73207368_20546869_72616d21_70726f67;
defparam bootram.RAM6.INIT_1C=256'h77617265_6669726d_696f6e20_64756374_2070726f_616c6964_4e6f2076_6e210000;
defparam bootram.RAM6.INIT_1D=256'h75696c74_746f2062_75676820_7468726f_696e6720_46616c6c_6e642e20_20666f75;
defparam bootram.RAM6.INIT_1E=256'h2025640a_7420746f_64207365_53706565_2e000000_77617265_6669726d_2d696e20;
defparam bootram.RAM6.INIT_1F=256'h53594d4d_58000000_57455f52_58000000_57455f54_00000000_4e4f4e45_00000000;
defparam bootram.RAM6.INIT_20=256'h6c3a2000_6e74726f_7720636f_20666c6f_726e6574_65746865_43000000_45545249;
defparam bootram.RAM6.INIT_21=256'h20676f74_7825782c_74652030_2077726f_4144563a_4e45475f_4155544f_5048595f;
defparam bootram.RAM6.INIT_22=256'h6f722069_21457272_00030203_00000001_00030003_00000000_780a0000_20307825;
defparam bootram.RAM6.INIT_23=256'h65637465_20457870_6c65723a_68616e64_6b657420_20706163_64617465_6e207570;
defparam bootram.RAM6.INIT_24=256'h2025640a_20676f74_20627574_2025642c_6e677468_64206c65_796c6f61_64207061;
defparam bootram.RAM6.INIT_25=256'h000023d4_0000234b_0000236d_00002382_000023d4_000023d4_0000233e_00000000;
defparam bootram.RAM6.INIT_26=256'h000023d4_000023d4_000023d4_000023d4_000023d4_000023d4_000023d4_000023d4;
defparam bootram.RAM6.INIT_27=256'h0000239e_0000235d_000023d4_000023d4_000023c8_000023b1_000023d4_000023d4;
defparam bootram.RAM6.INIT_28=256'h0a666c61_43444546_38394142_34353637_30313233_00000000_6f72740a_0a0a6162;
defparam bootram.RAM6.INIT_29=256'h6c617368_6e672066_0a57726f_25640a00_697a653d_25642073_7970653d_73682074;
defparam bootram.RAM6.INIT_2A=256'h6c617368_6e672066_0a57726f_00000000_6e67210a_63687475_652e2041_20747970;
defparam bootram.RAM6.INIT_2B=256'h65000000_792e6578_64756d6d_67210a00_6874756e_64204163_653a2025_2073697a;
defparam bootram.RAM6.INIT_2C=256'h000035e8_00000000_00000000_00000000_ffffff00_ffff00ff_ff00ffff_00ffffff;
defparam bootram.RAM6.INIT_2D=256'h000c0000_00190010_ffff0033_05050000_01010100_3fff0000_0050c285_c0a80a02;
defparam bootram.RAM6.INIT_2E=256'hffffffff_00003574_10101200_000033fc_000033f4_000033ec_000033e4_03197500;
defparam bootram.RAM6.INIT_2F=256'h00000000_00000000_00000000_00000000_00000000_00000000_ffffffff_00000000;
defparam bootram.RAM6.INIT_30=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_31=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_32=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_33=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_34=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_35=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_36=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_37=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_38=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_39=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_3A=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_3B=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_3C=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM0.INIT_3D=256'h04fd3d0d_3f943d0d_80519b99_ed388380_58887826_77348118_57577533_963d7905;
defparam bootram.RAM0.INIT_3E=256'h52725186_80c05372_e82e8438_a0537387_802e9838_92883f73_e1e45254_75705380;
defparam bootram.RAM0.INIT_3F=256'h0d82903f_0d04fa3d_b03f853d_52735186_b83f80c0_52735186_3f9039a0_c43f9ba6;
defparam bootram.RAM1.INIT_00=256'hefbc0cf9_3f820b80_c05191ba_8c5280e2_5191c33f_5280e2a0_87a93f89_80e28451;
defparam bootram.RAM1.INIT_01=256'h9c0c82d6_800b81e0_81e09c0c_e93f810b_84803f84_0cabdf3f_0b80efb8_cd909299;
defparam bootram.RAM1.INIT_02=256'h80085483_3f84ce3f_f63f869e_8008518f_3f84da3f_dc3f86aa_8008518f_3f84863f;
defparam bootram.RAM1.INIT_03=256'h52838080_ac3f8c93_8def3f94_52800851_3f838084_a23f84bd_80085194_e83f7352;
defparam bootram.RAM1.INIT_04=256'h51a5843f_3f838092_825194d3_a8528380_de3f80c7_80845194_8ab25283_5194e83f;
defparam bootram.RAM1.INIT_05=256'hc9387680_08802e80_80085680_518dea3f_883dfc05_3faecf3f_bd51acaa_8dda3f8f;
defparam bootram.RAM1.INIT_06=256'hcca63f80_90055180_e4528008_845380e2_8106ad38_fdee2e09_55557382_088e0522;
defparam bootram.RAM1.INIT_07=256'h74527551_fd3f8839_3f735183_da3f8582_7052548e_e93f9416_e2ec518f_089a3880;
defparam bootram.RAM1.INIT_08=256'ha13f86f2_85f63f8b_3f91b13f_3d0d84cb_ff9e39fe_3f8be93f_f73fa4d9_9a8d3f8c;
defparam bootram.RAM1.INIT_09=256'h82ac518a_5183ea3f_3f845284_ac518ae0_83f73f82_9f528051_51849b3f_3f9f5280;
defparam bootram.RAM1.INIT_0A=256'h82539f52_518ab93f_d03f82ac_52905183_8ac63f90_3f82ac51_885183dd_d33f8852;
defparam bootram.RAM1.INIT_0B=256'h8025df38_ff135372_518a9d3f_b43f80e4_529c5183_8aaa3f9f_3f80e451_805183c1;
defparam bootram.RAM1.INIT_0C=256'h5683760c_0d81e080_0d04fb3d_800c843d_983f810b_52815183_83bc3f9f_9f529e51;
defparam bootram.RAM1.INIT_0D=256'h5190a93f_53815281_90548880_760c8655_89e63f83_0c80e451_ef3f8076_80e45189;
defparam bootram.RAM1.INIT_0E=256'he488518d_80085280_5190913f_53825281_90548880_893f8655_e3ec518e_80085280;
defparam bootram.RAM1.INIT_0F=256'h279e3872_80537276_81705654_787a5757_04fa3d0d_0c873d0d_3f810b80_f13fa6e1;
defparam bootram.RAM1.INIT_10=256'h74740751_1353df39_38805581_81ff2e83_71335271_83388054_5270802e_17703352;
defparam bootram.RAM1.INIT_11=256'h5280eec4_5380e4a8_efc43486_0d810b80_0d04fe3d_800c883d_38815170_70802e83;
defparam bootram.RAM1.INIT_12=256'h873d7054_c4348654_810b80ef_5574bd38_80efc433_04f93d0d_3f843d0d_5180c798;
defparam bootram.RAM1.INIT_13=256'h0881ff06_fef33f80_86527551_802e9d38_ff065574_3f800881_d051b5d0_56825280;
defparam bootram.RAM1.INIT_14=256'h80efc034_0d04810b_800c893d_80eec40b_80c6cd3f_80eec451_86537552_55748d38;
defparam bootram.RAM1.INIT_15=256'h873dfc05_c0348454_810b80ef_5574b938_80efc033_04fb3d0d_80eec00c_80e4a408;
defparam bootram.RAM1.INIT_16=256'h903f8008_fc0551fe_8452873d_802e9938_ff065574_3f800881_d051b4f0_538c5280;
defparam bootram.RAM1.INIT_17=256'h5475538c_0d775684_0d04fb3d_800c873d_80eec00b_80eec00c_74863875_81ff0655;
defparam bootram.RAM1.INIT_18=256'hc0347480_810b80ef_80eec00c_8d387508_5574802e_0881ff06_b3b63f80_5280d051;
defparam bootram.RAM1.INIT_19=256'h0c51823d_0c81e08c_7080efc8_c8080607_067180ef_73097375_04803d0d_0c873d0d;
defparam bootram.RAM1.INIT_1A=256'h3d0d0481_980c5182_cc0c81e0_077080ef_efcc0806_75067180_0d730973_0d04803d;
defparam bootram.RAM1.INIT_1B=256'h5181b63f_0d8a5280_0d04ff3d_800c843d_81c73f72_53538051_3d0d7470_af3f04fe;
defparam bootram.RAM1.INIT_1C=256'hff065376_81157481_802e9038_06545472_337081ff_79565674_fb3d0d77_833d0d04;
defparam bootram.RAM1.INIT_1D=256'hfe3d0d74_833d0d04_8051cd3f_3d0d7352_3d0d04ff_0b800c87_3fe53980_52558191;
defparam bootram.RAM1.INIT_1E=256'h8051dd3f_3d0d7352_3d0d04ff_0b800c84_80e73f80_8a527251_53ffbd3f_76537052;
defparam bootram.RAM1.INIT_1F=256'h82908005_0d73a029_0d04ff3d_1234823d_3380eecc_51028f05_803d0d72_833d0d04;
defparam bootram.RAM1.INIT_20=256'h51c63f80_13335272_5380eecc_fe3d0d80_833d0d04_720c5351_b0057022_751080e4;
defparam bootram.RAM1.INIT_21=256'h748a2e09_76785654_04fc3d0d_38843d0d_827325e5_3f811353_527251ce_eed01333;
defparam bootram.RAM1.INIT_22=256'h90800554_73a02982_7351de3f_87388d52_2e098106_33537281_80eecc14_81069538;
defparam bootram.RAM1.INIT_23=256'h11085252_90800588_74a02982_04fe3d0d_0c863d0d_38748c15_72802ef8_84140853;
defparam bootram.RAM1.INIT_24=256'heed82270_a8880c80_0d800b81_0d04ff3d_800c843d_12085372_2e853890_ff537080;
defparam bootram.RAM1.INIT_25=256'h0d787a02_0d04fb3d_880c833d_800b81a8_840c5181_882a81a8_a8800c70_81ff0681;
defparam bootram.RAM1.INIT_26=256'h81065151_70862a70_81a89008_8386d053_2e81c738_81527380_33575556_88059f05;
defparam bootram.RAM1.INIT_27=256'h81a88c0c_74108107_52819f39_fde53f72_80e4bc51_5372e938_9338ff13_5271802e;
defparam bootram.RAM1.INIT_28=256'h38ff1353_71802e8e_06515152_812a7081_a8900870_86d05381_a8900c83_81900b81;
defparam bootram.RAM1.INIT_29=256'h802e80cf_51515271_70813251_2a708106_90087087_ae3f81a8_e4d851fd_72e93880;
defparam bootram.RAM1.INIT_2A=256'h90087081_d05381a8_900c8386_527181a8_2e8338a0_e8527381_80c53880_3873802e;
defparam bootram.RAM1.INIT_2B=256'h08527176_3f81a88c_d851fcdf_e93880e4_ff135372_802e8e38_51515271_2a708106;
defparam bootram.RAM1.INIT_2C=256'h04fb3d0d_0c873d0d_900c7180_c00b81a8_52883980_ffb73981_34ff1454_70810558;
defparam bootram.RAM1.INIT_2D=256'h71802e93_06515152_862a7081_a8900870_86d05381_57555683_059f0533_787a0288;
defparam bootram.RAM1.INIT_2E=256'h73802e84_0c81d052_1081a88c_81bb3974_8a3f7252_e4f851fc_72e93880_38ff1353;
defparam bootram.RAM1.INIT_2F=256'h2e8e38ff_51527180_70810651_0870812a_5381a890_0c8386d0_7181a890_38819052;
defparam bootram.RAM1.INIT_30=256'h5271802e_32515151_81067081_70872a70_81a89008_51fbcc3f_3880e4d8_135372e9;
defparam bootram.RAM1.INIT_31=256'h900c8386_527181a8_2e833890_d0527381_a88c0c80_38753381_802e80d8_80e23873;
defparam bootram.RAM1.INIT_32=256'hd851faf7_e93880e4_ff135372_802e8e38_51515271_2a708106_90087081_d05381a8;
defparam bootram.RAM1.INIT_33=256'h56ffa439_16ff1555_2e8e3881_51527180_81325151_70810670_0870872a_3f81a890;
defparam bootram.RAM1.INIT_34=256'h74259b38_54805372_fd3d0d75_873d0d04_5271800c_a8900c80_80c00b81_81528a39;
defparam bootram.RAM1.INIT_35=256'h0d04ff3d_e239853d_38811353_8f7127f1_515181cb_08707331_5281b8ac_81b8ac08;
defparam bootram.RAM1.INIT_36=256'h8c528751_8c0c80fa_ff0b8280_8280840c_800cef0b_e00b8280_80880c81_0dff0b82;
defparam bootram.RAM1.INIT_37=256'h0982808c_80880870_fb3d0d82_833d0d04_8025f138_ff115170_8405540c_9ee47270;
defparam bootram.RAM1.INIT_38=256'h52712d74_72517308_802e8f38_76065271_8c555574_810b80fa_51528053_08710658;
defparam bootram.RAM1.INIT_39=256'h52718726_ff3d0d73_873d0d04_7325dc38_57555387_84157610_8f398113_82808c0c;
defparam bootram.RAM1.INIT_3A=256'h0c535152_06828088_88087072_70098280_5181722b_0575710c_2980fa8c_9f387184;
defparam bootram.RAM1.INIT_3B=256'h803d0d81_833d0d04_81e0c80c_e0c40c52_74700881_02920522_04ff3d0d_833d0d04;
defparam bootram.RAM1.INIT_3C=256'h04fe3d0d_0c823d0d_0b81e0c0_2ef33882_51517080_08708406_0c81b8a0_0b81e0c0;
defparam bootram.RAM1.INIT_3D=256'h80529a39_53538180_902a710c_a0087571_933881b8_5272802e_70810654_81b8a008;
defparam bootram.RAM1.INIT_3E=256'h843d0d04_5271800c_ffa63f72_51f7dc3f_3880e594_71802e8b_81065152_71812a70;
defparam bootram.RAM1.INIT_3F=256'hff3d0d02_823d0d04_800b800c_f2388180_5170802e_80c00651_b8a00870_803d0d81;
defparam bootram.RAM2.INIT_00=256'h0b81e0c0_2ef33884_51517080_08709006_5281b8a0_81e0c00c_902b8807_8e052270;
defparam bootram.RAM2.INIT_01=256'haccd3f81_70335252_ae3f7214_38ba51f6_72802e86_75548053_04fd3d0d_0c833d0d;
defparam bootram.RAM2.INIT_02=256'h33535680_11335470_11335581_11335682_3d0d7783_3d0d04fb_27e63885_13538573;
defparam bootram.RAM2.INIT_03=256'h515b5f5d_30709f2a_bb053370_63029005_0d7c7e61_0d04f63d_ed3f873d_e5985180;
defparam bootram.RAM2.INIT_04=256'h55785480_26943879_30577777_51782d76_387952ad_75802e8a_80258f38_5b595776;
defparam bootram.RAM2.INIT_05=256'h51782d8c_e5a40533_3f800880_7651b593_bd3f7752_800851ff_51b4fb3f_53775276;
defparam bootram.RAM2.INIT_06=256'h08a1c35c_70840552_0d8c3d70_0d04f73d_963f823d_053351f5_3d0d028b_3d0d0480;
defparam bootram.RAM2.INIT_07=256'hdb388119_09810680_5675a52e_7681ff06_2e81d138_57577580_7081ff06_5a587833;
defparam bootram.RAM2.INIT_08=256'h3875802e_80e3248a_2eb93875_387580e3_80f024a0_80fb3875_7580f02e_70335759;
defparam bootram.RAM2.INIT_09=256'h7580f32e_f5248b38_ac387580_7580f52e_38818b39_e42e80c6_95397580_819e3881;
defparam bootram.RAM2.INIT_0A=256'h792d80da_80527551_33525956_84198312_80ec3977_f82eba38_f5397580_80db3880;
defparam bootram.RAM2.INIT_0B=256'ha1c35481_59568055_19710852_90397784_c3548053_568055a1_71085259_39778419;
defparam bootram.RAM2.INIT_0C=256'h39778419_fdd03f9e_90527551_c3548053_568055a1_71085259_39778419_538a5292;
defparam bootram.RAM2.INIT_0D=256'h59fea339_ec398119_3351792d_70810558_38805276_75802e8e_56763356_71085959;
defparam bootram.RAM2.INIT_0E=256'h81065151_2a813270_b408708c_3d0d81b8_e40c0480_8a0b81e5_8b3d0d04_800b800c;
defparam bootram.RAM2.INIT_0F=256'h55575454_72810655_982b7b07_9b053372_7b028805_fc3d0d79_823d0d04_5170ef38;
defparam bootram.RAM2.INIT_10=256'ha0743179_820a0752_2e863871_51517080_2a708106_07527282_3871810a_70802e86;
defparam bootram.RAM2.INIT_11=256'h742bff05_ff953f81_802e9338_0c745174_7081e5ec_81e5e80c_ffa93f71_712b5151;
defparam bootram.RAM2.INIT_12=256'h7274278f_55558053_76787a54_04fc3d0d_0c863d0d_52527080_70720651_81b88008;
defparam bootram.RAM2.INIT_13=256'h0672902a_7183ffff_802e8d38_902a5170_51ee3971_81155553_70227305_38721015;
defparam bootram.RAM2.INIT_14=256'h80efdc0c_3f767008_d451b6c4_755280ef_3d0d8653_3d0d04fd_71800c86_0552ec39;
defparam bootram.RAM2.INIT_15=256'h833d0d04_8025f338_12525270_0c8812ff_89518072_80efe452_04ff3d0d_54853d0d;
defparam bootram.RAM2.INIT_16=256'h52897225_12881252_2e8e3881_22547274_e0525270_800b80ef_96052253_fd3d0d02;
defparam bootram.RAM2.INIT_17=256'h802e8938_c73f8008_06535856_7183ffff_3d0d787a_3d0d04fa_70800c85_ee388051;
defparam bootram.RAM2.INIT_18=256'h2e8f3881_55527180_73088815_e0555555_e40b80ef_800880ef_050cad39_76800884;
defparam bootram.RAM2.INIT_19=256'h7054933d_f13d0d86_883d0d04_7684140c_3f757323_eb38a381_55897525_15881454;
defparam bootram.RAM2.INIT_1A=256'h8405a205_3f908002_0551b584_52913ddc_923d8805_933f7353_055254b5_53923dd6;
defparam bootram.RAM2.INIT_1B=256'h2380c091_8405aa05_81808002_0b8c3d23_a6052380_80028405_0b8b3d23_23818a80;
defparam bootram.RAM2.INIT_1C=256'h08028405_fdb73f80_3de40551_538a5291_5d665e80_ae052368_80028405_0b8d3d23;
defparam bootram.RAM2.INIT_1D=256'h0523ac53_028405be_913d2380_0523800b_028405ba_23963d22_3d22903d_ae052398;
defparam bootram.RAM2.INIT_1E=256'h973d2386_805b800b_04e83d0d_3f913d0d_0551a4f4_29829884_526980c0_913dd405;
defparam bootram.RAM2.INIT_1F=256'hf2052202_e33f0280_f80551b3_d4529a3d_865380ef_51b3f13f_9a3df205_539b3d52;
defparam bootram.RAM2.INIT_20=256'h3d0845a3_436e44a1_1143f005_0b9b3dc4_08585a80_3f800880_0523f7d8_840580e2;
defparam bootram.RAM2.INIT_21=256'h08701a78_56845875_06408c3d_088305fc_085fa33d_6e5ea13d_845c905d_3d084659;
defparam bootram.RAM2.INIT_22=256'h0654738c_9a387383_5473802e_760c7508_27843873_5a557375_71315156_7c319080;
defparam bootram.RAM2.INIT_23=256'ha3c63f75_08527651_08539416_eee53f75_80e5c051_802e8838_83065473_38941608;
defparam bootram.RAM2.INIT_24=256'hf6de3f9a_78822a51_3880c059_78bf2684_25ffac38_59577780_0817ff19_70840557;
defparam bootram.RAM2.INIT_25=256'h0523800b_840580ca_055a7902_237f1f94_800b943d_4040818a_3d0d6b6e_3d0d04ea;
defparam bootram.RAM2.INIT_26=256'hd2052380_02840580_963d2380_80075a79_236980c0_0580ce05_80800284_953d2381;
defparam bootram.RAM2.INIT_27=256'h0523913d_840580d2_095a7902_e03f8008_70525cfa_8a52933d_68478053_efdc0846;
defparam bootram.RAM2.INIT_28=256'h51f6ac3f_f7b83f7a_80e5ec51_5a799238_0881ff06_8ac83f80_70535c5e_7053983d;
defparam bootram.RAM2.INIT_29=256'h5b5b7933_7b1d7c1f_8053805c_557b5490_6b575d94_6d596058_39027f5a_ecd43fa9;
defparam bootram.RAM2.INIT_2A=256'h238d3d22_05228a3d_7f5802ae_04f73d0d_3f983d0d_ef38fd89_5c867c26_7b34811c;
defparam bootram.RAM2.INIT_2B=256'hf8055391_88548b3d_77567e55_05a60523_23800284_57768b3d_05238818_028405a2;
defparam bootram.RAM2.INIT_2C=256'h8f3d3484_0523860b_028405b2_3d239080_0d810b8e_0d04ee3d_9e3f8b3d_527d51fe;
defparam bootram.RAM2.INIT_2D=256'h3fe9ea3f_0551b0a0_52943dec_86538008_23e99a3f_8405b605_05348102_028405b5;
defparam bootram.RAM2.INIT_2E=256'h80080843_3fe9ce3f_0551b19d_52943df6_3f865380_0551b090_52943df2_84538008;
defparam bootram.RAM2.INIT_2F=256'h1b337a34_5a80e5b8_805b7a1c_54908653_943de405_80569c55_80588057_025c8059;
defparam bootram.RAM2.INIT_30=256'h862e0981_5f5d7d90_088e1122_3d0daa3d_3d0d04d9_fbcb3f94_7b26ef38_811b5b86;
defparam bootram.RAM2.INIT_31=256'h3f86ee39_9c51f596_795280e6_9b268d38_055b5b79_088429f2_901dac3d_06829d38;
defparam bootram.RAM2.INIT_32=256'h225a798c_d438841b_09810686_7990802e_821b225a_0686e238_812e0981_7a225a79;
defparam bootram.RAM2.INIT_33=256'h3fa81d70_52408885_389e1d70_810686b9_79812e09_861b225a_0686c638_842e0981;
defparam bootram.RAM2.INIT_34=256'h868f38a7_085c8008_add23f80_ffa80551_dc52a93d_845380ef_3f800843_525f87fd;
defparam bootram.RAM2.INIT_35=256'h841b33a2_80fe0523_22028405_3d23821b_3f7a22a1_7951aeb0_80efd452_3d5a8653;
defparam bootram.RAM2.INIT_36=256'h51adfd3f_a93de405_86537952_81820523_82028405_81810534_33028405_3d34851b;
defparam bootram.RAM2.INIT_37=256'h3f79537f_7a51ade0_53981d52_8e055b86_ef3f0281_05525aad_53aa3dea_8470547f;
defparam bootram.RAM2.INIT_38=256'h7c575d9c_7c597c58_3f027c5a_7e51adc8_86537a52_3f9e3d5f_0551add4_52a93df4;
defparam bootram.RAM2.INIT_39=256'h3f84ee39_ef38f999_5c867c26_7b34811c_5b5b7933_7b1d7f1d_05547d53_55a93ddc;
defparam bootram.RAM2.INIT_3A=256'h3879882a_810684d1_60842e09_2a435b5b_7022708c_e438901d_09810684_7d90802e;
defparam bootram.RAM2.INIT_3B=256'h865380e5_b4387e5e_065f7e84_2280ffff_c038861b_09810684_5a79852e_708f0651;
defparam bootram.RAM2.INIT_3C=256'hcb3f8008_535b5cab_efdc5470_1c625580_815e7e90_80088338_51abe13f_b852821d;
defparam bootram.RAM2.INIT_3D=256'hec11405d_33821c22_b83f891b_9c1d5184_38881d52_802e8481_7d87387b_8338815c;
defparam bootram.RAM2.INIT_3E=256'h42407d7a_11225d5d_08a41f84_8c1b087a_0683de38_912e0981_81bb387f_407f812e;
defparam bootram.RAM2.INIT_3F=256'hc33f8008_535d5df5_1d821d22_39ac1de4_e53f83bd_e6bc51f1_537d5280_2e8f3879;
defparam bootram.RAM3.INIT_00=256'hbf3f9c3d_527951ab_5a88537d_3d993d5f_237f499a_7a22993d_2e83a638_42800880;
defparam bootram.RAM3.INIT_01=256'hab9e3f88_05527951_a93dffb4_60478853_22973d23_b33f821b_527f51ab_40885379;
defparam bootram.RAM3.INIT_02=256'h1c5c887c_337b3481_1f5b5b79_5c7b1d7c_7e843d5e_7b567c55_51ab953f_5379527d;
defparam bootram.RAM3.INIT_03=256'h792d82ad_8405085a_26ef3861_1b5b887b_051c3481_79330284_5b7f1b5a_26ef3880;
defparam bootram.RAM3.INIT_04=256'h5a79832e_39811a33_bb388295_7d882e81_832e8a38_405b427d_a41e7033_398c1b08;
defparam bootram.RAM3.INIT_05=256'h51f4813f_f4387c22_09810681_5c79912e_12335c5e_80c01e89_a238ac1d_09810681;
defparam bootram.RAM3.INIT_06=256'h537a527d_3d5c5e88_4b983d9b_9b3d2379_085a7c22_fe388c1c_08802e80_80084180;
defparam bootram.RAM3.INIT_07=256'h8853a93d_3d23794d_821d229d_901c085a_51a9ed3f_537d527f_963d4088_51a9f93f;
defparam bootram.RAM3.INIT_08=256'h7c1f5b5b_5e5c7b1d_557e843d_3f7e567e_7d51a9cc_88537a52_51a9d53f_cc05527a;
defparam bootram.RAM3.INIT_09=256'h7b26ef38_811b5b88_84051c34_5a793302_805b7f1b_7c26ef38_811c5c88_79337b34;
defparam bootram.RAM3.INIT_0A=256'h840580cd_3d347e02_5d5d7e95_ac1de41d_3f80de39_e951e497_5a792d80_60840508;
defparam bootram.RAM3.INIT_0B=256'h6052943d_05237e53_840580d2_861a2202_22963d23_0523841a_840580ce_05347e02;
defparam bootram.RAM3.INIT_0C=256'h05237b56_840580ce_095a7902_c03f8008_527c51f1_537b812a_cc3f8008_70525bf1;
defparam bootram.RAM3.INIT_0D=256'h727427a4_b0085553_800b80f0_04fc3d0d_3fa93d0d_6151f5f7_7a537f52_7c557d54;
defparam bootram.RAM3.INIT_0E=256'h81135373_72518b39_81068538_70752e09_8c135351_56517108_80f0b854_38767008;
defparam bootram.RAM3.INIT_0F=256'h25ba3880_3f800880_5755ffb9_77797153_04fb3d0d_0c863d0d_ff517080_7326e738;
defparam bootram.RAM3.INIT_10=256'h0c547310_0680f0b4_08811187_3980f0b4_f0b00c8e_38811480_73872689_f0b00854;
defparam bootram.RAM3.INIT_11=256'h08055486_80081080_14519439_5280f0bc_54865375_b8120c51_760880f0_1470822b;
defparam bootram.RAM3.INIT_12=256'h73800824_d83f8054_0d7551fe_0d04fd3d_8f3f873d_bc0551a7_842980f0_53755273;
defparam bootram.RAM3.INIT_13=256'h0c853d0d_81547380_51a6e53f_bc055276_842980f0_54865373_10800805_99388008;
defparam bootram.RAM3.INIT_14=256'h7107800c_07831633_70882b72_07821433_2b71902b_12337198_75703381_04fd3d0d;
defparam bootram.RAM3.INIT_15=256'hff068b3d_387383ff_595776a8_f1982256_0d7d7f80_0d04f93d_5452853d_52535456;
defparam bootram.RAM3.INIT_16=256'h2380c039_51547674_80f19c05_14709029_38739029_832680d3_52565473_22707231;
defparam bootram.RAM3.INIT_17=256'h52739029_88538a3d_90291554_26ad3874_57547483_70723157_068d3d22_7383ffff;
defparam bootram.RAM3.INIT_18=256'h56ec3989_9c3f8116_547451e2_17703353_27913875_80567578_51a5d53f_80f19c05;
defparam bootram.RAM3.INIT_19=256'h140c800b_800b8288_54807323_80f19c54_9823800b_052280f1_3d0d029a_3d0d04fc;
defparam bootram.RAM3.INIT_1A=256'h38863d0d_837427d9_90145454_3f811482_0551ef9b_f1982274_b5aa5280_828c140c;
defparam bootram.RAM3.INIT_1B=256'h1a085b5d_38758288_567581be_70810651_7c2c8132_9c5a5c82_800b80f1_04f43d0d;
defparam bootram.RAM3.INIT_1C=256'h06708a32_800881ff_2e80c538_3f8008ff_7b51e1e1_1a88055b_80d63878_7981ff26;
defparam bootram.RAM3.INIT_1D=256'h7b708105_38815d77_76802e83_59515858_25075351_80257180_32703072_7030728d;
defparam bootram.RAM3.INIT_1E=256'h82881908_27ffb138_5a81ff7a_1a0c811a_800b828c_82881a0c_19088105_5d348288;
defparam bootram.RAM3.INIT_1F=256'h802eab38_78225675_7627bf38_1b0c568b_8111828c_828c1908_387c9138_802e80d2;
defparam bootram.RAM3.INIT_20=256'h7826ef38_81185888_75337734_781a5757_5b58771a_800b833d_55881954_82881908;
defparam bootram.RAM3.INIT_21=256'h5c837c27_82901a5a_1a0c811c_800b828c_82881a0c_a83f800b_7c0551f2_80f19822;
defparam bootram.RAM3.INIT_22=256'h53845281_759fff06_85559054_80faac23_05225675_3d0d029e_3d0d04fb_fea9388e;
defparam bootram.RAM3.INIT_23=256'h51515372_2a708106_80087081_3d0d81b0_800c04fa_80faac22_873d0d04_51eb853f;
defparam bootram.RAM3.INIT_24=256'ha43880ee_9abe2681_1453728c_e7a0a39f_81b0800c_0854810b_3881b084_802e81bd;
defparam bootram.RAM3.INIT_25=256'h58515380_80713152_0c98e5ea_7080eee0_0570832c_31741184_80eee008_e0088829;
defparam bootram.RAM3.INIT_26=256'h902b7090_f9dc2270_b1f05380_258538ff_72ffb1f0_90538c39_873880ce_ce907325;
defparam bootram.RAM3.INIT_27=256'h2270902b_2980f9e0_70902c73_2270902b_0c80f9de_7080f9f0_f9f00816_2c752980;
defparam bootram.RAM3.INIT_28=256'h56515654_5351555b_2c525755_18057087_f9ec0c73_2c297f80_7f317190_80f9ec08;
defparam bootram.RAM3.INIT_29=256'h5253fe87_83ffff06_90801370_38f08153_f0812584_538a3972_86388fff_8fff7325;
defparam bootram.RAM3.INIT_2A=256'h80c07370_dc705454_e33f80f9_528151e3_fa3fb8ef_908051fd_04fd3d0d_3f883d0d;
defparam bootram.RAM3.INIT_2B=256'h81b0800c_150c810b_0c800b94_800b9015_2398e5ea_800b8415_90732382_82055523;
defparam bootram.RAM3.INIT_2C=256'h74177033_9d055755_80028405_5199e83f_80c05268_3d705457_ea3d0d88_853d0d04;
defparam bootram.RAM3.INIT_2D=256'h81068538_81992e09_33515473_38741670_09810694_7381aa2e_ff2e9d38_51547381;
defparam bootram.RAM3.INIT_2E=256'h54845279_863d7054_04f93d0d_0c983d0d_80547380_7527d138_811555be_81548b39;
defparam bootram.RAM3.INIT_2F=256'h74800c89_83388155_2e098106_3f800875_73519ef8_80e6e052_80558453_5199983f;
defparam bootram.RAM3.INIT_30=256'h81ff0670_ed3f8008_dbc13f8e_80e6e451_0d92d63f_0c04fc3d_0b81e094_3d0d0481;
defparam bootram.RAM3.INIT_31=256'h883880e7_51515473_2a708106_b408708d_e33f81b8_3f80518d_5255e5aa_5380e784;
defparam bootram.RAM3.INIT_32=256'h80e7fc51_802e9c38_af3f8008_800a51fe_db893f98_80e7d051_3974b738_9c518187;
defparam bootram.RAM3.INIT_33=256'hce398c80_e8b45180_83f93f80_98800a51_a73f7452_82ac51e0_518da93f_daf53f81;
defparam bootram.RAM3.INIT_34=256'h0a5197db_ff528c80_805380ff_c63f8380_e8dc51da_2ebd3880_3f800880_0a51fed1;
defparam bootram.RAM3.INIT_35=256'hd73f8052_82ac51df_51daa03f_3f80e9ac_e73ffed3_82ac51df_51dab03f_3f80e988;
defparam bootram.RAM3.INIT_36=256'h54a05373_fd3d0d75_f9f40c04_0d047180_8a3f863d_e9e851da_3f883980_805183ab;
defparam bootram.RAM3.INIT_37=256'h5372802e_80f9f408_51d8ae3f_3f725272_b451e3e2_735280ea_3880c053_87e82e84;
defparam bootram.RAM3.INIT_38=256'h80f9f408_51d88a3f_80c05280_51d8923f_0da05280_0d04fe3d_722d853d_85387351;
defparam bootram.RAM3.INIT_39=256'h70810651_8008862a_ac3fff0b_0d9a518d_0d04fc3d_722d843d_85388051_5372802e;
defparam bootram.RAM3.INIT_3A=256'h71828024_802e9b38_e4547182_06535580_80088680_ec38820b_71802e80_53548155;
defparam bootram.RAM3.INIT_3B=256'h08528551_8ce73f80_ff548451_802e8338_e8547184_388a3987_71802e8e_8a388a54;
defparam bootram.RAM3.INIT_3C=256'heaec5553_fa800c80_11337080_0780ebac_70830672_80088a2c_882a8c06_8cdf3f71;
defparam bootram.RAM3.INIT_3D=256'h387480f9_f8082e98_3f7480f9_5252d8a3_eee41108_2b8c0680_8a3f7182_515452d8;
defparam bootram.RAM3.INIT_3E=256'h7380f9fc_81069638_74822e09_b93f9e39_06a338fe_812e0981_2ea63874_f80c7482;
defparam bootram.RAM3.INIT_3F=256'h0dd4ca3f_0d04fd3d_ec3f863d_3f99518b_7351fde8_0cfe9f3f_7380f9fc_082e8e38;
defparam bootram.RAM4.INIT_00=256'hf53f81ae_5298518b_8bcb3f8d_fc0c9951_ff0b80f9_80f9f80c_c13f800b_8008518b;
defparam bootram.RAM4.INIT_01=256'h70535484_07f49f06_80089080_518bae3f_de8a3f84_ae528451_8bec3fbe_80529c51;
defparam bootram.RAM4.INIT_02=256'h518b823f_e0f83f80_80eb8451_08537352_2e8d3880_3f738008_84518b99_518bcf3f;
defparam bootram.RAM4.INIT_03=256'h0a0681d0_0a077ed0_0a0681d0_3d0d7cd0_3d0d04f6_8ba83f85_07528051_80088480;
defparam bootram.RAM4.INIT_04=256'h81ab9977_51dbf93f_71770c8a_51dc813f_710c578a_82c08072_83ffff52_0a075956;
defparam bootram.RAM4.INIT_05=256'h51dbd53f_86770c78_805a8199_e33f80e1_0c7851db_82d4e677_ef3f8a59_0c8a51db;
defparam bootram.RAM4.INIT_06=256'h71730707_812a8806_2a840672_2a077183_82067187_0670852a_067081ff_7583ffff;
defparam bootram.RAM4.INIT_07=256'h70818006_872b6306_80c00677_0676852b_077081ff_06717307_74832ba0_73109006;
defparam bootram.RAM4.INIT_08=256'h07077310_88067173_0672812a_71832a84_71872a07_852a8206_7a882a70_73730707;
defparam bootram.RAM4.INIT_09=256'h80067373_6d067081_0677872b_852b80c0_81ff0676_73070770_2ba00671_90067483;
defparam bootram.RAM4.INIT_0A=256'h58525351_5a555b51_53515752_586b4452_6d0c5151_83ffff06_2b7b0770_07077088;
defparam bootram.RAM4.INIT_0B=256'h7081ff06_0676902a_902a9680_daa23f75_770c7851_3f819981_5653daac_5752575d;
defparam bootram.RAM4.INIT_0C=256'h07077310_88067173_0672812a_71832a84_71872a07_852a8206_81ff0670_70730770;
defparam bootram.RAM4.INIT_0D=256'h7081ff06_78872b07_06707207_852b80c0_81ff0676_73070770_2ba00671_90067483;
defparam bootram.RAM4.INIT_0E=256'h680c5156_80067407_882b83fe_872b0770_06710772_852b80c0_10900671_7a882a70;
defparam bootram.RAM4.INIT_0F=256'h0c7851d9_81998577_81a18056_52d9a13f_57515157_58525a5a_51555351_67405b51;
defparam bootram.RAM4.INIT_10=256'h88067173_0672812a_71832a84_71872a07_852a8206_81ff0670_ffff0670_933f7783;
defparam bootram.RAM4.INIT_11=256'h7f067081_0677872b_852b80c0_81ff0676_73070770_2ba00671_90067483_07077310;
defparam bootram.RAM4.INIT_12=256'h71730707_812a8806_2a840672_2a077183_82067187_2a70852a_07077a88_80067373;
defparam bootram.RAM4.INIT_13=256'h70818006_872b6906_80c00677_0676852b_077081ff_06717307_74832ba0_73109006;
defparam bootram.RAM4.INIT_14=256'h5b515852_57525a55_44525351_5151586b_ff066d0c_077083ff_70882b7b_73730707;
defparam bootram.RAM4.INIT_15=256'h96800678_3f77902a_7851d7dc_9983770c_c1805581_d7ea3f81_575c5653_53515752;
defparam bootram.RAM4.INIT_16=256'h812a8806_2a840672_2a077183_82067187_0670852a_077081ff_ff067073_902a7081;
defparam bootram.RAM4.INIT_17=256'h872b6106_80c00677_0676852b_077081ff_06717307_74832ba0_73109006_71730707;
defparam bootram.RAM4.INIT_18=256'h07077088_66067173_0672872b_852b80c0_10900671_7a882a70_73730707_70818006;
defparam bootram.RAM4.INIT_19=256'h515952d6_5a5b5751_53515852_5b515852_69425a54_6a0c5152_83ffff06_2b750770;
defparam bootram.RAM4.INIT_1A=256'h3f80f077_7851d6b8_3f71770c_7851d6c0_3f80770c_5252d6c8_70780c79_d33f9985;
defparam bootram.RAM4.INIT_1B=256'h7851d694_3f71770c_7851d69c_3f71770c_5252d6a4_70780c79_af3f8880_0c7851d6;
defparam bootram.RAM4.INIT_1C=256'h839a3f86_5280d051_fc055380_8254873d_04fb3d0d_3f8c3d0d_7851d68c_3f71770c;
defparam bootram.RAM4.INIT_1D=256'h93269038_59577782_84120858_80d73d08_80d53d08_ffb23d0d_873d0d04_3d22800c;
defparam bootram.RAM4.INIT_1E=256'h80ec8805_38758429_962681a2_9f165675_81ac39ff_51da873f_5280ebbc_77538294;
defparam bootram.RAM4.INIT_1F=256'h5f80c65c_f73f8008_80085e8c_398cf33f_085e818c_c03f8008_80c15ccd_56750804;
defparam bootram.RAM4.INIT_20=256'hfab0518a_17085280_1708538c_80ea3990_5e80d65c_83ffff06_883f8008_80fa39ff;
defparam bootram.RAM4.INIT_21=256'h5cbe3980_863880c4_5675802e_0881ff06_8ae53f80_80fab051_5c80d539_a03f80c5;
defparam bootram.RAM4.INIT_22=256'h05539017_d03dfe80_5ca63980_873f80d7_17085189_1708528c_94175390_c25cb939;
defparam bootram.RAM4.INIT_23=256'h82945580_8339a05c_51f7f83f_5c805280_8f3980d3_3f80d25c_08518c93_08528c17;
defparam bootram.RAM4.INIT_24=256'h887826ec_34811858_57753377_3d790557_771980d2_833d5a58_0554800b_d03dfdec;
defparam bootram.RAM4.INIT_25=256'hf83d0d7a_5183873f_cdf93fff_80ece451_04803d0d_80d03d0d_51e1aa3f_38838082;
defparam bootram.RAM4.INIT_26=256'h81055833_3d347670_5754738a_38758117_807425b7_ff165654_57575874_7c7f7f5a;
defparam bootram.RAM4.INIT_27=256'h51d3953f_ff06548a_3f800881_0651d1a9_527781ff_8a3dfc05_05348253_028405a1;
defparam bootram.RAM4.INIT_28=256'h8338dc56_80de5674_a3053355_fa3d0d02_8a3d0d04_5473800c_38c13981_73802e85;
defparam bootram.RAM4.INIT_29=256'h5702ab05_f93d0d7c_883d0d04_51ff893f_f75280d0_fc055381_8154883d_75883d34;
defparam bootram.RAM4.INIT_2A=256'h5473802e_ff067056_3f800881_5256d0c9_a7053370_fc055202_8153893d_33893d34;
defparam bootram.RAM4.INIT_2B=256'h38815574_73802e83_06705654_800881ff_51cecb3f_537b5275_25973876_9e388077;
defparam bootram.RAM4.INIT_2C=256'hff065574_3f800881_d051ffa0_81f75280_3dfc0553_0d815488_0d04fa3d_800c893d;
defparam bootram.RAM4.INIT_2D=256'h56755574_06833881_de2e0981_56567480_0b883d33_3f953980_f051ccaf_8a3880ec;
defparam bootram.RAM4.INIT_2E=256'h81c0b00c_0c89b00b_0b81c0ac_c0800ca6_80eb0b81_81c0940c_0d04990b_800c883d;
defparam bootram.RAM4.INIT_2F=256'h70812a70_81c0a408_81c0a00c_0c51820b_0781c098_80067081_72882bbe_04803d0d;
defparam bootram.RAM4.INIT_30=256'h810781c0_be800670_0d72882b_0d04803d_800c823d_81c0a808_5170f138_81065151;
defparam bootram.RAM4.INIT_31=256'hf138823d_51515170_2a708106_a4087081_a00c81c0_840b81c0_81c09c0c_980c5173;
defparam bootram.RAM4.INIT_32=256'h83065271_718a3872_75830652_57719138_06555557_7a7c7283_fa3d0d78_0d04ff39;
defparam bootram.RAM4.INIT_33=256'h08720c52_11771270_73822b77_75279438_72555573_3f72822a_815189b2_802e8638;
defparam bootram.RAM4.INIT_34=256'h5353c9c3_11335451_0680ed90_842a708f_3d0d7470_3d0d04fe_54e93988_54528114;
defparam bootram.RAM4.INIT_35=256'h0870882a_5382e090_0d8386d0_0d04fe3d_b63f843d_335253c9_80ed9011_3f728f06;
defparam bootram.RAM4.INIT_36=256'hfc3d0d02_843d0d04_51ca803f_3880eda0_135372e9_2e8e38ff_51527180_70810651;
defparam bootram.RAM4.INIT_37=256'h2a708106_90087088_d05382e0_55558386_80c08007_8c800607_80ff067c_9b05337a;
defparam bootram.RAM4.INIT_38=256'he0900c77_800c7382_3f7882e0_a051c9c3_e93880ed_ff135372_802e8e38_51515271;
defparam bootram.RAM4.INIT_39=256'h90087088_d05382e0_a9388386_5274802e_e0900c74_82800782_e0980c73_81ff0682;
defparam bootram.RAM4.INIT_3A=256'h08527180_3f82e080_a051c8ff_e93880ed_ff135372_802e8e38_51515271_2a708106;
defparam bootram.RAM4.INIT_3B=256'h863d0d04_51fee13f_53805280_55885480_940c8880_810b82e0_04fc3d0d_0c863d0d;
defparam bootram.RAM4.INIT_3C=256'h04fc3d0d_0c863d0d_81ff0680_cb3f8008_528151fe_8a805381_80559054_fc3d0d88;
defparam bootram.RAM4.INIT_3D=256'h06800c82_08813281_0dca3f80_0d04803d_af3f863d_528051fe_54865381_88805588;
defparam bootram.RAM4.INIT_3E=256'h85923f75_3d0d7756_3d0d04fb_2ef43882_06517080_800881ff_3d0deb3f_3d0d0480;
defparam bootram.RAM4.INIT_3F=256'hfdde3f87_81528051_9b0a0753_fe9b0a06_55a05475_b43f8880_38dd3fff_8008269b;
defparam bootram.RAM5.INIT_00=256'h38751754_ff2681b4_80557381_11565757_cb3d08ff_c93d0880_ba3d0d80_3d0d04ff;
defparam bootram.RAM5.INIT_01=256'h3d085273_755380cb_548cbe3f_883d7052_5381ff52_a7388280_80082681_84ce3f73;
defparam bootram.RAM5.INIT_02=256'h0a0680c0_0c76fec0_0b82e090_980c8880_3f7482e0_d43ffce6_fefd3ffe_518b993f;
defparam bootram.RAM5.INIT_03=256'h3f80c83d_900cfcb6_a00b82e0_e0900c8a_88a00b82_82e0980c_800c810b_0a0782e0;
defparam bootram.RAM5.INIT_04=256'h82e0840c_88157008_880c54fe_700882e0_54fe8415_82e08c0c_80157008_558f56fe;
defparam bootram.RAM5.INIT_05=256'hff169016_0cfbf73f_0b82e090_900c8a80_800b82e0_800c5488_700882e0_54fe8c15;
defparam bootram.RAM5.INIT_06=256'h7b7d7212_f93d0d79_c83d0d04_74800c80_980c8155_800b82e0_25ffbc38_56567580;
defparam bootram.RAM5.INIT_07=256'h5473802e_7581ff06_2e80c338_81577480_2680cb38_57738008_838a3f80_575a5656;
defparam bootram.RAM5.INIT_08=256'h19767631_3f731674_7551fdeb_77537352_83387654_57767527_74317555_a2388280;
defparam bootram.RAM5.INIT_09=256'h0c893d0d_81577680_39fd8c3f_828054dc_7527e138_74548280_802e8e38_57595674;
defparam bootram.RAM5.INIT_0A=256'h0b88160c_27903880_3f800874_1354829c_2e8d3873_54557380_76787a56_04fc3d0d;
defparam bootram.RAM5.INIT_0B=256'h08307276_81ec3f80_16565152_707406ff_3f800830_a63981fa_0c80750c_800b8416;
defparam bootram.RAM5.INIT_0C=256'h0881ff06_fc983f80_3d0d7554_3d0d04fd_fcc93f86_160c7151_160c7188_0c740684;
defparam bootram.RAM5.INIT_0D=256'h7088160c_08800805_b13f8814_2e943881_08841508_81538814_802e9f38_70545271;
defparam bootram.RAM5.INIT_0E=256'h51f9fd3f_53815281_5481f90a_888055a0_04fc3d0d_0c853d0d_80537280_51fc943f;
defparam bootram.RAM5.INIT_0F=256'h882a7081_d43f8008_7480c238_fa840855_fb3d0d80_863d0d04_0a06800c_8008fe80;
defparam bootram.RAM5.INIT_10=256'h7380c02e_83388155_3f73a02e_5154cdbe_edbc5458_56715580_81ff0670_ff068008;
defparam bootram.RAM5.INIT_11=256'h08ea1155_0c80fa84_7580fa84_fe3f9c39_edd451c2_2e8a3880_06547380_93387481;
defparam bootram.RAM5.INIT_12=256'h800880ee_04ff913f_0c873d0d_dc3f7480_cd843ff4_80edf451_8d387452_55827427;
defparam bootram.RAM5.INIT_13=256'h3d0d7d56_800c04f6_0b80082b_fefa3f81_2b800c04_810b8008_0c04f23f_de053380;
defparam bootram.RAM5.INIT_14=256'h0c810b82_2b82e080_840c7c88_8b0b82e0_82e0900c_0c88800b_0b82e098_f8b03f80;
defparam bootram.RAM5.INIT_15=256'hd3388880_73762780_7e558054_0cf7ff3f_0b82e090_900c8aa8_a80b82e0_e0980c88;
defparam bootram.RAM5.INIT_16=256'h085a82e0_5982e084_82e08808_e08c0858_f7e43f82_82e0900c_0c8a800b_0b82e090;
defparam bootram.RAM5.INIT_17=256'h51703375_91387117_52717327_38705380_70732783_52579053_3d767531_80085b88;
defparam bootram.RAM5.INIT_18=256'h0d7251f6_0d04803d_980c8c3d_800b82e0_54ffa939_ec397214_34811252_70810557;
defparam bootram.RAM5.INIT_19=256'h0870800c_82de3f80_88050851_08528c08_8c088c05_3d0d8053_028c0cfd_a13f8c08;
defparam bootram.RAM5.INIT_1A=256'h5182b93f_08880508_0508528c_538c088c_fd3d0d81_08028c0c_8c0c048c_54853d0d;
defparam bootram.RAM5.INIT_1B=256'h08880508_fc050c8c_800b8c08_0cf93d0d_8c08028c_0d8c0c04_0c54853d_80087080;
defparam bootram.RAM5.INIT_1C=256'h38810b8c_fc050888_050c8c08_0b8c08f4_88050c80_08308c08_8c088805_8025ab38;
defparam bootram.RAM5.INIT_1D=256'h308c088c_088c0508_25ab388c_8c050880_050c8c08_088c08fc_8c08f405_08f4050c;
defparam bootram.RAM5.INIT_1E=256'h8c08fc05_08f00508_f0050c8c_810b8c08_05088838_0c8c08fc_8c08f005_050c800b;
defparam bootram.RAM5.INIT_1F=256'h08fc0508_050c548c_708c08f8_a73f8008_05085181_528c0888_088c0508_0c80538c;
defparam bootram.RAM5.INIT_20=256'h0c048c08_893d0d8c_70800c54_08f80508_f8050c8c_08308c08_8c08f805_802e8c38;
defparam bootram.RAM5.INIT_21=256'h8c088805_88050830_93388c08_05088025_0c8c0888_8c08fc05_3d0d800b_028c0cfb;
defparam bootram.RAM5.INIT_22=256'h81538c08_088c050c_0508308c_388c088c_0880258c_8c088c05_08fc050c_0c810b8c;
defparam bootram.RAM5.INIT_23=256'h8c388c08_0508802e_548c08fc_08f8050c_8008708c_0851ad3f_8c088805_8c050852;
defparam bootram.RAM5.INIT_24=256'h0cfd3d0d_8c08028c_0d8c0c04_0c54873d_05087080_0c8c08f8_8c08f805_f8050830;
defparam bootram.RAM5.INIT_25=256'h08fc0508_27ac388c_08880508_8c05088c_050c8c08_0b8c08f8_fc050c80_810b8c08;
defparam bootram.RAM5.INIT_26=256'h0508108c_0c8c08fc_8c088c05_8c050810_99388c08_8c050824_800b8c08_802ea338;
defparam bootram.RAM5.INIT_27=256'h388c0888_050826a1_088c0888_8c088c05_2e80c938_fc050880_c9398c08_08fc050c;
defparam bootram.RAM5.INIT_28=256'h0c8c08fc_8c08f805_fc050807_05088c08_0c8c08f8_8c088805_8c050831_05088c08;
defparam bootram.RAM5.INIT_29=256'h08802e8f_8c089005_0cffaf39_8c088c05_0508812a_0c8c088c_8c08fc05_0508812a;
defparam bootram.RAM5.INIT_2A=256'h08f40508_050c518c_708c08f4_08f80508_518d398c_08f4050c_0508708c_388c0888;
defparam bootram.RAM5.INIT_2B=256'h70802eb0_07830651_8c387474_52837227_77795656_fc3d0d78_0d8c0c04_800c853d;
defparam bootram.RAM5.INIT_2C=256'h14545555_158115ff_06bd3881_712e0981_33525372_38743374_71ff2ea0_38ff1252;
defparam bootram.RAM5.INIT_2D=256'h8f388411_2e098106_70087308_74745451_863d0d04_800b800c_8106e238_71ff2e09;
defparam bootram.RAM5.INIT_2E=256'hfc3d0d76_863d0d04_7131800c_ffaf3972_70735555_8326e938_54545171_8414fc14;
defparam bootram.RAM5.INIT_2F=256'h2e983872_125271ff_2ea738ff_06517080_72750783_72278c38_5555558f_70797b55;
defparam bootram.RAM5.INIT_30=256'h04745172_0c863d0d_ea387480_2e098106_125271ff_055634ff_33747081_70810554;
defparam bootram.RAM5.INIT_31=256'h08717084_70840554_05530c72_08717084_70840554_05530c72_08717084_70840554;
defparam bootram.RAM5.INIT_32=256'h72708405_72279538_26c93883_1252718f_05530cf0_08717084_70840554_05530c72;
defparam bootram.RAM5.INIT_33=256'h8c059f05_76797102_39fc3d0d_7054ff83_8326ed38_fc125271_8405530c_54087170;
defparam bootram.RAM5.INIT_34=256'h73708105_2e933873_125271ff_2ea238ff_06517080_8a387483_55837227_33575553;
defparam bootram.RAM5.INIT_35=256'h902b0751_75077071_7474882b_863d0d04_3874800c_098106ef_5271ff2e_5534ff12;
defparam bootram.RAM5.INIT_36=256'h72717084_8405530c_0c727170_70840553_530c7271_71708405_27a53872_54518f72;
defparam bootram.RAM5.INIT_37=256'h26f23870_12527183_05530cfc_72717084_72279038_26dd3883_1252718f_05530cf0;
defparam bootram.RAM5.INIT_38=256'h802e80d4_83065170_38717407_802e80d9_55555272_7a7c7054_fa3d0d78_53ff9039;
defparam bootram.RAM5.INIT_39=256'h387081ff_802e8187_06a93872_712e0981_33565174_38713374_72ff2eb1_38ff1353;
defparam bootram.RAM5.INIT_3A=256'h33565170_38713374_098106d1_5272ff2e_ff155555_81128115_2e80fc38_06517080;
defparam bootram.RAM5.INIT_3B=256'h38710874_83732788_71745755_883d0d04_5270800c_71315152_81ff0671_81ff0675;
defparam bootram.RAM5.INIT_3C=256'h0670f884_fbfdff12_087009f7_2eb13874_13537280_ff9739fc_74765552_082e8838;
defparam bootram.RAM5.INIT_3D=256'h74765552_082ed038_38740876_837327d0_84175755_9a388415_51515170_82818006;
defparam bootram.RAM5.INIT_3E=256'h80fa880c_2e9e3873_54547281_80eeb408_3d0d800b_3d0d04fd_0b800c88_fedf3980;
defparam bootram.RAM5.INIT_3F=256'h0cffa8e0_7280fa88_51f6a33f_893f8008_8151ffb0_80eef852_ffa8993f_ffa8fd3f;
defparam bootram.RAM6.INIT_00=256'hef800bfc_ff3d0d80_3f00ff39_0851f686_afec3f80_528151ff_3f80eef8_3fffa7fc;
defparam bootram.RAM6.INIT_01=256'h0d0404ff_f138833d_2e098106_525270ff_fc127008_9138702d_5270ff2e_05700852;
defparam bootram.RAM6.INIT_02=256'h636b6574_6c207061_6e74726f_6e20636f_6f722069_21457272_00000040_a98b3f04;
defparam bootram.RAM6.INIT_03=256'h6c697479_74696269_6f6d7061_65642063_70656374_3a204578_646c6572_2068616e;
defparam bootram.RAM6.INIT_04=256'h6f722069_21457272_25640a00_676f7420_62757420_25642c20_62657220_206e756d;
defparam bootram.RAM6.INIT_05=256'h70656374_3a204578_646c6572_2068616e_636b6574_6c207061_6e74726f_6e20636f;
defparam bootram.RAM6.INIT_06=256'h74202564_7420676f_2c206275_68202564_656e6774_6164206c_61796c6f_65642070;
defparam bootram.RAM6.INIT_07=256'h203d2025_70656564_643a2073_616e6765_6b206368_206c696e_0a657468_0a000000;
defparam bootram.RAM6.INIT_08=256'h720a0000_6f616465_6f6f746c_44502062_31302055_50204e32_0a555352_640a0000;
defparam bootram.RAM6.INIT_09=256'h640a0000_723a2025_756d6265_7479206e_62696c69_70617469_20636f6d_46504741;
defparam bootram.RAM6.INIT_0A=256'h723a2025_756d6265_7479206e_62696c69_70617469_20636f6d_77617265_4669726d;
defparam bootram.RAM6.INIT_0B=256'h7061636b_65727920_65636f76_69702072_476f7420_00000000_61646472_640a0000;
defparam bootram.RAM6.INIT_0C=256'h0000078f_00000765_0000078f_0000078f_000006df_000006f6_00000000_65743a20;
defparam bootram.RAM6.INIT_0D=256'h0000066d_0000078f_000006a7_00000713_0000078f_0000078f_0000078f_0000078f;
defparam bootram.RAM6.INIT_0E=256'h00000738_00000733_0000072e_0000067a_0000078f_0000078f_0000078f_0000078f;
defparam bootram.RAM6.INIT_0F=256'h6e203d20_7273696f_70207665_20636869_4c4d5331_00000753_00000746_0000073f;
defparam bootram.RAM6.INIT_10=256'h30782578_6e203d20_7273696f_70207665_20636869_4c4d5332_0a000000_30782578;
defparam bootram.RAM6.INIT_11=256'h6932635f_01c300e2_054a0387_15290a94_3fff0000_0050c285_c0a80a02_0a000000;
defparam bootram.RAM6.INIT_12=256'h5f666f72_77616974_21000000_696c6564_47206661_4348444f_20574154_72656164;
defparam bootram.RAM6.INIT_13=256'h77726974_6932635f_64210000_61696c65_4f472066_54434844_72205741_5f786665;
defparam bootram.RAM6.INIT_14=256'h642e2564_25642e25_45000000_64210000_61696c65_4f472066_54434844_65205741;
defparam bootram.RAM6.INIT_15=256'hffff0000_ffffffff_00000000_43444546_38394142_34353637_30313233_2e256400;
defparam bootram.RAM6.INIT_16=256'h656e2061_6f66206c_656e7420_69676e6d_6420616c_3a206261_5f706b74_73656e64;
defparam bootram.RAM6.INIT_17=256'h65642074_6661696c_6f6e3a20_636f6d6d_6e65745f_66000000_72206275_6e642f6f;
defparam bootram.RAM6.INIT_18=256'h0a68616e_00000000_666f7220_696e6720_6c6f6f6b_63686520_74206361_6f206869;
defparam bootram.RAM6.INIT_19=256'h55445020_0a000000_3d202564_697a6520_72642073_20776569_6172703a_646c655f;
defparam bootram.RAM6.INIT_1A=256'h00000000_2025640a_3a202564_67746873_206c656e_74656e74_6e736973_696e636f;
defparam bootram.RAM6.INIT_1B=256'h616c697a_6e697469_656e2069_73206265_68206861_466c6173_53504920_0b0b0b0b;
defparam bootram.RAM6.INIT_1C=256'h53746172_640a0000_203d2025_6d616765_6f6e2069_75637469_50726f64_65640000;
defparam bootram.RAM6.INIT_1D=256'h64696e67_204c6f61_6f64652e_6665206d_6e207361_52582069_20556d54_74696e67;
defparam bootram.RAM6.INIT_1E=256'h2076616c_20666f72_6b696e67_43686563_72652e00_726d7761_65206669_20736166;
defparam bootram.RAM6.INIT_1F=256'h56616c69_2e2e2e00_6d616765_47412069_6e204650_6374696f_726f6475_69642070;
defparam bootram.RAM6.INIT_20=256'h642e2041_666f756e_61676520_4120696d_20465047_74696f6e_6f647563_64207072;
defparam bootram.RAM6.INIT_21=256'h2070726f_616c6964_4e6f2076_742e0000_20626f6f_6720746f_7074696e_7474656d;
defparam bootram.RAM6.INIT_22=256'h56616c69_2e0a0000_6f756e64_67652066_20696d61_46504741_696f6e20_64756374;
defparam bootram.RAM6.INIT_23=256'h204c6f61_756e642e_6520666f_6d776172_20666972_74696f6e_6f647563_64207072;
defparam bootram.RAM6.INIT_24=256'h61727469_2e205374_64696e67_206c6f61_73686564_46696e69_2e2e2e00_64696e67;
defparam bootram.RAM6.INIT_25=256'h6f6d206d_6e206672_65747572_523a2052_4552524f_2e000000_6d616765_6e672069;
defparam bootram.RAM6.INIT_26=256'h65722068_206e6576_6f756c64_73207368_20546869_72616d21_70726f67_61696e20;
defparam bootram.RAM6.INIT_27=256'h6669726d_696f6e20_64756374_2070726f_616c6964_4e6f2076_6e210000_61707065;
defparam bootram.RAM6.INIT_28=256'h746f2062_75676820_7468726f_696e6720_46616c6c_6e642e20_20666f75_77617265;
defparam bootram.RAM6.INIT_29=256'h7420746f_64207365_53706565_2e000000_77617265_6669726d_2d696e20_75696c74;
defparam bootram.RAM6.INIT_2A=256'h58000000_57455f52_58000000_57455f54_00000000_4e4f4e45_00000000_2025640a;
defparam bootram.RAM6.INIT_2B=256'h6e74726f_7720636f_20666c6f_726e6574_65746865_43000000_45545249_53594d4d;
defparam bootram.RAM6.INIT_2C=256'h7825782c_74652030_2077726f_4144563a_4e45475f_4155544f_5048595f_6c3a2000;
defparam bootram.RAM6.INIT_2D=256'h21457272_00030203_00000001_00030003_00000000_780a0000_20307825_20676f74;
defparam bootram.RAM6.INIT_2E=256'h20457870_6c65723a_68616e64_6b657420_20706163_64617465_6e207570_6f722069;
defparam bootram.RAM6.INIT_2F=256'h20676f74_20627574_2025642c_6e677468_64206c65_796c6f61_64207061_65637465;
defparam bootram.RAM6.INIT_30=256'h000023f1_00002413_00002428_0000247a_0000247a_000023e4_00000000_2025640a;
defparam bootram.RAM6.INIT_31=256'h0000247a_0000247a_0000247a_0000247a_0000247a_0000247a_0000247a_0000247a;
defparam bootram.RAM6.INIT_32=256'h00002403_0000247a_0000247a_0000246e_00002457_0000247a_0000247a_0000247a;
defparam bootram.RAM6.INIT_33=256'h61642073_6f207265_65642074_4661696c_00000000_6f72740a_0a0a6162_00002444;
defparam bootram.RAM6.INIT_34=256'h43444546_38394142_34353637_30313233_67000000_20666c61_626f6f74_61666520;
defparam bootram.RAM6.INIT_35=256'h0a666c61_64210000_61696c65_4f472066_54434844_74205741_5f776169_73706966;
defparam bootram.RAM6.INIT_36=256'h6c617368_6e672066_0a57726f_25640a00_697a653d_25642073_7970653d_73682074;
defparam bootram.RAM6.INIT_37=256'h6c617368_6e672066_0a57726f_00000000_6e67210a_63687475_652e2041_20747970;
defparam bootram.RAM6.INIT_38=256'h65000000_792e6578_64756d6d_67210a00_6874756e_64204163_653a2025_2073697a;
defparam bootram.RAM6.INIT_39=256'h00003788_00000000_00000000_00000000_ffffff00_ffff00ff_ff00ffff_00ffffff;
defparam bootram.RAM6.INIT_3A=256'h000c0000_00190010_ffff0033_04000400_01010100_3fff0000_0050c285_c0a80a02;
defparam bootram.RAM6.INIT_3B=256'hffffffff_00003714_10101200_00003560_00003558_00003550_00003548_03197500;
defparam bootram.RAM6.INIT_3C=256'h00000000_00000000_00000000_00000000_00000000_00000000_ffffffff_00000000;
defparam bootram.RAM6.INIT_3D=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_3E=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;
defparam bootram.RAM6.INIT_3F=256'h00000000_00000000_00000000_00000000_00000000_00000000_00000000_00000000;

View File

@@ -1,312 +0,0 @@
## Only for xc6slx75 in package fgg484 ver.A 2011/10/12
## ETH PHY
NET "GMII_GTX_CLK" LOC = H21;
NET "GMII_RX_CLK" LOC = H22;
NET "GMII_TX_CLK" LOC = J22;
NET "ETH_LED" LOC = W12;
NET "ETH_LEDG" LOC = Y15;
NET "GMII_RXD[0]" LOC = L20;
NET "GMII_RXD[1]" LOC = K22;
NET "GMII_RXD[2]" LOC = K21;
NET "GMII_RXD[3]" LOC = F18;
NET "GMII_RXD[4]" LOC = J20;
NET "GMII_RXD[5]" LOC = F19;
NET "GMII_RXD[6]" LOC = F20;
NET "GMII_RXD[7]" LOC = G22;
NET "GMII_RX_DV" LOC = L22;
NET "GMII_RX_ER" LOC = M22;
NET "GMII_TXD[0]" LOC = T22;
NET "GMII_TXD[1]" LOC = T21;
NET "GMII_TXD[2]" LOC = U22;
NET "GMII_TXD[3]" LOC = U20;
NET "GMII_TXD[4]" LOC = V22;
NET "GMII_TXD[5]" LOC = V21;
NET "GMII_TXD[6]" LOC = W22;
NET "GMII_TXD[7]" LOC = W20;
NET "GMII_TX_EN" LOC = T19;
NET "GMII_COL" LOC = N22;
NET "GMII_CRS" LOC = P20;
NET "GMII_TX_ER" LOC = R22;
NET "CLK_TO_MAC" LOC = G20;
NET "MDIO" LOC = F21;
NET "MDC" LOC = F22;
NET "PHY_INTn" LOC = E22;
NET "PHY_RESETn" LOC = R20;
## UARTS
NET "RXD[1]" LOC = T17; // FPGA output -> FTDI input
NET "RXD[2]" LOC = AB17; // FPGA output -> GPS input
NET "TXD[1]" LOC = T18; // FPGA input <- FTDI output
NET "TXD[2]" LOC = Y17; // FPGA input <- GPS output
## Global CLK
NET "CLK_FPGA_N" LOC = L19; // POSSIBLE UNUSED IF LVCMOS25
NET "CLK_FPGA_P" LOC = M20;
NET "FPGA_RESET" LOC = AB4;
## LMS
NET "RX1IQSEL" LOC = J4;//"RX_IQ_SEL_0"
NET "RX2IQSEL" LOC = P8;//"RX_IQ_SEL_1"
NET "TX1IQSEL" LOC = H6;//"TX_IQ_SEL_0"
NET "TX2IQSEL" LOC = M5;//"TX_IQ_SEL_1"
NET "RX1D[0]" LOC = J1;//"ADC_0[0]"
NET "RX1D[1]" LOC = L6;//"ADC_0[1]"
NET "RX1D[2]" LOC = H3;//"ADC_0[2]"
NET "RX1D[3]" LOC = K6;//"ADC_0[3]"
NET "RX1D[4]" LOC = K5;//"ADC_0[4]"
NET "RX1D[5]" LOC = H2;//"ADC_0[5]"
NET "RX1D[6]" LOC = J3;//"ADC_0[6]"
NET "RX1D[7]" LOC = K4;//"ADC_0[7]"
NET "RX1D[8]" LOC = J6;//"ADC_0[8]"
NET "RX1D[9]" LOC = M8;//"ADC_0[9]"
NET "RX1D[10]" LOC = J7;//"ADC_0[10]"
NET "RX1D[11]" LOC = N7;//"ADC_0[11]"
NET "RX2D[0]" LOC = T2;//"ADC_1[0]"
NET "RX2D[1]" LOC = T3;//"ADC_1[1]"
NET "RX2D[2]" LOC = U1;//"ADC_1[2]"
NET "RX2D[3]" LOC = T4;//"ADC_1[3]"
NET "RX2D[4]" LOC = V3;//"ADC_1[4]"
NET "RX2D[5]" LOC = T1;//"ADC_1[5]"
NET "RX2D[6]" LOC = U3;//"ADC_1[6]"
NET "RX2D[7]" LOC = U4;//"ADC_1[7]"
NET "RX2D[8]" LOC = V2;//"ADC_1[8]"
NET "RX2D[9]" LOC = V1;//"ADC_1[9]"
NET "RX2D[10]" LOC = W1;//"ADC_1[10]"
NET "RX2D[11]" LOC = W3;//"ADC_1[11]"
NET "ADC_CLK_O1" LOC = G3;//"RX1_CLK/2"
NET "ADC_CLK_O2" LOC = N1;//"RX2_CLK/2"
NET "RX1_EN" LOC = L1;//"ADC_EN_0"
NET "RX2_EN" LOC = Y2;//"ADC_EN_1"
NET "TX1EN" LOC = G1;
NET "TX2EN" LOC = N4;
NET "TX1CLK" LOC = K3;//"DAC_CLK_0"
NET "TX2CLK" LOC = M3;//"DAC_CLK_1"
NET "TX1D[0]" LOC = H4;//"DAC_0[0]"
NET "TX1D[1]" LOC = H8;//"DAC_0[1]"
NET "TX1D[2]" LOC = G4;//"DAC_0[2]"
NET "TX1D[3]" LOC = G7;//"DAC_0[3]"
NET "TX1D[4]" LOC = F5;//"DAC_0[4]"
NET "TX1D[5]" LOC = F7;//"DAC_0[5]"
NET "TX1D[6]" LOC = G6;//"DAC_0[6]"
NET "TX1D[7]" LOC = E5;//"DAC_0[7]"
NET "TX1D[8]" LOC = F3;//"DAC_0[8]"
NET "TX1D[9]" LOC = E4;//"DAC_0[9]"
NET "TX1D[10]" LOC = H1;//"DAC_0[10]"
NET "TX1D[11]" LOC = E6;//"DAC_0[11]"
NET "TX2D[0]" LOC = R3;//"DAC_1[0]"
NET "TX2D[1]" LOC = L4;//"DAC_1[1]"
NET "TX2D[2]" LOC = R1;//"DAC_1[2]"
NET "TX2D[3]" LOC = K7;//"DAC_1[3]"
NET "TX2D[4]" LOC = P2;//"DAC_1[4]"
NET "TX2D[5]" LOC = K8;//"DAC_1[5]"
NET "TX2D[6]" LOC = P1;//"DAC_1[6]"
NET "TX2D[7]" LOC = P4;//"DAC_1[7]"
NET "TX2D[8]" LOC = P5;//"DAC_1[8]"
NET "TX2D[9]" LOC = P6;//"DAC_1[9]"
NET "TX2D[10]" LOC = P3;//"DAC_1[10]"
NET "TX2D[11]" LOC = N3;//"DAC_1[11]"
NET "LMS1nRST" LOC = L3;//"LMS_RESET_0"
NET "LMS2nRST" LOC = Y1;//"LMS_RESET_1"
NET "SCLK1" LOC = F1;//LMS_SACLK_0
NET "SCLK2" LOC = H5;//LMS_SACLK_1
NET "MISO1" LOC = F2;//"LMS_SADIO_0"
NET "MISO2" LOC = N6;//"LMS_SADIO_1"
NET "MOSI1" LOC = E3;//"LMS_SADO_0"
NET "MOSI2" LOC = M7;//"LMS_SADO_1"
NET "SEN1" LOC = E1;//"LMS_SAEN_0"
NET "SEN2" LOC = M4;//"LMS_SAEN_1"
NET "DivSw1_N" LOC = K1;
NET "DivSw1_P" LOC = K2;
NET "DivSw2_N" LOC = M1;
NET "DivSw2_P" LOC = M2;
## PPS
NET "PPS_IN" LOC = AB18;
## SRAM
NET "RAM_A[0]" LOC = A14;
NET "RAM_A[1]" LOC = C14;
NET "RAM_A[2]" LOC = A6;
NET "RAM_A[3]" LOC = B6;
NET "RAM_A[4]" LOC = D3;
NET "RAM_A[5]" LOC = D1;
NET "RAM_A[6]" LOC = D2;
NET "RAM_A[7]" LOC = B18;
NET "RAM_A[8]" LOC = A18;
NET "RAM_A[9]" LOC = C17;
NET "RAM_A[10]" LOC = A17;
NET "RAM_A[11]" LOC = B16;
NET "RAM_A[12]" LOC = A16;
NET "RAM_A[13]" LOC = C16;
NET "RAM_A[14]" LOC = A13;
NET "RAM_A[15]" LOC = B12;
NET "RAM_A[16]" LOC = A12;
NET "RAM_A[17]" LOC = A11;
NET "RAM_A[18]" LOC = C1;
NET "RAM_A[19]" LOC = A15;
NET "RAM_A[20]" LOC = B14;
NET "RAM_BWn[0]" LOC = C4;
NET "RAM_BWn[1]" LOC = A4;
NET "RAM_BWn[2]" LOC = D7;
NET "RAM_BWn[3]" LOC = A5;
NET "RAM_CENn" LOC = C3;
NET "RAM_CLK" LOC = B3;
NET "RAM_LDn" LOC = B1;
NET "RAM_OEn" LOC = B2;
NET "RAM_WEn" LOC = A2;
NET "RAM_ZZ" LOC = F16;
NET "RAM_D[0]" LOC = E12;
NET "RAM_D[1]" LOC = D12;
NET "RAM_D[2]" LOC = D13;
NET "RAM_D[3]" LOC = C12;
NET "RAM_D[4]" LOC = D14;
NET "RAM_D[5]" LOC = C13;
NET "RAM_D[6]" LOC = D15;
NET "RAM_D[7]" LOC = C15;
NET "RAM_D[8]" LOC = D17;
NET "RAM_D[9]" LOC = D11;
NET "RAM_D[10]" LOC = D10;
NET "RAM_D[11]" LOC = C10;
NET "RAM_D[12]" LOC = D9;
NET "RAM_D[13]" LOC = C8;
NET "RAM_D[14]" LOC = C7;
NET "RAM_D[15]" LOC = D6;
NET "RAM_D[16]" LOC = C5;
NET "RAM_D[17]" LOC = D5;
NET "RAM_D[18]" LOC = A7;
NET "RAM_D[19]" LOC = B8;
NET "RAM_D[20]" LOC = A8;
NET "RAM_D[21]" LOC = C9;
NET "RAM_D[22]" LOC = D8;
NET "RAM_D[23]" LOC = H13;
NET "RAM_D[24]" LOC = F13;
NET "RAM_D[25]" LOC = G13;
NET "RAM_D[26]" LOC = C6;
NET "RAM_D[27]" LOC = E14;
NET "RAM_D[28]" LOC = F14;
NET "RAM_D[29]" LOC = F15;
NET "RAM_D[30]" LOC = E16;
NET "RAM_D[31]" LOC = H14;
NET "RAM_D[32]" LOC = A9;
NET "RAM_D[33]" LOC = B10;
NET "RAM_D[34]" LOC = A10;
NET "RAM_D[35]" LOC = C11;
## I2C
NET "SCL" LOC = AA14;
NET "SDA" LOC = AA16;
# DAC
NET "SCLK_DAC" LOC = AB19;
NET "SEN_DAC" LOC = Y19;
NET "MOSI_DAC" LOC = AA18;
## SPI Flash
NET "flash_clk" LOC = Y21;
NET "flash_cs" LOC = T5;
NET "flash_miso" LOC = AA20;
NET "flash_mosi" LOC = AB20;
## LEDS
NET "leds[1]" LOC = Y3;
NET "leds[2]" LOC = W4;
NET "leds[3]" LOC = AB2;
NET "leds[4]" LOC = Y4;
NET "leds[5]" LOC = AA2;
### Debug
NET "debug[0]" LOC = D22;
NET "debug[1]" LOC = E20;
NET "debug[2]" LOC = C22;
NET "debug[3]" LOC = D21;
NET "debug[4]" LOC = B22;
NET "debug[5]" LOC = C20;
NET "debug[6]" LOC = A21;
NET "debug[7]" LOC = B21;
NET "debug[8]" LOC = A20;
NET "debug[9]" LOC = B20;
NET "debug[10]" LOC = H20;
NET "debug[11]" LOC = J19;
NET "debug[12]" LOC = H18;
NET "debug[13]" LOC = H19;
NET "debug[14]" LOC = J16;
NET "debug[15]" LOC = J17;
NET "debug[16]" LOC = G19;
NET "debug[17]" LOC = H16;
NET "debug[18]" LOC = G16;
NET "debug[19]" LOC = D20;
NET "debug[20]" LOC = D19;
NET "debug[21]" LOC = F17;
NET "debug[22]" LOC = K17;
NET "debug[23]" LOC = C19;
NET "debug[24]" LOC = K19;
NET "debug[25]" LOC = N20;
NET "debug[26]" LOC = M19;
NET "debug[27]" LOC = K20;
NET "debug[28]" LOC = N19;
NET "debug[29]" LOC = K18;
NET "debug[30]" LOC = K16;
NET "debug[31]" LOC = L17;
NET "debug_clk[0]" LOC = L15;
NET "debug_clk[1]" LOC = N16;
#NET "CLK_FPGA_N" IOSTANDARD = LVPECL_25;// POSSIBLE LVCMOS25 OR UNUSED
#NET "CLK_FPGA_P" IOSTANDARD = LVPECL_25;// POSSIBLE LVCMOS25
NET "FPGA_RESET" IOSTANDARD = LVCMOS33;
NET "ETH_LED" IOSTANDARD = LVCMOS33;
NET "ETH_LEDG" IOSTANDARD = LVCMOS33;
NET "CLK_TO_MAC" IOSTANDARD = LVCMOS25;
NET "GMII_GTX_CLK" IOSTANDARD = LVCMOS25;
NET "PPS_IN" IOSTANDARD = LVCMOS33;
NET "SCL" IOSTANDARD = LVCMOS33;
NET "SDA" IOSTANDARD = LVCMOS33;
NET "flash_clk" IOSTANDARD = LVCMOS33;
NET "flash_cs" IOSTANDARD = LVCMOS33;
NET "flash_miso" IOSTANDARD = LVCMOS33;
NET "flash_mosi" IOSTANDARD = LVCMOS33;
NET "leds[1]" IOSTANDARD = LVCMOS33;
NET "leds[2]" IOSTANDARD = LVCMOS33;
NET "leds[3]" IOSTANDARD = LVCMOS33;
NET "leds[4]" IOSTANDARD = LVCMOS33;
NET "leds[5]" IOSTANDARD = LVCMOS33;
NET "GMII_GTX_CLK" SLEW = SLOW;
NET "flash_clk" SLEW = SLOW;
NET "SCLK_DAC" IOSTANDARD = LVCMOS33;
NET "SEN_DAC" IOSTANDARD = LVCMOS33;
NET "MOSI_DAC" IOSTANDARD = LVCMOS33;
NET "RXD[1]" IOSTANDARD = LVCMOS33;// FPGA output -> FTDI input
NET "RXD[2]" IOSTANDARD = LVCMOS33;// FPGA output -> GPS input
NET "RXD[3]" IOSTANDARD = LVCMOS33;
NET "TXD[1]" IOSTANDARD = LVCMOS33;// FPGA input <- FTDI output
NET "TXD[2]" IOSTANDARD = LVCMOS33;// FPGA input <- GPS output
NET "TXD[3]" IOSTANDARD = LVCMOS33;
NET "DivSw1_N" IOSTANDARD = LVCMOS25;
NET "DivSw1_P" IOSTANDARD = LVCMOS25;
NET "DivSw2_N" IOSTANDARD = LVCMOS25;
NET "DivSw2_P" IOSTANDARD = LVCMOS25;
NET "clk_fpga_p" TNM_NET = "clk_fpga_p";
TIMESPEC TS_clk_fpga_p = PERIOD "clk_fpga_p" 38 ns HIGH 50 %;
NET "clk_to_mac" TNM_NET = "clk_to_mac";
TIMESPEC TS_clk_to_mac = PERIOD "clk_to_mac" 8 ns HIGH 50 %;
NET "GMII_RX_CLK" TNM_NET = "GMII_RX_CLK";
TIMESPEC TS_GMII_RX_CLK = PERIOD "GMII_RX_CLK" 8 ns HIGH 50 %;

View File

@@ -1,434 +0,0 @@
//
// Copyright 2011 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>.
//
`timescale 1ns / 1ps
//`define LVDS 1
//`define DCM_FOR_RAMCLK
//////////////////////////////////////////////////////////////////////////////////
module u2plus_umtrx
(
input CLK_FPGA_P, input CLK_FPGA_N, // Diff
// ADC 1
input ADC_CLK_O1,
input RX1IQSEL,
output RX1_EN,
input [11:0] RX1D,
// ADC 2
input ADC_CLK_O2,
input RX2IQSEL,
output RX2_EN,
input [11:0] RX2D,
// DAC 1
input TX1CLK,
output TX1EN,
output reg TX1IQSEL,
output reg [11:0] TX1D,
// DAC 2
input TX2CLK,
output TX2EN,
output reg TX2IQSEL,
output reg [11:0] TX2D,
//LMS 1 Control
output SCLK1,
output LMS1nRST,
output SEN1,
input MISO1,
output MOSI1,
//LMS 2 Control
output SCLK2,
output LMS2nRST,
output SEN2,
input MISO2,
output MOSI2,
//Diversity switches
output DivSw1_N,
output DivSw1_P,
output DivSw2_N,
output DivSw2_P,
// Misc, debug
output [5:1] leds, // LED4 is shared w/INIT_B
input FPGA_RESET,
output [1:0] debug_clk,
output [31:0] debug,
output [3:1] TXD, input [3:1] RXD, // UARTs
inout SCL, inout SDA, // I2C
// PPS
input PPS_IN,
// SPI
output SEN_DAC, output SCLK_DAC, output MOSI_DAC,
// GigE PHY
input CLK_TO_MAC,
output reg [7:0] GMII_TXD,
output reg GMII_TX_EN,
output reg GMII_TX_ER,
output GMII_GTX_CLK,
input GMII_TX_CLK, // 100mbps clk
input GMII_RX_CLK,
input [7:0] GMII_RXD,
input GMII_RX_DV,
input GMII_RX_ER,
input GMII_COL,
input GMII_CRS,
input PHY_INTn, // open drain
inout MDIO,
output MDC,
output PHY_RESETn,
output ETH_LED,
output ETH_LEDG,
// SRAM
inout [35:0] RAM_D,
output [20:0] RAM_A,
output [3:0] RAM_BWn,
output RAM_ZZ,
output RAM_LDn,
output RAM_OEn,
output RAM_WEn,
output RAM_CENn,
output RAM_CLK,
// SPI Flash
output flash_cs,
output flash_clk,
output flash_mosi,
input flash_miso
);
wire CLK_TO_MAC_int, CLK_TO_MAC_int2;
// FPGA-specific pins connections
wire clk_fpga, dsp_clk, clk_div, dcm_out, wb_clk, clk_icap, lms_clk, clock_ready;
wire DivSw1, DivSw2;
OBUF DIVSW1_P_pin (.I(DivSw1),.O(DivSw1_P));
OBUF DIVSW1_N_pin (.I(~DivSw1),.O(DivSw1_N));
OBUF DIVSW2_P_pin (.I(DivSw2),.O(DivSw2_P));
OBUF DIVSW2_N_pin (.I(~DivSw2),.O(DivSw2_N));
wire exp_time_in;
wire exp_time_out;
wire exp_user_in;
wire exp_user_out;
reg [5:0] clock_ready_d;
always @(posedge clk_fpga)
clock_ready_d[5:0] <= {clock_ready_d[4:0],clock_ready};
wire dcm_rst = ~&clock_ready_d & |clock_ready_d;
`ifdef LVDS
wire [13:0] adc_a, adc_a_inv, adc_b;
capture_ddrlvds #(.WIDTH(14)) capture_ddrlvds
(.clk(dsp_clk), .ssclk_p(ADC_clkout_p), .ssclk_n(ADC_clkout_n),
.in_p({{ADCA_12_p, ADCA_10_p, ADCA_8_p, ADCA_6_p, ADCA_4_p, ADCA_2_p, ADCA_0_p},
{ADCB_12_p, ADCB_10_p, ADCB_8_p, ADCB_6_p, ADCB_4_p, ADCB_2_p, ADCB_0_p}}),
.in_n({{ADCA_12_n, ADCA_10_n, ADCA_8_n, ADCA_6_n, ADCA_4_n, ADCA_2_n, ADCA_0_n},
{ADCB_12_n, ADCB_10_n, ADCB_8_n, ADCB_6_n, ADCB_4_n, ADCB_2_n, ADCB_0_n}}),
.out({adc_a_inv,adc_b}));
assign adc_a = ~adc_a_inv;
`else
reg [13:0] adc_a, adc_b;
always @(posedge dsp_clk)
begin
adc_a <= ~{ADCA_12_p,ADCA_12_n, ADCA_10_p,ADCA_10_n, ADCA_8_p,ADCA_8_n, ADCA_6_p,ADCA_6_n,
ADCA_4_p,ADCA_4_n, ADCA_2_p,ADCA_2_n, ADCA_0_p,ADCA_0_n };
adc_b <= {ADCB_12_p,ADCB_12_n, ADCB_10_p,ADCB_10_n, ADCB_8_p,ADCB_8_n, ADCB_6_p,ADCB_6_n,
ADCB_4_p,ADCB_4_n, ADCB_2_p,ADCB_2_n, ADCB_0_p,ADCB_0_n };
end
`endif // !`ifdef LVDS
// Interface to ADC of LMS
reg [13:0] adc_a_0, adc_b_0, adc_a_1, adc_b_1;
assign RX1_EN = 1'b1;
assign RX2_EN = 1'b1;
always @(posedge lms_clk)
begin
if (RX1IQSEL == 1'b1)
adc_a_0 = {RX1D, 2'b00}; //ADC_I signal
else
adc_b_0 <= {RX1D, 2'b00}; // ADC_Q signal
end
always @(posedge lms_clk)
begin
if (RX2IQSEL == 1'b1)
adc_a_1 = {RX2D, 2'b00}; //ADC_I signal
else
adc_b_1 <= {RX2D, 2'b00}; // ADC_Q signal
end
// Handle Clocks
pll_clk pll_clk_instance
(// Clock in ports
.clk_in(CLK_FPGA_P), // IN
// Clock out ports
.wb_clk(wb_clk), // OUT 52 MHz
.dsp_clk(dsp_clk), // OUT 104 MHz
.clk270_100(clk270_100_buf), // OUT 104 MHz
.clk_fpga(clk_fpga), // OUT 104 MHz
.clk_icap(clk_icap), // OUT 13 MHz, 180 deg
.lms_clk(lms_clk), // OUT 26 MHz
// Status and control signals
.LOCKED_OUT(LOCKED_OUT)); // OUT
pll_rx pll_rx_instance
(// Clock in ports
.gmii_rx_clk(GMII_RX_CLK), // IN
// Clock out ports
.clk_rx(clk_rx), // OUT
.clk_to_mac(CLK_TO_MAC_int2), // OUT
.clk_rx_180(clk_rx_180)); // OUT
OFDDRRSE RAM_CLK_i1 (.Q(RAM_CLK),
.C0(clk270_100_buf),
.C1(~clk270_100_buf),
.CE(1'b1),
.D0(1'b1),
.D1(1'b0),
.R(1'b0),
.S(1'b0));
// I2C -- Don't use external transistors for open drain, the FPGA implements this
IOBUF scl_pin(.O(scl_pad_i), .IO(SCL), .I(scl_pad_o), .T(scl_pad_oen_o));
IOBUF sda_pin(.O(sda_pad_i), .IO(SDA), .I(sda_pad_o), .T(sda_pad_oen_o));
// LEDs are active low outputs
wire [6:0] leds_int;
assign {ETH_LEDG,ETH_LED,leds} = {7'b0011111 ^ leds_int}; // drive low to turn on leds
// SPI
wire miso, mosi, sclk;
assign {SCLK_DAC,MOSI_DAC} = ~SEN_DAC ? {sclk,mosi} : 2'B0;
assign {SCLK1,MOSI1} = ~SEN1 ? {sclk,mosi} : 2'B0;
assign {SCLK2,MOSI2} = ~SEN2 ? {sclk,mosi} : 2'B0;
assign miso = (~SEN1 & MISO1) | (~SEN2 & MISO2) ;
wire GMII_TX_EN_unreg, GMII_TX_ER_unreg;
wire [7:0] GMII_TXD_unreg;
wire GMII_GTX_CLK_int;
always @(posedge GMII_GTX_CLK_int)
begin
GMII_TX_EN <= GMII_TX_EN_unreg;
GMII_TX_ER <= GMII_TX_ER_unreg;
GMII_TXD <= GMII_TXD_unreg;
end
OFDDRRSE OFDDRRSE_gmii_inst
(.Q(GMII_GTX_CLK), // Data output (connect directly to top-level port)
.C0(GMII_GTX_CLK_int), // 0 degree clock input
.C1(~GMII_GTX_CLK_int), // 180 degree clock input
.CE(1), // Clock enable input
.D0(0), // Posedge data input
.D1(1), // Negedge data input
.R(0), // Synchronous reset input
.S(0) // Synchronous preset input
);
//
// Instantiate IO for Bidirectional bus to SRAM
//
wire [35:0] RAM_D_pi;
wire [35:0] RAM_D_po;
wire RAM_D_poe;
genvar i;
generate
for (i=0;i<36;i=i+1)
begin : gen_RAM_D_IO
`ifndef NO_EXT_FIFO
IOBUF #(
.DRIVE(12),
.IOSTANDARD("LVCMOS25"),
.SLEW("FAST")
)
RAM_D_i (
.O(RAM_D_pi[i]),
.I(RAM_D_po[i]),
.IO(RAM_D[i]),
.T(RAM_D_poe)
);
`endif // !`ifndef NO_EXT_FIFO
end // block: gen_RAM_D_IO
endgenerate
wire [11:0] dac_a_int1, dac_b_int1, dac_a_int2, dac_b_int2;
// Interface to DAC of LMS
assign TX1EN = 1'b1;
assign TX2EN = 1'b1;
reg dsp_clk_div2_tx=0; // DSP clock signal devided by 2
always @(negedge lms_clk)
begin
dsp_clk_div2_tx = ~dsp_clk_div2_tx;
if (dsp_clk_div2_tx)
begin
TX1D <= dac_a_int1[11:0]; //DAC_I signal
TX1IQSEL = 1'b0;
TX2D <= dac_a_int2[11:0]; //DAC_I signal
TX2IQSEL = 1'b0;
end
else
begin
TX1D <= dac_b_int1[11:0]; //DAC_Q signal
TX1IQSEL = 1'b1;
TX2D <= dac_b_int2[11:0]; //DAC_Q signal
TX2IQSEL = 1'b1;
end
end
wire pps;
assign pps = PPS_IN;
umtrx_core u2p_c(.dsp_clk (dsp_clk),
.wb_clk (wb_clk),
.lms_clk (clk_icap),
.clk_icap (clk_icap),
.clock_ready (clock_ready),
.clk_to_mac (CLK_TO_MAC_int2),
.pps_in (pps),
.leds (leds_int),
.debug (debug[31:0]),
.debug_clk (debug_clk[1:0]),
.exp_time_in (exp_time_in),
.exp_time_out (exp_time_out),
.GMII_COL (GMII_COL),
.GMII_CRS (GMII_CRS),
.GMII_TXD (GMII_TXD_unreg[7:0]),
.GMII_TX_EN (GMII_TX_EN_unreg),
.GMII_TX_ER (GMII_TX_ER_unreg),
.GMII_GTX_CLK (GMII_GTX_CLK_int),
.GMII_TX_CLK (GMII_TX_CLK),
.GMII_RXD (GMII_RXD[7:0]),
.GMII_RX_CLK (clk_rx),
.GMII_RX_DV (GMII_RX_DV),
.GMII_RX_ER (GMII_RX_ER),
.MDIO (MDIO),
.MDC (MDC),
.PHY_INTn (PHY_INTn),
.PHY_RESETn (PHY_RESETn),
.ser_enable (),
.ser_prbsen (),
.ser_loopen (),
.ser_rx_en (),
.ser_tx_clk (),
.ser_t (),
.ser_tklsb (),
.ser_tkmsb (),
.ser_rx_clk (),
.ser_r (),
.ser_rklsb (),
.ser_rkmsb (),
.adc_a_0 (adc_a_0[13:0]),
.adc_ovf_a_0 (1'b0),
.adc_on_a_0 (),
.adc_oe_a_0 (),
.adc_b_0 (adc_b_0[13:0]),
.adc_ovf_b_0 (1'b0),
.adc_on_b_0 (),
.adc_oe_b_0 (),
.adc_a_1 (adc_a_1[13:0]),
.adc_ovf_a_1 (1'b0),
.adc_on_a_1 (),
.adc_oe_a_1 (),
.adc_b_1 (adc_b_1[13:0]),
.adc_ovf_b_1 (1'b0),
.adc_on_b_1 (),
.adc_oe_b_1 (),
.lms_res ({LMS2nRST,LMS1nRST}),
.dac1_a (dac_a_int2),
.dac1_b (dac_b_int2),
.dac_a (dac_a_int1),
.dac_b (dac_b_int1),
.scl_pad_i (scl_pad_i),
.scl_pad_o (scl_pad_o),
.scl_pad_oen_o (scl_pad_oen_o),
.sda_pad_i (sda_pad_i),
.sda_pad_o (sda_pad_o),
.sda_pad_oen_o (sda_pad_oen_o),
.clk_en (),
.clk_sel (),
.clk_func (),
.clk_status (),
.sclk (sclk),
.mosi (mosi),
.miso (miso),
.sen_dac (SEN_DAC),
.sen_lms1 (SEN1),
.sen_lms2 (SEN2),
.io_tx (),
.io_rx (),
//Diversity switches
.DivSw1(DivSw1),
.DivSw2(DivSw2),
`ifndef NO_EXT_FIFO
.RAM_D_po (RAM_D_po),
.RAM_D_pi (RAM_D_pi),
.RAM_D_poe (RAM_D_poe),
.RAM_A (RAM_A),
.RAM_CE1n (RAM_CE1n),
.RAM_CENn (RAM_CENn),
.RAM_WEn (RAM_WEn),
.RAM_OEn (RAM_OEn),
.RAM_LDn (RAM_LDn),
`endif // !`ifndef NO_EXT_FIFO
.uart_tx_o (TXD[3:1]),
.uart_rx_i ({1'b1,RXD[3:1]}),
.uart_baud_o (),
.sim_mode (1'b0),
.clock_divider (2),
.button (FPGA_RESET),
.spiflash_cs (flash_cs),
.spiflash_clk (flash_clk),
.spiflash_miso (flash_miso),
.spiflash_mosi (flash_mosi)
);
`ifndef NO_EXT_FIFO
// Drive low so that RAM does not sleep.
assign RAM_ZZ = 0;
// Byte Writes are qualified by the global write enable
// Always do 36bit operations to extram.
assign RAM_BWn = 4'b0000;
`endif // !`ifndef NO_EXT_FIFO
endmodule // u2plus

View File

@@ -223,10 +223,16 @@ NET "AUX_SEN1" LOC = AA8; // ch1 ADF4350 load/enable
NET "AUX_SEN2" LOC = AB11; // ch2 ADF4350 load/enable
NET "AUX_LD1" LOC = AB6; // ch1 ADF4350 lock detect input
NET "AUX_LD2" LOC = AB9; // ch2 ADF4350 lock detect input
NET "AUX_XX" LOC = AA6; // empty awhile
NET "AUX_SCL" LOC = AB7;// I2C clock (teperature sensor etc.)
NET "AUX_SDA" LOC = AB10;// I2C data (teperature sensor etc.)
## PA control
NET "ENPA2" LOC = AB21;
NET "ENPA1" LOC = AA21;
NET "LOWPA" LOC = Y12;
NET "DCSYNC" LOC = AA6;
## LEDS
NET "leds[1]" LOC = Y3;
NET "leds[2]" LOC = W4;
@@ -234,7 +240,7 @@ NET "leds[3]" LOC = AB2;
NET "leds[4]" LOC = Y4;
NET "leds[5]" LOC = AA2;
NET "led_stat" LOC = AB3; // output for clock status (or something else) front panel LED !!!
// was stupid "master clock" LED indicator
// was stupid "master clock" LED indicator
### Debug // a lot changes !!!
NET "debug[0]" LOC = D22;
@@ -274,7 +280,7 @@ NET "debug_clk_n" LOC = L19;// was "debug_clk[1]" LOC = N16; !!!
// #NET "CLK_FPGA_N" IOSTANDARD = LVPECL_25;// LVCMOS25 - UNUSED !!!
#NET "CLK_FPGA" IOSTANDARD = LVCMOS25;// !!!
#NET "CLK_FPGA" IOSTANDARD = LVCMOS25;// !!!
NET "FPGA_RESET" IOSTANDARD = LVCMOS33;
NET "ETH_LED" IOSTANDARD = LVCMOS33;
@@ -314,6 +320,11 @@ NET "TXD[1]" IOSTANDARD = LVCMOS33;// FPGA input <- FTDI input !!! in v1a was o
NET "TXD[2]" IOSTANDARD = LVCMOS33;// FPGA input <- GPS input !!! in v1a was output !!!
NET "TXD[3]" IOSTANDARD = LVCMOS33;
NET "ENPA2" IOSTANDARD = LVCMOS33;
NET "ENPA1" IOSTANDARD = LVCMOS33;
NET "LOWPA" IOSTANDARD = LVCMOS33;
NET "DCSYNC" IOSTANDARD = LVCMOS33;
NET "DivSw1_N" IOSTANDARD = LVCMOS25;
NET "DivSw1_P" IOSTANDARD = LVCMOS25;
NET "DivSw2_N" IOSTANDARD = LVCMOS25;
@@ -328,7 +339,6 @@ NET "AUX_LD1" IOSTANDARD = LVCMOS33;// FPGA input !!!
NET "AUX_LD2" IOSTANDARD = LVCMOS33;// FPGA input !!!
NET "AUX_SDA" IOSTANDARD = LVCMOS33;// FPGA input !!!
NET "AUX_SCL" IOSTANDARD = LVCMOS33;// FPGA input !!!
NET "AUX_XX" IOSTANDARD = LVCMOS33;// FPGA input !!!
NET "CLK_FPGA_P" TNM_NET = "CLK_FPGA_P";
TIMESPEC TS_clk_fpga_p = PERIOD "CLK_FPGA_P" 38 ns HIGH 50 %;
@@ -337,4 +347,4 @@ NET "CLK_TO_MAC" TNM_NET = "CLK_TO_MAC";
TIMESPEC TS_clk_to_mac = PERIOD "CLK_TO_MAC" 8 ns HIGH 50 %;
NET "GMII_RX_CLK" TNM_NET = "GMII_RX_CLK";
TIMESPEC TS_GMII_RX_CLK = PERIOD "GMII_RX_CLK" 8 ns HIGH 50 %;
TIMESPEC TS_GMII_RX_CLK = PERIOD "GMII_RX_CLK" 8 ns HIGH 50 %;

View File

@@ -73,10 +73,16 @@ module u2plus_umtrx_v2
output AUX_SEN2,
input AUX_LD1,
input AUX_LD2,
input AUX_XX,
//input AUX_XX,
inout AUX_SCL,
inout AUX_SDA,
//PA control
output ENPA2,
output ENPA1,
output LOWPA,
output DCSYNC,
// PPS
input PPS_IN,
output GPS_ON,
@@ -305,7 +311,29 @@ wire DivSw1, DivSw2;
assign GPS_ON = 1'b1;
assign pps = PPS_IN;
wire enpa2_o, enpa1_o, lowpa_o;
OBUF enpa2_pin (.I(enpa2_o),.O(ENPA2));
OBUF enpa1_pin (.I(enpa1_o),.O(ENPA1));
OBUF lowpa_pin (.I(lowpa_o),.O(LOWPA));
reg dcsync_o;
wire en_dc_sync_o;
IOBUF DCSYNC_pin (.O(), .IO(DCSYNC), .I(dcsync_o), .T(~en_dc_sync_o));
reg [5:0] dc_count;
always @(posedge lms_clk) begin
if (en_dc_sync_o == 1'b1) begin
if (dc_count == 23) begin
dcsync_o <= ~dcsync_o;
dc_count <= 0;
end else
dc_count <= dc_count + 1;
end else begin
dc_count <= 0;
dcsync_o <= 1'b0;
end
end
umtrx_core u2p_c(
.sys_clk (dsp_clk),
.dsp_clk (lms_clk),
@@ -370,6 +398,11 @@ wire DivSw1, DivSw2;
//Diversity switches
.DivSw1(DivSw1),
.DivSw2(DivSw2),
//PA control
.enpa2(enpa2_o),
.enpa1(enpa1_o),
.lowpa(lowpa_o),
.en_dc_sync(en_dc_sync_o),
`ifndef NO_EXT_FIFO
.RAM_D_po (RAM_D_po),
.RAM_D_pi (RAM_D_pi),

View File

@@ -107,6 +107,12 @@ module umtrx_core
input aux_ld1,
input aux_ld2,
//PA control
output enpa2,
output enpa1,
output lowpa,
output en_dc_sync,
`ifndef NO_EXT_FIFO
// External RAM
input [35:0] RAM_D_pi,
@@ -131,20 +137,20 @@ module umtrx_core
output spiflash_cs, output spiflash_clk, input spiflash_miso, output spiflash_mosi
);
localparam SR_MISC = 0; // 7 regs
localparam SR_MISC = 0; // 8 regs
localparam SR_TIME64 = 10; // 6
localparam SR_BUF_POOL = 16; // 4
localparam SR_RX_FRONT0 = 20; // 5
localparam SR_RX_FRONT1 = 25; // 5
localparam SR_RX_CTRL0 = 32; // 9
localparam SR_RX_DSP0 = 48; // 7
localparam SR_RX_CTRL1 = 80; // 9
localparam SR_RX_DSP1 = 96; // 7
localparam SR_RX_CTRL2 = 66; // 9
localparam SR_RX_DSP2 = 76; // 7
localparam SR_RX_CTRL3 = 83; // 9
localparam SR_RX_DSP3 = 93; // 7
localparam SR_RX_CTRL0 = 30; // 9
localparam SR_RX_DSP0 = 40; // 7
localparam SR_RX_CTRL1 = 50; // 9
localparam SR_RX_DSP1 = 60; // 7
localparam SR_RX_CTRL2 = 70; // 9
localparam SR_RX_DSP2 = 80; // 7
localparam SR_RX_CTRL3 = 90; // 9
localparam SR_RX_DSP3 = 100; // 7
localparam SR_TX_FRONT0 = 110; // ?
localparam SR_TX_CTRL0 = 126; // 6
@@ -160,17 +166,22 @@ module umtrx_core
// FIFO Sizes, 9 = 512 lines, 10 = 1024, 11 = 2048
// all (most?) are 36 bits wide, so 9 is 1 BRAM, 10 is 2, 11 is 4 BRAMs
localparam DSP_RX_FIFOSIZE = 10;
localparam DSP_TX_FIFOSIZE = 10;
localparam DSP_RX_FIFOSIZE = 9;
localparam DSP_TX_FIFOSIZE = 9;
localparam ETH_TX_FIFOSIZE = 9;
localparam ETH_RX_FIFOSIZE = 11;
wire [7:0] set_addr, set_addr_dsp, set_addr_sys, set_addr_fe, set_addr_udp_wb, set_addr_udp_sys;
wire [31:0] set_data, set_data_dsp, set_data_sys, set_data_fe, set_data_udp_wb, set_data_udp_sys;
wire set_stb, set_stb_dsp, set_stb_sys, set_stb_fe, set_stb_udp_wb, set_stb_udp_sys;
wire set_stb_dsp0, set_stb_dsp1;
wire [31:0] set_data_dsp0, set_data_dsp1;
wire [7:0] set_addr_dsp0, set_addr_dsp1;
reg wb_rst;
wire dsp_rst, sys_rst, fe_rst;
wire net_clr;
wire [31:0] status;
wire bus_error, spi_int, i2c_int, aux_i2c_int, pps_int, onetime_int, periodic_int;
@@ -189,8 +200,6 @@ module umtrx_core
wire [31:0] irq;
wire [63:0] vita_time, vita_time_pps;
wire run_rx0, run_rx1, run_tx0, run_tx1;
//generate sync reset signals for dsp and sys domains
reset_sync sys_rst_sync(.clk(sys_clk), .reset_in(wb_rst), .reset_out(sys_rst));
@@ -219,7 +228,7 @@ module umtrx_core
wb_1master #(.decode_w(8),
.s0_addr(8'b0000_0000),.s0_mask(8'b1100_0000), // Main RAM (0-16K)
.s1_addr(8'b0100_0000),.s1_mask(8'b1111_0000), // Packet Router (16-20K)
.s2_addr(8'b0101_0000),.s2_mask(8'b1111_1100), // SPI
.s2_addr(8'b0101_0000),.s2_mask(8'b1111_1100), // Unused
.s3_addr(8'b0101_0100),.s3_mask(8'b1111_1100), // I2C
.s4_addr(8'b0101_1000),.s4_mask(8'b1111_1100), // GPSDO
.s5_addr(8'b0101_1100),.s5_mask(8'b1111_1100), // Readback
@@ -385,7 +394,7 @@ module umtrx_core
.set_stb(set_stb_sys), .set_addr(set_addr_sys), .set_data(set_data_sys),
.set_stb_udp(set_stb_udp_sys), .set_addr_udp(set_addr_udp_sys), .set_data_udp(set_data_udp_sys),
.stream_clk(sys_clk), .stream_rst(sys_rst), .stream_clr(1'b0),
.stream_clk(sys_clk), .stream_rst(sys_rst), .stream_clr(net_clr),
.status(status),
@@ -407,17 +416,80 @@ module umtrx_core
// /////////////////////////////////////////////////////////////////////////
// SPI -- Slave #2
wire [31:0] spi_debug;
wire [31:0] spi_readback;
reg [31:0] spi_readback0;
reg [31:0] spi_readback1;
wire spi_ready;
simple_spi_core #(.BASE(SR_SPI_CORE), .WIDTH(5)) shared_spi(
wire [0:0] AXIS_SPI_CONFIG_tdest;
wire [79:0] AXIS_SPI_CONFIG_tdata;
wire AXIS_SPI_CONFIG_tvalid;
wire AXIS_SPI_CONFIG_tready;
wire [0:0] AXIS_SPI_READBACK_tdest;
wire [31:0] AXIS_SPI_READBACK_tdata;
wire AXIS_SPI_READBACK_tvalid;
wire AXIS_SPI_READBACK_tready;
axis_spi_core #(.DESTW(1), .WIDTH(5), .DEBUG(0)) axis_shared_spi(
.clock(dsp_clk), .reset(dsp_rst),
.set_stb(set_stb_dsp), .set_addr(set_addr_dsp), .set_data(set_data_dsp),
.readback(spi_readback), .ready(spi_ready),
.CONFIG_tdest(AXIS_SPI_CONFIG_tdest),
.CONFIG_tdata(AXIS_SPI_CONFIG_tdata),
.CONFIG_tvalid(AXIS_SPI_CONFIG_tvalid),
.CONFIG_tready(AXIS_SPI_CONFIG_tready),
.READBACK_tdest(AXIS_SPI_READBACK_tdest),
.READBACK_tdata(AXIS_SPI_READBACK_tdata),
.READBACK_tvalid(AXIS_SPI_READBACK_tvalid),
.READBACK_tready(AXIS_SPI_READBACK_tready),
.sen({aux_sen2,aux_sen1,sen_dac,sen_lms2,sen_lms1}),
.sclk(sclk), .mosi(mosi), .miso(miso), .debug(spi_debug)
.sclk(sclk), .mosi(mosi), .miso(miso)
);
//setting register block for spi dest 0 (wishbone) and spi dest 1 (ctrl fifo)
//Note: the strobes are exclusive (settings fifo cross clock)
wire [79:0] spi_config [0:1];
wire [0:1] spi_trigger;
wire [0:1] set_stb_dsp_n = {set_stb_dsp0, set_stb_dsp1};
genvar i;
generate for (i=0; i <= 1; i=i+1) begin
setting_reg #(.my_addr(SR_SPI_CORE+2),.width(32)) axis_shared_spi_sr0(
.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp_n[i]),.addr(set_addr_dsp),.in(set_data_dsp),
.out(spi_config[i][31:0]),.changed(spi_trigger[i]));
setting_reg #(.my_addr(SR_SPI_CORE+1),.width(32)) axis_shared_spi_sr1(
.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp_n[i]),.addr(set_addr_dsp),.in(set_data_dsp),
.out(spi_config[i][63:32]),.changed());
setting_reg #(.my_addr(SR_SPI_CORE+0),.width(16)) axis_shared_spi_sr2(
.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp_n[i]),.addr(set_addr_dsp),.in(set_data_dsp),
.out(spi_config[i][79:64]),.changed());
end endgenerate
//assign config bus from setting register sources
//Note: the triggers are exclusive (settings fifo cross clock)
assign AXIS_SPI_CONFIG_tdest = (spi_trigger[0])?1'b0:1'b1;
assign AXIS_SPI_CONFIG_tdata = (spi_trigger[0])?spi_config[0]:spi_config[1];
assign AXIS_SPI_CONFIG_tvalid = (spi_trigger != 0);
//create spi ready to block the ctrl fifo ASAP
wire spi_ready_now = AXIS_SPI_CONFIG_tready && !AXIS_SPI_CONFIG_tvalid;
assign spi_ready = spi_ready_now && spi_ready_prev;
reg spi_ready_prev;
always @(posedge dsp_clk) begin
spi_ready_prev <= spi_ready_now;
end
//readback output bus latches values into readback register
assign AXIS_SPI_READBACK_tready = 1'b1;
always @(posedge dsp_clk) begin
if (AXIS_SPI_READBACK_tvalid && AXIS_SPI_READBACK_tready) begin
if (AXIS_SPI_READBACK_tdest == 1'b0) spi_readback0 <= AXIS_SPI_READBACK_tdata;
if (AXIS_SPI_READBACK_tdest == 1'b1) spi_readback1 <= AXIS_SPI_READBACK_tdata;
end
end
// /////////////////////////////////////////////////////////////////////////
// I2C -- Slave #3
i2c_master_top #(.ARST_LVL(1))
@@ -443,7 +515,7 @@ module umtrx_core
// Buffer Pool Status -- Slave #5
//compatibility number -> increment when the fpga has been sufficiently altered
localparam compat_num = {16'd9, 16'd0}; //major, minor
localparam compat_num = {16'd9, 16'd2}; //major, minor
wire [31:0] irq_readback = {16'b0, aux_ld2, aux_ld1, button, spi_ready, 12'b0};
@@ -451,7 +523,7 @@ module umtrx_core
(.wb_clk_i(wb_clk), .wb_rst_i(wb_rst), .wb_stb_i(s5_stb),
.wb_adr_i(s5_adr), .wb_dat_o(s5_dat_i), .wb_ack_o(s5_ack),
.word00(spi_readback),.word01(32'b0),.word02(32'b0),.word03(32'b0),
.word00(spi_readback0),.word01(`NUMDDC),.word02(`NUMDUC),.word03(32'b0),
.word04(32'b0),.word05(32'b0),.word06(32'b0),.word07(32'b0),
.word08(status),.word09(32'b0),.word10(vita_time[63:32]),
.word11(vita_time[31:0]),.word12(compat_num),.word13(irq_readback),
@@ -463,7 +535,7 @@ module umtrx_core
simple_gemac_wrapper #(.RXFIFOSIZE(ETH_RX_FIFOSIZE),
.TXFIFOSIZE(ETH_TX_FIFOSIZE)) simple_gemac_wrapper
(.clk125(clk_to_mac), .reset(wb_rst),
(.clk125(clk_to_mac), .reset(wb_rst | net_clr),
.GMII_GTX_CLK(GMII_GTX_CLK), .GMII_TX_EN(GMII_TX_EN),
.GMII_TX_ER(GMII_TX_ER), .GMII_TXD(GMII_TXD),
.GMII_RX_CLK(GMII_RX_CLK), .GMII_RX_DV(GMII_RX_DV),
@@ -493,10 +565,6 @@ module umtrx_core
(.clk_i(dsp_clk), .rst_i(dsp_rst), .set_stb_i(set_stb_dsp), .set_addr_i(set_addr_dsp), .set_data_i(set_data_dsp),
.clk_o(fe_clk), .rst_o(fe_rst), .set_stb_o(set_stb_fe), .set_addr_o(set_addr_fe), .set_data_o(set_data_fe));
wire set_stb_dsp0, set_stb_dsp1;
wire [31:0] set_data_dsp0, set_data_dsp1;
wire [7:0] set_addr_dsp0, set_addr_dsp1;
//mux settings_bus_crossclock and settings_readback_bus_fifo_ctrl with prio
assign set_stb_dsp = set_stb_dsp0 | set_stb_dsp1;
assign set_addr_dsp = set_stb_dsp1? set_addr_dsp1 : set_addr_dsp0;
@@ -537,7 +605,7 @@ module umtrx_core
.in_data(ctrl_data_dsp), .in_valid(ctrl_valid_dsp), .in_ready(ctrl_ready_dsp),
.out_data(resp_data_dsp), .out_valid(resp_valid_dsp), .out_ready(resp_ready_dsp),
.strobe(set_stb_dsp1), .addr(set_addr_dsp1), .data(set_data_dsp1),
.word00(spi_readback),.word01(32'b0),.word02(32'b0),.word03(32'b0),
.word00(spi_readback1),.word01(32'b0),.word02(32'b0),.word03(32'b0),
.word04(32'b0),.word05(32'b0),.word06(32'b0),.word07(32'b0),
.word08(32'b0),.word09(32'b0),.word10(vita_time[63:32]),
.word11(vita_time[31:0]),.word12(32'b0),.word13(irq_readback),
@@ -548,9 +616,9 @@ module umtrx_core
// Output control lines
wire phy_reset;
assign PHY_RESETn = ~phy_reset;
setting_reg #(.my_addr(SR_MISC+0),.width(2)) sr_lms_res
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out(lms_res),.changed());
setting_reg #(.my_addr(SR_MISC+0),.width(6)) sr_lms_res
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out({en_dc_sync, enpa2, enpa1, lowpa, lms_res}),.changed());
setting_reg #(.my_addr(SR_MISC+1),.width(1)) sr_clear_sfc
(.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),.changed(sfc_clear));
@@ -565,6 +633,9 @@ module umtrx_core
setting_reg #(.my_addr(SR_MISC+5),.width(1)) sr_bld
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out(bldr_done),.changed());
setting_reg #(.my_addr(SR_MISC+7),.width(1)) net_reset_sr
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out(net_clr),.changed());
// Diversity switches
setting_reg #(.my_addr(SR_DIVSW+0),.width(1), .at_reset(32'd1)) sr_divsw1
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out(DivSw1),.changed());
@@ -579,7 +650,8 @@ module umtrx_core
// In Rev3 there are only 6 leds, and the highest one is on the ETH connector
wire [7:0] led_src, led_sw;
wire [7:0] led_hw = {run_tx0, run_rx0, run_tx1, run_rx1, 1'b0};
wire LEDA, LEDB, LEDC, LEDE;
wire [7:0] led_hw = {LEDA, LEDC, LEDE, LEDB, 1'b0};
setting_reg #(.my_addr(SR_MISC+3),.width(8)) sr_led
(.clk(wb_clk),.rst(wb_rst),.strobe(set_stb),.addr(set_addr),.in(set_data),.out(led_sw),.changed());
@@ -663,20 +735,20 @@ module umtrx_core
// /////////////////////////////////////////////////////////////////////////
// RX Frontend
wire [23:0] front0_i, front0_q;
wire [23:0] rx_front0_i, rx_front0_q;
rx_frontend #(.BASE(SR_RX_FRONT0)) rx_frontend0
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.i_out(front0_i), .q_out(front0_q), .run(1'b1),
.i_out(rx_front0_i), .q_out(rx_front0_q), .run(1'b1),
.adc_a({adc0_a, 4'b0}), .adc_b({adc0_b, 4'b0})
);
wire [23:0] front1_i, front1_q;
wire [23:0] rx_front1_i, rx_front1_q;
rx_frontend #(.BASE(SR_RX_FRONT1)) rx_frontend1
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.i_out(front1_i), .q_out(front1_q), .run(1'b1),
.i_out(rx_front1_i), .q_out(rx_front1_q), .run(1'b1),
.adc_a({adc1_a, 4'b0}), .adc_b({adc1_b, 4'b0})
);
@@ -684,16 +756,13 @@ module umtrx_core
// RX chains
//switch to select frontend used per DSP
wire [3:0] run_rx_dsp;
wire [3:0] rx_fe_sw;
setting_reg #(.my_addr(SR_RX_FE_SW),.width(4)) sr_rx_fe_sw
(.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),.out(rx_fe_sw),.changed());
//run logic to map running DSPs to active frontends
wire [3:0] run_rx_dsp;
assign run_rx0 = |((~run_rx_dsp) & rx_fe_sw);
assign run_rx1 = |(run_rx_dsp & rx_fe_sw);
//*
generate
if (`NUMDDC > 0) begin
umtrx_rx_chain
#(
.PROT_DEST(4),
@@ -710,14 +779,18 @@ module umtrx_core
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_fe), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[0]?front1_i:front0_i),
.front_q(rx_fe_sw[0]?front1_q:front0_q),
.front_i(rx_fe_sw[0]?rx_front1_i:rx_front0_i),
.front_q(rx_fe_sw[0]?rx_front1_q:rx_front0_q),
.adc_stb(rx_fe_sw[0]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[0]),
.vita_data_sys(dsp_rx0_data), .vita_valid_sys(dsp_rx0_valid), .vita_ready_sys(dsp_rx0_ready),
.vita_time(vita_time)
);
end else begin
assign dsp_rx0_valid = 0;
assign run_rx_dsp[0] = 0;
end
if (`NUMDDC > 1) begin
umtrx_rx_chain
#(
.PROT_DEST(5),
@@ -733,19 +806,18 @@ module umtrx_core
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_fe), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[1]?front1_i:front0_i),
.front_q(rx_fe_sw[1]?front1_q:front0_q),
.front_i(rx_fe_sw[1]?rx_front1_i:rx_front0_i),
.front_q(rx_fe_sw[1]?rx_front1_q:rx_front0_q),
.adc_stb(rx_fe_sw[1]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[1]),
.vita_data_sys(dsp_rx1_data), .vita_valid_sys(dsp_rx1_valid), .vita_ready_sys(dsp_rx1_ready),
.vita_time(vita_time)
);
//*/
/*
assign dsp_rx0_valid = 0;
assign dsp_rx1_valid = 0;
//*/
/*
end else begin
assign dsp_rx1_valid = 0;
assign run_rx_dsp[1] = 0;
end
if (`NUMDDC > 2) begin
umtrx_rx_chain
#(
.PROT_DEST(6),
@@ -761,14 +833,18 @@ assign dsp_rx1_valid = 0;
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_fe), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[2]?front1_i:front0_i),
.front_q(rx_fe_sw[2]?front1_q:front0_q),
.front_i(rx_fe_sw[2]?rx_front1_i:rx_front0_i),
.front_q(rx_fe_sw[2]?rx_front1_q:rx_front0_q),
.adc_stb(rx_fe_sw[2]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[2]),
.vita_data_sys(dsp_rx2_data), .vita_valid_sys(dsp_rx2_valid), .vita_ready_sys(dsp_rx2_ready),
.vita_time(vita_time)
);
end else begin
assign dsp_rx2_valid = 0;
assign run_rx_dsp[2] = 0;
end
if (`NUMDDC > 3) begin
umtrx_rx_chain
#(
.PROT_DEST(7),
@@ -784,24 +860,47 @@ assign dsp_rx1_valid = 0;
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_fe), .set_data_fe(set_data_fe),
.front_i(rx_fe_sw[3]?front1_i:front0_i),
.front_q(rx_fe_sw[3]?front1_q:front0_q),
.front_i(rx_fe_sw[3]?rx_front1_i:rx_front0_i),
.front_q(rx_fe_sw[3]?rx_front1_q:rx_front0_q),
.adc_stb(rx_fe_sw[3]?adc1_strobe:adc0_strobe),
.run(run_rx_dsp[3]),
.vita_data_sys(dsp_rx3_data), .vita_valid_sys(dsp_rx3_valid), .vita_ready_sys(dsp_rx3_ready),
.vita_time(vita_time)
);
//*/
//*
assign dsp_rx2_valid = 0;
assign dsp_rx3_valid = 0;
//*/
end else begin
assign dsp_rx3_valid = 0;
assign run_rx_dsp[3] = 0;
end
endgenerate
// /////////////////////////////////////////////////////////////////////////
// TX Frontend
wire [23:0] tx_front0_i, tx_front0_q;
wire [3:0] dac0_a_pad, dac0_b_pad;
tx_frontend #(.BASE(SR_TX_FRONT0)) tx_frontend0
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.tx_i(tx_front0_i), .tx_q(tx_front0_q), .run(1'b1),
.dac_a({dac0_a, dac0_a_pad}), .dac_b({dac0_b, dac0_b_pad})
);
wire [23:0] tx_front1_i, tx_front1_q;
wire [3:0] dac1_a_pad, dac1_b_pad;
tx_frontend #(.BASE(SR_TX_FRONT1)) tx_frontend1
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.tx_i(tx_front1_i), .tx_q(tx_front1_q), .run(1'b1),
.dac_a({dac1_a, dac1_a_pad}), .dac_b({dac1_b, dac1_b_pad})
);
// /////////////////////////////////////////////////////////////////////////
// TX chains
wire [35:0] sram0_data, sram1_data;
wire sram0_valid, sram1_valid;
wire sram0_ready, sram1_ready;
wire run_tx_dsp0, run_tx_dsp1;
//switch to select frontend used per DSP
wire tx_fe_sw;
@@ -809,21 +908,17 @@ assign dsp_rx3_valid = 0;
(.clk(dsp_clk),.rst(dsp_rst),.strobe(set_stb_dsp),.addr(set_addr_dsp),.in(set_data_dsp),.out(tx_fe_sw),.changed());
//assign dac switch
wire [11:0] dac0_a_int, dac0_b_int;
wire [11:0] dac1_a_int, dac1_b_int;
assign {dac0_a, dac0_b} = (tx_fe_sw == 0)? {dac0_a_int, dac0_b_int} : {dac1_a_int, dac1_b_int};
assign {dac1_a, dac1_b} = (tx_fe_sw == 1)? {dac0_a_int, dac0_b_int} : {dac1_a_int, dac1_b_int};
wire [23:0] dac0_a_int, dac0_b_int;
wire [23:0] dac1_a_int, dac1_b_int;
assign {tx_front0_i, tx_front0_q} = (tx_fe_sw == 0)? {dac0_a_int, dac0_b_int} : {dac1_a_int, dac1_b_int};
assign {tx_front1_i, tx_front1_q} = (tx_fe_sw == 1)? {dac0_a_int, dac0_b_int} : {dac1_a_int, dac1_b_int};
//assign leds
wire run_tx_dsp0, run_tx_dsp1;
assign {run_tx0, run_tx1} = (tx_fe_sw == 0)? {run_tx_dsp0, run_tx_dsp1} : {run_tx_dsp1, run_tx_dsp0};
//*
generate
if (`NUMDUC > 0) begin
umtrx_tx_chain
#(
.PROT_DEST(0),
.DSPNO(0),
.FRONT_BASE(SR_TX_FRONT0),
.DSP_BASE(SR_TX_DSP0),
.CTRL_BASE(SR_TX_CTRL0),
.FIFOSIZE(DSP_TX_FIFOSIZE)
@@ -835,17 +930,21 @@ assign dsp_rx3_valid = 0;
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_fe), .set_data_fe(set_data_fe),
.dac_a(dac0_a_int), .dac_b(dac0_b_int), .dac_stb(dac0_strobe), .run(run_tx_dsp0),
.front_i(dac0_a_int), .front_q(dac0_b_int), .dac_stb(dac0_strobe), .run(run_tx_dsp0),
.vita_data_sys(sram0_data), .vita_valid_sys(sram0_valid), .vita_ready_sys(sram0_ready),
.err_data_sys(err_tx0_data), .err_valid_sys(err_tx0_valid), .err_ready_sys(err_tx0_ready),
.vita_time(vita_time)
);
end else begin
assign sram0_ready = 1;
assign err_tx0_valid = 0;
assign run_tx_dsp0 = 0;
end
if (`NUMDUC > 1) begin
umtrx_tx_chain
#(
.PROT_DEST(1),
.DSPNO(1),
.FRONT_BASE(SR_TX_FRONT1),
.DSP_BASE(SR_TX_DSP1),
.CTRL_BASE(SR_TX_CTRL1),
.FIFOSIZE(DSP_TX_FIFOSIZE)
@@ -857,18 +956,33 @@ assign dsp_rx3_valid = 0;
.fe_clk(fe_clk), .fe_rst(fe_rst),
.set_stb_dsp(set_stb_dsp), .set_addr_dsp(set_addr_dsp), .set_data_dsp(set_data_dsp),
.set_stb_fe(set_stb_fe), .set_addr_fe(set_addr_fe), .set_data_fe(set_data_fe),
.dac_a(dac1_a_int), .dac_b(dac1_b_int), .dac_stb(dac1_strobe), .run(run_tx_dsp1),
.front_i(dac1_a_int), .front_q(dac1_b_int), .dac_stb(dac1_strobe), .run(run_tx_dsp1),
.vita_data_sys(sram1_data), .vita_valid_sys(sram1_valid), .vita_ready_sys(sram1_ready),
.err_data_sys(err_tx1_data), .err_valid_sys(err_tx1_valid), .err_ready_sys(err_tx1_ready),
.vita_time(vita_time)
);
//*/
/*
assign sram0_ready = 1;
assign sram1_ready = 1;
assign err_tx0_valid = 0;
assign err_tx1_valid = 0;
//*/
end else begin
assign sram1_ready = 1;
assign err_tx1_valid = 0;
assign run_tx_dsp1 = 0;
end
endgenerate
// /////////////////////////////////////////////////////////////////////////
// configuration specific LED mapping
generate
if (`NUMDUC == 0) begin
//no tx case? -- each RX DSP gets a LED
assign {LEDE, LEDB, LEDA, LEDC} = run_rx_dsp;
end else begin
//default -- map active frontends to LED based on which DSP is active and how they are mapped
assign LEDC = |(run_rx_dsp & (~rx_fe_sw));
assign LEDB = |(run_rx_dsp & rx_fe_sw);
assign {LEDA, LEDE} = (tx_fe_sw == 0)? {run_tx_dsp0, run_tx_dsp1} : {run_tx_dsp1, run_tx_dsp0};
end
endgenerate
// ///////////////////////////////////////////////////////////////////////////////////
// DSP TX

View File

@@ -104,13 +104,24 @@ module umtrx_rx_chain
/*******************************************************************
* Cross clock fifo from sys to dsp clock domain
******************************************************************/
wire [35:0] vita_data_sys0;
wire vita_valid_sys0;
wire vita_ready_sys0;
axi_fifo_2clk #(.WIDTH(36), .SIZE(0)) fifo_2clock_vita
(
.i_aclk(dsp_clk), .i_tdata(vita_data_dsp), .i_tvalid(vita_valid_dsp), .i_tready(vita_ready_dsp),
.o_aclk(sys_clk), .o_tdata(vita_data_sys), .o_tvalid(vita_valid_sys), .o_tready(vita_ready_sys),
.o_aclk(sys_clk), .o_tdata(vita_data_sys0), .o_tvalid(vita_valid_sys0), .o_tready(vita_ready_sys0),
.reset(dsp_rst | sys_rst)
);
axi_packet_gate #(.WIDTH(36), .SIZE(FIFOSIZE)) fully_buffer_sys_domain
(
.clk(sys_clk), .reset(sys_rst), .clear(0),
.i_tdata(vita_data_sys0), .i_tvalid(vita_valid_sys0), .i_tready(vita_ready_sys0), .i_tlast(vita_data_sys0[33]), .i_terror(0),
.o_tdata(vita_data_sys), .o_tvalid(vita_valid_sys), .o_tready(vita_ready_sys), .o_tlast()
);
/*******************************************************************
* Debug
******************************************************************/

View File

@@ -6,7 +6,6 @@ module umtrx_tx_chain
#(
parameter PROT_DEST = 0, //framer index
parameter DSPNO = 0, //the dsp unit number: 0, 1, 2...
parameter FRONT_BASE = 0,
parameter DSP_BASE = 0,
parameter CTRL_BASE = 0,
parameter FIFOSIZE = 10,
@@ -32,9 +31,9 @@ module umtrx_tx_chain
input [7:0] set_addr_fe,
input [31:0] set_data_fe,
//dsp clock domain
output reg [11:0] dac_a,
output reg [11:0] dac_b,
//fe clock domain
output [23:0] front_i,
output [23:0] front_q,
input dac_stb,
output run,
@@ -52,28 +51,6 @@ module umtrx_tx_chain
wire [63:0] vita_time
);
/*******************************************************************
* Cross DAC signals from fe to dsp clock domain
* dac_a/b come from a register on the fe clock domain
******************************************************************/
wire [15:0] dac_a_16, dac_b_16;
always @(posedge fe_clk) begin
dac_a <= dac_a_16[15:4];
dac_b <= dac_b_16[15:4];
end
/*******************************************************************
* TX frontend on fe clock domain
******************************************************************/
wire [23:0] front_i, front_q;
tx_frontend #(.BASE(FRONT_BASE)) tx_frontend
(
.clk(fe_clk), .rst(fe_rst),
.set_stb(set_stb_fe),.set_addr(set_addr_fe),.set_data(set_data_fe),
.tx_i(front_i), .tx_q(front_q), .run(1'b1),
.dac_a(dac_a_16), .dac_b(dac_b_16)
);
/*******************************************************************
* DUC chain on fe clock domain
******************************************************************/
@@ -180,8 +157,6 @@ module umtrx_tx_chain
assign DATA[63:32] = vita_sample;
assign DATA[95:64] = duc_sample;
assign DATA[127:96] = {front_i[23:8], front_q[23:8]};
assign DATA[159:128] = {dac_a_16, dac_b_16};
assign DATA[191:160] = {dac_a, 4'b0, dac_b, 4'b0};
end
endgenerate

View File

@@ -19,19 +19,36 @@
## Build the UmTRX UHD module
########################################################################
cmake_minimum_required(VERSION 2.8)
project(UmTRX_UHD)
project(UmTRX-UHD)
########################################################################
# extract version info from git
########################################################################
include(${PROJECT_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake)
git_describe(UMTRX_VERSION --dirty)
string(REPLACE "g" "" UMTRX_VERSION ${UMTRX_VERSION}) #remove hash prefix g
message(STATUS "UMTRX_VERSION: ${UMTRX_VERSION}")
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/umtrx_version.in.hpp"
"${CMAKE_CURRENT_BINARY_DIR}/umtrx_version.hpp"
IMMEDIATE @ONLY)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
########################################################################
## Create a list of module sources
########################################################################
list(APPEND UMTRX_SOURCES
umtrx_impl.cpp
umtrx_monitor.cpp
umtrx_io_impl.cpp
umtrx_find.cpp
umtrx_iface.cpp
umtrx_eeprom.cpp
lms6002d.cpp
lms6002d_ctrl.cpp
tmp102_ctrl.cpp
ads1015_ctrl.cpp
power_amp.cpp
umtrx_fifo_ctrl.cpp
missing/platform.cpp #not properly exported from uhd, so we had to copy it
cores/rx_frontend_core_200.cpp
@@ -104,6 +121,13 @@ MESSAGE(STATUS "Boost include directories: ${Boost_INCLUDE_DIRS}")
MESSAGE(STATUS "Boost library directories: ${Boost_LIBRARY_DIRS}")
MESSAGE(STATUS "Boost libraries: ${Boost_LIBRARIES}")
#additional pthread requirement that may not be automatically included by boost
if (UNIX)
set(CMAKE_THREAD_PREFER_PTHREAD ON)
find_package(Threads)
list(APPEND UMTRX_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
endif()
########################################################################
# Helpful compiler flags
########################################################################
@@ -121,6 +145,20 @@ if(CMAKE_COMPILER_IS_GNUCXX)
endif()
########################################################################
# Look for device filter
########################################################################
message(STATUS "Checking uhd::device::register_device() API...")
message(STATUS " Reading ${UHD_INCLUDE_DIRS}/uhd/device.hpp...")
file(READ ${UHD_INCLUDE_DIRS}/uhd/device.hpp device_hpp)
string(FIND "${device_hpp}" "device_filter_t" has_device_filter)
if ("${has_device_filter}" STREQUAL "-1")
message(STATUS " has original API")
else()
add_definitions(-DUHD_HAS_DEVICE_FILTER)
message(STATUS " has filter API")
endif()
########################################################################
# Build the UmTRX module
########################################################################
@@ -137,3 +175,30 @@ install(
)
add_subdirectory(utils)
########################################################################
# uninstall target
########################################################################
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY)
add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
########################################################################
# package generator
########################################################################
if(NOT CPACK_GENERATOR)
set(CPACK_GENERATOR DEB)
endif()
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "UmTRX UHD support module")
set(CPACK_PACKAGE_VENDOR "Fairwaves")
set(CPACK_PACKAGE_CONTACT "http://fairwaves.co/wp/contact-us/")
set(CPACK_PACKAGE_VERSION ${UMTRX_VERSION})
SET(CPACK_DEBIAN_PACKAGE_DEPENDS "libboost-all-dev, uhd")
SET(CPACK_DEBIAN_PACKAGE_RECOMMENDS "python")
SET(CPACK_PACKAGE_FILE_NAME "umtrx_${UMTRX_VERSION}_${CMAKE_SYSTEM_PROCESSOR}")
SET(CPACK_SET_DESTDIR "ON")
include(CPack) #include last

149
host/ads1015_ctrl.cpp Normal file
View File

@@ -0,0 +1,149 @@
//
// Copyright 2014 Fairwaves 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 3 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, see <http://www.gnu.org/licenses/>.
//
#include "ads1015_ctrl.hpp"
#include <boost/assign/list_of.hpp>
#include <iostream>
#if defined(_MSC_VER) && (_MSC_VER <= 1700)
#define nan(arg) std::strtod("NAN()", (char**)NULL)
#endif
using namespace uhd;
ads1015_ctrl::ads1015_ctrl()
: _addr(ADS1015_NONE)
, _config_reg(0)
{
}
bool ads1015_ctrl::check(const uhd::i2c_iface::sptr& iface, ads1015_addr addr)
{
byte_vector_t cmd = boost::assign::list_of(ADS1015_REG_LO_THRES);
iface->write_i2c(addr, cmd);
byte_vector_t vec = iface->read_i2c(addr, 2);
uint16_t res = (((uint16_t)vec.at(0)) << 8) | vec.at(1);
if (res == 0 || ((res & 0xF) != 0)) {
return false;
}
cmd[0] = ADS1015_REG_HI_THRES;
iface->write_i2c(addr, cmd);
vec = iface->read_i2c(addr, 2);
res = (((uint16_t)vec.at(0)) << 8) | vec.at(1);
if (res == 0xFFFF || ((res & 0xF) != 0xF)) {
return false;
}
return true;
}
void ads1015_ctrl::init(i2c_iface::sptr iface, ads1015_addr addr)
{
_iface = iface;
_addr = addr;
_config_reg = get_reg(ADS1015_REG_CONFIG);
}
void ads1015_ctrl::set_input(ads1015_input input)
{
_config_reg = (_config_reg & ~ADS1015_CONF_MUX_MASK) |
(input << ADS1015_CONF_MUX_OFFS);
set_reg(ADS1015_REG_CONFIG, _config_reg);
}
void ads1015_ctrl::set_pga(ads1015_pga pga)
{
_config_reg = (_config_reg & ~ADS1015_CONF_PGA_MASK) |
(pga << ADS1015_CONF_PGA_OFFS);
set_reg(ADS1015_REG_CONFIG, _config_reg);
}
void ads1015_ctrl::set_mode(bool powerdown)
{
if (powerdown) {
_config_reg |= ADS1015_CONF_MODE;
} else {
_config_reg &= ~ADS1015_CONF_MODE;
}
set_reg(ADS1015_REG_CONFIG, _config_reg);
}
double ads1015_ctrl::get_value()
{
if (!_iface)
return nan("");
struct coeffs {
unsigned u;
unsigned d;
};
static const coeffs gain_cfs[] = {
{2,3}, // 6
{1,1}, // 4
{2,1}, // 2
{4,1}, // 1
{8,1}, // 0.5
{16,1}, // 0.25
};
unsigned pga = (_config_reg & ADS1015_CONF_PGA_MASK) >> ADS1015_CONF_PGA_OFFS;
if (pga > 5)
pga = 5;
if ((_config_reg & ADS1015_CONF_MODE) == ADS1015_CONF_MODE) {
// Power-down mode, start conversion
set_reg(ADS1015_REG_CONFIG, _config_reg | ADS1015_CONF_OS);
// Wait for conversion ready
unsigned i;
for (i = 0; i < ADS1015_POLL_RDY_WATCHDOG; i++) {
if (get_reg(ADS1015_REG_CONFIG) & ADS1015_CONF_OS)
break;
}
if (i == ADS1015_POLL_RDY_WATCHDOG)
return nan("");
}
uint16_t raw = get_reg(ADS1015_REG_CONVERSION);
double val = (raw >> 4);
val = val * gain_cfs[pga].d * 2 / (1000 * gain_cfs[pga].u );
return val;
}
uint16_t ads1015_ctrl::get_reg(ads1015_regs reg)
{
byte_vector_t cmd = boost::assign::list_of(reg);
_iface->write_i2c(_addr, cmd);
byte_vector_t vec = _iface->read_i2c(_addr, 2);
uint16_t res = (((uint16_t)vec.at(0)) << 8) | vec.at(1);
return res;
}
void ads1015_ctrl::set_reg(ads1015_regs reg, uint16_t value)
{
byte_vector_t cmd = boost::assign::list_of((uint8_t)reg)((uint8_t)(value >> 8))((uint8_t)(value & 0xFF));
_iface->write_i2c(_addr, cmd);
}

132
host/ads1015_ctrl.hpp Normal file
View File

@@ -0,0 +1,132 @@
//
// Copyright 2014 Fairwaves 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 3 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, see <http://www.gnu.org/licenses/>.
//
#ifndef INCLUDED_ADS1015_CTRL_HPP
#define INCLUDED_ADS1015_CTRL_HPP
#include <uhd/config.hpp>
#include <uhd/types/serial.hpp>
#include <boost/cstdint.hpp>
#include <boost/thread/thread.hpp>
#include <boost/utility.hpp>
/**
* @brief The ads1015_ctrl class
*
* Control of TI's ADS1015 12bit ADC with 4 muliplexers
*/
class ads1015_ctrl {
public:
enum ads1015_addr {
ADS1015_NONE = 0,
ADS1015_ADDR_GROUND = BOOST_BINARY( 1001000 ),
ADS1015_ADDR_VDD = BOOST_BINARY( 1001001 ),
ADS1015_ADDR_SDA = BOOST_BINARY( 1001010 ),
ADS1015_ADDR_SCL = BOOST_BINARY( 1001011 )
};
enum ads1015_input {
ADS1015_CONF_AIN0_AIN1 = 0,
ADS1015_CONF_AIN0_AIN3 = 1,
ADS1015_CONF_AIN1_AIN1 = 2,
ADS1015_CONF_AIN2_AIN1 = 3,
ADS1015_CONF_AIN0_GND = 4,
ADS1015_CONF_AIN1_GND = 5,
ADS1015_CONF_AIN2_GND = 6,
ADS1015_CONF_AIN3_GND = 7,
};
enum ads1015_pga {
ADS1015_PGA_6_144V = 0,
ADS1015_PGA_4_096V = 1,
ADS1015_PGA_2_048V = 2,
ADS1015_PGA_1_024V = 3,
ADS1015_PGA_0_512V = 4,
ADS1015_PGA_0_256V = 5,
};
enum ads1015_rate {
ADS1015_RATE_128SPS = 0,
ADS1015_RATE_250SPS = 1,
ADS1015_RATE_490SPS = 2,
ADS1015_RATE_920SPS = 3,
ADS1015_RATE_1600SPS = 4,
ADS1015_RATE_2400SPS = 5,
ADS1015_RATE_3300SPS = 6,
};
enum ads1015_comp {
ADS1015_COMP_QUE_1 = 0,
ADS1015_COMP_QUE_2 = 1,
ADS1015_COMP_QUE_4 = 2,
ADS1015_COMP_QUE_DIS = 3,
};
ads1015_ctrl();
void init(uhd::i2c_iface::sptr iface, ads1015_addr addr);
/** @brief check presence of device at @ref addr */
static bool check(const uhd::i2c_iface::sptr& iface, ads1015_addr addr);
void set_input(ads1015_input input);
void set_pga(ads1015_pga input);
double get_value();
void set_mode(bool powerdown);
private:
enum ads1015_regs {
ADS1015_REG_CONVERSION = 0,
ADS1015_REG_CONFIG = 1,
ADS1015_REG_LO_THRES = 2,
ADS1015_REG_HI_THRES = 3
};
enum ads1015_config {
ADS1015_CONF_OS = (1 << 15),
ADS1015_CONF_MUX_OFFS = (12),
ADS1015_CONF_MUX_MASK = (BOOST_BINARY( 111 ) << ADS1015_CONF_MUX_OFFS),
ADS1015_CONF_PGA_OFFS = (9),
ADS1015_CONF_PGA_MASK = (BOOST_BINARY( 111 ) << ADS1015_CONF_PGA_OFFS),
ADS1015_CONF_MODE = (1 << 8), ///< 1 - Power-down single conversion mode
ADS1015_CONF_DR_OFFS = (5),
ADS1015_CONF_DR_MASK = (BOOST_BINARY( 111 ) << ADS1015_CONF_DR_OFFS),
ADS1015_CONF_COMP_MODE= (1 << 4), ///< 1 - Window comparator
ADS1015_CONF_COMP_POL = (1 << 3), ///< 1 - Active high
ADS1015_CONF_COMP_LAT = (1 << 2), ///< 1 - Latching compartator
ADS1015_COMP_QUE_OFFS = (0),
ADS1015_CONF_QUE_MASK = (BOOST_BINARY( 11 ) << ADS1015_COMP_QUE_OFFS),
};
enum {
ADS1015_POLL_RDY_WATCHDOG = 1000
};
uint16_t get_reg(ads1015_regs reg);
void set_reg(ads1015_regs reg, uint16_t value);
uhd::i2c_iface::sptr _iface;
ads1015_addr _addr;
unsigned _config_reg;
};
#endif

View File

@@ -0,0 +1,136 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
# check if this is a submodule
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
#support dirty option (hash cant be specified)
list(FIND ARGN "--dirty" _index)
if (${_index} GREATER -1)
unset(hash)
endif()
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()

View File

@@ -0,0 +1,38 @@
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
set(HEAD_HASH "${HEAD_REF}")
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()

View File

@@ -0,0 +1,21 @@
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
message(STATUS "Uninstalling $ENV{DESTDIR}${file}")
if(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
exec_program(
"@CMAKE_COMMAND@" ARGS "-E remove \"$ENV{DESTDIR}${file}\""
OUTPUT_VARIABLE rm_out
RETURN_VALUE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}")
endif(NOT "${rm_retval}" STREQUAL 0)
else(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
message(STATUS "File $ENV{DESTDIR}${file} does not exist.")
endif(IS_SYMLINK "$ENV{DESTDIR}${file}" OR EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

View File

@@ -105,7 +105,13 @@ static void apply_fe_corrections(
//make the calibration file path
const fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd" / "cal" / (file_prefix + db_eeprom.serial + ".csv");
if (not fs::exists(cal_data_path)) return;
UHD_MSG(status) << "Looking for FE correction at: " << cal_data_path.c_str() << "... ";
if (not fs::exists(cal_data_path)) {
UHD_MSG(status) << "Not found" << std::endl;
return;
}
UHD_MSG(status) << "Found, loading... ";
//parse csv file or get from cache
if (not fe_cal_cache.has_key(cal_data_path.string())){
@@ -133,8 +139,9 @@ static void apply_fe_corrections(
}
std::sort(datas.begin(), datas.end(), fe_cal_comp);
fe_cal_cache[cal_data_path.string()] = datas;
UHD_MSG(status) << "Loaded " << cal_data_path.string() << std::endl;
UHD_MSG(status) << "Loaded" << std::endl;
} else {
UHD_MSG(status) << "Loaded from cache" << std::endl;
}
sub_tree->access<std::complex<double> >(fe_path)

View File

@@ -106,7 +106,7 @@ public:
_task_barrier.resize(size);
_task_handlers.resize(size);
for (size_t i = 1/*skip 0*/; i < size; i++){
_task_handlers[i] = task::make(boost::bind(&recv_packet_handler::converter_thread_task, this, i));
//_task_handlers[i] = task::make(boost::bind(&recv_packet_handler::converter_thread_task, this, i));
};
}
@@ -646,7 +646,7 @@ private:
_convert_bytes_to_copy = bytes_to_copy;
//perform N channels of conversion
converter_thread_task(0);
for (size_t i = 0; i < this->size(); i++) this->converter_thread_task(i);
//update the copy buffer's availability
info.data_bytes_to_copy -= bytes_to_copy;
@@ -666,7 +666,7 @@ private:
******************************************************************/
UHD_INLINE void converter_thread_task(const size_t index)
{
_task_barrier.wait();
//_task_barrier.wait();
//shortcut references to local data structures
buffers_info_type &buff_info = get_curr_buffer_info();
@@ -692,7 +692,7 @@ private:
info.buff.reset(); //effectively a release
}
if (index == 0) _task_barrier.wait_others();
//if (index == 0) _task_barrier.wait_others();
}
//! Shared variables for the worker threads

View File

@@ -88,7 +88,7 @@ public:
_task_barrier.resize(size);
_task_handlers.resize(size);
for (size_t i = 1/*skip 0*/; i < size; i++){
_task_handlers[i] = task::make(boost::bind(&send_packet_handler::converter_thread_task, this, i));
//_task_handlers[i] = task::make(boost::bind(&send_packet_handler::converter_thread_task, this, i));
};
}
@@ -377,7 +377,7 @@ private:
_convert_if_packet_info = &if_packet_info;
//perform N channels of conversion
converter_thread_task(0);
for (size_t i = 0; i < this->size(); i++) this->converter_thread_task(i);
_next_packet_seq++; //increment sequence after commits
return nsamps_per_buff;
@@ -390,7 +390,7 @@ private:
******************************************************************/
UHD_INLINE void converter_thread_task(const size_t index)
{
_task_barrier.wait();
//_task_barrier.wait();
//shortcut references to local data structures
managed_send_buffer::sptr &buff = _props[index].buff;
@@ -420,7 +420,7 @@ private:
buff->commit(num_vita_words32*sizeof(boost::uint32_t));
buff.reset(); //effectively a release
if (index == 0) _task_barrier.wait_others();
//if (index == 0) _task_barrier.wait_others();
}
//! Shared variables for the worker threads

View File

@@ -15,6 +15,9 @@
//
#include "lms6002d.hpp"
#include <boost/thread.hpp>
#define usleep(x) boost::this_thread::sleep(boost::posix_time::microseconds(x))
static int verbosity = 0;
@@ -115,7 +118,7 @@ double lms6002d_dev::txrx_pll_tune(uint8_t reg, double ref_clock, double out_fre
for (int i = 0; i < 64; i++) {
// Update VCOCAP
lms_write_bits(reg + 0x9, 0x3f, i);
//usleep(50);
usleep(50);
int comp = read_reg(reg + 0x0a);
switch (comp >> 6) {
@@ -164,16 +167,27 @@ void lms6002d_dev::init()
write_reg(0x09, 0x00); // RXOUTSW (disabled), CLK_EN (all disabled)
write_reg(0x17, 0xE0);
write_reg(0x27, 0xE3);
write_reg(0x64, 0x32);
write_reg(0x70, 0x01);
write_reg(0x79, 0x37);
write_reg(0x59, 0x09);
write_reg(0x47, 0x40);
// FAQ v1.0r12, 5.27:
write_reg(0x47, 0x40); // Improving Tx spurious emission performance
write_reg(0x59, 0x29); // Improving ADCs performance
write_reg(0x64, 0x36); // Common Mode Voltage For ADCs
write_reg(0x79, 0x37); // Higher LNA Gain
// Power down DC comparators to improve the receiver linearity
// (see FAQ v1.0r12, 5.26)
lms_set_bits(0x6E, (0x3 << 6));
lms_set_bits(0x5F, (0x1 << 7));
// Disable AUX PA
// PA_EN[0]:AUXPA = 0 (powered up) - for mask set v1
// PD_DRVAUX = 0 (powered up) - for mask set v0, test mode only
lms_set_bits(0x44, (3 << 1));
// Icp=0.2mA
// This gives much better results for the GMSK modulation
lms_write_bits(0x16, 0x1f, 0x02);
}
void lms6002d_dev::set_txrx_polarity_and_interleaving(int rx_fsync_polarity,
@@ -211,7 +225,7 @@ int lms6002d_dev::general_dc_calibration_loop(uint8_t dc_addr, uint8_t calibrati
if (verbosity > 1) printf("cnt=%d\n", try_cnt_limit);
// Wait for 6.4(1.6) us
//usleep(6.4);
usleep(6.4);
// Read DC_CLBR_DONE
reg_val = read_reg(calibration_reg_base+0x01);
@@ -241,6 +255,10 @@ int lms6002d_dev::general_dc_calibration_loop(uint8_t dc_addr, uint8_t calibrati
int lms6002d_dev::general_dc_calibration(uint8_t dc_addr, uint8_t calibration_reg_base)
{
// Power up DC comparators
lms_clear_bits(0x6E, (0x3 << 6));
lms_clear_bits(0x5F, (0x1 << 7));
// Set DC_REGVAL to 31
write_reg(calibration_reg_base+0x00, 31);
// Run the calibration first time
@@ -264,6 +282,11 @@ int lms6002d_dev::general_dc_calibration(uint8_t dc_addr, uint8_t calibration_re
}
}
// Power down DC comparators to improve the receiver linearity
// (see FAQ v1.0r12, 5.26)
lms_set_bits(0x6E, (0x3 << 6));
lms_set_bits(0x5F, (0x1 << 7));
if (verbosity > 0) printf("Successful DC Offset Calibration for register bank 0x%X, DC addr %d. Result: 0x%X\n",
calibration_reg_base, dc_addr, DC_REGVAL);
return DC_REGVAL;

View File

@@ -19,8 +19,9 @@
#define INCLUDED_LMS6002D_HPP
#include <stdio.h>
#include <inttypes.h>
#include <stdint.h>
#include <assert.h>
#include <cmath>
/*!
* LMS6002D control class
@@ -91,6 +92,14 @@ public:
lms_clear_bits(0x09, (1 << 2));
}
bool get_tx_pll_locked() {
return get_txrx_pll_locked(0x10);
}
bool get_rx_pll_locked() {
return get_txrx_pll_locked(0x20);
}
uint8_t get_tx_pa() {
return lms_read_shift(0x44, (0x07 << 3), 3);
}
@@ -121,9 +130,9 @@ public:
gain is in [-4 .. -35] dB range
Returns the old gain value */
int8_t set_tx_vga1gain(int8_t gain) {
/* Safety check */
if (not(-35 <= gain and gain <= -4))
gain = -35;
//clip
if (gain < -35) gain = -35;
if (gain > -4) gain = -4;
int8_t old_bits = lms_write_bits(0x41, 0x1f, 35 + gain);
return (old_bits & 0x1f) - 35;
}
@@ -134,30 +143,56 @@ public:
return lms_read_shift(0x41, 0x1f, 0) - 35;
}
/** Set Rx VGA1 gain.
gain is raw values [0 .. 127]
/** Set Rx VGA1 gain raw value
gain is raw values [0 .. 120]
Returns the old gain value */
int8_t set_rx_vga1gain(int8_t gain){
if (gain < 0) // according to standard max value of int8_t is always 127
int8_t set_rx_vga1gain_int(int8_t gain){
if (gain < 0 || gain >120)
gain = 0;
int8_t old_bits = lms_write_bits(0x76, 0x7f, gain);
return old_bits & 0x7f;
}
/** Get Rx VGA1 gain in dB.
gain is in [0 .. 127] range of abstract values
/** Get Rx VGA1 gain raw value
gain is in [0 .. 120] range of abstract values
Returns the gain value */
int8_t get_rx_vga1gain(){
int8_t get_rx_vga1gain_int(){
return lms_read_shift(0x76, 0x7f, 0);
}
/** Converts Rx VGA1 raw values to absolute dBs
code must be in [0 .. 120] range */
double rxvga1_int_to_db(int8_t code){
return 5.0 + 20*log10(127.0/(127.0-code));
}
/** Converts Rx VGA1 gain into raw integer values
db must be in [5 .. 30.17] dB range */
int8_t rxvga1_db_to_int(double db){
return (int8_t)(127.5 - 127 / pow(10, (db-5.0)/20));
}
/** Set Rx VGA1 gain in dB
gain is in [5 .. 30.17] dB range
Returns the old gain value */
double set_rx_vga1gain(double gain){
int8_t code = rxvga1_db_to_int(gain);
return rxvga1_int_to_db(set_rx_vga1gain_int(code));
}
/** Get Rx VGA1 gain in dB
Returns the gain value in [5 .. 30.17] dB range */
double get_rx_vga1gain(){
return rxvga1_int_to_db(get_rx_vga1gain_int());
}
/** Set VGA2 gain.
gain is in dB [0 .. 25]
Returns the old gain value */
int8_t set_tx_vga2gain(int8_t gain) {
/* Safety check */
if (not(0 <= gain and gain <= 25))
gain = 0;
//clip
if (gain < 0) gain = 0;
if (gain > 25) gain = 25;
int8_t old_bits = lms_write_bits(0x45, (0x1f << 3), (gain << 3));
return old_bits >> 3;
}
@@ -175,9 +210,9 @@ public:
gain is in dB [0 .. 60]
Returns the old gain value */
int8_t set_rx_vga2gain(int8_t gain) {
/* Safety check */
if (not (0 <= gain and gain <= 60))
gain = 0;
//clip
if (gain < 0) gain = 0;
if (gain > 60) gain = 60;
int8_t old_bits = lms_write_bits(0x65, 0x1f, gain/3);
return (old_bits & 0x1f) * 3;
}
@@ -472,6 +507,14 @@ public:
protected:
double txrx_pll_tune(uint8_t reg, double ref_clock, double out_freq);
bool get_txrx_pll_locked(uint8_t reg) {
int comp = read_reg(reg + 0x0a) >> 6;
if (comp == 0x00)
return true;
else
return false;
}
void lms_set_bits(uint8_t address, uint8_t mask) {
write_reg(address, read_reg(address) | (mask));
}

View File

@@ -21,6 +21,7 @@
#include <boost/thread.hpp>
#include <boost/array.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <utility>
#include <cmath>
#include <cfloat>
@@ -61,14 +62,42 @@ static const std::vector<std::string> lms_tx_antennas = list_of("TX0")("TX1")("T
static const std::vector<std::string> lms_rx_antennas = list_of("RX0")("RX1")("RX2")("RX3")("CAL");
static const uhd::dict<std::string, gain_range_t> lms_tx_gain_ranges = map_list_of
// ("VGA1", gain_range_t(-35, -4, double(1.0)))
// ("VGA2", gain_range_t(0, 25, double(1.0)))
//listing VGA2 first means that overall gain is first distributed to VGA2
("VGA2", gain_range_t(0, 25, double(1.0)))
("VGA1", gain_range_t(-35, -4, double(1.0)))
// Use a single control to manually control how VGA1/VGA2 are set
("VGA", gain_range_t(-35+0, -4+25, double(1.0)))
// ("VGA", gain_range_t(-35+0, -4+25, double(1.0)))
;
static const uhd::dict<std::string, gain_range_t> lms_rx_gain_ranges = map_list_of
("VGA1", gain_range_t(0, 126, double(1.0)))
// VGA1 follows the approximation of [dB] = 5 + 20*log10(127/(127-Code)) where 0 <= Code <= 120
("VGA1", gain_range_t( list_of
(range_t(5.00))(range_t(5.07))(range_t(5.14))(range_t(5.21))(range_t(5.28))
(range_t(5.35))(range_t(5.42))(range_t(5.49))(range_t(5.57))(range_t(5.64))
(range_t(5.71))(range_t(5.79))(range_t(5.86))(range_t(5.94))(range_t(6.01))
(range_t(6.09))(range_t(6.17))(range_t(6.25))(range_t(6.33))(range_t(6.41))
(range_t(6.49))(range_t(6.57))(range_t(6.65))(range_t(6.74))(range_t(6.82))
(range_t(6.90))(range_t(6.99))(range_t(7.08))(range_t(7.16))(range_t(7.25))
(range_t(7.34))(range_t(7.43))(range_t(7.52))(range_t(7.61))(range_t(7.71))
(range_t(7.80))(range_t(7.90))(range_t(7.99))(range_t(8.09))(range_t(8.19))
(range_t(8.29))(range_t(8.39))(range_t(8.49))(range_t(8.59))(range_t(8.69))
(range_t(8.80))(range_t(8.91))(range_t(9.01))(range_t(9.12))(range_t(9.23))
(range_t(9.35))(range_t(9.46))(range_t(9.57))(range_t(9.69))(range_t(9.81))
(range_t(9.93))(range_t(10.05))(range_t(10.17))(range_t(10.30))(range_t(10.43))
(range_t(10.55))(range_t(10.69))(range_t(10.82))(range_t(10.95))(range_t(11.09))
(range_t(11.23))(range_t(11.37))(range_t(11.51))(range_t(11.66))(range_t(11.81))
(range_t(11.96))(range_t(12.11))(range_t(12.27))(range_t(12.43))(range_t(12.59))
(range_t(12.76))(range_t(12.92))(range_t(13.10))(range_t(13.27))(range_t(13.45))
(range_t(13.63))(range_t(13.82))(range_t(14.01))(range_t(14.21))(range_t(14.41))
(range_t(14.61))(range_t(14.82))(range_t(15.03))(range_t(15.25))(range_t(15.48))
(range_t(15.71))(range_t(15.95))(range_t(16.19))(range_t(16.45))(range_t(16.71))
(range_t(16.97))(range_t(17.25))(range_t(17.53))(range_t(17.83))(range_t(18.13))
(range_t(18.45))(range_t(18.78))(range_t(19.12))(range_t(19.47))(range_t(19.84))
(range_t(20.23))(range_t(20.63))(range_t(21.06))(range_t(21.50))(range_t(21.97))
(range_t(22.47))(range_t(22.99))(range_t(23.55))(range_t(24.15))(range_t(24.80))
(range_t(25.49))(range_t(26.25))(range_t(27.08))(range_t(27.99))(range_t(29.01))
(range_t(30.17))
))
// We limit Rx VGA2 to 30dB, as docs say higher values are dangerous
("VGA2", gain_range_t(0, 30, double(3.0)))
// ToDo: Add LNA control here
@@ -86,14 +115,14 @@ public:
umtrx_lms6002d_dev(uhd::spi_iface::sptr spiface, const int slaveno) : _spiface(spiface), _slaveno(slaveno) {};
virtual void write_reg(uint8_t addr, uint8_t data) {
if (verbosity>2) printf("lms6002d_ctrl_impl::write_reg(addr=0x%x, data=0x%x)\n", addr, data);
if (verbosity>2) printf("umtrx_lms6002d_dev::write_reg(addr=0x%x, data=0x%x)\n", addr, data);
uint16_t command = (((uint16_t)0x80 | (uint16_t)addr) << 8) | (uint16_t)data;
_spiface->write_spi(_slaveno, spi_config_t::EDGE_RISE, command, 16);
}
virtual uint8_t read_reg(uint8_t addr) {
if(addr > 127) return 0; // incorrect address, 7 bit long expected
uint8_t data = _spiface->read_spi(_slaveno, spi_config_t::EDGE_RISE, addr << 8, 16);
if (verbosity>2) printf("lms6002d_ctrl_impl::read_reg(addr=0x%x) data=0x%x\n", addr, data);
if (verbosity>2) printf("umtrx_lms6002d_dev::read_reg(addr=0x%x) data=0x%x\n", addr, data);
return data;
}
};
@@ -124,6 +153,18 @@ public:
return this->set_enabled(dboard_iface::UNIT_TX, enb);
}
uhd::sensor_value_t get_rx_pll_locked()
{
boost::recursive_mutex::scoped_lock l(_mutex);
return uhd::sensor_value_t("LO", lms.get_rx_pll_locked(), "locked", "unlocked");
}
uhd::sensor_value_t get_tx_pll_locked()
{
boost::recursive_mutex::scoped_lock l(_mutex);
return uhd::sensor_value_t("LO", lms.get_tx_pll_locked(), "locked", "unlocked");
}
uhd::freq_range_t get_rx_bw_range(void)
{
return lms_bandwidth_range;
@@ -176,15 +217,20 @@ public:
uint8_t get_tx_vga1dc_i_int(void)
{
boost::recursive_mutex::scoped_lock l(_mutex);
return lms.get_tx_vga1dc_i_int();
}
uint8_t get_tx_vga1dc_q_int(void)
{
return lms.get_tx_vga1dc_i_int();
boost::recursive_mutex::scoped_lock l(_mutex);
return lms.get_tx_vga1dc_q_int();
}
protected:
double set_freq(dboard_iface::unit_t unit, double f) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_freq(%f)\n", f);
unsigned ref_freq = _clock_rate;
double actual_freq = 0;
@@ -214,6 +260,7 @@ public:
}
bool set_enabled(dboard_iface::unit_t unit, bool en) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_enabled(%d)\n", en);
if (unit==dboard_iface::UNIT_RX) {
if (en)
@@ -231,17 +278,21 @@ public:
}
double set_rx_gain(double gain, const std::string &name) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_gain(%f, %s)\n", gain, name.c_str());
assert_has(lms_rx_gain_ranges.keys(), name, "LMS6002D rx gain name");
if(name == "VGA1"){
if(name == "VGA1"){
lms.set_rx_vga1gain(gain);
} else if(name == "VGA2"){
return lms.get_rx_vga1gain();
} else if(name == "VGA2"){
lms.set_rx_vga2gain(gain);
return lms.get_rx_vga2gain();
} else UHD_THROW_INVALID_CODE_PATH();
return gain;
}
void set_rx_ant(const std::string &ant) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_ant(%s)\n", ant.c_str());
//validate input
assert_has(lms_rx_antennas, ant, "LMS6002D rx antenna name");
@@ -275,6 +326,7 @@ public:
}
double set_rx_bandwidth(double bandwidth) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_rx_bandwidth(%f)\n", bandwidth);
// Get the closest available bandwidth
bandwidth = lms_bandwidth_range.clip(bandwidth);
@@ -286,27 +338,19 @@ public:
}
double set_tx_gain(double gain, const std::string &name) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_gain(%f, %s)\n", gain, name.c_str());
//validate input
assert_has(lms_tx_gain_ranges.keys(), name, "LMS6002D tx gain name");
if (name == "VGA") {
// Calculate the best combination of VGA1 and VGA2 gains.
// For simplicity we just try to use VGA2 as much as possible
// and only then engage VGA1.
int desired_vga2 = int(gain) - tx_vga1gain;
if (desired_vga2 < 0)
tx_vga2gain = 0;
else if (desired_vga2 > 25)
tx_vga2gain = 25;
else
tx_vga2gain = desired_vga2;
tx_vga1gain = int(gain) - tx_vga2gain;
// Set the gains in hardware
if (verbosity>1) printf("lms6002d_ctrl_impl::set_tx_gain() VGA1=%d VGA2=%d\n", tx_vga1gain, tx_vga2gain);
lms.set_tx_vga1gain(tx_vga1gain);
lms.set_tx_vga2gain(tx_vga2gain);
if (name == "VGA1") {
if (verbosity>1) printf("db_lms6002d::set_tx_gain() VGA1=%d\n", int(gain));
lms.set_tx_vga1gain(int(gain));
return lms.get_tx_vga1gain();
} else if (name == "VGA2") {
if (verbosity>1) printf("db_lms6002d::set_tx_gain() VGA2=%d\n", int(gain));
lms.set_tx_vga2gain(int(gain));
return lms.get_tx_vga2gain();
} else {
UHD_THROW_INVALID_CODE_PATH();
}
@@ -316,6 +360,7 @@ public:
}
void set_tx_ant(const std::string &ant) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_ant(%s)\n", ant.c_str());
//validate input
assert_has(lms_tx_antennas, ant, "LMS6002D tx antenna ant");
@@ -335,6 +380,7 @@ public:
}
double set_tx_bandwidth(double bandwidth) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_bandwidth(%f)\n", bandwidth);
// Get the closest available bandwidth
bandwidth = lms_bandwidth_range.clip(bandwidth);
@@ -346,12 +392,14 @@ public:
}
uint8_t _set_tx_vga1dc_i_int(uint8_t offset) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_vga1dc_i_int(%d)\n", offset);
lms.set_tx_vga1dc_i_int(offset);
return offset;
}
uint8_t _set_tx_vga1dc_q_int(uint8_t offset) {
boost::recursive_mutex::scoped_lock l(_mutex);
if (verbosity>0) printf("lms6002d_ctrl_impl::set_tx_vga1dc_q_int(%d)\n", offset);
lms.set_tx_vga1dc_q_int(offset);
return offset;
@@ -369,6 +417,8 @@ private:
const int _lms_spi_number;
const int _adf4350_spi_number;
const double _clock_rate;
boost::recursive_mutex _mutex;
};
lms6002d_ctrl::sptr lms6002d_ctrl::make(uhd::spi_iface::sptr spiface, const int lms_spi_number, const int adf4350_spi_number, const double clock_rate)

View File

@@ -3,6 +3,7 @@
#include <uhd/types/ranges.hpp>
#include <uhd/types/serial.hpp>
#include <uhd/types/sensors.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>
#include <string>
@@ -22,6 +23,9 @@ public:
virtual bool set_rx_enabled(const bool enb) = 0;
virtual bool set_tx_enabled(const bool enb) = 0;
virtual uhd::sensor_value_t get_rx_pll_locked() = 0;
virtual uhd::sensor_value_t get_tx_pll_locked() = 0;
virtual double set_rx_gain(const double gain, const std::string &name) = 0;
virtual double set_tx_gain(const double gain, const std::string &name) = 0;

View File

@@ -15,7 +15,7 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
#include <uhd/utils/platform.hpp>
#include "platform.hpp"
#include <uhd/config.hpp>
#include <boost/functional/hash.hpp>
#ifdef UHD_PLATFORM_WIN32

36
host/missing/platform.hpp Normal file
View File

@@ -0,0 +1,36 @@
//
// Copyright 2010,2012 Ettus Research 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 3 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, see <http://www.gnu.org/licenses/>.
//
#ifndef INCLUDED_UHD_UTILS_PLATFORM_HPP_COPY
#define INCLUDED_UHD_UTILS_PLATFORM_HPP_COPY
#include <boost/cstdint.hpp>
namespace uhd {
/* Returns the process ID of the current process */
boost::int32_t get_process_id();
/* Returns a unique identifier for the current machine */
boost::uint32_t get_host_id();
/* Get a unique identifier for the current machine and process */
boost::uint32_t get_process_hash();
} //namespace uhd
#endif /* INCLUDED_UHD_UTILS_PLATFORM_HPP_COPY */

280
host/power_amp.cpp Normal file
View File

@@ -0,0 +1,280 @@
#include "power_amp.hpp"
#include <uhd/utils/msg.hpp>
#include <uhd/exception.hpp>
#include <boost/assign/list_of.hpp>
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <cmath>
using namespace uhd;
/***********************************************************************
* Declarations
**********************************************************************/
class power_amp_impl : public power_amp {
public:
// Voltage to Watts curves
typedef std::map<double,double> pa_curve_t;
power_amp_impl(pa_type_t pa_type, const pa_curve_t &v2w, const pa_curve_t &w2v);
virtual ~power_amp_impl();
// Get the PA type
virtual pa_type_t get_pa_type() const {return _pa_type;}
// Get the PA type as a string
virtual std::string get_pa_type_str() const {return pa_type_to_str(_pa_type);}
// Minimum and maximum supported output power in watts
virtual double min_power_w() const;
virtual double max_power_w() const;
// Minimum and maximum supported output power in dBm
virtual double min_power_dBm() const;
virtual double max_power_dBm() const;
// Get output power in watts for a given voltage
virtual double v2w(double v) const;
// Get input voltage required to generate given output power (in watts)
virtual double w2v(double w) const;
// Get output power in dBm for a given voltage
virtual double v2dBm(double v) const;
// Get input voltage required to generate given output power (in dBm)
virtual double dBm2v(double dBm) const;
protected:
// The PA type
pa_type_t _pa_type;
// Curves
const pa_curve_t &_v2w_curve;
const pa_curve_t _w2v_curve;
};
// Interpolate curve values
static double pa_interpolate_curve(const power_amp_impl::pa_curve_t &curve, double v);
// Convert an A->B map into a B->A map
template<typename map_t> static map_t map_reverse(map_t curve);
/***********************************************************************
* Constants
**********************************************************************/
// NOTE: All names MUST be uppercase for pa_str_to_type() to work correctly
const power_amp::pa_type_map_pair_t power_amp::_pa_type_map[] = {
{power_amp::PA_NONE, "NONE"}, // Also serves as the default
{power_amp::PA_EPA881F40A, "EPA881F40A"},
{power_amp::PA_EPA942H40A, "EPA942H40A"},
{power_amp::PA_EPA1800F37A, "EPA1800F37A"}
};
const power_amp_impl::pa_curve_t EPA942H40A_v2w_curve = boost::assign::map_list_of
(9.5, 1.15)
(10, 1.31)
(11, 1.6)
(12, 1.9)
(12.5, 2.1)
(13, 2.25)
(13.5, 2.44)
(14, 2.6)
(14.5, 2.8)
(15, 3.0)
(15.5, 3.2)
(16, 3.45)
(16.5, 3.7)
(17, 3.9)
(17.5, 4.1)
(18, 4.35)
(18.5, 4.6)
(19, 4.8)
(19.5, 5.1)
(20, 5.4)
(20.5, 5.65)
(21.1, 6.0)
(21.6, 6.2)
(22.1, 6.5)
(22.6, 6.8)
(23.1, 7.1)
(23.4, 7.25)
(23.7, 7.4)
(24, 7.55)
(24.2, 7.7)
(24.5, 7.9)
(24.8, 8.0)
(25.2, 8.25)
(25.5, 8.45)
(25.9, 8.65)
(26.2, 8.9)
(26.6, 9.1)
(28, 10.0);
/***********************************************************************
* Static functions
**********************************************************************/
template<typename map_t>
static map_t map_reverse(map_t curve)
{
map_t reversed;
for (typename map_t::iterator i = curve.begin(); i != curve.end(); ++i)
reversed[i->second] = i->first;
return reversed;
}
static double pa_interpolate_curve(const power_amp_impl::pa_curve_t &curve, double v)
{
power_amp_impl::pa_curve_t::const_iterator i = curve.upper_bound(v);
if (i == curve.end())
{
return (--i)->second;
}
if (i == curve.begin())
{
return i->second;
}
power_amp_impl::pa_curve_t::const_iterator l=i;
--l;
const double delta=(v - l->first) / (i->first - l->first);
return delta*i->second + (1-delta)*l->second;
}
/***********************************************************************
* Make
**********************************************************************/
power_amp::sptr power_amp::make(pa_type_t pa_type) {
switch (pa_type) {
case PA_NONE:
return power_amp::sptr();
case PA_EPA881F40A:
case PA_EPA942H40A:
case PA_EPA1800F37A:
default:
return power_amp::sptr(new power_amp_impl(pa_type, EPA942H40A_v2w_curve,
map_reverse(EPA942H40A_v2w_curve)));
}
}
/***********************************************************************
* power_amp methods
**********************************************************************/
power_amp::~power_amp()
{
}
std::string power_amp::pa_type_to_str(pa_type_t pa)
{
BOOST_FOREACH(const power_amp::pa_type_map_pair_t &pa_map_pair, _pa_type_map)
{
if (pa_map_pair.type == pa)
return pa_map_pair.name;
}
throw uhd::environment_error("Can't map PA type to a string.");
return "NONE";
}
power_amp::pa_type_t power_amp::pa_str_to_type(const std::string &pa_str)
{
std::string pa_str_upper = boost::to_upper_copy(pa_str);
BOOST_FOREACH(const power_amp::pa_type_map_pair_t &pa_map_pair, _pa_type_map)
{
if (pa_map_pair.name == pa_str_upper)
return pa_map_pair.type;
}
UHD_MSG(error) << "PA name " << pa_str << " is not recognized. "
<< "Setting PA type to NONE." << std::endl;
return power_amp::PA_NONE;
}
std::list<power_amp::pa_type_t> power_amp::list_pa_type()
{
std::list<power_amp::pa_type_t> list;
BOOST_FOREACH(const power_amp::pa_type_map_pair_t &pa_map_pair, _pa_type_map) {
list.push_back(pa_map_pair.type);
}
return list;
}
std::list<std::string> power_amp::list_pa_str()
{
std::list<std::string> list;
BOOST_FOREACH(const power_amp::pa_type_map_pair_t &pa_map_pair, _pa_type_map) {
list.push_back(pa_map_pair.name);
}
return list;
}
double power_amp::w2dBm(double w)
{
return 10*log10(w) + 30;
}
double power_amp::dBm2w(double dBm)
{
return pow(10, (dBm-30)/10);
}
/***********************************************************************
* power_amp_impl methods
**********************************************************************/
power_amp_impl::power_amp_impl(pa_type_t pa_type, const pa_curve_t &v2w, const pa_curve_t &w2v)
: _pa_type(pa_type)
, _v2w_curve(v2w)
, _w2v_curve(w2v)
{
}
power_amp_impl::~power_amp_impl()
{
}
double power_amp_impl::min_power_w() const
{
return _w2v_curve.begin()->first;
}
double power_amp_impl::max_power_w() const
{
return _w2v_curve.rbegin()->first;
}
double power_amp_impl::min_power_dBm() const
{
return w2dBm(min_power_w());
}
double power_amp_impl::max_power_dBm() const
{
return w2dBm(max_power_w());
}
double power_amp_impl::v2w(double v) const
{
return pa_interpolate_curve(_v2w_curve, v);
}
double power_amp_impl::w2v(double w) const
{
return pa_interpolate_curve(_w2v_curve, w);
}
double power_amp_impl::v2dBm(double v) const
{
return w2dBm(v2w(v));
}
double power_amp_impl::dBm2v(double dBm) const
{
return w2v(dBm2w(dBm));
}

75
host/power_amp.hpp Normal file
View File

@@ -0,0 +1,75 @@
#ifndef POWER_AMP_HPP
#define POWER_AMP_HPP
#include <uhd/config.hpp>
#include <map>
#include <list>
#include <boost/shared_ptr.hpp>
namespace uhd {
class power_amp {
public:
// Supported Power Amplifiers
enum pa_type_t {
PA_NONE, // No PA connected
PA_EPA881F40A, // EPA881F40A GSM850
PA_EPA942H40A, // EPA942H40A EGSM900
PA_EPA1800F37A // EPA1800F37A DCS1800
};
typedef boost::shared_ptr<power_amp> sptr;
static power_amp::sptr make(pa_type_t pa_type);
virtual ~power_amp();
// Get the PA type
virtual pa_type_t get_pa_type() const =0;
// Get the PA type as a string
virtual std::string get_pa_type_str() const =0;
// Convert PA type to a string
static std::string pa_type_to_str(pa_type_t pa);
// Convert a string to a PA type
static pa_type_t pa_str_to_type(const std::string &pa_str);
// Return a list of PA types
static std::list<pa_type_t> list_pa_type();
// Return a list of PA type strings
static std::list<std::string> list_pa_str();
// Convert watts -> dBm
static double w2dBm(double w);
// Convert dBm -> watts
static double dBm2w(double dBm);
// Minimum and maximum supported output power in watts
virtual double min_power_w() const =0;
virtual double max_power_w() const =0;
// Minimum and maximum supported output power in dBm
virtual double min_power_dBm() const =0;
virtual double max_power_dBm() const =0;
// Get output power in watts for a given voltage
virtual double v2w(double v) const =0;
// Get input voltage required to generate given output power (in watts)
virtual double w2v(double w) const =0;
// Get output power in dBm for a given voltage
virtual double v2dBm(double v) const =0;
// Get input voltage required to generate given output power (in dBm)
virtual double dBm2v(double dBm) const =0;
protected:
// Map PA types to string names
struct pa_type_map_pair_t {
pa_type_t type;
std::string name;
};
static const pa_type_map_pair_t _pa_type_map[];
};
}
#endif // POWER_AMP_HPP

124
host/tmp102_ctrl.cpp Normal file
View File

@@ -0,0 +1,124 @@
//
// Copyright 2014 Fairwaves 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 3 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, see <http://www.gnu.org/licenses/>.
//
#include "tmp102_ctrl.hpp"
#include <boost/assign/list_of.hpp>
#include <iostream>
#if defined(_MSC_VER) && (_MSC_VER <= 1700)
#define nan(arg) std::strtod("NAN()", (char**)NULL)
#endif
using namespace uhd;
tmp102_ctrl::tmp102_ctrl()
: _addr(TMP102_NONE)
, _config(0)
{
}
bool tmp102_ctrl::check(const uhd::i2c_iface::sptr& iface, tmp102_addr addr)
{
byte_vector_t cmd = boost::assign::list_of(REG_CONF);
iface->write_i2c(addr, cmd);
byte_vector_t vec = iface->read_i2c(addr, 2);
uint16_t res = (((uint16_t)vec.at(0)) << 8) | vec.at(1);
// Resolution bits are always set
if (((res & CONF_R_MASK) != CONF_R_MASK) || ((res & 0xF) != 0)) {
return false;
}
return true;
}
void tmp102_ctrl::init(i2c_iface::sptr iface, tmp102_addr addr)
{
_iface = iface;
_addr = addr;
_config = get_reg(REG_CONF);
}
double tmp102_ctrl::get_temp()
{
if (!_iface)
return nan("");
if (_config & CONF_SD) {
// Start conversion in shutdown mode
set_reg(REG_CONF, _config | CONF_OS);
// Wait for conversion ready
unsigned i;
for (i = 0; i < TMP102_POLL_RDY_WATCHDOG; i++) {
if (get_reg(REG_CONF) & CONF_OS)
break;
}
if (i == TMP102_POLL_RDY_WATCHDOG)
return nan("");
}
int16_t tmp = (int16_t)get_reg(REG_TEMP);
if (tmp & 0x001) {
tmp >>= 3;
} else {
tmp >>= 4;
}
return 0.0625 * (double)tmp;
}
void tmp102_ctrl::set_update_rate(conversion_rate rate)
{
_config &= ~CONF_CR_MASK;
_config |= (rate << CONF_CR_OFFS) & CONF_CR_MASK;
set_reg(REG_CONF, _config);
}
void tmp102_ctrl::set_ex_mode(bool ex_mode)
{
if (ex_mode)
_config |= CONF_EM;
else
_config &= ~CONF_EM;
set_reg(REG_CONF, _config);
}
void tmp102_ctrl::set_shutdown_mode(bool shutdown_mode)
{
if (shutdown_mode)
_config |= CONF_SD;
else
_config &= ~CONF_SD;
set_reg(REG_CONF, _config);
}
uint16_t tmp102_ctrl::get_reg(tmp102_regs reg)
{
byte_vector_t cmd = boost::assign::list_of(reg);
_iface->write_i2c(_addr, cmd);
byte_vector_t vec = _iface->read_i2c(_addr, 2);
uint16_t res = ((uint16_t)vec.at(0) << 8) | vec.at(1);
return res;
}
void tmp102_ctrl::set_reg(tmp102_regs reg, uint16_t value)
{
byte_vector_t cmd = boost::assign::list_of((uint8_t)reg)((uint8_t)(value >> 8))((uint8_t)(value & 0xFF));
_iface->write_i2c(_addr, cmd);
}

97
host/tmp102_ctrl.hpp Normal file
View File

@@ -0,0 +1,97 @@
//
// Copyright 2014 Fairwaves 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 3 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, see <http://www.gnu.org/licenses/>.
//
#ifndef INCLUDED_TMP102_CTRL_HPP
#define INCLUDED_TMP102_CTRL_HPP
#include <uhd/config.hpp>
#include <uhd/types/serial.hpp>
#include <boost/cstdint.hpp>
#include <boost/thread/thread.hpp>
#include <boost/utility.hpp>
/**
* @brief The tmp102_ctrl class
*
* Control of TI's TMP102 temperature sensors
*/
class tmp102_ctrl {
public:
enum conversion_rate {
TMP102_CR_025HZ = 0,
TMP102_CR_1HZ = 1,
TMP102_CR_4HZ = 2, // Default
TMP102_CR_8HZ = 3
};
enum tmp102_addr {
TMP102_NONE = 0,
TMP102_GROUND = BOOST_BINARY( 1001000 ),
TMP102_VDD = BOOST_BINARY( 1001001 ),
TMP102_SDA = BOOST_BINARY( 1001010 ),
TMP102_SCL = BOOST_BINARY( 1001011 )
};
tmp102_ctrl();
/** @brief check presence of device at @ref addr */
static bool check(const uhd::i2c_iface::sptr& iface, tmp102_addr addr);
void init(uhd::i2c_iface::sptr iface, tmp102_addr addr);
void set_update_rate(conversion_rate rate);
void set_ex_mode(bool ex_mode);
void set_shutdown_mode(bool shutdown_mode);
double get_temp();
private:
enum tmp102_regs {
REG_TEMP = 0,
REG_CONF = 1,
REG_TLOW = 2,
REG_THIGH = 3
};
enum config_reg {
CONF_OS = (1 << 15),
CONF_R_OFFS = (13), // Read only for TMP102
CONF_R_MASK = (BOOST_BINARY( 11 ) << CONF_R_OFFS),
CONF_F_OFFS = (11), // Fault queue
CONF_F_MASK = (BOOST_BINARY( 11 ) << CONF_F_OFFS),
CONF_POL = (1 << 10),
CONF_TM = (1 << 9), // Thermostat mode
CONF_SD = (1 << 8),
CONF_CR_OFFS = (6), // see conversion_rate
CONF_CR_MASK = (BOOST_BINARY( 11 ) << CONF_CR_OFFS),
CONF_AL = (1 << 5),
CONF_EM = (1 << 4) // Extended temp mode up to +150C
};
enum {
TMP102_POLL_RDY_WATCHDOG = 1000
};
uint16_t get_reg(tmp102_regs reg);
void set_reg(tmp102_regs reg, uint16_t value);
uhd::i2c_iface::sptr _iface;
tmp102_addr _addr;
uint16_t _config;
};
#endif

View File

@@ -55,9 +55,13 @@ static const uhd::dict<std::string, boost::uint8_t> UMTRX_OFFSETS = boost::assig
("tcxo-dac", 0xFF-3) // 2 bytes
("tx2-vga1-dc-i", 0xFF-4) // 1 byte
("tx2-vga1-dc-q", 0xFF-5) // 1 byte
("pa_dcdc_r", 0xFF-6) // 1 byte
("pa_low", 0xFF-7) // 1 byte
("pa_en1", 0xFF-8) // 1 byte
("pa_en2", 0xFF-9) // 1 byte
;
#if 0x18 + SERIAL_LEN + NAME_MAX_LEN >= 0xFF-5
#if 0x18 + SERIAL_LEN + NAME_MAX_LEN >= 0xFF-7
# error EEPROM address overlap! Get a bigger EEPROM.
#endif
@@ -87,6 +91,23 @@ void load_umtrx_eeprom(mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
mb_eeprom["tcxo-dac"] = uint16_bytes_to_string(
iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["tcxo-dac"], 2)
);
mb_eeprom["pa_dcdc_r"] =
boost::lexical_cast<std::string>(unsigned(iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_dcdc_r"], 1).at(0)));
{
uint8_t val = int(iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_low"], 1).at(0));
mb_eeprom["pa_low"] = (val==255)?"":boost::lexical_cast<std::string>(int(val));
}
{
uint8_t val = int(iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_en1"], 1).at(0));
mb_eeprom["pa_en1"] = (val != 0) ?"1":"0";
}
{
uint8_t val = int(iface.read_eeprom(N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_en2"], 1).at(0));
mb_eeprom["pa_en2"] = (val != 0) ?"1":"0";
}
}
void store_umtrx_eeprom(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
@@ -115,4 +136,24 @@ void store_umtrx_eeprom(const mboard_eeprom_t &mb_eeprom, i2c_iface &iface){
N100_EEPROM_ADDR, UMTRX_OFFSETS["tcxo-dac"],
string_to_uint16_bytes(mb_eeprom["tcxo-dac"])
);
if (mb_eeprom.has_key("pa_dcdc_r")) iface.write_eeprom(
N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_dcdc_r"],
byte_vector_t(1, boost::lexical_cast<unsigned>(mb_eeprom["pa_dcdc_r"]))
);
if (mb_eeprom.has_key("pa_low")) iface.write_eeprom(
N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_low"],
byte_vector_t(1, boost::lexical_cast<int>(mb_eeprom["pa_low"]))
);
if (mb_eeprom.has_key("pa_en1")) iface.write_eeprom(
N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_en1"],
byte_vector_t(1, boost::lexical_cast<int>(mb_eeprom["pa_en1"]))
);
if (mb_eeprom.has_key("pa_en2")) iface.write_eeprom(
N100_EEPROM_ADDR, UMTRX_OFFSETS["pa_en2"],
byte_vector_t(1, boost::lexical_cast<int>(mb_eeprom["pa_en2"]))
);
}

View File

@@ -39,18 +39,20 @@ static const boost::uint32_t MAX_SEQS_OUT = 15;
#define SPI_CTRL SR_SPI_CORE + 1
#define SPI_DATA SR_SPI_CORE + 2
// spi clock rate = master_clock/(div+1)/2
#define SPI_DIVIDER 4
#define SPI_DIVIDER 16
class umtrx_fifo_ctrl_impl : public umtrx_fifo_ctrl{
public:
umtrx_fifo_ctrl_impl(zero_copy_if::sptr xport, const boost::uint32_t sid):
umtrx_fifo_ctrl_impl(zero_copy_if::sptr xport, const boost::uint32_t sid, const boost::uint32_t window_size):
_xport(xport),
_sid(sid),
_window_size(std::min(window_size, MAX_SEQS_OUT)),
_seq_out(0),
_seq_ack(0),
_timeout(ACK_TIMEOUT)
{
UHD_MSG(status) << "fifo_ctrl.window_size = " << _window_size << std::endl;
while (_xport->get_recv_buff(0.0)){} //flush
this->set_time(uhd::time_spec_t(0.0));
this->set_tick_rate(1.0); //something possible but bogus
@@ -72,7 +74,7 @@ public:
this->send_pkt((addr - SETTING_REGS_BASE)/4, data, POKE32_CMD);
this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
this->wait_for_ack(_seq_out-_window_size);
}
boost::uint32_t peek32(wb_addr_type addr){
@@ -101,7 +103,7 @@ public:
boost::mutex::scoped_lock lock(_mutex);
this->send_pkt(SPI_DIV, SPI_DIVIDER, POKE32_CMD);
this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
this->wait_for_ack(_seq_out-_window_size);
_ctrl_word_cache = 0; // force update first time around
}
@@ -128,13 +130,13 @@ public:
//conditionally send control word
if (_ctrl_word_cache != ctrl_word){
this->send_pkt(SPI_CTRL, ctrl_word, POKE32_CMD);
this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
this->wait_for_ack(_seq_out-_window_size);
_ctrl_word_cache = ctrl_word;
}
//send data word
this->send_pkt(SPI_DATA, data_out, POKE32_CMD);
this->wait_for_ack(_seq_out-MAX_SEQS_OUT);
this->wait_for_ack(_seq_out-_window_size);
//conditional readback
if (readback){
@@ -230,6 +232,7 @@ private:
zero_copy_if::sptr _xport;
const boost::uint32_t _sid;
const boost::uint32_t _window_size;
boost::mutex _mutex;
boost::uint16_t _seq_out;
boost::uint16_t _seq_ack;
@@ -241,6 +244,6 @@ private:
};
umtrx_fifo_ctrl::sptr umtrx_fifo_ctrl::make(zero_copy_if::sptr xport, const boost::uint32_t sid){
return sptr(new umtrx_fifo_ctrl_impl(xport, sid));
umtrx_fifo_ctrl::sptr umtrx_fifo_ctrl::make(zero_copy_if::sptr xport, const boost::uint32_t sid, const size_t window_size){
return sptr(new umtrx_fifo_ctrl_impl(xport, sid, boost::uint32_t(window_size)));
}

View File

@@ -36,7 +36,7 @@ public:
typedef boost::shared_ptr<umtrx_fifo_ctrl> sptr;
//! Make a new FIFO control object
static sptr make(uhd::transport::zero_copy_if::sptr xport, const boost::uint32_t sid);
static sptr make(uhd::transport::zero_copy_if::sptr xport, const boost::uint32_t sid, const size_t window_size);
//! Set the command time that will activate
virtual void set_time(const uhd::time_spec_t &time) = 0;

View File

@@ -21,7 +21,7 @@
#include "umtrx_iface.hpp"
#include <uhd/exception.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/utils/platform.hpp>
#include "missing/platform.hpp"
#include <uhd/utils/tasks.hpp>
#include <uhd/utils/safe_call.hpp>
#include <uhd/types/dict.hpp>
@@ -354,7 +354,8 @@ public:
const std::string get_fw_version_string(void){
boost::uint32_t minor = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_VER_MINOR);
return str(boost::format("%u.%u") % _protocol_compat % minor);
boost::uint32_t githash = this->get_reg<boost::uint32_t, USRP2_REG_ACTION_FW_PEEK32>(U2_FW_REG_GIT_HASH);
return str(boost::format("%u.%u-g%x") % _protocol_compat % minor % githash);
}
private:

View File

@@ -17,13 +17,14 @@
#include "umtrx_impl.hpp"
#include "umtrx_regs.hpp"
#include "umtrx_version.hpp"
#include "cores/apply_corrections.hpp"
#include <uhd/utils/log.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/types/sensors.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp> //sleep
#include <boost/assign/list_of.hpp>
#include <boost/utility.hpp>
static int verbosity = 0;
@@ -32,6 +33,55 @@ using namespace uhd::usrp;
using namespace uhd::transport;
namespace asio = boost::asio;
// Values recommended by Andrey Sviyazov
const int umtrx_impl::UMTRX_VGA1_DEF = -20;
const int umtrx_impl::UMTRX_VGA2_DEF = 22;
const int umtrx_impl::UMTRX_VGA2_MIN = 0;
static const double _dcdc_val_to_volt_init[256] =
{
9.38, 9.38, 9.40, 9.42, 9.42, 9.44, 9.46, 9.46, 9.48, 9.50, // 10
9.50, 9.52, 9.54, 9.54, 9.56, 9.58, 9.58, 9.60, 9.60, 9.62, // 20
9.64, 9.66, 9.66, 9.68, 9.70, 9.70, 9.72, 9.74, 9.76, 9.76, // 30
9.78, 9.80, 9.82, 9.82, 9.84, 9.86, 9.88, 9.90, 9.92, 9.92, // 40
9.94, 9.96, 9.98, 9.98, 10.00, 10.02, 10.04, 10.06, 10.06, 10.08, // 50
10.10, 10.12, 10.14, 10.16, 10.18, 10.20, 10.20, 10.24, 10.24, 10.28, // 60
10.30, 10.32, 10.34, 10.34, 10.36, 10.38, 10.40, 10.42, 10.44, 10.46, // 70
10.48, 10.50, 10.52, 10.54, 10.56, 10.60, 10.62, 10.64, 10.66, 10.68, // 80
10.70, 10.72, 10.74, 10.76, 10.78, 10.80, 10.84, 10.86, 10.88, 10.90, // 90
10.94, 10.96, 10.98, 11.00, 11.02, 11.06, 11.06, 11.10, 11.12, 11.16, // 100
11.18, 11.20, 11.24, 11.26, 11.28, 11.32, 11.34, 11.38, 11.40, 11.44, // 110
11.46, 11.50, 11.50, 11.54, 11.58, 11.60, 11.64, 11.66, 11.70, 11.74, // 120
11.76, 11.80, 11.84, 11.86, 11.90, 11.94, 11.98, 12.00, 12.02, 12.06, // 130
12.10, 12.14, 12.18, 12.22, 12.26, 12.28, 12.32, 12.36, 12.40, 12.44, // 140
12.48, 12.54, 12.58, 12.62, 12.64, 12.68, 12.72, 12.76, 12.82, 12.86, // 150
12.90, 12.96, 13.00, 13.04, 13.10, 13.14, 13.20, 13.24, 13.30, 13.34, // 160
13.38, 13.44, 13.48, 13.54, 13.60, 13.66, 13.72, 13.76, 13.82, 13.88, // 170
13.94, 14.02, 14.06, 14.14, 14.20, 14.26, 14.30, 14.36, 14.42, 14.50, // 180
14.56, 14.64, 14.72, 14.78, 14.86, 14.92, 15.00, 15.08, 15.16, 15.24, // 190
15.32, 15.40, 15.46, 15.54, 15.62, 15.72, 15.80, 15.90, 16.00, 16.08, // 200
16.18, 16.28, 16.38, 16.48, 16.58, 16.68, 16.80, 16.90, 16.96, 17.08, // 210
17.20, 17.32, 17.44, 17.56, 17.68, 17.82, 17.94, 18.06, 18.20, 18.36, // 220
18.48, 18.64, 18.78, 18.94, 19.02, 19.18, 19.34, 19.50, 19.68, 19.84, // 230
20.02, 20.20, 20.38, 20.58, 20.76, 20.96, 21.18, 21.38, 21.60, 21.82, // 240
21.92, 22.16, 22.40, 22.66, 22.92, 23.18, 23.46, 23.74, 24.02, 24.30, // 250
24.62, 24.94, 25.28, 25.62, 25.98, 26.34
};
const std::vector<double> umtrx_impl::_dcdc_val_to_volt(_dcdc_val_to_volt_init, &_dcdc_val_to_volt_init[256]);
/***********************************************************************
* Property tree "alias" function
**********************************************************************/
template <typename T> property<T> &property_alias(uhd::property_tree::sptr &_tree,
const uhd::fs_path &orig, const uhd::fs_path &alias)
{
// By default route each chanel to its own antenna
return _tree->create<T>(alias)
.subscribe(boost::bind(&uhd::property<T>::set, boost::ref(_tree->access<T>(orig)), _1))
.publish(boost::bind(&uhd::property<T>::get, boost::ref(_tree->access<T>(orig))));
}
/***********************************************************************
* Make
**********************************************************************/
@@ -42,7 +92,11 @@ static device::sptr umtrx_make(const device_addr_t &device_addr){
device_addrs_t umtrx_find(const device_addr_t &hint);
UHD_STATIC_BLOCK(register_umtrx_device){
#ifdef UHD_HAS_DEVICE_FILTER
device::register_device(&umtrx_find, &umtrx_make, device::USRP);
#else
device::register_device(&umtrx_find, &umtrx_make);
#endif
}
/***********************************************************************
@@ -52,6 +106,12 @@ struct mtu_result_t{
size_t recv_mtu, send_mtu;
};
static std::vector<std::string> power_sensors =
boost::assign::list_of("PR1")("PF1")("PR2")("PF2");
static std::vector<std::string> dc_sensors =
boost::assign::list_of("zero")("Vin")("VinPA")("DCOUT");
static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &user_mtu){
udp_simple::sptr udp_sock = udp_simple::make_connected(
addr, BOOST_STRINGIZE(USRP2_UDP_CTRL_PORT)
@@ -120,6 +180,7 @@ static mtu_result_t determine_mtu(const std::string &addr, const mtu_result_t &u
umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
{
_device_ip_addr = device_addr["addr"];
UHD_MSG(status) << "UmTRX driver version: " << UMTRX_VERSION << std::endl;
UHD_MSG(status) << "Opening a UmTRX device... " << _device_ip_addr << std::endl;
//mtu self check -- not really doing anything with it
@@ -171,7 +232,8 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
// high performance settings control
////////////////////////////////////////////////////////////////
_iface->poke32(U2_REG_MISC_CTRL_SFC_CLEAR, 1); //clear settings fifo control state machine
_ctrl = umtrx_fifo_ctrl::make(this->make_xport(UMTRX_CTRL_FRAMER, device_addr_t()), UMTRX_CTRL_SID);
const size_t fifo_ctrl_window(device_addr.cast<size_t>("fifo_ctrl_window", 1024)); //default gets clipped to hardware maximum
_ctrl = umtrx_fifo_ctrl::make(this->make_xport(UMTRX_CTRL_FRAMER, device_addr_t()), UMTRX_CTRL_SID, fifo_ctrl_window);
_ctrl->peek32(0); //test readback
_tree->create<time_spec_t>(mb_path / "time/cmd")
.subscribe(boost::bind(&umtrx_fifo_ctrl::set_time, _ctrl, _1));
@@ -201,6 +263,83 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
_iface->poke32(U2_REG_MISC_LMS_RES, 0);
_iface->poke32(U2_REG_MISC_LMS_RES, LMS1_RESET | LMS2_RESET);
////////////////////////////////////////////////////////////////////////
// autodetect umtrx hardware rev and initialize rev. specific sensors
////////////////////////////////////////////////////////////////////////
detect_hw_rev(mb_path);
_tree->create<std::string>(mb_path / "hwrev").set(get_hw_rev());
UHD_MSG(status) << "Detected UmTRX " << get_hw_rev() << std::endl;
////////////////////////////////////////////////////////////////////////
// configure diversity switches
////////////////////////////////////////////////////////////////////////
// note: the control is also aliased to RF frontend later
_tree->create<bool>(mb_path / "divsw1")
.subscribe(boost::bind(&umtrx_impl::set_diversity, this, _1, 0))
.set(device_addr.cast<bool>("divsw1", false));
UHD_MSG(status) << "Diversity switch for channel 1: "
<< (_tree->access<bool>(mb_path / "divsw1").get()?"true":"false")
<< std::endl;
_tree->create<bool>(mb_path / "divsw2")
.subscribe(boost::bind(&umtrx_impl::set_diversity, this, _1, 1))
.set(device_addr.cast<bool>("divsw2", false));
UHD_MSG(status) << "Diversity switch for channel 2: "
<< (_tree->access<bool>(mb_path / "divsw2").get()?"true":"false")
<< std::endl;
////////////////////////////////////////////////////////////////////////
// set PLL divider
////////////////////////////////////////////////////////////////////////
// TODO: Add EEPROM cell to manually override this
_pll_div = 1;
////////////////////////////////////////////////////////////////////
// get the atached PA type
////////////////////////////////////////////////////////////////////
std::list<std::string> pa_types = power_amp::list_pa_str();
std::string pa_list_str;
BOOST_FOREACH(const std::string &pa_str, pa_types)
{
pa_list_str += pa_str + " ";
}
UHD_MSG(status) << "Known PA types: " << pa_list_str << std::endl;
power_amp::pa_type_t pa_type = power_amp::pa_str_to_type(device_addr.cast<std::string>("pa", "NONE"));
if (_hw_rev < UMTRX_VER_2_3_1 and pa_type != power_amp::PA_NONE)
{
UHD_MSG(error) << "PA type " << power_amp::pa_type_to_str(pa_type) << " is not supported for UmTRX "
<< get_hw_rev() << ". Setting PA type to NONE." << std::endl;
pa_type = power_amp::PA_NONE;
}
for (char name = 'A'; name <= 'B'; name++)
{
std::string name_str = std::string(1, name);
_pa[name_str] = power_amp::make(pa_type);
UHD_MSG(status) << "Installed PA for side" << name_str << ": " << power_amp::pa_type_to_str(pa_type) << std::endl;
}
if (_pa["A"])
{
_pa_power_max_dBm = _pa["A"]->max_power_dBm();
double limit_w = device_addr.cast<double>("pa_power_max_w", _pa["A"]->max_power_w());
if (limit_w != _pa["A"]->max_power_w()) {
_pa_power_max_dBm = power_amp::w2dBm(limit_w);
}
double limit_dbm = device_addr.cast<double>("pa_power_max_dbm", _pa["A"]->max_power_dBm());
if (limit_dbm != _pa["A"]->max_power_dBm()) {
_pa_power_max_dBm = limit_dbm;
}
if (_pa_power_max_dBm != _pa["A"]->max_power_dBm()) {
UHD_MSG(status) << "Limiting PA output power to: " << _pa_power_max_dBm << "dBm (" << power_amp::dBm2w(_pa_power_max_dBm) << "W)" << std::endl;
}
}
////////////////////////////////////////////////////////////////////
// create codec control objects
////////////////////////////////////////////////////////////////////
@@ -215,11 +354,6 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
_tree->create<int>(tx_codec_path / "gains"); //empty cuz gains are in frontend
}
////////////////////////////////////////////////////////////////
// sensors on the mboard
////////////////////////////////////////////////////////////////
_tree->create<sensor_value_t>(mb_path / "sensors"); //phony property so this dir exists
////////////////////////////////////////////////////////////////
// create frontend control objects
////////////////////////////////////////////////////////////////
@@ -253,21 +387,27 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
.set(true);
_tree->create<std::complex<double> >(rx_fe_path / "iq_balance" / "value")
.subscribe(boost::bind(&rx_frontend_core_200::set_iq_balance, rx_fe, _1))
.set(std::polar<double>(1.0, 0.0));
.set(std::polar<double>(0.0, 0.0));
/*
_tree->create<std::complex<double> >(tx_fe_path / "dc_offset" / "value")
.coerce(boost::bind(&tx_frontend_core_200::set_dc_offset, tx_fe, _1))
.set(std::complex<double>(0.0, 0.0));
*/
_tree->create<std::complex<double> >(tx_fe_path / "iq_balance" / "value")
.subscribe(boost::bind(&tx_frontend_core_200::set_iq_balance, tx_fe, _1))
.set(std::polar<double>(1.0, 0.0));
.set(std::polar<double>(0.0, 0.0));
}
////////////////////////////////////////////////////////////////
// create rx dsp control objects
////////////////////////////////////////////////////////////////
_rx_dsps.resize(2);
_rx_dsps[0] = rx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), UMTRX_DSP_RX0_SID, true);
_rx_dsps[1] = rx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), UMTRX_DSP_RX1_SID, true);
_rx_dsps.resize(_iface->peek32(U2_REG_NUM_DDC));
if (_rx_dsps.size() < 2) throw uhd::runtime_error(str(boost::format("umtrx rx_dsps %u -- (unsupported FPGA image?)") % _rx_dsps.size()));
if (_rx_dsps.size() > 0) _rx_dsps[0] = rx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_RX_DSP0), U2_REG_SR_ADDR(SR_RX_CTRL0), UMTRX_DSP_RX0_SID, true);
if (_rx_dsps.size() > 1) _rx_dsps[1] = rx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_RX_DSP1), U2_REG_SR_ADDR(SR_RX_CTRL1), UMTRX_DSP_RX1_SID, true);
if (_rx_dsps.size() > 2) _rx_dsps[2] = rx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_RX_DSP2), U2_REG_SR_ADDR(SR_RX_CTRL2), UMTRX_DSP_RX2_SID, true);
if (_rx_dsps.size() > 3) _rx_dsps[3] = rx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_RX_DSP3), U2_REG_SR_ADDR(SR_RX_CTRL3), UMTRX_DSP_RX3_SID, true);
_tree->create<sensor_value_t>(mb_path / "rx_dsps"); //phony property so this dir exists
for (size_t dspno = 0; dspno < _rx_dsps.size(); dspno++){
_rx_dsps[dspno]->set_mux("IQ", false/*no swap*/);
@@ -294,9 +434,11 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
////////////////////////////////////////////////////////////////
// create tx dsp control objects
////////////////////////////////////////////////////////////////
_tx_dsps.resize(2);
_tx_dsps[0] = tx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_TX_DSP0), U2_REG_SR_ADDR(SR_TX_CTRL0), UMTRX_DSP_TX0_SID);
_tx_dsps[1] = tx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_TX_DSP1), U2_REG_SR_ADDR(SR_TX_CTRL1), UMTRX_DSP_TX1_SID);
_tx_dsps.resize(_iface->peek32(U2_REG_NUM_DUC));
if (_tx_dsps.empty()) _tx_dsps.resize(1); //uhd cant support empty sides
if (_tx_dsps.size() > 0) _tx_dsps[0] = tx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_TX_DSP0), U2_REG_SR_ADDR(SR_TX_CTRL0), UMTRX_DSP_TX0_SID);
if (_tx_dsps.size() > 1) _tx_dsps[1] = tx_dsp_core_200::make(_ctrl, U2_REG_SR_ADDR(SR_TX_DSP1), U2_REG_SR_ADDR(SR_TX_CTRL1), UMTRX_DSP_TX1_SID);
_tree->create<sensor_value_t>(mb_path / "tx_dsps"); //phony property so this dir exists
for (size_t dspno = 0; dspno < _tx_dsps.size(); dspno++){
_tx_dsps[dspno]->set_link_rate(UMTRX_LINK_RATE_BPS);
@@ -348,8 +490,8 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
////////////////////////////////////////////////////////////////////
// create RF frontend interfacing
////////////////////////////////////////////////////////////////////
_lms_ctrl["A"] = lms6002d_ctrl::make(_ctrl/*spi*/, SPI_SS_LMS1, SPI_SS_AUX1, this->get_master_clock_rate());
_lms_ctrl["B"] = lms6002d_ctrl::make(_ctrl/*spi*/, SPI_SS_LMS2, SPI_SS_AUX2, this->get_master_clock_rate());
_lms_ctrl["A"] = lms6002d_ctrl::make(_ctrl/*spi*/, SPI_SS_LMS1, SPI_SS_AUX1, this->get_master_clock_rate() / _pll_div);
_lms_ctrl["B"] = lms6002d_ctrl::make(_ctrl/*spi*/, SPI_SS_LMS2, SPI_SS_AUX2, this->get_master_clock_rate() / _pll_div);
// LMS dboard do not have physical eeprom so we just hardcode values from host/lib/usrp/dboard/db_lms.cpp
dboard_eeprom_t rx_db_eeprom, tx_db_eeprom, gdb_db_eeprom;
@@ -381,9 +523,9 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
//sensors -- always say locked
_tree->create<sensor_value_t>(rx_rf_fe_path / "sensors" / "lo_locked")
.set(sensor_value_t("LO", true, "locked", "unlocked"));
.publish(boost::bind(&lms6002d_ctrl::get_rx_pll_locked, ctrl));
_tree->create<sensor_value_t>(tx_rf_fe_path / "sensors" / "lo_locked")
.set(sensor_value_t("LO", true, "locked", "unlocked"));
.publish(boost::bind(&lms6002d_ctrl::get_tx_pll_locked, ctrl));
//rx gains
BOOST_FOREACH(const std::string &name, ctrl->get_rx_gains())
@@ -397,14 +539,33 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
}
//tx gains
BOOST_FOREACH(const std::string &name, ctrl->get_tx_gains())
if (!_pa[fe_name])
{
_tree->create<meta_range_t>(tx_rf_fe_path / "gains" / name / "range")
.publish(boost::bind(&lms6002d_ctrl::get_tx_gain_range, ctrl, name));
// Use internal LMS gain control if we don't have a PA
BOOST_FOREACH(const std::string &name, ctrl->get_tx_gains())
{
_tree->create<meta_range_t>(tx_rf_fe_path / "gains" / name / "range")
.publish(boost::bind(&lms6002d_ctrl::get_tx_gain_range, ctrl, name));
_tree->create<double>(tx_rf_fe_path / "gains" / name / "value")
.coerce(boost::bind(&lms6002d_ctrl::set_tx_gain, ctrl, _1, name))
.set((ctrl->get_tx_gain_range(name).start() + ctrl->get_tx_gain_range(name).stop())/2.0);
}
} else {
// Set LMS internal VGA1 gain to optimal value
// VGA2 will be set in the set_tx_power()
ctrl->set_tx_gain(UMTRX_VGA1_DEF, "VGA1");
_tx_power_range[fe_name] = generate_tx_power_range(fe_name);
// Use PA control to control output power
_tree->create<meta_range_t>(tx_rf_fe_path / "gains" / "PA" / "range")
.publish(boost::bind(&umtrx_impl::get_tx_power_range, this, fe_name));
_tree->create<double>(tx_rf_fe_path / "gains" / "PA" / "value")
.coerce(boost::bind(&umtrx_impl::set_tx_power, this, _1, fe_name))
// Set default output power to maximum
.set(get_tx_power_range(fe_name).stop());
_tree->create<double>(tx_rf_fe_path / "gains" / name / "value")
.coerce(boost::bind(&lms6002d_ctrl::set_tx_gain, ctrl, _1, name))
.set((ctrl->get_tx_gain_range(name).start() + ctrl->get_tx_gain_range(name).stop())/2.0);
}
//rx freq
@@ -459,8 +620,10 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
//bind frontend corrections to the dboard freq props
_tree->access<double>(tx_rf_fe_path / "freq" / "value")
.set(0.0) //default value
.subscribe(boost::bind(&umtrx_impl::set_tx_fe_corrections, this, "0", fe_name, _1));
_tree->access<double>(rx_rf_fe_path / "freq" / "value")
.set(0.0) //default value
.subscribe(boost::bind(&umtrx_impl::set_rx_fe_corrections, this, "0", fe_name, _1));
//tx cal props
@@ -473,12 +636,19 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
//set Tx DC calibration values, which are read from mboard EEPROM
std::string tx_name = (fe_name=="A")?"tx1":"tx2";
const std::string dc_i = _iface->mb_eeprom.get(tx_name+"-vga1-dc-i", "");
const std::string dc_q = _iface->mb_eeprom.get(tx_name+"-vga1-dc-q", "");
if (not dc_i.empty()) _tree->access<uint8_t>(tx_rf_fe_path / "lms6002d" / "tx_dc_i" / "value")
.set(boost::lexical_cast<int>(dc_i));
if (not dc_q.empty()) _tree->access<uint8_t>(tx_rf_fe_path / "lms6002d" / "tx_dc_q" / "value")
.set(boost::lexical_cast<int>(dc_q));
const std::string dc_i_str = _iface->mb_eeprom.get(tx_name+"-vga1-dc-i", "");
const std::string dc_q_str = _iface->mb_eeprom.get(tx_name+"-vga1-dc-q", "");
double dc_i = dc_i_str.empty() ? 0.0 : dc_offset_int2double(boost::lexical_cast<int>(dc_i_str));
double dc_q = dc_q_str.empty() ? 0.0 : dc_offset_int2double(boost::lexical_cast<int>(dc_q_str));
//plugin dc_offset from lms into the frontend corrections
_tree->create<std::complex<double> >(mb_path / "tx_frontends" / fe_name / "dc_offset" / "value")
.publish(boost::bind(&umtrx_impl::get_dc_offset_correction, this, fe_name))
.subscribe(boost::bind(&umtrx_impl::set_dc_offset_correction, this, fe_name, _1))
.set(std::complex<double>(dc_i, dc_q));
// Alias diversity switch control from mb_path
property_alias<bool>(_tree, mb_path / "divsw"+(fe_name=="A"?"1":"2"), rx_rf_fe_path / "diversity");
}
//set TCXO DAC calibration value, which is read from mboard EEPROM
@@ -495,25 +665,153 @@ umtrx_impl::umtrx_impl(const device_addr_t &device_addr)
_tree->access<double>(mb_path / "dsp_rate")
.set(this->get_master_dsp_rate());
this->time64_self_test();
//reset cordic rates and their properties to zero
BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "rx_dsps"))
{
_tree->access<double>(mb_path / "rx_dsps" / name / "freq" / "value").set(0.0);
}
BOOST_FOREACH(const std::string &name, _tree->list(mb_path / "tx_dsps"))
{
_tree->access<double>(mb_path / "tx_dsps" / name / "freq" / "value").set(0.0);
}
_rx_streamers.resize(_rx_dsps.size());
_tx_streamers.resize(_tx_dsps.size());
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(subdev_spec_t("A:0 B:0"));
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(subdev_spec_t("A:0 B:0"));
subdev_spec_t rx_spec("A:0 B:0 A:0 B:0");
rx_spec.resize(_rx_dsps.size());
_tree->access<subdev_spec_t>(mb_path / "rx_subdev_spec").set(rx_spec);
subdev_spec_t tx_spec("A:0 B:0 A:0 B:0");
tx_spec.resize(_tx_dsps.size());
_tree->access<subdev_spec_t>(mb_path / "tx_subdev_spec").set(tx_spec);
_tree->access<std::string>(mb_path / "clock_source" / "value").set("internal");
_tree->access<std::string>(mb_path / "time_source" / "value").set("none");
//create status monitor and client handler
this->status_monitor_start(device_addr);
}
umtrx_impl::~umtrx_impl(void){
//TODO
umtrx_impl::~umtrx_impl(void)
{
this->status_monitor_stop();
BOOST_FOREACH(const std::string &fe_name, _lms_ctrl.keys())
{
lms6002d_ctrl::sptr ctrl = _lms_ctrl[fe_name];
try
{
ctrl->set_rx_enabled(false);
ctrl->set_tx_enabled(false);
}
catch (...){}
}
}
int umtrx_impl::volt_to_dcdc_r(double v)
{
if (v <= _dcdc_val_to_volt[0])
return 0;
else if (v >= _dcdc_val_to_volt[255])
return 255;
else
return std::lower_bound(_dcdc_val_to_volt.begin(), _dcdc_val_to_volt.end(), v) - _dcdc_val_to_volt.begin();
}
void umtrx_impl::set_pa_dcdc_r(uint8_t val)
{
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
// AD5245 control
if (_hw_rev >= UMTRX_VER_2_3_1)
{
_pa_dcdc_r = val;
_iface->write_i2c(BOOST_BINARY(0101100), boost::assign::list_of(0)(val));
}
}
uhd::gain_range_t umtrx_impl::generate_tx_power_range(const std::string &which) const
{
// Native PA range plus LMS6 VGA2 control. We keep LMS6 VGA1 constant to
// maintain high signal quality.
uhd::gain_range_t pa_range = generate_pa_power_range(which);
// UHD_MSG(status) << "Original PA output power range: " << pa_range.to_pp_string() << std::endl;
uhd::gain_range_t vga_range(pa_range.start() - (UMTRX_VGA2_DEF-UMTRX_VGA2_MIN), pa_range.start()-1, 1.0);
uhd::gain_range_t res_range(vga_range);
res_range.insert(res_range.end(), pa_range.begin(), pa_range.end());
// UHD_MSG(status) << "Generated Tx output power range: " << res_range.to_pp_string() << std::endl;
return res_range;
}
uhd::gain_range_t umtrx_impl::generate_pa_power_range(const std::string &which) const
{
double min_power = _pa[which]->min_power_dBm();
double max_power = _pa_power_max_dBm;
return uhd::gain_range_t(min_power, max_power, 0.1);
}
const uhd::gain_range_t &umtrx_impl::get_tx_power_range(const std::string &which) const
{
return _tx_power_range[which];
}
double umtrx_impl::set_tx_power(double power, const std::string &which)
{
double min_pa_power = _pa[which]->min_power_dBm();
double actual_power;
if (power >= min_pa_power)
{
UHD_MSG(status) << "Setting Tx power using PA (VGA2=" << UMTRX_VGA2_DEF << ", PA=" << power << ")" << std::endl;
// Set VGA2 to the recommended value and use PA to control Tx power
_lms_ctrl[which]->set_tx_gain(UMTRX_VGA2_DEF, "VGA2");
actual_power = set_pa_power(power, which);
} else {
double vga2_gain = UMTRX_VGA2_DEF - (min_pa_power-power);
UHD_MSG(status) << "Setting Tx power using VGA2 (VGA2=" << vga2_gain << ", PA=" << min_pa_power << ")" << std::endl;
// Set PA output power to minimum and use VGA2 to control Tx power
actual_power = _lms_ctrl[which]->set_tx_gain(vga2_gain, "VGA2");
actual_power = set_pa_power(min_pa_power, which) - (UMTRX_VGA2_DEF-actual_power);
}
return actual_power;
}
double umtrx_impl::set_pa_power(double power, const std::string &which)
{
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
// TODO:: Use DCDC bypass for maximum output power
// TODO:: Limit output power for UmSITE-TM3
// Find voltage required for the requested output power
double v = _pa[which]->dBm2v(power);
uint8_t dcdc_val = volt_to_dcdc_r(v);
// Set the value
set_nlow(true);
set_pa_dcdc_r(dcdc_val);
// Check what power do we actually have by reading the DCDC voltage
// and converting it to the PA power
double v_actual = read_dc_v("DCOUT").to_real();
double power_actual = _pa[which]->v2dBm(v_actual);
// TODO:: Check that power is actually there by reading VSWR sensor.
UHD_MSG(status) << "Setting PA power: Requested: " << power << "dBm = " << power_amp::dBm2w(power) << "W "
<< "(" << v << "V dcdc_r=" << int(dcdc_val) << "). "
<< "Actual: " << power_actual << "dBm = " << power_amp::dBm2w(power_actual) <<"W "
<< "(" << v_actual << "V)" << std::endl;
return power_actual;
}
void umtrx_impl::set_mb_eeprom(const uhd::i2c_iface::sptr &iface, const uhd::usrp::mboard_eeprom_t &eeprom)
{
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
store_umtrx_eeprom(eeprom, *iface);
}
void umtrx_impl::time64_self_test(void)
{
//check the the ticks elapsed across a sleep is within an expected range
@@ -549,3 +847,217 @@ uint16_t umtrx_impl::get_tcxo_dac(const umtrx_iface::sptr &iface){
if (verbosity>0) printf("umtrx_impl::get_tcxo_dac(): %d\n", val);
return (uint16_t)val;
}
std::complex<double> umtrx_impl::get_dc_offset_correction(const std::string &which) const
{
return std::complex<double>(
dc_offset_int2double(_lms_ctrl[which]->get_tx_vga1dc_i_int()),
dc_offset_int2double(_lms_ctrl[which]->get_tx_vga1dc_q_int()));
}
void umtrx_impl::set_dc_offset_correction(const std::string &which, const std::complex<double> &corr)
{
_lms_ctrl[which]->_set_tx_vga1dc_i_int(dc_offset_double2int(corr.real()));
_lms_ctrl[which]->_set_tx_vga1dc_q_int(dc_offset_double2int(corr.imag()));
}
double umtrx_impl::dc_offset_int2double(uint8_t corr)
{
return (corr-128)/128.0;
}
uint8_t umtrx_impl::dc_offset_double2int(double corr)
{
return (int)(corr*128 + 128.5);
}
uhd::sensor_value_t umtrx_impl::read_temp_c(const std::string &which)
{
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
double temp = (which == "A") ? _temp_side_a.get_temp() :
_temp_side_b.get_temp();
return uhd::sensor_value_t("Temp"+which, temp, "C");
}
uhd::sensor_value_t umtrx_impl::read_pa_v(const std::string &which)
{
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
unsigned i;
for (i = 0; i < 4; i++) {
if (which == power_sensors[i])
break;
}
UHD_ASSERT_THROW(i < 4);
_sense_pwr.set_input((ads1015_ctrl::ads1015_input)
(ads1015_ctrl::ADS1015_CONF_AIN0_GND + i));
double val = _sense_pwr.get_value() * 10;
return uhd::sensor_value_t("Voltage"+which, val, "V");
}
uhd::sensor_value_t umtrx_impl::read_dc_v(const std::string &which)
{
boost::recursive_mutex::scoped_lock l(_i2c_mutex);
unsigned i;
for (i = 0; i < 4; i++) {
if (which == dc_sensors[i])
break;
}
UHD_ASSERT_THROW(i < 4);
_sense_dc.set_input((ads1015_ctrl::ads1015_input)
(ads1015_ctrl::ADS1015_CONF_AIN0_GND + i));
double val = _sense_dc.get_value() * 40;
return uhd::sensor_value_t("Voltage"+which, val, "V");
}
void umtrx_impl::detect_hw_rev(const fs_path& mb_path)
{
//UmTRX v2.0 doesn't have temp sensors
//UmTRX v2.1 has a temp sensor only on A side
//UmTRX v2.2 has both temp sensor
//UmTRX v2.3.0 has power sensors ADC
//UmTRX v2.3.1 has power supply ADC & programmed resistor array
if (!tmp102_ctrl::check(_iface, tmp102_ctrl::TMP102_SDA)) {
_tree->create<sensor_value_t>(mb_path / "sensors"); //phony property so this dir exists
_hw_rev = UMTRX_VER_2_0;
return;
}
// Initialize side A temp sensor
_temp_side_a.init(_iface, tmp102_ctrl::TMP102_SDA);
_temp_side_a.set_ex_mode(true);
_tree->create<sensor_value_t>(mb_path / "sensors" / "tempA")
.publish(boost::bind(&umtrx_impl::read_temp_c, this, "A"));
UHD_MSG(status) << this->read_temp_c("A").to_pp_string() << std::endl;
if (!tmp102_ctrl::check(_iface, tmp102_ctrl::TMP102_SCL)) {
_hw_rev = UMTRX_VER_2_1;
return;
}
// Initialize side B temp sensor
_temp_side_b.init(_iface, tmp102_ctrl::TMP102_SCL);
_temp_side_b.set_ex_mode(true);
_tree->create<sensor_value_t>(mb_path / "sensors" / "tempB")
.publish(boost::bind(&umtrx_impl::read_temp_c, this, "B"));
UHD_MSG(status) << this->read_temp_c("B").to_pp_string() << std::endl;
if (!ads1015_ctrl::check(_iface, ads1015_ctrl::ADS1015_ADDR_VDD)) {
_hw_rev = UMTRX_VER_2_2;
return;
}
//Initialize PA sense ADC
_sense_pwr.init(_iface, ads1015_ctrl::ADS1015_ADDR_VDD);
_sense_pwr.set_mode(true);
_sense_pwr.set_pga(ads1015_ctrl::ADS1015_PGA_2_048V);
for (unsigned i = 0; i < power_sensors.size(); i++) {
_tree->create<sensor_value_t>(mb_path / "sensors" / "voltage"+power_sensors[i])
.publish(boost::bind(&umtrx_impl::read_pa_v, this, power_sensors[i]));
UHD_MSG(status) << this->read_pa_v(power_sensors[i]).to_pp_string() << std::endl;
}
if (!ads1015_ctrl::check(_iface, ads1015_ctrl::ADS1015_ADDR_GROUND)) {
_hw_rev = UMTRX_VER_2_3_0;
return;
}
_sense_dc.init(_iface, ads1015_ctrl::ADS1015_ADDR_GROUND);
_sense_dc.set_mode(true);
_sense_dc.set_pga(ads1015_ctrl::ADS1015_PGA_1_024V);
for (unsigned i = 0; i < power_sensors.size(); i++) {
_tree->create<sensor_value_t>(mb_path / "sensors" / "voltage"+dc_sensors[i])
.publish(boost::bind(&umtrx_impl::read_dc_v, this, dc_sensors[i]));
UHD_MSG(status) << this->read_dc_v(dc_sensors[i]).to_pp_string() << std::endl;
}
_hw_rev = UMTRX_VER_2_3_1;
_tree->create<uint8_t>(mb_path / "pa_dcdc_r")
.subscribe(boost::bind(&umtrx_impl::set_pa_dcdc_r, this, _1));
std::string pa_dcdc_r = _iface->mb_eeprom.get("pa_dcdc_r", "");
char* pa_dcdc_r_env = getenv("UMTRX_PA_DCDC_R");
if (pa_dcdc_r_env) {
UHD_MSG(status) << "EEPROM value of pa_dcdc_r:" << pa_dcdc_r.c_str()
<< " is overriden with env UMTRX_PA_DCDC_R:"
<< pa_dcdc_r_env << std::endl;
pa_dcdc_r = pa_dcdc_r_env;
}
if (pa_dcdc_r.empty())
set_pa_dcdc_r(0);
else
set_pa_dcdc_r(boost::lexical_cast<unsigned>(pa_dcdc_r));
_pa_en1 = (boost::lexical_cast<int>(_iface->mb_eeprom.get("pa_en1", "1")) == 1);
_pa_en2 = (boost::lexical_cast<int>(_iface->mb_eeprom.get("pa_en2", "1")) == 1);
if (getenv("UMTRX_PA_EN1")) _pa_en1 = (boost::lexical_cast<int>(getenv("UMTRX_PA_EN1")) != 0);
if (getenv("UMTRX_PA_EN2")) _pa_en2 = (boost::lexical_cast<int>(getenv("UMTRX_PA_EN2")) != 0);
std::string pa_low = _iface->mb_eeprom.get("pa_low", "");
char* pa_low_env = getenv("UMTRX_PA_LOW");
if (pa_low_env) {
UHD_MSG(status) << "EEPROM value of pa_low:" << pa_low.c_str()
<< " is overriden with env UMTRX_PA_LOW:"
<< pa_low_env << std::endl;
pa_low = pa_low_env;
}
if (pa_low.empty())
_pa_nlow = false;
else
_pa_nlow = (boost::lexical_cast<int>(pa_low) == 0);
_tree->create<bool>(mb_path / "pa_en1")
.subscribe(boost::bind(&umtrx_impl::set_enpa1, this, _1));
_tree->create<bool>(mb_path / "pa_en2")
.subscribe(boost::bind(&umtrx_impl::set_enpa2, this, _1));
_tree->create<bool>(mb_path / "pa_nlow")
.subscribe(boost::bind(&umtrx_impl::set_nlow, this, _1));
commit_pa_state();
UHD_MSG(status) << "PA low=`" << pa_low.c_str()
<< "` PA dcdc_r=`" << pa_dcdc_r.c_str()
<< "`" << std::endl;
}
void umtrx_impl::commit_pa_state()
{
if (_hw_rev >= UMTRX_VER_2_3_1)
_iface->poke32(U2_REG_MISC_LMS_RES, LMS1_RESET | LMS2_RESET
| PAREG_ENDCSYNC
| ((_pa_nlow) ? PAREG_NLOW_PA : 0)
| ((_pa_en1) ? PAREG_ENPA1 : 0)
| ((_pa_en2) ? PAREG_ENPA2 : 0));
}
void umtrx_impl::set_enpa1(bool en)
{
_pa_en1 = en; commit_pa_state();
}
void umtrx_impl::set_enpa2(bool en)
{
_pa_en2 = en; commit_pa_state();
}
void umtrx_impl::set_nlow(bool en)
{
_pa_nlow = en; commit_pa_state();
}
void umtrx_impl::set_diversity(bool en, int chan)
{
// chan 0 has inversed switch polarity
// chan 1 has straight switch polarity
_iface->poke32(U2_REG_SR_ADDR(SR_DIVSW+chan), (en != (chan==1)) ? 0 : 1);
}
const char* umtrx_impl::get_hw_rev() const
{
switch (_hw_rev) {
case UMTRX_VER_2_0: return "2.0";
case UMTRX_VER_2_1: return "2.1";
case UMTRX_VER_2_2: return "2.2";
case UMTRX_VER_2_3_0: return "2.3.0";
case UMTRX_VER_2_3_1: return "2.3.1";
default: return "[unknown]";
}
}

View File

@@ -28,6 +28,9 @@
#include "cores/rx_dsp_core_200.hpp"
#include "cores/tx_dsp_core_200.hpp"
#include "cores/time64_core_200.hpp"
#include "ads1015_ctrl.hpp"
#include "tmp102_ctrl.hpp"
#include "power_amp.hpp"
#include <uhd/usrp/mboard_eeprom.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/device.hpp>
@@ -35,6 +38,7 @@
#include <uhd/utils/byteswap.hpp>
#include <uhd/types/dict.hpp>
#include <uhd/types/stream_cmd.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/types/clock_config.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <boost/shared_ptr.hpp>
@@ -44,6 +48,8 @@
#include <uhd/transport/udp_simple.hpp>
#include <uhd/transport/udp_zero_copy.hpp>
#include <uhd/transport/bounded_buffer.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <uhd/types/ranges.hpp>
#include <uhd/exception.hpp>
#include <uhd/utils/static.hpp>
@@ -53,6 +59,9 @@
#include <uhd/usrp/subdev_spec.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/asio.hpp>
#include <boost/thread/mutex.hpp>
#include <uhd/utils/tasks.hpp>
// Halfthe size of USRP2 SRAM, because we split the same SRAM into buffers for two Tx channels instead of one.
static const size_t UMTRX_SRAM_BYTES = size_t(1 << 19);
@@ -76,6 +85,8 @@ static const boost::uint32_t UMTRX_DSP_TX1_SID = 3;
//RX stream IDs -- random -- no relevance to FPGA config
static const boost::uint32_t UMTRX_DSP_RX0_SID = 0x20;
static const boost::uint32_t UMTRX_DSP_RX1_SID = 0x21;
static const boost::uint32_t UMTRX_DSP_RX2_SID = 0x22;
static const boost::uint32_t UMTRX_DSP_RX3_SID = 0x23;
//! load and store for umtrx mboard eeprom map
void load_umtrx_eeprom(uhd::usrp::mboard_eeprom_t &mb_eeprom, uhd::i2c_iface &iface);
@@ -99,6 +110,43 @@ public:
boost::shared_ptr<async_md_type> _old_async_queue;
private:
enum umtrx_hw_rev {
UMTRX_VER_2_0,
UMTRX_VER_2_1,
UMTRX_VER_2_2,
UMTRX_VER_2_3_0,
UMTRX_VER_2_3_1
};
// hardware revision
umtrx_hw_rev _hw_rev;
unsigned _pll_div;
const char* get_hw_rev() const;
// Optimal VGA settings for GSM signal, according to our measurements.
static const int UMTRX_VGA1_DEF;
static const int UMTRX_VGA2_DEF;
static const int UMTRX_VGA2_MIN;
// Conversion table for converting DCDC_R values to actual voltages.
static const std::vector<double> _dcdc_val_to_volt;
// Find a dcdc_r value to approximate requested Vout voltage
static int volt_to_dcdc_r(double v);
ads1015_ctrl _sense_pwr;
ads1015_ctrl _sense_dc;
tmp102_ctrl _temp_side_a;
tmp102_ctrl _temp_side_b;
//PA control
bool _pa_nlow;
bool _pa_en1;
bool _pa_en2;
uint8_t _pa_dcdc_r;
double _pa_power_max_dBm; // Artifical PA output power limit, dBm
void set_pa_dcdc_r(uint8_t val);
uint8_t get_pa_dcdc_r() const {return _pa_dcdc_r;}
//communication interfaces
std::string _device_ip_addr;
@@ -107,6 +155,8 @@ private:
//controls for perifs
uhd::dict<std::string, lms6002d_ctrl::sptr> _lms_ctrl;
uhd::dict<std::string, uhd::power_amp::sptr> _pa;
uhd::dict<std::string, uhd::gain_range_t> _tx_power_range; // Tx output power range
//control for FPGA cores
std::vector<rx_frontend_core_200::sptr> _rx_fes;
@@ -130,12 +180,49 @@ private:
void set_rx_fe_corrections(const std::string &mb, const std::string &board, const double);
void set_tx_fe_corrections(const std::string &mb, const std::string &board, const double);
void set_tcxo_dac(const umtrx_iface::sptr &, const uint16_t val);
void detect_hw_rev(const uhd::fs_path &mb_path);
void commit_pa_state();
void set_enpa1(bool en);
void set_enpa2(bool en);
void set_nlow(bool en);
void set_diversity(bool en, int chan);
uhd::gain_range_t generate_tx_power_range(const std::string &which) const;
uhd::gain_range_t generate_pa_power_range(const std::string &which) const;
const uhd::gain_range_t &get_tx_power_range(const std::string &which) const;
double set_tx_power(double power, const std::string &which);
double set_pa_power(double power, const std::string &which);
uint16_t get_tcxo_dac(const umtrx_iface::sptr &);
uhd::transport::zero_copy_if::sptr make_xport(const size_t which, const uhd::device_addr_t &args);
std::complex<double> get_dc_offset_correction(const std::string &which) const;
void set_dc_offset_correction(const std::string &which, const std::complex<double> &corr);
static double dc_offset_int2double(uint8_t corr);
static uint8_t dc_offset_double2int(double corr);
//temp sensors read values in degC
uhd::sensor_value_t read_temp_c(const std::string &which);
uhd::sensor_value_t read_pa_v(const std::string &which);
uhd::sensor_value_t read_dc_v(const std::string &which);
boost::recursive_mutex _i2c_mutex;
//status monitoring
void status_monitor_start(const uhd::device_addr_t &device_addr);
void status_monitor_stop(void);
uhd::task::sptr _status_monitor_task;
void status_monitor_handler(void);
//tcp query server
uhd::task::sptr _server_query_task;
void server_query_handler(void);
boost::asio::io_service _server_query_io_service;
boost::shared_ptr<boost::asio::ip::tcp::acceptor> _server_query_tcp_acceptor;
void client_query_handle(boost::shared_ptr<boost::asio::ip::tcp::socket>);
void client_query_handle1(const boost::property_tree::ptree &request, boost::property_tree::ptree &response);
//streaming
std::vector<boost::weak_ptr<uhd::rx_streamer> > _rx_streamers;
std::vector<boost::weak_ptr<uhd::tx_streamer> > _tx_streamers;
boost::mutex _setupMutex;
};
#endif /* INCLUDED_UMTRX_IMPL_HPP */

View File

@@ -73,7 +73,6 @@ void umtrx_impl::update_rx_subdev_spec(const uhd::usrp::subdev_spec_t &spec)
void umtrx_impl::update_tx_subdev_spec(const uhd::usrp::subdev_spec_t &spec)
{
//sanity checking
validate_subdev_spec(_tree, spec, "tx");
boost::uint32_t tx_fe_sw = 0;
for (size_t i = 0; i < spec.size(); i++)
@@ -185,6 +184,7 @@ uhd::transport::zero_copy_if::sptr umtrx_impl::make_xport(const size_t which, co
**********************************************************************/
uhd::rx_streamer::sptr umtrx_impl::get_rx_stream(const uhd::stream_args_t &args_)
{
boost::mutex::scoped_lock l(_setupMutex);
stream_args_t args = args_;
//setup defaults for unspecified values
@@ -404,7 +404,12 @@ static void handle_tx_async_msgs(
}
stop_flow_control();
while (not xport->get_recv_buff()){};//flush after fc off
//flush after fc off, max time of 1s
size_t i = 0;
while (not xport->get_recv_buff(0.01))
{
if (i++ > 100) break;
}
}
/***********************************************************************
@@ -412,6 +417,7 @@ static void handle_tx_async_msgs(
**********************************************************************/
uhd::tx_streamer::sptr umtrx_impl::get_tx_stream(const uhd::stream_args_t &args_)
{
boost::mutex::scoped_lock l(_setupMutex);
stream_args_t args = args_;
//setup defaults for unspecified values

246
host/umtrx_monitor.cpp Normal file
View File

@@ -0,0 +1,246 @@
//
// Copyright 2015-2015 Fairwaves 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 3 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, see <http://www.gnu.org/licenses/>.
//
#include "umtrx_impl.hpp"
#include <uhd/utils/msg.hpp>
#include <uhd/types/sensors.hpp>
#include <uhd/types/ranges.hpp>
#include <boost/asio.hpp>
using namespace uhd;
using namespace uhd::usrp;
namespace asio = boost::asio;
/*!
* Querying sensors using the status monitor server.
* Requests are encoded in JSON and end in a newline.
* Responses are encoded in JSON and end in a newline.
*
* Start UmTRX driver with status_port set in args
* ./some_application --args="status_port=12345"
*
* import json
* import socket
* s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
* s.connect(("localhost", 12345))
* f = s.makefile() #gives us readline()
*
* #list branches in the property tree
* s.send(json.dumps(dict(action='LIST', path='/mboards/0/sensors'))+'\n')
* print json.loads(f.readline())
* {u'result': [u'tempA']}
*
* #check if the specified path exists
* s.send(json.dumps(dict(action='HAS', path='/mboards/0/sensors/tempA'))+'\n')
* print json.loads(f.readline())
* {u'result': u'true'}
*
* #get the value of a tree entry, types can be BOOL, INT, DOUBLE, SENSOR, RANGE
* s.send(json.dumps(dict(action='GET', path='/mboards/0/sensors/tempA', type='SENSOR'))+'\n')
* print json.loads(f.readline())
* {u'result': {u'unit': u'C', u'name': u'TempA', u'value': u'61.625000'}}
*
* #set the value of a tree entry, types can be BOOL, INT, DOUBLE
* s.send(json.dumps(dict(action='SET', path='/mboards/0/dboards/A/rx_frontends/0/freq/value', type='DOUBLE', value=1e9))+'\n')
* print json.loads(f.readline())
* {} #empty response means no error
*/
void umtrx_impl::status_monitor_start(const uhd::device_addr_t &device_addr)
{
if (device_addr.has_key("status_port"))
{
UHD_MSG(status) << "Creating TCP monitor on port " << device_addr.get("status_port") << std::endl;
_server_query_tcp_acceptor.reset(new asio::ip::tcp::acceptor(
_server_query_io_service, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), device_addr.cast<int>("status_port", 0))));
_server_query_task = task::make(boost::bind(&umtrx_impl::server_query_handler, this));
}
_status_monitor_task = task::make(boost::bind(&umtrx_impl::status_monitor_handler, this));
}
void umtrx_impl::status_monitor_stop(void)
{
_status_monitor_task.reset();
_server_query_task.reset();
}
static bool wait_read_sockfd(const int sockfd, const size_t timeoutMs)
{
//setup timeval for timeout
timeval tv;
tv.tv_sec = 0;
tv.tv_usec = timeoutMs*1000;
//setup rset for timeout
fd_set rset;
FD_ZERO(&rset);
FD_SET(sockfd, &rset);
//call select with timeout on receive socket
return ::select(sockfd+1, &rset, NULL, NULL, &tv) > 0;
}
void umtrx_impl::status_monitor_handler(void)
{
//TODO read the sensors and react...
//read_dc_v, etc...
//UHD_MSG(status) << this->read_temp_c("A").to_pp_string() << std::endl;
//TODO shutdown frontend when temp > thresh
//ctrl->set_rx_enabled(false);
//ctrl->set_tx_enabled(false);
//this sleep defines the polling time between status checks
//when the handler completes, it will be called again asap
//if the task is canceled, this sleep in interrupted for exit
boost::this_thread::sleep(boost::posix_time::milliseconds(1500));
}
void umtrx_impl::server_query_handler(void)
{
//accept the client socket (timeout is 100 ms, task is called again)
if (not wait_read_sockfd(_server_query_tcp_acceptor->native(), 100)) return;
boost::shared_ptr<asio::ip::tcp::socket> socket(new asio::ip::tcp::socket(_server_query_io_service));
_server_query_tcp_acceptor->accept(*socket);
//create a new thread to handle the client
boost::thread handler(boost::bind(&umtrx_impl::client_query_handle, this, socket));
handler.detach();
}
void umtrx_impl::client_query_handle(boost::shared_ptr<boost::asio::ip::tcp::socket> socket)
{
while (not boost::this_thread::interruption_requested())
{
boost::property_tree::ptree request, response;
//receive the request in JSON markup
boost::asio::streambuf requestBuff;
try
{
boost::asio::read_until(*socket, requestBuff, "\n");
std::istream is(&requestBuff);
boost::property_tree::read_json(is, request);
}
catch (const std::exception &ex)
{
if (requestBuff.size() == 0) return; //client ended
response.put("error", "request parser error: " + std::string(ex.what()));
}
//handle the request
try
{
this->client_query_handle1(request, response);
}
catch (const std::exception &ex)
{
response.put("error", "failed to handle request: " + std::string(ex.what()));
}
//send the response
boost::asio::streambuf responseBuff;
std::ostream os(&responseBuff);
try
{
boost::property_tree::write_json(os, response, false/*not pretty required*/);
boost::asio::write(*socket, responseBuff);
}
catch (const std::exception &ex)
{
UHD_MSG(error) << "client_query_handle send response failed, exit client thread: " << ex.what() << std::endl;
return;
}
}
}
void umtrx_impl::client_query_handle1(const boost::property_tree::ptree &request, boost::property_tree::ptree &response)
{
const std::string action = request.get("action", "");
const std::string path = request.get("path", "");
if (response.count("error") != 0)
{
//already in error
}
else if (path.empty())
{
response.put("error", "path field not specified");
}
else if (action.empty())
{
response.put("error", "action field not specified: GET, SET, HAS, LIST");
}
else if (action == "GET")
{
const std::string type = request.get("type", "");
if (type.empty()) response.put("error", "type field not specified: BOOL, INT, DOUBLE, SENSOR, RANGE");
else if (type == "BOOL") response.put("result", _tree->access<bool>(path).get());
else if (type == "INT") response.put("result", _tree->access<int>(path).get());
else if (type == "DOUBLE") response.put("result", _tree->access<double>(path).get());
else if (type == "SENSOR")
{
boost::property_tree::ptree result;
const sensor_value_t sensor = _tree->access<sensor_value_t>(path).get();
result.put("name", sensor.name);
result.put("value", sensor.value);
result.put("unit", sensor.unit);
response.add_child("result", result);
}
else if (type == "RANGE")
{
boost::property_tree::ptree result;
BOOST_FOREACH(const range_t &range, _tree->access<meta_range_t>(path).get())
{
boost::property_tree::ptree rangeData;
rangeData.put("start", range.start());
rangeData.put("stop", range.stop());
rangeData.put("step", range.step());
result.push_back(std::make_pair("", rangeData));
}
response.add_child("result", result);
}
else response.put("error", "unknown type: " + type);
}
else if (action == "SET")
{
const std::string type = request.get("type", "");
if (type.empty()) response.put("error", "type field not specified: BOOL, INT, DOUBLE");
else if (type == "BOOL") _tree->access<bool>(path).set(request.get<bool>("value"));
else if (type == "INT") _tree->access<int>(path).set(request.get<int>("value"));
else if (type == "DOUBLE") _tree->access<double>(path).set(request.get<double>("value"));
else response.put("error", "unknown type: " + type);
}
else if (action == "HAS")
{
response.put("result", _tree->exists(path));
}
else if (action == "LIST")
{
boost::property_tree::ptree result;
BOOST_FOREACH(const std::string &branchName, _tree->list(path))
{
boost::property_tree::ptree branchData;
branchData.put("", branchName);
result.push_back(std::make_pair("", branchData));
}
response.add_child("result", result);
}
else
{
response.put("error", "unknown action: " + action);
}
}

View File

@@ -39,20 +39,20 @@
////////////////////////////////////////////////////////////////////////
// Setting register offsets
////////////////////////////////////////////////////////////////////////
localparam SR_MISC = 0; // 7 regs
localparam SR_MISC = 0; // 9 regs
localparam SR_TIME64 = 10; // 6
localparam SR_BUF_POOL = 16; // 4
localparam SR_RX_FRONT0 = 20; // 5
localparam SR_RX_FRONT1 = 25; // 5
localparam SR_RX_CTRL0 = 32; // 9
localparam SR_RX_DSP0 = 48; // 7
localparam SR_RX_CTRL1 = 80; // 9
localparam SR_RX_DSP1 = 96; // 7
localparam SR_RX_CTRL2 = 66; // 9
localparam SR_RX_DSP2 = 76; // 7
localparam SR_RX_CTRL3 = 83; // 9
localparam SR_RX_DSP3 = 93; // 7
localparam SR_RX_CTRL0 = 30; // 9
localparam SR_RX_DSP0 = 40; // 7
localparam SR_RX_CTRL1 = 50; // 9
localparam SR_RX_DSP1 = 60; // 7
localparam SR_RX_CTRL2 = 70; // 9
localparam SR_RX_DSP2 = 80; // 7
localparam SR_RX_CTRL3 = 90; // 9
localparam SR_RX_DSP3 = 100; // 7
localparam SR_TX_FRONT0 = 110; // ?
localparam SR_TX_CTRL0 = 126; // 6
@@ -94,10 +94,9 @@ localparam SR_SPI_CORE = 185; // 3
// Readback regs
////////////////////////////////////////////////
#define U2_REG_SPI_RB READBACK_BASE + 4*0
#define U2_REG_ADC0 READBACK_BASE + 4*6
#define U2_REG_ADC1 READBACK_BASE + 4*7
#define U2_REG_NUM_DDC READBACK_BASE + 4*1
#define U2_REG_NUM_DUC READBACK_BASE + 4*2
#define U2_REG_STATUS READBACK_BASE + 4*8
#define U2_REG_GPIO_RB READBACK_BASE + 4*9
#define U2_REG_TIME64_HI_RB_IMM READBACK_BASE + 4*10
#define U2_REG_TIME64_LO_RB_IMM READBACK_BASE + 4*11
#define U2_REG_COMPAT_NUM_RB READBACK_BASE + 4*12
@@ -124,4 +123,10 @@ localparam SR_SPI_CORE = 185; // 3
#define LMS1_RESET (1<<0)
#define LMS2_RESET (1<<1)
// Defined for the U2_REG_MISC_LMS_RES register
#define PAREG_NLOW_PA (1<<2)
#define PAREG_ENPA1 (1<<3)
#define PAREG_ENPA2 (1<<4)
#define PAREG_ENDCSYNC (1<<5)
#endif

View File

@@ -0,0 +1 @@
#define UMTRX_VERSION "@UMTRX_VERSION@"

View File

@@ -32,7 +32,7 @@ extern "C" {
//fpga and firmware compatibility numbers
#define USRP2_FPGA_COMPAT_NUM 9
#define USRP2_FW_COMPAT_NUM 12
#define USRP2_FW_VER_MINOR 0
#define USRP2_FW_VER_MINOR 2
//used to differentiate control packets over data port
#define USRP2_INVALID_VRT_HEADER 0
@@ -55,6 +55,7 @@ typedef struct{
#define U2_FW_REG_LOCK_TIME 0
#define U2_FW_REG_LOCK_GPID 1
#define U2_FW_REG_VER_MINOR 7
#define U2_FW_REG_GIT_HASH 6
////////////////////////////////////////////////////////////////////////
// I2C addresses

View File

@@ -3,6 +3,10 @@
########################################################################
INSTALL(PROGRAMS
umtrx_net_burner
umtrx_nmea
umtrx_gps_coord
umtrx_auto_calibration
umtrx_firmware
DESTINATION bin
)
@@ -10,6 +14,19 @@ add_executable(umtrx_test_chains umtrx_test_chains.cpp)
target_link_libraries(umtrx_test_chains ${UMTRX_LIBRARIES})
install(TARGETS umtrx_test_chains DESTINATION bin)
add_executable(umtrx_test_gains umtrx_test_gains.cpp)
target_link_libraries(umtrx_test_gains ${UMTRX_LIBRARIES})
install(TARGETS umtrx_test_gains DESTINATION bin)
add_executable(umtrx_cal_tx_dc_offset umtrx_cal_tx_dc_offset.cpp)
target_link_libraries(umtrx_cal_tx_dc_offset ${UMTRX_LIBRARIES})
install(TARGETS umtrx_cal_tx_dc_offset DESTINATION bin)
add_executable(umtrx_cal_tx_iq_balance umtrx_cal_tx_iq_balance.cpp)
target_link_libraries(umtrx_cal_tx_iq_balance ${UMTRX_LIBRARIES})
install(TARGETS umtrx_cal_tx_iq_balance DESTINATION bin)
add_executable(umtrx_pa_ctrl umtrx_pa_ctrl.cpp)
target_link_libraries(umtrx_pa_ctrl ${UMTRX_LIBRARIES})
install(TARGETS umtrx_pa_ctrl DESTINATION bin)

View File

@@ -20,8 +20,8 @@ def plot_csv(file_path):
if not i: continue #skip titles
tx_lo, icor, qcor, meadured, delta = row
tx_lo = float(tx_lo)/1e9
icor = int(icor)
qcor = int(qcor)
icor = float(icor)
qcor = float(qcor)
freq_vals.append(tx_lo)
dc_i_vals.append(icor)
dc_q_vals.append(qcor)
@@ -34,7 +34,7 @@ def plot_csv(file_path):
plt.figure(1)
plt.subplot(311)
plt.plot(freq_vals, dc_i_vals, freq_vals, dc_q_vals,)
plt.ylim(0, 250)
#plt.ylim(0, 250)
plt.title("Freq (GHz) vs raw IQ corrections")
#plt.xlabel('Freq (GHz)')
plt.grid(True)
@@ -45,7 +45,7 @@ def plot_csv(file_path):
dc_i_std = [np.std(dc_i_vals_per_freq[f]) for f in freqs]
dc_q_std = [np.std(dc_q_vals_per_freq[f]) for f in freqs]
plt.plot(freqs, dc_i_std, freqs, dc_q_std)
plt.ylim(0, 150)
#plt.ylim(0, 150)
plt.title("Freq (GHz) vs stddev IQ corrections")
#plt.xlabel('Freq (GHz)')
plt.grid(True)
@@ -70,7 +70,7 @@ def plot_csv(file_path):
dc_i_avg = [np.mean(dc_i_vals_per_freq[f]) for f in freqs]
dc_q_avg = [np.mean(dc_q_vals_per_freq[f]) for f in freqs]
plt.plot(freqs, dc_i_avg, freqs, dc_q_avg)
plt.ylim(0, 250)
#plt.ylim(0, 250)
plt.title("Freq (GHz) vs averaged IQ corrections")
#plt.xlabel('Freq (GHz)')
plt.grid(True)

134
host/utils/umtrx_auto_calibration Executable file
View File

@@ -0,0 +1,134 @@
#!/bin/sh
if [ "$#" -lt "1" ] ; then
echo "Automatic calibration of an UmTRX for a set of given presets (bands)."
echo
echo "Usage:"
echo " umtrx_cal <preset> [<preset>] [<preset>] ..."
echo
echo " preset - GSM850, EGSM900 (same as GSM900), GSM1800 (same as DCS1800), GSM1900 (same as PCS1900)."
echo
echo "Calibrations to be performed:"
echo " - Tx DC offset calibration"
echo " - Tx IQ balance calibration"
echo
echo "The result of the calibration is stored in the DIR/.uhd/cal/ directory. DIR is one of the \$APPDATA, \$HOME and /tmp,"
echo "whichever is defined. Make sure you run calibration from the same user as the one who runs applications or define"
echo "\$APPDATA or \$HOME appropriately. Calibration files will be loaded by the application automatically on startup."
echo "Old calibration files are renamed when you run a calibration to avoid overwriting."
echo
echo "Calibration is permanent and only depends on temperature. If the temperature of the system is stable, you need to"
echo "run the calibration only once."
exit 1
fi
presets=$*
sides="A B"
uhd_args="--args=fifo_ctrl_window=0"
report=""
run_cal() {
what=$1 ; shift
freq_start=$1 ; shift
freq_stop=$1 ; shift
other_args=$*
freq_step=$(python -c "print $freq_stop - $freq_start if $freq_stop != $freq_start else 1e3")
if [ "$what" = "dc" ] ; then
cmd="umtrx_cal_tx_dc_offset"
elif [ "$what" = "iq" ] ; then
cmd="umtrx_cal_tx_iq_balance"
else
echo "Unknown calibration type \"$what\""
return 1
fi
for side in $sides ; do
echo
echo "------------------------------------------------------------------"
echo " Calibrating $what from $freq_start to $freq_stop for side $side"
echo "------------------------------------------------------------------"
echo
res=255
i=0
while [ $i -lt 10 -a $res -ne 0 ] ; do
i=$(expr $i + 1)
cmd_full="$cmd $uhd_args --freq_start $freq_start --freq_stop $freq_stop --freq_step $freq_step --which $side $other_args"
echo $cmd_full
$cmd_full
res=$(echo $?)
done
text_res="Calibration type $what side $side from $freq_start to $freq_stop:"
if [ $res -ne 0 ] ; then
text_res="$text_res FAIL"
else
text_res="$text_res SUCCESS"
fi
echo
echo "$text_res"
echo
report="$report$text_res\n"
done
}
run_preset() {
preset=$1
echo
echo "===================================================================="
echo " Running preset $preset"
echo "===================================================================="
echo
case $preset in
GSM850)
run_cal dc 869e6 894e6
# The band completely falls into the 810-930 VCO range
run_cal iq 869e6 894e6
;;
GSM900|EGSM900)
run_cal dc 925e6 960e6
# The band spans VCO ranges 810-930 and 930-11425
run_cal iq 925e6 930e6
run_cal iq 930.001e6 960e6 --append
;;
GSM1800|DCS1800)
run_cal dc 1805e6 1880e6
# The band spans VCO ranges 1620-1860 and 1860-2285
run_cal iq 1805e6 1860e6
run_cal iq 1860.001e6 1880e6 --append
;;
GSM1900|PCS1900)
run_cal dc 1930e6 1990e6
# The band completely falls into the 1860-2285 VCO range
run_cal iq 1930e6 1990e6
;;
*)
echo "Unknown preset"
exit 2
;;
esac
}
for preset in $presets ; do
run_preset $preset
done
echo
echo "===================================================================="
echo " Result"
echo "===================================================================="
echo
echo "$report"

View File

@@ -1,6 +1,6 @@
//
// Copyright 2010 Ettus Research LLC
// Copyright 2012 Fairwaves LLC
// Copyright 2012-1015 Fairwaves, Inc
//
// 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
@@ -17,16 +17,10 @@
//
#include "usrp_cal_utils.hpp"
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/random.hpp>
#include <iostream>
#include <complex>
#include <cmath>
@@ -35,77 +29,271 @@
namespace po = boost::program_options;
/***********************************************************************
* Transmit thread
* Calibration utility class
**********************************************************************/
static void tx_thread(uhd::usrp::multi_usrp::sptr usrp, const double tx_wave_freq, const double tx_wave_ampl){
uhd::set_thread_priority_safe();
class dc_cal_t {
public:
dc_cal_t(uhd::property<uint8_t> &dc_i_prop, uhd::property<uint8_t> &dc_q_prop,
uhd::rx_streamer::sptr rx_stream,
const size_t nsamps,
double bb_dc_freq,
double rx_rate,
int verbose,
bool debug_raw_data,
int init_dc_i=128, int init_dc_q=128);
//create a transmit streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
double init();
void run_q(int dc_q);
void run_i(int dc_i);
void run_iq(int dc_i, int dc_q);
//setup variables and allocate buffer
uhd::tx_metadata_t md;
md.has_time_spec = false;
std::vector<samp_type> buff(tx_stream->get_max_num_samps()*10);
void set_dc_i(double i) {prop_set_check(_dc_i_prop, i);}
void set_dc_q(double q) {prop_set_check(_dc_q_prop, q);}
void set_dc_i_best() {set_dc_i(_best_dc_i);}
void set_dc_q_best() {set_dc_q(_best_dc_q);}
//values for the wave table lookup
size_t index = 0;
const double tx_rate = usrp->get_tx_rate();
const size_t step = boost::math::iround(wave_table_len * tx_wave_freq/tx_rate);
wave_table table(tx_wave_ampl);
double get_lowest_offset() const {return _lowest_offset;}
int get_best_dc_i() const {return _best_dc_i;}
int get_best_dc_q() const {return _best_dc_q;}
//fill buff and send until interrupted
while (not boost::this_thread::interruption_requested()){
for (size_t i = 0; i < buff.size(); i++){
buff[i] = table(index += step);
buff[i] = samp_type(0, 0); //using no-power transmit to cal with
protected:
double _lowest_offset;
int _best_dc_i;
int _best_dc_q;
uhd::property<uint8_t> &_dc_i_prop;
uhd::property<uint8_t> &_dc_q_prop;
uhd::rx_streamer::sptr _rx_stream;
std::vector<samp_type> _buff;
const size_t _nsamps;
double _bb_dc_freq;
double _rx_rate;
int _verbose;
bool _debug_raw_data;
void prop_set_check(uhd::property<uint8_t> &prop, uint8_t val);
double get_dbrms();
bool run_x();
};
dc_cal_t::dc_cal_t(uhd::property<uint8_t> &dc_i_prop, uhd::property<uint8_t> &dc_q_prop,
uhd::rx_streamer::sptr rx_stream,
const size_t nsamps,
double bb_dc_freq,
double rx_rate,
int verbose,
bool debug_raw_data,
int init_dc_i,
int init_dc_q)
: _best_dc_i(init_dc_i), _best_dc_q(init_dc_q)
, _dc_i_prop(dc_i_prop), _dc_q_prop(dc_q_prop)
, _rx_stream(rx_stream)
, _nsamps(nsamps)
, _bb_dc_freq(bb_dc_freq)
, _rx_rate(rx_rate)
, _verbose(verbose)
, _debug_raw_data(debug_raw_data)
{
}
double dc_cal_t::init()
{
set_dc_i_best();
set_dc_q_best();
//get the DC offset tone size
_lowest_offset = get_dbrms();
if (_verbose) printf("initial_dc_dbrms = %2.0f dB\n", _lowest_offset);
if (_debug_raw_data) write_samples_to_file(_buff, "initial_samples.dat");
return _lowest_offset;
}
void dc_cal_t::run_q(int dc_q)
{
if (_verbose) printf(" dc_q = %d", dc_q);
set_dc_q(dc_q);
if (run_x())
_best_dc_q = dc_q;
}
void dc_cal_t::run_i(int dc_i)
{
if (_verbose) printf(" dc_i = %d", dc_i);
set_dc_i(dc_i);
if (run_x())
_best_dc_i = dc_i;
}
void dc_cal_t::run_iq(int dc_i, int dc_q)
{
if (_verbose) printf(" dc_i = %d dc_q = %d", dc_i, dc_q);
set_dc_i(dc_i);
set_dc_q(dc_q);
if (run_x()) {
_best_dc_i = dc_i;
_best_dc_q = dc_q;
}
}
void dc_cal_t::prop_set_check(uhd::property<uint8_t> &prop, uint8_t val)
{
prop.set(val);
uint8_t val_read = prop.get();
if (val_read != val)
throw std::runtime_error(
str(boost::format("Calibration property sets incorrectly. Requested %d, read back %d")
% int(val) % int(val_read)));
}
double dc_cal_t::get_dbrms()
{
//receive some samples
capture_samples(_rx_stream, _buff, _nsamps);
//calculate dB rms
return compute_tone_dbrms(_buff, _bb_dc_freq/_rx_rate);
}
bool dc_cal_t::run_x()
{
bool better = false;
//get the DC offset tone size
const double dc_dbrms = get_dbrms();
if (_verbose) printf(" dc_dbrms = %2.0f dB", dc_dbrms);
if (dc_dbrms < _lowest_offset){
_lowest_offset = dc_dbrms;
better = true;
if (_verbose) printf(" *");
if (_debug_raw_data) write_samples_to_file(_buff, "best_samples.dat");
}
if (_verbose) printf("\n");
return better;
}
/***********************************************************************
* Calibration method: Downhill
**********************************************************************/
static result_t calibrate_downhill(dc_cal_t &dc_cal,
double tx_lo,
int verbose)
{
//bounds and results from searching
int dc_i_start, dc_i_stop, dc_i_step;
int dc_q_start, dc_q_stop, dc_q_step;
//capture initial uncorrected value
const double initial_dc_dbrms = dc_cal.init();
for (size_t i = 0; i < 6; i++)
{
if (verbose) printf(" iteration %ld best_i = %d best_q = %d\n", i, dc_cal.get_best_dc_i(), dc_cal.get_best_dc_q());
switch (i) {
case 0:
dc_i_start = 0;
dc_i_stop = 256;
dc_q_start = 0;
dc_q_stop = 256;
dc_i_step = 10;
dc_q_step = 10;
break;
case 1:
dc_i_start = dc_cal.get_best_dc_i() - 15;
dc_i_stop = dc_cal.get_best_dc_i() + 15;
dc_q_start = dc_cal.get_best_dc_q() - 15;
dc_q_stop = dc_cal.get_best_dc_q() + 15;
dc_i_step = 1;
dc_q_step = 1;
break;
case 2:
case 3:
dc_i_start = dc_cal.get_best_dc_i() - 3;
dc_i_stop = dc_cal.get_best_dc_i() + 3;
dc_q_start = dc_cal.get_best_dc_q() - 3;
dc_q_stop = dc_cal.get_best_dc_q() + 3;
dc_i_step = 1;
dc_q_step = 1;
break;
default:
dc_i_start = dc_cal.get_best_dc_i() - 1;
dc_i_stop = dc_cal.get_best_dc_i() + 1;
dc_q_start = dc_cal.get_best_dc_q() - 1;
dc_q_stop = dc_cal.get_best_dc_q() + 1;
dc_i_step = 1;
dc_q_step = 1;
break;
};
if (i <= 2) {
// Itereate through I and Q sequentially
if (verbose) printf(" I in [%d; %d] step %d Q = %d\n",
dc_i_start, dc_i_stop, dc_i_step, dc_cal.get_best_dc_q());
dc_cal.set_dc_q_best();
for (int dc_i = dc_i_start; dc_i <= dc_i_stop; dc_i += dc_i_step){
dc_cal.run_i(dc_i);
}
if (verbose) printf(" I = %d Q in [%d; %d] step %d\n",
dc_cal.get_best_dc_i(), dc_q_start, dc_q_stop, dc_q_step);
dc_cal.set_dc_i_best();
for (int dc_q = dc_q_start; dc_q <= dc_q_stop; dc_q += dc_q_step){
dc_cal.run_q(dc_q);
}
} else {
// Itereate through all combinations of I and Q
if (verbose) printf(" I in [%d; %d] step %d Q in [%d; %d] step %d\n",
dc_i_start, dc_i_stop, dc_i_step,
dc_q_start, dc_q_stop, dc_q_step);
for (int dc_i = dc_i_start; dc_i <= dc_i_stop; dc_i += dc_i_step) {
for (int dc_q = dc_q_start; dc_q <= dc_q_stop; dc_q += dc_q_step) {
dc_cal.run_iq(dc_i, dc_q);
}
}
}
tx_stream->send(&buff.front(), buff.size(), md);
}
//send a mini EOB packet
md.end_of_burst = true;
tx_stream->send("", 0, md);
}
// Calibration result
result_t result;
result.freq = tx_lo;
result.real_corr = dc_cal.get_best_dc_i();
result.imag_corr = dc_cal.get_best_dc_q();
result.best = dc_cal.get_lowest_offset();
result.delta = initial_dc_dbrms - result.best;
/***********************************************************************
* Tune RX and TX routine
**********************************************************************/
static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double tx_lo_freq, const double rx_offset){
//tune the transmitter with no cordic
uhd::tune_request_t tx_tune_req(tx_lo_freq);
tx_tune_req.dsp_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
tx_tune_req.dsp_freq = 0;
usrp->set_tx_freq(tx_tune_req);
// Output to console
std::cout
<< result.freq/1e6 << " MHz "
<< "I/Q = " << result.real_corr << "/" << result.imag_corr << " "
<< "(" << dc_offset_int2double(result.real_corr) << "/"
<< dc_offset_int2double(result.imag_corr) << ") "
<< "leakage = " << result.best << " dB, "
<< "improvement = " << result.delta << " dB\n"
<< std::flush
;
//tune the receiver
usrp->set_rx_freq(uhd::tune_request_t(usrp->get_tx_freq(), rx_offset));
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
return usrp->get_tx_freq();
}
/***********************************************************************
* random uniform int
**********************************************************************/
static int uniform_rand(const int low, const int high)
{
static boost::random::mt19937 rng;
boost::random::uniform_int_distribution<> dist(low, high);
return dist(rng);
return result;
}
/***********************************************************************
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
std::string args, which, serial;
int verbose;
int vga1_gain, vga2_gain, rx_gain;
double tx_wave_freq, tx_wave_ampl, rx_offset;
double freq_start, freq_stop, freq_step;
size_t nsamps;
size_t ntrials;
std::string which;
int single_test_i, single_test_q;
po::options_description desc("Allowed options");
desc.add_options()
@@ -113,15 +301,22 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
("verbose", "enable some verbose")
("debug_raw_data", "save raw captured signals to files")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
("which", po::value<std::string>(&which)->default_value("A"), "Which chain A or B?")
("vga1", po::value<int>(&vga1_gain)->default_value(-20), "LMS6002D Tx VGA1 gain [-35 to -4]")
("vga2", po::value<int>(&vga2_gain)->default_value(22), "LMS6002D Tx VGA2 gain [0 to 25]")
("rx_gain", po::value<int>(&rx_gain)->default_value(50), "LMS6002D Rx combined gain [0 to 156]")
("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(50e3), "Transmit wave frequency in Hz")
("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts")
("rx_offset", po::value<double>(&rx_offset)->default_value(.9344e6), "RX LO offset from the TX LO in Hz")
("rx_offset", po::value<double>(&rx_offset)->default_value(300e3), "RX LO offset from the TX LO in Hz")
("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)")
("freq_stop", po::value<double>(&freq_stop), "Frequency stop in Hz (do not specify for default)")
("freq_step", po::value<double>(&freq_step)->default_value(default_freq_step), "Step size for LO sweep in Hz")
("nsamps", po::value<size_t>(&nsamps)->default_value(default_num_samps), "Samples per data capture")
("ntrials", po::value<size_t>(&ntrials)->default_value(1), "Num trials per TX LO")
("which", po::value<std::string>(&which)->default_value("A"), "Which chain A or B?")
("single_test", "Perform a single measurement and exit (freq = freq_start, I = single_test_i, Q = single_test_q]")
("single_test_i", po::value<int>(&single_test_i)->default_value(128), "Only in the single test mode! I channel calibration value [0 to 255]")
("single_test_q", po::value<int>(&single_test_q)->default_value(128), "Only in the single test mode! Q channel calibration value [0 to 255]")
("append", "Append measurements to the calibratoin file instead of rewriting [default=overwrite]")
;
po::variables_map vm;
@@ -130,31 +325,17 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
//print the help message
if (vm.count("help")){
std::cout << boost::format("USRP Generate TX DC Offset Calibration Table %s") % desc << std::endl;
std::cout << boost::format("UmTRX Generate TX DC Offset Calibration Table %s") % desc << std::endl;
std::cout <<
"This application measures leakage between RX and TX on an XCVR daughterboard to self-calibrate.\n"
"This application measures leakage between RX and TX using LMS6002D internal RF loopback to self-calibrate.\n"
<< std::endl;
return ~0;
return EXIT_FAILURE;
}
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
verbose = vm.count("verbose");
//set subdev spec
usrp->set_rx_subdev_spec(which+":0");
usrp->set_tx_subdev_spec(which+":0");
//set the antennas to cal
if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
}
usrp->set_rx_antenna("CAL");
usrp->set_tx_antenna("CAL");
//set optimum defaults
set_optimum_defaults(usrp);
// Create a USRP device
uhd::usrp::multi_usrp::sptr usrp = setup_usrp_for_cal(args, which, serial, vga1_gain, vga2_gain, rx_gain, verbose);
//create a receive streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
@@ -164,18 +345,18 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
boost::thread_group threads;
threads.create_thread(boost::bind(&tx_thread, usrp, tx_wave_freq, tx_wave_ampl));
//re-usable buffer for samples
std::vector<samp_type> buff;
//store the results here
std::vector<result_t> results;
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path tx_fe_path = "/mboards/0/dboards/"+which+"/tx_frontends/0";
uhd::property<uint8_t> &dc_i_prop = usrp->get_device()->get_tree()->access<uint8_t>(tx_fe_path / "lms6002d/tx_dc_i/value");
uhd::property<uint8_t> &dc_q_prop = usrp->get_device()->get_tree()->access<uint8_t>(tx_fe_path / "lms6002d/tx_dc_q/value");
uhd::property<uint8_t> &dc_i_prop = tree->access<uint8_t>(tx_fe_path / "lms6002d/tx_dc_i/value");
uhd::property<uint8_t> &dc_q_prop = tree->access<uint8_t>(tx_fe_path / "lms6002d/tx_dc_q/value");
if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6;
if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6;
UHD_MSG(status) << boost::format("Calibration frequency type: DC offset") << std::endl;
UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl;
for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){
const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset);
@@ -185,77 +366,37 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
const double actual_tx_freq = usrp->get_tx_freq();
const double actual_rx_freq = usrp->get_rx_freq();
const double bb_dc_freq = actual_tx_freq - actual_rx_freq;
if (vm.count("verbose")) printf("actual_rx_rate = %0.2f MHz\n", actual_rx_rate/1e6);
if (vm.count("verbose")) printf("actual_tx_freq = %0.2f MHz\n", actual_tx_freq/1e6);
if (vm.count("verbose")) printf("actual_rx_freq = %0.2f MHz\n", actual_rx_freq/1e6);
if (vm.count("verbose")) printf("bb_dc_freq = %0.2f MHz\n", bb_dc_freq/1e6);
if (verbose) printf("actual_rx_rate = %0.2f MHz\n", actual_rx_rate/1e6);
if (verbose) printf("actual_tx_freq = %0.2f MHz\n", actual_tx_freq/1e6);
if (verbose) printf("actual_rx_freq = %0.2f MHz\n", actual_rx_freq/1e6);
if (verbose) printf("bb_dc_freq = %0.2f MHz\n", bb_dc_freq/1e6);
for (size_t trial_no = 0; trial_no < ntrials; trial_no++)
{
//bounds and results from searching
double lowest_offset;
int best_dc_i = 128, best_dc_q = 128;
//capture initial uncorrected value
dc_i_prop.set(best_dc_i);
dc_q_prop.set(best_dc_q);
capture_samples(rx_stream, buff, nsamps);
const double initial_dc_dbrms = compute_tone_dbrms(buff, bb_dc_freq/actual_rx_rate);
lowest_offset = initial_dc_dbrms;
if (vm.count("verbose")) printf("initial_dc_dbrms = %2.0f dB\n", initial_dc_dbrms);
if (vm.count("debug_raw_data")) write_samples_to_file(buff, "initial_samples.dat");
for (int bound = 256; bound >= 8; bound /= 2) //how many bits of precision to care about for the search
if (vm.count("single_test"))
{
if (vm.count("verbose")) printf(" iteration %du\n", bound);
dc_cal_t dc_cal(dc_i_prop, dc_q_prop,
rx_stream,
nsamps,
bb_dc_freq,
actual_rx_rate,
verbose,
vm.count("debug_raw_data"),
single_test_i, single_test_q);
bool has_improvement = false;
for (int rand_search_no = 0; rand_search_no < bound/4; rand_search_no++) //how many random points to inspect
{
int dc_i = uniform_rand(std::max(0, best_dc_i-bound/2), std::min(256, best_dc_i+bound/2));
int dc_q = uniform_rand(std::max(0, best_dc_q-bound/2), std::min(256, best_dc_q+bound/2));
if (vm.count("verbose")) std::cout << "bound " << bound << " dc_i " << dc_i << " dc_q " << dc_q << std::endl;
dc_i_prop.set(dc_i);
dc_q_prop.set(dc_q);
//receive some samples
capture_samples(rx_stream, buff, nsamps);
const double dc_dbrms = compute_tone_dbrms(buff, bb_dc_freq/actual_rx_rate);
if (vm.count("verbose")) printf(" dc_dbrms = %2.0f dB", dc_dbrms);
if (dc_dbrms < lowest_offset){
lowest_offset = dc_dbrms;
best_dc_i = dc_i;
best_dc_q = dc_q;
has_improvement = true;
if (vm.count("verbose")) printf(" *");
if (vm.count("debug_raw_data")) write_samples_to_file(buff, "best_samples.dat");
}
if (vm.count("verbose")) printf("\n");
}
// Stop iterating if no imprevement, but do at least 3 iterations
if (!has_improvement and bound < 64) break;
}
if (vm.count("verbose")) printf(" best_dc_i = %d best_dc_q = %d", best_dc_i, best_dc_q);
if (vm.count("verbose")) printf(" lowest_offset = %2.0f dB delta = %2.0f dB\n", lowest_offset, initial_dc_dbrms - lowest_offset);
if (lowest_offset < initial_dc_dbrms){ //most likely valid, keep result
result_t result;
result.freq = tx_lo;
result.real_corr = best_dc_i;
result.imag_corr = best_dc_q;
result.best = lowest_offset;
result.delta = initial_dc_dbrms - lowest_offset;
results.push_back(result);
if (vm.count("verbose")){
std::cout << boost::format("TX DC: %f MHz: lowest offset %f dB, corrected %f dB") % (tx_lo/1e6) % result.best % result.delta << std::endl;
}
else std::cout << "." << std::flush;
const double dc_dbrms = dc_cal.init();;
printf("I = %d Q = %d ", single_test_i, single_test_q);
printf("dc_dbrms = %2.1f dB\n", dc_dbrms);
} else {
dc_cal_t dc_cal(dc_i_prop, dc_q_prop,
rx_stream,
nsamps,
bb_dc_freq,
actual_rx_rate,
verbose,
vm.count("debug_raw_data"));
// Perform normal calibration
results.push_back(calibrate_downhill(dc_cal, tx_lo, verbose));
}
}
}
@@ -265,7 +406,8 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
threads.interrupt_all();
threads.join_all();
store_results(usrp, results, "TX", "tx", "lms_dc", which);
if (not vm.count("single_test"))
store_results(usrp, results, "tx", "dc", vm.count("append"));
return 0;
return EXIT_SUCCESS;
}

View File

@@ -0,0 +1,243 @@
import SoapySDR
from SoapySDR import *
import math
import numpy
import matplotlib.pyplot as plt
from scipy import signal
import random
import time
import os
from optparse import OptionParser
SAMP_RATE = 13e6/4
FREQ_OFFSET = 0.3e6
FREQ_START = 700e6
FREQ_STOP = 1200e6
FREQ_STEP = 7e6
FREQ_VALIDATION_STEP = 2e6
SIDE = "A"
import numpy as np
def find_nearest(array,value):
idx = (np.abs(array-value)).argmin()
return array[idx]
def calcAvgPs(umtrx, rxStream, fftSize = 4096, numFFT = 10, numSkips=2):
samps = numpy.array([0]*fftSize, numpy.complex64)
avgFFT = numpy.array([0]*fftSize, numpy.complex64)
while umtrx.readStream(rxStream, [samps], fftSize, 0, 1000).ret != SOAPY_SDR_TIMEOUT: pass #read until timeout
umtrx.activateStream(rxStream, SOAPY_SDR_END_BURST, 0, fftSize*(numFFT+numSkips))
numActualFFTs = 0
for i in range(numFFT+numSkips):
if umtrx.readStream(rxStream, [samps], fftSize).ret != fftSize:
print 'D'
return calcAvgPs(umtrx, rxStream, fftSize, numFFT, numSkips)
if i < numSkips: continue #skip first for transients
samps *= signal.flattop(fftSize)
avgFFT += numpy.fft.fft(samps)
numActualFFTs += 1
avgFFT /= numActualFFTs
assert(len(avgFFT) == fftSize)
ps = 10*numpy.log10(numpy.abs(avgFFT)) - 20*math.log10(fftSize)
freqs = numpy.fft.fftfreq(fftSize, 1.0/SAMP_RATE)
return ps, freqs
def measureToneFromPs(ps_freqs, toneFreq, BW=SAMP_RATE/25):
ps, freqs = ps_freqs
tonePower = None
for idx in range(len(ps)):
if freqs[idx] > toneFreq-BW/2 and freqs[idx] < toneFreq+BW/2:
if tonePower is None: tonePower = ps[idx]
tonePower = max(ps[idx], tonePower)
return tonePower
def validateWithMeasurements(umtrx, rxStream, toneFreq, numAvgPts=5):
powers = list()
for i in range(numAvgPts):
ps, freqs = calcAvgPs(umtrx, rxStream)
powers.append(measureToneFromPs((ps, freqs), toneFreq))
return 10*numpy.log(numpy.average(numpy.exp(numpy.array(powers)/10))), numpy.std(powers)
def main():
umtrx = SoapySDR.Device(dict(driver='uhd', type='umtrx'))
#frontend map selects side on ch0
umtrx.setFrontendMapping(SOAPY_SDR_RX, SIDE+":0")
umtrx.setFrontendMapping(SOAPY_SDR_TX, SIDE+":0")
#print cal file we will use
serial = umtrx.getHardwareInfo()['tx0_serial']
cal_dest = os.path.join(os.path.expanduser("~"), '.uhd', 'cal', "tx_dc_cal_v0.2_%s.csv"%serial)
print 'going to write calibration data to:', cal_dest
#cal antennas for loopback
umtrx.setAntenna(SOAPY_SDR_RX, 0, "CAL")
umtrx.setAntenna(SOAPY_SDR_TX, 0, "CAL")
#set a low sample rate
umtrx.setSampleRate(SOAPY_SDR_RX, 0, SAMP_RATE)
umtrx.setSampleRate(SOAPY_SDR_TX, 0, SAMP_RATE)
rxStream = umtrx.setupStream(SOAPY_SDR_RX, "CF32")
#calibrate out dc offset at select frequencies
best_correction_per_freq = dict()
best_dc_power_per_freq = dict()
initial_dc_power_per_freq = dict()
stddev_dc_power_per_freq = dict()
average_dc_power_per_freq = dict()
for freq in numpy.arange(FREQ_START, FREQ_STOP, FREQ_STEP):
print 'Doing freq:', freq/1e6, 'MHz'
#tune rx with offset so we can see tx DC
umtrx.setFrequency(SOAPY_SDR_TX, 0, freq)
umtrx.setFrequency(SOAPY_SDR_RX, 0, freq + FREQ_OFFSET)
umtrx.getHardwareTime() #readback so commands are processed
best_correction = 0.0
best_dc_power = None
#grab values before correction
umtrx.setDCOffset(SOAPY_SDR_TX, 0, best_correction)
averagePowers, stddevPowers = validateWithMeasurements(umtrx, rxStream, -FREQ_OFFSET)
initial_dc_power_per_freq[freq] = averagePowers
for bound in (0.1, 0.05, 0.01):
this_correction = best_correction
for searchNo in range(50):
#print 'searchNo',searchNo
corr_i = random.uniform(this_correction.real-bound, this_correction.real+bound)
corr_q = random.uniform(this_correction.imag-bound, this_correction.imag+bound)
correction = complex(min(max(corr_i, -1), 1), min(max(corr_q, -1), 1))
umtrx.setDCOffset(SOAPY_SDR_TX, 0, correction)
ps, freqs = calcAvgPs(umtrx, rxStream)
dc_power = measureToneFromPs((ps, freqs), -FREQ_OFFSET)
if best_dc_power is None or best_dc_power > dc_power:
best_dc_power = dc_power
best_correction = correction
print 'best_dc_power', best_dc_power, ' best_correction', best_correction
#prove that its really the best...
umtrx.setDCOffset(SOAPY_SDR_TX, 0, best_correction)
averagePowers, stddevPowers = validateWithMeasurements(umtrx, rxStream, -FREQ_OFFSET)
print 'averagePowers', averagePowers
print 'stddevPowers', stddevPowers
best_correction_per_freq[freq] = best_correction
best_dc_power_per_freq[freq] = best_dc_power
stddev_dc_power_per_freq[freq] = stddevPowers
average_dc_power_per_freq[freq] = averagePowers
########################################################################
## produce tx cal serial format
########################################################################
cal_data = open(cal_dest, 'w')
cal_data.write("name, TX Frontend Calibration\n")
cal_data.write("serial, %s\n"%serial)
cal_data.write("timestamp, %d\n"%int(time.time()))
cal_data.write("version, 0, 1\n")
cal_data.write("DATA STARTS HERE\n")
cal_data.write("lo_frequency, correction_real, correction_imag, measured, delta\n")
for freq in sorted(best_correction_per_freq.keys()):
cal_data.write(', '.join(map(str, [
freq,
best_correction_per_freq[freq].real,
best_correction_per_freq[freq].imag,
best_dc_power_per_freq[freq],
initial_dc_power_per_freq[freq]-best_dc_power_per_freq[freq],
])) + '\n')
print ('wrote cal data to %s'%cal_dest)
"""
#recollect dc offsets with corrections applied:
validation_average_dc_offsets_per_freq = dict()
validation_stddev_dc_offsets_per_freq = dict()
original_dc_power_per_freq = dict()
for freq in numpy.arange(FREQ_START, FREQ_STOP, FREQ_VALIDATION_STEP):
#tune rx with offset so we can see tx DC
umtrx.setFrequency(SOAPY_SDR_TX, 0, freq)
umtrx.setFrequency(SOAPY_SDR_RX, 0, freq + FREQ_OFFSET)
umtrx.getHardwareTime() #readback so commands are processed
umtrx.setDCOffset(SOAPY_SDR_TX, 0, 0.0)
#get the original value before corrections
averagePowers, stddevPowers = validateWithMeasurements(umtrx, rxStream, -FREQ_OFFSET)
original_dc_power_per_freq[freq] = averagePowers
#pick the correction to use (closest in freq)
correction_freq = find_nearest(best_correction_per_freq.keys(), freq)
correction = best_correction_per_freq[correction_freq]
#perform the measurements again
umtrx.setDCOffset(SOAPY_SDR_TX, 0, correction)
averagePowers, stddevPowers = validateWithMeasurements(umtrx, rxStream, -FREQ_OFFSET)
validation_average_dc_offsets_per_freq[freq] = averagePowers
validation_stddev_dc_offsets_per_freq[freq] = stddevPowers
umtrx.closeStream(rxStream)
plt.figure(1)
plt.subplot(311)
freqs = sorted(average_dc_power_per_freq.keys())
vals = [average_dc_power_per_freq[f] for f in freqs]
cor_data = plt.plot(numpy.array(freqs)/1e6, vals, label='Correction')
freqs = sorted(validation_average_dc_offsets_per_freq.keys())
vals = [validation_average_dc_offsets_per_freq[f] for f in freqs]
val_data = plt.plot(numpy.array(freqs)/1e6, vals, label='Validation')
legend = plt.legend(loc='upper right', shadow=True)
plt.title("Freq (MHz) vs average power (dB)")
plt.grid(True)
plt.subplot(312)
freqs = sorted(stddev_dc_power_per_freq.keys())
vals = [stddev_dc_power_per_freq[f] for f in freqs]
cor_data = plt.plot(numpy.array(freqs)/1e6, vals, label='Correction')
freqs = sorted(validation_stddev_dc_offsets_per_freq.keys())
vals = [validation_stddev_dc_offsets_per_freq[f] for f in freqs]
val_data = plt.plot(numpy.array(freqs)/1e6, vals, label='Validation')
legend = plt.legend(loc='upper right', shadow=True)
plt.title("Freq (MHz) vs stddev power (dB)")
plt.grid(True)
plt.subplot(313)
freqs = sorted(original_dc_power_per_freq.keys())
vals = [abs(original_dc_power_per_freq[f]-validation_average_dc_offsets_per_freq[f]) for f in freqs]
plt.plot(numpy.array(freqs)/1e6, vals, label='Correction')
plt.title("Freq (MHz) vs correction (dB)")
plt.grid(True)
plt.show()
"""
if __name__ == '__main__':
parser = OptionParser()
parser.add_option("--side", dest="side", default=SIDE, help="A or B [default: %default]")
parser.add_option("--freq-start", dest="freq_start", default=FREQ_START, type="float", help="frequency start point in Hz [default: %default]")
parser.add_option("--freq-stop", dest="freq_stop", default=FREQ_STOP, type="float", help="frequency stop point in Hz [default: %default]")
parser.add_option("--freq-step", dest="freq_step", default=FREQ_STEP, type="float", help="frequency step size in Hz [default: %default]")
(options, args) = parser.parse_args()
SIDE = options.side
FREQ_START = options.freq_start
FREQ_STOP = options.freq_stop
FREQ_STEP = options.freq_step
main()

View File

@@ -0,0 +1,187 @@
//
// Copyright 2010,2012 Ettus Research LLC
// Copyright 2015 Fairwaves, Inc
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
//
#include "usrp_cal_utils.hpp"
#include <uhd/utils/safe_main.hpp>
#include <boost/program_options.hpp>
#include <boost/math/special_functions/round.hpp>
#include <iostream>
#include <complex>
#include <ctime>
#include <cstdlib>
namespace po = boost::program_options;
static const size_t num_search_steps = 5;
static const size_t num_search_iters = 7;
/***********************************************************************
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args, which, serial;
int verbose;
int vga1_gain, vga2_gain, rx_gain;
double tx_wave_freq, tx_wave_ampl, rx_offset;
double freq_start, freq_stop, freq_step;
size_t nsamps;
po::options_description desc("Allowed options");
desc.add_options()
("help", "help message")
("verbose", "enable some verbose")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
("which", po::value<std::string>(&which)->default_value("A"), "Which chain A or B?")
("vga1", po::value<int>(&vga1_gain)->default_value(-20), "LMS6002D Tx VGA1 gain [-35 to -4]")
("vga2", po::value<int>(&vga2_gain)->default_value(22), "LMS6002D Tx VGA2 gain [0 to 25]")
("rx_gain", po::value<int>(&rx_gain)->default_value(50), "LMS6002D Rx combined gain [0 to 156]")
("tx_wave_freq", po::value<double>(&tx_wave_freq)->default_value(50e3), "Transmit wave frequency in Hz")
("tx_wave_ampl", po::value<double>(&tx_wave_ampl)->default_value(0.7), "Transmit wave amplitude in counts")
("rx_offset", po::value<double>(&rx_offset)->default_value(300e3), "RX LO offset from the TX LO in Hz")
("freq_start", po::value<double>(&freq_start), "Frequency start in Hz (do not specify for default)")
("freq_stop", po::value<double>(&freq_stop), "Frequency stop in Hz (do not specify for default)")
("freq_step", po::value<double>(&freq_step)->default_value(default_freq_step), "Step size for LO sweep in Hz")
("nsamps", po::value<size_t>(&nsamps)->default_value(default_num_samps), "Samples per data capture")
("append", "Append measurements to the calibratoin file instead of rewriting [default=overwrite]")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
//print the help message
if (vm.count("help")){
std::cout << boost::format("UmTRX Generate TX IQ Balance Calibration Table %s") % desc << std::endl;
std::cout <<
"This application measures leakage between RX and TX using LMS6002D internal RF loopback to self-calibrate.\n"
<< std::endl;
return EXIT_FAILURE;
}
verbose = vm.count("verbose");
// Create a USRP device
uhd::usrp::multi_usrp::sptr usrp = setup_usrp_for_cal(args, which, serial, vga1_gain, vga2_gain, rx_gain, verbose);
//create a receive streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
uhd::rx_streamer::sptr rx_stream = usrp->get_rx_stream(stream_args);
//create a transmitter thread
boost::thread_group threads;
threads.create_thread(boost::bind(&tx_thread, usrp, tx_wave_freq, tx_wave_ampl));
//re-usable buffer for samples
std::vector<samp_type> buff;
//store the results here
std::vector<result_t> results;
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path tx_fe_path = "/mboards/0/tx_frontends/"+which;
uhd::property<std::complex<double> > &iq_prop = tree->access<std::complex<double> >(tx_fe_path / "iq_balance" / "value");
if (not vm.count("freq_start")) freq_start = usrp->get_tx_freq_range().start() + 50e6;
if (not vm.count("freq_stop")) freq_stop = usrp->get_tx_freq_range().stop() - 50e6;
UHD_MSG(status) << boost::format("Calibration frequency type: IQ balance") << std::endl;
UHD_MSG(status) << boost::format("Calibration frequency range: %d MHz -> %d MHz") % (freq_start/1e6) % (freq_stop/1e6) << std::endl;
for (double tx_lo_i = freq_start; tx_lo_i <= freq_stop; tx_lo_i += freq_step){
const double tx_lo = tune_rx_and_tx(usrp, tx_lo_i, rx_offset);
//frequency constants for this tune event
const double actual_rx_rate = usrp->get_rx_rate();
const double actual_tx_freq = usrp->get_tx_freq();
const double actual_rx_freq = usrp->get_rx_freq();
const double bb_tone_freq = actual_tx_freq + tx_wave_freq - actual_rx_freq;
const double bb_imag_freq = actual_tx_freq - tx_wave_freq - actual_rx_freq;
//capture initial uncorrected value
iq_prop.set(0.0);
capture_samples(rx_stream, buff, nsamps);
const double initial_suppression = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate) - compute_tone_dbrms(buff, bb_imag_freq/actual_rx_rate);
//bounds and results from searching
std::complex<double> best_correction;
double phase_corr_start = -.3, phase_corr_stop = .3, phase_corr_step;
double ampl_corr_start = -.3, ampl_corr_stop = .3, ampl_corr_step;
double best_suppression = 0, best_phase_corr = 0, best_ampl_corr = 0;
for (size_t i = 0; i < num_search_iters; i++){
phase_corr_step = (phase_corr_stop - phase_corr_start)/(num_search_steps-1);
ampl_corr_step = (ampl_corr_stop - ampl_corr_start)/(num_search_steps-1);
for (double phase_corr = phase_corr_start; phase_corr <= phase_corr_stop + phase_corr_step/2; phase_corr += phase_corr_step){
for (double ampl_corr = ampl_corr_start; ampl_corr <= ampl_corr_stop + ampl_corr_step/2; ampl_corr += ampl_corr_step){
const std::complex<double> correction(ampl_corr, phase_corr);
iq_prop.set(correction);
//receive some samples
capture_samples(rx_stream, buff, nsamps);
const double tone_dbrms = compute_tone_dbrms(buff, bb_tone_freq/actual_rx_rate);
const double imag_dbrms = compute_tone_dbrms(buff, bb_imag_freq/actual_rx_rate);
const double suppression = tone_dbrms - imag_dbrms;
if (suppression > best_suppression){
best_correction = correction;
best_suppression = suppression;
best_phase_corr = phase_corr;
best_ampl_corr = ampl_corr;
}
}}
if (verbose) std::cout << "best_phase_corr " << best_phase_corr << std::endl;
if (verbose) std::cout << "best_ampl_corr " << best_ampl_corr << std::endl;
if (verbose) std::cout << "best_suppression " << best_suppression << std::endl;
phase_corr_start = best_phase_corr - phase_corr_step;
phase_corr_stop = best_phase_corr + phase_corr_step;
ampl_corr_start = best_ampl_corr - ampl_corr_step;
ampl_corr_stop = best_ampl_corr + ampl_corr_step;
}
if (best_suppression > 30){ //most likely valid, keep result
result_t result;
result.freq = tx_lo;
result.real_corr = best_correction.real();
result.imag_corr = best_correction.imag();
result.best = best_suppression;
result.delta = best_suppression - initial_suppression;
results.push_back(result);
if (verbose){
std::cout << boost::format("TX IQ: %f MHz: best suppression %f dB, corrected %f dB") % (tx_lo/1e6) % result.best % result.delta << std::endl;
}
else std::cout << "." << std::flush;
}
}
std::cout << std::endl;
//stop the transmitter
threads.interrupt_all();
threads.join_all();
store_results(usrp, results, "tx", "iq", vm.count("append"));
return EXIT_SUCCESS;
}

16
host/utils/umtrx_firmware Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
case word in
flash )
umtrx_net_burner --addr=192.168.10.2 --fpga=/usr/share/umtrx/firmware/u2plus_umtrx_v2.bin --fw=/usr/share/umtrx/firmware/umtrx_txrx_uhd.bin --reset
;;
check )
;;
* )
cat <<-EOF
Usage:
$0 flash - burn packaged firmware to umtrx
$0 check - compare versions of packaged firmware and one installed on umtrx
EOF
;;
esac

22
host/utils/umtrx_gps_coord Executable file
View File

@@ -0,0 +1,22 @@
#!/bin/sh
if [ "x$1" = "x-h" -o "x$1" = "x--help" ] ; then
echo "Usage:"
echo " umtrx_gps_coord [umtrx_ip]"
echo
echo " umtrx_ip - (optional) UmTRX IP address [default=192.168.10.2]"
echo
echo "Output:"
echo " hh:mm:ss.SSS UTC <lat>N <lon>W <altitude> m"
exit 1
fi
if [ $# -eq 0 ] ; then
UMTRX_ADDR="192.168.10.2"
else
UMTRX_ADDR=$1
fi
echo . | nc -u $UMTRX_ADDR 49171 | \
awk -F, '/\$GPGGA/ {print substr($2,0,3) ":" substr($2,3,2) ":" substr($2,5,2) "." substr($2,8,3) " UTC", (substr($3,0,2) + (substr($3,3) / 60.0)) $4, (substr($5,0,3) + (substr($5,4) / 60.0)) $6, $10 " m"; fflush();}'

View File

@@ -137,25 +137,14 @@ def is_valid_fw_image(fw_image):
########################################################################
# interface discovery and device enumeration
########################################################################
def command(*args):
p = subprocess.Popen(
args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
ret = p.wait()
verbose = p.stdout.read().decode()
if ret != 0: raise Exception(verbose)
return verbose
def get_interfaces():
if(platform.system() is "Windows"): return win_get_interfaces()
else: return unix_get_interfaces()
def unix_get_interfaces():
ifconfig = command("/sbin/ifconfig")
ip_addr_re = "cast\D*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
bcasts = re.findall(ip_addr_re, ifconfig)
ipint = subprocess.check_output(["/sbin/ip", "-4", "a", "s", "up"])
ip_addr_re = "brd\D*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})"
bcasts = re.findall(ip_addr_re, ipint)
return bcasts
def win_get_interfaces():

17
host/utils/umtrx_nmea Executable file
View File

@@ -0,0 +1,17 @@
#!/bin/sh
if [ "x$1" = "x-h" -o "x$1" = "x--help" ] ; then
echo "Usage:"
echo " umtrx_nmea [umtrx_ip]"
echo
echo " umtrx_ip - (optional) UmTRX IP address [default=192.168.10.2]"
exit 1
fi
if [ $# -eq 0 ] ; then
UMTRX_ADDR="192.168.10.2"
else
UMTRX_ADDR=$1
fi
echo . | nc -u $UMTRX_ADDR 49171

View File

@@ -0,0 +1,124 @@
//
// Copyright 2014 Fairwaves 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 3 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, see <http://www.gnu.org/licenses/>.
//
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/types/sensors.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/random.hpp>
#include <iostream>
#include <complex>
#include <cmath>
#include <ctime>
namespace po = boost::program_options;
/***********************************************************************
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[]){
std::string args;
unsigned pa_dcdc_r = 0;
int divsw1 = -1;
int divsw2 = -1;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "help message")
("verbose", "enable some verbose")
("debug_raw_data", "save raw captured signals to files")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
("dcdc_cal,C", "Calibrate DC/DC")
("paen1", "Enable PA1")
("paen2", "Enable PA2")
("padis1", "Disable PA1")
("padis2", "Disable PA2")
("divsw1", po::value<int>(&divsw1), "1 - Enable / 0 - Disable DivSW1")
("divsw2", po::value<int>(&divsw2), "1 - Enable / 0 - Disable DivSW2")
("palow", "Turn off internal DC/DC")
("pa_dcdc_r", po::value<unsigned>(&pa_dcdc_r),"Turn on internal DC/DC")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
//print the help message
if (vm.count("help")){
std::cout << desc << std::endl;
return ~0;
}
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path mb_path = "/mboards/0";
if (vm.count("paen1")) {
tree->access<bool>(mb_path / "pa_en1").set(true);
}
if (vm.count("paen2")) {
tree->access<bool>(mb_path / "pa_en2").set(true);
}
if (vm.count("palow")) {
tree->access<bool>(mb_path / "pa_nlow").set(false);
}
if (vm.count("padis1")) {
tree->access<bool>(mb_path / "pa_en1").set(false);
}
if (vm.count("padis2")) {
tree->access<bool>(mb_path / "pa_en2").set(false);
}
if (vm.count("pa_dcdc_r")) {
tree->access<bool>(mb_path / "pa_nlow").set(true);
tree->access<uint8_t>(mb_path / "pa_dcdc_r").set(pa_dcdc_r);
}
if (vm.count("dcdc_cal")) {
tree->access<bool>(mb_path / "pa_nlow").set(true);
unsigned i;
for (i = 0; i < 256; i++) {
tree->access<uint8_t>(mb_path / "pa_dcdc_r").set(i);
if (i == 0) {
boost::this_thread::sleep(boost::posix_time::seconds(1));
}
boost::this_thread::sleep(boost::posix_time::milliseconds(100)); // Wait for value to settle
std::cout << "[" << std::setw(3) << i << "]="
<< tree->access<uhd::sensor_value_t>(mb_path / "sensors" / "voltageDCOUT").get().to_pp_string().c_str()
<< std::endl;
}
}
if (vm.count("divsw1")) {
tree->access<bool>(mb_path / "dboards" / "A" / "rx_frontends" / "0" / "diversiy").set(divsw1 ? 1 : 0);
}
if (vm.count("divsw2")) {
tree->access<bool>(mb_path / "dboards" / "B" / "rx_frontends" / "0" / "diversiy").set(divsw1 ? 1 : 0);
}
return 0;
}

View File

@@ -0,0 +1,112 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##########################
### Property tree API
##########################
import socket
import json
class umtrx_property_tree:
def connect(self, host="localhost", port=12345):
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.connect((host, port))
self.f = self.s.makefile()
def close(self):
self.s.close()
#
# Helper methods
#
def _send_request(self, action, path, value_type=None, value=None):
d = dict(action=action, path=path)
if value_type is not None: d['type'] = value_type
if value is not None: d['value'] = value
return self.s.send(json.dumps(d)+'\n')
def _recv_response(self):
resp = self.f.readline().strip()
if len(resp)>0:
return json.loads(resp)
else:
return None
#
# Getters (raw)
#
def query_bool_raw(self, path):
self._send_request('GET', path, value_type='BOOL')
return self._recv_response()
def query_int_raw(self, path):
self._send_request('GET', path, value_type='INT')
return self._recv_response()
def query_double_raw(self, path):
self._send_request('GET', path, value_type='DOUBLE')
return self._recv_response()
def query_sensor_raw(self, path):
self._send_request('GET', path, value_type='SENSOR')
return self._recv_response()
def query_range_raw(self, path):
self._send_request('GET', path, value_type='RANGE')
return self._recv_response()
#
# Getters (value)
#
def query_bool_value(self, path):
res = self.query_bool_raw(path)
return res['result']['value']
def query_int_value(self, path):
res = self.query_int_raw(path)
return res['result']['value']
def query_double_value(self, path):
res = self.query_double_raw(path)
return res['result']['value']
def query_sensor_value(self, path):
res = self.query_sensor_raw(path)
return res['result']['value']
def query_range_value(self, path):
res = self.query_range_raw(path)
return res['result']
#
# Setters
#
def set_bool(self, path, val):
self._send_request('SET', path, value_type='BOOL', value=val)
return self._recv_response()
def set_int(self, path, val):
self._send_request('SET', path, value_type='INT', value=val)
return self._recv_response()
def set_double(self, path, val):
self._send_request('SET', path, value_type='DOUBLE', value=val)
return self._recv_response()
#
# Check path presence and list paths
#
def has_path_raw(self, path):
self._send_request('HAS', path)
return self._recv_response()
def list_path_raw(self, path):
self._send_request('LIST', path)
return self._recv_response()

View File

@@ -0,0 +1,49 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##########################
### Query sensors
##########################
from umtrx_property_tree import umtrx_property_tree
from umtrx_vswr import umtrx_vswr
s = umtrx_property_tree()
s.connect()
sensors_path="/mboards/0/sensors"
res = s.list_path_raw(sensors_path)
sensors_list = res.get('result', [])
print "Sensors:"
for sensor in sensors_list:
reply = s.query_sensor_raw(sensors_path+"/"+sensor)
if reply.has_key('result'):
res = reply['result']
print " %15s = %9s %s" % (res['name'], res['value'], res['unit'])
else:
print "Can't read sensor %s" % sensor
#vswr_calibration = TM10_VSWR_cal
#vswr_calibration = TM3_VSWR_cal
vswr_calibration = 0
for num in [1, 2]:
vpr_name = 'voltagePR'+str(num)
vpf_name = 'voltagePF'+str(num)
if vpr_name in sensors_list and vpf_name in sensors_list:
vpr = float(s.query_sensor_value(sensors_path+'/'+vpr_name))
vpf = float(s.query_sensor_value(sensors_path+'/'+vpf_name))
vswr = umtrx_vswr(vpf, vpr, vswr_calibration)
print "TRX %d power detector:" % num
print " VPF = %5.2f V" % vpf
print " PF = %5.1f dBm" % vswr.pf()
print " VPR = %5.2f V" % vpr
print " PR = %5.1f dBm" % vswr.pr()
print " VSWR = %6.2f" % vswr.vswr()
print " Gamma = %5.3f" % vswr.gamma()
print " Return Loss = %5.1f dB" % vswr.return_loss()
print " Mismatch Loss = %5.3f dB" % vswr.mismatch_loss()
print " Through power = %5.2f %%" % (100.0*vswr.pf_rate())
print " Reflected power = %5.2f %%" % (100.0*vswr.pr_rate())
s.close()

View File

@@ -176,47 +176,55 @@ int UHD_SAFE_MAIN(int argc, char *argv[]){
uhd::i2c_iface::sptr i2c = usrp->get_device()->get_tree()->access<uhd::i2c_iface::sptr>("/mboards/0/i2c_iface").get();
//set the tx sample rate
std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl;
usrp->set_tx_rate(tx_rate);
std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl << std::endl;
if (usrp->get_tx_num_channels() > 0)
{
std::cout << boost::format("Setting TX Rate: %f Msps...") % (tx_rate/1e6) << std::endl;
usrp->set_tx_rate(tx_rate);
std::cout << boost::format("Actual TX Rate: %f Msps...") % (usrp->get_tx_rate()/1e6) << std::endl << std::endl;
}
//set the rx sample rate
std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl;
usrp->set_rx_rate(rx_rate);
std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;
if (usrp->get_rx_num_channels() > 0)
{
std::cout << boost::format("Setting RX Rate: %f Msps...") % (rx_rate/1e6) << std::endl;
usrp->set_rx_rate(rx_rate);
std::cout << boost::format("Actual RX Rate: %f Msps...") % (usrp->get_rx_rate()/1e6) << std::endl << std::endl;
}
std::cout << boost::format("Setting device timestamp to 0...") << std::endl;
usrp->set_time_now(uhd::time_spec_t(0.0));
//test tx chains
for (size_t i = 0; i < 2; i++)
//*
for (size_t i = 0; i < usrp->get_tx_num_channels(); i++)
{
std::cout << "TX test with DSP " << i << std::endl;
std::cout << "===> TX test with DSP " << i << std::endl;
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(i);
test_tx_chain(usrp, stream_args, ampl, begin_delta, num_samps);
}
if (usrp->get_tx_num_channels() >= 2)
{
std::cout << "TX test dual DSP " << std::endl;
std::cout << "===> TX test all DSP " << std::endl;
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(0);
stream_args.channels.push_back(1);
for (size_t i = 0; i < usrp->get_tx_num_channels(); i++) stream_args.channels.push_back(i);
test_tx_chain(usrp, stream_args, ampl, begin_delta, num_samps);
}
//*/
//test rx chains
for (size_t i = 0; i < 2; i++)
for (size_t i = 0; i < usrp->get_rx_num_channels(); i++)
{
std::cout << "RX test with DSP " << i << std::endl;
std::cout << "===> RX test with DSP " << i << std::endl;
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(i);
test_rx_chain(usrp, stream_args, begin_delta, num_samps);
}
if (usrp->get_rx_num_channels() >= 2)
{
std::cout << "RX test dual DSP " << std::endl;
std::cout << "===> RX test all DSP " << std::endl;
uhd::stream_args_t stream_args("fc32");
stream_args.channels.push_back(0);
stream_args.channels.push_back(1);
for (size_t i = 0; i < usrp->get_rx_num_channels(); i++) stream_args.channels.push_back(i);
test_rx_chain(usrp, stream_args, begin_delta, num_samps);
}

View File

@@ -0,0 +1,134 @@
//
// Copyright 2015 Fairwaves 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 3 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, see <http://www.gnu.org/licenses/>.
//
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/safe_main.hpp>
#include <uhd/utils/paths.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/types/sensors.hpp>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
#include <boost/thread/thread.hpp>
#include <boost/math/special_functions/round.hpp>
#include <boost/random.hpp>
#include <iostream>
#include <complex>
#include <cmath>
#include <ctime>
namespace po = boost::program_options;
static size_t failCount = 0;
#define CHECK(expr, expected) { \
const double actual = expr; \
const bool ok = (actual == expected); \
if (not ok) failCount++; \
std::cout << "Check: " << #expr << " == " << #expected << "\t\t\t" << ((ok)?"OK":"FAIL") << std::endl; \
if (not ok) std::cout << "\t FAIL: actual = " << actual << std::endl; }
/***********************************************************************
* Main
**********************************************************************/
int UHD_SAFE_MAIN(int argc, char *argv[])
{
std::string args;
po::options_description desc("Allowed options");
desc.add_options()
("help,h", "help message")
("args", po::value<std::string>(&args)->default_value(""), "device address args [default = \"\"]")
;
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
//print the help message
if (vm.count("help")){
std::cout << desc << std::endl;
return ~0;
}
//create a usrp device
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path mb_path = "/mboards/0";
//get the spi-interface to check gain values
uhd::spi_iface::sptr spiface = tree->access<uhd::spi_iface::sptr>(mb_path / "spi_iface").get();
for (size_t ch = 0; ch <= 1; ch++)
{
std::cout << std::endl << "==== Testing channel: " << ch << std::endl;
std::cout << std::endl << "Check RX gain ranges:" << std::endl;
CHECK(usrp->get_rx_gain_range("VGA1", ch).start(), 0);
CHECK(usrp->get_rx_gain_range("VGA1", ch).stop(), 126);
CHECK(usrp->get_rx_gain_range("VGA2", ch).start(), 0);
CHECK(usrp->get_rx_gain_range("VGA2", ch).stop(), 30);
CHECK(usrp->get_rx_gain_range(ch).start(), 0);
CHECK(usrp->get_rx_gain_range(ch).stop(), 156);
std::cout << std::endl << "Check TX gain ranges:" << std::endl;
CHECK(usrp->get_tx_gain_range("VGA1", ch).start(), -35);
CHECK(usrp->get_tx_gain_range("VGA1", ch).stop(), -4);
CHECK(usrp->get_tx_gain_range("VGA2", ch).start(), 0);
CHECK(usrp->get_tx_gain_range("VGA2", ch).stop(), 25);
CHECK(usrp->get_tx_gain_range(ch).start(), -35);
CHECK(usrp->get_tx_gain_range(ch).stop(), 21);
std::cout << std::endl << "Test RX gain distribution:" << std::endl;
usrp->set_rx_gain(0, ch);
CHECK(usrp->get_rx_gain(ch), 0);
CHECK(usrp->get_rx_gain("VGA1", ch), 0);
CHECK(usrp->get_rx_gain("VGA2", ch), 0);
usrp->set_rx_gain(15, ch);
CHECK(usrp->get_rx_gain(ch), 15);
CHECK(usrp->get_rx_gain("VGA1", ch), 15);
CHECK(usrp->get_rx_gain("VGA2", ch), 0);
usrp->set_rx_gain(129, ch);
CHECK(usrp->get_rx_gain(ch), 129);
CHECK(usrp->get_rx_gain("VGA1", ch), 126);
CHECK(usrp->get_rx_gain("VGA2", ch), 3);
std::cout << std::endl << "Test TX gain distribution:" << std::endl;
usrp->set_tx_gain(-35, ch);
CHECK(usrp->get_tx_gain(ch), -35);
CHECK(usrp->get_tx_gain("VGA2", ch), 0);
CHECK(usrp->get_tx_gain("VGA1", ch), -35);
usrp->set_tx_gain(-10, ch);
CHECK(usrp->get_tx_gain(ch), -10);
CHECK(usrp->get_tx_gain("VGA2", ch), 0);
CHECK(usrp->get_tx_gain("VGA1", ch), -10);
usrp->set_tx_gain(10, ch);
CHECK(usrp->get_tx_gain(ch), 10);
CHECK(usrp->get_tx_gain("VGA2", ch), 14);
CHECK(usrp->get_tx_gain("VGA1", ch), -4);
}
//print status
std::cout << std::endl;
const bool fail = failCount > 0;
if (fail) std::cerr << std::endl << failCount << " TESTS FAILED!!!" << std::endl;
else std::cout << std::endl << "ALL TESTS PASSED" << std::endl;
std::cout << "Done!" << std::endl;
return fail?EXIT_FAILURE:EXIT_SUCCESS;
}

68
host/utils/umtrx_vswr.py Normal file
View File

@@ -0,0 +1,68 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
##########################
### VSWR calculations
##########################
# Implemented as described at:
# http://www.markimicrowave.com/assets/data/return%20loss%20to%20vswr.pdf
import math
# TODO: requires better calibration
TM10_VSWR_cal=0.3/2
class umtrx_vswr:
def __init__(self, VPF, VPR, calibration=0, coef=0.05):
self.vpf = VPF
self.vpr = VPR
self.calibration = calibration
self.coef = coef
self._gamma = self._calc_gamma()
def _calc_gamma(self):
''' Internal function: calculate Gamma '''
return math.pow(10, -self.return_loss()/20.0)
def pf(self):
''' Estimated through power, dBm '''
return (self.vpf-self.calibration)/self.coef
def pr(self):
''' Estimated reflected power, dBm '''
return (self.vpr-self.calibration)/self.coef
def return_loss(self):
''' Estimated return loss, dB '''
return self.pf()-self.pr()
def gamma(self):
''' Estimated Gamma '''
return self._gamma
def vswr(self):
''' Estimated VSWR '''
gamma = self._gamma
if gamma == 1.0:
return float("inf")
else:
return (1+gamma)/(1-gamma)
def mismatch_loss(self):
''' Estimated mismatch loss, dB '''
gamma = self._gamma
if gamma == 1.0:
return float("-inf")
else:
return -10.0 * math.log(1.0-gamma*gamma, 10)
def pf_rate(self):
''' Estimated reflected power rate, % '''
gamma = self._gamma
return 1.0 - gamma*gamma
def pr_rate(self):
''' Estimated reflected power rate, % '''
gamma = self._gamma
return gamma*gamma

View File

@@ -16,10 +16,16 @@
//
#include <uhd/utils/paths.hpp>
#include <uhd/utils/thread_priority.hpp>
#include <uhd/utils/algorithm.hpp>
#include <uhd/utils/msg.hpp>
#include <uhd/property_tree.hpp>
#include <uhd/usrp/multi_usrp.hpp>
#include <uhd/usrp/dboard_eeprom.hpp>
#include <boost/filesystem.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/thread/thread.hpp>
#include <boost/math/special_functions/round.hpp>
#include <iostream>
#include <vector>
#include <complex>
@@ -37,67 +43,9 @@ typedef std::complex<float> samp_type;
**********************************************************************/
static const double tau = 6.28318531;
static const size_t wave_table_len = 8192;
static const size_t num_search_steps = 5;
static const size_t num_search_iters = 7;
static const double default_freq_step = 1e6;
static const size_t default_num_samps = 10000;
/***********************************************************************
* Set standard defaults for devices
**********************************************************************/
static inline void set_optimum_defaults(uhd::usrp::multi_usrp::sptr usrp){
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path mb_path = "/mboards/0";
const std::string mb_name = tree->access<std::string>(mb_path / "name").get();
if (mb_name.find("USRP2") != std::string::npos or mb_name.find("N200") != std::string::npos or mb_name.find("N210") != std::string::npos){
usrp->set_tx_rate(12.5e6);
usrp->set_rx_rate(12.5e6);
}
else if (mb_name.find("UMTRX") != std::string::npos){
usrp->set_tx_rate(13e6/2);
usrp->set_tx_bandwidth(5e6);
usrp->set_rx_rate(13e6/2);
usrp->set_rx_bandwidth(5e6);
}
else if (mb_name.find("B100") != std::string::npos){
usrp->set_tx_rate(4e6);
usrp->set_rx_rate(4e6);
}
else if (mb_name.find("E100") != std::string::npos or mb_name.find("E110") != std::string::npos){
usrp->set_tx_rate(4e6);
usrp->set_rx_rate(8e6);
}
else{
throw std::runtime_error("self-calibration is not supported for this hardware");
}
const uhd::fs_path tx_fe_path = "/mboards/0/dboards/A/tx_frontends/0";
const std::string tx_name = tree->access<std::string>(tx_fe_path / "name").get();
if (tx_name.find("WBX") != std::string::npos or tx_name.find("SBX") != std::string::npos){
usrp->set_tx_gain(0);
}
else if (tx_name.find("LMS6002D") != std::string::npos){
usrp->set_tx_gain(10);
}
else{
throw std::runtime_error("self-calibration is not supported for this hardware");
}
const uhd::fs_path rx_fe_path = "/mboards/0/dboards/A/tx_frontends/0";
const std::string rx_name = tree->access<std::string>(rx_fe_path / "name").get();
if (rx_name.find("WBX") != std::string::npos or rx_name.find("SBX") != std::string::npos){
usrp->set_rx_gain(25);
}
else if (rx_name.find("LMS6002D") != std::string::npos){
usrp->set_rx_gain(10);
}
else{
throw std::runtime_error("self-calibration is not supported for this hardware");
}
}
/***********************************************************************
* Sinusoid wave table
**********************************************************************/
@@ -146,50 +94,91 @@ static inline void write_samples_to_file(
outfile.close();
}
/***********************************************************************
* Retrieve d'board serial
**********************************************************************/
static std::string get_serial(
uhd::usrp::multi_usrp::sptr usrp,
const std::string &tx_rx
){
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
// Will work on 1st subdev, top-level must make sure it's the right one
uhd::usrp::subdev_spec_t subdev_spec = usrp->get_rx_subdev_spec();
const uhd::fs_path db_path = "/mboards/0/dboards/" + subdev_spec[0].db_name + "/" + tx_rx + "_eeprom";
const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get();
return db_eeprom.serial;
}
/***********************************************************************
* Convert integer calibration values to floats
**********************************************************************/
static double dc_offset_int2double(uint8_t corr)
{
return (corr-128)/128.0;
}
/***********************************************************************
* Store data to file
**********************************************************************/
static void store_results(
uhd::usrp::multi_usrp::sptr usrp,
const std::vector<result_t> &results,
const std::string &XX,
const std::string &xx,
const std::string &what,
const std::string &which
const std::string &rx_tx, // "tx" or "rx"
const std::string &what, // Type of test, e.g. "iq"
bool append
){
//extract eeprom serial
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path db_path = "/mboards/0/dboards/"+which+"/" + xx + "_eeprom";
const uhd::usrp::dboard_eeprom_t db_eeprom = tree->access<uhd::usrp::dboard_eeprom_t>(db_path).get();
if (db_eeprom.serial.empty()) throw std::runtime_error(XX + " dboard has empty serial!");
std::ofstream cal_data;
bool write_header=true;
std::string rx_tx_upper = boost::to_upper_copy(rx_tx);
std::string serial = get_serial(usrp, rx_tx);
//make the calibration file path
fs::path cal_data_path = fs::path(uhd::get_app_path()) / ".uhd";
fs::create_directory(cal_data_path);
cal_data_path = cal_data_path / "cal";
fs::create_directory(cal_data_path);
cal_data_path = cal_data_path / str(boost::format("%s_%s_cal_v0.1_%s.csv") % xx % what % db_eeprom.serial);
cal_data_path = cal_data_path / str(boost::format("%s_%s_cal_v0.2_%s.csv") % rx_tx % what % serial);
if (fs::exists(cal_data_path)){
fs::rename(cal_data_path, cal_data_path.string() + str(boost::format(".%d") % time(NULL)));
if (append)
write_header = false;
else
fs::rename(cal_data_path, cal_data_path.string() + str(boost::format(".%d") % time(NULL)));
}
//fill the calibration file
std::ofstream cal_data(cal_data_path.string().c_str());
cal_data << boost::format("name, %s Frontend Calibration\n") % XX;
cal_data << boost::format("serial, %s\n") % db_eeprom.serial;
cal_data << boost::format("timestamp, %d\n") % time(NULL);
cal_data << boost::format("version, 0, 1\n");
cal_data << boost::format("DATA STARTS HERE\n");
cal_data << "lo_frequency, correction_real, correction_imag, measured, delta\n";
cal_data.open(cal_data_path.string().c_str(), std::ofstream::out | std::ofstream::app);
if (write_header)
{
//fill the calibration file
cal_data << boost::format("name, %s Frontend Calibration\n") % rx_tx_upper;
cal_data << boost::format("serial, %s\n") % serial;
cal_data << boost::format("timestamp, %d\n") % time(NULL);
cal_data << boost::format("version, 0, 1\n");
cal_data << boost::format("DATA STARTS HERE\n");
// For DC calibration we also store LMS6002D integer values
if (what == "dc")
cal_data << "lo_frequency, correction_real, correction_imag, measured, delta, int_i, int_q\n";
else
cal_data << "lo_frequency, correction_real, correction_imag, measured, delta\n";
}
for (size_t i = 0; i < results.size(); i++){
cal_data
<< results[i].freq << ", "
<< results[i].real_corr << ", "
<< results[i].imag_corr << ", "
<< results[i].best << ", "
<< results[i].delta << "\n"
;
// Write to file
cal_data << results[i].freq;
if (what == "dc") {
cal_data << ", " << dc_offset_int2double(results[i].real_corr);
cal_data << ", " << dc_offset_int2double(results[i].imag_corr);
} else {
cal_data << ", " << results[i].real_corr;
cal_data << ", " << results[i].imag_corr;
}
cal_data << ", " << results[i].best;
cal_data << ", " << results[i].delta;
if (what == "dc") {
cal_data << ", " << results[i].real_corr;
cal_data << ", " << results[i].imag_corr;
}
cal_data << "\n";
}
std::cout << "wrote cal data to " << cal_data_path << std::endl;
@@ -234,3 +223,105 @@ static void capture_samples(
throw std::runtime_error("did not get all the samples requested");
}
}
/***********************************************************************
* Transmit thread
**********************************************************************/
static void tx_thread(uhd::usrp::multi_usrp::sptr usrp, const double tx_wave_freq, const double tx_wave_ampl){
uhd::set_thread_priority_safe();
//create a transmit streamer
uhd::stream_args_t stream_args("fc32"); //complex floats
uhd::tx_streamer::sptr tx_stream = usrp->get_tx_stream(stream_args);
//setup variables and allocate buffer
uhd::tx_metadata_t md;
md.has_time_spec = false;
std::vector<samp_type> buff(tx_stream->get_max_num_samps()*10);
//values for the wave table lookup
size_t index = 0;
const double tx_rate = usrp->get_tx_rate();
const size_t step = boost::math::iround(wave_table_len * tx_wave_freq/tx_rate);
wave_table table(tx_wave_ampl);
//fill buff and send until interrupted
while (not boost::this_thread::interruption_requested()){
for (size_t i = 0; i < buff.size(); i++){
buff[i] = table(index += step);
}
tx_stream->send(&buff.front(), buff.size(), md);
}
//send a mini EOB packet
md.end_of_burst = true;
tx_stream->send("", 0, md);
}
/***********************************************************************
* Tune RX and TX routine
**********************************************************************/
static double tune_rx_and_tx(uhd::usrp::multi_usrp::sptr usrp, const double tx_lo_freq, const double rx_offset){
//tune the transmitter with no cordic
uhd::tune_request_t tx_tune_req(tx_lo_freq);
tx_tune_req.dsp_freq_policy = uhd::tune_request_t::POLICY_MANUAL;
tx_tune_req.dsp_freq = 0;
usrp->set_tx_freq(tx_tune_req);
//tune the receiver
usrp->set_rx_freq(uhd::tune_request_t(usrp->get_tx_freq(), rx_offset));
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
return usrp->get_tx_freq();
}
/***********************************************************************
* Setup function
**********************************************************************/
static uhd::usrp::multi_usrp::sptr setup_usrp_for_cal(const std::string &args, const std::string &which, std::string &serial,
int vga1_gain, int vga2_gain, int rx_gain, int verbose)
{
std::cout << std::endl;
std::cout << boost::format("Creating the usrp device with: %s...") % args << std::endl;
uhd::usrp::multi_usrp::sptr usrp = uhd::usrp::multi_usrp::make(args);
// Do we have an UmTRX here?
uhd::property_tree::sptr tree = usrp->get_device()->get_tree();
const uhd::fs_path mb_path = "/mboards/0";
const std::string mb_name = tree->access<std::string>(mb_path / "name").get();
if (mb_name.find("UMTRX") == std::string::npos){
throw std::runtime_error("This utility supports only UmTRX hardware.");
}
//set subdev spec
usrp->set_rx_subdev_spec(which+":0");
usrp->set_tx_subdev_spec(which+":0");
UHD_MSG(status) << "Running calibration for " << usrp->get_tx_subdev_name(0) << std::endl;
serial = get_serial(usrp, "tx");
UHD_MSG(status) << "Daughterboard serial: " << serial << std::endl;
//set the antennas to cal
if (not uhd::has(usrp->get_rx_antennas(), "CAL") or not uhd::has(usrp->get_tx_antennas(), "CAL")){
throw std::runtime_error("This board does not have the CAL antenna option, cannot self-calibrate.");
}
usrp->set_rx_antenna("CAL");
usrp->set_tx_antenna("CAL");
//set optimum defaults
// GSM symbol rate * 4
usrp->set_tx_rate(13e6/12);
usrp->set_rx_rate(13e6/12);
// 500kHz LPF
usrp->set_tx_bandwidth(1e6);
usrp->set_rx_bandwidth(1e6);
// Our recommended VGA1/VGA2
usrp->set_tx_gain(vga1_gain, "VGA1");
usrp->set_tx_gain(vga2_gain, "VGA2");
usrp->set_rx_gain(rx_gain);
if (verbose) printf("actual Tx VGA1 gain = %.0f dB\n", usrp->get_tx_gain("VGA1"));
if (verbose) printf("actual Tx VGA2 gain = %.0f dB\n", usrp->get_tx_gain("VGA2"));
if (verbose) printf("actual Rx gain = %.0f dB\n", usrp->get_rx_gain());
return usrp;
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -25,6 +25,14 @@ SET(CMAKE_SYSTEM_NAME Generic)
CMAKE_FORCE_C_COMPILER(zpu-elf-gcc GNU)
PROJECT(USRP_NXXX_FW C)
########################################################################
# extract the git hash
########################################################################
include(${PROJECT_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake)
get_git_head_revision(GITREFSPEC GITHASH)
string(SUBSTRING "${GITHASH}" 0 8 GITHASH)
add_definitions(-DGITHASH=0x${GITHASH})
########################################################################
# lwIP header include dirs
########################################################################

View File

@@ -323,6 +323,7 @@ main(void)
//init readback for firmware minor version number
fw_regs[U2_FW_REG_VER_MINOR] = USRP2_FW_VER_MINOR;
fw_regs[U2_FW_REG_GIT_HASH] = GITHASH;
#ifdef BOOTLOADER
//load the production FPGA image or firmware if appropriate
@@ -333,6 +334,9 @@ main(void)
#endif
#ifdef UMTRX
//cause net reset...
wb_poke32(_SR_ADDR(7), 1);
wb_poke32(_SR_ADDR(7), 0);
umtrx_init();
#endif

View File

@@ -0,0 +1,130 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
# check if this is a submodule
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
#message(STATUS "Arguments to execute_process: ${ARGN}")
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()

View File

@@ -0,0 +1,38 @@
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
set(HEAD_HASH "${HEAD_REF}")
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()

View File

@@ -18,6 +18,7 @@
#include "i2c.h"
#include "mdelay.h"
#include "usrp2/fw_common.h"
#include "nonstdio.h"
static const int EEPROM_PAGESIZE = 16;
@@ -26,7 +27,11 @@ bool find_safe_booted_flag(void) {
return 0;
#else
unsigned char flag_byte;
eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1);
if (!eeprom_read(USRP2_I2C_ADDR_MBOARD, USRP2_EE_MBOARD_BOOTLOADER_FLAGS, &flag_byte, 1)) {
puts("Failed to read safe boot flag");
return false;
}
return (flag_byte == 0x5E);
#endif
}

View File

@@ -58,8 +58,8 @@ static char uart_mode[4] = {
};
static char uart_speeds[4] = {
[UART_DEBUG] = US_230400,
[UART_EXP] = US_230400,
[UART_DEBUG] = US_115200,
[UART_EXP] = US_115200,
[UART_GPS] = US_9600
};

View File

@@ -36,6 +36,8 @@ static uint16_t prescaler_values[MAX_WB_DIV+1] = {
PRESCALER(4), // 4: 25 MHz
};
#define WATCHDOG 50000
void
i2c_init(void)
{
@@ -58,8 +60,13 @@ i2c_init(void)
static inline void
wait_for_xfer(void)
{
while (i2c_regs->cmd_status & I2C_ST_TIP) // wait for xfer to complete
;
unsigned i = WATCHDOG;
while ((i != 0) && (i2c_regs->cmd_status & I2C_ST_TIP)) // wait for xfer to complete
--i;
if (i == 0) {
puts("wait_for_xfer WATCHDOG failed!");
}
}
static inline bool
@@ -79,8 +86,13 @@ i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len)
if (len == 0) // reading zero bytes always works
return true;
while (i2c_regs->cmd_status & I2C_ST_BUSY)
;
unsigned i = WATCHDOG;
while ((i != 0) && (i2c_regs->cmd_status & I2C_ST_BUSY))
--i;
if (i == 0) {
puts("i2c_read WATCHDOG failed!");
return false;
}
i2c_regs->data = (i2c_addr << 1) | 1; // 7 bit address and read bit (1)
// generate START and write addr
@@ -104,8 +116,13 @@ i2c_read (unsigned char i2c_addr, unsigned char *buf, unsigned int len)
bool
i2c_write(unsigned char i2c_addr, const unsigned char *buf, unsigned int len)
{
while (i2c_regs->cmd_status & I2C_ST_BUSY)
;
unsigned i = WATCHDOG;
while ((i != 0) && (i2c_regs->cmd_status & I2C_ST_BUSY))
--i;
if (i == 0) {
puts("i2c_write WATCHDOG failed!");
return false;
}
i2c_regs->data = (i2c_addr << 1) | 0; // 7 bit address and write bit (0)

View File

@@ -241,20 +241,20 @@ typedef struct {
////////////////////////////////////////////////////
#define localparam static const int
localparam SR_MISC = 0; // 7 regs
localparam SR_MISC = 0; // 8 regs
localparam SR_TIME64 = 10; // 6
localparam SR_BUF_POOL = 16; // 4
localparam SR_RX_FRONT0 = 20; // 5
localparam SR_RX_FRONT1 = 25; // 5
localparam SR_RX_CTRL0 = 32; // 9
localparam SR_RX_DSP0 = 48; // 7
localparam SR_RX_CTRL1 = 80; // 9
localparam SR_RX_DSP1 = 96; // 7
localparam SR_RX_CTRL2 = 66; // 9
localparam SR_RX_DSP2 = 76; // 7
localparam SR_RX_CTRL3 = 83; // 9
localparam SR_RX_DSP3 = 93; // 7
localparam SR_RX_CTRL0 = 30; // 9
localparam SR_RX_DSP0 = 40; // 7
localparam SR_RX_CTRL1 = 50; // 9
localparam SR_RX_DSP1 = 60; // 7
localparam SR_RX_CTRL2 = 70; // 9
localparam SR_RX_DSP2 = 80; // 7
localparam SR_RX_CTRL3 = 90; // 9
localparam SR_RX_DSP3 = 100; // 7
localparam SR_TX_FRONT0 = 110; // ?
localparam SR_TX_CTRL0 = 126; // 6
@@ -264,6 +264,8 @@ localparam SR_TX_CTRL1 = 161; // 6
localparam SR_TX_DSP1 = 170; // 5
localparam SR_DIVSW = 180; // 2
localparam SR_RX_FE_SW = 183; // 1
localparam SR_TX_FE_SW = 184; // 1
localparam SR_SPI_CORE = 185; // 3
#define _SR_ADDR(sr) (SETTING_REGS_BASE + (sr) * sizeof(uint32_t))

View File

@@ -51,5 +51,5 @@ uint32_t spi_transact(bool readback, int slave, uint32_t data, int length, uint3
if (!readback) return 0;
spi_wait();
return readback_mux->spi;
return readback_mux->spi & ((1 << length)-1);
}

View File

@@ -37,11 +37,11 @@ umtrx_init(void)
uint32_t res;
//issue a reset to the LMS chips
output_regs->lms_res == (LMS1_RESET | LMS2_RESET); // reset pins of lms chips switched to 1
output_regs->lms_res = (LMS1_RESET | LMS2_RESET); // reset pins of lms chips switched to 1
mdelay(100);
output_regs->lms_res = 0; // reset pins of lms chips switched to 0
mdelay(100);
output_regs->lms_res == (LMS1_RESET | LMS2_RESET); // reset pins of lms chips switched to 1
output_regs->lms_res = (LMS1_RESET | LMS2_RESET); // reset pins of lms chips switched to 1
// Check LMS presense
res = spi_transact(SPI_TXRX, SPI_SS_LMS1, LMS_RD_CMD(0x04), 16, SPI_PUSH_FALL|SPI_LATCH_RISE);

View File

@@ -59,18 +59,20 @@ void start_program(void)
void do_the_bootload_thing(void) {
#ifdef NO_FLASH
puts("Starting USRP2+ without flash.");
puts("Starting UmTRX without flash.");
return;
#else
spif_init(); //initialize SPI flash clock
bool production_image = find_safe_booted_flag();
puts("SPI Flash has been initialized");
bool production_image = find_safe_booted_flag();
printf("Production image = %d\n", production_image);
set_safe_booted_flag(0); //haven't booted yet
if(BUTTON_PUSHED) { //see memory_map.h
puts("Starting USRP2+ in safe mode. Loading safe firmware.");
return;
puts("Starting UmTRX in safe mode. Loading safe firmware.");
return;
}
if(!production_image) {
@@ -86,7 +88,7 @@ void do_the_bootload_thing(void) {
#endif
}
puts("No valid production FPGA image found.\n");
// return;
return;
}
if(is_valid_fw_image(PROD_FW_IMAGE_LOCATION_ADDR)) {
puts("Valid production firmware found. Loading...");
@@ -105,22 +107,5 @@ void do_the_bootload_thing(void) {
return;
}
puts("No valid production firmware found. Falling through to built-in firmware.");
/*
if(is_valid_fw_image(SAFE_FW_IMAGE_LOCATION_ADDR)) {
spi_flash_read(SAFE_FW_IMAGE_LOCATION_ADDR, FW_IMAGE_SIZE_BYTES, (void *)RAM_BASE);
puts("Finished loading. Starting image.");
mdelay(300);
start_program();
puts("ERROR: return from main program! This should never happen!");
mdelay(300);
#ifdef SPARTAN6
icap_s6_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR, SAFE_FPGA_IMAGE_LOCATION_ADDR);
#else
icap_s3_reload_fpga(SAFE_FPGA_IMAGE_LOCATION_ADDR);
#endif
return;
}
puts("ERROR: no safe firmware image available. Falling through to built-in firmware.");
*/
#endif
}

View File

@@ -24,6 +24,9 @@
#include "spi_flash.h"
#include "memory_map.h"
#define WATCHDOG 50000
#include <nonstdio.h>
void
spif_init(void)
{
@@ -39,8 +42,11 @@ spif_init(void)
inline void
spif_wait(void)
{
while (spif_regs->ctrl & SPI_CTRL_GO_BSY)
;
unsigned i = WATCHDOG;
while ((i != 0) && (spif_regs->ctrl & SPI_CTRL_GO_BSY))
--i;
if (i == 0)
puts("spif_wait WATCHDOG failed!");
}
uint32_t