我在做一块数字IO卡,IO卡的功能包括32路单端数字I/O输出。
32路单端I/O的数据速率为200Mbps,利用100MHz时钟,使用ODDR实现此功能。ODDR能实现双倍时钟的数据速率。在时钟上升沿输出一个数据,在时钟下降沿输出另一个数据。ODDR的工作模式有2种:同沿和不同沿。同沿方式通过延迟一个时钟,能节省时钟和CLB资源,提高性能。
ODDR#(
.DDR_CLK_EDGE("OPPOSITE_EDGE"),//"OPPOSITE_EDGE" or "SAME_EDGE"
.INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1
.SRTYPE("SYNC") // Set/Resettype: "SYNC" or "ASYNC"
) ODDR_inst (
.Q (Q), // 1-bit DDR output
.C (C), // 1-bit clock input
.CE (CE),// 1-bit clock enable input
.D1 (D1),// 1-bit data input (positive edge)
.D2 (D2),// 1-bit data input (negative edge)
.R (R), // 1-bit reset
.S (S) // 1-bit set
);
我的使用方法为:
wire[63:0] do32;
wire[31:0] do_o;
wiredo_clk_sel;
wire[31:0] do_en;
genvar dq_o;
generate
for(dq_o= 0; dq_o < 32; dq_o = dq_o+1) begin: gen_do
ODDR #(
.DDR_CLK_EDGE("SAME_EDGE"),
.INIT(1'b0),
.SRTYPE("SYNC")
) do_oddr (
.Q (do_o[dq_o] ),
.C (do_clk_sel ),
.CE (1'b1 ),
.D1 (do32[dq_o] ),//64位
.D2 (do32[dq_o+ 32] ),
.R (do_en[dq_o] ),
.S (1'b0 )
);
end
assign dio[dq_o]=do_if_ctrl[dq_o]? (do_reg_vld[dq_o]?do_reg[dq_o]: do_dout_vld? do_dout[dq_o] : do_df_out_en[ dq_o ] &(~do_df_out_en_iv[dq_o]) ? do_df[dq_o ]: 1'bz ) :1’bz;
endgenerate
dio信号是顶层的inout类型双向端口。数字I/O卡的输出数据有三种类型:寄存器静态数据;动态数据;Flash数据。综合可以通过,但是在MAP过程中,出现了32个错误:
Thedual data rate register "gen_do[0].do_oddr" failed to join an OLOGIC component as required.
Thedual data rate register "gen_do[1].do_oddr" failed to join an OLOGIC component as required.
…
Thedual data rate register "gen_do[31].do_oddr" failed to join an OLOGIC component as required.
错误的原因是ODDR的输出必须直接连到输出pad上,不可以再引进逻辑内部。因此会出现do_oddr的输出无法连入OLOGIC中。
我的解决办法是:
通过IOBUF将双向dio数据分离成要输入到FPGA中的di_d和从FPGA获得do_o. IOBUF的控制位T为高时FPGA输入I端口数据使能,为低时输出O使能。
IOBUF#(
.DRIVE(12), // Specify the output drivestrength
.IOSTANDARD("DEFAULT"), //Specify the I/O standard
.SLEW("SLOW") // Specify theoutput slew rate
) IOBUF_inst (
.O (di_d[dq_o] ), // Buffer output to fpga
.IO (dio[dq_o] ), // Buffer inout port (connect directly to top-level port)
.I (do_o[dq_o]), // Buffer input from fpga
.T (dir_o[dq_o/8 ]) // 3-state enableinput, high=input, low=output
);
将数据端口准备输出的数据准备好后,再赋值给ODDR的D端口,将Q输出连接IOBUF的O上。MAP成功。
看来学习下Xilinx的器件手册还是很有用的。UG190.