Search
lxdream.org :: lxdream/src/sh4/cache.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/cache.c
changeset 1067:d3c00ffccfcd
prev983:b0d0785aa194
prev946:d41ee7994db7
author nkeynes
date Fri May 29 18:47:05 2015 +1000 (5 years ago)
permissions -rw-r--r--
last change Fix test case
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 "clock.h"
    25 #include "sh4/sh4core.h"
    26 #include "sh4/sh4mmio.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 struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
    47 static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
    48 unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
    51 /*********************** General module requirements ********************/
    53 void CCN_reset()
    54 {
    55     /* Clear everything for consistency */
    56     memset( ccn_icache, 0, sizeof(ccn_icache) );
    57     memset( ccn_ocache, 0, sizeof(ccn_icache) );
    58     memset( ccn_icache_data, 0, sizeof(ccn_icache) );
    59     memset( ccn_ocache_data, 0, sizeof(ccn_icache) );
    60 }
    62 void CCN_save_state( FILE *f )
    63 {
    64     fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
    65     fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
    66     fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
    67     fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
    68 }
    70 int CCN_load_state( FILE *f )
    71 {
    72     /* Setup the cache mode according to the saved register value
    73      * (mem_load runs before this point to load all MMIO data)
    74      */
    75     mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
    77     if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
    78         return 1;
    79     }
    80     if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
    81         return 1;
    82     }
    83     if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
    84         return 1;
    85     }
    86     if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
    87         return 1;
    88     }
    89     return 0;
    90 }
    92 /************************* OCRAM memory address space ************************/
    94 #define OCRAMPAGE0 (&ccn_ocache_data[4096])  /* Lines 128-255 */
    95 #define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */
    97 static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr )
    98 {
    99     return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));
   100 }
   101 static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )
   102 {
   103     return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
   104 }
   105 static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )
   106 {
   107     return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
   108 }
   109 static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )
   110 {
   111     *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;
   112 }
   113 static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )
   114 {
   115     *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;
   116 }
   117 static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )
   118 {
   119     *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;
   120 }
   121 static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )
   122 {
   123     memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );
   124 }
   125 static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )
   126 {
   127     memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );
   128 }
   130 struct mem_region_fn mem_region_ocram_page0 = {
   131         ocram_page0_read_long, ocram_page0_write_long,
   132         ocram_page0_read_word, ocram_page0_write_word,
   133         ocram_page0_read_byte, ocram_page0_write_byte,
   134         ocram_page0_read_burst, ocram_page0_write_burst,
   135         unmapped_prefetch, ocram_page0_read_byte };
   137 static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
   138 {
   139     return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
   140 }
   141 static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
   142 {
   143     return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
   144 }
   145 static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
   146 {
   147     return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
   148 }
   149 static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
   150 {
   151     *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
   152 }
   153 static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
   154 {
   155     *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
   156 }
   157 static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
   158 {
   159     *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
   160 }
   161 static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
   162 {
   163     memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
   164 }
   165 static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
   166 {
   167     memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
   168 }
   170 struct mem_region_fn mem_region_ocram_page1 = {
   171         ocram_page1_read_long, ocram_page1_write_long,
   172         ocram_page1_read_word, ocram_page1_write_word,
   173         ocram_page1_read_byte, ocram_page1_write_byte,
   174         ocram_page1_read_burst, ocram_page1_write_burst,
   175         unmapped_prefetch, ocram_page1_read_byte };
   177 /**************************** Cache functions ********************************/
   178 char ccn_cache_map[16 MB]; // 24 bits of address space
   180 /**
   181  * Load a 32-byte cache line from external memory at the given ext address.
   182  * @param addr external address pre-masked to 1FFFFFFE0 
   183  */
   184 sh4addr_t FASTCALL ccn_ocache_load_line( sh4addr_t addr )
   185 {
   186     int entry = addr & 0x00003FE0;
   187     struct cache_line *line = &ccn_ocache[entry>>5];
   188     unsigned char *cache_data = &ccn_ocache_data[entry];
   189     sh4addr_t old_addr = line->tag;
   190     line->tag = addr & 0x1FFFFFE0;
   191     char oldstate = ccn_cache_map[old_addr>>5];
   192     ccn_cache_map[old_addr>>5] = 0;
   193     ccn_cache_map[addr>>5] = CACHE_VALID;
   194     if( oldstate == (CACHE_VALID|CACHE_DIRTY) ) {
   195         // Cache line is dirty - writeback. 
   196         ext_address_space[old_addr>>12]->write_burst(old_addr, cache_data);
   197     }
   198     ext_address_space[addr>>12]->read_burst(cache_data, addr & 0x1FFFFFE0);
   199     return addr;
   200 }
   202 /* Long read through the operand cache */
   203 /*
   204 int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr );
   205 int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr );
   206 int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr );
   207 void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t val );
   208 void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t val );
   209 void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t val );
   211 */
   212 static int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr )
   213 {
   214     addr &= 0x1FFFFFFF;
   215     if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
   216         ccn_ocache_load_line(addr);
   217     }
   218     return *(int32_t *)&ccn_ocache_data[addr & 0x3FFF];
   219 }
   221 static int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr )
   222 {
   223     addr &= 0x1FFFFFFF;
   224     if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
   225         ccn_ocache_load_line(addr);
   226     }
   227     return SIGNEXT16(*(int16_t *)&ccn_ocache_data[addr&0x3FFF]);    
   228 }
   230 static int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr )
   231 {
   232     addr &= 0x1FFFFFFF;
   233     if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
   234         ccn_ocache_load_line(addr);
   235     }
   236     return SIGNEXT8(ccn_ocache_data[addr&0x3FFF]);        
   237 }
   239 static void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t value )
   240 {
   241     addr &= 0x1FFFFFFF;
   242     if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
   243         ccn_ocache_load_line(addr);
   244     }
   245     ccn_cache_map[addr>>5] |= CACHE_DIRTY;
   246     *(uint32_t *)&ccn_ocache_data[addr&0x3FFF] = value;
   247 }
   249 static void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t value )
   250 {
   251     addr &= 0x1FFFFFFF;
   252     if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
   253         ccn_ocache_load_line(addr);
   254     }
   255     ccn_cache_map[addr>>5] |= CACHE_DIRTY;
   256     *(uint16_t *)&ccn_ocache_data[addr&0x3FFF] = (uint16_t)value;
   257 }
   259 static void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t value )
   260 {
   261     addr &= 0x1FFFFFFF;
   262     if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
   263         ccn_ocache_load_line(addr);
   264     }
   265     ccn_cache_map[addr>>5] |= CACHE_DIRTY;
   266     ccn_ocache_data[addr&0x3FFF] = (uint8_t)value;
   267 }
   269 static void FASTCALL ccn_ocache_prefetch( sh4addr_t addr )
   270 {
   271     addr &= 0x1FFFFFFF;
   272     if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
   273         ccn_ocache_load_line(addr);
   274     }
   275 }
   277 void FASTCALL ccn_ocache_invalidate( sh4addr_t addr )
   278 {
   279     addr &= 0x1FFFFFFF;
   280     ccn_cache_map[addr>>5] &= ~CACHE_VALID;
   281 }
   283 void FASTCALL ccn_ocache_purge( sh4addr_t addr )
   284 {
   285     addr &= 0x1FFFFFE0;
   286     int oldflags = ccn_cache_map[addr>>5]; 
   287     ccn_cache_map[addr>>5] &= ~CACHE_VALID;
   288     if( oldflags == (CACHE_VALID|CACHE_DIRTY) ) {
   289         unsigned char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
   290         ext_address_space[addr>>12]->write_burst(addr, cache_data);
   291     }
   292 }
   294 void FASTCALL ccn_ocache_writeback( sh4addr_t addr )
   295 {
   296     addr &= 0x1FFFFFE0;
   297     if( ccn_cache_map[addr>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
   298         ccn_cache_map[addr>>5] &= ~CACHE_DIRTY;
   299         unsigned char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
   300         ext_address_space[addr>>12]->write_burst(addr, cache_data);
   301     }
   302 }
   304 struct mem_region_fn ccn_ocache_cb_region = {
   305     ccn_ocache_read_long, ccn_ocache_write_long_copyback,
   306     ccn_ocache_read_word, ccn_ocache_write_word_copyback,
   307     ccn_ocache_read_byte, ccn_ocache_write_byte_copyback,
   308     unmapped_read_burst, unmapped_write_burst,
   309     ccn_ocache_prefetch, ccn_ocache_read_byte };
   312 /************************** Cache direct access ******************************/
   314 static int32_t FASTCALL ccn_icache_addr_read( sh4addr_t addr )
   315 {
   316     int entry = (addr & 0x00001FE0);
   317     return ccn_icache[entry>>5].tag;
   318 }
   320 static void FASTCALL ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
   321 {
   322     int entry = (addr & 0x00003FE0);
   323     struct cache_line *line = &ccn_ocache[entry>>5];
   324     if( addr & 0x08 ) { // Associative
   325         /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
   326     } else {
   327         line->tag = val & 0x1FFFFC01;
   328         line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
   329     }
   330 }
   332 struct mem_region_fn p4_region_icache_addr = {
   333         ccn_icache_addr_read, ccn_icache_addr_write,
   334         unmapped_read_long, unmapped_write_long,
   335         unmapped_read_long, unmapped_write_long,
   336         unmapped_read_burst, unmapped_write_burst,
   337         unmapped_prefetch, unmapped_read_long };
   340 static int32_t FASTCALL ccn_icache_data_read( sh4addr_t addr )
   341 {
   342     int entry = (addr & 0x00001FFC);
   343     return *(uint32_t *)&ccn_icache_data[entry];
   344 }
   346 static void FASTCALL ccn_icache_data_write( sh4addr_t addr, uint32_t val )
   347 {
   348     int entry = (addr & 0x00001FFC);
   349     *(uint32_t *)&ccn_icache_data[entry] = val;    
   350 }
   352 struct mem_region_fn p4_region_icache_data = {
   353         ccn_icache_data_read, ccn_icache_data_write,
   354         unmapped_read_long, unmapped_write_long,
   355         unmapped_read_long, unmapped_write_long,
   356         unmapped_read_burst, unmapped_write_burst,
   357         unmapped_prefetch, unmapped_read_long };
   359 static int32_t FASTCALL ccn_ocache_addr_read( sh4addr_t addr )
   360 {
   361     int entry = (addr & 0x00003FE0);
   362     sh4addr_t tag = ccn_ocache[entry>>5].tag;
   363     return (tag&0x1FFFFC00) | ccn_cache_map[tag>>5];
   364 }
   366 static void FASTCALL ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
   367 {
   368     int entry = (addr & 0x00003FE0);
   369     struct cache_line *line = &ccn_ocache[entry>>5];
   370     if( addr & 0x08 ) { // Associative
   371     } else {
   372         sh4addr_t tag = line->tag;
   373         if( ccn_cache_map[tag>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
   374             // Cache line is dirty - writeback. 
   375             unsigned char *cache_data = &ccn_ocache_data[entry];
   376             ext_address_space[tag>>12]->write_burst(tag, cache_data);
   377         }
   378         line->tag = tag = (val & 0x1FFFFC00) | (addr & 0x3E0);
   379         ccn_cache_map[tag>>5] = val & 0x03;
   380     }
   381 }
   383 struct mem_region_fn p4_region_ocache_addr = {
   384         ccn_ocache_addr_read, ccn_ocache_addr_write,
   385         unmapped_read_long, unmapped_write_long,
   386         unmapped_read_long, unmapped_write_long,
   387         unmapped_read_burst, unmapped_write_burst,
   388         unmapped_prefetch, unmapped_read_long };
   391 static int32_t FASTCALL ccn_ocache_data_read( sh4addr_t addr )
   392 {
   393     int entry = (addr & 0x00003FFC);
   394     return *(uint32_t *)&ccn_ocache_data[entry];
   395 }
   397 static void FASTCALL ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
   398 {
   399     int entry = (addr & 0x00003FFC);
   400     *(uint32_t *)&ccn_ocache_data[entry] = val;
   401 }
   403 struct mem_region_fn p4_region_ocache_data = {
   404         ccn_ocache_data_read, ccn_ocache_data_write,
   405         unmapped_read_long, unmapped_write_long,
   406         unmapped_read_long, unmapped_write_long,
   407         unmapped_read_burst, unmapped_write_burst,
   408         unmapped_prefetch, unmapped_read_long };
   411 /****************** Cache control *********************/
   413 void CCN_set_cache_control( int reg )
   414 {
   415     uint32_t i;
   417     if( reg & CCR_ICI ) { /* icache invalidate */
   418         for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
   419             ccn_icache[i].key = -1;
   420             ccn_icache[i].tag &= ~CACHE_VALID;
   421         }
   422     }
   424     if( reg & CCR_OCI ) { /* ocache invalidate */
   425         for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
   426             ccn_ocache[i].key = -1;
   427             ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
   428         }
   429     }
   431     switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
   432     case MEM_OC_INDEX0: /* OIX=0 */
   433         for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
   434             sh4_address_space[i] = &mem_region_ocram_page0;
   435             sh4_address_space[i+1] = &mem_region_ocram_page0;
   436             sh4_address_space[i+2] = &mem_region_ocram_page1;
   437             sh4_address_space[i+3] = &mem_region_ocram_page1;
   438         }
   439         break;
   440     case MEM_OC_INDEX1: /* OIX=1 */
   441         for( i=OCRAM_START; i<OCRAM_MID; i++ )
   442             sh4_address_space[i] = &mem_region_ocram_page0;
   443         for( i=OCRAM_MID; i<OCRAM_END; i++ )
   444             sh4_address_space[i] = &mem_region_ocram_page1;
   445         break;
   446     default: /* disabled */
   447         for( i=OCRAM_START; i<OCRAM_END; i++ )
   448             sh4_address_space[i] = &mem_region_unmapped;
   449         break;
   450     }
   451 }
   453 /**
   454  * Prefetch for non-storequeue regions
   455  */
   456 void FASTCALL ccn_prefetch( sh4addr_t addr )
   457 {
   459 }
   461 /************************** Uncached memory access ***************************/
   462 int32_t FASTCALL ccn_uncached_read_long( sh4addr_t addr )
   463 {
   464     sh4r.slice_cycle += (4*sh4_bus_period);
   465     addr &= 0x1FFFFFFF;
   466     return ext_address_space[addr>>12]->read_long(addr);
   467 }
   468 int32_t FASTCALL ccn_uncached_read_word( sh4addr_t addr )
   469 {
   470     sh4r.slice_cycle += (4*sh4_bus_period);
   471     addr &= 0x1FFFFFFF;
   472     return ext_address_space[addr>>12]->read_word(addr);
   473 }
   474 int32_t FASTCALL ccn_uncached_read_byte( sh4addr_t addr )
   475 {
   476     sh4r.slice_cycle += (4*sh4_bus_period);
   477     addr &= 0x1FFFFFFF;
   478     return ext_address_space[addr>>12]->read_byte(addr);
   479 }
   480 void FASTCALL ccn_uncached_write_long( sh4addr_t addr, uint32_t val )
   481 {
   482     sh4r.slice_cycle += (4*sh4_bus_period);
   483     addr &= 0x1FFFFFFF;
   484     return ext_address_space[addr>>12]->write_long(addr, val);
   485 }
   486 void FASTCALL ccn_uncached_write_word( sh4addr_t addr, uint32_t val )
   487 {
   488     sh4r.slice_cycle += (4*sh4_bus_period);
   489     addr &= 0x1FFFFFFF;
   490     return ext_address_space[addr>>12]->write_word(addr, val);
   491 }
   492 void FASTCALL ccn_uncached_write_byte( sh4addr_t addr, uint32_t val )
   493 {
   494     sh4r.slice_cycle += (4*sh4_bus_period);
   495     addr &= 0x1FFFFFFF;
   496     return ext_address_space[addr>>12]->write_byte(addr, val);
   497 }
   498 void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )
   499 {
   500 }
   502 struct mem_region_fn ccn_uncached_region = {
   503         ccn_uncached_read_long, ccn_uncached_write_long,
   504         ccn_uncached_read_word, ccn_uncached_write_word,
   505         ccn_uncached_read_byte, ccn_uncached_write_byte,
   506         unmapped_read_burst, unmapped_write_burst,
   507         ccn_uncached_prefetch, ccn_uncached_read_byte };
   510 /********************************* Store-queue *******************************/
   511 /*
   512  * The storequeue is strictly speaking part of the cache, but most of 
   513  * the complexity is actually around its addressing (ie in the MMU). The
   514  * methods here can assume we've already passed SQMD protection and the TLB
   515  * lookups (where appropriate).
   516  */  
   517 void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val )
   518 {
   519     sh4r.store_queue[(addr>>2)&0xF] = val;
   520 }
   521 int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr )
   522 {
   523     return sh4r.store_queue[(addr>>2)&0xF];
   524 }
   526 /**
   527  * Variant used when tlb is disabled - address will be the original prefetch
   528  * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't
   529  * be hardcoded on 4K page boundaries, so we manually decode it here.
   530  */
   531 void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr ) 
   532 {
   533     int queue = (addr&0x20)>>2;
   534     sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
   535     uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24;
   536     sh4addr_t target = (addr&0x03FFFFE0) | hi;
   537     ext_address_space[target>>12]->write_burst( target, src );
   538 }
   540 /**
   541  * Variant used when tlb is enabled - address in this case is already
   542  * mapped to the external target address.
   543  */
   544 void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr )
   545 {
   546     int queue = (addr&0x20)>>2;
   547     sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
   548     ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );
   549 }
.