Search
lxdream.org :: lxdream/src/sh4/cache.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/cache.c
changeset 971:886e1ec8447d
prev968:6fb1481859a4
next975: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
file annotate diff log raw
1.1 --- a/src/sh4/cache.c Thu Jan 15 11:23:20 2009 +0000
1.2 +++ b/src/sh4/cache.c Thu Jan 22 02:58:13 2009 +0000
1.3 @@ -21,6 +21,7 @@
1.4 #include "dream.h"
1.5 #include "mem.h"
1.6 #include "mmio.h"
1.7 +#include "clock.h"
1.8 #include "sh4/sh4core.h"
1.9 #include "sh4/sh4mmio.h"
1.10 #include "sh4/xltcache.h"
1.11 @@ -43,13 +44,22 @@
1.12
1.13
1.14 static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
1.15 -static struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
1.16 +struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
1.17 static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
1.18 -static unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
1.19 +unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
1.20
1.21
1.22 /*********************** General module requirements ********************/
1.23
1.24 +void CCN_reset()
1.25 +{
1.26 + /* Clear everything for consistency */
1.27 + memset( ccn_icache, 0, sizeof(ccn_icache) );
1.28 + memset( ccn_ocache, 0, sizeof(ccn_icache) );
1.29 + memset( ccn_icache_data, 0, sizeof(ccn_icache) );
1.30 + memset( ccn_ocache_data, 0, sizeof(ccn_icache) );
1.31 +}
1.32 +
1.33 void CCN_save_state( FILE *f )
1.34 {
1.35 fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
1.36 @@ -165,6 +175,141 @@
1.37 ocram_page1_read_burst, ocram_page1_write_burst,
1.38 unmapped_prefetch };
1.39
1.40 +/**************************** Cache functions ********************************/
1.41 +char ccn_cache_map[16 MB]; // 24 bits of address space
1.42 +
1.43 +/**
1.44 + * Load a 32-byte cache line from external memory at the given ext address.
1.45 + * @param addr external address pre-masked to 1FFFFFFE0
1.46 + */
1.47 +sh4addr_t FASTCALL ccn_ocache_load_line( sh4addr_t addr )
1.48 +{
1.49 + int entry = addr & 0x00003FE0;
1.50 + struct cache_line *line = &ccn_ocache[entry>>5];
1.51 + char *cache_data = &ccn_ocache_data[entry];
1.52 + sh4addr_t old_addr = line->tag;
1.53 + line->tag = addr & 0x1FFFFFE0;
1.54 + char oldstate = ccn_cache_map[old_addr>>5];
1.55 + ccn_cache_map[old_addr>>5] = 0;
1.56 + ccn_cache_map[addr>>5] = CACHE_VALID;
1.57 + if( oldstate == (CACHE_VALID|CACHE_DIRTY) ) {
1.58 + // Cache line is dirty - writeback.
1.59 + ext_address_space[old_addr>>12]->write_burst(old_addr, cache_data);
1.60 + }
1.61 + ext_address_space[addr>>12]->read_burst(cache_data, addr & 0x1FFFFFE0);
1.62 + return addr;
1.63 +}
1.64 +
1.65 +/* Long read through the operand cache */
1.66 +/*
1.67 +int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr );
1.68 +int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr );
1.69 +int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr );
1.70 +void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t val );
1.71 +void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t val );
1.72 +void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t val );
1.73 +
1.74 +*/
1.75 +static int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr )
1.76 +{
1.77 + addr &= 0x1FFFFFFF;
1.78 + if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
1.79 + ccn_ocache_load_line(addr);
1.80 + }
1.81 + return *(int32_t *)&ccn_ocache_data[addr & 0x3FFF];
1.82 +}
1.83 +
1.84 +static int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr )
1.85 +{
1.86 + addr &= 0x1FFFFFFF;
1.87 + if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
1.88 + ccn_ocache_load_line(addr);
1.89 + }
1.90 + return SIGNEXT16(*(int16_t *)&ccn_ocache_data[addr&0x3FFF]);
1.91 +}
1.92 +
1.93 +static int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr )
1.94 +{
1.95 + addr &= 0x1FFFFFFF;
1.96 + if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
1.97 + ccn_ocache_load_line(addr);
1.98 + }
1.99 + return SIGNEXT8(ccn_ocache_data[addr&0x3FFF]);
1.100 +}
1.101 +
1.102 +static void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t value )
1.103 +{
1.104 + addr &= 0x1FFFFFFF;
1.105 + if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
1.106 + ccn_ocache_load_line(addr);
1.107 + }
1.108 + ccn_cache_map[addr>>5] |= CACHE_DIRTY;
1.109 + *(uint32_t *)&ccn_ocache_data[addr&0x3FFF] = value;
1.110 +}
1.111 +
1.112 +static void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t value )
1.113 +{
1.114 + addr &= 0x1FFFFFFF;
1.115 + if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
1.116 + ccn_ocache_load_line(addr);
1.117 + }
1.118 + ccn_cache_map[addr>>5] |= CACHE_DIRTY;
1.119 + *(uint16_t *)&ccn_ocache_data[addr&0x3FFF] = (uint16_t)value;
1.120 +}
1.121 +
1.122 +static void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t value )
1.123 +{
1.124 + addr &= 0x1FFFFFFF;
1.125 + if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
1.126 + ccn_ocache_load_line(addr);
1.127 + }
1.128 + ccn_cache_map[addr>>5] |= CACHE_DIRTY;
1.129 + ccn_ocache_data[addr&0x3FFF] = (uint8_t)value;
1.130 +}
1.131 +
1.132 +static void FASTCALL ccn_ocache_prefetch( sh4addr_t addr )
1.133 +{
1.134 + addr &= 0x1FFFFFFF;
1.135 + if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
1.136 + ccn_ocache_load_line(addr);
1.137 + }
1.138 +}
1.139 +
1.140 +void FASTCALL ccn_ocache_invalidate( sh4addr_t addr )
1.141 +{
1.142 + addr &= 0x1FFFFFFF;
1.143 + ccn_cache_map[addr>>5] &= ~CACHE_VALID;
1.144 +}
1.145 +
1.146 +void FASTCALL ccn_ocache_purge( sh4addr_t addr )
1.147 +{
1.148 + addr &= 0x1FFFFFE0;
1.149 + int oldflags = ccn_cache_map[addr>>5];
1.150 + ccn_cache_map[addr>>5] &= ~CACHE_VALID;
1.151 + if( oldflags == (CACHE_VALID|CACHE_DIRTY) ) {
1.152 + char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
1.153 + ext_address_space[addr>>12]->write_burst(addr, cache_data);
1.154 + }
1.155 +}
1.156 +
1.157 +void FASTCALL ccn_ocache_writeback( sh4addr_t addr )
1.158 +{
1.159 + addr &= 0x1FFFFFE0;
1.160 + if( ccn_cache_map[addr>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
1.161 + ccn_cache_map[addr>>5] &= ~CACHE_DIRTY;
1.162 + char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
1.163 + ext_address_space[addr>>12]->write_burst(addr, cache_data);
1.164 + }
1.165 +}
1.166 +
1.167 +struct mem_region_fn ccn_ocache_cb_region = {
1.168 + ccn_ocache_read_long, ccn_ocache_write_long_copyback,
1.169 + ccn_ocache_read_word, ccn_ocache_write_word_copyback,
1.170 + ccn_ocache_read_byte, ccn_ocache_write_byte_copyback,
1.171 + unmapped_read_burst, unmapped_write_burst,
1.172 + ccn_ocache_prefetch };
1.173 +
1.174 +
1.175 /************************** Cache direct access ******************************/
1.176
1.177 static int32_t FASTCALL ccn_icache_addr_read( sh4addr_t addr )
1.178 @@ -212,11 +357,11 @@
1.179 unmapped_read_burst, unmapped_write_burst,
1.180 unmapped_prefetch };
1.181
1.182 -
1.183 static int32_t FASTCALL ccn_ocache_addr_read( sh4addr_t addr )
1.184 {
1.185 int entry = (addr & 0x00003FE0);
1.186 - return ccn_ocache[entry>>5].tag;
1.187 + sh4addr_t tag = ccn_ocache[entry>>5].tag;
1.188 + return (tag&0x1FFFFC00) | ccn_cache_map[tag>>5];
1.189 }
1.190
1.191 static void FASTCALL ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
1.192 @@ -225,13 +370,14 @@
1.193 struct cache_line *line = &ccn_ocache[entry>>5];
1.194 if( addr & 0x08 ) { // Associative
1.195 } else {
1.196 - if( (line->tag & (CACHE_VALID|CACHE_DIRTY)) == (CACHE_VALID|CACHE_DIRTY) ) {
1.197 - unsigned char *cache_data = &ccn_ocache_data[entry&0x00003FE0];
1.198 + sh4addr_t tag = line->tag;
1.199 + if( ccn_cache_map[tag>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
1.200 // Cache line is dirty - writeback.
1.201 - ext_address_space[line->tag>>12]->write_burst(line->key, cache_data);
1.202 + unsigned char *cache_data = &ccn_ocache_data[entry];
1.203 + ext_address_space[tag>>12]->write_burst(tag, cache_data);
1.204 }
1.205 - line->tag = val & 0x1FFFFC03;
1.206 - line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
1.207 + line->tag = tag = (val & 0x1FFFFC00) | (addr & 0x3E0);
1.208 + ccn_cache_map[tag>>5] = val & 0x03;
1.209 }
1.210 }
1.211
1.212 @@ -271,12 +417,14 @@
1.213
1.214 if( reg & CCR_ICI ) { /* icache invalidate */
1.215 for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
1.216 + ccn_icache[i].key = -1;
1.217 ccn_icache[i].tag &= ~CACHE_VALID;
1.218 }
1.219 }
1.220
1.221 if( reg & CCR_OCI ) { /* ocache invalidate */
1.222 for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
1.223 + ccn_icache[i].key = -1;
1.224 ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
1.225 }
1.226 }
1.227 @@ -311,13 +459,55 @@
1.228
1.229 }
1.230
1.231 -/**
1.232 - * Prefetch for non-cached regions. Oddly enough, this does nothing whatsoever.
1.233 - */
1.234 +/************************** Uncached memory access ***************************/
1.235 +int32_t FASTCALL ccn_uncached_read_long( sh4addr_t addr )
1.236 +{
1.237 + sh4r.slice_cycle += (4*sh4_bus_period);
1.238 + addr &= 0x1FFFFFFF;
1.239 + return ext_address_space[addr>>12]->read_long(addr);
1.240 +}
1.241 +int32_t FASTCALL ccn_uncached_read_word( sh4addr_t addr )
1.242 +{
1.243 + sh4r.slice_cycle += (4*sh4_bus_period);
1.244 + addr &= 0x1FFFFFFF;
1.245 + return ext_address_space[addr>>12]->read_word(addr);
1.246 +}
1.247 +int32_t FASTCALL ccn_uncached_read_byte( sh4addr_t addr )
1.248 +{
1.249 + sh4r.slice_cycle += (4*sh4_bus_period);
1.250 + addr &= 0x1FFFFFFF;
1.251 + return ext_address_space[addr>>12]->read_byte(addr);
1.252 +}
1.253 +void FASTCALL ccn_uncached_write_long( sh4addr_t addr, uint32_t val )
1.254 +{
1.255 + sh4r.slice_cycle += (4*sh4_bus_period);
1.256 + addr &= 0x1FFFFFFF;
1.257 + return ext_address_space[addr>>12]->write_long(addr, val);
1.258 +}
1.259 +void FASTCALL ccn_uncached_write_word( sh4addr_t addr, uint32_t val )
1.260 +{
1.261 + sh4r.slice_cycle += (4*sh4_bus_period);
1.262 + addr &= 0x1FFFFFFF;
1.263 + return ext_address_space[addr>>12]->write_word(addr, val);
1.264 +}
1.265 +void FASTCALL ccn_uncached_write_byte( sh4addr_t addr, uint32_t val )
1.266 +{
1.267 + sh4r.slice_cycle += (4*sh4_bus_period);
1.268 + addr &= 0x1FFFFFFF;
1.269 + return ext_address_space[addr>>12]->write_byte(addr, val);
1.270 +}
1.271 void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )
1.272 {
1.273 -
1.274 }
1.275 +
1.276 +struct mem_region_fn ccn_uncached_region = {
1.277 + ccn_uncached_read_long, ccn_uncached_write_long,
1.278 + ccn_uncached_read_word, ccn_uncached_write_word,
1.279 + ccn_uncached_read_byte, ccn_uncached_write_byte,
1.280 + unmapped_read_burst, unmapped_write_burst,
1.281 + ccn_uncached_prefetch };
1.282 +
1.283 +
1.284 /********************************* Store-queue *******************************/
1.285 /*
1.286 * The storequeue is strictly speaking part of the cache, but most of
1.287 @@ -358,3 +548,4 @@
1.288 sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
1.289 ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );
1.290 }
1.291 +
.