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

Subversion Repositories zipcpu

[/] [zipcpu/] [trunk/] [rtl/] [core/] [pfcache.v] - Blame information for rev 194

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 69 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3 82 dgisselq
// Filename:    pfcache.v
4 69 dgisselq
//
5
// Project:     Zip CPU -- a small, lightweight, RISC CPU soft core
6
//
7
// Purpose:     Keeping our CPU fed with instructions, at one per clock and
8
//              with no stalls.  An unusual feature of this cache is the
9
//      requirement that the entire cache may be cleared (if necessary).
10
//
11
// Creator:     Dan Gisselquist, Ph.D.
12
//              Gisselquist Technology, LLC
13
//
14
////////////////////////////////////////////////////////////////////////////////
15
//
16 194 dgisselq
// Copyright (C) 2015-2016, Gisselquist Technology, LLC
17 69 dgisselq
//
18
// This program is free software (firmware): you can redistribute it and/or
19
// modify it under the terms of  the GNU General Public License as published
20
// by the Free Software Foundation, either version 3 of the License, or (at
21
// your option) any later version.
22
//
23
// This program is distributed in the hope that it will be useful, but WITHOUT
24
// ANY WARRANTY; without even the implied warranty of MERCHANTIBILITY or
25
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
26
// for more details.
27
//
28
// License:     GPL, v3, as defined and found on www.gnu.org,
29
//              http://www.gnu.org/licenses/gpl.html
30
//
31
//
32
////////////////////////////////////////////////////////////////////////////////
33
//
34
module  pfcache(i_clk, i_rst, i_new_pc, i_clear_cache,
35
                        // i_early_branch, i_from_addr,
36
                        i_stall_n, i_pc, o_i, o_pc, o_v,
37
                o_wb_cyc, o_wb_stb, o_wb_we, o_wb_addr, o_wb_data,
38
                        i_wb_ack, i_wb_stall, i_wb_err, i_wb_data,
39
                        o_illegal);
40
        parameter       LGCACHELEN = 8, ADDRESS_WIDTH=24,
41 194 dgisselq
                        LGLINES=5; // Log of the number of separate cache lines
42
        localparam      CACHELEN=(1<<LGCACHELEN); // Size of our cache memory
43
        localparam      CW=LGCACHELEN;  // Short hand for LGCACHELEN
44
        localparam      PW=LGCACHELEN-LGLINES; // Size of a cache line
45
        localparam      BUSW = 32;      // Number of data lines on the bus
46
        localparam      AW=ADDRESS_WIDTH; // Shorthand for ADDRESS_WIDTH
47 69 dgisselq
        input                           i_clk, i_rst, i_new_pc;
48
        input                           i_clear_cache;
49
        input                           i_stall_n;
50
        input           [(AW-1):0]       i_pc;
51 176 dgisselq
        output  wire    [(BUSW-1):0]     o_i;
52
        output  wire    [(AW-1):0]       o_pc;
53 69 dgisselq
        output  wire                    o_v;
54
        //
55
        output  reg             o_wb_cyc, o_wb_stb;
56
        output  wire            o_wb_we;
57
        output  reg     [(AW-1):0]       o_wb_addr;
58
        output  wire    [(BUSW-1):0]     o_wb_data;
59
        //
60
        input                           i_wb_ack, i_wb_stall, i_wb_err;
61
        input           [(BUSW-1):0]     i_wb_data;
62
        //
63
        output  reg                     o_illegal;
64
 
65
        // Fixed bus outputs: we read from the bus only, never write.
66
        // Thus the output data is ... irrelevant and don't care.  We set it
67
        // to zero just to set it to something.
68
        assign  o_wb_we = 1'b0;
69
        assign  o_wb_data = 0;
70
 
71 176 dgisselq
        wire                    r_v;
72 69 dgisselq
        reg     [(BUSW-1):0]     cache   [0:((1<<CW)-1)];
73 194 dgisselq
        reg     [(AW-CW-1):0]    tags    [0:((1<<(LGLINES))-1)];
74
        reg     [((1<<(LGLINES))-1):0]   vmask;
75 69 dgisselq
 
76
        reg     [(AW-1):0]       lastpc;
