From 729bf794272450d9ff465cda8a5ee7edededd98a Mon Sep 17 00:00:00 2001 From: Alex Forencich Date: Thu, 13 Nov 2025 21:27:03 -0800 Subject: [PATCH] eth: Move link speed detection logic from MAC wrapper to PHY interface Signed-off-by: Alex Forencich --- src/eth/rtl/taxi_eth_mac_1g_gmii.sv | 73 ++------------------------- src/eth/rtl/taxi_eth_mac_1g_rgmii.sv | 73 ++------------------------- src/eth/rtl/taxi_gmii_phy_if.sv | 74 +++++++++++++++++++++++++--- src/eth/rtl/taxi_rgmii_phy_if.sv | 74 +++++++++++++++++++++++++--- 4 files changed, 142 insertions(+), 152 deletions(-) diff --git a/src/eth/rtl/taxi_eth_mac_1g_gmii.sv b/src/eth/rtl/taxi_eth_mac_1g_gmii.sv index a2441b6..5cbc30a 100644 --- a/src/eth/rtl/taxi_eth_mac_1g_gmii.sv +++ b/src/eth/rtl/taxi_eth_mac_1g_gmii.sv @@ -197,9 +197,6 @@ module taxi_eth_mac_1g_gmii # input wire logic cfg_rx_pfc_en = 1'b0 ); -logic [1:0] link_speed_reg = 2'b10; -logic mii_select_reg = 1'b0; - wire tx_mii_select_sync; taxi_sync_signal #( @@ -208,7 +205,7 @@ taxi_sync_signal #( ) tx_mii_select_sync_inst ( .clk(tx_clk), - .in(mii_select_reg), + .in(!link_speed[1]), .out(tx_mii_select_sync) ); @@ -220,74 +217,10 @@ taxi_sync_signal #( ) rx_mii_select_sync_inst ( .clk(rx_clk), - .in(mii_select_reg), + .in(!link_speed[1]), .out(rx_mii_select_sync) ); -// PHY speed detection -logic [2:0] rx_prescale = 3'd0; - -always_ff @(posedge rx_clk) begin - rx_prescale <= rx_prescale + 3'd1; -end - -wire rx_prescale_sync; - -taxi_sync_signal #( - .WIDTH(1), - .N(2) -) -rx_prescale_sync_inst ( - .clk(gtx_clk), - .in(rx_prescale[2]), - .out(rx_prescale_sync) -); - -logic [6:0] rx_speed_count_1 = 0; -logic [1:0] rx_speed_count_2 = 0; -logic rx_prescale_sync_last_reg = 1'b0; - -always_ff @(posedge gtx_clk) begin - rx_prescale_sync_last_reg <= rx_prescale_sync; - rx_speed_count_1 <= rx_speed_count_1 + 1; - - if (rx_prescale_sync ^ rx_prescale_sync_last_reg) begin - rx_speed_count_2 <= rx_speed_count_2 + 1; - end - - if (&rx_speed_count_1) begin - // reference count overflow - 10M - rx_speed_count_1 <= 0; - rx_speed_count_2 <= 0; - link_speed_reg <= 2'b00; - mii_select_reg <= 1'b1; - end - - if (&rx_speed_count_2) begin - // prescaled count overflow - 100M or 1000M - rx_speed_count_1 <= 0; - rx_speed_count_2 <= 0; - if (rx_speed_count_1[6:5] != 0) begin - // large reference count - 100M - link_speed_reg <= 2'b01; - mii_select_reg <= 1'b1; - end else begin - // small reference count - 1000M - link_speed_reg <= 2'b10; - mii_select_reg <= 1'b0; - end - end - - if (gtx_rst) begin - rx_speed_count_1 <= 0; - rx_speed_count_2 <= 0; - link_speed_reg <= 2'b10; - mii_select_reg <= 1'b0; - end -end - -assign link_speed = link_speed_reg; - wire [7:0] mac_gmii_rxd; wire mac_gmii_rx_dv; wire mac_gmii_rx_er; @@ -331,7 +264,7 @@ gmii_phy_if_inst ( .phy_gmii_tx_en(gmii_tx_en), .phy_gmii_tx_er(gmii_tx_er), - .mii_select(mii_select_reg) + .link_speed(link_speed) ); taxi_eth_mac_1g #( diff --git a/src/eth/rtl/taxi_eth_mac_1g_rgmii.sv b/src/eth/rtl/taxi_eth_mac_1g_rgmii.sv index 52919d5..45d9335 100644 --- a/src/eth/rtl/taxi_eth_mac_1g_rgmii.sv +++ b/src/eth/rtl/taxi_eth_mac_1g_rgmii.sv @@ -196,9 +196,6 @@ module taxi_eth_mac_1g_rgmii # input wire logic cfg_rx_pfc_en = 1'b0 ); -logic [1:0] link_speed_reg = 2'b10; -logic mii_select_reg = 1'b0; - wire tx_mii_select_sync; taxi_sync_signal #( @@ -207,7 +204,7 @@ taxi_sync_signal #( ) tx_mii_select_sync_inst ( .clk(tx_clk), - .in(mii_select_reg), + .in(!link_speed[1]), .out(tx_mii_select_sync) ); @@ -219,74 +216,10 @@ taxi_sync_signal #( ) rx_mii_select_sync_inst ( .clk(rx_clk), - .in(mii_select_reg), + .in(!link_speed[1]), .out(rx_mii_select_sync) ); -// PHY speed detection -logic [2:0] rx_prescale = 3'd0; - -always_ff @(posedge rx_clk) begin - rx_prescale <= rx_prescale + 3'd1; -end - -wire rx_prescale_sync; - -taxi_sync_signal #( - .WIDTH(1), - .N(2) -) -rx_prescale_sync_inst ( - .clk(gtx_clk), - .in(rx_prescale[2]), - .out(rx_prescale_sync) -); - -logic [6:0] rx_speed_count_1 = 0; -logic [1:0] rx_speed_count_2 = 0; -logic rx_prescale_sync_last_reg = 1'b0; - -always_ff @(posedge gtx_clk) begin - rx_prescale_sync_last_reg <= rx_prescale_sync; - rx_speed_count_1 <= rx_speed_count_1 + 1; - - if (rx_prescale_sync ^ rx_prescale_sync_last_reg) begin - rx_speed_count_2 <= rx_speed_count_2 + 1; - end - - if (&rx_speed_count_1) begin - // reference count overflow - 10M - rx_speed_count_1 <= 0; - rx_speed_count_2 <= 0; - link_speed_reg <= 2'b00; - mii_select_reg <= 1'b1; - end - - if (&rx_speed_count_2) begin - // prescaled count overflow - 100M or 1000M - rx_speed_count_1 <= 0; - rx_speed_count_2 <= 0; - if (rx_speed_count_1[6:5] != 0) begin - // large reference count - 100M - link_speed_reg <= 2'b01; - mii_select_reg <= 1'b1; - end else begin - // small reference count - 1000M - link_speed_reg <= 2'b10; - mii_select_reg <= 1'b0; - end - end - - if (gtx_rst) begin - rx_speed_count_1 <= 0; - rx_speed_count_2 <= 0; - link_speed_reg <= 2'b10; - mii_select_reg <= 1'b0; - end -end - -assign link_speed = link_speed_reg; - wire [7:0] mac_gmii_rxd; wire mac_gmii_rx_dv; wire mac_gmii_rx_er; @@ -331,7 +264,7 @@ rgmii_phy_if_inst ( .phy_rgmii_txd(rgmii_txd), .phy_rgmii_tx_ctl(rgmii_tx_ctl), - .speed(link_speed) + .link_speed(link_speed) ); taxi_eth_mac_1g #( diff --git a/src/eth/rtl/taxi_gmii_phy_if.sv b/src/eth/rtl/taxi_gmii_phy_if.sv index c9cc9ce..592e89c 100644 --- a/src/eth/rtl/taxi_gmii_phy_if.sv +++ b/src/eth/rtl/taxi_gmii_phy_if.sv @@ -56,11 +56,73 @@ module taxi_gmii_phy_if # output wire logic phy_gmii_tx_er, /* - * Control + * Status */ - input wire logic mii_select + output wire logic [1:0] link_speed ); +// PHY speed detection +logic [2:0] rx_prescale = 3'd0; + +always_ff @(posedge mac_gmii_rx_clk) begin + rx_prescale <= rx_prescale + 3'd1; +end + +wire rx_prescale_sync; + +taxi_sync_signal #( + .WIDTH(1), + .N(2) +) +rx_prescale_sync_inst ( + .clk(gtx_clk), + .in(rx_prescale[2]), + .out(rx_prescale_sync) +); + +logic [6:0] rx_speed_count_1 = '0; +logic [1:0] rx_speed_count_2 = '0; +logic rx_prescale_sync_last_reg = 1'b0; + +logic [1:0] link_speed_reg = '0; + +assign link_speed = link_speed_reg; + +always_ff @(posedge gtx_clk) begin + rx_prescale_sync_last_reg <= rx_prescale_sync; + rx_speed_count_1 <= rx_speed_count_1 + 1; + + if (rx_prescale_sync ^ rx_prescale_sync_last_reg) begin + rx_speed_count_2 <= rx_speed_count_2 + 1; + end + + if (&rx_speed_count_1) begin + // reference count overflow - 10M + rx_speed_count_1 <= '0; + rx_speed_count_2 <= '0; + link_speed_reg <= 2'b00; + end + + if (&rx_speed_count_2) begin + // prescaled count overflow - 100M or 1000M + rx_speed_count_1 <= '0; + rx_speed_count_2 <= '0; + if (rx_speed_count_1[6:5] != 0) begin + // large reference count - 100M + link_speed_reg <= 2'b01; + end else begin + // small reference count - 1000M + link_speed_reg <= 2'b10; + end + end + + if (gtx_rst) begin + rx_speed_count_1 <= '0; + rx_speed_count_2 <= '0; + link_speed_reg <= 2'b10; + end +end + taxi_ssio_sdr_in #( .SIM(SIM), .VENDOR(VENDOR), @@ -92,16 +154,16 @@ if (!SIM && VENDOR == "XILINX") begin BUFGMUX gmii_bufgmux_inst ( - .I0(gtx_clk), - .I1(phy_mii_tx_clk), - .S(mii_select), + .I0(phy_mii_tx_clk), + .I1(gtx_clk), + .S(link_speed_reg[1]), .O(mac_gmii_tx_clk) ); end else begin // generic/simulation implementation (no vendor primitives) - assign mac_gmii_tx_clk = mii_select ? phy_mii_tx_clk : gtx_clk; + assign mac_gmii_tx_clk = link_speed_reg[1] ? gtx_clk : phy_mii_tx_clk; end diff --git a/src/eth/rtl/taxi_rgmii_phy_if.sv b/src/eth/rtl/taxi_rgmii_phy_if.sv index 4581495..ef048a1 100644 --- a/src/eth/rtl/taxi_rgmii_phy_if.sv +++ b/src/eth/rtl/taxi_rgmii_phy_if.sv @@ -57,11 +57,73 @@ module taxi_rgmii_phy_if # output wire logic phy_rgmii_tx_ctl, /* - * Control + * Status */ - input wire logic [1:0] speed + output wire logic [1:0] link_speed ); +// PHY speed detection +logic [2:0] rx_prescale = 3'd0; + +always_ff @(posedge mac_gmii_rx_clk) begin + rx_prescale <= rx_prescale + 3'd1; +end + +wire rx_prescale_sync; + +taxi_sync_signal #( + .WIDTH(1), + .N(2) +) +rx_prescale_sync_inst ( + .clk(gtx_clk), + .in(rx_prescale[2]), + .out(rx_prescale_sync) +); + +logic [6:0] rx_speed_count_1 = '0; +logic [1:0] rx_speed_count_2 = '0; +logic rx_prescale_sync_last_reg = 1'b0; + +logic [1:0] link_speed_reg = '0; + +assign link_speed = link_speed_reg; + +always_ff @(posedge gtx_clk) begin + rx_prescale_sync_last_reg <= rx_prescale_sync; + rx_speed_count_1 <= rx_speed_count_1 + 1; + + if (rx_prescale_sync ^ rx_prescale_sync_last_reg) begin + rx_speed_count_2 <= rx_speed_count_2 + 1; + end + + if (&rx_speed_count_1) begin + // reference count overflow - 10M + rx_speed_count_1 <= '0; + rx_speed_count_2 <= '0; + link_speed_reg <= 2'b00; + end + + if (&rx_speed_count_2) begin + // prescaled count overflow - 100M or 1000M + rx_speed_count_1 <= '0; + rx_speed_count_2 <= '0; + if (rx_speed_count_1[6:5] != 0) begin + // large reference count - 100M + link_speed_reg <= 2'b01; + end else begin + // small reference count - 1000M + link_speed_reg <= 2'b10; + end + end + + if (gtx_rst) begin + rx_speed_count_1 <= '0; + rx_speed_count_2 <= '0; + link_speed_reg <= 2'b10; + end +end + // receive wire rgmii_rx_ctl_1; @@ -95,7 +157,7 @@ logic [5:0] count_reg = 6'd0, count_next; always_ff @(posedge gtx_clk) begin rgmii_tx_clk_1_reg <= rgmii_tx_clk_2_reg; - if (speed == 2'b00) begin + if (link_speed_reg == 2'b00) begin // 10M count_reg <= count_reg + 1; rgmii_tx_clk_en_reg <= 1'b0; @@ -107,7 +169,7 @@ always_ff @(posedge gtx_clk) begin rgmii_tx_clk_en_reg <= 1'b1; count_reg <= 0; end - end else if (speed == 2'b01) begin + end else if (link_speed_reg == 2'b01) begin // 100M count_reg <= count_reg + 1; rgmii_tx_clk_en_reg <= 1'b0; @@ -142,7 +204,7 @@ logic rgmii_tx_ctl_2; logic gmii_clk_en; always_comb begin - if (speed == 2'b00) begin + if (link_speed_reg == 2'b00) begin // 10M rgmii_txd_1 = mac_gmii_txd[3:0]; rgmii_txd_2 = mac_gmii_txd[3:0]; @@ -154,7 +216,7 @@ always_comb begin rgmii_tx_ctl_2 = mac_gmii_tx_en; end gmii_clk_en = rgmii_tx_clk_en_reg; - end else if (speed == 2'b01) begin + end else if (link_speed_reg == 2'b01) begin // 100M rgmii_txd_1 = mac_gmii_txd[3:0]; rgmii_txd_2 = mac_gmii_txd[3:0];