From 8363d90c7e3fe116d3a4ce12c3037d875f133a47 Mon Sep 17 00:00:00 2001 From: Private Island Networks Date: Mon, 1 Sep 2025 12:37:36 -0400 Subject: cont: update controller complex for Betsy: see privateisland.tech/dev/pi-controller --- src/controller.v | 1055 +++++++++++++++++++++++++++++++++++------------------- src/half_fifo.v | 263 ++++++++------ src/switch.v | 300 ++++++---------- 3 files changed, 930 insertions(+), 688 deletions(-) (limited to 'src') 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 -- cgit v1.2.3-8-gadcc