From 5723ec1a34181f1cfef9b8e870ab2e9a0362487c Mon Sep 17 00:00:00 2001
From: mindchasers <privateisland@mindchasers.com>
Date: Wed, 1 May 2019 18:16:45 -0400
Subject: initial commit, all basic functions work on Darsena V02

---
 source/controller.v | 474 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 474 insertions(+)
 create mode 100644 source/controller.v

(limited to 'source/controller.v')

diff --git a/source/controller.v b/source/controller.v
new file mode 100644
index 0000000..6ede860
--- /dev/null
+++ b/source/controller.v
@@ -0,0 +1,474 @@
+/*
+ *       controller.v
+ *       
+ *   Copyright (C) 2018, 2109 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 controller
+ *	
+ */
+ 
+`timescale 1ns /10ps
+
+module controller	#(parameter ADDR_SZ = 7)
+(
+	input rstn,
+	input clk,
+	input init,
+	input pulse_100ms,
+	
+	// PCS status lines
+	input [3:0] pcs_rx_error,
+	input [1:0] pll_lol,
+	
+	// link status
+	input [3:0] port_up,
+	
+	// mdio_controller interface
+	output	reg mdio_cont_start,
+	input 	mdio_cont_done,
+	output reg [ADDR_SZ-1:0] mdio_routine_addr,
+	input mdio_run,			// the mdio controller is active
+	
+	// mdio_data params
+	output reg [4:0] mdio_page,
+	output reg [4:0] mdio_reg_addr,
+	output reg [7:0] mdio_w_data_h, 
+	output reg [7:0] mdio_w_data_l,
+	
+	// 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,
+	
+	output reg [1:0]  mdio_mux_sel,
+	output i2c_fifo_priority,
+	
+	// TX custom packet
+	output reg tx_metrics
+
+);
+
+	// state encoding  
+	localparam 	BUFFER_SZ = 8;	// index starts at 1, 0 is cmd
+
+	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;
+
+	// 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;
+
+	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 i2c_fifo_priority = 1'b1;
+	assign pcs_s = { pll_lol, pcs_rx_error };
+	assign link_s = port_up;
+	
+	/* 
+	*  	main state machine for controller 
+	*/
+    always @(posedge clk or negedge rstn) 
+		begin 
+			if ( !rstn )
+				cont_state <= S0;
+			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;
+					default: cont_state <= cont_state;	
+				endcase
+		end
+		
+/*
+*	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
+		
+	// 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	
+		
+	// 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;
+			else
+				cont_cmd <= 1'b0;
+		end	
+
+	/*
+	*	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
+	
+	
+    always @(posedge clk or negedge rstn) 
+		begin 
+			if ( !rstn )
+				mdio_cont_start <= 1'b0;
+			else if ( cont_done && mdio_cmd )
+				mdio_cont_start <= 1'b1;
+			else
+				mdio_cont_start <= 1'b0;
+		end
+		
+	/*
+	* 	driver: mdio_route_addr
+	*/
+    always @(posedge clk or negedge rstn) 
+		begin 
+			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;
+		end
+		
+	// mdio_cont_busy and mux self
+    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
+		
+	/* fifo_mux_sel = 1 when controller does NOT have FIFO bus */
+	assign fifo_mux_sel = mdio_cont_busy | mdio_run;
+		
+	/* set mdio page 	*/
+    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 )
+				mdio_reg_addr <= 'd0;
+			else if ( rx_cmd && cmd == ASCIIr )
+				mdio_reg_addr <= { buffer[1][0], buffer[2][3: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
+		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	
+		
+	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];
+
+	/* 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	
+		
+	// 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];
+	
+	// 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];
+
+				end
+		end	
+
+	assign mac_reset[0] = x_reg[0][0];
+	assign phy_resetn[0] = ~x_reg[0][1];
+
+	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	
+		
+	/* transmit test packet */
+    always @(posedge clk or negedge rstn) 
+		begin 
+			if ( !rstn )
+				tx_metrics <= 1'b0;
+			else if ( rx_cmd && cmd == ASCIIt )
+				tx_metrics <= 1'b1;
+			else
+				tx_metrics <= 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	
+
+		
+   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 <= { 2'b00, pcs_s };
+			else if ( cont_state == S2 && cmd == ASCIIl )	// link status
+				read_fifo_d_o <= { 3'b000, link_s };			
+		end
+
+	/*
+	*	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;
+		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;
+		end
+
+
+endmodule
-- 
cgit v1.2.3-8-gadcc