OpenCores
URL https://opencores.org/ocsvn/heap_sorter/heap_sorter/trunk

Subversion Repositories heap_sorter

[/] [heap_sorter/] [trunk/] [high_speed_pipelined_4clk_per_word/] [src/] [sorter_ctrl.vhd] - Blame information for rev 6

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 5 wzab
-------------------------------------------------------------------------------
2
-- Title      : Sorting node controller for heap-sorter
3
-- Project    : heap-sorter
4
-------------------------------------------------------------------------------
5
-- File       : sorter_ctrl.vhd
6
-- Author     : Wojciech M. Zabolotny <wzab@ise.pw.edu.pl>
7
-- Company    : 
8
-- Created    : 2010-05-14
9 6 wzab
-- Last update: 2018-03-12
10 5 wzab
-- Platform   : 
11
-- Standard   : VHDL'93
12
-------------------------------------------------------------------------------
13
-- Description: 
14
-------------------------------------------------------------------------------
15
-- Copyright (c) 2010 Wojciech M. Zabolotny
16
-- This file is published under the BSD license, so you can freely adapt
17
-- it for your own purposes.
18
-- Additionally this design has been described in my article:
19
--    Wojciech M. Zabolotny, "Dual port memory based Heapsort implementation
20
--    for FPGA", Proc. SPIE 8008, 80080E (2011); doi:10.1117/12.905281
21
-- I'd be glad if you cite this article when you publish something based
22
-- on my design.
23
-------------------------------------------------------------------------------
24
-- Revisions  :
25
-- Date        Version  Author  Description
26
-- 2010-05-14  1.0      wzab    Created
27
-------------------------------------------------------------------------------
28
-------------------------------------------------------------------------------
29
-- The sorter controller is connected with three dual port memories.
30
-- The first dual port memory tm_... provides the "upstream data"
31
-- The second dual port memory lm_... provides the "left branch of downstream data"
32
-- The third dual port memory rm_... provides the "right branch of downstream data"
33
-- The controller is notified about availability of the new data by the
34
-- "update" signal.
35
-- However in this architecture we need to service two upstream memories!
36
-- That's because we want to save one cycle, and to be able to issue
37
--
38
-- Important feature of each controller is the ability to clear the memory
39
-- after reset.
40
-------------------------------------------------------------------------------
41
library ieee;
42
use ieee.std_logic_1164.all;
43
use ieee.numeric_std.all;
44
use ieee.std_logic_textio.all;
45
use std.textio.all;
46
library work;
47
use work.sorter_pkg.all;
48
use work.sys_config.all;
49
 
50
entity sorter_ctrl is
51
 
