filename | src/sh4/cache.c |
changeset | 946:d41ee7994db7 |
prev | 939:6f2302afeb89 |
next | 1067:d3c00ffccfcd |
author | nkeynes |
date | Tue Jan 06 01:58:08 2009 +0000 (14 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | Fully integrate SQ with the new address space code - added additional 'prefetch' memory accessor. TLB is utterly untested, but non-TLB at least still works. |
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 "sh4/sh4core.h"
25 #include "sh4/sh4mmio.h"
26 #include "sh4/xltcache.h"
27 #include "sh4/mmu.h"
29 #define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)
30 #define OCRAM_MID (0x7E000000>>LXDREAM_PAGE_BITS)
31 #define OCRAM_END (0x80000000>>LXDREAM_PAGE_BITS)
33 #define CACHE_VALID 1
34 #define CACHE_DIRTY 2
36 #define ICACHE_ENTRY_COUNT 256
37 #define OCACHE_ENTRY_COUNT 512
39 struct cache_line {
40 uint32_t key; // Fast address match - bits 5..28 for valid entry, -1 for invalid entry
41 uint32_t tag; // tag + flags value from the address field
42 };
45 static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
46 static struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
47 static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
48 static unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
51 /*********************** General module requirements ********************/
53 void CCN_save_state( FILE *f )
54 {
55 fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
56 fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
57 fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
58 fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
59 }
61 int CCN_load_state( FILE *f )
62 {
63 /* Setup the cache mode according to the saved register value
64 * (mem_load runs before this point to load all MMIO data)
65 */
66 mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
68 if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
69 return 1;
70 }
71 if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
72 return 1;
73 }
74 if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
75 return 1;
76 }
77 if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
78 return 1;
79 }
80 return 0;
81 }
83 /************************* OCRAM memory address space ************************/
85 #define OCRAMPAGE0 (&ccn_ocache_data[4096]) /* Lines 128-255 */
86 #define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */
88 static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr )
89 {
90 return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));
91 }
92 static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )
93 {
94 return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
95 }
96 static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )
97 {
98 return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
99 }
100 static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )
101 {
102 *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;
103 }
104 static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )
105 {
106 *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;
107 }
108 static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )
109 {
110 *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;
111 }
112 static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )
113 {
114 memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );
115 }
116 static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )
117 {
118 memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );
119 }
121 struct mem_region_fn mem_region_ocram_page0 = {
122 ocram_page0_read_long, ocram_page0_write_long,
123 ocram_page0_read_word, ocram_page0_write_word,
124 ocram_page0_read_byte, ocram_page0_write_byte,
125 ocram_page0_read_burst, ocram_page0_write_burst,
126 unmapped_prefetch };
128 static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
129 {
130 return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
131 }
132 static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
133 {
134 return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
135 }
136 static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
137 {
138 return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
139 }
140 static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
141 {
142 *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
143 }
144 static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
145 {
146 *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
147 }
148 static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
149 {
150 *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
151 }
152 static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
153 {
154 memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
155 }
156 static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
157 {
158 memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
159 }
161 struct mem_region_fn mem_region_ocram_page1 = {
162 ocram_page1_read_long, ocram_page1_write_long,
163 ocram_page1_read_word, ocram_page1_write_word,
164 ocram_page1_read_byte, ocram_page1_write_byte,
165 ocram_page1_read_burst, ocram_page1_write_burst,
166 unmapped_prefetch };
168 /************************** Cache direct access ******************************/
170 static int32_t ccn_icache_addr_read( sh4addr_t addr )
171 {
172 int entry = (addr & 0x00001FE0);
173 return ccn_icache[entry>>5].tag;
174 }
176 static void ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
177 {
178 int entry = (addr & 0x00003FE0);
179 struct cache_line *line = &ccn_ocache[entry>>5];
180 if( addr & 0x08 ) { // Associative
181 /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
182 } else {
183 line->tag = val & 0x1FFFFC01;
184 line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
185 }
186 }
188 struct mem_region_fn p4_region_icache_addr = {
189 ccn_icache_addr_read, ccn_icache_addr_write,
190 unmapped_read_long, unmapped_write_long,
191 unmapped_read_long, unmapped_write_long,
192 unmapped_read_burst, unmapped_write_burst,
193 unmapped_prefetch };
196 static int32_t ccn_icache_data_read( sh4addr_t addr )
197 {
198 int entry = (addr & 0x00001FFC);
199 return *(uint32_t *)&ccn_icache_data[entry];
200 }
202 static void ccn_icache_data_write( sh4addr_t addr, uint32_t val )
203 {
204 int entry = (addr & 0x00001FFC);
205 *(uint32_t *)&ccn_icache_data[entry] = val;
206 }
208 struct mem_region_fn p4_region_icache_data = {
209 ccn_icache_data_read, ccn_icache_data_write,
210 unmapped_read_long, unmapped_write_long,
211 unmapped_read_long, unmapped_write_long,
212 unmapped_read_burst, unmapped_write_burst,
213 unmapped_prefetch };
216 static int32_t ccn_ocache_addr_read( sh4addr_t addr )
217 {
218 int entry = (addr & 0x00003FE0);
219 return ccn_ocache[entry>>5].tag;
220 }
222 static void ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
223 {
224 int entry = (addr & 0x00003FE0);
225 struct cache_line *line = &ccn_ocache[entry>>5];
226 if( addr & 0x08 ) { // Associative
227 } else {
228 if( (line->tag & (CACHE_VALID|CACHE_DIRTY)) == (CACHE_VALID|CACHE_DIRTY) ) {
229 char *cache_data = &ccn_ocache_data[entry&0x00003FE0];
230 // Cache line is dirty - writeback.
231 ext_address_space[line->tag>>12]->write_burst(line->key, cache_data);
232 }
233 line->tag = val & 0x1FFFFC03;
234 line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
235 }
236 }
238 struct mem_region_fn p4_region_ocache_addr = {
239 ccn_ocache_addr_read, ccn_ocache_addr_write,
240 unmapped_read_long, unmapped_write_long,
241 unmapped_read_long, unmapped_write_long,
242 unmapped_read_burst, unmapped_write_burst,
243 unmapped_prefetch };
246 static int32_t ccn_ocache_data_read( sh4addr_t addr )
247 {
248 int entry = (addr & 0x00003FFC);
249 return *(uint32_t *)&ccn_ocache_data[entry];
250 }
252 static void ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
253 {
254 int entry = (addr & 0x00003FFC);
255 *(uint32_t *)&ccn_ocache_data[entry] = val;
256 }
258 struct mem_region_fn p4_region_ocache_data = {
259 ccn_ocache_data_read, ccn_ocache_data_write,
260 unmapped_read_long, unmapped_write_long,
261 unmapped_read_long, unmapped_write_long,
262 unmapped_read_burst, unmapped_write_burst,
263 unmapped_prefetch };
266 /****************** Cache control *********************/
268 void CCN_set_cache_control( int reg )
269 {
270 uint32_t i;
272 if( reg & CCR_ICI ) { /* icache invalidate */
273 for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
274 ccn_icache[i].tag &= ~CACHE_VALID;
275 }
276 }
278 if( reg & CCR_OCI ) { /* ocache invalidate */
279 for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
280 ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
281 }
282 }
284 switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
285 case MEM_OC_INDEX0: /* OIX=0 */
286 for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
287 sh4_address_space[i] = &mem_region_ocram_page0;
288 sh4_address_space[i+1] = &mem_region_ocram_page0;
289 sh4_address_space[i+2] = &mem_region_ocram_page1;
290 sh4_address_space[i+3] = &mem_region_ocram_page1;
291 }
292 break;
293 case MEM_OC_INDEX1: /* OIX=1 */
294 for( i=OCRAM_START; i<OCRAM_MID; i++ )
295 sh4_address_space[i] = &mem_region_ocram_page0;
296 for( i=OCRAM_MID; i<OCRAM_END; i++ )
297 sh4_address_space[i] = &mem_region_ocram_page1;
298 break;
299 default: /* disabled */
300 for( i=OCRAM_START; i<OCRAM_END; i++ )
301 sh4_address_space[i] = &mem_region_unmapped;
302 break;
303 }
304 }
306 /**
307 * Prefetch for non-storequeue regions
308 */
309 void FASTCALL ccn_prefetch( sh4addr_t addr )
310 {
312 }
314 /**
315 * Prefetch for non-cached regions. Oddly enough, this does nothing whatsoever.
316 */
317 void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )
318 {
320 }
321 /********************************* Store-queue *******************************/
322 /*
323 * The storequeue is strictly speaking part of the cache, but most of
324 * the complexity is actually around its addressing (ie in the MMU). The
325 * methods here can assume we've already passed SQMD protection and the TLB
326 * lookups (where appropriate).
327 */
328 void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val )
329 {
330 sh4r.store_queue[(addr>>2)&0xF] = val;
331 }
332 int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr )
333 {
334 return sh4r.store_queue[(addr>>2)&0xF];
335 }
337 /**
338 * Variant used when tlb is disabled - address will be the original prefetch
339 * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't
340 * be hardcoded on 4K page boundaries, so we manually decode it here.
341 */
342 void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr )
343 {
344 int queue = (addr&0x20)>>2;
345 sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
346 uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24;
347 sh4addr_t target = (addr&0x03FFFFE0) | hi;
348 ext_address_space[target>>12]->write_burst( target, src );
349 }
351 /**
352 * Variant used when tlb is enabled - address in this case is already
353 * mapped to the external target address.
354 */
355 void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr )
356 {
357 int queue = (addr&0x20)>>2;
358 sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
359 ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );
360 }
.