-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathgc_word_packer.vhd
216 lines (180 loc) · 6.8 KB
/
gc_word_packer.vhd
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
-------------------------------------------------------------------------------
-- Title : Word packer/unpacker
-- Project : General Cores Collection library
-------------------------------------------------------------------------------
-- File : gc_word_packer.vhd
-- Author : Tomasz Wlostowski
-- Company : CERN
-- Created : 2012-09-13
-- Last update: 2020-09-18
-- Platform : FPGA-generic
-- Standard : VHDL'93
-------------------------------------------------------------------------------
-- Description: Packs/unpacks g_input_width-sized word(s) into g_output_width-
-- sized word(s). Data is packed starting from the least significant word.
-- Packet width must be integer multiple of the unpacked width.
-------------------------------------------------------------------------------
--
-- Copyright (c) 2012 CERN / BE-CO-HT
--
-- This source file is free software; you can redistribute it
-- and/or modify it under the terms of the GNU Lesser General
-- Public License as published by the Free Software Foundation;
-- either version 2.1 of the License, or (at your option) any
-- later version.
--
-- This source is distributed in the hope that it will be
-- useful, but WITHOUT ANY WARRANTY; without even the implied
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
-- PURPOSE. See the GNU Lesser General Public License for more
-- details.
--
-- You should have received a copy of the GNU Lesser General
-- Public License along with this source; if not, download it
-- from http://www.gnu.org/licenses/lgpl-2.1.html
--
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.gencores_pkg.all;
entity gc_word_packer is
generic(
-- width of the input words
g_input_width : integer;
-- width of the output words
g_output_width : integer);
port(
clk_i : in std_logic;
rst_n_i : in std_logic;
-- input data
d_i : in std_logic_vector(g_input_width-1 downto 0);
-- input data valid
d_valid_i : in std_logic;
-- synchronous input data request, when active, the source
-- is allowed to assert d_valid_i in next clock cycle.
d_req_o : out std_logic;
-- flushes packer input, immediately outputting (incomplete) packed word to q_o
-- even if the number of input words is less than g_output_width.
-- Unused when g_input_width > g_output_width (unpacking)
flush_i : in std_logic := '0';
-- data output
q_o : out std_logic_vector(g_output_width-1 downto 0);
-- data output valid
q_valid_o : out std_logic;
-- data input/output ID. Outputs the current word counter for the unpacked word
-- if g_input_width > g_output_width (unpacking) or outputs the word counter
-- for the input data word.
q_id_o : out unsigned;
-- synchronous data request: if active, packer can output data in following
-- clock cycle.
q_req_i : in std_logic
);
end gc_word_packer;
architecture rtl of gc_word_packer is
function f_max(a : integer; b : integer) return integer is
begin
if(a > b) then
return a;
else
return b;
end if;
end f_max;
function f_min(a : integer; b : integer) return integer is
begin
if(a < b) then
return a;
else
return b;
end if;
end f_min;
constant c_sreg_size : integer := f_max(g_input_width, g_output_width);
constant c_sreg_entries : integer := c_sreg_size / f_min(g_input_width, g_output_width);
constant count_zero : unsigned(f_log2_ceil(c_sreg_entries + 1) - 1 downto 0) := (others => '0');
signal sreg : std_logic_vector(c_sreg_size-1 downto 0);
signal count : unsigned(f_log2_ceil(c_sreg_entries + 1) - 1 downto 0);
signal empty : std_logic;
signal q_valid_comb, q_valid_reg, q_req_d0 : std_logic;
begin -- rtl
-- Fixme: flush functionality.
gen_grow : if(g_output_width > g_input_width) generate
p_grow : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
count <= (others => '0');
else
if(d_valid_i = '1') then
if(q_valid_reg = '0') then
sreg(to_integer(count) * g_input_width + g_input_width-1 downto to_integer(count) * g_input_width) <= d_i;
else
sreg(g_input_width-1 downto 0) <= d_i;
end if;
end if;
if(q_valid_comb = '1') then
count <= (others => '0');
elsif(d_valid_i = '1') then
count <= count + 1;
end if;
q_valid_reg <= q_valid_comb;
end if;
end if;
end process;
q_valid_o <= q_valid_reg;
q_valid_comb <= '1' when (q_req_i = '1' and (count = c_sreg_entries or (count = c_sreg_entries-1 and d_valid_i = '1'))) else '0';
d_req_o <= '1' when q_req_i = '1' and (count /= c_sreg_entries) else '0';
q_o <= sreg;
q_id_o <= count;
end generate gen_grow;
gen_shrink : if(g_output_width < g_input_width) generate
p_shrink : process(clk_i)
begin
if rising_edge(clk_i) then
if rst_n_i = '0' then
count <= (others => '0');
empty <= '1';
q_req_d0 <= '0';
else
q_req_d0 <= q_req_i;
if(d_valid_i = '1') then
sreg <= d_i;
end if;
if(count = c_sreg_entries-1 and d_valid_i = '0' and q_valid_comb = '1') then
empty <= '1';
elsif(d_valid_i = '1') then
empty <= '0';
end if;
if(q_valid_comb = '1') then
if(count = c_sreg_entries-1) then
count <= (others => '0');
else
count <= count + 1;
end if;
end if;
end if;
end if;
end process;
q_valid_o <= q_valid_comb;
d_req_o <= '1' when d_valid_i = '0' and (empty = '1' or (q_req_i = '1' and count = c_sreg_entries-1)) else '0';
p_gen_output : process(count, sreg, empty, d_i, d_valid_i, q_req_d0)
begin
q_id_o <= count;
if (q_req_d0 = '1' and empty = '0') then
q_valid_comb <= '1';
q_o <= sreg(to_integer(count) * g_output_width + g_output_width-1 downto to_integer(count) * g_output_width);
elsif (empty = '1' and d_valid_i = '1' and q_req_d0 = '1') then
q_valid_comb <= '1';
q_o <= d_i(g_output_width-1 downto 0);
else
q_valid_comb <= '0';
q_o <= (others => 'X');
end if;
end process;
end generate gen_shrink;
gen_equal : if(g_output_width = g_input_width) generate
q_o <= d_i;
q_valid_o <= d_valid_i;
d_req_o <= q_req_i;
q_id_o <= count_zero;
end generate gen_equal;
end rtl;