Welcome, guest! Login / Register - Why register?
Psst.. new poll here.
[email protected] webmail now available. Want one? Go here.
Cannot use outlook/hotmail/live here to register as they blocking our mail servers. #microsoftdeez
Obey the Epel!

Paste

Pasted as Verilog by registered user Socrates ( 13 years ago )
//
//  udp_port_to_channel_mapper
//
//  This component is used to map incoming Ethernet packets onto specific
//  Avalon ST channels to allow them to be easily demultiplexed and routed.
//  This component receives Ethernet packets on an Avalon ST sink interface and
//  transmits the channelized packets out an Avalon ST source interface.  The
//  configuration and monitoring of this peripheral is performed thru an Avalon
//  MM slave interface.
//  
//  This component inspects the incoming Ethernet packet to locate specific
//  UDP packets that have been programmed in this component to map to a
//  specific Avalon ST channel.  There are 5 possible channels that this
//  component will map to, 4 programmable UDP port numbers, or the fifth
//  channel where all unmapped packets are assigned.
//  
//  The standard format of each of the header layers is illustrated below, you
//  can think of each layer being wrapped in the payload section of the layer
//  above it, with the Ethernet packet layout being the outer most wrapper.
//  
//  Standard Ethernet Packet Layout
//  |-------------------------------------------------------|
//  |                Destination MAC Address                |
//  |                           ----------------------------|
//  |                           |                           |
//  |----------------------------                           |
//  |                  Source MAC Address                   |
//  |-------------------------------------------------------|
//  |         EtherType         |                           |
//  |----------------------------                           |
//  |                                                       |
//  |                   Ethernet Payload                    |
//  |                                                       |
//  |-------------------------------------------------------|
//  |                 Frame Check Sequence                  |
//  |-------------------------------------------------------|
//
//  Standard IP Packet Layout
//  |-------------------------------------------------------|
//  | VER  | HLEN |     TOS     |       Total Length        |
//  |-------------------------------------------------------|
//  |       Identification      | FLGS |    FRAG OFFSET     |
//  |-------------------------------------------------------|
//  |     TTL     |    PROTO    |      Header Checksum      |
//  |-------------------------------------------------------|
//  |                   Source IP Address                   |
//  |-------------------------------------------------------|
//  |                Destination IP Address                 |
//  |-------------------------------------------------------|
//  |                                                       |
//  |                      IP Payload                       |
//  |                                                       |
//  |-------------------------------------------------------|
//
//  Standard UDP Packet Layout
//  |-------------------------------------------------------|
//  |      Source UDP Port      |   Destination UDP Port    |
//  |-------------------------------------------------------|
//  |    UDP Message Length     |       UDP Checksum        |
//  |-------------------------------------------------------|
//  |                                                       |
//  |                      UDP Payload                      |
//  |                                                       |
//  |-------------------------------------------------------|
//
//  The general packet channel mapping flows like this:
//  
//  This component supports the mapping of up to 4 UDP port numbers.
//
//  The primary condition that this component looks at to qualify a packet to
//  be mapped to a channel is the Destination UDP Port number in the UDP
//  header.  However, as the Ethernet packet is received by this component a
//  number of other sanity checks are made to ensure that we have a UDP packet
//  to deal with.  Here are the qualifications that are applied to the various
//  fields of the header layers:
//  
//      MAC Destination Address     = X
//      MAC Source Address          = X
//      MAC EtherType               = must be IPV4
//      IP Version                  = must be IPV4
//      IP Header Length            = must be FIVE
//      IP Type of Service          = X
//      IP Total Length             = X
//      IP Identification           = X
//      IP Flags                    = must NOT be fragmented
//      IP Fragment Offset          = must be ZERO
//      IP Time to Live             = X
//      IP Protocol                 = must be UDP
//      IP Checksum                 = must verify
//      IP Source Address           = X
//      IP Destination Address      = X
//      UDP Source UDP Port         = X
//      UDP Destination UDP Port    = must match user programmed value
//      UDP UDP Message Length      = X
//      UDP UDP Checksum            = X
//      
//  If any of the observed fields do not match their expected values then the
//  packet will be assigned to the default channel and forwarded.  If all of
//  the fields match their expected values and the user has programmed a
//  particular UDP port number into a channel mapping and enabled it, then the
//  packet will be mapped onto that channel and forwarded.
//  
//  You can see that there are a few restrictions placed on the received
//  packets to make them eligible for mapping.  First, only a single MAC
//  header is allowed, no VLAN headers are allowed.  Second, only a standard 20
//  byte IP header is allowed, no option words are allowed.  Third, the packet
//  must not be fragmented.
//  
//  ---------------------------------------------------------------------------
//  Register Map
//  ---------------------------------------------------------------------------
//  
//  The slave interface for the udp_port_to_channel_mapper is broken up into 5
//  32-bit registers with the following layout:
//  
//  Register 0 - Channel 0 Mapping Register
//      Bits [15:0] - R/W - this is the destination UDP port value to map on this channel
//      Bits [16]   - R/W - this bit enables this channel, 1 is enabled, 0 is disabled
//                  
//  Register 1 - Channel 1 Mapping Register
//      Bits [15:0] - R/W - this is the destination UDP port value to map on this channel
//      Bits [16]   - R/W - this bit enables this channel, 1 is enabled, 0 is disabled
//                  
//  Register 2 - Channel 2 Mapping Register
//      Bits [15:0] - R/W - this is the destination UDP port value to map on this channel
//      Bits [16]   - R/W - this bit enables this channel, 1 is enabled, 0 is disabled
//                  
//  Register 3 - Channel 3 Mapping Register
//      Bits [15:0] - R/W - this is the destination UDP port value to map on this channel
//      Bits [16]   - R/W - this bit enables this channel, 1 is enabled, 0 is disabled
//                  
//  Register 4 - Packet Count Register
//      Bits [31:0] - R/WC - this is the number of packets that have been
//                  processed since the last reset or clearing of this register.
//                  
//  R - Readable
//  W - Writeable
//  WC - Clear on Write
//

