1-- Copyright (c) 2016 Nokia Research Center
2--
3-- Permission is hereby granted, free of charge, to any person obtaining a
4-- copy of this software and associated documentation files (the "Software"),
5-- to deal in the Software without restriction, including without limitation
6-- the rights to use, copy, modify, merge, publish, distribute, sublicense,
7-- and/or sell copies of the Software, and to permit persons to whom the
8-- Software is furnished to do so, subject to the following conditions:
9--
10-- The above copyright notice and this permission notice shall be included in
11-- all copies or substantial portions of the Software.
12--
13-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18-- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19-- DEALINGS IN THE SOFTWARE.
20-------------------------------------------------------------------------------
21-- Title      : AXI lite interface to TTA debugger and stream IO
22-- Project    :
23-------------------------------------------------------------------------------
24-- File       : tta-axislave.vhdl
25-- Author     : Tommi Zetterman  <tommi.zetterman@nokia.com>
26-- Company    : Nokia Research Center
27-- Created    : 2014-06-23
28-- Last update: 2017-06-01
29-- Platform   :
30-- Standard   : VHDL'93
31-------------------------------------------------------------------------------
32-- Description:
33-------------------------------------------------------------------------------
34-- Copyright (c) 2014 Nokia Research Center
35-------------------------------------------------------------------------------
36-- Revisions  :
37-- Date        Version  Author  Description
38-- 2014-06-23  1.0      zetterma Created (as axi4dbgslave-rtl.vhdl
39-- 2015-01-27  1.1      viitanet Modified into a processor wrapper
40-- 2016-11-18  1.1      tervoa   Added full AXI4 interface
41-- 2017-03-27  1.2      tervoa   Fixed burst transfer logic
42-- 2017-04-25  1.3      tervoa   Combined entiy and architecture files
43-- 2017-06-01  1.4      tervoa   Converted to memory buses with handshaking
44-- 2017-06-01  1.5      tervoa   Fix address increment logic
45-- 2018-07-30  1.6      tervoa   Support for optional sync reset
46-------------------------------------------------------------------------------
47library ieee;
48use ieee.std_logic_1164.all;
49use ieee.numeric_std.all;
50
51entity tta_axislave is
52  generic (
53    -- Must be at least 2 + max(max(IMEMADDRWIDTH+IMEMWORDSEL,db_addr_width),
54    --                          fu_LSU_addrw-2)
55    -- where IMEMWORDSEL = bit_width((IMEMDATAWIDTH+31)/32)
56    axi_addrw_g : integer := 17;
57    axi_dataw_g  : integer := 32;
58    axi_idw_g   : integer := 12;
59    sync_reset_g : integer := 0
60  );
61  port (
62    clk       : in std_logic;
63    rstx      : in std_logic;
64    -- Accelerator interface
65    avalid_out : out std_logic;
66    aready_in  : in  std_logic;
67    aaddr_out  : out std_logic_vector(axi_addrw_g-2-1 downto 0);
68    awren_out  : out std_logic;
69    astrb_out  : out std_logic_vector(axi_dataw_g/8-1 downto 0);
70    adata_out  : out std_logic_vector(axi_dataw_g-1 downto 0);
71    rvalid_in  : in  std_logic;
72    rready_out : out std_logic;
73    rdata_in   : in  std_logic_vector(axi_dataw_g-1 downto 0);
74    -- AXI slave port
75    s_axi_awid     : in  STD_LOGIC_VECTOR (axi_idw_g-1 downto 0);
76    s_axi_awaddr   : in  STD_LOGIC_VECTOR (axi_addrw_g-1 downto 0);
77    s_axi_awlen    : in  STD_LOGIC_VECTOR (8-1 downto 0);
78    s_axi_awsize   : in  STD_LOGIC_VECTOR (3-1 downto 0);
79    s_axi_awburst  : in  STD_LOGIC_VECTOR (2-1 downto 0);
80    s_axi_awvalid  : in  STD_LOGIC;
81    s_axi_awready  : out STD_LOGIC;
82    s_axi_wdata    : in  STD_LOGIC_VECTOR (31 downto 0);
83    s_axi_wstrb    : in  STD_LOGIC_VECTOR (3 downto 0);
84    s_axi_wvalid   : in  STD_LOGIC;
85    s_axi_wready   : out STD_LOGIC;
86    s_axi_bid      : out STD_LOGIC_VECTOR (axi_idw_g-1 downto 0);
87    s_axi_bresp    : out STD_LOGIC_VECTOR (2-1 downto 0);
88    s_axi_bvalid   : out STD_LOGIC;
89    s_axi_bready   : in  STD_LOGIC;
90    s_axi_arid     : in  STD_LOGIC_VECTOR (axi_idw_g-1 downto 0);
91    s_axi_araddr   : in  STD_LOGIC_VECTOR (axi_addrw_g-1 downto 0);
92    s_axi_arlen    : in  STD_LOGIC_VECTOR (8-1 downto 0);
93    s_axi_arsize   : in  STD_LOGIC_VECTOR (3-1 downto 0);
94    s_axi_arburst  : in  STD_LOGIC_VECTOR (2-1 downto 0);
95    s_axi_arvalid  : in  STD_LOGIC;
96    s_axi_arready  : out STD_LOGIC;
97    s_axi_rid      : out STD_LOGIC_VECTOR (axi_idw_g-1 downto 0);
98    s_axi_rdata    : out STD_LOGIC_VECTOR (31 downto 0);
99    s_axi_rresp    : out STD_LOGIC_VECTOR (2-1 downto 0);
100    s_axi_rlast    : out STD_LOGIC;
101    s_axi_rvalid   : out STD_LOGIC;
102    s_axi_rready   : in  STD_LOGIC
103  );
104end entity tta_axislave;
105
106architecture rtl of tta_axislave is
107
108  constant sync_reset_c : boolean := sync_reset_g /= 0;
109
110  constant FIXED_BURST : std_logic_vector(1 downto 0) := "00";
111  constant INCR_BURST  : std_logic_vector(1 downto 0) := "01";
112  constant WRAP_BURST  : std_logic_vector(1 downto 0) := "10";
113
114  constant AXI_OKAY    : std_logic_vector(1 downto 0) := "00";
115  constant AXI_SLVERR  : std_logic_vector(1 downto 0) := "10";
116
117  type u8_array is array (natural range <>) of unsigned(7 downto 0);
118  constant burst_size_lut_c : u8_array(0 to 7) :=
119          ("00000001", "00000010","00000100","00001000",
120           "00010000", "00100000","01000000","10000000");
121
122  type state_t is (S_READY, S_WRITE_DATA, S_FINISH_WRITE,
123                   S_READ_DATA, S_FINISH_READ);
124  signal state   : state_t;
125
126  -- Output registers
127  signal s_axi_awready_r : std_logic;
128  signal s_axi_wready_r  : std_logic;
129  signal s_axi_bid_r     : std_logic_vector(s_axi_bid'range);
130  signal s_axi_bresp_r   : std_logic_vector(s_axi_bresp'range);
131  signal s_axi_bvalid_r  : std_logic;
132  signal s_axi_arready_r : std_logic;
133  signal s_axi_rid_r     : std_logic_vector(s_axi_rid'range);
134  signal s_axi_rdata_r   : std_logic_vector(s_axi_rdata'range);
135  signal s_axi_rresp_r   : std_logic_vector(s_axi_rresp'range);
136  signal s_axi_rlast_r   : std_logic;
137  signal s_axi_rvalid_r  : std_logic;
138
139  signal astrb_r, stall_strb_r    : std_logic_vector(astrb_out'range);
140  signal adata_r, stall_data_r    : std_logic_vector(adata_out'range);
141  signal aaddr_r, stall_addr_r    : std_logic_vector(aaddr_out'range);
142  signal avalid_r, awren_r, stall_data_valid_r, rready_r : std_logic;
143
144  signal burst_cnt_r     : unsigned(s_axi_arlen'range);
145  signal read_cnt_r      : unsigned(s_axi_arlen'range);
146  signal transaction_r   : std_logic_vector(s_axi_arid'range);
147
148  signal burst_type_r : std_logic_vector(s_axi_arburst'range);
149  signal burst_size_r : unsigned(7 downto 0);
150  signal wrap_mask_r  : std_logic_vector(s_axi_araddr'range);
151  signal axi_addr_r   : std_logic_vector(s_axi_araddr'range);
152
153  signal axi_stall_r    : std_logic;
154
155
156  function increment_addr(burst_type    : std_logic_vector(s_axi_arburst'range);
157                          size          : unsigned;
158                          wrap_mask     : std_logic_vector(axi_addrw_g-1 downto 0);
159                          address       : std_logic_vector(axi_addrw_g-1 downto 0))
160                          return std_logic_vector is
161  variable address_tmp : std_logic_vector(axi_addrw_g-1 downto 0);
162  begin
163    case burst_type is
164      when FIXED_BURST =>
165        return address;
166      when INCR_BURST =>
167        return std_logic_vector(unsigned(address) + size);
168      when WRAP_BURST => -- UNTESTED
169        address_tmp := std_logic_vector(unsigned(address) + size);
170
171        for I in address'range loop
172          if wrap_mask(I) = '0' then
173            address_tmp(I) := address(I);
174          end if;
175        end loop;
176
177        return address_tmp;
178      when others =>
179        -- coverage off
180        -- pragma translate_off
181        assert false report "Unrecognized burst type" severity warning;
182        -- pragma translate_on
183        -- coverage on
184        return address;
185    end case;
186  end function increment_addr;
187
188  function wrap_mask(axsize : std_logic_vector(s_axi_arsize'range);
189                     axlen  : std_logic_vector(s_axi_arlen'range))
190                     return std_logic_vector is
191  variable mask_temp : std_logic_vector(axi_addrw_g-1 downto 0);
192  variable axsize_int : integer range 0 to 7
193                      := to_integer(unsigned(axsize));
194  begin
195    for I in mask_temp'range loop
196      if I < axsize_int then
197        mask_temp(I) := '0';
198      elsif I < axsize_int + axlen'high then
199        mask_temp(I) := axlen(I - axsize_int);
200      else
201        mask_temp(I) := '0';
202      end if;
203    end loop;
204    return mask_temp;
205  end function wrap_mask;
206
207begin
208
209  sync : process(clk, rstx)
210    variable axi_addr_v : std_logic_vector(axi_addr_r'range);
211  begin
212    if not sync_reset_c and rstx = '0' then
213      s_axi_awready_r <= '0';
214      s_axi_wready_r  <= '0';
215      s_axi_bid_r     <= (others => '0');
216      s_axi_bresp_r   <= (others => '0');
217      s_axi_bvalid_r  <= '0';
218      s_axi_arready_r <= '0';
219      s_axi_rid_r     <= (others => '0');
220      s_axi_rdata_r   <= (others => '0');
221      s_axi_rresp_r   <= (others => '0');
222      s_axi_rlast_r   <= '0';
223      s_axi_rvalid_r  <= '0';
224
225      avalid_r <= '0';
226      aaddr_r  <= (others => '0');
227      awren_r  <= '0';
228      astrb_r  <= (others => '0');
229      adata_r  <= (others => '0');
230      rready_r <= '0';
231
232      axi_addr_r          <= (others => '0');
233      state               <= S_READY;
234      burst_cnt_r         <= (others => '0');
235      transaction_r       <= (others => '0');
236      stall_strb_r        <= (others => '0');
237      stall_data_r        <= (others => '0');
238      stall_addr_r        <= (others => '0');
239      stall_data_valid_r  <= '0';
240    elsif rising_edge(clk) then
241      if sync_reset_c and rstx = '0' then
242        s_axi_awready_r <= '0';
243        s_axi_wready_r  <= '0';
244        s_axi_bid_r     <= (others => '0');
245        s_axi_bresp_r   <= (others => '0');
246        s_axi_bvalid_r  <= '0';
247        s_axi_arready_r <= '0';
248        s_axi_rid_r     <= (others => '0');
249        s_axi_rdata_r   <= (others => '0');
250        s_axi_rresp_r   <= (others => '0');
251        s_axi_rlast_r   <= '0';
252        s_axi_rvalid_r  <= '0';
253
254        avalid_r <= '0';
255        aaddr_r  <= (others => '0');
256        awren_r  <= '0';
257        astrb_r  <= (others => '0');
258        adata_r  <= (others => '0');
259        rready_r <= '0';
260
261        axi_addr_r          <= (others => '0');
262        state               <= S_READY;
263        burst_cnt_r         <= (others => '0');
264        transaction_r       <= (others => '0');
265        stall_strb_r        <= (others => '0');
266        stall_data_r        <= (others => '0');
267        stall_addr_r        <= (others => '0');
268        stall_data_valid_r  <= '0';
269      else
270        if s_axi_arready_r = '1' and s_axi_arvalid = '1' then
271          s_axi_arready_r <= '0';
272        end if;
273        if s_axi_awready_r = '1' and s_axi_awvalid = '1' then
274          s_axi_awready_r <= '0';
275        end if;
276
277        s_axi_wready_r  <= '0';
278        rready_r        <= '0';
279        s_axi_rlast_r   <= '0';
280
281        -- valid_r(0)    <= '0';
282        -- valid_r(2 downto 1) <= valid_r(1 downto 0);
283
284        axi_stall_r   <= '0';
285        case state is
286
287          when S_READY =>
288            if s_axi_awvalid = '1' then
289              s_axi_awready_r <= '1';
290              axi_addr_r      <= s_axi_awaddr;
291              transaction_r   <= s_axi_awid;
292              wrap_mask_r     <= wrap_mask(s_axi_awsize, s_axi_awlen);
293
294              burst_size_r  <= burst_size_lut_c(to_integer(
295                                                  unsigned(s_axi_awsize)));
296              burst_type_r  <= s_axi_awburst;
297              burst_cnt_r   <= unsigned(s_axi_awlen);
298              state         <= S_WRITE_DATA;
299            elsif s_axi_arvalid = '1' then
300              s_axi_arready_r <= '1';
301              transaction_r   <= s_axi_arid;
302              wrap_mask_r     <= wrap_mask(s_axi_arsize, s_axi_arlen);
303
304              axi_addr_r      <= s_axi_araddr;
305              aaddr_r         <= s_axi_araddr(s_axi_araddr'high downto 2);
306              avalid_r        <= '1';
307              awren_r         <= '0';
308              rready_r        <= '1';
309
310              burst_size_r  <= burst_size_lut_c(to_integer(
311                                                  unsigned(s_axi_arsize)));
312              burst_cnt_r   <= unsigned(s_axi_arlen);
313              read_cnt_r    <= unsigned(s_axi_arlen);
314              burst_type_r  <= s_axi_arburst;
315              state         <= S_READ_DATA;
316            end if;
317
318          when S_WRITE_DATA =>
319
320            if avalid_r = '0' or stall_data_valid_r = '0' then
321              s_axi_wready_r <= '1';
322            else
323              s_axi_wready_r <= '0';
324            end if;
325
326            if avalid_r = '1' and aready_in = '1' then
327              if stall_data_valid_r = '1' then
328                astrb_r <= stall_strb_r;
329                adata_r <= stall_data_r;
330                awren_r <= '1';
331                aaddr_r <= stall_addr_r;
332                stall_data_valid_r <= '0';
333              else
334                avalid_r <= '0';
335              end if;
336            end if;
337
338            if s_axi_wvalid = '1' and s_axi_wready_r = '1' then
339              if   (aready_in = '1' and stall_data_valid_r = '0')
340                 or avalid_r = '0' then
341                avalid_r <= '1';
342                awren_r  <= '1';
343                astrb_r  <= s_axi_wstrb;
344                adata_r  <= s_axi_wdata;
345                aaddr_r  <= axi_addr_r(axi_addr_r'high downto 2);
346              else
347                stall_data_valid_r <= '1';
348                stall_data_r       <= s_axi_wdata;
349                stall_strb_r       <= s_axi_wstrb;
350                stall_addr_r       <= axi_addr_r(axi_addr_r'high downto 2);
351              end if;
352
353              if burst_cnt_r = 0 then
354                s_axi_wready_r <= '0';
355                s_axi_bresp_r  <= AXI_OKAY;
356                s_axi_bvalid_r <= '1';
357                s_axi_bid_r  <= transaction_r;
358                state        <= S_FINISH_WRITE;
359              else
360                axi_addr_r <= increment_addr(burst_type_r, burst_size_r,
361                                             wrap_mask_r, axi_addr_r);
362                burst_cnt_r  <= burst_cnt_r - 1;
363              end if;
364            end if;
365
366
367          when S_FINISH_WRITE =>
368            if s_axi_bready = '1' then
369              s_axi_bvalid_r <= '0';
370            end if;
371
372            if avalid_r = '1' and aready_in = '1' then
373              if stall_data_valid_r = '1' then
374                astrb_r <= stall_strb_r;
375                adata_r <= stall_data_r;
376                awren_r <= '1';
377
378                stall_data_valid_r <= '0';
379              else
380                avalid_r <= '0';
381                awren_r  <= '0';
382              end if;
383            end if;
384
385            if avalid_r = '0' and s_axi_bvalid_r = '0' then
386              state <= S_READY;
387            end if;
388
389          when S_READ_DATA =>
390            if s_axi_rready = '1' and s_axi_rvalid_r = '1' then
391              if stall_data_valid_r = '1' then
392                s_axi_rdata_r      <= stall_data_r;
393                stall_data_valid_r <= '0';
394              else
395                s_axi_rvalid_r <= '0';
396              end if;
397            end if;
398
399            if avalid_r = '1' and aready_in = '1' then
400              if read_cnt_r = 0 then
401                avalid_r <= '0';
402              else
403                axi_addr_v := increment_addr(burst_type_r, burst_size_r,
404                                             wrap_mask_r, axi_addr_r);
405                axi_addr_r <= axi_addr_v;
406                aaddr_r    <= axi_addr_v(axi_addr_v'high downto 2);
407                read_cnt_r <= read_cnt_r - 1;
408              end if;
409            end if;
410
411            if s_axi_rvalid_r = '0' or stall_data_valid_r = '0' then
412              rready_r <= '1';
413            else
414              rready_r <= '0';
415            end if;
416
417            if rvalid_in = '1' and rready_r = '1' then
418              if (s_axi_rready = '1'and stall_data_valid_r = '0')
419                 or s_axi_rvalid_r = '0' then
420                s_axi_rvalid_r <= '1';
421                s_axi_rdata_r  <= rdata_in;
422                s_axi_rresp_r  <= AXI_OKAY;
423                s_axi_rid_r    <= transaction_r;
424              else
425                stall_data_valid_r <= '1';
426                stall_data_r       <= rdata_in;
427                rready_r           <= '0';
428              end if;
429
430              if burst_cnt_r = 0 then
431                if (s_axi_rready = '1'and stall_data_valid_r = '0')
432                   or s_axi_rvalid_r = '0' then
433                   s_axi_rlast_r <= '1';
434                end if;
435                rready_r <= '0';
436                state <= S_FINISH_READ;
437              else
438                burst_cnt_r  <= burst_cnt_r - 1;
439              end if;
440            end if;
441
442          when S_FINISH_READ =>
443            if s_axi_rready = '1' and s_axi_rvalid_r = '1' then
444              if stall_data_valid_r = '1' then
445                s_axi_rlast_r      <= '1';
446                s_axi_rdata_r      <= stall_data_r;
447                stall_data_valid_r <= '0';
448              else
449                s_axi_rvalid_r <= '0';
450                s_axi_rlast_r  <= '0';
451                state          <= S_READY;
452              end if;
453            end if;
454
455        end case;
456      end if;
457    end if;
458  end process;
459
460  s_axi_awready  <= s_axi_awready_r;
461  s_axi_wready   <= s_axi_wready_r;
462  s_axi_bid      <= s_axi_bid_r;
463  s_axi_bresp    <= s_axi_bresp_r;
464  s_axi_bvalid   <= s_axi_bvalid_r;
465  s_axi_arready  <= s_axi_arready_r;
466  s_axi_rid      <= s_axi_rid_r;
467  s_axi_rdata    <= s_axi_rdata_r;
468  s_axi_rresp    <= s_axi_rresp_r;
469  s_axi_rlast    <= s_axi_rlast_r;
470  s_axi_rvalid   <= s_axi_rvalid_r;
471  avalid_out     <= avalid_r;
472  aaddr_out      <= aaddr_r;
473  awren_out      <= awren_r;
474  astrb_out      <= astrb_r;
475  adata_out      <= adata_r;
476  rready_out     <= rready_r;
477end architecture rtl;
478