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 Mon Feb 13 20:00:27 2012 +1000 (12 years ago)
permissions -rw-r--r--
last change Fix MMU on non-translated platforms
- reintroduce old VMA translation functions (slightly modified)
- modify shadow processing to work on post-translated memory ops
file annotate diff log raw
nkeynes@931
     1
/**
nkeynes@931
     2
 * $Id$
nkeynes@939
     3
 * Implements the on-chip operand cache, instruction cache, and store queue.
nkeynes@931
     4
 *
nkeynes@931
     5
 * Copyright (c) 2008 Nathan Keynes.
nkeynes@931
     6
 *
nkeynes@931
     7
 * This program is free software; you can redistribute it and/or modify
nkeynes@931
     8
 * it under the terms of the GNU General Public License as published by
nkeynes@931
     9
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@931
    10
 * (at your option) any later version.
nkeynes@931
    11
 *
nkeynes@931
    12
 * This program is distributed in the hope that it will be useful,
nkeynes@931
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@931
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@931
    15
 * GNU General Public License for more details.
nkeynes@931
    16
 */
nkeynes@931
    17
nkeynes@931
    18
#define MODULE sh4_module
nkeynes@931
    19
nkeynes@931
    20
#include <string.h>
nkeynes@931
    21
#include "dream.h"
nkeynes@931
    22
#include "mem.h"
nkeynes@931
    23
#include "mmio.h"
nkeynes@971
    24
#include "clock.h"
nkeynes@931
    25
#include "sh4/sh4core.h"
nkeynes@931
    26
#include "sh4/sh4mmio.h"
nkeynes@946
    27
#include "sh4/mmu.h"
nkeynes@931
    28
nkeynes@931
    29
#define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)
nkeynes@931
    30
#define OCRAM_MID   (0x7E000000>>LXDREAM_PAGE_BITS)
nkeynes@931
    31
#define OCRAM_END   (0x80000000>>LXDREAM_PAGE_BITS)
nkeynes@931
    32
nkeynes@931
    33
#define CACHE_VALID 1
nkeynes@931
    34
#define CACHE_DIRTY 2
nkeynes@931
    35
nkeynes@931
    36
#define ICACHE_ENTRY_COUNT 256
nkeynes@931
    37
#define OCACHE_ENTRY_COUNT 512
nkeynes@931
    38
nkeynes@931
    39
struct cache_line {
nkeynes@931
    40
    uint32_t key;  // Fast address match - bits 5..28 for valid entry, -1 for invalid entry
nkeynes@931
    41
    uint32_t tag;  // tag + flags value from the address field
nkeynes@931
    42
};    
nkeynes@931
    43
nkeynes@931
    44
nkeynes@931
    45
static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
nkeynes@971
    46
struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
nkeynes@931
    47
static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
nkeynes@971
    48
unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
nkeynes@931
    49
nkeynes@931
    50
nkeynes@931
    51
/*********************** General module requirements ********************/
nkeynes@931
    52
nkeynes@971
    53
void CCN_reset()
nkeynes@971
    54
{
nkeynes@971
    55
    /* Clear everything for consistency */
nkeynes@971
    56
    memset( ccn_icache, 0, sizeof(ccn_icache) );
nkeynes@971
    57
    memset( ccn_ocache, 0, sizeof(ccn_icache) );
nkeynes@971
    58
    memset( ccn_icache_data, 0, sizeof(ccn_icache) );
nkeynes@971
    59
    memset( ccn_ocache_data, 0, sizeof(ccn_icache) );
nkeynes@971
    60
}
nkeynes@971
    61
nkeynes@931
    62
void CCN_save_state( FILE *f )
nkeynes@931
    63
{
nkeynes@931
    64
    fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
nkeynes@931
    65
    fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
nkeynes@931
    66
    fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
nkeynes@931
    67
    fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
nkeynes@931
    68
}
nkeynes@931
    69
nkeynes@931
    70
int CCN_load_state( FILE *f )
nkeynes@931
    71
{
nkeynes@931
    72
    /* Setup the cache mode according to the saved register value
nkeynes@931
    73
     * (mem_load runs before this point to load all MMIO data)
nkeynes@931
    74
     */
nkeynes@931
    75
    mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
nkeynes@931
    76
nkeynes@931
    77
    if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
nkeynes@931
    78
        return 1;
nkeynes@931
    79
    }
