Search
lxdream.org :: lxdream/src/sh4/cache.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/cache.c
changeset 980:deb4361928fe
prev975:007bf7eb944f
next983:b0d0785aa194
author nkeynes
date Wed Feb 04 21:45:21 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Fix signedness in mmu_ext_page_remapped (Thanks kaz!)
Fix fallthrough case in mmu_utlb_entry_for_vpn
Fix signedness warnings in cache.c
file annotate diff log raw
nkeynes@953
     1
/**
nkeynes@953
     2
 * $Id$
nkeynes@953
     3
 * Implements the on-chip operand cache, instruction cache, and store queue.
nkeynes@953
     4
 *
nkeynes@953
     5
 * Copyright (c) 2008 Nathan Keynes.
nkeynes@953
     6
 *
nkeynes@953
     7
 * This program is free software; you can redistribute it and/or modify
nkeynes@953
     8
 * it under the terms of the GNU General Public License as published by
nkeynes@953
     9
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@953
    10
 * (at your option) any later version.
nkeynes@953
    11
 *
nkeynes@953
    12
 * This program is distributed in the hope that it will be useful,
nkeynes@953
    13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@953
    14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@953
    15
 * GNU General Public License for more details.
nkeynes@953
    16
 */
nkeynes@953
    17
nkeynes@953
    18
#define MODULE sh4_module
nkeynes@953
    19
nkeynes@953
    20
#include <string.h>
nkeynes@953
    21
#include "dream.h"
nkeynes@953
    22
#include "mem.h"
nkeynes@953
    23
#include "mmio.h"
nkeynes@971
    24
#include "clock.h"
nkeynes@953
    25
#include "sh4/sh4core.h"
nkeynes@953
    26
#include "sh4/sh4mmio.h"
nkeynes@953
    27
#include "sh4/mmu.h"
nkeynes@953
    28
nkeynes@953
    29
#define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)
nkeynes@953
    30
#define OCRAM_MID   (0x7E000000>>LXDREAM_PAGE_BITS)
nkeynes@953
    31
#define OCRAM_END   (0x80000000>>LXDREAM_PAGE_BITS)
nkeynes@953
    32
nkeynes@953
    33
#define CACHE_VALID 1
nkeynes@953
    34
#define CACHE_DIRTY 2
nkeynes@953
    35
nkeynes@953
    36
#define ICACHE_ENTRY_COUNT 256
nkeynes@953
    37
#define OCACHE_ENTRY_COUNT 512
nkeynes@953
    38
nkeynes@953
    39
struct cache_line {
nkeynes@953
    40
    uint32_t key;  // Fast address match - bits 5..28 for valid entry, -1 for invalid entry
nkeynes@953
    41
    uint32_t tag;  // tag + flags value from the address field
nkeynes@953
    42
};    
nkeynes@953
    43
nkeynes@953
    44
nkeynes@953
    45
static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
nkeynes@971
    46
struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
nkeynes@953
    47
static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
nkeynes@971
    48
unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
nkeynes@953
    49
nkeynes@953
    50
nkeynes@953
    51
/*********************** General module requirements ********************/
nkeynes@953
    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@953
    62
void CCN_save_state( FILE *f )
nkeynes@953
    63
{
nkeynes@953
    64
    fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
nkeynes@953
    65
    fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
nkeynes@953
    66
    fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
nkeynes@953
    67
    fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
nkeynes@953
    68
}
nkeynes@953
    69
nkeynes@953
    70
int CCN_load_state( FILE *f )
nkeynes@953
    71
{
nkeynes@953
    72
    /* Setup the cache mode according to the saved register value
nkeynes@953
    73
     * (mem_load runs before this point to load all MMIO data)
nkeynes@953
    74
     */
nkeynes@953
    75
    mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
nkeynes@953
    76
nkeynes@953
    77
    if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
nkeynes@953
    78
        return 1;
nkeynes@953
    79
    }
nkeynes@953
    80
    if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
nkeynes@953
    81
        return 1;
nkeynes@953
    82
    }
nkeynes@953
    83
    if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
nkeynes@953
    84
        return 1;
nkeynes@953
    85
    }
nkeynes@953
    86
    if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
nkeynes@953
    87
        return 1;
nkeynes@953
    88
    }
nkeynes@953
    89
    return 0;
nkeynes@953
    90
}
nkeynes@953
    91
nkeynes@953
    92
/************************* OCRAM memory address space ************************/
nkeynes@953
    93
nkeynes@953
    94
