FPGA——三速自适应以太网设计(2)GMII与RGMII接口

FPGA——三速自适应以太网设计(2)GMII与RGMII接口只在时钟的上升沿通过 RGMII 接口处理低四位 下个时钟上升沿再处理高四位

大家好,欢迎来到IT知识分享网。

基础知识

(1)GMII

(2)RGMII

时钟是双沿采样

(3)IDDR

GMII设计转RGMII接口

module RGMII_Tri( /*--------rgmii port--------*/ input i_rxc , input [3 :0] i_rxd , input i_rx_ctl , output o_txc , output [3 :0] o_txd , output o_tx_ctl , /*--------data port--------*/ output o_rxc , input [7 :0] i_send_data , input i_send_valid , output [7 :0] o_rec_data , output o_rec_valid , output o_rec_end , output [1:0] o_speed , output o_link ); reg [7 :0] ri_send_data =0 ; reg ri_send_valid=0 ; reg [7 :0] ro_rec_data = 0 ; reg ro_rec_valid= 0 ; reg ro_rec_end = 0 ; reg r_cnt_10_100= 0 ; reg r_tx_cnt_10_100 = 0 ; reg [1 :0] ro_speed=0 ; reg ro_link =0 ; reg [1 :0] r_rec_valid=0 ; wire w_rxc_bufr ; wire w_rxc_bufio ; wire w_rxc_idelay ; wire [3 :0] w_rxd_ibuf ; wire w_rx_ctl_ibuf ; (* mark_debug = "true" *)wire [7 :0] w_rec_data ; (* mark_debug = "true" *)wire [1 :0] w_rec_valid ; wire [3 :0] w_send_d1 ; wire [3 :0] w_send_d2 ; wire w_send_valid ; wire i_speed1000 ; wire w_txc ; assign w_txc = ~w_rxc_bufr; assign o_rxc = w_rxc_bufr; assign o_speed = ro_speed ; assign o_link = ro_link ; assign i_speed1000 = ro_speed == 2'b10 ? 1 : 0; assign o_rec_data = ro_rec_data ; assign o_rec_valid = ro_rec_valid; assign o_rec_end = ro_rec_end ; OBUF #( .DRIVE (12 ), // Specify the output drive strength .IOSTANDARD ("DEFAULT" ), // Specify the output I/O standard .SLEW ("SLOW" ) // Specify the output slew rate ) OBUF_inst ( .O (o_txc ), // Buffer output (connect directly to top-level port) .I (w_txc ) // Buffer input  ); // 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/Reset type: "SYNC" or "ASYNC"  // ) ODDR_inst ( // .Q (o_txc ), // 1-bit DDR output // .C (w_rxc_bufr ), // 1-bit clock input // .CE (1 ), // 1-bit clock enable input // .D1 (0 ), // 1-bit data input (positive edge) // .D2 (1 ), // 1-bit data input (negative edge) // .R (0 ), // 1-bit reset // .S (0 ) // 1-bit set // ); BUFIO BUFIO_inst ( .O (w_rxc_bufio ), .I (i_rxc ) ); BUFR #( .BUFR_DIVIDE ("BYPASS" ), .SIM_DEVICE ("7SERIES" ) ) BUFR_inst ( .O (w_rxc_bufr ), .CE (1 ), .CLR (0 ), .I (i_rxc ) ); // (* IODELAY_GROUP = "rgmii" *) // IDELAYCTRL IDELAYCTRL_U0 ( // .RDY (RDY), // 1-bit output: Ready output // .REFCLK (REFCLK), // 1-bit input: Reference clock input // .RST (RST) // 1-bit input: Active high reset input // ); // (* IODELAY_GROUP = "rgmii" *) // IDELAYE2 #( // .CINVCTRL_SEL ("FALSE" ), // Enable dynamic clock inversion (FALSE, TRUE) // .DELAY_SRC ("IDATAIN" ), // Delay input (IDATAIN, DATAIN) // .HIGH_PERFORMANCE_MODE ("FALSE" ), // Reduced jitter ("TRUE"), Reduced power ("FALSE") // .IDELAY_TYPE ("FIXED" ), // FIXED, VARIABLE, VAR_LOAD, VAR_LOAD_PIPE // .IDELAY_VALUE (0 ), // Input delay tap setting (0-31) 0.15625 // .PIPE_SEL ("FALSE" ), // Select pipelined mode, FALSE, TRUE // .REFCLK_FREQUENCY (200.0 ), // IDELAYCTRL clock input frequency in MHz (190.0-210.0, 290.0-310.0). // .SIGNAL_PATTERN ("DATA" ) // DATA, CLOCK input signal // ) // IDELAYE2_inst ( // .CNTVALUEOUT (), // 5-bit output: Counter value output // .DATAOUT (w_rxc_idelay ), // 1-bit output: Delayed data output // .C (), // 1-bit input: Clock input // .CE (), // 1-bit input: Active high enable increment/decrement input // .CINVCTRL (), // 1-bit input: Dynamic clock inversion input // .CNTVALUEIN (), // 5-bit input: Counter value input // .DATAIN (), // 1-bit input: Internal delay data input // .IDATAIN (i_rxc ), // 1-bit input: Data input from the I/O // .INC (), // 1-bit input: Increment / Decrement tap delay input // .LD (), // 1-bit input: Load IDELAY_VALUE input // .LDPIPEEN (), // 1-bit input: Enable PIPELINE register to load data input // .REGRST () // 1-bit input: Active-high reset tap-delay input // ); genvar rxd_i; generate for(rxd_i = 0 ;rxd_i < 4 ;rxd_i = rxd_i + 1) begin IBUF #( .IBUF_LOW_PWR ("TRUE" ), .IOSTANDARD ("DEFAULT" ) ) IBUF_U ( .O (w_rxd_ibuf[rxd_i] ), // Buffer output .I (i_rxd[rxd_i] ) // Buffer input (connect directly to top-level port) ); IDDR #( .DDR_CLK_EDGE ("SAME_EDGE_PIPELINED" ), .INIT_Q1 (1'b0 ), .INIT_Q2 (1'b0 ), .SRTYPE ("SYNC" ) ) IDDR_u0 ( .Q1 (w_rec_data[rxd_i] ), // 1-bit output for positive edge of clock  .Q2 (w_rec_data[rxd_i +4] ), // 1-bit output for negative edge of clock .C (w_rxc_bufio ), .CE (1 ), .D (w_rxd_ibuf[rxd_i] ), .R (0 ), .S (0 ) ); end endgenerate IBUF #( .IBUF_LOW_PWR ("TRUE" ), .IOSTANDARD ("DEFAULT" ) ) IBUF_U ( .O (w_rx_ctl_ibuf ), // Buffer output .I (i_rx_ctl ) // Buffer input (connect directly to top-level port) ); IDDR #( .DDR_CLK_EDGE ("SAME_EDGE_PIPELINED" ), .INIT_Q1 (1'b0 ), .INIT_Q2 (1'b0 ), .SRTYPE ("SYNC" ) ) IDDR_u0 ( .Q1 (w_rec_valid[0] ), // 1-bit output for positive edge of clock  .Q2 (w_rec_valid[1] ), // 1-bit output for negative edge of clock .C (w_rxc_bufio ), .CE (1 ), .D (w_rx_ctl_ibuf ), .R (0 ), .S (0 ) ); always@(posedge w_rxc_bufr) begin if(!i_speed1000 && (&w_rec_valid)) r_cnt_10_100 <= r_cnt_10_100 + 1; else r_cnt_10_100 <= 'd0; end always@(posedge w_rxc_bufr) begin if(&w_rec_valid && i_speed1000) ro_rec_valid <= 'd1; else ro_rec_valid <= r_cnt_10_100; end always@(posedge w_rxc_bufr) begin if(i_speed1000) ro_rec_data <= w_rec_data; else ro_rec_data <= { 
   w_rec_data[3:0],ro_rec_data[7:4]}; end always@(posedge w_rxc_bufr) begin r_rec_valid <= w_rec_valid; end always@(posedge w_rxc_bufr) begin if(!w_rec_valid && r_rec_valid) ro_rec_end <= 'd1; else ro_rec_end <= 'd0; end always@(posedge w_rxc_bufr) begin if(w_rec_valid == 'd0) begin ro_speed <= w_rec_data[2:1]; ro_link <= w_rec_data[0]; end else begin ro_speed <= ro_speed; ro_link <= ro_link ; end end /*---------rgmii send--------*/ always@(posedge w_rxc_bufr) begin ri_send_data <= i_send_data; ri_send_valid <= i_send_valid; end always@(posedge w_rxc_bufr) begin if(i_send_valid) r_tx_cnt_10_100 <= r_tx_cnt_10_100 + 1; else r_tx_cnt_10_100 <= 'd0; end genvar txd_i; generate for(txd_i = 0 ;txd_i < 4 ; txd_i = txd_i + 1) begin assign w_send_d1[txd_i] = i_speed1000 ? i_send_data[txd_i] : r_tx_cnt_10_100 == 0 ? i_send_data[txd_i] : ri_send_data[txd_i + 4]; assign w_send_d2[txd_i] = i_speed1000 ? i_send_data[txd_i + 4] : r_tx_cnt_10_100 == 0 ? i_send_data[txd_i] : ri_send_data[txd_i + 4]; ODDR #( .DDR_CLK_EDGE ("OPPOSITE_EDGE" ), .INIT (1'b0 ), .SRTYPE ("SYNC" ) ) ODDR_u ( .Q (o_txd[txd_i] ), .C (w_txc ), .CE (1 ), .D1 (w_send_d1[txd_i] ), .D2 (w_send_d2[txd_i] ), .R (0 ), .S (0 ) ); end endgenerate assign w_send_valid = i_speed1000 ? i_send_valid : i_send_valid | ri_send_valid; ODDR#( .DDR_CLK_EDGE ("OPPOSITE_EDGE" ), .INIT (1'b0 ), .SRTYPE ("SYNC" ) ) ODDR_uu0 ( .Q (o_tx_ctl ), .C (w_txc ), .CE (1 ), .D1 (w_send_valid ), .D2 (w_send_valid ), .R (0 ), .S (0 ) ); endmodule 

跨时钟传输模块

module RGMII_RAM( input i_udp_stack_clk , input [7 :0] i_GMII_data , input i_GMII_valid , output [7 :0] o_GMII_data , output o_GMII_valid , input i_rxc , input i_speed1000 , output [7 :0] o_send_data , output o_send_valid , input [7 :0] i_rec_data , input i_rec_valid , input i_rec_end ); /*function/ /*parameter*/ /*port/ /*mechine*/ /*reg*/ reg [10:0] r_ram_addr_A=0 ; reg [10:0] r_rec_len =0 ; reg r_ram_en_B =0 ; reg r_ram_en_B_1d=0 ; reg r_ram_en_B_2d=0 ; reg [10:0] r_ram_addr_B=0 ; reg r_fifo_wr_en=0 ; reg r_fifo_rd_en=0 ; reg ri_rec_en =0 ; reg r_read_run =0 ; reg [10:0] r_read_cnt =0 ; reg [7 :0] ro_GMII_data =0 ; reg ro_GMII_valid=0 ; reg [10:0] r_tx_ram_addr_A=10 ; reg [10:0] r_tx_len=10 ; reg r_tx_fifo_wren=0 ; reg ri_GMII_valid=0 ; reg r_tx_ram_en_B=0 ; reg [10:0] r_tx_ram_addr_B=0 ; reg r_tx_fifo_rden=0 ; reg r_tx_read_run=0 ; reg [10:0] r_tx_cnt =0 ; reg [7 :0] ro_send_data =0 ; reg ro_send_valid=0 ; reg w_rxc=0 ; reg ri_rec_end=0 ; reg ro_send_valid_1d=0 ; /*wire/ wire [7 :0] w_ram_dout_B ; wire [10:0] w_fifo_dout ; wire w_fifo_full ; wire w_fifo_empty ; wire [7 :0] w_tx_ram_dout ; wire [10:0] w_tx_fifo_dout ; wire w_tx_fifo_full ; wire w_tx_fifo_empty ; /*component*/ RAM_8_1600 RAM_8_1600_U0 ( .clka (i_rxc ), // input wire clka .ena (i_rec_valid ), // input wire ena .wea (i_rec_valid ), // input wire [0 : 0] wea .addra (r_ram_addr_A ), // input wire [10 : 0] addra .dina (i_rec_data ), // input wire [7 : 0] dina .douta ( ), // output wire [7 : 0] douta .clkb (i_udp_stack_clk), // input wire clkb .enb (r_ram_en_B ), // input wire enb .web (0 ), // input wire [0 : 0] web .addrb (r_ram_addr_B ), // input wire [10 : 0] addrb .dinb (0 ), // input wire [7 : 0] dinb .doutb (w_ram_dout_B ) // output wire [7 : 0] doutb ); FIFO_ASYNC_11_64 FIFO_ASYNC_11_64_u0 ( .wr_clk (i_rxc ), // input wire wr_clk .rd_clk (i_udp_stack_clk), // input wire rd_clk .din (r_rec_len ), // input wire [10 : 0] din .wr_en (r_fifo_wr_en ), // input wire wr_en .rd_en (r_fifo_rd_en ), // input wire rd_en .dout (w_fifo_dout ), // output wire [10 : 0] dout .full (w_fifo_full ), // output wire full .empty (w_fifo_empty ) // output wire empty ); RAM_8_1600 RAM_8_1600_tx_U0 ( .clka (i_udp_stack_clk ), // input wire clka .ena (i_GMII_valid ), // input wire ena .wea (i_GMII_valid ), // input wire [0 : 0] wea .addra (r_tx_ram_addr_A ), // input wire [10 : 0] addra .dina (i_GMII_data ), // input wire [7 : 0] dina .douta (), // output wire [7 : 0] douta .clkb (i_rxc ), // input wire clkb .enb (r_tx_ram_en_B ), // input wire enb .web (0 ), // input wire [0 : 0] web .addrb (r_tx_ram_addr_B ), // input wire [10 : 0] addrb .dinb (0 ), // input wire [7 : 0] dinb .doutb (w_tx_ram_dout ) // output wire [7 : 0] doutb ); FIFO_ASYNC_11_64 FIFO_ASYNC_11_64_tx_u0 ( .wr_clk (i_udp_stack_clk ), // input wire wr_clk .rd_clk (i_rxc ), // input wire rd_clk .din (r_tx_len ), // input wire [10 : 0] din .wr_en (r_tx_fifo_wren ), // input wire wr_en .rd_en (r_tx_fifo_rden ), // input wire rd_en .dout (w_tx_fifo_dout ), // output wire [10 : 0] dout .full (w_tx_fifo_full ), // output wire full .empty (w_tx_fifo_empty ) // output wire empty ); /*assign/ assign o_GMII_data = ro_GMII_data ; assign o_GMII_valid = ro_GMII_valid ; assign o_send_data = ro_send_data ; assign o_send_valid = ro_send_valid_1d ; /*always/ /*--------rgmii--------*/ always@(posedge i_rxc) begin if(i_rec_valid) r_ram_addr_A <= r_ram_addr_A + 1; else if(i_rec_end) r_ram_addr_A <= 'd0; else r_ram_addr_A <= r_ram_addr_A; end always@(posedge i_rxc) begin if(i_rec_valid) r_rec_len <= r_ram_addr_A + 1; else r_rec_len <= r_rec_len; end always@(posedge i_rxc) begin ri_rec_end <= i_rec_end; end always@(posedge i_rxc) begin if(i_rec_end & !ri_rec_end) r_fifo_wr_en <= 'd1; else r_fifo_wr_en <= 'd0; end always@(posedge i_rxc) begin if(r_tx_cnt == w_tx_fifo_dout) r_tx_read_run <= 'd0; else if(!w_tx_fifo_empty) r_tx_read_run <= 'd1; else r_tx_read_run <= r_tx_read_run; end always@(posedge i_rxc) begin if(!r_tx_read_run && !w_tx_fifo_empty) r_tx_fifo_rden <= 'd1; else r_tx_fifo_rden <= 'd0; end always@(posedge i_rxc) begin end always@(posedge i_rxc) begin if(i_speed1000) if(r_tx_cnt == w_tx_fifo_dout) r_tx_ram_en_B <= 'd0; else if(r_tx_fifo_rden) r_tx_ram_en_B <= 'd1; else r_tx_ram_en_B <= r_tx_ram_en_B; else if(r_tx_ram_en_B) r_tx_ram_en_B <= 'd0; else if(r_tx_fifo_rden || r_tx_read_run) r_tx_ram_en_B <= 'd1; else r_tx_ram_en_B <= 'd0; end always@(posedge i_rxc) begin if(r_tx_ram_en_B) r_tx_ram_addr_B <= r_tx_ram_addr_B + 1; else r_tx_ram_addr_B <= 'd0; end always@(posedge i_rxc) begin if(r_tx_ram_en_B) r_tx_cnt <= r_tx_cnt + 1; else r_tx_cnt <= 'd0; end always@(posedge i_rxc) begin ro_send_data <= w_tx_ram_dout; ro_send_valid <= r_tx_ram_en_B; end /*--------udp--------*/ always@(posedge i_udp_stack_clk) begin if(r_read_cnt == w_fifo_dout) r_read_run <= 'd0; else if(!w_fifo_empty) r_read_run <= 'd1; else r_read_run <= r_read_run; end always@(posedge i_udp_stack_clk) begin if(!r_read_run && !w_fifo_empty) r_fifo_rd_en <= 'd1; else r_fifo_rd_en <= 'd0; end always@(posedge i_udp_stack_clk) begin if(r_read_cnt == w_fifo_dout) r_read_cnt <= 'd0; else if(r_ram_en_B) r_read_cnt <= r_read_cnt + 1; else r_read_cnt <= r_read_cnt; end always@(posedge i_udp_stack_clk) begin if(r_read_cnt == w_fifo_dout) r_ram_en_B <= 'd0; else if(r_fifo_rd_en) r_ram_en_B <= 'd1; else r_ram_en_B <= r_ram_en_B; end always@(posedge i_udp_stack_clk) begin if(r_ram_en_B) r_ram_addr_B <= r_ram_addr_B + 1; else r_ram_addr_B <= 'd0; end always@(posedge i_udp_stack_clk) begin r_ram_en_B_1d <= r_ram_en_B; ro_GMII_data <= w_ram_dout_B; r_ram_en_B_2d <= r_ram_en_B_1d; end always@(posedge i_udp_stack_clk) begin if(!r_ram_en_B & r_ram_en_B_1d) ro_GMII_valid <= 'd0; else if(r_ram_en_B_1d & !r_ram_en_B_2d) ro_GMII_valid <= 'd1; else ro_GMII_valid <= ro_GMII_valid; end always@(posedge i_udp_stack_clk) begin if(i_GMII_valid) r_tx_ram_addr_A <= r_tx_ram_addr_A + 1; else r_tx_ram_addr_A <= 'd0; end always@(posedge i_udp_stack_clk) begin if(i_GMII_valid) r_tx_len <= r_tx_ram_addr_A; else r_tx_len <= r_tx_len; end always@(posedge i_udp_stack_clk) begin ri_GMII_valid <= i_GMII_valid; ro_send_valid_1d <= ro_send_valid; end always@(posedge i_udp_stack_clk) begin if(!i_GMII_valid & ri_GMII_valid) r_tx_fifo_wren <= 'd1; else r_tx_fifo_wren <= 'd0; end endmodule 

有问题可以加企鹅群 交流

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/133405.html

(0)
上一篇 2025-07-23 17:20
下一篇 2025-07-23 17:26

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信