summaryrefslogtreecommitdiffhomepage
path: root/source/switch.v
diff options
context:
space:
mode:
authormindchasers <privateisland@mindchasers.com>2019-05-01 18:16:45 -0400
committermindchasers <privateisland@mindchasers.com>2019-05-01 18:16:45 -0400
commit5723ec1a34181f1cfef9b8e870ab2e9a0362487c (patch)
tree0dc958d5b1931934ded5d0302b2b5fedab081d2c /source/switch.v
initial commit, all basic functions work on Darsena V02
Diffstat (limited to 'source/switch.v')
-rw-r--r--source/switch.v480
1 files changed, 480 insertions, 0 deletions
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

Highly Recommended Verilog Books