diff options
Diffstat (limited to 'source/mac.v')
-rw-r--r-- | source/mac.v | 895 |
1 files changed, 895 insertions, 0 deletions
diff --git a/source/mac.v b/source/mac.v new file mode 100644 index 0000000..8941710 --- /dev/null +++ b/source/mac.v @@ -0,0 +1,895 @@ +/* + * mac.v + * + * Copyright (C) 2018, 2019 Mind Chasers Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * function: SGMII TX/RX/AN state machines + * + */ + +`timescale 1ns /10ps + +module mac( + input rstn, + input phy_resetn, // The external PHY has its reset signal asserted + input clk, + input tap_port, + + // SGMII AN + input link_timer, + input [1:0] fixed_speed, + input an_disable, + output reg an_link_up, + output reg an_duplex, + output reg phy_up, + output reg mode_100Mbit, + + // Switch I/F + input [1:0] tx_mode, + output reg tx_f, + + // PCS / SERDES health + input rx_lsm, + input rx_cv_err, + input rx_disp_err, + input rx_cdr_lol, + input rx_los, + + // PCS data I/F + input rx_k, + input [7:0] rx_data, + output reg tx_k, + output reg [7:0] tx_data, + output reg tx_disp_correct, + + // Flags and Interrupts + output reg rx_enet_bcast, + output reg rx_ipv4_arp, + output keep, + + // TX FCS + output reg fcs_init, + output reg fcs_enable, + output reg [1:0] fcs_addr, + output reg [7:0] fcs_dout, + input [7:0] fcs_din, + + // SGMII RX / FIFO Write + output rx_fifo_we, + output [8:0] rx_fifo_d, + output reg rx_error, + output reg rx_wr_done, + + // SGMII TX / FIFO Read + output reg tx_fifo_re, + input [8:0] tx_fifo_d, + input tx_fifo_empty, + + // Packet Filter + output rx_sample, + output reg ipv4_pkt_start, + output reg trigger, + + + output reg rx_k_m1, + output reg rx_k_m2, + output reg rx_k_m3, + output reg rx_k_m4, + + output reg[7:0] rx_data_m1, + output reg[7:0] rx_data_m2, + output reg[7:0] rx_data_m3, + output reg[7:0] rx_data_m4, + + // Param RAM for TAP port + output [10:0] dpr_ad, + output dpr_we, + output dpr_ce, + input [8:0] dpr_di, + output [8:0] dpr_do, + + // Metrics and Interrupts + output reg mac_int, + output reg rx_sop, // start of packet + output reg rx_eop, + output reg tx_sop, + output reg tx_eop, + output reg metrics_start, + input [8:0] metrics_d, + + // Debug + output reg rx_active, + output reg tx_active +); + +`include "sgmii_params.v" +`include "ethernet_params.v" + +localparam AN_TX_CONFIG_HI = 8'h00, + AN_TX_CONFIG_HI_ACK = 8'h40, + AN_TX_CONFIG_LO = 8'h01; + +localparam RX_ST_IDLE=4'h0, RX_ST_SOP=4'h1, RX_ST_PREAMBLE=4'h2, RX_ST_SFD=4'h3, RX_ST_MAC_ADDR=4'h4, + RX_ST_MAC_TYPE0=4'h5, RX_ST_MAC_TYPE1=4'h6, RX_ST_DATA=4'h7, RX_ST_DATA_DONE0=4'h8, + RX_ST_DATA_DONE1=4'h9, RX_ST_DATA_DONE2=4'ha; + +localparam TX_ST_0=4'h0, TX_ST_1=4'h1, TX_ST_2=4'h2, TX_ST_3=4'h3, + TX_ST_4=4'h4, TX_ST_5=4'h5, TX_ST_6=4'h6, TX_ST_7=4'h7, + TX_ST_8=4'h8, TX_ST_9=4'h9, TX_ST_A=4'ha, TX_ST_B=4'hb, + TX_ST_C=4'hc, TX_ST_D=4'hd, TX_ST_E=4'he, TX_ST_F=4'hf; + +reg [3:0] rx_cnt_100mbit, tx_cnt_100mbit; + +wire tx_sample, tx_sample_re; +wire rx_packet_complete; +wire mode_1Gbit; +reg [1:0] an_speed; + +reg [3:0] rx_state; +reg [10:0] rx_byte_cnt; +reg [10:0] rx_pkt_length; +reg [15:0] rx_l3_proto; + +reg [7:0] tx_data_an, tx_data_idle, tx_data_pkt; +reg tx_k_an, tx_k_idle, tx_k_pkt; + +// Transmit Registers and Wires +reg [3:0] tx_state; // transmit state machine +reg [10:0] tx_byte_cnt; +reg [5:0] param_addr; + +reg tx_f_an, tx_f_idle, tx_f_pkt; +reg tx_last_byte; + +// FIFOs: +reg [8:0] tx_fifo_d_m1; + +// FCS +reg fcs_addr_e; + +// pipeline the param RAM for timing +reg [8:0] dpr_di_reg; + +// counter for detecting Ethernet broadcast, only needs to count to 6 +reg [2:0] rx_enet_bcast_cnt; + + +/* + * RX DIRECTION + * + */ + +/* + * A shallow pool of RX registers for analysis + */ +always @(posedge clk or negedge rstn) + begin + if (!rstn) + begin + rx_k_m1 <= 1'b0; + rx_k_m2 <= 1'b0; + rx_k_m3 <= 1'b0; + rx_k_m4 <= 1'b0; + rx_data_m1 <= 8'h0; + rx_data_m2 <= 8'h0; + rx_data_m3 <= 8'h0; + rx_data_m4 <= 8'h0; + end + else if (mode_1Gbit || rx_sample || rx_state == RX_ST_IDLE || rx_state == RX_ST_DATA_DONE2 ) + begin + rx_k_m1 <= rx_k; + rx_k_m2 <= rx_k_m1; + rx_k_m3 <= rx_k_m2; + rx_k_m4 <= rx_k_m3; + rx_data_m1 <= rx_data; + rx_data_m2 <= rx_data_m1; + rx_data_m3 <= rx_data_m2; + rx_data_m4 <= rx_data_m3; + end + end + +/* + * SGMII Auto Negotiation State Machine + * Look for configuration /C/ ordered set + * /C/ is Alternating /C1/ and /C2/ + * /C1/: /K28.5/D21.5/Config_Reg + * /C2/: /K28.5/D2.2/Config_Reg + * Config Reg: Low High + * + * Not using a link timer and not counting 3 frames because testing rmshows it's unnecessary + * + */ +always @(posedge clk or negedge rstn) + if (!rstn) + begin + an_link_up <= 1'b0; + an_duplex <= 1'b0; + an_speed <= SGMII_SPEED_RSVD; + phy_up <= 1'b0; + end + else if ( !phy_resetn ) + begin + an_link_up <= 1'b0; + an_duplex <= 1'b0; + an_speed <= SGMII_SPEED_RSVD; + phy_up <= 1'b0; + end + else if ( an_disable ) + begin + phy_up <= 1'b1; + end + // D21.5 is part of config ( M2 has low, M1 has high ) + else if (!rx_k_m1 && !rx_k_m2 && !rx_k_m3 && rx_data_m3 == D21_5 && rx_k_m4 && rx_data_m4 == K28_5 ) + begin + an_link_up <= rx_data_m1[7]; + an_duplex <= rx_data_m1[4]; + an_speed <= rx_data_m1[3:2]; + phy_up <= 1'b0; + end + // IDLE2 1:0xBC, 0:0x50 + else if ( !rx_k_m1 && rx_data_m1 == D16_2 && rx_k_m2 == 1'b1 && rx_data_m2 == K28_5 ) + phy_up <= 1'b1; + +// 100 MBit Support. There are no plans to support 10 MBit, so 100 MBit inactive is the same as 1GBit active +// if/else encodes the priority +always @(*) + if (fixed_speed == SGMII_SPEED_100MBIT) + mode_100Mbit = 1'b1; + else if (fixed_speed == SGMII_SPEED_1GBIT) + mode_100Mbit = 1'b0; + else if (an_speed == SGMII_SPEED_100MBIT ) + mode_100Mbit = 1'b1; + else + mode_100Mbit = 1'b0; + +assign mode_1Gbit = ~mode_100Mbit; + +// RX 100 Mbit support +assign rx_sample = (rx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0; +always @(posedge clk or negedge rstn) + if (!rstn) + rx_cnt_100mbit <= 4'b0; + else if ( rx_cnt_100mbit == 4'd9 || rx_sop ) + rx_cnt_100mbit <= 4'b0; + else + rx_cnt_100mbit <= rx_cnt_100mbit + 4'd1; + + +/* + * rx_state machine + * capture the Ethernet MAC header + packet. +*/ +always @(posedge clk, negedge rstn) + if (!rstn) + rx_state <= RX_ST_IDLE; + else if ( rx_eop || !phy_resetn ) // EOP will reset state machine + rx_state <= RX_ST_IDLE; + else if ( phy_up ) + case ( rx_state ) + RX_ST_IDLE: if (rx_data_m1 == K27_7 && rx_k_m1 ) // Found /S/ + rx_state <= RX_ST_SOP; + RX_ST_SOP: if ( rx_sample ) // Capture /S/ + rx_state <= RX_ST_PREAMBLE; + RX_ST_PREAMBLE: if ( rx_sample && rx_data_m1 == 8'hd5 ) // 0xd5 preamble + rx_state <= RX_ST_SFD; + RX_ST_SFD: if ( rx_sample ) + rx_state <= RX_ST_MAC_ADDR; + RX_ST_MAC_ADDR: if ( rx_sample && rx_byte_cnt == 12 ) // Use this state transition to signal end of ethernet header and start of packet + rx_state <= RX_ST_MAC_TYPE0; + RX_ST_MAC_TYPE0: if ( rx_sample ) + rx_state <= RX_ST_MAC_TYPE1; // Capture ethertype + RX_ST_MAC_TYPE1: if ( rx_sample ) + rx_state <= RX_ST_DATA; // + RX_ST_DATA: if ( rx_sample && rx_packet_complete ) // write into FIFO until pkt length + rx_state <= RX_ST_DATA_DONE0; + RX_ST_DATA_DONE0: if ( rx_sample ) + rx_state <= RX_ST_DATA_DONE1; // write an extra byte into the FIFO + RX_ST_DATA_DONE1: if ( rx_sample ) + rx_state <= RX_ST_DATA_DONE2; // write an extra byte into the FIFO + RX_ST_DATA_DONE2: if ( rx_sample ) + rx_state <= rx_state; // waiting for /T/ + default: rx_state <= rx_state; + endcase + else + rx_state <= RX_ST_IDLE; + +/* + * rx_fifo_we +*/ +assign rx_fifo_we = ( rx_sample && ( rx_state >= RX_ST_SFD && rx_state <= RX_ST_DATA_DONE1 ) ) ? 1'b1 : 1'b0; + + +/* + * Detect Ethernet Broadcast (destination address = ff:ff:ff:ff:ff:ff) + * + */ +always @(posedge clk, negedge rstn) + if (!rstn) + rx_enet_bcast_cnt <= 3'h0; + else if ( rx_sample ) + if (rx_data_m1 == 9'hff) + rx_enet_bcast_cnt <= rx_enet_bcast_cnt + 1; + else + rx_enet_bcast_cnt <= 3'h0; + +/* Ethernet Broadcast Dest Address, must be a one shot */ +always @(posedge clk, negedge rstn) + if (!rstn) + rx_enet_bcast <= 1'b0; + else if ( rx_sample ) + if ( rx_enet_bcast_cnt == 3'h6 ) + rx_enet_bcast <= 1'b1; + else + rx_enet_bcast <= 1'b0; + +/* + create a one shot that will assert during RX_ST_DATA_DONE1 so external logic can know + that the FIFO write has come to an end ( reset pointers, etc. ) + + For 100Mbit, since the states change 10 clocks apart, set it during RX_ST_DATA_DONE1 +*/ +always @(posedge clk, negedge rstn) + if (!rstn) + rx_wr_done <= 1'b0; + else if ( mode_1Gbit && rx_state == RX_ST_DATA_DONE0 ) + rx_wr_done <= 1'b1; + else if ( mode_100Mbit && rx_sample && rx_state == RX_ST_DATA_DONE1 ) + rx_wr_done <= 1'b1; + else + rx_wr_done <= 1'b0; + +/* capture layer 3 protocol (e.g., ipv4 or ipv6) */ +always @(posedge clk, negedge rstn) + if ( !rstn ) + rx_l3_proto <= 0; + else if ( rx_sop ) + rx_l3_proto <= 0; + else if ( rx_sample && rx_state == RX_ST_MAC_TYPE0 ) + rx_l3_proto <= { rx_data_m2, rx_data_m1 }; + +// assert ipv4 ARP flag for filtering operations +always @(posedge clk, negedge rstn) + if (!rstn) + rx_ipv4_arp <= 1'b0; + else if ( rx_sample && rx_state == RX_ST_MAC_TYPE1 && rx_l3_proto == ETHER_TYPE_ARP) + rx_ipv4_arp <= 1'b1; + else + rx_ipv4_arp <= 1'b0; + +/* + * keep flag + * signals must be one shot + * + */ + assign keep = rx_enet_bcast | rx_ipv4_arp; + + +/* rx_error + * */ +always @(*) + if ( rx_sample && rx_state >= RX_ST_DATA && ( rx_l3_proto != ETHER_TYPE_IPV4 && rx_l3_proto != ETHER_TYPE_IPV6 && rx_l3_proto != ETHER_TYPE_ARP) ) + rx_error = 1; + else + rx_error = 0; + +/* rx_byte_cnt */ +always @(posedge clk, negedge rstn) + if (!rstn) + rx_byte_cnt <= 'h0; + else if (rx_sample) + if ( rx_state == RX_ST_IDLE || rx_state == RX_ST_PREAMBLE ) + rx_byte_cnt <= 'h0; + else if ( rx_state == RX_ST_MAC_TYPE0 ) + rx_byte_cnt <= 'h1; + else + rx_byte_cnt <= rx_byte_cnt + 1; + +/* rx_pkt_length */ +always @(posedge clk, negedge rstn) + if ( !rstn ) + rx_pkt_length <= 0; + else if ( rx_sop ) + rx_pkt_length <= 0; + else if (rx_sample) + if ( rx_l3_proto == ETHER_TYPE_IPV4 && rx_state == RX_ST_DATA && rx_byte_cnt == 'h4 ) + rx_pkt_length <= { rx_data_m2[2:0], rx_data_m1 }; + else if ( rx_l3_proto == ETHER_TYPE_IPV6 && rx_state == RX_ST_DATA && rx_byte_cnt == 'h6 ) + rx_pkt_length <= { rx_data_m2[2:0], rx_data_m1 } + 'd40; + else if ( rx_l3_proto == ETHER_TYPE_ARP && rx_state == RX_ST_DATA ) + rx_pkt_length <= 'd46; + +/* ipv4 flag */ +always @(posedge clk, negedge rstn) + if ( !rstn ) + ipv4_pkt_start <= 1'b0; + else if ( rx_sample && rx_l3_proto == ETHER_TYPE_IPV4 && rx_state == RX_ST_MAC_TYPE1 ) + ipv4_pkt_start <= 1; + else + ipv4_pkt_start <= 0; + +assign rx_packet_complete = ( rx_sample && rx_state >= RX_ST_DATA && rx_pkt_length == rx_byte_cnt ) ? 1 : 0; + +// FIFO data interface +assign rx_fifo_d[7:0] = rx_data_m1; +assign rx_fifo_d[8] = rx_packet_complete; + + +/* + * rx_sop, K27_7, 0xFB /S/ Start_of_Packet + */ +always @(posedge clk or negedge rstn) + if (!rstn) + rx_sop <=1'b0; + else if ( rx_data_m1 == K27_7 && rx_k_m1 == 1'b1 ) + rx_sop <= 1'b1; + else + rx_sop <= 1'b0; + +/* + * rx_eop, K29_7, 0xFD, /T/ End_of_Packet + */ +always @(posedge clk or negedge rstn) + if (!rstn) + rx_eop <=1'b0; + else if ( rx_data_m1 == K29_7 && rx_k_m1 == 1'b1 ) + rx_eop <= 1'b1; + else + rx_eop <= 1'b0; + +/* MAC Interrupt + * Create one shot interrupt while interrupt source is active + * Rely on interrupt controller to latch & clear + */ +always @(posedge clk or negedge rstn) + if (!rstn) + mac_int <=1'b0; + else if ( !rx_lsm || rx_cv_err || rx_cdr_lol || rx_los ) + mac_int <= 1'b1; + else + mac_int <= 1'b0; + + +/* Debug RX */ +always @(posedge clk or negedge rstn) + if (!rstn) + rx_active <=1'b0; + else if ( rx_state != 0 ) + rx_active <= 1'b1; + else + rx_active <= 1'b0; + + + +/* + * TX DIRECTION + * + */ + + + // TX 100 Mbit support +assign tx_sample_re = (tx_cnt_100mbit == 4'd8 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0; +assign tx_sample = (tx_cnt_100mbit == 4'd9 && mode_100Mbit) || !mode_100Mbit ? 1'b1 : 1'b0; +always @(posedge clk or negedge rstn) + if (!rstn) + tx_cnt_100mbit <= 4'b0; + else if ( tx_state == TX_ST_0 ) + tx_cnt_100mbit <= 4'b1; // steal a bit here during preamble so we keep an even bit count + else if ( tx_cnt_100mbit == 4'd9 ) + tx_cnt_100mbit <= 4'b0; + else + tx_cnt_100mbit <= tx_cnt_100mbit + 1; + + +/* +* +* Transmit Mux +*/ +always@(*) + begin + case(tx_mode) + TX_MODE_AN : + begin + tx_data = tx_data_an; + tx_k = tx_k_an; + tx_f = tx_f_an; + end + TX_MODE_IDLE : + begin + tx_data = tx_data_idle; + tx_k = tx_k_idle; + tx_f = tx_f_idle; + end + TX_MODE_XMT_PKT : + begin + tx_data = tx_data_pkt; + tx_k = tx_k_pkt; + tx_f = tx_f_pkt; + end + TX_MODE_XMT_METRICS : + begin + tx_data = tx_data_pkt; + tx_k = tx_k_pkt; + tx_f = tx_f_pkt; + end + default : + begin + tx_data = K_ERROR; + tx_k = 1'b1; + tx_f = 1'b1; + end + endcase + end + + +/* + * CONFIG SM +* During SGMII auto negotiation, send /C1/ and /C2/ ordered sets +* C1: /K28.5/D21.5/Config Regs +* C2: /K28.5/D2.2/Config Regs +*/ +always @(*) + begin + tx_f_an = 1'b0; + tx_k_an = 1'b0; + case(tx_byte_cnt[2:0]) + 3'd0: + begin + tx_data_an = K28_5; + tx_k_an = 1'b1; + end + 3'd1: + tx_data_an = D21_5; + 3'd2: + tx_data_an = AN_TX_CONFIG_LO; + 3'd3: + if (!an_link_up) + tx_data_an = AN_TX_CONFIG_HI; + else + tx_data_an = AN_TX_CONFIG_HI_ACK; + 3'd4: + begin + tx_data_an = K28_5; + tx_k_an = 1'b1; + end + 3'd5: + tx_data_an = D2_2; + 3'd6: + tx_data_an = AN_TX_CONFIG_LO; + 3'd7: + if (!an_link_up) + begin + tx_f_an = 1'b1; + tx_data_an = AN_TX_CONFIG_HI; + end + else + begin + tx_f_an = 1'b1; + tx_data_an = AN_TX_CONFIG_HI_ACK; + end + default: + begin + tx_data_an = K_ERROR; + tx_k_an = 1'b1; + tx_f_an = 1'b1; + end + endcase + end + +/* IDLE2 SM */ +always @(*) + begin + tx_f_idle = 1'b0; + case(tx_byte_cnt[1:0]) + 3'd0: + begin + tx_data_idle = K28_5; + tx_k_idle = 1'b1; + end + 3'd1: + begin + tx_data_idle = D16_2; + tx_k_idle = 1'b0; + tx_f_idle = 1'b1; + end + default: + begin + tx_data_idle = K_ERROR; + tx_k_idle = 1'b1; + tx_f_idle = 1'b1; + end + endcase + end + + + + +/* +* Transmit Packet State Machine for TX_MODE_XMT_PKT and TX_MODE_XMT_METRICS +* +* +* Note: the first /I/ following a transmitted frame or Configuration ordered set +* restores the current positive or negative running disparity to a +* negative value. +* +*/ +always @(posedge clk, negedge rstn) + begin + if ( !rstn ) + tx_state <= TX_ST_0; + else if ( !phy_resetn ) + tx_state <= TX_ST_0; + else + case(tx_state) + TX_ST_0: if ( tx_mode >= TX_MODE_XMT_PKT && !tx_f_pkt ) // /S/ + tx_state <= TX_ST_1; + TX_ST_1: if ( tx_sample && tx_byte_cnt == 8'h5 ) // preamble 0x55 + tx_state <= TX_ST_2; + TX_ST_2: if ( tx_sample ) + tx_state <= TX_ST_3; // preamble 0x55, assert tx_fifo_re, reset tx_byte_cnt + TX_ST_3: if ( tx_sample ) + tx_state <= TX_ST_4; // preamble 0xD5 + TX_ST_4: if ( tx_sample && tx_last_byte && tx_byte_cnt < 60 ) // check if we need to pad? + tx_state <= TX_ST_5; + else if ( tx_sample && (tx_fifo_empty || tx_last_byte) ) // check if we're done + tx_state <= TX_ST_6; + TX_ST_5: if ( tx_sample && tx_byte_cnt >= 60 ) // pad state, test for sufficient frame size + tx_state <= TX_ST_6; + TX_ST_6: if ( tx_sample && fcs_addr == 2'b10 ) // Start FCS + tx_state <= TX_ST_7; + TX_ST_7: if (tx_sample && fcs_addr == 2'b11 ) // Finish FCS + tx_state <= TX_ST_8; + TX_ST_8: tx_state <= TX_ST_9; // EOP /T/ + TX_ST_9: if ( tx_byte_cnt[0] && !mode_100Mbit) // test for odd # of code words when in Gig mode for extra /R/ insertion + tx_state <= TX_ST_A; + else + tx_state <= TX_ST_B; + TX_ST_A: tx_state <= TX_ST_B; // 2nd /R/ if necessary ( odd position ) + TX_ST_B: tx_state <= TX_ST_C; // I2, K28.5 + TX_ST_C: tx_state <= TX_ST_0; // I2, D16.2 + + default: tx_state <= tx_state; + endcase + end + + + + +/* +* tx related data mux and control signals +* +*/ +always @(*) + begin + tx_f_pkt = 1'b0; + tx_k_pkt = 1'b0; + tx_disp_correct = 1'b0; + tx_last_byte = 1'b0; + fcs_init = 1'b0; + fcs_addr_e = 1'b0; + fcs_dout = tx_fifo_d_m1[7:0]; + metrics_start = 1'b0; + case(tx_state) + TX_ST_0: + begin + tx_data_pkt = K27_7; // start of packet + tx_k_pkt = 1'b1; + fcs_init = 1'b1; + end + TX_ST_1: begin + tx_data_pkt = 8'h55; // preamble, we need 6 bytes total of 0x55 + end + TX_ST_2: begin + tx_data_pkt = 8'h55; // preamble, single byte of 0x55 and assert fifo_re + end + TX_ST_3: begin + tx_data_pkt = 8'hD5; // preamble, single byte of 0xd5 completes the preamble) + end + TX_ST_4: + begin + if ( tx_mode == TX_MODE_XMT_METRICS && tx_byte_cnt <= SZ_ETH_HEADER + SZ_IPV4_HEADER + SZ_UDP_HEADER ) + begin + tx_data_pkt = dpr_di_reg[7:0]; // packet headers + fcs_dout = dpr_di_reg[7:0]; + metrics_start = 1'b1; // keeps the metrics counters in reset + end + else if ( tx_mode == TX_MODE_XMT_METRICS ) + begin + tx_data_pkt = metrics_d; // packet content + fcs_dout = metrics_d[7:0]; + tx_last_byte = metrics_d[8]; + end + else + begin + tx_data_pkt = tx_fifo_d_m1[7:0]; // read data from memory + tx_last_byte = tx_fifo_d_m1[8]; + end + end + TX_ST_5: + begin + tx_data_pkt = 8'h0; // pad + end + TX_ST_6: begin + tx_data_pkt = fcs_din; // read from fcs + fcs_addr_e = 1'b1; + end + TX_ST_7: begin + tx_data_pkt = fcs_din; // read from fcs + fcs_addr_e = 1'b1; + end + TX_ST_8: + begin + tx_data_pkt = K29_7; // end of packet + tx_k_pkt = 1'b1; + end + TX_ST_9: + begin + tx_data_pkt = K23_7; // carrier extend + tx_k_pkt = 1'b1; + end + TX_ST_A: + begin + tx_data_pkt = K23_7; // carrier extend + tx_k_pkt = 1'b1; + end + TX_ST_B: + begin + tx_data_pkt = K28_5; // 1st idle code + tx_k_pkt = 1'b1; + end + TX_ST_C: + begin + tx_data_pkt = D16_2; // 2nd idle code + tx_disp_correct = 1'b1; // PCS may convert D16.2 to a D5.6 for I2 to flip disparity + tx_f_pkt = 1'b1; + end + default: + begin + tx_data_pkt = K_ERROR; + tx_k_pkt = 1'b1; + tx_f_pkt = 1'b1; + end + endcase +end + +/* + * tx_fifo_re + * + * The use of the read fifo is different between 1Gbit and 100Mbit. + * + */ +always @(*) + if ( tx_mode == TX_MODE_XMT_PKT ) + if ( mode_1Gbit && tx_state >= TX_ST_2 && tx_state <= TX_ST_4 ) + tx_fifo_re = 1'b1; + else if ( mode_100Mbit && tx_sample_re && tx_state > TX_ST_2 && tx_state <= TX_ST_4 ) + tx_fifo_re = 1'b1; + else if ( mode_100Mbit && tx_state == TX_ST_8 ) // we need an extra FIFO strobe at 100MBit for a single 1G clk + tx_fifo_re = 1'b1; + else + tx_fifo_re = 1'b0; + else + tx_fifo_re = 1'b0; + + +always @(posedge clk, negedge rstn) + if (!rstn) + param_addr <= 'h0; + else if (tx_sample) + if ( mode_100Mbit && tx_state == TX_ST_1 && tx_byte_cnt == 'h5 ) + param_addr <= 'h0; + else if ( mode_1Gbit && tx_state == TX_ST_1 && tx_byte_cnt == 'h4 ) + param_addr <= 'h0; + else + param_addr <= param_addr + 1; + +/* + tx_byte_cnt + + Increment at pcs clock rate for PCS layer data (e.g., /I1/, /C/, /S/, etc. + + Increment at sample rate for Ethernet data + +*/ +always @(posedge clk, negedge rstn) + if (!rstn) + tx_byte_cnt <= 'h0; + else if (tx_sample || tx_state == TX_ST_0 || tx_state > TX_ST_7 || tx_mode < TX_MODE_XMT_PKT ) + if (tx_f) + tx_byte_cnt <= 'h0; + else if ( tx_state == TX_ST_2 ) + tx_byte_cnt <= 'h0; // start counting the Ethernet Frame after preamble + else + tx_byte_cnt <= tx_byte_cnt + 1; + +/* + * pipeline data from FIFO + */ +always @(posedge clk or negedge rstn) +begin + if ( !rstn ) + tx_fifo_d_m1 <= 9'h0; + else if ( tx_sample ) + tx_fifo_d_m1 <= tx_fifo_d; +end + +/* +* FCS +*/ +always @(posedge clk or negedge rstn) + begin + if ( !rstn ) + fcs_addr <= 2'b00; + else if (tx_sample) + if ( !fcs_addr_e ) + fcs_addr <= 2'b00; + else + fcs_addr <= fcs_addr + 1; + end + +always @(*) + if (mode_1Gbit && (tx_state == TX_ST_4 || tx_state == TX_ST_5) ) + fcs_enable = 1'b1; + else if ( mode_100Mbit && tx_sample && (tx_state == TX_ST_4 || tx_state == TX_ST_5) ) + fcs_enable = 1'b1; + else + fcs_enable = 1'b0; + +/* +* DPRAM, param ram Control for TAP port +*/ +always @(posedge clk or negedge rstn) + if ( !rstn ) + dpr_di_reg <= 9'h0; + else if (tx_sample) + dpr_di_reg <= dpr_di; + + +assign dpr_we = 1'b0; +assign dpr_ce = 1'b1; +assign dpr_ad = { 4'h0, param_addr }; + +/* + * tx_sop, K27_7, 0xFB /S/ Start_of_Packet + * We choose to not include TX_MODE_CUSTOM_PKT for this metric + */ +always @(posedge clk or negedge rstn) + if (!rstn) + tx_sop <=1'b0; + else if ( tx_state == TX_ST_0 && tx_mode == TX_MODE_XMT_PKT ) + tx_sop <= 1'b1; + else + tx_sop <= 1'b0; + + /* + * tx_eop, K29_7, 0xFD, /T/ End_of_Packet + */ +always @(posedge clk or negedge rstn) + if (!rstn) + tx_eop <=1'b0; + else if ( tx_state == TX_ST_7 ) + tx_eop <= 1'b1; + else + tx_eop <= 1'b0; + +/* Debug TX */ +always @(posedge clk or negedge rstn) + if (!rstn) + tx_active <=1'b0; + else if ( tx_state != 0 ) + tx_active <= 1'b1; + else + tx_active <= 1'b0; + +endmodule |