module udp_port_to_channel_mapper
(
    // clock interface
    input           csi_clock_clk,
    input           csi_clock_reset,
    
    // slave interface
    input           avs_s0_write,
    input           avs_s0_read,
    input   [2:0]   avs_s0_address,
    input   [3:0]   avs_s0_byteenable,
    input   [31:0]  avs_s0_writedata,
    output  [31:0]  avs_s0_readdata,
    
    // source interface
    output          aso_src0_valid,
    input           aso_src0_ready,
    output  [31:0]  aso_src0_data,
    output  [1:0]   aso_src0_empty,
    output          aso_src0_startofpacket,
    output          aso_src0_endofpacket,
    output  [2:0]   aso_src0_channel,
    
    // sink interface
    input           asi_snk0_valid,
    output          asi_snk0_ready,
    input   [31:0]  asi_snk0_data,
    input   [1:0]   asi_snk0_empty,
    input           asi_snk0_startofpacket,
    input           asi_snk0_endofpacket
);

localparam [4:0] STATE_PW_0     = 5'd0;
localparam [4:0] STATE_PW_1     = 5'd1;
localparam [4:0] STATE_PW_2     = 5'd2;
localparam [4:0] STATE_PW_3     = 5'd3;
localparam [4:0] STATE_PW_4     = 5'd4;
localparam [4:0] STATE_PW_5     = 5'd5;
localparam [4:0] STATE_PW_6     = 5'd6;
localparam [4:0] STATE_PW_7     = 5'd7;
localparam [4:0] STATE_PW_8     = 5'd8;
localparam [4:0] STATE_PW_9     = 5'd9;
localparam [4:0] STATE_PW_10    = 5'd10;
localparam [4:0] STATE_PW_N     = 5'd11;

