Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Trouble getting started with a Spartan-6

Status
Not open for further replies.
I've spent some time looking through the example code and I think I more or less understand how its supposed to work, but I'm still clearly missing something. My code does not simulate as expected. I have the following main module:

module main(

// input clocks for PLL
input wire clkADC_p,
input wire clkADC_n,
input wire clkWall,

// input LVDS bit rate clock
input wire clkin_p,
input wire clkin_n,

//input LVDS frame clock
input wire clkFrame_p,
input wire clkFrame_n,

//input LVDS data
input wire [1:0] datain_p,
input wire [1:0] datain_n,

//LVDS reset
input reset,

//output clock control for PLL
output wire vxcoCtrl,
//output wire div_clk,

//ouput deserialized data
output wire [15:0] dataout,

// Indicator that program was successful
output wire LEDIndicator);

// Begin main program

// ADC clock
wire clkADC;
wire div_clk;
// Divided down ADC clock by divisor
reg [25:0] divisor = 1382400;
parameter integer S = 8 ; // Set the serdes factor to 8
parameter integer C = 0 + 1; // Set the number of channels (increment by one for drive)
parameter integer D = 2*C ; // Set the number LVDS inputs = 2 * number of channels
parameter integer DS = (D*S)-1; // Used for bus widths = serdes factor * number of inputs - 1

wire [DS:0] rxd ; // Data from serdeses
wire [S-1:0] rxf ; // Recieved Data from Frame Clock
reg state ;
reg bslip ;
reg [3:0] count ;

assign rst = reset ; // active high reset pin

// turn on LED indicator to show successful programming
assign LEDIndicator = 1'b1;

// Configure differential PECL clock input
IBUFDS #(
.CAPACITANCE("DONT_CARE"),
.DIFF_TERM("FALSE"),
.IBUF_DELAY_VALUE("0"),
.IFD_DELAY_VALUE("AUTO"),
.IOSTANDARD("LVPECL_33"))
IBUFDS_inst1 (
.O(clkADC),
.I(clkADC_p),
.IB(clkADC_n));

// Perform clock divider
clk_divider clk_divider_inst (
.clk(clkADC),
.divisor(divisor),
.div_clk(div_clk));

// do PLL clock phase comparison
assign vxcoCtrl = div_clk ^ clkWall;


//Clock Input. Generate ioclocks via BUFIO2
serdes_1_to_n_clk_ddr_s8_diff #(
.S (S), // Set the serdes factor to 8
.DIFF_TERM ("TRUE")) // Enable or disable diff termination
inst_clkin (
.clkin_p (clkin_p),
.clkin_n (clkin_n),
.rxioclkp (rxioclkp),
.rxioclkn (rxioclkn),
.rx_serdesstrobe (rx_serdesstrobe),
.rx_bufg_x1 (rx_bufg_x1));