77
        reg     [(CW-1):0]       rdaddr;
78 176 dgisselq
        reg     [(AW-1):CW]     tagvalipc, tagvallst;
79
        wire    [(AW-1):CW]     tagval;
80 82 dgisselq
        wire    [(AW-1):PW]     lasttag;
81 129 dgisselq
        reg                     illegal_valid;
82 82 dgisselq
        reg     [(AW-1):PW]     illegal_cache;
83 69 dgisselq
 
84 176 dgisselq
        // initial      o_i = 32'h76_00_00_00;  // A NOOP instruction
85
        // initial      o_pc = 0;
86
        reg     [(BUSW-1):0]     r_pc_cache, r_last_cache;
87
        reg     [(AW-1):0]       r_pc, r_lastpc;
88
        reg     isrc;
89 69 dgisselq
        always @(posedge i_clk)
90 176 dgisselq
        begin
91
                // We don't have the logic to select what to read, we must
92
                // read both the value at i_pc and lastpc.  cache[i_pc] is
93
                // the value we return if the cache is good, cacne[lastpc] is
94
                // the value we return if we've been stalled, weren't valid,
95
                // or had to wait a clock or two.  (Remember i_pc can't stop
96
                // changing for a clock, so we need to keep track of the last
97
                // one from before it stopped.)
98
                //
99
                // Here we keep track of which answer we want/need
100
                isrc <= ((r_v)&&(i_stall_n))||(i_new_pc);
101 69 dgisselq
 
102 176 dgisselq
                // Here we read both, and select which was write using isrc
103
                // on the next clock.
104
                r_pc_cache <= cache[i_pc[(CW-1):0]];
105
                r_last_cache <= cache[lastpc[(CW-1):0]];
106
                r_pc <= i_pc;
107
                r_lastpc <= lastpc;
108
        end
109
        assign  o_pc = (isrc) ? r_pc : r_lastpc;
110
        assign  o_i  = (isrc) ? r_pc_cache : r_last_cache;
111
 
112
        reg     tagsrc;
113 69 dgisselq
        always @(posedge i_clk)
114 118 dgisselq
                // It may be possible to recover a clock once the cache line
115
                // has been filled, but our prior attempt to do so has lead
116
                // to a race condition, so we keep this logic simple.
117
                if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
118 176 dgisselq
                        tagsrc <= 1'b1;
119 118 dgisselq
                else
120 176 dgisselq
                        tagsrc <= 1'b0;
121
        initial tagvalipc = 0;
122
        always @(posedge i_clk)
123
                tagvalipc <= tags[i_pc[(CW-1):PW]];
124
        initial tagvallst = 0;
125
        always @(posedge i_clk)
126
                tagvallst <= tags[lastpc[(CW-1):PW]];
127
        assign  tagval = (tagsrc)?tagvalipc : tagvallst;
128 69 dgisselq
 
129
        // i_pc will only increment when everything else isn't stalled, thus
130
        // we can set it without worrying about that.   Doing this enables
131
        // us to work in spite of stalls.  For example, if the next address
132
        // isn't valid, but the decoder is stalled, get the next address
133
        // anyway.
134
        initial lastpc = 0;
135
        always @(posedge i_clk)
136 71 dgisselq
                if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
137 69 dgisselq
                        lastpc <= i_pc;
138
 
139 82 dgisselq
        assign  lasttag = lastpc[(AW-1):PW];
140 69 dgisselq
 
141 176 dgisselq
        wire    w_v_from_pc, w_v_from_last;
142
        assign  w_v_from_pc = ((i_pc[(AW-1):PW] == lasttag)
143
                                &&(tagvalipc == i_pc[(AW-1):CW])
144 69 dgisselq
                                &&(vmask[i_pc[(CW-1):PW]]));
145 176 dgisselq
        assign  w_v_from_last = (
146 82 dgisselq
                                //(lastpc[(AW-1):PW] == lasttag)&&
147
                                (tagval == lastpc[(AW-1):CW])
148 69 dgisselq
                                &&(vmask[lastpc[(CW-1):PW]]));
149
 
150
        reg     [1:0]    delay;
151
 
152
        initial delay = 2'h3;