wire            source_cycle;
wire            sink_cycle;
wire    [35:0]  fifo_sink_word;
wire    [35:0]  fifo_source_word;
wire            data_fifo_empty;
wire            data_fifo_full;
reg     [4:0]   state;
reg             count_packet;
reg             clear_packet_count;
reg     [31:0]  packet_count;
wire            read_next_channel;
reg             write_next_channel;
wire    [2:0]   channel_fifo_in;
wire    [2:0]   channel_fifo_out;
wire            channel_fifo_empty;
wire            channel_fifo_full;
wire            qualified_packet;
reg     [15:0]  udp_chan_0;
reg     [15:0]  udp_chan_1;
reg     [15:0]  udp_chan_2;
reg     [15:0]  udp_chan_3;
reg             udp_chan_0_en;
reg             udp_chan_1_en;
reg             udp_chan_2_en;
reg             udp_chan_3_en;

reg             mac_type_is_ipv4;
reg             ip_hdr_is_ipv4;
reg             ip_hdr_len_is_5;
reg     [19:0]  ip_hdr_csum;
reg             ip_flg_not_frag;
reg             ip_frag_zero;
reg             ip_proto_is_udp;
reg     [15:0]  udp_dest_port;

//
// misc
//
assign fifo_sink_word   = {asi_snk0_data, asi_snk0_empty, asi_snk0_endofpacket, asi_snk0_startofpacket};

//
// packet transmit state machine
//
assign aso_src0_data            = fifo_source_word[35:4];
assign aso_src0_empty           = fifo_source_word[3:2];
assign aso_src0_endofpacket     = fifo_source_word[1];
assign aso_src0_startofpacket   = fifo_source_word[0];
assign aso_src0_channel         = channel_fifo_out;

assign aso_src0_valid   = !data_fifo_empty & !channel_fifo_empty;
                        
assign asi_snk0_ready   = !data_fifo_full;

assign source_cycle = aso_src0_valid & aso_src0_ready;
assign sink_cycle   = asi_snk0_valid & asi_snk0_ready;

