summaryrefslogtreecommitdiffhomepage
path: root/source/mac.v
diff options
context:
space:
mode:
Diffstat (limited to 'source/mac.v')
-rw-r--r--source/mac.v973
1 files changed, 0 insertions, 973 deletions
diff --git a/source/mac.v b/source/mac.v
deleted file mode 100644
index b5b980a..0000000
--- a/source/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

Highly Recommended Verilog Books