nkeynes@931
    80
    if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
nkeynes@931
    81
        return 1;
nkeynes@931
    82
    }
nkeynes@931
    83
    if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
nkeynes@931
    84
        return 1;
nkeynes@931
    85
    }
nkeynes@931
    86
    if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
nkeynes@931
    87
        return 1;
nkeynes@931
    88
    }
nkeynes@931
    89
    return 0;
nkeynes@931
    90
}
nkeynes@931
    91
nkeynes@931
    92
/************************* OCRAM memory address space ************************/
nkeynes@931
    93
nkeynes@931
    94
#define OCRAMPAGE0 (&ccn_ocache_data[4096])  /* Lines 128-255 */
nkeynes@931
    95
#define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */
nkeynes@931
    96
nkeynes@931
    97
static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr )
nkeynes@931
    98
{
nkeynes@931
    99
    return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));
nkeynes@931
   100
}
nkeynes@931
   101
static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )
nkeynes@931
   102
{
nkeynes@931
   103
    return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
nkeynes@931
   104
}
nkeynes@931
   105
static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )
nkeynes@931
   106
{
nkeynes@931
   107
    return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
nkeynes@931
   108
}
nkeynes@931
   109
static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )
nkeynes@931
   110
{
nkeynes@931
   111
    *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;
nkeynes@931
   112
}
nkeynes@931
   113
static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )
nkeynes@931
   114
{
nkeynes@931
   115
    *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;
nkeynes@931
   116
}
nkeynes@931
   117
static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@931
   118
{
nkeynes@931
   119
    *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;
nkeynes@931
   120
}
nkeynes@931
   121
static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@931
   122
{
nkeynes@931
   123
    memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );
nkeynes@931
   124
}
nkeynes@931
   125
static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@931
   126
{
nkeynes@931
   127
    memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );
nkeynes@931
   128
}
nkeynes@931
   129
nkeynes@931
   130
struct mem_region_fn mem_region_ocram_page0 = {
nkeynes@931
   131
        ocram_page0_read_long, ocram_page0_write_long,
nkeynes@931
   132
        ocram_page0_read_word, ocram_page0_write_word,
nkeynes@931
   133
        ocram_page0_read_byte, ocram_page0_write_byte,
nkeynes@946
   134
        ocram_page0_read_burst, ocram_page0_write_burst,
nkeynes@975
   135
        unmapped_prefetch, ocram_page0_read_byte };
nkeynes@931
   136
nkeynes@931
   137
static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
nkeynes@931
   138
{
nkeynes@931
   139
    return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
nkeynes@931
   140
}
nkeynes@931
   141
static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
nkeynes@931
   142
{
nkeynes@931
   143
    return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
nkeynes@931
   144
}
nkeynes@931
   145
static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
nkeynes@931
   146
{
nkeynes@931
   147
    return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
nkeynes@931
   148
}
nkeynes@931
   149
static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
nkeynes@931
   150
{
nkeynes@931
   151
    *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
nkeynes@931
   152
}
nkeynes@931
   153
static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
nkeynes@931
   154
{
nkeynes@931
   155
    *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
nkeynes@931
   156
}
nkeynes@931
   157
static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@931
   158
{
nkeynes@931
   159
    *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
nkeynes@931
   160
}
nkeynes@931
   161
static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@931
   162
{
nkeynes@931
   163
    memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
nkeynes@931
   164
}
nkeynes@931
   165
static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@931
   166
{
nkeynes@931
   167
    memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
nkeynes@931
   168
}
nkeynes@931
   169
nkeynes@931
   170
struct mem_region_fn mem_region_ocram_page1 = {
nkeynes@931
   171
        ocram_page1_read_long, ocram_page1_write_long,
nkeynes@931
   172
        ocram_page1_read_word, ocram_page1_write_word,
nkeynes@931
   173
        ocram_page1_read_byte, ocram_page1_write_byte,
nkeynes@946
   174
        ocram_page1_read_burst, ocram_page1_write_burst,
nkeynes@975
   175
        unmapped_prefetch, ocram_page1_read_byte };
nkeynes@953
   176
nkeynes@971
   177
/**************************** Cache functions ********************************/
nkeynes@971
   178
char ccn_cache_map[16 MB]; // 24 bits of address space
nkeynes@971
   179
nkeynes@971
   180
