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/bin_to_ascii.v    |  128 +++
 source/cam.v             |   85 ++
 source/clk_gen.v         |   67 ++
 source/controller.v      |  474 ++++++++++
 source/definitions.v     |   28 +
 source/dpram.v           |  102 +++
 source/drop2_fifo.v      |  255 ++++++
 source/drop_fifo.v       |  220 +++++
 source/ethernet_params.v |   38 +
 source/fcs.v             |  142 +++
 source/half_fifo.v       |  194 +++++
 source/i2c.v             |  391 +++++++++
 source/interrupts.v      |   77 ++
 source/ipv4.v            |  152 ++++
 source/mac.v             |  895 +++++++++++++++++++
 source/mdio.v            |  146 ++++
 source/mdio_cont.v       |  159 ++++
 source/mdio_data_ti.v    |  128 +++
 source/metrics.v         |  102 +++
 source/pcs.v             |  228 +++++
 source/pkt_filter.v      |   93 ++
 source/sgmii_params.v    |   50 ++
 source/spi.v             |  300 +++++++
 source/switch.v          |  480 ++++++++++
 source/sync2_fifo.v      |  141 +++
 source/sync4_fifo.v      |  206 +++++
 source/sync_fifo.v       |  110 +++
 source/top.v             | 2177 ++++++++++++++++++++++++++++++++++++++++++++++
 28 files changed, 7568 insertions(+)
 create mode 100644 source/bin_to_ascii.v
 create mode 100644 source/cam.v
 create mode 100644 source/clk_gen.v
 create mode 100644 source/controller.v
 create mode 100644 source/definitions.v
 create mode 100644 source/dpram.v
 create mode 100644 source/drop2_fifo.v
 create mode 100644 source/drop_fifo.v
 create mode 100644 source/ethernet_params.v
 create mode 100644 source/fcs.v
 create mode 100644 source/half_fifo.v
 create mode 100644 source/i2c.v
 create mode 100644 source/interrupts.v
 create mode 100644 source/ipv4.v
 create mode 100644 source/mac.v
 create mode 100644 source/mdio.v
 create mode 100644 source/mdio_cont.v
 create mode 100644 source/mdio_data_ti.v
 create mode 100644 source/metrics.v
 create mode 100644 source/pcs.v
 create mode 100644 source/pkt_filter.v
 create mode 100644 source/sgmii_params.v
 create mode 100644 source/spi.v
 create mode 100644 source/switch.v
 create mode 100644 source/sync2_fifo.v
 create mode 100644 source/sync4_fifo.v
 create mode 100644 source/sync_fifo.v
 create mode 100644 source/top.v

(limited to 'source')