#define OCRAMPAGE0 (&ccn_ocache_data[4096])  /* Lines 128-255 */
nkeynes@953
    95
#define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */
nkeynes@953
    96
nkeynes@953
    97
static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr )
nkeynes@953
    98
{
nkeynes@953
    99
    return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));
nkeynes@953
   100
}
nkeynes@953
   101
static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )
nkeynes@953
   102
{
nkeynes@953
   103
    return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
nkeynes@953
   104
}
nkeynes@953
   105
static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )
nkeynes@953
   106
{
nkeynes@953
   107
    return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
nkeynes@953
   108
}
nkeynes@953
   109
static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )
nkeynes@953
   110
{
nkeynes@953
   111
    *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;
nkeynes@953
   112
}
nkeynes@953
   113
static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )
nkeynes@953
   114
{
nkeynes@953
   115
    *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;
nkeynes@953
   116
}
nkeynes@953
   117
static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@953
   118
{
nkeynes@953
   119
    *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;
nkeynes@953
   120
}
nkeynes@953
   121
static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@953
   122
{
nkeynes@953
   123
    memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );
nkeynes@953
   124
}
nkeynes@953
   125
static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@953
   126
{
nkeynes@953
   127
    memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );
nkeynes@953
   128
}
nkeynes@953
   129
nkeynes@953
   130
struct mem_region_fn mem_region_ocram_page0 = {
nkeynes@953
   131
        ocram_page0_read_long, ocram_page0_write_long,
nkeynes@953
   132
        ocram_page0_read_word, ocram_page0_write_word,
nkeynes@953
   133
        ocram_page0_read_byte, ocram_page0_write_byte,
nkeynes@953
   134
        ocram_page0_read_burst, ocram_page0_write_burst,
nkeynes@975
   135
        unmapped_prefetch, ocram_page0_read_byte };
nkeynes@953
   136
nkeynes@953
   137
static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
nkeynes@953
   138
{
nkeynes@953
   139
    return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
nkeynes@953
   140
}
nkeynes@953
   141
static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
nkeynes@953
   142
{
nkeynes@953
   143
    return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
nkeynes@953
   144
}
nkeynes@953
   145
static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
nkeynes@953
   146
{
nkeynes@953
   147
    return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
nkeynes@953
   148
}
nkeynes@953
   149
static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
nkeynes@953
   150
{
nkeynes@953
   151
    *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
nkeynes@953
   152
}
nkeynes@953
   153
static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
nkeynes@953
   154
{
nkeynes@953
   155
    *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
nkeynes@953
   156
}
nkeynes@953
   157
static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@953
   158
{
nkeynes@953
   159
    *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
nkeynes@953
   160
}
nkeynes@953
   161
static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@953
   162
{
nkeynes@953
   163
    memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
nkeynes@953
   164
}
nkeynes@953
   165
static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@953
   166
{
nkeynes@953
   167
    memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
nkeynes@953
   168
}
nkeynes@953
   169
nkeynes@953
   170
