summaryrefslogtreecommitdiffhomepage
path: root/src/controller.v
diff options
context:
space:
mode:
Diffstat (limited to 'src/controller.v')
-rw-r--r--src/controller.v1055
1 files changed, 681 insertions, 374 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

Highly Recommended Verilog Books