1 |
9 |
ns32kum |
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
2 |
|
|
//
|
3 |
|
|
// This file is part of the M32632 project
|
4 |
|
|
// http://opencores.org/project,m32632
|
5 |
|
|
//
|
6 |
|
|
// Filename: ICACHE_SM.v
|
7 |
|
|
// Version: 1.0
|
8 |
|
|
// Date: 30 May 2015
|
9 |
|
|
//
|
10 |
|
|
// Copyright (C) 2015 Udo Moeller
|
11 |
|
|
//
|
12 |
|
|
// This source file may be used and distributed without
|
13 |
|
|
// restriction provided that this copyright statement is not
|
14 |
|
|
// removed from the file and that any derivative work contains
|
15 |
|
|
// the original copyright notice and the associated disclaimer.
|
16 |
|
|
//
|
17 |
|
|
// This source file is free software; you can redistribute it
|
18 |
|
|
// and/or modify it under the terms of the GNU Lesser General
|
19 |
|
|
// Public License as published by the Free Software Foundation;
|
20 |
|
|
// either version 2.1 of the License, or (at your option) any
|
21 |
|
|
// later version.
|
22 |
|
|
//
|
23 |
|
|
// This source is distributed in the hope that it will be
|
24 |
|
|
// useful, but WITHOUT ANY WARRANTY; without even the implied
|
25 |
|
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
26 |
|
|
// PURPOSE. See the GNU Lesser General Public License for more
|
27 |
|
|
// details.
|
28 |
|
|
//
|
29 |
|
|
// You should have received a copy of the GNU Lesser General
|
30 |
|
|
// Public License along with this source; if not, download it
|
31 |
|
|
// from http://www.opencores.org/lgpl.shtml
|
32 |
|
|
//
|
33 |
|
|
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
34 |
|
|
//
|
35 |
|
|
// Modules contained in this file:
|
36 |
|
|
// 1. KOLDETECT Collision Detection Unit
|
37 |
|
|
// 2. ICACHE_SM Instruction Cache State Machine
|
38 |
|
|
//
|
39 |
11 |
ns32kum |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
40 |
9 |
ns32kum |
|
41 |
11 |
ns32kum |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
42 |
9 |
ns32kum |
//
|
43 |
|
|
// 1. KOLDETECT Collision Detection Unit
|
44 |
|
|
//
|
45 |
11 |
ns32kum |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
46 |
|
|
module KOLDETECT ( BCLK, BRESET, DRAM_WR, CVALID, ADDR, TAG0, TAG1 , CFG , C_VALID, READ_I, ACC_OK, HOLD, KDET, INVAL_A, ENA_HK,
|
47 |
9 |
ns32kum |
NEWCVAL, KOLLISION, STOP_ICRD, RUN_ICRD, KILL, KILLADR, ICTODC, STOP_CINV );
|
48 |
|
|
|
49 |
|
|
input BCLK;
|
50 |
|
|
input BRESET;
|
51 |
|
|
input DRAM_WR;
|
52 |
|
|
input [23:0] CVALID; // Data from master Valid RAM
|
53 |
|
|
input [27:4] ADDR;
|
54 |
|
|
input [27:12] TAG0,TAG1;
|
55 |
|
|
input [1:0] CFG;
|
56 |
|
|
input [23:0] C_VALID; // Data from secondary Valid RAM
|
57 |
|
|
input READ_I;
|
58 |
|
|
input ACC_OK;
|
59 |
|
|
input HOLD; // active low
|
60 |
|
|
input KDET;
|
61 |
|
|
input INVAL_A; // Cache Invalidate All
|
62 |
|
|
input ENA_HK; // Enable HOLD and Kohaerenz
|
63 |
|
|
|
64 |
|
|
output [23:0] NEWCVAL;
|
65 |
|
|
output KOLLISION;
|
66 |
|
|
output STOP_ICRD;
|
67 |
|
|
output RUN_ICRD;
|
68 |
|
|
output KILL;
|
69 |
|
|
output [11:7] KILLADR;
|
70 |
|
|
output [2:0] ICTODC;
|
71 |
|
|
output STOP_CINV;
|
72 |
|
|
|
73 |
|
|
reg [27:4] addr_r;
|
74 |
|
|
reg [7:0] maske,clear;
|
75 |
|
|
reg do_koll;
|
76 |
|
|
reg [2:0] counter;
|
77 |
|
|
reg [1:0] wpointer,rpointer;
|
78 |
|
|
reg [35:0] adrfifo;
|
79 |
|
|
reg [8:0] fifo_q,fifo_c;
|
80 |
|
|
reg [1:0] state;
|
81 |
|
|
reg pipe;
|
82 |
|
|
reg do_kill;
|
83 |
|
|
reg dma;
|
84 |
|
|
|
85 |
|
|
wire [7:0] set_0,set_1;
|
86 |
|
|
wire match_0,match_1;
|
87 |
|
|
wire valid_0,valid_1;
|
88 |
|
|
wire found_0,found_1;
|
89 |
|
|
wire kolli,dma_kolli;
|
90 |
|
|
wire last_match;
|
91 |
|
|
wire wr_entry;
|
92 |
|
|
wire [23:0] cdaten;
|
93 |
|
|
wire [8:0] kaddr;
|
94 |
|
|
wire [7:0] new_0,new_1;
|
95 |
|
|
wire dma_mode,ic_dma;
|
96 |
|
|
wire free,ende;
|
97 |
|
|
wire init_b;
|
98 |
|
|
|
99 |
11 |
ns32kum |
always @(posedge BCLK) do_koll <= DRAM_WR & CFG[0]; // one cycle pulse, without Cache Enable no collision
|
100 |
9 |
ns32kum |
always @(posedge BCLK) addr_r <= ADDR;
|
101 |
|
|
|
102 |
|
|
// similar logic like in CA_MATCH
|
103 |
|
|
|
104 |
|
|
assign set_0 = C_VALID[7:0];
|
105 |
|
|
assign set_1 = C_VALID[15:8];
|
106 |
|
|
|
107 |
|
|
assign valid_0 = set_0[addr_r[6:4]];
|
108 |
|
|
assign valid_1 = set_1[addr_r[6:4]];
|
109 |
|
|
|
110 |
|
|
assign match_0 = ( TAG0 == addr_r[27:12] ); // 4KB
|
111 |
|
|
assign match_1 = ( TAG1 == addr_r[27:12] ); // 4KB
|
112 |
|
|
|
113 |
|
|
assign found_0 = valid_0 & match_0;
|
114 |
|
|
assign found_1 = valid_1 & match_1;
|
115 |
|
|
|
116 |
|
|
assign kolli = (found_0 | found_1) & ~CFG[1] & do_koll; // Action only if ICACHE is not locked
|
117 |
|
|
|
118 |
|
|
assign KOLLISION = (found_0 | found_1) & do_koll; // to Statistik Modul, Register there
|
119 |
|
|
|
120 |
|
|
assign dma_kolli = (found_0 | found_1) & ~CFG[1] & CFG[0];
|
121 |
|
|
|
122 |
|
|
// the FIFO with 4 entries :
|
123 |
|
|
assign init_b = CFG[0] & ~INVAL_A; // initialise if CINV A too
|
124 |
|
|
|
125 |
|
|
always @(posedge BCLK)
|
126 |
|
|
if (!init_b) wpointer <= 2'b00;
|
127 |
|
|
else
|
128 |
|
|
wpointer <= wpointer + {1'b0,wr_entry};
|
129 |
|
|
|
130 |
|
|
always @(posedge BCLK)
|
131 |
|
|
if (!init_b) rpointer <= 2'b00;
|
132 |
|
|
else
|
133 |
|
|
rpointer <= rpointer + {1'b0,do_kill};
|
134 |
|
|
|
135 |
|
|
always @(posedge BCLK)
|
136 |
|
|
begin
|
137 |
|
|
if (wr_entry && (wpointer == 2'b00)) adrfifo[8:0] <= {addr_r[11:4],found_1};
|
138 |
|
|
if (wr_entry && (wpointer == 2'b01)) adrfifo[17:9] <= {addr_r[11:4],found_1};
|
139 |
|
|
if (wr_entry && (wpointer == 2'b10)) adrfifo[26:18] <= {addr_r[11:4],found_1};
|
140 |
|
|
if (wr_entry && (wpointer == 2'b11)) adrfifo[35:27] <= {addr_r[11:4],found_1};
|
141 |
|
|
end
|
142 |
|
|
|
143 |
|
|
always @(adrfifo or rpointer)
|
144 |
|
|
case (rpointer)
|
145 |
|
|
2'b00 : fifo_q = adrfifo[8:0];
|
146 |
|
|
2'b01 : fifo_q = adrfifo[17:9];
|
147 |
|
|
2'b10 : fifo_q = adrfifo[26:18];
|
148 |
|
|
2'b11 : fifo_q = adrfifo[35:27];
|
149 |
|
|
endcase
|
150 |
|
|
|
151 |
|
|
always @(adrfifo or wpointer) // for Match of last entry use wpointer
|
152 |
|
|
case (wpointer)
|
153 |
|
|
2'b01 : fifo_c = adrfifo[8:0];
|
154 |
|
|
2'b10 : fifo_c = adrfifo[17:9];
|
155 |
|
|
2'b11 : fifo_c = adrfifo[26:18];
|
156 |
|
|
2'b00 : fifo_c = adrfifo[35:27];
|
157 |
|
|
endcase
|
158 |
|
|
|
159 |
|
|
// Control
|
160 |
|
|
|
161 |
11 |
ns32kum |
assign last_match = counter[2] & (fifo_c == {addr_r[11:4],found_1}); // if Match with last Entry no new Entry
|
162 |
9 |
ns32kum |
|
163 |
|
|
assign wr_entry = kolli & ~last_match;
|
164 |
|
|
|
165 |
|
|
always @(posedge BCLK)
|
166 |
|
|
casex ({init_b,wr_entry,do_kill,counter})
|
167 |
|
|
6'b0_xx_xxx : counter <= 3'b000;
|
168 |
|
|
6'b1_00_xxx : counter <= counter;
|
169 |
|
|
6'b1_11_xxx : counter <= counter;
|
170 |
|
|
6'b1_10_000 : counter <= 3'b100;
|
171 |
11 |
ns32kum |
6'b1_10_1xx : counter <= (counter[1:0] == 2'b11) ? 3'b111 : {counter[2],(counter[1:0] + 2'b01)}; // Overflow avoid
|
172 |
9 |
ns32kum |
6'b1_01_1xx : counter <= (counter[1:0] == 2'b00) ? 3'b000 : {counter[2],(counter[1:0] + 2'b11)};
|
173 |
|
|
default : counter <= counter;
|
174 |
|
|
endcase
|
175 |
|
|
|
176 |
|
|
// DMA Access
|
177 |
|
|
always @(posedge BCLK) dma <= ~HOLD; // there is only one FF for this , from here to DCACHE
|
178 |
|
|
|
179 |
|
|
// Controlling of ICACHE
|
180 |
|
|
|
181 |
|
|
assign free = (~READ_I | ACC_OK) & ENA_HK; // switch off if CINV
|
182 |
|
|
|
183 |
|
|
always @(posedge BCLK) // state[1] state[0]
|
184 |
|
|
casex ({BRESET,dma,counter[2],free,ende,STOP_ICRD,dma_mode})
|
185 |
|
|
7'b0_xx_xx_xx : state <= 2'b00;
|
186 |
|
|
7'b1_00_xx_00 : state <= 2'b00;
|
187 |
|
|
7'b1_01_1x_00 : state <= 2'b10; // Start of DCACHE Kohaerenz
|
188 |
|
|
7'b1_1x_1x_00 : state <= 2'b11; // Start of DMA
|
189 |
|
|
//
|
190 |
|
|
7'b1_xx_x0_10 : state <= 2'b10; // without "ende" it stays as is
|
191 |
|
|
7'b1_0x_x1_10 : state <= 2'b00; // DMA is not active
|
192 |
|
|
7'b1_1x_x1_10 : state <= 2'b11; // to DMA !
|
193 |
|
|
//
|
194 |
|
|
7'b1_00_xx_11 : state <= 2'b00;
|
195 |
|
|
7'b1_01_xx_11 : state <= 2'b10;
|
196 |
|
|
7'b1_1x_xx_11 : state <= 2'b11;
|
197 |
|
|
default : state <= 2'b00;
|
198 |
|
|
endcase
|
199 |
|
|
|
200 |
|
|
assign STOP_ICRD = state[1]; // used for Multiplexer
|
201 |
|
|
assign dma_mode = state[0]; // internal Multiplexer
|
202 |
|
|
|
203 |
|
|
assign STOP_CINV = state[1] & ~ENA_HK; // stops CINV if DMA access or Kohaerenz access
|
204 |
|
|
|
205 |
|
|
assign ende = (counter[1:0] == 2'b00) & do_kill;
|
206 |
|
|
|
207 |
|
|
assign ic_dma = STOP_ICRD & dma_mode; // Signal to DCACHE that ICACHE has stoped
|
208 |
|
|
|
209 |
|
|
always @(posedge BCLK) pipe <= STOP_ICRD;
|
210 |
|
|
|
211 |
|
|
assign RUN_ICRD = ~(STOP_ICRD | pipe); // Release for IC_READ
|
212 |
|
|
|
213 |
11 |
ns32kum |
always @(posedge BCLK) do_kill <= STOP_ICRD & ~dma_mode & ~do_kill; // Write pulse in Cache Valid RAM, 1 cycle on, 1 cycle off
|
214 |
9 |
ns32kum |
|
215 |
|
|
assign KILL = do_kill | (KDET & dma_kolli);
|
216 |
|
|
|
217 |
|
|
// Valid Daten prepare : different sources for DMA and DCACHE Kohaerenz
|
218 |
|
|
|
219 |
|
|
assign cdaten = dma_mode ? C_VALID : CVALID;
|
220 |
|
|
assign kaddr = dma_mode ? {addr_r[11:4],found_1} : fifo_q;
|
221 |
|
|
|
222 |
|
|
assign KILLADR = kaddr[8:4];
|
223 |
|
|
|
224 |
|
|
always @(kaddr)
|
225 |
|
|
case (kaddr[3:1])
|
226 |
|
|
3'h0 : clear = 8'hFE;
|
227 |
|
|
3'h1 : clear = 8'hFD;
|
228 |
|
|
3'h2 : clear = 8'hFB;
|
229 |
|
|
3'h3 : clear = 8'hF7;
|
230 |
|
|
3'h4 : clear = 8'hEF;
|
231 |
|
|
3'h5 : clear = 8'hDF;
|
232 |
|
|
3'h6 : clear = 8'hBF;
|
233 |
|
|
3'h7 : clear = 8'h7F;
|
234 |
|
|
endcase
|
235 |
|
|
|
236 |
|
|
assign new_0 = kaddr[0] ? cdaten[7:0] : (cdaten[7:0] & clear);
|
237 |
|
|
assign new_1 = kaddr[0] ? (cdaten[15:8] & clear) : cdaten[15:8];
|
238 |
|
|
|
239 |
|
|
assign NEWCVAL = {cdaten[23:16],new_1,new_0};
|
240 |
|
|
|
241 |
|
|
// multiple signals are needed in DCACHE :
|
242 |
|
|
assign ICTODC = {dma,ic_dma,~(counter[2:1] == 2'b11)};
|
243 |
|
|
|
244 |
|
|
endmodule
|
245 |
|
|
|
246 |
11 |
ns32kum |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
247 |
9 |
ns32kum |
//
|
248 |
|
|
// 2. ICACHE_SM Instruction Cache State Machine
|
249 |
|
|
//
|
250 |
11 |
ns32kum |
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
251 |
9 |
ns32kum |
module ICACHE_SM ( BCLK, BRESET, IO_SPACE, MDONE, IO_READY, MMU_HIT, CA_HIT, READ, PTE_ACC,
|
252 |
|
|
USE_CA, PTB_WR, PTB_SEL, USER, PROT_ERROR,
|
253 |
|
|
DRAM_ACC, IO_RD, IO_ACC, IC_PREQ, ACC_OK, HIT_ALL, CUPDATE, AUX_DAT, NEW_PTB, PTB_ONE );
|
254 |
|
|
|
255 |
|
|
input BCLK;
|
256 |
|
|
input BRESET;
|
257 |
|
|
input IO_SPACE;
|
258 |
|
|
input MDONE; // Memory Done : Feedback from DRAM Controller, BCLK aligned
|
259 |
|
|
input IO_READY;
|
260 |
|
|
input MMU_HIT,CA_HIT;
|
261 |
|
|
input READ;
|
262 |
|
|
input PTE_ACC;
|
263 |
|
|
input USE_CA;
|
264 |
|
|
input PTB_WR,PTB_SEL;
|
265 |
|
|
input USER;
|
266 |
|
|
input PROT_ERROR;
|
267 |
|
|
|
268 |
|
|
output reg DRAM_ACC,IO_RD;
|
269 |
|
|
output IO_ACC;
|
270 |
|
|
output IC_PREQ;
|
271 |
|
|
output ACC_OK;
|
272 |
|
|
output HIT_ALL;
|
273 |
|
|
output CUPDATE;
|
274 |
|
|
output AUX_DAT;
|
275 |
|
|
output reg NEW_PTB,PTB_ONE;
|
276 |
|
|
|
277 |
|
|
reg [3:0] new_state;
|
278 |
|
|
reg rd_done;
|
279 |
|
|
reg card_flag;
|
280 |
|
|
reg rd_rdy;
|
281 |
|
|
|
282 |
|
|
wire io_busy;
|
283 |
|
|
wire dram_go;
|
284 |
|
|
wire rd_ende;
|
285 |
|
|
wire do_ca_rd;
|
286 |
|
|
|
287 |
|
|
// Cycle : /-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_/-\_
|
288 |
|
|
// Access : _/-----------------------------------\__
|
289 |
|
|
// State Machine : ____/----------------------------\______
|
290 |
|
|
// Busy status ...
|
291 |
|
|
|
292 |
|
|
assign rd_ende = CA_HIT | rd_rdy; // CA_HIT only if Cache activ !
|
293 |
|
|
|
294 |
|
|
always @( READ // only READ , global control
|
295 |
|
|
or PROT_ERROR // is not allowed !
|
296 |
|
|
//
|
297 |
|
|
or IO_SPACE // indicates access in the IO_WELT
|
298 |
|
|
or io_busy // is already active ?
|
299 |
|
|
//
|
300 |
|
|
or MMU_HIT // Hit in the MMU , now only a READ can be active
|
301 |
|
|
or rd_ende // Cache Hit
|
302 |
|
|
or DRAM_ACC // DRAM Access running
|
303 |
|
|
//
|
304 |
|
|
or PTE_ACC ) // PTE Access running
|
305 |
|
|
// #_# #_# #_#
|
306 |
|
|
casex ({READ,PROT_ERROR,IO_SPACE,io_busy,MMU_HIT,rd_ende,DRAM_ACC,PTE_ACC})
|
307 |
|
|
// MMU Miss : PTE load from memory
|
308 |
|
|
8'b10_xx_0xx_0 : new_state = 4'b0100; // start PTE access
|
309 |
|
|
// IO-Address selected : external access starts if not already BUSY
|
310 |
|
|
8'b10_10_1xx_x : new_state = 4'b0001;
|
311 |
|
|
// DRAM Access : Cache Miss at READ
|
312 |
|
|
8'b10_0x_100_x : new_state = 4'b1010; // can start directly
|
313 |
|
|
default : new_state = 4'b0;
|
314 |
|
|
endcase
|
315 |
|
|
|
316 |
|
|
assign IO_ACC = new_state[0]; // to load the Register for Data and Addr
|
317 |
|
|
assign dram_go = new_state[1];
|
318 |
|
|
assign IC_PREQ = new_state[2]; // MMU to DCACHE !
|
319 |
|
|
assign do_ca_rd = new_state[3];
|
320 |
|
|
|
321 |
|
|
assign HIT_ALL = MMU_HIT & CA_HIT; // for Update "Last-Set" , MMU_HIT contains ZUGRIFF
|
322 |
|
|
|
323 |
|
|
always @(posedge BCLK or negedge BRESET)
|
324 |
|
|
if (!BRESET) card_flag <= 1'b0;
|
325 |
|
|
else card_flag <= (do_ca_rd & ~rd_rdy) | (card_flag & ~MDONE);
|
326 |
|
|
|
327 |
|
|
assign CUPDATE = card_flag & USE_CA & MDONE; // USE_CA = ~CI & ~LDC;
|
328 |
|
|
|
329 |
|
|
always @(posedge BCLK) rd_rdy <= card_flag & MDONE;
|
330 |
|
|
|
331 |
11 |
ns32kum |
// The cache RAM can not provide fast enough the data after an Update. In this case a secondary data path is activated
|
332 |
9 |
ns32kum |
assign AUX_DAT = rd_rdy;
|
333 |
|
|
|
334 |
|
|
// DRAM Interface :
|
335 |
|
|
|
336 |
|
|
always @(posedge BCLK) if (dram_go) DRAM_ACC <= 1'b1;
|
337 |
|
|
else
|
338 |
|
|
DRAM_ACC <= DRAM_ACC & ~MDONE & BRESET;
|
339 |
|
|
// IO Interface :
|
340 |
|
|
|
341 |
|
|
always @(posedge BCLK)
|
342 |
|
|
begin
|
343 |
|
|
if (IO_ACC) IO_RD <= READ; else IO_RD <= IO_RD & ~IO_READY & BRESET;
|
344 |
|
|
end
|
345 |
|
|
|
346 |
11 |
ns32kum |
assign io_busy = IO_RD | rd_done; // access is gone in next clock cycle, therefore blocked with "rd_done"
|
347 |
9 |
ns32kum |
|
348 |
11 |
ns32kum |
always @(posedge BCLK) rd_done <= READ & IO_READY; // For READ one clock later for data to come through
|
349 |
9 |
ns32kum |
|
350 |
|
|
// global feedback to opcode fetch unit : you can continue
|
351 |
|
|
|
352 |
|
|
assign ACC_OK = IO_SPACE ? rd_done : (READ & MMU_HIT & rd_ende);
|
353 |
|
|
|
354 |
|
|
// PTB1 und PTB0
|
355 |
|
|
|
356 |
|
|
always @(posedge BCLK) NEW_PTB <= PTB_WR; // to MMU Update Block
|
357 |
|
|
always @(posedge BCLK) if (PTB_WR) PTB_ONE <= PTB_SEL;
|
358 |
|
|
|
359 |
|
|
endmodule
|