struct mem_region_fn mem_region_ocram_page1 = {
nkeynes@953
   171
        ocram_page1_read_long, ocram_page1_write_long,
nkeynes@953
   172
        ocram_page1_read_word, ocram_page1_write_word,
nkeynes@953
   173
        ocram_page1_read_byte, ocram_page1_write_byte,
nkeynes@953
   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@971
   311
nkeynes@953
   312
/************************** Cache direct access ******************************/
nkeynes@953
   313
nkeynes@968
   314
static int32_t FASTCALL ccn_icache_addr_read( sh4addr_t addr )
nkeynes@953
   315
{
nkeynes@953
   316
    int entry = (addr & 0x00001FE0);
nkeynes@953
   317
    return ccn_icache[entry>>5].tag;
nkeynes@953
   318
}
nkeynes@953
   319
nkeynes@968
   320
static void FASTCALL ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
nkeynes@953
   321
{
nkeynes@953
   322
    int entry = (addr & 0x00003FE0);
nkeynes@953
   323
    struct cache_line *line = &ccn_ocache[entry>>5];
nkeynes@953
   324
    if( addr & 0x08 ) { // Associative
nkeynes@953
   325
        /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
nkeynes@953
   326
    } else {
nkeynes@953
   327
        line->tag = val & 0x1FFFFC01;
nkeynes@953
   328
        line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
nkeynes@953
   329
    }
nkeynes@953
   330
}
nkeynes@953
   331
nkeynes@953
   332
struct mem_region_fn p4_region_icache_addr = {
nkeynes@953
   333
        ccn_icache_addr_read, ccn_icache_addr_write,
nkeynes@953
   334
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   335
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   336
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   337
        unmapped_prefetch, unmapped_read_long };
nkeynes@953
   338
nkeynes@953
   339
nkeynes@968
   340
static int32_t FASTCALL ccn_icache_data_read( sh4addr_t addr )
nkeynes@953
   341
{
nkeynes@953
   342
    int entry = (addr & 0x00001FFC);
nkeynes@953
   343
    return *(uint32_t *)&ccn_icache_data[entry];
nkeynes@953
   344
}
nkeynes@953
   345
nkeynes@968
   346
static void FASTCALL ccn_icache_data_write( sh4addr_t addr, uint32_t val )
nkeynes@953
   347
{
nkeynes@953
   348
    int entry = (addr & 0x00001FFC);
nkeynes@953
   349
    *(uint32_t *)&ccn_icache_data[entry] = val;    
nkeynes@953
   350
}
nkeynes@953
   351
nkeynes@953
   352
struct mem_region_fn p4_region_icache_data = {
nkeynes@953
   353
        ccn_icache_data_read, ccn_icache_data_write,
nkeynes@953
   354
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   355
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   356
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   357
        unmapped_prefetch, unmapped_read_long };
nkeynes@953
   358
nkeynes@968
   359
static int32_t FASTCALL ccn_ocache_addr_read( sh4addr_t addr )
nkeynes@953
   360
{
nkeynes@953
   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@953
   364
}
nkeynes@953
   365
nkeynes@968
   366
static void FASTCALL ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
nkeynes@953
   367
{
nkeynes@953
   368
    int entry = (addr & 0x00003FE0);
nkeynes@953
   369
    struct cache_line *line = &ccn_ocache[entry>>5];
nkeynes@953
   370
    if( addr & 0x08 ) { // Associative
nkeynes@953
   371
    } else {
nkeynes@971
   372
        sh4addr_t tag = line->tag;
nkeynes@971
   373
        if( ccn_cache_map[tag>>5] == (CACHE_VALID|CACHE_DIRTY) ) {
nkeynes@953
   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@953
   377
        }
nkeynes@971
   378
        line->tag = tag = (val & 0x1FFFFC00) | (addr & 0x3E0);
nkeynes@971
   379
        ccn_cache_map[tag>>5] = val & 0x03;
nkeynes@953
   380
    }
nkeynes@953
   381
}
nkeynes@953
   382
nkeynes@953
   383
struct mem_region_fn p4_region_ocache_addr = {
nkeynes@953
   384
        ccn_ocache_addr_read, ccn_ocache_addr_write,
nkeynes@953
   385
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   386
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   387
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   388
        unmapped_prefetch, unmapped_read_long };
nkeynes@953
   389
nkeynes@953
   390
nkeynes@968
   391
static int32_t FASTCALL ccn_ocache_data_read( sh4addr_t addr )
nkeynes@953
   392
{
nkeynes@953
   393
    int entry = (addr & 0x00003FFC);
nkeynes@953
   394
    return *(uint32_t *)&ccn_ocache_data[entry];
nkeynes@953
   395
}
nkeynes@953
   396
nkeynes@968
   397
static void FASTCALL ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
nkeynes@953
   398
{
nkeynes@953
   399
    int entry = (addr & 0x00003FFC);
nkeynes@953
   400
    *(uint32_t *)&ccn_ocache_data[entry] = val;
nkeynes@953
   401
}
nkeynes@953
   402
nkeynes@953
   403
struct mem_region_fn p4_region_ocache_data = {
nkeynes@953
   404
        ccn_ocache_data_read, ccn_ocache_data_write,
nkeynes@953
   405
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   406
        unmapped_read_long, unmapped_write_long,
nkeynes@953
   407
        unmapped_read_burst, unmapped_write_burst,
nkeynes@975
   408
        unmapped_prefetch, unmapped_read_long };
nkeynes@953
   409
nkeynes@953
   410
nkeynes@953
   411
/****************** Cache control *********************/
nkeynes@953
   412
nkeynes@953
   413
void CCN_set_cache_control( int reg )
nkeynes@953
   414
{
nkeynes@953
   415
    uint32_t i;
nkeynes@953
   416
    
nkeynes@953
   417
    if( reg & CCR_ICI ) { /* icache invalidate */
nkeynes@953
   418
        for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
nkeynes@971
   419
            ccn_icache[i].key = -1;
nkeynes@953
   420
            ccn_icache[i].tag &= ~CACHE_VALID;
nkeynes@953
   421
        }
nkeynes@953
   422
    }
nkeynes@953
   423
    
nkeynes@953
   424
    if( reg & CCR_OCI ) { /* ocache invalidate */
nkeynes@953
   425
        for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
nkeynes@971
   426
            ccn_icache[i].key = -1;
nkeynes@953
   427
            ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
nkeynes@953
   428
        }
nkeynes@953
   429
    }
