3 * Implements the on-chip operand cache and instruction caches
5 * Copyright (c) 2008 Nathan Keynes.
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.
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.
18 #define MODULE sh4_module
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)
35 #define ICACHE_ENTRY_COUNT 256
36 #define OCACHE_ENTRY_COUNT 512
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
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 )
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);
60 int CCN_load_state( FILE *f )
62 /* Setup the cache mode according to the saved register value
63 * (mem_load runs before this point to load all MMIO data)
65 mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
67 if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
70 if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
73 if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
76 if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
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 )
90 return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));
92 static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )
94 return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
96 static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )
98 return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
100 static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )
102 *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;
104 static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )
106 *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;
108 static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )
110 *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;
112 static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )
114 memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );
116 static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )
118 memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );
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 )
129 return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
131 static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
133 return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
135 static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
137 return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
139 static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
141 *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
143 static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
145 *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
147 static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
149 *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
151 static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
153 memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
155 static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
157 memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
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 )
170 int entry = (addr & 0x00001FE0);
171 return ccn_icache[entry>>5].tag;
174 static void ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
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 */
181 line->tag = val & 0x1FFFFC01;
182 line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
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 )
195 int entry = (addr & 0x00001FFC);
196 return *(uint32_t *)&ccn_icache_data[entry];
199 static void ccn_icache_data_write( sh4addr_t addr, uint32_t val )
201 int entry = (addr & 0x00001FFC);
202 *(uint32_t *)&ccn_icache_data[entry] = val;
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 )
214 int entry = (addr & 0x00003FE0);
215 return ccn_ocache[entry>>5].tag;
218 static void ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
220 int entry = (addr & 0x00003FE0);
221 struct cache_line *line = &ccn_ocache[entry>>5];
222 if( addr & 0x08 ) { // Associative
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);
229 line->tag = val & 0x1FFFFC03;
230 line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
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 )
243 int entry = (addr & 0x00003FFC);
244 return *(uint32_t *)&ccn_ocache_data[entry];
247 static void ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
249 int entry = (addr & 0x00003FFC);
250 *(uint32_t *)&ccn_ocache_data[entry] = val;
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 )
266 if( reg & CCR_ICI ) { /* icache invalidate */
267 for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
268 ccn_icache[i].tag &= ~CACHE_VALID;
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);
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;
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;
293 default: /* disabled */
294 for( i=OCRAM_START; i<OCRAM_END; i++ )
295 sh4_address_space[i] = &mem_region_unmapped;
.