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