summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/an.v122
-rw-r--r--src/bin_to_ascii.v128
-rw-r--r--src/cam.v48
-rw-r--r--src/clk_gen.v67
-rw-r--r--src/cont_params.v61
-rw-r--r--src/controller.v136
-rw-r--r--src/directives.v34
-rw-r--r--src/dpram.v102
-rw-r--r--src/dpram_inf.v84
-rw-r--r--src/drop_fifo.v328
-rw-r--r--src/ethernet_params.v36
-rw-r--r--src/fcs.v155
-rw-r--r--src/half_fifo.v299
-rw-r--r--src/i2c.v391
-rw-r--r--src/interrupts.v77
-rw-r--r--src/ipv4_rx.v (renamed from src/ipv4.v)75
-rw-r--r--src/ipv4_rx_c.v134
-rw-r--r--src/ipv4_tx_c.v179
-rw-r--r--src/ipv4_tx_mle.v175
-rw-r--r--src/link_timer.v67
-rw-r--r--src/mac.v973
-rw-r--r--src/mac_rgmii.v998
-rw-r--r--src/mdio.v5
-rw-r--r--src/mdio_cont.v93
-rw-r--r--src/mdio_data_ti.v181
-rw-r--r--src/metrics.v102
-rw-r--r--src/ml_engine.v563
-rw-r--r--src/pkt_filter.v106
-rw-r--r--src/rgmii_params.v46
-rw-r--r--src/sgmii_params.v55
-rw-r--r--src/spi.v315
-rw-r--r--src/switch.v656
-rw-r--r--src/sync_fifo.v13
-rw-r--r--src/udp_rx.v117
-rw-r--r--src/udp_rx_c.v89
35 files changed, 3552 insertions, 3458 deletions
diff --git a/src/an.v b/src/an.v
deleted file mode 100644
index 18b5d95..0000000
--- a/src/an.v
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * an.v
- *
- * Copyright 2021 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: Auto Negotiation
- *
- * Notes: a simplified version of AN suitable for SGMII only (not 1000BASE-SX)
- */
-
-`timescale 1ns /10ps
-
-module an(
- input rstn,
- input phy_resetn, // The external PHY has its reset signal asserted
- input clk,
-
- // AN
- input [1:0] phy_type, // SGMII==0, SX=1, SMA=3
- input pulse_1_6ms, // SGMII
- input pulse_10ms, // SX
- input [1:0] fixed_speed,
- input an_disable,
- output reg an_duplex,
- output reg [1:0] an_speed,
- output reg an_link_up,
- output reg [15:0] tx_config_reg,
- output reg phy_up,
-
- input rx_k_m1,
- input rx_k_m2,
- input rx_k_m3,
- input rx_k_m4,
-
- input [7:0] rx_data_m1,
- input [7:0] rx_data_m2,
- input [7:0] rx_data_m3,
- input [7:0] rx_data_m4
-
- // Debug
-);
-
-`include "sgmii_params.v"
-`include "ethernet_params.v"
-
-localparam PHY_TYPE_SGMII = 2'b00,
- PHY_TYPE_SX = 2'b01,
- PHY_TYPE_RSVD = 2'b10,
- PHY_TYPE_SMA = 2'b11;
-
-
-localparam AN_TYPE_SX = 1'b0,
- AN_TYPE_SGMII = 1'b1;
-
-localparam AN_ST_DISABLE=4'h0, AN_ST_ENABLE=4'h1, AN_ST_RESTART=4'h2,
- AN_ST_ABILITY_DETECT=4'h3, AN_ST_ACK_DETECT=4'h4,
- AN_ST_COMPLETE_ACK=4'h5, AN_ST_IDLE_DETECT=4'h6, AN_ST_LINK_OK=4'h7;
-
-// AN
-reg [2:0] an_state;
-wire an_ability_detect;
-wire an_link_timer_pulse;
-reg rx_config_detect;
-reg [15:0] rx_config_reg, tx_config_reg;
-reg [1:0] rx_config_cnt; // use to count consecutive rx config_regs
-
-/*
- * SGMII Auto Negotiation State Machine
- * Look for configuration /C/ ordered set
- * /C/ is Alternating /C1/ and /C2/
- * /C1/: /K28.5/D21.5(0xb5)/Config_Reg
- * /C2/: /K28.5/D2.2(0x42)/Config_Reg
- * Config Reg: Low High
- */
-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;
-
-
-assign an_ability_detect = (rx_config_cnt == 2'd3 && rx_config_reg != 16'h0000 );
-assign link_timer_pulse = (phy_type == PHY_TYPE_SGMII && pulse_1_6ms) || (phy_type == PHY_TYPE_SX && pulse_10ms);
-
-endmodule
diff --git a/src/bin_to_ascii.v b/src/bin_to_ascii.v
deleted file mode 100644
index 12464dc..0000000
--- a/src/bin_to_ascii.v
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * 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/src/cam.v b/src/cam.v
index 082194a..5fefb81 100644
--- a/src/cam.v
+++ b/src/cam.v
@@ -1,7 +1,8 @@
/*
* cam.v
*
- * Copyright (C) 2018, 2019 Mind Chasers Inc.
+ * Copyright (C) 2025 Private Island Networks Inc.
+ * Copyright (C) 2018-2022 Mind Chasers Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,66 +19,55 @@
* function: single cycle, parameterized CAM
*
*/
-
-`timescale 1ns /10ps
-module cam #(parameter DEPTH = 4,
- parameter DEPTHW = 2,
- parameter WIDTH = 32)
+module cam #(parameter DEPTH = 8, DATAW = 32)
(
input rstn,
input clk,
// input for programming
+ input prgclk,
input sel,
input we,
- input [DEPTHW+1:0] addr, // add two bits for the byte selects
- input [7:0] d_in,
+ input [$clog2(DEPTH)-1:0] addr, // include two lsbits for the byte selects
+ input [DATAW-1:0] d_i,
+ output [DATAW-1:0] d_o,
input search,
- input [(WIDTH-1):0]search_address,
+ input [DATAW-1:0] search_address,
// output
output reg match
);
+
- reg [(WIDTH-1):0] content[0:DEPTH-1];
- reg [(DEPTH-1):0] valid;
+ reg [DATAW-1:0] content[0:DEPTH-1];
+ reg valid[0:DEPTH-1];
integer i,j;
// Program the CAM
- always @(posedge clk, negedge rstn)
+ always @(posedge prgclk, negedge rstn)
if( !rstn ) begin
for (i=0; i < DEPTH; i=i+1) begin
- content[i] <= 32'h0;
+ content[i] <= 'd0;
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;
+ begin
+ content[addr] <= d_i;
+ valid[addr] <= 1'b1;
end
+ assign d_o = valid[addr] ? content[addr] : 'd0;
+
+
// 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
diff --git a/src/clk_gen.v b/src/clk_gen.v
deleted file mode 100644
index 9d3e054..0000000
--- a/src/clk_gen.v
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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/src/cont_params.v b/src/cont_params.v
new file mode 100644
index 0000000..cbdddcc
--- /dev/null
+++ b/src/cont_params.v
@@ -0,0 +1,61 @@
+/*
+ * cont_params.v
+ *
+ * Copyright (C) 2024-2025 Private Island Networks Inc.
+ * Copyright (C) 2018-2023 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: Controller related parameters
+ *
+ */
+
+
+`ifdef INCLUDED
+
+/* Message Protocol:
+ * Type: 8-bit (rx_cnt==4)
+ * Token: 8-bit (rx_cnt==5)
+ * Address: 16-bit (rx_cnt==6,7)
+ * Data: 32-bit (rx_cnt==8,9,10,11)
+ */
+
+localparam MSG_SZ = 8'h8;
+
+// Message Types (16-bit address)
+localparam MSG_TYPE_NULL = 8'h0;
+localparam MSG_TYPE_WRITE = 8'h1;
+localparam MSG_TYPE_READ = 8'h2;
+localparam MSG_TYPE_REPLY_SUCCESS = 8'h3;
+localparam MSG_TYPE_REPLY_ERROR = 8'h4;
+localparam MSG_TYPE_NOTIY = 8'h5;
+
+
+localparam MSG_CONTROLLER_ADDR = 16'h0000;
+localparam MSG_MAC_ADDR = 16'h0100;
+localparam MSG_PKT_FILTER_ADDR = 16'h0200;
+localparam MSG_SWITCH_ADDR = 16'h0500;
+localparam MSG_MDIO_ADDR = 16'h0600;
+localparam MSG_MLE_ADDR = 16'h0700;
+localparam MSG_INVALID_ADDR = 16'h0800;
+
+
+localparam HF_TX_WR_PTR_ADDR = 16'd0;
+localparam HF_TX_RD_PTR_ADDR = 16'd1; // read only
+localparam HF_TX_BYTE_CNT_ADDR = 16'd1; // write only
+localparam HF_RX_WR_PTR_LTCH_ADDR = 16'd2;
+localparam HF_NULL = 16'd3;
+localparam HF_RESET_PTRS = 16'd4;
+
+
+`endif
diff --git a/src/controller.v b/src/controller.v
index 54d6976..e30d461 100644
--- a/src/controller.v
+++ b/src/controller.v
@@ -1,5 +1,5 @@
/*
- * controller.v
+ * controller.v
*
* Copyright (C) 2023-2025 Private Island Networks Inc.
* Copyright (C) 2018-2022 Mind Chasers Inc.
@@ -18,8 +18,7 @@
*
* function: FPGA internal state machine controller
*
- * see https://privateisland.tech/dev/pi-doc for further details
- *
+ * see https://privateisland.tech/dev/pi-controller for further details
*
*/
@@ -35,18 +34,20 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
// link status
input [NUM_PHYS-1:0] phy_up,
- // Memory Controller bus
+ // Memory Controller I/F
output reg mem_we,
output mem_oe,
output reg [15:0] mem_addr,
output reg[31:0] mem_d_o,
input [31:0] mem_d_i,
+ input mem_tgt_ready,
// Device selects for Controller peripherals
output reg [1:0] mac_addr,
output reg [15:0] pkt_filter_addr,
output reg pkt_filter_sel,
output reg mac_sel,
+ output reg mle_sel,
output reg hf_ptrs_sel,
output reg hf_tx_sel,
output reg hf_rx_sel,
@@ -88,7 +89,7 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
// Version: upper byte is major, lower byte is minor
localparam FW_VERSION_VALUE = 16'h0001;
// Version Increment: Set to 0 when releasing version; otherwise, increment value for each preliminary / trial release
- localparam FW_INCREMENT_VALUE = 16'h0002;
+ localparam FW_INCREMENT_VALUE = 16'h0007;
// Main Controller states
localparam CONT_ST_INIT= 3'h0, CONT_ST_IDLE=3'h1, CONT_ST_START=3'h2, CONT_ST_BUSY=3'h3,
@@ -108,13 +109,14 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
localparam MEM_EVENT_NONE=3'h0, MEM_EVENT_FIFO=3'h1;
// Controller Address Space
- localparam FW_VERSION_ADDR = 16'h0000;
- localparam FW_INCREMENT_ADDR = 16'h0004;
- localparam MAC_ADDR = 16'h0010;
- localparam PHY_ADDR = 16'h0014; // Controls mdio_mux_sel, not the MIDO PHY Address
- localparam PKT_FILT_ADDR = 16'h0018;
- localparam RX_MSG_CNT_ADDR = 16'h0020;
- localparam TX_PKT_CNT_ADDR = 16'h0024;
+ localparam
+ FW_VERSION_ADDR = 16'h0000,
+ FW_INCREMENT_ADDR = 16'h0004,
+ MAC_ADDR = 16'h0010,
+ PHY_ADDR = 16'h0014, // Controls mdio_mux_sel, not the MIDO PHY Address
+ PKT_FILT_ADDR = 16'h0018,
+ RX_MSG_CNT_ADDR = 16'h0020,
+ TX_PKT_CNT_ADDR = 16'h0024;
/* Define Variables and Nets Below */
reg [2:0] cont_state;
@@ -137,7 +139,7 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
// Command Processing
reg rx_msg_captured;
- reg mdio_cmd, cont_msg;
+ reg mdio_cmd, mem_cmd, cont_msg;
reg [15:0] mdio_d;
// MDIO Init
@@ -150,10 +152,11 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
reg [10:0] tx_wr_ptr; // write into the HFIFO TX data
reg rx_rd_active, tx_wr_active;
reg [4:0] rx_cnt, tx_cnt;
+ reg mem_tgt_ready_m1, mem_tgt_ready_m2;
// metrics
reg [15:0] rx_msg_cnt;
- reg [15:0] tx_pkt_cnt;
+ reg [15:0] tx_msg_cnt;
// Synchronize rx_fifo_int
@@ -166,7 +169,18 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
rx_fifo_int_m1 <= rx_fifo_int;
rx_fifo_int_m2 <= rx_fifo_int_m1;
end
-
+
+ // Synchronize mem_tgt_ready
+ always @(posedge clk, negedge rstn)
+ if (!rstn) begin
+ mem_tgt_ready_m1 <= 1'b0;
+ mem_tgt_ready_m2 <= 1'b0;
+ end
+ else begin
+ mem_tgt_ready_m1 <= mem_tgt_ready;
+ mem_tgt_ready_m2 <= mem_tgt_ready_m1;
+ end
+
// rx_msg_captured signals a message has been received
always @(posedge clk or negedge rstn)
if (!rstn)
@@ -178,7 +192,6 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
// rx_msg_cnt
- // TODO: reset counter by writing the register
always @(posedge clk or negedge rstn)
if (!rstn)
rx_msg_cnt <= 16'd0;
@@ -203,6 +216,8 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
CONT_ST_BUSY:
if (cont_msg || msg_error)
cont_state <= CONT_ST_DONE;
+ else if (mem_cmd && mem_tgt_ready_m2)
+ cont_state <= CONT_ST_DONE;
else if (mdio_cmd && mdio_cont_done)
cont_state <= CONT_ST_DONE;
CONT_ST_DONE:
@@ -217,7 +232,7 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
cont_msg <= 1'b0;
else if (cont_state == CONT_ST_IDLE && !rx_msg_captured)
cont_msg <= 1'b0;
- else if (rx_msg_captured && (msg_addr[15:8] < MSG_MDIO_ADDR[15:8]))
+ else if (rx_msg_captured && (msg_addr[15:8] == MSG_CONTROLLER_ADDR[15:8]))
cont_msg <= 1'b1;
/***********************************************************************
@@ -293,7 +308,7 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
else if (mem_state == MEM_ST_RD_FIFO && rx_cnt == 5'h9 && !msg_addr_valid)
msg_error <= 1'b1;
- // msg data on writes
+ // msg data
always @(posedge clk or negedge rstn)
if (!rstn)
msg_data <= 32'd0;
@@ -309,7 +324,6 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
msg_data[7:0] <= mem_d_i[7:0];
// msg_response
- // TODO: add other peripherals
always @(posedge clk, negedge rstn)
if (!rstn)
msg_response <= 16'heeee;
@@ -317,20 +331,25 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
msg_response <= 16'heeee;
else if (mem_state == MEM_ST_RD_FIFO_DONE && cont_state == CONT_ST_DONE)
casez (msg_addr)
- FW_VERSION_ADDR : msg_response <= FW_VERSION_VALUE;
+ FW_VERSION_ADDR : msg_response <= FW_VERSION_VALUE;
FW_INCREMENT_ADDR : msg_response <= FW_INCREMENT_VALUE;
MAC_ADDR: msg_response <= mac_addr;
PHY_ADDR: msg_response <= mdio_mux_sel;
PKT_FILT_ADDR: msg_response <= pkt_filter_addr;
- RX_MSG_CNT_ADDR : msg_response <= rx_msg_cnt;
- TX_PKT_CNT_ADDR : msg_response <= tx_pkt_cnt;
- {MSG_MDIO_ADDR[15:8],8'h??}: msg_response <= mdio_d;
+ RX_MSG_CNT_ADDR : msg_response <= rx_msg_cnt;
+ TX_PKT_CNT_ADDR : msg_response <= tx_msg_cnt;
+ {MSG_MAC_ADDR[15:8],8'h??}: msg_response <= mem_d_i;
+ {MSG_MDIO_ADDR[15:8],8'h??}: msg_response <= mdio_d;
+ {MSG_MLE_ADDR[15:8],8'h??}: msg_response <= mem_d_i;
default: msg_response <= mem_d_i[15:0];
endcase
- /*
- * MDIO controller related
- */
+
+/***********************************************************************
+ *
+ * MDIO controller related
+ *
+ **********************************************************************/
// mdio_cmd address decode
always @(posedge clk or negedge rstn)
@@ -368,7 +387,7 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
end
// set mdio_phy_addr
- assign mdio_phy_addr = 5'h0c; // Set phy_addr[3:2]
+ assign mdio_phy_addr = 5'h00; // Set phy_addr[3:2]
// set mdio_reg_addr
always @(posedge clk or negedge rstn)
@@ -383,20 +402,18 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
/* set mdio_w_data_l and mdio_w_data_h */
always @(posedge clk or negedge rstn)
- begin
- if (!rstn) begin
- mdio_w_data_l <= 'd0;
- mdio_w_data_h <= 'd0;
- end
- else if (mi_state > MI_ST_INIT && mi_state < MI_ST_IDLE) begin
- mdio_w_data_h <= mdio_init_w_data_h;
- mdio_w_data_l <= mdio_init_w_data_l;
- end
- else if (mdio_cmd && msg_type == MSG_TYPE_WRITE) begin
- mdio_w_data_h <= msg_data[15:8];
- mdio_w_data_l <= msg_data[7:0];
- end
- end
+ if (!rstn) begin
+ mdio_w_data_l <= 'd0;
+ mdio_w_data_h <= 'd0;
+ end
+ else if (mi_state > MI_ST_INIT && mi_state < MI_ST_IDLE) begin
+ mdio_w_data_h <= mdio_init_w_data_h;
+ mdio_w_data_l <= mdio_init_w_data_l;
+ end
+ else if (mdio_cmd && msg_type == MSG_TYPE_WRITE) begin
+ mdio_w_data_h <= msg_data[15:8];
+ mdio_w_data_l <= msg_data[7:0];
+ end
// mdio_d, data from MDIO read cycle
always @(posedge clk or negedge rstn)
@@ -410,27 +427,21 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
// PHY Reset
always @(posedge clk, negedge rstn)
if (!rstn)
- phy_resetn <= 2'b00;
- else if (1'b0)
- phy_resetn <= 2'b00; // assert reset
+ phy_resetn <= 3'b000;
else
- phy_resetn <= 2'b11;
+ phy_resetn = 3'b111;
// MAC Reset
always @(posedge clk, negedge rstn)
if (!rstn)
- mac_reset <= 2'b11;
- else if (1'b0)
- mac_reset <= 2'b11; // assert reset
+ mac_reset <= 3'b111;
else
- mac_reset <= 2'b00;
+ mac_reset = 3'b000;
/***********************************************************************
*
* Memory Controller and HFIFO Access LAN Controller
*
- * TODO: Review and implement better LAN flow control
- *
**********************************************************************/
// Memory Controller Tie Offs
@@ -468,7 +479,15 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
MEM_ST_DONE: mem_state <= MEM_ST_IDLE; // update tx_wr_ptr
default: mem_state <= MEM_ST_IDLE;
endcase
-
+
+ // mem_cmd address decode
+ always @(posedge clk or negedge rstn)
+ if (!rstn)
+ mem_cmd <= 1'b0;
+ else if (cont_state == CONT_ST_IDLE && !rx_msg_captured)
+ mem_cmd <= 1'b0;
+ else if (rx_msg_captured && msg_addr[15:8] >= MSG_MAC_ADDR[15:8] && msg_addr[15:8] < MSG_MLE_ADDR[15:8])
+ mem_cmd <= 1'b1;
// Primary Memory Controller Actions
always @(posedge clk, negedge rstn)
@@ -477,6 +496,7 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
mem_d_o <= 32'd0;
mem_addr <= HF_NULL;
mac_sel <= 1'b0;
+ mle_sel <= 1'b0;
pkt_filter_sel <= 1'b0;
hf_ptrs_sel <= 1'b0;
hf_tx_sel <= 1'b0;
@@ -513,6 +533,7 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
case (msg_addr[15:8])
MSG_MAC_ADDR[15:8]: mac_sel <= 1'b1;
MSG_PKT_FILTER_ADDR[15:8]: pkt_filter_sel <= 1'b1;
+ MSG_MLE_ADDR[15:8]: mle_sel <= 1'b1;
endcase
end
end
@@ -520,6 +541,9 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
hf_tx_sel <= 1'b0;
hf_rx_sel <= 1'b0;
mem_we <= 1'b0;
+ mac_sel <= 1'b0;
+ mle_sel <= 1'b0;
+ pkt_filter_sel <= 1'b0;
end
else if (mem_state == MEM_ST_REPLY_START && tx_fifo_empty) begin // write byte cnt
hf_ptrs_sel <= 1'b1;
@@ -579,8 +603,6 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
mem_we <= 1'b0;
mem_d_o <= 32'd0;
mem_addr <= HF_NULL;
- mac_sel <= 1'b0;
- pkt_filter_sel <= 1'b0;
hf_ptrs_sel <= 1'b0;
hf_tx_sel <= 1'b0;
hf_rx_sel <= 1'b0;
@@ -606,11 +628,9 @@ module controller #(parameter MDIO_ADDR_SZ = 7, parameter NUM_PHYS=3)
always @(posedge clk, negedge rstn)
if (!rstn)
- tx_pkt_cnt <= 16'd0;
+ tx_msg_cnt <= 16'd0;
else if (mem_state == MEM_ST_DONE) // MSG
- tx_pkt_cnt <= tx_pkt_cnt + 1'b1;
-
-
+ tx_msg_cnt <= tx_msg_cnt + 1'b1;
/***********************************************************************
*
diff --git a/src/directives.v b/src/directives.v
deleted file mode 100644
index 5760c23..0000000
--- a/src/directives.v
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * directives.v
- *
- * Copyright (C) 2018, 2019, 2020, 2021 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.
- *
- * Description: misc. directives for board options
- *
- */
-
-// Debug Options for Darsena
-//`define DEBUG_I2C
-//`define DEBUG_MDIO
-//`define DEBUG_SPI
-//`define ARD_EXP_UART
-
-`define DARSENA_V02
-//`define DARSENA_V03
-
-// Shield Definition (PORTS 3 & 4)
-//`define SHIELD_SMA_SMA
-`define SHIELD_GIGE_SMA
-//`define SHIELD_SFP_SMA
diff --git a/src/dpram.v b/src/dpram.v
deleted file mode 100644
index 53c1efc..0000000
--- a/src/dpram.v
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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/src/dpram_inf.v b/src/dpram_inf.v
new file mode 100644
index 0000000..5112dfb
--- /dev/null
+++ b/src/dpram_inf.v
@@ -0,0 +1,84 @@
+/*
+ * dpram_inf.v
+ *
+ * Copyright (C) 2024-2025 Private Island Networks 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.
+ *
+ * Inferred DPRAM
+ *
+*/
+
+module dpram_inf
+#(parameter DATA_WIDTH=9, parameter ADDR_WIDTH=11, parameter DPRAM_INIT="zero.txt")
+(
+ input rstn,
+ // PORT A
+ input a_clk,
+ input a_clk_e,
+ input a_we,
+ input a_oe,
+ input [(ADDR_WIDTH-1):0] a_addr,
+ input [(DATA_WIDTH-1):0] a_din,
+ output reg [(DATA_WIDTH-1):0] a_dout,
+ // PORT A
+ input b_clk,
+ input b_clk_e,
+ input b_we,
+ input b_oe,
+ input [(ADDR_WIDTH-1):0] b_addr,
+ input [(DATA_WIDTH-1):0] b_din,
+ output reg [(DATA_WIDTH-1):0] b_dout
+);
+
+ `ifdef SIMULATION
+ localparam DPRAM_FILE = {"../../",DPRAM_INIT};
+ `else
+ localparam DPRAM_FILE = DPRAM_INIT;
+ `endif
+
+ // Declare the RAM variable
+ reg [11:0] ram[2**ADDR_WIDTH-1:0];
+ initial begin
+ $readmemh(DPRAM_FILE, ram);
+ end
+
+ always @ (posedge a_clk)
+ begin
+ // Port A
+ if (a_clk_e && a_we)
+ begin
+ ram[a_addr] <= a_din;
+ a_dout <= a_din;
+ end
+ else
+ begin
+ a_dout <= ram[a_addr][(DATA_WIDTH-1):0];
+ end
+ end
+
+ always @ (posedge b_clk)
+ begin
+ // Port B
+ if (b_clk_e && b_we)
+ begin
+ ram[b_addr] <= b_din;
+ b_dout <= b_din;
+ end
+ else
+ begin
+ b_dout <= ram[b_addr][(DATA_WIDTH-1):0];
+ end
+ end
+
+endmodule
diff --git a/src/drop_fifo.v b/src/drop_fifo.v
index 736947c..faefac0 100644
--- a/src/drop_fifo.v
+++ b/src/drop_fifo.v
@@ -1,8 +1,8 @@
/*
* drop_fifo.v
*
- * Copyright 2018, 2019, 2020, 2021 Mind Chasers Inc.
- * Copyright 2023 Private Island Networks Inc.
+ * Copyright (C) 2023-2025 Private Island Networks Inc.
+ * Copyright (C) 2018-2021 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.
@@ -23,154 +23,200 @@
*/
module drop_fifo(
- input rstn,
- input clk,
- input passthrough, // don't store / delay data, write through instead
- input enable, // enable the FIFO
- input keep, // this packet won't be dropped, start transferring it (writer must be sure FIFO won't run dry during writes)
-
- // input data
- input we_in,
- input [8:0] d_in,
- input wr_done, // keep should occur before wr_done is asserted.
- input rx_eop,
-
- // output data
- output reg we_out,
- output reg [8:0] d_out,
-
- // debug
- output reg active
+ input rstn,
+ input phy_up, // Use the associated PHY state to gate write activity into the DF
+ input rx_clk,
+ input tx_clk,
+ input passthrough, // don't store / delay data, write through instead
+ input enable, // enable the FIFO
+ input keep, // this packet won't be dropped, start transferring it (writer must be sure FIFO won't run dry during writes)
+
+ // input data
+ input we_in,
+ input [8:0] d_in,
+ input wr_done, // keep should occur before wr_done is asserted.
+ input rx_idle, // Use to clean up states and pointers
+ input rx_error,
+
+ // output data
+ output reg we_out, // assert when data is available for writing to the next stage
+ output reg [8:0] d_out,
+
+ // debug
+ output reg active
);
-
-// local parameters and includes
-
-
-// nets and registers
-reg [10:0] wr_ptr0, wr_ptr1; // wr_ptr0 is updated on each write; wr_ptr1 is updated at end of packet
-reg [10:0] rd_ptr;
-wire [8:0] d_out_internal;
-reg read_run, read_run_m1, read_run_m2; // read continues while read_run is set
-reg kept;
-wire fifo_empty;
-
-/*
- * kept: assert for length of write duration after keep asserts (when enable is active)
- */
-always @(posedge clk, negedge rstn)
- if( !rstn )
- kept <= 1'b0;
- else if ( wr_done )
- kept <= 1'b0;
- else if ( keep && enable )
- kept <= 1'b1;
-/*
- * wr_ptr0 logic
- */
-always @(posedge clk, negedge rstn)
- if( !rstn )
- wr_ptr0 <= 'd0;
- else if ( we_in )
- wr_ptr0 <= wr_ptr0 + 1'b1;
+ // local parameters and includes
+ localparam SZ_DPRAM = 16'd2048;
-/*
- * wr_ptr1 logic
- * sync pointers at end of rx packet for next packet
-*/
-always @(posedge clk, negedge rstn)
- if( !rstn )
- wr_ptr1 <= 'd0;
- else if ( wr_done )
- wr_ptr1 <= wr_ptr0 +1; // a write takes place with wr_done
-/*
- * read_run logic
- * continues until the FIFO is empty
- */
-always @(posedge clk, negedge rstn)
- if( !rstn )
- read_run <= 1'b0;
- else if (kept && wr_done)
- read_run <= 1'b1;
- else if ( fifo_empty )
- read_run <= 1'b0;
-
-
-always @(posedge clk, negedge rstn)
- if( !rstn )
- read_run_m1 <= 1'b0;
- else
- read_run_m1 <= read_run;
+ // nets and registers
+ reg [10:0] wr_ptr0, wr_ptr1; // wr_ptr0 is updated on each write; wr_ptr1 is updated at end of packet
+ reg [10:0] rd_ptr;
+ wire [8:0] d_out_internal;
+ reg read_run, read_run_m1, read_run_m2; // read continues while read_run is set
+ reg wr_done_m1, wr_done_m2, wr_done_m3; // CDC flag
+ reg rx_idle_m1, rx_idle_m2;
+ reg kept;
+ wire fifo_empty;
+ reg [15:0] df_bytes;
+
+ /*
+ * kept: assert for length of write duration after keep asserts (when enable is active)
+ */
+ always @(posedge rx_clk, negedge rstn)
+ if(!rstn)
+ kept <= 1'b0;
+ else if (read_run_m2) // CDC flag that is asserted for multiple clocks
+ kept <= 1'b0;
+ else if (phy_up && keep && enable)
+ kept <= 1'b1;
+
+ /*
+ * wr_ptr0 logic
+ */
+ always @(posedge rx_clk, negedge rstn)
+ if(!rstn)
+ wr_ptr0 <= 'd0;
+ else if (phy_up && we_in)
+ wr_ptr0 <= wr_ptr0 + 1'b1;
+
+
+ // convert clock domain for rx_idle
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn) begin
+ rx_idle_m1 <= 1'b0;
+ rx_idle_m2 <= 1'b0;
+ end
+ else begin
+ rx_idle_m1 <= rx_idle;
+ rx_idle_m2 <= rx_idle_m1;
+ end
+
+ // convert clock domain for wr_done
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn) begin
+ wr_done_m1 <= 1'b0;
+ wr_done_m2 <= 1'b0;
+ wr_done_m3 <= 1'b0;
+ end
+ else begin
+ wr_done_m1 <= wr_done;
+ wr_done_m2 <= wr_done_m1;
+ wr_done_m3 <= wr_done_m2;
+ end
+
+ /*
+ * wr_ptr1 logic
+ * sync pointers at end of RX packet
+ */
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn)
+ wr_ptr1 <= 'd0;
+ else if (phy_up && wr_done_m3)
+ wr_ptr1 <= wr_ptr0; //
+ else if (rx_idle_m2 && !read_run)
+ wr_ptr1 <= wr_ptr0; // final clean up
+
+ /*
+ * read_run logic
+ * continues until the FIFO is empty
+ */
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn)
+ read_run <= 1'b0;
+ else if (phy_up && kept && wr_done_m3)
+ read_run <= 1'b1;
+ else if (fifo_empty)
+ read_run <= 1'b0;
-always @(posedge clk, negedge rstn)
- if( !rstn )
- read_run_m2 <= 1'b0;
- else
- read_run_m2 <= read_run_m1;
-
-/*
-* rd_ptr logic
-*/
-always @(posedge clk, negedge rstn)
- if( !rstn )
- rd_ptr <= 'd0;
- else if (kept && wr_done)
- rd_ptr <= wr_ptr1; // set rd_ptr to the beginning of where the write started
- else if (read_run && !fifo_empty)
- rd_ptr <= rd_ptr+ 1'b1;
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn) begin
+ read_run_m1 <= 1'b0;
+ read_run_m2 <= 1'b0;
+ end
+ else begin
+ read_run_m1 <= read_run;
+ read_run_m2 <= read_run_m1;
+ end
-/*
- * we_out logic
- */
-always @(posedge clk, negedge rstn)
- if( !rstn )
- we_out <= 1'b0;
- else if ( read_run_m1 && read_run_m2 )
- we_out <= 1'b1;
- else
- we_out <= 1'b0;
-
-assign fifo_empty = (wr_ptr1 == rd_ptr);
+ /*
+ * rd_ptr logic
+ */
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn)
+ rd_ptr <= 'd0;
+ else if (phy_up && kept && wr_done_m2)
+ rd_ptr <= wr_ptr1; // set rd_ptr to the beginning of where the write started
+ else if (read_run && !fifo_empty)
+ rd_ptr <= rd_ptr+ 1'b1;
-/*
- * d_out register
- *
- */
-always @(posedge clk, negedge rstn)
- if( !rstn )
- d_out <= 'd0;
- else
- d_out <= d_out_internal;
+ /*
+ * we_out logic
+ */
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn)
+ we_out <= 1'b0;
+ else if (read_run && read_run_m1)
+ we_out <= 1'b1;
+ else
+ we_out <= 1'b0;
-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_ptr0 ),
-.a_din( d_in ),
-.a_dout( ),
-// port B
-.b_clk( clk ),
-.b_clk_e( read_run ),
-.b_we( 1'b0 ),
-.b_oe( 1'b1 ),
-.b_addr( rd_ptr ),
-.b_din( 9'h0 ),
-.b_dout( d_out_internal )
-);
-
+ assign fifo_empty = (wr_ptr1 == rd_ptr);
+
+ /*
+ * d_out register
+ *
+ */
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn)
+ d_out <= 'd0;
+ else
+ d_out <= d_out_internal;
+
+ // debug flag
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn)
+ active <= 1'b0;
+ else if (we_in || we_out)
+ active <= 1'b1;
+ else
+ active <= 1'b0;
+
+ /*
+ * debug: bytes in DF
+ */
+ always @(posedge rx_clk, negedge rstn)
+ if(!rstn)
+ df_bytes <= 'd0;
+ else if (! phy_up)
+ df_bytes <= 'd0;
+ else
+ if (wr_ptr1 <= wr_ptr0)
+ df_bytes <= (wr_ptr0 + 1'b1) - wr_ptr1;
+ else
+ df_bytes <= SZ_DPRAM + (wr_ptr0+1'b1) - wr_ptr1;
+
+
+ dpram_inf dpram_fifo(
+ .rstn(rstn),
+ .a_clk(rx_clk),
+ .a_clk_e(1'b1),
+ .a_we(we_in),
+ .a_oe(1'b0),
+ .a_addr(wr_ptr0),
+ .a_din(d_in),
+ .a_dout(),
+ // port B
+ .b_clk(tx_clk),
+ .b_clk_e(read_run),
+ .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/src/ethernet_params.v b/src/ethernet_params.v
index dcb7dba..406f46f 100644
--- a/src/ethernet_params.v
+++ b/src/ethernet_params.v
@@ -1,7 +1,8 @@
/*
- * ethernet_params.v
+ * ethernet_params.v
*
- * Copyright (C) 2018, 2019, 2020 Mind Chasers Inc.
+ * Copyright (C) 2024-2025 Private Island Networks Inc.
+ * Copyright (C) 2018-2023 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.
@@ -18,22 +19,37 @@
* function: Ethernet related parameters
*
*/
+
+
+`ifdef INCLUDED
+localparam TX_SRC_SEL_PHY0 = 3'b000,
+ TX_SRC_SEL_PHY1 = 3'b001,
+ TX_SRC_SEL_PHY2 = 3'b010,
+ TX_SRC_SEL_MLE = 3'b110,
+ TX_SRC_SEL_UC = 3'b111;
+
+localparam PHY_TYPE_SGMII = 2'b00,
+ PHY_TYPE_RGMII = 2'b01,
+ PHY_TYPE_1000BASE_X = 2'b10,
+ PHY_TYPE_OTHER = 2'b11;
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_ETH_HEADER = 14; // MAC SRC, DEST, ETHER TYPE, w/o VLAN
+localparam SZ_IPV4_HEADER = 20; // w/o Options
localparam SZ_UDP_HEADER = 8;
localparam TX_MODE_AN = 3'b000,
-TX_MODE_IDLE = 3'b001,
-TX_MODE_XMT_PKT = 3'b010, // anything >= to this is a mode where a packet is transmitted
-TX_MODE_XMT_METRICS = 3'b011,
-TX_MODE_XMT_CUSTOM = 3'b100;
+ TX_MODE_IDLE = 3'b001,
+ TX_MODE_XMT_PKT = 3'b010, // anything >= to this is a mode where a packet is transmitted
+ TX_MODE_XMT_METRICS = 3'b011,
+ TX_MODE_XMT_CUSTOM = 3'b100;
// 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;
+ ETHER_TYPE_IPV6 = 16'h86DD,
+ ETHER_TYPE_ARP = 16'h0806;
+
+`endif
diff --git a/src/fcs.v b/src/fcs.v
index 6abf536..e0b3b21 100644
--- a/src/fcs.v
+++ b/src/fcs.v
@@ -1,7 +1,7 @@
/*
- * fcs.v
- *
- * Copyright (C) 2018, 2019 Mind Chasers Inc.
+ * fcs.v
+ * Copyright (C) 2025 Private Island Networks Inc.
+ * 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.
@@ -19,7 +19,6 @@
*
*
*/
-`timescale 1ns /10ps
////////////////////////////////////////////////////////////////////////////////
// Copyright (C) 1999-2008 Easics NV.
@@ -65,78 +64,78 @@ module fcs(
);
-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
+ 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/src/half_fifo.v b/src/half_fifo.v
index c85f6ac..fb02176 100644
--- a/src/half_fifo.v
+++ b/src/half_fifo.v
@@ -50,170 +50,169 @@ module half_fifo #(parameter DATA_WIDTH = 9, DPRAM_DEPTH=11)
output reg [10:0] tx_byte_cnt,
output [DATA_WIDTH-1:0] fifo_d_out,
output tx_empty
-
);
`define INCLUDED
`include "cont_params.v"
`undef INCLUDED
-/*
- * Pointers for accessing memory.
- * UC writes TX and reads RX
- * Switch writes (via FIFO I/F) RX and reads TX
- * This is the opposite of the system view
- */
-reg [DPRAM_DEPTH-1:0] rx_wr_ptr, rx_wr_ptr_latched;
-
-reg [DPRAM_DEPTH-1:0] tx_wr_ptr, tx_wr_ptr_latched;
-reg [DPRAM_DEPTH-1:0] tx_rd_ptr;
-
-reg tx_wr_ptr_written, tx_wr_ptr_written_m1, tx_wr_ptr_written_m2;
-
-reg fifo_we_m1;
-
-reg reset_ptrs;
-wire [DATA_WIDTH-1:0] dpram_tx_dout, dpram_rx_dout;
-
-/* read data mux, refer to addr params above */
-always @(*)
- casez({ dpram_tx_sel, dpram_rx_sel, dpram_ptrs_sel, dpram_addr[2:0] })
- 6'b001000: dpram_dout = tx_wr_ptr;
- 6'b001001: dpram_dout = tx_rd_ptr; // meta stable
- 6'b001010: dpram_dout = rx_wr_ptr_latched;
- 6'b001011: dpram_dout = 11'd0;
- 6'b001100: dpram_dout = {10'd0, reset_ptrs};
- 6'b010???: dpram_dout = {2'b00, dpram_rx_dout};
- 6'b100???: dpram_dout = {2'b00, dpram_tx_dout};
- default: dpram_dout = {2'b00, dpram_rx_dout};
- endcase
+ /*
+ * Pointers for accessing memory.
+ * UC writes TX and reads RX
+ * Switch writes (via FIFO I/F) RX and reads TX
+ * This is the opposite of the system view
+ */
+ reg [DPRAM_DEPTH-1:0] rx_wr_ptr, rx_wr_ptr_latched;
-always @(posedge uc_clk, negedge rstn)
- if (!rstn)
- reset_ptrs <= 1'b0;
- else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_RESET_PTRS)
- reset_ptrs <= dpram_din[0];
+ reg [DPRAM_DEPTH-1:0] tx_wr_ptr, tx_wr_ptr_latched;
+ reg [DPRAM_DEPTH-1:0] tx_rd_ptr;
-always @(posedge uc_clk, negedge rstn)
- if (!rstn)
- tx_byte_cnt <= 11'd0;
- else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_BYTE_CNT_ADDR)
- tx_byte_cnt <= dpram_din;
-
-/* TX wr ptr (UC writes) */
-always @(posedge uc_clk, negedge rstn)
- if (!rstn) begin
- tx_wr_ptr <= 'h0;
- tx_wr_ptr_written <= 1'b0;
- end
- else if (reset_ptrs) begin
- tx_wr_ptr <= 'h0;
- tx_wr_ptr_written <= 1'b1;
- end
- else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_WR_PTR_ADDR) begin
- tx_wr_ptr <= dpram_din;
- tx_wr_ptr_written <= 1'b1;
- end
- else
- tx_wr_ptr_written <= 1'b0;
+ reg tx_wr_ptr_written, tx_wr_ptr_written_m1, tx_wr_ptr_written_m2;
-always @(posedge fifo_clk, negedge rstn)
- if (!rstn) begin
- tx_wr_ptr_written_m1 <= 1'b0;
- tx_wr_ptr_written_m2 <= 1'b0;
- end
- else begin
- tx_wr_ptr_written_m1 <= tx_wr_ptr_written;
- tx_wr_ptr_written_m2 <= tx_wr_ptr_written_m1;
- end
+ reg fifo_we_m1;
+ reg reset_ptrs;
+ wire [DATA_WIDTH-1:0] dpram_tx_dout, dpram_rx_dout;
-always @(posedge fifo_clk, negedge rstn)
- if(!rstn)
- tx_wr_ptr_latched <= 8'h00;
- else if (tx_wr_ptr_written_m2)
- tx_wr_ptr_latched <= tx_wr_ptr;
+ /* read data mux, refer to addr params above */
+ always @(*)
+ casez({ dpram_tx_sel, dpram_rx_sel, dpram_ptrs_sel, dpram_addr[2:0] })
+ 6'b001000: dpram_dout = tx_wr_ptr;
+ 6'b001001: dpram_dout = tx_rd_ptr; // meta stable
+ 6'b001010: dpram_dout = rx_wr_ptr_latched;
+ 6'b001011: dpram_dout = 11'd0;
+ 6'b001100: dpram_dout = {10'd0, reset_ptrs};
+ 6'b010???: dpram_dout = {2'b00, dpram_rx_dout};
+ 6'b100???: dpram_dout = {2'b00, dpram_tx_dout};
+ default: dpram_dout = {2'b00, dpram_rx_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] == HF_RESET_PTRS)
+ reset_ptrs <= dpram_din[0];
+
+ always @(posedge uc_clk, negedge rstn)
+ if (!rstn)
+ tx_byte_cnt <= 11'd0;
+ else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_BYTE_CNT_ADDR)
+ tx_byte_cnt <= dpram_din;
-/* TX rd ptr (switch reads via FIFO), auto increment */
-always @(posedge fifo_clk, negedge rstn)
- if(!rstn)
- tx_rd_ptr <= 11'd0;
- else if (reset_ptrs)
- tx_rd_ptr <= 11'd0;
- else if (fifo_re && !tx_empty) // advance the pointer if FIFO isn't empty
- tx_rd_ptr <= tx_rd_ptr + 1'b1;
-
-/* RX wr ptr (switch writes via FIFO) */
-always @(posedge fifo_clk, negedge rstn)
- if(!rstn)
- rx_wr_ptr <= 11'd0;
- else if (reset_ptrs)
- rx_wr_ptr <= 11'd0;
- else if (fifo_we)
- rx_wr_ptr <= rx_wr_ptr + 1'b1;
+ /* TX wr ptr (UC writes) */
+ always @(posedge uc_clk, negedge rstn)
+ if (!rstn) begin
+ tx_wr_ptr <= 'h0;
+ tx_wr_ptr_written <= 1'b0;
+ end
+ else if (reset_ptrs) begin
+ tx_wr_ptr <= 'h0;
+ tx_wr_ptr_written <= 1'b1;
+ end
+ else if (dpram_ptrs_sel && dpram_we && dpram_addr[2:0] == HF_TX_WR_PTR_ADDR) begin
+ tx_wr_ptr <= dpram_din;
+ tx_wr_ptr_written <= 1'b1;
+ end
+ else
+ tx_wr_ptr_written <= 1'b0;
+
+ always @(posedge fifo_clk, negedge rstn)
+ if (!rstn) begin
+ tx_wr_ptr_written_m1 <= 1'b0;
+ tx_wr_ptr_written_m2 <= 1'b0;
+ end
+ else begin
+ tx_wr_ptr_written_m1 <= tx_wr_ptr_written;
+ tx_wr_ptr_written_m2 <= tx_wr_ptr_written_m1;
+ end
+
+
+ always @(posedge fifo_clk, negedge rstn)
+ if(!rstn)
+ tx_wr_ptr_latched <= 8'h00;
+ else if (tx_wr_ptr_written_m2)
+ tx_wr_ptr_latched <= tx_wr_ptr;
+
+ /* TX rd ptr (switch reads via FIFO), auto increment */
+ always @(posedge fifo_clk, negedge rstn)
+ if(!rstn)
+ tx_rd_ptr <= 11'd0;
+ else if (reset_ptrs)
+ tx_rd_ptr <= 11'd0;
+ else if (fifo_re && !tx_empty) // advance the pointer if FIFO isn't empty
+ tx_rd_ptr <= tx_rd_ptr + 1'b1;
-assign tx_empty = (tx_rd_ptr == tx_wr_ptr_latched);
-
-/* 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;
+ /* RX wr ptr (switch writes via FIFO) */
+ always @(posedge fifo_clk, negedge rstn)
+ if(!rstn)
+ rx_wr_ptr <= 11'd0;
+ else if (reset_ptrs)
+ rx_wr_ptr <= 11'd0;
+ else if (fifo_we)
+ rx_wr_ptr <= rx_wr_ptr + 1'b1;
+
+ assign tx_empty = (tx_rd_ptr == tx_wr_ptr_latched);
-// Metastability note: rx_wr_ptr_latched should be read one or more clock cycles after rx_fifo_int asserts
-always @(posedge fifo_clk, negedge rstn)
- if (!rstn) begin
- rx_fifo_int <= 1'b0;
- rx_wr_ptr_latched <= 11'd0;
- end
- else if (!fifo_we & fifo_we_m1) begin // end of write
- rx_fifo_int <= 1'b1;
- rx_wr_ptr_latched <= rx_wr_ptr;
- end
- else if (rx_fifo_int_acked) // clear interrupt
- rx_fifo_int <= 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;
+
+ // Metastability note: rx_wr_ptr_latched should be read one or more clock cycles after rx_fifo_int asserts
+ always @(posedge fifo_clk, negedge rstn)
+ if (!rstn) begin
+ rx_fifo_int <= 1'b0;
+ rx_wr_ptr_latched <= 11'd0;
+ end
+ else if (!fifo_we & fifo_we_m1) begin // end of write
+ rx_fifo_int <= 1'b1;
+ rx_wr_ptr_latched <= rx_wr_ptr;
+ end
+ else if (rx_fifo_int_acked) // clear interrupt
+ rx_fifo_int <= 1'b0;
+
+ /* controller uses A side, FIFO uses B side
+ * controller writes TX path and reads RX path */
+ // 2K DPRAM
+ dpram_inf dpram_tx(
+ .rstn(rstn),
+ .a_clk(uc_clk),
+ .a_clk_e(dpram_tx_sel),
+ .a_we(dpram_we),
+ .a_oe(1'b1),
+ .a_addr(dpram_addr),
+ .a_din(dpram_din[8:0]),
+ .a_dout(dpram_tx_dout),
+ // port B
+ .b_clk(fifo_clk),
+ .b_clk_e(1'b1),
+ .b_we(1'b0),
+ .b_oe(fifo_re),
+ .b_addr(tx_rd_ptr),
+ .b_din(9'h0),
+ .b_dout(fifo_d_out)
+ );
-/* controller uses A side, FIFO uses B side
- * controller writes TX path and reads RX path */
-// 2K DPRAM
-dpram_inf dpram_tx(
- .rstn(rstn),
- .a_clk(uc_clk),
- .a_clk_e(dpram_tx_sel),
- .a_we(dpram_we),
- .a_oe(1'b1),
- .a_addr(dpram_addr),
- .a_din(dpram_din[8:0]),
- .a_dout(dpram_tx_dout),
- // port B
- .b_clk(fifo_clk),
- .b_clk_e(1'b1),
- .b_we(1'b0),
- .b_oe(fifo_re),
- .b_addr(tx_rd_ptr),
- .b_din(9'h0),
- .b_dout(fifo_d_out)
-);
-
-// 2K DPRAM
-dpram_inf dpram_rx(
- .rstn(rstn),
- .a_clk(uc_clk),
- .a_clk_e(dpram_rx_sel),
- .a_we(1'b0),
- .a_oe(1'b1),
- .a_addr(dpram_addr),
- .a_din(9'h000),
- .a_dout(dpram_rx_dout),
- // port B
- .b_clk(fifo_clk),
- .b_clk_e(1'b1),
- .b_we(fifo_we),
- .b_oe(1'b0),
- .b_addr(rx_wr_ptr),
- .b_din(fifo_d_in),
- .b_dout()
-);
+ // 2K DPRAM
+ dpram_inf dpram_rx(
+ .rstn(rstn),
+ .a_clk(uc_clk),
+ .a_clk_e(dpram_rx_sel),
+ .a_we(1'b0),
+ .a_oe(1'b1),
+ .a_addr(dpram_addr),
+ .a_din(9'h000),
+ .a_dout(dpram_rx_dout),
+ // port B
+ .b_clk(fifo_clk),
+ .b_clk_e(1'b1),
+ .b_we(fifo_we),
+ .b_oe(1'b0),
+ .b_addr(rx_wr_ptr),
+ .b_din(fifo_d_in),
+ .b_dout()
+ );
endmodule
diff --git a/src/i2c.v b/src/i2c.v
deleted file mode 100644
index aca6452..0000000
--- a/src/i2c.v
+++ /dev/null
@@ -1,391 +0,0 @@
-/*
- * 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/src/interrupts.v b/src/interrupts.v
deleted file mode 100644
index c77dfb7..0000000
--- a/src/interrupts.v
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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/src/ipv4.v b/src/ipv4_rx.v
index 55ab7a7..f948729 100644
--- a/src/ipv4.v
+++ b/src/ipv4_rx.v
@@ -1,7 +1,8 @@
/*
- * ipv4.v
+ * ipv4_rx.v
*
- * Copyright (C) 2018, 2019 Mind Chasers Inc.
+ * Copyright (C) 2024-2025 Private Island Networks Inc.
+ * 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.
@@ -30,30 +31,30 @@
* 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,
-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_sample, // enable in case we have connected at 100 Mbit
+ 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,
- // 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
- );
+ // 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,
@@ -67,6 +68,9 @@ module ipv4_rx (
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;
+ localparam IP_DST_MATCH_2 = 3,
+ IP_DST_MATCH_3 = 168,
+ IP_DST_MATCH_4 = 192;
reg [3:0] rx_state;
reg [10:0] rx_byte_cnt;
@@ -102,12 +106,12 @@ module ipv4_rx (
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 )
+ else if ( (rx_sample && rx_state != RX_ST_IDLE && rx_sample) || pkt_start )
rx_byte_cnt <= rx_byte_cnt + 1;
/* protocol */
- always @(posedge clk, negedge rstn)
+ always @(posedge clk, negedge rstn)
if ( !rstn )
protocol <= 0;
else if ( rx_eop )
@@ -126,9 +130,9 @@ module ipv4_rx (
rx_pkt_length <= { rx_data_m2[2:0], rx_data_m1 };
/*
- * Packet Filter Trigger(s), assert the sample before the data appears
- *
- */
+ * Packet Filter Trigger(s), assert the sample before the data appears
+ *
+ */
always @(posedge clk, negedge rstn)
if (!rstn)
trigger_src_addr <= 1'b0;
@@ -138,15 +142,24 @@ module ipv4_rx (
trigger_src_addr <= 1'b0;
always @(posedge clk, negedge rstn)
- if (!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 pkt_complete = ( rx_state >= RX_ST_DATA && rx_pkt_length == rx_byte_cnt+1 ) ? 1'b1 : 1'b0;
assign rx_error = 0;
+ // ipv4 keep logic: add your criteria below
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ keep <= 1'b0;
+ else if (1'b0)
+ keep <= 1'b1;
+ else
+ keep <= 1'b0;
+
endmodule
diff --git a/src/ipv4_rx_c.v b/src/ipv4_rx_c.v
new file mode 100644
index 0000000..262d328
--- /dev/null
+++ b/src/ipv4_rx_c.v
@@ -0,0 +1,134 @@
+/*
+ * ipv4_rx_c.v
+ *
+ * Copyright (C) 2024-2025 Private Island Networks Inc.
+ * 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 for the internal controller
+ *
+ *
+ * 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....................................
+ *
+ *
+ */
+
+module ipv4_rx_c #(parameter IP_DST_MATCH_1=192, IP_DST_MATCH_2=168,
+ IP_DST_MATCH_3=5, IP_DST_MATCH_4=200)
+(
+ input rstn,
+ input clk,
+
+ // control
+ input phy_up,
+
+ // packet data
+ input pkt_start, // assert for each new frame to start state machines
+ input rx_sample, // enable in case we have connected at 100 Mbit
+ 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 ip_addr_match
+);
+
+ /* 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;
+
+ /*
+ * rx_state machine
+ * capture an IPv4 Packet
+ *
+ */
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_state <= RX_ST_IDLE;
+ else if ( rx_eop || !phy_up ) // EOP will reset state machine
+ rx_state <= RX_ST_IDLE;
+ else
+ 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;
+ default: rx_state <= RX_ST_IDLE;
+ endcase
+
+ /* 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_sample && rx_state != RX_ST_IDLE && rx_sample) || 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 };
+
+ // IPv4 Dest Address match logic
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ ip_addr_match <= 1'b0;
+ else if (rx_eop)
+ ip_addr_match <= 1'b0;
+ else if ( rx_sample && rx_data_m1 == (IP_DST_MATCH_4) && rx_data_m2 == IP_DST_MATCH_3 && rx_data_m3 == IP_DST_MATCH_2 && rx_data_m4 == IP_DST_MATCH_1 )
+ ip_addr_match <= 1'b1;
+
+ assign pkt_complete = ( rx_state >= RX_ST_DATA && rx_pkt_length == rx_byte_cnt+1 ) ? 1'b1 : 1'b0;
+
+
+endmodule
diff --git a/src/ipv4_tx_c.v b/src/ipv4_tx_c.v
new file mode 100644
index 0000000..3c33548
--- /dev/null
+++ b/src/ipv4_tx_c.v
@@ -0,0 +1,179 @@
+/*
+ * ipv4_tx.v
+ *
+ * Copyright 2025 Private Island Networks Inc.
+ * Copyright 2018, 2019, 2020 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: Layer 3 (and 4) Support for Controller Transmit
+ *
+ *
+ */
+
+module ipv4_tx_c(
+ input rstn,
+ input phy_resetn,
+ input clk,
+
+ // Control Interface
+ input cont_clk, // controller clock
+ input cont_sel,
+ input cont_we,
+ input [7:0] cont_addr,
+ input [15:0] cont_d_i,
+ output reg [15:0] cont_d_o,
+
+ // Line State
+ input mode_100Mbit,
+ input phy_up,
+
+ // Switch I/F
+ input [2:0] tx_mode,
+ input [2:0] tx_src_sel,
+ input [10:0] byte_cnt_i,
+
+ // MAC Interface
+ input fifo_re_i,
+ output reg fifo_empty_o,
+ output reg [8:0] fifo_d_o,
+
+ // Debug
+ output [7:0] gpio
+);
+
+`define INCLUDED
+`include "ethernet_params.v"
+`include "rgmii_params.v"
+`undef INCLUDED
+
+ localparam TX_CNT_OFFSET = 11'h15; // offset for start of IP Header in Ethernet frame
+ localparam TX_CNT_CKSUM_START = TX_CNT_OFFSET + 10;
+
+ wire ipv4_hdr_active;
+ reg [10:0] tx_cnt;
+ reg [17:0] ipv4_cksum;
+ reg [15:0] ipv4_pkt_length;
+ reg [15:0] udp_pkt_length;
+ integer i;
+
+ assign ipv4_hdr_active = (tx_mode == TX_MODE_XMT_CUSTOM && tx_src_sel == TX_SRC_SEL_UC);
+
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ tx_cnt <= 11'd0;
+ else if (ipv4_hdr_active)
+ tx_cnt <= tx_cnt + 1'b1;
+ else
+ tx_cnt <= 11'd0;
+
+
+ always @(posedge clk, negedge rstn)
+ if ( !rstn ) begin
+ ipv4_pkt_length <= 16'd0;
+ udp_pkt_length <= 16'd0;
+ end
+ else if (ipv4_hdr_active && tx_cnt == 11'd0) begin
+ ipv4_pkt_length <= byte_cnt_i + SZ_IPV4_HEADER + SZ_UDP_HEADER;
+ udp_pkt_length <= byte_cnt_i + SZ_UDP_HEADER;
+ end
+
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ ipv4_cksum <= 18'd0;
+ else if (!ipv4_hdr_active)
+ ipv4_cksum <= 18'd0;
+ else if (tx_cnt < 11'd20 && tx_cnt[0])
+ ipv4_cksum <= ipv4_cksum + (ipv4_hdr(tx_cnt-1)<<8) + ipv4_hdr(tx_cnt);
+ // else if (tx_cnt == 11'd20)
+ // ipv4_cksum <= ipv4_cksum + ipv4_pkt_length;
+ else if (tx_cnt == 11'd21)
+ ipv4_cksum <= {2'b00,ipv4_cksum[15:0]} + {16'h0000,ipv4_cksum[17:16]};
+ else if (tx_cnt == 11'd22)
+ ipv4_cksum <= {2'b00, ~ipv4_cksum[15:0]};
+
+ // fifo_empty_o
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ fifo_empty_o <= 1'b1;
+ else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < (TX_CNT_OFFSET + SZ_IPV4_HEADER + SZ_UDP_HEADER))
+ fifo_empty_o <= 1'b0;
+ else
+ fifo_empty_o <= 1'b1;
+
+ // fifo_d_o
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ fifo_d_o <= 9'h000;
+ else if (tx_cnt == TX_CNT_CKSUM_START)
+ fifo_d_o <= ipv4_cksum[15:8];
+ else if (tx_cnt == TX_CNT_CKSUM_START+1)
+ fifo_d_o <= ipv4_cksum[7:0];
+ else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < TX_CNT_OFFSET + SZ_IPV4_HEADER)
+ fifo_d_o <= ipv4_hdr(tx_cnt-TX_CNT_OFFSET);
+ else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < TX_CNT_OFFSET + SZ_IPV4_HEADER + SZ_UDP_HEADER)
+ fifo_d_o <= udp_hdr(tx_cnt-(TX_CNT_OFFSET + SZ_IPV4_HEADER));
+ else
+ fifo_d_o <= 9'h000;
+
+
+ // generate the IPv4 header
+ // Assuming the header is only 20 bytes, this is both efficient and flexible
+ function automatic [7:0] ipv4_hdr;
+ input [10:0] ad;
+ case(ad)
+ 0: ipv4_hdr = 8'h45; // Version
+ 1: ipv4_hdr = 8'h00; // IHL
+ 2: ipv4_hdr = ipv4_pkt_length[15:8]; // Total Length
+ 3: ipv4_hdr = ipv4_pkt_length[7:0];
+ 4: ipv4_hdr = 8'h54;
+ 5: ipv4_hdr = 8'hDB;
+ 6: ipv4_hdr = 8'h40;
+ 7: ipv4_hdr = 8'h00;
+ 8: ipv4_hdr = 8'h40; // TTL
+ 9: ipv4_hdr = 8'h11; // L4 Protocol (UDP=0x11)
+ 10: ipv4_hdr = 8'h00; // Checksum
+ 11: ipv4_hdr = 8'h00;
+ 12: ipv4_hdr = 8'd192; // IP Source Address
+ 13: ipv4_hdr = 8'd168;
+ 14: ipv4_hdr = 8'd5;
+ 15: ipv4_hdr = 8'd100;
+ 16: ipv4_hdr = 8'd192; // IP Destination Address
+ 17: ipv4_hdr = 8'd168;
+ 18: ipv4_hdr = 8'd5;
+ 19: ipv4_hdr = 8'd40;
+ default: ipv4_hdr = 8'h00;
+ endcase
+ endfunction
+
+
+ // generate the UDP header
+ function automatic [7:0] udp_hdr;
+ input [10:0] ad;
+ case(ad)
+ 0: udp_hdr = 8'h80; // SRC Port
+ 1: udp_hdr = 8'h00; //
+ 2: udp_hdr = 8'h80; // DST Port
+ 3: udp_hdr = 8'h00;
+ 4: udp_hdr = udp_pkt_length[15:8]; // Length
+ 5: udp_hdr = udp_pkt_length[7:0];
+ 6: udp_hdr = 8'h00; //Checksum
+ 7: udp_hdr = 8'h00;
+ default: udp_hdr = 8'h00;
+ endcase
+ endfunction
+
+ assign gpio[0] = |ipv4_cksum[7:0];
+ assign gpio[1] = |ipv4_cksum[15:8];
+
+endmodule
diff --git a/src/ipv4_tx_mle.v b/src/ipv4_tx_mle.v
new file mode 100644
index 0000000..28d6d85
--- /dev/null
+++ b/src/ipv4_tx_mle.v
@@ -0,0 +1,175 @@
+/*
+ * ipv4_tx.v
+ *
+ * Copyright 2025 Private Island Networks Inc.
+ * Copyright 2018, 2019, 2020 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: Layer 3 (and 4) Support for Controller Transmit
+ *
+ */
+
+module ipv4_tx_mle(
+ input rstn,
+ input phy_resetn,
+ input clk,
+
+ // Control Interface
+ input cont_clk, // controller clock
+ input cont_sel,
+ input cont_we,
+ input [7:0] cont_addr,
+ input [15:0] cont_d_i,
+ output reg [15:0] cont_d_o,
+
+ // Line State
+ input mode_100Mbit,
+ input phy_up,
+
+ // Switch I/F
+ input [2:0] tx_mode,
+ input [2:0] tx_src_sel,
+ input [10:0] byte_cnt_i, // # of payload bytes
+
+ // MAC Interface
+ input fifo_re_i,
+ output reg fifo_empty_o,
+ output reg [8:0] fifo_d_o,
+
+ // Debug
+ output [7:0] gpio
+);
+
+ `define INCLUDED
+ `include "ethernet_params.v"
+ `include "rgmii_params.v"
+ `undef INCLUDED
+
+ localparam TX_CNT_OFFSET = 11'h15; // offset for start of IP Header in Ethernet frame
+ localparam TX_CNT_CKSUM_START = TX_CNT_OFFSET + 10;
+
+ wire ipv4_hdr_active;
+ reg [10:0] tx_cnt;
+ reg [17:0] ipv4_cksum;
+ reg [15:0] ipv4_pkt_length;
+ reg [15:0] udp_pkt_length;
+ integer i;
+
+ assign ipv4_hdr_active = (tx_mode == TX_MODE_XMT_CUSTOM && tx_src_sel == TX_SRC_SEL_MLE);
+
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ tx_cnt <= 11'd0;
+ else if (ipv4_hdr_active)
+ tx_cnt <= tx_cnt + 1'b1;
+ else
+ tx_cnt <= 11'd0;
+
+ always @(posedge clk, negedge rstn)
+ if ( !rstn ) begin
+ ipv4_pkt_length <= 16'd0;
+ udp_pkt_length <= 16'd0;
+ end
+ else if (ipv4_hdr_active && tx_cnt == 11'd0) begin
+ ipv4_pkt_length <= byte_cnt_i + SZ_IPV4_HEADER + SZ_UDP_HEADER;
+ udp_pkt_length <= byte_cnt_i + SZ_UDP_HEADER;
+ end
+
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ ipv4_cksum <= 18'd0;
+ else if (!ipv4_hdr_active)
+ ipv4_cksum <= 18'd0;
+ else if (tx_cnt < 11'd20 && tx_cnt[0])
+ ipv4_cksum <= ipv4_cksum + (ipv4_hdr(tx_cnt-1)<<8) + ipv4_hdr(tx_cnt);
+ else if (tx_cnt == 11'd21)
+ ipv4_cksum <= {2'b00,ipv4_cksum[15:0]} + {16'h0000,ipv4_cksum[17:16]};
+ else if (tx_cnt == 11'd22)
+ ipv4_cksum <= {2'b00, ~ipv4_cksum[15:0]};
+
+ // fifo_empty_o
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ fifo_empty_o <= 1'b1;
+ else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < (TX_CNT_OFFSET + SZ_IPV4_HEADER + SZ_UDP_HEADER))
+ fifo_empty_o <= 1'b0;
+ else
+ fifo_empty_o <= 1'b1;
+
+ // fifo_d_o
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ fifo_d_o <= 9'h000;
+ else if (tx_cnt == TX_CNT_CKSUM_START)
+ fifo_d_o <= ipv4_cksum[15:8];
+ else if (tx_cnt == TX_CNT_CKSUM_START+1)
+ fifo_d_o <= ipv4_cksum[7:0];
+ else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < TX_CNT_OFFSET + SZ_IPV4_HEADER)
+ fifo_d_o <= ipv4_hdr(tx_cnt-TX_CNT_OFFSET);
+ else if (tx_cnt >= TX_CNT_OFFSET && tx_cnt < TX_CNT_OFFSET + SZ_IPV4_HEADER + SZ_UDP_HEADER)
+ fifo_d_o <= udp_hdr(tx_cnt-(TX_CNT_OFFSET + SZ_IPV4_HEADER));
+ else
+ fifo_d_o <= 9'h000;
+
+
+ // generate the IPv4 header
+ // Assuming the header is only 20 bytes, this is both efficient and flexible
+ function automatic [7:0] ipv4_hdr;
+ input [10:0] ad;
+ case(ad)
+ 0: ipv4_hdr = 8'h45; // Version
+ 1: ipv4_hdr = 8'h00; // IHL
+ 2: ipv4_hdr = ipv4_pkt_length[15:8]; // Total Length
+ 3: ipv4_hdr = ipv4_pkt_length[7:0];
+ 4: ipv4_hdr = 8'h54;
+ 5: ipv4_hdr = 8'hDB;
+ 6: ipv4_hdr = 8'h40;
+ 7: ipv4_hdr = 8'h00;
+ 8: ipv4_hdr = 8'h40; // TTL
+ 9: ipv4_hdr = 8'h11; // L4 Protocol (UDP=0x11)
+ 10: ipv4_hdr = 8'h00; // Checksum
+ 11: ipv4_hdr = 8'h00;
+ 12: ipv4_hdr = 8'd192; // IP Source Address
+ 13: ipv4_hdr = 8'd168;
+ 14: ipv4_hdr = 8'd5;
+ 15: ipv4_hdr = 8'd100;
+ 16: ipv4_hdr = 8'd192; // IP Destination Address
+ 17: ipv4_hdr = 8'd168;
+ 18: ipv4_hdr = 8'd5;
+ 19: ipv4_hdr = 8'd40;
+ default: ipv4_hdr = 8'h00;
+ endcase
+ endfunction
+
+
+ // generate the UDP header
+ function automatic [7:0] udp_hdr;
+ input [10:0] ad;
+ case(ad)
+ 0: udp_hdr = 8'h80; // SRC Port
+ 1: udp_hdr = 8'h10; //
+ 2: udp_hdr = 8'h80; // DST Port
+ 3: udp_hdr = 8'h10;
+ 4: udp_hdr = udp_pkt_length[15:8]; // Length
+ 5: udp_hdr = udp_pkt_length[7:0];
+ 6: udp_hdr = 8'h00; //Checksum
+ 7: udp_hdr = 8'h00;
+ default: udp_hdr = 8'h00;
+ endcase
+ endfunction
+
+ assign gpio[0] = |ipv4_cksum[7:0];
+ assign gpio[1] = |ipv4_cksum[15:8];
+
+endmodule
diff --git a/src/link_timer.v b/src/link_timer.v
deleted file mode 100644
index 7b501ff..0000000
--- a/src/link_timer.v
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * link_timer.v
- *
- * Copyright 2020 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 link timer pulse (1.6 and 10 ms) per SGMII and IEEE 802.3
- *
- */
-
-module link_timer(
- input rstn,
- input clk, // 125 MHz data clock
- output pulse_1_6ms,
- output pulse_10ms
-);
-
- reg [13:0] cnt; // 0.1 ms counter
- reg [3:0] cnt_1_6ms;
- reg [6:0] cnt_10ms;
-
- // 0.1 ms counter
- always @ (posedge clk or negedge rstn)
- if ( !rstn )
- cnt <= 'd0;
- else if (cnt == 'd12500)
- cnt <= 'd0;
- else
- cnt <= cnt + 1;
-
- // 1.6 ms counter
- always @ (posedge clk or negedge rstn)
- if ( !rstn )
- cnt_1_6ms <= 'd0;
- else if (cnt == 'd12500)
- if (cnt_1_6ms == 'd16)
- cnt_1_6ms <= 'd0;
- else
- cnt_1_6ms <= cnt_1_6ms + 1;
-
- assign pulse_1_6ms = (cnt == 'd12500 && cnt_1_6ms == 'd15);
-
- // 10 ms counter
- always @ (posedge clk or negedge rstn)
- if ( !rstn )
- cnt_10ms <= 'd0;
- else if (cnt == 'd12500)
- if (cnt_10ms == 'd99)
- cnt_10ms <= 'd0;
- else
- cnt_10ms <= cnt_10ms + 1;
-
- assign pulse_10ms = (cnt == 'd12500 && cnt_10ms == 'd99);
-
-
-endmodule \ No newline at end of file
diff --git a/src/mac.v b/src/mac.v
deleted file mode 100644
index b5b980a..0000000
--- a/src/mac.v
+++ /dev/null
@@ -1,973 +0,0 @@
-/*
- * mac.v
- *
- * Copyright 2018, 2019, 2020, 2021 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 MAC Layer
- *
- */
-
-module mac(
- input rstn,
- input phy_resetn, // The external PHY has its reset signal asserted
- input clk,
- input tap_port,
-
- // PCS / SERDES health
- input rx_lsm,
- input rx_cv_err,
- input rx_disp_err,
- input rx_cdr_lol,
- input rx_los,
-
- // AN
- input [1:0] phy_type, // SGMII==0, SX=1, SMA=3
- input pulse_1_6ms, // SGMII
- input pulse_10ms, // SX
- input [1:0] fixed_speed,
- input an_disable,
- output an_duplex,
- output phy_up,
- output reg mode_100Mbit,
-
- // Switch I/F
- input [2:0] tx_mode,
- output reg tx_f,
-
- // 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,
-
- // 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,
-
- // MAC RX / FIFO Write
- output rx_fifo_we,
- output [8:0] rx_fifo_d,
- output reg rx_error,
- output rx_keep,
- output reg rx_wr_done,
- output reg [10:0] rx_byte_cnt,
- output [1:0] rx_mode,
-
- // MAC TX / FIFO Read
- input [10:0] tx_byte_cnt_i,
- input [2:0] tx_src_sel,
- 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
- output [10:0] dpr_ad,
- output dpr_we,
- output dpr_ce,
- input [8:0] dpr_di,
- output [8:0] dpr_do,
-
- // Flags, Metrics, Interrupts, and Debug
- output reg rx_enet_bcast,
- output reg rx_ipv4_arp,
- 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,
- output reg rx_active,
- output reg tx_active
-);
-
-`include "sgmii_params.v"
-`include "ethernet_params.v"
-
-localparam PHY_TYPE_SGMII = 2'b00,
- PHY_TYPE_SX = 2'b01,
- PHY_TYPE_RSVD = 2'b10,
- PHY_TYPE_SMA = 2'b11;
-
-localparam AN_TX_CONFIG_HI = 8'h00,
- AN_TX_CONFIG_HI_ACK = 8'h40,
- AN_TX_CONFIG_LO = 8'h21;
-
-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;
-
-// AN
-wire [15:0] tx_config_reg;
-wire [1:0] an_speed;
-
-reg [3:0] rx_cnt_100mbit, tx_cnt_100mbit;
-wire tx_sample, tx_sample_re;
-wire rx_packet_complete;
-wire mode_1Gbit;
-
-reg [3:0] rx_state;
-reg [10:0] rx_pkt_length;
-reg [15:0] rx_l3_proto;
-
-// TODO: consider reorganizing state machines to reuse registers.
-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 [10:0] param_addr;
-
-reg tx_f_an, tx_f_idle, tx_f_pkt;
-reg i_tx_disp_correct;
-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;
-
-// layer 3 TX support
-reg [18:0] tx_ipv4_cksum;
-reg [15:0] tx_ipv4_length;
-
-// layer 4 TX support
-reg [15:0] tx_udp_length;
-
-wire tx_finished;
-wire tx_temp;
-
-
-/*
- * 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
-
-// Auto Negotiation
-an an_inst (
- .rstn(rstn),
- .phy_resetn(phy_resetn),
- .clk(clk),
- // AN
- .phy_type(phy_type),
- .pulse_1_6ms(pulse_1_6ms),
- .pulse_10ms(pulse_10ms),
- .fixed_speed(fixed_speed),
- .an_disable(an_disable),
- .an_duplex(an_duplex),
- .an_speed(an_speed),
- .an_link_up(an_link_up),
- .tx_config_reg(tx_config_reg),
- .phy_up(phy_up),
-
- .rx_k_m1(rx_k_m1),
- .rx_k_m2(rx_k_m2),
- .rx_k_m3(rx_k_m3),
- .rx_k_m4(rx_k_m4),
-
- .rx_data_m1(rx_data_m1),
- .rx_data_m2(rx_data_m2),
- .rx_data_m3(rx_data_m3),
- .rx_data_m4(rx_data_m4)
- );
-
-
-// 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;
-
-// rx_mode
-assign rx_mode = 2'b00;
-
-
-/*
- * Detect Ethernet Broadcast (destination address = ff:ff:ff:ff:ff:ff)
- * TODO: Add state information to only trigger on DEST ADDRESS
- *
- */
-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;
-
-/*
- * rx_keep flag
- * signals must be one shot
- *
- */
- assign rx_keep = rx_enet_bcast | rx_ipv4_arp;
-
-/* rx_error
- * TODO: should be one shot?
- * */
-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;
-assign tx_sample = (tx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit;
-
-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 @(posedge clk or negedge rstn)
- if (!rstn) begin
- tx_data <= 8'h00;
- tx_k <= 1'b0;
- tx_disp_correct <= 1'b0;
- end
- else begin
- case(tx_mode)
- TX_MODE_AN:
- begin
- tx_data <= tx_data_an;
- tx_k <= tx_k_an;
- tx_disp_correct <= i_tx_disp_correct;
- end
- TX_MODE_IDLE:
- begin
- tx_data <= tx_data_idle;
- tx_k <= tx_k_idle;
- tx_disp_correct <= i_tx_disp_correct;
- end
- default:
- begin
- tx_data <= tx_data_pkt;
- tx_k <= tx_k_pkt;
- tx_disp_correct <= i_tx_disp_correct;
- end
- endcase
- end
-
-// tx_f mux
-always @(*)
- case(tx_mode)
- TX_MODE_AN: tx_f <= tx_f_an;
- TX_MODE_IDLE: tx_f <= tx_f_idle;
- default : tx_f <= tx_f_pkt;
- endcase
-
-
-/*
- * 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
-
-
-/*
- * TX Finished Logic
- */
-assign tx_temp = (tx_mode==TX_MODE_XMT_CUSTOM && tx_byte_cnt==tx_ipv4_length+SZ_ETH_HEADER);
-assign tx_finished = tx_last_byte || (tx_mode==TX_MODE_XMT_CUSTOM && tx_byte_cnt==(tx_ipv4_length+SZ_ETH_HEADER));
-
-
-
-
-/*
-* Transmit Packet State Machine
-*
-*
-* 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_finished && tx_byte_cnt < 60 ) // check if we need to pad?
- tx_state <= TX_ST_5;
- else if ( tx_sample && tx_finished) // 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
-* TODO: add additional states for stuffing header values
-* TODO: this will need to be registered at some point
-*
-*/
-always @(*)
- begin
- tx_f_pkt = 1'b0;
- tx_k_pkt = 1'b0;
- i_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_CUSTOM && tx_byte_cnt == 'd17) begin
- tx_data_pkt = tx_ipv4_length[15:8];
- fcs_dout = tx_ipv4_length[15:8];
- end
- else if (tx_mode == TX_MODE_XMT_CUSTOM && tx_byte_cnt == 'd18) begin
- tx_data_pkt = tx_ipv4_length[7:0];
- fcs_dout = tx_ipv4_length[7:0];
- end
- else if (tx_mode == TX_MODE_XMT_CUSTOM && tx_byte_cnt == 'd25) begin
- tx_data_pkt = tx_ipv4_cksum[15:8];
- fcs_dout = tx_ipv4_cksum[15:8];
- end
- else if (tx_mode == TX_MODE_XMT_CUSTOM && tx_byte_cnt == 'd26) begin
- tx_data_pkt = tx_ipv4_cksum[7:0];
- fcs_dout = tx_ipv4_cksum[7:0];
- end
- else if (tx_mode == TX_MODE_XMT_CUSTOM && tx_byte_cnt == 'd38) begin
- tx_data_pkt = 8'h0 + tx_src_sel[2]; // UDP destination port
- fcs_dout = 8'h0 + tx_src_sel[2];
- end
- else if (tx_mode == TX_MODE_XMT_CUSTOM && tx_byte_cnt == 'd39) begin
- tx_data_pkt = tx_udp_length[15:8];
- fcs_dout = tx_udp_length[15:8];
- end
- else if (tx_mode == TX_MODE_XMT_CUSTOM && tx_byte_cnt == 'd40) begin
- tx_data_pkt = tx_udp_length[7:0];
- fcs_dout = tx_udp_length[7:0];
- end
- else if ( (tx_mode == TX_MODE_XMT_METRICS || tx_mode == TX_MODE_XMT_CUSTOM)
- && 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 FIFO
- tx_last_byte = tx_fifo_d_m1[8];
- end
- end
- TX_ST_5:
- begin
- tx_data_pkt = 8'h00; // pad
- fcs_dout = 8'h00;
- 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
- i_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 if (tx_mode == TX_MODE_XMT_CUSTOM && tx_state == TX_ST_4 && tx_byte_cnt > SZ_ETH_HEADER + SZ_IPV4_HEADER + SZ_UDP_HEADER - 2)
- tx_fifo_re = 1'b1;
- 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 == 'h2 )
- 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 = param_addr;
-assign dpr_do = 9'd0;
-
-/*
- * 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;
-
-// Layer 3 TX Support
-always @(posedge clk or negedge rstn)
- if (!rstn)
- tx_ipv4_length <= 16'h0000;
- else if ( tx_state == TX_ST_1 )
- tx_ipv4_length <= {5'h00, tx_byte_cnt_i} +SZ_IPV4_HEADER + SZ_UDP_HEADER;
-
-// tx_ipv4_cksum
-always @(posedge clk or negedge rstn)
- if (!rstn)
- tx_ipv4_cksum <= 18'h00000;
- else if ( tx_state == TX_ST_2 )
- tx_ipv4_cksum <= {10'h000, dpr_di_reg[7:0]};
- else if ( tx_state == TX_ST_3 )
- tx_ipv4_cksum <= {2'b00, dpr_di_reg[7:0], tx_ipv4_cksum[7:0]};
- else if (tx_state == TX_ST_4 && tx_byte_cnt == 'd1)
- tx_ipv4_cksum <= tx_ipv4_cksum + tx_ipv4_length;
- else if (tx_state == TX_ST_4 && tx_byte_cnt == 'd2)
- tx_ipv4_cksum <= {2'b00,tx_ipv4_cksum[15:0]} + {16'h0000,tx_ipv4_cksum[17:16]};
- else if (tx_state == TX_ST_4 && tx_byte_cnt == 'd3)
- tx_ipv4_cksum <= {2'b00, ~tx_ipv4_cksum[15:0]};
-
-// Layer 4 TX Support
-always @(posedge clk or negedge rstn)
- if (!rstn)
- tx_udp_length <= 16'h0000;
- else if ( tx_state == TX_ST_1 )
- tx_udp_length <= {5'h00, tx_byte_cnt_i} + SZ_UDP_HEADER;
-
-/* Debug TX */
-always @(posedge clk or negedge rstn)
- if (!rstn)
- tx_active <=1'b0;
- else if ( tx_state == TX_ST_1 )
- tx_active <= 1'b1;
- else
- tx_active <= 1'b0;
-
-endmodule
diff --git a/src/mac_rgmii.v b/src/mac_rgmii.v
new file mode 100644
index 0000000..aa96705
--- /dev/null
+++ b/src/mac_rgmii.v
@@ -0,0 +1,998 @@
+/*
+ * mac_rgmii.v
+ *
+ * Copyright 2025 Private Island Networks Inc.
+ * Copyright 2018, 2019, 2020 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 MAC Layer for RGMII Interface
+ *
+ */
+
+module mac_rgmii(
+ input rstn,
+ input phy_resetn, // The external PHY has its reset signal asserted
+ input rx_clk, // rx_clk
+ input tx_clk,
+ input tap_port,
+
+ // Control Interface
+ input cont_clk, // controller clock
+ input cont_sel,
+ input cont_we,
+ input [7:0] cont_addr,
+ input [15:0] cont_d_i,
+ output reg [15:0] cont_d_o,
+ output cont_tgt_ready,
+
+ // ML Engine Interface
+ input mle_active,
+ input mle_if_enable,
+ input mle_if_oe,
+ output reg mle_if_we,
+ output reg mle_if_empty,
+ output reg [8:0] mle_if_d_o,
+
+ // Line State
+ input fixed_speed, // 0 = 100 MBit, 1 = GigE
+ output mode_100Mbit,
+ output reg phy_up,
+
+ // Switch I/F
+ input [2:0] tx_mode,
+ output reg tx_f,
+
+ // RGMII data I/F
+ input [1:0] rx_ctl,
+ input [7:0] rx_d,
+ output reg [1:0] tx_ctl,
+ output reg [7:0] tx_d,
+
+ // RX FCS
+ output reg fcs_rx_init,
+ output reg fcs_rx_enable,
+ output reg [1:0] fcs_rx_addr,
+ output reg [7:0] fcs_rx_dout,
+ input [7:0] fcs_rx_din,
+
+ // TX FCS
+ output reg fcs_tx_init,
+ output reg fcs_tx_enable,
+ output reg [1:0] fcs_tx_addr,
+ output reg [7:0] fcs_tx_dout,
+ input [7:0] fcs_tx_din,
+
+ // MAC RX / FIFO Write
+ output rx_fifo_we,
+ output [8:0] rx_fifo_d,
+ output rx_keep,
+ output reg rx_wr_done,
+ output reg [10:0] rx_byte_cnt,
+ output reg rx_idle,
+ output reg rx_error,
+
+ // MAC TX / FIFO Read
+ input [10:0] tx_byte_cnt_i,
+ input [2:0] tx_src_sel,
+ output reg tx_fifo_re,
+ input [8:0] tx_fifo_d,
+ input tx_fifo_empty,
+
+ // Alternate TX Port utilized by Controller
+ input tx_uc_fifo_empty,
+ input [8:0] tx_uc_fifo_d,
+
+ // Alternate TX Port utilized by MLE
+ input tx_mle_fifo_empty,
+ input [8:0] tx_mle_fifo_d,
+
+ // Packet Filter
+ output rx_sample,
+ output reg ipv4_pkt_start,
+ output trigger,
+
+ output reg[1:0] rx_ctl_m1,
+ output reg[1:0] rx_ctl_m2,
+ output reg[1:0] rx_ctl_m3,
+ output reg[1:0] rx_ctl_m4,
+
+ output reg[7:0] rx_d_m1,
+ output reg[7:0] rx_d_m2,
+ output reg[7:0] rx_d_m3,
+ output reg[7:0] rx_d_m4,
+
+ // Param RAM
+ output reg [10:0] dpr_ad,
+ output dpr_we,
+ output dpr_ce,
+ input [8:0] dpr_di,
+ output [8:0] dpr_do,
+
+ // Flags, Metrics, Interrupts, and Debug
+ output reg rx_enet_bcast,
+ output reg rx_ipv4_arp,
+ output reg [15:0] rx_l3_proto,
+ output reg [11:0] rx_pkt_length,
+ output reg mac_int,
+ output reg rx_sop, // start of packet
+ output reg rx_eop,
+ output reg tx_sop,
+ output reg tx_eop,
+
+ // Debug
+ output reg rx_active,
+ output reg tx_active
+);
+
+`define INCLUDED
+`include "ethernet_params.v"
+`include "rgmii_params.v"
+`undef INCLUDED
+
+
+ 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, RX_ST_DATA_DONE3=4'hb, RX_ST_DATA_DONE4=4'hc;
+
+ 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_EOP=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;
+
+ // Controller Address Space
+ localparam
+ RX_PKT_CNT_ADDR = 16'h0000,
+ TX_PKT_CNT_ADDR = 16'h0004;
+
+ reg [3:0] rx_cnt_100mbit, tx_cnt_100mbit;
+ wire mode_1Gbit;
+
+ wire tx_sample, tx_sample_re;
+ reg rx_packet_complete;
+
+ reg [9:0] rx_line_up_cnt;
+ reg link_up;
+ reg [1:0] link_speed; // TODO: what's the right IEEE name?
+ reg link_duplex;
+ reg phy_up_m1; // previous state
+
+ reg [3:0] rx_state;
+
+ // TODO: consider reorganizing state machines to reuse registers.
+ reg [7:0] tx_d_an, tx_d_idle, tx_data_pkt;
+ reg [1:0] tx_ctl_an, tx_ctl_idle, tx_ctl_pkt;
+ reg tx_f_an, tx_f_idle, tx_f_pkt;
+
+ // Transmit Registers and Wires
+ reg [3:0] tx_state; // transmit state machine
+ reg [10:0] tx_cnt;
+ reg tx_last_byte;
+ wire tx_finished;
+
+ // FIFOs:
+ reg [8:0] tx_fifo_d_m1, tx_fifo_d_m2;
+
+ // FCS
+ reg fcs_tx_addr_e, fcs_rx_addr_e;
+ reg fcs_rx_error;
+
+ // pipeline the param RAM for timing
+ reg [8:0] dpr_di_reg, dpr_di_reg_m1;
+
+ // counter for detecting Ethernet broadcast, only needs to count to 6
+ reg [2:0] rx_enet_bcast_cnt;
+
+ // ML Engine
+ reg [3:0] mle_if_cnt;
+
+ // Metrics
+ reg [15:0] rx_pkt_cnt;
+ reg [15:0] tx_pkt_cnt;
+
+
+ /*
+ * Controller Interface
+ *
+ * System's internal controller can write and read important parameters
+ *
+ */
+
+ // Controller Read Data Mux
+ always @(posedge cont_clk, negedge rstn)
+ if (!rstn)
+ cont_d_o <= 16'hcccc;
+ else
+ case (cont_addr)
+ RX_PKT_CNT_ADDR: cont_d_o <= rx_pkt_cnt;
+ TX_PKT_CNT_ADDR: cont_d_o <= tx_pkt_cnt;
+ default: cont_d_o <= cont_d_o;
+ endcase
+
+ // TODO: add logic to prevent controller reading metastable data
+ assign cont_tgt_ready = 1'b1;
+
+
+ /*
+ * ML Engine Interface
+ *
+ */
+
+ // mle_if_cnt:
+ // TODO: write cnt at end, rework this logic and make it more meaningful
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn) begin
+ mle_if_cnt <= 4'd0;
+ mle_if_empty <= 1'b1;
+ mle_if_we <= 1'b0;
+ end
+ else if (rx_eop) begin
+ mle_if_cnt <= 4'd4;
+ mle_if_empty <= 1'b0;
+ mle_if_we <= 1'b0;
+ end
+ else if (mle_if_cnt > 4'd0 && mle_if_enable) begin
+ mle_if_cnt <= mle_if_cnt - 1'b1;
+ mle_if_empty <= 1'b0;
+ mle_if_we <= 1'b1;
+ end
+ else if (mle_if_cnt == 'd0 && mle_if_enable) begin
+ mle_if_empty <= 1'b1;
+ mle_if_we <= 1'b0;
+ end
+
+
+ // mle_if_d_o:
+ always @(posedge tx_clk, negedge rstn)
+ if(!rstn)
+ mle_if_d_o <= 'd0;
+ else if (mle_if_enable) begin
+ if (mle_if_cnt > 4'd1)
+ mle_if_d_o <= mle_if_d_o + 1'b1;
+ else if (mle_if_cnt == 4'd1)
+ mle_if_d_o <= (mle_if_d_o + 1'b1) | 9'h100;
+ else
+ mle_if_d_o <= 'd0;
+ end
+
+
+
+ /*
+ * RX DIRECTION
+ *
+ */
+
+ /*
+ * A shallow pool of RX registers for analysis
+ */
+ always @(posedge rx_clk, negedge rstn)
+ begin
+ if (!rstn) begin
+ rx_ctl_m1 <= NORMAL_INTERFRAME;
+ rx_ctl_m2 <= NORMAL_INTERFRAME;
+ rx_ctl_m3 <= NORMAL_INTERFRAME;
+ rx_ctl_m4 <= NORMAL_INTERFRAME;
+ rx_d_m1 <= 8'h0;
+ rx_d_m2 <= 8'h0;
+ rx_d_m3 <= 8'h0;
+ rx_d_m4 <= 8'h0;
+ end
+ else begin
+ rx_ctl_m1 <= rx_ctl;
+ rx_ctl_m2 <= rx_ctl_m1;
+ rx_ctl_m3 <= rx_ctl_m2;
+ rx_ctl_m4 <= rx_ctl_m3;
+ rx_d_m1 <= rx_d;
+ rx_d_m2 <= rx_d_m1;
+ rx_d_m3 <= rx_d_m2;
+ rx_d_m4 <= rx_d_m3;
+ end
+ end
+
+
+ // Link State
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ rx_line_up_cnt <= 10'd0;
+ else if ((rx_ctl_m1 == NORMAL_INTERFRAME && rx_d_m1 == {D_IDLE, D_IDLE}) || rx_ctl_m1 == NORMAL_DATA_RX) begin
+ if (rx_line_up_cnt < 10'd1023)
+ rx_line_up_cnt <= rx_line_up_cnt + 1'b1;
+ end
+ else
+ rx_line_up_cnt <= 10'd0;
+
+ //
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ phy_up <= 1'b0;
+ else if (rx_line_up_cnt >= 10'd5)
+ phy_up <= 1'b1;
+ else
+ phy_up <= 1'b0;
+
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ phy_up_m1 <= 1'b0;
+ else
+ phy_up_m1 <= phy_up;
+
+ // capture link metrics during normal inter-frame
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn) begin
+ link_up <= 1'b0;
+ link_speed <= 2'b11; // reserved
+ link_duplex <= 1'b0;
+ end
+ else if (rx_ctl == NORMAL_INTERFRAME) begin
+ link_up <= rx_d[0];
+ link_speed <= rx_d[2:1];
+ link_duplex <= rx_d[3];
+ end
+
+
+ assign mode_1Gbit = 1'b1;
+ assign mode_100Mbit = !mode_1Gbit;
+
+ // RX 100 Mbit support
+ assign rx_sample = (rx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0;
+ always @(posedge rx_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 rx_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 && phy_up_m1 )
+ case ( rx_state )
+ RX_ST_IDLE: if (rx_ctl_m1 == NORMAL_DATA_RX) //
+ rx_state <= RX_ST_SOP;
+ RX_ST_SOP: if ( rx_sample ) //
+ rx_state <= RX_ST_PREAMBLE;
+ RX_ST_PREAMBLE: if ( rx_sample && rx_d_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;
+ RX_ST_DATA_DONE1: if ( rx_sample )
+ rx_state <= RX_ST_DATA_DONE2;
+ RX_ST_DATA_DONE2: if ( rx_sample )
+ rx_state <= RX_ST_DATA_DONE3;
+ RX_ST_DATA_DONE3: if ( rx_sample )
+ rx_state <= RX_ST_DATA_DONE4;
+ RX_ST_DATA_DONE4: if ( rx_sample )
+ rx_state <= rx_state;
+ 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)
+ * TODO: Add state information to only trigger on DEST ADDRESS
+ *
+ */
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ rx_enet_bcast_cnt <= 3'h0;
+ else if ( rx_sample )
+ if (rx_d_m1 == 9'hff)
+ rx_enet_bcast_cnt <= rx_enet_bcast_cnt + 1'b1;
+ else
+ rx_enet_bcast_cnt <= 3'h0;
+
+ /* Ethernet Broadcast Dest Address, must be a one shot */
+ always @(posedge rx_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 rx_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 rx_clk, negedge rstn)
+ if ( !rstn )
+ rx_l3_proto <= 16'd0;
+ else if ( rx_sop )
+ rx_l3_proto <= 16'd0;
+ else if ( rx_sample && rx_state == RX_ST_MAC_TYPE0 )
+ rx_l3_proto <= { rx_d_m2, rx_d_m1 };
+
+ // assert ipv4 ARP flag for filtering operations
+ always @(posedge rx_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;
+
+ /*
+ * rx_keep flag
+ * signals must be one shot
+ */
+ // assign rx_keep = rx_enet_bcast | rx_ipv4_arp;
+ assign rx_keep = rx_state == RX_ST_MAC_TYPE1;
+
+ // 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'b1;
+ else if (fcs_rx_error)
+ rx_error = 1'b1;
+ else
+ rx_error = 1'b0;
+
+ /* rx_byte_cnt */
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ rx_byte_cnt <= 11'd0;
+ else if (rx_sample)
+ if ( rx_state == RX_ST_IDLE || rx_state == RX_ST_PREAMBLE )
+ rx_byte_cnt <= 11'd0;
+ else if ( rx_state == RX_ST_MAC_TYPE0 )
+ rx_byte_cnt <= 11'd1;
+ else
+ rx_byte_cnt <= rx_byte_cnt + 1'b1;
+
+ /* rx_pkt_length */
+ always @(posedge rx_clk, negedge rstn)
+ if ( !rstn )
+ rx_pkt_length <= 12'd0;
+ else if ( rx_sop )
+ rx_pkt_length <= 12'd0;
+ else if (rx_sample)
+ if ( rx_l3_proto == ETHER_TYPE_IPV4 && rx_state == RX_ST_DATA && rx_byte_cnt == 'h4 )
+ rx_pkt_length <= { rx_d_m2[2:0], rx_d_m1 };
+ else if ( rx_l3_proto == ETHER_TYPE_IPV6 && rx_state == RX_ST_DATA && rx_byte_cnt == 'h6 )
+ rx_pkt_length <= { rx_d_m2[2:0], rx_d_m1 } + 'd40;
+ else if ( rx_l3_proto == ETHER_TYPE_ARP && rx_state == RX_ST_DATA )
+ rx_pkt_length <= 'd46;
+
+ /* ipv4 flag */
+ always @(posedge rx_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;
+
+ // implement minimum Ethernet frame of 64 bytes
+ always @(*)
+ if (rx_pkt_length >= 12'd46)
+ rx_packet_complete = (rx_sample && rx_state >= RX_ST_DATA && rx_pkt_length == rx_byte_cnt);
+ else
+ rx_packet_complete = (rx_sample && rx_state >= RX_ST_DATA && rx_byte_cnt == 12'd46);
+
+ // FIFO data interface
+ assign rx_fifo_d[7:0] = rx_d_m1;
+ assign rx_fifo_d[8] = rx_packet_complete;
+
+
+ // TODO: take into account errors RXERR
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ rx_sop <= 1'b0;
+ else if (rx_ctl_m1 ==NORMAL_DATA_RX && rx_ctl_m2 == NORMAL_INTERFRAME)
+ rx_sop <= 1'b1;
+ else
+ rx_sop <= 1'b0;
+
+ /*
+ * rx_idle
+ */
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ rx_idle <= 1'b0;
+ else if (rx_state == RX_ST_IDLE)
+ rx_idle <= 1'b1;
+ else
+ rx_idle <= 1'b0;
+
+ /*
+ * rx_eop
+ */
+ always @(posedge rx_clk, negedge rstn)
+ if (!rstn)
+ rx_eop <= 1'b0;
+ else if (rx_ctl_m2 ==NORMAL_DATA_RX && rx_ctl_m1 == NORMAL_INTERFRAME)
+ 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 rx_clk or negedge rstn)
+ if (!rstn)
+ mac_int <=1'b0;
+ else if ( rx_error )
+ mac_int <= 1'b1;
+ else
+ mac_int <= 1'b0;
+
+
+ /* RX Metrics and Debug */
+ always @(posedge rx_clk or negedge rstn)
+ if (!rstn)
+ rx_active <=1'b0;
+ else if ( rx_state != 0 )
+ rx_active <= 1'b1;
+ else
+ rx_active <= 1'b0;
+
+ // rx_pkt_cnt
+ always @(posedge rx_clk or negedge rstn)
+ if (!rstn)
+ rx_pkt_cnt <= 16'd0;
+ else if (rx_eop)
+ rx_pkt_cnt <= rx_pkt_cnt + 1'b1;
+
+ always @(*)
+ if (mode_1Gbit && (rx_state > RX_ST_SFD && rx_state <= RX_ST_DATA_DONE0) )
+ fcs_rx_enable = 1'b1;
+ else if ( mode_100Mbit && rx_sample && (rx_state > RX_ST_PREAMBLE && rx_state <= RX_ST_DATA_DONE0))
+ fcs_rx_enable = 1'b1;
+ else
+ fcs_rx_enable = 1'b0;
+
+ /* FCS RX State Machine */
+ always @(posedge rx_clk or negedge rstn)
+ if (!rstn) begin
+ fcs_rx_init <= 1'b0;
+ fcs_rx_addr_e <= 1'b0;
+ fcs_rx_dout <= 8'h00;
+ end
+ else if(rx_state == RX_ST_SOP)
+ fcs_rx_init = 1'b1;
+ else if (rx_state > RX_ST_DATA && rx_state <= RX_ST_DATA_DONE3) begin
+ fcs_rx_init <= 1'b0;
+ fcs_rx_addr_e <= 1'b1;
+ fcs_rx_dout <= 8'h00;
+ end
+ else begin
+ fcs_rx_init <= 1'b0;
+ fcs_rx_addr_e <= 1'b0;
+ fcs_rx_dout <= rx_d_m1;
+ end
+
+ always @(posedge rx_clk or negedge rstn)
+ begin
+ if ( !rstn )
+ fcs_rx_addr <= 2'b00;
+ else if (rx_sample)
+ if ( !fcs_rx_addr_e )
+ fcs_rx_addr <= 2'b00;
+ else
+ fcs_rx_addr <= fcs_rx_addr + 1'b1;
+ end
+
+ // Test FCS RX result
+ always @(posedge rx_clk or negedge rstn)
+ if ( !rstn )
+ fcs_rx_error <= 1'b0;
+ else if (fcs_rx_addr_e && rx_d_m2 != fcs_rx_din)
+ fcs_rx_error <= 1'b1;
+ else
+ fcs_rx_error <= 1'b0;
+
+
+ /*
+ * TX DIRECTION
+ *
+ */
+
+
+ // TX 100 Mbit support
+ assign tx_sample_re = (tx_cnt_100mbit == 4'd8 && mode_100Mbit) || !mode_100Mbit;
+ assign tx_sample = (tx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit;
+
+ always @(posedge tx_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'b1;
+
+ /*
+ *
+ * Transmit Mux
+ */
+ always @(posedge tx_clk or negedge rstn)
+ if (!rstn) begin
+ tx_d <= 8'hDD;
+ tx_ctl <= 2'b00;
+ end
+ else begin
+ case(tx_mode)
+ TX_MODE_AN: // before phy_up == 1
+ begin
+ tx_d <= tx_d_an;
+ tx_ctl <= tx_ctl_an;
+ end
+ TX_MODE_IDLE:
+ begin
+ tx_d <= tx_d_idle;
+ tx_ctl <= tx_ctl_idle;
+ end
+ default:
+ begin
+ tx_d <= tx_data_pkt;
+ tx_ctl <= tx_ctl_pkt;
+ end
+ endcase
+ end
+
+
+
+ // tx_f mux
+ always @(*)
+ case(tx_mode)
+ TX_MODE_AN: tx_f <= tx_f_an;
+ TX_MODE_IDLE: tx_f <= tx_f_idle;
+ default : tx_f <= tx_f_pkt;
+ endcase
+
+ /* AN SM */
+ always @(*)
+ begin
+ tx_f_an = 1'b1;
+ case(tx_cnt[0])
+ 3'd0:
+ begin
+ tx_d_an = 8'hDD;
+ tx_ctl_an = 2'b00;
+ end
+ default: begin
+ tx_d_an = 8'hDD;
+ tx_ctl_an = 2'b00;
+ end
+ endcase
+ end
+
+ /* IDLE SM */
+ always @(*)
+ begin
+ tx_f_idle = 1'b1;
+ case(tx_cnt[0])
+ 3'd0:
+ begin
+ tx_d_idle = 8'hDD;
+ tx_ctl_idle = 2'b00;
+ end
+ default: begin
+ tx_d_idle = 8'hDD;
+ tx_ctl_idle = 2'b00;
+ end
+ endcase
+ end
+
+ /*
+ * TX Finished Logic
+ */
+ assign tx_finished = tx_last_byte || tx_cnt == 11'd2000;
+
+ /*
+ * Transmit Packet State Machine
+ *
+ */
+ always @(posedge tx_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 ) //
+ tx_state <= TX_ST_1;
+ TX_ST_1: if ( tx_sample && tx_cnt == 11'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_cnt
+ TX_ST_3: if ( tx_sample )
+ tx_state <= TX_ST_4; // preamble 0xD5
+ TX_ST_4: if ( tx_sample && tx_finished && tx_cnt < 60 ) // check if we need to pad?
+ tx_state <= TX_ST_5;
+ else if ( tx_sample && tx_finished) // check if we're done
+ tx_state <= TX_ST_6;
+ TX_ST_5: if ( tx_sample && tx_cnt >= 60 ) // pad state, test for sufficient frame size
+ tx_state <= TX_ST_6;
+ TX_ST_6: if ( tx_sample && fcs_tx_addr == 2'b10 ) // Start FCS
+ tx_state <= TX_ST_7;
+ TX_ST_7: if (tx_sample && fcs_tx_addr == 2'b11 ) // Finish FCS
+ tx_state <= TX_ST_EOP;
+ TX_ST_EOP: tx_state <= TX_ST_0; // EOP
+ default: tx_state <= tx_state;
+ endcase
+ end
+
+ /*
+ * tx related data mux and control signals
+ * TODO: add additional states for stuffing header values
+ * TODO: this will need to be registered at some point
+ *
+ */
+ always @(*)
+ begin
+ tx_f_pkt = 1'b0;
+ tx_ctl_pkt = 2'b11;
+ tx_last_byte = 1'b0;
+ fcs_tx_init = 1'b0;
+ fcs_tx_addr_e = 1'b0;
+ fcs_tx_dout = tx_fifo_d_m1[7:0];
+ case(tx_state)
+ TX_ST_0:
+ begin
+ tx_data_pkt = 8'hDD; // start of packet
+ tx_ctl_pkt = 2'b00;
+ fcs_tx_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_CUSTOM && tx_cnt <= SZ_ETH_HEADER) begin
+ tx_data_pkt = dpr_di_reg_m1[7:0]; // packet headers
+ fcs_tx_dout = dpr_di_reg_m1[7:0];
+ end
+ else if (tx_mode == TX_MODE_XMT_CUSTOM && tx_cnt <= SZ_ETH_HEADER + SZ_IPV4_HEADER + SZ_UDP_HEADER )
+ if(tx_src_sel == TX_SRC_SEL_UC) begin
+ tx_data_pkt = tx_uc_fifo_d[7:0]; // packet headers
+ fcs_tx_dout = tx_uc_fifo_d[7:0];
+ end
+ else begin // mle
+ tx_data_pkt = tx_mle_fifo_d[7:0];
+ fcs_tx_dout = tx_mle_fifo_d[7:0];
+ end
+ else if (tx_mode == TX_MODE_XMT_CUSTOM)
+ begin
+ tx_data_pkt = tx_fifo_d_m2[7:0]; // read data from FIFO with extra delay
+ fcs_tx_dout = tx_fifo_d_m2[7:0];
+ tx_last_byte = tx_fifo_d_m2[8];
+ end
+ else
+ begin
+ tx_data_pkt = tx_fifo_d_m1[7:0]; // read data from FIFO
+ tx_last_byte = tx_fifo_d_m1[8];
+ end
+ end
+ TX_ST_5:
+ begin
+ tx_data_pkt = 8'h00; // pad
+ fcs_tx_dout = 8'h00;
+ end
+ TX_ST_6: begin
+ tx_data_pkt = fcs_tx_din; // read from fcs
+ fcs_tx_addr_e = 1'b1;
+ end
+ TX_ST_7: begin
+ tx_data_pkt = fcs_tx_din; // read from fcs
+ fcs_tx_addr_e = 1'b1;
+ end
+ TX_ST_EOP:
+ begin
+ tx_data_pkt = 8'hDD; // end of packet
+ tx_ctl_pkt = 2'b00;
+ tx_f_pkt = 1'b1;
+ end
+ default:
+ begin
+ tx_data_pkt = 8'hDD;
+ tx_ctl_pkt = 2'b00;
+ 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_EOP ) // 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 if (tx_mode == TX_MODE_XMT_CUSTOM && tx_state == TX_ST_4 && tx_cnt > SZ_ETH_HEADER + SZ_IPV4_HEADER + SZ_UDP_HEADER - 3)
+ tx_fifo_re = 1'b1;
+ else
+ tx_fifo_re = 1'b0;
+
+
+
+
+ // tx_cnt: count number of transmit bytes / octets
+ always @(posedge tx_clk, negedge rstn)
+ if (!rstn)
+ tx_cnt <= 11'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_cnt <= 11'h0;
+ else if ( tx_state == TX_ST_2 )
+ tx_cnt <= 11'h0; // start counting the Ethernet Frame after preamble
+ else if (tx_cnt < 11'd2000)
+ tx_cnt <= tx_cnt + 1'b1;
+
+ /*
+ * pipeline data from FIFO
+ */
+ always @(posedge tx_clk or negedge rstn)
+ begin
+ if ( !rstn ) begin
+ tx_fifo_d_m1 <= 9'h0;
+ tx_fifo_d_m2 <= 9'h0;
+ end
+ else begin
+ tx_fifo_d_m1 <= tx_fifo_d;
+ tx_fifo_d_m2 <= tx_fifo_d_m1;
+ end
+ end
+
+ /*
+ * FCS
+ */
+ always @(posedge tx_clk or negedge rstn)
+ begin
+ if ( !rstn )
+ fcs_tx_addr <= 2'b00;
+ else if (tx_sample)
+ if ( !fcs_tx_addr_e )
+ fcs_tx_addr <= 2'b00;
+ else
+ fcs_tx_addr <= fcs_tx_addr + 1'b1;
+ end
+
+ always @(*)
+ if (mode_1Gbit && (tx_state == TX_ST_4 || tx_state == TX_ST_5) )
+ fcs_tx_enable = 1'b1;
+ else if ( mode_100Mbit && tx_sample && (tx_state == TX_ST_4 || tx_state == TX_ST_5) )
+ fcs_tx_enable = 1'b1;
+ else
+ fcs_tx_enable = 1'b0;
+
+ /*
+ * DPRAM, param ram Control for TAP port
+ */
+
+
+ always @(posedge tx_clk, negedge rstn)
+ if (!rstn)
+ dpr_ad <= 11'h0;
+ else if (tx_sample)
+ if ( mode_100Mbit && tx_state == TX_ST_1 && tx_cnt == 11'h5 )
+ dpr_ad <= 'h0;
+ else if ( mode_1Gbit && tx_state == TX_ST_1 && tx_cnt == 11'h1 )
+ dpr_ad <= 'h0;
+ else
+ dpr_ad <= dpr_ad + 1'b1;
+
+
+ always @(posedge tx_clk or negedge rstn)
+ if ( !rstn ) begin
+ dpr_di_reg <= 9'h0;
+ dpr_di_reg_m1 <= 9'h0;
+ end
+ else if (tx_sample) begin
+ dpr_di_reg <= dpr_di;
+ dpr_di_reg_m1 <= dpr_di_reg;
+ end
+
+
+ assign dpr_we = 1'b0;
+ assign dpr_ce = 1'b1;
+ assign dpr_do = 9'd0;
+
+ /*
+ * tx_sop, K27_7, 0xFB /S/ Start_of_Packet
+ * We choose to not include TX_MODE_CUSTOM_PKT for this metric
+ */
+ always @(posedge tx_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 tx_clk or negedge rstn)
+ if (!rstn)
+ tx_eop <=1'b0;
+ else if ( tx_state == TX_ST_EOP )
+ tx_eop <= 1'b1;
+ else
+ tx_eop <= 1'b0;
+
+ /* TX Debug and Metrics */
+ always @(posedge tx_clk or negedge rstn)
+ if (!rstn)
+ tx_active <=1'b0;
+ else if ( tx_state == TX_ST_1 )
+ tx_active <= 1'b1;
+ else
+ tx_active <= 1'b0;
+
+ always @(posedge tx_clk, negedge rstn)
+ if (!rstn)
+ tx_pkt_cnt <= 16'd0;
+ else if (tx_eop)
+ tx_pkt_cnt <= tx_pkt_cnt + 1'b1;
+
+
+
+endmodule
diff --git a/src/mdio.v b/src/mdio.v
index 3339dcc..21dfa71 100644
--- a/src/mdio.v
+++ b/src/mdio.v
@@ -1,6 +1,7 @@
/*
* mdio.v
*
+ * Copyright (C) 2025 Private Island Networks Inc.
* Copyright (C) 2018, 2019 Mind Chasers Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,8 +21,6 @@
*/
-`timescale 1ns /10ps
-
module mdio(
input rstn,
input mdc, // clock
@@ -69,7 +68,7 @@ module mdio(
else if ( ld )
state <= 0;
else if ( run )
- state <= state + 1;
+ state <= state + 1'b1;
end
// register data for MDIO TX
diff --git a/src/mdio_cont.v b/src/mdio_cont.v
index ad595fd..a31a30d 100644
--- a/src/mdio_cont.v
+++ b/src/mdio_cont.v
@@ -1,6 +1,7 @@
/*
- * mdio_cont.v
+ * mdio_cont.v
*
+ * Copyright (C) 2025 Private Island Networks Inc.
* Copyright (C) 2018, 2019 Mind Chasers Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +20,7 @@
*
*/
-`timescale 1ns /10ps
-
-module mdio_controller #(parameter ADDR_SZ = 6)
+module mdio_cont #(parameter ADDR_SZ = 6)
(
// system interface
@@ -86,69 +85,59 @@ module mdio_controller #(parameter ADDR_SZ = 6)
/* 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
+ if ( !rstn )
+ work_done <= 1'b0;
+ else if ( cont_state == S1 && di[7] == 1'b1 )
+ work_done <= 1'b1;
+ else
+ work_done <= 1'b0;
/* 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
+ 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;
/* 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
+ if (!rstn)
+ rwn <= 1'b1;
+ else if (work_done)
+ rwn <= 1'b1;
+ else if ( cont_state == S1 )
+ rwn <= di[5];
/* 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
+ if (!rstn)
+ reg_addr <= 5'h0;
+ else if (work_done)
+ reg_addr <= 5'h0;
+ else if ( cont_state == S1 )
+ reg_addr <= di[4:0];
/* 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
+ if (!rstn)
+ addr <= 0;
+ else if (work_done)
+ addr <= 0;
+ else if (work_start)
+ addr <= routine_addr[ADDR_SZ-1:0];
+ else if ( cont_state == S3 || cont_state == S4 || cont_state == S8 )
+ addr <= addr + 1'b1;
// 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
+ 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;
// combinatorial logic here
assign ld_dl = ( cont_state == S4 ) ? 1'b1 : 1'b0;
diff --git a/src/mdio_data_ti.v b/src/mdio_data_ti.v
index aef537d..b2e7cf4 100644
--- a/src/mdio_data_ti.v
+++ b/src/mdio_data_ti.v
@@ -1,6 +1,7 @@
/*
* mdio_data_ti.v ( TI DP83867 PHY )
*
+ * Copyright (C) 2025 Private Island Networks Inc.
* Copyright (C) 2018, 2019 Mind Chasers Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +20,9 @@
*
*/
-
-
-`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,
@@ -36,93 +32,94 @@ module mdio_data_ti #(parameter ADDR_SZ = 7)
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
+
+ localparam R = 8'h20;
+ localparam W = 8'h00;
+ localparam EOP = 8'h80;
+
+ /* REGCR[15:14] holds the access function: address (00), data with no post increment (01),
+ data with post increment on read and writes (10) and data with post increment on writes only (11). */
+ localparam REGCR = 5'h0d; // MDIO Manageable MMD access control
+ localparam ADDAR = 5'h0e;
+
+ reg [7:0]data;
+
+ assign d = oe ? data : 8'h00;
+
+ always @ (*)
+ begin
+ case (ad)
+ /*
+ Subroutine: SGMII Init ( i ): read PHY Control Register (PHYCR), Address 0x0010
+ */
+
+ // read the PHYCR register, SGMII Enable is bit 11
+ 0: data = R|8'h10; //
+
+ /*
+ Subroutine: Read Live Status ( s )
+ */
+ // read the live copper status PHYSTS (0x0011)
+ 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
+ */
+ 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 from 0 to 31.
+ */
+ 48: data = { 3'b001, reg_addr };
+
+ /*
+ Subroutine: : Write a register from 0 to 31.
+ */
+ 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/src/metrics.v b/src/metrics.v
deleted file mode 100644
index bce3389..0000000
--- a/src/metrics.v
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * 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/src/ml_engine.v b/src/ml_engine.v
new file mode 100644
index 0000000..ec50d87
--- /dev/null
+++ b/src/ml_engine.v
@@ -0,0 +1,563 @@
+/*
+ * ml_engine.v
+ *
+ * Copyright (C) 2025 Private Island Networks 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: Machine Learning Engine Framework
+ *
+ * see https://privateisland.tech/dev/pi-ml-framework
+ *
+ */
+
+module ml_engine #(parameter NUM_IF=8, DPRAM_DEPTH=1024)
+(
+ input rstn,
+ input clk,
+
+ // controller interface
+ input cont_clk,
+ input cont_sel,
+ input cont_we,
+ input [15:0] cont_addr,
+ input [15:0] cont_d_i,
+ output reg [15:0] cont_d_o,
+ output cont_tgt_ready,
+
+ // module interface
+ output reg evt_start,
+ output reg evt_active,
+ output reg [NUM_IF-1:0] enable,
+ input [NUM_IF-1:0] empty,
+ input clk_e,
+ input we,
+ input [8:0] d_i,
+
+ // switch interface
+ output reg fifo_empty_o,
+ input fifo_re,
+ output [8:0] fifo_d_o,
+ output [10:0] byte_cnt
+
+ // action interface
+
+ // memory/coefficient interface
+
+);
+
+`define DIRECT_OUTPUT // this disables processing and second DPRAM
+
+ localparam BLOCK_OFFSET = 'h80; // 128 bytes
+ localparam BLOCK_OFFSET_SHIT = 'd7; // Left shift to multiple by 128
+
+`ifdef SIMULATION
+ localparam EVT_CNT_DELAY_1 = 32'h0000_0010,
+ EVT_CNT_DELAY_2 = 32'h0000_0020,
+ EVT_CNT_OUT = 32'h0000_0030,
+ EVT_CNT_STOP = 32'h0000_00C0,
+ EVT_CNT_MAX = 32'h0000_0100;
+`else
+ localparam EVT_CNT_DELAY_1 = 32'h0000_0010,
+ EVT_CNT_DELAY_2 = 32'h0000_0020,
+ EVT_CNT_OUT = 32'h0000_0030,
+ EVT_CNT_STOP = 32'h0800_0000,
+ EVT_CNT_MAX = 32'h1000_0000; // Sets max event interval
+`endif
+
+
+ // Controller I/F Addresses
+ localparam MLE_ENABLE_ADDR = 'h0;
+
+ // FSM States: two loops: event/block and data unit (DU)
+ localparam MLE_ST_IDLE=4'h0, MLE_ST_START=4'h1, MLE_ST_EVT_START = 4'h2,
+ MLE_ST_DU_START = 4'h3, MLE_ST_DU_CONT = 4'h4, MLE_ST_DU_DONE = 4'h5,
+ MLE_ST_EVT_DONE = 4'h6;
+
+ // variables
+ reg mle_enable, mle_enable_m1, mle_enable_m2;
+ reg[31:0] evt_counter;
+ reg evt_delay_1, evt_delay_2, evt_delay_out;
+
+ reg [NUM_IF-1:0] empty_m1, empty_m2;
+
+ // Set up 1K DPRAM as 8 blocks of 128 words.
+ wire [$clog2(DPRAM_DEPTH)-1:0] wr_addr0, wr_addr1;
+ wire [$clog2(DPRAM_DEPTH)-1:0] rd_addr0, rd_addr1;
+ reg [2:0] wr_block0, wr_block1;
+ reg [2:0] rd_block0, rd_block1;
+ reg [6:0] wr_ptr0, wr_ptr1;
+ reg [6:0] rd_ptr0, rd_ptr1;
+ wire rd_oe0;
+ reg [6:0] cnt0;
+ reg [$clog2(DPRAM_DEPTH)-1:0] pkt_sz;
+
+ wire [8:0] d_s0_o, d_i_internal;
+
+ reg [NUM_IF-1:0] enable_logic_active; // enable logic active
+
+ wire we0, we1;
+
+ reg [3:0] mle_0_state, mle_1_state, mle_2_state;
+ reg d_out_avail;
+ wire [8:0] fifo_d;
+ reg fifo_empty;
+ reg fifo_d_out_flag;
+
+ // Debug
+ reg [8*12:1] mle_0_state_str;
+
+
+ /******************************************************
+
+ Controller Interface
+
+ System's internal controller can write and read important parameters
+
+ ******************************************************/
+
+ // Controller Read Data Mux
+ always @(posedge cont_clk, negedge rstn)
+ if (!rstn)
+ cont_d_o <= 16'hcccc;
+ else
+ case (cont_addr)
+ MLE_ENABLE_ADDR: cont_d_o <= mle_enable;
+ default: cont_d_o <= cont_d_o;
+ endcase
+
+ // TODO: add logic to prevent controller reading metastable data
+ assign cont_tgt_ready = 1'b1;
+
+
+ // mle_enable: enable / disable the MLE
+ always @(posedge cont_clk, negedge rstn)
+ if (!rstn)
+ mle_enable <= 1'b0;
+ else if (cont_we && cont_sel && cont_addr == MLE_ENABLE_ADDR)
+ mle_enable <= cont_d_i[0];
+
+ // synchronizer for controller vars
+ always @(posedge clk, negedge rstn)
+ if( !rstn ) begin
+ mle_enable_m1 <= 1'b0;
+ mle_enable_m2 <= 1'b0;
+ end
+ else begin
+ mle_enable_m1 <= mle_enable;
+ mle_enable_m2 <= mle_enable_m1;
+ end
+
+ /******************************************************
+
+ Event Logic
+
+ ******************************************************/
+
+ // evt_counter:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ evt_counter <= EVT_CNT_MAX;
+ else if (evt_counter == EVT_CNT_MAX)
+ evt_counter <= 'd0;
+ else
+ evt_counter <= evt_counter + 1'b1;
+
+ // evt_start:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ evt_start <= 'd0;
+ else if (mle_enable_m2 && evt_counter == 32'd0)
+ evt_start <= 1'b1;
+ else
+ evt_start <= 1'b0;
+
+ // evt_active:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ evt_active <= 'd0;
+ else if (evt_counter == EVT_CNT_STOP)
+ evt_active <= 1'b0;
+ else if (evt_start)
+ evt_active <= 'd1;
+
+ /******************************************************
+
+ FSM_0, Accept data from RX modules into DPRAM Step 0
+
+ ******************************************************/
+
+ // FSM_0:
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ mle_0_state <= MLE_ST_IDLE;
+ else
+ case (mle_0_state)
+ MLE_ST_IDLE: if (evt_start && !(&empty))
+ mle_0_state <= MLE_ST_EVT_START;
+ MLE_ST_EVT_START: if (!(&empty)) // Is a DU available?
+ mle_0_state <= MLE_ST_DU_START;
+ MLE_ST_DU_START:
+ mle_0_state <= MLE_ST_DU_CONT;
+ MLE_ST_DU_CONT: if (d_i[8]) // Done flag set?
+ mle_0_state <= MLE_ST_DU_DONE;
+ MLE_ST_DU_DONE: if (&empty) // Is another DU available?
+ mle_0_state <= MLE_ST_EVT_DONE;
+ else
+ mle_0_state <= MLE_ST_DU_START;
+ MLE_ST_EVT_DONE: if (1'b1)
+ mle_0_state <= MLE_ST_IDLE;
+ default: mle_0_state <= mle_0_state;
+ endcase
+
+
+ always @(*)
+ case(mle_0_state)
+ MLE_ST_IDLE: mle_0_state_str <= "IDLE";
+ MLE_ST_START: mle_0_state_str <= "START";
+ MLE_ST_EVT_START: mle_0_state_str <= "EVT_START";
+ MLE_ST_DU_START: mle_0_state_str <= "DU_START";
+ MLE_ST_DU_CONT: mle_0_state_str <= "DU_CONT";
+ MLE_ST_DU_DONE: mle_0_state_str <= "DU_DONE";
+ MLE_ST_EVT_DONE: mle_0_state_str <= "EVT_DONE";
+ default: mle_0_state_str <= "UNDEFINED";
+ endcase
+
+
+ // wr_block0:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_block0 <= 'd1;
+ else if (evt_start)
+ wr_block0 <= wr_block0 + 1'b1;
+
+ // wr_ptr0: dpram_s0 write address
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_ptr0 <= 'd0;
+ else if (!(|enable))
+ wr_ptr0 <= 'd0;
+ else if (we0)
+ wr_ptr0 <= wr_ptr0 + 1'b1;
+
+ assign wr_addr0 = (wr_block0 << BLOCK_OFFSET_SHIT) + wr_ptr0;
+ assign we0 = we;
+
+ // enable_logic_active: assert a bit to indicate which enable logic block is active
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ enable_logic_active <= 'd0;
+ else if (mle_0_state == MLE_ST_IDLE)
+ enable_logic_active <= 'd0;
+ else if (mle_0_state == MLE_ST_EVT_START)
+ enable_logic_active <= 1'b1;
+ else if (mle_0_state == MLE_ST_DU_DONE)
+ enable_logic_active <= enable_logic_active << 1;
+
+ // enable logic: assert each enable until empty
+ generate
+ genvar i;
+ for (i=0; i< NUM_IF; i=i+1) begin: enable_logic
+ always @(posedge clk, negedge rstn)
+ if(!rstn)
+ enable[i] <= 1'b0;
+ else if (enable[i] && empty[i])
+ enable[i] <= 1'b0;
+ else if (enable_logic_active[i] && !empty[i])
+ enable[i] <= 1'b1;
+ else
+ enable[i] <= 1'b0;
+
+ always @(posedge clk, negedge rstn)
+ if(!rstn) begin
+ empty_m1[i] <= 1'b1;
+ empty_m2[i] <= 1'b1;
+ end
+ else begin
+ empty_m1[i] <= empty[i];
+ empty_m2[i] <= empty_m1[i];
+ end
+ end
+ endgenerate
+
+ // cnt0: count number of words written into dpram_s0 per event cycle
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ cnt0 <= 'd0;
+ else if (!evt_active)
+ cnt0 <= 'd0;
+ else if (|enable && !(|empty))
+ cnt0 <= cnt0 + 1'b1;
+
+
+ // Instantiate x9 DPRAM for Step 0 DPRAM
+ dpram_inf #(.ADDR_WIDTH(10),.DPRAM_INIT("mle_ram_0.txt")) dpram_s0(
+ .rstn(rstn),
+ .a_clk(clk),
+ .a_clk_e(clk_e),
+ .a_we(we0),
+ .a_oe(1'b0),
+ .a_addr(wr_addr0),
+ .a_din(d_i),
+ .a_dout(),
+ // port B
+ .b_clk(clk),
+ .b_clk_e(1'b1),
+ .b_we(1'b0),
+ .b_oe(rd_oe0),
+ .b_addr(rd_addr0),
+ .b_din(9'h0),
+ .b_dout(d_s0_o)
+ );
+
+`ifdef DIRECT_OUTPUT
+
+ assign rd_oe0 = fifo_re;
+ assign fifo_d = d_s0_o;
+ assign fifo_d_o[7:0] = fifo_empty ? 8'h00 : d_s0_o[7:0];
+ assign fifo_d_o[8] = fifo_empty_o ? 1'b1 : 1'b0;
+ assign rd_addr0 = rd_addr1;
+ assign wr_addr1 = wr_addr0;
+ assign we1 = we0;
+
+`else
+
+
+ /******************************************************
+
+ FSM_1: Read data from DPRAM Step 0.
+ read and store code. FSM logic/path may depend on code
+ Do I need a size field?
+
+ ******************************************************/
+
+ // evt_delay_1:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ evt_delay_1 <= 'd0;
+ else if (evt_counter == EVT_CNT_DELAY_1)
+ evt_delay_1 <= 1'b1;
+ else
+ evt_delay_1 <= 1'b0;
+
+ // FSM_1:
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ mle_1_state <= MLE_ST_IDLE;
+ else if (evt_active)
+ case (mle_1_state)
+ MLE_ST_IDLE: if (evt_delay_1)
+ mle_1_state <= MLE_ST_DU_START;
+ MLE_ST_DU_START:
+ mle_1_state <= MLE_ST_DU_CONT;
+ MLE_ST_DU_CONT: if (d_s0_o[8])
+ mle_1_state <= MLE_ST_DU_DONE;
+ MLE_ST_DU_DONE: if (d_s0_o[8])
+ mle_1_state <= MLE_ST_IDLE;
+ else
+ mle_1_state <= MLE_ST_DU_START;
+ default: mle_1_state <= mle_1_state;
+ endcase
+
+ // rd_block0:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ rd_block0 <= 'd0;
+ else if (evt_delay_1)
+ rd_block0 <= wr_block0;
+
+ // rd_ptr0: dpram_s0 read pointer
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ rd_ptr0 <= 'd0;
+ else
+ rd_ptr0 <= rd_ptr0 + 1'b1;
+
+ assign rd_addr0 = rd_block0 << BLOCK_OFFSET_SHIT + rd_ptr0;
+
+ // rd_oe0:
+ assign rd_oe0 = 1'b1;
+
+ // wr_block1:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_block1 <= 'd1;
+ else if (evt_delay_2)
+ wr_block1 <= wr_block0;
+
+ // wr_ptr1: dpram_s1 write address
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ wr_ptr1 <= 'd0;
+ else if (1'b0)
+ wr_ptr1 <= wr_ptr1 + 1'b1;
+
+ assign wr_addr1 = wr_block1 << BLOCK_OFFSET_SHIT + wr_ptr1;
+
+
+
+ // we1: write enable for dpram_s1
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ we1 <= 1'b0;
+ else if (1'b0)
+ we1 <= 1'b1;
+ else
+ we1 <= 1'b0;
+
+
+
+ // Instantiate 1k x 9 DPRAM
+ // dpram_s1: port B interfaces with Switch
+ dpram_inf #(.ADDR_WIDTH(10), .DPRAM_INIT("mle_ram_1.txt")) dpram_s1(
+ .rstn(rstn),
+ .a_clk(clk),
+ .a_clk_e(1'b1),
+ .a_we(we1),
+ .a_oe(1'b0),
+ .a_addr(wr_addr1),
+ .a_din(d_i_internal),
+ .a_dout(),
+ // port B
+ .b_clk(clk),
+ .b_clk_e(1'b1),
+ .b_we(1'b0),
+ .b_oe(fifo_re),
+ .b_addr(rd_addr1),
+ .b_din(9'h0),
+ .b_dout(fifo_d)
+ );
+
+ /******************************************************
+
+ FSM_2, Transfer data from Processing to DPRAM Out
+
+ ******************************************************/
+
+ // evt_delay_2:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ evt_delay_2 <= 'd0;
+ else if (evt_counter == EVT_CNT_DELAY_2)
+ evt_delay_2 <= 1'b1;
+ else
+ evt_delay_2 <= 1'b0;
+
+
+ // FSM_2:
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ mle_2_state <= MLE_ST_IDLE;
+ else if (evt_active)
+ case (mle_2_state)
+ MLE_ST_EVT_START: if (1'b1)
+ mle_2_state <= MLE_ST_DU_START;
+ MLE_ST_DU_START: if (1'b1)
+ mle_2_state <= MLE_ST_DU_CONT;
+ MLE_ST_DU_CONT: if (1'b1)
+ mle_2_state <= MLE_ST_DU_DONE;
+ MLE_ST_DU_DONE: if (1'b1)
+ mle_2_state <= MLE_ST_EVT_DONE;
+ MLE_ST_EVT_DONE: if (1'b1)
+ mle_2_state <= MLE_ST_IDLE;
+ default: mle_2_state <= mle_2_state;
+ endcase
+
+
+ /******************************************************
+
+ Output, Switch reads from dpram_s1
+
+ ******************************************************/
+
+
+`endif
+
+ // d_out_avail: data for output is available
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ d_out_avail <= 1'b0;
+ else if (evt_delay_out)
+ d_out_avail <= 1'b0;
+ else if (we1)
+ d_out_avail <= 1'b1;
+
+ // evt_delay_out:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ evt_delay_out <= 'd0;
+ else if (evt_counter == EVT_CNT_OUT && d_out_avail)
+ evt_delay_out <= 1'b1;
+ else
+ evt_delay_out <= 1'b0;
+
+ // fifo_d_out_flag: bit 8 from dpram_s1
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ fifo_d_out_flag <= 1'b0;
+ else if (fifo_re)
+ fifo_d_out_flag <= fifo_d[8];
+ else
+ fifo_d_out_flag <= 1'b0;
+
+ assign byte_cnt = BLOCK_OFFSET;
+
+
+ // fifo_empty: assert when the last byte from the DPRAM is read
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ fifo_empty <= 1'b1;
+ else if (fifo_d_out_flag)
+ fifo_empty <= 1'b1;
+ else if (evt_delay_out)
+ fifo_empty <= 1'b0;
+
+
+ // fifo_empty_o: module output to indicate to reader to stop
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ fifo_empty_o <= 1'b1;
+ else if (rd_addr1 == (rd_block1 << BLOCK_OFFSET_SHIT) + (byte_cnt-1))
+ fifo_empty_o <= 1'b1;
+ else if (evt_delay_out)
+ fifo_empty_o <= 1'b0;
+
+
+ // rd_block1:
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ rd_block1 <= 'd0;
+ else if (evt_delay_out)
+ rd_block1 <= wr_block0;
+
+ // rd_ptr1: dpram_s1 write address
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ rd_ptr1 <= 'd0;
+ else if (evt_delay_out)
+ rd_ptr1 <= 'd0;
+ else if (fifo_re)
+ rd_ptr1 <= rd_ptr1 + 1'b1;
+
+ assign rd_addr1 = (rd_block1 << BLOCK_OFFSET_SHIT) + rd_ptr1;
+
+ // pkt_sz: store number of bytes in dpram_s1 to use as packet size
+ always @(posedge clk, negedge rstn)
+ if( !rstn )
+ pkt_sz <= 'd0;
+ else
+ pkt_sz <= pkt_sz;
+
+
+
+endmodule
diff --git a/src/pkt_filter.v b/src/pkt_filter.v
index 9140c74..843315a 100644
--- a/src/pkt_filter.v
+++ b/src/pkt_filter.v
@@ -1,7 +1,8 @@
/*
- * pkt_filter.v
+ * pkt_filter.v
*
- * Copyright 2018, 2019, 2020, 2021 Mind Chasers Inc.
+ * Copyright (C) 2025 Private Island Networks Inc.
+ * Copyright (C) 2018-2022 Mind Chasers Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,26 +20,24 @@
*
*/
-`timescale 1ns /10ps
-
-module pkt_filter #(parameter DEPTH = 4,
- parameter DEPTHW = 2,
- parameter WIDTH = 32)
+module pkt_filter #(parameter DEPTH = 8, parameter DATAW = 32)
(
input rstn,
input clk,
// input for programming
+ input prgclk,
input sel,
input we,
- input [DEPTHW+1:0] addr,
- input [7:0] d_in,
+ input [$clog2(DEPTH)-1:0] addr,
+ input [DATAW-1:0] d_i,
+ output [DATAW-1:0] d_o,
// 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,
+ input[7:0] rx_d_m1,
+ input[7:0] rx_d_m2,
+ input[7:0] rx_d_m3,
+ input[7:0] rx_d_m4,
// filter
input new_frame, // assert for each new frame to reset state machines
@@ -48,48 +47,47 @@ module pkt_filter #(parameter DEPTH = 4,
output reg keep
);
-reg trigger_m1;
-wire match;
-
-
-/* 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 )
-);
-
+ reg trigger_m1;
+ wire match;
+ /* 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), .DATAW(DATAW)) cam_0(
+ .rstn( rstn ),
+ .clk( clk ),
+
+ // Input for programming
+ .prgclk(prgclk),
+ .sel( sel ),
+ .we( we ),
+ .addr(addr),
+ .d_i(d_i),
+ .d_o(d_o),
+ // CAM action
+ .search( trigger ),
+ .search_address( { rx_d_m4, rx_d_m3, rx_d_m2, rx_d_m1 } ),
+ .match( match )
+ );
+
endmodule
diff --git a/src/rgmii_params.v b/src/rgmii_params.v
new file mode 100644
index 0000000..d0f4390
--- /dev/null
+++ b/src/rgmii_params.v
@@ -0,0 +1,46 @@
+/*
+ * rgmii_params.v
+ *
+ * Copyright 2025 Private Island Networks 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: RGMII Related Parameters
+ *
+ */
+
+`ifdef INCLUDED
+
+ // PHY Status Params (Table 4)
+ localparam LINK_UP = 4'b0001,
+ LINK_DOWN = 4'b0000;
+
+ localparam CLOCK_SPEED_2_5 = 4'b0000,
+ CLOCK_SPEED_25 = 4'b0010,
+ CLOCK_SPEED_125 = 4'b0100,
+ CLOCK_SPEED_RSVD = 4'b0110;
+
+ localparam FULL_DUPLEX = 4'b1000,
+ HALF_DUPLEX = 4'b0000;
+
+ localparam D_IDLE = FULL_DUPLEX | CLOCK_SPEED_125 | LINK_UP;
+
+
+ // RGMII CTL Bits
+ localparam NORMAL_INTERFRAME = 2'b00,
+ CARRIER_STATUS = 2'b01,
+ ERROR_DATA_RX = 2'b10,
+ NORMAL_DATA_RX = 2'b11;
+
+
+`endif
diff --git a/src/sgmii_params.v b/src/sgmii_params.v
deleted file mode 100644
index a36160e..0000000
--- a/src/sgmii_params.v
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * sgmii_params.v
- *
- * Copyright 2018, 2019, 2020 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_0 = 8'h1c,
- K28_1 = 8'h3c,
- K28_2 = 8'h5c,
- K28_3 = 8'h7c,
- K28_4 = 8'h9c,
- K28_5 = 8'hbc,
- K28_6 = 8'hdc,
- K29_7 = 8'hfd, // /T/ End_of_Packet
- K_ERROR = 8'hee;
diff --git a/src/spi.v b/src/spi.v
deleted file mode 100644
index d7c054b..0000000
--- a/src/spi.v
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * spi.v
- *
- * Copyright (C) 2018, 2019, 2020, 2021 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 spi_clk_low, spi_clk_low_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
-
-
- // create two seq one shots for actions
- always @(posedge clk or negedge bit_cnt_rstn)
- begin
- if ( !bit_cnt_rstn )
- spi_clk_low <= 0;
- else if ( spi_cs && spi_clk && !spi_clk_m1 && spi_clk_m2 )
- spi_clk_low <= 1'b1;
- else
- spi_clk_low <= 1'b0;
- end
-
- always @(posedge clk or negedge bit_cnt_rstn)
- begin
- if ( !bit_cnt_rstn )
- spi_clk_low_m1 <= 0;
- else
- spi_clk_low_m1 <= spi_clk_low;
- 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_m1 ) 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)
- if (!bit_cnt_rstn)
- we <= 1'b0;
- else if ( spi_cs )
- if ( spi_clk_high && !rwn && bit_cnt == 5'd26 )
- we <= 1'b1;
- else
- we <= 1'b0;
-
- /* SPI data output enable */
- assign spi_d_oe = spi_cs;
-
-
- /*
- * clock out msb first.
- *
- */
- always @(posedge clk or negedge bit_cnt_rstn)
- 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 && bit_cnt < 'd26 )
- spi_d_o <= word_cnt['d25-bit_cnt];
- else if ( rwn && bit_cnt >= 'd18 && bit_cnt < 'd26 )
- spi_d_o <= d_i['d25-bit_cnt];
- else
- spi_d_o <= 1'b0;
- end
- else if (spi_cs && spi_clk_high_m1 && rwn && bit_cnt == 'd26)
- spi_d_o <= d_i[8];
-
- assign oe = mem_sel && rwn;
-
- /* 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
- \ No newline at end of file
diff --git a/src/switch.v b/src/switch.v
index fa6d75e..661d848 100644
--- a/src/switch.v
+++ b/src/switch.v
@@ -38,18 +38,21 @@ module switch #(parameter NUM_PHYS=3)
input [8:0] rx_d_20,
input [8:0] rx_d_21,
input [8:0] rx_d_u0,
+ input [8:0] rx_mle_fifo_d,
// RX FIFO read enables
output reg rx_fifo_re_01, rx_fifo_re_02, rx_fifo_re_0u,
output reg rx_fifo_re_10, rx_fifo_re_12,
output reg rx_fifo_re_20, rx_fifo_re_21,
output reg rx_fifo_re_u0,
+ output reg rx_fifo_re_mle,
// RX FIFO Empty flags
input rx_fifo_empty_01, rx_fifo_empty_02, rx_fifo_empty_0u,
input rx_fifo_empty_10, rx_fifo_empty_12,
input rx_fifo_empty_20, rx_fifo_empty_21,
input rx_fifo_empty_u0,
+ input rx_fifo_empty_mle,
input [NUM_PHYS-1:0] rx_wr_done,
@@ -58,6 +61,7 @@ module switch #(parameter NUM_PHYS=3)
input [10:0] rx1_byte_cnt,
input [10:0] rx2_byte_cnt,
input [10:0] rxu_byte_cnt,
+ input [10:0] rx_mle_byte_cnt,
// TX FIFO output from internal muxes
output reg [8:0] tx_d0,
@@ -94,348 +98,358 @@ module switch #(parameter NUM_PHYS=3)
input tx_custom
);
-
-
-// IPG for Port 0
-wire ipg_met;
-reg [6:0] ipg_cnt;
-
-reg rx_fifo_empty_u0_m1, rx_fifo_empty_u0_m2;
-
-
-reg [3:0] fr_100mbit_cnt;
-reg i_tx_fifo_we_u;
-reg [10:0] i_rx0_byte_cnt, i_rx1_byte_cnt, i_rx2_byte_cnt;
-
-`define INCLUDED
-`include "ethernet_params.v"
-`undef INCLUDED
-
-localparam SEL_PHY0 = 3'b000,
- SEL_PHY1 = 3'b001,
- SEL_PHY2 = 3'b010,
- SEL_UC = 3'b111;
-
-
-// capture the rx_byte_cnt values when write is done. TODO: needs to be a shallow Q to match FIFO
-always @(posedge clk, negedge rstn)
- if ( !rstn )
- i_rx0_byte_cnt <= 'h0;
- else if ( rx_wr_done[0])
- i_rx0_byte_cnt <= rx0_byte_cnt;
-
-always @(posedge clk, negedge rstn)
- if ( !rstn )
- i_rx1_byte_cnt <= 'h0;
- else if ( rx_wr_done[1])
- i_rx1_byte_cnt <= rx1_byte_cnt;
-
-always @(posedge clk, negedge rstn)
- if ( !rstn )
- i_rx2_byte_cnt <= 'h0;
- else if ( rx_wr_done[2])
- i_rx2_byte_cnt <= rx2_byte_cnt;
-
-assign ipg_met = ipg_cnt >= IPG ? 1'b1 : 1'b0;
-
-/* free running 100Mbit counter */
-always @(posedge clk, negedge rstn)
- 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'b1;
-
-/* IPG counter */
-always @(posedge clk, negedge rstn)
- 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'b1;
-
-
-// Transfer to the pclk domain
-always @(posedge clk, negedge rstn)
- if ( !rstn ) begin
- rx_fifo_empty_u0_m1 <= 1'b1;
- rx_fifo_empty_u0_m2 <= 1'b1;
- end
- else begin
- rx_fifo_empty_u0_m1 <= rx_fifo_empty_u0;
- rx_fifo_empty_u0_m2 <= rx_fifo_empty_u0_m1;
- end
-
-
-// TX0 Switch Logic
-// Possible sources: u, 1, 2
-always @(posedge clk, negedge rstn)
- if ( !rstn )
- begin
- tx_mode0 <= TX_MODE_AN;
- tx0_src_sel <= SEL_PHY1;
- tx0_byte_cnt <= 'h0;
- 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 (!rx_fifo_empty_u0_m2 ) // controller has data
- begin
- tx_mode0 <= TX_MODE_XMT_CUSTOM;
- tx0_src_sel <= SEL_UC;
- tx0_byte_cnt <= rxu_byte_cnt;
- end
-`ifdef PHY2_PRESENT
- else if (tx0_src_sel==SEL_PHY1 && !rx_fifo_empty_20 )
- begin
- tx_mode0 <= TX_MODE_XMT_PKT;
- tx0_src_sel <= SEL_PHY2;
- tx0_byte_cnt <= i_rx2_byte_cnt;
- end
-`endif
- else if (!rx_fifo_empty_10 )
- begin
- tx_mode0 <= TX_MODE_XMT_PKT;
- tx0_src_sel <= SEL_PHY1;
- tx0_byte_cnt <= i_rx1_byte_cnt;
- end
-`ifdef PHY2_PRESENT
- else if (!rx_fifo_empty_20 )
- begin
- tx_mode0 <= TX_MODE_XMT_PKT;
- tx0_src_sel <= SEL_PHY2;
- tx0_byte_cnt <= i_rx2_byte_cnt;
- end
-`endif
- 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
+ `define INCLUDED
+ `include "ethernet_params.v"
+ `undef INCLUDED
+ // IPG for Port 0
+ wire ipg_met;
+ reg [6:0] ipg_cnt;
+
+ reg rx_fifo_empty_u0_m1, rx_fifo_empty_u0_m2;
+
+
+ reg [3:0] fr_100mbit_cnt;
+ reg i_tx_fifo_we_u;
+ reg [10:0] i_rx0_byte_cnt, i_rx1_byte_cnt, i_rx2_byte_cnt;
-// 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 = rx_d_u0;
- 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_u0 = 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_UC: rx_fifo_re_u0 = 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_UC: tx_fifo_empty[0] = rx_fifo_empty_u0_m2;
- default: tx_fifo_empty[0] = 1'b1;
- endcase
-end
-// TX1 Switch Logic
-// Possible sources: 0, 2 in priority
-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;
-`ifdef PHY2_PRESENT
- else if (tx1_src_sel==SEL_PHY0 && !rx_fifo_empty_21 )
- begin
- tx_mode1 <= TX_MODE_XMT_PKT;
- tx1_src_sel <= SEL_PHY2;
- end
-`endif
- else if (!rx_fifo_empty_01 )
- begin
- tx_mode1 <= TX_MODE_XMT_PKT;
- tx1_src_sel <= SEL_PHY0;
- end
-`ifdef PHY2_PRESENT
- else if (!rx_fifo_empty_21 )
- begin
- tx_mode1 <= TX_MODE_XMT_PKT;
- tx1_src_sel <= SEL_PHY2;
- end
-`endif
- 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
+ // capture the rx_byte_cnt values when write is done. TODO: needs to be a shallow Q to match FIFO
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ i_rx0_byte_cnt <= 'h0;
+ else if ( rx_wr_done[0])
+ i_rx0_byte_cnt <= rx0_byte_cnt;
-// 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_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;
- case(tx1_src_sel)
- SEL_PHY0: rx_fifo_re_01 = tx_fifo_re[1];
- SEL_PHY2: rx_fifo_re_21 = 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_UC: tx_fifo_empty[1] = 1'b1;
- default: tx_fifo_empty[1] = 1'b1;
- endcase
-end
-
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ i_rx1_byte_cnt <= 'h0;
+ else if ( rx_wr_done[1])
+ i_rx1_byte_cnt <= rx1_byte_cnt;
+
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ i_rx2_byte_cnt <= 'h0;
+ else if ( rx_wr_done[2])
+ i_rx2_byte_cnt <= rx2_byte_cnt;
+
+ assign ipg_met = ipg_cnt >= IPG ? 1'b1 : 1'b0;
+
+ /* free running 100Mbit counter */
+ always @(posedge clk, negedge rstn)
+ 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'b1;
+
+ /* IPG counter */
+ always @(posedge clk, negedge rstn)
+ 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'b1;
+
+
+ // Transfer to the pclk domain
+ always @(posedge clk, negedge rstn)
+ if ( !rstn ) begin
+ rx_fifo_empty_u0_m1 <= 1'b1;
+ rx_fifo_empty_u0_m2 <= 1'b1;
+ end
+ else begin
+ rx_fifo_empty_u0_m1 <= rx_fifo_empty_u0;
+ rx_fifo_empty_u0_m2 <= rx_fifo_empty_u0_m1;
+ end
+
-/*
- * TX2 Switch Logic
- * Possible Sources: 0, 1
- */
-always @(posedge clk, negedge rstn)
- if ( !rstn )
+ // TX0 Switch Logic
+ // Possible sources: u, mle, 1, 2
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
begin
- tx_mode2 <= TX_MODE_AN;
- tx2_src_sel <= SEL_PHY0;
+ tx_mode0 <= TX_MODE_AN;
+ tx0_src_sel <= TX_SRC_SEL_PHY1;
+ tx0_byte_cnt <= 'h0;
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 )
+ 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 (!rx_fifo_empty_mle) // mle has data
+ begin
+ tx_mode0 <= TX_MODE_XMT_CUSTOM;
+ tx0_src_sel <= TX_SRC_SEL_MLE;
+ tx0_byte_cnt <= rx_mle_byte_cnt;
+ end
+ else if (!rx_fifo_empty_u0_m2 ) // controller has data
begin
- tx_mode2 <= TX_MODE_XMT_PKT;
- tx2_src_sel <= SEL_PHY1;
+ tx_mode0 <= TX_MODE_XMT_CUSTOM;
+ tx0_src_sel <= TX_SRC_SEL_UC;
+ tx0_byte_cnt <= rxu_byte_cnt;
end
- else if (!rx_fifo_empty_02 )
+ `ifdef PHY2_PRESENT
+ else if (tx0_src_sel==TX_SRC_SEL_PHY1 && !rx_fifo_empty_20 )
begin
- tx_mode2 <= TX_MODE_XMT_PKT;
- tx2_src_sel <= SEL_PHY0;
+ tx_mode0 <= TX_MODE_XMT_PKT;
+ tx0_src_sel <= TX_SRC_SEL_PHY2;
+ tx0_byte_cnt <= i_rx2_byte_cnt;
+ end
+ `endif
+ else if (!rx_fifo_empty_10 )
+ begin
+ tx_mode0 <= TX_MODE_XMT_PKT;
+ tx0_src_sel <= TX_SRC_SEL_PHY1;
+ tx0_byte_cnt <= i_rx1_byte_cnt;
end
- else if (!rx_fifo_empty_12 )
+ `ifdef PHY2_PRESENT
+ else if (!rx_fifo_empty_20 )
begin
- tx_mode2 <= TX_MODE_XMT_PKT;
- tx2_src_sel <= SEL_PHY1;
+ tx_mode0 <= TX_MODE_XMT_PKT;
+ tx0_src_sel <= TX_SRC_SEL_PHY2;
+ tx0_byte_cnt <= i_rx2_byte_cnt;
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;
+ `endif
+ 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)
+ TX_SRC_SEL_PHY0: tx_d0 = 9'h000;
+ TX_SRC_SEL_PHY1: tx_d0 = rx_d_10;
+ TX_SRC_SEL_PHY2: tx_d0 = rx_d_20;
+ TX_SRC_SEL_MLE: tx_d0 = rx_mle_fifo_d;
+ TX_SRC_SEL_UC: tx_d0 = rx_d_u0;
+ default: tx_d0 = 9'h000;
endcase
+ end
-// 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;
- 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;
- case(tx2_src_sel)
- SEL_PHY0: rx_fifo_re_02 = tx_fifo_re[2];
- SEL_PHY1: rx_fifo_re_12 = tx_fifo_re[2];
- endcase
-end
+ // TX0 FIFO read enable
+ always @(*) begin
+ rx_fifo_re_10 = 1'b0;
+ rx_fifo_re_20 = 1'b0;
+ rx_fifo_re_mle = 1'b0;
+ rx_fifo_re_u0 = 1'b0;
-// 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; //
- default: tx_fifo_empty[2] = 1'b1;
- endcase
-end
+ case(tx0_src_sel)
+ TX_SRC_SEL_PHY1: rx_fifo_re_10 = tx_fifo_re[0];
+ TX_SRC_SEL_PHY2: rx_fifo_re_20 = tx_fifo_re[0];
+ TX_SRC_SEL_MLE: rx_fifo_re_mle = tx_fifo_re[0];
+ TX_SRC_SEL_UC: rx_fifo_re_u0 = tx_fifo_re[0];
+ endcase
+ end
-
-
-/*
- * Transmit Logic for UC
- *
- * The only possible driver is PHY0
- *
- * We need to delay the fifo_we one clock since the DPRAM read data comes out one clock delayed
- */
+ // TX0 FIFO Empty Routing
+ always @(*) begin
+ case(tx0_src_sel)
+ TX_SRC_SEL_PHY1: tx_fifo_empty[0] = rx_fifo_empty_10;
+ TX_SRC_SEL_PHY2: tx_fifo_empty[0] = rx_fifo_empty_20;
+ TX_SRC_SEL_MLE: tx_fifo_empty[0] = rx_fifo_empty_mle;
+ TX_SRC_SEL_UC: tx_fifo_empty[0] = rx_fifo_empty_u0_m2;
+ default: tx_fifo_empty[0] = 1'b1;
+ endcase
+ end
-assign tx_du = rx_d_0u;
-
-always @(*)
- if ( !rx_fifo_empty_0u )
+ // TX1 Switch Logic
+ // Possible sources: 0, 2 in priority
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
begin
- i_tx_fifo_we_u = 1'b1;
- rx_fifo_re_0u = 1'b1;
- end
- else
- begin
- i_tx_fifo_we_u = 1'b0;
- rx_fifo_re_0u = 1'b0;
+ tx_mode1 <= TX_MODE_AN;
+ tx1_src_sel <= TX_SRC_SEL_PHY0;
+ tx1_byte_cnt <= 'h0;
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;
+ `ifdef PHY2_PRESENT
+ else if (tx1_src_sel==TX_SRC_SEL_PHY0 && !rx_fifo_empty_21 )
+ begin
+ tx_mode1 <= TX_MODE_XMT_PKT;
+ tx1_src_sel <= TX_SRC_SEL_PHY2;
+ tx1_byte_cnt <= i_rx1_byte_cnt;
+ end
+ `endif
+ else if (!rx_fifo_empty_01 )
+ begin
+ tx_mode1 <= TX_MODE_XMT_PKT;
+ tx1_src_sel <= TX_SRC_SEL_PHY0;
+ tx1_byte_cnt <= i_rx0_byte_cnt;
+ end
+ `ifdef PHY2_PRESENT
+ else if (!rx_fifo_empty_21 )
+ begin
+ tx_mode1 <= TX_MODE_XMT_PKT;
+ tx1_src_sel <= TX_SRC_SEL_PHY2;
+ tx1_byte_cnt <= i_rx1_byte_cnt;
+ end
+ `endif
+ 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)
+ TX_SRC_SEL_PHY0: tx_d1 = rx_d_01;
+ TX_SRC_SEL_PHY1: tx_d1 = 9'h000;
+ TX_SRC_SEL_PHY2: tx_d1 = rx_d_21;
+ TX_SRC_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;
+ case(tx1_src_sel)
+ TX_SRC_SEL_PHY0: rx_fifo_re_01 = tx_fifo_re[1];
+ TX_SRC_SEL_PHY2: rx_fifo_re_21 = tx_fifo_re[1];
+ endcase
+ end
+
+ // TX1 FIFO Empty Routing
+ always @(*) begin
+ case(tx1_src_sel)
+ TX_SRC_SEL_PHY0: tx_fifo_empty[1] = rx_fifo_empty_01;
+ TX_SRC_SEL_PHY1: tx_fifo_empty[1] = 1'b1;
+ TX_SRC_SEL_PHY2: tx_fifo_empty[1] = rx_fifo_empty_21;
+ TX_SRC_SEL_UC: tx_fifo_empty[1] = 1'b1;
+ default: tx_fifo_empty[1] = 1'b1;
+ endcase
+ end
+
-always @(posedge clk, negedge rstn)
- if ( !rstn )
- tx_fifo_we_u <= 1'b0;
- else
- tx_fifo_we_u <= i_tx_fifo_we_u;
+ // TX2 Switch Logic
+ // Possible sources: 0, 1
+ always @(posedge clk, negedge rstn)
+ if ( !rstn )
+ begin
+ tx_mode2 <= TX_MODE_AN;
+ tx2_src_sel <= TX_SRC_SEL_PHY0;
+ tx2_byte_cnt <= 'h0;
+ 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==TX_SRC_SEL_PHY0 && !rx_fifo_empty_12 )
+ begin
+ tx_mode2 <= TX_MODE_XMT_PKT;
+ tx2_src_sel <= TX_SRC_SEL_PHY1;
+ tx2_byte_cnt <= i_rx1_byte_cnt;
+ end
+ else if (!rx_fifo_empty_02 )
+ begin
+ tx_mode2 <= TX_MODE_XMT_PKT;
+ tx2_src_sel <= TX_SRC_SEL_PHY0;
+ tx2_byte_cnt <= i_rx0_byte_cnt;
+ end
+ else if (!rx_fifo_empty_12 )
+ begin
+ tx_mode2 <= TX_MODE_XMT_PKT;
+ tx2_src_sel <= TX_SRC_SEL_PHY1;
+ tx2_byte_cnt <= i_rx1_byte_cnt;
+ 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)
+ TX_SRC_SEL_PHY0: tx_d2 = rx_d_02;
+ TX_SRC_SEL_PHY1: tx_d2 = rx_d_12;
+ TX_SRC_SEL_PHY2: tx_d2 = 9'h000;
+ 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;
+ case(tx2_src_sel)
+ TX_SRC_SEL_PHY0: rx_fifo_re_02 = tx_fifo_re[2];
+ TX_SRC_SEL_PHY1: rx_fifo_re_12 = tx_fifo_re[2];
+ endcase
+ end
+
+ // TX2 FIFO Empty Routing
+ always @(*) begin
+ case(tx2_src_sel)
+ TX_SRC_SEL_PHY0: tx_fifo_empty[2] = rx_fifo_empty_02;
+ TX_SRC_SEL_PHY1: tx_fifo_empty[2] = rx_fifo_empty_12;
+ TX_SRC_SEL_PHY2: tx_fifo_empty[2] = 1'b0; //
+ default: tx_fifo_empty[2] = 1'b1;
+ endcase
+ end
+
+
+
+ /*
+ * Transmit Logic for UC
+ *
+ * The only possible driver is PHY0
+ *
+ * We need to delay the fifo_we one clock since the DPRAM read data comes out one clock delayed
+ */
+
+ assign tx_du = rx_d_0u;
+
+ always @(*)
+ if ( !rx_fifo_empty_0u )
+ begin
+ i_tx_fifo_we_u = 1'b1;
+ rx_fifo_re_0u = 1'b1;
+ end
+ else
+ begin
+ i_tx_fifo_we_u = 1'b0;
+ rx_fifo_re_0u = 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 \ No newline at end of file
diff --git a/src/sync_fifo.v b/src/sync_fifo.v
index 56c83d4..52c15cd 100644
--- a/src/sync_fifo.v
+++ b/src/sync_fifo.v
@@ -1,6 +1,7 @@
/*
- * sync_fifo.v
+ * sync_fifo.v
*
+ * Copyright (C) 2025 Private Island Networks Inc.
* Copyright (C) 2018, 2019 Mind Chasers Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +20,6 @@
*
*/
-`timescale 1ns /10ps
-
module sync_fifo #(parameter FIFO_PTR = 11,
FIFO_WIDTH = 9,
FIFO_DEPTH = 2048 )
@@ -47,7 +46,9 @@ module sync_fifo #(parameter FIFO_PTR = 11,
);
+`define INCLUDED
`include "ethernet_params.v"
+`undef INCLUDED
reg [FIFO_PTR-1:0] wr_ptr;
reg [FIFO_PTR-1:0] rd_ptr;
@@ -60,7 +61,7 @@ always @(posedge clk, negedge rstn)
else if ( reset_ptrs )
wr_ptr <= 'd0;
else if ( we )
- wr_ptr <= wr_ptr + 1;
+ wr_ptr <= wr_ptr + 1'b1;
/*
* rd_ptr
@@ -72,7 +73,7 @@ always @(posedge clk, negedge rstn)
else if ( reset_ptrs )
rd_ptr <= 'd0;
else if ( re && !empty )
- rd_ptr <= rd_ptr + 1;
+ rd_ptr <= rd_ptr + 1'b1;
assign empty = ( rd_ptr == wr_ptr ) ? 1'b1 : 1'b0;
assign almost_full = wr_bytes_available < MTU ? 1'b1 : 1'b0;
@@ -88,7 +89,7 @@ always @(posedge clk, negedge rstn)
assign active = ~empty;
-dpram dpram_fifo(
+dpram_inf dpram_fifo(
.rstn( rstn ),
.a_clk( clk ),
.a_clk_e( 1'b1 ),
diff --git a/src/udp_rx.v b/src/udp_rx.v
new file mode 100644
index 0000000..8b548aa
--- /dev/null
+++ b/src/udp_rx.v
@@ -0,0 +1,117 @@
+/*
+ * udp_rx.v
+ *
+ * Copyright (C) 2023-2025 Private Island Networks Inc.
+ * Copyright (C) 2021 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 UDP
+ *
+ *
+ * 0-15 16:32
+ * 0 Source port Destination port
+ * 4 Length Checksum
+ *
+ */
+
+module udp_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_sample, // enable in case we have connected at 100 Mbit
+ 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_port,
+ output reg trigger_dst_port,
+ output reg keep
+);
+
+ /* Byte Address (when last byte of field is present on rx_data_m1 ) */
+ localparam UDP_SRC_PORT=0, UDP_DST_PORT=2, UDP_LEN=4, UDP_CKSUM =6;
+
+ 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;
+
+ reg [3:0] rx_state;
+ reg [3:0] rx_byte_cnt;
+ wire rx_error;
+
+ /*
+ * rx_state machine
+ * capture a UDP 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_sample && pkt_start ) // synch reset
+ rx_byte_cnt <= 0;
+ else if ( rx_sample && rx_byte_cnt <= 4'h7 )
+ rx_byte_cnt <= rx_byte_cnt + 1'b1;
+
+ /*
+ * Packet Filter Trigger(s)
+ *
+ */
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ trigger_src_port <= 1'b0;
+ else if ( rx_sample && rx_byte_cnt == UDP_SRC_PORT )
+ trigger_src_port <= 1'b1;
+ else
+ trigger_src_port <= 1'b0;
+
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ trigger_dst_port <= 1'b0;
+ else if ( rx_sample && rx_byte_cnt == UDP_DST_PORT )
+ trigger_dst_port <= 1'b1;
+ else
+ trigger_dst_port <= 1'b0;
+
+ assign pkt_complete = ( rx_byte_cnt == 3'h7 );
+ assign rx_error = 0;
+
+endmodule
diff --git a/src/udp_rx_c.v b/src/udp_rx_c.v
new file mode 100644
index 0000000..546990f
--- /dev/null
+++ b/src/udp_rx_c.v
@@ -0,0 +1,89 @@
+/*
+ * udp_rx_c.v
+ *
+ * Copyright (C) 2023-2025 Private Island Networks Inc.
+ * Copyright (C) 2021 Mind Chasers Inc.
+ *
+ * function: Receive State Machine and Logic for UDP for the internall Controller
+ *
+ *
+ * 0-15 16:32
+ * 0 Source port Destination port
+ * 4 Length Checksum
+ *
+ * UDP Parser for Controller Port
+ */
+
+module udp_rx_c #(parameter UDP_PORT_MATCH_H=8'h90, parameter UDP_PORT_MATCH_L=8'h20) (
+ input rstn,
+ input clk,
+
+ // control
+ input phy_up,
+
+ // packet data
+ input pkt_start, // assert for each new frame to start state machines
+ input rx_sample, // enable in case we have connected at 100 Mbit
+ 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 udp_port_match
+);
+
+ /* Byte Address (when last byte of field is present on rx_data_m1 ) */
+ localparam UDP_SRC_PORT=0, UDP_DST_PORT=2, UDP_LEN=4, UDP_CKSUM =6;
+
+ 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;
+
+ reg [3:0] rx_state;
+ reg [3:0] rx_byte_cnt;
+
+ /*
+ * rx_state machine
+ * capture a UDP Packet
+ *
+ */
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_state <= RX_ST_IDLE;
+ else if ( rx_eop || !phy_up ) // EOP will reset state machine
+ rx_state <= RX_ST_IDLE;
+ else
+ 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;
+ default: rx_state <= RX_ST_IDLE;
+ endcase
+
+ /* rx_byte_cnt */
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ rx_byte_cnt <= 0;
+ else if ( rx_sample && pkt_start ) // synch reset
+ rx_byte_cnt <= 0;
+ else if ( rx_sample && rx_byte_cnt <= 4'h7 )
+ rx_byte_cnt <= rx_byte_cnt + 1'b1;
+
+ // UDP Dest Port match logic
+ always @(posedge clk, negedge rstn)
+ if (!rstn)
+ udp_port_match <= 1'b0;
+ else if ( rx_byte_cnt == 4'h3 && rx_data_m1 == (UDP_PORT_MATCH_L) && rx_data_m2 == UDP_PORT_MATCH_H)
+ udp_port_match <= 1'b1;
+ else
+ udp_port_match <= 1'b0;
+
+ assign pkt_complete = ( rx_byte_cnt == 3'h7 );
+
+endmodule

Highly Recommended Verilog Books