Xilinx的IP核gig_ethernet_pcs_pma例化案例
1G/2.5G Ethernet PCS/PMA or SGMII v16.1
废话不BB,直接用。手册看完,一礼拜没理解透。理解出现偏差。最后实验出真知。
IP核例化
gig_ethernet_pcs_pma_0 gig_ethernet_pcs_pma_0 (
.gtrefclk_p (gtrefclk1_p),
.gtrefclk_n (gtrefclk1_n),
.gtrefclk_out (),
.gtrefclk_bufg_out (),
.txn (sfp_tx_n),
.txp (sfp_tx_p),
.rxn (sfp_rx_n),
.rxp (sfp_rx_p),
.independent_clock_bufg (clk_200M),
.userclk_out (),
.userclk2_out (gmii_clk),
.rxuserclk_out (),
.rxuserclk2_out (),
.resetdone (),
.pma_reset_out (),
.mmcm_locked_out (),
.sgmii_clk_r (),
.sgmii_clk_f (),
.sgmii_clk_en (sgmii_clk_en),
.gmii_txd (gmii_txd ),
.gmii_tx_en (gmii_tx_en ),
.gmii_tx_er ('b0),
.gmii_rxd (gmii_rxd ),
.gmii_rx_dv (gmii_rx_dv ),
.gmii_rx_er ( ),
.gmii_isolate ( ),
.configuration_vector (5'b10000 ),
.an_interrupt (an_interrupt),
.an_adv_config_vector (16'h8821 ),
.an_restart_config ('b0 ),
.speed_is_10_100 (speed_is_10_100),
.speed_is_100 (speed_is_100 ),
.status_vector ( ),
.reset (!rst_n ),
.signal_detect (1'b1 ),
.gt0_pll0outclk_out (),
.gt0_pll0outrefclk_out (),
.gt0_pll1outclk_out (),
.gt0_pll1outrefclk_out (),
.gt0_pll0lock_out (),
.gt0_pll0refclklost_out ()
);
计数开头的55,判断1000M或者100M
对端是强制端。比如设置电脑端为,100M半双工。即使an_adv_config_vector设置1000M,底层自协商就能连接上。自协商结束,an_interrupt=1’b1;但status_vector[11:10]的值完全不反应实际的速率。还是010,千兆的值。实际是百兆。能正常接受数据,gmii_clk一直为125M。所以计数前导码55,1000M,就是7个55,100M就是70个55.简单区分百兆和千兆。再去配置speed_is_100 ,speed_is_10_100 。这样sgmii_clk_en就是我想要的频率了。如果speed_is_100 = 0 ,speed_is_10_100 = 0;sgmii_clk_en常1;如果speed_is_100 = 1 ,speed_is_10_100 = 1;sgmii_clk_en是12.5M脉冲;详细见手册。 这里做了几次实验。如果speed_is_100 = 0 ,speed_is_10_100 = 0;写死,百兆千兆都能正常接受数据。如果speed_is_100 = 1 ,speed_is_10_100 = 1;写死,千兆就无法正常接受数据了,表现为,gmii_rxd还是百兆时钟切换数据。
reg gmii_rx_dv_r ;
always @(posedge gmii_clk) gmii_rx_dv_r <= gmii_rx_dv ;
reg judge_flag ;
always @(posedge gmii_clk)
if (!rst_n) judge_flag <= 'b0 ;
else if (gmii_rx_dv && !gmii_rx_dv_r) judge_flag <= 'b1 ;
else if (judge_flag && gmii_rxd==8'hd5) judge_flag <= 'b0 ;
reg [7:0] cnt_55 ;
always @(posedge gmii_clk)
if (!rst_n) cnt_55 <= 'd0 ;
else if (judge_flag && gmii_rxd==8'h55) cnt_55 <= cnt_55 + 'd1 ;
else cnt_55 <= 'd0 ;
always @(posedge gmii_clk)
if (!rst_n) flag_1000M <= 'b0 ;
else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 < 'd10) flag_1000M <= 'b1 ;
else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 > 'd10) flag_1000M <= 'b0 ;
always @(posedge gmii_clk)
if (!rst_n) flag_100M <= 'b0 ;
else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 > 'd10) flag_100M <= 'b1 ;
else if (judge_flag && gmii_rxd==8'hd5 && cnt_55 < 'd10) flag_100M <= 'b0 ;
reg speed_is_100 ;
reg speed_is_10_100 ;
always @(posedge gmii_clk)
if (!rst_n) begin speed_is_100 <= 1'b0 ; speed_is_10_100 <= 1'b0 ; end
else if (flag_1000M) begin speed_is_100 <= 1'b0 ; speed_is_10_100 <= 1'b0 ; end
else if (flag_100M) begin speed_is_100 <= 1'b1 ; speed_is_10_100 <= 1'b1 ; end
以太网数据异步缓存FIFO
跨始终域问题。千兆都是125M.没有问题。百兆就要设计一下了。接受数据,等接受完成后,再读。发送数据简单了。
wire eth_clk = flag_1000M ? gmii_clk : sgmii_clk_en ;
fifo_gig_ethernet fifo_gig_ethernet_T (
.wr_clk (gmii_clk ),
.din (eth_tx_data ),
.wr_en (eth_tx_en ),
.rd_clk (eth_clk ),
.rd_en ('b1 ),
.dout (gmii_txd ),
.valid (gmii_tx_en ),
.full ( ),
.empty ( )
);
wire empty_R ;
reg rd_en_R ;
always @(posedge gmii_clk)
if (!rst_n) rd_en_R <= 1'b0 ;
else if (gmii_rx_dv_r && !gmii_rx_dv) rd_en_R <= 1'b1 ;
else if (empty_R) rd_en_R <= 1'b0 ;
fifo_gig_ethernet fifo_gig_ethernet_R (
.wr_clk (eth_clk ),
.din (gmii_rxd ),
.wr_en (gmii_rx_dv ),
.rd_clk (gmii_clk ),
.rd_en (rd_en_R ),
.dout (eth_rx_data ),
.valid (eth_rx_vaild ),
.full ( ),
.empty (empty_R )
);
总结
这里就发现坑的地方了。明明an_adv_config_vector设置的千兆。却能链接上。接受发送数据都没有问题。底层自协商完成了,已经是百兆的工作模式了。这和我配置an_adv_config_vector没有半点关系。之前花了好长时间,想去得到协商结果,再去配置an_adv_config_vector,还得an_restart_config上升沿重启。实际半毛钱关系都没。 我的理解是an_adv_config_vector是我希望的最佳工作模式。如果对端也是自协商端,就能接受到我的FLP,得到这个值,我也能在status_vector里得到对方的能力值。如果对方强制端,不发FLP,我就得不到参数,status_vector的值就是无意义的。但是底层还是通过NLP得知对方是100M,就自协商100M建立了链接。an_interrupt 置 1 了;而我就没法得到速度参数。
如图,接受数据 百兆 千兆
如图,发送数据 百兆
千兆
|