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

Subversion Repositories potato

[/] [potato/] [trunk/] [src/] [pp_icache.vhd] - Blame information for rev 45

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 25 skordal
-- The Potato Processor - A simple processor for FPGAs
2
-- (c) Kristian Klomsten Skordal 2014 - 2015 <kristian.skordal@wafflemail.net>
3
-- Report bugs and issues on <http://opencores.org/project,potato,bugtracker>
4
 
5
library ieee;
6
use ieee.std_logic_1164.all;
7
use ieee.numeric_std.all;
8
 
9
use work.pp_types.all;
10
use work.pp_utilities.all;
11
 
12 44 skordal
--! @brief Simple read-only direct-mapped instruction cache.
13
entity pp_icache is
14 25 skordal
        generic(
15 44 skordal
                LINE_SIZE : natural := 4;  --! Number of words per cache line
16
                NUM_LINES : natural := 128 --! Number of lines in the cache
17 25 skordal
        );
18
        port(
19
                clk   : in std_logic;
20
                reset : in std_logic;
21
 
22
                -- Control interface:
23
                cache_enable    : in std_logic;
24
                cache_flush     : in std_logic;
25
                cached_areas    : in std_logic_vector(31 downto 0);
26
 
27
                -- Memory interface:
28
                mem_address_in   : in  std_logic_vector(31 downto 0);
29
                mem_data_in      : in  std_logic_vector(31 downto 0);
30
                mem_data_out     : out std_logic_vector(31 downto 0);
31
                mem_data_size    : in  std_logic_vector( 1 downto 0);
32
                mem_read_req     : in  std_logic;
33
                mem_read_ack     : out std_logic;
34
                mem_write_req    : in  std_logic;
35
                mem_write_ack    : out std_logic;
36
 
37
                -- Wishbone interface:
38
                wb_inputs  : in wishbone_master_inputs;
39
                wb_outputs : out wishbone_master_outputs
40
        );
41 44 skordal
end entity pp_icache;
42 25 skordal
 
43 44 skordal
architecture behaviour of pp_icache is
44 25 skordal
 
45 44 skordal
        -- Counter types:
46
        subtype line_counter_type is natural range 0 to NUM_LINES;
47
        subtype word_counter_type is natural range 0 to LINE_SIZE;
48 25 skordal
 
49 44 skordal
        -- Cache line types:
50
        subtype cache_line_type is std_logic_vector((LINE_SIZE * 32) - 1 downto 0);
51
        type cache_line_word_array is array(0 to LINE_SIZE - 1) of std_logic_vector(31 downto 0);
52
        type cache_line_array is array(0 to NUM_LINES - 1) of cache_line_type;
53
 
54
        -- Cache tag type:
55
        subtype cache_tag_type is std_logic_vector(31 - log2(LINE_SIZE * 4) - log2(NUM_LINES) downto 0);
56
        type cache_tag_array is array(0 to NUM_LINES - 1) of cache_tag_type;
57
 
58
        -- Cache memories:
59
        signal cache_memory : cache_line_array;
60
        signal tag_memory   : cache_tag_array;
61
        signal valid        : std_logic_vector(NUM_LINES - 1 downto 0) := (others => '0');
62
 
63
        attribute ram_style : string;
64
        attribute ram_style of cache_memory: signal is "block";
65
        --attribute ram_style of tag_memory: signal is "block";
66
 
67 25 skordal
        -- Cache controller signals:
68 44 skordal
        type state_type is (IDLE, CACHE_READ_STALL, SINGLE_READ, SINGLE_WRITE,
69
                LOAD_CACHELINE_START, LOAD_CACHELINE_WAIT_ACK, LOAD_CACHELINE_FINISH);
70 25 skordal
        signal state : state_type := IDLE;
71
 
72 44 skordal
        -- Is the current input address in the cache?
73
        signal input_address_cached : boolean;
74
 
75
        -- Input address components:
76
        signal input_address_line : std_logic_vector(log2(NUM_LINES) - 1 downto 0);
77
        signal input_address_word : std_logic_vector(log2(LINE_SIZE) - 1 downto 0);
78
        signal input_address_tag  : std_logic_vector(31 - log2(LINE_SIZE * 4) - log2(NUM_LINES) downto 0);
79
 
80
        -- Cacheline matching the current input address:
81
        signal current_cache_line, cache_lookup : cache_line_type;
82
        signal current_cache_line_words : cache_line_word_array;
83
        signal current_tag : cache_tag_type;
84
 
85
        -- Base address to store a cacheline to:
86
        signal cl_store_address : std_logic_vector(31 downto log2(LINE_SIZE * 4));
87
        -- Base address to load a cacheline from:
88
        signal cl_load_address  : std_logic_vector(31 downto log2(LINE_SIZE * 4));
89
        -- Cache line to load:
90
        signal cl_current_line : line_counter_type;
91
        -- Current word being loaded/stored:
92
        signal cl_current_word  : word_counter_type;
93
 
