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