filename | src/sh4/cache.c |
changeset | 971:886e1ec8447d |
prev | 968:6fb1481859a4 |
next | 975:007bf7eb944f |
author | nkeynes |
date | Thu Jan 22 02:58:13 2009 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Fix 1k-entry allocation Break asid remap into two passes for simplicity |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 * Implements the on-chip operand cache, instruction cache, and store queue.
4 *
5 * Copyright (c) 2008 Nathan Keynes.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 */
18 #define MODULE sh4_module
20 #include <string.h>
21 #include "dream.h"
22 #include "mem.h"
23 #include "mmio.h"
24 #include "clock.h"
25 #include "sh4/sh4core.h"
26 #include "sh4/sh4mmio.h"
27 #include "sh4/xltcache.h"
28 #include "sh4/mmu.h"
30 #define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)
31 #define OCRAM_MID (0x7E000000>>LXDREAM_PAGE_BITS)
32 #define OCRAM_END (0x80000000>>LXDREAM_PAGE_BITS)
34 #define CACHE_VALID 1
35 #define CACHE_DIRTY 2
37 #define ICACHE_ENTRY_COUNT 256
38 #define OCACHE_ENTRY_COUNT 512
40 struct cache_line {
41 uint32_t key; // Fast address match - bits 5..28 for valid entry, -1 for invalid entry
42 uint32_t tag; // tag + flags value from the address field
43 };
46 static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
47 struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
48 static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
49 unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
52 /*********************** General module requirements ********************/
54 void CCN_reset()
55 {
56 /* Clear everything for consistency */
57 memset( ccn_icache, 0, sizeof(ccn_icache) );
58 memset( ccn_ocache, 0, sizeof(ccn_icache) );
59 memset( ccn_icache_data, 0, sizeof(ccn_icache) );
60 memset( ccn_ocache_data, 0, sizeof(ccn_icache) );
61 }
63 void CCN_save_state( FILE *f )
64 {
65 fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
66 fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
67 fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
68 fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
69 }
71 int CCN_load_state( FILE *f )
72 {
73 /* Setup the cache mode according to the saved register value
74 * (mem_load runs before this point to load all MMIO data)
75 */
76 mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
78 if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
79 return 1;
80 }
81 if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
82 return 1;
83 }
84 if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
85 return 1;
86 }
87 if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
88 return 1;
89 }
90 return 0;
91 }
93 /************************* OCRAM memory address space ************************/
95 #define OCRAMPAGE0 (&ccn_ocache_data[4096]) /* Lines 128-255 */
96 #define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */
98 static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr )
99 {
100 return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));
101 }
102 static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )
103 {
104 return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
105 }
106 static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )
107 {
108 return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
109 }
110 static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )
111 {
112 *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;
113 }
114 static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )
115 {
116 *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;
117 }
118 static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )
119 {
120 *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;
121 }
122 static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )
123 {
124 memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );
125 }
126 static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )
127 {
128 memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );
129 }
131 struct mem_region_fn mem_region_ocram_page0 = {
132 ocram_page0_read_long, ocram_page0_write_long,
133 ocram_page0_read_word, ocram_page0_write_word,
134 ocram_page0_read_byte, ocram_page0_write_byte,
135 ocram_page0_read_burst, ocram_page0_write_burst,
136 unmapped_prefetch };
138 static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
139 {
140 return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
141 }
142 static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
143 {
144 return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
145 }
146 static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
147 {
148 return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
149 }
150 static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
151 {
152 *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
153 }
154 static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
155 {
156 *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
157 }
158 static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
159 {
160 *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
161 }
162 static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
163 {
164 memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
165 }
166 static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
167 {
168 memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
169 }
171 struct mem_region_fn mem_region_ocram_page1 = {
172 ocram_page1_read_long, ocram_page1_write_long,
173 ocram_page1_read_word, ocram_page1_write_word,
174 ocram_page1_read_byte, ocram_page1_write_byte,
175 ocram_page1_read_burst, ocram_page1_write_burst,
176 unmapped_prefetch };
178 /**************************** Cache functions ********************************/
179 char ccn_cache_map[16 MB]; // 24 bits of address space
181 /**
182 * Load a 32-byte cache line from external memory at the given ext address.
183 * @param addr external address pre-masked to 1FFFFFFE0
184 */
185 sh4addr_t FASTCALL ccn_ocache_load_line( sh4addr_t addr )
186 {
187 int entry = addr & 0x00003FE0;
188 struct cache_line *line = &ccn_ocache[entry>>5];
189 char *cache_data = &ccn_ocache_data[entry];
190 sh4addr_t old_addr = line->tag;
191 line->tag = addr & 0x1FFFFFE0;
192 char oldstate = ccn_cache_map[old_addr>>5];
193 ccn_cache_map[old_addr>>5] = 0;
194 ccn_cache_map[addr>>5] = CACHE_VALID;
195 if( oldstate == (CACHE_VALID|CACHE_DIRTY) ) {
196 // Cache line is dirty - writeback.
197 ext_address_space[old_addr>>12]->write_burst(old_addr, cache_data);
198 }
199 ext_address_space[addr>>12]->read_burst(cache_data, addr & 0x1FFFFFE0);
200 return addr;
201 }
203 /* Long read through the operand cache */
204 /*
205 int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr );
206 int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr );
207 int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr );
208 void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t val );
209 void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t val );
210 void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t val );
212 */
213 static int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr )
214 {
215 addr &= 0x1FFFFFFF;
216 if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
217 ccn_ocache_load_line(addr);
218 }
219 return *(int32_t *)&ccn_ocache_data[addr & 0x3FFF];
220 }
222 static int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr )
223 {
224 addr &= 0x1FFFFFFF;
225 if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
226 ccn_ocache_load_line(addr);
227 }
228 return SIGNEXT16(*(int16_t *)&ccn_ocache_data[addr&0x3FFF]);
229 }
231 static int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr )
232 {
233 addr &= 0x1FFFFFFF;
234 if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
235 ccn_ocache_load_line(addr);
236 }
237 return SIGNEXT8(ccn_ocache_data[addr&0x3FFF]);
238 }
240 static void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t value )
241 {
242 addr &= 0x1FFFFFFF;
243 if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
244 ccn_ocache_load_line(addr);
245 }
246 ccn_cache_map[addr>>5] |= CACHE_DIRTY;
247 *(uint32_t *)&ccn_ocache_data[addr&0x3FFF] = value;
248 }
250 static void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t value )
251 {
252 addr &= 0x1FFFFFFF;
253 if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
254 ccn_ocache_load_line(addr);
255 }
256 ccn_cache_map[addr>>5] |= CACHE_DIRTY;
257 *(uint16_t *)&ccn_ocache_data[addr&0x3FFF] = (uint16_t)value;
258 }
260 static void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t value )
261 {
262 addr &= 0x1FFFFFFF;
263 if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
264 ccn_ocache_load_line(addr);
265 }
266 ccn_cache_map[addr>>5] |= CACHE_DIRTY;
267 ccn_ocache_data[addr&0x3FFF] = (uint8_t)value;
268 }
270 static void FASTCALL ccn_ocache_prefetch( sh4addr_t addr )
271 {
272 addr &= 0x1FFFFFFF;
273 if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
274 ccn_ocache_load_line(addr);
275 }
276 }
278 void FASTCALL ccn_ocache_invalidate( sh4addr_t addr )
279 {
280 addr &= 0x1FFFFFFF;
281 ccn_cache_map[addr>>5] &= ~CACHE_VALID;
282 }
284 void FASTCALL ccn_ocache_purge( sh4addr_t addr )
285 {
286 addr &= 0x1FFFFFE0;
287 int oldflags = ccn_cache_map[addr>>5];
288 ccn_cache_map[addr>>5] &= ~CACHE_VALID;
289 if( oldflags == (CACHE_VALID|CACHE_DIRTY) ) {
290 char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
291 ext_address_space[addr>>12]->write_burst(addr, cache_data);
292 }
293 }
295 void FASTCALL ccn_ocache_writeback( sh4addr_t addr )
296 {
297 addr &= 0x1FFFFFE0;
298 if( ccn_cache_map[addr>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
299 ccn_cache_map[addr>>5] &= ~CACHE_DIRTY;
300 char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
301 ext_address_space[addr>>12]->write_burst(addr, cache_data);
302 }
303 }
305 struct mem_region_fn ccn_ocache_cb_region = {
306 ccn_ocache_read_long, ccn_ocache_write_long_copyback,
307 ccn_ocache_read_word, ccn_ocache_write_word_copyback,
308 ccn_ocache_read_byte, ccn_ocache_write_byte_copyback,
309 unmapped_read_burst, unmapped_write_burst,
310 ccn_ocache_prefetch };
313 /************************** Cache direct access ******************************/
315 static int32_t FASTCALL ccn_icache_addr_read( sh4addr_t addr )
316 {
317 int entry = (addr & 0x00001FE0);
318 return ccn_icache[entry>>5].tag;
319 }
321 static void FASTCALL ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
322 {
323 int entry = (addr & 0x00003FE0);
324 struct cache_line *line = &ccn_ocache[entry>>5];
325 if( addr & 0x08 ) { // Associative
326 /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
327 } else {
328 line->tag = val & 0x1FFFFC01;
329 line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
330 }
331 }
333 struct mem_region_fn p4_region_icache_addr = {
334 ccn_icache_addr_read, ccn_icache_addr_write,
335 unmapped_read_long, unmapped_write_long,
336 unmapped_read_long, unmapped_write_long,
337 unmapped_read_burst, unmapped_write_burst,
338 unmapped_prefetch };
341 static int32_t FASTCALL ccn_icache_data_read( sh4addr_t addr )
342 {
343 int entry = (addr & 0x00001FFC);
344 return *(uint32_t *)&ccn_icache_data[entry];
345 }
347 static void FASTCALL ccn_icache_data_write( sh4addr_t addr, uint32_t val )
348 {
349 int entry = (addr & 0x00001FFC);
350 *(uint32_t *)&ccn_icache_data[entry] = val;
351 }
353 struct mem_region_fn p4_region_icache_data = {
354 ccn_icache_data_read, ccn_icache_data_write,
355 unmapped_read_long, unmapped_write_long,
356 unmapped_read_long, unmapped_write_long,
357 unmapped_read_burst, unmapped_write_burst,
358 unmapped_prefetch };
360 static int32_t FASTCALL ccn_ocache_addr_read( sh4addr_t addr )
361 {
362 int entry = (addr & 0x00003FE0);
363 sh4addr_t tag = ccn_ocache[entry>>5].tag;
364 return (tag&0x1FFFFC00) | ccn_cache_map[tag>>5];
365 }
367 static void FASTCALL ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
368 {
369 int entry = (addr & 0x00003FE0);
370 struct cache_line *line = &ccn_ocache[entry>>5];
371 if( addr & 0x08 ) { // Associative
372 } else {
373 sh4addr_t tag = line->tag;
374 if( ccn_cache_map[tag>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
375 // Cache line is dirty - writeback.
376 unsigned char *cache_data = &ccn_ocache_data[entry];
377 ext_address_space[tag>>12]->write_burst(tag, cache_data);
378 }
379 line->tag = tag = (val & 0x1FFFFC00) | (addr & 0x3E0);
380 ccn_cache_map[tag>>5] = val & 0x03;
381 }
382 }
384 struct mem_region_fn p4_region_ocache_addr = {
385 ccn_ocache_addr_read, ccn_ocache_addr_write,
386 unmapped_read_long, unmapped_write_long,
387 unmapped_read_long, unmapped_write_long,
388 unmapped_read_burst, unmapped_write_burst,
389 unmapped_prefetch };
392 static int32_t FASTCALL ccn_ocache_data_read( sh4addr_t addr )
393 {
394 int entry = (addr & 0x00003FFC);
395 return *(uint32_t *)&ccn_ocache_data[entry];
396 }
398 static void FASTCALL ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
399 {
400 int entry = (addr & 0x00003FFC);
401 *(uint32_t *)&ccn_ocache_data[entry] = val;
402 }
404 struct mem_region_fn p4_region_ocache_data = {
405 ccn_ocache_data_read, ccn_ocache_data_write,
406 unmapped_read_long, unmapped_write_long,
407 unmapped_read_long, unmapped_write_long,
408 unmapped_read_burst, unmapped_write_burst,
409 unmapped_prefetch };
412 /****************** Cache control *********************/
414 void CCN_set_cache_control( int reg )
415 {
416 uint32_t i;
418 if( reg & CCR_ICI ) { /* icache invalidate */
419 for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
420 ccn_icache[i].key = -1;
421 ccn_icache[i].tag &= ~CACHE_VALID;
422 }
423 }
425 if( reg & CCR_OCI ) { /* ocache invalidate */
426 for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
427 ccn_icache[i].key = -1;
428 ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
429 }
430 }
432 switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
433 case MEM_OC_INDEX0: /* OIX=0 */
434 for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
435 sh4_address_space[i] = &mem_region_ocram_page0;
436 sh4_address_space[i+1] = &mem_region_ocram_page0;
437 sh4_address_space[i+2] = &mem_region_ocram_page1;
438 sh4_address_space[i+3] = &mem_region_ocram_page1;
439 }
440 break;
441 case MEM_OC_INDEX1: /* OIX=1 */
442 for( i=OCRAM_START; i<OCRAM_MID; i++ )
443 sh4_address_space[i] = &mem_region_ocram_page0;
444 for( i=OCRAM_MID; i<OCRAM_END; i++ )
445 sh4_address_space[i] = &mem_region_ocram_page1;
446 break;
447 default: /* disabled */
448 for( i=OCRAM_START; i<OCRAM_END; i++ )
449 sh4_address_space[i] = &mem_region_unmapped;
450 break;
451 }
452 }
454 /**
455 * Prefetch for non-storequeue regions
456 */
457 void FASTCALL ccn_prefetch( sh4addr_t addr )
458 {
460 }
462 /************************** Uncached memory access ***************************/
463 int32_t FASTCALL ccn_uncached_read_long( sh4addr_t addr )
464 {
465 sh4r.slice_cycle += (4*sh4_bus_period);
466 addr &= 0x1FFFFFFF;
467 return ext_address_space[addr>>12]->read_long(addr);
468 }
469 int32_t FASTCALL ccn_uncached_read_word( sh4addr_t addr )
470 {
471 sh4r.slice_cycle += (4*sh4_bus_period);
472 addr &= 0x1FFFFFFF;
473 return ext_address_space[addr>>12]->read_word(addr);
474 }
475 int32_t FASTCALL ccn_uncached_read_byte( sh4addr_t addr )
476 {
477 sh4r.slice_cycle += (4*sh4_bus_period);
478 addr &= 0x1FFFFFFF;
479 return ext_address_space[addr>>12]->read_byte(addr);
480 }
481 void FASTCALL ccn_uncached_write_long( sh4addr_t addr, uint32_t val )
482 {
483 sh4r.slice_cycle += (4*sh4_bus_period);
484 addr &= 0x1FFFFFFF;
485 return ext_address_space[addr>>12]->write_long(addr, val);
486 }
487 void FASTCALL ccn_uncached_write_word( sh4addr_t addr, uint32_t val )
488 {
489 sh4r.slice_cycle += (4*sh4_bus_period);
490 addr &= 0x1FFFFFFF;
491 return ext_address_space[addr>>12]->write_word(addr, val);
492 }
493 void FASTCALL ccn_uncached_write_byte( sh4addr_t addr, uint32_t val )
494 {
495 sh4r.slice_cycle += (4*sh4_bus_period);
496 addr &= 0x1FFFFFFF;
497 return ext_address_space[addr>>12]->write_byte(addr, val);
498 }
499 void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )
500 {
501 }
503 struct mem_region_fn ccn_uncached_region = {
504 ccn_uncached_read_long, ccn_uncached_write_long,
505 ccn_uncached_read_word, ccn_uncached_write_word,
506 ccn_uncached_read_byte, ccn_uncached_write_byte,
507 unmapped_read_burst, unmapped_write_burst,
508 ccn_uncached_prefetch };
511 /********************************* Store-queue *******************************/
512 /*
513 * The storequeue is strictly speaking part of the cache, but most of
514 * the complexity is actually around its addressing (ie in the MMU). The
515 * methods here can assume we've already passed SQMD protection and the TLB
516 * lookups (where appropriate).
517 */
518 void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val )
519 {
520 sh4r.store_queue[(addr>>2)&0xF] = val;
521 }
522 int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr )
523 {
524 return sh4r.store_queue[(addr>>2)&0xF];
525 }
527 /**
528 * Variant used when tlb is disabled - address will be the original prefetch
529 * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't
530 * be hardcoded on 4K page boundaries, so we manually decode it here.
531 */
532 void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr )
533 {
534 int queue = (addr&0x20)>>2;
535 sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
536 uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24;
537 sh4addr_t target = (addr&0x03FFFFE0) | hi;
538 ext_address_space[target>>12]->write_burst( target, src );
539 }
541 /**
542 * Variant used when tlb is enabled - address in this case is already
543 * mapped to the external target address.
544 */
545 void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr )
546 {
547 int queue = (addr&0x20)>>2;
548 sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
549 ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );
550 }
.