153 176 dgisselq
        reg     rvsrc;
154 69 dgisselq
        always @(posedge i_clk)
155 71 dgisselq
                if ((i_rst)||(i_clear_cache)||(i_new_pc)||((r_v)&&(i_stall_n)))
156 69 dgisselq
                begin
157 176 dgisselq
                        // r_v <= r_v_from_pc;
158
                        rvsrc <= 1'b1;
159 69 dgisselq
                        delay <= 2'h2;
160 71 dgisselq
                end else if (~r_v) begin // Otherwise, r_v was true and we were
161 176 dgisselq
                        // stalled, hence only if ~r_v
162
                        rvsrc <= 1'b0;
163 69 dgisselq
                        if (o_wb_cyc)
164
                                delay <= 2'h2;
165
                        else if (delay != 0)
166 88 dgisselq
                                delay <= delay + 2'b11; // i.e. delay -= 1;
167 69 dgisselq
                end
168 176 dgisselq
        reg     r_v_from_pc, r_v_from_last;
169
        always @(posedge i_clk)
170
                r_v_from_pc <= w_v_from_pc;
171
        always @(posedge i_clk)
172
                r_v_from_last <= w_v_from_last;
173 69 dgisselq
 
174 176 dgisselq
        assign  r_v = ((rvsrc)?(r_v_from_pc):(r_v_from_last));
175
        assign  o_v = (((rvsrc)?(r_v_from_pc):(r_v_from_last))
176
                                ||((o_illegal)&&(~o_wb_cyc)))
177
                        &&(~i_new_pc)&&(~i_rst);
178 69 dgisselq
 
179 176 dgisselq
        reg     last_ack;
180
        initial last_ack = 1'b0;
181
        always @(posedge i_clk)
