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
|
//
// Copyright 2019 Ettus Research, a National Instruments Brand
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Module: axi_embed_tlast_tkeep
//
// Description:
//
// This module takes the TLAST and TKEEP values of an AXI-Stream interface
// and embeds them into the data stream. This allows a data pipe to be used
// that isn't wide enough for the TDATA, TLAST,and TKEEP to be passed through
// in parallel. Since TLAST and TKEEP are only usually needed for one word
// per packet, this also reduces the amount of memory required to store a
// packet. Note that this module only supports TKEEP at the end of a packet
// when TLAST is asserted. See also axi_extract_tlast_tkeep.
//
// This embedding is accomplished by using an escape sequence using the word
// 0xDEADBEEF as the escape code. If TLAST and TKEEP are both 0 (the usual
// case) then no escape sequence is used. Any word that has "DEADBEEF" in the
// most significant position is considered an escape word. The least
// significant bits of the escape word contain the TKEEP and TLAST bits. The
// word following the escape word is the normal data word associated with
// those TLAST and TKEEP values.
//
// Here are some examples for the case where DATA_W = 64
//
// 0x1234567887654321 with TLAST=0 and TKEEP=0 becomes
// 0x1234567887654321
//
// 0x1234567887654321 with TLAST=1 and TKEEP=0 becomes
// 0xDEADBEEF00000001 0x1234567887654321
//
// 0x1234567887654321 with TLAST=1 and TKEEP=2 becomes
// 0xDEADBEEF00000005 0x1234567887654321
//
// 0x1234567887654321 with TLAST=0 and TKEEP=1 becomes
// 0x1234567887654321 (because TKEEP is ignored when TLAST=0)
//
// 0xDEADBEEFFEEDCAFE without TLAST=0 and TKEEP=0 becomes
// 0xDEADBEEF00000000 0xDEADBEEFFEEDCAFE
//
// 0xDEADBEEFFEEDCAFE with TLAST=0 and TKEEP=1 becomes
// 0xDEADBEEF00000002 0xDEADBEEFFEEDCAFE
//
module axi_embed_tlast_tkeep #(
parameter DATA_W = 64,
parameter KEEP_W = DATA_W/8
) (
input clk,
input rst,
// Input AXI-Stream
input [DATA_W-1:0] i_tdata,
input [KEEP_W-1:0] i_tkeep,
input i_tlast,
input i_tvalid,
output i_tready,
// Output AXI-Stream
output reg [DATA_W-1:0] o_tdata,
output o_tvalid,
input o_tready
);
localparam ESC_WORD_W = 32;
localparam [ESC_WORD_W-1:0] ESC_WORD = 'hDEADBEEF;
//---------------------------------------------------------------------------
// Parameter Checking
//---------------------------------------------------------------------------
if (DATA_W < ESC_WORD_W+KEEP_W+1) begin : gen_assertion
// Cause an error if DATA_W is not large enough.
DATA_W_is_not_large_enough_to_store_escape_code_TKEEP_and_TLAST();
end
//---------------------------------------------------------------------------
// State Machine
//---------------------------------------------------------------------------
localparam PASS = 0;
localparam ESCAPE = 1;
localparam ST_IDLE = 0;
localparam ST_DATA = 1;
reg [0:0] state = ST_IDLE;
reg [0:0] next_state;
reg [0:0] select;
always @(posedge clk) begin
if (rst) begin
state <= ST_IDLE;
end else begin if (o_tready)
state <= next_state;
end
end
always @(*) begin
case(state)
ST_IDLE: begin
if (i_tlast && i_tvalid) begin
next_state = ST_DATA;
select = ESCAPE;
end else if ((i_tdata[DATA_W-1 -: ESC_WORD_W] == ESC_WORD) && i_tvalid) begin
next_state = ST_DATA;
select = ESCAPE;
end else begin
next_state = ST_IDLE;
select = PASS;
end
end
ST_DATA: begin
select = PASS;
if (i_tvalid) begin
next_state = ST_IDLE;
end else begin
next_state = ST_DATA;
end
end
endcase
end
//---------------------------------------------------------------------------
// Output Multiplexers
//---------------------------------------------------------------------------
always @(*) begin
case(select)
PASS : begin
o_tdata = i_tdata;
end
ESCAPE : begin
o_tdata = {DATA_W{1'b0}};
o_tdata[DATA_W-1 -: ESC_WORD_W] = ESC_WORD;
o_tdata[ 1 +: KEEP_W] = i_tkeep;
o_tdata[ 0 +: 1] = i_tlast;
end
endcase
end
assign o_tvalid = (select == PASS) ? i_tvalid : 1'b1;
assign i_tready = (select == PASS) ? o_tready : 1'b0;
endmodule
|