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

Subversion Repositories openarty

[/] [openarty/] [trunk/] [rtl/] [cpu/] [pfcache.v] - Blame information for rev 60

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

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

powered by: WebSVN 2.1.0

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