/**
nkeynes@971
   181
 * Load a 32-byte cache line from external memory at the given ext address.
nkeynes@971
   182
 * @param addr external address pre-masked to 1FFFFFFE0 
nkeynes@971
   183
 */
nkeynes@971
   184
sh4addr_t FASTCALL ccn_ocache_load_line( sh4addr_t addr )
nkeynes@971
   185
{
nkeynes@971
   186
    int entry = addr & 0x00003FE0;
nkeynes@971
   187
    struct cache_line *line = &ccn_ocache[entry>>5];
nkeynes@980
   188
    unsigned char *cache_data = &ccn_ocache_data[entry];
nkeynes@971
   189
    sh4addr_t old_addr = line->tag;
nkeynes@971
   190
    line->tag = addr & 0x1FFFFFE0;
nkeynes@971
   191
    char oldstate = ccn_cache_map[old_addr>>5];
nkeynes@971
   192
    ccn_cache_map[old_addr>>5] = 0;
nkeynes@971
   193
    ccn_cache_map[addr>>5] = CACHE_VALID;
nkeynes@971
   194
    if( oldstate == (CACHE_VALID|CACHE_DIRTY) ) {
nkeynes@971
   195
        // Cache line is dirty - writeback. 
nkeynes@971
   196
        ext_address_space[old_addr>>12]->write_burst(old_addr, cache_data);
nkeynes@971
   197
    }
nkeynes@971
   198
    ext_address_space[addr>>12]->read_burst(cache_data, addr & 0x1FFFFFE0);
nkeynes@971
   199
    return addr;
nkeynes@971
   200
}
nkeynes@971
   201
nkeynes@971
   202
/* Long read through the operand cache */
nkeynes@971
   203
/*
nkeynes@971
   204
int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr );
nkeynes@971
   205
int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr );
nkeynes@971
   206
int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr );
nkeynes@971
   207
void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t val );
nkeynes@971
   208
void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t val );
nkeynes@971
   209
void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t val );
nkeynes@971
   210
nkeynes@971
   211
*/
nkeynes@971
   212
static int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr )
nkeynes@971
   213
{
nkeynes@971
   214
    addr &= 0x1FFFFFFF;
nkeynes@971
   215
    if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
nkeynes@971
   216
        ccn_ocache_load_line(addr);
nkeynes@971
   217
    }
nkeynes@971
   218
    return *(int32_t *)&ccn_ocache_data[addr & 0x3FFF];
nkeynes@971
   219
}
nkeynes@971
   220
nkeynes@971
   221
static int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr )
nkeynes@971
   222
{
nkeynes@971
   223
    addr &= 0x1FFFFFFF;
nkeynes@971
   224
    if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
nkeynes@971
   225
        ccn_ocache_load_line(addr);
nkeynes@971
   226
    }
nkeynes@971
   227
    return SIGNEXT16(*(int16_t *)&ccn_ocache_data[addr&0x3FFF]);    
nkeynes@971
   228
}
nkeynes@971
   229
nkeynes@971
   230
static int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr )
nkeynes@971
   231
{
nkeynes@971
   232
    addr &= 0x1FFFFFFF;
nkeynes@971
   233
    if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
nkeynes@971
   234
        ccn_ocache_load_line(addr);
nkeynes@971
   235
    }
nkeynes@971
   236
    return SIGNEXT8(ccn_ocache_data[addr&0x3FFF]);        
nkeynes@971
   237
}
nkeynes@971
   238
nkeynes@971
   239
static void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t value )
nkeynes@971
   240
{
nkeynes@971
   241
    addr &= 0x1FFFFFFF;
nkeynes@971
   242
    if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
nkeynes@971
   243
        ccn_ocache_load_line(addr);
nkeynes@971
   244
    }
nkeynes@971
   245
    ccn_cache_map[addr>>5] |= CACHE_DIRTY;
nkeynes@971
   246
    *(uint32_t *)&ccn_ocache_data[addr&0x3FFF] = value;
nkeynes@971
   247
}
nkeynes@971
   248
nkeynes@971
   249
static void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t value )
nkeynes@971
   250
{
nkeynes@971
   251
    addr &= 0x1FFFFFFF;
nkeynes@971
   252
    if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
nkeynes@971
   253
        ccn_ocache_load_line(addr);
nkeynes@971
   254
    }
nkeynes@971
   255
    ccn_cache_map[addr>>5] |= CACHE_DIRTY;
