diff options
Diffstat (limited to 'src/controller.v')
| -rw-r--r-- | src/controller.v | 779 |
1 files changed, 779 insertions, 0 deletions
diff --git a/src/controller.v b/src/controller.v new file mode 100644 index 0000000..54d6976 --- /dev/null +++ b/src/controller.v @@ -0,0 +1,779 @@ +/* + * controller.v + * + * 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * function: FPGA internal state machine controller + * + * see https://privateisland.tech/dev/pi-doc for further details + * + * + */ + +module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3) +( + input rstn, + input clk, + + // status & errors from ports + input [NUM_PHYS-1:0] phy_int, + input [NUM_PHYS-1:0] mac_int, + + // link status + 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 [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 [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, + + // Device Resets + output reg [NUM_PHYS-1:0] phy_resetn, + output reg [NUM_PHYS-1:0] mac_reset, + + // Debug + output [7:0] gpio +); + +`define INCLUDED +`include "cont_params.v" +`include "ethernet_params.v" +`undef INCLUDED + + /* 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; + + // 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; + + /* 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; + + /* + * 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 <= CONT_ST_INIT; + else + case (cont_state) + 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]; + + // 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]; + + // 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]; + + // 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 + 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 + */ + + // 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) + mdio_cont_start <= 1'b0; + 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 + + // mdio_routine_addr depends on msg_type + always @(posedge clk or negedge rstn) + begin + if (!rstn) + mdio_routine_addr <= 'd0; + 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 + + // set mdio_phy_addr + assign mdio_phy_addr = 5'h0c; // Set phy_addr[3:2] + + // set mdio_reg_addr + always @(posedge clk or negedge rstn) + begin + if (!rstn) + mdio_reg_addr <= 'd0; + 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 (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 + + // 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 + + // 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; + + // 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 + * + **********************************************************************/ + + // Memory Controller Tie Offs + assign mem_oe = 1'b1; + + // 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 + + + // 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; + + // 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]; + + // 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 + + /*********************************************************************** + * + * MDIO Initialization + * + * TODO: Specific for Betsy, such as PHY LED assignment + * + **********************************************************************/ + + // 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 + + + // 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 + 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 |



