summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/controller.v1055
-rw-r--r--src/half_fifo.v263
-rw-r--r--src/switch.v300
3 files changed, 930 insertions, 688 deletions
diff --git a/src/controller.v b/src/controller.v
index 2b95d1e..54d6976 100644
--- a/src/controller.v
+++ b/src/controller.v
@@ -1,7 +1,8 @@
/*
* controller.v
*
- * Copyright (C) 2018, 2109, 2020, 2021 Mind Chasers Inc.
+ * Copyright (C) 2023-2025 Private Island Networks Inc.
+ * Copyright (C) 2018-2022 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.
@@ -17,456 +18,762 @@
*
* function: FPGA internal state machine controller
*
+ * see https://privateisland.tech/dev/pi-doc for further details
+ *
+ *
*/
-
-`timescale 1ns /10ps
-module controller #(parameter ADDR_SZ = 7)
+module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
(
input rstn,
input clk,
- input init,
- input pulse_100ms,
-
- // PCS status lines
- input [3:0] pcs_rx_error,
- input [1:0] pll_lol,
+
+ // status & errors from ports
+ input [NUM_PHYS-1:0] phy_int,
+ input [NUM_PHYS-1:0] mac_int,
// link status
- input [3:0] port_up,
+ input [NUM_PHYS-1:0] phy_up,
+
+ // Memory Controller bus
+ output reg mem_we,
+ output mem_oe,
+ output reg [15:0] mem_addr,
+ output reg[31:0] mem_d_o,
+ input [31:0] mem_d_i,
+
+ // Device selects for Controller peripherals
+ output reg [1:0] mac_addr,
+ output reg [15:0] pkt_filter_addr,
+ output reg pkt_filter_sel,
+ output reg mac_sel,
+ output reg hf_ptrs_sel,
+ output reg hf_tx_sel,
+ output reg hf_rx_sel,
+
+ // half FIFO interface
+ input rx_fifo_int,
+ output reg rx_fifo_int_acked,
+ input tx_fifo_empty,
// mdio_controller interface
output reg mdio_cont_start,
input mdio_cont_done,
- output reg [ADDR_SZ-1:0] mdio_routine_addr,
+ output reg [MDIO_ADDR_SZ-1:0] mdio_routine_addr,
input mdio_run, // the mdio controller is active
+ input mdio_we, //
+ input [15:0] mdio_d_i, // data read
// mdio_data params
- output reg [4:0] mdio_page,
+ output [4:0] mdio_phy_addr,
output reg [4:0] mdio_reg_addr,
output reg [7:0] mdio_w_data_h,
output reg [7:0] mdio_w_data_l,
+ output reg [1:0] mdio_mux_sel,
- // bin_to_ascii interface for MDIO or CONT -> bin_to_ascii -> FIFO -> I2C
- input bin_to_ascii_run, // asserted if block is active and writing FIFO
-
- // sync_fifo interface: controller to fifo
- output fifo_mux_sel, // 0 is self, 1 is mdio_controller
- output reg fifo_we,
- output reg [6:0] read_fifo_d_o,
-
- // i2c interface: i2c to controller
- input i2c_rx_we,
- input i2c_rx_done,
- input [7:0] i2c_d_in,
-
- // DCU Resets
- output [1:0] pcs_rst_dual,
- output [1:0] serdes_rst_dual,
- output [1:0] tx_serdes_rst,
-
- // Channel
- output [3:0] phy_resetn,
- output [3:0] mac_reset,
-
- output [3:0] tx_pcs_rst,
- output [3:0] rx_serdes_rst,
- output [3:0] rx_pcs_rst,
+ // Device Resets
+ output reg [NUM_PHYS-1:0] phy_resetn,
+ output reg [NUM_PHYS-1:0] mac_reset,
- output reg [1:0] mdio_mux_sel,
-
- // TX custom packet
- output reg tx_custom
-
+ // Debug
+ output [7:0] gpio
);
- // state encoding
- localparam BUFFER_SZ = 8; // index starts at 1, 0 is cmd
+`define INCLUDED
+`include "cont_params.v"
+`include "ethernet_params.v"
+`undef INCLUDED
- localparam S0= 4'h0, S1=4'h1, S2=4'h2, S3=4'h3,
- S4= 4'h4, S5=4'h5, S6=4'h6, S7=4'h7,
- S8= 4'h8, S9=4'h9, S10=4'ha, S11=4'hb,
- S12= 4'hc, S13=4'hd, S14=4'he, S15=4'hf;
+ /* Define Parameters Below */
+ // Version: upper byte is major, lower byte is minor
+ localparam FW_VERSION_VALUE = 16'h0001;
+ // Version Increment: Set to 0 when releasing version; otherwise, increment value for each preliminary / trial release
+ localparam FW_INCREMENT_VALUE = 16'h0002;
- // ascii codes we use
- localparam ASCIIc = 7'h63, // channel resets
- ASCIId = 7'h64, // set and dump page
- ASCIIf = 7'h66, // FIFO control
- ASCIIi = 7'h69, // init ( sgmii mode )
- ASCIIl = 7'h6c, // link status
- ASCIIm = 7'h6d, // mdio mux
- ASCIIp = 7'h70, // PCS /SERDES block status
- ASCIIq = 7'h71,
- ASCIIr = 7'h72, // set address and read reg
- ASCIIs = 7'h73, // show mdio line status
- ASCIIt = 7'h74, // transmit test packet
- ASCIIu = 7'h75,
- ASCIIw = 7'h77, // write reg at preset page and address
- ASCIIx = 7'h78, // control word
- ASCIIy = 7'h79, // extended read
- ASCIIz = 7'h7a, // extended write
- ASCII_ = 7'h5f,
- LF = 7'h0a,
- CR = 7'h0d;
+ // Main Controller states
+ localparam CONT_ST_INIT= 3'h0, CONT_ST_IDLE=3'h1, CONT_ST_START=3'h2, CONT_ST_BUSY=3'h3,
+ CONT_ST_DONE= 3'h4, CONT_ST_5=3'h5, CONT_ST_6=3'h6, CONT_ST_7=3'h7;
+
+ // Memory states
+ localparam MEM_ST_START=4'h0, MEM_ST_1=4'h1, MEM_ST_2=4'h2, MEM_ST_3=4'h3,
+ MEM_ST_IDLE=4'h4, MEM_ST_RX_START=4'h5, MEM_ST_RX_GET_WR_PTR=4'h6,
+ MEM_ST_RD_FIFO_START=4'h7, MEM_ST_RD_FIFO=4'h8, MEM_ST_RD_FIFO_DONE=4'h9,
+ MEM_ST_A=4'ha, MEM_ST_B=4'hb, MEM_ST_VALIDATE=4'hc, MEM_ST_REPLY_START=4'hd,
+ MEM_ST_REPLY=4'he, MEM_ST_DONE=4'hf;
+
+ // MDIO Init
+ localparam MI_ST_INIT=4'h0, MI_ST_1=4'h1, MI_ST_2=4'h2, MI_ST_3=4'h3, MI_ST_4=4'h4,
+ MI_ST_5=4'h5, MI_ST_6=4'h6, MI_ST_7=4'h7, MI_ST_8=4'h8, MI_ST_IDLE=4'h9;
+
+ localparam MEM_EVENT_NONE=3'h0, MEM_EVENT_FIFO=3'h1;
+
+ // Controller Address Space
+ localparam FW_VERSION_ADDR = 16'h0000;
+ localparam FW_INCREMENT_ADDR = 16'h0004;
+ localparam MAC_ADDR = 16'h0010;
+ localparam PHY_ADDR = 16'h0014; // Controls mdio_mux_sel, not the MIDO PHY Address
+ localparam PKT_FILT_ADDR = 16'h0018;
+ localparam RX_MSG_CNT_ADDR = 16'h0020;
+ localparam TX_PKT_CNT_ADDR = 16'h0024;
- reg [1:0] x_reg[0:3]; // ASCIIx: phy_reset and mac_reset
- reg [2:0] c_reg[0:3]; // ASCIIc one reg per channel
- reg [2:0] u_reg[0:1]; // 2 DCU's: pcs_rst_dual, serdes_rst_dual, tx_serdes_rst
-
- reg [3:0] cont_state;
- reg [3:0] cnt; // input cnt, 0 is cmd, 1-8 are buffer, beyond are thrown out & flag is set
- reg [6:0] cmd;
- integer i;
-
- reg [6:0] buffer [1:BUFFER_SZ]; // data buffer
-
- reg mdio_cmd, cont_cmd;
- wire rx_cmd;
- reg mdio_cont_busy;
-
- wire[5:0] pcs_s;
- wire[3:0] link_s;
-
- reg cont_start, cont_busy, cont_done;
-
- assign pcs_s = { pll_lol, pcs_rx_error };
- assign link_s = port_up;
+ /* Define Variables and Nets Below */
+ reg [2:0] cont_state;
+ reg [3:0] mem_state;
+
+ reg [3:0] mi_state; // mdio init state
+ reg [7:0] mdio_init_cnt;
+ reg [1:0] mdio_init_mux_sel;
+
+ // metastability synchronizer regs
+ reg rx_fifo_int_m1, rx_fifo_int_m2;
+
+ // Vars to capture Message fields
+ reg [7:0] msg_type; // 1st byte in message
+ reg [7:0] msg_token; // 2nd byte
+ reg [15:0] msg_addr; // 3rd and 4th bytes
+ reg [31:0] msg_data; // 5th through 8th bytes
+ reg msg_addr_valid, msg_addr_ro, msg_error; // flags
+ reg [31:0] msg_response; // response to a valid message
+
+ // Command Processing
+ reg rx_msg_captured;
+ reg mdio_cmd, cont_msg;
+ reg [15:0] mdio_d;
+
+ // MDIO Init
+ reg [7:0] mdio_init_w_data_h, mdio_init_w_data_l;
+ reg [3:0] mdio_init_reg_addr;
+ reg [MDIO_ADDR_SZ-1:0] mdio_init_routine_addr;
+
+ // memory controller, HFIFO vars
+ reg [10:0] rx_wr_ptr, rx_rd_ptr; // access the HFIFO RX data
+ reg [10:0] tx_wr_ptr; // write into the HFIFO TX data
+ reg rx_rd_active, tx_wr_active;
+ reg [4:0] rx_cnt, tx_cnt;
+
+ // metrics
+ reg [15:0] rx_msg_cnt;
+ reg [15:0] tx_pkt_cnt;
+
+
+ // Synchronize rx_fifo_int
+ always @(posedge clk, negedge rstn)
+ if (!rstn) begin
+ rx_fifo_int_m1 <= 1'b0;
+ rx_fifo_int_m2 <= 1'b0;
+ end
+ else begin
+ rx_fifo_int_m1 <= rx_fifo_int;
+ rx_fifo_int_m2 <= rx_fifo_int_m1;
+ end
+ // rx_msg_captured signals a message has been received
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ rx_msg_captured <= 1'b0;
+ else if (mem_state == MEM_ST_RD_FIFO && !rx_rd_active)
+ rx_msg_captured <= 1'b1;
+ else
+ rx_msg_captured <= 1'b0;
+
+
+ // rx_msg_cnt
+ // TODO: reset counter by writing the register
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ rx_msg_cnt <= 16'd0;
+ else if (rx_msg_captured)
+ rx_msg_cnt <= rx_msg_cnt + 1'b1;
+
/*
- * main state machine for controller
+ * state machine for internal controller
+ * internal commands are handled in this FSM
+ * MDIO and other external commands need to finish before reaching the end state
*/
always @(posedge clk or negedge rstn)
begin
- if ( !rstn )
- cont_state <= S0;
+ if (!rstn)
+ cont_state <= CONT_ST_INIT;
else
case (cont_state)
- S0: cont_state <= S1; // S0 is default on reset
- S1: if ( rx_cmd && cont_cmd )
- cont_state <= S2;
- else if ( rx_cmd )
- cont_state <= S3;
- S2: cont_state <= S3; // respond to cont cmd
- S3: if ( !cont_busy )
- cont_state <= S4;
- S4: if ( !mdio_cont_busy )
- cont_state <= S1;
+ CONT_ST_INIT: cont_state <= CONT_ST_IDLE;
+ CONT_ST_IDLE: if (rx_msg_captured)
+ cont_state <= CONT_ST_START;
+ CONT_ST_START: cont_state <= CONT_ST_BUSY;
+ CONT_ST_BUSY:
+ if (cont_msg || msg_error)
+ cont_state <= CONT_ST_DONE;
+ else if (mdio_cmd && mdio_cont_done)
+ cont_state <= CONT_ST_DONE;
+ CONT_ST_DONE:
+ cont_state <= CONT_ST_IDLE;
default: cont_state <= cont_state;
endcase
end
+
+ // cont_msg address decode
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ cont_msg <= 1'b0;
+ else if (cont_state == CONT_ST_IDLE && !rx_msg_captured)
+ cont_msg <= 1'b0;
+ else if (rx_msg_captured && (msg_addr[15:8] < MSG_MDIO_ADDR[15:8]))
+ cont_msg <= 1'b1;
+
+/***********************************************************************
+ *
+ * Parse messages received from the LAN
+ *
+ **********************************************************************/
+
+ // msg_type
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ msg_type <= 7'h0;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_type <= 7'h0;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h4)
+ msg_type <= mem_d_i[7:0];
-/*
-* Controller Tasks, controller always runs upon rx_cmd.
-* Other tasks will hold off until cont_done asserts
-*/
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- cont_start <= 1'b0;
- else if ( rx_cmd )
- cont_start <= 1'b1;
- else
- cont_start <= 1'b0;
- end
+ // msg_token
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ msg_token <= 7'h0;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_token <= 7'h0;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h5)
+ msg_token <= mem_d_i[7:0];
- // cont_busy
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- cont_busy <= 1'b0;
- else if ( cont_start )
- cont_busy <= 1'b1;
- else if ( cont_done )
- cont_busy <= 1'b0;
- end
+ // message address
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ msg_addr <= 16'h0000;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_addr <= 16'h0000;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h6)
+ msg_addr[15:8] <= mem_d_i[7:0];
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h7)
+ msg_addr[7:0] <= mem_d_i[7:0];
- // cont_done
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- cont_done <= 1'b0;
- else if ( cont_busy )
- cont_done <= 1'b1;
- else
- cont_done <= 1'b0;
- end
-
- always @(cmd)
- begin
- if ( cmd == ASCIIp || cmd == ASCIIl )
- cont_cmd <= 1'b1;
+ // message address valid testing
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ msg_addr_valid <= 1'b0;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_addr_valid <= 1'b0;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h8)
+ if (msg_addr == FW_VERSION_ADDR || msg_addr == FW_INCREMENT_ADDR ||
+ (msg_addr == MAC_ADDR || msg_addr == PHY_ADDR || msg_addr == PKT_FILT_ADDR) ||
+ (msg_addr == RX_MSG_CNT_ADDR || msg_addr == TX_PKT_CNT_ADDR) ||
+ (msg_addr >= MSG_MAC_ADDR && msg_addr < MSG_INVALID_ADDR))
+ msg_addr_valid <= 1'b1;
else
- cont_cmd <= 1'b0;
- end
+ msg_addr_valid <= 1'b0;
+
+ // message read only logic
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ msg_addr_ro <= 1'b0;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_addr_ro <= 1'b0;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h9)
+ if (msg_addr == FW_VERSION_ADDR || msg_addr == FW_INCREMENT_ADDR)
+ msg_addr_ro <= 1'b1;
+ else
+ msg_addr_ro <= 1'b0;
+
+ // msg_error
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ msg_error <= 1'b0;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_error <= 1'b0;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h5 && msg_type > MSG_TYPE_REPLY_ERROR)
+ msg_error <= 1'b1;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h9 && !msg_addr_valid)
+ msg_error <= 1'b1;
+
+ // msg data on writes
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ msg_data <= 32'd0;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_data <= 32'd0;
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'd8)
+ msg_data[31:24] <= mem_d_i[7:0];
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'd9)
+ msg_data[23:16] <= mem_d_i[7:0];
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'd10)
+ msg_data[15:8] <= mem_d_i[7:0];
+ else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'd11)
+ msg_data[7:0] <= mem_d_i[7:0];
+
+ // msg_response
+ // TODO: add other peripherals
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ msg_response <= 16'heeee;
+ else if (mem_state == MEM_ST_IDLE)
+ msg_response <= 16'heeee;
+ else if (mem_state == MEM_ST_RD_FIFO_DONE && cont_state == CONT_ST_DONE)
+ casez (msg_addr)
+ FW_VERSION_ADDR : msg_response <= FW_VERSION_VALUE;
+ FW_INCREMENT_ADDR : msg_response <= FW_INCREMENT_VALUE;
+ MAC_ADDR: msg_response <= mac_addr;
+ PHY_ADDR: msg_response <= mdio_mux_sel;
+ PKT_FILT_ADDR: msg_response <= pkt_filter_addr;
+ RX_MSG_CNT_ADDR : msg_response <= rx_msg_cnt;
+ TX_PKT_CNT_ADDR : msg_response <= tx_pkt_cnt;
+ {MSG_MDIO_ADDR[15:8],8'h??}: msg_response <= mdio_d;
+ default: msg_response <= mem_d_i[15:0];
+ endcase
/*
* MDIO controller related
*/
- always @(cmd)
- begin
- if ( cmd == ASCIIi || cmd == ASCIIs || cmd == ASCIId || cmd == ASCIIr || cmd == ASCIIw || cmd == ASCIIy || cmd == ASCIIz )
- mdio_cmd <= 1'b1;
- else
- mdio_cmd <= 1'b0;
- end
-
-
+
+ // mdio_cmd address decode
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ mdio_cmd <= 1'b0;
+ else if (cont_state == CONT_ST_IDLE && !rx_msg_captured)
+ mdio_cmd <= 1'b0;
+ else if (rx_msg_captured && msg_addr[15:8] == MSG_MDIO_ADDR[15:8])
+ mdio_cmd <= 1'b1;
+
+ // mdio_cont_start indicates to MDIO controller to begin
always @(posedge clk or negedge rstn)
begin
- if ( !rstn )
+ if (!rstn)
mdio_cont_start <= 1'b0;
- else if ( cont_done && mdio_cmd )
+ else if (mi_state == MI_ST_1 || mi_state == MI_ST_3 || mi_state == MI_ST_5)
+ mdio_cont_start <= 1'b0;
+ else if (mdio_cmd && cont_state == CONT_ST_START)
mdio_cont_start <= 1'b1;
else
mdio_cont_start <= 1'b0;
end
- /*
- * driver: mdio_route_addr
- */
+ // mdio_routine_addr depends on msg_type
always @(posedge clk or negedge rstn)
begin
- if ( !rstn )
+ if (!rstn)
mdio_routine_addr <= 'd0;
- else if ( cont_done && mdio_cmd )
- if ( cmd == ASCIIi )
- mdio_routine_addr <= 'd0;
- else if ( cmd == ASCIIs )
- mdio_routine_addr <= 'd20;
- else if ( cmd == ASCIId )
- mdio_routine_addr <= 'd25;
- else if ( cmd == ASCIIr )
- mdio_routine_addr <= 'd48;
- else if ( cmd == ASCIIw )
- mdio_routine_addr <= 'd50;
- else if ( cmd == ASCIIy )
- mdio_routine_addr <= 'd60;
- else if ( cmd == ASCIIz )
- mdio_routine_addr <= 'd80;
+ else if (mi_state > MI_ST_INIT && mi_state < MI_ST_IDLE)
+ mdio_routine_addr <= mdio_init_routine_addr;
+ else if (mdio_cmd && cont_state == CONT_ST_START && msg_type == MSG_TYPE_READ)
+ mdio_routine_addr <= 'd48;
+ else if (mdio_cmd && cont_state == CONT_ST_START && msg_type == MSG_TYPE_WRITE)
+ mdio_routine_addr <= 'd50;
end
- // mdio_cont_busy
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- mdio_cont_busy <= 1'b0;
- else if ( mdio_cont_start )
- mdio_cont_busy <= 1'b1;
- else if ( mdio_cont_done )
- mdio_cont_busy <= 1'b0;
- end
+ // set mdio_phy_addr
+ assign mdio_phy_addr = 5'h0c; // Set phy_addr[3:2]
- /* fifo_mux_sel = 1 when controller does NOT have FIFO bus */
- assign fifo_mux_sel = mdio_cont_busy | mdio_run;
-
- /* set mdio page */
+ // set mdio_reg_addr
always @(posedge clk or negedge rstn)
begin
- if ( !rstn )
- mdio_page <= 'd0;
- else if ( rx_cmd && cmd == ASCIId )
- mdio_page <= { buffer[1][0], buffer[2][3:0] };
- end
-
- /* set mdio_reg_addr */
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
+ if (!rstn)
mdio_reg_addr <= 'd0;
- else if ( rx_cmd && cmd == ASCIIr )
- mdio_reg_addr <= { buffer[1][0], buffer[2][3:0] };
+ else if (mi_state > MI_ST_INIT && mi_state < MI_ST_IDLE)
+ mdio_reg_addr <= mdio_init_reg_addr;
+ else if (mdio_cmd && cont_state == CONT_ST_START)
+ mdio_reg_addr <= msg_addr[4:0];
end
/* set mdio_w_data_l and mdio_w_data_h */
always @(posedge clk or negedge rstn)
begin
- if ( !rstn )
- begin
- mdio_w_data_l <= 'd0;
- mdio_w_data_h <= 'd0;
- end
- else if ( rx_cmd && (cmd == ASCIIw || cmd == ASCIIy || cmd == ASCIIz ) )
- begin
- mdio_w_data_h <= { buffer[1][3:0], buffer[2][3:0] };
- mdio_w_data_l <= { buffer[3][3:0], buffer[4][3:0] };
- end
+ if (!rstn) begin
+ mdio_w_data_l <= 'd0;
+ mdio_w_data_h <= 'd0;
+ end
+ else if (mi_state > MI_ST_INIT && mi_state < MI_ST_IDLE) begin
+ mdio_w_data_h <= mdio_init_w_data_h;
+ mdio_w_data_l <= mdio_init_w_data_l;
+ end
+ else if (mdio_cmd && msg_type == MSG_TYPE_WRITE) begin
+ mdio_w_data_h <= msg_data[15:8];
+ mdio_w_data_l <= msg_data[7:0];
+ end
end
- // Channel Resets
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- begin
- c_reg[0] <= 'hff;
- c_reg[1] <= 'hff;
- c_reg[2] <= 'hff;
- c_reg[3] <= 'hff;
- end
- else if ( rx_cmd && cmd == ASCIIc )
- begin
- c_reg[0] <= buffer[4][2:0];
- c_reg[1] <= buffer[3][2:0];
- c_reg[2] <= buffer[2][2:0];
- c_reg[3] <= buffer[1][2:0];
- end
- end
+ // mdio_d, data from MDIO read cycle
+ always @(posedge clk or negedge rstn)
+ begin
+ if (!rstn)
+ mdio_d <= 16'h0000;
+ else if (mdio_we)
+ mdio_d <= mdio_d_i;
+ end
- assign rx_pcs_rst[0] = c_reg[0][0];
- assign rx_serdes_rst[0] = c_reg[0][1];
- assign tx_pcs_rst[0]= c_reg[0][2];
-
- assign rx_pcs_rst[1] = c_reg[1][0];
- assign rx_serdes_rst[1] = c_reg[1][1];
- assign tx_pcs_rst[1]= c_reg[1][2];
-
- assign rx_pcs_rst[2] = c_reg[2][0];
- assign rx_serdes_rst[2] = c_reg[2][1];
- assign tx_pcs_rst[2]= c_reg[2][2];
-
- assign rx_pcs_rst[3] = c_reg[3][0];
- assign rx_serdes_rst[3] = c_reg[3][1];
- assign tx_pcs_rst[3]= c_reg[3][2];
+ // PHY Reset
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ phy_resetn <= 2'b00;
+ else if (1'b0)
+ phy_resetn <= 2'b00; // assert reset
+ else
+ phy_resetn <= 2'b11;
- /* DCU resets */
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- begin
- u_reg[0] <= 'hff;
- u_reg[1] <= 'hff;
- end
- else if ( rx_cmd && cmd == ASCIIu )
- begin
- u_reg[0] <= buffer[2][2:0];
- u_reg[1] <= buffer[1][2:0];
- end
- end
+ // MAC Reset
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ mac_reset <= 2'b11;
+ else if (1'b0)
+ mac_reset <= 2'b11; // assert reset
+ else
+ mac_reset <= 2'b00;
+
+/***********************************************************************
+ *
+ * Memory Controller and HFIFO Access LAN Controller
+ *
+ * TODO: Review and implement better LAN flow control
+ *
+ **********************************************************************/
- // DCU0 Reset assignments
- assign pcs_rst_dual[0] = u_reg[0][2];
- assign serdes_rst_dual[0] = u_reg[0][1];
- assign tx_serdes_rst[0] = u_reg[0][0];
+ // Memory Controller Tie Offs
+ assign mem_oe = 1'b1;
- // DCU1 Reset assignments
- assign pcs_rst_dual[1] = u_reg[1][2];
- assign serdes_rst_dual[1] = u_reg[1][1];
- assign tx_serdes_rst[1] = u_reg[1][0];
-
- /* X control */
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- begin
- x_reg[0] <= 'hff;
- x_reg[1] <= 'hff;
- x_reg[2] <= 'hff;
- x_reg[3] <= 'hff;
-
- end
- else if ( rx_cmd && cmd == ASCIIx )
- begin
- x_reg[0] <= buffer[4][1:0];
- x_reg[1] <= buffer[3][1:0];
- x_reg[2] <= buffer[2][1:0];
- x_reg[3] <= buffer[1][1:0];
+ // Memory Controller State Machine
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ mem_state <= MEM_ST_START;
+ else
+ case (mem_state)
+ MEM_ST_START: mem_state <= MEM_ST_IDLE; // states before idle are initialization states
+ MEM_ST_IDLE:
+ if (rx_fifo_int_m2 && tx_fifo_empty)
+ mem_state <= MEM_ST_RX_START;
+ MEM_ST_RX_START: mem_state <= MEM_ST_RX_GET_WR_PTR; // get rx_wr_ptr
+ MEM_ST_RX_GET_WR_PTR: mem_state <= MEM_ST_RD_FIFO_START; // read first word into cmd buffer
+ MEM_ST_RD_FIFO_START: mem_state <= MEM_ST_RD_FIFO;
+ MEM_ST_RD_FIFO:
+ if(!rx_rd_active)
+ mem_state <= MEM_ST_RD_FIFO_DONE;
+ MEM_ST_RD_FIFO_DONE:
+ if (cont_state == CONT_ST_DONE)
+ mem_state <= MEM_ST_VALIDATE;
+ MEM_ST_VALIDATE:
+ if (msg_type == MSG_TYPE_READ || msg_type == MSG_TYPE_WRITE)
+ mem_state <= MEM_ST_REPLY_START;
+ else
+ mem_state <= MEM_ST_IDLE;
+ MEM_ST_REPLY_START: if (tx_fifo_empty) // wait for TX FIFO to empty
+ mem_state <= MEM_ST_REPLY;
+ MEM_ST_REPLY: // write the response
+ if(!tx_wr_active)
+ mem_state <= MEM_ST_DONE;
+ MEM_ST_DONE: mem_state <= MEM_ST_IDLE; // update tx_wr_ptr
+ default: mem_state <= MEM_ST_IDLE;
+ endcase
+
- end
- end
+ // Primary Memory Controller Actions
+ always @(posedge clk, negedge rstn)
+ if (!rstn) begin
+ mem_we <= 1'b0;
+ mem_d_o <= 32'd0;
+ mem_addr <= HF_NULL;
+ mac_sel <= 1'b0;
+ pkt_filter_sel <= 1'b0;
+ hf_ptrs_sel <= 1'b0;
+ hf_tx_sel <= 1'b0;
+ hf_rx_sel <= 1'b0;
+ end
+ else if (mem_state == MEM_ST_START || mem_state == MEM_ST_IDLE) begin
+ mem_we <= 1'b0;
+ mem_d_o <= 32'd0;
+ mem_addr <= HF_NULL;
+ hf_ptrs_sel <= 1'b0;
+ hf_tx_sel <= 1'b0;
+ hf_rx_sel <= 1'b0;
+ end
+ else if (mem_state == MEM_ST_RX_START) begin // start processing interrupt from LAN
+ hf_ptrs_sel <= 1'b1;
+ mem_addr <= HF_RX_WR_PTR_LTCH_ADDR;
+ end
+ else if (mem_state >= MEM_ST_RX_GET_WR_PTR && mem_state <= MEM_ST_RD_FIFO) begin
+ hf_ptrs_sel <= 1'b0;
+ hf_rx_sel <= 1'b1;
+ mem_addr <= rx_rd_ptr;
+ end
+ // perform message related memory functions as needed
+ else if (mem_state == MEM_ST_RD_FIFO_DONE && cont_state == CONT_ST_START) begin
+ hf_ptrs_sel <= 1'b0;
+ hf_tx_sel <= 1'b0;
+ hf_rx_sel <= 1'b0;
+ if ((msg_type == MSG_TYPE_WRITE || msg_type == MSG_TYPE_READ) && !msg_error) begin
+ mem_d_o <= msg_data;
+ mem_addr <= msg_addr[7:0];
+ if (msg_type == MSG_TYPE_WRITE)
+ mem_we <= 1'b1;
+ // address decode
+ case (msg_addr[15:8])
+ MSG_MAC_ADDR[15:8]: mac_sel <= 1'b1;
+ MSG_PKT_FILTER_ADDR[15:8]: pkt_filter_sel <= 1'b1;
+ endcase
+ end
+ end
+ else if (mem_state == MEM_ST_RD_FIFO_DONE && cont_state == CONT_ST_DONE) begin
+ hf_tx_sel <= 1'b0;
+ hf_rx_sel <= 1'b0;
+ mem_we <= 1'b0;
+ end
+ else if (mem_state == MEM_ST_REPLY_START && tx_fifo_empty) begin // write byte cnt
+ hf_ptrs_sel <= 1'b1;
+ hf_tx_sel <= 1'b0;
+ hf_rx_sel <= 1'b0;
+ mem_we <= 1'b1;
+ mem_addr <= HF_TX_BYTE_CNT_ADDR;
+ mem_d_o <= MSG_SZ;
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd0) begin // write Response to hfifo
+ hf_ptrs_sel <= 1'b0;
+ hf_tx_sel <= 1'b1;
+ hf_rx_sel <= 1'b0;
+ mem_we <= 1'b1;
+ mem_addr <= tx_wr_ptr;
+ if (msg_error || (msg_type == MSG_TYPE_WRITE && msg_addr_ro))
+ mem_d_o <= MSG_TYPE_REPLY_ERROR;
+ else
+ mem_d_o <= MSG_TYPE_REPLY_SUCCESS;
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd1) begin
+ mem_addr <= tx_wr_ptr;
+ mem_d_o <= msg_token;
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd2) begin // write addr to hfifo
+ mem_addr <= tx_wr_ptr;
+ mem_d_o <= msg_addr[15:8];
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd3) begin
+ mem_addr <= tx_wr_ptr;
+ mem_d_o <= msg_addr[7:0];
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd4) begin // write address to hfifo
+ mem_addr <= tx_wr_ptr;
+ mem_d_o <= msg_response[31:24];
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd5) begin // write data msb to hfifo
+ mem_addr <= tx_wr_ptr;
+ mem_d_o <= {24'd0, msg_response[23:16]};
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd6) begin // write data msb to hfifo
+ mem_addr <= tx_wr_ptr;
+ mem_d_o <= msg_response[15:8];
+ end
+ else if (mem_state == MEM_ST_REPLY && tx_cnt == 5'd7) begin // write data lsb to hfifo
+ mem_addr <= tx_wr_ptr;
+ mem_d_o <= {1'b1, msg_response[7:0]}; // bit 8: set end of frame bit
+ end
+ else if (mem_state == MEM_ST_DONE) begin // update tx_wr_ptr in hfifo
+ hf_tx_sel <= 1'b0;
+ hf_ptrs_sel <= 1'b1;
+ mem_addr <= HF_TX_WR_PTR_ADDR;
+ mem_we <= 1'b1;
+ mem_d_o <= {21'd0, tx_wr_ptr};
+ end
+ else begin
+ mem_we <= 1'b0;
+ mem_d_o <= 32'd0;
+ mem_addr <= HF_NULL;
+ mac_sel <= 1'b0;
+ pkt_filter_sel <= 1'b0;
+ hf_ptrs_sel <= 1'b0;
+ hf_tx_sel <= 1'b0;
+ hf_rx_sel <= 1'b0;
+ end
+
+ // rx_cnt
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_cnt <= 5'd2;
+ else if (mem_state == MEM_ST_IDLE)
+ rx_cnt <= 5'd2;
+ else if (rx_rd_active)
+ rx_cnt <= rx_cnt + 1'b1;
+
+ // tx_cnt
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ tx_cnt <= 5'd0;
+ else if (mem_state == MEM_ST_IDLE || mem_state == MEM_ST_REPLY_START)
+ tx_cnt <= 5'd0;
+ else if (tx_wr_active)
+ tx_cnt <= tx_cnt + 1'b1;
+
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ tx_pkt_cnt <= 16'd0;
+ else if (mem_state == MEM_ST_DONE) // MSG
+ tx_pkt_cnt <= tx_pkt_cnt + 1'b1;
+
+
+
+/***********************************************************************
+ *
+ * HFIFO Control Logic for accessing the LAN
+ *
+ * General Flow:
+ * interrupt
+ * receive message (data path: Controller from LAN->Switch->Controller)
+ * transmit response(s) (data path: Controller->Switch->LAN)
+ *
+ **********************************************************************/
+
+ // ACK HFIFO interrupt due to LAN activity
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_fifo_int_acked <= 1'b0;
+ else if (mem_state == MEM_ST_RX_START && tx_fifo_empty)
+ rx_fifo_int_acked <= 1'b1;
+ else
+ rx_fifo_int_acked <= 1'b0;
+
+ // rx_rd_ptr for reading from HFIFO
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_rd_ptr <= 11'd0;
+ else if (mem_state == MEM_ST_RX_START)
+ rx_rd_ptr <= rx_rd_ptr + SZ_ETH_HEADER + SZ_IPV4_HEADER + SZ_UDP_HEADER;
+ else if (rx_rd_active && rx_rd_ptr != rx_wr_ptr)
+ rx_rd_ptr <= rx_rd_ptr + 11'd1;
- assign mac_reset[0] = x_reg[0][0];
- assign phy_resetn[0] = ~x_reg[0][1];
+ // capture rx_wr_ptr to determine when FIFO is empty
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_wr_ptr <= 11'h0;
+ else if (mem_state == MEM_ST_RX_GET_WR_PTR)
+ rx_wr_ptr <= mem_d_i[10:0];
- assign mac_reset[1] = x_reg[1][0];
- assign phy_resetn[1] = ~x_reg[1][1];
-
- assign mac_reset[2] = x_reg[2][0];
- assign phy_resetn[2] = ~x_reg[2][1];
-
- assign mac_reset[3] = x_reg[3][0];
- assign phy_resetn[3] = ~x_reg[3][1];
-
-
- /* mdio_mux_sel */
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- mdio_mux_sel <= 'h0;
- else if ( rx_cmd && cmd == ASCIIm )
- mdio_mux_sel <= buffer[1][1:0];
- end
+ // rx_rd_active
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_rd_active <= 1'b0;
+ else if (rx_rd_ptr != rx_wr_ptr && (mem_state == MEM_ST_RD_FIFO_START || mem_state == MEM_ST_RD_FIFO))
+ rx_rd_active <= 1'b1;
+ else
+ rx_rd_active <= 1'b0;
+
+ // tx_wr_active into TX DPRAM
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ tx_wr_active <= 1'b0;
+ else if ((mem_state == MEM_ST_REPLY_START && tx_fifo_empty) || (mem_state == MEM_ST_REPLY && tx_cnt <= MSG_SZ[4:0])) // Response
+ tx_wr_active <= 1'b1;
+ else
+ tx_wr_active <= 1'b0;
+
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ tx_wr_ptr <= 11'd0;
+ else if (tx_wr_active)
+ tx_wr_ptr <= tx_wr_ptr + 11'd1;
+
+
+ /***********************************************************************
+ *
+ * Write Logic for Controller Internal Registers
+ *
+ **********************************************************************/
+
+ always @(posedge clk, negedge rstn)
+ if (!rstn) begin
+ mac_addr <= 2'd0;
+ mdio_mux_sel <= 2'b00;
+ pkt_filter_addr <= 16'd0;
+ end
+ else if (rx_msg_captured && !msg_error && msg_type == MSG_TYPE_WRITE) begin
+ if (msg_addr==MAC_ADDR)
+ mac_addr <= msg_data[1:0];
+ else if (msg_addr==PHY_ADDR)
+ mdio_mux_sel <= msg_data[1:0];
+ else if (msg_addr==PKT_FILT_ADDR)
+ pkt_filter_addr <= msg_data[15:0];
+ end
- /* transmit custom packet */
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- tx_custom <= 1'b0;
- else if ( rx_cmd && cmd == ASCIIt )
- tx_custom <= 1'b1;
- else
- tx_custom <= 1'b0;
- end
-
- /* FIFO logic */
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- fifo_we <= 1'b0;
- else if ( cont_state == S2 )
- fifo_we <= 1'b1;
- else
- fifo_we <= 1'b0;
- end
-
+ /***********************************************************************
+ *
+ * MDIO Initialization
+ *
+ * TODO: Specific for Betsy, such as PHY LED assignment
+ *
+ **********************************************************************/
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- read_fifo_d_o <= 0;
- else if ( cont_state == S2 && cmd == ASCIIp ) // pcs status
- read_fifo_d_o <= { 1'b0, pcs_s };
- else if ( cont_state == S2 && cmd == ASCIIl ) // link status
- read_fifo_d_o <= { 3'b000, link_s };
- end
+ // Give the board and circuits time to stabilize (being overly cautious)
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ mdio_init_cnt <= 8'd0;
+ else if (mi_state == MI_ST_2 && mdio_cont_done)
+ mdio_init_cnt <= 8'd0;
+ else if (mdio_init_cnt < 8'd100)
+ mdio_init_cnt <= mdio_init_cnt + 8'd1;
+
+
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ mi_state <= MI_ST_INIT;
+ else if (1'b1)
+ mi_state <= MI_ST_INIT;
+ else
+ case (mi_state)
+ MI_ST_INIT: if (mdio_init_cnt == 8'd100)
+ mi_state <= MI_ST_1;
+ MI_ST_1: mi_state <= MI_ST_2;
+ MI_ST_2: if (mdio_cont_done)
+ mi_state <= MI_ST_INIT;
+ MI_ST_3: mi_state <= MI_ST_4;
+ MI_ST_4: if (mdio_cont_done)
+ mi_state <= MI_ST_5;
+ MI_ST_5: mi_state <= MI_ST_6;
+ MI_ST_6: if (mdio_cont_done)
+ mi_state <= MI_ST_IDLE;
+ MI_ST_7: mi_state <= MI_ST_8;
+ MI_ST_8: if (mdio_cont_done)
+ mi_state <= MI_ST_IDLE;
+ default: mi_state <= MI_ST_IDLE;
+ endcase
- /*
- * capture the cmd and buffer
- * rx_cmd is a one shot at the end that triggers the state machine
- */
- assign rx_cmd = i2c_rx_done;
-
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- cmd <= 7'h0;
- else if ( i2c_rx_we && cnt == 4'h0 )
- cmd <= i2c_d_in;
- end
-
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- begin
- for (i=1; i<=BUFFER_SZ; i=i+1)
- begin
- buffer[i] <= 'h0;
- end
- end
- else if ( i2c_rx_we && cnt > 0 && cnt <= BUFFER_SZ )
- buffer[cnt] <= i2c_d_in;
+
+ // MDIO INIT
+ // TODO: Configure PHY LEDs
+ always @(posedge clk or negedge rstn)
+ if (!rstn) begin
+ mdio_init_mux_sel <= 2'b00;
+ mdio_init_reg_addr <= 'd3; // PHYIDR2
+ mdio_init_routine_addr <= 'd20;
+ mdio_init_w_data_h <= 8'h00;
+ mdio_init_w_data_l <= 8'h00;
end
-
- /*
- * counter for I2c rx buffer.
- */
- always @(posedge clk or negedge rstn)
- begin
- if ( !rstn )
- cnt <= 'h0;
- else if (i2c_rx_done)
- cnt <= 'h0;
- else if (i2c_rx_we )
- cnt <= cnt + 1;
+ else if (mi_state == MI_ST_1) begin // Extended Read of PHY0 PROG_GAIN
+ mdio_init_mux_sel <= 2'b00;
+ mdio_init_routine_addr <= 'd20; // 'd60;
+ mdio_init_w_data_h <= 8'h01;
+ mdio_init_w_data_l <= 8'hD5;
end
+ else if (mi_state == MI_ST_3) begin // Extended Write of PHY0 PROG_GAIN
+ mdio_init_routine_addr <= 'd80;
+ mdio_init_w_data_h <= 8'hF5;
+ mdio_init_w_data_l <= 8'h02;
+ end
+ else if (mi_state == MI_ST_5) begin // Extended Read of PHY1 PROG_GAIN
+ mdio_init_mux_sel <= 2'b01;
+ mdio_init_routine_addr <= 'd60;
+ mdio_init_w_data_h <= 8'h01;
+ mdio_init_w_data_l <= 8'hD5;
+ end
+ else if (mi_state == MI_ST_7) begin // Extended Write of PHY1 PROG_GAIN
+ mdio_init_routine_addr <= 'd80;
+ mdio_init_w_data_h <= 8'hF5;
+ mdio_init_w_data_l <= 8'h03;
+ end
+
+ /*
+ * Debug
+ */
+ assign gpio = 8'h00;
-
+
endmodule
diff --git a/src/half_fifo.v b/src/half_fifo.v
index e18f543..c85f6ac 100644
--- a/src/half_fifo.v
+++ b/src/half_fifo.v
@@ -1,7 +1,8 @@
/*
* half_fifo.v
*
- * Copyright (C) 2018, 2019 Mind Chasers Inc.
+ * Copyright (C) 2024-2025 Private Island Networks Inc.
+ * Copyright (C) 2018-2022 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.
@@ -15,180 +16,204 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- * function: micro / FIFO interface
+ * Internal Controller / FIFO interface for accessing Ethernet Switch
+ *
*
*/
-`timescale 1ns /10ps
-
-module half_fifo #(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11 )
+module half_fifo #(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11)
(
input rstn,
- input uc_clk,
input fifo_clk,
+ input uc_clk,
+
+ // controller interrupt support
+ output reg rx_fifo_int, // signals that a complete packet has arrived
+ input rx_fifo_int_acked,
- // UC interrupt support
- output reg fifo_we_int,
-
- // tx_mode
- input tx_mode,
-
- // UC side: common DPRAM signals for RX and TX
+ // controller interface
input [DPRAM_DEPTH-1:0] dpram_addr,
- input [DATA_WIDTH-1:0] dpram_din,
- output reg [DATA_WIDTH-1:0] dpram_dout,
+ input [DPRAM_DEPTH-1:0] dpram_din, // size it to include 11-bit pointers
+ output reg [DPRAM_DEPTH-1:0] dpram_dout, // size it to include 11-bit pointers
input dpram_we,
input dpram_oe,
- // UC select signals
input dpram_ptrs_sel,
- input dpram_rx_sel,
input dpram_tx_sel,
+ input dpram_rx_sel,
- // FIFO TX (input)
+ // FIFO RX (switch -> hfifo -> controller)
input fifo_we,
input [DATA_WIDTH-1:0] fifo_d_in,
- // FIFO RX (output)
+ // FIFO TX (controller -> hfifo -> switch)
input fifo_re,
+ output reg [10:0] tx_byte_cnt,
output [DATA_WIDTH-1:0] fifo_d_out,
-
- // FIFO flags
- output rx_empty, // dpram 0 (reader)
- output tx_full
+ output tx_empty
);
+`define INCLUDED
+`include "cont_params.v"
+`undef INCLUDED
+
/*
* Pointers for accessing memory.
- * UC writes RX and reads TX
- * Switch writes (via FIFO I/F) TX and reads RX
+ * UC writes TX and reads RX
+ * Switch writes (via FIFO I/F) RX and reads TX
+ * This is the opposite of the system view
*/
-reg [DPRAM_DEPTH-1:0] rx_wr_ptr;
-reg [DPRAM_DEPTH-1:0] rx_rd_ptr;
+reg [DPRAM_DEPTH-1:0] rx_wr_ptr, rx_wr_ptr_latched;
-reg [DPRAM_DEPTH-1:0] tx_wr_ptr;
+reg [DPRAM_DEPTH-1:0] tx_wr_ptr, tx_wr_ptr_latched;
reg [DPRAM_DEPTH-1:0] tx_rd_ptr;
+reg tx_wr_ptr_written, tx_wr_ptr_written_m1, tx_wr_ptr_written_m2;
+
reg fifo_we_m1;
reg reset_ptrs;
-wire [DATA_WIDTH-1:0] dpram_rx_dout, dpram_tx_dout;
+wire [DATA_WIDTH-1:0] dpram_tx_dout, dpram_rx_dout;
-/* read data mux */
+/* read data mux, refer to addr params above */
always @(*)
- casez({ dpram_rx_sel, dpram_tx_sel, dpram_ptrs_sel, dpram_addr[2:0] } )
- 6'b001000: dpram_dout = rx_wr_ptr;
- 6'b001001: dpram_dout = rx_rd_ptr;
- 6'b001010: dpram_dout = tx_wr_ptr;
- 6'b001011: dpram_dout = tx_rd_ptr;
- 6'b001100: dpram_dout = reset_ptrs;
- 6'b010???: dpram_dout = dpram_tx_dout;
- 6'b100???: dpram_dout = dpram_rx_dout;
- default: dpram_dout = dpram_tx_dout;
+ casez({ dpram_tx_sel, dpram_rx_sel, dpram_ptrs_sel, dpram_addr[2:0] })
+ 6'b001000: dpram_dout = tx_wr_ptr;
+ 6'b001001: dpram_dout = tx_rd_ptr; // meta stable
+ 6'b001010: dpram_dout = rx_wr_ptr_latched;
+ 6'b001011: dpram_dout = 11'd0;
+ 6'b001100: dpram_dout = {10'd0, reset_ptrs};
+ 6'b010???: dpram_dout = {2'b00, dpram_rx_dout};
+ 6'b100???: dpram_dout = {2'b00, dpram_tx_dout};
+ default: dpram_dout = {2'b00, dpram_rx_dout};
endcase
always @(posedge uc_clk, negedge rstn)
- if ( !rstn )
+ if (!rstn)
reset_ptrs <= 1'b0;
- else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h4 )
+ else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_RESET_PTRS)
reset_ptrs <= dpram_din[0];
-
-/* RX wr ptr (UC writes) */
+
always @(posedge uc_clk, negedge rstn)
- if ( !rstn )
- rx_wr_ptr <= 'h0;
- else if ( reset_ptrs )
- rx_wr_ptr <= 'h0;
- else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h0 )
- rx_wr_ptr <= dpram_din;
-
-/* TX rd ptr (uP reads) */
+ if (!rstn)
+ tx_byte_cnt <= 11'd0;
+ else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_BYTE_CNT_ADDR)
+ tx_byte_cnt <= dpram_din;
+
+/* TX wr ptr (UC writes) */
always @(posedge uc_clk, negedge rstn)
- if ( !rstn )
- tx_rd_ptr <= 'h0;
- else if ( reset_ptrs )
- tx_rd_ptr <= 'h0;
- else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h3 )
- tx_rd_ptr <= dpram_din;
+ if (!rstn) begin
+ tx_wr_ptr <= 'h0;
+ tx_wr_ptr_written <= 1'b0;
+ end
+ else if (reset_ptrs) begin
+ tx_wr_ptr <= 'h0;
+ tx_wr_ptr_written <= 1'b1;
+ end
+ else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_WR_PTR_ADDR) begin
+ tx_wr_ptr <= dpram_din;
+ tx_wr_ptr_written <= 1'b1;
+ end
+ else
+ tx_wr_ptr_written <= 1'b0;
-/* RX rd ptr (switch reads via FIFO), auto increment */
always @(posedge fifo_clk, negedge rstn)
- if( !rstn )
- rx_rd_ptr <= 'd0;
- else if ( reset_ptrs )
- rx_rd_ptr <= 'd0;
- else if ( fifo_re && !rx_empty ) // advance the pointer if FIFO isn't empty
- rx_rd_ptr <= rx_rd_ptr + 1;
-
- /* TX wr ptr (switch writes via FIFO) */
+ if (!rstn) begin
+ tx_wr_ptr_written_m1 <= 1'b0;
+ tx_wr_ptr_written_m2 <= 1'b0;
+ end
+ else begin
+ tx_wr_ptr_written_m1 <= tx_wr_ptr_written;
+ tx_wr_ptr_written_m2 <= tx_wr_ptr_written_m1;
+ end
+
+
always @(posedge fifo_clk, negedge rstn)
- if( !rstn )
- tx_wr_ptr <= 'd0;
- else if ( reset_ptrs )
- tx_wr_ptr <= 'd0;
- else if ( fifo_we )
- tx_wr_ptr <= tx_wr_ptr + 1;
+ if(!rstn)
+ tx_wr_ptr_latched <= 8'h00;
+ else if (tx_wr_ptr_written_m2)
+ tx_wr_ptr_latched <= tx_wr_ptr;
-
-assign rx_empty = (rx_rd_ptr == rx_wr_ptr) ? 1'b1 : 1'b0;
-assign tx_full = (tx_rd_ptr != tx_wr_ptr) ? 1'b1 : 1'b0;
+/* TX rd ptr (switch reads via FIFO), auto increment */
+always @(posedge fifo_clk, negedge rstn)
+ if(!rstn)
+ tx_rd_ptr <= 11'd0;
+ else if (reset_ptrs)
+ tx_rd_ptr <= 11'd0;
+ else if (fifo_re && !tx_empty) // advance the pointer if FIFO isn't empty
+ tx_rd_ptr <= tx_rd_ptr + 1'b1;
+
+/* RX wr ptr (switch writes via FIFO) */
+always @(posedge fifo_clk, negedge rstn)
+ if(!rstn)
+ rx_wr_ptr <= 11'd0;
+ else if (reset_ptrs)
+ rx_wr_ptr <= 11'd0;
+ else if (fifo_we)
+ rx_wr_ptr <= rx_wr_ptr + 1'b1;
+assign tx_empty = (tx_rd_ptr == tx_wr_ptr_latched);
-
-/* Assert interrupt whenever fifo_we is negated ( writing is done ) */
+/* Assert interrupt whenever fifo_we is negated (writing is done) */
always @(posedge fifo_clk, negedge rstn)
- if ( !rstn )
+ if (!rstn)
fifo_we_m1 <= 1'b0;
else
fifo_we_m1 <= fifo_we;
-
+// Metastability note: rx_wr_ptr_latched should be read one or more clock cycles after rx_fifo_int asserts
always @(posedge fifo_clk, negedge rstn)
- if ( !rstn )
- fifo_we_int <= 1'b0;
- else if ( !fifo_we & fifo_we_m1 )
- fifo_we_int <= 1'b1;
- else
- fifo_we_int <= 1'b0;
+ if (!rstn) begin
+ rx_fifo_int <= 1'b0;
+ rx_wr_ptr_latched <= 11'd0;
+ end
+ else if (!fifo_we & fifo_we_m1) begin // end of write
+ rx_fifo_int <= 1'b1;
+ rx_wr_ptr_latched <= rx_wr_ptr;
+ end
+ else if (rx_fifo_int_acked) // clear interrupt
+ rx_fifo_int <= 1'b0;
-
-/* micro uses A side, FIFO uses B side */
-dpram dpram_rx(
- .rstn( rstn ),
- .a_clk( uc_clk ),
- .a_clk_e( dpram_rx_sel ),
- .a_we( dpram_we ),
- .a_oe( 1'b1 ),
- .a_addr( { 2'b00, dpram_addr } ),
- .a_din( dpram_din ),
- .a_dout( dpram_rx_dout ),
+/* controller uses A side, FIFO uses B side
+ * controller writes TX path and reads RX path */
+// 2K DPRAM
+dpram_inf dpram_tx(
+ .rstn(rstn),
+ .a_clk(uc_clk),
+ .a_clk_e(dpram_tx_sel),
+ .a_we(dpram_we),
+ .a_oe(1'b1),
+ .a_addr(dpram_addr),
+ .a_din(dpram_din[8:0]),
+ .a_dout(dpram_tx_dout),
// port B
- .b_clk( fifo_clk ),
- .b_clk_e( 1'b1 ),
- .b_we( 1'b0 ),
- .b_oe( fifo_re ),
- .b_addr( { 2'b00, rx_rd_ptr } ),
- .b_din( 9'h0 ),
- .b_dout( fifo_d_out )
+ .b_clk(fifo_clk),
+ .b_clk_e(1'b1),
+ .b_we(1'b0),
+ .b_oe(fifo_re),
+ .b_addr(tx_rd_ptr),
+ .b_din(9'h0),
+ .b_dout(fifo_d_out)
);
-dpram dpram_tx(
- .rstn( rstn ),
- .a_clk( uc_clk ),
- .a_clk_e( dpram_tx_sel ),
- .a_we( dpram_we ),
- .a_oe( 1'b1 ),
- .a_addr( { 2'b00, dpram_addr } ),
- .a_din( dpram_din ),
- .a_dout( dpram_tx_dout ),
+// 2K DPRAM
+dpram_inf dpram_rx(
+ .rstn(rstn),
+ .a_clk(uc_clk),
+ .a_clk_e(dpram_rx_sel),
+ .a_we(1'b0),
+ .a_oe(1'b1),
+ .a_addr(dpram_addr),
+ .a_din(9'h000),
+ .a_dout(dpram_rx_dout),
// port B
- .b_clk( fifo_clk ),
- .b_clk_e( 1'b1 ),
- .b_we( fifo_we ),
- .b_oe( 1'b0 ),
- .b_addr( { 2'b00, tx_wr_ptr } ),
- .b_din( fifo_d_in ),
- .b_dout( )
+ .b_clk(fifo_clk),
+ .b_clk_e(1'b1),
+ .b_we(fifo_we),
+ .b_oe(1'b0),
+ .b_addr(rx_wr_ptr),
+ .b_din(fifo_d_in),
+ .b_dout()
);
endmodule
diff --git a/src/switch.v b/src/switch.v
index 98aec4a..fa6d75e 100644
--- a/src/switch.v
+++ b/src/switch.v
@@ -1,7 +1,8 @@
/*
- * switch.v
+ * switch.v
*
- * Copyright 2018, 2019, 2020, 2021 Mind Chasers Inc.
+ * Copyright 2024, 2025 Private Island Networks Inc.
+ * Copyright 2018 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.
@@ -15,113 +16,104 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- * function: Soft Ethernet Switch
+ * function: switch packet paths from RX to TX for LF_A_V01
*
*/
-`timescale 1ns /10ps
-
-module switch(
+module switch #(parameter NUM_PHYS=3)
+(
input rstn,
input clk,
// PHY status
- input [3:0] phy_up,
- input [3:0] mode_100Mbit,
+ input [NUM_PHYS-1:0] phy_up,
+ input [NUM_PHYS-1: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_0u,
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,
+ input [8:0] rx_d_u0,
// 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,
+ output reg rx_fifo_re_01, rx_fifo_re_02, rx_fifo_re_0u,
+ output reg rx_fifo_re_10, rx_fifo_re_12,
+ output reg rx_fifo_re_20, rx_fifo_re_21,
+ output reg rx_fifo_re_u0,
// 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,
+ input rx_fifo_empty_01, rx_fifo_empty_02, rx_fifo_empty_0u,
+ input rx_fifo_empty_10, rx_fifo_empty_12,
+ input rx_fifo_empty_20, rx_fifo_empty_21,
+ input rx_fifo_empty_u0,
+
+ input [NUM_PHYS-1:0] rx_wr_done,
// RX Byte Count
- input [3:0] rx_wr_done,
input [10:0] rx0_byte_cnt,
input [10:0] rx1_byte_cnt,
input [10:0] rx2_byte_cnt,
- input [10:0] rx3_byte_cnt,
+ input [10:0] rxu_byte_cnt,
// 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,
+ input [NUM_PHYS-1: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,
+ output reg [NUM_PHYS-1:0] tx_fifo_empty,
// TX modes for the PHYs and uc
output reg [2:0] tx_mode0,
output reg [2:0] tx_mode1,
output reg [2:0] tx_mode2,
- output reg [2:0] tx_mode3,
- output reg tx_modeu,
+ output reg [2:0] tx_modeu,
// TX byte cnt
output reg [10:0] tx0_byte_cnt,
output reg [10:0] tx1_byte_cnt,
output reg [10:0] tx2_byte_cnt,
- output reg [10:0] tx3_byte_cnt,
- // TX Source Select
- output reg [2:0] tx_src_sel0,
- output reg [2:0] tx_src_sel1,
- output reg [2:0] tx_src_sel2,
- output reg [2:0] tx_src_sel3,
+ output reg [2:0] tx0_src_sel,
+ output reg [2:0] tx1_src_sel,
+ output reg [2:0] tx2_src_sel,
// TX state machine done flag
- input [3:0] tx_f,
+ input [NUM_PHYS-1:0] tx_f,
// TX custom packet
input tx_custom
);
+
+
// IPG for Port 0
wire ipg_met;
reg [6:0] ipg_cnt;
-reg [3:0] fr_100mbit_cnt;
-reg i_tx_fifo_we_u;
+reg rx_fifo_empty_u0_m1, rx_fifo_empty_u0_m2;
-reg [10:0] i_rx0_byte_cnt, i_rx1_byte_cnt, i_rx2_byte_cnt, i_rx3_byte_cnt;
+reg [3:0] fr_100mbit_cnt;
+reg i_tx_fifo_we_u;
+reg [10:0] i_rx0_byte_cnt, i_rx1_byte_cnt, i_rx2_byte_cnt;
+
+`define INCLUDED
`include "ethernet_params.v"
-`include "sgmii_params.v"
+`undef INCLUDED
localparam SEL_PHY0 = 3'b000,
SEL_PHY1 = 3'b001,
SEL_PHY2 = 3'b010,
- SEL_PHY3 = 3'b011,
SEL_UC = 3'b111;
@@ -144,12 +136,6 @@ always @(posedge clk, negedge rstn)
else if ( rx_wr_done[2])
i_rx2_byte_cnt <= rx2_byte_cnt;
-always @(posedge clk, negedge rstn)
- if ( !rstn )
- i_rx3_byte_cnt <= 'h0;
- else if ( rx_wr_done[3])
- i_rx3_byte_cnt <= rx3_byte_cnt;
-
assign ipg_met = ipg_cnt >= IPG ? 1'b1 : 1'b0;
/* free running 100Mbit counter */
@@ -159,7 +145,7 @@ always @(posedge clk, negedge rstn)
else if ( fr_100mbit_cnt == 4'd9 )
fr_100mbit_cnt <= 4'd0;
else
- fr_100mbit_cnt <= fr_100mbit_cnt + 1;
+ fr_100mbit_cnt <= fr_100mbit_cnt + 1'b1;
/* IPG counter */
always @(posedge clk, negedge rstn)
@@ -170,16 +156,28 @@ always @(posedge clk, negedge rstn)
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;
+ ipg_cnt <= ipg_cnt + 1'b1;
+
+
+// Transfer to the pclk domain
+always @(posedge clk, negedge rstn)
+ if ( !rstn ) begin
+ rx_fifo_empty_u0_m1 <= 1'b1;
+ rx_fifo_empty_u0_m2 <= 1'b1;
+ end
+ else begin
+ rx_fifo_empty_u0_m1 <= rx_fifo_empty_u0;
+ rx_fifo_empty_u0_m2 <= rx_fifo_empty_u0_m1;
+ end
// TX0 Switch Logic
-// Possible sources: 1, 2
+// Possible sources: u, 1, 2
always @(posedge clk, negedge rstn)
if ( !rstn )
begin
tx_mode0 <= TX_MODE_AN;
- tx_src_sel0 <= SEL_PHY1;
+ tx0_src_sel <= SEL_PHY1;
tx0_byte_cnt <= 'h0;
end
else if ( tx_f[0] )
@@ -192,24 +190,34 @@ always @(posedge clk, negedge rstn)
tx_mode0 <= TX_MODE_AN;
else if ( !ipg_met )
tx_mode0 <= TX_MODE_IDLE;
- else if (tx_src_sel0==SEL_PHY1 && !rx_fifo_empty_20 )
+ else if (!rx_fifo_empty_u0_m2 ) // controller has data
begin
tx_mode0 <= TX_MODE_XMT_CUSTOM;
- tx_src_sel0 <= SEL_PHY2;
+ tx0_src_sel <= SEL_UC;
+ tx0_byte_cnt <= rxu_byte_cnt;
+ end
+`ifdef PHY2_PRESENT
+ else if (tx0_src_sel==SEL_PHY1 && !rx_fifo_empty_20 )
+ begin
+ tx_mode0 <= TX_MODE_XMT_PKT;
+ tx0_src_sel <= SEL_PHY2;
tx0_byte_cnt <= i_rx2_byte_cnt;
end
+`endif
else if (!rx_fifo_empty_10 )
begin
tx_mode0 <= TX_MODE_XMT_PKT;
- tx_src_sel0 <= SEL_PHY1;
+ tx0_src_sel <= SEL_PHY1;
tx0_byte_cnt <= i_rx1_byte_cnt;
end
+`ifdef PHY2_PRESENT
else if (!rx_fifo_empty_20 )
begin
- tx_mode0 <= TX_MODE_XMT_CUSTOM;
- tx_src_sel0 <= SEL_PHY2;
+ tx_mode0 <= TX_MODE_XMT_PKT;
+ tx0_src_sel <= SEL_PHY2;
tx0_byte_cnt <= i_rx2_byte_cnt;
end
+`endif
TX_MODE_XMT_PKT:
if ( !phy_up[0] )
tx_mode0 <= TX_MODE_AN;
@@ -218,13 +226,14 @@ always @(posedge clk, negedge rstn)
default: tx_mode0 <= TX_MODE_IDLE;
endcase
+
// TX0 data mux
always @(*) begin
- case(tx_src_sel0)
+ 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;
+ SEL_UC: tx_d0 = rx_d_u0;
default: tx_d0 = 9'h000;
endcase
end
@@ -233,31 +242,31 @@ end
always @(*) begin
rx_fifo_re_10 = 1'b0;
rx_fifo_re_20 = 1'b0;
- rx_fifo_re_30 = 1'b0;
- case(tx_src_sel0)
+ rx_fifo_re_u0 = 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];
+ SEL_UC: rx_fifo_re_u0 = tx_fifo_re[0];
endcase
end
// TX0 FIFO Empty Routing
always @(*) begin
- case(tx_src_sel0)
+ 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;
+ SEL_UC: tx_fifo_empty[0] = rx_fifo_empty_u0_m2;
+ default: tx_fifo_empty[0] = 1'b1;
endcase
end
// TX1 Switch Logic
-// Possible sources: 0, 2, 3 in priority
+// Possible sources: 0, 2 in priority
always @(posedge clk, negedge rstn)
if ( !rstn )
begin
tx_mode1 <= TX_MODE_AN;
- tx_src_sel1 <= SEL_PHY0;
+ tx1_src_sel <= SEL_PHY0;
end
else if ( tx_f[1] )
case( tx_mode1 )
@@ -267,31 +276,25 @@ always @(posedge clk, negedge rstn)
TX_MODE_IDLE:
if ( !phy_up[1] )
tx_mode1 <= TX_MODE_AN;
- else if (tx_src_sel1==SEL_PHY0 && !rx_fifo_empty_21 )
- begin
- tx_mode1 <= TX_MODE_XMT_PKT;
- tx_src_sel1 <= SEL_PHY2;
- end
- else if (tx_src_sel1==SEL_PHY0 && !rx_fifo_empty_31 )
+`ifdef PHY2_PRESENT
+ else if (tx1_src_sel==SEL_PHY0 && !rx_fifo_empty_21 )
begin
tx_mode1 <= TX_MODE_XMT_PKT;
- tx_src_sel1 <= SEL_PHY3;
+ tx1_src_sel <= SEL_PHY2;
end
+`endif
else if (!rx_fifo_empty_01 )
begin
tx_mode1 <= TX_MODE_XMT_PKT;
- tx_src_sel1 <= SEL_PHY0;
+ tx1_src_sel <= SEL_PHY0;
end
+`ifdef PHY2_PRESENT
else if (!rx_fifo_empty_21 )
begin
tx_mode1 <= TX_MODE_XMT_PKT;
- tx_src_sel1 <= SEL_PHY2;
- end
- else if (!rx_fifo_empty_31 )
- begin
- tx_mode1 <= TX_MODE_XMT_PKT;
- tx_src_sel1 <= SEL_PHY3;
+ tx1_src_sel <= SEL_PHY2;
end
+`endif
TX_MODE_XMT_PKT:
if ( !phy_up[1] )
tx_mode1 <= TX_MODE_AN;
@@ -302,11 +305,10 @@ always @(posedge clk, negedge rstn)
// TX1 data mux
always @(*) begin
- case(tx_src_sel1)
+ 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
@@ -316,21 +318,18 @@ end
always @(*) begin
rx_fifo_re_01 = 1'b0;
rx_fifo_re_21 = 1'b0;
- rx_fifo_re_31 = 1'b0;
- case(tx_src_sel1)
+ 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(tx_src_sel1)
+ 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
@@ -339,16 +338,13 @@ 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.
+ * Possible Sources: 0, 1
*/
always @(posedge clk, negedge rstn)
if ( !rstn )
begin
tx_mode2 <= TX_MODE_AN;
- tx_src_sel2 <= SEL_PHY0;
+ tx2_src_sel <= SEL_PHY0;
end
else if ( tx_f[2] )
case( tx_mode2 )
@@ -358,30 +354,20 @@ always @(posedge clk, negedge rstn)
TX_MODE_IDLE:
if ( !phy_up[2] )
tx_mode2 <= TX_MODE_AN;
- else if (tx_src_sel2==SEL_PHY0 && !rx_fifo_empty_12 )
+ else if (tx2_src_sel==SEL_PHY0 && !rx_fifo_empty_12 )
begin
tx_mode2 <= TX_MODE_XMT_PKT;
- tx_src_sel2 <= SEL_PHY1;
+ tx2_src_sel <= SEL_PHY1;
end
else if (!rx_fifo_empty_02 )
begin
tx_mode2 <= TX_MODE_XMT_PKT;
- tx_src_sel2 <= SEL_PHY0;
+ tx2_src_sel <= SEL_PHY0;
end
else if (!rx_fifo_empty_12 )
begin
tx_mode2 <= TX_MODE_XMT_PKT;
- tx_src_sel2 <= SEL_PHY1;
- end
- else if (!rx_fifo_empty_u2)
- begin
- tx_mode2 <= TX_MODE_XMT_PKT;
- tx_src_sel2 <= SEL_UC;
- end
- else if (tx_custom)
- begin
- tx_mode2 <= TX_MODE_XMT_CUSTOM;
- tx_src_sel2 <= SEL_PHY2;
+ tx2_src_sel <= SEL_PHY1;
end
TX_MODE_XMT_PKT:
if ( !phy_up[2] )
@@ -393,11 +379,10 @@ always @(posedge clk, negedge rstn)
// TX2 data mux
always @(*) begin
- case(tx_src_sel2)
+ 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
@@ -406,119 +391,44 @@ end
always @(*) begin
rx_fifo_re_02 = 1'b0;
rx_fifo_re_12 = 1'b0;
- rx_fifo_re_u2 = 1'b0;
- case(tx_src_sel2)
+ 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(tx_src_sel2)
+ 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; //
- 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;
- tx_src_sel3 <= 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 (tx_src_sel3==SEL_PHY1 && !rx_fifo_empty_03 )
- begin
- tx_mode3 <= TX_MODE_XMT_PKT;
- tx_src_sel3 <= SEL_PHY0;
- end
- else if (!rx_fifo_empty_13 )
- begin
- tx_mode3 <= TX_MODE_XMT_PKT;
- tx_src_sel3 <= SEL_PHY1;
- end
- else if (!rx_fifo_empty_03 )
- begin
- tx_mode3 <= TX_MODE_XMT_PKT;
- tx_src_sel3 <= 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(tx_src_sel3)
- 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(tx_src_sel3)
- 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(tx_src_sel3)
- 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
+ * The only possible driver is PHY0
*
* 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;
+assign tx_du = rx_d_0u;
always @(*)
- if ( !rx_fifo_empty_2u )
+ if ( !rx_fifo_empty_0u )
begin
i_tx_fifo_we_u = 1'b1;
- rx_fifo_re_2u = 1'b1;
+ rx_fifo_re_0u = 1'b1;
end
else
begin
i_tx_fifo_we_u = 1'b0;
- rx_fifo_re_2u = 1'b0;
+ rx_fifo_re_0u = 1'b0;
end
always @(posedge clk, negedge rstn)
@@ -528,4 +438,4 @@ always @(posedge clk, negedge rstn)
tx_fifo_we_u <= i_tx_fifo_we_u;
-endmodule
+endmodule \ No newline at end of file

Highly Recommended Verilog Books