nkeynes@971
   256
    *(uint16_t *)&ccn_ocache_data[addr&0x3FFF] = (uint16_t)value;
nkeynes@971
   257
}
nkeynes@971
   258
nkeynes@971
   259
static void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t value )
nkeynes@971
   260
{
nkeynes@971
   261
    addr &= 0x1FFFFFFF;
nkeynes@971
   262
    if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
nkeynes@971
   263
        ccn_ocache_load_line(addr);
nkeynes@971
   264
    }
nkeynes@971
   265
    ccn_cache_map[addr>>5] |= CACHE_DIRTY;
nkeynes@971
   266
    ccn_ocache_data[addr&0x3FFF] = (uint8_t)value;
nkeynes@971
   267
}
nkeynes@971
   268
nkeynes@971
   269
static void FASTCALL ccn_ocache_prefetch( sh4addr_t addr )
nkeynes@971
   270
{
nkeynes@971
   271
    addr &= 0x1FFFFFFF;
nkeynes@971
   272
    if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) {
nkeynes@971
   273
        ccn_ocache_load_line(addr);
nkeynes@971
   274
    }
nkeynes@971
   275
}
nkeynes@971
   276
nkeynes@971
   277
void FASTCALL ccn_ocache_invalidate( sh4addr_t addr )
nkeynes@971
   278
{
nkeynes@971
   279
    addr &= 0x1FFFFFFF;
nkeynes@971
   280
    ccn_cache_map[addr>>5] &= ~CACHE_VALID;
nkeynes@971
   281
}
nkeynes@971
   282
nkeynes@971
   283
void FASTCALL ccn_ocache_purge( sh4addr_t addr )
nkeynes@971
   284
{
nkeynes@971
   285
    addr &= 0x1FFFFFE0;
nkeynes@971
   286
    int oldflags = ccn_cache_map[addr>>5]; 
nkeynes@971
   287
    ccn_cache_map[addr>>5] &= ~CACHE_VALID;
nkeynes@971
   288
    if( oldflags == (CACHE_VALID|CACHE_DIRTY) ) {
nkeynes@980
   289
        unsigned char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
nkeynes@971
   290
        ext_address_space[addr>>12]->write_burst(addr, cache_data);
nkeynes@971
   291
    }
nkeynes@971
   292
}
nkeynes@971
   293
nkeynes@971
   294
