diff options
-rw-r--r-- | source/mac.v | 318 |
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; |