1//
2// Copyright 2011 Ettus Research LLC
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16//
17
18
19// Split vita packets longer than one GPIF frame, add padding on short frames
20
21module packet_splitter
22  #(parameter FRAME_LEN=256)
23   (input clk, input reset, input clear,
24    input  [7:0] frames_per_packet,
25    input [18:0] data_i,
26    input src_rdy_i,
27    output dst_rdy_o,
28    output [18:0] data_o,
29    output src_rdy_o,
30    input dst_rdy_i,
31    output [31:0] debug0,
32    output [31:0] debug1);
33
34   reg [1:0] state;
35   reg [15:0] length;
36   reg [15:0] frame_len;
37   reg [7:0]  frame_count;
38
39   localparam PS_IDLE = 0;
40   localparam PS_FRAME = 1;
41   localparam PS_NEW_FRAME = 2;
42   localparam PS_PAD = 3;
43
44   wire       eof_i = data_i[17];
45
46   always @(posedge clk)
47     if(reset | clear)
48       begin
49	  state <= PS_IDLE;
50	  frame_count <= 0;
51       end
52     else
53       case(state)
54	 PS_IDLE :
55	   if(src_rdy_i & dst_rdy_i)
56	     begin
57		length <= { data_i[14:0],1'b0};
58		frame_len <= FRAME_LEN;
59		state <= PS_FRAME;
60		frame_count <= 1;
61	     end
62	 PS_FRAME :
63	   if(src_rdy_i & dst_rdy_i)
64	     if((frame_len == 2) & ((length == 2) | eof_i))
65	       state <= PS_IDLE;
66	     else if(frame_len == 2)
67	       begin
68		  length <= length - 1;
69		  state <= PS_NEW_FRAME;
70		  frame_count <= frame_count + 1;
71	       end
72	     else if((length == 2)|eof_i)
73	       begin
74		  frame_len <= frame_len - 1;
75		  state <= PS_PAD;
76	       end
77	     else
78	       begin
79		  frame_len <= frame_len - 1;
80		  length <= length - 1;
81	       end
82	 PS_NEW_FRAME :
83	   if(src_rdy_i & dst_rdy_i)
84	     begin
85		frame_len <= FRAME_LEN;
86		if((length == 2)|eof_i)
87		  state <= PS_PAD;
88		else
89		  begin
90		     state <= PS_FRAME;
91		     length <= length - 1;
92		  end // else: !if((length == 2)|eof_i)
93	     end // if (src_rdy_i & dst_rdy_i)
94
95	 PS_PAD :
96	   if(dst_rdy_i)
97	     if(frame_len == 2)
98	       state <= PS_IDLE;
99	     else
100	       frame_len <= frame_len - 1;
101
102       endcase // case (state)
103
104   wire next_state_is_idle = dst_rdy_i & (frame_len==2) &
105	( (state==PS_PAD) | ( (state==PS_FRAME) & src_rdy_i & ((length==2)|eof_i) ) );
106
107
108
109
110   assign dst_rdy_o = dst_rdy_i & (state != PS_PAD);
111   assign src_rdy_o = src_rdy_i | (state == PS_PAD);
112
113   wire eof_out = (frame_len == 2) & (state != PS_IDLE) & (state != PS_NEW_FRAME);
114   wire sof_out = (state == PS_IDLE) | (state == PS_NEW_FRAME);
115   wire occ_out = eof_out & next_state_is_idle & (frames_per_packet != frame_count);
116
117   wire [15:0] data_out = data_i[15:0];
118   assign data_o = {occ_out, eof_out, sof_out, data_out};
119
120   assign debug0 = { 8'd0, dst_rdy_o, src_rdy_o, next_state_is_idle, eof_out, sof_out, occ_out, state[1:0], frame_count[7:0], frames_per_packet[7:0] };
121   assign debug1 = { length[15:0], frame_len[15:0] };
122
123endmodule // packet_splitter
124