diff options
author | Martin Braun <martin.braun@ettus.com> | 2020-01-23 16:10:22 -0800 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2020-01-28 09:35:36 -0800 |
commit | bafa9d95453387814ef25e6b6256ba8db2df612f (patch) | |
tree | 39ba24b5b67072d354775272e687796bb511848d /fpga/usrp3/top/x300/capture_ddrlvds.v | |
parent | 3075b981503002df3115d5f1d0b97d2619ba30f2 (diff) | |
download | uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.gz uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.tar.bz2 uhd-bafa9d95453387814ef25e6b6256ba8db2df612f.zip |
Merge FPGA repository back into UHD repository
The FPGA codebase was removed from the UHD repository in 2014 to reduce
the size of the repository. However, over the last half-decade, the
split between the repositories has proven more burdensome than it has
been helpful. By merging the FPGA code back, it will be possible to
create atomic commits that touch both FPGA and UHD codebases. Continuous
integration testing is also simplified by merging the repositories,
because it was previously difficult to automatically derive the correct
UHD branch when testing a feature branch on the FPGA repository.
This commit also updates the license files and paths therein.
We are therefore merging the repositories again. Future development for
FPGA code will happen in the same repository as the UHD host code and
MPM code.
== Original Codebase and Rebasing ==
The original FPGA repository will be hosted for the foreseeable future
at its original local location: https://github.com/EttusResearch/fpga/
It can be used for bisecting, reference, and a more detailed history.
The final commit from said repository to be merged here is
05003794e2da61cabf64dd278c45685a7abad7ec. This commit is tagged as
v4.0.0.0-pre-uhd-merge.
If you have changes in the FPGA repository that you want to rebase onto
the UHD repository, simply run the following commands:
- Create a directory to store patches (this should be an empty
directory):
mkdir ~/patches
- Now make sure that your FPGA codebase is based on the same state as
the code that was merged:
cd src/fpga # Or wherever your FPGA code is stored
git rebase v4.0.0.0-pre-uhd-merge
Note: The rebase command may look slightly different depending on what
exactly you're trying to rebase.
- Create a patch set for your changes versus v4.0.0.0-pre-uhd-merge:
git format-patch v4.0.0.0-pre-uhd-merge -o ~/patches
Note: Make sure that only patches are stored in your output directory.
It should otherwise be empty. Make sure that you picked the correct
range of commits, and only commits you wanted to rebase were exported
as patch files.
- Go to the UHD repository and apply the patches:
cd src/uhd # Or wherever your UHD repository is stored
git am --directory fpga ~/patches/*
rm -rf ~/patches # This is for cleanup
== Contributors ==
The following people have contributed mainly to these files (this list
is not complete):
Co-authored-by: Alex Williams <alex.williams@ni.com>
Co-authored-by: Andrej Rode <andrej.rode@ettus.com>
Co-authored-by: Ashish Chaudhari <ashish@ettus.com>
Co-authored-by: Ben Hilburn <ben.hilburn@ettus.com>
Co-authored-by: Ciro Nishiguchi <ciro.nishiguchi@ni.com>
Co-authored-by: Daniel Jepson <daniel.jepson@ni.com>
Co-authored-by: Derek Kozel <derek.kozel@ettus.com>
Co-authored-by: EJ Kreinar <ej@he360.com>
Co-authored-by: Humberto Jimenez <humberto.jimenez@ni.com>
Co-authored-by: Ian Buckley <ian.buckley@gmail.com>
Co-authored-by: Jörg Hofrichter <joerg.hofrichter@ni.com>
Co-authored-by: Jon Kiser <jon.kiser@ni.com>
Co-authored-by: Josh Blum <josh@joshknows.com>
Co-authored-by: Jonathon Pendlum <jonathan.pendlum@ettus.com>
Co-authored-by: Martin Braun <martin.braun@ettus.com>
Co-authored-by: Matt Ettus <matt@ettus.com>
Co-authored-by: Michael West <michael.west@ettus.com>
Co-authored-by: Moritz Fischer <moritz.fischer@ettus.com>
Co-authored-by: Nick Foster <nick@ettus.com>
Co-authored-by: Nicolas Cuervo <nicolas.cuervo@ettus.com>
Co-authored-by: Paul Butler <paul.butler@ni.com>
Co-authored-by: Paul David <paul.david@ettus.com>
Co-authored-by: Ryan Marlow <ryan.marlow@ettus.com>
Co-authored-by: Sugandha Gupta <sugandha.gupta@ettus.com>
Co-authored-by: Sylvain Munaut <tnt@246tNt.com>
Co-authored-by: Trung Tran <trung.tran@ettus.com>
Co-authored-by: Vidush Vishwanath <vidush.vishwanath@ettus.com>
Co-authored-by: Wade Fife <wade.fife@ettus.com>
Diffstat (limited to 'fpga/usrp3/top/x300/capture_ddrlvds.v')
-rw-r--r-- | fpga/usrp3/top/x300/capture_ddrlvds.v | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/fpga/usrp3/top/x300/capture_ddrlvds.v b/fpga/usrp3/top/x300/capture_ddrlvds.v new file mode 100644 index 000000000..f5bd5a4a0 --- /dev/null +++ b/fpga/usrp3/top/x300/capture_ddrlvds.v @@ -0,0 +1,200 @@ +// +// Copyright 2011-2014 Ettus Research LLC +// Copyright 2017 Ettus Research, a National Instruments Company +// +// SPDX-License-Identifier: LGPL-3.0-or-later +// + +// The two clocks are aligned externally in order to eliminate the need for a FIFO. +// A FIFO cannot be used to transition between clock domains because it can cause +// alignment issues between the output of multiple modules. + +module capture_ddrlvds #( + parameter WIDTH = 14, //Width of the SS data bus + parameter PATT_CHECKER = "FALSE", //{TRUE, FALSE}: Is the integrated ramp pattern checker + parameter DATA_IDELAY_MODE = "BYPASSED", //{BYPASSED, FIXED, DYNAMIC} + parameter DATA_IDELAY_VAL = 16, //IDELAY value for FIXED mode. In DYNAMIC mode, this value is used by the timing analyzer + parameter DATA_IDELAY_FREF = 200.0 //Reference clock frequency for the IDELAYCTRL +) ( + // ADC IO Pins + input adc_clk_p, + input adc_clk_n, + input [WIDTH-1:0] adc_data_p, + input [WIDTH-1:0] adc_data_n, + + //System synchronous clock + input radio_clk, + + //IDELAY settings + input data_delay_stb, + input [4:0] data_delay_val, + + //Capture clock and output data + output adc_cap_clk, + output [(2*WIDTH)-1:0] data_out, + + //Pattern checker options (sync to radio_clk) + input checker_en, + output [3:0] checker_locked, + output [3:0] checker_failed +); + + //------------------------------------------------------------------- + // Clock Path + + wire adc_buf_clk; + + // Route source synchronous clock to differential input clock buffer + // then to a global clock buffer. We route to a global buffer because + // the data bus being capture spans multiple banks. + IBUFGDS ss_clk_ibufgds_i ( + .I(adc_clk_p), .IB(adc_clk_n), + .O(adc_buf_clk) + ); + + BUFG ss_clk_bufg_i ( + .I(adc_buf_clk), + .O(adc_cap_clk) + ); + + //------------------------------------------------------------------- + // Data Path + + wire [WIDTH-1:0] adc_data_buf, adc_data_del; + wire [(2*WIDTH)-1:0] adc_data_aclk; + reg [(2*WIDTH)-1:0] adc_data_rclk, adc_data_rclk_sync; + + genvar i; + generate for(i = 0; i < WIDTH; i = i + 1) begin : gen_lvds_pins + + // Use a differential IO buffer to get the data into the IOB + IBUFDS ibufds_i ( + .I(adc_data_p[i]), .IB(adc_data_n[i]), + .O(adc_data_buf[i]) + ); + + // Use an optional IDELAY to tune the capture interface from + // software. This is a clock to data delay calibration so all + // data bits are delayed by the same amount. + if (DATA_IDELAY_MODE != "BYPASSED") begin + // Pipeline IDELAY control signals to ease routing + reg data_delay_stb_reg; + reg [4:0] data_delay_val_reg; + always @(posedge radio_clk) + {data_delay_stb_reg, data_delay_val_reg} <= {data_delay_stb, data_delay_val}; + + IDELAYE2 #( + .DELAY_SRC("IDATAIN"), // Delay input (IDATAIN, DATAIN) + .IDELAY_TYPE(DATA_IDELAY_MODE=="FIXED"?"FIXED":"VAR_LOAD"), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE + .SIGNAL_PATTERN("DATA"), // DATA, CLOCK input signal + .HIGH_PERFORMANCE_MODE("TRUE"), // Reduced jitter ("TRUE"), Reduced power ("FALSE") + .PIPE_SEL("FALSE"), // Select pipelined mode, FALSE, TRUE + .CINVCTRL_SEL("FALSE"), // Enable dynamic clock inversion (FALSE, TRUE) + .IDELAY_VALUE(DATA_IDELAY_VAL), // Input delay tap setting (0-31) + .REFCLK_FREQUENCY(DATA_IDELAY_FREF) // IDELAYCTRL clock input frequency in MHz (190.0-210.0). + ) idelay_i ( + .DATAIN(1'b0), // Internal delay data input + .IDATAIN(adc_data_buf[i]), // Data input from the I/O + .DATAOUT(adc_data_del[i]), // Delayed data output + .C(radio_clk), // Clock input + .LD(data_delay_stb_reg), // Load IDELAY_VALUE input + .CE(1'b0), // Active high enable increment/decrement input + .INC(1'b0), // Increment / Decrement tap delay input + .CINVCTRL(1'b0), // Dynamic clock inversion input + .CNTVALUEIN(data_delay_val_reg), // Counter value input + .CNTVALUEOUT(), // Counter value output + .LDPIPEEN(1'b0), // Enable PIPELINE register to load data input + .REGRST(1'b0) // Reset for the pipeline register.Only used in VAR_LOAD_PIPE mode. + ); + end else begin + assign adc_data_del[i] = adc_data_buf[i]; + end + + // Use the global ADC clock to capture delayed data into an IDDR. + // Each IQ sample is transferred in QDR mode i.e. odd and even on + // a rising and falling edge of the clock + IDDR #( + .DDR_CLK_EDGE("SAME_EDGE_PIPELINED") + ) iddr_i ( + .C(adc_cap_clk), .CE(1'b1), + .D(adc_data_del[i]), .R(1'b0), .S(1'b0), + .Q1(adc_data_aclk[2*i]), .Q2(adc_data_aclk[(2*i)+1]) + ); + end endgenerate + + // Transfer data from the source-synchronous ADC clock domian to the + // system synchronous radio clock domain. We assume that adc_cap_clk + // and radio_clk are generated from the same source and have the same + // frequency however, they have an unknown but constant phase offset. + // In order to cross domains, we use a simple synchronizer to avoid any + // sample-sample delay uncertainty introduced by FIFOs. + // NOTE: The path between adc_data_aclk and adc_data_rclk must be + // constrained to prevent build to build variations. Also, the + // phase of the two clocks must be aligned ensure that the data + // capture is safe + always @(posedge radio_clk) + {adc_data_rclk_sync, adc_data_rclk} <= {adc_data_rclk, adc_data_aclk}; + + // The synchronized output is the output of this module + assign data_out = adc_data_rclk_sync; + + //------------------------------------------------------------------- + // Checkers + + generate if (PATT_CHECKER == "TRUE") begin + wire checker_en_aclk; + wire [1:0] checker_locked_aclk, checker_failed_aclk; + + synchronizer #(.INITIAL_VAL(1'b0)) checker_en_aclk_sync_i ( + .clk(adc_cap_clk), .rst(1'b0), .in(checker_en), .out(checker_en_aclk)); + synchronizer #(.INITIAL_VAL(1'b0)) checker_locked_aclk_0_sync_i ( + .clk(radio_clk), .rst(1'b0), .in(checker_locked_aclk[0]), .out(checker_locked[0])); + synchronizer #(.INITIAL_VAL(1'b0)) checker_locked_aclk_1_sync_i ( + .clk(radio_clk), .rst(1'b0), .in(checker_locked_aclk[1]), .out(checker_locked[1])); + synchronizer #(.INITIAL_VAL(1'b0)) checker_failed_aclk_0_sync_i ( + .clk(radio_clk), .rst(1'b0), .in(checker_failed_aclk[0]), .out(checker_failed[0])); + synchronizer #(.INITIAL_VAL(1'b0)) checker_failed_aclk_1_sync_i ( + .clk(radio_clk), .rst(1'b0), .in(checker_failed_aclk[1]), .out(checker_failed[1])); + + cap_pattern_verifier #( // Q Channel : Synchronous to SSCLK + .WIDTH(WIDTH), .PATTERN("RAMP"), .HOLD_CYCLES(1), + .RAMP_START(0), .RAMP_STOP({WIDTH{1'b1}}), .RAMP_INCR(1) + ) aclk_q_checker_i ( + .clk(adc_cap_clk), .rst(~checker_en_aclk), + .valid(1'b1), .data(~adc_data_aclk[WIDTH-1:0]), + .count(), .errors(), + .locked(checker_locked_aclk[0]), .failed(checker_failed_aclk[0]) + ); + + cap_pattern_verifier #( // I Channel : Synchronous to SSCLK + .WIDTH(WIDTH), .PATTERN("RAMP"), .HOLD_CYCLES(1), + .RAMP_START(0), .RAMP_STOP({WIDTH{1'b1}}), .RAMP_INCR(1) + ) aclk_i_checker_i ( + .clk(adc_cap_clk), .rst(~checker_en_aclk), + .valid(1'b1), .data(~adc_data_aclk[(2*WIDTH)-1:WIDTH]), + .count(), .errors(), + .locked(checker_locked_aclk[1]), .failed(checker_failed_aclk[1]) + ); + + cap_pattern_verifier #( // Q Channel : Synchronous to Radio CLK + .WIDTH(WIDTH), .PATTERN("RAMP"), .HOLD_CYCLES(1), + .RAMP_START(0), .RAMP_STOP({WIDTH{1'b1}}), .RAMP_INCR(1) + ) rclk_q_checker_i ( + .clk(radio_clk), .rst(~checker_en), + .valid(1'b1), .data(~adc_data_rclk_sync[WIDTH-1:0]), + .count(), .errors(), + .locked(checker_locked[2]), .failed(checker_failed[2]) + ); + + cap_pattern_verifier #( // I Channel : Synchronous to Radio CLK + .WIDTH(WIDTH), .PATTERN("RAMP"), .HOLD_CYCLES(1), + .RAMP_START(0), .RAMP_STOP({WIDTH{1'b1}}), .RAMP_INCR(1) + ) rclk_i_checker_i ( + .clk(radio_clk), .rst(~checker_en), + .valid(1'b1), .data(~adc_data_rclk_sync[(2*WIDTH)-1:WIDTH]), + .count(), .errors(), + .locked(checker_locked[3]), .failed(checker_failed[3]) + ); + end endgenerate + +endmodule // capture_ddrlvds |