GCC Code Coverage Report
Directory: generated/vunit_out/preprocessed/ Exec Total Coverage
File: generated/vunit_out/preprocessed/reg_file/axi_lite_reg_file.vhd Lines: 64 64 100.0 %
Date: 2021-06-12 04:12:08 Branches: 211 295 71.5 %

Line Branch Exec Source
1
282
-- -------------------------------------------------------------------------------------------------
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
-- General register file controlled over AXI-Lite.
9
-- -------------------------------------------------------------------------------------------------
10
11
library ieee;
12
use ieee.std_logic_1164.all;
13
use ieee.numeric_std.all;
14
15
library common;
16
use common.addr_pkg.all;
17
18
library axi;
19
use axi.axi_pkg.all;
20
use axi.axi_lite_pkg.all;
21
22
use work.reg_file_pkg.all;
23
24
25








88519
entity axi_lite_reg_file is
26
  generic (
27
    regs : reg_definition_vec_t;
28
    default_values : reg_vec_t(regs'range) := (others => (others => '0'))
29
  );
30
  port (
31
    clk : in std_logic;
32
    -- Register control bus
33
    axi_lite_m2s : in axi_lite_m2s_t;
34
    axi_lite_s2m : out axi_lite_s2m_t := (
35
      read => (
36
        ar => (ready => '1'),
37
        r => axi_lite_s2m_r_init),
38
      write => (
39
        aw => (ready => '1'),
40
        w => axi_lite_s2m_w_init,
41
        b => axi_lite_s2m_b_init)
42
      );
43
    -- Register values
44
    regs_up : in reg_vec_t(regs'range) := default_values;
45
    regs_down : out reg_vec_t(regs'range) := default_values;
46
    -- Each bit is pulsed for one cycle when the corresponding register is read/written
47
    reg_was_read : out std_logic_vector(regs'range) := (others => '0');
48
    reg_was_written : out std_logic_vector(regs'range) := (others => '0')
49
  );
50
end entity;
51
52
architecture a of axi_lite_reg_file is
53
54
47
  constant addr_and_mask_vec : addr_and_mask_vec_t := to_addr_and_mask_vec(regs);
55
56
15293
  signal reg_values : reg_vec_t(regs'range) := default_values;
57
58
47
  constant invalid_addr : integer := regs'length;
59
  subtype decoded_idx_t is integer range 0 to invalid_addr;
60
61
begin
62
63
64167
  regs_down <= reg_values;
64
65
66
  ------------------------------------------------------------------------------
67
  read_block : block
68
    type read_state_t is (ar, r);
69
47
    signal read_state : read_state_t := ar;
70
47
    signal read_idx : decoded_idx_t := invalid_addr;
71
47
    signal valid_read_address : boolean := false;
72
  begin
73
74
    -- An address transaction has occured and the address points to a valid read register
75



90692
    valid_read_address <= read_idx /= invalid_addr and is_read_type(regs(read_idx).reg_type);
76
77
6713
    read_process : process
78
    begin
79

90565
      wait until rising_edge(clk);
80
81

22636
      axi_lite_s2m.read.r.valid <= '0';
82
83


131638
      reg_was_read <= (others => '0');
84
85
22636
      if valid_read_address then
86

63594
        axi_lite_s2m.read.r.resp <= axi_resp_okay;
87
88

21198
        if is_fabric_gives_value_type(regs(read_idx).reg_type) then
89


7326
          axi_lite_s2m.read.r.data(reg_values(0)'range) <= regs_up(read_idx);
90
        else
91


692208
          axi_lite_s2m.read.r.data(reg_values(0)'range) <= reg_values(read_idx);
92
        end if;
93
      else
94

4314
        axi_lite_s2m.read.r.resp <= axi_resp_slverr;
95


185502
        axi_lite_s2m.read.r.data <= (others => '-');
96
      end if;
97
98
22636
      case read_state is
99
        when ar =>
100
22256
          if axi_lite_m2s.read.ar.valid and axi_lite_s2m.read.ar.ready then
101

190
            axi_lite_s2m.read.ar.ready <= '0';
102

190
            read_idx <= decode(axi_lite_m2s.read.ar.addr, addr_and_mask_vec);
103
104

22256
            read_state <= r;
105
          end if;
106
107
        when r =>
108

380
          axi_lite_s2m.read.r.valid <= '1';
109
380
          if axi_lite_m2s.read.r.ready and axi_lite_s2m.read.r.valid then
110

190
            axi_lite_s2m.read.r.valid <= '0';
111

190
            axi_lite_s2m.read.ar.ready <= '1';
112
113
190
            if valid_read_address then
114


188
              reg_was_read(read_idx) <= '1';
115
            end if;
116
117

45272
            read_state <= ar;
118
          end if;
119
      end case;
120
    end process;
121
  end block;
122
123
124
  ------------------------------------------------------------------------------
125
  write_block : block
126
    type write_state_t is (aw, w, b);
127
47
    signal write_state : write_state_t := aw;
128
47
    signal write_idx : decoded_idx_t := invalid_addr;
129
47
    signal valid_write_address : boolean := false;
130
  begin
131
132
    -- Constrain initial state value to be valid enum. It seems the formal check will allow enums
133
    -- to assume invalid (initial) values.
134
    -- psl write_state_enum_should_be_valid : assert always
135
    --   (write_state = aw or write_state = w or write_state = b) @ rising_edge(clk);
136
137
    -- An address transaction has occured and the address points to a valid write register
138



90703
    valid_write_address <= write_idx /= invalid_addr and is_write_type(regs(write_idx).reg_type);
139
140
15943
    write_process : process
141
    begin
142

90565
      wait until rising_edge(clk);
143
144


131638
      reg_was_written <= (others => '0');
145
146
22636
      if valid_write_address then
147

64419
        axi_lite_s2m.write.b.resp <= axi_resp_okay;
148
      else
149

3489
        axi_lite_s2m.write.b.resp <= axi_resp_slverr;
150
      end if;
151
152
22636
      for list_idx in regs'range loop
153

54501
        if is_write_pulse_type(regs(list_idx).reg_type) then
154
          -- Set default value zero. If a write occurs to this register, the value
155
          -- will be asserted for one cycle below.
156




206861
          reg_values(list_idx) <= (others => '0');
157
        end if;
158
      end loop;
159
160

22636
      case write_state is
161
        when aw =>
162
22402
          if axi_lite_m2s.write.aw.valid and axi_lite_s2m.write.aw.ready then
163

117
            axi_lite_s2m.write.aw.ready <= '0';
164

117
            axi_lite_s2m.write.w.ready <= '1';
165
166

117
            write_idx <= decode(axi_lite_m2s.write.aw.addr, addr_and_mask_vec);
167

22402
            write_state <= w;
168
          end if;
169
170
        when w =>
171
117
          if axi_lite_m2s.write.w.valid and axi_lite_s2m.write.w.ready then
172
117
            if valid_write_address then
173


3795
              reg_values(write_idx) <= axi_lite_m2s.write.w.data(reg_values(0)'range);
174


115
              reg_was_written(write_idx) <= '1';
175
            end if;
176
177

117
            axi_lite_s2m.write.w.ready <= '0';
178

117
            axi_lite_s2m.write.b.valid <= '1';
179
180

117
            write_state <= b;
181
          end if;
182
183
        when b =>
184
117
          if axi_lite_m2s.write.b.ready and axi_lite_s2m.write.b.valid then
185

117
            axi_lite_s2m.write.aw.ready <= '1';
186

117
            axi_lite_s2m.write.b.valid <= '0';
187

45319
            write_state <= aw;
188
          end if;
189
      end case;
190
    end process;
191
  end block;
192
193
194
  ------------------------------------------------------------------------------
195
  psl_block : block
196
556
    constant reg_was_accessed_zero : std_logic_vector(reg_was_read'range) := (others => '0');
197
  begin
198
    -- psl default clock is rising_edge(clk);
199
    --
200
    -- psl reg_was_written_should_pulse_only_one_clock_cycle : assert always
201
    --   {reg_was_written /= reg_was_accessed_zero} |=> (reg_was_written = reg_was_accessed_zero);
202
    --
203
    -- psl reg_was_read_should_pulse_only_one_clock_cycle : assert always
204
    --   {reg_was_read /= reg_was_accessed_zero} |=> (reg_was_read = reg_was_accessed_zero);
205
    --
206
    -- Asserting reg_was_read typically prompts something in the PL that changes the register value.
207
    -- Hence it is important that reg_was_read is asserted after the actual read (R) transaction
208
    -- has occured, and not e.g. after the AR transaction.
209
    -- psl reg_was_read_should_pulse_when_read_transaction_occurs : assert always
210
    --   (reg_was_read /= reg_was_accessed_zero) -> prev(axi_lite_m2s.read.r.ready and axi_lite_s2m.read.r.valid);
211
  end block;
212
213
end architecture;