94
        -- Buffer for holding a cache line while loading:
95
        signal load_buffer : cache_line_type;
96
        signal load_buffer_tag : cache_tag_type;
97
 
98
        -- Causes a cache line to be stored in the cache memory:
99
        signal store_cache_line : std_logic;
100
 
101
        -- Set when the current input address matches a cache line:
102
        signal cache_hit : std_logic;
103
 
104
        -- For regular reads:
105
        signal read_ack : std_logic;
106
        signal read_data_out : std_logic_vector(31 downto 0);
107
 
108
        -- For regular writes:
109
        signal write_ack : std_logic;
110
 
111 25 skordal
        -- Gets the amount to shift output data to the processor with for requests of size != 32 bits:
112
        function get_data_shift(size : in std_logic_vector(1 downto 0); address : in std_logic_vector)
113
                return natural is
114
        begin
115
                case size is
116
                        when b"01" =>
117
                                case address(1 downto 0) is
118
                                        when b"00" =>
119
                                                return 0;
120
                                        when b"01" =>
121
                                                return 8;
122
                                        when b"10" =>
123
                                                return 16;
124
                                        when b"11" =>
125
                                                return 24;
126
                                        when others =>
127
                                                return 0;
128
                                end case;
129
                        when b"10" =>
130
                                if address(1) = '0' then
131
                                        return 0;
132
                                else
133
                                        return 16;
134
                                end if;
135
                        when others =>
136
                                return 0;
137
                end case;
138
        end function get_data_shift;
139
 
140
begin
141
 
142 44 skordal
        --assert is_pow2(LINE_SIZE) report "Cache line size must be a power of 2!" severity FAILURE;
143
        --assert is_pow2(NUM_LINES) report "Number of cache lines must be a power of 2!" severity FAILURE;
144 25 skordal
 
145
        -- Check if the current input address should be/is in the cache:
146 44 skordal
        input_address_cached <= cached_areas(to_integer(unsigned(mem_address_in(31 downto 27)))) = '1';
147 25 skordal
 
148 44 skordal
        mem_data_out <= current_cache_line_words(to_integer(unsigned(input_address_word))) when
149
                        input_address_cached and cache_enable = '1' and cache_flush = '0'
150
                else read_data_out;
151
        mem_read_ack <= (cache_hit and mem_read_req)
152
                when state = IDLE and input_address_cached and cache_enable = '1' and cache_flush = '0'
153
                else read_ack;
154
        write_ack <= wb_inputs.ack when state = SINGLE_WRITE else '0';
155
        mem_write_ack <= write_ack;
156 25 skordal
 
157 44 skordal
        input_address_line <= mem_address_in(log2(LINE_SIZE * 4) + log2(NUM_LINES) - 1 downto log2(LINE_SIZE * 4));
158
        input_address_tag  <= mem_address_in(31 downto log2(LINE_SIZE * 4) + log2(NUM_LINES));
159
 
160
        find_word: process(clk)
161
        begin
162
                if rising_edge(clk) then
163
                        input_address_word <= mem_address_in(log2(LINE_SIZE * 4) - 1 downto 2);
164
                end if;
165
        end process find_word;
166
 
167
        cacheline_lookup: process(clk)
168
        begin
169
                if rising_edge(clk) then
170
                        if store_cache_line = '1' then
171
                                cache_memory(cl_current_line) <= load_buffer;
172
                        end if;
173
 
174
                        current_cache_line <= cache_memory(to_integer(unsigned(input_address_line)));
175
                end if;
176
        end process cacheline_lookup;
177
 
178
        decompose_cache_line: for i in 0 to LINE_SIZE - 1 generate
179
                current_cache_line_words(i) <= current_cache_line(32 * i + 31 downto 32 * i);
180
        end generate decompose_cache_line;
181
 
182
        tag_lookup: process(clk)
183
        begin
184
                if rising_edge(clk) then
185
                        if reset = '1' then
186
                                cache_hit <= '0';
187
                        else
188
                                if store_cache_line = '1' then
189
                                        tag_memory(cl_current_line) <= load_buffer_tag;
190
                                end if;
191
 
192
                                current_tag <= tag_memory(to_integer(unsigned(input_address_line)));
193
                                cache_hit <= valid(to_integer(unsigned(input_address_line))) and to_std_logic(tag_memory(to_integer(unsigned(input_address_line))) = input_address_tag);
194
                        end if;
195
                end if;
196
        end process tag_lookup;
197
 
198 25 skordal
        controller: process(clk)
199 44 skordal
                variable current_word : std_logic_vector(31 downto 0);
200 25 skordal
        begin
201
                if rising_edge(clk) then
202
                        if reset = '1' then
203
                                state <= IDLE;
204
                                wb_outputs.cyc <= '0';
205
                                wb_outputs.stb <= '0';
206 44 skordal
                                store_cache_line <= '0';
207
                                read_ack <= '0';
208
                                valid <= (others => '0');
209
                                read_data_out <= (others => '0');
