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

Subversion Repositories xulalx25soc

[/] [xulalx25soc/] [trunk/] [rtl/] [cpu/] [pfcache.v] - Blame information for rev 113

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

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

powered by: WebSVN 2.1.0

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