filename | src/sh4/cache.c |
changeset | 953:f4a156508ad1 |
next | 968:6fb1481859a4 |
author | nkeynes |
date | Thu Jan 15 03:54:21 2009 +0000 (15 years ago) |
permissions | -rw-r--r-- |
last change | Fix missing prototype for mmu_vma_to_phys_disasm Fix missing return value in mmu_ext_page_remapped |
file | annotate | diff | log | raw |
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +00001.2 +++ b/src/sh4/cache.c Thu Jan 15 03:54:21 2009 +00001.3 @@ -0,0 +1,360 @@1.4 +/**1.5 + * $Id$1.6 + * Implements the on-chip operand cache, instruction cache, and store queue.1.7 + *1.8 + * Copyright (c) 2008 Nathan Keynes.1.9 + *1.10 + * This program is free software; you can redistribute it and/or modify1.11 + * it under the terms of the GNU General Public License as published by1.12 + * the Free Software Foundation; either version 2 of the License, or1.13 + * (at your option) any later version.1.14 + *1.15 + * This program is distributed in the hope that it will be useful,1.16 + * but WITHOUT ANY WARRANTY; without even the implied warranty of1.17 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the1.18 + * GNU General Public License for more details.1.19 + */1.20 +1.21 +#define MODULE sh4_module1.22 +1.23 +#include <string.h>1.24 +#include "dream.h"1.25 +#include "mem.h"1.26 +#include "mmio.h"1.27 +#include "sh4/sh4core.h"1.28 +#include "sh4/sh4mmio.h"1.29 +#include "sh4/xltcache.h"1.30 +#include "sh4/mmu.h"1.31 +1.32 +#define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)1.33 +#define OCRAM_MID (0x7E000000>>LXDREAM_PAGE_BITS)1.34 +#define OCRAM_END (0x80000000>>LXDREAM_PAGE_BITS)1.35 +1.36 +#define CACHE_VALID 11.37 +#define CACHE_DIRTY 21.38 +1.39 +#define ICACHE_ENTRY_COUNT 2561.40 +#define OCACHE_ENTRY_COUNT 5121.41 +1.42 +struct cache_line {1.43 + uint32_t key; // Fast address match - bits 5..28 for valid entry, -1 for invalid entry1.44 + uint32_t tag; // tag + flags value from the address field1.45 +};1.46 +1.47 +1.48 +static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];1.49 +static struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];1.50 +static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];1.51 +static unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];1.52 +1.53 +1.54 +/*********************** General module requirements ********************/1.55 +1.56 +void CCN_save_state( FILE *f )1.57 +{1.58 + fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );1.59 + fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );1.60 + fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);1.61 + fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);1.62 +}1.63 +1.64 +int CCN_load_state( FILE *f )1.65 +{1.66 + /* Setup the cache mode according to the saved register value1.67 + * (mem_load runs before this point to load all MMIO data)1.68 + */1.69 + mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );1.70 +1.71 + if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {1.72 + return 1;1.73 + }1.74 + if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {1.75 + return 1;1.76 + }1.77 + if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {1.78 + return 1;1.79 + }1.80 + if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {1.81 + return 1;1.82 + }1.83 + return 0;1.84 +}1.85 +1.86 +/************************* OCRAM memory address space ************************/1.87 +1.88 +#define OCRAMPAGE0 (&ccn_ocache_data[4096]) /* Lines 128-255 */1.89 +#define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */1.90 +1.91 +static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr )1.92 +{1.93 + return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));1.94 +}1.95 +static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )1.96 +{1.97 + return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));1.98 +}1.99 +static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )1.100 +{1.101 + return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));1.102 +}1.103 +static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )1.104 +{1.105 + *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;1.106 +}1.107 +static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )1.108 +{1.109 + *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;1.110 +}1.111 +static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )1.112 +{1.113 + *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;1.114 +}1.115 +static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )1.116 +{1.117 + memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );1.118 +}1.119 +static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )1.120 +{1.121 + memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );1.122 +}1.123 +1.124 +struct mem_region_fn mem_region_ocram_page0 = {1.125 + ocram_page0_read_long, ocram_page0_write_long,1.126 + ocram_page0_read_word, ocram_page0_write_word,1.127 + ocram_page0_read_byte, ocram_page0_write_byte,1.128 + ocram_page0_read_burst, ocram_page0_write_burst,1.129 + unmapped_prefetch };1.130 +1.131 +static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )1.132 +{1.133 + return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));1.134 +}1.135 +static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )1.136 +{1.137 + return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));1.138 +}1.139 +static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )1.140 +{1.141 + return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));1.142 +}1.143 +static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )1.144 +{1.145 + *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;1.146 +}1.147 +static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )1.148 +{1.149 + *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;1.150 +}1.151 +static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )1.152 +{1.153 + *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;1.154 +}1.155 +static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )1.156 +{1.157 + memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );1.158 +}1.159 +static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )1.160 +{1.161 + memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );1.162 +}1.163 +1.164 +struct mem_region_fn mem_region_ocram_page1 = {1.165 + ocram_page1_read_long, ocram_page1_write_long,1.166 + ocram_page1_read_word, ocram_page1_write_word,1.167 + ocram_page1_read_byte, ocram_page1_write_byte,1.168 + ocram_page1_read_burst, ocram_page1_write_burst,1.169 + unmapped_prefetch };1.170 +1.171 +/************************** Cache direct access ******************************/1.172 +1.173 +static int32_t ccn_icache_addr_read( sh4addr_t addr )1.174 +{1.175 + int entry = (addr & 0x00001FE0);1.176 + return ccn_icache[entry>>5].tag;1.177 +}1.178 +1.179 +static void ccn_icache_addr_write( sh4addr_t addr, uint32_t val )1.180 +{1.181 + int entry = (addr & 0x00003FE0);1.182 + struct cache_line *line = &ccn_ocache[entry>>5];1.183 + if( addr & 0x08 ) { // Associative1.184 + /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */1.185 + } else {1.186 + line->tag = val & 0x1FFFFC01;1.187 + line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);1.188 + }1.189 +}1.190 +1.191 +struct mem_region_fn p4_region_icache_addr = {1.192 + ccn_icache_addr_read, ccn_icache_addr_write,1.193 + unmapped_read_long, unmapped_write_long,1.194 + unmapped_read_long, unmapped_write_long,1.195 + unmapped_read_burst, unmapped_write_burst,1.196 + unmapped_prefetch };1.197 +1.198 +1.199 +static int32_t ccn_icache_data_read( sh4addr_t addr )1.200 +{1.201 + int entry = (addr & 0x00001FFC);1.202 + return *(uint32_t *)&ccn_icache_data[entry];1.203 +}1.204 +1.205 +static void ccn_icache_data_write( sh4addr_t addr, uint32_t val )1.206 +{1.207 + int entry = (addr & 0x00001FFC);1.208 + *(uint32_t *)&ccn_icache_data[entry] = val;1.209 +}1.210 +1.211 +struct mem_region_fn p4_region_icache_data = {1.212 + ccn_icache_data_read, ccn_icache_data_write,1.213 + unmapped_read_long, unmapped_write_long,1.214 + unmapped_read_long, unmapped_write_long,1.215 + unmapped_read_burst, unmapped_write_burst,1.216 + unmapped_prefetch };1.217 +1.218 +1.219 +static int32_t ccn_ocache_addr_read( sh4addr_t addr )1.220 +{1.221 + int entry = (addr & 0x00003FE0);1.222 + return ccn_ocache[entry>>5].tag;1.223 +}1.224 +1.225 +static void ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )1.226 +{1.227 + int entry = (addr & 0x00003FE0);1.228 + struct cache_line *line = &ccn_ocache[entry>>5];1.229 + if( addr & 0x08 ) { // Associative1.230 + } else {1.231 + if( (line->tag & (CACHE_VALID|CACHE_DIRTY)) == (CACHE_VALID|CACHE_DIRTY) ) {1.232 + char *cache_data = &ccn_ocache_data[entry&0x00003FE0];1.233 + // Cache line is dirty - writeback.1.234 + ext_address_space[line->tag>>12]->write_burst(line->key, cache_data);1.235 + }1.236 + line->tag = val & 0x1FFFFC03;1.237 + line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);1.238 + }1.239 +}1.240 +1.241 +struct mem_region_fn p4_region_ocache_addr = {1.242 + ccn_ocache_addr_read, ccn_ocache_addr_write,1.243 + unmapped_read_long, unmapped_write_long,1.244 + unmapped_read_long, unmapped_write_long,1.245 + unmapped_read_burst, unmapped_write_burst,1.246 + unmapped_prefetch };1.247 +1.248 +1.249 +static int32_t ccn_ocache_data_read( sh4addr_t addr )1.250 +{1.251 + int entry = (addr & 0x00003FFC);1.252 + return *(uint32_t *)&ccn_ocache_data[entry];1.253 +}1.254 +1.255 +static void ccn_ocache_data_write( sh4addr_t addr, uint32_t val )1.256 +{1.257 + int entry = (addr & 0x00003FFC);1.258 + *(uint32_t *)&ccn_ocache_data[entry] = val;1.259 +}1.260 +1.261 +struct mem_region_fn p4_region_ocache_data = {1.262 + ccn_ocache_data_read, ccn_ocache_data_write,1.263 + unmapped_read_long, unmapped_write_long,1.264 + unmapped_read_long, unmapped_write_long,1.265 + unmapped_read_burst, unmapped_write_burst,1.266 + unmapped_prefetch };1.267 +1.268 +1.269 +/****************** Cache control *********************/1.270 +1.271 +void CCN_set_cache_control( int reg )1.272 +{1.273 + uint32_t i;1.274 +1.275 + if( reg & CCR_ICI ) { /* icache invalidate */1.276 + for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {1.277 + ccn_icache[i].tag &= ~CACHE_VALID;1.278 + }1.279 + }1.280 +1.281 + if( reg & CCR_OCI ) { /* ocache invalidate */1.282 + for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {1.283 + ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);1.284 + }1.285 + }1.286 +1.287 + switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {1.288 + case MEM_OC_INDEX0: /* OIX=0 */1.289 + for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {1.290 + sh4_address_space[i] = &mem_region_ocram_page0;1.291 + sh4_address_space[i+1] = &mem_region_ocram_page0;1.292 + sh4_address_space[i+2] = &mem_region_ocram_page1;1.293 + sh4_address_space[i+3] = &mem_region_ocram_page1;1.294 + }1.295 + break;1.296 + case MEM_OC_INDEX1: /* OIX=1 */1.297 + for( i=OCRAM_START; i<OCRAM_MID; i++ )1.298 + sh4_address_space[i] = &mem_region_ocram_page0;1.299 + for( i=OCRAM_MID; i<OCRAM_END; i++ )1.300 + sh4_address_space[i] = &mem_region_ocram_page1;1.301 + break;1.302 + default: /* disabled */1.303 + for( i=OCRAM_START; i<OCRAM_END; i++ )1.304 + sh4_address_space[i] = &mem_region_unmapped;1.305 + break;1.306 + }1.307 +}1.308 +1.309 +/**1.310 + * Prefetch for non-storequeue regions1.311 + */1.312 +void FASTCALL ccn_prefetch( sh4addr_t addr )1.313 +{1.314 +1.315 +}1.316 +1.317 +/**1.318 + * Prefetch for non-cached regions. Oddly enough, this does nothing whatsoever.1.319 + */1.320 +void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )1.321 +{1.322 +1.323 +}1.324 +/********************************* Store-queue *******************************/1.325 +/*1.326 + * The storequeue is strictly speaking part of the cache, but most of1.327 + * the complexity is actually around its addressing (ie in the MMU). The1.328 + * methods here can assume we've already passed SQMD protection and the TLB1.329 + * lookups (where appropriate).1.330 + */1.331 +void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val )1.332 +{1.333 + sh4r.store_queue[(addr>>2)&0xF] = val;1.334 +}1.335 +int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr )1.336 +{1.337 + return sh4r.store_queue[(addr>>2)&0xF];1.338 +}1.339 +1.340 +/**1.341 + * Variant used when tlb is disabled - address will be the original prefetch1.342 + * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't1.343 + * be hardcoded on 4K page boundaries, so we manually decode it here.1.344 + */1.345 +void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr )1.346 +{1.347 + int queue = (addr&0x20)>>2;1.348 + sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];1.349 + uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24;1.350 + sh4addr_t target = (addr&0x03FFFFE0) | hi;1.351 + ext_address_space[target>>12]->write_burst( target, src );1.352 +}1.353 +1.354 +/**1.355 + * Variant used when tlb is enabled - address in this case is already1.356 + * mapped to the external target address.1.357 + */1.358 +void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr )1.359 +{1.360 + int queue = (addr&0x20)>>2;1.361 + sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];1.362 + ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );1.363 +}
.