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

Subversion Repositories openarty

[/] [openarty/] [trunk/] [rtl/] [cpu/] [fastcache.v] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 dgisselq
////////////////////////////////////////////////////////////////////////////////
2
//
3
// Filename:    fastcache.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  fastcache(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
        output  wire    [(BUSW-1):0]     o_i;
48
        output  wire    [(AW-1):0]       o_pc;
49
        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
        wire                    r_v;
68
        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
        reg     [(AW-1):CW]     tagvalipc, tagvallst;
75
        wire    [(AW-1):CW]     tagval;
76
        wire    [(AW-1):PW]     lasttag;
77
        reg                     illegal_valid;
78
        reg     [(AW-1):PW]     illegal_cache;
79
 
80
        // 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
        always @(posedge i_clk)
86
                if (~r_v)
87
                        isrc <= 1'b0;
88
                else if ((i_stall_n)||(i_new_pc))
89
                        isrc <= 1'b1;
90
        always @(posedge i_clk)
91
                r_pc_cache <= cache[i_pc[(CW-1):0]];
92
        always @(posedge i_clk)
93
                r_last_cache <= cache[lastpc[(CW-1):0]];
94
        always @(posedge i_clk)
95
                r_pc <= i_pc;
96
        always @(posedge i_clk)
97
                r_lastpc <= lastpc;
98
        assign  o_pc = (isrc) ? r_pc : r_lastpc;
99
        assign  o_i  = (isrc) ? r_pc_cache : r_last_cache;
100
 
101
        reg     tagsrc;
102
        always @(posedge i_clk)
103
                // It may be possible to recover a clock once the cache line
104
                // has been filled, but our prior attempt to do so has lead
105
                // to a race condition, so we keep this logic simple.
106
                if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
107
                        tagsrc <= 1'b1;
108
                else
109
                        tagsrc <= 1'b0;
110
        initial tagvalipc = 0;
111
        always @(posedge i_clk)
112
                tagvalipc <= tags[i_pc[(CW-1):PW]];
113
        initial tagvallst = 0;
114
        always @(posedge i_clk)
115
                tagvallst <= tags[lastpc[(CW-1):PW]];
116
        assign  tagval = (tagsrc)?tagvalipc : tagvallst;
117
 
118
        // i_pc will only increment when everything else isn't stalled, thus
119
        // we can set it without worrying about that.   Doing this enables
120
        // us to work in spite of stalls.  For example, if the next address
121
        // isn't valid, but the decoder is stalled, get the next address
122
        // anyway.
123
        initial lastpc = 0;
124
        always @(posedge i_clk)
125
                if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
126
                        lastpc <= i_pc;
127
 
128
        assign  lasttag = lastpc[(AW-1):PW];
129
        // initial      lasttag = 0;
130
        // always @(posedge i_clk)
131
                // if (((r_v)&&(i_stall_n))||(i_clear_cache)||(i_new_pc))
132
                        // lasttag <= i_pc[(AW-1):PW];
133
 
134
        wire    w_v_from_pc, w_v_from_last;
135
        assign  w_v_from_pc = ((i_pc[(AW-1):PW] == lasttag)
136
                                &&(tagvalipc == i_pc[(AW-1):CW])
137
                                &&(vmask[i_pc[(CW-1):PW]]));
138
        assign  w_v_from_last = (
139
                                //(lastpc[(AW-1):PW] == lasttag)&&
140
                                (tagvallst == lastpc[(AW-1):CW])
141
                                &&(vmask[lastpc[(CW-1):PW]]));
142
 
143
        reg     [1:0]    delay;
144
 
145
        initial delay = 2'h3;
146
        reg     rvsrc;
147
        always @(posedge i_clk)
148
                if ((i_rst)||(i_clear_cache)||(i_new_pc)||((r_v)&&(i_stall_n)))
149
                begin
150
                        // r_v <= r_v_from_pc;
151
                        rvsrc <= 1'b1;
152
                        delay <= 2'h2;
153
                end else if (~r_v) begin // Otherwise, r_v was true and we were
154
                        // stalled, hence only if ~r_v
155
                        rvsrc <= 1'b0;
156
                        if (o_wb_cyc)
157
                                delay <= 2'h2;
158
                        else if (delay != 0)
159
                                delay <= delay + 2'b11; // i.e. delay -= 1;
160
                end
161
        reg     r_v_from_pc, r_v_from_last;
162
        always @(posedge i_clk)
163
                r_v_from_pc <= w_v_from_pc;
164
        always @(posedge i_clk)
165
                r_v_from_last <= w_v_from_last;
166
 
167
        assign  r_v = ((rvsrc)?(r_v_from_pc):(r_v_from_last));
168
        assign  o_v = ((rvsrc)?(r_v_from_pc):(r_v_from_last))&&(~i_new_pc);
169
 
170
        reg     last_ack;
171
        initial last_ack <= 1'b0;
172
        always @(posedge i_clk)