diff --git a/source/bin_to_ascii.v b/source/bin_to_ascii.v
new file mode 100644
index 0000000..12464dc
--- /dev/null
+++ b/source/bin_to_ascii.v
@@ -0,0 +1,128 @@
+/*
+ *       bin_to_asc.v
+ *
+ *   Copyright (C) 2018, 2019 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: Convert binary to ASCII ( 16-bit or 8-bit )
+ *
+ */
+
+`timescale 1ns /10ps
+
+module bin_to_ascii(
+	input rstn,
+	input clk,
+	input width, 	    // 0 for 8-bit, 1 for 16-bit
+	
+	// mdio interface
+	input we_i,			// latch the data and start
+	input [15:0] d_in,	// binary in
+	
+	// mdio controller interface
+	output reg run,		// block has the output bus
+	output reg done,	// block is done it's processing, use as an internal reset
+	input busy,			// instruct the block to hold off on writing
+	
+	// write to output port
+	output we_o,	    // asserts we for each ascii word to write out	
+	output reg [6:0] d_out	// ascii out
+);
+
+	// ascii codes we use
+	localparam	ASCII_	= 7'h5f,
+				ASCIIq  = 7'h3f,
+				LF  	= 7'h0a,
+				CR 		= 7'h0d;
+
+
+	reg [2:0] cnt;	// count the nibbles, last two are for CR and LF
+	reg [3:0] d_bin_in_4;
+	reg [15:0] d;	// internally latched data
+
+	/* start running on we */
+    always @(posedge clk or negedge rstn) 
+		begin 
+			if ( !rstn | done )
+				run <= 1'b0;
+			else if ( we_i ) 
+				run <= 1'b1;
+		end
+		
+	/* register the incoming data */
+    always @(posedge clk, negedge rstn) 
+		begin 
+			if ( !rstn )
+				d <= 16'h0;
+			else if ( we_i ) 
+				d <= d_in;
+		end	
+
+	/* increment the counter when running, start at 0 or 2 depending on width */
+    always @(posedge clk or negedge rstn) 
+		begin 
+			if ( !rstn | done ) 
+				cnt <= 3'd0;
+			else if ( we_i & ~width )
+				cnt <= 3'd2;
+			else if ( run )
+				cnt <= cnt + 1;
+		end
+		
+    always @(posedge clk or negedge rstn) 
+		begin 
+			if ( !rstn ) 
+				done <= 1'b0;
+			else if ( cnt == 3'd5 )
+				done <= 1'b1;
+			else 
+				done <= 1'b0;
+		end
+		
+	assign we_o = run && ~done;
+		
+	/* d_bin_in_4 mux */
+	always@(*)
+		begin
+			case ( cnt )
+				3'b000: d_bin_in_4 = d[15:12];
+				3'b001: d_bin_in_4 = d[11:8];
+				3'b010: d_bin_in_4 = d[7:4];
+				3'b011: d_bin_in_4 = d[3:0];
+				default: d_bin_in_4 = d[3:0];
+			endcase
+		end
+
+	/* perform the conversion  */
+    always @(*) 
+		begin 
+			d_out = { 3'b011, d_bin_in_4 };
+			if ( cnt < 3'd4 && d_bin_in_4 >= 4'd10 )
+				case( d_bin_in_4 )
+					4'ha : d_out = 7'h61;
+					4'hb : d_out = 7'h62;
+					4'hc : d_out = 7'h63;
+					4'hd : d_out = 7'h64;
+					4'he : d_out = 7'h65;
+					4'hf : d_out = 7'h66;
+					default : d_out = 7'h3f;	// question mark
+				endcase
+			else if ( cnt == 3'd4 ) 
+				d_out = CR;
+			else if ( cnt == 3'd5 )
+				d_out = LF;
+		end
+		
+endmodule
+			
diff --git a/source/cam.v b/source/cam.v
new file mode 100644
index 0000000..082194a
--- /dev/null
+++ b/source/cam.v
@@ -0,0 +1,85 @@
+/* 
+ * 	cam.v
+ * 	
+ *   Copyright (C) 2018, 2019 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: single cycle, parameterized CAM 
+ *	
+ */
+ 
+`timescale 1ns /10ps
+
+module cam #(parameter DEPTH = 4,
+			parameter DEPTHW = 2,
+			parameter WIDTH = 32)
+(
+	input	rstn,
+	input	clk,
+	
+	// input for programming
+	input 	sel,
+	input 	we,
+	input 	[DEPTHW+1:0] addr,		// add two bits for the byte selects
+	input 	[7:0]	d_in,
+	
+	input 	search,
+	input	[(WIDTH-1):0]search_address,
+	
+	// output
+	output reg match
+);
+	
+	reg [(WIDTH-1):0] content[0:DEPTH-1];
+	reg [(DEPTH-1):0] valid;
+	integer i,j;
+	
+	// Program the CAM
+	always @(posedge clk, negedge rstn)
+		if( !rstn ) begin
+			for (i=0; i < DEPTH; i=i+1)	begin
+				content[i] <= 32'h0;
+				valid[i] <= 1'b0;
+			end
+		end
+		else if ( we && sel )
+			if (addr[1:0] == 2'b00) begin
+				content[addr[DEPTHW+1:2]][7:0] <= d_in;
+				valid[addr[DEPTHW+1:2]] <= 1'b1;
+			end
+			else if (addr[1:0] == 2'b01) begin
+				content[addr[DEPTHW+1:2]][15:8] <= d_in;
+				valid[addr[DEPTHW+1:2]] <= 1'b1;
+			end
+			else if (addr[1:0] == 2'b10) begin
+				content[addr[DEPTHW+1:2]][23:16] <= d_in;
+				valid[addr[DEPTHW+1:2]] <= 1'b1;
+			end
+			else if (addr[1:0] == 2'b11) begin
+				content[addr[DEPTHW+1:2]][31:24] <= d_in;
+				valid[addr[DEPTHW+1:2]] <= 1'b1;
+			end
+		
+	// search the CAM
+	always @(posedge clk) begin
+		match <= 1'b0;
+		for (j=0; j < DEPTH; j=j+1)	begin
+			if (search && valid[j] && search_address == content[j])
+				match <= 1'b1;
+
+		end
+	end
+	
+	
+endmodule
diff --git a/source/clk_gen.v b/source/clk_gen.v
new file mode 100644
index 0000000..9d3e054
--- /dev/null
+++ b/source/clk_gen.v
@@ -0,0 +1,67 @@
+/*
+ *       clk_gen.v
+ *
+ *   Copyright (C) 2018, 2019 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: Generate system / controller clocks from internal oscillator
+ *	
+ */
+
+`timescale 1ns /10ps
+
+module clk_gen(
+	input rstn,
+	output	clk_10,
+	output 	clk_5,
+	output	clk_2_5,
+	output	clk_1_25,
+	output  clk_slow
+);
+
+
+	wire clk;
+	reg [8:0] clk_cnt;
+	wire clk_0_625, clk_0_3125, clk_75K, clk_37_5K, clk_150K;
+	
+	/* 
+	+/- 15% variation in output frequency 
+	128 is the default for a 2.5 MHz clock, +/- 15% 
+	32 is 9.7 MHz
+	16 for 19.4 MHz.
+	*/
+	OSCG oscg_inst(.OSC(clk));
+	defparam oscg_inst.DIV = 32;	
+
+	always @ (posedge clk or negedge rstn) 
+	begin 
+	   if  ( !rstn )
+		   clk_cnt <= 0;
+	   else
+		   clk_cnt <= clk_cnt + 1;
+	end
+
+	assign clk_10 = clk;			// 10 MHz system clock
+	assign clk_5 = clk_cnt[0];
+	assign clk_2_5 = clk_cnt[1];
+	assign clk_1_25 = clk_cnt[2];	// 1.22MHz
+	assign clk_0_625 = clk_cnt[3];
+	assign clk_0_3125 = clk_cnt[4];
+	assign clk_150K = clk_cnt[5];
+	assign clk_75K = clk_cnt[6];
+	assign clk_37_5K = clk_cnt[7];
+
+	assign clk_slow = clk_37_5K;
+	
+endmodule
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
diff --git a/source/definitions.v b/source/definitions.v
new file mode 100644
index 0000000..e612262
--- /dev/null
+++ b/source/definitions.v
@@ -0,0 +1,28 @@
+/*
+ *       definitions.v
+ *
+ *   Copyright 2(C) 018, 2019 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: misc. constants
+ *
+ */
+
+// Debug Options
+//`define DEBUG_I2C
+//`define DEBUG_MDIO
+`define DEBUG_SPI
+
+// V02 boards can route UART to FT2232H
+`define ARD_EXP_UART
diff --git a/source/dpram.v b/source/dpram.v
new file mode 100644
index 0000000..53c1efc
--- /dev/null
+++ b/source/dpram.v
@@ -0,0 +1,102 @@
+/*	
+ * 	dpram.v
+ * 
+ *   Copyright (C) 2018, 2019 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: DPRAM wrapper
+ * 
+ */
+
+`timescale 1ns /10ps
+
+
+module dpram(
+	input  rstn,
+	
+	// port A
+	input a_clk,
+	input a_clk_e,
+	input a_we,
+	input a_oe,
+	input [10:0] a_addr,
+	input [8:0]  a_din,
+	output [8:0] a_dout,
+	
+	// port B
+	input b_clk,
+	input b_clk_e,
+	input b_we,
+	input b_oe,
+	input [10:0] b_addr,
+	input [8:0]  b_din,
+	output [8:0] b_dout
+);
+
+
+DP16KD dp16kd_inst(
+	// input data port A
+	.DIA17( 1'b0 ), .DIA16( 1'b0  ), .DIA15( 1'b0  ), .DIA14( 1'b0  ), .DIA13( 1'b0  ), 
+	.DIA12(  1'b0 ), .DIA11( 1'b0  ), .DIA10( 1'b0  ), .DIA9( 1'b0  ), .DIA8( a_din[8]  ), 
+	.DIA7( a_din[7] ), .DIA6( a_din[6]  ), .DIA5( a_din[5]  ), .DIA4( a_din[4] ), 
+	.DIA3( a_din[3]  ), .DIA2( a_din[2]  ), .DIA1(  a_din[1] ), .DIA0(  a_din[0]  ),
+	
+	// input address bus port A
+	.ADA13( a_addr[10] ), .ADA12( a_addr[9] ), 
+	.ADA11( a_addr[8] ), .ADA10(  a_addr[7]), .ADA9(  a_addr[6] ), .ADA8( a_addr[5] ),
+	.ADA7( a_addr[4] ), .ADA6( a_addr[3] ), .ADA5( a_addr[2] ), .ADA4( a_addr[1] ), .ADA3( a_addr[0] ),
+	.ADA2( 1'b0 ), .ADA1( 1'b0 ), .ADA0( 1'b0 ), 
+	
+	.CEA( a_clk_e ), 	// clock enable
+	.OCEA( a_oe ), 	// output clock enable
+	.CLKA( a_clk ), // clock for port A
+	.WEA( a_we ), 	// write enable 
+	.CSA2( 1'b0 ), .CSA1( 1'b0 ), .CSA0( 1'b0 ), // chip selects 
+	.RSTA( ~rstn ),	// reset for port A
+	
+	// outputs
+	.DOA17(), .DOA16(), .DOA15(), .DOA14(), .DOA13(), .DOA12(), .DOA11(), .DOA10(), .DOA9( ),
+	.DOA8( a_dout[8] ), .DOA7( a_dout[7] ), .DOA6( a_dout[6] ), .DOA5( a_dout[5] ), .DOA4( a_dout[4] ), 
+	.DOA3( a_dout[3] ), .DOA2( a_dout[2] ), .DOA1( a_dout[1] ), .DOA0( a_dout[0] ),
+	
+	// input data port B
+	.DIB17( 1'b0 ), .DIB16( 1'b0 ), .DIB15( 1'b0 ), .DIB14( 1'b0 ), .DIB13( 1'b0 ), 
+	.DIB12( 1'b0 ), .DIB11( 1'b0 ), .DIB10( 1'b0 ), .DIB9( 1'b0 ),
+	.DIB8( b_din[8] ), .DIB7( b_din[7] ), .DIB6( b_din[6] ), .DIB5( b_din[5] ), 
+	.DIB4(  b_din[4] ), .DIB3(  b_din[3] ), .DIB2( b_din[2] ), .DIB1( b_din[1] ), .DIB0( b_din[0] ),
+	
+	// input address bus port B
+	.ADB13( b_addr[10] ), .ADB12( b_addr[9] ), .ADB11( b_addr[8] ), .ADB10( b_addr[7] ), .ADB9( b_addr[6] ), 
+	.ADB8( b_addr[5] ), .ADB7( b_addr[4] ), .ADB6( b_addr[3] ), .ADB5( b_addr[2] ),
+	.ADB4( b_addr[1] ), .ADB3( b_addr[0] ), .ADB2( 1'b0 ), .ADB1(  1'b0 ), .ADB0(  1'b0 ),
+	
+	.CEB( b_clk_e ), // clock enable
+	.OCEB( b_oe ), // output clock enable
+	.CLKB( b_clk ), // clock for port B
+	.WEB( b_we ), // write enable 
+	.CSB2( 1'b0 ), .CSB1( 1'b0 ), .CSB0( 1'b0 ), // chip selects 
+	.RSTB( ~rstn ),	// reset for port B
+	
+	// outputs
+	
+	.DOB17(), .DOB16(), .DOB15(), .DOB14(), .DOB13(), .DOB12(), .DOB11(), .DOB10(), .DOB9( ),
+	.DOB8( b_dout[8] ), .DOB7( b_dout[7] ), .DOB6( b_dout[6] ), .DOB5( b_dout[5] ), 
+	.DOB4( b_dout[4] ), .DOB3( b_dout[3] ), .DOB2( b_dout[2] ), .DOB1( b_dout[1] ), .DOB0( b_dout[0] ) 
+	
+); 
+// defparam dp16kd_inst.INITVAL_00 = "0x123456789abcdef0123456789abcdef0123456789abcdef0123456789abcaa9980123456789abcde";
+defparam dp16kd_inst.DATA_WIDTH_A = 9;
+defparam dp16kd_inst.DATA_WIDTH_B = 9;
+
+endmodule
diff --git a/source/drop2_fifo.v b/source/drop2_fifo.v
new file mode 100644
index 0000000..dcadd92
--- /dev/null
+++ b/source/drop2_fifo.v
@@ -0,0 +1,255 @@
+/*
+ *   drop2_fifo.v
+ *
+ *   Copyright (C) 2018, 2019 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:  Double buffered side-by-side FIFO 
+ *   Uses 2 DPRAMs with additional logic for paths involving 1G to 100Mbit 
+ *       
+ */
+
+`timescale 1ns /10ps
+
+module drop2_fifo(
+		input	rstn,
+		input	clk,
+		input 	enable,
+		
+		// control (drop, keep, and done are asserted for one clock )
+		input	keep,				// this packet won't be dropped, start transferring it (KEEPS ARE AND'ED)
+		input	passthrough,			// don't store data, write through instead
+		
+		// input
+		input	we_in,
+		input  wr_done,
+		input [8:0]	d_in,
+		
+		// output
+		output 	we_out,
+		output	reg [8:0] d_out,
+		
+		// debug
+		output reg active
+);
+
+// local parameters and includes
+
+
+// nets and registers
+
+// the msbit of the ptr selects the DPRAM
+reg	[11:0] 	wr_ptr;
+reg	[11:0] 	rd_ptr;
+
+wire [8:0]  d_out_0, d_out_1, d_out_internal;
+
+reg read_run, read_run_m1;		// read continues while read_run is set
+reg i_we_out, i_we_out_m1;		// internal we_out
+wire re;						// read enable for dpram
+reg rd_done_p1, rd_done;
+wire i_keep;
+reg kept;
+
+assign i_keep = keep & enable;
+
+wire dpram0_a_clk_e, dpram1_a_clk_e;
+wire dpram0_b_clk_e, dpram1_b_clk_e;
+
+/* 
+ * kept: assert for length of write duration after keep asserts
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		kept <= 1'b0;
+	else if ( wr_done )
+		kept <= 1'b0;
+	else if ( i_keep )
+		kept <= 1'b1;
+	
+/*
+ * 	read_run logic
+ *	read starts after wr_done
+ * 	continues until the FIFO is empty
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+	begin
+		read_run <= 1'b0;
+		read_run_m1 <= 1'b0;
+	end
+	else if ( rd_done_p1 )
+	begin
+		read_run <= 1'b0;
+		read_run_m1 <= 1'b0;
+	end
+	else if ( kept && wr_done )
+	begin
+		read_run <= 1'b1;
+	end
+	else
+		read_run_m1 <= read_run;
+	
+assign re = read_run;
+
+/*
+ * 	we_out logic
+ * 	delayed version of re
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		i_we_out <= 1'b0;
+	else if ( read_run && read_run_m1 )
+		i_we_out <= 1'b1;
+	else
+		i_we_out <= 1'b0;
+	
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		i_we_out_m1 <= 1'b0;
+	else
+		i_we_out_m1 <= i_we_out;
+	
+// OR these two signals to stretch we_out to the last byte from FIFO
+assign we_out = i_we_out | i_we_out_m1;
+	
+/*
+ *  upper / lower half DPRAM logic
+ *  directs upper or lower write buffer in FIFO
+ *  toggle on each done event (rx_data is complete)
+ *  don't toggle on a drop event (reuse buffer)
+ */
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		wr_ptr[11] <= 1'b0;		// init to the lower bank
+	else if ( wr_done && kept )
+		wr_ptr[11]  <= ~wr_ptr[11]; 
+	
+/*
+ * wr_ptr logic excluding msbit
+ * reset pointer when wr_done
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		wr_ptr[10:0] <= 'd0;
+	else if ( wr_done )
+		wr_ptr[10:0] <= 'd0;
+	else if ( we_in )
+		wr_ptr[10:0] <= wr_ptr[10:0] + 1;
+
+/* 
+ * each time the FIFO is empty, set rd_ptr[11] to wr_ptr[11]
+ * FIFO becomes empty through reading
+ */
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		rd_ptr[11] <= 1'b0;		// init to the lower bank
+	else if ( rd_done )
+		rd_ptr[11] <= wr_ptr[11];	
+	
+/*
+ * rd_ptr logic excluding msbit
+ */	
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		rd_ptr[10:0] <= 'd0;
+	else if ( rd_done )
+		rd_ptr[10:0] <= 'd0;
+	else if ( re )
+		rd_ptr[10:0] <= rd_ptr[10:0] + 1;
+	
+/*
+ * d_out register
+ * 
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		d_out <= 'd0;
+	else
+		d_out <= d_out_internal;
+		
+		
+/*
+*	rd_done logic
+*/
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		begin
+			rd_done_p1 <= 1'b0;
+			rd_done <= 1'b0;
+		end
+	else
+		begin
+			rd_done_p1 <= d_out_internal[8];
+			rd_done <= rd_done_p1;
+		end
+	
+// debug
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		active <= 1'b0;
+	else if ( we_in || we_out )
+		active <= 1'b1;
+	else 
+		active <= 1'b0;	
+	
+assign dpram0_a_clk_e = ~wr_ptr[11];
+assign dpram1_a_clk_e = wr_ptr[11];
+
+assign dpram0_b_clk_e = ~rd_ptr[11];
+assign dpram1_b_clk_e = rd_ptr[11];
+
+assign d_out_internal = dpram0_b_clk_e ? d_out_0 : d_out_1;
+		
+
+dpram dpram_0(
+.rstn(  rstn  ),
+.a_clk( clk ),
+.a_clk_e( dpram0_a_clk_e ),
+.a_we( we_in ),
+.a_oe( 1'b0 ),
+.a_addr( wr_ptr[10:0] ),
+.a_din( d_in ),
+.a_dout( ),
+// port B
+.b_clk(  clk ),
+.b_clk_e( dpram0_b_clk_e ),
+.b_we( 1'b0 ),
+.b_oe( re  ),
+.b_addr( rd_ptr[10:0] ),
+.b_din( 9'h0 ),
+.b_dout( d_out_0 )
+);
+
+dpram dpram_1(
+	.rstn(  rstn  ),
+	.a_clk( clk ),
+	.a_clk_e( dpram1_a_clk_e ),
+	.a_we( we_in ),
+	.a_oe( 1'b0 ),
+	.a_addr( wr_ptr[10:0] ),
+	.a_din( d_in ),
+	.a_dout( ),
+		// port B
+	.b_clk(  clk ),
+	.b_clk_e( dpram1_b_clk_e ),
+	.b_we( 1'b0 ),
+	.b_oe( re  ),
+	.b_addr( rd_ptr[10:0] ),
+	.b_din( 9'h0 ),
+	.b_dout( d_out_1 )
+);
+
+
+endmodule
diff --git a/source/drop_fifo.v b/source/drop_fifo.v
new file mode 100644
index 0000000..393c20b
--- /dev/null
+++ b/source/drop_fifo.v
@@ -0,0 +1,220 @@
+/*
+ *   drop_fifo.v
+ *
+ *   Copyright (C) 2018, 2019 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: Double buffered side-by-side FIFO for delaying data until keep / drop decision is made
+ *       
+ */
+
+`timescale 1ns /10ps
+
+module drop_fifo(
+		input	rstn,
+		input	clk,
+		input	enable, 
+		
+		// control (keep or drop by default)
+		input	keep,				// this packet won't be dropped, start transferring it
+		input	passthrough,		// don't store / delay data, write through instead
+		
+		// input
+		input	we_in,
+		input  wr_done,
+		input [8:0]	d_in,
+		
+		// output
+		output 	we_out,
+		output	reg [8:0] d_out,
+		
+		// debug
+		output reg active
+);
+
+// local parameters and includes
+
+
+// nets and registers
+
+// the msbit of the ptr selects top or bottom half
+reg	[10:0] 	wr_ptr;
+reg	[10:0] 	rd_ptr;
+
+wire [8:0]  d_out_internal;
+
+reg read_run, read_run_m1;		// read continues while read_run is set
+reg i_we_out, i_we_out_m1;		// internal we_out
+wire re;						// read enable for dpram
+reg rd_done_p1, rd_done;
+wire i_keep;
+reg kept;
+
+assign i_keep = keep & enable;
+	
+/*
+ * 	read_run logic
+ *  read starts after each keep assertion
+ * 	continues until the FIFO is empty
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		read_run <= 1'b0;
+	else if ( rd_done_p1 )
+		read_run <= 1'b0;
+	else if ( i_keep )
+		read_run <= 1'b1;
+
+
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		read_run_m1 <= 1'b0;
+	else 
+		read_run_m1 <= read_run;	
+	
+assign re = read_run;
+
+
+/*
+ * 	we_out logic
+ * 	delayed version of re
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		i_we_out <= 1'b0;
+	else if ( read_run && read_run_m1 )
+		i_we_out <= 1'b1;
+	else
+		i_we_out <= 1'b0;
+	
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		i_we_out_m1 <= 1'b0;
+	else
+		i_we_out_m1 <= i_we_out;
+	
+// OR these two signals to stretch we_out to the last byte from FIFO
+assign we_out = i_we_out | i_we_out_m1;
+	
+/* 
+ * kept: assert for length of write duration after keep asserts
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		kept <= 1'b0;
+	else if ( wr_done )
+		kept <= 1'b0;
+	else if ( i_keep )
+		kept <= 1'b1;
+	
+/*
+ *  upper / lower half DPRAM logic
+ *  directs upper or lower write buffer in FIFO
+ *  toggle each time a packet is kept and write is finished
+ */
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		wr_ptr[10] <= 1'b0;		// init to the lower bank
+	else if ( wr_done && kept )
+		wr_ptr[10]  <= ~wr_ptr[10]; 
+	
+/*
+ * wr_ptr logic excluding msbit
+ * reset pointer when wr_done
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		wr_ptr[9:0] <= 'd0;
+	else if ( wr_done )
+		wr_ptr[9:0] <= 'd0;
+	else if ( we_in )
+		wr_ptr[9:0] <= wr_ptr[9:0] + 1;
+
+/* 
+ * each time the FIFO is empty, set rd_ptr[10] to wr_ptr[10]
+ * FIFO becomes empty through reading
+ */
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		rd_ptr[10] <= 1'b0;		// init to the lower bank
+	else if ( rd_done )
+		rd_ptr[10] <= wr_ptr[10];	
+	
+/*
+ * rd_ptr logic excluding msbit
+ */	
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		rd_ptr[9:0] <= 'd0;
+	else if ( rd_done )
+		rd_ptr[9:0] <= 'd0;
+	else if ( re )
+		rd_ptr[9:0] <= rd_ptr[9:0] + 1;
+	
+/*
+ * d_out register
+ * 
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		d_out <= 'd0;
+	else
+		d_out <= d_out_internal;
+		
+		
+/*
+*	rd_done logic
+*/
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		begin
+			rd_done_p1 <= 1'b0;
+			rd_done <= 1'b0;
+		end
+	else
+		begin
+			rd_done_p1 <= d_out_internal[8];
+			rd_done <= rd_done_p1;
+		end
+		
+	
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		active <= 1'b0;
+	else if ( we_in || we_out )
+		active <= 1'b1;
+	else 
+		active <= 1'b0;
+
+dpram dpram_fifo(
+.rstn(  rstn  ),
+.a_clk( clk ),
+.a_clk_e( 1'b1 ),
+.a_we( we_in ),
+.a_oe( 1'b0 ),
+.a_addr( wr_ptr ),
+.a_din( d_in ),
+.a_dout( ),
+// port B
+.b_clk(  clk ),
+.b_clk_e( re ),
+.b_we( 1'b0 ),
+.b_oe( 1'b1  ),
+.b_addr( rd_ptr ),
+.b_din( 9'h0 ),
+.b_dout( d_out_internal )
+);
+
+
+endmodule
diff --git a/source/ethernet_params.v b/source/ethernet_params.v
new file mode 100644
index 0000000..e974a05
--- /dev/null
+++ b/source/ethernet_params.v
@@ -0,0 +1,38 @@
+/*
+ *       ethernet_params.v
+ *
+ *   Copyright (C) 2018, 2019 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:	Ethernet related parameters
+ *		
+ */
+
+
+localparam MTU = 1520;	// Ethernet is actually 1500+framing (max 18)
+localparam IPG = 96; 	// Inter-packet Gap Bits
+
+localparam SZ_ETH_HEADER = 14;			// w/o VLAN
+localparam SZ_IPV4_HEADER = 20;			// w/o Options
+localparam SZ_UDP_HEADER = 8;
+
+localparam	TX_MODE_AN = 2'b00,
+TX_MODE_IDLE = 2'b01,
+TX_MODE_XMT_PKT = 2'b10,		// anything >= to this is a mode where a packet is transmitted
+TX_MODE_XMT_METRICS = 2'b11;
+
+// Note: The Length/Type field is transmitted and received with the high order octet first.
+localparam 	ETHER_TYPE_IPV4 = 16'h0800,
+ETHER_TYPE_IPV6 = 16'h86DD,
+ETHER_TYPE_ARP = 16'h0806;	
diff --git a/source/fcs.v b/source/fcs.v
new file mode 100644
index 0000000..6abf536
--- /dev/null
+++ b/source/fcs.v
@@ -0,0 +1,142 @@
+/*
+ *       fcs.v
+ *       
+ *   Copyright (C) 2018, 2019 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: FCS checksum
+ *		
+ *
+ */
+`timescale 1ns /10ps
+
+////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 1999-2008 Easics NV.
+// This source file may be used and distributed without restriction
+// provided that this copyright statement is not removed from the file
+// and that any derivative work contains the original copyright notice
+// and the associated disclaimer.
+//
+// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+//
+// Purpose : synthesizable CRC function
+//   * polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+//   * data width: 8
+//
+// Info : tools@easics.be
+//        http://www.easics.com
+////////////////////////////////////////////////////////////////////////////////
+
+/*
+*	a) The first 32 bits of the frame are complemented.
+*	b) The n bits of the MAC frame considered to be the coefficients of a polynomial M(x) of degree n � 1. 
+*		The first bit of the Destination Address field corresponds to the x(n�1) term 
+*		and the last bit of the MAC Client Data field (or Pad field if present) corresponds to the x0 term.
+*	c) M(x) is multiplied by x**32 and divided by G(x), producing a remainder R(x) of degree = 31.
+*	d) The coefficients of R(x) are considered to be a 32-bit sequence.
+*	e) The bit sequence is complemented and the result is the CRC.
+*	f) FCS should be trnansmitted msbit first ( opposite of the rest of MAC frame )
+*/
+module fcs(
+	input rstn,
+	input clk,
+	
+	// control interface
+	input init,
+	input enable, 
+	
+	// addr & data
+	input [1:0] addr,
+	input [0:7] din,
+	output [7:0] dout
+);
+
+
+reg [31:0] crc;
+reg [7:0] d;
+
+assign dout = ~{ d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7] };
+
+always @(*)
+	begin
+		case(addr)
+			2'b00:	d <= crc[31:24];
+			2'b01:	d <= crc[23:16];
+			2'b10:	d <= crc[15:8];
+			2'b11:	d <= crc[7:0];
+		endcase
+	end
+
+always @(posedge clk or negedge rstn)
+	if(!rstn)
+		crc <= 32'hffffffff;
+	else if (init)
+		crc <= 32'hffffffff;
+	else if (enable)
+		crc <= nextCRC32_D8(din,crc);
+
+// {d[0],d[1],d[2],d[3],d[4],d[5],d[6],d[7]}
+
+  // polynomial: x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1
+  // data width: 8
+  // convention: the first serial bit is D[7]
+  function [31:0] nextCRC32_D8;
+
+    input [0:7] Data;
+    input [31:0] crc;
+    reg [0:7] d;
+    reg [31:0] c;
+    reg [31:0] newcrc;
+  begin
+    d = Data;
+    c = crc;
+
+    newcrc[0] = d[6] ^ d[0] ^ c[24] ^ c[30];
+    newcrc[1] = d[7] ^ d[6] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[30] ^ c[31];
+    newcrc[2] = d[7] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[26] ^ c[30] ^ c[31];
+    newcrc[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[27] ^ c[31];
+    newcrc[4] = d[6] ^ d[4] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[28] ^ c[30];
+    newcrc[5] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
+    newcrc[6] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30] ^ c[31];
+    newcrc[7] = d[7] ^ d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[29] ^ c[31];
+    newcrc[8] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
+    newcrc[9] = d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29];
+    newcrc[10] = d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[2] ^ c[24] ^ c[26] ^ c[27] ^ c[29];
+    newcrc[11] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[3] ^ c[24] ^ c[25] ^ c[27] ^ c[28];
+    newcrc[12] = d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ d[0] ^ c[4] ^ c[24] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30];
+    newcrc[13] = d[7] ^ d[6] ^ d[5] ^ d[3] ^ d[2] ^ d[1] ^ c[5] ^ c[25] ^ c[26] ^ c[27] ^ c[29] ^ c[30] ^ c[31];
+    newcrc[14] = d[7] ^ d[6] ^ d[4] ^ d[3] ^ d[2] ^ c[6] ^ c[26] ^ c[27] ^ c[28] ^ c[30] ^ c[31];
+    newcrc[15] = d[7] ^ d[5] ^ d[4] ^ d[3] ^ c[7] ^ c[27] ^ c[28] ^ c[29] ^ c[31];
+    newcrc[16] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[24] ^ c[28] ^ c[29];
+    newcrc[17] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[25] ^ c[29] ^ c[30];
+    newcrc[18] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[26] ^ c[30] ^ c[31];
+    newcrc[19] = d[7] ^ d[3] ^ c[11] ^ c[27] ^ c[31];
+    newcrc[20] = d[4] ^ c[12] ^ c[28];
+    newcrc[21] = d[5] ^ c[13] ^ c[29];
+    newcrc[22] = d[0] ^ c[14] ^ c[24];
+    newcrc[23] = d[6] ^ d[1] ^ d[0] ^ c[15] ^ c[24] ^ c[25] ^ c[30];
+    newcrc[24] = d[7] ^ d[2] ^ d[1] ^ c[16] ^ c[25] ^ c[26] ^ c[31];
+    newcrc[25] = d[3] ^ d[2] ^ c[17] ^ c[26] ^ c[27];
+    newcrc[26] = d[6] ^ d[4] ^ d[3] ^ d[0] ^ c[18] ^ c[24] ^ c[27] ^ c[28] ^ c[30];
+    newcrc[27] = d[7] ^ d[5] ^ d[4] ^ d[1] ^ c[19] ^ c[25] ^ c[28] ^ c[29] ^ c[31];
+    newcrc[28] = d[6] ^ d[5] ^ d[2] ^ c[20] ^ c[26] ^ c[29] ^ c[30];
+    newcrc[29] = d[7] ^ d[6] ^ d[3] ^ c[21] ^ c[27] ^ c[30] ^ c[31];
+    newcrc[30] = d[7] ^ d[4] ^ c[22] ^ c[28] ^ c[31];
+    newcrc[31] = d[5] ^ c[23] ^ c[29];
+    nextCRC32_D8 = newcrc;
+  end
+  endfunction
+endmodule
diff --git a/source/half_fifo.v b/source/half_fifo.v
new file mode 100644
index 0000000..e18f543
--- /dev/null
+++ b/source/half_fifo.v
@@ -0,0 +1,194 @@
+/* 
+ *	half_fifo.v
+ *
+ *   Copyright (C) 2018, 2019 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: micro / FIFO interface
+ *
+ */
+
+`timescale 1ns /10ps
+
+module	half_fifo	#(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11 )
+(
+	input	rstn,
+	input	uc_clk,
+	input	fifo_clk,
+	
+	// UC interrupt support
+	output 	reg fifo_we_int,
+	
+	// tx_mode 
+	input tx_mode,
+	
+	// UC side: common DPRAM signals for RX and TX
+	input [DPRAM_DEPTH-1:0] dpram_addr,
+	input [DATA_WIDTH-1:0]  dpram_din,
+	output reg [DATA_WIDTH-1:0] dpram_dout,
+	input dpram_we,
+	input dpram_oe,
+	// UC select signals
+	input dpram_ptrs_sel,
+	input dpram_rx_sel,
+	input dpram_tx_sel,
+
+	// FIFO TX (input)
+	input	fifo_we,
+	input	[DATA_WIDTH-1:0]	fifo_d_in,
+
+	// FIFO RX (output)
+	input 	fifo_re,
+	output	[DATA_WIDTH-1:0]	fifo_d_out,
+	
+	// FIFO flags
+	output	rx_empty,			// dpram 0 (reader)
+	output 	tx_full
+	
+);	
+
+/* 
+ * Pointers for accessing memory.
+ * UC writes RX and reads TX
+ * Switch writes (via FIFO I/F) TX and reads RX
+ */  
+reg	[DPRAM_DEPTH-1:0] 	rx_wr_ptr;
+reg	[DPRAM_DEPTH-1:0] 	rx_rd_ptr;
+
+reg	[DPRAM_DEPTH-1:0] 	tx_wr_ptr;
+reg	[DPRAM_DEPTH-1:0] 	tx_rd_ptr;
+
+reg fifo_we_m1;
+
+reg reset_ptrs;
+wire [DATA_WIDTH-1:0] dpram_rx_dout, dpram_tx_dout;
+
+/* read data mux */
+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;
+	endcase
+	
+always @(posedge uc_clk, negedge rstn)
+	if ( !rstn )
+		reset_ptrs <= 1'b0;
+	else if ( dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == 3'h4 )
+		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) */
+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;
+	
+/* 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) */
+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;	
+	
+
+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;
+	
+
+
+/* Assert interrupt whenever fifo_we is negated ( writing is done ) */
+always @(posedge fifo_clk, negedge rstn)
+	if ( !rstn )
+		fifo_we_m1 <= 1'b0;
+	else
+		fifo_we_m1 <= fifo_we;
+	
+
+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;
+	
+
+/*  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 ),
+	// 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 )
+);
+
+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 ),
+	// 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( )
+);
+
+endmodule
diff --git a/source/i2c.v b/source/i2c.v
new file mode 100644
index 0000000..aca6452
--- /dev/null
+++ b/source/i2c.v
@@ -0,0 +1,391 @@
+/*
+ *       i2c.v
+ *
+ *   Copyright (C) 2018, 2019 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: I2C slave controller for communicating with internal controller
+ *		
+ */
+
+
+`timescale 1ns /10ps
+
+
+module i2c(
+	input 	rstn,
+	input 	clk, 
+	
+	// external I2C I/O
+	input	scl_i,		// serial clock
+	output	scl_o,		// serial clock out
+	output	scl_oe,		// serial clock output enable
+	
+	input 	sda_i,		// serial data in
+	output  reg	sda_o,	// serial data out
+	output	reg sda_oe,	// serial data output enable
+	
+	// shared memory and controller data output
+	output [7:0] mem_do,
+	
+	// dedicated memory interface
+	output [10:0] mem_ad,
+	output mem_ce,
+	output reg mem_we,
+	input [7:0] mem_di,
+	
+	// dedicated controller write interface
+	output reg cont_we,
+	output cont_done,
+	
+	// Controller->FIFO input interface
+	input tx_fifo_empty,		// use for control and pass as msbit of data
+	input [6:0] fifo_di,		// data from FIFO to transmit on I2C
+	output reg fifo_re
+
+);
+
+localparam  CONT_SEL = 7'h10,
+			DPRAM_SEL = 7'h20,
+			SCI_SEL = 7'h30;
+	
+// slave-related signals
+
+reg	scl_high, scl_low;
+reg [4:0] bit_cnt;	// cnt the bits received
+reg start;		// falling SDA while SCL is high
+reg stop;		// rising SDA while SCL is high
+reg	run;		// assert while running and counting bits
+reg rwn;		// follows address
+
+reg [6:0] dev_ad;	// 7-bit device address
+reg [7:0] addr;		// address
+reg [7:0] d;		// data received from external i2c controller during an I2C write
+wire target_sel, dpram_sel, cont_sel;
+reg scl_i_m1, scl_i_m2, sda_i_m1;	// delayed versions of the inputs
+reg ack;
+
+wire [7:0] i_di;	// internal data in muxed from external sources (e.g., DPRAM and controller)
+
+assign i_di = dpram_sel ? mem_di : { tx_fifo_empty, fifo_di };
+
+// master-related signals
+//reg halt;		// assert if we lose arbitration, detect a zero in place of a one
+
+assign scl_oe = 1'b0;
+
+// since it's open drain, never drive the outputs high
+assign scl_o = 1'b0;
+
+// slave interface
+
+/*
+	debounce and capture the asynch inputs
+	delayed signals, by default, they're 1 since they're open drain
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if (!rstn)
+			begin
+				scl_i_m1 <= 1'b1;
+				scl_i_m2 <= 1'b1;
+				sda_i_m1 <= 1'b1;
+			end
+		else
+			begin
+				scl_i_m1 <= scl_i;
+				scl_i_m2 <= scl_i_m1;
+				sda_i_m1 <= sda_i;
+			end
+	end
+
+/*
+	create a one shot when scl is first stable high 
+	use this to register inputs
+*/
+always@(posedge clk or negedge rstn)
+	begin
+		if (!rstn)
+			scl_high <= 1'b0;
+		else if (scl_i && scl_i_m1 && ~scl_i_m2)
+			scl_high <= 1'b1;
+		else
+			scl_high <= 1'b0;
+	end
+
+/*
+	create a one shot when scl is first stable low
+	use this to register outputs
+*/
+always@(posedge clk or negedge rstn)
+	begin
+		if (!rstn)
+			scl_low <= 1'b0;
+		else if ( !scl_i && !scl_i_m1 && scl_i_m2)
+			scl_low <= 1'b1;
+		else
+			scl_low <= 1'b0;
+	end
+	
+/* 
+	one shot start/restart bit, sda 1 to 0 anytime while scl is high
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if (!rstn)	
+			start <= 1'b0;
+		else if ( scl_i == 1'b1 &&  scl_i_m1 == 1'b1 && sda_i == 1'b0 &&  sda_i_m1 == 1'b1 ) 
+			start <= 1'b1;
+		else
+			start <= 1'b0;
+	end
+	
+/*
+	one shot stop bit, sda 0 to 1 anytime while scl is high
+*/
+assign cont_done = stop & ~rwn;
+
+always @(posedge clk or negedge rstn)
+	begin
+		if (!rstn )
+			stop <= 1'b0;
+		else if ( scl_i == 1'b1 &&  scl_i_m1 == 1'b1 && sda_i == 1'b1 &&  sda_i_m1 == 1'b0 ) 
+			stop <= 1'b1;
+		else
+			stop <= 1'b0;
+	end
+
+/*
+	This I2C block runs between start and stop while run == 1
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if (!rstn)
+			run <= 1'b0;
+		else if ( start )
+			run <= 1'b1;
+		else if ( stop ) 
+			run <= 1'b0;
+	end
+	
+
+/* 
+	bit_cnt indicates the state of the i2c transfer:
+	start/stop act as synchronous resets
+	otherwise, bit_cnt can change when scl is low
+	
+	31 (1F): reserved for first cycle after start / idle state
+	0:6: dev_ad
+	7: rwn, ACK is clocked out
+	8: 
+	9:16: if rwn == 0 addr, else d, ACK is clocked out on 16
+	17:  ( restart to 9 if read )
+	18:25: write data, ack write data is clocked out on 25
+	26:  ( restart to 18 for write data )
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if ( !rstn )
+			bit_cnt <= 5'h1f;
+		else if ( start || stop )
+			bit_cnt <= 5'h1f;
+		else if ( run && scl_low )
+			begin
+				if ( rwn && bit_cnt == 5'd17 )
+					bit_cnt <= 5'd9;
+				else if ( bit_cnt == 5'd26 )
+					bit_cnt <= 5'd18;
+				else
+					bit_cnt <= bit_cnt + 1;
+			end
+	end
+	
+/*
+	shift device address (dev_ad) into the module from the i2c bus
+*/
+always @(posedge clk or negedge rstn)	
+	begin
+		if ( !rstn )
+			dev_ad <= 7'h0;
+		else if ( stop ) 
+			dev_ad <= 7'h0;
+		else if ( run && scl_high && bit_cnt <= 5'h6 )
+			dev_ad <= { dev_ad[5:0], sda_i };
+	end
+	
+
+/*
+	shift I2C memory addr into the module from the i2c bus during first cycle
+	auto increment on subsequent byte reads during same I2C cycle
+*/
+always @(posedge clk or negedge rstn)	
+	begin
+		if (!rstn)
+				addr <= 8'h00;
+		else if ( run && scl_high)
+			begin
+				if ( !rwn && bit_cnt >= 5'd9 && bit_cnt <= 5'd16 )
+					addr <= { addr[6:0], sda_i };
+				else if ( (rwn && bit_cnt == 5'd17) || (!rwn && bit_cnt == 5'd26)  ) 
+					addr <= addr + 1;	
+			end
+	end
+
+
+/*
+*	shift write data (d) into the module from the i2c bus.
+*/
+always @(posedge clk or negedge rstn)	
+	begin
+		if (!rstn)
+				d <= 8'ha5;
+		else if ( run && scl_high && !rwn && !start && bit_cnt >= 5'd18 && bit_cnt < 5'd26 )
+				d <= { d[6:0], sda_i };
+	end
+
+
+	
+assign dpram_sel =  ( dev_ad == DPRAM_SEL ) ? 1 : 0;
+assign cont_sel = ( dev_ad == CONT_SEL ) ? 1 : 0;
+assign target_sel = cont_sel | dpram_sel;	   
+
+/*
+	register ack during I2C reads when bit_cnt == 17
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if ( !rstn )
+			ack <= 1'b0;
+		else if ( run && scl_high && rwn && bit_cnt == 5'd17 )
+			ack <= ~sda_i;
+	end
+
+/*
+	register rwn bit
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if ( !rstn )
+			rwn <= 1'b1;
+		else if ( stop )
+			rwn <= 1'b1;
+		else if ( run && scl_high && bit_cnt == 5'd7 )
+			rwn <= sda_i;
+	end
+	
+/*
+	sda_oe logic, note that the bit_cnt will be changing simultaneously, so it's one behind
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if ( !rstn )
+			begin
+				sda_oe <= 1'b0;
+				sda_o <= 1'b1;
+			end
+		else if ( stop )
+			begin
+				sda_oe <= 1'b0;
+				sda_o <= 1'b1;
+			end			
+		else if ( scl_low ) 
+			begin
+				// ack the first byte written by master if it's addressed to our I2C slave
+				if ( target_sel && bit_cnt == 5'd7 )
+					begin
+						sda_oe <= 1'b1;
+						sda_o <= 1'b0;
+					end
+				// ack write address
+				else if ( target_sel && rwn == 1'b0 && bit_cnt == 5'd16 )
+					begin
+						sda_oe <= 1'b1;
+						sda_o <= 1'b0;
+					end
+				// ack write data
+				else if ( target_sel && rwn == 1'b0 && bit_cnt == 5'd25 )
+					begin
+						sda_oe <= 1'b1;
+						sda_o <= 1'b0;
+					end
+				// drive read data
+				else if ( target_sel && rwn == 1'b1 && bit_cnt >= 5'd8 && bit_cnt <=5'd15 )	// xmt data for read cycle
+					begin
+						sda_oe <= 1'b1;
+						sda_o <= i_di[7-bit_cnt[2:0]];
+					end
+				// drive data for first bit of burst read cycle, multi-byte if we get an ack
+				// if no ack, then the burst read or single read is done
+				else if ( target_sel && rwn == 1'b1 && ack && bit_cnt == 5'd17 )	
+					begin
+						sda_oe <= 1'b1;
+						sda_o <= i_di[7];
+					end
+				else
+					begin
+						sda_oe <= 1'b0;
+						sda_o <= 1'b1;		// don't care
+					end
+			end
+	end
+	
+/* DPRAM Control */
+assign mem_ad = {3'b0, addr};
+assign mem_ce = 1'b1;	
+
+/*
+		driver: mem_do 
+		shared between both cont and dpram interfaces
+		drive addr for first byte since this is the controller cmd 
+*/
+assign mem_do = ( bit_cnt <= 5'd17 ) ? addr : d;
+
+// mem_we bit
+always @(posedge clk or negedge rstn)
+	begin
+		if ( !rstn )
+			mem_we <= 1'b0;
+		else if ( run && scl_high && dpram_sel && !rwn && bit_cnt == 5'd26 )
+			mem_we <= 1'b1;
+		else
+			mem_we <= 1'b0;
+	end
+	
+// cont_we bit is asserted at the end of both command and data bytes
+always @(posedge clk or negedge rstn)
+	begin
+		if ( !rstn )
+			cont_we <= 1'b0;
+		else if ( run && scl_high && cont_sel && !rwn && (bit_cnt == 5'd26 || bit_cnt == 5'd17) )
+			cont_we <= 1'b1;
+		else
+			cont_we <= 1'b0;
+	end
+	
+/*
+*	drive: fifo_re
+*	Stop asserting during a burst if we don't get an ACK (use sda_i for real-time ACK)
+*/
+always @(posedge clk or negedge rstn)
+	begin
+		if ( !rstn )
+			fifo_re <= 1'b0;
+		else if ( run && scl_high && cont_sel && rwn && !tx_fifo_empty && ( bit_cnt == 5'd8 || ( bit_cnt == 5'd17 && !sda_i ) ) )
+			fifo_re <= 1'b1;
+		else
+			fifo_re <= 1'b0;
+	end
+	
+	
+endmodule
diff --git a/source/interrupts.v b/source/interrupts.v
new file mode 100644
index 0000000..c77dfb7
--- /dev/null
+++ b/source/interrupts.v
@@ -0,0 +1,77 @@
+/*
+ *      interrupts.v
+ *
+ *   Copyright (C) 2018, 2019 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: uC Interrupt Controller
+ *
+ */
+
+`timescale 1ns /10ps
+
+
+module interrupts (
+	input rstn,
+	input clk,
+	input uc_clk,
+
+
+// uC interface
+	input   sel,
+	input 	we,
+	input 	addr,
+	input 	[6:0]	d_in,
+	output  [6:0]	d_out,
+	
+	// interrupt sources
+	input cont_int,
+	input [3:0] phy_int,
+	input [3:0] mac_int,
+	
+	// int out
+	output int_o
+);
+	
+localparam	INT_CONTROLLER = 'h01,
+			INT_PHY0 = 'h02,
+			INT_PHY1 = 'h04,
+			INT_MAC0 = 'h08,
+			INT_MAC1 = 'h10,
+			INT_MAC2 = 'h20,
+			INT_MAC3 = 'h40;
+	
+reg [6:0] int_enable;
+reg [6:0] int_src;
+
+assign d_out = addr ? int_src : int_enable;
+assign int_o = int_src[6] & int_enable[6] | int_src[5] & int_enable[5] | int_src[4] & int_enable[4] | int_src[3] & int_enable[3] |
+				int_src[2] & int_enable[2] | int_src[1] & int_enable[1] | int_src[0] & int_enable[0];
+
+always @(posedge uc_clk or negedge rstn)
+	if (!rstn)
+		int_enable <= INT_MAC2 | INT_MAC3;
+	else if (sel && we && !addr)
+		int_enable <= d_in;
+
+always @(posedge uc_clk or negedge rstn)
+	if (!rstn)
+		int_src <= 7'h0;
+	else if (sel && we && addr)
+		int_src <= d_in;
+	else 
+		int_src <= int_src | { mac_int, phy_int[1:0], cont_int };
+
+	
+endmodule
diff --git a/source/ipv4.v b/source/ipv4.v
new file mode 100644
index 0000000..55ab7a7
--- /dev/null
+++ b/source/ipv4.v
@@ -0,0 +1,152 @@
+/*
+ *       ipv4.v
+ *
+ *   Copyright (C) 2018, 2019 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: Receive State Machine and Logic for IPv4
+ *	
+ *	
+ *		0-7				8-15		16-23				24-31
+ *	0	Version/IHL		TOS			Total Length.............
+ *	4	Identification......		Flags/Frag Off...........
+ *	8	TTL				Protocol	Header Checksum..........
+ *	12	Source IP Address....................................
+ *	16	Dest IP Address......................................
+ *	20	Options / Padding....................................
+ *
+ *
+ *	When pkt_start is detected, rx_data_m2 has the first byte
+ */
+
+`timescale 1ns /10ps
+
+module ipv4_rx (
+		input	rstn,
+		input	clk,
+		
+		// control
+		input phy_resetn,
+		input phy_up,
+	
+		// packet data
+		input pkt_start,			// assert for each new frame to start state machines
+		input rx_eop,				// use as a synch reset
+		input[7:0] rx_data_m1, 
+		input[7:0] rx_data_m2, 
+		input[7:0] rx_data_m3, 		// first byte of packet appears here simultaneous with pkt_start
+		input[7:0] rx_data_m4,
+		
+		// flags
+		output pkt_complete,
+		output reg trigger_src_addr,
+		output reg trigger_dst_addr,
+		output reg keep
+		);
+	
+	/* Byte Address (when last byte of field is present on rx_data_m1 ) */
+	localparam	IPV4_TOS=1, IPV4_LENGTH=3, IPV4_IP_ID=5, IPV4_PROTOCOL=9, 
+				IPV4_HDR_CKSUM=11, IPV4_SRC_ADDR=15, IPV4_DST_ADDR=19;
+	
+	localparam 	RX_ST_IDLE=4'h0, RX_ST_DATA=4'h1, RX_ST_DONE=4'h2, RX_ST_3=4'h3,
+		RX_ST_4=4'h4, RX_ST_5=4'h5, RX_ST_6=4'h6, RX_ST_7=4'h7,
+		RX_ST_8=4'h8, RX_ST_9=4'h9, RX_ST_A=4'ha, RX_ST_B=4'hb,
+		RX_ST_C=4'hc, RX_ST_D=4'hd, RX_ST_E=4'he, RX_ST_F=4'hf;
+	
+	localparam IPV4_PROTO_ICMP = 1, IPV4_PROTO_IGMP = 2, IPV4_PROTO_TCP = 6, IPV4_PROTO_UDP = 17,
+		IPV4_PROTO_ENCAP = 41, IPV4_PROTO_OSPF = 89, IPV4_PROTO_SCTP = 132;
+		
+			
+	reg [3:0] rx_state;
+	reg [10:0] rx_byte_cnt;
+	reg [10:0] rx_pkt_length;
+	reg [7:0] protocol;
+	wire rx_error;
+
+	/*		
+	 * 		rx_state machine
+	 * 		capture an IPv4 Packet
+	 *  
+	 */
+	always @(posedge clk, negedge rstn)
+		if (!rstn)
+			rx_state <= RX_ST_IDLE;	
+		else if ( rx_eop || !phy_resetn )						// EOP will reset state machine
+			rx_state <= RX_ST_IDLE;	
+		else if ( phy_up )
+			case ( rx_state )
+				RX_ST_IDLE: if ( pkt_start )		//	Found /S/
+						rx_state <= RX_ST_DATA;
+				RX_ST_DATA: if (pkt_complete)
+						rx_state <= RX_ST_DONE;
+				RX_ST_DONE: rx_state <= RX_ST_IDLE;
+			endcase
+		else 
+			rx_state <= RX_ST_IDLE;
+
+
+	/* rx_byte_cnt */
+	always @(posedge clk, negedge rstn)
+		if (!rstn)
+			rx_byte_cnt <= 0;
+		else if ( rx_state == RX_ST_IDLE && !pkt_start )	// synch reset 
+			rx_byte_cnt <= 1;
+		else if ( rx_state != RX_ST_IDLE || pkt_start )
+			rx_byte_cnt <= rx_byte_cnt + 1;
+
+	
+	/* protocol */
+		always @(posedge clk, negedge rstn)
+	if ( !rstn )	
+		protocol <= 0;
+	else if ( rx_eop )
+		protocol <= 0;
+	else if ( rx_byte_cnt == IPV4_PROTOCOL ) 
+		protocol <= rx_data_m1;			
+			
+	
+	/* rx_pkt_length */
+	always @(posedge clk, negedge rstn)
+		if ( !rstn )	
+			rx_pkt_length <= 11'h7ff;
+		else if ( rx_eop )
+			rx_pkt_length <= 11'h7ff;
+		else if ( rx_state == RX_ST_DATA && rx_byte_cnt == IPV4_LENGTH ) 
+			rx_pkt_length <= { rx_data_m2[2:0], rx_data_m1 };
+
+	/*
+		 *  Packet Filter Trigger(s), assert the sample before the data appears 
+		 *  
+		 */
+	always @(posedge clk, negedge rstn)
+		if (!rstn) 
+			trigger_src_addr <= 1'b0;
+		else if ( rx_byte_cnt == IPV4_SRC_ADDR-1 )
+			trigger_src_addr <= 1'b1;
+		else
+			trigger_src_addr <= 1'b0;
+
+	always @(posedge clk, negedge rstn)
+		if (!rstn) 
+			trigger_dst_addr <= 1'b0;
+		else if ( rx_byte_cnt == IPV4_DST_ADDR-1 )
+			trigger_dst_addr <= 1'b1;
+		else
+			trigger_dst_addr <= 1'b0;
+		
+	assign pkt_complete = ( rx_state >= RX_ST_DATA && rx_pkt_length == rx_byte_cnt+1 ) ? 1 : 0;
+	assign rx_error = 0;
+
+	
+endmodule
diff --git a/source/mac.v b/source/mac.v
new file mode 100644
index 0000000..8941710
--- /dev/null
+++ b/source/mac.v
@@ -0,0 +1,895 @@
+/*
+ *       mac.v
+ *
+ *   Copyright (C) 2018, 2019 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: SGMII TX/RX/AN state machines
+ *
+ */
+
+`timescale 1ns /10ps
+
+module mac(
+	input rstn,
+	input phy_resetn,		// The external PHY has its reset signal asserted
+	input clk,
+	input tap_port,
+	
+	// SGMII AN  
+	input link_timer,
+	input [1:0] fixed_speed,
+	input an_disable,
+	output reg an_link_up,
+	output reg an_duplex,		 
+	output reg phy_up,	
+	output reg mode_100Mbit, 
+	
+	// Switch I/F
+	input [1:0] tx_mode,
+	output reg tx_f,
+
+	// PCS / SERDES health
+	input rx_lsm,
+	input rx_cv_err,
+	input rx_disp_err, 
+	input rx_cdr_lol,
+	input rx_los,		
+	
+	// PCS data I/F
+	input rx_k,
+	input [7:0] rx_data,
+	output reg tx_k,
+	output reg [7:0] tx_data,
+	output reg tx_disp_correct,
+	
+	// Flags and Interrupts
+	output reg rx_enet_bcast,
+	output reg rx_ipv4_arp,
+	output keep,
+	
+	// TX FCS
+	output reg fcs_init,
+	output reg fcs_enable,
+	output reg [1:0] fcs_addr,
+	output reg [7:0] fcs_dout,
+	input [7:0] fcs_din,
+	
+	// SGMII RX / FIFO Write
+	output rx_fifo_we,
+	output [8:0] rx_fifo_d,
+	output reg rx_error,
+	output reg rx_wr_done,
+	
+	// SGMII TX / FIFO Read
+	output reg tx_fifo_re,	
+	input [8:0] tx_fifo_d,
+	input tx_fifo_empty,
+	
+	// Packet Filter
+	output rx_sample,
+	output reg ipv4_pkt_start,
+	output reg trigger,
+
+	
+	output reg rx_k_m1, 
+	output reg rx_k_m2, 
+	output reg rx_k_m3, 
+	output reg rx_k_m4,
+	
+	output reg[7:0] rx_data_m1, 
+	output reg[7:0] rx_data_m2, 
+	output reg[7:0] rx_data_m3, 
+	output reg[7:0] rx_data_m4,
+	
+	// Param RAM for TAP port
+	output [10:0] dpr_ad,
+	output dpr_we,
+	output dpr_ce,
+	input [8:0] dpr_di,
+	output [8:0] dpr_do,
+	
+	// Metrics and Interrupts
+	output reg mac_int,
+	output reg rx_sop,		// start of packet
+	output reg rx_eop,
+	output reg tx_sop,
+	output reg tx_eop,
+	output reg metrics_start,
+	input [8:0] metrics_d,
+	
+	// Debug
+	output reg rx_active,
+	output reg tx_active
+);
+
+`include "sgmii_params.v"
+`include "ethernet_params.v"
+
+localparam  AN_TX_CONFIG_HI =		8'h00,
+			AN_TX_CONFIG_HI_ACK =	8'h40,
+			AN_TX_CONFIG_LO = 		8'h01;
+
+localparam 	RX_ST_IDLE=4'h0, RX_ST_SOP=4'h1, RX_ST_PREAMBLE=4'h2, RX_ST_SFD=4'h3, RX_ST_MAC_ADDR=4'h4,
+			RX_ST_MAC_TYPE0=4'h5, RX_ST_MAC_TYPE1=4'h6, RX_ST_DATA=4'h7, RX_ST_DATA_DONE0=4'h8,
+			RX_ST_DATA_DONE1=4'h9, RX_ST_DATA_DONE2=4'ha;
+			
+localparam 	TX_ST_0=4'h0, TX_ST_1=4'h1, TX_ST_2=4'h2, TX_ST_3=4'h3,
+			TX_ST_4=4'h4, TX_ST_5=4'h5, TX_ST_6=4'h6, TX_ST_7=4'h7,
+			TX_ST_8=4'h8, TX_ST_9=4'h9, TX_ST_A=4'ha, TX_ST_B=4'hb,
+			TX_ST_C=4'hc, TX_ST_D=4'hd, TX_ST_E=4'he, TX_ST_F=4'hf;
+			
+reg [3:0] rx_cnt_100mbit, tx_cnt_100mbit;
+
+wire tx_sample, tx_sample_re;
+wire rx_packet_complete;
+wire mode_1Gbit;
+reg [1:0] an_speed;
+
+reg [3:0] rx_state;
+reg [10:0] rx_byte_cnt;
+reg [10:0] rx_pkt_length;
+reg [15:0] rx_l3_proto;
+
+reg [7:0] tx_data_an, tx_data_idle, tx_data_pkt;
+reg tx_k_an, tx_k_idle, tx_k_pkt;
+
+// Transmit Registers and Wires
+reg [3:0] tx_state;			// transmit state machine
+reg [10:0] tx_byte_cnt;
+reg [5:0] param_addr;
+
+reg tx_f_an, tx_f_idle, tx_f_pkt;
+reg tx_last_byte;
+
+// FIFOs:
+reg [8:0] tx_fifo_d_m1;
+
+// FCS
+reg fcs_addr_e;
+
+// pipeline the param RAM for timing
+reg [8:0] dpr_di_reg;
+
+// counter for detecting Ethernet broadcast, only needs to count to 6
+reg [2:0] rx_enet_bcast_cnt;
+
+
+/*
+ * 		RX DIRECTION
+ * 		
+ */
+
+/* 
+ * 	A shallow pool of RX registers for analysis
+ */
+always @(posedge clk or negedge rstn)
+	begin
+		if (!rstn)
+			begin
+				rx_k_m1 <= 1'b0;
+				rx_k_m2 <= 1'b0;
+				rx_k_m3 <= 1'b0;
+				rx_k_m4 <= 1'b0;
+				rx_data_m1 <= 8'h0;
+				rx_data_m2 <= 8'h0;
+				rx_data_m3 <= 8'h0;
+				rx_data_m4 <= 8'h0;
+			end
+		else if (mode_1Gbit || rx_sample || rx_state == RX_ST_IDLE || rx_state == RX_ST_DATA_DONE2 )
+			begin
+				rx_k_m1 <= rx_k;
+				rx_k_m2 <= rx_k_m1;	
+				rx_k_m3 <= rx_k_m2;
+				rx_k_m4 <= rx_k_m3;
+				rx_data_m1 <= rx_data;
+				rx_data_m2 <= rx_data_m1;
+				rx_data_m3 <= rx_data_m2;
+				rx_data_m4 <= rx_data_m3;
+			end
+	end
+	
+/*
+ * 	SGMII Auto Negotiation  State Machine
+ * 	Look for configuration /C/ ordered set
+ * 	/C/ is Alternating /C1/ and /C2/
+ * 	/C1/: /K28.5/D21.5/Config_Reg
+ * 	/C2/: /K28.5/D2.2/Config_Reg
+ *	Config Reg:  Low High  
+ * 	
+ * 	Not using a link timer and not counting 3 frames because testing rmshows it's unnecessary
+ * 	
+ */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		begin
+			an_link_up <= 1'b0;
+			an_duplex <= 1'b0;
+			an_speed <= SGMII_SPEED_RSVD;
+			phy_up <= 1'b0;
+		end
+	else if ( !phy_resetn )
+		begin
+			an_link_up <= 1'b0;
+			an_duplex <= 1'b0;
+			an_speed <= SGMII_SPEED_RSVD;
+			phy_up <= 1'b0;
+		end
+	else if ( an_disable )
+		begin
+			phy_up <= 1'b1;
+		end
+	// D21.5 is part of config ( M2 has low, M1 has high )
+	else if  (!rx_k_m1 && !rx_k_m2 && !rx_k_m3 && rx_data_m3 == D21_5 && rx_k_m4 && rx_data_m4 == K28_5 )
+		begin		
+			an_link_up <= rx_data_m1[7];
+			an_duplex <= rx_data_m1[4];
+			an_speed <= rx_data_m1[3:2];
+			phy_up <= 1'b0;
+		end	
+	// IDLE2 1:0xBC, 0:0x50
+	else if ( !rx_k_m1 && rx_data_m1 == D16_2 && rx_k_m2 == 1'b1 && rx_data_m2 == K28_5 )
+		phy_up <= 1'b1;	
+
+// 100 MBit Support.  There are no plans to support 10 MBit, so 100 MBit inactive is the same as 1GBit active
+// if/else encodes the priority
+always @(*)
+	if (fixed_speed == SGMII_SPEED_100MBIT)
+		mode_100Mbit = 1'b1;
+	else if (fixed_speed == SGMII_SPEED_1GBIT)
+		mode_100Mbit = 1'b0;
+	else if (an_speed == SGMII_SPEED_100MBIT )
+		mode_100Mbit = 1'b1;
+	else 
+		mode_100Mbit = 1'b0;
+
+assign mode_1Gbit = ~mode_100Mbit;
+
+// RX 100 Mbit support
+assign rx_sample = (rx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0;
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		rx_cnt_100mbit <= 4'b0;
+	else if ( rx_cnt_100mbit == 4'd9 || rx_sop )
+		rx_cnt_100mbit <= 4'b0;
+	else
+		rx_cnt_100mbit <= rx_cnt_100mbit + 4'd1;		
+
+		
+/*		
+ * 		rx_state machine
+ * 		capture the Ethernet MAC header + packet.
+*/
+always @(posedge clk, negedge rstn)
+	if (!rstn)
+		rx_state <= RX_ST_IDLE;	
+	else if ( rx_eop || !phy_resetn )						// EOP will reset state machine
+		rx_state <= RX_ST_IDLE;	
+	else if ( phy_up )
+		case ( rx_state )
+			RX_ST_IDLE: if (rx_data_m1 == K27_7 && rx_k_m1 )		//	Found /S/
+						rx_state <= RX_ST_SOP;
+			RX_ST_SOP: if ( rx_sample ) 							// Capture /S/
+						rx_state <= RX_ST_PREAMBLE;					
+			RX_ST_PREAMBLE: if ( rx_sample && rx_data_m1 == 8'hd5 )	// 0xd5 preamble 
+						rx_state <= RX_ST_SFD;												
+			RX_ST_SFD: if ( rx_sample )
+						rx_state <= RX_ST_MAC_ADDR;
+			RX_ST_MAC_ADDR: if ( rx_sample && rx_byte_cnt == 12 ) 	// Use this state transition to signal end of ethernet header and start of packet
+						rx_state <= RX_ST_MAC_TYPE0;
+			RX_ST_MAC_TYPE0: if ( rx_sample ) 
+						rx_state <= RX_ST_MAC_TYPE1;				// Capture ethertype
+			RX_ST_MAC_TYPE1: if ( rx_sample )
+						rx_state <= RX_ST_DATA;					// 
+			RX_ST_DATA: if ( rx_sample && rx_packet_complete )	// write into FIFO until pkt length
+						rx_state <= RX_ST_DATA_DONE0;
+			RX_ST_DATA_DONE0: if ( rx_sample )
+						rx_state <= RX_ST_DATA_DONE1;					// write an extra byte into the FIFO
+			RX_ST_DATA_DONE1: if ( rx_sample )
+						rx_state <= RX_ST_DATA_DONE2;					// write an extra byte into the FIFO			
+			RX_ST_DATA_DONE2: if ( rx_sample )
+						rx_state <= rx_state;				// waiting for /T/
+			default: rx_state <= rx_state;
+		endcase
+	else 
+		rx_state <= RX_ST_IDLE;
+	
+/* 
+ *	rx_fifo_we
+*/
+assign rx_fifo_we = ( rx_sample && ( rx_state >= RX_ST_SFD && rx_state <= RX_ST_DATA_DONE1 ) ) ? 1'b1 : 1'b0;
+
+
+/*
+ *  Detect Ethernet Broadcast  (destination address = ff:ff:ff:ff:ff:ff)
+ *  
+ */
+always @(posedge clk, negedge rstn)
+	if (!rstn)  
+		rx_enet_bcast_cnt <= 3'h0;
+	else if ( rx_sample )
+	 	if (rx_data_m1 == 9'hff)
+			rx_enet_bcast_cnt <= rx_enet_bcast_cnt + 1;
+		else
+			rx_enet_bcast_cnt <= 3'h0;
+
+/* Ethernet Broadcast Dest Address, must be a one shot */
+always @(posedge clk, negedge rstn)
+	if (!rstn) 
+		rx_enet_bcast <= 1'b0;
+	else if ( rx_sample )
+		if ( rx_enet_bcast_cnt == 3'h6 )
+			rx_enet_bcast <= 1'b1;
+		else
+			rx_enet_bcast <= 1'b0;
+
+/* 
+	create a one shot that will assert during RX_ST_DATA_DONE1 so external logic can know
+	that the FIFO write has come to an end ( reset pointers, etc. )
+	
+	For 100Mbit, since the states change 10 clocks apart, set it during RX_ST_DATA_DONE1
+*/
+always @(posedge clk, negedge rstn)
+	if (!rstn)
+		rx_wr_done <= 1'b0;
+	else if ( mode_1Gbit && rx_state == RX_ST_DATA_DONE0 )
+		rx_wr_done <= 1'b1;
+	else if ( mode_100Mbit && rx_sample && rx_state == RX_ST_DATA_DONE1 )
+		rx_wr_done <= 1'b1;
+	else
+		rx_wr_done <= 1'b0;
+		
+/* capture layer 3 protocol (e.g., ipv4 or ipv6)	*/
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		rx_l3_proto <= 0;
+	else if ( rx_sop )
+		rx_l3_proto <= 0;
+	else if  ( rx_sample && rx_state == RX_ST_MAC_TYPE0 )
+		rx_l3_proto <= { rx_data_m2, rx_data_m1 };
+		
+// assert ipv4 ARP flag for filtering operations
+always @(posedge clk, negedge rstn)
+	if (!rstn)
+		rx_ipv4_arp <= 1'b0;
+	else if  ( rx_sample && rx_state == RX_ST_MAC_TYPE1 && rx_l3_proto == ETHER_TYPE_ARP)
+		rx_ipv4_arp <= 1'b1;		
+	else 
+		rx_ipv4_arp <= 1'b0;	
+	
+/* 
+ * keep flag
+ * signals must be one shot
+ * 
+ */
+ assign keep = rx_enet_bcast | rx_ipv4_arp; 
+
+	
+/* rx_error 	
+ * */
+always @(*)
+	if ( rx_sample &&  rx_state >= RX_ST_DATA && (  rx_l3_proto != ETHER_TYPE_IPV4 && rx_l3_proto != ETHER_TYPE_IPV6 && rx_l3_proto != ETHER_TYPE_ARP) )
+		rx_error = 1;
+	else
+		rx_error = 0;
+
+/* rx_byte_cnt */
+always @(posedge clk, negedge rstn)
+	if (!rstn)
+		rx_byte_cnt <= 'h0;
+	else if (rx_sample)
+		if ( rx_state == RX_ST_IDLE ||  rx_state == RX_ST_PREAMBLE ) 
+			rx_byte_cnt <= 'h0;
+		else if ( rx_state == RX_ST_MAC_TYPE0 )
+			rx_byte_cnt <= 'h1;
+		else 
+			rx_byte_cnt <= rx_byte_cnt + 1;
+	
+/* rx_pkt_length */
+always @(posedge clk, negedge rstn)
+	if ( !rstn )	
+		rx_pkt_length <= 0;
+	else if ( rx_sop )
+		rx_pkt_length <= 0;
+	else if (rx_sample)
+		if ( rx_l3_proto == ETHER_TYPE_IPV4 && rx_state == RX_ST_DATA && rx_byte_cnt == 'h4 ) 
+			rx_pkt_length <= { rx_data_m2[2:0], rx_data_m1 };
+		else if ( rx_l3_proto == ETHER_TYPE_IPV6 && rx_state == RX_ST_DATA && rx_byte_cnt == 'h6 ) 	
+			rx_pkt_length <= { rx_data_m2[2:0], rx_data_m1 } + 'd40;
+		else if ( rx_l3_proto == ETHER_TYPE_ARP && rx_state == RX_ST_DATA )
+			rx_pkt_length <= 'd46;
+	
+/* ipv4 flag */
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		ipv4_pkt_start <= 1'b0;
+	else if ( rx_sample && rx_l3_proto == ETHER_TYPE_IPV4 && rx_state == RX_ST_MAC_TYPE1 ) 
+		ipv4_pkt_start <= 1;	
+	else
+		ipv4_pkt_start <= 0;
+	
+assign rx_packet_complete = ( rx_sample && rx_state >= RX_ST_DATA && rx_pkt_length == rx_byte_cnt ) ? 1 : 0;
+	
+// FIFO data interface
+assign rx_fifo_d[7:0] = rx_data_m1;
+assign rx_fifo_d[8] = rx_packet_complete;
+
+
+/* 
+ *	rx_sop, K27_7, 0xFB  /S/	Start_of_Packet
+ */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		rx_sop	<=1'b0;
+	else if ( rx_data_m1 == K27_7 && rx_k_m1 == 1'b1 )
+		rx_sop <= 1'b1;
+	else
+		rx_sop <= 1'b0;
+			
+/* 
+ *	rx_eop, K29_7, 0xFD, /T/	End_of_Packet
+ */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		rx_eop <=1'b0;
+	else if ( rx_data_m1 == K29_7 && rx_k_m1 == 1'b1 )
+		rx_eop <= 1'b1;
+	else
+		rx_eop <= 1'b0;
+	
+/* MAC Interrupt 
+ * Create one shot interrupt while interrupt source is active
+ * Rely on interrupt controller to latch & clear
+ */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		mac_int <=1'b0;
+	else if ( !rx_lsm || rx_cv_err || rx_cdr_lol || rx_los )
+		mac_int <= 1'b1;
+	else
+		mac_int <= 1'b0;	
+			
+	
+/* Debug RX */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		rx_active <=1'b0;
+	else if ( rx_state != 0 )
+		rx_active <= 1'b1;
+	else
+		rx_active <= 1'b0;
+	
+	
+	
+/*
+ * 		TX DIRECTION
+ * 		
+ */
+ 
+ 
+ // TX 100 Mbit support
+assign tx_sample_re = (tx_cnt_100mbit == 4'd8 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0;
+assign tx_sample = (tx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0;
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		tx_cnt_100mbit <= 4'b0;
+	else if ( tx_state == TX_ST_0 )
+		tx_cnt_100mbit <= 4'b1;			// steal a bit here during preamble so we keep an even bit count
+	else if ( tx_cnt_100mbit == 4'd9 )
+		tx_cnt_100mbit <= 4'b0;
+	else
+		tx_cnt_100mbit <= tx_cnt_100mbit + 1;	
+ 
+ 
+/*
+*
+*	Transmit Mux 
+*/
+always@(*)
+	begin
+		case(tx_mode)
+			TX_MODE_AN : 
+				begin
+					tx_data = tx_data_an;
+					tx_k = tx_k_an;
+					tx_f = tx_f_an;
+				end
+			TX_MODE_IDLE : 
+				begin
+					tx_data = tx_data_idle;
+					tx_k = tx_k_idle;
+					tx_f = tx_f_idle;
+				end
+			TX_MODE_XMT_PKT : 
+				begin
+					tx_data = tx_data_pkt;
+					tx_k = tx_k_pkt;
+					tx_f = tx_f_pkt;
+				end
+			TX_MODE_XMT_METRICS : 
+				begin
+					tx_data = tx_data_pkt;
+					tx_k = tx_k_pkt;
+					tx_f = tx_f_pkt;
+				end
+			default : 
+				begin
+					tx_data = K_ERROR;
+					tx_k = 1'b1;
+					tx_f = 1'b1;
+				end
+		endcase
+	end
+
+
+/*  
+ * 	CONFIG SM
+*	During SGMII auto negotiation, send /C1/ and /C2/ ordered sets
+*	C1: /K28.5/D21.5/Config Regs
+*	C2: /K28.5/D2.2/Config Regs
+*/
+always @(*)
+	begin
+		tx_f_an = 1'b0;
+		tx_k_an = 1'b0;
+		case(tx_byte_cnt[2:0])
+			3'd0: 
+				begin
+					tx_data_an = K28_5;
+					tx_k_an = 1'b1;
+				end
+			3'd1: 
+				tx_data_an = D21_5;
+			3'd2: 
+				tx_data_an = AN_TX_CONFIG_LO;
+			3'd3: 
+				if (!an_link_up)
+					tx_data_an = AN_TX_CONFIG_HI;
+				else 
+					tx_data_an = AN_TX_CONFIG_HI_ACK;
+			3'd4: 
+				begin
+					tx_data_an = K28_5;
+					tx_k_an = 1'b1;
+				end
+			3'd5: 
+				tx_data_an = D2_2;
+			3'd6: 
+				tx_data_an = AN_TX_CONFIG_LO;
+			3'd7: 
+				if (!an_link_up)
+				begin
+					tx_f_an = 1'b1;	
+					tx_data_an = AN_TX_CONFIG_HI;
+				end
+				else
+				begin
+					tx_f_an = 1'b1;	
+					tx_data_an = AN_TX_CONFIG_HI_ACK;
+				end
+			default:
+				begin
+					tx_data_an = K_ERROR;
+					tx_k_an = 1'b1;
+					tx_f_an = 1'b1;
+				end
+		endcase
+	end
+	
+/* IDLE2 SM	*/
+always @(*)
+	begin
+		tx_f_idle = 1'b0;
+		case(tx_byte_cnt[1:0])
+			3'd0: 
+				begin
+					tx_data_idle = K28_5;
+					tx_k_idle = 1'b1;
+				end
+			3'd1: 
+				begin
+					tx_data_idle = D16_2;
+					tx_k_idle = 1'b0;
+					tx_f_idle = 1'b1;
+				end
+			default:
+				begin
+					tx_data_idle = K_ERROR;
+					tx_k_idle = 1'b1;
+					tx_f_idle = 1'b1;
+				end
+		endcase
+	end 
+	
+
+
+
+/* 	
+*	Transmit Packet State Machine for TX_MODE_XMT_PKT and TX_MODE_XMT_METRICS
+*	
+*
+*		Note: the first /I/ following a transmitted frame or Configuration ordered set
+*		restores the current positive or negative running disparity to a
+*		negative value.
+*
+*/
+always @(posedge clk, negedge rstn) 
+	begin 
+		if ( !rstn )
+			tx_state <= TX_ST_0;
+		else if ( !phy_resetn )
+			tx_state <= TX_ST_0;
+		else
+			case(tx_state)
+				TX_ST_0: if ( tx_mode >= TX_MODE_XMT_PKT && !tx_f_pkt )	// /S/
+							tx_state <= TX_ST_1;
+				TX_ST_1: if ( tx_sample && tx_byte_cnt == 8'h5 )		// preamble 0x55
+							tx_state <= TX_ST_2;
+				TX_ST_2: if ( tx_sample ) 
+							tx_state <= TX_ST_3;						// preamble 0x55, assert tx_fifo_re, reset tx_byte_cnt
+				TX_ST_3: if ( tx_sample )
+							tx_state <= TX_ST_4;						// preamble 0xD5
+				TX_ST_4: if ( tx_sample && tx_last_byte && tx_byte_cnt < 60 )		// check if we need to pad?
+							tx_state <= TX_ST_5;
+						 else if ( tx_sample && (tx_fifo_empty || tx_last_byte) )	// check if we're done
+							tx_state <= TX_ST_6;
+				TX_ST_5: if ( tx_sample && tx_byte_cnt >= 60 )		// pad state, test for sufficient frame size
+						tx_state <= TX_ST_6;
+				TX_ST_6: if ( tx_sample && fcs_addr == 2'b10 )		// Start FCS
+							tx_state <= TX_ST_7;
+				TX_ST_7: if (tx_sample && fcs_addr == 2'b11 )		// Finish FCS
+							tx_state <= TX_ST_8;
+				TX_ST_8: tx_state <= TX_ST_9;						// EOP /T/
+				TX_ST_9: if ( tx_byte_cnt[0] && !mode_100Mbit)		// test for odd # of code words when in Gig mode for extra /R/ insertion
+							tx_state <= TX_ST_A;
+						else
+							tx_state <= TX_ST_B;
+				TX_ST_A: tx_state <= TX_ST_B;						// 2nd /R/ if necessary ( odd position )
+				TX_ST_B: tx_state <= TX_ST_C;						// I2, K28.5
+				TX_ST_C: tx_state <= TX_ST_0;						// I2, D16.2
+
+				default: tx_state <= tx_state;
+			endcase
+	end
+	
+	
+	
+		
+/*
+*		tx related data mux and control signals
+*
+*/
+always @(*)
+	begin
+		tx_f_pkt = 1'b0;
+		tx_k_pkt = 1'b0;
+		tx_disp_correct = 1'b0;
+		tx_last_byte = 1'b0;
+		fcs_init = 1'b0;
+		fcs_addr_e = 1'b0;
+		fcs_dout = tx_fifo_d_m1[7:0];
+		metrics_start = 1'b0;
+		case(tx_state)
+			TX_ST_0: 
+				begin
+					tx_data_pkt = K27_7;		// start of packet
+					tx_k_pkt = 1'b1;
+					fcs_init = 1'b1;
+				end
+			TX_ST_1: begin
+					tx_data_pkt = 8'h55;		// preamble, we need 6 bytes total of 0x55
+				end
+			TX_ST_2: begin
+					tx_data_pkt = 8'h55;		// preamble, single byte of 0x55 and assert fifo_re	
+				end
+			TX_ST_3: begin
+					tx_data_pkt = 8'hD5;		// preamble, single byte of 0xd5 completes the preamble)
+				end
+			TX_ST_4: 
+				begin
+					if ( tx_mode == TX_MODE_XMT_METRICS && tx_byte_cnt <= SZ_ETH_HEADER + SZ_IPV4_HEADER + SZ_UDP_HEADER )
+						begin
+							tx_data_pkt = dpr_di_reg[7:0];			// packet headers
+							fcs_dout = dpr_di_reg[7:0];
+							metrics_start = 1'b1;					// keeps the metrics counters in reset
+						end
+					else if ( tx_mode == TX_MODE_XMT_METRICS )
+						begin
+							tx_data_pkt = metrics_d;			// packet content
+							fcs_dout = metrics_d[7:0];
+							tx_last_byte = metrics_d[8];
+						end
+					else
+						begin
+							tx_data_pkt = tx_fifo_d_m1[7:0];		// read data from memory
+							tx_last_byte = tx_fifo_d_m1[8];
+						end
+				end
+			TX_ST_5:
+				begin
+					tx_data_pkt = 8'h0;		// pad				
+				end
+			TX_ST_6: begin
+					tx_data_pkt = fcs_din;		// read from fcs			
+					fcs_addr_e = 1'b1;
+				end
+			TX_ST_7: begin
+					tx_data_pkt = fcs_din;		// read from fcs
+					fcs_addr_e = 1'b1;
+				end
+			TX_ST_8: 
+				begin
+					tx_data_pkt = K29_7;		// end of packet
+					tx_k_pkt = 1'b1;
+				end
+			TX_ST_9: 	
+				begin
+					tx_data_pkt = K23_7;		// carrier extend
+					tx_k_pkt = 1'b1;
+				end
+			TX_ST_A: 
+				begin
+					tx_data_pkt = K23_7;		// carrier extend
+					tx_k_pkt = 1'b1;
+				end
+			TX_ST_B: 
+				begin
+					tx_data_pkt = K28_5;		// 1st idle code
+					tx_k_pkt = 1'b1;
+				end
+			TX_ST_C: 
+				begin
+					tx_data_pkt = D16_2;		// 2nd idle code
+					tx_disp_correct = 1'b1;	// PCS may convert D16.2 to a D5.6 for I2 to flip disparity
+					tx_f_pkt = 1'b1;
+				end
+			default:
+				begin
+					tx_data_pkt = K_ERROR;
+					tx_k_pkt = 1'b1;
+					tx_f_pkt = 1'b1;
+				end				
+		endcase
+end
+
+/* 
+ *	tx_fifo_re
+ *
+ *	The use of the read fifo is different between 1Gbit and 100Mbit.
+ *	
+ */
+always @(*)
+ 	if ( tx_mode == TX_MODE_XMT_PKT )
+		 if ( mode_1Gbit && tx_state >= TX_ST_2 && tx_state <= TX_ST_4 )
+			 tx_fifo_re = 1'b1;
+		 else if ( mode_100Mbit && tx_sample_re && tx_state > TX_ST_2 && tx_state <= TX_ST_4 ) 
+	 		 tx_fifo_re = 1'b1;
+		 else if ( mode_100Mbit && tx_state == TX_ST_8 )	// we need an extra FIFO strobe at 100MBit for a single 1G clk
+		 	 tx_fifo_re = 1'b1;		 	
+		 else
+			 tx_fifo_re = 1'b0;
+ 	else
+ 		tx_fifo_re = 1'b0;	
+
+
+always @(posedge clk, negedge rstn)
+	if (!rstn)
+		param_addr <= 'h0;
+	else if (tx_sample)
+		if ( mode_100Mbit && tx_state == TX_ST_1 && tx_byte_cnt == 'h5 )
+			param_addr <= 'h0;
+		else if ( mode_1Gbit && tx_state == TX_ST_1 && tx_byte_cnt == 'h4 )
+			param_addr <= 'h0;
+		else
+			param_addr <= param_addr + 1;
+		
+/* 
+	tx_byte_cnt 
+	
+	Increment at pcs clock rate for PCS layer data (e.g., /I1/, /C/, /S/, etc.
+	
+	Increment at sample rate for Ethernet data
+	
+*/
+always @(posedge clk, negedge rstn)
+	if (!rstn)
+		tx_byte_cnt <= 'h0;
+	else if (tx_sample || tx_state == TX_ST_0 || tx_state > TX_ST_7 || tx_mode < TX_MODE_XMT_PKT )
+		if (tx_f)
+			tx_byte_cnt <= 'h0;
+		else if ( tx_state == TX_ST_2 )
+			tx_byte_cnt <= 'h0;					// start counting the Ethernet Frame after preamble
+		else
+			tx_byte_cnt <= tx_byte_cnt + 1;
+
+/*
+ *	pipeline data from FIFO
+ */
+always @(posedge clk or negedge rstn) 
+begin 
+	if ( !rstn )
+		tx_fifo_d_m1 <= 9'h0;
+	else if ( tx_sample )
+		tx_fifo_d_m1 <= tx_fifo_d;
+end
+
+/*
+*	FCS
+*/
+always @(posedge clk or negedge rstn) 
+	begin 
+		if ( !rstn )
+			fcs_addr <= 2'b00;
+		else if (tx_sample)
+			if ( !fcs_addr_e )
+				fcs_addr <= 2'b00;
+			else
+				fcs_addr <= fcs_addr + 1;
+	end
+	
+always @(*)
+	if (mode_1Gbit && (tx_state == TX_ST_4 || tx_state == TX_ST_5) )
+		fcs_enable = 1'b1;
+	else if ( mode_100Mbit && tx_sample &&  (tx_state == TX_ST_4 || tx_state == TX_ST_5)  )
+		fcs_enable = 1'b1;		
+	else
+		fcs_enable = 1'b0;	
+	
+/*
+*	DPRAM, param ram Control for TAP port
+*/
+always @(posedge clk or negedge rstn) 
+	if ( !rstn )
+		dpr_di_reg <= 9'h0;
+	else if (tx_sample)
+		dpr_di_reg <= dpr_di;
+		
+
+assign dpr_we = 1'b0;
+assign dpr_ce = 1'b1;
+assign dpr_ad = { 4'h0, param_addr };
+
+/* 
+ *	tx_sop, K27_7, 0xFB  /S/	Start_of_Packet
+ *  We choose to not include TX_MODE_CUSTOM_PKT for this metric
+ */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		tx_sop	<=1'b0;
+	else if ( tx_state == TX_ST_0 && tx_mode == TX_MODE_XMT_PKT )
+		tx_sop <= 1'b1;
+	else
+		tx_sop <= 1'b0;
+			
+	/* 
+		 *	tx_eop, K29_7, 0xFD, /T/	End_of_Packet
+		 */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		tx_eop <=1'b0;
+	else if ( tx_state == TX_ST_7 )
+		tx_eop <= 1'b1;
+	else
+		tx_eop <= 1'b0;
+	
+/* Debug TX */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		tx_active <=1'b0;
+	else if ( tx_state != 0 )
+		tx_active <= 1'b1;
+	else
+		tx_active <= 1'b0;
+
+endmodule
diff --git a/source/mdio.v b/source/mdio.v
new file mode 100644
index 0000000..3339dcc
--- /dev/null
+++ b/source/mdio.v
@@ -0,0 +1,146 @@
+/*
+ *      mdio.v
+ *
+ *   Copyright (C) 2018, 2019 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: MDIO HW driver / bit banger
+ *	
+ */
+
+
+`timescale 1ns /10ps
+
+module mdio(
+	input rstn,
+	input mdc,				// clock
+	
+	// mdio 
+	input mdi,
+	output reg mdo,
+	output reg mdo_oe,
+	
+	// mdio_controller interface
+	input rwn,				// read / write not
+	input [4:0] phy_addr,		
+	input [4:0] reg_addr,
+	input [15:0] di,
+	input ld,				// load, start
+	output reg run,
+	output done,            // mdio xfer is done
+	
+	// output port to converter
+	output reg [15:0] dout,
+	output we
+);
+	
+	reg [5:0] state;
+	reg [15:0] d;  
+	
+	// run state machine
+	// run starts when ld is asserted and finishes when done is asserted
+    always @(negedge mdc or negedge rstn)	
+		begin
+			if ( !rstn)
+				run <= 1'b0;
+			else if ( ld )
+				run <= 1'b1;				
+			else if ( done )
+				run <= 1'b0;
+		end
+
+
+	// increment state during run
+    always @(negedge mdc or negedge rstn) 
+		begin 
+			if ( !rstn )
+				state <= 0;
+			else if ( ld ) 
+				state <= 0;
+			else if ( run ) 
+				state <= state + 1;
+		end
+		
+	// register data for MDIO TX
+    always @(negedge mdc or negedge rstn)	
+		begin
+			if ( !rstn )
+				d <= 0;
+			else if ( ld )
+				d <= di;				
+		end
+				
+	// done combo logic
+	assign done = ( state == 6'd36 ) ? 1'b1 : 1'b0;
+
+	// only assert we on mdio reads 
+	assign we = done && rwn;	
+				
+	// mdo_oe logic
+	always @(*)
+		begin
+			mdo_oe = 1'b0;
+			if ( run && !rwn && state < 6'd36 )
+				mdo_oe = 1'b1;
+			else if ( run && rwn && state < 6'd14 )
+				mdo_oe = 1'b1;
+		end			
+	
+	// mdo mux
+	always @(*)
+		begin
+			mdo = 1'b0;
+			casez(state)
+				6'h0: 	mdo = 1'b0;
+				6'h1: 	mdo = 1'b1;
+				6'h2: 	if (rwn)
+							mdo = 1'b1;
+						else
+							mdo = 1'b0;
+				6'h3: 	if (rwn)
+							mdo = 1'b0;
+						else
+							mdo = 1'b1;
+				6'h4:	mdo = phy_addr[4];
+				6'h5:	mdo = phy_addr[3];
+				6'h6:	mdo = phy_addr[2];
+				6'h7:	mdo = phy_addr[1];
+				6'h8:	mdo = phy_addr[0];
+				6'h9:	mdo = reg_addr[4];
+				6'ha:	mdo = reg_addr[3];
+				6'hb:	mdo = reg_addr[2];
+				6'hc:	mdo = reg_addr[1];
+				6'hd:	mdo = reg_addr[0];
+				6'he: 	mdo = 1'b1;			// it's a don't care if we're doing a read
+				6'hf:	mdo = 1'b0;
+				6'h1?:	mdo = rwn ? 1'b1 : d[31-state];		// msbit
+				default: mdo = 1'b1;
+			endcase
+		end	
+		
+		
+	/*
+	*	capture mdi on rising edge
+	* 	data out shift register 
+	*	( shift into it from mdio to parallel reg )
+	*/
+    always @(posedge mdc or negedge rstn)	
+		begin
+			if ( !rstn )
+				dout <= 16'h0;
+			else if ( rwn && run && ( state >= 16 && state <= 31 ))
+				dout <= { dout[14:0], mdi };
+		end
+	
+endmodule
diff --git a/source/mdio_cont.v b/source/mdio_cont.v
new file mode 100644
index 0000000..ad595fd
--- /dev/null
+++ b/source/mdio_cont.v
@@ -0,0 +1,159 @@
+/*
+ *       mdio_cont.v
+ *
+ *	 Copyright (C) 2018, 2019 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: MDIO controller / state machine
+ *
+ */
+
+`timescale 1ns /10ps
+
+module mdio_controller		#(parameter ADDR_SZ = 6)
+(
+	
+	// system interface
+	input rstn,
+	input clk,				// mdio mdc clock	
+	
+	// worker interface
+	input work_start,
+	output reg work_run,
+	output reg work_done,
+	input [ADDR_SZ-1:0] routine_addr,
+	
+	// arbitration
+	input buffer_full,
+
+	// memory interface
+	output reg [ADDR_SZ-1:0] addr,	// controller address
+	input [7:0] di,			// controller data bus
+	
+	// mdio interface
+	output reg [4:0] reg_addr,
+	output reg [15:0] dout,	// data output ( for writes )
+	output ld, 				// load control / address, 
+	output reg rwn,			// read / write not
+	input done
+);
+	
+	localparam ST_SZ = 4;
+	reg [ST_SZ-1:0] cont_state;
+	wire ld_dl, ld_dh;
+	
+	
+	// state encoding
+	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;
+
+
+	/* 
+	*  keep running until an eop is found 
+	*/
+    always @(posedge clk or negedge rstn) 
+		begin 
+			if (!rstn)
+				cont_state <= S0;
+			else
+				case (cont_state)
+					S0: if (work_start == 1'b1) cont_state <= S1;
+					S1: cont_state <= S2;
+					S2: if ( work_done == 1'b1 ) cont_state <= S0;
+						else if ( buffer_full ) cont_state <= S2;	// wait for the fifo to empty out
+						else if ( ~rwn ) cont_state <= S3;
+						else cont_state <= S6;
+					S3: cont_state <= S4;
+					S4: cont_state <= S5;
+					S5: cont_state <= S6;
+					S6: cont_state <= S7;
+					S7: if ( done == 1'b1 ) cont_state <= S8;
+					S8: cont_state <= S1;
+				endcase
+		end
+	
+	/* read the eop bit during S1 */
+	always @(posedge clk or negedge rstn)
+		begin
+			if ( !rstn )
+				work_done <= 1'b0;
+			else if ( cont_state == S1 && di[7] == 1'b1 ) 
+				work_done <= 1'b1;
+			else
+				work_done <= 1'b0;
+		end
+		
+	/* work_run */
+	always @(posedge clk or negedge rstn)
+		begin
+			if ( !rstn )
+				work_run <= 1'b0;
+			else if ( work_start == 1'b1 ) 
+				work_run <= 1'b1;
+			else if ( work_done == 1'b1 )
+				work_run <= 1'b0;
+		end	
+		
+	/* set RWN for duration of cyle */
+	always @(posedge clk or negedge rstn)
+		begin
+			if ( rstn == 1'b0 || work_done ==1'b1 )
+				begin
+					rwn <= 1'b1;
+				end
+			else if ( cont_state == S1 )
+				begin
+					rwn <= di[5];
+				end		
+		end
+				
+	/* reg_addr is the mdio register address */
+	always @(posedge clk or negedge rstn)
+		begin
+			if ( rstn == 1'b0 || work_done ==1'b1 )
+				reg_addr <= 5'h0;
+			else if ( cont_state == S1 )
+				reg_addr <= di[4:0];	  
+		end
+		
+	/* addr is the program address */
+	always @(posedge clk or negedge rstn)
+		begin
+			if (rstn == 1'b0 || work_done == 1'b1 )
+				addr <= 0;
+			else if ( work_start == 1'b1 )
+				addr <= routine_addr[ADDR_SZ-1:0];
+			else if ( cont_state == S3 || cont_state == S4 || cont_state == S8 )
+				addr <= addr + 1;
+		end
+				
+	// latch the write data to mdio
+	always @(posedge clk or negedge rstn)
+		begin
+			if (rstn == 0)
+				dout <= 16'h0000;
+			else if ( ld_dl == 1'b1 )
+				dout[7:0] <= di;
+			else if ( ld_dh == 1'b1 )
+				dout[15:8] <= di;
+		end
+		
+	// combinatorial logic here
+	assign ld_dl = ( cont_state == S4 ) ? 1'b1 : 1'b0;
+	assign ld_dh = ( cont_state == S5 ) ? 1'b1 : 1'b0;
+	assign ld = ( cont_state == S6 ) ? 1'b1 : 1'b0;
+	
+
+endmodule
diff --git a/source/mdio_data_ti.v b/source/mdio_data_ti.v
new file mode 100644
index 0000000..aef537d
--- /dev/null
+++ b/source/mdio_data_ti.v
@@ -0,0 +1,128 @@
+/*
+ *   mdio_data_ti.v  ( TI DP83867 PHY )
+ *
+ *   Copyright (C) 2018, 2019 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: MDIO ROM for TI DP83867 PHY 
+ *	
+ */
+
+
+
+`timescale 1ns /10ps
+
+module mdio_data_ti #(parameter ADDR_SZ = 7)
+(
+	// params that alter the data returned
+	input [4:0] page,
+	input [4:0] reg_addr,
+	input [7:0] data_in_h,
+	input [7:0] data_in_l,
+	
+	// ROM interface
+	input oe,
+	input [ADDR_SZ-1:0]ad,	
+	output [7:0]d
+);
+
+localparam R = 8'h20;
+localparam W = 8'h00;
+localparam EOP = 8'h80;
+
+localparam REGCR = 5'h0d;
+localparam ADDAR = 5'h0e;
+
+reg [7:0]data;
+
+assign d = oe ? data : 8'hzz;
+
+// register 22 is page       
+always @ (*)
+begin
+	case (ad)	
+		/* 
+			Subroutine: SGMII Init ( i ) Not Needed for TI PHY, but read PHY Control Register (PHYCR), Address 0x0010
+		*/	
+		
+		// read the PHYCR register, SGMII Enable is bill 11
+		0: data = R|8'h10;		// pg 18, reg 20
+		
+		/* 
+			Subroutine: Read Live Status ( s )
+		*/
+		// read the live copper status PHYSTS (0x17) 
+		20 : data = R|8'h11;	// read addr[17]
+		
+		/* 
+			Subroutine: Dump Registers 0:3
+		*/
+		25: data = R|8'd0;
+		26 : data = R|8'd1;
+		27 : data = R|8'd2;
+		28 : data = R|8'd3;
+		
+		/* 
+			Subroutine: : Loopback ( 0_0.14 )
+		*/
+		40 : data = W|8'd0;				// write addr[0]
+		44 : data = 8'b01000000;		// collision, speed select, reserved
+		45 : data = 8'b01010001;		// reset, loopback, speed, AN enable, power down, isolate, restart AN, duplex;
+		
+		// read it back
+		46: data = R|8'd0;
+		
+		/* 
+			Subroutine: : Read a register.
+		*/
+		48: data = { 3'b001, reg_addr };
+		
+		/* 
+			Subroutine: : Write a register.
+		*/
+		50: data = { 3'b000, reg_addr };
+		51: data = data_in_l;
+		52: data = data_in_h;
+		// read it back		
+		// 53: data = { 3'b001, reg_addr };
+		
+		// y: extended read
+		60: data = {3'b000 , REGCR };		
+		61: data = 8'h1f;
+		62: data = 8'h00;
+		// Write the extended address to 0xe
+		63: data = { 3'b000, ADDAR };
+		64: data = data_in_l;
+		65: data = data_in_h;
+		// Write 0x401f to 0xd
+		66: data = { 3'b000, REGCR };
+		67: data = 8'h1f;
+		68: data = 8'h40;
+		// Read value in extended register: read 0x0E
+		69: data = { 3'b001, ADDAR  };		
+		
+		// z: extended write
+		// Write value in extended register: 0x0E
+		80: data = { 3'b000, ADDAR };
+		81: data = data_in_l;
+		82: data = data_in_h;
+		// read it back		
+		83: data = { 3'b001, ADDAR  };
+		
+		default: data = R|EOP;
+	endcase
+end
+
+endmodule
+	
diff --git a/source/metrics.v b/source/metrics.v
new file mode 100644
index 0000000..bce3389
--- /dev/null
+++ b/source/metrics.v
@@ -0,0 +1,102 @@
+/*
+ *       metrics.v
+ *       
+ *   Copyright (C) 2018, 2019 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: Collect metrics here and register them for transmit
+ *
+ *		
+ */
+ 
+`timescale 1ns /10ps
+
+module metrics(
+		input rstn,
+		input clk,
+		input mode_100Mbit,
+
+		// input data for gathering metrics
+		input [3:0] rx_mac_keep,
+		input rx_pf_keep_01,
+		input rx_pf_keep_02,
+		input rx_pf_keep_10,
+		input rx_pf_keep_12,
+		input rx_pf_keep_20,
+		input rx_pf_keep_21,
+		input rx_pf_keep_23,
+	
+		input [3:0] rx_eop, 
+		input [3:0] rx_sop,
+		input [3:0] tx_eop,
+		input [3:0] tx_sop,
+		
+		// metric outputs
+		input metrics_start,
+		output reg [8:0] metrics_d
+);
+	
+reg [7:0] rx_pkt_cnt;
+reg [7:0] tx_pkt_cnt;
+
+reg [7:0] rx0_drop_cnt;
+reg [7:0] rx1_drop_cnt;
+
+reg [3:0] bit_cnt;
+reg [3:0] addr;
+
+always @(posedge clk or negedge rstn)
+	if (!rstn) begin
+		bit_cnt <= 4'h0;
+		addr <= 4'h0;
+		end
+	else if ( metrics_start ) begin
+		bit_cnt <= 4'h0;
+		addr <= 4'h0;
+		end
+	else if ( !mode_100Mbit || ( mode_100Mbit && bit_cnt == 4'h9 ) ) begin
+		bit_cnt <= 4'h0;
+		addr <= addr + 1;
+		end
+	else 
+		bit_cnt <= bit_cnt + 1;
+		
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		rx_pkt_cnt <= 'h0;
+	else if (rx_eop[2])
+		rx_pkt_cnt <= rx_pkt_cnt + 1;
+		
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		tx_pkt_cnt <= 'h0;
+	else if (tx_eop[2])
+		tx_pkt_cnt <= tx_pkt_cnt + 1;
+	
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		metrics_d <= 9'h100;
+	else begin
+		case(addr)
+			'h0: metrics_d <=  { 1'b0, rx_pkt_cnt };
+			'h1: metrics_d <=  { 1'b0, tx_pkt_cnt };
+			'h2: metrics_d <=  { 1'b0, rx0_drop_cnt };
+			'h3: metrics_d <=  { 1'b1, rx1_drop_cnt };
+			default: metrics_d <= 9'h100;
+		endcase
+	end
+		
+
+
+endmodule
diff --git a/source/pcs.v b/source/pcs.v
new file mode 100644
index 0000000..8722887
--- /dev/null
+++ b/source/pcs.v
@@ -0,0 +1,228 @@
+/* synthesis translate_off*/
+`define SBP_SIMULATION
+/* synthesis translate_on*/
+`ifndef SBP_SIMULATION
+`define SBP_SYNTHESIS
+`endif
+
+//
+// Verific Verilog Description of module pcs
+//
+module pcs (sgmii0_rx_cv_err, sgmii0_rx_disp_err, sgmii0_rx_k, sgmii0_rxdata, 
+            sgmii0_sci_addr, sgmii0_sci_rddata, sgmii0_sci_wrdata, sgmii0_tx_disp_correct, 
+            sgmii0_tx_k, sgmii0_txdata, sgmii0_xmit, sgmii1_rx_cv_err, 
+            sgmii1_rx_disp_err, sgmii1_rx_k, sgmii1_rxdata, sgmii1_tx_disp_correct, 
+            sgmii1_tx_k, sgmii1_txdata, sgmii1_xmit, sgmii2_rx_cv_err, 
+            sgmii2_rx_disp_err, sgmii2_rx_k, sgmii2_rxdata, sgmii2_sci_addr, 
+            sgmii2_sci_rddata, sgmii2_sci_wrdata, sgmii2_tx_disp_correct, 
+            sgmii2_tx_k, sgmii2_txdata, sgmii2_xmit, refclk0_refclkn, 
+            refclk0_refclkp, sgmii0_ctc_del_s, sgmii0_ctc_ins_s, sgmii0_ctc_orun_s, 
+            sgmii0_ctc_urun_s, sgmii0_cyawstn, sgmii0_hdinn, sgmii0_hdinp, 
+            sgmii0_hdoutn, sgmii0_hdoutp, sgmii0_lsm_status_s, sgmii0_rst_dual_c, 
+            sgmii0_rx_cdr_lol_s, sgmii0_rx_los_low_s, sgmii0_rx_pcs_rst_c, 
+            sgmii0_rx_pwrup_c, sgmii0_rx_serdes_rst_c, sgmii0_sci_en, 
+            sgmii0_sci_en_dual, sgmii0_sci_int, sgmii0_sci_rd, sgmii0_sci_sel, 
+            sgmii0_sci_sel_dual, sgmii0_sci_wrn, sgmii0_serdes_rst_dual_c, 
+            sgmii0_signal_detect_c, sgmii0_tx_pclk, sgmii0_tx_pcs_rst_c, 
+            sgmii0_tx_pwrup_c, sgmii0_tx_serdes_rst_c, sgmii0_txi_clk, sgmii0_pll_lol, 
+            sgmii1_ctc_del_s, sgmii1_ctc_ins_s, sgmii1_ctc_orun_s, sgmii1_ctc_urun_s, 
+            sgmii1_hdinn, sgmii1_hdinp, sgmii1_hdoutn, sgmii1_hdoutp, 
+            sgmii1_lsm_status_s, sgmii1_rst_dual_c, 
+            sgmii1_rx_cdr_lol_s, sgmii1_rx_los_low_s, sgmii1_rx_pcs_rst_c, 
+            sgmii1_rx_pwrup_c, sgmii1_rx_serdes_rst_c,  
+            sgmii1_serdes_pdb, sgmii1_serdes_rst_dual_c, sgmii1_signal_detect_c, 
+            sgmii1_tx_pclk, sgmii1_tx_pcs_rst_c, sgmii1_tx_pwrup_c, sgmii1_tx_serdes_rst_c, 
+            sgmii1_txi_clk, sgmii2_ctc_del_s, sgmii2_ctc_ins_s, sgmii2_ctc_orun_s, 
+            sgmii2_ctc_urun_s, sgmii2_cyawstn, sgmii2_hdinn, sgmii2_hdinp, 
+            sgmii2_hdoutn, sgmii2_hdoutp, sgmii2_lsm_status_s, sgmii2_pll_lol, 
+            sgmii2_rst_dual_c, sgmii2_rx_cdr_lol_s, sgmii2_rx_los_low_s, 
+            sgmii2_rx_pcs_rst_c, sgmii2_rx_pwrup_c, sgmii2_rx_serdes_rst_c, 
+            sgmii2_sci_en, sgmii2_sci_en_dual, sgmii2_sci_int, sgmii2_sci_rd, 
+            sgmii2_sci_sel, sgmii2_sci_sel_dual, sgmii2_sci_wrn, sgmii2_serdes_pdb, 
+            sgmii2_serdes_rst_dual_c, sgmii2_signal_detect_c, sgmii2_tx_pclk, 
+            sgmii2_tx_pcs_rst_c, sgmii2_tx_pwrup_c, sgmii2_tx_serdes_rst_c, 
+            sgmii2_txi_clk, refclk0_refclko) /* synthesis sbp_module=true */ ;
+    output [0:0]sgmii0_rx_cv_err;
+    output [0:0]sgmii0_rx_disp_err;
+    output [0:0]sgmii0_rx_k;
+    output [7:0]sgmii0_rxdata;
+    input [5:0]sgmii0_sci_addr;
+    output [7:0]sgmii0_sci_rddata;
+    input [7:0]sgmii0_sci_wrdata;
+    input [0:0]sgmii0_tx_disp_correct;
+    input [0:0]sgmii0_tx_k;
+    input [7:0]sgmii0_txdata;
+    input [0:0]sgmii0_xmit;
+    output [0:0]sgmii1_rx_cv_err;
+    output [0:0]sgmii1_rx_disp_err;
+    output [0:0]sgmii1_rx_k;
+    output [7:0]sgmii1_rxdata;
+    input [0:0]sgmii1_tx_disp_correct;
+    input [0:0]sgmii1_tx_k;
+    input [7:0]sgmii1_txdata;
+    input [0:0]sgmii1_xmit;
+    output [0:0]sgmii2_rx_cv_err;
+    output [0:0]sgmii2_rx_disp_err;
+    output [0:0]sgmii2_rx_k;
+    output [7:0]sgmii2_rxdata;
+    input [5:0]sgmii2_sci_addr;
+    output [7:0]sgmii2_sci_rddata;
+    input [7:0]sgmii2_sci_wrdata;
+    input [0:0]sgmii2_tx_disp_correct;
+    input [0:0]sgmii2_tx_k;
+    input [7:0]sgmii2_txdata;
+    input [0:0]sgmii2_xmit;
+    input refclk0_refclkn;
+    input refclk0_refclkp;
+    output sgmii0_ctc_del_s;
+    output sgmii0_ctc_ins_s;
+    output sgmii0_ctc_orun_s;
+    output sgmii0_ctc_urun_s;
+    input sgmii0_cyawstn;
+    input sgmii0_hdinn;
+    input sgmii0_hdinp;
+    output sgmii0_hdoutn;
+    output sgmii0_hdoutp;
+    output sgmii0_lsm_status_s;
+    input sgmii0_rst_dual_c;
+    output sgmii0_rx_cdr_lol_s;
+    output sgmii0_rx_los_low_s;
+    input sgmii0_rx_pcs_rst_c;
+    input sgmii0_rx_pwrup_c;
+    input sgmii0_rx_serdes_rst_c;
+    input sgmii0_sci_en;
+    input sgmii0_sci_en_dual;
+    output sgmii0_sci_int;
+    input sgmii0_sci_rd;
+    input sgmii0_sci_sel;
+    input sgmii0_sci_sel_dual;
+    input sgmii0_sci_wrn;
+    input sgmii0_serdes_rst_dual_c;
+    input sgmii0_signal_detect_c;
+    output sgmii0_tx_pclk;
+    input sgmii0_tx_pcs_rst_c;
+    input sgmii0_tx_pwrup_c;
+    input sgmii0_tx_serdes_rst_c;
+    input sgmii0_txi_clk;
+	output sgmii0_pll_lol;
+    output sgmii1_ctc_del_s;
+    output sgmii1_ctc_ins_s;
+    output sgmii1_ctc_orun_s;
+    output sgmii1_ctc_urun_s;
+    input sgmii1_hdinn;
+    input sgmii1_hdinp;
+    output sgmii1_hdoutn;
+    output sgmii1_hdoutp;
+    output sgmii1_lsm_status_s;
+    input sgmii1_rst_dual_c;
+    output sgmii1_rx_cdr_lol_s;
+    output sgmii1_rx_los_low_s;
+    input sgmii1_rx_pcs_rst_c;
+    input sgmii1_rx_pwrup_c;
+    input sgmii1_rx_serdes_rst_c;
+    input sgmii1_serdes_pdb;
+    input sgmii1_serdes_rst_dual_c;
+    input sgmii1_signal_detect_c;
+    output sgmii1_tx_pclk;
+    input sgmii1_tx_pcs_rst_c;
+    input sgmii1_tx_pwrup_c;
+    input sgmii1_tx_serdes_rst_c;
+    input sgmii1_txi_clk;
+    output sgmii2_ctc_del_s;
+    output sgmii2_ctc_ins_s;
+    output sgmii2_ctc_orun_s;
+    output sgmii2_ctc_urun_s;
+    input sgmii2_cyawstn;
+    input sgmii2_hdinn;
+    input sgmii2_hdinp;
+    output sgmii2_hdoutn;
+    output sgmii2_hdoutp;
+    output sgmii2_lsm_status_s;
+    output sgmii2_pll_lol;
+    input sgmii2_rst_dual_c;
+    output sgmii2_rx_cdr_lol_s;
+    output sgmii2_rx_los_low_s;
+    input sgmii2_rx_pcs_rst_c;
+    input sgmii2_rx_pwrup_c;
+    input sgmii2_rx_serdes_rst_c;
+    input sgmii2_sci_en;
+    input sgmii2_sci_en_dual;
+    output sgmii2_sci_int;
+    input sgmii2_sci_rd;
+    input sgmii2_sci_sel;
+    input sgmii2_sci_sel_dual;
+    input sgmii2_sci_wrn;
+    input sgmii2_serdes_pdb;
+    input sgmii2_serdes_rst_dual_c;
+    input sgmii2_signal_detect_c;
+    output sgmii2_tx_pclk;
+    input sgmii2_tx_pcs_rst_c;
+    input sgmii2_tx_pwrup_c;
+    input sgmii2_tx_serdes_rst_c;
+    input sgmii2_txi_clk;
+	output refclk0_refclko;
+    
+    
+    wire sli_rst_wire0, sli_rst_wire2;
+    
+    assign sli_rst_wire0 = sgmii0_serdes_rst_dual_c ||  sgmii0_tx_serdes_rst_c ||  (!sgmii1_serdes_pdb) ||  (!sgmii0_tx_pwrup_c) ||  (!sgmii1_tx_pwrup_c);
+    assign sli_rst_wire2 = sgmii2_serdes_rst_dual_c ||  sgmii2_tx_serdes_rst_c ||  (!sgmii2_serdes_pdb) ||  (!sgmii2_tx_pwrup_c);
+    refclk0 refclk0_inst (.refclkn(refclk0_refclkn), .refclko(refclk0_refclko), 
+            .refclkp(refclk0_refclkp));
+    sgmii0 sgmii0_inst (.rx_cv_err({sgmii0_rx_cv_err}), .rx_disp_err({sgmii0_rx_disp_err}), 
+           .rx_k({sgmii0_rx_k}), .rxdata({sgmii0_rxdata}), .sci_addr({sgmii0_sci_addr}), 
+           .sci_rddata({sgmii0_sci_rddata}), .sci_wrdata({sgmii0_sci_wrdata}), 
+           .tx_disp_correct({sgmii0_tx_disp_correct}), .tx_k({sgmii0_tx_k}), 
+           .txdata({sgmii0_txdata}), .xmit({sgmii0_xmit}), .ctc_del_s(sgmii0_ctc_del_s), 
+           .ctc_ins_s(sgmii0_ctc_ins_s), .ctc_orun_s(sgmii0_ctc_orun_s), 
+           .ctc_urun_s(sgmii0_ctc_urun_s), .cyawstn(sgmii0_cyawstn), .hdinn(sgmii0_hdinn), 
+           .hdinp(sgmii0_hdinp), .hdoutn(sgmii0_hdoutn), .hdoutp(sgmii0_hdoutp), 
+           .lsm_status_s(sgmii0_lsm_status_s), .pll_refclki(refclk0_refclko), 
+           .rst_dual_c(sgmii0_rst_dual_c), .rx_cdr_lol_s(sgmii0_rx_cdr_lol_s), 
+           .rx_los_low_s(sgmii0_rx_los_low_s), .rx_pcs_rst_c(sgmii0_rx_pcs_rst_c), 
+           .rx_pwrup_c(sgmii0_rx_pwrup_c), .rx_serdes_rst_c(sgmii0_rx_serdes_rst_c), 
+           .rxrefclk(refclk0_refclko), .sci_en(sgmii0_sci_en), .sci_en_dual(sgmii0_sci_en_dual), 
+           .sci_int(sgmii0_sci_int), .sci_rd(sgmii0_sci_rd), .sci_sel(sgmii0_sci_sel), 
+           .sci_sel_dual(sgmii0_sci_sel_dual), .sci_wrn(sgmii0_sci_wrn), 
+           .serdes_pdb(sgmii1_serdes_pdb), .serdes_rst_dual_c(sgmii0_serdes_rst_dual_c), 
+           .signal_detect_c(sgmii0_signal_detect_c), .sli_rst(sli_rst_wire0), 
+           .tx_pclk(sgmii0_tx_pclk), .tx_pcs_rst_c(sgmii0_tx_pcs_rst_c), 
+           .tx_pwrup_c(sgmii0_tx_pwrup_c), .tx_serdes_rst_c(sgmii0_tx_serdes_rst_c), 
+           .txi_clk(sgmii0_txi_clk), .pll_lol(sgmii0_pll_lol));
+    sgmii1 sgmii1_inst (.rx_cv_err({sgmii1_rx_cv_err}), .rx_disp_err({sgmii1_rx_disp_err}), 
+           .rx_k({sgmii1_rx_k}), .rxdata({sgmii1_rxdata}), .tx_disp_correct({sgmii1_tx_disp_correct}), 
+           .tx_k({sgmii1_tx_k}), .txdata({sgmii1_txdata}), .xmit({sgmii1_xmit}), 
+           .ctc_del_s(sgmii1_ctc_del_s), .ctc_ins_s(sgmii1_ctc_ins_s), .ctc_orun_s(sgmii1_ctc_orun_s), 
+           .ctc_urun_s(sgmii1_ctc_urun_s), .hdinn(sgmii1_hdinn), .hdinp(sgmii1_hdinp), 
+           .hdoutn(sgmii1_hdoutn), .hdoutp(sgmii1_hdoutp), .lsm_status_s(sgmii1_lsm_status_s), 
+           .pll_refclki(refclk0_refclko), .rst_dual_c(sgmii1_rst_dual_c), 
+           .rx_cdr_lol_s(sgmii1_rx_cdr_lol_s), .rx_los_low_s(sgmii1_rx_los_low_s), 
+           .rx_pcs_rst_c(sgmii1_rx_pcs_rst_c), .rx_pwrup_c(sgmii1_rx_pwrup_c), 
+           .rx_serdes_rst_c(sgmii1_rx_serdes_rst_c), .rxrefclk(refclk0_refclko), 
+           .serdes_pdb(sgmii1_serdes_pdb), .serdes_rst_dual_c(sgmii1_serdes_rst_dual_c), 
+           .signal_detect_c(sgmii1_signal_detect_c), .tx_pclk(sgmii1_tx_pclk), 
+           .tx_pcs_rst_c(sgmii1_tx_pcs_rst_c), .tx_pwrup_c(sgmii1_tx_pwrup_c), 
+           .tx_serdes_rst_c(sgmii1_tx_serdes_rst_c), .txi_clk(sgmii1_txi_clk));
+    sgmii2 sgmii2_inst (.rx_cv_err({sgmii2_rx_cv_err}), .rx_disp_err({sgmii2_rx_disp_err}), 
+           .rx_k({sgmii2_rx_k}), .rxdata({sgmii2_rxdata}), .sci_addr({sgmii2_sci_addr}), 
+           .sci_rddata({sgmii2_sci_rddata}), .sci_wrdata({sgmii2_sci_wrdata}), 
+           .tx_disp_correct({sgmii2_tx_disp_correct}), .tx_k({sgmii2_tx_k}), 
+           .txdata({sgmii2_txdata}), .xmit({sgmii2_xmit}), .ctc_del_s(sgmii2_ctc_del_s), 
+           .ctc_ins_s(sgmii2_ctc_ins_s), .ctc_orun_s(sgmii2_ctc_orun_s), 
+           .ctc_urun_s(sgmii2_ctc_urun_s), .cyawstn(sgmii2_cyawstn), .hdinn(sgmii2_hdinn), 
+           .hdinp(sgmii2_hdinp), .hdoutn(sgmii2_hdoutn), .hdoutp(sgmii2_hdoutp), 
+           .lsm_status_s(sgmii2_lsm_status_s), .pll_lol(sgmii2_pll_lol), 
+           .pll_refclki(refclk0_refclko), .rst_dual_c(sgmii2_rst_dual_c), 
+           .rx_cdr_lol_s(sgmii2_rx_cdr_lol_s), .rx_los_low_s(sgmii2_rx_los_low_s), 
+           .rx_pcs_rst_c(sgmii2_rx_pcs_rst_c), .rx_pwrup_c(sgmii2_rx_pwrup_c), 
+           .rx_serdes_rst_c(sgmii2_rx_serdes_rst_c), .rxrefclk(refclk0_refclko), 
+           .sci_en(sgmii2_sci_en), .sci_en_dual(sgmii2_sci_en_dual), .sci_int(sgmii2_sci_int), 
+           .sci_rd(sgmii2_sci_rd), .sci_sel(sgmii2_sci_sel), .sci_sel_dual(sgmii2_sci_sel_dual), 
+           .sci_wrn(sgmii2_sci_wrn), .serdes_pdb(sgmii2_serdes_pdb), .serdes_rst_dual_c(sgmii2_serdes_rst_dual_c), 
+           .signal_detect_c(sgmii2_signal_detect_c), .sli_rst(sli_rst_wire2), 
+           .tx_pclk(sgmii2_tx_pclk), .tx_pcs_rst_c(sgmii2_tx_pcs_rst_c), 
+           .tx_pwrup_c(sgmii2_tx_pwrup_c), .tx_serdes_rst_c(sgmii2_tx_serdes_rst_c), 
+           .txi_clk(sgmii2_txi_clk));
+    
+endmodule
+
diff --git a/source/pkt_filter.v b/source/pkt_filter.v
new file mode 100644
index 0000000..e632d32
--- /dev/null
+++ b/source/pkt_filter.v
@@ -0,0 +1,93 @@
+/* 
+ *	pkt_filter.v
+ *
+ *   Copyright (C) 2018, 2019 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: packet filter / CAM wrapper with keep / drop logic 
+ *	 
+ */
+ 
+`timescale 1ns /10ps
+
+module pkt_filter #(parameter DEPTH = 4,
+			parameter DEPTHW = 2,
+			parameter WIDTH = 32)
+(
+	input	rstn,
+	input	clk,
+	
+	// input for programming
+	input   sel,
+	input 	we,
+	input 	[DEPTHW+1:0] addr,
+	input 	[7:0]	d_in,
+	
+	// registered data
+	input[7:0] rx_data_m1, 
+	input[7:0] rx_data_m2, 
+	input[7:0] rx_data_m3, 
+	input[7:0] rx_data_m4,
+	
+	// filter
+	input new_frame,	// assert for each new frame to reset state machines
+	input block,
+	input invert,
+	input trigger,
+	output reg keep
+);
+
+reg trigger_m1;
+
+
+/* trigger_m1 is used to sync the CAM search with testing the results below */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		trigger_m1 <= 1'b0;
+	else
+		trigger_m1 <= trigger;
+
+/* keep is a one shot */
+always @(posedge clk or negedge rstn)
+	if (!rstn)
+		keep <= 1'b0;
+	else if (trigger_m1)
+		if ( block )
+			keep <= 1'b0;
+		else if ( !invert )
+			keep <= match;
+		else begin
+			keep <= ~match;
+		end	
+	else
+		keep <= 1'b0;
+	
+cam  #(.DEPTH(DEPTH), .DEPTHW(DEPTHW), .WIDTH(WIDTH)) cam_0(
+	.rstn( rstn ),
+	.clk( clk ),
+	
+	// input for programming
+	.sel( sel ),
+	.we( we ),
+	.addr( addr ),
+	.d_in( d_in ),
+	// cam action
+	.search( trigger ),
+	.search_address( { rx_data_m4, rx_data_m3, rx_data_m2, rx_data_m1 } ),
+	.match( match )
+);
+	
+	
+	
+endmodule
diff --git a/source/sgmii_params.v b/source/sgmii_params.v
new file mode 100644
index 0000000..70cb1f1
--- /dev/null
+++ b/source/sgmii_params.v
@@ -0,0 +1,50 @@
+/*
+ *       sgmii_params.v
+ *
+ *   Copyright (C) 2018, 2019 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: SGMII Related Parameters
+ *
+ */
+
+
+/* SGMII Speed Bits [11:10]	*/
+
+localparam	SGMII_SPEED_10MBIT	= 2'b00,
+			SGMII_SPEED_100MBIT = 2'b01,
+			SGMII_SPEED_1GBIT = 2'b10,
+			SGMII_SPEED_RSVD = 2'b11,
+			SGMII_SPEED_AN = 2'b11;	
+
+
+/* 
+ *	Notes about K Codes:
+ *		Start of Packet: /S/, K27.7, 0xFB
+ *		End of Packet: /T/, K23.7, 0xF7
+ *
+ */
+localparam 	D2_2	=	8'h42,
+			D2_5	=	8'ha2,
+			D5_6	= 	8'hC5,
+			D10_2	=	8'h4a,
+			D16_2	=	8'h50,
+			D21_5	=	8'hb5,		// used in a Config Code Group
+			
+			/* Note that these are only K codes if the k bit is asserted */
+			K23_7	= 	8'hf7,		// 	/R/ Carrier Extend
+			K27_7	= 	8'hfb,		// 	/S/	Start_of_Packet
+			K28_5	=	8'hbc,
+			K29_7	=	8'hfd,		// 	/T/	End_of_Packet
+			K_ERROR =	8'hee;
diff --git a/source/spi.v b/source/spi.v
new file mode 100644
index 0000000..7d6004e
--- /dev/null
+++ b/source/spi.v
@@ -0,0 +1,300 @@
+/*
+ *      spi.v
+ *
+ *   Copyright (C) 2018, 2019 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: SPI slave controller
+ *	
+ * 	refer to SPI protocol figure at https://mindchasers.com/dev/hw-spi
+ *	
+ *		
+ */
+ 
+`timescale 1ns /10ps
+ 
+ module spi( 
+ 	input rstn,
+ 	input clk,
+ 	
+ 	// SPI signals
+ 	input spi_cs,
+ 	input spi_clk,
+ 	input spi_d_in,
+ 	output reg spi_d_o,
+ 	output spi_d_oe,
+ 	
+ 	// internal FPGA memory interface
+ 	output [10:0] mem_addr,	
+ 	output [4:0] mux_sel,
+ 	input [8:0] d_i,			// data out of FPGA memories
+ 	output reg [8:0] d_o,		// data into FPGA memories
+	
+ 	// individual memory selects
+ 	output reg we,
+ 	output oe,
+ 	output reg dpram_tx_sel,
+ 	output reg dpram_rx_sel,
+ 	output reg dpram_ptrs_sel,
+ 	output reg [3:0] param_sel,
+ 	output reg pkt_filter_sel_01,
+ 	output reg pkt_filter_sel_02,
+ 	output reg pkt_filter_sel_03,
+ 	output reg pkt_filter_sel_10,
+ 	output reg pkt_filter_sel_12,
+ 	output reg pkt_filter_sel_13,
+ 	output reg pkt_filter_sel_20,
+ 	output reg pkt_filter_sel_21,
+ 	output reg pkt_filter_sel_23,
+ 	output reg pkt_filter_sel_2u,
+ 	output reg pkt_filter_sel_30,
+ 	output reg pkt_filter_sel_31,
+ 	output reg pkt_filter_sel_32,
+ 	output reg pkt_filter_sel_u2,
+ 	output reg interrupts_sel,
+ 	output reg[1:0] sci_sel_dual,
+ 	output reg[3:0] sci_sel_ch		
+ );
+ 	
+ 	localparam start_code = 9'h76;
+ 	
+ 	wire bit_cnt_rstn;	// async reset at start of SPI cycle
+ 	
+ 	reg spi_clk_m1, spi_clk_m2;			// detect / debounce the SPI CLK
+ 	reg spi_clk_high, spi_clk_high_m1;	// one shot clocks for sequencing events 
+ 	
+ 	reg [4:0] bit_cnt;	// cnt the bits
+ 	reg [6:0] word_cnt;	// number of bytes transferred, OK to roll over
+ 	
+ 	// capture these from SPI bus
+ 	reg [7:0] dev_ad;	// device address
+ 	reg rwn;			// follows address
+ 	reg [8:0] addr;		// address
+
+	wire mem_sel, pkt_filter_sel;	//
+	 	
+ 	// async reset at the start of each SPI transfer
+ 	assign bit_cnt_rstn = spi_cs & rstn;	
+ 	
+ 	// debounce and capture the asynch spi_clk
+ 	always @(posedge clk or negedge bit_cnt_rstn)
+ 	begin
+ 		if ( !bit_cnt_rstn ) begin
+ 			spi_clk_m1 <= 1'b0;
+ 			spi_clk_m2 <= 1'b0;
+ 		end
+ 		else if ( spi_cs ) begin
+ 			spi_clk_m1 <= spi_clk;
+ 			spi_clk_m2 <= spi_clk_m1;
+ 		end
+ 	end 
+ 	
+ 	// create two seq one shots for actions
+ 	always @(posedge clk or negedge bit_cnt_rstn)
+ 	begin
+ 		if ( !bit_cnt_rstn ) 
+ 			spi_clk_high <= 0;
+ 		else if ( spi_cs && spi_clk && spi_clk_m1 && !spi_clk_m2 )
+ 			spi_clk_high <= 1'b1;
+ 		else
+ 			spi_clk_high <= 1'b0;
+ 	end
+ 	
+ 	always @(posedge clk or negedge bit_cnt_rstn)
+ 	begin
+ 		if ( !bit_cnt_rstn ) 
+ 			spi_clk_high_m1 <= 0;
+ 		else
+ 			spi_clk_high_m1 <= spi_clk_high;
+ 	end
+ 	
+ 
+ 	/* 
+	bit_cnt indicates the state of the SPI transfer
+	
+	0:7: dev_ad
+	8: rwn
+	9:17: addr
+	18:26: data (repeats)
+ 	 */
+ 	always @(posedge clk or negedge bit_cnt_rstn)
+ 	begin
+ 		if ( !bit_cnt_rstn )
+ 			bit_cnt <= 5'h0;
+ 		else if ( spi_cs && spi_clk_high ) begin
+ 			if ( bit_cnt == 5'd26 )
+ 				bit_cnt <= 5'd18;
+ 			else
+ 				bit_cnt <= bit_cnt + 1;
+ 		end
+ 	end
+ 	
+ 	// word_cnt
+ 	always @(posedge clk or negedge bit_cnt_rstn)
+ 	begin
+ 		if (!bit_cnt_rstn)
+ 			word_cnt <= 0;
+ 		else if ( spi_cs && spi_clk_high && bit_cnt == 5'd26 ) 
+ 			word_cnt <= word_cnt + 1;
+ 	end
+ 	
+ 	/* Logic to capture common dev_ad, rwn, and address */
+ 	
+ 	// capture dev_ad
+ 	always @(posedge clk or negedge bit_cnt_rstn)	
+ 	begin
+ 		if ( !bit_cnt_rstn )
+ 			dev_ad <= 'h0;
+ 		else if ( spi_cs && spi_clk_high && bit_cnt < 5'd8 )
+ 			dev_ad <= { dev_ad[6:0], spi_d_in };
+ 	end
+ 	
+ 	// capture rwn bit
+ 	always @(posedge clk or negedge bit_cnt_rstn)
+ 	begin
+ 		if ( !bit_cnt_rstn )
+ 			rwn <= 1'b1;
+ 		else if ( spi_cs && spi_clk_high && bit_cnt == 5'd8 )
+ 			rwn <= spi_d_in;
+ 	end
+ 	
+ 	// capture addr
+ 	always @(posedge clk or negedge bit_cnt_rstn)	
+ 	begin
+ 		if (!bit_cnt_rstn)
+ 			addr <= 'h0;
+ 		else if (spi_cs ) begin
+ 			if ( spi_clk_high && bit_cnt >= 5'd9 && bit_cnt <= 5'd17 )
+ 				addr <= { addr[7:0], spi_d_in };
+ 			// delay advancing addr until write completes
+ 			else if ( spi_clk_high_m1 && bit_cnt == 5'd26 )
+ 				addr <= addr + 1;
+ 		end
+ 	end
+
+ 	assign mem_addr = { dev_ad[1:0], addr };
+ 	
+ 	/* Logic for write data into FPGA */
+ 	
+ 	// capture write data
+ 	always @(posedge clk or negedge bit_cnt_rstn)	
+ 	begin
+ 		if (!bit_cnt_rstn)
+ 			d_o <= 8'h0;
+ 		else if (spi_cs && spi_clk_high && !rwn && bit_cnt >= 5'd18)
+ 			d_o <= { d_o[7:0], spi_d_in };
+ 	end 	
+ 	
+ 	// we
+ 	always @(posedge clk or negedge bit_cnt_rstn)
+ 	begin
+ 		if (!bit_cnt_rstn)
+ 			we <= 1'b0;
+ 		else if ( spi_cs ) begin
+	 		if ( spi_clk_high && !rwn && bit_cnt == 5'd25 ) 
+	 			we <= 1'b1;
+	 		else
+	 			we <= 1'b0;
+	 	end;
+ 	end
+ 	
+ 	/* SPI data output enable */
+	assign spi_d_oe = spi_cs;
+ 	
+ 
+ 	/* 
+ 	 * 	clock out msb first.  
+ 	 * 	First bit comes out on cs
+ 	 */
+ 	always @(posedge clk or negedge bit_cnt_rstn)	
+ 	begin
+ 	if ( !bit_cnt_rstn )
+ 		spi_d_o <= start_code[8];
+ 	else if ( spi_cs && spi_clk_high_m1 ) begin
+		if ( bit_cnt < 9 )
+			spi_d_o <= start_code['d8 - bit_cnt[3:0]];
+	 	else if ( !rwn && bit_cnt >= 'd18 )
+	 		spi_d_o <= word_cnt['d8 - bit_cnt[3:0]];
+		else if ( rwn && bit_cnt >= 'd18 )
+			spi_d_o <= d_i['d8 - bit_cnt[3:0]];
+		else 
+			spi_d_o <= 1'b0;
+	 	end
+	end
+ 	
+ 	assign oe = ( (dpram_rx_sel || dpram_tx_sel) && rwn) ? 1'b1 : 1'b0;
+ 	
+ 	
+ 	/* Address Decoding */
+ 	assign pkt_filter_sel = pkt_filter_sel_01 | pkt_filter_sel_02 | pkt_filter_sel_10 | pkt_filter_sel_12 |
+ 		pkt_filter_sel_20 | pkt_filter_sel_21 | pkt_filter_sel_23;
+
+ 	assign mem_sel = dpram_rx_sel | dpram_tx_sel | dpram_ptrs_sel | pkt_filter_sel | param_sel[0] | 
+ 		param_sel[1] | param_sel[2] | param_sel[2] | interrupts_sel;
+ 	
+ 	
+ 	// use to steer data into this module 
+ 	assign mux_sel = dev_ad[6:2];
+ 	
+ 	// address decode
+ 	always @(*)
+ 	begin
+ 		sci_sel_dual = 2'b00;
+ 		sci_sel_ch = 4'b000;
+ 		dpram_rx_sel = 1'b0;
+ 		dpram_tx_sel = 1'b0;
+ 		dpram_ptrs_sel = 1'b0;
+ 		pkt_filter_sel_01 = 1'b0;
+ 		pkt_filter_sel_02 = 1'b0;
+ 		pkt_filter_sel_10 = 1'b0;
+ 		pkt_filter_sel_12 = 1'b0;
+ 		pkt_filter_sel_20 = 1'b0;
+ 		pkt_filter_sel_21 = 1'b0;
+ 		pkt_filter_sel_23 = 1'b0;
+ 		param_sel = 4'b0000;
+ 		interrupts_sel = 1'b0;
+ 		casez( dev_ad[7:0] ) 
+ 			8'b00000000: sci_sel_ch = 4'b0001;	// sgmii0
+ 			8'b00000001: sci_sel_ch = 4'b0010;	// sgmii1 
+ 			8'b00000010: sci_sel_dual = 2'b01;	// DCU0 Dual
+ 			8'b00000100: sci_sel_ch = 4'b0100;	// sgmii2
+ 			8'b00000101: sci_sel_ch = 4'b1000;	// sgmii3
+ 			8'b00000110: sci_sel_dual = 2'b10;	// DCU1 Dual
+ 			8'b000010??: dpram_rx_sel = 1'b1;		
+ 			8'b000011??: dpram_tx_sel = 1'b1;
+ 			8'b00010000: dpram_ptrs_sel = 1'b1;
+ 			8'b00010001: interrupts_sel = 1'b1;
+ 			8'b001000??: param_sel[0] = 1'b1;
+ 			8'b001001??: param_sel[1] = 1'b1;
+ 			8'b001010??: param_sel[2] = 1'b1;			
+ 			8'b001011??: param_sel[3] = 1'b1;
+ 			8'b01000001: pkt_filter_sel_01 = 1'b1;
+ 			8'b01000010: pkt_filter_sel_02 = 1'b1;
+ 			8'b01000011: pkt_filter_sel_03 = 1'b1;
+ 			8'b01001000: pkt_filter_sel_10 = 1'b1;
+ 			8'b01001010: pkt_filter_sel_12 = 1'b1;
+ 			8'b01001011: pkt_filter_sel_13 = 1'b1;
+ 			8'b01010000: pkt_filter_sel_20 = 1'b1;
+ 			8'b01010001: pkt_filter_sel_21 = 1'b1;
+ 			8'b01010011: pkt_filter_sel_23 = 1'b1;
+ 			8'b01010111: pkt_filter_sel_2u = 1'b1; 
+ 			8'b01011000: pkt_filter_sel_30 = 1'b1; 
+ 			8'b01011001: pkt_filter_sel_31 = 1'b1;
+ 			8'b01011010: pkt_filter_sel_32 = 1'b1; 
+ 			8'b01111010: pkt_filter_sel_u2 = 1'b1;
+ 		endcase
+ 	end
+ 	
+ endmodule
+ 	
diff --git a/source/switch.v b/source/switch.v
new file mode 100644
index 0000000..f929b68
--- /dev/null
+++ b/source/switch.v
@@ -0,0 +1,480 @@
+/*
+ *       switch.v
+ *
+ *   Copyright (C) 2018, 2019 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: switch packet paths from RX to TX
+ *
+ */
+
+`timescale 1ns /10ps
+
+module switch(
+	input rstn,
+	input clk,
+	
+	// PHY status
+	input [3:0] phy_up,
+	input [3: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_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,
+	
+	// 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,
+	
+	// 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,
+	
+	// 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,
+	output reg tx_fifo_we_u,
+	
+	// TX FIFO Empty Flags (need to route to RX output FIFOs)
+	output reg [3:0] tx_fifo_empty,
+	
+	// TX modes for the PHYs and uc
+	output reg [1:0] tx_mode0,
+	output reg [1:0] tx_mode1,	
+	output reg [1:0] tx_mode2,
+	output reg [1:0] tx_mode3,
+	output reg tx_modeu,
+	
+	// TX state machine done flag
+	input [3:0] tx_f,
+	
+	// TX custom packet
+	input tx_metrics
+);
+	
+reg [2:0] tx0_src_sel;
+reg [2:0] tx1_src_sel;
+reg [2:0] tx2_src_sel;
+reg [2:0] tx3_src_sel;
+
+// IPG for Port 0
+wire ipg_met;
+reg [6:0] ipg_cnt;
+reg [3:0] fr_100mbit_cnt;
+
+reg i_tx_fifo_we_u;
+
+`include "ethernet_params.v"
+`include "sgmii_params.v"
+			
+localparam  SEL_PHY0 = 3'b000,
+			SEL_PHY1 = 3'b001,
+			SEL_PHY2 = 3'b010,
+			SEL_PHY3 = 3'b011,
+			SEL_UC =   3'b111;
+
+
+assign ipg_met = ipg_cnt >= IPG ? 1'b1 : 1'b0;
+	
+/* free running 100Mbit counter */
+always @(posedge clk, negedge rstn) 
+begin 
+	if ( !rstn )
+		fr_100mbit_cnt <= 4'd0;
+	else if ( fr_100mbit_cnt == 4'd9 )
+		fr_100mbit_cnt <= 4'd0;
+	else
+		fr_100mbit_cnt <= fr_100mbit_cnt + 1;
+end
+	
+/* IPG counter */
+always @(posedge clk, negedge rstn) 
+begin 
+	if ( !rstn )
+		ipg_cnt <= 7'd0;
+	else if ( tx_f[0] && tx_mode0 >= TX_MODE_XMT_PKT )
+		ipg_cnt <= 7'd0;
+	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;
+end
+
+
+// TX0 Switch Logic
+// Possible sources: 1, 2
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+	begin
+		tx_mode0 <= TX_MODE_AN;
+		tx0_src_sel <= SEL_PHY1;
+	end
+	else if ( tx_f[0] )
+		case( tx_mode0 )
+			TX_MODE_AN: 
+				if ( phy_up[0] ) 
+					tx_mode0 <= TX_MODE_IDLE;
+			TX_MODE_IDLE: 
+				if ( !phy_up[0] ) 
+					tx_mode0 <= TX_MODE_AN;
+				else if ( !ipg_met )
+					tx_mode0 <= TX_MODE_IDLE;
+				else if (tx0_src_sel==SEL_PHY1  && !rx_fifo_empty_20 )
+				begin
+					tx_mode0 <= TX_MODE_XMT_PKT;
+					tx0_src_sel <= SEL_PHY2;
+				end
+				else if (!rx_fifo_empty_10 )
+				begin
+					tx_mode0 <= TX_MODE_XMT_PKT;
+					tx0_src_sel <= SEL_PHY1;
+				end	
+				else if (!rx_fifo_empty_20 )
+				begin
+					tx_mode0 <= TX_MODE_XMT_PKT;
+					tx0_src_sel <= SEL_PHY2;
+				end
+			TX_MODE_XMT_PKT: 
+				if ( !phy_up[0] )
+					tx_mode0 <= TX_MODE_AN;
+				else
+					tx_mode0 <= TX_MODE_IDLE;
+			default: tx_mode0 <= TX_MODE_IDLE;
+		endcase
+	
+// TX0 data mux
+always @(*) begin
+	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;
+		default:  tx_d0 = 9'h000;
+	endcase
+end
+
+// TX0 FIFO read enable
+always @(*) begin
+	rx_fifo_re_10 = 1'b0;
+	rx_fifo_re_20 = 1'b0;
+	rx_fifo_re_30 = 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];
+	endcase
+end
+
+// TX0 FIFO Empty Routing
+always @(*) begin
+	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;
+	endcase
+end
+
+// TX1 Switch Logic
+// Possible sources: 0, 3
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+	begin
+		tx_mode1 <= TX_MODE_AN;
+		tx1_src_sel <= SEL_PHY0;
+	end
+	else if ( tx_f[1] )
+		case( tx_mode1 )
+			TX_MODE_AN: 
+				if ( phy_up[1] ) 
+					tx_mode1 <= TX_MODE_IDLE;
+			TX_MODE_IDLE: 
+				if ( !phy_up[1] ) 
+					tx_mode1 <= TX_MODE_AN;
+				else if (tx1_src_sel==SEL_PHY0  && !rx_fifo_empty_31 )
+				begin
+					tx_mode1 <= TX_MODE_XMT_PKT;
+					tx1_src_sel <= SEL_PHY3;
+				end
+				else if (!rx_fifo_empty_01 )
+				begin
+					tx_mode1 <= TX_MODE_XMT_PKT;
+					tx1_src_sel <= SEL_PHY0;
+				end
+				else if (!rx_fifo_empty_31 )
+				begin
+					tx_mode1 <= TX_MODE_XMT_PKT;
+					tx1_src_sel <= SEL_PHY3;
+				end	
+			TX_MODE_XMT_PKT: 
+				if ( !phy_up[1] )
+					tx_mode1 <= TX_MODE_AN;
+				else
+					tx_mode1 <= TX_MODE_IDLE;
+			default: tx_mode1 <= TX_MODE_IDLE;
+		endcase
+		
+// TX1 data mux
+always @(*) begin
+	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
+end
+
+// TX1 FIFO read enable
+always @(*) begin
+	rx_fifo_re_01 = 1'b0;
+	rx_fifo_re_21 = 1'b0;
+	rx_fifo_re_31 = 1'b0;
+	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(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
+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.
+ */ 
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		begin
+			tx_mode2 <= TX_MODE_AN;
+			tx2_src_sel <= SEL_PHY0;
+		end
+	else if ( tx_f[2] )
+		case( tx_mode2 )
+			TX_MODE_AN: 
+				if ( phy_up[2] ) 
+					tx_mode2 <= TX_MODE_IDLE;
+			TX_MODE_IDLE: 
+				if ( !phy_up[2] ) 
+					tx_mode2 <= TX_MODE_AN;
+				else if (tx2_src_sel==SEL_PHY0  && !rx_fifo_empty_12 )
+					begin
+						tx_mode2 <= TX_MODE_XMT_PKT;
+						tx2_src_sel <= SEL_PHY1;
+					end
+				else if (!rx_fifo_empty_02 )
+					begin
+						tx_mode2 <= TX_MODE_XMT_PKT;
+						tx2_src_sel <= SEL_PHY0;
+					end	
+				else if (!rx_fifo_empty_12 )
+					begin
+						tx_mode2 <= TX_MODE_XMT_PKT;
+						tx2_src_sel <= SEL_PHY1;
+					end
+				else if (!rx_fifo_empty_u2)
+					begin
+						tx_mode2 <= TX_MODE_XMT_PKT;
+						tx2_src_sel <= SEL_UC;
+					end
+				else if (tx_metrics)
+					begin
+						tx_mode2 <= TX_MODE_XMT_METRICS;
+						tx2_src_sel <= SEL_PHY2;
+					end
+			TX_MODE_XMT_PKT: 
+				if ( !phy_up[2] )
+					tx_mode2 <= TX_MODE_AN;
+				else
+					tx_mode2 <= TX_MODE_IDLE;
+			default: tx_mode2 <= TX_MODE_IDLE;
+		endcase
+	
+// TX2 data mux
+always @(*) begin
+	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
+
+// TX2 FIFO read enable
+always @(*) begin
+	rx_fifo_re_02 = 1'b0;
+	rx_fifo_re_12 = 1'b0;
+	rx_fifo_re_u2 = 1'b0;
+	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(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;					// this is done for metrics.  
+		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;
+		tx3_src_sel <= 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 (tx3_src_sel==SEL_PHY1  && !rx_fifo_empty_03 )
+				begin
+					tx_mode3 <= TX_MODE_XMT_PKT;
+					tx3_src_sel <= SEL_PHY0;
+				end
+				else if (!rx_fifo_empty_13 )
+				begin
+					tx_mode3 <= TX_MODE_XMT_PKT;
+					tx3_src_sel <= SEL_PHY1;
+				end	
+				else if (!rx_fifo_empty_03 )
+				begin
+					tx_mode3 <= TX_MODE_XMT_PKT;
+					tx3_src_sel <= 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(tx3_src_sel)
+			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(tx3_src_sel)
+			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(tx3_src_sel)
+			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
+ *
+ *	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;
+
+always @(*)
+	if ( !rx_fifo_empty_2u )
+		begin
+			i_tx_fifo_we_u = 1'b1;
+			rx_fifo_re_2u = 1'b1;
+		end
+	else
+		begin
+			i_tx_fifo_we_u = 1'b0;
+			rx_fifo_re_2u = 1'b0; 
+		end
+		
+always @(posedge clk, negedge rstn)
+	if ( !rstn )
+		tx_fifo_we_u <= 1'b0;
+	else
+		tx_fifo_we_u <= i_tx_fifo_we_u;
+
+	
+endmodule
diff --git a/source/sync2_fifo.v b/source/sync2_fifo.v
new file mode 100644
index 0000000..029cfce
--- /dev/null
+++ b/source/sync2_fifo.v
@@ -0,0 +1,141 @@
+/*
+ *	sync2_fifo.v
+ *
+ *   Copyright (C) 2018, 2019 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: Multi Buffered Sync FIFO suitable for rate conversion from 1G to 100 Mbit
+ *
+ *
+ */
+	
+
+`timescale 1ns /10ps
+
+module	sync2_fifo	#(parameter	FIFO_PTR = 12,
+					FIFO_WIDTH = 9,
+					FIFO_DEPTH = 4096 )
+(
+	input	rstn,
+	input	clk,
+	
+
+	// input
+	input	we,
+	input	[FIFO_WIDTH-1:0]	d_in,
+
+	// output
+	input 	re,
+	output	[FIFO_WIDTH-1:0]	d_out,		
+	output	empty,
+	output almost_full,
+	
+	// fifo_control
+	input reset_ptrs
+
+);
+
+`include "ethernet_params.v"
+
+
+reg	[FIFO_PTR-1:0] 	wr_ptr;
+reg	[FIFO_PTR-1:0] 	rd_ptr;
+reg [FIFO_PTR:0] bytes;			// use for size calculation below
+
+wire [FIFO_WIDTH-1:0]  d_out_0, d_out_1, d_out_internal;
+
+wire dpram0_a_clk_e, dpram1_a_clk_e;
+wire dpram0_b_clk_e, dpram1_b_clk_e;
+
+
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		wr_ptr <= 'd0;
+	else if ( reset_ptrs )
+		wr_ptr <= 'd0;
+	else if ( we )
+		wr_ptr <= wr_ptr + 1;
+		
+/* 
+ * 	rd_ptr
+ * 	use empty flat to make sure rd_ptr doesn't advance when empty ( error condition )
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		rd_ptr <= 'd0;
+	else if ( reset_ptrs )
+		rd_ptr <= 'd0;
+	else if ( re && !empty )
+		rd_ptr <= rd_ptr + 1;
+
+assign empty = ( rd_ptr == wr_ptr ) ? 1'b1 : 1'b0;
+
+// leave room for a MTU frame
+assign almost_full = bytes > FIFO_DEPTH-MTU ? 1'b1 : 1'b0;
+
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		bytes <= 'd0;
+	else if ( wr_ptr >= rd_ptr )
+		bytes <= wr_ptr - rd_ptr;
+	else
+		bytes <= (wr_ptr - rd_ptr)+FIFO_DEPTH;
+		
+	assign dpram0_a_clk_e = ~wr_ptr[FIFO_PTR-1];
+	assign dpram1_a_clk_e = wr_ptr[FIFO_PTR-1];
+
+	assign dpram0_b_clk_e = ~rd_ptr[FIFO_PTR-1];
+	assign dpram1_b_clk_e = rd_ptr[FIFO_PTR-1];
+
+	assign d_out = dpram0_b_clk_e ? d_out_0 : d_out_1;
+
+dpram dpram_fifo0(
+	.rstn(  rstn  ),
+	.a_clk( clk ),
+	.a_clk_e( dpram0_a_clk_e ),
+	.a_we( we ),
+	.a_oe( 1'b0 ),
+	.a_addr( wr_ptr[10:0] ),
+	.a_din( d_in ),
+	.a_dout( ),
+	// port B
+	.b_clk(  clk ),
+	.b_clk_e( dpram0_b_clk_e ),
+	.b_we( 1'b0 ),
+	.b_oe( 1'b1  ),
+	.b_addr( rd_ptr[10:0]  ),
+	.b_din( 9'h0 ),
+	.b_dout( d_out_0 )
+);
+
+dpram dpram_fifo1(
+		.rstn(  rstn  ),
+		.a_clk( clk ),
+		.a_clk_e( dpram1_a_clk_e ),
+		.a_we( we ),
+		.a_oe( 1'b0 ),
+		.a_addr( wr_ptr[10:0]  ),
+		.a_din( d_in ),
+		.a_dout( ),
+		// port B
+		.b_clk(  clk ),
+		.b_clk_e( dpram1_b_clk_e ),
+		.b_we( 1'b0 ),
+		.b_oe( 1'b1  ),
+		.b_addr( rd_ptr[10:0]  ),
+		.b_din( 9'h0 ),
+		.b_dout( d_out_1 )
+	);
+
+endmodule
diff --git a/source/sync4_fifo.v b/source/sync4_fifo.v
new file mode 100644
index 0000000..c7c1fb6
--- /dev/null
+++ b/source/sync4_fifo.v
@@ -0,0 +1,206 @@
+/*
+ *       sync4_fifo.v
+ *
+ *   Copyright (C) 2018, 2019 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: FIFO / data store between RX and TX for each path
+ *
+ */
+
+`timescale 1ns /10ps
+
+module	sync4_fifo	#(parameter	FIFO_PTR = 13,
+					FIFO_WIDTH = 9,
+					FIFO_DEPTH = 8192 )
+(
+	input	rstn,
+	input	clk,
+	
+	// input
+	input	we,
+	input	[FIFO_WIDTH-1:0]	d_in,
+
+	// output
+	input 	re,
+	output reg	[FIFO_WIDTH-1:0]	d_out,		
+	output	empty,
+	output  almost_full,
+	
+	// fifo_control
+	input reset_ptrs,
+	
+	// debug
+	output active
+
+);
+
+`include "ethernet_params.v"
+
+reg	[FIFO_PTR-1:0] 	wr_ptr;
+reg	[FIFO_PTR-1:0] 	rd_ptr;
+reg [FIFO_PTR-1:0] wr_bytes_available;			// use for size calculation below
+
+wire [FIFO_WIDTH-1:0]  d_out_0, d_out_1, d_out_2, d_out_3;
+
+wire dpram0_a_clk_e, dpram1_a_clk_e, dpram2_a_clk_e, dpram3_a_clk_e;
+wire dpram0_b_clk_e, dpram1_b_clk_e, dpram2_b_clk_e, dpram3_b_clk_e;
+reg dpram0_b_clk_e_m1, dpram1_b_clk_e_m1, dpram2_b_clk_e_m1, dpram3_b_clk_e_m1;
+
+
+always @(posedge clk, negedge rstn)
+	if( !rstn ) begin
+		dpram0_b_clk_e_m1 <= 1'b0;
+		dpram1_b_clk_e_m1 <= 1'b0;
+		dpram2_b_clk_e_m1 <= 1'b0;
+		dpram3_b_clk_e_m1 <= 1'b0;
+		end
+	else begin
+		dpram0_b_clk_e_m1 <= dpram0_b_clk_e;
+		dpram1_b_clk_e_m1 <= dpram1_b_clk_e;
+		dpram2_b_clk_e_m1 <= dpram2_b_clk_e;
+		dpram3_b_clk_e_m1 <= dpram3_b_clk_e;
+	end
+
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		wr_ptr <= 'd0;
+	else if ( reset_ptrs )
+		wr_ptr <= 'd0;
+	else if ( we )
+		wr_ptr <= wr_ptr + 1;
+		
+/* 
+ * 	rd_ptr
+ * 	use empty flag to make sure rd_ptr doesn't advance when empty ( error condition )
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		rd_ptr <= 'd0;
+	else if ( reset_ptrs )
+		rd_ptr <= 'd0;
+	else if ( re && !empty )
+		rd_ptr <= rd_ptr + 1;	
+
+assign empty = ( rd_ptr == wr_ptr ) ? 1'b1 : 1'b0;
+assign almost_full = wr_bytes_available < MTU ? 1'b1 : 1'b0;
+
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		wr_bytes_available <= FIFO_DEPTH-1;
+	else if ( wr_ptr >= rd_ptr )
+		wr_bytes_available <= FIFO_DEPTH-1 - (wr_ptr - rd_ptr);
+	else
+		wr_bytes_available <= rd_ptr - wr_ptr;
+		
+assign dpram0_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b00 ? 1'b1 : 1'b0;
+assign dpram1_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b01 ? 1'b1 : 1'b0;
+assign dpram2_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b10 ? 1'b1 : 1'b0;
+assign dpram3_a_clk_e = wr_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b11 ? 1'b1 : 1'b0;
+
+assign dpram0_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b00 ? 1'b1 : 1'b0;
+assign dpram1_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b01 ? 1'b1 : 1'b0;
+assign dpram2_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b10 ? 1'b1 : 1'b0;
+assign dpram3_b_clk_e = rd_ptr[FIFO_PTR-1:FIFO_PTR-2] == 2'b11 ? 1'b1 : 1'b0;
+	
+// we have to delay the mux one bit for when the DPRAM switches.  Otherwise, we read from the wrong DPRAM for one time slot
+always @(*)
+	if (dpram0_b_clk_e_m1)
+		d_out = d_out_0;
+	else if (dpram1_b_clk_e_m1)
+		d_out = d_out_1;
+	else if (dpram2_b_clk_e_m1)
+		d_out = d_out_2;
+	else if (dpram3_b_clk_e_m1)
+		d_out = d_out_3;
+	
+assign active = ~empty;
+
+dpram dpram_fifo0(
+	.rstn(  rstn  ),
+	.a_clk( clk ),
+	.a_clk_e( dpram0_a_clk_e ),
+	.a_we( we ),
+	.a_oe( 1'b0 ),
+	.a_addr( wr_ptr[10:0] ),
+	.a_din( d_in ),
+	.a_dout( ),
+	// port B
+	.b_clk(  clk ),
+	.b_clk_e( dpram0_b_clk_e ),
+	.b_we( 1'b0 ),
+	.b_oe( 1'b1  ),
+	.b_addr( rd_ptr[10:0]  ),
+	.b_din( 9'h0 ),
+	.b_dout( d_out_0 )
+);
+
+dpram dpram_fifo1(
+		.rstn(  rstn  ),
+		.a_clk( clk ),
+		.a_clk_e( dpram1_a_clk_e ),
+		.a_we( we ),
+		.a_oe( 1'b0 ),
+		.a_addr( wr_ptr[10:0]  ),
+		.a_din( d_in ),
+		.a_dout( ),
+		// port B
+		.b_clk(  clk ),
+		.b_clk_e( dpram1_b_clk_e ),
+		.b_we( 1'b0 ),
+		.b_oe( 1'b1  ),
+		.b_addr( rd_ptr[10:0]  ),
+		.b_din( 9'h0 ),
+		.b_dout( d_out_1 )
+	);
+	
+dpram dpram_fifo2(
+		.rstn(  rstn  ),
+		.a_clk( clk ),
+		.a_clk_e( dpram2_a_clk_e ),
+		.a_we( we ),
+		.a_oe( 1'b0 ),
+		.a_addr( wr_ptr[10:0]  ),
+		.a_din( d_in ),
+		.a_dout( ),
+		// port B
+		.b_clk(  clk ),
+		.b_clk_e( dpram2_b_clk_e ),
+		.b_we( 1'b0 ),
+		.b_oe( 1'b1  ),
+		.b_addr( rd_ptr[10:0]  ),
+		.b_din( 9'h0 ),
+		.b_dout( d_out_2 )
+	);
+	
+dpram dpram_fifo3(
+		.rstn(  rstn  ),
+		.a_clk( clk ),
+		.a_clk_e( dpram3_a_clk_e ),
+		.a_we( we ),
+		.a_oe( 1'b0 ),
+		.a_addr( wr_ptr[10:0]  ),
+		.a_din( d_in ),
+		.a_dout( ),
+		// port B
+		.b_clk(  clk ),
+		.b_clk_e( dpram3_b_clk_e ),
+		.b_we( 1'b0 ),
+		.b_oe( 1'b1  ),
+		.b_addr( rd_ptr[10:0]  ),
+		.b_din( 9'h0 ),
+		.b_dout( d_out_3 )
+	);
+
+endmodule
diff --git a/source/sync_fifo.v b/source/sync_fifo.v
new file mode 100644
index 0000000..56c83d4
--- /dev/null
+++ b/source/sync_fifo.v
@@ -0,0 +1,110 @@
+/*
+ *       sync_fifo.v
+ *
+ *   Copyright (C) 2018, 2019 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: FIFO / data store between RX and TX for each path
+ *
+ */
+
+`timescale 1ns /10ps
+
+module	sync_fifo	#(parameter	FIFO_PTR = 11,
+					FIFO_WIDTH = 9,
+					FIFO_DEPTH = 2048 )
+(
+	input	rstn,
+	input	clk,
+	
+
+	// input
+	input	we,
+	input	[FIFO_WIDTH-1:0]	d_in,
+
+	// output
+	input 	re,
+	output	[FIFO_WIDTH-1:0]	d_out,		
+	output	empty,
+	output almost_full,
+	
+	// fifo_control
+	input reset_ptrs,
+	
+	// debug
+	output active
+
+);
+	
+`include "ethernet_params.v"
+
+reg	[FIFO_PTR-1:0] 	wr_ptr;
+reg	[FIFO_PTR-1:0] 	rd_ptr;
+reg [FIFO_PTR-1:0] wr_bytes_available;			// use for size calculation below
+
+
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		wr_ptr <= 'd0;
+	else if ( reset_ptrs )
+		wr_ptr <= 'd0;
+	else if ( we )
+		wr_ptr <= wr_ptr + 1;
+		
+/* 
+ * 	rd_ptr
+ * 	use empty flat to make sure rd_ptr doesn't advance when empty ( error condition )
+ */
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		rd_ptr <= 'd0;
+	else if ( reset_ptrs )
+		rd_ptr <= 'd0;
+	else if ( re && !empty )
+		rd_ptr <= rd_ptr + 1;
+
+assign empty = ( rd_ptr == wr_ptr ) ? 1'b1 : 1'b0;
+assign almost_full = wr_bytes_available < MTU ? 1'b1 : 1'b0;
+
+always @(posedge clk, negedge rstn)
+	if( !rstn )
+		wr_bytes_available <= FIFO_DEPTH-1;
+	else if ( wr_ptr >= rd_ptr )
+		wr_bytes_available <= FIFO_DEPTH-1 - (wr_ptr - rd_ptr);
+	else
+		wr_bytes_available <= rd_ptr - wr_ptr;
+	
+assign active = ~empty;
+		
+
+dpram dpram_fifo(
+	.rstn(  rstn  ),
+	.a_clk( clk ),
+	.a_clk_e( 1'b1 ),
+	.a_we( we ),
+	.a_oe( 1'b0 ),
+	.a_addr( wr_ptr ),
+	.a_din( d_in ),
+	.a_dout( ),
+	// port B
+	.b_clk(  clk ),
+	.b_clk_e( re ),
+	.b_we( 1'b0 ),
+	.b_oe( re  ),
+	.b_addr( rd_ptr ),
+	.b_din( 9'h0 ),
+	.b_dout( d_out )
+);
+
+endmodule
diff --git a/source/top.v b/source/top.v
new file mode 100644
index 0000000..1b0b8c3
--- /dev/null
+++ b/source/top.v
@@ -0,0 +1,2177 @@
+/*
+ *       top.v
+ *
+ *       Copyright (C) 2018, 2019 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.
+ *       
+ */
+
+`timescale 1ns /10ps
+
+module top(
+	input  rstn,
+
+	// REFCLK
+	input refclkp_d0, refclkn_d0, 
+	input refclkp_d1, refclkn_d1,
+	
+	// PHY Control
+	output phy0_resetn,
+	
+	output phy1_resetn,
+	
+	output phy2_resetn,
+	
+	// SGMII0
+	input	sgmii0_hdinp,
+	input	sgmii0_hdinn,
+	output	sgmii0_hdoutp,
+	output	sgmii0_hdoutn,
+	
+	// SGMII1
+	input	sgmii1_hdinp,
+	input	sgmii1_hdinn,
+	output	sgmii1_hdoutp,
+	output	sgmii1_hdoutn,
+	
+	// SGMII2
+	input	sgmii2_hdinp,
+	input	sgmii2_hdinn,
+	output	sgmii2_hdoutp,
+	output	sgmii2_hdoutn,
+	
+	// SGMII3
+	input	sgmii3_hdinp,
+	input	sgmii3_hdinn,
+	output	sgmii3_hdoutp,
+	output	sgmii3_hdoutn,
+	
+	// MDIO ( management )
+	output phy_mdc,
+	inout phy0_mdio,
+	input [1:0] phy0_gpio,
+	
+	inout phy1_mdio,
+	input [1:0] phy1_gpio,
+
+	output phy2_mdc,
+	inout phy2_mdio,
+	
+	input phy0_intn,
+	input phy1_intn,
+	
+	// Microcontroller SPI and bit banging
+	input fpga_spics,
+	input fpga_mclk,
+	output fpga_miso,
+	input fpga_mosi,
+	output fpga_int,
+	
+	// I2C
+	inout i2c_scl,
+	inout i2c_sda,
+
+	// K02 UART
+	input uart_txd,
+	output uart_rxd,
+	
+	output fpga_jtag_e,
+	
+	// FTDI UART signals muxed with JTAG
+	input ftdi_tck_txd,
+	output ftdi_tdi_rxd,
+
+    output [2:0] led,
+	
+	output ard_sda,
+	output ard_scl,
+	output ard_txd1,
+	output ard_rxd1,
+	output ard_txd2,	
+	input ard_rxd2,
+	output ard_txd3,	
+	input ard_rxd3,
+	
+	output  pe0,
+	output  pe1,
+	output  pe3,
+	output  pe4,
+	output  pe5,
+	output  pg5,
+	output  ph3,
+	output  ph4,
+	inout [9:0] pa
+	
+);
+	
+`include "sgmii_params.v"
+`include "definitions.v"
+
+
+/* PARAMS */
+localparam MDIO_ROM_ADDR_SZ = 7;
+
+/* nets and variables */
+
+// clocks
+wire 	clk_slow, clk_1_25, clk_10, clk_20;
+wire 	clk_100;
+wire 	refclko;
+
+// misc resets
+wire [3:0] phy_resetn;	// bit[0] will get pruned out for now
+wire [3:0] mac_reset;
+
+// dcu resets
+wire [1:0] pcs_rst_dual;
+wire [1:0] serdes_rst_dual;
+wire [1:0] tx_serdes_rst;	
+
+// channel resets
+wire [3:0] rx_pcs_rst;
+wire [3:0] rx_serdes_rst;
+wire [3:0] tx_pcs_rst;
+
+// MDIO controller and driver
+wire mdio_cont_work_start, mdio_cont_work_run;
+wire mdio_cont_work_done;
+wire [MDIO_ROM_ADDR_SZ-1:0] mdio_routine_addr;
+wire [1:0] mdio_mux_sel;
+wire mdio_done, mdo_oe;
+wire mdo;
+reg mdi;
+wire [15:0] mdio_wd;
+wire [15:0] mdio_rd;
+wire [4:0] mdio_reg_addr;
+wire mdio_ld, mdio_run;
+wire mdio_rwn;
+wire bin_to_ascii_run;
+
+// MDIO Data block
+wire [MDIO_ROM_ADDR_SZ-1:0] rom_a;
+wire [7:0] rom_d;
+wire [4:0] mdio_reg_addr_set;
+wire [7:0] mdio_w_data_h_set, mdio_w_data_l_set;
+wire [4:0] mdio_page_set;
+
+// I2C
+wire sda_oe, scl_oe, sda_o, scl_o;
+wire i2c_fifo_priority;
+
+wire read_fifo_we;
+wire [8:0] fifo_r_d;
+
+// bin to ASCII
+wire [15:0] bin_to_ascii_d_in;
+wire [6:0] cont_rd;
+
+// PCS, mac
+wire pcs_pclk;
+wire [1:0] pll_lol;
+wire sgmii_rx_k[0:3], sgmii_tx_k[0:3];
+wire sgmii_tx_disp_correct[0:3];
+wire sgmii_rx_cv_err[0:3], sgmii_rx_disp_err[0:3], sgmii_rx_cdr_lol[0:3];
+wire sgmii_lsm_status[0:3], sgmii_rx_los_low[0:3];
+wire [7:0] rx_data0, rx_data1, rx_data2, rx_data3;
+wire [7:0] tx_data0, tx_data1, tx_data2, tx_data3;
+wire [6:0] read_fifo_d_i;
+wire [3:0] rx_sample;
+
+// ipv4
+wire [3:0] ipv4_pkt_start;
+wire [3:0] ipv4_pkt_complete;
+
+reg cont_fifo_re_m1, cont_fifo_re_m2;
+wire cont_fifo_empty;
+wire i2c_fifo_re;
+wire i2c_cont_we, i2c_cont_done;
+wire i_cont_fifo_re;	
+wire bin_to_ascii_we, mdio_rd_we, cont_rd_we;	
+wire [3:0] phy_up;
+
+// Interrupts
+wire [6:0] int_do;
+wire [3:0] mac_int;
+wire int_sel;
+
+// Common Internal Memory Bus
+wire[10:0] mem_addr;
+wire [8:0] mem_d_i;
+reg [8:0] mem_d_o;
+wire mem_we, mem_oe;
+wire [4:0] mem_do_mux_sel;
+
+// DPRAM
+wire [10:0] param_phy2_addr ;
+wire [8:0] param_phy2_din, param_phy2_dout;
+wire param_phy2_ce, param_phy2_we;
+
+wire [7:0] i2c_d_o;
+wire [8:0] micro_fifo_do;
+wire sys_mem_rx_ce, sys_mem_tx_ce, sys_mem_ptrs_sel;
+wire [3:0] param_sel;
+
+// drop_fifos and filter
+wire rx0_k_m1, rx0_k_m2, rx0_k_m3, rx0_k_m4;
+wire [7:0] rx0_data_m1, rx0_data_m2, rx0_data_m3, rx0_data_m4;
+
+wire rx1_k_m1, rx1_k_m2, rx1_k_m3, rx1_k_m4;
+wire [7:0] rx1_data_m1, rx1_data_m2, rx1_data_m3, rx1_data_m4;
+
+wire rx2_k_m1, rx2_k_m2, rx2_k_m3, rx2_k_m4;
+wire [7:0] rx2_data_m1, rx2_data_m2, rx2_data_m3, rx2_data_m4; 
+
+wire rx3_k_m1, rx3_k_m2, rx3_k_m3, rx3_k_m4;
+wire [7:0] rx3_data_m1, rx3_data_m2, rx3_data_m3, rx3_data_m4; 
+
+wire [3:0] rx_mac_keep;
+wire [3:0] rx_sc_wr_done;
+
+// drop filter outputs
+wire rx_df_fifo_we_01, rx_df_fifo_we_02, rx_df_fifo_we_03;
+wire rx_df_fifo_we_10, rx_df_fifo_we_12, rx_df_fifo_we_13;
+wire rx_df_fifo_we_20, rx_df_fifo_we_21, rx_df_fifo_we_23, rx_df_fifo_we_2u;
+wire rx_df_fifo_we_30, rx_df_fifo_we_31, rx_df_fifo_we_32;
+wire rx_df_fifo_we_u2;
+
+wire [8:0]  rx_df_fifo_d_01, rx_df_fifo_d_02, rx_df_fifo_d_03; 
+wire [8:0]  rx_df_fifo_d_10, rx_df_fifo_d_12, rx_df_fifo_d_13; 
+wire [8:0]  rx_df_fifo_d_20, rx_df_fifo_d_21, rx_df_fifo_d_23, rx_df_fifo_d_2u; 
+wire [8:0]  rx_df_fifo_d_30, rx_df_fifo_d_31, rx_df_fifo_d_32;
+wire [8:0]  rx_df_fifo_d_u2;
+
+// pkt filter
+wire [3:0] trigger;
+wire [3:0] rx_enet_bcast;
+wire [3:0] rx_ipv4_arp;
+wire rx_pf_keep_01;
+wire rx_pf_keep_02;
+wire rx_pf_keep_03;
+wire rx_pf_keep_10;
+wire rx_pf_keep_12;
+wire rx_pf_keep_13;
+wire rx_pf_keep_20;
+wire rx_pf_keep_21;
+wire rx_pf_keep_23;
+wire rx_pf_keep_2u;
+wire rx_pf_keep_30;
+wire rx_pf_keep_31;
+wire rx_pf_keep_32;
+wire rx_pf_keep_u2;
+
+// rx_fifos
+wire [3:0] rx_sc_fifo_we;
+wire rx_sw_fifo_re_01, rx_sw_fifo_re_02, rx_sw_fifo_re_03;
+wire rx_sf_fifo_empty_01, rx_sf_fifo_empty_02, rx_sf_fifo_empty_03;
+wire rx_sw_fifo_re_10, rx_sw_fifo_re_12, rx_sw_fifo_re_13;
+wire rx_sf_fifo_empty_10, rx_sf_fifo_empty_12, rx_sf_fifo_empty_13;
+wire rx_sw_fifo_re_20, rx_sw_fifo_re_21, rx_sw_fifo_re_23, rx_sw_fifo_re_2u;
+wire rx_sf_fifo_empty_20, rx_sf_fifo_empty_21, rx_sf_fifo_empty_23, rx_sf_fifo_empty_2u;
+wire rx_sw_fifo_re_30, rx_sw_fifo_re_31, rx_sw_fifo_re_32;
+wire rx_sf_fifo_empty_30, rx_sf_fifo_empty_31, rx_sf_fifo_empty_32;
+wire rx_sw_fifo_re_u2, rx_uc_fifo_empty_u2;
+wire [8:0] rx_sc_fifo_d0, rx_sc_fifo_d1, rx_sc_fifo_d2, rx_sc_fifo_d3;
+wire [8:0] rx_sf_fifo_d_01, rx_sf_fifo_d_02, rx_sf_fifo_d_03;
+wire [8:0] rx_sf_fifo_d_10, rx_sf_fifo_d_12, rx_sf_fifo_d_13;
+wire [8:0] rx_sf_fifo_d_20, rx_sf_fifo_d_21, rx_sf_fifo_d_23, rx_sf_fifo_d_2u;
+wire [8:0] rx_sf_fifo_d_30, rx_sf_fifo_d_31, rx_sf_fifo_d_32;
+wire [8:0] rx_uc_fifo_d_u2;
+wire rx_sf_almost_full_01, rx_sf_almost_full_02, rx_sf_almost_full_03;
+wire rx_sf_almost_full_10, rx_sf_almost_full_12, rx_sf_almost_full_13;
+wire rx_sf_almost_full_20, rx_sf_almost_full_21, rx_sf_almost_full_23;
+
+
+// between switch and mac
+wire [8:0] tx_sw_fifo_d0, tx_sw_fifo_d1, tx_sw_fifo_d2, tx_sw_fifo_d3, tx_sw_fifo_du;
+wire [3:0] tx_sc_fifo_re;
+wire tx_uc_fifo_re;
+wire [3:0] tx_sw_fifo_empty;
+wire tx_sw_fifo_we;
+
+wire [1:0] tx_sw_mode0, tx_sw_mode1, tx_sw_mode2, tx_sw_mode3;
+wire tx_sw_modeu;
+wire [3:0] tx_sc_done;
+
+// 100 Mbit
+wire[3:0] mode_100Mbit;
+
+wire pkt_filter_sel_01, pkt_filter_sel_02, pkt_filter_sel_03;
+wire pkt_filter_sel_10, pkt_filter_sel_12, pkt_filter_sel_13;
+wire pkt_filter_sel_20, pkt_filter_sel_21, pkt_filter_sel_23, pkt_filter_sel_2u;
+wire pkt_filter_sel_u2;
+
+// FCS
+wire [1:0] fcs_addr0, fcs_addr1, fcs_addr2, fcs_addr3;
+wire [7:0] fcs_din0, fcs_din1, fcs_din2, fcs_din3;
+wire [7:0] fcs_dout0, fcs_dout1, fcs_dout2, fcs_dout3;
+wire[3:0] fcs_init, fcs_enable;
+
+// half FIFO / DPRAM interface for uP
+wire hfifo_we, hfifo_re; 
+wire [8:0] hfifo_tx_d, hfifo_rx_d;
+wire hfifo_empty;
+wire micro_fifo_int;
+wire tx_uc_block;
+	
+// SCI
+wire[1:0] sci_sel_dual;
+wire[3:0] sci_sel_ch;
+wire[7:0] sci_rddata0, sci_rddata1 ;
+wire[1:0] sci_int;
+
+// Metrics
+wire tx_metrics, metrics_start;
+wire [8:0] metrics_d;
+
+// Network Debug & Metrics
+wire sample_enable;
+reg [3:0] rx_active, tx_active;
+wire [3:0] mac_rx_active;
+wire [3:0] drop_rx0_active, drop_rx1_active, drop_rx2_active, drop_rx3_active;
+wire [3:0] sync_rx0_active, sync_rx1_active, sync_rx2_active, sync_rx3_active;
+wire [3:0] mac_tx_active;
+wire [3:0] rx_sc_error;
+wire [3:0] rx_eop, rx_sop;
+wire [3:0] tx_eop, tx_sop;
+
+
+/****************************
+ * 
+ *   Logic Begins Below 
+ *   
+ ***************************/
+
+/* Lattice requires GSR to be in top-level module and be named GSR_INST */
+GSR GSR_INST(.GSR(rstn));
+PUR PUR_INST(.PUR(1'b1));
+
+assign phy_mdc = clk_10;
+assign phy2_mdc = clk_10;
+
+assign phy0_resetn = phy_resetn[0];
+assign phy1_resetn = phy_resetn[1];
+assign phy2_resetn = phy_resetn[2];
+
+	
+/* 
+ * Clocks derived from the internal OSCG
+ */
+clk_gen clk_gen_0(
+	.rstn( rstn ),
+	.clk_10( clk_10 ),
+	.clk_5( ),
+	.clk_2_5( ),	
+	.clk_1_25( clk_1_25 ),
+	.clk_slow( clk_slow )
+);
+
+
+/* 
+*   main controller
+*   
+*   controls worker blocks
+*   interfaces with uC via I2C
+*
+*/      
+controller #(.ADDR_SZ( MDIO_ROM_ADDR_SZ ))controller_0
+(
+	.rstn( rstn ),
+	.clk( clk_10 ),
+	.init(1'b1),
+	.pulse_100ms( 1'b0 ),
+	// PCS status lines
+	.pcs_rx_error( mac_int ),
+	.pll_lol( pll_lol ),
+	// link status
+	.port_up( phy_up ),
+	// mdio_controller interface
+	.mdio_cont_start(mdio_cont_work_start),
+	.mdio_cont_done(mdio_cont_work_done),
+	.mdio_routine_addr( mdio_routine_addr ),
+	.mdio_run( mdio_run ),
+	// mdio_data params
+	.mdio_page( mdio_page_set ),
+	.mdio_reg_addr( mdio_reg_addr_set ),
+	.mdio_w_data_h( mdio_w_data_h_set ),
+	.mdio_w_data_l( mdio_w_data_l_set ),
+	// bin_to_ascii interface
+	.bin_to_ascii_run( bin_to_ascii_run ),
+	// ext_sys_fifo interface: controller to external I/F FIFO
+	.fifo_mux_sel( read_fifo_mux_sel ),
+	.fifo_we( cont_rd_we ),
+	.read_fifo_d_o( cont_rd ),
+	// i2c interface
+	.i2c_rx_we ( i2c_cont_we ),
+	.i2c_rx_done ( i2c_cont_done ),
+	.i2c_d_in( i2c_d_o ),
+	// reset and config
+	.pcs_rst_dual( pcs_rst_dual ),
+	.serdes_rst_dual( serdes_rst_dual ),
+	.tx_serdes_rst( tx_serdes_rst ),
+	.phy_resetn( phy_resetn ),
+	.mac_reset( mac_reset ),
+	.tx_pcs_rst( tx_pcs_rst ),
+	.rx_serdes_rst( rx_serdes_rst ),
+	.rx_pcs_rst( rx_pcs_rst ),
+	.mdio_mux_sel( mdio_mux_sel ),
+	.i2c_fifo_priority( i2c_fifo_priority ),
+	// TX custom packet
+	.tx_metrics( tx_metrics )
+
+);
+
+/*
+ * Controls the routing of data and transmit modes
+ */
+switch switch_0(
+	.rstn( rstn ),
+	.clk( pcs_pclk ),
+	// PHY status
+	.phy_up( phy_up ),
+	.mode_100Mbit ( mode_100Mbit ),
+	// FIFO input data from RX FIFOs
+	.rx_d_01( rx_sf_fifo_d_01 ),
+	.rx_d_02( rx_sf_fifo_d_02 ),
+	.rx_d_03( rx_sf_fifo_d_03 ),
+	.rx_d_10( rx_sf_fifo_d_10 ),
+	.rx_d_12( rx_sf_fifo_d_12 ),
+	.rx_d_13( rx_sf_fifo_d_13 ),
+	.rx_d_20( rx_sf_fifo_d_20 ),
+	.rx_d_21( rx_sf_fifo_d_21 ),
+	.rx_d_23( rx_sf_fifo_d_23 ),
+	.rx_d_2u( rx_sf_fifo_d_2u ),
+	.rx_d_30( rx_sf_fifo_d_30 ),
+	.rx_d_31( rx_sf_fifo_d_31 ),
+	.rx_d_32( rx_sf_fifo_d_32 ),
+	.rx_d_u2( rx_uc_fifo_d_u2 ),
+	// RX FIFO read enables
+	.rx_fifo_re_01( rx_sw_fifo_re_01 ),
+	.rx_fifo_re_02( rx_sw_fifo_re_02 ),
+	.rx_fifo_re_03( rx_sw_fifo_re_03 ),
+	.rx_fifo_re_10( rx_sw_fifo_re_10 ),
+	.rx_fifo_re_12( rx_sw_fifo_re_12 ),
+	.rx_fifo_re_13( rx_sw_fifo_re_13 ),
+	.rx_fifo_re_20( rx_sw_fifo_re_20 ),
+	.rx_fifo_re_21( rx_sw_fifo_re_21 ),
+	.rx_fifo_re_23( rx_sw_fifo_re_23 ),
+	.rx_fifo_re_2u( rx_sw_fifo_re_2u ),
+	.rx_fifo_re_30( rx_sw_fifo_re_30 ),
+	.rx_fifo_re_31( rx_sw_fifo_re_31 ),
+	.rx_fifo_re_32( rx_sw_fifo_re_32 ),
+	.rx_fifo_re_u2( rx_sw_fifo_re_u2 ),
+	// RX FIFO Empty flags
+	.rx_fifo_empty_01( rx_sf_fifo_empty_01 ),
+	.rx_fifo_empty_02( rx_sf_fifo_empty_02 ),
+	.rx_fifo_empty_03( rx_sf_fifo_empty_03 ),
+	.rx_fifo_empty_10( rx_sf_fifo_empty_10 ),
+	.rx_fifo_empty_12( rx_sf_fifo_empty_12 ),
+	.rx_fifo_empty_13( rx_sf_fifo_empty_13 ),
+	.rx_fifo_empty_20( rx_sf_fifo_empty_20 ),
+	.rx_fifo_empty_21( rx_sf_fifo_empty_21 ),
+	.rx_fifo_empty_23( rx_sf_fifo_empty_23 ),
+	.rx_fifo_empty_2u( rx_sf_fifo_empty_2u ),
+	.rx_fifo_empty_30( rx_sf_fifo_empty_30 ),
+	.rx_fifo_empty_31( rx_sf_fifo_empty_31 ),
+	.rx_fifo_empty_32( rx_sf_fifo_empty_32 ),
+	.rx_fifo_empty_u2( rx_uc_fifo_empty_u2 ),
+	// TX FIFO output from internal muxes
+	.tx_d0( tx_sw_fifo_d0),
+	.tx_d1( tx_sw_fifo_d1 ),
+	.tx_d2( tx_sw_fifo_d2 ),
+	.tx_d3( tx_sw_fifo_d3 ),
+	.tx_du( tx_sw_fifo_du ),
+	// TX FIFO read enable inputs (need to route to RX output FIFOs)
+	.tx_fifo_re( tx_sc_fifo_re ),
+	.tx_fifo_we_u ( tx_sw_fifo_we ),
+	// TX FIFO Empty Flags (need to route to RX output FIFOs)
+	.tx_fifo_empty( tx_sw_fifo_empty ),
+	// TX modes for the PHYs and uc
+	.tx_mode0( tx_sw_mode0 ),
+	.tx_mode1( tx_sw_mode1 ),
+	.tx_mode2( tx_sw_mode2 ),
+	.tx_mode3( tx_sw_mode3 ),
+	.tx_modeu( tx_modeu ),
+	// TX state machine done flag
+	.tx_f( tx_sc_done ),
+	// TX custom packet
+	.tx_metrics	( tx_metrics )
+);
+
+
+/*
+ * RX and TX controller logic tied to PCS/SGMII protocol
+ */
+mac mac_0(
+	.rstn( ~mac_reset[0] ),
+	.phy_resetn ( phy_resetn[0] ),
+	.clk( pcs_pclk ),	
+	.tap_port ( 1'b0 ),
+	// SGMII AN  
+	.link_timer( 1'b0 ),
+	.fixed_speed(SGMII_SPEED_AN),
+	.an_disable( 1'b0 ),
+	.an_link_up(  ),
+	.an_duplex(  ),
+	.mode_100Mbit( mode_100Mbit[0] ),
+	.phy_up( phy_up[0] ),
+	// Switch I/F
+	.tx_mode( tx_sw_mode0 ),
+	.tx_f( tx_sc_done[0] ),
+	// PCS / SERDES health
+	.rx_lsm( sgmii_lsm_status[0] ),
+	.rx_cv_err ( sgmii_rx_cv_err[0] ),
+	.rx_disp_err( sgmii_rx_disp_err[0] ),
+	.rx_cdr_lol( sgmii_rx_cdr_lol[0] ),
+	.rx_los ( sgmii_rx_los_low[0] ),
+	// PCS data I/F
+	.rx_k( sgmii_rx_k[0] ),
+	.rx_data( rx_data0 ),
+	.tx_k( sgmii_tx_k[0] ),
+	.tx_data( tx_data0 ),
+	.tx_disp_correct( sgmii_tx_disp_correct[0] ),
+	// Flags and Interrupts 
+	.keep( rx_mac_keep[0] ),
+	// TX FCS
+	.fcs_init( fcs_init[0] ),
+	.fcs_enable( fcs_enable[0] ),
+	.fcs_addr( fcs_addr0 ),
+	.fcs_dout( fcs_din0 ),
+	.fcs_din( fcs_dout0 ),
+	// SGMII RX / FIFO Write
+	.rx_fifo_we( rx_sc_fifo_we[0] ),
+	.rx_fifo_d( rx_sc_fifo_d0 ),
+	.rx_error( rx_sc_error[0] ),
+	.rx_wr_done( rx_sc_wr_done[0] ),
+	// SGMII TX / FIFO Read
+	.tx_fifo_re( tx_sc_fifo_re[0] ),
+	.tx_fifo_d( tx_sw_fifo_d0 ),
+	.tx_fifo_empty( tx_sw_fifo_empty[0] ),
+	// Packet Filter
+	.rx_sample( rx_sample[0] ),
+	.ipv4_pkt_start( ipv4_pkt_start[0] ),
+	.trigger( ),
+	.rx_enet_bcast( rx_enet_bcast[0] ),
+	.rx_ipv4_arp( rx_ipv4_arp[0] ),	
+	.rx_k_m1( rx0_k_m1 ), 
+	.rx_k_m2( rx0_k_m2 ), 
+	.rx_k_m3( rx0_k_m3), 
+	.rx_k_m4( rx0_k_m4 ),
+	.rx_data_m1( rx0_data_m1 ), 
+	.rx_data_m2( rx0_data_m2 ), 
+	.rx_data_m3( rx0_data_m3), 
+	.rx_data_m4( rx0_data_m4 ),
+	// Param RAM
+	.dpr_ad( ),
+	.dpr_we( ),
+	.dpr_ce( ),
+	.dpr_di( 9'h0),
+	.dpr_do( ),
+	// Metrics and Interrupts
+	.mac_int( mac_int[0] ),
+	.rx_sop( rx_sop[0] ),
+	.rx_eop( rx_eop[0] ),
+	.tx_sop( tx_sop[0] ),
+	.tx_eop( tx_eop[0] ),
+	.metrics_start ( ),
+	.metrics_d ( 9'h0 ),
+	.rx_active( mac_rx_active[0] ),
+	.tx_active( mac_tx_active[0] )
+);
+
+
+ipv4_rx ipv4_rx_0(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),	
+		// control
+		.phy_resetn ( phy_resetn[0] ),
+		.phy_up( phy_up[0] ),
+		// packet data
+		.pkt_start( ipv4_pkt_start[0] ),
+		.rx_eop( rx_eop[0] ),
+		.rx_data_m1( rx0_data_m1 ), 
+		.rx_data_m2( rx0_data_m2 ), 
+		.rx_data_m3( rx0_data_m3), 
+		.rx_data_m4( rx0_data_m4 ),	
+		// flags
+		.pkt_complete(ipv4_pkt_complete[0]),
+		.trigger_src_addr(  ),
+		.trigger_dst_addr( trigger[0] ),
+		.keep(  )
+		);
+
+
+pkt_filter pkt_filter_01(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_01 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx0_data_m1 ), 
+		.rx_data_m2( rx0_data_m2 ), 
+		.rx_data_m3( rx0_data_m3), 
+		.rx_data_m4( rx0_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[0] ),
+		.block( 1'b0 ),
+		.invert( 1'b1 ),
+		.trigger( trigger[0] ),
+		.keep( rx_pf_keep_01 )
+);
+
+drop_fifo drop_fifo_01(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b1 ),
+		// control
+		.keep ( rx_pf_keep_01 | rx_mac_keep[0] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[0] ),
+		.wr_done( rx_sc_wr_done[0] ),
+		.d_in( rx_sc_fifo_d0 ),
+		// output
+		.we_out( rx_df_fifo_we_01 ),
+		.d_out( rx_df_fifo_d_01 ),
+		// debug
+		.active( drop_rx0_active[1] )
+);
+	
+sync_fifo sync_fifo_rx_01(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		// input
+		.we ( rx_df_fifo_we_01 & phy_up[1] ),
+		.d_in ( rx_df_fifo_d_01 ),
+		// output
+		.re ( rx_sw_fifo_re_01 ),
+		.d_out( rx_sf_fifo_d_01 ),
+		.empty( rx_sf_fifo_empty_01 ),
+		.almost_full(  ),
+		.reset_ptrs( 1'b0 ),
+		// debug
+		.active( sync_rx0_active[1] )
+);
+	
+pkt_filter pkt_filter_02(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_02 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx0_data_m1 ), 
+		.rx_data_m2( rx0_data_m2 ), 
+		.rx_data_m3( rx0_data_m3), 
+		.rx_data_m4( rx0_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[0] ),
+		.block( rx_sf_almost_full_02 ),
+		.invert( 1'b1 ),
+		.trigger( trigger[0] ),
+		.keep( rx_pf_keep_02 )
+);
+
+drop2_fifo drop_fifo_02(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b1 ),
+		// control
+		.keep ( rx_pf_keep_02 | rx_mac_keep[0] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[0] ),
+		.wr_done( rx_sc_wr_done[0] ),
+		.d_in( rx_sc_fifo_d0 ),
+		// output
+		.we_out( rx_df_fifo_we_02 ),
+		.d_out( rx_df_fifo_d_02 ),
+		.active( drop_rx0_active[2] )
+	);
+
+sync_fifo sync_fifo_rx_02(
+	.rstn( rstn ),
+	.clk ( pcs_pclk ),
+	// input
+	.we ( rx_df_fifo_we_02 & phy_up[2] ),
+	.d_in ( rx_df_fifo_d_02 ),
+	// output
+	.re ( rx_sw_fifo_re_02 ),
+	.d_out( rx_sf_fifo_d_02 ),
+	.empty( rx_sf_fifo_empty_02 ),
+	.almost_full( rx_sf_almost_full_02 ),
+	.reset_ptrs( 1'b0 ),
+	// debug
+	.active(sync_rx0_active[2]  )
+);
+
+
+pkt_filter pkt_filter_03(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_03 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx0_data_m1 ), 
+		.rx_data_m2( rx0_data_m2 ), 
+		.rx_data_m3( rx0_data_m3), 
+		.rx_data_m4( rx0_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[0] ),
+		.block( rx_sf_almost_full_03 ),
+		.invert( 1'b0 ),
+		.trigger( trigger[0] ),
+		.keep( rx_pf_keep_03 )
+	);
+
+drop_fifo drop_fifo_03(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b0 ),
+		// control
+		.keep ( rx_pf_keep_03 | rx_mac_keep[0] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[0] ),
+		.wr_done( rx_sc_wr_done[0] ),
+		.d_in( rx_sc_fifo_d0 ),
+		// output
+		.we_out( rx_df_fifo_we_03 ),
+		.d_out( rx_df_fifo_d_03 ),
+		.active( drop_rx0_active[3] )
+	);
+
+sync_fifo sync_fifo_rx_03(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		// input
+		.we ( rx_df_fifo_we_03 & phy_up[3] ),
+		.d_in ( rx_df_fifo_d_03 ),
+		// output
+		.re ( rx_sw_fifo_re_03 ),
+		.d_out( rx_sf_fifo_d_03 ),
+		.empty( rx_sf_fifo_empty_03 ),
+		.almost_full( rx_sf_almost_full_03 ),
+		.reset_ptrs( 1'b0 ),
+		// debug
+		.active( sync_rx0_active[3] )
+	);
+
+fcs fcs_0(
+	.rstn( rstn ),
+	.clk( pcs_pclk ),
+	.init( fcs_init[0] ),
+	.enable( fcs_enable[0] ), 
+	.addr( fcs_addr0 ),
+	.din( fcs_din0 ),
+	.dout( fcs_dout0 )
+);
+
+
+mac mac_1(
+	.rstn( ~mac_reset[1] ),
+	.phy_resetn ( phy_resetn[1] ),
+	.clk( pcs_pclk ),
+	.tap_port ( 1'b0 ),
+	// SGMII AN
+	.link_timer( 1'b0 ),
+	.fixed_speed(SGMII_SPEED_AN),
+	.an_disable( 1'b0 ),
+	.an_link_up(  ),
+	.an_duplex(  ),
+	.mode_100Mbit( mode_100Mbit[1] ),
+	.phy_up( phy_up[1] ),
+	// Switch I/F
+	.tx_mode( tx_sw_mode1 ),
+	.tx_f( tx_sc_done[1] ),
+	// PCS / SERDES health
+	.rx_lsm( sgmii_lsm_status[1] ),
+	.rx_cv_err ( sgmii_rx_cv_err[1] ),
+	.rx_disp_err( sgmii_rx_disp_err[1] ),
+	.rx_cdr_lol( sgmii_rx_cdr_lol[1] ),
+	.rx_los ( sgmii_rx_los_low[1] ),
+	// PCS data I/F
+	.rx_k( sgmii_rx_k[1] ),
+	.rx_data( rx_data1 ),
+	.tx_k( sgmii_tx_k[1] ),
+	.tx_data( tx_data1 ),
+	.tx_disp_correct( sgmii_tx_disp_correct[1] ),
+	// Flags and Interrupts
+	.keep( rx_mac_keep[1] ),
+	// FCS
+	.fcs_init( fcs_init[1] ),
+	.fcs_enable( fcs_enable[1] ),
+	.fcs_addr( fcs_addr1 ),
+	.fcs_dout( fcs_din1 ),
+	.fcs_din( fcs_dout1 ),
+	// SGMII RX / FIFO Write
+	.rx_fifo_we(  rx_sc_fifo_we[1]  ),
+	.rx_fifo_d( rx_sc_fifo_d1 ),
+	.rx_error( rx_sc_error[1] ),
+	.rx_wr_done( rx_sc_wr_done[1] ),
+	// SGMII TX / FIFO Read
+	.tx_fifo_re( tx_sc_fifo_re[1] ),
+	.tx_fifo_d( tx_sw_fifo_d1 ),
+	.tx_fifo_empty( tx_sw_fifo_empty[1] ),
+	// Packet Filter
+	.rx_sample( ),
+	.ipv4_pkt_start( ipv4_pkt_start[1] ),
+	.trigger( ),
+	.rx_enet_bcast( rx_enet_bcast[1] ),
+	.rx_ipv4_arp( rx_ipv4_arp[1] ),	
+	.rx_k_m1( rx1_k_m1 ), 
+	.rx_k_m2( rx1_k_m2 ), 
+	.rx_k_m3( rx1_k_m3), 
+	.rx_k_m4( rx1_k_m4 ),
+	.rx_data_m1( rx1_data_m1 ), 
+	.rx_data_m2( rx1_data_m2 ), 
+	.rx_data_m3( rx1_data_m3), 
+	.rx_data_m4( rx1_data_m4 ),
+	// Param RAM
+	.dpr_ad(  ),
+	.dpr_we( ),
+	.dpr_ce( ),
+	.dpr_di( 9'h0),
+	.dpr_do( ),
+	// Metrics  and Interrupts
+	.mac_int( mac_int[1] ),
+	.rx_sop( rx_sop[1] ),
+	.rx_eop( rx_eop[1] ),
+	.tx_sop( tx_sop[1] ),
+	.tx_eop( tx_eop[1] ),
+	.metrics_start ( ),
+	.metrics_d ( 9'h0 ),
+	.rx_active( mac_rx_active[1] ),
+	.tx_active( mac_tx_active[1] )
+);
+
+ipv4_rx ipv4_rx_1(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),	
+		// control
+		.phy_resetn ( phy_resetn[1] ),
+		.phy_up( phy_up[1] ),
+		// packet data
+		.pkt_start( ipv4_pkt_start[1] ),
+		.rx_eop( rx_eop[1] ),
+		.rx_data_m1( rx1_data_m1 ), 
+		.rx_data_m2( rx1_data_m2 ), 
+		.rx_data_m3( rx1_data_m3), 
+		.rx_data_m4( rx1_data_m4 ),	
+		// flags
+		.pkt_complete(ipv4_pkt_complete[1]),
+		.trigger_src_addr(  ),
+		.trigger_dst_addr( trigger[1] ),
+		.keep(  )
+	);
+
+pkt_filter #(.DEPTH(8), .DEPTHW(3), .WIDTH(32)) pkt_filter_10(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_10 ),
+		.we( mem_we ),
+		.addr( mem_addr[4:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx1_data_m1 ), 
+		.rx_data_m2( rx1_data_m2 ), 
+		.rx_data_m3( rx1_data_m3), 
+		.rx_data_m4( rx1_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[1] ),
+		.block( 1'b0 ),
+		.invert( 1'b1 ),
+		.trigger( trigger[1] ),
+		.keep( rx_pf_keep_10 )
+	);
+
+drop_fifo drop_fifo_10(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b1 ),
+		// control
+		.keep ( rx_pf_keep_10 | rx_mac_keep[1] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[1] ),
+		.wr_done( rx_sc_wr_done[1] ),
+		.d_in( rx_sc_fifo_d1 ),
+		// output
+		.we_out( rx_df_fifo_we_10 ),
+		.d_out( rx_df_fifo_d_10 ),
+		// debug
+		.active( drop_rx1_active[0] )
+	);
+	
+sync_fifo sync_fifo_rx_10(
+	.rstn( rstn ),
+	.clk ( pcs_pclk ),
+	// input / RX
+	.we ( rx_df_fifo_we_10 & phy_up[0] ),
+	.d_in ( rx_df_fifo_d_10 ),
+	// output / TX
+	.re ( rx_sw_fifo_re_10 ),
+	.d_out( rx_sf_fifo_d_10 ),
+	.empty( rx_sf_fifo_empty_10 ),
+	.almost_full(  ),
+	.reset_ptrs( 1'b0 ),
+	// debug
+	.active( sync_rx1_active[0] )
+);
+
+pkt_filter pkt_filter_12(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_12 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx1_data_m1 ), 
+		.rx_data_m2( rx1_data_m2 ), 
+		.rx_data_m3( rx1_data_m3), 
+		.rx_data_m4( rx1_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[1] ),
+		.block( rx_sf_almost_full_12 ),
+		.invert( 1'b0 ),
+		.trigger( trigger[1] ),
+		.keep( rx_pf_keep_12 )
+	);
+	
+drop_fifo drop_fifo_12(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b0 ),
+		// control
+		.keep ( rx_pf_keep_12 | rx_mac_keep[1] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[1] ),
+		.wr_done( rx_sc_wr_done[1] ),
+		.d_in( rx_sc_fifo_d1 ),
+		// output
+		.we_out( rx_df_fifo_we_12 ),
+		.d_out( rx_df_fifo_d_12 ),
+		// debug
+		.active( drop_rx1_active[2] )
+	);
+
+sync_fifo sync_fifo_rx_12(
+	.rstn( rstn ),
+	.clk ( pcs_pclk ),
+	// input / RX
+	.we ( rx_df_fifo_we_12 & phy_up[2] ),
+	.d_in ( rx_df_fifo_d_12 ),
+	// output / TX
+	.re ( rx_sw_fifo_re_12 ),
+	.d_out( rx_sf_fifo_d_12 ),
+	.empty( rx_sf_fifo_empty_12 ),
+	.almost_full( rx_sf_almost_full_12 ),
+	.reset_ptrs( 1'b0 ),
+	// debug
+	.active( sync_rx1_active[2] )
+);
+
+pkt_filter pkt_filter_13(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_13 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx1_data_m1 ), 
+		.rx_data_m2( rx1_data_m2 ), 
+		.rx_data_m3( rx1_data_m3), 
+		.rx_data_m4( rx1_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[1] ),
+		.block( 1'b0 ),
+		.invert( 1'b1 ),
+		.trigger( trigger[1] ),
+		.keep( rx_pf_keep_13 )
+	);
+
+drop_fifo drop_fifo_13(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b1 ),
+		// control
+		.keep ( rx_pf_keep_13 | rx_mac_keep[1] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[1] ),
+		.wr_done( rx_sc_wr_done[1] ),
+		.d_in( rx_sc_fifo_d1 ),
+		// output
+		.we_out( rx_df_fifo_we_13 ),
+		.d_out( rx_df_fifo_d_13 ),
+		// debug
+		.active( drop_rx1_active[3] )
+	);
+	
+sync_fifo sync_fifo_rx_13(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		// input / RX
+		.we ( rx_df_fifo_we_13 & phy_up[3] ),
+		.d_in ( rx_df_fifo_d_13 ),
+		// output / TX
+		.re ( rx_sw_fifo_re_13 ),
+		.d_out( rx_sf_fifo_d_13 ),
+		.empty( rx_sf_fifo_empty_13 ),
+		.almost_full(  ),
+		.reset_ptrs( 1'b0 ),
+		// debug
+		.active( sync_rx1_active[3] )
+	);
+
+fcs fcs_1(
+	.rstn( rstn ),
+	.clk( pcs_pclk ),
+	.init( fcs_init[1] ),
+	.enable( fcs_enable[1] ), 
+	.addr( fcs_addr1 ),
+	.din( fcs_din1 ),
+	.dout( fcs_dout1 )
+);
+
+metrics metrics_2(
+	.rstn( rstn ),
+	.clk( pcs_pclk ),
+	.mode_100Mbit( mode_100Mbit[2] ),
+	// input data for gathering metrics
+	.rx_mac_keep( rx_mac_keep ),
+	.rx_pf_keep_01( rx_pf_keep_01 ),
+	.rx_pf_keep_02( rx_pf_keep_02 ),
+	.rx_pf_keep_10( rx_pf_keep_10 ),
+	.rx_pf_keep_12( rx_pf_keep_12 ),
+	.rx_pf_keep_20( rx_pf_keep_20 ),
+	.rx_pf_keep_21( rx_pf_keep_21 ),
+	.rx_pf_keep_23( rx_pf_keep_23 ),
+	
+	.rx_sop( rx_sop ),
+	.rx_eop( rx_eop ),
+	.tx_sop( tx_sop ),
+	.tx_eop( tx_eop ),
+	// metric outputs
+	.metrics_start ( metrics_start ),
+	.metrics_d( metrics_d )
+);
+
+
+mac mac_2(
+	.rstn( ~mac_reset[2] & ~sgmii_rx_los_low[2] ),
+	.phy_resetn ( phy_resetn[2] ),
+	.clk( pcs_pclk ),
+	.tap_port ( 1'b0 ),
+	// SGMII AN
+	.link_timer( 1'b0 ),
+	.fixed_speed(SGMII_SPEED_1GBIT),
+	.an_disable( 1'b1 ),
+	.an_link_up(  ),
+	.an_duplex(  ),
+	.mode_100Mbit( mode_100Mbit[2] ),
+	.phy_up( phy_up[2] ),
+	// Switch I/F	
+	.tx_mode( tx_sw_mode2 ),
+	.tx_f( tx_sc_done[2] ),
+	// PCS / SERDES health
+	.rx_lsm( sgmii_lsm_status[2] ),
+	.rx_cv_err ( sgmii_rx_cv_err[2] ),
+	.rx_disp_err( sgmii_rx_disp_err[2] ),
+	.rx_cdr_lol( sgmii_rx_cdr_lol[2] ),
+	.rx_los ( sgmii_rx_los_low[2] ),
+	// PCS data I/F
+	.rx_k( sgmii_rx_k[2] ),
+	.rx_data( rx_data2 ),
+	.tx_k( sgmii_tx_k[2] ),
+	.tx_data( tx_data2 ),
+	.tx_disp_correct( sgmii_tx_disp_correct[2] ),
+	// Flags and Interrupts
+	.keep( rx_mac_keep[2] ),
+	// FCS
+	.fcs_init( fcs_init[2] ),
+	.fcs_enable( fcs_enable[2] ),
+	.fcs_addr( fcs_addr2 ),
+	.fcs_dout( fcs_din2 ),
+	.fcs_din( fcs_dout2 ),
+	// SGMII RX / FIFO Write
+	.rx_fifo_we( rx_sc_fifo_we[2] ),
+	.rx_fifo_d( rx_sc_fifo_d2 ),
+	.rx_error( rx_sc_error[2] ),
+	.rx_wr_done( rx_sc_wr_done[2] ),
+	// SGMII TX / FIFO Read
+	.tx_fifo_re( tx_sc_fifo_re[2] ),
+	.tx_fifo_d( tx_sw_fifo_d2 ),
+	.tx_fifo_empty( tx_sw_fifo_empty[2]),
+	// Packet Filter
+ 	.rx_sample( ),
+	.ipv4_pkt_start( ipv4_pkt_start[2] ),
+	.trigger( ),
+	.rx_enet_bcast( rx_enet_bcast[2] ),
+	.rx_ipv4_arp( rx_ipv4_arp[2] ),	
+	.rx_k_m1( rx2_k_m1 ), 
+	.rx_k_m2( rx2_k_m2 ), 
+	.rx_k_m3( rx2_k_m3), 
+	.rx_k_m4( rx2_k_m4 ),
+	.rx_data_m1( rx2_data_m1 ), 
+	.rx_data_m2( rx2_data_m2 ), 
+	.rx_data_m3( rx2_data_m3), 
+	.rx_data_m4( rx2_data_m4 ),
+	// Param RAM
+	.dpr_ad( param_phy2_addr ),
+	.dpr_we( param_phy2_we ),
+	.dpr_ce( param_phy2_ce ),
+	.dpr_di( param_phy2_din ),
+	.dpr_do( param_phy2_dout ),
+	// Metrics and Interrupts
+	.mac_int( mac_int[2] ), 
+	.rx_sop( rx_sop[2] ),
+	.rx_eop( rx_eop[2] ),
+	.tx_sop( tx_sop[2] ),
+	.tx_eop( tx_eop[2] ),
+	.metrics_start ( metrics_start ),
+	.metrics_d( metrics_d ),
+	// Debug
+	.rx_active( mac_rx_active[2] ),
+	.tx_active( mac_tx_active[2] )
+);
+
+ipv4_rx ipv4_rx_2(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),	
+		// control
+		.phy_resetn ( phy_resetn[2] ),
+		.phy_up( phy_up[2] ),
+		// packet data
+		.pkt_start( ipv4_pkt_start[2] ),
+		.rx_eop( rx_eop[2] ),
+		.rx_data_m1( rx2_data_m1 ), 
+		.rx_data_m2( rx2_data_m2 ), 
+		.rx_data_m3( rx2_data_m3), 
+		.rx_data_m4( rx2_data_m4 ),	
+		// flags
+		.pkt_complete(ipv4_pkt_complete[2]),
+		.trigger_src_addr(  ),
+		.trigger_dst_addr( trigger[2] ),
+		.keep(  )
+	);
+
+
+pkt_filter pkt_filter_20(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_20 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx2_data_m1 ), 
+		.rx_data_m2( rx2_data_m2 ), 
+		.rx_data_m3( rx2_data_m3), 
+		.rx_data_m4( rx2_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[2] ),
+		.block( rx_sf_almost_full_20 ),
+		.invert( 1'b1 ),
+		.trigger( trigger[2] ),
+		.keep( rx_pf_keep_20 )
+);
+
+drop_fifo drop_fifo_20(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b1 ),
+		// control
+		.keep ( rx_pf_keep_20 | rx_mac_keep[2] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[2] ),
+		.wr_done( rx_sc_wr_done[2] ),
+		.d_in( rx_sc_fifo_d2 ),
+		// output
+		.we_out( rx_df_fifo_we_20 ),
+		.d_out( rx_df_fifo_d_20 ),
+		// debug
+		.active( drop_rx2_active[0] )
+	);
+
+
+sync4_fifo sync_fifo_rx_20(
+	.rstn( rstn ),
+	.clk ( pcs_pclk ),
+	// input / RX
+	.we ( rx_df_fifo_we_20 & phy_up[0]),
+	.d_in ( rx_df_fifo_d_20 ),
+	// output / TX
+	.re ( rx_sw_fifo_re_20 ),
+	.d_out( rx_sf_fifo_d_20 ),
+	.empty( rx_sf_fifo_empty_20 ),
+	.almost_full( rx_sf_almost_full_20 ),
+	.reset_ptrs( 1'b0 ),
+	// debug
+	.active( sync_rx2_active[0] )
+);
+
+pkt_filter pkt_filter_21(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_21 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx2_data_m1 ), 
+		.rx_data_m2( rx2_data_m2 ), 
+		.rx_data_m3( rx2_data_m3), 
+		.rx_data_m4( rx2_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[2] ),
+		.block( 1'b0 ),
+		.invert( 1'b0 ),
+		.trigger( trigger[2] ),
+		.keep( rx_pf_keep_21 )
+);
+	
+drop_fifo drop_fifo_21(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b0 ),
+		// control
+		.keep ( rx_pf_keep_21 | rx_mac_keep[2] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[2] ),
+		.wr_done( rx_sc_wr_done[2] ),
+		.d_in( rx_sc_fifo_d2 ),
+		// output
+		.we_out( rx_df_fifo_we_21 ),
+		.d_out( rx_df_fifo_d_21 ),
+		// debug
+		.active( drop_rx2_active[1] )
+	);
+
+sync_fifo sync_fifo_rx_21(
+	.rstn( rstn ),
+	.clk ( pcs_pclk ),
+	// input / RX
+	.we ( rx_df_fifo_we_21 & phy_up[1] ),
+	.d_in ( rx_df_fifo_d_21 ),
+	// output
+	.re ( rx_sw_fifo_re_21 ),
+	.d_out( rx_sf_fifo_d_21 ),
+	.empty( rx_sf_fifo_empty_21 ),
+	.almost_full(  ),
+	.reset_ptrs( 1'b0 ),
+	// debug
+	.active( sync_rx2_active[1] )
+);
+
+pkt_filter pkt_filter_2u(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_2u ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx2_data_m1 ), 
+		.rx_data_m2( rx2_data_m2 ), 
+		.rx_data_m3( rx2_data_m3), 
+		.rx_data_m4( rx2_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[2] ),
+		.block( tx_uc_block ),
+		.invert( 1'b0 ),
+		.trigger( trigger[2] ),
+		.keep( rx_pf_keep_2u )
+	);
+
+drop_fifo drop_fifo_2u(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b0 ),
+		// control
+		.passthrough( 1'b0 ),
+		.keep ( rx_pf_keep_2u | rx_mac_keep[2] ),
+		// input
+		.we_in( rx_sc_fifo_we[2] ),
+		.wr_done( rx_sc_wr_done[2] ),
+		.d_in( rx_sc_fifo_d2 ),
+		// output
+		.we_out( rx_df_fifo_we_2u ), 
+		.d_out( rx_df_fifo_d_2u ),
+		// debug
+		.active( )
+	);
+
+sync_fifo sync_fifo_rx_2u(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		// input / RX
+		.we ( rx_df_fifo_we_2u ),
+		.d_in ( rx_df_fifo_d_2u ),
+		// output
+		.re ( rx_sw_fifo_re_2u ),
+		.d_out( rx_sf_fifo_d_2u ),
+		.empty( rx_sf_fifo_empty_2u ),
+		.almost_full(  ),
+		.reset_ptrs( 1'b0 ),
+		// debug
+		.active(  )
+);
+
+fcs fcs_2(
+	.rstn( rstn ),
+	.clk( pcs_pclk ),
+	.init( fcs_init[2] ),
+	.enable( fcs_enable[2] ), 
+	.addr( fcs_addr2 ),
+	.din( fcs_din2 ),
+	.dout( fcs_dout2 )
+);
+
+mac mac_3(
+		.rstn( ~mac_reset[3] & ~sgmii_rx_los_low[3] ),
+		.phy_resetn ( phy_resetn[3] ),
+		.clk( pcs_pclk ),	
+		.tap_port ( 1'b0 ),
+		// SGMII AN  
+		.link_timer( 1'b0 ),
+		.fixed_speed(SGMII_SPEED_1GBIT),
+		.an_disable( 1'b1 ),
+		.an_link_up(  ),
+		.an_duplex(  ),
+		.mode_100Mbit( mode_100Mbit[3] ),
+		.phy_up( phy_up[3] ),
+		// Switch I/F
+		.tx_mode( tx_sw_mode3 ),
+		.tx_f( tx_sc_done[3] ),
+		// PCS / SERDES health
+		.rx_lsm( sgmii_lsm_status[3] ),
+		.rx_cv_err ( sgmii_rx_cv_err[3] ),
+		.rx_disp_err( sgmii_rx_disp_err[3] ),
+		.rx_cdr_lol( sgmii_rx_cdr_lol[3] ),
+		.rx_los ( sgmii_rx_los_low[3] ),
+		// PCS data I/F
+		.rx_k( sgmii_rx_k[3] ),
+		.rx_data( rx_data3 ),
+		.tx_k( sgmii_tx_k[3] ),
+		.tx_data( tx_data3 ),
+		.tx_disp_correct( sgmii_tx_disp_correct[3] ),
+		// Flags and Interrupts 
+		.keep( rx_mac_keep[3] ),
+		// TX FCS
+		.fcs_init( fcs_init[3] ),
+		.fcs_enable( fcs_enable[3] ),
+		.fcs_addr( fcs_addr3 ),
+		.fcs_dout( fcs_din3 ),
+		.fcs_din( fcs_dout3 ),
+		// SGMII RX / FIFO Write
+		.rx_fifo_we( rx_sc_fifo_we[3] ),
+		.rx_fifo_d( rx_sc_fifo_d3 ),
+		.rx_error( rx_sc_error[3] ),
+		.rx_wr_done( rx_sc_wr_done[3] ),
+		// SGMII TX / FIFO Read
+		.tx_fifo_re( tx_sc_fifo_re[3] ),
+		.tx_fifo_d( tx_sw_fifo_d3 ),
+		.tx_fifo_empty( tx_sw_fifo_empty[3] ),
+		// Packet Filter
+		.rx_sample( rx_sample[3] ),
+		.ipv4_pkt_start( ipv4_pkt_start[3] ),
+		.trigger( ),
+		.rx_enet_bcast( rx_enet_bcast[3] ),
+		.rx_ipv4_arp( rx_ipv4_arp[3] ),	
+		.rx_k_m1( rx3_k_m1 ), 
+		.rx_k_m2( rx3_k_m2 ), 
+		.rx_k_m3( rx3_k_m3), 
+		.rx_k_m4( rx3_k_m4 ),
+		.rx_data_m1( rx3_data_m1 ), 
+		.rx_data_m2( rx3_data_m2 ), 
+		.rx_data_m3( rx3_data_m3), 
+		.rx_data_m4( rx3_data_m4 ),
+		// Param RAM
+		.dpr_ad( ),
+		.dpr_we( ),
+		.dpr_ce( ),
+		.dpr_di( 9'h0),
+		.dpr_do( ),
+		// Metrics  and Interrupts
+		.mac_int( mac_int[3] ),
+		.rx_sop( rx_sop[3] ),
+		.rx_eop( rx_eop[3] ),
+		.tx_sop( tx_sop[3] ),
+		.tx_eop( tx_eop[3] ),
+		.metrics_start ( ),
+		.metrics_d ( 9'h0 ),
+		// Debug
+		.rx_active( mac_rx_active[3] ),
+		.tx_active( mac_tx_active[3] )
+
+	);
+
+
+ipv4_rx ipv4_rx_3(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),	
+		// control
+		.phy_resetn ( phy_resetn[3] ),
+		.phy_up( phy_up[3] ),
+		// packet data
+		.pkt_start( ipv4_pkt_start[3] ),
+		.rx_eop( rx_eop[3] ),
+		.rx_data_m1( rx3_data_m1 ), 
+		.rx_data_m2( rx3_data_m2 ), 
+		.rx_data_m3( rx3_data_m3), 
+		.rx_data_m4( rx3_data_m4 ),	
+		// flags
+		.pkt_complete(ipv4_pkt_complete[3]),
+		.trigger_src_addr(  ),
+		.trigger_dst_addr( trigger[3] ),
+		.keep(  )
+	);
+	
+
+
+pkt_filter pkt_filter_30(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_30 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx3_data_m1 ), 
+		.rx_data_m2( rx3_data_m2 ), 
+		.rx_data_m3( rx3_data_m3), 
+		.rx_data_m4( rx3_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[3] ),
+		.block( 1'b0 ),
+		.invert( 1'b0 ),
+		.trigger( trigger[3] ),
+		.keep( rx_pf_keep_30 )
+	);
+
+drop_fifo drop_fifo_30(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b0 ),
+		// control
+		.keep ( rx_pf_keep_30 | rx_mac_keep[3] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[3] ),
+		.wr_done( rx_sc_wr_done[3] ),
+		.d_in( rx_sc_fifo_d3 ),
+		// output
+		.we_out( rx_df_fifo_we_30 ),
+		.d_out( rx_df_fifo_d_30 ),
+		// debug
+		.active( drop_rx3_active[0] )
+	);
+	
+sync_fifo sync_fifo_rx_30(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		// input
+		.we ( rx_df_fifo_we_30 & phy_up[0] ),
+		.d_in ( rx_df_fifo_d_30 ),
+		// output
+		.re ( rx_sw_fifo_re_30 ),
+		.d_out( rx_sf_fifo_d_30 ),
+		.empty( rx_sf_fifo_empty_30 ),
+		.almost_full(  ),
+		.reset_ptrs( 1'b0 ),
+		// debug
+		.active( sync_rx3_active[0] )
+	);
+	
+pkt_filter pkt_filter_31(
+		.rstn( rstn ),
+		.clk( pcs_pclk ),
+		// input for programming
+		.sel( pkt_filter_sel_31 ),
+		.we( mem_we ),
+		.addr( mem_addr[3:0] ),
+		.d_in( mem_d_i[7:0] ),
+		// registered data
+		.rx_data_m1( rx3_data_m1 ), 
+		.rx_data_m2( rx3_data_m2 ), 
+		.rx_data_m3( rx3_data_m3), 
+		.rx_data_m4( rx3_data_m4 ),	
+		// filter
+		.new_frame ( rx_sop[3] ),
+		.block( 1'b0 ),
+		.invert( 1'b1 ),
+		.trigger( trigger[3] ),
+		.keep( rx_pf_keep_31 )
+	);
+
+drop_fifo drop_fifo_31(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		.enable( 1'b1 ),
+		// control
+		.keep ( rx_pf_keep_31 | rx_mac_keep[3] ),
+		.passthrough( 1'b0 ),
+		// input
+		.we_in( rx_sc_fifo_we[3] ),
+		.wr_done( rx_sc_wr_done[3] ),
+		.d_in( rx_sc_fifo_d3 ),
+		// output
+		.we_out( rx_df_fifo_we_31 ),
+		.d_out( rx_df_fifo_d_31 ),
+		// debug
+		.active( drop_rx3_active[1] )
+	);
+	
+sync_fifo sync_fifo_rx_31(
+		.rstn( rstn ),
+		.clk ( pcs_pclk ),
+		// input
+		.we ( rx_df_fifo_we_31 & phy_up[1] ),
+		.d_in ( rx_df_fifo_d_31 ),
+		// output
+		.re ( rx_sw_fifo_re_31 ),
+		.d_out( rx_sf_fifo_d_31 ),
+		.empty( rx_sf_fifo_empty_31 ),
+		.almost_full(  ),
+		.reset_ptrs( 1'b0 ),
+		// debug
+		.active( sync_rx3_active[1] )
+	);
+	
+fcs fcs_3(
+	.rstn( rstn ),
+	.clk( pcs_pclk ),
+	.init( fcs_init[3] ),
+	.enable( fcs_enable[3] ), 
+	.addr( fcs_addr3 ),
+	.din( fcs_din3 ),
+	.dout( fcs_dout3 )
+);
+
+/* 
+ * uCont i/f FIFO 
+ * FIFO side connects to network switch
+ * RX: processor writes (data into switch)
+ * TX: processor reads (data from switch)
+ */
+half_fifo  #(.DPRAM_DEPTH(9)) micro_fifo_0 (
+		.rstn(  rstn  ),
+		.uc_clk(clk_10),
+		.fifo_clk(pcs_pclk),
+		// UC interrupt support
+		.fifo_we_int ( micro_fifo_int ),
+		// TX mode
+		.tx_mode(tx_sw_modeu),
+		// DPRAM common
+		.dpram_addr( mem_addr[8:0] ),
+		.dpram_din( mem_d_i[8:0] ), 
+		.dpram_dout( micro_fifo_do ),
+		.dpram_we( mem_we ),
+		.dpram_oe( mem_oe ),
+		// UC select signals
+		.dpram_ptrs_sel( dpram_ptrs_sel ),
+		.dpram_rx_sel( dpram_rx_sel ),
+		.dpram_tx_sel( dpram_tx_sel ),
+		// FIFO TX (input)
+		.fifo_we( tx_sw_fifo_we ),
+		.fifo_d_in( tx_sw_fifo_du ),
+		// FIFO RX (output)
+		.fifo_re( rx_sw_fifo_re_u2 ),
+		.fifo_d_out( rx_uc_fifo_d_u2 ),
+		// FIFO flags
+		.rx_empty( rx_uc_fifo_empty_u2 ),
+		.tx_full ( tx_uc_block )
+	);
+
+/*
+ * Param RAM
+ */
+dpram param_ram_2(
+        .rstn(  rstn  ),
+        .a_clk( fb_clk ),
+        .a_clk_e( param_sel[2] ),
+        .a_we( mem_we ),
+        .a_oe( 1'b0 ),
+        .a_addr( mem_addr  ),
+        .a_din( mem_d_i[8:0] ),
+        .a_dout( ),
+        // port B
+        .b_clk(  pcs_pclk ),
+        .b_clk_e( param_phy2_ce  ),
+        .b_we( param_phy2_we ),
+        .b_oe( 1'b1  ),
+        .b_addr( param_phy2_addr ),
+        .b_din( param_phy2_dout ),
+        .b_dout( param_phy2_din )
+);
+ 
+/* 
+ * PCS block that encapsulates two DCUs and the SCI block 
+ */
+pcs pcs_0 (
+
+	.refclk0_refclkn(refclkp_d0), 
+	.refclk0_refclkp(refclkn_d0), 
+	.refclk0_refclko( refclko ),
+
+	// cross DCU tie offs
+	.sgmii0_cyawstn( 1'b0 ),
+
+	//DCU0 CH0 to PHY0
+    .sgmii0_hdinn(sgmii0_hdinn), 
+	.sgmii0_hdinp(sgmii0_hdinp), 
+	.sgmii0_hdoutn(sgmii0_hdoutn), 
+	.sgmii0_hdoutp(sgmii0_hdoutp), 
+	
+	// DCU resets
+	.sgmii0_tx_serdes_rst_c( tx_serdes_rst[0] ),			// rset LOL signal in PLL 
+	.sgmii0_rst_dual_c( pcs_rst_dual[0] ), 					// resets all serdes channels including aux and PCS
+	.sgmii0_serdes_rst_dual_c( serdes_rst_dual[0] ),		// resets serdes dual gated by fpga_reset_enable
+	
+	// channel resets
+	.sgmii0_rx_pcs_rst_c( rx_pcs_rst[0] ),			// reset channel PCS logic
+	.sgmii0_rx_serdes_rst_c( rx_serdes_rst[0] ),	// reset digital logic in serdes rx
+	.sgmii0_tx_pcs_rst_c( tx_pcs_rst[0] ),			// reset channel PCS logic
+	
+	.sgmii0_rx_pwrup_c(1'b1),			// channel power up
+	.sgmii0_tx_pwrup_c(1'b1), 			// channel power up
+	
+	/* tx_pclk: Transmit Primary Clock. Direct connection to Primary
+	 * clock network. When gearing is not enabled, this output
+	 * equals the transmit full rate clock. When 2:1 gearing
+	 * is enabled, it is a divide-by-2 half-rate clock.    
+	 */
+	.sgmii0_tx_pclk( pcs_pclk ),	// direct connection from primary clock network
+	.sgmii0_txi_clk( pcs_pclk ),	// clocks the TX UI FIFOS (see Figure 27)
+	
+    .sgmii0_tx_disp_correct(sgmii_tx_disp_correct[0]), 	
+    .sgmii0_tx_k(sgmii_tx_k[0]), 
+	.sgmii0_txdata( tx_data0 ), 
+	.sgmii0_xmit(1'b0), 						
+    .sgmii0_signal_detect_c(1'b1),	
+	.sgmii0_rx_cv_err( sgmii_rx_cv_err[0] ),	// code violation with associated data, PCS will drive 0xEE and K=1 (Table 9-4)
+    .sgmii0_rx_disp_err( sgmii_rx_disp_err[0] ), 
+	.sgmii0_rx_k( sgmii_rx_k[0] ), 
+	.sgmii0_rxdata( rx_data0 ), 
+    .sgmii0_lsm_status_s( sgmii_lsm_status[0] ), 	// lane is synced with commas ( 0 means no commas detected )  
+    .sgmii0_rx_cdr_lol_s( sgmii_rx_cdr_lol[0] ), 	// CDR Loss of lock
+	.sgmii0_rx_los_low_s( sgmii_rx_los_low[0] ),	// Loss of signal (LO THRESHOLD RANGE) detection    
+
+	.sgmii0_ctc_ins_s(), 			// skip char added by CTC
+	.sgmii0_ctc_orun_s(), 			// CTC FIFO over run error
+	.sgmii0_ctc_urun_s(),			// CTC FIFO under run error
+	.sgmii0_ctc_del_s(), 			// skip char deleted by CTC
+	.sgmii0_pll_lol( pll_lol[0] ),
+	
+	//DCU0 CH1 to PHY1
+	.sgmii1_hdinn( sgmii1_hdinn ), 
+	.sgmii1_hdinp( sgmii1_hdinp ), 
+	.sgmii1_hdoutn( sgmii1_hdoutn ),
+	.sgmii1_hdoutp( sgmii1_hdoutp ), 
+	
+	// DCU resets
+	.sgmii1_rst_dual_c( pcs_rst_dual[0] ),
+	.sgmii1_serdes_rst_dual_c( serdes_rst_dual[0] ),
+	.sgmii1_tx_serdes_rst_c( tx_serdes_rst[0] ),
+	
+	// Channel resets
+    .sgmii1_rx_pcs_rst_c( rx_pcs_rst[1] ),
+	.sgmii1_rx_serdes_rst_c( rx_serdes_rst[1] ),
+	.sgmii1_tx_pcs_rst_c( tx_pcs_rst[1] ),
+	
+	.sgmii1_rx_pwrup_c( 1'b1 ), 	
+	.sgmii1_tx_pwrup_c( 1'b1 ),
+ 	.sgmii1_serdes_pdb( 1'b1 ), 
+	
+    .sgmii1_tx_pclk( ), 
+    .sgmii1_txi_clk( pcs_pclk ),
+
+	.sgmii1_rx_cv_err( sgmii_rx_cv_err[1] ), 
+    .sgmii1_rx_disp_err( sgmii_rx_disp_err[1] ), 
+	.sgmii1_rx_k( sgmii_rx_k[1] ), 
+	.sgmii1_rxdata( rx_data1 ), 
+	.sgmii1_tx_disp_correct( sgmii_tx_disp_correct[1] ), 
+    .sgmii1_tx_k(  sgmii_tx_k[1] ), 
+	.sgmii1_txdata( tx_data1 ), 
+	.sgmii1_xmit( 1'b0 ), 			
+	
+	.sgmii1_signal_detect_c( 1'b1 ), 
+	
+	.sgmii1_ctc_del_s(), 
+	.sgmii1_ctc_ins_s(), 
+	.sgmii1_ctc_orun_s(),	
+    .sgmii1_ctc_urun_s(), 
+	
+	.sgmii1_lsm_status_s( sgmii_lsm_status[1] ), 
+	.sgmii1_rx_cdr_lol_s( sgmii_rx_cdr_lol[1] ), 
+	.sgmii1_rx_los_low_s( sgmii_rx_los_low[1] ),
+
+	// DCU1 CH0 to Expansion
+	.sgmii2_hdinn( sgmii2_hdinn ), 
+	.sgmii2_hdinp( sgmii2_hdinp ), 
+	.sgmii2_hdoutn( sgmii2_hdoutn ),
+	.sgmii2_hdoutp( sgmii2_hdoutp ), 
+	
+	// DCU Tie Offs
+	.sgmii2_cyawstn( 1'b0 ),
+	
+	// DCU resets
+	.sgmii2_rst_dual_c(  pcs_rst_dual[1] ),
+	.sgmii2_serdes_rst_dual_c( serdes_rst_dual[1] ),
+	.sgmii2_tx_serdes_rst_c( tx_serdes_rst[1] ),
+
+	// Channel resets
+	.sgmii2_rx_pcs_rst_c( rx_pcs_rst[2] ),
+	.sgmii2_rx_serdes_rst_c( rx_serdes_rst[2] ),
+	.sgmii2_tx_pcs_rst_c( tx_pcs_rst[2] ),
+	
+	.sgmii2_rx_pwrup_c( 1'b1 ), 	
+	.sgmii2_tx_pwrup_c( 1'b1 ),
+	.sgmii2_serdes_pdb( 1'b1 ), 
+	
+    .sgmii2_tx_pclk( ),
+    .sgmii2_txi_clk( pcs_pclk ),
+
+	.sgmii2_rx_cv_err( sgmii_rx_cv_err[2] ), 
+    .sgmii2_rx_disp_err( sgmii_rx_disp_err[2] ), 
+	.sgmii2_rx_k( sgmii_rx_k[2] ), 
+	.sgmii2_rxdata( rx_data2 ), 
+	.sgmii2_tx_disp_correct( sgmii_tx_disp_correct[2] ), 
+    .sgmii2_tx_k( sgmii_tx_k[2] ), 
+	.sgmii2_txdata( tx_data2 ), 
+	.sgmii2_xmit( 1'b0 ), 
+	
+	.sgmii2_signal_detect_c( 1'b1 ), 
+	
+	.sgmii2_ctc_del_s(), 
+	.sgmii2_ctc_ins_s(), 
+	.sgmii2_ctc_orun_s(),	
+    .sgmii2_ctc_urun_s(), 
+	
+	.sgmii2_lsm_status_s( sgmii_lsm_status[2] ), 
+	.sgmii2_rx_cdr_lol_s( sgmii_rx_cdr_lol[2] ), 
+	.sgmii2_rx_los_low_s( sgmii_rx_los_low[2] ),
+	
+	.sgmii2_pll_lol( pll_lol[1] ),
+	
+	// DCU1 CH1 to Expansion
+	.sgmii3_hdinn( sgmii3_hdinn ), 
+	.sgmii3_hdinp( sgmii3_hdinp ), 
+	.sgmii3_hdoutn( sgmii3_hdoutn ),
+	.sgmii3_hdoutp( sgmii3_hdoutp ),
+	
+	// DCU resets
+	.sgmii3_rst_dual_c( pcs_rst_dual[1] ),
+	.sgmii3_serdes_rst_dual_c( serdes_rst_dual[1] ),
+	.sgmii3_tx_serdes_rst_c( tx_serdes_rst[1] ),
+	
+	// Channel resets
+	.sgmii3_rx_pcs_rst_c( rx_pcs_rst[3] ),
+	.sgmii3_rx_serdes_rst_c( rx_serdes_rst[3] ),
+	.sgmii3_tx_pcs_rst_c( tx_pcs_rst[3] ),
+	
+	.sgmii3_rx_pwrup_c( 1'b1 ), 	
+	.sgmii3_tx_pwrup_c( 1'b1 ),
+	
+	.sgmii3_tx_pclk( ), 
+	.sgmii3_txi_clk( pcs_pclk ),
+
+	.sgmii3_rx_cv_err( sgmii_rx_cv_err[3] ), 
+	.sgmii3_rx_disp_err( sgmii_rx_disp_err[3] ), 
+	.sgmii3_rx_k( sgmii_rx_k[3] ), 
+	.sgmii3_rxdata( rx_data3 ), 
+	.sgmii3_tx_disp_correct( sgmii_tx_disp_correct[3] ), 
+	.sgmii3_tx_k(  sgmii_tx_k[3] ), 
+	.sgmii3_txdata( tx_data3 ), 
+	.sgmii3_xmit( 1'b0 ), 				
+	
+	.sgmii3_signal_detect_c( 1'b1 ), 
+	
+	.sgmii3_ctc_del_s(), 
+	.sgmii3_ctc_ins_s(), 
+	.sgmii3_ctc_orun_s(),	
+	.sgmii3_ctc_urun_s(), 
+	
+	.sgmii3_lsm_status_s( sgmii_lsm_status[3] ), 
+	.sgmii3_rx_cdr_lol_s( sgmii_rx_cdr_lol[3] ), 
+	.sgmii3_rx_los_low_s( sgmii_rx_los_low[3] ),
+
+	
+	// DCU0 SCI 
+	.sgmii0_sci_sel_dual( sci_sel_dual[0] ),
+	.sgmii0_sci_en_dual( 1'b1 ),
+	.sgmii0_sci_addr( mem_addr[5:0] ),		// SCI Register Address Bits
+	.sgmii0_sci_rddata( sci_rddata0 ),
+	.sgmii0_sci_wrdata( mem_d_i[7:0] ),
+	.sgmii0_sci_rd( ~fb_oen ),
+	.sgmii0_sci_wrn( fb_rwn ),
+
+	
+	.sgmii0_sci_sel( sci_sel_ch[0] ),
+	.sgmii0_sci_en( 1'b1 ),
+	
+	.sgmii1_sci_sel( sci_sel_ch[1] ),
+	.sgmii1_sci_en( 1'b1 ),
+	
+	.sgmii0_sci_int( sci_int[1] ),
+	
+	// DCU1 SCI
+	.sgmii2_sci_sel_dual( sci_sel_dual[1] ),
+	.sgmii2_sci_en_dual( 1'b1 ),	
+	.sgmii2_sci_addr( mem_addr[5:0] ),		// SCI Register Address Bits
+	.sgmii2_sci_rddata( sci_rddata1 ),
+	.sgmii2_sci_wrdata( mem_d_i[7:0] ),
+	.sgmii2_sci_rd( ~fb_oen ),
+	.sgmii2_sci_wrn( fb_rwn ),
+	
+	.sgmii2_sci_sel( sci_sel_ch[2] ),
+	.sgmii2_sci_en( 1'b1 ),
+
+	.sgmii2_sci_int( sci_int[0] ),
+	
+	.sgmii3_sci_sel( sci_sel_ch[3] )
+	
+);
+
+
+
+mdio_controller #(.ADDR_SZ( MDIO_ROM_ADDR_SZ )) mdio_controller_0
+(
+	.rstn(rstn),
+	.clk(clk_10),
+	.work_start(mdio_cont_work_start),
+	.work_run(mdio_cont_work_run),
+	.work_done(mdio_cont_work_done),
+	.routine_addr( mdio_routine_addr ),
+	.buffer_full(1'b0),
+	.addr(rom_a),
+	.di(rom_d),
+	.reg_addr(mdio_reg_addr),		
+	.dout(mdio_wd),
+	.ld(mdio_ld),
+	.rwn(mdio_rwn),
+	.done(mdio_done)
+);
+	
+mdio_data_ti  #(.ADDR_SZ( MDIO_ROM_ADDR_SZ )) mdio_data_ti_0(
+	.ad( rom_a ),
+	.page( mdio_page_set ),
+	.reg_addr( mdio_reg_addr_set ),
+	.data_in_h( mdio_w_data_h_set ),
+	.data_in_l( mdio_w_data_l_set ),
+	.d( rom_d ),
+	.oe( 1'b1 )
+);
+
+
+/* MDIO mux and output enables */
+always @(*) begin
+	case (mdio_mux_sel)
+		2'b00: mdi = phy0_mdio;
+		2'b01: mdi = phy1_mdio;
+		2'b10: mdi = phy2_mdio;
+		2'b11: mdi = 1'b1;  
+	endcase
+end
+
+assign phy0_mdio = (mdo_oe & ~mdio_mux_sel[1] & ~mdio_mux_sel[0]) ? mdo : 1'bz;
+assign phy1_mdio = (mdo_oe & ~mdio_mux_sel[1] & mdio_mux_sel[0]) ? mdo : 1'bz;
+assign phy2_mdio = (mdo_oe & mdio_mux_sel[1] & ~mdio_mux_sel[0]) ? mdo : 1'bz;
+	
+mdio mdio_0(
+	.rstn(rstn),
+	.mdc(clk_10),
+	// MDIO
+	.mdi(mdi),
+	.mdo(mdo),
+	.mdo_oe(mdo_oe),
+	// mdio controller interface
+	.rwn(mdio_rwn),
+	.phy_addr(5'h00),
+	.reg_addr(mdio_reg_addr),
+	.di(mdio_wd),
+	.ld(mdio_ld),
+	.run( mdio_run ),
+	.done(mdio_done),       // signal controller that mdio xfer is done
+	// output port to converter
+	.dout(mdio_rd),
+	.we( mdio_rd_we )
+);
+
+
+spi spi_0 (
+	.rstn(rstn),
+	.clk(clk_10),
+	// spi signals
+	.spi_cs( fpga_spics ),
+	.spi_clk( fpga_mclk ),
+	.spi_d_in( fpga_mosi),
+	.spi_d_o( spi_do ),
+	.spi_d_oe(spi_do_e ),
+	// internal FPGA memory 
+	.mem_addr( mem_addr ),
+	.mux_sel ( mem_do_mux_sel ),
+	.d_i( mem_d_o ),
+	.d_o( mem_d_i ),
+	// individual memory selects
+	.we( mem_we ),
+	.oe( mem_oe ),
+	.dpram_tx_sel( dpram_tx_sel ),
+	.dpram_rx_sel( dpram_rx_sel ),
+	.dpram_ptrs_sel( dpram_ptrs_sel ),
+	.param_sel( param_sel ),
+	.pkt_filter_sel_01( pkt_filter_sel_01 ),
+	.pkt_filter_sel_02( pkt_filter_sel_02 ),
+	.pkt_filter_sel_03( pkt_filter_sel_03 ),
+	.pkt_filter_sel_10( pkt_filter_sel_10 ),
+	.pkt_filter_sel_12( pkt_filter_sel_12 ),
+	.pkt_filter_sel_13( pkt_filter_sel_13 ),
+	.pkt_filter_sel_20( pkt_filter_sel_20 ),
+	.pkt_filter_sel_21( pkt_filter_sel_21 ),
+	.pkt_filter_sel_23( pkt_filter_sel_23 ),
+	.pkt_filter_sel_2u( pkt_filter_sel_2u ),
+	.pkt_filter_sel_30( pkt_filter_sel_30 ),
+	.pkt_filter_sel_31( pkt_filter_sel_31 ),
+	.pkt_filter_sel_32( pkt_filter_sel_32 ),
+	.pkt_filter_sel_u2( pkt_filter_sel_u2 ),
+	.interrupts_sel( int_sel ),
+	.sci_sel_dual( sci_sel_dual ),
+	.sci_sel_ch( sci_sel_ch )
+);
+
+assign fpga_miso = spi_do_e ? spi_do : 1'bz;
+
+/* data mux out of internal memories */
+always@(*)
+begin
+	case(mem_do_mux_sel)
+		5'b00000:	mem_d_o = { 2'b0, sci_rddata1 };
+		5'b00001:	mem_d_o = { 2'b0, sci_rddata0 };
+		5'b00010:	mem_d_o = { 1'b0, micro_fifo_do };
+		5'b00011:	mem_d_o = { 1'b0, micro_fifo_do };
+		5'b00100:	mem_d_o = { 1'b0, micro_fifo_do };
+		5'b10000:   mem_d_o = { 2'b0, int_do };
+		default: mem_d_o = 9'h0;
+	endcase
+end
+
+interrupts interrupts_0(
+	.rstn( rstn ),	
+	.clk( pcs_pclk ),
+	.uc_clk( clk_10 ),
+	// uC interface
+	.sel( int_sel ),
+	.we( mem_we ),
+	.addr( mem_addr[0] ),
+	.d_in( mem_d_i[6:0] ),
+	.d_out( int_do ),
+	// interrupt sources
+	.cont_int( micro_fifo_int ),
+	.phy_int ( { 2'b0, phy1_intn, phy0_intn }),
+	.mac_int ( { mac_int[3], mac_int[2], mac_int[1], mac_int[0] } ),
+	.int_o( fpga_int )
+);
+
+
+assign i2c_sda = sda_oe ? sda_o : 1'bz;
+assign i2c_scl = scl_oe ? scl_o : 1'bz;
+
+i2c i2c_0(
+	.rstn( rstn ),
+	.clk( clk_10 ),
+	// external I2C I/O
+	.scl_i( i2c_scl ),
+	.scl_o( scl_o ),
+	.scl_oe( scl_oe ),
+	.sda_i( i2c_sda ),
+	.sda_o( sda_o ),
+	.sda_oe( sda_oe ),
+	// shared memory and controller data output
+	.mem_do( i2c_d_o ),
+	// dedicated memory interface
+	.mem_ad(  ),
+	.mem_we(  ),
+	.mem_ce( ),
+	.mem_di( 8'haa ),
+	// dedicated controller write interface
+	.cont_we( i2c_cont_we ),
+	.cont_done( i2c_cont_done ),
+	// Controller->FIFO input interface
+	.fifo_re( i2c_fifo_re ),
+	.tx_fifo_empty(  cont_fifo_empty ),
+	.fifo_di( fifo_r_d[6:0] )
+);
+
+
+/* 
+*	ext_sys_fifo delays and enables:
+*	we need the re delay since we need to generate a re pulse from the  
+*	we need the mdio_we delay since the fifo is clocked twice: high and low data
+*
+*/
+always@ ( posedge clk_10 or negedge rstn )
+	begin
+		if ( !rstn )
+			begin
+				cont_fifo_re_m1 <= 1'b0;
+				cont_fifo_re_m2 <= 1'b0;
+			end
+		else
+			begin
+				cont_fifo_re_m1 <= i2c_fifo_re;
+				cont_fifo_re_m2 <= cont_fifo_re_m1;
+			end
+	end
+
+// create a single re pulse since i2c runs slow.
+assign i_cont_fifo_re = cont_fifo_re_m1 & ~cont_fifo_re_m2;
+
+assign bin_to_ascii_we = mdio_rd_we | cont_rd_we;
+assign bin_to_ascii_d_in = read_fifo_mux_sel ? mdio_rd : cont_rd;
+
+/* 
+ * Input: MDIO writes
+ * Output: I2C read FIFO
+ */
+bin_to_ascii bin_to_ascii_0(
+	.rstn( rstn ),
+	.clk( clk_10 ),
+	.width ( 1'b1 ),
+	// mdio interface
+	.we_i ( bin_to_ascii_we ),
+	.d_in( bin_to_ascii_d_in ),
+	// mdio controller interface
+	.run ( bin_to_ascii_run ),
+	.done (),
+	.busy( 1'b0 ),
+	// fifo port
+	.we_o ( read_fifo_we ),
+	.d_out( read_fifo_d_i )
+);
+
+/*
+ * Input: bin_to_ascii
+ * Output: I2C read
+ */
+sync_fifo ext_sys_fifo_0(
+	.rstn( rstn ),
+	.clk ( clk_10 ),
+	// input
+	.we ( read_fifo_we ),
+	.d_in ( { 2'b0, read_fifo_d_i } ),
+	// output
+	.re ( i_cont_fifo_re ),
+	.d_out( fifo_r_d ),
+	.empty( cont_fifo_empty ),
+	.almost_full(  ),
+	.reset_ptrs( 1'b0 ),
+	// debug
+	.active( )
+);
+
+
+/* JTAG Enable for 2-bit external buffer */
+assign fpga_jtag_e =1'bz;
+
+
+/* LED Assignment */
+assign led[0] = 1'b1;
+assign led[1] = phy_up[0];
+assign led[2] = phy_up[1];
+
+
+/* Debug: rx_active and tx_active 
+ * Intention is to use these as sample enables in Reveal or
+ * external triggering 
+ */
+always @(posedge pcs_pclk or negedge rstn) 
+	if ( !rstn )
+		rx_active[2] <= 1'b0;
+	else if (mac_rx_active[2] || drop_rx2_active[0] || sync_rx2_active[0]  )
+		rx_active[2] <= 1'b1;
+	else
+		rx_active[2] <= 1'b0;
+	
+always @(posedge pcs_pclk or negedge rstn) 
+	if ( !rstn )
+		tx_active[0] <= 1'b0;
+	else if (mac_tx_active[0])
+		tx_active[0] <= 1'b1;
+	else
+		tx_active[0] <= 1'b0;
+	
+assign sample_enable = rx_active[2] | tx_active[0];
+
+	
+/* Debug and Arduino Expansion, see definitions.v */
+`ifdef DEBUG_SPI
+	assign ard_scl = fpga_mclk;
+	assign ard_sda = fpga_spics;
+	assign ard_rxd1 = spi_do_e ? spi_do : 1'bz;
+	assign ard_txd1 = fpga_mosi;
+`elsif DEBUG_MDIO
+	assign ard_scl = phy_mdc;
+	assign ard_sda = phy0_mdio;
+	assign ard_rxd1 = 1'bz;
+	assign ard_txd1 = refclko;
+`elsif DEBUG_IC2
+	assign ard_scl = i2c_scl;
+	assign ard_sda = sda_oe ? sda_o : i2c_sda;
+	assign ard_rxd1 = 1'bz;
+	assign ard_txd1 = sda_oe;
+`else 
+	assign ard_scl = fpga_int;
+	assign ard_sda = 1'bz;
+	assign ard_rxd1 = 1'bz;
+	assign ard_txd1 = 1'bz;
+`endif
+
+`ifdef ARD_EXP_UART
+	assign ard_txd2 = uart_txd;
+	assign uart_rxd = ard_rxd2;
+`else
+	assign ftdi_tdi_rxd = uart_txd;
+	assign uart_rxd = ftdi_tck_txd;	
+`endif
+
+	assign  pe0  = 1'bz;
+	assign  pe1  = 1'bz;
+	assign  pe3  = 1'bz;
+	assign  pe4  = 1'bz;
+	assign  pe5  = 1'bz;
+	assign  pg5  = 1'bz;
+	assign  ph3  = 1'bz;
+	assign  ph4  = 1'bz;
+	
+endmodule
-- 
cgit v1.2.3-8-gadcc