always @ (posedge csi_clock_clk or posedge csi_clock_reset)
begin
    if(csi_clock_reset)
    begin
        state               <= STATE_PW_0;
        mac_type_is_ipv4    <= 0;
        ip_hdr_is_ipv4      <= 0;
        ip_hdr_len_is_5     <= 0;
        ip_hdr_csum         <= 0;
        ip_flg_not_frag     <= 0;
        ip_frag_zero        <= 0;
        ip_proto_is_udp     <= 0;
        udp_dest_port       <= 0;
        write_next_channel  <= 0;
        count_packet        <= 0;
    end
    else
    begin
        case(state)
        STATE_PW_0:
        // packet_word_0    = mac_dst[47:16];
        begin
            count_packet    <= 1'b0;
        
            if(sink_cycle)
            begin
                state <= STATE_PW_1;
            end
        end
        STATE_PW_1:
        // packet_word_1    = {mac_dst[15:0], mac_src[47:32]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_2;
            end
        end
        STATE_PW_2:
        // packet_word_2    = mac_src[31:0];
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_3;
            end
        end
        STATE_PW_3:
        // packet_word_3    = {MAC_TYPE, ip_word_0[31:16]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_4;
                
                mac_type_is_ipv4    <= (asi_snk0_data[31:16] == 16'h0800) ? (1'b1) : (1'b0);
                ip_hdr_is_ipv4      <= (asi_snk0_data[15:12] == 4'h4) ? (1'b1) : (1'b0);
                ip_hdr_len_is_5     <= (asi_snk0_data[11:8] == 4'h5) ? (1'b1) : (1'b0);
                ip_hdr_csum         <= asi_snk0_data[15:0];
            end
        end
        STATE_PW_4:
        // packet_word_4    = {ip_word_0[15:0], ip_word_1[31:16]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_5;

                ip_hdr_csum <= ip_hdr_csum + asi_snk0_data[31:16] + asi_snk0_data[15:0];
            end
        end
        STATE_PW_5:
        // packet_word_5    = {ip_word_1[15:0], ip_word_2[31:16]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_6;
                
                ip_flg_not_frag <= (asi_snk0_data[29] == 1'b0) ? (1'b1) : (1'b0);
                ip_frag_zero    <= (asi_snk0_data[28:16] == 13'h0000) ? (1'b1) : (1'b0);
                ip_proto_is_udp <= (asi_snk0_data[7:0] == 8'd17) ? (1'b1) : (1'b0);
                ip_hdr_csum     <= ip_hdr_csum + asi_snk0_data[31:16] + asi_snk0_data[15:0];
            end
        end
        STATE_PW_6:
        // packet_word_6    = {ip_word_2[15:0], ip_word_3[31:16]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_7;

                ip_hdr_csum     <= ip_hdr_csum + asi_snk0_data[31:16] + asi_snk0_data[15:0];
            end
        end
        STATE_PW_7:
        // packet_word_7    = {ip_word_3[15:0], ip_word_4[31:16]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_8;
                
                ip_hdr_csum     <= ip_hdr_csum + asi_snk0_data[31:16] + asi_snk0_data[15:0];
            end
        end
        STATE_PW_8:
        // packet_word_8    = {ip_word_4[15:0], udp_word_0[31:16]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_9;

                ip_hdr_csum     <= ip_hdr_csum + asi_snk0_data[31:16];
            end
        end
        STATE_PW_9:
        // packet_word_9    = {udp_word_0[15:0], udp_word_1[31:16]};
        begin
            if(sink_cycle)
            begin
                state <= STATE_PW_10;
                
                ip_hdr_csum         <= ip_hdr_csum[15:0] + ip_hdr_csum[19:16];
                udp_dest_port       <= asi_snk0_data[31:16];
                write_next_channel  <= 1'b1;
            end
        end
        STATE_PW_10:
        // packet_word_10   = {udp_word_1[15:0], first_two_bytes};
        begin
            write_next_channel  <= 1'b0;

            if(sink_cycle)
            begin
                state <= STATE_PW_N;
            end
        end
        STATE_PW_N:
        // packet_word_n    = sink_data;
        begin
            if(sink_cycle)
            begin
                if(asi_snk0_endofpacket)
                begin
                    state           <= STATE_PW_0;
                    count_packet    <= 1'b1;
                end
                else
                begin
                end
            end
        end
        default:
        begin
            state <= STATE_PW_0;
        end
        endcase
    end
end

//
// packet_count state machine
//
always @ (posedge csi_clock_clk or posedge csi_clock_reset)
begin
    if(csi_clock_reset)
    begin
        packet_count    <= 0;
    end
    else if(clear_packet_count)
    begin
        packet_count    <= 0;
    end
    else if(count_packet)
    begin
        packet_count    <= packet_count + 1;
    end
end

//
// slave interface machine
//
assign avs_s0_readdata  =   (avs_s0_address == 3'h0) ? ({{15{1'b0}}, udp_chan_0_en, udp_chan_0}) :
                            (avs_s0_address == 3'h1) ? ({{15{1'b0}}, udp_chan_1_en, udp_chan_1}) :
                            (avs_s0_address == 3'h2) ? ({{15{1'b0}}, udp_chan_2_en, udp_chan_2}) :
                            (avs_s0_address == 3'h3) ? ({{15{1'b0}}, udp_chan_3_en, udp_chan_3}) :
                            (packet_count);

