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
|