Removed copy of FPGA source files.

Original-commit: fd3e84941de463fa1a7ebab0a69515b4bf2614cd
This commit is contained in:
Martin Braun
2014-10-07 11:25:20 +02:00
parent 56e84828fe
commit 74893643ca
2415 changed files with 0 additions and 1492030 deletions
-3
View File
@@ -1,3 +0,0 @@
vita.txt
xo.txt
zpu.txt
-23
View File
@@ -1,23 +0,0 @@
#
# Copyright 2013 Ettus Research LLC
#
##################################################
# Packet Processing Sources
##################################################
PACKET_PROC_SRCS = $(abspath $(addprefix $(BASE_DIR)/../lib/packet_proc/, \
eth_dispatch.v \
ip_hdr_checksum.v \
vrlp_eth_framer.v \
chdr_eth_framer.v \
eth_interface.v \
vrlp_to_compressed_vita.v \
compressed_vita_to_vrlp.v \
source_flow_control.v \
cvita_insert_tlast.v \
cvita_dest_lookup.v \
cvita_chunker.v \
cvita_dechunker.v \
axis_packet_debug.v \
cvita_packet_debug.v \
))
-71
View File
@@ -1,71 +0,0 @@
//
// Copyright 2014 Ettus Research LLC
//
module axis_packet_debug (
input clk,
input reset,
input clear,
//Packet In
input [63:0] tdata,
input tlast,
input tvalid,
input tready,
//Per packet info
output reg pkt_strobe,
output reg [15:0] length,
output reg [63:0] checksum,
//Statistics
output reg [31:0] pkt_count
);
localparam ST_HEADER = 1'b0;
localparam ST_DATA = 1'b1;
//Packet state logic
reg pkt_state;
always @(posedge clk) begin
if (reset) begin
pkt_state <= ST_HEADER;
end else if (tvalid & tready) begin
pkt_state <= tlast ? ST_HEADER : ST_DATA;
end
end
//Trigger logic
always @(posedge clk)
if (reset)
pkt_strobe <= 1'b0;
else
pkt_strobe <= tvalid & tready & tlast;
//Length capture
always @(posedge clk)
if (reset || pkt_state == ST_HEADER)
length <= tlast ? 16'd8 : 16'd0;
else
if (tvalid & tready)
length <= length + 16'd8;
//Checksum capture
always @(posedge clk)
if (reset || pkt_state == ST_HEADER)
checksum <= 64'd0;
else
if (tvalid & tready)
checksum <= checksum ^ tdata;
//Counts
always @(posedge clk)
if (reset | clear) begin
pkt_count <= 32'd0;
end else begin
if (tvalid & tready & tlast) begin
pkt_count <= pkt_count + 32'd1;
end
end
endmodule // cvita_packet_debug
-136
View File
@@ -1,136 +0,0 @@
// chdr_eth_framer
// Takes a CHDR stream in and adds udp, ip, and ethernet framing
// Uses 8 setting reg addresses. First 4 are simple registers:
// BASE+0 : Upper 16 bits of ethernet src mac
// BASE+1 : Lower 32 bits of ethernet src mac
// BASE+2 : IP src address
// BASE+3 : UDP src port
//
// Next 4 control write ports on a RAM indexed by destination field of stream ID
// BASE+4 : Dest SID for next 3 regs
// BASE+5 : Dest IP
// BASE+6 : Dest UDP port, upper 16 bits of dest mac
// BASE+7 : Lower 32 bits of dest mac
//
module chdr_eth_framer
#(parameter BASE=0)
(input clk, input reset, input clear,
input set_stb, input [7: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,
output [31:0] debug );
localparam SR_AWIDTH = 8;
reg [7:0] sid;
reg [15:0] chdr_len;
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;
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];
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_src, mac_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_checksum;
wire [31:0] ip_src, ip_dst;
wire [15:0] udp_src, udp_dst;
wire [15:0] udp_len = (16'd8 + chdr_len);
wire [15:0] udp_checksum = 16'h0;
setting_reg #(.my_addr(BASE), .awidth(SR_AWIDTH), .width(16)) set_mac_upper
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(mac_src[47:32]), .changed());
setting_reg #(.my_addr(BASE+1), .awidth(SR_AWIDTH), .width(32)) set_mac_lower
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(mac_src[31:0]), .changed());
setting_reg #(.my_addr(BASE+2), .awidth(SR_AWIDTH), .width(32)) set_ip
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(ip_src), .changed());
setting_reg #(.my_addr(BASE+3), .awidth(SR_AWIDTH), .width(16)) set_udp
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(udp_src), .changed());
// Tables of MAC/IP/UDP addresses
wire [7:0] ram_addr; // FIXME we could skip this part if we had wider SR addresses
setting_reg #(.my_addr(BASE+4), .awidth(SR_AWIDTH), .width(8)) set_ram_addr
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(ram_addr), .changed());
ram_2port #(.DWIDTH(32), .AWIDTH(8)) ram_ip
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+5)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[7:0]), .dib(32'hFFFF_FFFF), .dob(ip_dst));
ram_2port #(.DWIDTH(32), .AWIDTH(8)) ram_udpmac
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+6)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[7:0]), .dib(32'hFFFF_FFFF), .dob({udp_dst,mac_dst[47:32]}));
ram_2port #(.DWIDTH(32), .AWIDTH(8)) ram_maclower
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+7)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[7:0]), .dib(32'hFFFF_FFFF), .dob(mac_dst[31:0]));
ip_hdr_checksum ip_hdr_checksum
(.clk(clk), .in({misc_ip,ip_len,ident,flag_frag,ttl_prot,16'd0,ip_src,ip_dst}),
.out(iphdr_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
-78
View File
@@ -1,78 +0,0 @@
module compressed_vita_to_vrlp
(input clk, input reset, input clear,
input [63:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [63:0] o_tdata, output [15:0] o_tuser, output o_tlast, output o_tvalid, input o_tready
);
wire [19:0] vrlp_size = 20'd3 + {4'b0000,i_tdata[47:32]};
reg odd_len;
reg [2:0] cv2v_state;
reg [63:0] o_tdata_int;
wire o_tlast_int, o_tvalid_int, o_tready_int;
localparam CV2V_VRLP = 3'd0; // VRLP header
localparam CV2V_VRT_ECH = 3'd1; // Extension context header
localparam CV2V_VRT_IFH = 3'd2; // IF Data header
localparam CV2V_BODY = 3'd3;
localparam CV2V_VEND_ODD = 3'd4;
localparam CV2V_VEND_EVEN = 3'd4;
always @(posedge clk)
if(reset | clear)
begin
cv2v_state <= CV2V_VRLP;
odd_len <= 1'b0;
end
else
case(cv2v_state)
CV2V_VRLP :
if(i_tvalid & o_tready_int)
begin
odd_len <= i_tdata[32];
if(i_tdata[63])
cv2v_state <= CV2V_VRT_ECH;
else
cv2v_state <= CV2V_VRT_IFH;
end
CV2V_VRT_ECH, CV2V_VRT_IFH :
if(i_tvalid & o_tready_int)
cv2v_state <= CV2V_BODY;
CV2V_BODY :
if(i_tlast & i_tvalid & o_tready_int)
if(odd_len)
cv2v_state <= CV2V_VRLP;
else
cv2v_state <= CV2V_VEND_EVEN;
CV2V_VEND_EVEN :
if(o_tready_int)
cv2v_state <= CV2V_VRLP;
endcase // case (cv2v_state)
assign i_tready = o_tready_int & (cv2v_state != CV2V_VRLP) & (cv2v_state != CV2V_VEND_EVEN);
assign o_tvalid_int = i_tvalid | (cv2v_state == CV2V_VEND_EVEN);
always @*
case(cv2v_state)
CV2V_VRLP : o_tdata_int <= { 32'h5652_4c50 /*VRLP*/, i_tdata[59:48] /*seqnum*/, vrlp_size[19:0] };
CV2V_VRT_ECH : o_tdata_int <= { 4'h5 /*type*/, 4'h0, 3'b00, i_tdata[61] /*time*/, i_tdata[51:48] /*seqnum*/, i_tdata[47:32] /*len*/, i_tdata[31:0] /*sid*/ };
CV2V_VRT_IFH : o_tdata_int <= { 4'h1 /*type*/, 1'b0, i_tdata[62] /*TRL*/, 1'b0, i_tdata[60] /*eob*/, 3'b00, i_tdata[61] /*time*/, i_tdata[51:48] /*seqnum*/, i_tdata[47:32] /*len*/, i_tdata[31:0] /*sid*/ };
CV2V_BODY : o_tdata_int <= (i_tlast & odd_len) ? { i_tdata[63:32], 32'h5645_4E44 /*VEND*/ } : i_tdata;
CV2V_VEND_EVEN : o_tdata_int <= { 32'h5645_4E44 /*VEND*/, 32'h0};
default : o_tdata_int <= i_tdata;
endcase // case (cv2v_state)
assign o_tlast_int = (cv2v_state == CV2V_VEND_EVEN) | ((cv2v_state == CV2V_BODY) & i_tlast & odd_len);
// Short FIFO before output
axi_fifo_short #(.WIDTH(81)) axi_fifo_short
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({o_tlast_int, i_tdata[15:0], o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
.o_tdata({o_tlast, o_tuser, o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
endmodule // compressed_vita_to_vrlp
-91
View File
@@ -1,91 +0,0 @@
//
// Copyright 2013 Ettus Research LLC
//
// Quantize cvita packets to a configurable quantum value. o_tlast and
// i_tready will be held off until the entire quantized packet is xferred.
// If quantum is changed, it is the responsibility of the client to clear
// this module. error is asserted if a packet is larger than the quantum
// error can be reset by asserting reset or clear.
module cvita_chunker # (
parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF
) (
input clk,
input reset,
input clear,
input [15:0] frame_size,
input [63:0] i_tdata,
input i_tlast,
input i_tvalid,
output i_tready,
output [63:0] o_tdata,
output o_tlast,
output o_tvalid,
input o_tready,
output error
);
localparam ST_HEADER = 2'd0;
localparam ST_DATA = 2'd1;
localparam ST_PADDING = 2'd2;
localparam ST_ERROR = 2'd3;
reg [1:0] state;
reg [15:0] frame_rem;
wire [15:0] cvita_len_ceil = i_tdata[47:32] + 7;
wire [15:0] axi_len = {3'b000, cvita_len_ceil[15:3]};
always @(posedge clk) begin
if (reset | clear) begin
state <= ST_HEADER;
frame_rem <= 16'd0;
end else if (o_tvalid & o_tready) begin
case (state)
ST_HEADER: begin
if (axi_len > frame_size)
state <= ST_ERROR;
else if (i_tlast)
state <= ST_PADDING;
else
state <= ST_DATA;
frame_rem <= frame_size - 16'd1;
end
ST_DATA: begin
if (i_tlast) begin
state <= o_tlast ? ST_HEADER : ST_PADDING;
frame_rem <= o_tlast ? 16'd0 : (frame_rem - 16'd1);
end else begin
state <= ST_DATA;
frame_rem <= frame_rem - 16'd1;
end
end
ST_PADDING: begin
if (o_tlast) begin
state <= ST_HEADER;
frame_rem <= 16'd0;
end else begin
state <= ST_PADDING;
frame_rem <= frame_rem - 16'd1;
end
end
endcase
end
end
assign i_tready = o_tready & (state != ST_PADDING);
assign o_tvalid = i_tvalid | (state == ST_PADDING);
assign o_tlast = (frame_rem != 0) ? (frame_rem == 16'd1) : (axi_len == 16'd1);
assign o_tdata = (state == ST_PADDING) ? PAD_VALUE : i_tdata;
assign error = (state == ST_ERROR);
endmodule // cvita_chunker
-187
View File
@@ -1,187 +0,0 @@
//
// Copyright 2013 Ettus Research LLC
//
`timescale 500ps/1ps
module cvita_chunker_tb();
// TB stimulus
reg clk = 0;
reg reset = 1;
reg clear = 0;
reg [15:0] quantum;
// Check vars
reg [31:0] o_xfer_count = 0, i_xfer_count = 0;
reg [63:0] o_last_tdata = 0;
always #10 clk = ~clk;
initial $dumpfile("cvita_chunker_tb.vcd");
initial $dumpvars(0,cvita_chunker_tb);
function check_result;
input [31:0] o_xfer_count_arg;
input [31:0] i_xfer_count_arg;
input [63:0] o_last_tdata_arg;
input error_arg;
begin
//Check vars
check_result = 1;
check_result = check_result & ((o_xfer_count_arg == o_xfer_count) !== 0);
check_result = check_result & ((i_xfer_count_arg == i_xfer_count) !== 0);
check_result = check_result & ((o_last_tdata_arg == o_last_tdata) !== 0);
check_result = check_result & ((error_arg == error) != 0);
if (check_result) begin
$display ("... Passed");
end else begin
$display ("... FAILED!!!");
$display ("o_xfer_count = %d (Expected %d)",o_xfer_count,o_xfer_count_arg);
$display ("i_xfer_count = %d (Expected %d)",i_xfer_count,i_xfer_count_arg);
$display ("o_last_tdata = %h (Expected %h)",o_last_tdata,o_last_tdata_arg);
$display ("error = %d (Expected %d)",error,error_arg);
end
//Reset vars
o_xfer_count = 0;
i_xfer_count = 0;
o_last_tdata = 64'h0;
end
endfunction
task send_packet;
input [63:0] data_start;
input [31:0] len;
begin
if(len < 9) begin
{i_tlast, i_tdata} <= { 1'b1, data_start[63:48],len[15:0], data_start[31:0] };
i_tvalid <= 1;
@(posedge clk);
i_tvalid <= 0;
end else begin
{i_tlast, i_tdata} <= { 1'b0, data_start[63:48],len[15:0], data_start[31:0] };
i_tvalid <= 1;
@(posedge clk);
repeat(((len-1)/8)-1) begin
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
@(posedge clk);
end
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
i_tlast <= 1;
@(posedge clk);
i_tvalid <= 0;
end // else: !if(len < 3)
end
endtask // send_packet
task reset_quantum_atomic;
input [15:0] quant;
begin
quantum <= quant;
clear <= 1;
@(posedge clk);
clear <= 0;
@(posedge clk);
end
endtask // reset_quantum_atomic
initial begin
#100 reset = 0;
#200000;
$finish;
end
reg [63:0] i_tdata;
reg i_tlast;
reg i_tvalid;
wire i_tready;
wire [63:0] o_tdata;
wire o_tlast, o_tvalid, o_tready;
wire error;
initial begin
quantum <= 256;
i_tvalid <= 0;
while(reset) @(posedge clk);
$write ("Running test case: First packet after reset");
send_packet(64'h00000001_00000000, 128);
while(o_tvalid) @(posedge clk);
check_result(256,16,64'hFFFFFFFF_FFFFFFFF,0);
reset_quantum_atomic(8);
$write ("Running test case: sizeof(packet) < quantum");
send_packet(64'h00000001_00000000, 40);
while(o_tvalid) @(posedge clk);
check_result(8,5,64'hFFFFFFFF_FFFFFFFF,0);
reset_quantum_atomic(5);
$write ("Running test case: sizeof(packet) == quantum");
send_packet(64'h00000001_00000000, 40);
while(o_tvalid) @(posedge clk);
check_result(5,5,64'h00000030_00000008,0);
$write ("Running test case: sizeof(packet) == quantum - 64bits");
send_packet(64'h00000001_00000000, 32);
while(o_tvalid) @(posedge clk);
check_result(5,4,64'hFFFFFFFF_FFFFFFFF,0);
$write ("Running test case: sizeof(packet) == quantum + 64bits");
send_packet(64'h00000001_00000000, 48);
while(o_tvalid) @(posedge clk);
check_result(32'hxxxxxxxx,32'hxxxxxxxx,64'hxxxxxxxx_xxxxxxxx,1);
$write ("Running test case: Error reset");
reset_quantum_atomic(8);
check_result(32'hxxxxxxxx,32'hxxxxxxxx,64'hxxxxxxxx_xxxxxxxx,0);
$write ("Running test case: sizeof(packet) > quantum");
send_packet(64'h00000001_00000000, 80);
while(o_tvalid) @(posedge clk);
check_result(32'hxxxxxxxx,32'hxxxxxxxx,64'hxxxxxxxx_xxxxxxxx,1);
reset_quantum_atomic(8);
$write ("Running test case: sizeof(packet) == 2");
send_packet(64'h00000001_00000000, 8);
while(o_tvalid) @(posedge clk);
check_result(8,1,64'hFFFFFFFF_FFFFFFFF,0);
$write ("Running test case: Multiple packets back-to-back");
send_packet(64'h00000001_00000000, 40);
while(o_tvalid) @(posedge clk);
send_packet(64'h00000001_00000000, 16);
while(o_tvalid) @(posedge clk);
send_packet(64'h00000001_00000000, 64);
while(o_tvalid) @(posedge clk);
check_result(24,15,64'h0000004e0000000e,0);
end // initial begin
cvita_chunker dut (
.clk(clk), .reset(reset), .clear(clear), .frame_size(quantum),
.i_tdata(i_tdata), .i_tlast(i_tlast), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready),
.error(error));
assign o_tready = 1;
always @(posedge clk) begin
if (o_tvalid & o_tready) begin
o_xfer_count <= o_xfer_count + 1;
o_last_tdata <= o_tdata;
end
if (i_tvalid & i_tready) i_xfer_count <= i_xfer_count + 1;
end
endmodule // cvita_chunker_tb
-90
View File
@@ -1,90 +0,0 @@
//
// Copyright 2013 Ettus Research LLC
//
module cvita_dechunker # (
parameter PAD_VALUE = 64'hFFFFFFFF_FFFFFFFF
) (
input clk,
input reset,
input clear,
input [15:0] frame_size,
input [63:0] i_tdata,
input i_tvalid,
output i_tready,
output [63:0] o_tdata,
output o_tlast,
output o_tvalid,
input o_tready,
output error
);
localparam ST_HEADER = 2'd0;
localparam ST_DATA = 2'd1;
localparam ST_PADDING = 2'd2;
localparam ST_ERROR = 2'd3;
reg [1:0] state;
reg [15:0] frame_rem, pkt_rem;
wire i_tlast;
wire [15:0] cvita_len_ceil = i_tdata[47:32] + 7;
wire [15:0] axi_len = {3'b000, cvita_len_ceil[15:3]};
always @(posedge clk) begin
if (reset | clear) begin
state <= ST_HEADER;
frame_rem <= 16'd0;
pkt_rem <= 16'd0;
end else if (i_tvalid & i_tready) begin
case (state)
ST_HEADER: begin
if (axi_len > frame_size)
state <= ST_ERROR;
else if (~o_tlast)
state <= ST_DATA;
else
state <= ST_PADDING;
frame_rem <= frame_size - 16'd1;
pkt_rem <= axi_len - 16'd1;
end
ST_DATA: begin
if (o_tlast) begin
state <= i_tlast ? ST_HEADER : ST_PADDING;
pkt_rem <= 16'd0;
end else begin
state <= ST_DATA;
pkt_rem <= pkt_rem - 16'd1;
end
frame_rem <= frame_rem - 16'd1;
end
ST_PADDING: begin
if (i_tlast) begin
state <= ST_HEADER;
frame_rem <= 16'd0;
end else begin
state <= ST_PADDING;
frame_rem <= frame_rem - 16'd1;
end
end
endcase
end
end
assign i_tready = o_tready | (state == ST_PADDING);
assign i_tlast = (frame_rem == 16'd1); //Temp signal
assign o_tvalid = i_tvalid & (state != ST_PADDING);
assign o_tlast = (pkt_rem != 0) ? (pkt_rem == 16'd1) : (axi_len == 16'd1);
assign o_tdata = i_tdata;
assign error = (state == ST_ERROR);
endmodule // cvita_dechunker
-183
View File
@@ -1,183 +0,0 @@
//
// Copyright 2013 Ettus Research LLC
//
`timescale 500ps/1ps
module cvita_dechunker_tb();
// TB stimulus
reg clk = 0;
reg reset = 1;
reg clear = 0;
reg [15:0] quantum;
wire error;
// Check vars
reg [31:0] o_xfer_count = 0, i_xfer_count = 0;
reg [63:0] o_last_tdata = 0;
always #10 clk = ~clk;
initial $dumpfile("cvita_dechunker_tb.vcd");
initial $dumpvars(0,cvita_dechunker_tb);
function check_result;
input [31:0] o_xfer_count_arg;
input [31:0] i_xfer_count_arg;
input [63:0] o_last_tdata_arg;
input error_arg;
begin
//Check vars
check_result = 1;
check_result = check_result & ((o_xfer_count_arg == o_xfer_count) !== 0);
check_result = check_result & ((i_xfer_count_arg == i_xfer_count) !== 0);
check_result = check_result & ((o_last_tdata_arg == o_last_tdata) !== 0);
check_result = check_result & ((error_arg == error) != 0);
if (check_result) begin
$display ("... Passed");
end else begin
$display ("... FAILED!!!");
$display ("o_xfer_count = %d (Expected %d)",o_xfer_count,o_xfer_count_arg);
$display ("i_xfer_count = %d (Expected %d)",i_xfer_count,i_xfer_count_arg);
$display ("o_last_tdata = %h (Expected %h)",o_last_tdata,o_last_tdata_arg);
$display ("error = %d (Expected %d)",error,error_arg);
end
//Reset vars
o_xfer_count = 0;
i_xfer_count = 0;
o_last_tdata = 64'h0;
end
endfunction
task send_packet;
input [63:0] data_start;
input [31:0] len;
input [31:0] quant;
begin
if(quant < 2) begin
{i_tlast, i_tdata} <= { 1'b1, data_start[63:48],len[15:0], data_start[31:0] };
i_tvalid <= 1;
@(posedge clk);
i_tvalid <= 0;
end else begin
{i_tlast, i_tdata} <= { 1'b0, data_start[63:48],len[15:0], data_start[31:0] };
i_tvalid <= 1;
@(posedge clk);
repeat(quant - 2) begin
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
@(posedge clk);
end
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
i_tlast <= 1;
@(posedge clk);
i_tvalid <= 1'b0;
end // else: !if(len < 3)
end
endtask // send_packet
task reset_quantum_atomic;
input [15:0] quant;
begin
quantum <= quant;
clear <= 1;
@(posedge clk);
clear <= 0;
@(posedge clk);
end
endtask // reset_quantum_atomic
initial begin
#100 reset = 0;
#200000;
$finish;
end
reg [63:0] i_tdata;
reg i_tlast;
reg i_tvalid;
wire i_tready;
wire [63:0] o_tdata;
wire o_tlast, o_tvalid, o_tready;
initial begin
quantum <= 8;
i_tvalid <= 0;
while(reset) @(posedge clk);
$write ("Running test case: First packet after reset");
send_packet(64'h00000001_00000000, 32, 8);
@(posedge clk);
check_result(4,8,64'hxxxxxxxx_xxxxxx06, 0);
reset_quantum_atomic(10);
$write ("Running test case: sizeof(packet) < quantum");
send_packet(64'h00000001_00000000, 64, 10);
@(posedge clk);
check_result(8,10,64'hxxxxxxxx_xxxxxx0e, 0);
$write ("Running test case: sizeof(packet) == quantum");
send_packet(64'h00000001_00000000, 80, 10);
@(posedge clk);
check_result(10,10,64'hxxxxxxxx_xxxxxx12, 0);
$write ("Running test case: sizeof(packet) == quantum - 64bits");
send_packet(64'h00000001_00000000, 72, 10);
@(posedge clk);
check_result(9,10,64'hxxxxxxxx_xxxxxx10, 0);
$write ("Running test case: sizeof(packet) == quantum + 64bits");
send_packet(64'h00000001_00000000, 88, 10);
@(posedge clk);
check_result(32'hxxxxxxxx,10,64'hxxxxxxxx_xxxxxxxx, 1);
reset_quantum_atomic(10);
$write ("Running test case: sizeof(packet) > quantum");
send_packet(64'h00000001_00000000, 88, 10);
@(posedge clk);
check_result(32'hxxxxxxxx,10,64'hxxxxxxxx_xxxxxxxx, 1);
reset_quantum_atomic(8);
$write ("Running test case: sizeof(packet) == 2");
send_packet(64'h00000001_00000000, 8, 8);
@(posedge clk);
check_result(1,8,64'hxxxxxxxx_xxxxxx00, 0);
$write ("Running test case: Multiple packets");
send_packet(64'h00000001_00000000, 8, 8);
send_packet(64'h00000001_00000000, 16, 8);
send_packet(64'h00000001_00000000, 24, 8);
send_packet(64'h00000001_00000000, 32, 8);
@(posedge clk);
check_result(10,32,64'hxxxxxxxx_xxxxxx06, 0);
end // initial begin
cvita_dechunker dut (
.clk(clk), .reset(reset), .clear(clear), .frame_size(quantum),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tlast(o_tlast), .o_tvalid(o_tvalid), .o_tready(o_tready),
.error(error));
assign o_tready = 1;
always @(posedge clk) begin
if (o_tvalid & o_tready) begin
o_xfer_count <= o_xfer_count + 1;
o_last_tdata <= o_tdata;
end
if (i_tvalid & i_tready) i_xfer_count <= i_xfer_count + 1;
end
endmodule // cvita_dechunker_tb
-48
View File
@@ -1,48 +0,0 @@
// Map the endpoint dest part of the SID in the CVITA header to a destination
// This destination (o_tdest) signal will be valid with o_tdata
// This only works with VALID CVITA frames
module cvita_dest_lookup
#(
parameter DEST_WIDTH = 4
)
(
input clk, input rst,
input set_stb, input [7:0] set_addr, input [DEST_WIDTH-1:0] set_data,
input [63:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready,
output [DEST_WIDTH-1:0] o_tdest
);
reg [7:0] endpoint;
ram_2port #(.DWIDTH(DEST_WIDTH), .AWIDTH(8)) dest_lut
(
.clka(clk), .ena(1'b1), .wea(set_stb), .addra(set_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(endpoint), .dib(8'hff), .dob(o_tdest)
);
reg forward;
reg [1:0] count;
always @(posedge clk) begin
if (rst) begin
forward <= 1'b0;
count <= 2'b0;
end
else if (forward == 1'b0 && i_tvalid) begin
if (count == 2'b11) forward <= 1'b1;
endpoint <= i_tdata[23:16];
count <= count + 1'b1;
end
else if (forward == 1'b1 && i_tvalid && i_tready && i_tlast) begin
forward <= 1'b0;
count <= 2'b0;
end
end
assign o_tdata = i_tdata;
assign o_tlast = i_tlast;
assign o_tvalid = i_tvalid && forward;
assign i_tready = o_tready && forward;
endmodule // cvita_dest_lookup
-33
View File
@@ -1,33 +0,0 @@
// Insert tlast bit for fifos that don't support it. This only works with VALID CVITA frames
// A single partial or invalid frame will make this wrong FOREVER
module cvita_insert_tlast
(input clk, input reset, input clear,
input [63:0] i_tdata, input i_tvalid, output i_tready,
output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
assign o_tdata = i_tdata;
assign o_tvalid = i_tvalid;
assign i_tready = o_tready;
wire [15:0] cvita_len_ceil = i_tdata[47:32] + 7;
wire [15:0] axi_len = {3'b000, cvita_len_ceil[15:3]};
reg [15:0] count;
assign o_tlast = (count != 0) ? (count == 16'd1) : (axi_len == 16'd1);
always @(posedge clk)
if(reset | clear)
begin
count <= 16'd0;
end
else
if(i_tready & i_tvalid)
if(count != 16'd0)
count <= count - 16'd1;
else
count <= axi_len - 16'd1;
endmodule // cvita_insert_tlast
-92
View File
@@ -1,92 +0,0 @@
`timescale 1ns/1ps
module cvita_insert_tlast_tb();
reg clk = 0;
reg reset = 1;
always #10 clk = ~clk;
initial $dumpfile("cvita_insert_tlast_tb.vcd");
initial $dumpvars(0,cvita_insert_tlast_tb);
task send_packet;
input [63:0] data_start;
input [31:0] len;
begin
if(len < 9)
begin
{i_tlast, i_tdata} <= { 1'b1, data_start[63:48],len[15:0], data_start[31:0] };
i_tvalid <= 1;
@(posedge clk);
i_tvalid <= 0;
end
else
begin
{i_tlast, i_tdata} <= { 1'b0, data_start[63:48],len[15:0], data_start[31:0] };
i_tvalid <= 1;
@(posedge clk);
repeat(((len-2)/2)-1+len[0])
begin
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
@(posedge clk);
end
i_tdata <= i_tdata + 64'h0000_0002_0000_0002;
i_tlast <= 1;
@(posedge clk);
i_tvalid <= 1'b0;
end // else: !if(len < 3)
end
endtask // send_packet
initial
begin
#1000 reset = 0;
#200000;
$finish;
end
reg [63:0] i_tdata;
reg i_tlast;
reg i_tvalid;
wire i_tready;
wire [63:0] o_tdata;
wire o_tlast, o_tvalid, o_tready, o_tlast_regen;
initial
begin
i_tvalid <= 0;
while(reset)
@(posedge clk);
@(posedge clk);
send_packet(64'hA0000000_A0000001, 24);
send_packet(64'hA0000000_A0000001, 20);
send_packet(64'hA0000000_A0000001, 16);
send_packet(64'hA0000000_A0000001, 12);
send_packet(64'hA0000000_A0000001, 8);
send_packet(64'hA0000000_A0000001, 4);
send_packet(64'hA0000000_A0000001, 4);
send_packet(64'hA0000000_A0000001, 8);
send_packet(64'hA0000000_A0000001, 12);
end // initial begin
cvita_insert_tlast dut
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata(i_tdata), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata(o_tdata), .o_tlast(o_tlast_regen), .o_tvalid(o_tvalid), .o_tready(o_tready));
assign o_tready = 1;
always @(posedge clk)
if(o_tvalid & o_tready)
begin
$display ("TLAST %x\t TLAST_REGEN %x",i_tlast, o_tlast_regen);
if(i_tlast != o_tlast_regen)
$display("ERROR!!!!!!");
end
endmodule // cvita_insert_tlast_tb
-108
View File
@@ -1,108 +0,0 @@
//
// Copyright 2014 Ettus Research LLC
//
module cvita_packet_debug (
input clk,
input reset,
input clear,
//Packet In
input [63:0] tdata,
input tlast,
input tvalid,
input tready,
//Per packet info
output reg pkt_strobe,
output reg [63:0] header,
output reg [63:0] timestamp,
output reg [15:0] actual_length,
output reg [63:0] checksum,
//Statistics
output reg [31:0] pkt_count,
output reg [31:0] ctrl_pkt_count
);
localparam ST_HEADER = 2'd0;
localparam ST_TIME = 2'd1;
localparam ST_DATA = 2'd2;
//Packet state logic
reg [1:0] pkt_state;
always @(posedge clk) begin
if (reset) begin
pkt_state <= ST_HEADER;
end else if (tvalid & tready) begin
case(pkt_state)
ST_HEADER: begin
if (!tlast)
pkt_state <= (tdata[61]) ? ST_TIME : ST_DATA;
end
ST_TIME: begin
pkt_state <= (tlast) ? ST_HEADER : ST_DATA;
end
ST_DATA: begin
pkt_state <= (tlast) ? ST_HEADER : ST_DATA;
end
default: pkt_state <= ST_HEADER;
endcase
end
end
//Trigger logic
always @(posedge clk)
if (reset)
pkt_strobe <= 1'b0;
else
pkt_strobe <= tvalid & tready & tlast;
//Header capture
always @(posedge clk)
if (reset)
header <= 64'd0;
else if (pkt_state == ST_HEADER)
if (tvalid & tready)
header <= tdata;
//Timestamp capture
always @(posedge clk)
if (reset)
timestamp <= 64'd0;
else if (pkt_state == ST_TIME)
if (tvalid & tready)
timestamp <= tdata;
//Length capture
always @(posedge clk)
if (reset || pkt_state == ST_HEADER)
actual_length <= (tvalid & tready & tlast) ? 16'd8 : 16'd0;
else
if (tvalid & tready)
actual_length <= actual_length + 16'd8;
//Checksum capture
always @(posedge clk)
if (reset || pkt_state == ST_HEADER)
checksum <= 64'd0;
else if (pkt_state == ST_DATA)
if (tvalid & tready)
checksum <= checksum ^ tdata;
//Counts
always @(posedge clk)
if (reset | clear) begin
pkt_count <= 32'd0;
ctrl_pkt_count <= 32'd0;
end else begin
if (tvalid & tready & tlast) begin
pkt_count <= pkt_count + 32'd1;
if (pkt_state == ST_HEADER && tdata[63])
ctrl_pkt_count <= ctrl_pkt_count + 32'd1;
else if (header[63])
ctrl_pkt_count <= ctrl_pkt_count + 32'd1;
end
end
endmodule // cvita_packet_debug
-516
View File
@@ -1,516 +0,0 @@
// Ethernet dispatcher
// Incoming ethernet packets are examined and sent to the correct destination
// There are 3 destinations, ZPU, other ethernet port (out), and vita router
// Packets going to the vita router will have the ethernet/ip/udp headers stripped off.
//
// To make things simpler, we start out by sending all packets to zpu and out port.
// By the end of the eth/ip/udp headers, we can determine where the correct destination is.
// If the correct destination is vita, we send an error indication on the zpu and out ports,
// which will cause the axi_packet_gate to drop those packets, and send the vita frame to
// the vita port.
//
// If at the end of the headers we determine the packet should go to zpu, then we send an
// error indication on the out port, the rest of the packet to zpu and nothing on vita.
// If it should go to out, we send the error indication to zpu, the rest of the packet to out,
// and nothing on vita.
//
// Downstream we should have adequate fifo space, otherwise we could get backed up here.
//
// No tuser bits sent to vita, as vita assumes there are no errors and that occupancy is
// indicated by the length field of the vita header.
//
// Rules for forwarding:
//
// Ethernet Broadcast (Dst MAC = ff:ff:ff:ff:ff:ff). Forward to both ZPU and XO MAC.
// ? Ethernet Multicast (Dst MAC = USRP_NEXT_HOP). Forward only to ZPU.
// ? Ethernet Multicast (Dst MAC = Unknown). Forward only to XO.
// Ethernet Unicast (Dst MAC = Unknown). Forward only to XO.
// Ethernet Unicast (Dst MAC = local). Look deeper......
// IP Broadcast. Forward to both ZPU and XO MAC. (Should be coverd by Eth broadcast)
// IP Multicast. ? Unknow Action.
// IP Unicast (Dst IP = local). Look deeper....
// UDP (Port = Listed) and its a VRLP packet. Forward only to VITA Radio Core.
// UDP (Port = Unknown). Forward only to ZPU.
//
//
module eth_dispatch
#(parameter BASE=0)
(
// Clocking and reset interface
input clk,
input reset,
input clear,
// Setting register interface
input set_stb,
input [15:0] set_addr,
input [31:0] set_data,
// Input 68bit AXI-Stream interface (from MAC)
input [63:0] in_tdata,
input [3:0] in_tuser,
input in_tlast,
input in_tvalid,
output in_tready,
// Output AXI-STream interface to VITA Radio Core
output [63:0] vita_tdata,
output [3:0] vita_tuser,
output vita_tlast,
output vita_tvalid,
input vita_tready,
// Output AXI-Stream interface to ZPU
output [63:0] zpu_tdata,
output [3:0] zpu_tuser,
output zpu_tlast,
output zpu_tvalid,
input zpu_tready,
// Output AXI-Stream interface to cross-over MAC
output [63:0] xo_tdata,
output [3:0] xo_tuser,
output xo_tlast,
output xo_tvalid,
input xo_tready,
// Debug
output [2:0] debug_flags,
output [31:0] debug
);
//---------------------------------------------------------
// State machine declarations
//---------------------------------------------------------
reg [2:0] state;
localparam WAIT_PACKET = 0;
localparam READ_HEADER = 1;
localparam FORWARD_ZPU = 2;
localparam FORWARD_ZPU_AND_XO = 3;
localparam FORWARD_XO = 4;
localparam FORWARD_RADIO_CORE = 5;
localparam DROP_PACKET = 6;
localparam CLASSIFY_PACKET = 7;
// Small RAM stores packet header during parsing.
// IJB consider changing HEADER_RAM_SIZE to 7
localparam HEADER_RAM_SIZE = 9;
(*ram_style="distributed"*) reg [68:0] header_ram [HEADER_RAM_SIZE-1:0];
reg [3:0] header_ram_addr;
wire header_done = (header_ram_addr == HEADER_RAM_SIZE-1);
reg fwd_input;
reg [63:0] in_tdata_reg;
wire out_tvalid;
wire out_tready;
wire out_tlast;
wire [3:0] out_tuser;
wire [63:0] out_tdata;
// Output AXI-Stream interface to VITA Radio Core
wire [63:0] vita_pre_tdata;
wire [3:0] vita_pre_tuser;
wire vita_pre_tlast;
wire vita_pre_tvalid;
wire vita_pre_tready;
// Output AXI-Stream interface to ZPU
wire [63:0] zpu_pre_tdata;
wire [3:0] zpu_pre_tuser;
wire zpu_pre_tlast;
wire zpu_pre_tvalid;
wire zpu_pre_tready;
// Output AXI-Stream interface to cross-over MAC
wire [63:0] xo_pre_tdata;
wire [3:0] xo_pre_tuser;
wire xo_pre_tlast;
wire xo_pre_tvalid;
wire xo_pre_tready;
// Packet Parse Flags
reg is_eth_dst_addr;
reg is_eth_broadcast;
reg is_eth_type_ipv4;
reg is_ipv4_dst_addr;
reg is_ipv4_proto_udp;
reg is_ipv4_proto_icmp;
reg [1:0] is_udp_dst_ports;
reg is_icmp_no_fwd;
reg is_chdr;
//---------------------------------------------------------
// Settings regs
//---------------------------------------------------------
// MAC address for the dispatcher module.
// This value is used to determine if the packet is meant
// for this device should be consumed
wire [47:0] my_mac;
setting_reg #(.my_addr(BASE), .awidth(16), .width(32)) sr_my_mac_lsb
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(my_mac[31:0]),.changed());
setting_reg #(.my_addr(BASE+1), .awidth(16), .width(16)) sr_my_mac_msb
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(my_mac[47:32]),.changed());
// IP address for the dispatcher module.
// This value is used to determine if the packet is addressed
// to this device
wire [31:0] my_ip;
setting_reg #(.my_addr(BASE+2), .awidth(16), .width(32)) sr_my_ip
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out(my_ip[31:0]),.changed());
// This module supports two destination ports
wire [15:0] my_port0, my_port1;
setting_reg #(.my_addr(BASE+3), .awidth(16), .width(32)) sr_udp_port
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({my_port1[15:0],my_port0[15:0]}),.changed());
// forward_ndest: Forward to crossover path if MAC Addr in packet
// does not match "my_mac"
// forward_bcast: Forward broadcasts to crossover path
wire forward_ndest, forward_bcast;
setting_reg #(.my_addr(BASE+4), .awidth(16), .width(2)) sr_forward_ctrl
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({forward_ndest, forward_bcast}),.changed());
//ICMP Type and Code to forward packet to ZPU
wire [7:0] my_icmp_type, my_icmp_code;
setting_reg #(.my_addr(BASE+5), .awidth(16), .width(16)) sr_icmp_ctrl
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),
.in(set_data),.out({my_icmp_type, my_icmp_code}),.changed());
//---------------------------------------------------------
// Packet Forwarding State machine.
//---------------------------------------------------------
// Read input packet and store the header into a RAM for
// classification. A header is defined as HEADER_RAM_SIZE
// number of 64-bit words.
// Based on clasification results, output the packet to the
// VITA port, crossover(XO) port or the ZPU. Note that the
// XO and ZPU ports require fully framed Eth packets so data
// from the RAM has to be replayed on the output. The state
// machine will hold off input packets until the header is
// replayed. The state machine also supports dropping pkts.
always @(posedge clk)
if (reset || clear) begin
state <= WAIT_PACKET;
header_ram_addr <= 0;
fwd_input <= 0;
end else begin
// Defaults.
case(state)
//
// Wait for start of a packet
// IJB: Add protection for a premature EOF here
//
WAIT_PACKET: begin
if (in_tvalid && in_tready) begin
header_ram[header_ram_addr] <= {in_tlast,in_tuser,in_tdata};
header_ram_addr <= header_ram_addr + 1;
state <= READ_HEADER;
end
fwd_input <= 0;
end
//
// Continue to read full packet header into RAM.
//
READ_HEADER: begin
if (in_tvalid && in_tready) begin
header_ram[header_ram_addr] <= {in_tlast,in_tuser,in_tdata};
// Have we reached end of fields we parse in header or got a short packet?
if (header_done || in_tlast) begin
// Make decision about where this packet is forwarded to.
state <= CLASSIFY_PACKET;
end // if (header_done || in_tlast)
else begin
header_ram_addr <= header_ram_addr + 1;
state <= READ_HEADER;
end // else: !if(header_done || in_tlast)
end // if (in_tvalid && in_tready)
end // case: READ_HEADER
//
// Classify Packet
//
CLASSIFY_PACKET: begin
// Make decision about where this packet is forwarded to.
if (is_eth_type_ipv4 && is_ipv4_proto_icmp && is_icmp_no_fwd) begin
header_ram_addr <= 0;
state <= FORWARD_ZPU;
end else if (is_eth_broadcast) begin
header_ram_addr <= 0;
state <= forward_bcast? FORWARD_ZPU_AND_XO : FORWARD_ZPU;
end else if (!is_eth_dst_addr && forward_ndest) begin
header_ram_addr <= 0;
state <= FORWARD_XO;
end else if (!is_eth_dst_addr && !forward_ndest) begin
header_ram_addr <= HEADER_RAM_SIZE - 1;
state <= DROP_PACKET;
end else if ((is_udp_dst_ports != 0) && is_chdr) begin
header_ram_addr <= 6; // Jump to CHDR
state <= FORWARD_RADIO_CORE;
end else begin
header_ram_addr <= 0;
state <= FORWARD_ZPU;
end
end // case: CLASSIFY_PACKET
//
// Forward this packet only to local ZPU
//
FORWARD_ZPU: begin
if (out_tvalid && out_tready) begin
if (out_tlast) begin
state <= WAIT_PACKET;
end
if (header_done) fwd_input <= 1;
header_ram_addr <= out_tlast? 4'b0 : header_ram_addr + 1;
end
end
//
// Forward this packet to both local ZPU and XO
//
FORWARD_ZPU_AND_XO: begin
if (out_tvalid && out_tready) begin
if (out_tlast) begin
state <= WAIT_PACKET;
end
if (header_done) fwd_input <= 1;
header_ram_addr <= out_tlast? 4'b0 : header_ram_addr + 1;
end
end
//
// Forward this packet to XO only
//
FORWARD_XO: begin
if (out_tvalid && out_tready) begin
if (out_tlast) begin
state <= WAIT_PACKET;
end
if (header_done) fwd_input <= 1;
header_ram_addr <= out_tlast? 4'b0 : header_ram_addr + 1;
end
end
//
// Forward this packet to the Radio Core only
//
FORWARD_RADIO_CORE: begin
if (out_tvalid && out_tready) begin
if (out_tlast) begin
state <= WAIT_PACKET;
end
if (header_done) fwd_input <= 1;
header_ram_addr <= out_tlast? 4'b0 : header_ram_addr + 1;
end
end
//
// Drop this packet on the ground
//
DROP_PACKET: begin
if (out_tvalid && out_tready) begin
if (out_tlast) begin
state <= WAIT_PACKET;
end
if (header_done) fwd_input <= 1;
header_ram_addr <= out_tlast? 4'b0 : header_ram_addr + 1;
end
end
endcase // case (state)
end // else: !if(reset || clear)
//---------------------------------------------------------
// Classifier State machine.
// Deep packet inspection during header ingress.
//---------------------------------------------------------
// As the packet header is pushed into the RAM, set classification
// bits so that by the time the input state machine reaches the
// CLASSIFY_PACKET state, the packet has been fully identified.
always @(posedge clk)
if (reset || clear) begin
is_eth_dst_addr <= 1'b0;
is_eth_broadcast <= 1'b0;
is_eth_type_ipv4 <= 1'b0;
is_ipv4_dst_addr <= 1'b0;
is_ipv4_proto_udp <= 1'b0;
is_ipv4_proto_icmp <= 1'b0;
is_udp_dst_ports <= 0;
is_icmp_no_fwd <= 0;
is_chdr <= 1'b0;
end else if (in_tvalid && in_tready) begin // if (reset || clear)
in_tdata_reg <= in_tdata;
case (header_ram_addr)
// Pipelined, so nothing to look at first cycle.
// Reset all the flags here.
0: begin
is_eth_dst_addr <= 1'b0;
is_eth_broadcast <= 1'b0;
is_eth_type_ipv4 <= 1'b0;
is_ipv4_dst_addr <= 1'b0;
is_ipv4_proto_udp <= 1'b0;
is_ipv4_proto_icmp <= 1'b0;
is_udp_dst_ports <= 0;
is_icmp_no_fwd <= 0;
is_chdr <= 1'b0;
end
1: begin
// Look at upper 16bits of MAC Dst Addr.
if (in_tdata_reg[15:0] == 16'hFFFF)
is_eth_broadcast <= 1'b1;
if (in_tdata_reg[15:0] == my_mac[47:32])
is_eth_dst_addr <= 1'b1;
end
2: begin
// Look at lower 32bits of MAC Dst Addr.
if (is_eth_broadcast && (in_tdata_reg[63:32] == 32'hFFFFFFFF))
is_eth_broadcast <= 1'b1;
else
is_eth_broadcast <= 1'b0;
if (is_eth_dst_addr && (in_tdata_reg[63:32] == my_mac[31:0]))
is_eth_dst_addr <= 1'b1;
else
is_eth_dst_addr <= 1'b0;
end // case: 2
3: begin
// Look at Ethertype
if (in_tdata_reg[47:32] == 16'h0800)
is_eth_type_ipv4 <= 1'b1;
// Extract Packet Length
// ADD THIS HERE.
end
4: begin
// Look at protocol enapsulated by IPv4
if ((in_tdata_reg[23:16] == 8'h11) && is_eth_type_ipv4)
is_ipv4_proto_udp <= 1'b1;
if ((in_tdata_reg[23:16] == 8'h01) && is_eth_type_ipv4)
is_ipv4_proto_icmp <= 1'b1;
end
5: begin
// Look at IP DST Address.
if ((in_tdata_reg[31:0] == my_ip[31:0]) && is_eth_type_ipv4)
is_ipv4_dst_addr <= 1'b1;
end
6: begin
// Look at UDP dest port
if ((in_tdata_reg[47:32] == my_port0[15:0]) && is_ipv4_proto_udp)
is_udp_dst_ports[0] <= 1'b1;
if ((in_tdata_reg[47:32] == my_port1[15:0]) && is_ipv4_proto_udp)
is_udp_dst_ports[1] <= 1'b1;
// Look at ICMP type and code
if (in_tdata_reg[63:48] == {my_icmp_type, my_icmp_code} && is_ipv4_proto_icmp)
is_icmp_no_fwd <= 1'b1;
end
7: begin
// Look for a possible CHDR header string
// IJB. NOTE this is not a good test for a CHDR packet, we perhaps don;t need this state anyhow.
if (in_tdata_reg[63:32] != 32'h0)
is_chdr <= 1'b1;
end
8: begin
// Check VRT Stream ID
// ADD THIS HERE.
// IJB. Perhaps delete this state.
end
endcase // case (header_ram_addr)
end // if (in_tvalid && in_tready)
//---------------------------------------------------------
// Output (Egress) Interface muxing
//---------------------------------------------------------
assign out_tready =
(state == DROP_PACKET) ||
((state == FORWARD_RADIO_CORE) && vita_pre_tready) ||
((state == FORWARD_XO) && xo_pre_tready) ||
((state == FORWARD_ZPU) && zpu_pre_tready) ||
((state == FORWARD_ZPU_AND_XO) && zpu_pre_tready && xo_pre_tready);
assign out_tvalid = ((state == FORWARD_RADIO_CORE) ||
(state == FORWARD_XO) ||
(state == FORWARD_ZPU) ||
(state == FORWARD_ZPU_AND_XO) ||
(state == DROP_PACKET)) && (!fwd_input || in_tvalid);
assign {out_tlast,out_tuser,out_tdata} = fwd_input ? {in_tlast,in_tuser,in_tdata} : header_ram[header_ram_addr];
assign in_tready = (state == WAIT_PACKET) ||
(state == READ_HEADER) ||
(out_tready && fwd_input);
//
// Because we can forward to both the ZPU and XO FIFO's concurrently
// we have to make sure both can accept data in the same cycle.
// This makes it possible for either destination to block the other.
// Make sure (both) destination(s) can accept data before passing it.
//
assign xo_pre_tvalid = out_tvalid &&
((state == FORWARD_XO) ||
((state == FORWARD_ZPU_AND_XO) && zpu_pre_tready));
assign zpu_pre_tvalid = out_tvalid &&
((state == FORWARD_ZPU) ||
((state == FORWARD_ZPU_AND_XO) && xo_pre_tready));
assign vita_pre_tvalid = out_tvalid &&
(state == FORWARD_RADIO_CORE);
assign {zpu_pre_tlast, zpu_pre_tuser, zpu_pre_tdata} = {out_tlast, out_tuser, out_tdata};
assign {xo_pre_tlast, xo_pre_tuser, xo_pre_tdata} = {out_tlast, out_tuser, out_tdata};
assign {vita_pre_tlast, vita_pre_tuser, vita_pre_tdata} = {out_tlast, out_tuser, out_tdata};
//---------------------------------------------------------
// Egress FIFO's
//---------------------------------------------------------
// These FIFO's have to be fairly large to prevent any egress
// port from backpressuring the input state machine.
// The ZPU and XO ports are inherently slow consumers so they
// get a large buffer. The VITA port is fast but high throughput
// so even that needs a large FIFO.
axi_fifo #(.WIDTH(69),.SIZE(10))
axi_fifo_zpu (
.clk(clk),
.reset(reset),
.clear(clear),
.i_tdata({zpu_pre_tlast,zpu_pre_tuser,zpu_pre_tdata}),
.i_tvalid(zpu_pre_tvalid),
.i_tready(zpu_pre_tready),
.o_tdata({zpu_tlast,zpu_tuser,zpu_tdata}),
.o_tvalid(zpu_tvalid),
.o_tready(zpu_tready),
.space(),
.occupied()
);
axi_fifo #(.WIDTH(69),.SIZE(10))
axi_fifo_xo (
.clk(clk),
.reset(reset),
.clear(clear),
.i_tdata({xo_pre_tlast,xo_pre_tuser,xo_pre_tdata}),
.i_tvalid(xo_pre_tvalid),
.i_tready(xo_pre_tready),
.o_tdata({xo_tlast,xo_tuser,xo_tdata}),
.o_tvalid(xo_tvalid),
.o_tready(xo_tready),
.space(),
.occupied()
);
axi_fifo #(.WIDTH(69),.SIZE(10))
axi_fifo_vita (
.clk(clk),
.reset(reset),
.clear(clear),
.i_tdata({vita_pre_tlast,vita_pre_tuser,vita_pre_tdata}),
.i_tvalid(vita_pre_tvalid),
.i_tready(vita_pre_tready),
.o_tdata({vita_tlast,vita_tuser,vita_tdata}),
.o_tvalid(vita_tvalid),
.o_tready(vita_tready),
.space(),
.occupied()
);
endmodule // eth_dispatch
-311
View File
@@ -1,311 +0,0 @@
//
// Copyright 2012 Ettus Research LLC
//
`timescale 1 ps / 1 ps
module eth_dispatch_tb();
// Clocking and reset interface
reg clk;
reg reset;
reg clear;
// Setting register interface
reg set_stb;
reg [15:0] set_addr;
reg [31:0] set_data;
// Input 68bit AXI-Stream interface (from MAC)
wire [63:0] in_tdata;
wire [3:0] in_tuser;
wire in_tlast;
wire in_tvalid;
wire in_tready;
// Output AXI-Stream interface to VITA Radio Core
wire [63:0] vita_tdata;
wire [3:0] vita_tuser;
wire vita_tlast;
wire vita_tvalid;
wire vita_tready;
// Output AXI-Stream interface to ZPU
wire [63:0] zpu_tdata;
wire [3:0] zpu_tuser;
wire zpu_tlast;
wire zpu_tvalid;
wire zpu_tready;
// Output AXI-Stream interface to cross-over MAC
wire [63:0] xo_tdata;
wire [3:0] xo_tuser;
wire xo_tlast;
wire xo_tvalid;
wire xo_tready;
reg [63:0] data_in;
reg [3:0] user_in;
reg valid_in;
wire ready_in;
reg last_in;
eth_dispatch
#(.BASE(0))
eth_dispatch_i
(
// Clocking and reset interface
.clk(clk),
.reset(reset),
.clear(clear),
// Setting register interface
.set_stb(set_stb),
.set_addr(set_addr),
.set_data(set_data),
// Input 68bit AXI-Stream interface (from MAC)
.in_tdata(in_tdata),
.in_tuser(in_tuser),
.in_tlast(in_tlast),
.in_tvalid(in_tvalid),
.in_tready(in_tready),
// Output AXI-STream interface to VITA Radio Core
.vita_tdata(vita_tdata),
.vita_tuser(vita_tuser),
.vita_tlast(vita_tlast),
.vita_tvalid(vita_tvalid),
.vita_tready(vita_tready),
// Output AXI-Stream interface to ZPU
.zpu_tdata(zpu_tdata),
.zpu_tuser(zpu_tuser),
.zpu_tlast(zpu_tlast),
.zpu_tvalid(zpu_tvalid),
.zpu_tready(zpu_tready),
// Output AXI-Stream interface to cross-over MAC
.xo_tdata(xo_tdata),
.xo_tuser(xo_tuser),
.xo_tlast(xo_tlast),
.xo_tvalid(xo_tvalid),
.xo_tready(xo_tready)
);
//
// Define Clocks
//
initial begin
clk = 1'b1;
end
// 125MHz clock
always #4000 clk = ~clk;
//
// Good starting state
//
initial begin
reset <= 0;
clear <= 0;
set_stb <= 0;
set_addr <= 0;
set_data <= 0;
data_in <= 0;
user_in <= 0;
valid_in <= 0;
last_in <= 0;
end
//
// Task Libaray
//
task write_setting_bus;
input [15:0] address;
input [31:0] data;
begin
@(negedge clk);
set_stb = 1'b0;
set_addr = 16'h0;
set_data = 32'h0;
@(negedge clk);
set_stb = 1'b1;
set_addr = address;
set_data = data;
@(negedge clk);
set_stb = 1'b0;
set_addr = 16'h0;
set_data = 32'h0;
end
endtask // write_setting_bus
task enqueue_line;
input last;
input [2:0] keep;
input [63:0] data;
begin
data_in <= {keep, data};
last_in <= last;
valid_in <= 1;
while (~ready_in) begin
@(negedge clk);
end
@(negedge clk);
data_in <= 0;
last_in <= 0;
valid_in <= 0;
end
endtask // enqueue_line
task enqueue_arp_req;
input [47:0] src_mac;
input [31:0] src_ip;
input [47:0] dst_mac;
input [31:0] dst_ip;
begin
@(negedge clk);
// Line 0
enqueue_line( 0, 3'b0, {48'h0,16'hffff});
// Line 1 - Eth
enqueue_line( 0, 3'b0, {32'hffffffff,src_mac[47:16]});
// Line 2 - Eth+ARP (HTYPE = 1, PTYPE = 0x0800)
enqueue_line( 0, 3'b0, {src_mac[15:0],16'h0806,16'h0001,16'h0800});
// Line 3 - HLEN=6, PLEN=4 OPER=1
enqueue_line( 0, 3'b0, {8'h06,8'h04,16'h0001,src_mac[47:16]});
// Line 4 - ARP
enqueue_line( 0, 3'b0, {src_mac[15:0],src_ip[31:0],dst_mac[47:32]});
// Line 5 - ARP
enqueue_line( 1, 3'b0, {dst_mac[31:0],dst_ip[31:0]});
end
endtask // enqueue_arp_req
reg [11:0] frame_count =12'h0;
task enqueue_vita_pkt;
// We assume that we always have SID and TSF fields.
input [47:0] mac;
input [31:0] ip;
input [15:0] udp;
input [15:0] vita_size;
input [63:0] vita_tsf;
input [31:0] vita_sid;
integer i;
reg [15:0] j;
reg [19:0] vrl_size;
reg [15:0] udp_size;
reg [15:0] ip_size;
begin
vrl_size = vita_size + 3;
udp_size = vrl_size*4 + 8;
ip_size = udp_size + 20;
@(negedge clk);
// Line 0
enqueue_line( 0, 3'b0, {48'h0,mac[47:32]});
// Line 1 - Eth
enqueue_line( 0, 3'b0, {mac[31:0],32'h11223344});
// Line 2 - Eth+IP
enqueue_line( 0, 3'b0, {16'h5566,16'h0800,16'h0000,ip_size});
// Line 3 - IP
enqueue_line( 0, 3'b0, 'h11<<16);
// Line 4 - IP
enqueue_line( 0, 3'b0, {32'h09080706, ip});
// Line 5 - UDP
enqueue_line( 0, 3'b0, {16'h1234, udp, udp_size, 16'h0});
// Line 6 - VRL
enqueue_line( 0, 3'b0, {"VRLP",frame_count,vrl_size});
// Line 7 - VRT
enqueue_line( 0, 3'b0, {16'b0001000000010000, vita_size,vita_sid}); //vita hdr + SID
enqueue_line( 0, 3'b0, vita_tsf);
j = 0;
for (i = 6; i < vita_size; i = i + 2) begin
enqueue_line( 0 , 3'b0, {j,j+16'h1,j+16'h2,j+16'h3});
j = j + 4;
end
if (i-vita_size==0) // 2x32words to finish VITA packet.
enqueue_line( 1, 3'b0, {j,j+16'h1,j+16'h2,j+16'h3});
else // 1x32bit word to finish VITA packet
enqueue_line( 1, 3'h4, {j,j+16'h1,j+16'h2,j+16'h3});
end
endtask // enqueue_packet
//
// Simulation specific testbench is included here
//
`include "simulation_script.v"
//
// Input FIFO
//
axi_fifo_short
#(.WIDTH(69)) axi_fifo_short_in
(
.clk(clk),
.reset(reset),
.clear(clear),
.o_tdata({in_tlast,in_tuser,in_tdata}),
.o_tvalid(in_tvalid),
.o_tready(in_tready),
.i_tdata({last_in,user_in,data_in}),
.i_tvalid(valid_in),
.i_tready(ready_in),
.space(),
.occupied()
);
//
// Output Sinks
//
axi_probe_tb
#(.FILENAME("zpu.txt"),.VITA_PORT0(60000),.VITA_PORT1(60001)) axi_probe_tb_zpu
(
.clk(clk),
.reset(reset),
.clear(clear),
.tdata(zpu_tdata),
.tvalid(zpu_tvalid),
.tready(zpu_tready),
.tlast(zpu_tlast)
);
assign zpu_tready = 1'b1;
axi_probe_tb
#(.FILENAME("xo.txt"),.VITA_PORT0(60000),.VITA_PORT1(60001)) axi_probe_tb_xo
(
.clk(clk),
.reset(reset),
.clear(clear),
.tdata(xo_tdata),
.tvalid(xo_tvalid),
.tready(xo_tready),
.tlast(xo_tlast)
);
assign xo_tready = 1'b1;
axi_probe_tb
#(.FILENAME("vita.txt"),.VITA_PORT0(60000),.VITA_PORT1(60001),.START_AT_VRL(1)) axi_probe_tb_vita
(
.clk(clk),
.reset(reset),
.clear(clear),
.tdata(vita_tdata),
.tvalid(vita_tvalid),
.tready(vita_tready),
.tlast(vita_tlast)
);
assign vita_tready = 1'b1;
endmodule // eth_dispatch_tb
-140
View File
@@ -1,140 +0,0 @@
// Adapts from internal VITA to ethernet packets. Also handles ZPU and ethernet crossover interfaces.
module eth_interface
#(parameter BASE=0,
parameter XO_FIFOSIZE=10,
parameter ZPU_FIFOSIZE=10,
parameter VITA_FIFOSIZE=10,
parameter ETHOUT_FIFOSIZE=10)
(input clk, input reset, input clear,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
// Eth ports
output [63:0] eth_tx_tdata, output [3:0] eth_tx_tuser, output eth_tx_tlast, output eth_tx_tvalid, input eth_tx_tready,
input [63:0] eth_rx_tdata, input [3:0] eth_rx_tuser, input eth_rx_tlast, input eth_rx_tvalid, output eth_rx_tready,
// Vita router interface
output [63:0] e2v_tdata, output e2v_tlast, output e2v_tvalid, input e2v_tready,
input [63:0] v2e_tdata, input v2e_tlast, input v2e_tvalid, output v2e_tready,
// Ethernet crossover
output [63:0] xo_tdata, output [3:0] xo_tuser, output xo_tlast, output xo_tvalid, input xo_tready,
input [63:0] xi_tdata, input [3:0] xi_tuser, input xi_tlast, input xi_tvalid, output xi_tready,
// ZPU
output [63:0] e2z_tdata, output [3:0] e2z_tuser, output e2z_tlast, output e2z_tvalid, input e2z_tready,
input [63:0] z2e_tdata, input [3:0] z2e_tuser, input z2e_tlast, input z2e_tvalid, output z2e_tready,
// Debug
output [31:0] debug_flags,
output [31:0] debug
);
wire [63:0] v2ef_tdata;
wire [3:0] v2ef_tuser;
wire v2ef_tlast, v2ef_tvalid, v2ef_tready;
// //////////////////////////////////////////////////////////////
// Incoming Ethernet path
// Includes FIFO on the output going to ZPU
wire [63:0] epg_tdata_int;
wire [3:0] epg_tuser_int;
wire epg_tlast_int, epg_tvalid_int, epg_tready_int;
//
// Packet gate ensures on entire ingressing packet is buffered before feeding it downstream so that it bursts
// efficiently internally without holding resources allocted for longer than optimal. This also means that an upstream
// error discovered in the packet can allow the packet to be destroyed here, before it gets deeper into the USRP.
//
// This gate must be able to hold at least 9900 bytes which is the maximum length between the SOF and EOF
// as asserted by the 1G and 10G MACs. This is required in case one of the max size packets has an error
// and needs to be dropped. With SIZE=11, this gate will hold 2 8k packets.
axi_packet_gate #(.WIDTH(68), .SIZE(11)) packet_gater
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({eth_rx_tuser, eth_rx_tdata}), .i_tlast(eth_rx_tlast),
.i_terror(eth_rx_tuser[3]), //top bit of user bus is error
.i_tvalid(eth_rx_tvalid), .i_tready(eth_rx_tready),
.o_tdata({epg_tuser_int, epg_tdata_int}), .o_tlast(epg_tlast_int),
.o_tvalid(epg_tvalid_int), .o_tready(epg_tready_int));
//
// Based on programmed rules, parse network headers and decide which internal destination(s) this packet will be forwarded to.
//
wire [63:0] e2v_tdata_int;
wire e2v_tlast_int, e2v_tvalid_int, e2v_tready_int;
wire [63:0] e2z_tdata_int;
wire [3:0] e2z_tuser_int;
wire e2z_tlast_int, e2z_tvalid_int, e2z_tready_int;
wire [2:0] dispatch_debug_flags;
eth_dispatch #(.BASE(BASE+8)) eth_dispatch
(.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb), .set_addr(set_addr) , .set_data(set_data),
.in_tdata(epg_tdata_int), .in_tuser(epg_tuser_int), .in_tlast(epg_tlast_int), .in_tvalid(epg_tvalid_int), .in_tready(epg_tready_int),
.vita_tdata(e2v_tdata_int), .vita_tlast(e2v_tlast_int), .vita_tvalid(e2v_tvalid_int), .vita_tready(e2v_tready_int),
.zpu_tdata(e2z_tdata_int), .zpu_tuser(e2z_tuser_int), .zpu_tlast(e2z_tlast_int), .zpu_tvalid(e2z_tvalid_int), .zpu_tready(e2z_tready_int),
.xo_tdata(xo_tdata), .xo_tuser(xo_tuser), .xo_tlast(xo_tlast), .xo_tvalid(xo_tvalid), .xo_tready(xo_tready), // to other eth port
.debug_flags(dispatch_debug_flags),.debug(debug));
axi_fifo_short #(.WIDTH(65)) e2v_pipeline_srl
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({e2v_tlast_int,e2v_tdata_int}), .i_tvalid(e2v_tvalid_int), .i_tready(e2v_tready_int),
.o_tdata({e2v_tlast,e2v_tdata}), .o_tvalid(e2v_tvalid), .o_tready(e2v_tready),
.space(), .occupied()
);
//
// ZPU can be slow to respond (relative to packet wirespeed) so extra buffer for packets destined there so it doesn't back up.
//
axi_fifo #(.WIDTH(69),.SIZE(ZPU_FIFOSIZE)) zpu_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({e2z_tlast_int,e2z_tuser_int,e2z_tdata_int}), .i_tvalid(e2z_tvalid_int), .i_tready(e2z_tready_int),
.o_tdata({e2z_tlast,e2z_tuser,e2z_tdata}), .o_tvalid(e2z_tvalid), .o_tready(e2z_tready));
// //////////////////////////////////////////////////////////////
// Outgoing Ethernet path
// Includes FIFOs on path from VITA router, from ethernet crossover, and on the overall output
wire [63:0] eth_tx_tdata_int;
wire [3:0] eth_tx_tuser_int;
wire eth_tx_tlast_int, eth_tx_tvalid_int, eth_tx_tready_int;
wire [63:0] xi_tdata_int;
wire [3:0] xi_tuser_int;
wire xi_tlast_int, xi_tvalid_int, xi_tready_int;
wire [63:0] v2e_tdata_int;
wire v2e_tlast_int, v2e_tvalid_int, v2e_tready_int;
axi_fifo #(.WIDTH(65),.SIZE(VITA_FIFOSIZE)) vitaout_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({v2e_tlast,v2e_tdata}), .i_tvalid(v2e_tvalid), .i_tready(v2e_tready),
.o_tdata({v2e_tlast_int,v2e_tdata_int}), .o_tvalid(v2e_tvalid_int), .o_tready(v2e_tready_int));
chdr_eth_framer #(.BASE(BASE)) my_eth_framer
(.clk(clk), .reset(reset), .clear(clear),
.set_stb(set_stb), .set_addr(set_addr) , .set_data(set_data),
.in_tdata(v2e_tdata_int), .in_tlast(v2e_tlast_int), .in_tvalid(v2e_tvalid_int), .in_tready(v2e_tready_int),
.out_tdata(v2ef_tdata), .out_tuser(v2ef_tuser), .out_tlast(v2ef_tlast), .out_tvalid(v2ef_tvalid), .out_tready(v2ef_tready),
.debug());
axi_fifo #(.WIDTH(69),.SIZE(XO_FIFOSIZE)) xo_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({xi_tlast,xi_tuser,xi_tdata}), .i_tvalid(xi_tvalid), .i_tready(xi_tready),
.o_tdata({xi_tlast_int,xi_tuser_int,xi_tdata_int}), .o_tvalid(xi_tvalid_int), .o_tready(xi_tready_int));
axi_mux4 #(.PRIO(0), .WIDTH(68)) eth_mux
(.clk(clk), .reset(reset), .clear(clear),
.i0_tdata({z2e_tuser,z2e_tdata}), .i0_tlast(z2e_tlast), .i0_tvalid(z2e_tvalid), .i0_tready(z2e_tready),
.i1_tdata({v2ef_tuser,v2ef_tdata}), .i1_tlast(v2ef_tlast), .i1_tvalid(v2ef_tvalid), .i1_tready(v2ef_tready),
.i2_tdata({xi_tuser_int,xi_tdata_int}), .i2_tlast(xi_tlast_int), .i2_tvalid(xi_tvalid_int), .i2_tready(xi_tready_int),
.i3_tdata(), .i3_tlast(), .i3_tvalid(1'b0), .i3_tready(),
.o_tdata({eth_tx_tuser_int,eth_tx_tdata_int}), .o_tlast(eth_tx_tlast_int), .o_tvalid(eth_tx_tvalid_int), .o_tready(eth_tx_tready_int));
axi_fifo #(.WIDTH(69),.SIZE(ETHOUT_FIFOSIZE)) ethout_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({eth_tx_tlast_int,eth_tx_tuser_int,eth_tx_tdata_int}), .i_tvalid(eth_tx_tvalid_int), .i_tready(eth_tx_tready_int),
.o_tdata({eth_tx_tlast,eth_tx_tuser,eth_tx_tdata}), .o_tvalid(eth_tx_tvalid), .o_tready(eth_tx_tready));
endmodule // eth_interface
-24
View File
@@ -1,24 +0,0 @@
// Compute IP header checksum. 2 cycles of latency.
module ip_hdr_checksum
(input clk, input [159:0] in, output reg [15:0] out);
wire [18:0] padded [0:9];
reg [18:0] sum_a, sum_b;
genvar i;
generate
for(i=0 ; i<10 ; i=i+1)
assign padded[i] = {3'b000,in[i*16+15:i*16]};
endgenerate
always @(posedge clk) sum_a = padded[0] + padded[1] + padded[2] + padded[3] + padded[4];
always @(posedge clk) sum_b = padded[5] + padded[6] + padded[7] + padded[8] + padded[9];
wire [18:0] sum = sum_a + sum_b;
always @(posedge clk)
out <= ~(sum[15:0] + {13'd0,sum[18:16]});
endmodule // ip_hdr_checksum
-38
View File
@@ -1,38 +0,0 @@
module ip_hdr_checksum_tb();
initial $dumpfile("ip_hdr_checksum_tb.vcd");
initial $dumpvars(0,ip_hdr_checksum_tb);
reg clk;
wire [159:0] in = {
16'h4500,
16'h0030,
16'h4422,
16'h4000,
16'h8006,
16'h0000,
16'h8c7c,
16'h19ac,
16'hae24,
16'h1e2b
};
wire [15:0] out;
ip_hdr_checksum ip_hdr_checksum
(.clk(clk),
.in(in),
.out(out));
initial
begin
clk <= 0;
#100 clk <= 1;
#100 clk <= 0;
#100 clk <= 1;
#100 $display("Computed 0x%x, should be 0x442e", out);
#100 $finish;
end
endmodule // ip_hdr_checksum_tb
-127
View File
@@ -1,127 +0,0 @@
// source_flow_control.v
//
// This block passes the in_* AXI port to the out_* AXI port only when it has
// enough flow control credits. Data is held when there are not enough credits.
// Credits are replenished with extension context packets which update the
// last_consumed packet register. Max credits are controlled by settings regs.
// The 2nd line of the packet contains the sequence number in the low 12 bits.
// These packets should not have a time value, but if they do it will be ignored.
module source_flow_control
#(parameter BASE=0)
(input clk, input reset, input clear,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input [63:0] fc_tdata, input fc_tlast, input fc_tvalid, output fc_tready,
input [63:0] in_tdata, input in_tlast, input in_tvalid, output in_tready,
output [63:0] out_tdata, output out_tlast, output out_tvalid, input out_tready);
reg [31:0] last_seqnum_consumed;
wire [31:0] window_size;
wire [31:0] go_until_seqnum = last_seqnum_consumed + window_size + 1;
reg [31:0] current_seqnum;
wire window_reset;
wire window_enable;
wire setting_changed;
setting_reg #(.my_addr(BASE)) sr_window_size
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(window_size),.changed(setting_changed));
setting_reg #(.my_addr(BASE+1), .width(1)) sr_window_enable
(.clk(clk),.rst(reset),.strobe(set_stb),.addr(set_addr),.in(set_data),
.out(window_enable),.changed(window_reset));
reg go;
reg [1:0] sfc_state;
localparam SFC_HEAD = 2'd0;
localparam SFC_TIME = 2'd1;
localparam SFC_BODY = 2'd2;
localparam SFC_DUMP = 2'd3;
always @(posedge clk)
if(reset | clear | window_reset)
begin
last_seqnum_consumed <= 32'hFFFFFFFF;
sfc_state <= SFC_HEAD;
end
else
if(fc_tvalid & fc_tready)
case(sfc_state)
SFC_HEAD :
if(fc_tlast)
sfc_state <= SFC_HEAD; // Error. CHDR packet with only a header is an error.
else if(~fc_tdata[63]) // Is this NOT an extension context packet?
sfc_state <= SFC_DUMP; // Error. Only extension context packets should come in on this interface.
else if(fc_tdata[61]) // Does this packet have time?
sfc_state <= SFC_TIME;
else
sfc_state <= SFC_BODY;
SFC_TIME :
if(fc_tlast)
sfc_state <= SFC_HEAD; // Error, CHDR packet with only header and time is an error.
else
sfc_state <= SFC_BODY;
SFC_BODY :
begin
last_seqnum_consumed <= fc_tdata[31:0]; // Sequence number is in lower 32bits.
if(fc_tlast)
sfc_state <= SFC_HEAD;
else
sfc_state <= SFC_DUMP; // Error. Not expecting any more data in a CHDR packet.
end
SFC_DUMP : // shouldn't ever need to be here, this is an error condition
if(fc_tlast)
sfc_state <= SFC_HEAD;
endcase // case (sfc_state)
assign fc_tready = 1'b1; // Always consume FC -- FIXME Even if we are getting reset?
assign out_tdata = in_tdata; // CHDR data flows through combinatorially.
assign out_tlast = in_tlast;
assign in_tready = go ? out_tready : 1'b0;
assign out_tvalid = go ? in_tvalid : 1'b0;
//
// Each time we recieve the end of an IF data packet increment the current_seqnum.
// We bravely assume that no packets go missing...or at least that they will be detected elsewhere
// and then handled appropriately.
// The SEQNUM needs to be initialized every time we start a new stream. In new_rx_framer this is done
// as a side effect of writing a new SID value to the setting reg.
//
// By incrementing current_seqnum on the last signal we get the nice effect that packet flow is
// always suspended between packets rather than within a packet.
//
always @(posedge clk)
if(reset | clear | window_reset)
current_seqnum <= 0;
else if (in_tvalid && in_tready && in_tlast)
current_seqnum <= current_seqnum + 1;
always @(posedge clk)
if(reset | clear)
go <= 1'b0;
else
if(~window_enable)
go <= 1'b1;
else
case(go)
1'b0 :
// This test assumes the host is well behaved in sending good numbers for packets consumed
// and that current_seqnum increments always by 1 only.
// This way wraps are dealt with without a large logic penalty.
if (in_tvalid & (go_until_seqnum - current_seqnum != 0))
// if(in_tvalid & (go_until_seqnum > current_seqnum)) // FIXME will need to handle wrap of 32-bit seqnum
go <= 1'b1;
1'b1 :
if(in_tvalid & in_tready & in_tlast)
go <= 1'b0;
endcase // case (go)
endmodule // source_flow_control
-249
View File
@@ -1,249 +0,0 @@
`timescale 1ns/1ps
module source_flow_control_tb();
reg clk = 0;
reg reset = 1;
always #10 clk = ~clk;
initial $dumpfile("source_flow_control_tb.vcd");
initial $dumpvars(0,source_flow_control_tb);
initial
begin
#1000 reset = 0;
#20000;
$finish;
end
reg [63:0] tdata;
wire [63:0] tdata_int;
reg tlast;
wire tlast_int;
reg tvalid = 1'b0;
wire tvalid_int;
wire tready, tready_int;
reg [63:0] fc_tdata;
reg fc_tlast, fc_tvalid;
wire fc_tready;
wire [63:0] out_tdata;
wire out_tlast, out_tready, out_tvalid;
wire [15:0] occ_in, occ_out;
reg set_stb = 0;
reg [7:0] set_addr;
reg [31:0] set_data;
task send_fc_packet;
input [31:0] seqnum;
input [31:0] sid;
input always_go;
begin
@(posedge clk);
fc_tlast <= 1'b0;
fc_tdata <= { 1'b1, 1'b0, 1'b0, 1'b0, 12'hABC, 16'd4, sid };
fc_tvalid <= 1;
@(posedge clk);
fc_tlast <= 1'b1;
//fc_tdata <= { 52'h0,seqnum };
fc_tdata <= { 31'h0,always_go, seqnum };
@(posedge clk);
fc_tvalid <= 0;
@(posedge clk);
end
endtask // send_packet
task send_packet;
input ec;
input timed;
input [11:0] seqnum;
input [31:0] sid;
input [63:0] vtime;
input [15:0] addr;
input [31:0] data;
begin
// Send a packet
@(posedge clk);
tlast <= 1'b0;
tdata <= { ec, 1'b0, timed, 1'b0, seqnum, timed ? 16'd6 : 16'd4, sid };
tvalid <= 1;
@(posedge clk);
if(timed)
begin
tdata <= vtime;
@(posedge clk);
end
tlast <= 1'b1;
tdata <= { 16'h0, addr, data };
@(posedge clk);
tlast <= 1'b0;
tvalid <= 0;
@(posedge clk);
end
endtask // send_packet
initial
begin
tvalid <= 1'b0;
while(reset)
@(posedge clk);
@(posedge clk);
// Set flow control window to be 2
set_stb <= 1;
set_addr <= 0;
set_data <= 2;
@(posedge clk);
set_stb <= 0;
// ExtContext. Time. Seq=0, SID=DEAD_6789, Time=10
send_packet(1'b1,1'b1,12'h0,32'hDEAD_6789,64'h10,16'hB,32'hF00D_1234);
send_packet(1'b1,1'b1,12'h1,32'hDEAD_6789,64'h20,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h2,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h3,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h4,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h5,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h6,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h7,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h8,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
#500;
// Consumed 2 packets
send_fc_packet(32'd1,32'h3,1'b0);
#300;
// Consumed 1 packet
send_fc_packet(32'd2,32'h3,1'b0);
#500;
// Consumed 2 packets
send_fc_packet(32'd4,32'h3,1'b0);
#400;
// Send same SEQ ID again to test it causes no changes.
send_fc_packet(32'd4,32'h3,1'b0);
#300;
// Consumed 1 packet
send_fc_packet(32'd5,32'h3,1'b0);
#500;
// Consumed 2 packets
send_fc_packet(32'd7,32'h3,1'b0);
#500;
send_packet(1'b1,1'b1,12'h9,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'hA,32'hDEAD_6789,64'h30,16'hC,32'hABCD_4321);
#300;
// Consumed 1 packet
send_fc_packet(32'd8,32'h3,1'b0);
//
// Now force internal sequence count to close to wrap value to test corner case
//
#100;
source_flow_control.current_seqnum <= 32'hFFFF_FFFC;
#100;
send_fc_packet(32'hFFFF_FFFA,32'h3,1'b0);
#100;
send_packet(1'b1,1'b1,12'hFFC,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
#200;
send_packet(1'b1,1'b1,12'hFFD,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'hFFE,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'hFFF,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h000,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h001,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h002,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
#200;
// Consumed 2 packets
send_fc_packet(32'hFFFF_FFFC,32'h3,1'b0);
#200;
// Consumed 2 packets
send_fc_packet(32'hFFFF_FFFE,32'h3,1'b0);
send_packet(1'b1,1'b1,12'h003,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h004,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
#200;
// Consumed 2 packets
send_fc_packet(32'h0,32'h3,1'b0);
#200;
// Consumed 2 packets
send_fc_packet(32'h2,32'h3,1'b0);
#500;
//
// Again force internal sequence count to close to wrap value to test new corner case
//
#100;
source_flow_control.current_seqnum <= 32'hFFFF_FFFC;
#100;
send_fc_packet(32'hFFFF_FFFA,32'h3,1'b0);
#100;
send_packet(1'b1,1'b1,12'hFFC,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
#200;
send_packet(1'b1,1'b1,12'hFFD,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'hFFE,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'hFFF,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h000,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h001,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h002,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
#200;
// Consumed 1 packets
send_fc_packet(32'hFFFF_FFFB,32'h3,1'b0);
#200;
// Consumed 1 packets
send_fc_packet(32'hFFFF_FFFC,32'h3,1'b0);
send_packet(1'b1,1'b1,12'h003,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
send_packet(1'b1,1'b1,12'h004,32'hDEAD_6789,64'h40,16'hC,32'hABCD_4321);
#200;
// Consumed 1 packets
send_fc_packet(32'hFFFF_FFFD,32'h3,1'b0);
#200;
// Consumed 1 packets
send_fc_packet(32'hFFFF_FFFE,32'h3,1'b0);
#200;
// Consumed 1 packets
send_fc_packet(32'hFFFF_FFFF,32'h3,1'b0);
#200;
// Consumed 1 packets
send_fc_packet(32'h0,32'h3,1'b0);
#200;
// Consumed 1 packets
send_fc_packet(32'h1,32'h3,1'b0);
#200;
// Consumed 1 packets
send_fc_packet(32'h2,32'h3,1'b0);
#500;
end
axi_fifo #(.WIDTH(65), .SIZE(10)) fifo_in
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({tlast,tdata}), .i_tvalid(tvalid), .i_tready(tready),
.o_tdata({tlast_int,tdata_int}), .o_tvalid(tvalid_int), .o_tready(tready_int),
.occupied(occ_in));
source_flow_control source_flow_control
(.clk(clk), .reset(reset), .clear(1'b0),
.set_stb(set_stb), .set_addr(set_addr), .set_data(set_data),
.fc_tdata(fc_tdata), .fc_tlast(fc_tlast), .fc_tvalid(fc_tvalid), .fc_tready(fc_tready),
.in_tdata(tdata_int), .in_tlast(tlast_int), .in_tvalid(tvalid_int), .in_tready(tready_int),
.out_tdata(out_tdata), .out_tlast(out_tlast), .out_tvalid(out_tvalid), .out_tready(out_tready)
);
wire [63:0] dump_tdata;
wire dump_tlast, dump_tvalid, dump_tready;
axi_fifo #(.WIDTH(65), .SIZE(10)) fifo_out
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({out_tlast,out_tdata}), .i_tvalid(out_tvalid), .i_tready(out_tready),
.o_tdata({dump_tlast,dump_tdata}), .o_tvalid(dump_tvalid), .o_tready(dump_tready),
.occupied(occ_out));
assign dump_tready = 0;
always @(posedge clk)
if(out_tvalid & out_tready)
begin
$display("%x",out_tdata);
if(out_tlast)
$display("TLAST");
end
endmodule // source_flow_control_tb
-137
View File
@@ -1,137 +0,0 @@
// vita_eth_framer
// Takes a vita stream in and adds udp, ip, and ethernet framing
// Uses 8 setting reg addresses. First 4 are simple registers:
// BASE+0 : Upper 16 bits of ethernet src mac
// BASE+1 : Lower 32 bits of ethernet src mac
// BASE+2 : IP src address
// BASE+3 : UDP src port
//
// Next 4 control write ports on a RAM indexed by destination field of stream ID
// BASE+4 : Dest SID for next 3 regs
// BASE+5 : Dest IP
// BASE+6 : Dest UDP port, upper 16 bits of dest mac
// BASE+7 : Lower 32 bits of dest mac
module vita_eth_framer
#(parameter BASE=0)
(input clk, input reset, input clear,
input set_stb, input [7: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,
output [31:0] debug );
localparam SR_AWIDTH = 8;
reg [31:0] sid;
reg [15:0] vita_len;
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 <= 32'd0;
vita_len <= 16'd0;
end
else
case(vef_state)
VEF_IDLE :
if(in_tvalid)
begin
vef_state <= 1;
sid <= in_tdata[31:0];
vita_len <= in_tdata[47:32];
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,vita_len[0],2'b00} : 4'b0000;
assign out_tdata = tdata;
wire [15:0] vita_len_in_bytes = {vita_len[13:0],2'b00}; // Vita length is in 32-bit words
wire [47:0] pad = 48'h0;
wire [47:0] mac_src, mac_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 + vita_len_in_bytes); // 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_checksum;
wire [31:0] ip_src, ip_dst;
wire [15:0] udp_src, udp_dst;
wire [15:0] udp_len = (16'd8 + vita_len_in_bytes);
wire [15:0] udp_checksum = 16'h0;
setting_reg #(.my_addr(BASE), .awidth(SR_AWIDTH), .width(16)) set_mac_upper
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(mac_src[47:32]), .changed());
setting_reg #(.my_addr(BASE+1), .awidth(SR_AWIDTH), .width(32)) set_mac_lower
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(mac_src[31:0]), .changed());
setting_reg #(.my_addr(BASE+2), .awidth(SR_AWIDTH), .width(32)) set_ip
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(ip_src), .changed());
setting_reg #(.my_addr(BASE+3), .awidth(SR_AWIDTH), .width(16)) set_udp
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(udp_src), .changed());
// Tables of MAC/IP/UDP addresses
wire [8:0] ram_addr; // FIXME we could skip this part if we had wider SR addresses
setting_reg #(.my_addr(BASE+4), .awidth(SR_AWIDTH), .width(9)) set_ram_addr
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(ram_addr), .changed());
ram_2port #(.DWIDTH(32), .AWIDTH(9)) ram_ip
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+5)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[8:0]), .dib(32'hFFFF_FFFF), .dob(ip_dst));
ram_2port #(.DWIDTH(32), .AWIDTH(9)) ram_udpmac
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+6)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[8:0]), .dib(32'hFFFF_FFFF), .dob({udp_dst,mac_dst[47:32]}));
ram_2port #(.DWIDTH(32), .AWIDTH(9)) ram_maclower
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+7)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[8:0]), .dib(32'hFFFF_FFFF), .dob(mac_dst[31:0]));
ip_hdr_checksum ip_hdr_checksum
(.clk(clk), .in({misc_ip,ip_len,ident,flag_frag,ttl_prot,16'd0,ip_src,ip_dst}),
.out(iphdr_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 // vita_eth_framer
-139
View File
@@ -1,139 +0,0 @@
// vrlp_eth_framer
// Takes a vrlp stream in and adds udp, ip, and ethernet framing
// Uses 8 setting reg addresses. First 4 are simple registers:
// BASE+0 : Upper 16 bits of ethernet src mac
// BASE+1 : Lower 32 bits of ethernet src mac
// BASE+2 : IP src address
// BASE+3 : UDP src port
//
// Next 4 control write ports on a RAM indexed by destination field of stream ID
// BASE+4 : Dest SID for next 3 regs
// BASE+5 : Dest IP
// BASE+6 : Dest UDP port, upper 16 bits of dest mac
// BASE+7 : Lower 32 bits of dest mac
//
// in_tuser holds streamid
module vrlp_eth_framer
#(parameter BASE=0)
(input clk, input reset, input clear,
input set_stb, input [7:0] set_addr, input [31:0] set_data,
input [63:0] in_tdata, input [15:0] in_tuser, 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,
output [31:0] debug );
localparam SR_AWIDTH = 8;
reg [15:0] sid;
reg [15:0] vrlp_len;
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 <= 16'd0;
vrlp_len <= 16'd0;
end
else
case(vef_state)
VEF_IDLE :
if(in_tvalid)
begin
vef_state <= 1;
sid <= in_tuser[15:0];
vrlp_len <= in_tdata[15:0]; // modified for VRLP header
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)
wire [15:0] vrlp_len_in_bytes = {vrlp_len[13:0],2'b00}; // Vrlp length is in 32-bit words
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,vrlp_len_in_bytes[2:0]} : 4'b0000;
assign out_tdata = tdata;
wire [47:0] pad = 48'h0;
wire [47:0] mac_src, mac_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 + vrlp_len_in_bytes); // 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_checksum;
wire [31:0] ip_src, ip_dst;
wire [15:0] udp_src, udp_dst;
wire [15:0] udp_len = (16'd8 + vrlp_len_in_bytes);
wire [15:0] udp_checksum = 16'h0;
setting_reg #(.my_addr(BASE), .awidth(SR_AWIDTH), .width(16)) set_mac_upper
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(mac_src[47:32]), .changed());
setting_reg #(.my_addr(BASE+1), .awidth(SR_AWIDTH), .width(32)) set_mac_lower
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(mac_src[31:0]), .changed());
setting_reg #(.my_addr(BASE+2), .awidth(SR_AWIDTH), .width(32)) set_ip
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(ip_src), .changed());
setting_reg #(.my_addr(BASE+3), .awidth(SR_AWIDTH), .width(16)) set_udp
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(udp_src), .changed());
// Tables of MAC/IP/UDP addresses
wire [8:0] ram_addr; // FIXME we could skip this part if we had wider SR addresses
setting_reg #(.my_addr(BASE+4), .awidth(SR_AWIDTH), .width(9)) set_ram_addr
(.clk(clk), .rst(reset),
.strobe(set_stb), .addr(set_addr), .in(set_data),
.out(ram_addr), .changed());
ram_2port #(.DWIDTH(32), .AWIDTH(9)) ram_ip
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+5)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[8:0]), .dib(32'hFFFF_FFFF), .dob(ip_dst));
ram_2port #(.DWIDTH(32), .AWIDTH(9)) ram_udpmac
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+6)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[8:0]), .dib(32'hFFFF_FFFF), .dob({udp_dst,mac_dst[47:32]}));
ram_2port #(.DWIDTH(32), .AWIDTH(9)) ram_maclower
(.clka(clk), .ena(1'b1), .wea(set_stb & (set_addr == BASE+7)), .addra(ram_addr), .dia(set_data), .doa(),
.clkb(clk), .enb(1'b1), .web(1'b0), .addrb(sid[8:0]), .dib(32'hFFFF_FFFF), .dob(mac_dst[31:0]));
ip_hdr_checksum ip_hdr_checksum
(.clk(clk), .in({misc_ip,ip_len,ident,flag_frag,ttl_prot,16'd0,ip_src,ip_dst}),
.out(iphdr_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 // vrlp_eth_framer
-90
View File
@@ -1,90 +0,0 @@
module vrlp_to_compressed_vita
(input clk, input reset, input clear,
input [63:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [63:0] o_tdata, output o_tlast, output o_tvalid, input o_tready);
wire [63:0] o_tdata_int;
wire o_tlast_int, o_tvalid_int, o_tready_int;
reg [1:0] v2cv_state;
reg [11:0] seqnum;
reg trim_line;
localparam V2CV_VRLP = 2'd0;
localparam V2CV_VRTH = 2'd1;
localparam V2CV_BODY = 2'd2;
localparam V2CV_DUMP = 2'd3;
wire is_ec = i_tdata[63:60] == 4'h5;
wire has_trailer = i_tdata[58] & ~is_ec;
wire has_time = |i_tdata[53:52];
wire eob = i_tdata[56] & ~is_ec;
wire [15:0] len = i_tdata[47:32];
wire [31:0] sid = i_tdata[31:0];
wire [63:0] compressed_hdr = { is_ec, has_trailer, has_time, eob, seqnum, len, sid };
wire bad_vita = |i_tdata[55:54] /* has secs */ | i_tdata[59] /* has class */ | ( {i_tdata[63],i_tdata[61:60]} != 3'b001 );
reg [15:0] len_reg;
wire [16:0] vita_words32 = i_tdata[16:0]-17'd4;
assign trim_now = 0;
always @(posedge clk)
if(reset | clear)
begin
v2cv_state <= V2CV_VRLP;
seqnum <= 12'd0;
trim_line <= 1'b0;
len_reg <= 16'd0;
end
else
case(v2cv_state)
V2CV_VRLP :
if(i_tvalid)
begin
seqnum <= i_tdata[31:20];
trim_line <= i_tdata[0];
len_reg <= vita_words32[16:1];
if(~i_tlast)
v2cv_state <= V2CV_VRTH;
end
V2CV_VRTH :
if(i_tvalid & o_tready_int)
begin
len_reg <= len_reg - 16'd1;
if(i_tlast)
v2cv_state <= V2CV_VRLP;
else if(bad_vita)
v2cv_state <= V2CV_DUMP;
else
v2cv_state <= V2CV_BODY;
end
V2CV_BODY :
if(i_tvalid & o_tready_int)
begin
len_reg <= len_reg - 16'd1;
if(i_tlast)
v2cv_state <= V2CV_VRLP;
else if(len_reg == 16'd0)
v2cv_state <= V2CV_DUMP;
end
V2CV_DUMP :
if(i_tvalid)
if(i_tlast)
v2cv_state <= V2CV_VRLP;
endcase // case (v2cv_state)
assign o_tdata_int = (v2cv_state == V2CV_VRTH) ? compressed_hdr : i_tdata;
assign o_tlast_int = i_tlast | (len_reg == 16'd0);
assign o_tvalid_int = i_tvalid && (((v2cv_state == V2CV_VRTH) && !bad_vita) || (v2cv_state == V2CV_BODY));
assign i_tready = o_tready_int | (v2cv_state == V2CV_VRLP) | (v2cv_state == V2CV_DUMP);
axi_fifo_short #(.WIDTH(65)) short_fifo
(.clk(clk), .reset(reset), .clear(clear),
.i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready),
.space(), .occupied());
endmodule // vrlp_to_compressed_vita
@@ -1,120 +0,0 @@
`timescale 1ns/1ps
module vrlp_to_compressed_vita_tb();
reg clk = 0;
reg reset = 1;
always #10 clk = ~clk;
initial $dumpfile("vrlp_to_compressed_vita_tb.vcd");
initial $dumpvars(0,vrlp_to_compressed_vita_tb);
task send_packet;
input [63:0] data_start;
input [31:0] len;
begin
// Send a packet
@(posedge clk);
{i_tlast, i_tdata} <= { 1'b0, data_start };
i_tvalid <= 1;
@(posedge clk);
i_tdata <= 64'hAAAA_BBBB_CCCC_0000;
repeat(len-2)
begin
i_tvalid <= 1;
@(posedge clk);
i_tdata <= i_tdata + 1;
end
i_tlast <= 1;
i_tdata <= i_tdata + 1;
@(posedge clk);
i_tvalid <= 1'b0;
@(posedge clk);
end
endtask // send_packet
initial
begin
#1000 reset = 0;
#200000;
$finish;
end
wire [63:0] o_tdata;
reg [63:0] i_tdata;
wire [2:0] o_tuser;
reg [2:0] i_tuser;
reg i_tlast;
wire o_tlast;
wire o_tvalid, i_tready;
reg i_tvalid, o_tready;
reg i_terror;
localparam RPT_COUNT = 16;
initial
begin
i_tvalid <= 0;
o_tready <= 0;
while(reset)
@(posedge clk);
@(posedge clk);
//send_packet(64'hA0,3'd0, 16, 0);
send_packet(64'hAABC_0008_DEAD_BEEF, 4);
send_packet(64'h7DEF_0008_8765_4321, 4);
send_packet(64'hAABC_0007_F00D_1234, 4);
send_packet(64'h7DEF_0007_ABCD_4321, 4);
o_tready <= 1;
//send_packet(64'hC0,3'd0, 16, 1);
//send_packet(64'hD0,3'd0, 16, 0);
//send_packet(64'hE0,3'd0, 16, 0);
//send_packet(64'hF0,3'd0, 16, 0);
@(posedge clk);
end // initial begin
wire i_terror_int, i_tlast_int, i_tready_int, i_tvalid_int;
wire [2:0] i_tuser_int;
wire [63:0] i_tdata_int;
wire o_tlast_int, o_tready_int, o_tvalid_int;
wire [2:0] o_tuser_int;
wire [63:0] o_tdata_int;
wire [63:0] vrlp_tdata;
wire vrlp_tlast, vrlp_tvalid, vrlp_tready;
axi_fifo #(.WIDTH(65), .SIZE(10)) fifo
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({i_tlast,i_tdata}), .i_tvalid(i_tvalid), .i_tready(i_tready),
.o_tdata({i_tlast_int,i_tdata_int}), .o_tvalid(i_tvalid_int), .o_tready(i_tready_int));
compressed_vita_to_vrlp dut0
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata(i_tdata_int), .i_tlast(i_tlast_int), .i_tvalid(i_tvalid_int), .i_tready(i_tready_int),
.o_tdata(vrlp_tdata), .o_tlast(vrlp_tlast), .o_tvalid(vrlp_tvalid), .o_tready(vrlp_tready));
vrlp_to_compressed_vita dut1
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata(vrlp_tdata), .i_tlast(vrlp_tlast), .i_tvalid(vrlp_tvalid), .i_tready(vrlp_tready),
.o_tdata(o_tdata_int), .o_tlast(o_tlast_int), .o_tvalid(o_tvalid_int), .o_tready(o_tready_int));
axi_fifo #(.WIDTH(65), .SIZE(10)) fifo_out
(.clk(clk), .reset(reset), .clear(1'b0),
.i_tdata({o_tlast_int,o_tdata_int}), .i_tvalid(o_tvalid_int), .i_tready(o_tready_int),
.o_tdata({o_tlast,o_tdata}), .o_tvalid(o_tvalid), .o_tready(o_tready));
always @(posedge clk)
if(o_tvalid & o_tready)
begin
$display("%x",o_tdata);
if(o_tlast)
$display("======EOF========");
end
endmodule // vrlp_to_compressed_vita_tb