210 25 skordal
                        else
211
                                case state is
212
                                        when IDLE =>
213 44 skordal
                                                read_ack <= '0';
214
                                                if cache_flush = '1' then
215
                                                        valid <= (others => '0');
216
                                                elsif input_address_cached and cache_enable = '1' then
217
                                                        if (mem_read_req = '1' or mem_write_req = '1') and cache_hit = '0' then
218
                                                                wb_outputs.adr <= mem_address_in(31 downto log2(LINE_SIZE * 4)) & (log2(LINE_SIZE * 4) - 1 downto 0 => '0');
219
                                                                wb_outputs.cyc <= '1';
220
                                                                wb_outputs.we <= '0';
221
                                                                wb_outputs.sel <= (others => '1');
222
                                                                load_buffer_tag <= input_address_tag;
223
                                                                cl_load_address <= mem_address_in(31 downto log2(LINE_SIZE * 4));
224
                                                                cl_store_address <= input_address_tag & input_address_line;
225
                                                                cl_current_line <= to_integer(unsigned(input_address_line));
226
                                                                cl_current_word <= 0;
227
                                                                state <= LOAD_CACHELINE_START;
228
                                                        end if;
229
                                                else
230
                                                        if mem_read_req = '1' and read_ack = '0' then            -- Do an uncached read
231 25 skordal
                                                                wb_outputs.adr <= mem_address_in;
232 44 skordal
                                                                wb_outputs.sel <= wb_get_data_sel(mem_data_size, mem_address_in);
233 25 skordal
                                                                wb_outputs.cyc <= '1';
234
                                                                wb_outputs.stb <= '1';
235
                                                                wb_outputs.we <= '0';
236
                                                                state <= SINGLE_READ;
237
                                                        elsif mem_write_req = '1' then  -- Do an uncached write
238
                                                                wb_outputs.adr <= mem_address_in;
239
                                                                wb_outputs.dat <= std_logic_vector(shift_left(unsigned(mem_data_in),
240
                                                                        get_data_shift(mem_data_size, mem_address_in)));
241 44 skordal
                                                                wb_outputs.sel <= wb_get_data_sel(mem_data_size, mem_address_in);
242 25 skordal
                                                                wb_outputs.cyc <= '1';
243
                                                                wb_outputs.stb <= '1';
244
                                                                wb_outputs.we <= '1';
245
                                                                state <= SINGLE_WRITE;
246
                                                        end if;
247 44 skordal
                                                end if;
248
                                        when CACHE_READ_STALL =>
249
                                                state <= IDLE;
250 25 skordal
                                        when SINGLE_READ =>
251
                                                if wb_inputs.ack = '1' then
252 44 skordal
                                                        read_data_out <= std_logic_vector(shift_right(unsigned(wb_inputs.dat),
253 25 skordal
                                                                get_data_shift(mem_data_size, mem_address_in)));
254
                                                        wb_outputs.cyc <= '0';
255
                                                        wb_outputs.stb <= '0';
256 44 skordal
                                                        read_ack <= '1';
257 25 skordal
                                                        state <= IDLE;
258
                                                end if;
259
                                        when SINGLE_WRITE =>
260
                                                if wb_inputs.ack = '1' then
261
                                                        wb_outputs.cyc <= '0';
262
                                                        wb_outputs.stb <= '0';
263
                                                        wb_outputs.we <= '0';
264
                                                        state <= IDLE;
265
                                                end if;
266 44 skordal
                                        when LOAD_CACHELINE_START =>
267
                                                wb_outputs.stb <= '1';
268
                                                wb_outputs.we <= '0';
269
                                                wb_outputs.adr <= cl_load_address & std_logic_vector(to_unsigned(cl_current_word, log2(LINE_SIZE))) & b"00";
270
                                                state <= LOAD_CACHELINE_WAIT_ACK;
271
                                        when LOAD_CACHELINE_WAIT_ACK =>
272
                                                if wb_inputs.ack = '1' then
273
                                                        wb_outputs.stb <= '0';
274
                                                        load_buffer(cl_current_word * 32 + 31 downto cl_current_word * 32) <= wb_inputs.dat;
275
                                                        if natural(cl_current_word) = LINE_SIZE - 1 then
276
                                                                wb_outputs.cyc <= '0';
277
                                                                store_cache_line <= '1';
278
                                                                state <= LOAD_CACHELINE_FINISH;
279
                                                        else
280
                                                                cl_current_word <= cl_current_word + 1;
281
                                                                state <= LOAD_CACHELINE_START;
282
                                                        end if;
283
                                                end if;
284
                                        when LOAD_CACHELINE_FINISH =>
285
                                                store_cache_line <= '0';
286
                                                valid(cl_current_line) <= '1';
287
                                                state <= CACHE_READ_STALL;
288 25 skordal
                                end case;
289
                        end if;
290
                end if;
291
        end process controller;
292
 
293
end architecture behaviour;

powered by: WebSVN 2.1.0

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