手っ取り早くシミュレーションしてISERDESE3を理解しよう。
ざっくり動かすとこんな感じになる。
CLK_P/Nは内部の差動クロックといえば良いのかな?
CLKDIVはCLK_P/Nの2分周、DIN_P/NはCLK_P/Nと同じ周波数で、MIPIをリードするためにDDR想定です。
そうすると、DOUTにパラレルデータ、DOUT_CLKにCLK_P/Nの4分周が出てくる。
もし、SDRの場合は偶数ビットか奇数ビットのどちらかにデータが現れるらしい。
SDRを使う場合はデータシートをご覧くだされ。
ISERDESE5のDOUTで気をつけなければいけないのはどこでデータがロックするかなんだけど、それはわからないのでISERDESE3の後段でビットアライメントを合わせる回路が必要に成る。
あとはREFCLK_FREQUENCYに注意かな?
module csi_rx_lane_phy(
input RST_N,
input CLK_P,
input CLK_N,
input CLKDIV,
input DIN_P,
input DIN_N,
output DOUT_CLK,
output [7:0] DOUT
);
wire in_data;
wire [7:0] serdes_data;
IBUFDS
#(
.DIFF_TERM("TRUE"),
.IBUF_LOW_PWR("FALSE"),
.IOSTANDARD("DEFAULT")
)
u_IBUFDS
(
.I(DIN_P),
.IB(DIN_N),
.O(in_data)
);
IDELAYE3 #(
.CASCADE("NONE"),
.DELAY_FORMAT("TIME"),
.DELAY_SRC("IDATAIN"),
.DELAY_TYPE("FIXED"),
.DELAY_VALUE(0),
.IS_CLK_INVERTED(0),
.IS_RST_INVERTED(0),
.LOOPBACK("FALSE"),
.REFCLK_FREQUENCY(500.0),
.SIM_DEVICE("ULTRASCALE_PLUS"),
.SIM_VERSION(2.0),
.UPDATE_MODE("ASYNC")
)
u_IDELAYE3(
.CASC_OUT(),
.CNTVALUEOUT(),
.DATAOUT(in_delayed),
.CASC_IN(),
.CASC_RETURN(),
.CE(),
.CLK(CLKDIV),
.CNTVALUEIN(),
.DATAIN(),
.EN_VTC(),
.IDATAIN(in_data),
.INC(),
.LOAD(),
.RST(~RST_N)
);
wire serdes_clk, fifo_empty;
ISERDESE3 #(
.DATA_WIDTH(8),
.DDR_CLK_EDGE("OPPOSITE_EDGE"),
.FIFO_ENABLE("FALSE"),
.FIFO_SYNC_MODE("FALSE"),
.IDDR_MODE("FALSE"),
.IS_CLK_B_INVERTED(0),
.IS_CLK_INVERTED(0),
.IS_RST_INVERTED(0),
.SIM_DEVICE("ULTRASCALE_PLUS"),
.SIM_VERSION(2.0)
)
u_ISERDESE3 (
.FIFO_EMPTY(fifo_empty),
.INTERNAL_DIVCLK(serdes_clk),
.Q(serdes_data),
.CLK(CLK_P),
.CLKDIV(CLKDIV),
.CLK_B(CLK_N),
.D(in_data),
.FIFO_RD_CLK(),
.FIFO_RD_EN(),
.RST(~RST_N)
);
assign DOUT = serdes_data;
assign DOUT_CLK = serdes_clk;
endmodule
`timescale 1ns / 1ps
module tb_csi_rx_lane_phy;
reg RST_N;
reg CLK_P;
wire CLK_N;
reg CLKDIV;
reg DIN_P;
wire DIN_N;
wire DOUT_CLK;
wire [7:0] DOUT;
initial begin
CLK_P = 0;
CLKDIV = 0;
RST_N = 0;
#100;
RST_N = 1;
end
always begin
#(2) CLK_P <= ~CLK_P;
end
always begin
#(4) CLKDIV <= ~CLKDIV;
end
assign CLK_N = ~CLK_P;
initial begin
#100000;
$finish();
end
always begin
wait(RST_N);
#(1) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 1;
#(2) DIN_P = 1;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(2) DIN_P = 0;
#(2) DIN_P = 1;
#(1);
end
assign DIN_N = ~DIN_P;
csi_rx_lane_phy u_csi_rx_lane_phy(
.RST_N(RST_N),
.CLK_P(CLK_P),
.CLK_N(CLK_N),
.CLKDIV(CLKDIV),
.DIN_P(DIN_P),
.DIN_N(DIN_N),
.DOUT_CLK(DOUT_CLK),
.DOUT(DOUT)
);
endmodule