void FASTCALL ccn_ocache_writeback( sh4addr_t addr )
nkeynes@971
   295
{
nkeynes@971
   296
    addr &= 0x1FFFFFE0;
nkeynes@971
   297
    if( ccn_cache_map[addr>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
nkeynes@971
   298
        ccn_cache_map[addr>>5] &= ~CACHE_DIRTY;
nkeynes@980
   299
        unsigned char *cache_data = &ccn_ocache_data[addr & 0x3FE0];
nkeynes@971
   300
        ext_address_space[addr>>12]->write_burst(addr, cache_data);
nkeynes@971
   301
    }
nkeynes@971
   302
}
nkeynes@971
   303
nkeynes@971
   304
struct mem_region_fn ccn_ocache_cb_region = {
nkeynes@971
   305
    ccn_ocache_read_long, ccn_ocache_write_long_copyback,
nkeynes@971
   306
    ccn_ocache_read_word, ccn_ocache_write_word_copyback,
nkeynes@971
   307
    ccn_ocache_read_byte, ccn_ocache_write_byte_copyback,
nkeynes@971
   308
    unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   309
    ccn_ocache_prefetch, ccn_ocache_read_byte };
nkeynes@971
   310
nkeynes@931
   311
nkeynes@933
   312
/************************** Cache direct access ******************************/
nkeynes@933
   313
nkeynes@968
   314
static int32_t FASTCALL ccn_icache_addr_read( sh4addr_t addr )
nkeynes@933
   315
{
nkeynes@933
   316
    int entry = (addr & 0x00001FE0);
nkeynes@933
   317
    return ccn_icache[entry>>5].tag;
nkeynes@933
   318
}
nkeynes@933
   319
nkeynes@968
   320
static void FASTCALL ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   321
{
nkeynes@933
   322
    int entry = (addr & 0x00003FE0);
nkeynes@933
   323
    struct cache_line *line = &ccn_ocache[entry>>5];
nkeynes@933
   324
    if( addr & 0x08 ) { // Associative
nkeynes@933
   325
        /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
nkeynes@933
   326
    } else {
nkeynes@933
   327
        line->tag = val & 0x1FFFFC01;
nkeynes@933
   328
        line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
nkeynes@933
   329
    }
nkeynes@933
   330
}
nkeynes@933
   331
nkeynes@933
   332
struct mem_region_fn p4_region_icache_addr = {
nkeynes@933
   333
        ccn_icache_addr_read, ccn_icache_addr_write,
nkeynes@933
   334
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   335
        unmapped_read_long, unmapped_write_long,
nkeynes@946
   336
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   337
        unmapped_prefetch, unmapped_read_long };
nkeynes@933
   338
nkeynes@933
   339
nkeynes@968
   340
static int32_t FASTCALL ccn_icache_data_read( sh4addr_t addr )
nkeynes@933
   341
{
nkeynes@933
   342
    int entry = (addr & 0x00001FFC);
nkeynes@933
   343
    return *(uint32_t *)&ccn_icache_data[entry];
nkeynes@933
   344
}
nkeynes@933
   345
nkeynes@968
   346
static void FASTCALL ccn_icache_data_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   347
{
nkeynes@933
   348
    int entry = (addr & 0x00001FFC);
nkeynes@933
   349
    *(uint32_t *)&ccn_icache_data[entry] = val;    
nkeynes@933
   350
}
nkeynes@933
   351
nkeynes@933
   352
struct mem_region_fn p4_region_icache_data = {
nkeynes@933
   353
        ccn_icache_data_read, ccn_icache_data_write,
nkeynes@933
   354
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   355
        unmapped_read_long, unmapped_write_long,
nkeynes@946
   356
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   357
        unmapped_prefetch, unmapped_read_long };
nkeynes@933
   358
nkeynes@968
   359
static int32_t FASTCALL ccn_ocache_addr_read( sh4addr_t addr )
nkeynes@933
   360
{
nkeynes@933
   361
    int entry = (addr & 0x00003FE0);
nkeynes@971
   362
    sh4addr_t tag = ccn_ocache[entry>>5].tag;
nkeynes@971
   363
    return (tag&0x1FFFFC00) | ccn_cache_map[tag>>5];
nkeynes@933
   364
}
nkeynes@933
   365
nkeynes@968
   366
static void FASTCALL ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   367
{
nkeynes@933
   368
    int entry = (addr & 0x00003FE0);
nkeynes@933
   369
    struct cache_line *line = &ccn_ocache[entry>>5];
nkeynes@933
   370
    if( addr & 0x08 ) { // Associative
nkeynes@933
   371
    } else {
nkeynes@971
   372
        sh4addr_t tag = line->tag;
nkeynes@971
   373
        if( ccn_cache_map[tag>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
nkeynes@933
   374
            // Cache line is dirty - writeback. 
nkeynes@971
   375
            unsigned char *cache_data = &ccn_ocache_data[entry];
nkeynes@971
   376
            ext_address_space[tag>>12]->write_burst(tag, cache_data);
nkeynes@933
   377
        }
nkeynes@971
   378
        line->tag = tag = (val & 0x1FFFFC00) | (addr & 0x3E0);
nkeynes@971
   379
        ccn_cache_map[tag>>5] = val & 0x03;
nkeynes@933
   380
    }
nkeynes@933
   381
}
nkeynes@933
   382
nkeynes@933
   383
struct mem_region_fn p4_region_ocache_addr = {
nkeynes@933
   384
        ccn_ocache_addr_read, ccn_ocache_addr_write,
nkeynes@933
   385
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   386
        unmapped_read_long, unmapped_write_long,
nkeynes@946
   387
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   388
        unmapped_prefetch, unmapped_read_long };
nkeynes@933
   389
nkeynes@933
   390
nkeynes@968
   391
static int32_t FASTCALL ccn_ocache_data_read( sh4addr_t addr )
nkeynes@933
   392
{
nkeynes@933
   393
    int entry = (addr & 0x00003FFC);
nkeynes@933
   394
    return *(uint32_t *)&ccn_ocache_data[entry];
nkeynes@933
   395
}
nkeynes@933
   396
nkeynes@968
   397
static void FASTCALL ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   398
{
nkeynes@933
   399
    int entry = (addr & 0x00003FFC);
nkeynes@933
   400
    *(uint32_t *)&ccn_ocache_data[entry] = val;
nkeynes@933
   401
}
nkeynes@933
   402
nkeynes@933
   403
struct mem_region_fn p4_region_ocache_data = {
nkeynes@933
   404
        ccn_ocache_data_read, ccn_ocache_data_write,
nkeynes@933
   405
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   406
        unmapped_read_long, unmapped_write_long,
nkeynes@946
   407
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   408
        unmapped_prefetch, unmapped_read_long };
nkeynes@933
   409
nkeynes@933
   410
nkeynes@931
   411
/****************** Cache control *********************/
nkeynes@931
   412
nkeynes@931
   413
void CCN_set_cache_control( int reg )
nkeynes@931
   414
{
nkeynes@931
   415
    uint32_t i;
nkeynes@933
   416
    
nkeynes@933
   417
    if( reg & CCR_ICI ) { /* icache invalidate */
nkeynes@933
   418
        for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
nkeynes@971
   419
            ccn_icache[i].key = -1;
nkeynes@933
   420
            ccn_icache[i].tag &= ~CACHE_VALID;
nkeynes@933
   421
        }
nkeynes@933
   422
    }
nkeynes@933
   423
    
nkeynes@933
   424
    if( reg & CCR_OCI ) { /* ocache invalidate */
nkeynes@933
   425
        for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
nkeynes@983
   426
            ccn_ocache[i].key = -1;
nkeynes@933
   427
            ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
nkeynes@933
   428
        }
nkeynes@933
   429
    }
nkeynes@933
   430
    
nkeynes@931
   431
    switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
nkeynes@931
   432
    case MEM_OC_INDEX0: /* OIX=0 */
nkeynes@931
   433
        for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
nkeynes@931
   434
            sh4_address_space[i] = &mem_region_ocram_page0;
nkeynes@931
   435
            sh4_address_space[i+1] = &mem_region_ocram_page0;
nkeynes@931
   436
            sh4_address_space[i+2] = &mem_region_ocram_page1;
nkeynes@931
   437
            sh4_address_space[i+3] = &mem_region_ocram_page1;
nkeynes@931
   438
        }
