149 lines
3.6 KiB
Verilog
149 lines
3.6 KiB
Verilog
//
|
|
// AXI stream neds N+1 bits to transmit packets of N bits so that the LAST bit can be represented.
|
|
// LAST occurs relatively infrequently and can be synthesized by using an in-band ESC code to generate
|
|
// a multi-word sequence to encode it (and the escape character when it appears as data input).
|
|
//
|
|
// 0x1234567887654321 with last becomes
|
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0x1234567887654321
|
|
//
|
|
// 0xDEADBEEFFEEDCAFE with last becomes
|
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000001 0xDEADBEEFFEEDCAFE
|
|
//
|
|
// 0xDEADBEEFFEEDCAFE without last becomes
|
|
// 0xDEADBEEFFEEDCAFE 0x0000000000000000 0xDEADBEEFFEEDCAFE
|
|
//
|
|
|
|
module axi_extract_tlast
|
|
#(parameter WIDTH=64)
|
|
(
|
|
input clk,
|
|
input reset,
|
|
input clear,
|
|
//
|
|
input [WIDTH-1:0] i_tdata,
|
|
input i_tvalid,
|
|
output reg i_tready,
|
|
//
|
|
output [WIDTH-1:0] o_tdata,
|
|
output reg o_tlast,
|
|
output reg o_tvalid,
|
|
input o_tready,
|
|
//
|
|
output reg checksum_error_reg
|
|
|
|
);
|
|
|
|
reg [1:0] state, next_state;
|
|
|
|
localparam IDLE = 0;
|
|
localparam EXTRACT1 = 1;
|
|
localparam EXTRACT2 = 2;
|
|
localparam EXTRACT3 = 3;
|
|
|
|
assign o_tdata = i_tdata;
|
|
|
|
reg [31:0] checksum, old_checksum;
|
|
reg checksum_error;
|
|
|
|
|
|
always @(posedge clk)
|
|
if (reset | clear) begin
|
|
checksum <= 0;
|
|
old_checksum <= 0;
|
|
end else if (o_tready && i_tvalid && o_tlast) begin
|
|
checksum <= 0;
|
|
old_checksum <= 0;
|
|
end else if (i_tready && i_tvalid && (state == IDLE)) begin
|
|
checksum <= checksum + i_tdata[31:0] + i_tdata[63:32];
|
|
old_checksum <= checksum;
|
|
end
|
|
|
|
always @(posedge clk)
|
|
checksum_error_reg <= checksum_error;
|
|
|
|
always @(posedge clk)
|
|
if (reset | clear) begin
|
|
state <= IDLE;
|
|
end else begin
|
|
state <= next_state;
|
|
end
|
|
|
|
always @(*) begin
|
|
checksum_error = 0;
|
|
case(state)
|
|
//
|
|
// Search for Escape sequence "0xDEADBEEFFEEDCAFE"
|
|
// If ESC found don't pass data downstream but transition to next state.
|
|
// else pass data downstream.
|
|
//
|
|
IDLE: begin
|
|
o_tlast = 1'b0;
|
|
if ((i_tdata == 64'hDEADBEEFFEEDCAFE) && i_tvalid)
|
|
begin
|
|
next_state = EXTRACT1;
|
|
o_tvalid = 1'b0;
|
|
i_tready = 1'b1;
|
|
end
|
|
else
|
|
begin
|
|
next_state = IDLE;
|
|
o_tvalid = i_tvalid;
|
|
i_tready = o_tready;
|
|
end // else: !if((i_tdata == 'hDEADBEEFFEEDCAFE) && i_tvalid)
|
|
end // case: IDLE
|
|
//
|
|
// Look at next data. If it's a 0x1 then o_tlast should be asserted with next data word.
|
|
// if it's 0x0 then it signals emulation of the Escape code in the original data stream
|
|
// and we should just pass the next data word through unchanged with no o_tlast indication.
|
|
//
|
|
EXTRACT1: begin
|
|
o_tvalid = 1'b0;
|
|
i_tready = 1'b1;
|
|
o_tlast = 1'b0;
|
|
if (i_tvalid) begin
|
|
if (i_tdata[31:0] == 'h1)
|
|
begin
|
|
if (old_checksum != i_tdata[63:32])
|
|
checksum_error = 1'b1;
|
|
next_state = EXTRACT2;
|
|
end
|
|
else // We assume emulation and don't look for illegal codes.
|
|
begin
|
|
next_state = EXTRACT3;
|
|
end // else: !if(i_tdata == 'h1)
|
|
end else begin // if (i_tvalid)
|
|
next_state = EXTRACT1;
|
|
end // else: !if(i_tvalid)
|
|
end // case: EXTRACT1
|
|
//
|
|
// Assert o_tlast with data word.
|
|
//
|
|
EXTRACT2: begin
|
|
o_tvalid = i_tvalid;
|
|
i_tready = o_tready;
|
|
o_tlast = 1'b1;
|
|
if (i_tvalid & o_tready)
|
|
next_state = IDLE;
|
|
else
|
|
next_state = EXTRACT2;
|
|
end
|
|
//
|
|
// Emulation, don't assert o_tlast with dataword.
|
|
//
|
|
EXTRACT3: begin
|
|
o_tvalid = i_tvalid;
|
|
i_tready = o_tready;
|
|
o_tlast = 1'b0;
|
|
if (i_tvalid & o_tready)
|
|
next_state = IDLE;
|
|
else
|
|
next_state = EXTRACT2;
|
|
end
|
|
endcase // case(state)
|
|
end
|
|
|
|
|
|
|
|
endmodule // axi_extract_tlast
|
|
|
|
|