// Data Inputs
serdes_1_to_n_data_ddr_s8_diff #(
.S (S),
.D (D),
.DIFF_TERM ("TRUE")) // Enable or disable diff termination
inst_datain (
.use_phase_detector (1'b1), // '1' enables the phase detector logic
.datain_p (datain_p),
.datain_n (datain_n),
.rxioclkp (rxioclkp),
.rxioclkn (rxioclkn),
.rxserdesstrobe (rx_serdesstrobe),
.gclk (rx_bufg_x1),
.bitslip (bslip),
.reset (rst),
.data_out (rxd),
.debug_in (2'b00),
.debug ());

// Frame clock to use in logic of bitslip
// Data Inputs
serdes_1_to_n_data_ddr_s8_diff #(
.S (S),
.D (1),
.DIFF_TERM ("TRUE")) // Enable or disable diff termination
inst_frameclk (
.use_phase_detector (1'b1), // '1' enables the phase detector logic
.datain_p (clkFrame_p),
.datain_n (clkFrame_n),
.rxioclkp (rxioclkp),
.rxioclkn (rxioclkn),
.rxserdesstrobe (rx_serdesstrobe),
.gclk (rx_bufg_x1),
.bitslip (bslip),
.reset (rst),
.data_out (rxf),
.debug_in (2'b00),
.debug ());


always @ (posedge rx_bufg_x1 or posedge rst) // example bitslip logic, if required
begin
if (reset == 1'b1) begin
state <= 0 ;
bslip <= 1'b0 ;
count <= 4'b0000 ;
end
else begin
if (state == 0) begin
if (rxf[S-1:0] != 8'b00000000 & rxf[S-1:0] != 8'b11111111) begin
bslip <= 1'b1 ; // bitslip needed
state <= 1 ;
count <= 4'b0000 ;
end
end
else if (state == 1) begin
bslip <= 1'b0 ; // bitslip low
count <= count + 4'b0001 ;
if (count == 4'b1111) begin
state <= 0;
end
end
end
end

//output deserialized data
assign dataout = rxd;


endmodule

With the following test module:

module main_tb ();

// Inputs
reg clkADC_p; //ADC clock
reg clkADC_n;
reg clkWall; //60 Hz clock
reg clkin_p; //LVDS bit clock from ADC
reg clkin_n;
reg clkFrame_p; //LVDS frame clock from ADC
reg clkFrame_n;
reg [1:0] datain_p; //LVDS datain
reg [1:0] datain_n;
reg reset; //reset signal for LVDS deserialization block

// Outputs
wire vxcoCtrl; //Output control signal for the clock PLL
wire [15:0] dataout; //Deserialized data out
//wire div_clk;
wire LEDIndicator; //successful programming

// Instantiate the Unit Under Test (UUT)
main uut (
.clkADC_p(clkADC_p),
.clkADC_n(clkADC_n),
.clkWall(clkWall),
.clkin_p(clkin_p),
.clkin_n(clkin_n),
.clkFrame_p(clkFrame_p),
.clkFrame_n(clkFrame_n),
.datain_p(datain_p),
.datain_n(datain_n),
.reset(reset),
.vxcoCtrl(vxcoCtrl),
.dataout(dataout),
//.div_clk(div_clk),
.LEDIndicator(LEDIndicator)
);

initial begin
// Initialize Inputs
clkADC_p = 1;
clkADC_n = 0;
clkWall = 1;
clkin_p = 1;
clkin_n = 0;
clkFrame_p = 1;
clkFrame_n = 0;
datain_n = 2'b11;
datain_p = 2'b00;
reset = 0;
end

//define ADC clock
always begin
#10 clkADC_p = ~clkADC_p;
clkADC_n = ~clkADC_n;
end

//define wall clock
always begin
#100 clkWall = ~clkWall;
end

//define LVDS bit rate clock
always begin
#1 clkin_p = ~clkin_p;
clkin_n = ~clkin_n;
end

//definte LVDS frame clock
always begin
#16 clkFrame_p = ~clkFrame_p;
clkFrame_n = ~clkFrame_n;
end

//define LVDS frame slip to test bitslip
always begin
#100 clkFrame_p = ~clkFrame_p;
clkFrame_n = ~clkFrame_n;
end

//define the LVDS datain test bit stream
always begin
#1 datain_p[0] = ~datain_p[0];
datain_n[0] = ~datain_n[0];
#1 datain_p[0] = ~datain_p[0];
datain_n[0] = ~datain_n[0];
datain_p[1] = ~datain_p[1];
datain_n[1] = ~datain_n[1];
end

always begin
#1000 $finish;
end

endmodule

The two modules serdes_1_to_n_data_ddr_s8_diff and serdes_1_to_n_clk_ddr_s8_diff are from the XAPP1064.

It compiles and simulates. My first question is what causes the delay in the startup of rxioclkp? It doesn't start for about 100 ps in simulation. Is this inherent to the IODELAY2 block?

My main question is why there is no data out. It seems as if rx_serdesstrobe and rx_bufg_x1 go low and stay low always and so does bslip. I've done some poking around but nothing jumps out at me but I'm sure I'm misunderstanding the functional blocks somehow (or how verilog works which is equally likely). This project would be a lot more tractable if there were someone in-house at my company that I could ask questions.

Thanks again for all of your help.
 

I can't remember the exact figure (100ns?), but you should always wait some period of time for the global reset (GSR) before certain things will start working properly. In particular, simulated PLL/DCMs also don't start working immediately when an input signal is applied - you should monitor their 'locked' outputs. Anyway, you would expect an IODELAY2 block to have an inherent delay.. by definition ;) I always wait until GSR has finished before de-asserting any 'reset' registers.

Anyway, I'm not sure why rx_bufg_x1 isn't toggling, but nothing will work if it's not. Have a poke around in the serdes_1_to_n_clk_ddr_s8_diff signals in ISim to make sure that everything in the signal path is receiving the correct signals. It's easy to make a typo that causes only one end of a differential clock to toggle, or whatever.

So make sure that rx_bufio2_x1 (which drives rx_bufg_x1) is toggling, and that rxioclkp is toggling (within the clk_ddr_s8_diff module, not in your top level test bench), and that ddly_m/ddly_s are toggling, and that iob_data_in_p/iob_data_in_n are toggling, and rx_clk_in_p/rx_clk_in_n are toggling, and that clkin_p/clkin_n are toggling. Fortunately there is a pretty straightforward chain of events.
 

Here is my current code for the module serdes_1_to_n_clk_ddr_s8_diff. I do not think I changed anything from the provided version in the XAPP.

timescale 1ps/1ps

module serdes_1_to_n_clk_ddr_s8_diff (clkin_p, clkin_n, rxioclkp, rxioclkn, rx_serdesstrobe, rx_bufg_x1) ;

parameter integer S = 8 ; // Parameter to set the serdes factor 1..8
parameter DIFF_TERM = "False" ; // Parameter to enable internal differential termination

input clkin_p ; // Input from LVDS receiver pin
input clkin_n ; // Input from LVDS receiver pin
output rxioclkp ; // IO Clock network
output rxioclkn ; // IO Clock network
output rx_serdesstrobe ; // Parallel data capture strobe
output rx_bufg_x1 ; // Global clock output

wire ddly_m; // Master output from IODELAY1
wire ddly_s; // Slave output from IODELAY1
wire rx_clk_in ; //
wire iob_data_in_p ; //
wire iob_data_in_n ; //

parameter RX_SWAP_CLK = 1'b0 ; // pinswap mask for input clock (0 = no swap (default), 1 = swap). Allows input to be connected the wrong way round to ease PCB routing.

IBUFDS_DIFF_OUT #(
.DIFF_TERM (DIFF_TERM))
iob_clk_in (
.I (clkin_p),
.IB (clkin_n),
.OB (rx_clk_in_n),
.O (rx_clk_in_p)) ;

assign iob_data_in_p = rx_clk_in_p ^ RX_SWAP_CLK ; // Invert clock as required
assign iob_data_in_n = rx_clk_in_n ^ RX_SWAP_CLK ; // Invert clock as required

// IODELAY for the differential inputs.
//

IODELAY2 #(
.DATA_RATE ("SDR"), // <SDR>, DDR
.SIM_TAPDELAY_VALUE (49), // nominal tap delay (sim parameter only)
.IDELAY_VALUE (0), // {0 ... 255}
.IDELAY2_VALUE (0), // {0 ... 255}
.ODELAY_VALUE (0), // {0 ... 255}
.IDELAY_MODE ("NORMAL"), // "NORMAL", "PCI"
.SERDES_MODE ("MASTER"), // <NONE>, MASTER, SLAVE
.IDELAY_TYPE ("FIXED"), // "DEFAULT", "DIFF_PHASE_DETECTOR", "FIXED", "VARIABLE_FROM_HALF_MAX", "VARIABLE_FROM_ZERO"
.COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), // <STAY_AT_LIMIT>, WRAPAROUND
.DELAY_SRC ("IDATAIN")) // "IO", "IDATAIN", "ODATAIN"
iodelay_m (
.IDATAIN (iob_data_in_p), // data from master IOB
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_m), // Output data 1 to ILOGIC/ISERDES2
.DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2
.IOCLK0 (1'b0), // High speed clock for calibration
.IOCLK1 (1'b0), // High speed clock for calibration
.CLK (1'b0), // Fabric clock (GCLK) for control signals
.CAL (1'b0), // Calibrate enable signal
.INC (1'b0), // Increment counter
.CE (1'b0), // Clock Enable
.RST (1'b0), // Reset delay line to 1/2 max in this case
.BUSY ()) ; // output signal indicating sync circuit has finished / calibration has finished

IODELAY2 #(
.DATA_RATE ("SDR"), // <SDR>, DDR
.SIM_TAPDELAY_VALUE (49), // nominal tap delay (sim parameter only)
.IDELAY_VALUE (0), // {0 ... 255}
.IDELAY2_VALUE (0), // {0 ... 255}
.ODELAY_VALUE (0), // {0 ... 255}
.IDELAY_MODE ("NORMAL"), // "NORMAL", "PCI"
.SERDES_MODE ("SLAVE"), // <NONE>, MASTER, SLAVE
.IDELAY_TYPE ("FIXED"), // "DEFAULT", "DIFF_PHASE_DETECTOR", "FIXED", "VARIABLE_FROM_HALF_MAX", "VARIABLE_FROM_ZERO"
.COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), // <STAY_AT_LIMIT>, WRAPAROUND
.DELAY_SRC ("IDATAIN")) // "IO", "IDATAIN", "ODATAIN"
iodelay_s (
.IDATAIN (iob_data_in_n), // data from slave IOB
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_s), // Output data 1 to ILOGIC/ISERDES2
.DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2
.IOCLK0 (1'b0), // High speed clock for calibration
.IOCLK1 (1'b0), // High speed clock for calibration
.CLK (1'b0), // Fabric clock (GCLK) for control signals
.CAL (1'b0), // Calibrate control signal, never needed as the slave supplies the clock input to the PLL
.INC (1'b0), // Increment counter
.CE (1'b0), // Clock Enable
.RST (1'b0), // Reset delay line
.BUSY ()) ; // output signal indicating sync circuit has finished / calibration has finished

BUFG bufg_pll_x1 (.I(rx_bufio2_x1), .O(rx_bufg_x1) ) ;

BUFIO2_2CLK #(
.DIVIDE (S)) // The DIVCLK divider divide-by value; default 1
bufio2_2clk_inst (
.I (ddly_m), // Input source clock 0 degrees
.IB (ddly_s), // Input source clock 0 degrees
.IOCLK (rxioclkp), // Output Clock for IO
.DIVCLK (rx_bufio2_x1), // Output Divided Clock
.SERDESSTROBE (rx_serdesstrobe)) ; // Output SERDES strobe (Clock Enable)

BUFIO2 #(
.I_INVERT ("FALSE"), //
.DIVIDE_BYPASS ("FALSE"), //
.USE_DOUBLER ("FALSE")) //
bufio2_inst (
.I (ddly_s), // N_clk input from IDELAY
.IOCLK (rxioclkn), // Output Clock
.DIVCLK (), // Output Divided Clock
.SERDESSTROBE ()) ; // Output SERDES strobe (Clock Enable)

endmodule


In this module, clkin_p and clkin_n are toggling and out of phase. Same goes for rx_clk_in_p/n and iob_data_in_p/n. ddly_m/s are also toggling and out of phase (should they be out of phase?). Same goes for rxioclkp/n. The place everything seems to break down is rx_bufio2_x1. That is stuck at 0 and as a result so is rx_bufg_x1 and rx_serdesstrobe. Also, in this code rx_clk_in doesn't seem to be tied to anything. Should it be? I've looked at this for awhile and nothing is jumping out at me. Any help would be appreciated.

A more basic question. When calling other modules, what govers whether the variables you are passing it needs to be declared ahead of time? For example, in my main module, I make the call

//Clock Input. Generate ioclocks via BUFIO2
serdes_1_to_n_clk_ddr_s8_diff #(
.S (S), // Set the serdes factor
.DIFF_TERM ("TRUE")) // Enable or disable diff termination
inst_clkin (
.clkin_p (clkin_p),
.clkin_n (clkin_n),
.rxioclkp (rxioclkp),
.rxioclkn (rxioclkn),
.rx_serdesstrobe (rx_serdesstrobe),
.rx_bufg_x1 (rx_bufg_x1));

However, I have no declared the wires rxioclkp etc in my code yet. Why is this allowed? Is the declaration implicit for outputs or something? I'm probably thinking about this the wrong way since I'm an object oriented programmer by training.
 

Ok changing it from a 1ps update to a 1ns update made it work. I guess the simulator was telling me the FPGA can't operate at a THz which is reasonable. My bits don't seem to make any sense but at least I'm getting something out.

Does my bitslip logic seem correct?

---------- Post added at 17:48 ---------- Previous post was at 16:29 ----------

Sorry to inundate the thread with questions but things keep coming up. Now it seems as if the bitslip logic is "working." However I'm getting the inverted bits of what I'd expect. Is dataout going to be a 1 when datain_p is 1 or datain_n is 1?
 

Ah, I was going to say that the 1ps/1ps would cause problems.

The bitslip looks okay, but I'd have to see it in simulation. You should see the bits rotating until it settles on all zeros or ones, and then you won't get any more blip assertions.

Not sure about the inverted bits. It should give dataout=1 when datain_p is 1. I would try setting the _p signals to 1 and _n to 0, not varying them through time, and then tracing them through the data path.
 

I was on vacation for the last week and a half and just started working on this again. Before leaving I managed to show in simulation that all of the bitslipping was working and all was good. However, when going through the implement design stage I got an unrouteable design. Thinking maybe it had to do with the combination of different functions I was using I implemented a simpler module that only performed a 2 channel LVDS deserializtion. Same problem. I don't understand the error exactly and was wondering if someone could shed some light on this or point me in a debugging direction. Here is my code:

This is the top level:

module top_nto1_ddr_diff_rx (
input reset, // reset (active high)
input [1:0] datain_p, datain_n, // lvds data inputs
input clkin_p, clkin_n, // lvds clock input
output [15:0] dataout) ; // dummy outputs

// Parameters for serdes factor and number of IO pins

parameter integer S = 8 ; // Set the serdes factor to 8
parameter integer D = 2 ; // Set the number of inputs and outputs
parameter integer DS = (D*S)-1 ; // Used for bus widths = serdes factor * number of inputs - 1

wire rst ;
wire [DS:0] rxd ; // Data from serdeses
reg [DS:0] rxr ; // Registered Data from serdeses
reg state ;
reg bslip ;
reg [3:0] count ;

assign rst = reset ; // active high reset pin
assign dataout = rxr ;

// Clock Input. Generate ioclocks via BUFIO2

serdes_1_to_n_clk_ddr_s8_diff #(
.S (S),
.DIFF_TERM ("TRUE")) // Enable or disable diff termination
inst_clkin (
.clkin_p (clkin_p),
.clkin_n (clkin_n),
.rxioclkp (rxioclkp),
.rxioclkn (rxioclkn),
.rx_serdesstrobe (rx_serdesstrobe),
.rx_bufg_x1 (rx_bufg_x1));

// Data Inputs

serdes_1_to_n_data_ddr_s8_diff #(
.S (S),
.D (D),
.DIFF_TERM ("TRUE")) // Enable or disable diff termination
inst_datain (
.use_phase_detector (1'b1), // '1' enables the phase detector logic
.datain_p (datain_p),
.datain_n (datain_n),
.rxioclkp (rxioclkp),
.rxioclkn (rxioclkn),
.rxserdesstrobe (rx_serdesstrobe),
.gclk (rx_bufg_x1),
.bitslip (bslip),
.reset (rst),
.data_out (rxd),
.debug_in (2'b00),
.debug ());

always @ (posedge rx_bufg_x1 or posedge rst) // example bitslip logic, if required
begin
if (rst == 1'b1) begin
state <= 0 ;
bslip <= 1'b0 ;
count <= 4'b0000 ;
end
else begin
if (state == 0) begin
if (rxd[3:0] != 4'h3) begin
bslip <= 1'b1 ; // bitslip needed
state <= 1 ;
count <= 4'b0000 ;
end
end
else if (state == 1) begin
bslip <= 1'b0 ; // bitslip low
count <= count + 4'b0001 ;
if (count == 4'b1111) begin
state <= 0;
end
end
end
end

always @ (posedge rx_bufg_x1) // process received data
begin
rxr <= rxd ;
end

endmodule


These are the lower modules provided by XAPP1064:

module serdes_1_to_n_clk_ddr_s8_diff (clkin_p, clkin_n, rxioclkp, rxioclkn, rx_serdesstrobe, rx_bufg_x1) ;

parameter integer S = 8 ; // Parameter to set the serdes factor 1..8
parameter DIFF_TERM = "FALSE" ; // Parameter to enable internal differential termination

input clkin_p ; // Input from LVDS receiver pin
input clkin_n ; // Input from LVDS receiver pin
output rxioclkp ; // IO Clock network
output rxioclkn ; // IO Clock network
output rx_serdesstrobe ; // Parallel data capture strobe
output rx_bufg_x1 ; // Global clock output

wire ddly_m; // Master output from IODELAY1
wire ddly_s; // Slave output from IODELAY1
wire rx_clk_in ; //
wire iob_data_in_p ; //
wire iob_data_in_n ; //

parameter RX_SWAP_CLK = 1'b0 ; // pinswap mask for input clock (0 = no swap (default), 1 = swap). Allows input to be connected the wrong way round to ease PCB routing.

IBUFDS_DIFF_OUT #(
.DIFF_TERM (DIFF_TERM))
iob_clk_in (
.I (clkin_p),
.IB (clkin_n),
.OB (rx_clk_in_n),
.O (rx_clk_in_p)) ;

assign iob_data_in_p = rx_clk_in_p ^ RX_SWAP_CLK ; // Invert clock as required
assign iob_data_in_n = rx_clk_in_n ^ RX_SWAP_CLK ; // Invert clock as required

// IODELAY for the differential inputs.
//

IODELAY2 #(
.DATA_RATE ("SDR"), // <SDR>, DDR
.SIM_TAPDELAY_VALUE (49), // nominal tap delay (sim parameter only)
.IDELAY_VALUE (0), // {0 ... 255}
.IDELAY2_VALUE (0), // {0 ... 255}
.ODELAY_VALUE (0), // {0 ... 255}
.IDELAY_MODE ("NORMAL"), // "NORMAL", "PCI"
.SERDES_MODE ("MASTER"), // <NONE>, MASTER, SLAVE
.IDELAY_TYPE ("FIXED"), // "DEFAULT", "DIFF_PHASE_DETECTOR", "FIXED", "VARIABLE_FROM_HALF_MAX", "VARIABLE_FROM_ZERO"
.COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), // <STAY_AT_LIMIT>, WRAPAROUND
.DELAY_SRC ("IDATAIN")) // "IO", "IDATAIN", "ODATAIN"
iodelay_m (
.IDATAIN (iob_data_in_p), // data from master IOB
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_m), // Output data 1 to ILOGIC/ISERDES2
.DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2
.IOCLK0 (1'b0), // High speed clock for calibration
.IOCLK1 (1'b0), // High speed clock for calibration
.CLK (1'b0), // Fabric clock (GCLK) for control signals
.CAL (1'b0), // Calibrate enable signal
.INC (1'b0), // Increment counter
.CE (1'b0), // Clock Enable
.RST (1'b0), // Reset delay line to 1/2 max in this case
.BUSY ()) ; // output signal indicating sync circuit has finished / calibration has finished

IODELAY2 #(
.DATA_RATE ("SDR"), // <SDR>, DDR
.SIM_TAPDELAY_VALUE (49), // nominal tap delay (sim parameter only)
.IDELAY_VALUE (0), // {0 ... 255}
.IDELAY2_VALUE (0), // {0 ... 255}
.ODELAY_VALUE (0), // {0 ... 255}
.IDELAY_MODE ("NORMAL"), // "NORMAL", "PCI"
.SERDES_MODE ("SLAVE"), // <NONE>, MASTER, SLAVE
.IDELAY_TYPE ("FIXED"), // "DEFAULT", "DIFF_PHASE_DETECTOR", "FIXED", "VARIABLE_FROM_HALF_MAX", "VARIABLE_FROM_ZERO"
.COUNTER_WRAPAROUND ("STAY_AT_LIMIT"), // <STAY_AT_LIMIT>, WRAPAROUND
.DELAY_SRC ("IDATAIN")) // "IO", "IDATAIN", "ODATAIN"
iodelay_s (
.IDATAIN (iob_data_in_n), // data from slave IOB
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_s), // Output data 1 to ILOGIC/ISERDES2
.DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2
.IOCLK0 (1'b0), // High speed clock for calibration
.IOCLK1 (1'b0), // High speed clock for calibration
.CLK (1'b0), // Fabric clock (GCLK) for control signals
.CAL (1'b0), // Calibrate control signal, never needed as the slave supplies the clock input to the PLL
.INC (1'b0), // Increment counter
.CE (1'b0), // Clock Enable
.RST (1'b0), // Reset delay line
.BUSY ()) ; // output signal indicating sync circuit has finished / calibration has finished

BUFG bufg_pll_x1 (.I(rx_bufio2_x1), .O(rx_bufg_x1) ) ;

BUFIO2_2CLK #(
.DIVIDE (S)) // The DIVCLK divider divide-by value; default 1
bufio2_2clk_inst (
.I (ddly_m), // Input source clock 0 degrees
.IB (ddly_s), // Input source clock 0 degrees
.IOCLK (rxioclkp), // Output Clock for IO
.DIVCLK (rx_bufio2_x1), // Output Divided Clock
.SERDESSTROBE (rx_serdesstrobe)) ; // Output SERDES strobe (Clock Enable)

BUFIO2 #(
.I_INVERT ("FALSE"), //
.DIVIDE_BYPASS ("FALSE"), //
.USE_DOUBLER ("FALSE")) //
bufio2_inst (
.I (ddly_s), // N_clk input from IDELAY
.IOCLK (rxioclkn), // Output Clock
.DIVCLK (), // Output Divided Clock
.SERDESSTROBE ()) ; // Output SERDES strobe (Clock Enable)

endmodule


module serdes_1_to_n_data_ddr_s8_diff (use_phase_detector, datain_p, datain_n, rxioclkp, rxioclkn, rxserdesstrobe, reset, gclk, bitslip, debug_in, data_out, debug) ;

parameter integer S = 8 ; // Parameter to set the serdes factor 1..8
parameter integer D = 16 ; // Set the number of inputs and outputs
parameter DIFF_TERM = "FALSE" ; // Parameter to enable internal differential termination

input use_phase_detector ; // '1' enables the phase detcetor logic
input [D-1:0] datain_p ; // Input from LVDS receiver pin
input [D-1:0] datain_n ; // Input from LVDS receiver pin
input rxioclkp ; // IO Clock network
input rxioclkn ; // IO Clock network
input rxserdesstrobe ; // Parallel data capture strobe
input reset ; // Reset line
input gclk ; // Global clock
input bitslip ; // Bitslip control line
input [1:0] debug_in ; // Debug Inputs
output [(D*S)-1:0] data_out ; // Output data
output [2*D+6:0] debug ; // Debug bus, 2D+6 = 2 lines per input (from mux and ce) + 7, leave nc if debug not required

wire [D-1:0] ddly_m; // Master output from IODELAY1
wire [D-1:0] ddly_s; // Slave output from IODELAY1
wire [D-1:0] busys ; //
wire [D-1:0] rx_data_in ; //
wire [D-1:0] rx_data_in_fix ; //
wire [D-1:0] cascade ; //
wire [D-1:0] pd_edge ; //
reg [8:0] counter ;
reg [3:0] state ;
reg cal_data_sint ;
wire [D-1:0] busy_data ;
reg busy_data_d ;
wire cal_data_slave ;
reg enable ;
reg cal_data_master ;
reg rst_data ;
reg inc_data_int ;
wire inc_data ;
reg [D-1:0] ce_data ;
reg valid_data_d ;
reg incdec_data_d ;
wire [(8*D)-1:0] mdataout ; //
reg [4:0] pdcounter ;
wire [D-1:0] valid_data ;
wire [D-1:0] incdec_data ;
reg [D-1:0] mux ;
reg ce_data_inta ;
reg flag ;
wire [D:0] incdec_data_or ;
wire [D-1:0] incdec_data_im ;
wire [D:0] valid_data_or ;
wire [D-1:0] valid_data_im ;
wire [D:0] busy_data_or ;
wire [D-1:0] all_ce ;

parameter SIM_TAP_DELAY = 49 ; //
parameter [D-1:0] RX_SWAP_MASK = 16'h0000 ; // pinswap mask for input bits (0 = no swap (default), 1 = swap). Allows inputs to be connected the wrong way round to ease PCB routing.

assign busy_data = busys ;
assign cal_data_slave = cal_data_sint ;
assign debug = {mux, cal_data_master, rst_data, cal_data_slave, busy_data_d, inc_data, ce_data, valid_data_d, incdec_data_d};

genvar i ;
genvar j ;

always @ (posedge gclk or posedge reset)
begin
if (reset == 1'b1) begin
state <= 0 ;
cal_data_master <= 1'b0 ;
cal_data_sint <= 1'b0 ;
counter <= 9'b000000000 ;
enable <= 1'b0 ;
mux <= 16'h0001 ;
end
else begin
counter <= counter + 9'b000000001 ;
if (counter[8] == 1'b1) begin
counter <= 9'b000000000 ;
end
if (counter[5] == 1'b1) begin
enable <= 1'b1 ;
end
if (state == 0 && enable == 1'b1) begin // Wait for all IODELAYs to be available
cal_data_master <= 1'b0 ;
cal_data_sint <= 1'b0 ;
rst_data <= 1'b0 ;
if (busy_data_d == 1'b0) begin
state <= 1 ;
end
end
else if (state == 1) begin // Issue calibrate command to both master and slave, needed for simulation, not for the silicon
cal_data_master <= 1'b1 ;
cal_data_sint <= 1'b1 ;
if (busy_data_d == 1'b1) begin // and wait for command to be accepted
state <= 2 ;
end
end
else if (state == 2) begin // Now RST all master and slave IODELAYs, needed for simulation, not for the silicon
cal_data_master <= 1'b0 ;
cal_data_sint <= 1'b0 ;
if (busy_data_d == 1'b0) begin
rst_data <= 1'b1 ;
state <= 3 ;
end
end
else if (state == 3) begin // Wait fo all IODELAYs to be available
rst_data <= 1'b0 ;
if (busy_data_d == 1'b0) begin
state <= 4 ;
end
end
else if (state == 4) begin // Wait for occasional enable
if (counter[8] == 1'b1) begin
state <= 5 ;
end
end
else if (state == 5) begin // Calibrate slave only
if (busy_data_d == 1'b0) begin
cal_data_sint <= 1'b1 ;
state <= 6 ;
if (D != 1) begin
mux <= {mux[D-2:0], mux[D-1]} ;
end
end
end
else if (state == 6) begin // Wait for command to be accepted
if (busy_data_d == 1'b1) begin
cal_data_sint <= 1'b0 ;
state <= 7 ;
end
end
else if (state == 7) begin // Wait for all IODELAYs to be available, ie CAL command finished
cal_data_sint <= 1'b0 ;
if (busy_data_d == 1'b0) begin
state <= 4 ;
end
end
end
end

always @ (posedge gclk or posedge reset) // Per-bit phase detection state machine
begin
if (reset == 1'b1) begin
pdcounter <= 5'h10 ;
ce_data_inta <= 1'b0 ;
flag <= 1'b0 ; // flag is there to only allow one inc or dec per cal (test)
end
else begin
busy_data_d <= busy_data_or[D] ;
if (use_phase_detector == 1'b1) begin // decide whther pd is used
incdec_data_d <= incdec_data_or[D] ;
valid_data_d <= valid_data_or[D] ;
if (ce_data_inta == 1'b1) begin
ce_data = mux ;
end
else begin
ce_data = mux ^ mux ;
end
if (state == 7) begin
flag <= 1'b0 ;
end
else if (state != 4 || busy_data_d == 1'b1) begin // Reset filter if state machine issues a cal command or unit is busy
pdcounter <= 5'b10000 ;
ce_data_inta <= 1'b0 ;
end
else if (pdcounter == 5'b11111 && flag == 1'b0) begin // Filter has reached positive max - increment the tap count
ce_data_inta <= 1'b1 ;
inc_data_int <= 1'b1 ;
pdcounter <= 5'b10000 ;
flag <= 1'b1 ;
end
else if (pdcounter == 5'b00000 && flag == 1'b0) begin // Filter has reached negative max - decrement the tap count
ce_data_inta <= 1'b1 ;
inc_data_int <= 1'b0 ;
pdcounter <= 5'b10000 ;
flag <= 1'b1 ;
end
else if (valid_data_d == 1'b1) begin // increment filter
ce_data_inta <= 1'b0 ;
if (incdec_data_d == 1'b1 && pdcounter != 5'b11111) begin
pdcounter <= pdcounter + 5'b00001 ;
end
else if (incdec_data_d == 1'b0 && pdcounter != 5'b00000) begin // decrement filter
pdcounter <= pdcounter + 5'b11111 ;
end
end
else begin
ce_data_inta <= 1'b0 ;
end
end
else begin
ce_data = all_ce ;
inc_data_int <= debug_in[1] ;
end
end
end

assign inc_data = inc_data_int ;

assign incdec_data_or[0] = 1'b0 ; // Input Mux - Initialise generate loop OR gates
assign valid_data_or[0] = 1'b0 ;
assign busy_data_or[0] = 1'b0 ;

generate
for (i = 0 ; i <= (D-1) ; i = i+1)
begin : loop0

assign incdec_data_im = incdec_data & mux ; // Input muxes
assign incdec_data_or[i+1] = incdec_data_im | incdec_data_or ; // AND gates to allow just one signal through at a tome
assign valid_data_im = valid_data & mux ; // followed by an OR
assign valid_data_or[i+1] = valid_data_im | valid_data_or ; // for the three inputs from each PD
assign busy_data_or[i+1] = busy_data | busy_data_or ; // The busy signals just need an OR gate

assign all_ce = debug_in[0] ;

assign rx_data_in_fix = rx_data_in ^ RX_SWAP_MASK ; // Invert signals as required

IBUFDS #(
.DIFF_TERM (DIFF_TERM))
data_in (
.I (datain_p),
.IB (datain_n),
.O (rx_data_in));

IODELAY2 #(
.DATA_RATE ("DDR"), // <SDR>, DDR
.IDELAY_VALUE (0), // {0 ... 255}
.IDELAY2_VALUE (0), // {0 ... 255}
.IDELAY_MODE ("NORMAL" ), // NORMAL, PCI
.ODELAY_VALUE (0), // {0 ... 255}
.IDELAY_TYPE ("DIFF_PHASE_DETECTOR"),// "DEFAULT", "DIFF_PHASE_DETECTOR", "FIXED", "VARIABLE_FROM_HALF_MAX", "VARIABLE_FROM_ZERO"
.COUNTER_WRAPAROUND ("WRAPAROUND" ), // <STAY_AT_LIMIT>, WRAPAROUND
.DELAY_SRC ("IDATAIN" ), // "IO", "IDATAIN", "ODATAIN"
.SERDES_MODE ("MASTER"), // <NONE>, MASTER, SLAVE
.SIM_TAPDELAY_VALUE (SIM_TAP_DELAY)) //
iodelay_m (
.IDATAIN (rx_data_in_fix), // data from primary IOB
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_m), // Output data 1 to ILOGIC/ISERDES2
.DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2
.IOCLK0 (rxioclkp), // High speed clock for calibration
.IOCLK1 (rxioclkn), // High speed clock for calibration
.CLK (gclk), // Fabric clock (GCLK) for control signals
.CAL (cal_data_master), // Calibrate control signal
.INC (inc_data), // Increment counter
.CE (ce_data), // Clock Enable
.RST (rst_data), // Reset delay line
.BUSY ()) ; // output signal indicating sync circuit has finished / calibration has finished

IODELAY2 #(
.DATA_RATE ("DDR"), // <SDR>, DDR
.IDELAY_VALUE (0), // {0 ... 255}
.IDELAY2_VALUE (0), // {0 ... 255}
.IDELAY_MODE ("NORMAL" ), // NORMAL, PCI
.ODELAY_VALUE (0), // {0 ... 255}
.IDELAY_TYPE ("DIFF_PHASE_DETECTOR"),// "DEFAULT", "DIFF_PHASE_DETECTOR", "FIXED", "VARIABLE_FROM_HALF_MAX", "VARIABLE_FROM_ZERO"
.COUNTER_WRAPAROUND ("WRAPAROUND" ), // <STAY_AT_LIMIT>, WRAPAROUND
.DELAY_SRC ("IDATAIN" ), // "IO", "IDATAIN", "ODATAIN"
.SERDES_MODE ("SLAVE"), // <NONE>, MASTER, SLAVE
.SIM_TAPDELAY_VALUE (SIM_TAP_DELAY)) //
iodelay_s (
.IDATAIN (rx_data_in_fix), // data from primary IOB
.TOUT (), // tri-state signal to IOB
.DOUT (), // output data to IOB
.T (1'b1), // tri-state control from OLOGIC/OSERDES2
.ODATAIN (1'b0), // data from OLOGIC/OSERDES2
.DATAOUT (ddly_s), // Output data 1 to ILOGIC/ISERDES2
.DATAOUT2 (), // Output data 2 to ILOGIC/ISERDES2
.IOCLK0 (rxioclkp), // High speed clock for calibration
.IOCLK1 (rxioclkn), // High speed clock for calibration
.CLK (gclk), // Fabric clock (GCLK) for control signals
.CAL (cal_data_slave), // Calibrate control signal
.INC (inc_data), // Increment counter
.CE (ce_data), // Clock Enable
.RST (rst_data), // Reset delay line
.BUSY (busys)) ; // output signal indicating sync circuit has finished / calibration has finished

ISERDES2 #(
.DATA_WIDTH (S), // SERDES word width. This should match the setting is BUFPLL
.DATA_RATE ("DDR"), // <SDR>, DDR
.BITSLIP_ENABLE ("TRUE"), // <FALSE>, TRUE
.SERDES_MODE ("MASTER"), // <DEFAULT>, MASTER, SLAVE
.INTERFACE_TYPE ("RETIMED")) // NETWORKING, NETWORKING_PIPELINED, <RETIMED>
iserdes_m (
.D (ddly_m),
.CE0 (1'b1),
.CLK0 (rxioclkp),
.CLK1 (rxioclkn),
.IOCE (rxserdesstrobe),
.RST (reset),
.CLKDIV (gclk),
.SHIFTIN (pd_edge),
.BITSLIP (bitslip),
.FABRICOUT (),
.Q4 (mdataout[(8*i)+7]),
.Q3 (mdataout[(8*i)+6]),
.Q2 (mdataout[(8*i)+5]),
.Q1 (mdataout[(8*i)+4]),
.DFB (),
.CFB0 (),
.CFB1 (),
.VALID (valid_data),
.INCDEC (incdec_data),
.SHIFTOUT (cascade));

ISERDES2 #(
.DATA_WIDTH (S), // SERDES word width. This should match the setting is BUFPLL
.DATA_RATE ("DDR"), // <SDR>, DDR
.BITSLIP_ENABLE ("TRUE"), // <FALSE>, TRUE
.SERDES_MODE ("SLAVE"), // <DEFAULT>, MASTER, SLAVE
.INTERFACE_TYPE ("RETIMED")) // NETWORKING, NETWORKING_PIPELINED, <RETIMED>
iserdes_s (
.D (ddly_s),
.CE0 (1'b1),
.CLK0 (rxioclkp),
.CLK1 (rxioclkn),
.IOCE (rxserdesstrobe),
.RST (reset),
.CLKDIV (gclk),
.SHIFTIN (cascade),
.BITSLIP (bitslip),
.FABRICOUT (),
.Q4 (mdataout[(8*i)+3]),
.Q3 (mdataout[(8*i)+2]),
.Q2 (mdataout[(8*i)+1]),
.Q1 (mdataout[(8*i)+0]),
.DFB (),
.CFB0 (),
.CFB1 (),
.VALID (),
.INCDEC (),
.SHIFTOUT (pd_edge));

// Assign received data bits to correct place in data word, and invert as necessary using information from the data mask

for (j = 7 ; j >= (8-S) ; j = j-1) // j is for serdes factor
begin : loop2
assign data_out[((D*(j+S-8))+i)] = mdataout[(8*i)+j] ;
end
end
endgenerate

endmodule

And here is the user contraints file:

# Timing

net "rx_bufg_x1" period = 125 MHz ; # Receiver global buffer = bit rate/serdes factor eg 1 Gbps/8

# Pin Locations

NET "clkin_p" DIFF_TERM = "TRUE";
NET "clkin_p" IOSTANDARD = LVDS_33;
NET "clkin_p" LOC = N5;
NET "clkin_n" DIFF_TERM = "TRUE";
NET "clkin_n" IOSTANDARD = LVDS_33;

NET "datain_p[0]" DIFF_TERM = "TRUE";
NET "datain_p[0]" IOSTANDARD = LVDS_33;
NET "datain_p[0]" LOC = R3;
NET "datain_n[0]" DIFF_TERM = "TRUE";
NET "datain_n[0]" IOSTANDARD = LVDS_33;
NET "datain_p[1]" DIFF_TERM = "TRUE";
NET "datain_p[1]" IOSTANDARD = LVDS_33;
NET "datain_p[1]" LOC = T4;
NET "datain_n[1]" DIFF_TERM = "TRUE";
NET "datain_n[1]" IOSTANDARD = LVDS_33;

NET "reset" IOSTANDARD = LVTTL;
NET "reset" PULLUP;
NET "reset" LOC = V12;
NET "reset" SLEW = FAST;
NET "dataout[0]" IOSTANDARD = LVTTL;
NET "dataout[0]" SLEW = FAST;
NET "dataout[0]" LOC = U7;
NET "dataout[1]" IOSTANDARD = LVTTL;
NET "dataout[1]" SLEW = FAST;
NET "dataout[1]" LOC = V7;
NET "dataout[2]" IOSTANDARD = LVTTL;
NET "dataout[2]" SLEW = FAST;
NET "dataout[2]" LOC = N7;
NET "dataout[3]" IOSTANDARD = LVTTL;
NET "dataout[3]" SLEW = FAST;
NET "dataout[3]" LOC = P8;
NET "dataout[4]" IOSTANDARD = LVTTL;
NET "dataout[4]" SLEW = FAST;
NET "dataout[4]" LOC = T6;
NET "dataout[5]" IOSTANDARD = LVTTL;
NET "dataout[5]" SLEW = FAST;
NET "dataout[5]" LOC = V6;
NET "dataout[6]" IOSTANDARD = LVTTL;
NET "dataout[6]" SLEW = FAST;
NET "dataout[6]" LOC = E8;
NET "dataout[7]" IOSTANDARD = LVTTL;
NET "dataout[7]" SLEW = FAST;
NET "dataout[7]" LOC = E7;
NET "dataout[8]" IOSTANDARD = LVTTL;
NET "dataout[8]" SLEW = FAST;
NET "dataout[8]" LOC = E6;
NET "dataout[9]" IOSTANDARD = LVTTL;
NET "dataout[9]" SLEW = FAST;
NET "dataout[9]" LOC = F7;
NET "dataout[10]" IOSTANDARD = LVTTL;
NET "dataout[10]" SLEW = FAST;
NET "dataout[10]" LOC = A5;
NET "dataout[11]" IOSTANDARD = LVTTL;
NET "dataout[11]" SLEW = FAST;
NET "dataout[11]" LOC = C5;
NET "dataout[12]" IOSTANDARD = LVTTL;
NET "dataout[12]" SLEW = FAST;
NET "dataout[12]" LOC = L7;
NET "dataout[13]" IOSTANDARD = LVTTL;
NET "dataout[13]" SLEW = FAST;
NET "dataout[13]" LOC = L5;
NET "dataout[14]" IOSTANDARD = LVTTL;
NET "dataout[14]" SLEW = FAST;
NET "dataout[14]" LOC = L4;
NET "dataout[15]" IOSTANDARD = LVTTL;
NET "dataout[15]" SLEW = FAST;
NET "dataout[15]" LOC = L3;

VCCAUX = 3.3 ;


The error I get is "unrouteable Net:inst_clkin/rx_clk_in_p"

Thanks in advance for any help,

Scott
 

The error I get is "unrouteable Net:inst_clkin/rx_clk_in_p"

Real quick reply ... that sort of thing typically means that you're using the wrong clock buffer type somewhere. As in the mapper is expecting to connect two clocking resources of the same type but you're inadvertently using two different things.

It synthesizes just fine, and barfs when you get to the mapper stage right? It shouldn't really matter, but does it suddenly work when you remove that XOR stage at "^ RX_SWAP_CLK ; // Invert clock as required" ??

I've had this sort of thing when connecting the PLL outputs from coregen to a DDR IO. Where coregen is supposed to generate the right kind of buffer, but in reality it stuffs up.
 

It synthesizes fine, translates fine, maps fine, and barfs on the Place and Route. Removing the XOR so that those two lines read as

assign iob_data_in_p = rx_clk_in_p; // Invert clock as required
assign iob_data_in_n = rx_clk_in_n; // Invert clock as required

didn't change anything. Can you expand on what you mean by two different clock buffers (remembering that I'm really bootstrapping myself here and don't have a good foundation at all)? This implementation is almost solely code provided by XAPP1064 with my own user constraints file so I must be doing something really dumb I think.

Scott
 

Mmmh, P&R barfing is slightly different situation than with the mapper. So that might just be a different thing than what I'm thinking of (and failing horribly at explaining anyways ;) I blame lack of sleep and whoever wrote the preseed documentation for debian. May he live in interesting times.


Also ...

However, I have no declared the wires rxioclkp etc in my code yet. Why is this allowed? Is the declaration implicit for outputs or something? I'm probably thinking about this the wrong way since I'm an object oriented programmer by training.

Are you sure you have no sneaky undeclared wires? Verilog is really awesome at making stuff up! You don'd declare something? No problem! Verilog makes something up for you on the go. If you don't like surprises, I suggest using

Code:
`default_nettype none

at the start of your modules. As in the very first line of the .v file. And if you want to be polite to potential other code from other people, put this one as last line of the .v file:

Code:
`default_nettype wire

That way 1) verilog will not invent wires for you and cause surprises, and 2) other people's code that may count on this effect will still work as expected.

It's probably not related to that, but since you asked about undeclared wires.

The main reason I use this is it protects me from stupid 1 letter typos that are hard to spot.


edit:

Code:
# Pin Locations

NET "clkin_p" DIFF_TERM = "TRUE";
NET "clkin_p" IOSTANDARD = LVDS_33;
NET "clkin_p" LOC = N5;
NET "clkin_n" DIFF_TERM = "TRUE";
NET "clkin_n" IOSTANDARD = LVDS_33;

NET "datain_p[0]" DIFF_TERM = "TRUE";
...


Awww, clkin_n doesn't get a LOC constraint? That's not very nice...

You may want to add ...

Code:
NET "clkin_n" LOC = ...;

... and see if that changes the routing situation.
 
Last edited:

Should you really be declaring the negative side of differential pairs? Isn't it implied by the LOC of the positive side?

Scott

---------- Post added at 22:05 ---------- Previous post was at 21:56 ----------

Also adding that line at the very first line of each of the modules provided by XAPP1064 causes the synthesis to barf. I tried then adding that line at the end to see if it would help but it causes a syntax error.

---------- Post added at 22:09 ---------- Previous post was at 22:05 ----------

Ok, syntax error resolved but with those lines added at the beginning and end of modules provided above, I get the following errors on synthesis:


ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 83: <rx_clk_in_n> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 84: <rx_clk_in_p> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 86: <rx_clk_in_p> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 87: <rx_clk_in_n> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 148: <rx_bufio2_x1> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 156: <rx_bufio2_x1> is not declared.
ERROR:HDLCompiler:598 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 58: Module <serdes_1_to_n_clk_ddr_s8_diff> ignored due to previous errors.

Clearly either the code provided by XAPP1064 is not correct or I'm using it incorrectly. I'm guessing its the latter?
 

Should you really be declaring the negative side of differential pairs? Isn't it implied by the LOC of the positive side?

Personally I don't trust the xilinx tools to come up with ANYTHING clever. So it is definitely not implied. At best it is resolved in your favor during mapping. But if you are out of luck it does something stupid and places clkin_n at some random LOC first. And then can't route the clkin_p anymore because they are at different locations.


Also adding that line at the very first line of each of the modules provided by XAPP1064 causes the synthesis to barf. I tried then adding that line at the end to see if it would help but it causes a syntax error.

Nono, that's not the plan. You only add those lines to your OWN .v files where you know what YOU are doing. Because YOU never rely on sloppy implicitly declared wires. Obviously. With other people's code all bets are off. Actually the fact that the XAPP code suddenly breaks is a nice indicator that they do have some implicit wires in there somewhere. In and of itself no problem, since YOU don't have to maintain that code. But for your own code you really would like an early warning when you are simply forgetting a wire, or mistyped a name by 1 letter. Or the every popular mismatched bitvector lengths.


Ok, syntax error resolved but with those lines added at the beginning and end of modules provided above, I get the following errors on synthesis:


ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 83: <rx_clk_in_n> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 84: <rx_clk_in_p> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 86: <rx_clk_in_p> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 87: <rx_clk_in_n> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 148: <rx_bufio2_x1> is not declared.
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 156: <rx_bufio2_x1> is not declared.
ERROR:HDLCompiler:598 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_clk_ddr_s8_diff.v" Line 58: Module <serdes_1_to_n_clk_ddr_s8_diff> ignored due to previous errors.

Clearly either the code provided by XAPP1064 is not correct or I'm using it incorrectly. I'm guessing its the latter?

Excellent! And this is the whole point. Now you get big fat errors, instead of silent sneaky verilog style Lets Make Stuff Up.

The thing is that by default the default nettype is set to wire. Which means:


This will compile just fine, and probably NOT do what you want:
Code:
`default_nettype wire

...

wire this_does_exist;

assign this_does_exist = lets_make_shit_up;


Why will the above still compile? because "lets_make_shit_up" is set to net type "wire" the moment it encounters it. As in it has never been declared before, and as such it is assigned the default nettype. Which is wire.


This will throw an error, preventing you from pulling your hair out because you can't find what the hell is going on:
Code:
`default_nettype none

...

wire this_does_exist;

assign this_does_exist = lets_make_shit_up;

Same sort of story as above, only this time lets_make_shit_up is assigned net type "none". Which means no circuit. Which means big fat error pointing out that you forgot to declare "lets_make_shit_up" first.
 

That was a very helpful explanation, thank you. However, I still have this not routeable issue.

The project I'm currently trying to route and place is a very simple project. All I did was take the files from XAPP1064, make some small changes to the number of inputs and outputs, and create a user constraint file for it. This was originally part of a bigger project that wouldn't route either, but I decided to try to debug this issue one piece at a time. So since I only have modules in my project right now that were provided by an XAPP I shouldn't be placing those lines at the beginning or end and therefore I no longer have a synthesis problem. The question remains what about the XAPP is unrouteable.
 

Well ... "serdes_1_to_n_ clk_ddr_s8_diff.v" is that your code or someone else's?

Also, small hints like this:

Code:
ERROR:HDLCompiler:69 - "C:\Users\Scott\Product Development\8200 Development\FPGA Development\Support Docs\XAPP1064\Verilog_Source\Macros\serdes_1_to_n_ clk_ddr_s8_diff.v" Line 156: <rx_bufio2_x1> is not declared.

"rx_bufio2_x1" is not declared. And "rx_bufio2_x1" in this case really means "rx_bufio2_x[1]". So could very well be that it is declared somewhere as a 1-bit "vector", and then try to use it as a 2-bit vector. Because you will note that there is no similar error that goes like:

Line 34734589: <rx_bufio2_x0> is not declared.

That "rx_bufio2_x0" aka "rx_bufio2_x[0]" aka "rx_bufio2_x" will be declared somewhere to make you feel happy. So I'd take a look at how rx_bufio2_x is declared and how it is used (1-bit or multi-bit).


"The question remains what about the XAPP is unrouteable."

Yeah, that is always tricky. Those unroutable error messages are always a bit vague at best. About as helpful as the average C-compiler error message from 10 years ago. Error near dffghdkgjh_yygnnn() in line 987 of wtf.c. Translation: you forgot a semicolon somewhere on line 3. Possibly in another file.

---------- Post added at 23:25 ---------- Previous post was at 23:13 ----------

If you want I could take a look at it. If so, please attach a zip of the entire project directory. That makes it easier for me not to make assumptions. :)
 

That is a useful hint but I don't think its helpful here. That module is XAPP code, not my own. I'll attach the project here. Thanks for the help.
 

Attachments

  • LVDSdeserializationTest.zip
    285 KB · Views: 48

k. will take a look at it.

---------- Post added 25-02-12 at 00:48 ---------- Previous post was 24-02-12 at 23:43 ----------

Heh.


I grabbed the original xapp1064.zip and used your .UCF, which was a nogo.

Here's my own .ucf snippet which results in working place & route... I think you can take it from here. ;)

Code:
// SP601 (ug518.pdf) :
// NET "FMC_LA23_P" LOC = "N5"; ## D23 on J1
// NET "FMC_LA23_N" LOC = "P6"; ## D24 on J1
// NET "FMC_CLK0_M2C_P" LOC = "C10"; ## H4 on J1
// NET "FMC_CLK0_M2C_N" LOC = "A10"; ## H5 on J1

// NET "clkin_p" DIFF_TERM = "TRUE";
// NET "clkin_p" IOSTANDARD = LVDS_33;
// NET "clkin_p" LOC = "N5";
NET "clkin_p" LOC = "C10"; // lets try actual clock capable pins
// NET "clkin_n" DIFF_TERM = "TRUE";
// NET "clkin_n" IOSTANDARD = LVDS_33;
// NET "clkin_n" LOC = "P6";
NET "clkin_n" LOC = "A10"; // lets try actual clock capable pins

Incidentally, this is a variation on the theme I mentioned earlier:

mrflibble said:
Real quick reply ... that sort of thing typically means that you're using the wrong clock buffer type somewhere. As in the mapper is expecting to connect two clocking resources of the same type but you're inadvertently using two different things.
 

Oh man thats exactly what I was hoping was not the problem. Routing the ADC's bit rate clock to anything other than the pins I was using is very hard. Is there no way to route the bit rate clock into the pins I was using?
 

I'm afraid the strict answer is going to be "no". The more friendly answer is "maybe, it depends". But for using the exact set of features you were using there you do need the dedicated clock inputs.

So your design requirements are "need differential clock input" and further constraints are "ideally I want to restrict input to these specific pins" or something? What are you trying to do exactly? I'll re-read the thread after this to see if I missed anything, but right now I'll assume there are design details missing that you could specify to help us understand what you want to do. ;-) Anyways, regarding those clock input pins, other ones that are an option? Those C10+A10 LOCs that I choose are not the only options you have for dedicated clock inputs, just the quickest I could find (based on the package you selected in your project) for doing a quick test.

From your OP I see you are using a Drigmorn3. Not super familiar with the hardware specifics, and too lazy for schematics just now, but .... are there no dedicated clock inputs on an easily accessible connector somewhere that you can use? As said, those C10+A10 are just one option of severa lif you want to do things exactly the XAPP1064 way.
 

There are easily accessible clock inputs (I've used one of them for something else) but its on a different connector header than the one I was using to interface the ADC to FPGA. I had designed a board to interface the two and the reason I'm complaining is its going to have to be a little bit more complicated than what I was planning. Its ok, I'll live. But thank you for your help. I'll let you know how it goes.
 

How fast did you say your ADC is? 83 MHz * 4? I have a feeling that you will struggle to reliably achieve this on a Drigmorn3 because it has a big, dirty 0.1" header with no trace length matching or impedance control (for reference, I struggled to get above about 10 MHz with a similar development board). If you have to route your clock to another header, you may introduce more problems.

I would strongly recommend changing to a development board that allows you to reliably do high speed communications, such as a Digilent Atlys (good), Digilent Nexys 3 (not quite as good but probably fine), or Xilinx SP605 (excellent, though the FMC connector is a bit fiddly to prototype with). All three provide matched differential pairs and clock inputs on the same connector.
 

When the ISE talks about inputs needing to be on the same half-bank, what does that mean? How do I know what input is on what half bank?

Scott
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top