always @ (posedge csi_clock_clk or posedge csi_clock_reset)
begin
    if(csi_clock_reset)
    begin
        clear_packet_count  <= 0;
        udp_chan_0          <= 0;
        udp_chan_1          <= 0;
        udp_chan_2          <= 0;
        udp_chan_3          <= 0;
        udp_chan_0_en       <= 0;
        udp_chan_1_en       <= 0;
        udp_chan_2_en       <= 0;
        udp_chan_3_en       <= 0;
    end
    else if(avs_s0_write)
    begin
        case(avs_s0_address)
            3'h0:
            begin
                if(avs_s0_byteenable[0] == 1'b1)
                    udp_chan_0[7:0]     <= avs_s0_writedata[7:0];
                if(avs_s0_byteenable[1] == 1'b1)
                    udp_chan_0[15:8]    <= avs_s0_writedata[15:8];
                if(avs_s0_byteenable[2] == 1'b1)
                    udp_chan_0_en   <= avs_s0_writedata[16];
            end
            3'h1:
            begin
                if(avs_s0_byteenable[0] == 1'b1)
                    udp_chan_1[7:0]     <= avs_s0_writedata[7:0];
                if(avs_s0_byteenable[1] == 1'b1)
                    udp_chan_1[15:8]    <= avs_s0_writedata[15:8];
                if(avs_s0_byteenable[2] == 1'b1)
                    udp_chan_1_en   <= avs_s0_writedata[16];
            end
            3'h2:
            begin
                if(avs_s0_byteenable[0] == 1'b1)
                    udp_chan_2[7:0]     <= avs_s0_writedata[7:0];
                if(avs_s0_byteenable[1] == 1'b1)
                    udp_chan_2[15:8]    <= avs_s0_writedata[15:8];
                if(avs_s0_byteenable[2] == 1'b1)
                    udp_chan_2_en   <= avs_s0_writedata[16];
            end
            3'h3:
            begin
                if(avs_s0_byteenable[0] == 1'b1)
                    udp_chan_3[7:0]     <= avs_s0_writedata[7:0];
                if(avs_s0_byteenable[1] == 1'b1)
                    udp_chan_3[15:8]    <= avs_s0_writedata[15:8];
                if(avs_s0_byteenable[2] == 1'b1)
                    udp_chan_3_en   <= avs_s0_writedata[16];
            end
            3'h3: clear_packet_count <= 1;
            default: ;
        endcase
    end
    else
    begin
        clear_packet_count <= 0;
    end
end

//
// data and status fifo instances
//
up2cm_data_fifo up2cm_data_fifo_inst (
    .aclr   ( csi_clock_reset ),
    .clock  ( csi_clock_clk ),
    .data   ( fifo_sink_word ),
    .rdreq  ( source_cycle ),
    .wrreq  ( sink_cycle ),
    .empty  ( data_fifo_empty ),
    .full   ( data_fifo_full ),
    .q      ( fifo_source_word )
    );

assign read_next_channel = source_cycle & aso_src0_endofpacket;

assign qualified_packet =   mac_type_is_ipv4    &
                            ip_hdr_is_ipv4      &
                            ip_hdr_len_is_5     &
                            (ip_hdr_csum[15:0] == 16'hFFFF) &
                            ip_flg_not_frag     &
                            ip_frag_zero        &
                            ip_proto_is_udp;

assign channel_fifo_in =    (qualified_packet && (udp_dest_port == udp_chan_0) && udp_chan_0_en) ? (3'h0) :
                            (qualified_packet && (udp_dest_port == udp_chan_1) && udp_chan_1_en) ? (3'h1) :
                            (qualified_packet && (udp_dest_port == udp_chan_2) && udp_chan_2_en) ? (3'h2) :
                            (qualified_packet && (udp_dest_port == udp_chan_3) && udp_chan_3_en) ? (3'h3) :
                            (3'h4);

up2cm_channel_fifo  up2cm_channel_fifo_inst (
    .aclr   ( csi_clock_reset ),
    .clock  ( csi_clock_clk ),
    .data   ( channel_fifo_in ),
    .rdreq  ( read_next_channel ),
    .wrreq  ( write_next_channel ),
    .empty  ( channel_fifo_empty ),
    .full   ( channel_fifo_full ),
    .q      ( channel_fifo_out )
    );

endmodule

 

Revise this Paste

Your Name: Code Language: