GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/common/handshake_pipeline.vhd Lines: 54 54 100.0 %
Date: 2021-06-12 04:12:08 Branches: 147 210 70.0 %

Line Branch Exec Source
1
168
-- -------------------------------------------------------------------------------------------------
2
-- Copyright (c) Lukas Vik. All rights reserved.
3
--
4
-- This file is part of the tsfpga project.
5
-- https://tsfpga.com
6
-- https://gitlab.com/tsfpga/tsfpga
7
-- -------------------------------------------------------------------------------------------------
8
-- Handshake pipeline. Is used to ease the timing of a streaming data interface by inserting
9
-- register stages on the data and, in some modes, the control signals.
10
--
11
-- There are many modes available, with different characteristics.
12
-- See the descriptions within the code.
13
-- -------------------------------------------------------------------------------------------------
14
15
library ieee;
16
use ieee.std_logic_1164.all;
17
18
19

14772
entity handshake_pipeline is
20
  generic (
21
    data_width : integer;
22
    -- Setting to false can save logic footprint, at the cost of lower throughput
23
    full_throughput : boolean := true;
24
    -- Can result in smaller logic footprint and higher througphput, at the cost of worse timing
25
    -- on the input_ready signal.
26
    allow_poor_input_ready_timing : boolean := false
27
  );
28
  port (
29
    clk : in std_logic;
30
    --
31
    input_ready : out std_logic := '0';
32
    input_valid : in std_logic;
33
    input_last : in std_logic := '-';
34
    input_data : in std_logic_vector(data_width - 1 downto 0);
35
    --
36
    output_ready : in std_logic;
37
    output_valid : out std_logic := '0';
38
    output_last : out std_logic := '0';
39
    output_data : out std_logic_vector(data_width - 1 downto 0) := (others => '0')
40
  );
41
end entity;
42
43
56
architecture a of handshake_pipeline is
44
45
begin
46
47
  ------------------------------------------------------------------------------
48
  choose_mode : if full_throughput and allow_poor_input_ready_timing generate
49
50
    -- In this mode, the data and control signals are driven by registers, except for input_ready
51
    -- which will have an increased critical path. It still maintaints full throughput,
52
    -- and has a much smaller footprint than the full skid-aside buffer.
53
    --
54
    -- It is suitable in situtations where there is a complex net driving the data, which needs to
55
    -- be pipelined in order to achieve timing closure, but the timing of the control signals is
56
    -- not critical.
57
58

46190
    input_ready <= output_ready or not output_valid;
59
60
61
    ------------------------------------------------------------------------------
62
34
    main : process
63
    begin
64

34900
      wait until rising_edge(clk);
65
66
8725
      if input_ready then
67

6904
        output_valid <= input_valid;
68


117368
        output_data <= input_data;
69

17450
        output_last <= input_last;
70
      end if;
71
    end process;
72
73
74
  ------------------------------------------------------------------------------
75
  elsif full_throughput and not allow_poor_input_ready_timing generate
76
77
    -- This mode is a full skid-aside buffer, aka skid buffer.
78
    --
79
    -- It makes sure that all output signals (data as well as control signals) are driven by
80
    -- a register.  It does so while sustaining full throughput. It has the best timing
81
    -- characteristics but also the largest logic footprint.
82
83
12
    signal input_ready_int : std_logic := '1';
84
85
    type state_t is (wait_for_input_valid, full_handshake_throughput, wait_for_output_ready);
86
12
    signal state : state_t := wait_for_input_valid;
87
88
266
    signal input_data_skid : std_logic_vector(input_data'range);
89
26
    signal input_last_skid : std_logic;
90
91
  begin
92
93


1619928
    input_ready <= input_ready_int;
94
95
96
    ------------------------------------------------------------------------------
97
520
    main : process
98
    begin
99

1617544
      wait until rising_edge(clk);
100
101

404386
      case state is
102
        when wait_for_input_valid =>
103
381002
          if input_valid then
104
            -- input_ready is '1', so if we get here an input transaction has occured
105

11615
            output_valid <= '1';
106


280809
            output_data <= input_data;
107

11615
            output_last <= input_last;
108

381002
            state <= full_handshake_throughput;
109
          end if;
110
111
        when full_handshake_throughput =>
112
          -- input_ready and output_valid are always '1' in this state
113
114
21942
          if input_valid and output_ready then
115
            -- Input and output transactions have occured. Update data register.
116


48195
            output_data <= input_data;
117

2835
            output_last <= input_last;
118
19107
          elsif output_ready then
119
            -- Output transaction has occured, but no input transaction
120

11615
            output_valid <= '0';
121

11615
            state <= wait_for_input_valid;
122
7492
          elsif input_valid then
123
            -- Input transaction has occured, but no output transaction
124
            -- Values from input transaction will be saved in the skid-aside buffer while we wait for output_ready.
125

1180
            input_ready_int <= '0';
126

21942
            state <= wait_for_output_ready;
127
          end if;
128
129
        when wait_for_output_ready =>
130
1442
          if output_ready then
131
            -- output_valid is '1', so if we get here an output transaction has occured
132

1180
            input_ready_int <= '1';
133


20060
            output_data <= input_data_skid;
134

1180
            output_last <= input_last_skid;
135

1180
            state <= full_handshake_throughput;
136
          end if;
137
      end case;
138
139
404386
      if input_ready and input_valid then
140


349064
        input_data_skid <= input_data;
141

808772
        input_last_skid <= input_last;
142
      end if;
143
    end process;
144
145
146
  ------------------------------------------------------------------------------
147
  elsif (not full_throughput) and allow_poor_input_ready_timing generate
148
149
    -- All signals are driven by registers, except input_ready which will have an increased
150
    -- critical path. This mode will be able to maintain a one half throughput.
151
    --
152
    -- Compared to the first mode in this file, this one has a lower load on the input_ready.
153
    -- This results in somewhat better timing on the input_ready signal, at the cost of
154
    -- lower throughput.
155
156
14
  begin
157
158


55298
    input_ready <= output_ready and output_valid;
159
160
161
    ------------------------------------------------------------------------------
162
17
    main : process
163
    begin
164

43984
      wait until rising_edge(clk);
165
166

10996
      output_valid <= input_valid and not (output_valid and output_ready);
167


186932
      output_data <= input_data;
168


1573176
      output_last <= input_last;
169
    end process;
170
171
172
  ------------------------------------------------------------------------------
173
  elsif (not full_throughput) and (not allow_poor_input_ready_timing) generate
174
175
    -- All signals are driven by registers, which results in the best timing but also the lowest
176
    -- throughput. This mode will be able to maintain a one third throughput.
177
178
41
  begin
179
180
181
    ------------------------------------------------------------------------------
182
533
    main : process
183
    begin
184

1551184
      wait until rising_edge(clk);
185
186

387795
      input_ready <= output_ready and output_valid;
187
      -- Since there is a one cycle latency on output_valid, and a one cycle latency on input_ready,
188
      -- we have to stall for two cycles after a transaction, to allow the "input" master to update
189
      -- data and valid.
190

387795
      output_valid <= input_valid and not (output_valid and output_ready) and not input_ready;
191


16289735
      output_data <= input_data;
192

775618
      output_last <= input_last;
193
    end process;
194
195
  end generate;
196
197
end architecture;