filename | src/sh4/cache.c |
changeset | 939:6f2302afeb89 |
prev | 933:880c37bb1909 |
next | 946:d41ee7994db7 |
author | nkeynes |
date | Sat Jan 03 03:30:26 2009 +0000 (15 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | MMU work-in-progress * Move SDRAM out into separate sdram.c * Move all page-table management into mmu.c * Convert UTLB management to use the new page-tables * Rip out all calls to mmu_vma_to_phys_* and replace with direct access |
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"
28 #define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)
29 #define OCRAM_MID (0x7E000000>>LXDREAM_PAGE_BITS)
30 #define OCRAM_END (0x80000000>>LXDREAM_PAGE_BITS)
32 #define CACHE_VALID 1
33 #define CACHE_DIRTY 2
35 #define ICACHE_ENTRY_COUNT 256
36 #define OCACHE_ENTRY_COUNT 512
38 struct cache_line {
39 uint32_t key; // Fast address match - bits 5..28 for valid entry, -1 for invalid entry
40 uint32_t tag; // tag + flags value from the address field
41 };
44 static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
45 static struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
46 static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
47 static unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
50 /*********************** General module requirements ********************/
52 void CCN_save_state( FILE *f )
53 {
54 fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
55 fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
56 fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
57 fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
58 }
60 int CCN_load_state( FILE *f )
61 {
62 /* Setup the cache mode according to the saved register value
63 * (mem_load runs before this point to load all MMIO data)
64 */
65 mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
67 if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
68 return 1;
69 }
70 if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
71 return 1;
72 }
73 if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
74 return 1;
75 }
76 if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
77 return 1;
78 }
79 return 0;
80 }
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 };
127 static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
128 {
129 return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
130 }
131 static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
132 {
133 return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
134 }
135 static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
136 {
137 return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
138 }
139 static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
140 {
141 *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
142 }
143 static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
144 {
145 *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
146 }
147 static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
148 {
149 *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
150 }
151 static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
152 {
153 memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
154 }
155 static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
156 {
157 memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
158 }
160 struct mem_region_fn mem_region_ocram_page1 = {
161 ocram_page1_read_long, ocram_page1_write_long,
162 ocram_page1_read_word, ocram_page1_write_word,
163 ocram_page1_read_byte, ocram_page1_write_byte,
164 ocram_page1_read_burst, ocram_page1_write_burst };
166 /************************** Cache direct access ******************************/
168 static int32_t ccn_icache_addr_read( sh4addr_t addr )
169 {
170 int entry = (addr & 0x00001FE0);
171 return ccn_icache[entry>>5].tag;
172 }
174 static void ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
175 {
176 int entry = (addr & 0x00003FE0);
177 struct cache_line *line = &ccn_ocache[entry>>5];
178 if( addr & 0x08 ) { // Associative
179 /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
180 } else {
181 line->tag = val & 0x1FFFFC01;
182 line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
183 }
184 }
186 struct mem_region_fn p4_region_icache_addr = {
187 ccn_icache_addr_read, ccn_icache_addr_write,
188 unmapped_read_long, unmapped_write_long,
189 unmapped_read_long, unmapped_write_long,
190 unmapped_read_burst, unmapped_write_burst };
193 static int32_t ccn_icache_data_read( sh4addr_t addr )
194 {
195 int entry = (addr & 0x00001FFC);
196 return *(uint32_t *)&ccn_icache_data[entry];
197 }
199 static void ccn_icache_data_write( sh4addr_t addr, uint32_t val )
200 {
201 int entry = (addr & 0x00001FFC);
202 *(uint32_t *)&ccn_icache_data[entry] = val;
203 }
205 struct mem_region_fn p4_region_icache_data = {
206 ccn_icache_data_read, ccn_icache_data_write,
207 unmapped_read_long, unmapped_write_long,
208 unmapped_read_long, unmapped_write_long,
209 unmapped_read_burst, unmapped_write_burst };
212 static int32_t ccn_ocache_addr_read( sh4addr_t addr )
213 {
214 int entry = (addr & 0x00003FE0);
215 return ccn_ocache[entry>>5].tag;
216 }
218 static void ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
219 {
220 int entry = (addr & 0x00003FE0);
221 struct cache_line *line = &ccn_ocache[entry>>5];
222 if( addr & 0x08 ) { // Associative
223 } else {
224 if( (line->tag & (CACHE_VALID|CACHE_DIRTY)) == (CACHE_VALID|CACHE_DIRTY) ) {
225 char *cache_data = &ccn_ocache_data[entry&0x00003FE0];
226 // Cache line is dirty - writeback.
227 ext_address_space[line->tag>>12]->write_burst(line->key, cache_data);
228 }
229 line->tag = val & 0x1FFFFC03;
230 line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
231 }
232 }
234 struct mem_region_fn p4_region_ocache_addr = {
235 ccn_ocache_addr_read, ccn_ocache_addr_write,
236 unmapped_read_long, unmapped_write_long,
237 unmapped_read_long, unmapped_write_long,
238 unmapped_read_burst, unmapped_write_burst };
241 static int32_t ccn_ocache_data_read( sh4addr_t addr )
242 {
243 int entry = (addr & 0x00003FFC);
244 return *(uint32_t *)&ccn_ocache_data[entry];
245 }
247 static void ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
248 {
249 int entry = (addr & 0x00003FFC);
250 *(uint32_t *)&ccn_ocache_data[entry] = val;
251 }
253 struct mem_region_fn p4_region_ocache_data = {
254 ccn_ocache_data_read, ccn_ocache_data_write,
255 unmapped_read_long, unmapped_write_long,
256 unmapped_read_long, unmapped_write_long,
257 unmapped_read_burst, unmapped_write_burst };
260 /****************** Cache control *********************/
262 void CCN_set_cache_control( int reg )
263 {
264 uint32_t i;
266 if( reg & CCR_ICI ) { /* icache invalidate */
267 for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
268 ccn_icache[i].tag &= ~CACHE_VALID;
269 }
270 }
272 if( reg & CCR_OCI ) { /* ocache invalidate */
273 for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
274 ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
275 }
276 }
278 switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
279 case MEM_OC_INDEX0: /* OIX=0 */
280 for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
281 sh4_address_space[i] = &mem_region_ocram_page0;
282 sh4_address_space[i+1] = &mem_region_ocram_page0;
283 sh4_address_space[i+2] = &mem_region_ocram_page1;
284 sh4_address_space[i+3] = &mem_region_ocram_page1;
285 }
286 break;
287 case MEM_OC_INDEX1: /* OIX=1 */
288 for( i=OCRAM_START; i<OCRAM_MID; i++ )
289 sh4_address_space[i] = &mem_region_ocram_page0;
290 for( i=OCRAM_MID; i<OCRAM_END; i++ )
291 sh4_address_space[i] = &mem_region_ocram_page1;
292 break;
293 default: /* disabled */
294 for( i=OCRAM_START; i<OCRAM_END; i++ )
295 sh4_address_space[i] = &mem_region_unmapped;
296 break;
297 }
298 }
301 /***** Store-queue (considered part of the cache by the SH7750 manual) ******/
302 static void FASTCALL p4_storequeue_write_long( sh4addr_t addr, uint32_t val )
303 {
304 sh4r.store_queue[(addr>>2)&0xF] = val;
305 }
306 static int32_t FASTCALL p4_storequeue_read_long( sh4addr_t addr )
307 {
308 return sh4r.store_queue[(addr>>2)&0xF];
309 }
311 struct mem_region_fn p4_region_storequeue = {
312 p4_storequeue_read_long, p4_storequeue_write_long,
313 p4_storequeue_read_long, p4_storequeue_write_long,
314 p4_storequeue_read_long, p4_storequeue_write_long,
315 unmapped_read_burst, unmapped_write_burst }; // No burst access.
.