summaryrefslogtreecommitdiffhomepage
path: root/source
diff options
context:
space:
mode:
authormindchasers <privateisland@mindchasers.com>2019-05-01 18:16:45 -0400
committermindchasers <privateisland@mindchasers.com>2019-05-01 18:16:45 -0400
commit5723ec1a34181f1cfef9b8e870ab2e9a0362487c (patch)
tree0dc958d5b1931934ded5d0302b2b5fedab081d2c /source
initial commit, all basic functions work on Darsena V02
Diffstat (limited to 'source')
-rw-r--r--source/bin_to_ascii.v128
-rw-r--r--source/cam.v85
-rw-r--r--source/clk_gen.v67
-rw-r--r--source/controller.v474
-rw-r--r--source/definitions.v28
-rw-r--r--source/dpram.v102
-rw-r--r--source/drop2_fifo.v255
-rw-r--r--source/drop_fifo.v220
-rw-r--r--source/ethernet_params.v38
-rw-r--r--source/fcs.v142
-rw-r--r--source/half_fifo.v194
-rw-r--r--source/i2c.v391
-rw-r--r--source/interrupts.v77
-rw-r--r--source/ipv4.v152
-rw-r--r--source/mac.v895
-rw-r--r--source/mdio.v146
-rw-r--r--source/mdio_cont.v159
-rw-r--r--source/mdio_data_ti.v128
-rw-r--r--source/metrics.v102
-rw-r--r--source/pcs.v228
-rw-r--r--source/pkt_filter.v93
-rw-r--r--source/sgmii_params.v50
-rw-r--r--source/spi.v300
-rw-r--r--source/switch.v480
-rw-r--r--source/sync2_fifo.v141
-rw-r--r--source/sync4_fifo.v206
-rw-r--r--source/sync_fifo.v110
-rw-r--r--source/top.v2177
28 files changed, 7568 insertions, 0 deletions
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