Search
lxdream.org :: lxdream/src/sh4/cache.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/cache.c
changeset 933:880c37bb1909
prev931:430048ea8b71
next939:6f2302afeb89
author nkeynes
date Sat Dec 27 02:59:35 2008 +0000 (15 years ago)
branchlxdream-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     }
.