filename | src/sh4/cache.c |
changeset | 933:880c37bb1909 |
prev | 931:430048ea8b71 |
next | 939:6f2302afeb89 |
author | nkeynes |
date | Sat Dec 27 02:59:35 2008 +0000 (15 years ago) |
branch | lxdream-mem |
permissions | -rw-r--r-- |
last change | Replace fpscr_mask/fpscr flags in xlat_cache_block with a single xlat_sh4_mode, which tracks the field of the same name in sh4r - actually a little faster this way. Now depends on SR.MD, FPSCR.PR and FPSCR.SZ (although it doesn't benefit from the SR flag yet). Also fixed the failure to check the flags in the common case (code address returned by previous block) which took away the performance benefits, but oh well. |
view | annotate | diff | log | raw |
1 /**
2 * $Id$
3 * Implements the on-chip operand cache and instruction caches
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 }
.