1 -------------------------------------------------------------------------- 2 -- 3 -- Copyright (C) 1993, Peter J. Ashenden 4 -- Mail: Dept. Computer Science 5 -- University of Adelaide, SA 5005, Australia 6 -- e-mail: petera@cs.adelaide.edu.au 7 -- 8 -- This program is free software; you can redistribute it and/or modify 9 -- it under the terms of the GNU General Public License as published by 10 -- the Free Software Foundation; either version 1, or (at your option) 11 -- any later version. 12 -- 13 -- This program is distributed in the hope that it will be useful, 14 -- but WITHOUT ANY WARRANTY; without even the implied warranty of 15 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 -- GNU General Public License for more details. 17 -- 18 -- You should have received a copy of the GNU General Public License 19 -- along with this program; if not, write to the Free Software 20 -- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 -- 22 -------------------------------------------------------------------------- 23 -- 24 -- $RCSfile: cache-behaviour.vhdl,v $ $Revision: 1.1 $ $Date: 2000/05/08 14:36:47 $ 25 -- 26 -------------------------------------------------------------------------- 27 -- 28 -- Behavioural architecture for cache. 29 -- 30 31 32 use work.bv_arithmetic.bv_to_natural, 33 work.bv_arithmetic.natural_to_bv; 34 35 36 architecture behaviour of cache is 37 38 begin -- behaviour 39 40 cache_behaviour : process 41 42 constant words_per_line : positive := line_size / 4; 43 constant number_of_sets : positive := cache_size / line_size / associativity; 44 45 subtype word_offset_range is natural range 0 to words_per_line-1; 46 subtype entry_index_range is natural range 0 to associativity-1; 47 subtype set_index_range is natural range 0 to number_of_sets-1; 48 49 type line is array (word_offset_range) of dlx_word; 50 51 type entry is record 52 tag : natural; 53 valid : boolean; 54 dirty : boolean; 55 data : line; 56 end record; 57 58 type store_array is array (set_index_range, entry_index_range) of entry; 59 60 variable store : store_array; 61 variable cpu_address : natural; 62 variable word_offset : word_offset_range; 63 variable set_index : set_index_range; 64 variable cpu_tag : natural; 65 variable entry_index : entry_index_range; 66 variable hit : boolean; 67 variable next_replacement_entry_index : entry_index_range := 0; 68 69 70 procedure do_read_hit is 71 begin 72 cpu_d <= store(set_index, entry_index).data(word_offset); 73 cpu_ready <= '1' after Tpd_clk_out; 74 wait until phi2 = '0'; 75 cpu_d <= null after Tpd_clk_out; 76 cpu_ready <= '0' after Tpd_clk_out; 77 end do_read_hit; 78 79 80 procedure do_write_through is 81 begin 82 wait until phi1 = '1'; 83 if reset = '1' then 84 return; 85 end if; 86 mem_a <= cpu_a after Tpd_clk_out; 87 mem_width <= cpu_width after Tpd_clk_out; 88 mem_d <= cpu_d after Tpd_clk_out; 89 mem_write <= '1' after Tpd_clk_out; 90 mem_burst <= '0' after Tpd_clk_out; 91 mem_enable <= '1' after Tpd_clk_out; 92 wait until mem_ready = '1' or reset = '1'; 93 cpu_ready <= mem_ready after Tpd_clk_out; 94 wait until phi2 = '0'; 95 mem_d <= null after Tpd_clk_out; 96 mem_write <= '0' after Tpd_clk_out; 97 mem_enable <= '0' after Tpd_clk_out; 98 cpu_ready <= '0' after Tpd_clk_out; 99 end do_write_through; 100 101 102 procedure do_write_hit is 103 begin 104 case cpu_width is 105 when width_word => 106 store(set_index, entry_index).data(word_offset) := cpu_d; 107 when width_halfword => 108 if cpu_a(1) = '0' then -- ms half word 109 store(set_index, entry_index).data(word_offset)(0 to 15) := cpu_d(0 to 15); 110 else -- ls half word 111 store(set_index, entry_index).data(word_offset)(16 to 23) := cpu_d(16 to 23); 112 end if; 113 when width_byte => 114 if cpu_a(1) = '0' then -- ms half word 115 if cpu_a(0) = '0' then -- byte 0 116 store(set_index, entry_index).data(word_offset)(0 to 7) := cpu_d(0 to 7); 117 else -- byte 1 118 store(set_index, entry_index).data(word_offset)(8 to 15) := cpu_d(8 to 15); 119 end if; 120 else -- ls half word 121 if cpu_a(0) = '0' then -- byte 2 122 store(set_index, entry_index).data(word_offset)(16 to 23) := cpu_d(16 to 23); 123 else -- byte 3 124 store(set_index, entry_index).data(word_offset)(24 to 31) := cpu_d(24 to 31); 125 end if; 126 end if; 127 end case; 128 if write_strategy = copy_back then 129 store(set_index, entry_index).dirty := true; 130 end if; 131 -- 132 -- if write_through cache, also update main memory 133 if write_strategy = write_through then 134 do_write_through; 135 else -- copy_back cache 136 cpu_ready <= '1' after Tpd_clk_out; 137 wait until phi2 = '0'; 138 cpu_ready <= '0' after Tpd_clk_out; 139 end if; 140 end do_write_hit; 141 142 143 procedure copy_back_line is 144 variable next_address : natural; 145 variable old_word_offset : natural; 146 begin 147 next_address := (store(set_index, entry_index).tag * number_of_sets 148 + set_index) * line_size; 149 wait until phi1 = '1'; 150 if reset = '1' then 151 return; 152 end if; 153 mem_width <= width_word after Tpd_clk_out; 154 mem_write <= '1' after Tpd_clk_out; 155 mem_enable <= '1' after Tpd_clk_out; 156 mem_burst <= '1' after Tpd_clk_out; 157 old_word_offset := 0; 158 burst_loop : loop 159 if old_word_offset = words_per_line-1 then 160 mem_burst <= '0' after Tpd_clk_out; 161 end if; 162 mem_a <= natural_to_bv(next_address, mem_a'length) after Tpd_clk_out; 163 mem_d <= store(set_index, entry_index).data(old_word_offset) after Tpd_clk_out; 164 wait_loop : loop 165 wait until phi2 = '0'; 166 exit burst_loop when reset = '1' 167 or (mem_ready = '1' and old_word_offset = words_per_line-1); 168 exit wait_loop when mem_ready = '1'; 169 end loop wait_loop; 170 old_word_offset := old_word_offset + 1; 171 next_address := next_address + 4; 172 end loop burst_loop; 173 store(set_index, entry_index).dirty := false; 174 mem_d <= null after Tpd_clk_out; 175 mem_write <= '0' after Tpd_clk_out; 176 mem_enable <= '0' after Tpd_clk_out; 177 end copy_back_line; 178 179 180 procedure fetch_line is 181 variable next_address : natural; 182 variable new_word_offset : natural; 183 begin 184 next_address := (cpu_address / line_size) * line_size; 185 wait until phi1 = '1'; 186 if reset = '1' then 187 return; 188 end if; 189 mem_width <= width_word after Tpd_clk_out; 190 mem_write <= '0' after Tpd_clk_out; 191 mem_enable <= '1' after Tpd_clk_out; 192 mem_burst <= '1' after Tpd_clk_out; 193 new_word_offset := 0; 194 burst_loop : loop 195 if new_word_offset = words_per_line-1 then 196 mem_burst <= '0' after Tpd_clk_out; 197 end if; 198 mem_a <= natural_to_bv(next_address, mem_a'length) after Tpd_clk_out; 199 wait_loop : loop 200 wait until phi2 = '0'; 201 store(set_index, entry_index).data(new_word_offset) := mem_d; 202 exit burst_loop when reset = '1' 203 or (mem_ready = '1' and new_word_offset = words_per_line-1); 204 exit wait_loop when mem_ready = '1'; 205 end loop wait_loop; 206 new_word_offset := new_word_offset + 1; 207 next_address := next_address + 4; 208 end loop burst_loop; 209 store(set_index, entry_index).valid := true; 210 store(set_index, entry_index).tag := cpu_tag; 211 store(set_index, entry_index).dirty := false; 212 mem_enable <= '0' after Tpd_clk_out; 213 end fetch_line; 214 215 216 procedure replace_line is 217 begin 218 -- first chose an entry using "random" number generator 219 entry_index := next_replacement_entry_index; 220 next_replacement_entry_index 221 := (next_replacement_entry_index + 1) mod associativity; 222 if store(set_index, entry_index).dirty then 223 copy_back_line; 224 end if; 225 fetch_line; 226 end replace_line; 227 228 229 procedure do_read_miss is 230 begin 231 replace_line; 232 if reset = '1' then 233 return; 234 end if; 235 do_read_hit; 236 end do_read_miss; 237 238 239 procedure do_write_miss is 240 begin 241 -- if write_through cache, just update main memory 242 if write_strategy = write_through then 243 do_write_through; 244 else -- copy_back cache 245 replace_line; 246 if reset = '1' then 247 return; 248 end if; 249 do_write_hit; 250 end if; 251 end do_write_miss; 252 253 254 begin -- process cache_behaviour 255 -- reset: initialize outputs and the cache store valid bits 256 cpu_ready <= '0'; 257 cpu_d <= null; 258 mem_enable <= '0'; 259 mem_width <= width_word; 260 mem_write <= '0'; 261 mem_burst <= '0'; 262 mem_a <= X"00000000"; 263 mem_d <= null; 264 for init_set_index in set_index_range loop 265 for init_entry_index in entry_index_range loop 266 store(init_set_index, init_entry_index).valid := false; 267 store(init_set_index, init_entry_index).dirty := false; 268 end loop; -- init_entry_index 269 end loop; -- init_set_index 270 -- 271 loop 272 -- wait for a cpu request 273 wait until phi2 = '1' and cpu_enable = '1'; 274 -- decode address 275 cpu_address := bv_to_natural(cpu_a); 276 word_offset := (cpu_address mod line_size) / 4; 277 set_index := (cpu_address / line_size) mod number_of_sets; 278 cpu_tag := cpu_address / line_size / number_of_sets; 279 -- check for hit 280 hit := false; 281 for lookup_entry_index in entry_index_range loop 282 if store(set_index, lookup_entry_index).valid 283 and store(set_index, lookup_entry_index).tag = cpu_tag then 284 hit := true; 285 entry_index := lookup_entry_index; 286 exit; 287 end if; 288 end loop; -- lookup_entry 289 -- 290 if hit then 291 if cpu_write = '1' then 292 do_write_hit; 293 else 294 do_read_hit; 295 end if; 296 else 297 if cpu_write = '1' then 298 do_write_miss; 299 else 300 do_read_miss; 301 end if; 302 end if; 303 exit when reset = '1'; 304 end loop; 305 -- loop exited on reset: wait until it goes inactive 306 -- then start again 307 wait until phi2 = '0' and reset = '0'; 308 end process cache_behaviour; 309 310 end behaviour; 311
This page was generated using GHDL 0.14 (20040829) [Sokcho edition], a program written by Tristan Gingold