52
  generic (
53
    NLEVELS   : integer;                -- number of levels (max number of
54
    -- address bits
55
    NADDRBITS : integer                 -- number of used address bits
56
    );
57
 
58
  port (
59
    -- Top memory connections
60
    tm_din       : in  T_DATA_REC;
61
    tm_dout      : out T_DATA_REC;
62
    tm_addr      : out std_logic_vector(NLEVELS-1 downto 0);
63
    tm_we        : out std_logic;
64
    -- Left memory connections
65
    lm_din       : in  T_DATA_REC;
66
    lm_dout      : out T_DATA_REC;
67
    lm_addr      : out std_logic_vector(NLEVELS-1 downto 0);
68
    lm_we        : out std_logic;
69
    -- Right memory connections
70
    rm_din       : in  T_DATA_REC;
71
    rm_dout      : out T_DATA_REC;
72
    rm_addr      : out std_logic_vector(NLEVELS-1 downto 0);
73
    rm_we        : out std_logic;
74
    -- Upper level controller connections
75
    up_in        : in  std_logic;
76
    up_in_val    : in  T_DATA_REC;
77
    up_in_addr   : in  std_logic_vector(NLEVELS-1 downto 0);
78
    -- Upper level update notifier
79
    up_out       : out std_logic;
80
    up_out_val   : out T_DATA_REC;
81
    up_out_addr  : out std_logic_vector(NLEVELS-1 downto 0);
82
    -- Lower level controller connections
83
    low_out      : out std_logic;
84
    low_out_val  : out T_DATA_REC;
85
    low_out_addr : out std_logic_vector(NLEVELS-1 downto 0);
86
    low_in       : in  std_logic;
87
    low_in_val   : in  T_DATA_REC;
88
    low_in_addr  : in  std_logic_vector(NLEVELS-1 downto 0);
89
    -- Lower level update notifier
90
    -- System connections
91
    clk          : in  std_logic;
92
    clk_en       : in  std_logic;
93
    ready_in     : in  std_logic;
94
    ready_out    : out std_logic;       -- signals, when memory is cleared
95
    -- after reset
96
    rst_n        : in  std_logic);
97
end sorter_ctrl;
98
 
99
architecture sorter_ctrl_arch1 of sorter_ctrl is
100
 
101
  type T_CTRL_STATE is (CTRL_RESET, CTRL_CLEAR, CTRL_IDLE, CTRL_S2, CTRL_S1, CTRL_S0);
102
  signal ctrl_state, ctrl_state_next                                     : T_CTRL_STATE := CTRL_IDLE;
103
  signal addr, addr_i                                                    : std_logic_vector(NLEVELS-1 downto 0);
104
  signal s_up_in_addr, s_up_in_addr_i                                    : std_logic_vector(NLEVELS-1 downto 0);
105
  signal s_up_out_addr, s_up_out_addr_i                                  : std_logic_vector(NLEVELS-1 downto 0);
106
  signal s_ready_out, s_ready_out_i                                      : std_logic;
107
  signal s_up_out, s_up_out_i                                            : std_logic;
108
  signal s_addr_out                                                      : std_logic_vector(NLEVELS-1 downto 0);
109
  signal s_tm_dout                                                       : T_DATA_REC;
110
  signal s_up_out_val_i, s_up_out_val                                    : T_DATA_REC   := DATA_REC_INIT_DATA;
111
  signal s_up_in_val_i, s_up_in_val                                      : T_DATA_REC   := DATA_REC_INIT_DATA;
112
  signal res_sort_cmp_lt_l_up, res_sort_cmp_lt_l_r, res_sort_cmp_lt_r_up : boolean      := false;
113
  signal s_l_val, s_l_val_i                                              : T_DATA_REC;
114
  signal s_r_val, s_r_val_i                                              : T_DATA_REC;
115
 
116
 
117
  constant ADDR_MAX : std_logic_vector(NLEVELS-1 downto 0) := std_logic_vector(to_unsigned(2**NADDRBITS-1, NLEVELS));
118
 
119
begin
120
 
121
  tm_dout <= s_tm_dout;
122
-- We have the two-process state machine.
123
  p1 : process (addr, ctrl_state, lm_din, low_in, low_in_addr(NADDRBITS),
124
                low_in_addr(NADDRBITS-1 downto 0), low_in_val, ready_in,
125
                res_sort_cmp_lt_l_r, res_sort_cmp_lt_l_up,
126
                res_sort_cmp_lt_r_up, rm_din, s_l_val, s_r_val, s_ready_out,
127
                s_up_in_val, up_in, up_in_addr, up_in_val)
128
    variable rline : line;
129
 
130
  begin  -- process p1
131
    -- defaults
132
    ctrl_state_next <= ctrl_state;
133
    tm_we           <= '0';
134
    rm_we           <= '0';
135
    lm_we           <= '0';
136
    lm_addr         <= (others => '0');
137
    rm_addr         <= (others => '0');
138
    tm_addr         <= (others => '0');
139
    s_ready_out_i   <= s_ready_out;
140
    addr_i          <= addr;
141
    low_out_val     <= DATA_REC_INIT_DATA;  -- to avoid latches
142
    low_out         <= '0';
143
    s_up_in_val_i   <= s_up_in_val;
144
    up_out_addr     <= (others => '0');
145
    up_out_val      <= DATA_REC_INIT_DATA;
146
    up_out          <= '0';
147
    lm_dout         <= DATA_REC_INIT_DATA;
148
    rm_dout         <= DATA_REC_INIT_DATA;
149
    s_tm_dout       <= DATA_REC_INIT_DATA;
150
    s_addr_out      <= (others => '0');
151
    s_l_val_i       <= s_l_val;
152
    s_r_val_i       <= s_r_val;
153
    case ctrl_state is
154
      when CTRL_RESET =>
155
        addr_i          <= (others => '0');
156
        s_ready_out_i   <= '0';
157
        ctrl_state_next <= CTRL_CLEAR;
158
      when CTRL_CLEAR =>
159
        lm_addr <= addr;
160
        rm_addr <= addr;
161
        lm_dout <= DATA_REC_INIT_DATA;
162
        rm_dout <= DATA_REC_INIT_DATA;
163
        lm_we   <= '1';
164
        rm_we   <= '1';
165
        if addr = ADDR_MAX then
166
          if ready_in = '1' then
167
            s_ready_out_i   <= '1';
168
            ctrl_state_next <= CTRL_IDLE;
169
          end if;
170
        else
171
          addr_i <= std_logic_vector(unsigned(addr)+1);
172
        end if;
173
      when CTRL_IDLE =>
174
        -- We read "down" memories ("upper" value is provided by the ``bypass channel'')
175
        if up_in = '1' then
176
          ctrl_state_next <= CTRL_S0;
177
          tm_addr         <= up_in_addr;
178
          lm_addr         <= up_in_addr;
179
          rm_addr         <= up_in_addr;
180
          addr_i          <= up_in_addr;
181
          s_up_in_val_i   <= up_in_val;
182
        end if;
183
      when CTRL_S0 =>
184
        tm_addr         <= addr;
185
        lm_addr         <= addr;
186
        rm_addr         <= addr;
187
        -- We wait, until the memories produce the data, (there is an output
188
        -- register on the memory's output!)
189
        ctrl_state_next <= CTRL_S1;
190
      when CTRL_S1 =>
191
        -- The memory values are available, so we start the comparison
192
        s_l_val_i <= lm_din;
193
        s_r_val_i <= rm_din;
194
        -- Check, if we need to take value from lower ``bypass channel''
195
        if low_in = '1' then
196
          --if SORT_DEBUG then
197
          --  write(rline, string'(" x! "));
198
          --end if;
199
          if (addr(NADDRBITS-1 downto 0) = low_in_addr(NADDRBITS-1 downto 0)) then
200
            -- We are reading a value which was just updated, so we need to get it
201
            -- from ``bypass channel'' instead of memory
202
            --if SORT_DEBUG then
203
            --  write(rline, string'(" y! "));
204
            --end if;
205
            if low_in_addr(NADDRBITS) = '1' then
206
              s_l_val_i <= low_in_val;
207
            else
208
              s_r_val_i <= low_in_val;
209
            end if;
210
          end if;
211
        end if;
212
        ctrl_state_next <= CTRL_S2;
213
      when CTRL_S2 =>
214
        -- In this cycle we can compare data
215
        -- Debug output!
216
        --if SORT_DEBUG then
217
        --  write(rline, string'("CMP "));
218
        --  write(rline, NADDRBITS);
219
        --  write(rline, string'(" U:"));
220
        --  wrstlv(rline, tdrec2stlv(s_up_in_val));
221
        --end if;
222
        --if SORT_DEBUG then
223
        --  write(rline, string'(" L:"));
224
        --  wrstlv(rline, tdrec2stlv(l_val));
225
        --  write(rline, string'(" R:"));
226
        --  wrstlv(rline, tdrec2stlv(r_val));
227
        --  write(rline, string'(" A:"));
228
        --end if;
229
        s_up_out_i <= '0';                  -- Cancel previous UP notification
230
        if res_sort_cmp_lt_l_up and res_sort_cmp_lt_l_r then
231
          -- The L-ram value is the smallest
232
          -- Output the value from the L-ram and put the new value into the L-ram
233
          s_tm_dout <= s_l_val;
234
          tm_addr   <= addr;
235
          tm_we     <= '1';
236
 
237
          up_out_val  <= s_l_val;
238
          up_out      <= '1';
239
          up_out_addr <= addr;
240
 
241
          lm_addr <= addr;
242
          lm_dout <= s_up_in_val;
243
          lm_we   <= '1';
244
 
245
          -- Low out must be sent one cycle before idle!
246
          low_out               <= '1';
247
          low_out_val           <= s_up_in_val;
248
          s_addr_out(NADDRBITS) <= '1';
249
 
250
          if NADDRBITS > 0 then
251
            s_addr_out(NADDRBITS-1 downto 0) <= addr(NADDRBITS-1 downto 0);
252
          end if;
253
          --wrstlv(rline, s_addr_out);
254
          ctrl_state_next <= CTRL_IDLE;
255
        --if SORT_DEBUG then
256
        --  write(rline, string'(" T<->L"));
257
        --end if;
258
        elsif res_sort_cmp_lt_r_up then
259
          -- The R-ram value is the smallest
260
          -- Output the value from the R-ram and put the new value into the R-ram
261
          s_tm_dout <= s_r_val;
262
          tm_addr   <= addr;
263
          tm_we     <= '1';
264
 
265
          up_out_val  <= s_r_val;
266
          up_out      <= '1';
267
          up_out_addr <= addr;
268
 
269
          rm_addr <= addr;
270
          rm_dout <= s_up_in_val;
271
          rm_we   <= '1';
272
 
273
          low_out     <= '1';
274
          low_out_val <= s_up_in_val;
275
 
276
          s_addr_out(NADDRBITS) <= '0';
277
          if NADDRBITS > 0 then
278
            s_addr_out(NADDRBITS-1 downto 0) <= addr(NADDRBITS-1 downto 0);
279
          end if;
280
          ctrl_state_next <= CTRL_IDLE;
281
        --if SORT_DEBUG then
282
        --  wrstlv(rline, s_addr_out);
283
        --  write(rline, string'(" T<->R"));
284
        --end if;
285
        else
286
          -- The new value is the smallest
287
          -- Nothing to do, no update downstream
288
          s_tm_dout <= s_up_in_val;
289
          tm_we     <= '1';
290
          tm_addr   <= addr;
291
 
292
          up_out_val  <= s_up_in_val;
293
          up_out      <= '1';
294
          up_out_addr <= addr;
295
 
296
          ctrl_state_next <= CTRL_IDLE;
297
        --wrstlv(rline, up_in_addr);
298
        --if SORT_DEBUG then
299
        --  write(rline, string'(" T===T"));
300
        --end if;
301
        end if;
302
      --if SORT_DEBUG then
303
      --  writeline(reports, rline);
304
      --end if;
305
      when others => null;
306
    end case;
307
  end process p1;
308
 
309 6 wzab
  sort_cmp_lt_1: entity work.sort_cmp_lt
310
    port map (
311
      clk   => clk,
312
      rst_n => rst_n,
313
      v1    => s_l_val_i,
314
      v2    => s_up_in_val,
315
      lt    => res_sort_cmp_lt_l_up);
316
 
317
  sort_cmp_lt_2: entity work.sort_cmp_lt
318
    port map (
319
      clk   => clk,
320
      rst_n => rst_n,
321
      v1    => s_l_val_i,
322
      v2    => s_r_val_i,
323
      lt    => res_sort_cmp_lt_l_r);
324
 
325
  sort_cmp_lt_3: entity work.sort_cmp_lt
326
    port map (
327
      clk   => clk,
328
      rst_n => rst_n,
329
      v1    => s_r_val_i,
330
      v2    => s_up_in_val,
331
      lt    => res_sort_cmp_lt_r_up);
332
 
333 5 wzab
  p2 : process (clk) is
334
  begin  -- process p2
335
    if clk'event and clk = '1' then     -- rising clock edge
336
      if rst_n = '0' then               -- asynchronous reset (active low)
337
        ctrl_state           <= CTRL_RESET;
338
        s_ready_out          <= '0';
339
        addr                 <= (others => '0');
340
        s_up_in_val          <= DATA_REC_INIT_DATA;
341
        s_l_val              <= DATA_REC_INIT_DATA;
342
        s_r_val              <= DATA_REC_INIT_DATA;
343
      --update_out  <= '0';
344
      --addr_out    <= (others => '0');
345
      else
346
        s_ready_out          <= s_ready_out_i;
347
        ctrl_state           <= ctrl_state_next;
348
        addr                 <= addr_i;
349
        s_up_in_val          <= s_up_in_val_i;
350
        s_l_val              <= s_l_val_i;
351
        s_r_val              <= s_r_val_i;
352
      end if;
353
    end if;
354
  end process p2;
355
  ready_out    <= s_ready_out;
356
  low_out_addr <= s_addr_out;
357
end sorter_ctrl_arch1;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.