From 5723ec1a34181f1cfef9b8e870ab2e9a0362487c Mon Sep 17 00:00:00 2001 From: mindchasers Date: Wed, 1 May 2019 18:16:45 -0400 Subject: initial commit, all basic functions work on Darsena V02 --- source/switch.v | 480 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100644 source/switch.v (limited to 'source/switch.v') diff --git a/source/switch.v b/source/switch.v new file mode 100644 index 0000000..f929b68 --- /dev/null +++ b/source/switch.v @@ -0,0 +1,480 @@ +/* + * switch.v + * + * Copyright (C) 2018, 2019 Mind Chasers Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * function: switch packet paths from RX to TX + * + */ + +`timescale 1ns /10ps + +module switch( + input rstn, + input clk, + + // PHY status + input [3:0] phy_up, + input [3:0] mode_100Mbit, + + // FIFO input data from RX FIFOs + input [8:0] rx_d_01, + input [8:0] rx_d_02, + input [8:0] rx_d_03, + input [8:0] rx_d_10, + input [8:0] rx_d_12, + input [8:0] rx_d_13, + input [8:0] rx_d_20, + input [8:0] rx_d_21, + input [8:0] rx_d_23, + input [8:0] rx_d_2u, + input [8:0] rx_d_30, + input [8:0] rx_d_31, + input [8:0] rx_d_32, + input [8:0] rx_d_u2, + + // RX FIFO read enables + output reg rx_fifo_re_01, rx_fifo_re_02, rx_fifo_re_03, + output reg rx_fifo_re_10, rx_fifo_re_12, rx_fifo_re_13, + output reg rx_fifo_re_20, rx_fifo_re_21, rx_fifo_re_23, rx_fifo_re_2u, + output reg rx_fifo_re_30, rx_fifo_re_31, rx_fifo_re_32, + output reg rx_fifo_re_u2, + + // RX FIFO Empty flags + input rx_fifo_empty_01, rx_fifo_empty_02, rx_fifo_empty_03, + input rx_fifo_empty_10, rx_fifo_empty_12, rx_fifo_empty_13, + input rx_fifo_empty_20, rx_fifo_empty_21, rx_fifo_empty_23, rx_fifo_empty_2u, + input rx_fifo_empty_30, rx_fifo_empty_31, rx_fifo_empty_32, + input rx_fifo_empty_u2, + + // TX FIFO output from internal muxes + output reg [8:0] tx_d0, + output reg [8:0] tx_d1, + output reg [8:0] tx_d2, + output reg [8:0] tx_d3, + output [8:0] tx_du, + + // TX FIFO read enable inputs (need to route to RX output FIFOs) + input [3:0] tx_fifo_re, + output reg tx_fifo_we_u, + + // TX FIFO Empty Flags (need to route to RX output FIFOs) + output reg [3:0] tx_fifo_empty, + + // TX modes for the PHYs and uc + output reg [1:0] tx_mode0, + output reg [1:0] tx_mode1, + output reg [1:0] tx_mode2, + output reg [1:0] tx_mode3, + output reg tx_modeu, + + // TX state machine done flag + input [3:0] tx_f, + + // TX custom packet + input tx_metrics +); + +reg [2:0] tx0_src_sel; +reg [2:0] tx1_src_sel; +reg [2:0] tx2_src_sel; +reg [2:0] tx3_src_sel; + +// IPG for Port 0 +wire ipg_met; +reg [6:0] ipg_cnt; +reg [3:0] fr_100mbit_cnt; + +reg i_tx_fifo_we_u; + +`include "ethernet_params.v" +`include "sgmii_params.v" + +localparam SEL_PHY0 = 3'b000, + SEL_PHY1 = 3'b001, + SEL_PHY2 = 3'b010, + SEL_PHY3 = 3'b011, + SEL_UC = 3'b111; + + +assign ipg_met = ipg_cnt >= IPG ? 1'b1 : 1'b0; + +/* free running 100Mbit counter */ +always @(posedge clk, negedge rstn) +begin + if ( !rstn ) + fr_100mbit_cnt <= 4'd0; + else if ( fr_100mbit_cnt == 4'd9 ) + fr_100mbit_cnt <= 4'd0; + else + fr_100mbit_cnt <= fr_100mbit_cnt + 1; +end + +/* IPG counter */ +always @(posedge clk, negedge rstn) +begin + if ( !rstn ) + ipg_cnt <= 7'd0; + else if ( tx_f[0] && tx_mode0 >= TX_MODE_XMT_PKT ) + ipg_cnt <= 7'd0; + else if ( mode_100Mbit[0] && fr_100mbit_cnt == 4'd9 && !ipg_met ) + ipg_cnt <= ipg_cnt + 1; + else if ( !mode_100Mbit[0] && !ipg_met ) + ipg_cnt <= ipg_cnt + 1; +end + + +// TX0 Switch Logic +// Possible sources: 1, 2 +always @(posedge clk, negedge rstn) + if ( !rstn ) + begin + tx_mode0 <= TX_MODE_AN; + tx0_src_sel <= SEL_PHY1; + end + else if ( tx_f[0] ) + case( tx_mode0 ) + TX_MODE_AN: + if ( phy_up[0] ) + tx_mode0 <= TX_MODE_IDLE; + TX_MODE_IDLE: + if ( !phy_up[0] ) + tx_mode0 <= TX_MODE_AN; + else if ( !ipg_met ) + tx_mode0 <= TX_MODE_IDLE; + else if (tx0_src_sel==SEL_PHY1 && !rx_fifo_empty_20 ) + begin + tx_mode0 <= TX_MODE_XMT_PKT; + tx0_src_sel <= SEL_PHY2; + end + else if (!rx_fifo_empty_10 ) + begin + tx_mode0 <= TX_MODE_XMT_PKT; + tx0_src_sel <= SEL_PHY1; + end + else if (!rx_fifo_empty_20 ) + begin + tx_mode0 <= TX_MODE_XMT_PKT; + tx0_src_sel <= SEL_PHY2; + end + TX_MODE_XMT_PKT: + if ( !phy_up[0] ) + tx_mode0 <= TX_MODE_AN; + else + tx_mode0 <= TX_MODE_IDLE; + default: tx_mode0 <= TX_MODE_IDLE; + endcase + +// TX0 data mux +always @(*) begin + case(tx0_src_sel) + SEL_PHY0: tx_d0 = 9'h000; + SEL_PHY1: tx_d0 = rx_d_10; + SEL_PHY2: tx_d0 = rx_d_20; + SEL_UC: tx_d0 = 9'h000; + default: tx_d0 = 9'h000; + endcase +end + +// TX0 FIFO read enable +always @(*) begin + rx_fifo_re_10 = 1'b0; + rx_fifo_re_20 = 1'b0; + rx_fifo_re_30 = 1'b0; + case(tx0_src_sel) + SEL_PHY1: rx_fifo_re_10 = tx_fifo_re[0]; + SEL_PHY2: rx_fifo_re_20 = tx_fifo_re[0]; + SEL_PHY3: rx_fifo_re_30 = tx_fifo_re[0]; + endcase +end + +// TX0 FIFO Empty Routing +always @(*) begin + case(tx0_src_sel) + SEL_PHY1: tx_fifo_empty[0] = rx_fifo_empty_10; + SEL_PHY2: tx_fifo_empty[0] = rx_fifo_empty_20; + SEL_PHY3: tx_fifo_empty[0] = rx_fifo_empty_30; + default: tx_fifo_empty[0] = 1'b1; + endcase +end + +// TX1 Switch Logic +// Possible sources: 0, 3 +always @(posedge clk, negedge rstn) + if ( !rstn ) + begin + tx_mode1 <= TX_MODE_AN; + tx1_src_sel <= SEL_PHY0; + end + else if ( tx_f[1] ) + case( tx_mode1 ) + TX_MODE_AN: + if ( phy_up[1] ) + tx_mode1 <= TX_MODE_IDLE; + TX_MODE_IDLE: + if ( !phy_up[1] ) + tx_mode1 <= TX_MODE_AN; + else if (tx1_src_sel==SEL_PHY0 && !rx_fifo_empty_31 ) + begin + tx_mode1 <= TX_MODE_XMT_PKT; + tx1_src_sel <= SEL_PHY3; + end + else if (!rx_fifo_empty_01 ) + begin + tx_mode1 <= TX_MODE_XMT_PKT; + tx1_src_sel <= SEL_PHY0; + end + else if (!rx_fifo_empty_31 ) + begin + tx_mode1 <= TX_MODE_XMT_PKT; + tx1_src_sel <= SEL_PHY3; + end + TX_MODE_XMT_PKT: + if ( !phy_up[1] ) + tx_mode1 <= TX_MODE_AN; + else + tx_mode1 <= TX_MODE_IDLE; + default: tx_mode1 <= TX_MODE_IDLE; + endcase + +// TX1 data mux +always @(*) begin + case(tx1_src_sel) + SEL_PHY0: tx_d1 = rx_d_01; + SEL_PHY1: tx_d1 = 9'h000; + SEL_PHY2: tx_d1 = rx_d_21; + SEL_PHY3: tx_d1 = rx_d_31; + SEL_UC: tx_d1 = 9'h000; + default: tx_d1 = 9'h000; + endcase +end + +// TX1 FIFO read enable +always @(*) begin + rx_fifo_re_01 = 1'b0; + rx_fifo_re_21 = 1'b0; + rx_fifo_re_31 = 1'b0; + case(tx1_src_sel) + SEL_PHY0: rx_fifo_re_01 = tx_fifo_re[1]; + SEL_PHY2: rx_fifo_re_21 = tx_fifo_re[1]; + SEL_PHY3: rx_fifo_re_31 = tx_fifo_re[1]; + endcase +end + +// TX1 FIFO Empty Routing +always @(*) begin + case(tx1_src_sel) + SEL_PHY0: tx_fifo_empty[1] = rx_fifo_empty_01; + SEL_PHY1: tx_fifo_empty[1] = 1'b1; + SEL_PHY2: tx_fifo_empty[1] = rx_fifo_empty_21; + SEL_PHY3: tx_fifo_empty[1] = rx_fifo_empty_31; + SEL_UC: tx_fifo_empty[1] = 1'b1; + default: tx_fifo_empty[1] = 1'b1; + endcase +end + + +/* + * TX2 Switch Logic + * Possible Sources: 0, 1, UC + * Note that for TX_MODE_XMT_METRICS, we set the source to be loopback, but it is expected that the + * phy controller will use a combination of local memory and the metrics block for its data. These decisions + * should be revisited when implementing loopback within this switch module. + */ +always @(posedge clk, negedge rstn) + if ( !rstn ) + begin + tx_mode2 <= TX_MODE_AN; + tx2_src_sel <= SEL_PHY0; + end + else if ( tx_f[2] ) + case( tx_mode2 ) + TX_MODE_AN: + if ( phy_up[2] ) + tx_mode2 <= TX_MODE_IDLE; + TX_MODE_IDLE: + if ( !phy_up[2] ) + tx_mode2 <= TX_MODE_AN; + else if (tx2_src_sel==SEL_PHY0 && !rx_fifo_empty_12 ) + begin + tx_mode2 <= TX_MODE_XMT_PKT; + tx2_src_sel <= SEL_PHY1; + end + else if (!rx_fifo_empty_02 ) + begin + tx_mode2 <= TX_MODE_XMT_PKT; + tx2_src_sel <= SEL_PHY0; + end + else if (!rx_fifo_empty_12 ) + begin + tx_mode2 <= TX_MODE_XMT_PKT; + tx2_src_sel <= SEL_PHY1; + end + else if (!rx_fifo_empty_u2) + begin + tx_mode2 <= TX_MODE_XMT_PKT; + tx2_src_sel <= SEL_UC; + end + else if (tx_metrics) + begin + tx_mode2 <= TX_MODE_XMT_METRICS; + tx2_src_sel <= SEL_PHY2; + end + TX_MODE_XMT_PKT: + if ( !phy_up[2] ) + tx_mode2 <= TX_MODE_AN; + else + tx_mode2 <= TX_MODE_IDLE; + default: tx_mode2 <= TX_MODE_IDLE; + endcase + +// TX2 data mux +always @(*) begin + case(tx2_src_sel) + SEL_PHY0: tx_d2 = rx_d_02; + SEL_PHY1: tx_d2 = rx_d_12; + SEL_PHY2: tx_d2 = 9'h000; + SEL_UC: tx_d2 = rx_d_u2; + default: tx_d2 = 9'h000; + endcase +end + +// TX2 FIFO read enable +always @(*) begin + rx_fifo_re_02 = 1'b0; + rx_fifo_re_12 = 1'b0; + rx_fifo_re_u2 = 1'b0; + case(tx2_src_sel) + SEL_PHY0: rx_fifo_re_02 = tx_fifo_re[2]; + SEL_PHY1: rx_fifo_re_12 = tx_fifo_re[2]; + SEL_UC: rx_fifo_re_u2 = tx_fifo_re[2]; + endcase +end + +// TX2 FIFO Empty Routing +always @(*) begin + case(tx2_src_sel) + SEL_PHY0: tx_fifo_empty[2] = rx_fifo_empty_02; + SEL_PHY1: tx_fifo_empty[2] = rx_fifo_empty_12; + SEL_PHY2: tx_fifo_empty[2] = 1'b0; // this is done for metrics. + SEL_UC: tx_fifo_empty[2] = rx_fifo_empty_u2; + default: tx_fifo_empty[2] = 1'b1; + endcase +end + + +// TX3 Switch Logic +// Possible sources: 0, 1 +always @(posedge clk, negedge rstn) + if ( !rstn ) + begin + tx_mode3 <= TX_MODE_AN; + tx3_src_sel <= SEL_PHY1; + end + else if ( tx_f[3] ) + case( tx_mode3 ) + TX_MODE_AN: + if ( phy_up[3] ) + tx_mode3 <= TX_MODE_IDLE; + TX_MODE_IDLE: + if ( !phy_up[3] ) + tx_mode3 <= TX_MODE_AN; + else if (tx3_src_sel==SEL_PHY1 && !rx_fifo_empty_03 ) + begin + tx_mode3 <= TX_MODE_XMT_PKT; + tx3_src_sel <= SEL_PHY0; + end + else if (!rx_fifo_empty_13 ) + begin + tx_mode3 <= TX_MODE_XMT_PKT; + tx3_src_sel <= SEL_PHY1; + end + else if (!rx_fifo_empty_03 ) + begin + tx_mode3 <= TX_MODE_XMT_PKT; + tx3_src_sel <= SEL_PHY0; + end + TX_MODE_XMT_PKT: + if ( !phy_up[3] ) + tx_mode3 <= TX_MODE_AN; + else + tx_mode3 <= TX_MODE_IDLE; + default: tx_mode3 <= TX_MODE_IDLE; + endcase + + // TX3 data mux + always @(*) begin + case(tx3_src_sel) + SEL_PHY0: tx_d3 = rx_d_03; + SEL_PHY1: tx_d3 = rx_d_13; + SEL_PHY2: tx_d3 = rx_d_23; + SEL_PHY3: tx_d3 = 9'h000; + SEL_UC: tx_d3 = 9'h000; + default: tx_d3 = 9'h000; + endcase + end + + // TX3 FIFO read enable + always @(*) begin + rx_fifo_re_03 = 1'b0; + rx_fifo_re_13 = 1'b0; + rx_fifo_re_23 = 1'b0; + case(tx3_src_sel) + SEL_PHY0: rx_fifo_re_03 = tx_fifo_re[3]; + SEL_PHY1: rx_fifo_re_13 = tx_fifo_re[3]; + SEL_PHY2: rx_fifo_re_23 = tx_fifo_re[3]; + endcase + end + + // TX3 FIFO Empty Routing + always @(*) begin + case(tx3_src_sel) + SEL_PHY0: tx_fifo_empty[3] = rx_fifo_empty_03; + SEL_PHY1: tx_fifo_empty[3] = rx_fifo_empty_13; + SEL_PHY2: tx_fifo_empty[3] = rx_fifo_empty_23; + default: tx_fifo_empty[3] = 1'b1; + endcase + end + +/* + * Transmit Logic for UC + * + * The only possible driver is PHY2 + * + * We need to delay the fifo_we one clock since the DPRAM read data comes out one clock delayed + */ + +assign tx_du = rx_d_2u; + +always @(*) + if ( !rx_fifo_empty_2u ) + begin + i_tx_fifo_we_u = 1'b1; + rx_fifo_re_2u = 1'b1; + end + else + begin + i_tx_fifo_we_u = 1'b0; + rx_fifo_re_2u = 1'b0; + end + +always @(posedge clk, negedge rstn) + if ( !rstn ) + tx_fifo_we_u <= 1'b0; + else + tx_fifo_we_u <= i_tx_fifo_we_u; + + +endmodule -- cgit v1.2.3-8-gadcc