182
                last_ack <= (o_wb_cyc)&&(
183
                                (rdaddr[(PW-1):1]=={(PW-1){1'b1}})
184
                                &&((rdaddr[0])||(i_wb_ack)));
185 69 dgisselq
 
186 176 dgisselq
        reg     needload;
187
        initial needload = 1'b0;
188
        always @(posedge i_clk)
189
                needload <= ((~r_v)&&(delay==0)
190
                        &&((tagvallst != lastpc[(AW-1):CW])
191
                                ||(~vmask[lastpc[(CW-1):PW]]))
192
                        &&((~illegal_valid)
193
                                ||(lastpc[(AW-1):PW] != illegal_cache)));
194
 
195
        reg     last_addr;
196
        initial last_addr = 1'b0;
197
        always @(posedge i_clk)
198
                last_addr <= (o_wb_cyc)&&(o_wb_addr[(PW-1):1] == {(PW-1){1'b1}})
199
                                &&((~i_wb_stall)|(o_wb_addr[0]));
200
 
201 69 dgisselq
        initial o_wb_cyc  = 1'b0;
202
        initial o_wb_stb  = 1'b0;
203
        initial o_wb_addr = {(AW){1'b0}};
204
        initial rdaddr    = 0;
205
        always @(posedge i_clk)
206
                if ((i_rst)||(i_clear_cache))
207
                begin
208
                        o_wb_cyc <= 1'b0;
209
                        o_wb_stb <= 1'b0;
210
                end else if (o_wb_cyc)
211
                begin
212 129 dgisselq
                        if (i_wb_err)
213
                                o_wb_stb <= 1'b0;
214 176 dgisselq
                        else if ((o_wb_stb)&&(~i_wb_stall)&&(last_addr))
215
                                o_wb_stb <= 1'b0;
216 69 dgisselq
 
217 176 dgisselq
                        if (((i_wb_ack)&&(last_ack))||(i_wb_err))
218 69 dgisselq
                                o_wb_cyc <= 1'b0;
219 82 dgisselq
 
220 69 dgisselq
                        // else if (rdaddr[(PW-1):1] == {(PW-1){1'b1}})
221
                        //      tags[lastpc[(CW-1):PW]] <= lastpc[(AW-1):CW];
222
 
223 176 dgisselq
                end else if (needload)
224 69 dgisselq
                begin
225
                        o_wb_cyc  <= 1'b1;
226
                        o_wb_stb  <= 1'b1;
227
                end
228
 
229 176 dgisselq
        always @(posedge i_clk)
230
                if (o_wb_cyc) // &&(i_wb_ack)
231
                        tags[o_wb_addr[(CW-1):PW]] <= o_wb_addr[(AW-1):CW];
232
        always @(posedge i_clk)
233
                if ((o_wb_cyc)&&(i_wb_ack))
234
                        rdaddr <= rdaddr + 1;
235
                else if (~o_wb_cyc)
236
                        rdaddr <= { lastpc[(CW-1):PW], {(PW){1'b0}} };
237
 
238
        always @(posedge i_clk)
239
                if ((o_wb_stb)&&(~i_wb_stall)&&(~last_addr))
240
                        o_wb_addr[(PW-1):0] <= o_wb_addr[(PW-1):0]+1;
241
                else if (~o_wb_cyc)
242
                        o_wb_addr <= { lastpc[(AW-1):PW], {(PW){1'b0}} };
243
 
244 69 dgisselq
        // Can't initialize an array, so leave cache uninitialized
245 176 dgisselq
        // We'll also never get an ack without sys being active, so skip
246
        // that check.  Or rather, let's just use o_wb_cyc instead.  This
247
        // will work because multiple writes to the same address, ending with
248
        // a valid write, aren't a problem.
249 69 dgisselq
        always @(posedge i_clk)
250 176 dgisselq
                if (o_wb_cyc) // &&(i_wb_ack)
251 69 dgisselq
                        cache[rdaddr] <= i_wb_data;
252
 
253
        // VMask ... is a section loaded?
254 176 dgisselq
        // Note "svmask".  It's purpose is to delay the vmask setting by one
255
        // clock, so that we can insure the right value of the cache is loaded
256
        // before declaring that the cache line is valid.  Without this, the
257
        // cache line would get read, and the instruction would read from the
258
        // last cache line.
259
        reg     svmask;
260 69 dgisselq
        initial vmask = 0;
261 176 dgisselq
        initial svmask = 1'b0;
262 194 dgisselq
        reg     [(LGLINES-1):0]  saddr;
263 69 dgisselq
        always @(posedge i_clk)
264
                if ((i_rst)||(i_clear_cache))
265 176 dgisselq
                begin
266 69 dgisselq
                        vmask <= 0;
267 176 dgisselq
                        svmask<= 1'b0;
268
                end
269 118 dgisselq
                else begin
270 176 dgisselq
                        svmask <= ((o_wb_cyc)&&(i_wb_ack)&&(last_ack));
271
 
272
                        if (svmask)
273
                                vmask[saddr] <= 1'b1;
274
                        if ((~o_wb_cyc)&&(needload))
275 118 dgisselq
                                vmask[lastpc[(CW-1):PW]] <= 1'b0;
276
                end
277 176 dgisselq
        always @(posedge i_clk)
278
                if ((o_wb_cyc)&&(i_wb_ack))
279
                        saddr <= rdaddr[(CW-1):PW];
280 69 dgisselq
 
281
        initial illegal_cache = 0;
282 71 dgisselq
        initial illegal_valid = 0;
283 69 dgisselq
        always @(posedge i_clk)
284
                if ((i_rst)||(i_clear_cache))
285 71 dgisselq
                begin
286 69 dgisselq
                        illegal_cache <= 0;
287 71 dgisselq
                        illegal_valid <= 0;
288
                end else if ((o_wb_cyc)&&(i_wb_err))
289
                begin
290 129 dgisselq
                        illegal_cache <= o_wb_addr[(AW-1):PW];
291 71 dgisselq
                        illegal_valid <= 1'b1;
292
                end
293 69 dgisselq
 
294
        initial o_illegal = 1'b0;
295
        always @(posedge i_clk)
296 176 dgisselq
                if ((i_rst)||(i_clear_cache)||(o_wb_cyc))
297 71 dgisselq
                        o_illegal <= 1'b0;
298
                else
299
                        o_illegal <= (illegal_valid)
300
                                &&(illegal_cache == i_pc[(AW-1):PW]);
301 69 dgisselq
 
302
endmodule

powered by: WebSVN 2.1.0

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