173
                last_ack <= (o_wb_cyc)&&(
174
                                (rdaddr[(PW-1):1]=={(PW){1'b1}})
175
                                &&((rdaddr[0])||(i_wb_ack)));
176
 
177
        reg     needload;
178
        initial needload = 1'b0;
179
        always @(posedge i_clk)
180
                needload <= ((~r_v)&&(delay==0)
181
                        &&((tagvallst != lastpc[(AW-1):CW])
182
                                ||(~vmask[lastpc[(CW-1):PW]]))
183
                        &&((~illegal_valid)
184
                                ||(lastpc[(AW-1):PW] != illegal_cache)));
185
 
186
        reg     last_addr;
187
        initial last_addr = 1'b0;
188
        always @(posedge i_clk)
189
                last_addr <= (o_wb_cyc)&&(o_wb_addr[(PW-2):1] == {(PW-1){1'b1}})
190
                                &&((~i_wb_stall)|(o_wb_addr[0]));
191
 
192
        initial o_wb_cyc  = 1'b0;
193
        initial o_wb_stb  = 1'b0;
194
        initial o_wb_addr = {(AW){1'b0}};
195
        initial rdaddr    = 0;
196
        always @(posedge i_clk)
197
                if ((i_rst)||(i_clear_cache))
198
                begin
199
                        o_wb_cyc <= 1'b0;
200
                        o_wb_stb <= 1'b0;
201
                end else if (o_wb_cyc)
202
                begin
203
                        if (i_wb_err)
204
                                o_wb_stb <= 1'b0;
205
                        else if ((o_wb_stb)&&(~i_wb_stall)&&(last_addr))
206
                                o_wb_stb <= 1'b0;
207
 
208
                        if (((i_wb_ack)&&(last_ack))||(i_wb_err))
209
                                o_wb_cyc <= 1'b0;
210
 
211
                        // else if (rdaddr[(PW-1):1] == {(PW-1){1'b1}})
212
                        //      tags[lastpc[(CW-1):PW]] <= lastpc[(AW-1):CW];
213
 
214
                end else if (needload)
215
                begin
216
                        o_wb_cyc  <= 1'b1;
217
                        o_wb_stb  <= 1'b1;
218
                end
219
 
220
        always @(posedge i_clk)
221
                if (o_wb_cyc) // &&(i_wb_ack)
222
                        tags[o_wb_addr[(CW-1):PW]] <= o_wb_addr[(AW-1):CW];
223
        always @(posedge i_clk)
224
                if ((o_wb_cyc)&&(i_wb_ack))
225
                        rdaddr <= rdaddr + 1;
226
                else if (~o_wb_cyc)
227
                        rdaddr <= { lastpc[(CW-1):PW], {(PW){1'b0}} };
228
 
229
        always @(posedge i_clk)
230
                if ((o_wb_stb)&&(~i_wb_stall)&&(~last_addr))
231
                        o_wb_addr[(PW-1):0] <= o_wb_addr[(PW-1):0]+1;
232
                else if (~o_wb_cyc)
233
                        o_wb_addr <= { lastpc[(AW-1):PW], {(PW){1'b0}} };
234
 
235
        // Can't initialize an array, so leave cache uninitialized
236
        // We'll also never get an ack without sys being active, so skip
237
        // that check.  Or rather, let's just use o_wb_cyc instead.  This
238
        // will work because multiple writes to the same address, ending with
239
        // a valid write, aren't a problem.
240
        always @(posedge i_clk)
241
                if (o_wb_cyc) // &&(i_wb_ack)
242
                        cache[rdaddr] <= i_wb_data;
243
 
244
        // VMask ... is a section loaded?
245
        initial vmask = 0;
246
        always @(posedge i_clk)
247
                if ((i_rst)||(i_clear_cache))
248
                        vmask <= 0;
249
                else begin
250
                        if ((o_wb_cyc)&&(i_wb_ack)&&(last_ack))
251
                                vmask[rdaddr[(CW-1):PW]] <= 1'b1;
252
                        if ((~o_wb_cyc)&&(needload))
253
                                vmask[lastpc[(CW-1):PW]] <= 1'b0;
254
                end
255
 
256
        initial illegal_cache = 0;
257
        initial illegal_valid = 0;
258
        always @(posedge i_clk)
259
                if ((i_rst)||(i_clear_cache))
260
                begin
261
                        illegal_cache <= 0;
262
                        illegal_valid <= 0;
263
                end else if ((o_wb_cyc)&&(i_wb_err))
264
                begin
265
                        illegal_cache <= o_wb_addr[(AW-1):PW];
266
                        illegal_valid <= 1'b1;
267
                end
268
 
269
        initial o_illegal = 1'b0;
270
        always @(posedge i_clk)
271
                if ((i_rst)||(i_clear_cache))
272
                        o_illegal <= 1'b0;
273
                else
274
                        o_illegal <= (illegal_valid)
275
                                &&(illegal_cache == i_pc[(AW-1):PW]);
276
 
277
endmodule

powered by: WebSVN 2.1.0

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