nkeynes@931
   439
        break;
nkeynes@931
   440
    case MEM_OC_INDEX1: /* OIX=1 */
nkeynes@931
   441
        for( i=OCRAM_START; i<OCRAM_MID; i++ )
nkeynes@931
   442
            sh4_address_space[i] = &mem_region_ocram_page0;
nkeynes@931
   443
        for( i=OCRAM_MID; i<OCRAM_END; i++ )
nkeynes@931
   444
            sh4_address_space[i] = &mem_region_ocram_page1;
nkeynes@931
   445
        break;
nkeynes@931
   446
    default: /* disabled */
nkeynes@931
   447
        for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@931
   448
            sh4_address_space[i] = &mem_region_unmapped;
nkeynes@931
   449
        break;
nkeynes@931
   450
    }
nkeynes@939
   451
}
nkeynes@939
   452
nkeynes@946
   453
/**
nkeynes@946
   454
 * Prefetch for non-storequeue regions
nkeynes@946
   455
 */
nkeynes@946
   456
void FASTCALL ccn_prefetch( sh4addr_t addr )
nkeynes@946
   457
{
nkeynes@946
   458
    
nkeynes@946
   459
}
nkeynes@939
   460
nkeynes@971
   461
/************************** Uncached memory access ***************************/
nkeynes@971
   462
int32_t FASTCALL ccn_uncached_read_long( sh4addr_t addr )
nkeynes@971
   463
{
nkeynes@971
   464
    sh4r.slice_cycle += (4*sh4_bus_period);
nkeynes@971
   465
    addr &= 0x1FFFFFFF;
nkeynes@971
   466
    return ext_address_space[addr>>12]->read_long(addr);
nkeynes@971
   467
}
nkeynes@971
   468
int32_t FASTCALL ccn_uncached_read_word( sh4addr_t addr )
nkeynes@971
   469
{
nkeynes@971
   470
    sh4r.slice_cycle += (4*sh4_bus_period);
nkeynes@971
   471
    addr &= 0x1FFFFFFF;
nkeynes@971
   472
    return ext_address_space[addr>>12]->read_word(addr);
nkeynes@971
   473
}
nkeynes@971
   474
