Search
lxdream.org :: lxdream/src/sh4/cache.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/cache.c
changeset 953:f4a156508ad1
next968:6fb1481859a4
author nkeynes
date Tue Jan 13 11:56:28 2009 +0000 (15 years ago)
permissions -rw-r--r--
last change Merge lxdream-mem branch back to trunk
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"
    27 #include "sh4/mmu.h"
    29 #define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)
    30 #define OCRAM_MID   (0x7E000000>>LXDREAM_PAGE_BITS)
    31 #define OCRAM_END   (0x80000000>>LXDREAM_PAGE_BITS)
    33 #define CACHE_VALID 1
    34 #define CACHE_DIRTY 2
    36 #define ICACHE_ENTRY_COUNT 256
    37 #define OCACHE_ENTRY_COUNT 512
    39 struct cache_line {
    40     uint32_t key;  // Fast address match - bits 5..28 for valid entry, -1 for invalid entry
    41     uint32_t tag;  // tag + flags value from the address field
    42 };    
    45 static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
    46 static struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
    47 static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
    48 static unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
    51 /*********************** General module requirements ********************/
    53 void CCN_save_state( FILE *f )
    54 {
    55     fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
    56     fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
    57     fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
    58     fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
    59 }
    61 int CCN_load_state( FILE *f )
    62 {
    63     /* Setup the cache mode according to the saved register value
    64      * (mem_load runs before this point to load all MMIO data)
    65      */
    66     mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
    68     if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
    69         return 1;
    70     }
    71     if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
    72         return 1;
    73     }
    74     if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
    75         return 1;
    76     }
    77     if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
    78         return 1;
    79     }
    80     return 0;
    81 }
    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,
   126         unmapped_prefetch };
   128 static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
   129 {
   130     return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
   131 }
   132 static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
   133 {
   134     return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
   135 }
   136 static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
   137 {
   138     return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
   139 }
   140 static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
   141 {
   142     *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
   143 }
   144 static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
   145 {
   146     *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
   147 }
   148 static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
   149 {
   150     *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
   151 }
   152 static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
   153 {
   154     memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
   155 }
   156 static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
   157 {
   158     memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
   159 }
   161 struct mem_region_fn mem_region_ocram_page1 = {
   162         ocram_page1_read_long, ocram_page1_write_long,
   163         ocram_page1_read_word, ocram_page1_write_word,
   164         ocram_page1_read_byte, ocram_page1_write_byte,
   165         ocram_page1_read_burst, ocram_page1_write_burst,
   166         unmapped_prefetch };
   168 /************************** Cache direct access ******************************/
   170 static int32_t ccn_icache_addr_read( sh4addr_t addr )
   171 {
   172     int entry = (addr & 0x00001FE0);
   173     return ccn_icache[entry>>5].tag;
   174 }
   176 static void ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
   177 {
   178     int entry = (addr & 0x00003FE0);
   179     struct cache_line *line = &ccn_ocache[entry>>5];
   180     if( addr & 0x08 ) { // Associative
   181         /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
   182     } else {
   183         line->tag = val & 0x1FFFFC01;
   184         line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
   185     }
   186 }
   188 struct mem_region_fn p4_region_icache_addr = {
   189         ccn_icache_addr_read, ccn_icache_addr_write,
   190         unmapped_read_long, unmapped_write_long,
   191         unmapped_read_long, unmapped_write_long,
   192         unmapped_read_burst, unmapped_write_burst,
   193         unmapped_prefetch };
   196 static int32_t ccn_icache_data_read( sh4addr_t addr )
   197 {
   198     int entry = (addr & 0x00001FFC);
   199     return *(uint32_t *)&ccn_icache_data[entry];
   200 }
   202 static void ccn_icache_data_write( sh4addr_t addr, uint32_t val )
   203 {
   204     int entry = (addr & 0x00001FFC);
   205     *(uint32_t *)&ccn_icache_data[entry] = val;    
   206 }
   208 struct mem_region_fn p4_region_icache_data = {
   209         ccn_icache_data_read, ccn_icache_data_write,
   210         unmapped_read_long, unmapped_write_long,
   211         unmapped_read_long, unmapped_write_long,
   212         unmapped_read_burst, unmapped_write_burst,
   213         unmapped_prefetch };
   216 static int32_t ccn_ocache_addr_read( sh4addr_t addr )
   217 {
   218     int entry = (addr & 0x00003FE0);
   219     return ccn_ocache[entry>>5].tag;
   220 }
   222 static void ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
   223 {
   224     int entry = (addr & 0x00003FE0);
   225     struct cache_line *line = &ccn_ocache[entry>>5];
   226     if( addr & 0x08 ) { // Associative
   227     } else {
   228         if( (line->tag & (CACHE_VALID|CACHE_DIRTY)) == (CACHE_VALID|CACHE_DIRTY) ) {
   229             char *cache_data = &ccn_ocache_data[entry&0x00003FE0];
   230             // Cache line is dirty - writeback. 
   231             ext_address_space[line->tag>>12]->write_burst(line->key, cache_data);
   232         }
   233         line->tag = val & 0x1FFFFC03;
   234         line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
   235     }
   236 }
   238 struct mem_region_fn p4_region_ocache_addr = {
   239         ccn_ocache_addr_read, ccn_ocache_addr_write,
   240         unmapped_read_long, unmapped_write_long,
   241         unmapped_read_long, unmapped_write_long,
   242         unmapped_read_burst, unmapped_write_burst,
   243         unmapped_prefetch };
   246 static int32_t ccn_ocache_data_read( sh4addr_t addr )
   247 {
   248     int entry = (addr & 0x00003FFC);
   249     return *(uint32_t *)&ccn_ocache_data[entry];
   250 }
   252 static void ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
   253 {
   254     int entry = (addr & 0x00003FFC);
   255     *(uint32_t *)&ccn_ocache_data[entry] = val;
   256 }
   258 struct mem_region_fn p4_region_ocache_data = {
   259         ccn_ocache_data_read, ccn_ocache_data_write,
   260         unmapped_read_long, unmapped_write_long,
   261         unmapped_read_long, unmapped_write_long,
   262         unmapped_read_burst, unmapped_write_burst,
   263         unmapped_prefetch };
   266 /****************** Cache control *********************/
   268 void CCN_set_cache_control( int reg )
   269 {
   270     uint32_t i;
   272     if( reg & CCR_ICI ) { /* icache invalidate */
   273         for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
   274             ccn_icache[i].tag &= ~CACHE_VALID;
   275         }
   276     }
   278     if( reg & CCR_OCI ) { /* ocache invalidate */
   279         for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
   280             ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
   281         }
   282     }
   284     switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
   285     case MEM_OC_INDEX0: /* OIX=0 */
   286         for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
   287             sh4_address_space[i] = &mem_region_ocram_page0;
   288             sh4_address_space[i+1] = &mem_region_ocram_page0;
   289             sh4_address_space[i+2] = &mem_region_ocram_page1;
   290             sh4_address_space[i+3] = &mem_region_ocram_page1;
   291         }
   292         break;
   293     case MEM_OC_INDEX1: /* OIX=1 */
   294         for( i=OCRAM_START; i<OCRAM_MID; i++ )
   295             sh4_address_space[i] = &mem_region_ocram_page0;
   296         for( i=OCRAM_MID; i<OCRAM_END; i++ )
   297             sh4_address_space[i] = &mem_region_ocram_page1;
   298         break;
   299     default: /* disabled */
   300         for( i=OCRAM_START; i<OCRAM_END; i++ )
   301             sh4_address_space[i] = &mem_region_unmapped;
   302         break;
   303     }
   304 }
   306 /**
   307  * Prefetch for non-storequeue regions
   308  */
   309 void FASTCALL ccn_prefetch( sh4addr_t addr )
   310 {
   312 }
   314 /**
   315  * Prefetch for non-cached regions. Oddly enough, this does nothing whatsoever.
   316  */
   317 void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )
   318 {
   320 }
   321 /********************************* Store-queue *******************************/
   322 /*
   323  * The storequeue is strictly speaking part of the cache, but most of 
   324  * the complexity is actually around its addressing (ie in the MMU). The
   325  * methods here can assume we've already passed SQMD protection and the TLB
   326  * lookups (where appropriate).
   327  */  
   328 void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val )
   329 {
   330     sh4r.store_queue[(addr>>2)&0xF] = val;
   331 }
   332 int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr )
   333 {
   334     return sh4r.store_queue[(addr>>2)&0xF];
   335 }
   337 /**
   338  * Variant used when tlb is disabled - address will be the original prefetch
   339  * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't
   340  * be hardcoded on 4K page boundaries, so we manually decode it here.
   341  */
   342 void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr ) 
   343 {
   344     int queue = (addr&0x20)>>2;
   345     sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
   346     uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24;
   347     sh4addr_t target = (addr&0x03FFFFE0) | hi;
   348     ext_address_space[target>>12]->write_burst( target, src );
   349 }
   351 /**
   352  * Variant used when tlb is enabled - address in this case is already
   353  * mapped to the external target address.
   354  */
   355 void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr )
   356 {
   357     int queue = (addr&0x20)>>2;
   358     sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
   359     ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );
   360 }
.