1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
/////////////////////////////////////////////////////////////////////
//
// Copyright 2014-2017 Ettus Research, A National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: chdr_eth_framer
// Description:
// - Takes a CHDR stream in and adds udp, ip, and ethernet framing
// - Use a RAM indexed by destination field of stream ID
// - Local RAM: For local host packets
// - Remote RAM: For remote host with different local_addr
//
/////////////////////////////////////////////////////////////////////
module n3xx_chdr_eth_framer #(
parameter BASE = 0,
parameter AWIDTH = 8
)(
input clk,
input reset,
input clear,
input set_stb,
input [AWIDTH-1:0] set_addr,
input [31:0] set_data,
input [63:0] in_tdata,
input in_tlast,
input in_tvalid,
output in_tready,
output [63:0] out_tdata,
output [3:0] out_tuser,
output out_tlast,
output out_tvalid,
input out_tready,
input [47:0] mac_src,
input [31:0] ip_src,
input [15:0] udp_src,
output [31:0] debug
);
localparam [11:0] REG_LOCAL_DST_IP = BASE + 'h0;
localparam [11:0] REG_LOCAL_DST_UDP_MAC_MSB = BASE + 'h100;
localparam [11:0] REG_LOCAL_DST_MAC_LSB = BASE + 'h200;
localparam [11:0] REG_REMOTE_DST_IP = BASE + 'h340;
localparam [11:0] REG_REMOTE_DST_UDP_MAC_MSB = BASE + 'h380;
localparam [11:0] REG_REMOTE_DST_MAC_LSB = BASE + 'h3c0;
reg [7:0] sid;
reg [15:0] chdr_len;
reg [3:0] local_addr;
reg [2:0] vef_state;
localparam VEF_IDLE = 3'd0;
localparam VEF_PAYLOAD = 3'd7;
reg [63:0] tdata;
always @(posedge clk)
if(reset | clear)
begin
vef_state <= VEF_IDLE;
sid <= 8'd0;
chdr_len <= 16'd0;
local_addr <= 4'd0;
end
else
case(vef_state)
VEF_IDLE :
if(in_tvalid)
begin
vef_state <= 1;
sid <= in_tdata[7:0];
chdr_len <= in_tdata[47:32];
local_addr <= in_tdata[11:8];
end
VEF_PAYLOAD :
if(in_tvalid & out_tready)
if(in_tlast)
vef_state <= VEF_IDLE;
default :
if(out_tready)
vef_state <= vef_state + 3'd1;
endcase // case (vef_state)
assign in_tready = (vef_state == VEF_PAYLOAD) ? out_tready : 1'b0;
assign out_tvalid = (vef_state == VEF_PAYLOAD) ? in_tvalid : (vef_state == VEF_IDLE) ? 1'b0 : 1'b1;
assign out_tlast = (vef_state == VEF_PAYLOAD) ? in_tlast : 1'b0;
assign out_tuser = ((vef_state == VEF_PAYLOAD) & in_tlast) ? {1'b0,chdr_len[2:0]} : 4'b0000;
assign out_tdata = tdata;
wire [47:0] pad = 48'h0;
wire [47:0] mac_dst;
wire [47:0] mac_local_dst;
wire [47:0] mac_remote_dst;
wire [15:0] eth_type = 16'h0800;
wire [15:0] misc_ip = { 4'd4 /* IPv4 */, 4'd5 /* IP HDR Len */, 8'h00 /* DSCP and ECN */};
wire [15:0] ip_len = (16'd28 + chdr_len); // 20 for IP, 8 for UDP
wire [15:0] ident = 16'h0;
wire [15:0] flag_frag = { 3'b010 /* don't fragment */, 13'h0 };
wire [15:0] ttl_prot = { 8'h10 /* TTL */, 8'h11 /* UDP */ };
wire [15:0] iphdr_local_checksum;
wire [15:0] iphdr_remote_checksum;
wire [15:0] iphdr_checksum;
wire [31:0] ip_dst;
wire [31:0] ip_local_dst;
wire [31:0] ip_remote_dst;
wire [15:0] udp_dst;
wire [15:0] udp_local_dst;
wire [15:0] udp_remote_dst;
wire [15:0] udp_len = (16'd8 + chdr_len);
wire [15:0] udp_checksum = 16'h0;
// Tables of MAC/IP/UDP addresses for LOCAL sid
ram_2port #(.DWIDTH(32), .AWIDTH(8)) ram_ip_local
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr[11:8] == REG_LOCAL_DST_IP[11:8])), .addra(set_addr[7:0]), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[7:0]), .dib(32'hFFFF_FFFF), .dob(ip_local_dst));
ram_2port #(.DWIDTH(32), .AWIDTH(8)) ram_udpmac_local
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr[11:8] == REG_LOCAL_DST_UDP_MAC_MSB[11:8])), .addra(set_addr[7:0]), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[7:0]), .dib(32'hFFFF_FFFF), .dob({udp_local_dst,mac_local_dst[47:32]}));
ram_2port #(.DWIDTH(32), .AWIDTH(8)) ram_maclower_local
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr[11:8] == REG_LOCAL_DST_MAC_LSB[11:8])), .addra(set_addr[7:0]), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[7:0]), .dib(32'hFFFF_FFFF), .dob(mac_local_dst[31:0]));
// Tables of MAC/IP/UDP addresses for REMOTE sid/local_addr
// Support only for 16 local_address
ram_2port #(.DWIDTH(32), .AWIDTH(4)) ram_ip_remote
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr[7:4] == REG_REMOTE_DST_IP[7:4])), .addra(set_addr[3:0]), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(local_addr), .dib(32'hFFFF_FFFF), .dob(ip_remote_dst));
ram_2port #(.DWIDTH(32), .AWIDTH(4)) ram_udpmac_remote
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr[7:4] == REG_REMOTE_DST_UDP_MAC_MSB[7:4])), .addra(set_addr[3:0]), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(local_addr), .dib(32'hFFFF_FFFF), .dob({udp_remote_dst,mac_remote_dst[47:32]}));
ram_2port #(.DWIDTH(32), .AWIDTH(4)) ram_maclower_remote
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr[7:4] == REG_REMOTE_DST_MAC_LSB[7:4])), .addra(set_addr[3:0]), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(local_addr), .dib(32'hFFFF_FFFF), .dob(mac_remote_dst[31:0]));
ip_hdr_checksum ip_hdr_checksum_local
(.clk(clk), .in({misc_ip,ip_len,ident,flag_frag,ttl_prot,16'd0,ip_src,ip_local_dst}),
.out(iphdr_local_checksum));
ip_hdr_checksum ip_hdr_checksum_remote
(.clk(clk), .in({misc_ip,ip_len,ident,flag_frag,ttl_prot,16'd0,ip_src,ip_remote_dst}),
.out(iphdr_remote_checksum));
assign mac_dst = (local_addr == 4'b0 | local_addr == 4'b1) ? mac_local_dst : mac_remote_dst;
assign ip_dst = (local_addr == 4'b0 | local_addr == 4'b1) ? ip_local_dst : ip_remote_dst;
assign udp_dst = (local_addr == 4'b0 | local_addr == 4'b1) ? udp_local_dst : udp_remote_dst;
assign iphdr_checksum = (local_addr == 4'b0 | local_addr == 4'b1) ? iphdr_local_checksum : iphdr_remote_checksum;
always @*
case(vef_state)
1 : tdata <= { pad[47:0], mac_dst[47:32]};
2 : tdata <= { mac_dst[31:0], mac_src[47:16]};
3 : tdata <= { mac_src[15:0], eth_type[15:0], misc_ip[15:0], ip_len[15:0] };
4 : tdata <= { ident[15:0], flag_frag[15:0], ttl_prot[15:0], iphdr_checksum[15:0]};
5 : tdata <= { ip_src, ip_dst};
6 : tdata <= { udp_src, udp_dst, udp_len, udp_checksum};
default : tdata <= in_tdata;
endcase // case (vef_state)
endmodule // chdr_eth_framer
|