nkeynes@953
   430
    
nkeynes@953
   431
    switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
nkeynes@953
   432
    case MEM_OC_INDEX0: /* OIX=0 */
nkeynes@953
   433
        for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
nkeynes@953
   434
            sh4_address_space[i] = &mem_region_ocram_page0;
nkeynes@953
   435
            sh4_address_space[i+1] = &mem_region_ocram_page0;
nkeynes@953
   436
            sh4_address_space[i+2] = &mem_region_ocram_page1;
nkeynes@953
   437
            sh4_address_space[i+3] = &mem_region_ocram_page1;
nkeynes@953
   438
        }
nkeynes@953
   439
        break;
nkeynes@953
   440
    case MEM_OC_INDEX1: /* OIX=1 */
nkeynes@953
   441
        for( i=OCRAM_START; i<OCRAM_MID; i++ )
nkeynes@953
   442
            sh4_address_space[i] = &mem_region_ocram_page0;
nkeynes@953
   443
        for( i=OCRAM_MID; i<OCRAM_END; i++ )
nkeynes@953
   444
            sh4_address_space[i] = &mem_region_ocram_page1;
nkeynes@953
   445
        break;
nkeynes@953
   446
    default: /* disabled */
nkeynes@953
   447
        for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@953
   448
            sh4_address_space[i] = &mem_region_unmapped;
nkeynes@953
   449
        break;
nkeynes@953
   450
    }
nkeynes@953
   451
}
nkeynes@953
   452
nkeynes@953
   453
/**
nkeynes@953
   454
 * Prefetch for non-storequeue regions
nkeynes@953
   455
 */
nkeynes@953
   456
void FASTCALL ccn_prefetch( sh4addr_t addr )
nkeynes@953
   457
{
nkeynes@953
   458
    
nkeynes@953
   459
}
nkeynes@953
   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@953
   498
void FASTCALL ccn_uncached_prefetch( sh4addr_t addr )
nkeynes@953
   499
{
nkeynes@953
   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@953
   510
/********************************* Store-queue *******************************/
nkeynes@953
   511
/*
nkeynes@953
   512
 * The storequeue is strictly speaking part of the cache, but most of 
nkeynes@953
   513
 * the complexity is actually around its addressing (ie in the MMU). The
nkeynes@953
   514
 * methods here can assume we've already passed SQMD protection and the TLB
nkeynes@953
   515
 * lookups (where appropriate).
nkeynes@953
   516
 */  
nkeynes@953
   517
void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val )
nkeynes@953
   518
{
nkeynes@953
   519
    sh4r.store_queue[(addr>>2)&0xF] = val;
nkeynes@953
   520
}
nkeynes@953
   521
int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr )
nkeynes@953
   522
{
nkeynes@953
   523
    return sh4r.store_queue[(addr>>2)&0xF];
nkeynes@953
   524
}
nkeynes@953
   525
nkeynes@953
   526
/**
nkeynes@953
   527
 * Variant used when tlb is disabled - address will be the original prefetch
nkeynes@953
   528
 * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't
nkeynes@953
   529
 * be hardcoded on 4K page boundaries, so we manually decode it here.
nkeynes@953
   530
 */
nkeynes@953
   531
void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr ) 
nkeynes@953
   532
{
nkeynes@953
   533
    int queue = (addr&0x20)>>2;
nkeynes@953
   534
    sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
nkeynes@953
   535
    uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24;
nkeynes@953
   536
    sh4addr_t target = (addr&0x03FFFFE0) | hi;
nkeynes@953
   537
    ext_address_space[target>>12]->write_burst( target, src );
nkeynes@953
   538
}
nkeynes@953
   539
nkeynes@953
   540
/**
nkeynes@953
   541
 * Variant used when tlb is enabled - address in this case is already
nkeynes@953
   542
 * mapped to the external target address.
nkeynes@953
   543
 */
nkeynes@953
   544
void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr )
nkeynes@953
   545
{
nkeynes@953
   546
    int queue = (addr&0x20)>>2;
nkeynes@953
   547
    sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
nkeynes@953
   548
    ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src );
nkeynes@953
   549
}
nkeynes@971
   550
.