summaryrefslogtreecommitdiffhomepage
path: root/source
diff options
context:
space:
mode:
Diffstat (limited to 'source')
-rw-r--r--source/mac.v318
1 files changed, 206 insertions, 112 deletions
diff --git a/source/mac.v b/source/mac.v
index 8941710..d408301 100644
--- a/source/mac.v
+++ b/source/mac.v
@@ -1,7 +1,7 @@
/*
* mac.v
*
- * Copyright (C) 2018, 2019 Mind Chasers 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.
@@ -15,29 +15,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
- * function: SGMII TX/RX/AN state machines
+ * function: Ethernet MAC Layer
*
*/
-`timescale 1ns /10ps
-
module mac(
input rstn,
input phy_resetn, // The external PHY has its reset signal asserted
input clk,
input tap_port,
- // SGMII AN
- input link_timer,
+ // 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_link_up,
output reg an_duplex,
output reg phy_up,
output reg mode_100Mbit,
// Switch I/F
- input [1:0] tx_mode,
+ input [2:0] tx_mode,
output reg tx_f,
// PCS / SERDES health
@@ -66,13 +65,15 @@ module mac(
output reg [7:0] fcs_dout,
input [7:0] fcs_din,
- // SGMII RX / FIFO Write
+ // MAC RX / FIFO Write
output rx_fifo_we,
output [8:0] rx_fifo_d,
output reg rx_error,
output reg rx_wr_done,
+ output reg [10:0] rx_byte_cnt,
- // SGMII TX / FIFO Read
+ // MAC TX / FIFO Read
+ input [10:0] tx_byte_cnt_i,
output reg tx_fifo_re,
input [8:0] tx_fifo_d,
input tx_fifo_empty,
@@ -82,7 +83,6 @@ module mac(
output reg ipv4_pkt_start,
output reg trigger,
-
output reg rx_k_m1,
output reg rx_k_m2,
output reg rx_k_m3,
@@ -116,10 +116,23 @@ module mac(
`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'h01;
+
+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;
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,
@@ -135,22 +148,33 @@ reg [3:0] rx_cnt_100mbit, tx_cnt_100mbit;
wire tx_sample, tx_sample_re;
wire rx_packet_complete;
wire mode_1Gbit;
+
+
+// AN
+reg [2:0] an_state;
reg [1:0] an_speed;
+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
+reg an_link_up;
reg [3:0] rx_state;
-reg [10:0] rx_byte_cnt;
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 [5:0] param_addr;
+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:
@@ -165,6 +189,13 @@ 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;
+
/*
* RX DIRECTION
@@ -204,46 +235,45 @@ always @(posedge clk or negedge rstn)
* SGMII Auto Negotiation State Machine
* Look for configuration /C/ ordered set
* /C/ is Alternating /C1/ and /C2/
- * /C1/: /K28.5/D21.5/Config_Reg
- * /C2/: /K28.5/D2.2/Config_Reg
+ * /C1/: /K28.5/D21.5(0xb5)/Config_Reg
+ * /C2/: /K28.5/D2.2(0x42)/Config_Reg
* Config Reg: Low High
- *
- * Not using a link timer and not counting 3 frames because testing rmshows it's unnecessary
- *
*/
always @(posedge clk or negedge rstn)
if (!rstn)
- begin
- an_link_up <= 1'b0;
- an_duplex <= 1'b0;
- an_speed <= SGMII_SPEED_RSVD;
- phy_up <= 1'b0;
- end
+ 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
+ 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
+ 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
+ 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;
+ phy_up <= 1'b1;
+
// 100 MBit Support. There are no plans to support 10 MBit, so 100 MBit inactive is the same as 1GBit active
// if/else encodes the priority
+// TODO: possibly add more logic here to create an error condition if 10MBit is detected
always @(*)
if (fixed_speed == SGMII_SPEED_100MBIT)
mode_100Mbit = 1'b1;
@@ -270,7 +300,8 @@ always @(posedge clk or negedge rstn)
/*
* rx_state machine
* capture the Ethernet MAC header + packet.
-*/
+ *
+ */
always @(posedge clk, negedge rstn)
if (!rstn)
rx_state <= RX_ST_IDLE;
@@ -313,6 +344,7 @@ assign rx_fifo_we = ( rx_sample && ( rx_state >= RX_ST_SFD && rx_state <= RX_ST_
/*
* 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)
@@ -373,10 +405,14 @@ always @(posedge clk, negedge rstn)
* signals must be one shot
*
*/
- assign keep = rx_enet_bcast | rx_ipv4_arp;
-
+`ifdef PASSTHROUGH
+ assign keep = rx_enet_bcast | rx_ipv4_arp;
+ `else
+ assign keep = 1'b0;
+`endif
/* 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) )
@@ -478,9 +514,10 @@ always @(posedge clk or negedge rstn)
*/
- // TX 100 Mbit support
-assign tx_sample_re = (tx_cnt_100mbit == 4'd8 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0;
-assign tx_sample = (tx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0;
+// 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;
@@ -496,41 +533,42 @@ always @(posedge clk or negedge rstn)
*
* Transmit Mux
*/
-always@(*)
- begin
+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_f = tx_f_an;
- end
- TX_MODE_IDLE :
- begin
- tx_data = tx_data_idle;
- tx_k = tx_k_idle;
- tx_f = tx_f_idle;
- end
- TX_MODE_XMT_PKT :
+ TX_MODE_AN:
begin
- tx_data = tx_data_pkt;
- tx_k = tx_k_pkt;
- tx_f = tx_f_pkt;
+ tx_data <= tx_data_an;
+ tx_k <= tx_k_an;
+ tx_disp_correct <= i_tx_disp_correct;
end
- TX_MODE_XMT_METRICS :
+ TX_MODE_IDLE:
begin
- tx_data = tx_data_pkt;
- tx_k = tx_k_pkt;
- tx_f = tx_f_pkt;
+ tx_data <= tx_data_idle;
+ tx_k <= tx_k_idle;
+ tx_disp_correct <= i_tx_disp_correct;
end
- default :
+ default:
begin
- tx_data = K_ERROR;
- tx_k = 1'b1;
- tx_f = 1'b1;
+ 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
/*
@@ -544,46 +582,46 @@ always @(*)
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:
+ 3'd0:
+ begin
+ tx_data_an = K28_5;
+ tx_k_an = 1'b1;
+ end
+ 3'd1:
tx_data_an = D21_5;
- 3'd2:
+ 3'd2:
tx_data_an = AN_TX_CONFIG_LO;
- 3'd3:
+ 3'd3:
if (!an_link_up)
tx_data_an = AN_TX_CONFIG_HI;
- else
+ 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:
+ 3'd4:
+ begin
+ tx_data_an = K28_5;
+ tx_k_an = 1'b1;
+ end
+ 3'd5:
tx_data_an = D2_2;
- 3'd6:
+ 3'd6:
tx_data_an = AN_TX_CONFIG_LO;
- 3'd7:
+ 3'd7:
if (!an_link_up)
begin
- tx_f_an = 1'b1;
+ tx_f_an = 1'b1;
tx_data_an = AN_TX_CONFIG_HI;
end
else
begin
- tx_f_an = 1'b1;
+ 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
+ begin
+ tx_data_an = K_ERROR;
+ tx_k_an = 1'b1;
+ tx_f_an = 1'b1;
+ end
endcase
end
@@ -616,13 +654,13 @@ always @(*)
/*
-* Transmit Packet State Machine for TX_MODE_XMT_PKT and TX_MODE_XMT_METRICS
+* 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.
-*
+* negative value.
+*
*/
always @(posedge clk, negedge rstn)
begin
@@ -642,7 +680,7 @@ always @(posedge clk, negedge rstn)
tx_state <= TX_ST_4; // preamble 0xD5
TX_ST_4: if ( tx_sample && tx_last_byte && tx_byte_cnt < 60 ) // check if we need to pad?
tx_state <= TX_ST_5;
- else if ( tx_sample && (tx_fifo_empty || tx_last_byte) ) // check if we're done
+ else if ( tx_sample && tx_last_byte) // check if we're done
tx_state <= TX_ST_6;
TX_ST_5: if ( tx_sample && tx_byte_cnt >= 60 ) // pad state, test for sufficient frame size
tx_state <= TX_ST_6;
@@ -662,19 +700,18 @@ always @(posedge clk, negedge rstn)
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;
- tx_disp_correct = 1'b0;
+ i_tx_disp_correct = 1'b0;
tx_last_byte = 1'b0;
fcs_init = 1'b0;
fcs_addr_e = 1'b0;
@@ -698,7 +735,32 @@ always @(*)
end
TX_ST_4:
begin
- if ( tx_mode == TX_MODE_XMT_METRICS && tx_byte_cnt <= SZ_ETH_HEADER + SZ_IPV4_HEADER + SZ_UDP_HEADER )
+ 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 == '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];
@@ -712,13 +774,14 @@ always @(*)
end
else
begin
- tx_data_pkt = tx_fifo_d_m1[7:0]; // read data from memory
+ 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'h0; // pad
+ tx_data_pkt = 8'h00; // pad
+ fcs_dout = 8'h00;
end
TX_ST_6: begin
tx_data_pkt = fcs_din; // read from fcs
@@ -751,7 +814,7 @@ always @(*)
TX_ST_C:
begin
tx_data_pkt = D16_2; // 2nd idle code
- tx_disp_correct = 1'b1; // PCS may convert D16.2 to a D5.6 for I2 to flip disparity
+ 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:
@@ -779,6 +842,8 @@ always @(*)
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;
@@ -789,7 +854,7 @@ always @(posedge clk, negedge rstn)
else if (tx_sample)
if ( mode_100Mbit && tx_state == TX_ST_1 && tx_byte_cnt == 'h5 )
param_addr <= 'h0;
- else if ( mode_1Gbit && tx_state == TX_ST_1 && tx_byte_cnt == 'h4 )
+ else if ( mode_1Gbit && tx_state == TX_ST_1 && tx_byte_cnt == 'h2 )
param_addr <= 'h0;
else
param_addr <= param_addr + 1;
@@ -858,7 +923,7 @@ always @(posedge clk or negedge rstn)
assign dpr_we = 1'b0;
assign dpr_ce = 1'b1;
-assign dpr_ad = { 4'h0, param_addr };
+assign dpr_ad = param_addr;
/*
* tx_sop, K27_7, 0xFB /S/ Start_of_Packet
@@ -867,7 +932,7 @@ assign dpr_ad = { 4'h0, param_addr };
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 )
+ else if ( tx_state == TX_ST_0 && tx_mode >= TX_MODE_XMT_PKT )
tx_sop <= 1'b1;
else
tx_sop <= 1'b0;
@@ -883,11 +948,40 @@ always @(posedge clk or negedge rstn)
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 != 0 )
+ else if ( tx_state == TX_ST_1 )
tx_active <= 1'b1;
else
tx_active <= 1'b0;

Highly Recommended Verilog Books