int32_t FASTCALL ccn_uncached_read_byte( sh4addr_t addr )
nkeynes@971
   475
{
nkeynes@971
   476
    sh4r.slice_cycle += (4*sh4_bus_period);
nkeynes@971
   477
    addr &= 0x1FFFFFFF;
nkeynes@971
   478
    return ext_address_space[addr>>12]->read_byte(addr);
nkeynes@971
   479
}
nkeynes@971
   480
void FASTCALL ccn_uncached_write_long( sh4addr_t addr, uint32_t val )
nkeynes@971
   481
{
nkeynes@971
   482
    sh4r.slice_cycle += (4*sh4_bus_period);
nkeynes@971
   483
    addr &= 0x1FFFFFFF;
nkeynes@971
   484
    return ext_address_space[addr>>12]->write_long(addr, val);
nkeynes@971
   485
}
nkeynes@971
   486
void FASTCALL ccn_uncached_write_word( sh4addr_t addr, uint32_t val )
nkeynes@971
   487
{
nkeynes@971
   488
    sh4r.slice_cycle += (4*sh4_bus_period);
nkeynes@971
   489
    addr &= 0x1FFFFFFF;
nkeynes@971
   490
    return ext_address_space[addr>>12]->write_word(addr, val);
nkeynes@971
   491
}
nkeynes@971
   492
void FASTCALL ccn_uncached_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@971
   493
{
nkeynes@971
   494
    sh4r.slice_cycle += (4*sh4_bus_period);
nkeynes@971
   495
    addr &= 0x1FFFFFFF;
nkeynes@971
   496
    return ext_address_space[addr>>12]->write_byte(addr, val);
nkeynes@971
   497
}
nkeynes@946
   498
void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )
nkeynes@946
   499
{
nkeynes@946
   500
}
nkeynes@971
   501
nkeynes@971
   502
struct mem_region_fn ccn_uncached_region = {
nkeynes@971
   503
        ccn_uncached_read_long, ccn_uncached_write_long,
nkeynes@971
   504
        ccn_uncached_read_word, ccn_uncached_write_word,
nkeynes@971
   505
        ccn_uncached_read_byte, ccn_uncached_write_byte,
nkeynes@971
   506
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   507
        ccn_uncached_prefetch, ccn_uncached_read_byte };
nkeynes@971
   508
nkeynes@971
   509
nkeynes@946
   510
/********************************* Store-queue *******************************/
nkeynes@946
   511
/*
nkeynes@946
   512
 * The storequeue is strictly speaking part of the cache, but most of 
nkeynes@946
   513
 * the complexity is actually around its addressing (ie in the MMU). The
nkeynes@946
   514
 * methods here can assume we've already passed SQMD protection and the TLB
nkeynes@946
   515
 * lookups (where appropriate).
nkeynes@946
   516
 */  
nkeynes@946
   517
void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val )
nkeynes@939
   518
{
nkeynes@939
   519
    sh4r.store_queue[(addr>>2)&0xF] = val;
nkeynes@939
   520
}
nkeynes@946
   521
int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr )
nkeynes@939
   522
{
nkeynes@939
   523
    return sh4r.store_queue[(addr>>2)&0xF];
nkeynes@939
   524
}
nkeynes@939
   525
nkeynes@946
   526
/**
nkeynes@946
   527
 * Variant used when tlb is disabled - address will be the original prefetch
nkeynes@946
   528
 * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't
nkeynes@946
   529
 * be hardcoded on 4K page boundaries, so we manually decode it here.
nkeynes@946
   530
 */
nkeynes@946
   531
void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr ) 
nkeynes@946
   532
{
nkeynes@946
   533
    int queue = (addr&0x20)>>2;
nkeynes@946
   534
    sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
nkeynes@946
   535
    uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24;
nkeynes@946
   536
    sh4addr_t target = (addr&0x03FFFFE0) | hi;
nkeynes@946
   537
    ext_address_space[target>>12]->write_burst( target, src );
nkeynes@946
   538
}
nkeynes@946
   539
nkeynes@946
   540
/**
nkeynes@946
   541
 * Variant used when tlb is enabled - address in this case is already
nkeynes@946
   542
 * mapped to the external target address.
nkeynes@946
   543
 */
nkeynes@946
   544
void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr )
nkeynes@946
   545
{
nkeynes@946
   546
    int queue = (addr&0x20)>>2;
nkeynes@946
   547
    sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
nkeynes@946
   548
    ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );
nkeynes@946
   549
}
nkeynes@971
   550
.