Search
lxdream.org :: lxdream/src/sh4/cache.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/cache.c
changeset 933:880c37bb1909
prev931:430048ea8b71
next939:6f2302afeb89
author nkeynes
date Wed Dec 24 06:06:23 2008 +0000 (13 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change Start putting cache together
file annotate diff log raw
nkeynes@931
     1
/**
nkeynes@931
     2
 * $Id$
nkeynes@931
     3
 * Implements the on-chip operand cache and instruction caches
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@931
    24
#include "sh4/sh4core.h"
nkeynes@931
    25
#include "sh4/sh4mmio.h"
nkeynes@931
    26
#include "sh4/xltcache.h"
nkeynes@931
    27
nkeynes@931
    28
#define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS)
nkeynes@931
    29
#define OCRAM_MID   (0x7E000000>>LXDREAM_PAGE_BITS)
nkeynes@931
    30
#define OCRAM_END   (0x80000000>>LXDREAM_PAGE_BITS)
nkeynes@931
    31
nkeynes@931
    32
#define CACHE_VALID 1
nkeynes@931
    33
#define CACHE_DIRTY 2
nkeynes@931
    34
nkeynes@931
    35
#define ICACHE_ENTRY_COUNT 256
nkeynes@931
    36
#define OCACHE_ENTRY_COUNT 512
nkeynes@931
    37
nkeynes@931
    38
struct cache_line {
nkeynes@931
    39
    uint32_t key;  // Fast address match - bits 5..28 for valid entry, -1 for invalid entry
nkeynes@931
    40
    uint32_t tag;  // tag + flags value from the address field
nkeynes@931
    41
};    
nkeynes@931
    42
nkeynes@931
    43
nkeynes@931
    44
static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT];
nkeynes@931
    45
static struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT];
nkeynes@931
    46
static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32];
nkeynes@931
    47
static unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32];
nkeynes@931
    48
nkeynes@931
    49
nkeynes@931
    50
/*********************** General module requirements ********************/
nkeynes@931
    51
nkeynes@931
    52
void CCN_save_state( FILE *f )
nkeynes@931
    53
{
nkeynes@931
    54
    fwrite( &ccn_icache, sizeof(ccn_icache), 1, f );
nkeynes@931
    55
    fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f );
nkeynes@931
    56
    fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f);
nkeynes@931
    57
    fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f);
nkeynes@931
    58
}
nkeynes@931
    59
nkeynes@931
    60
int CCN_load_state( FILE *f )
nkeynes@931
    61
{
nkeynes@931
    62
    /* Setup the cache mode according to the saved register value
nkeynes@931
    63
     * (mem_load runs before this point to load all MMIO data)
nkeynes@931
    64
     */
nkeynes@931
    65
    mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
nkeynes@931
    66
nkeynes@931
    67
    if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) {
nkeynes@931
    68
        return 1;
nkeynes@931
    69
    }
nkeynes@931
    70
    if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) {
nkeynes@931
    71
        return 1;
nkeynes@931
    72
    }
nkeynes@931
    73
    if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) {
nkeynes@931
    74
        return 1;
nkeynes@931
    75
    }
nkeynes@931
    76
    if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) {
nkeynes@931
    77
        return 1;
nkeynes@931
    78
    }
nkeynes@931
    79
    return 0;
nkeynes@931
    80
}
nkeynes@931
    81
nkeynes@931
    82
nkeynes@931
    83
/************************* OCRAM memory address space ************************/
nkeynes@931
    84
nkeynes@931
    85
#define OCRAMPAGE0 (&ccn_ocache_data[4096])  /* Lines 128-255 */
nkeynes@931
    86
#define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */
nkeynes@931
    87
nkeynes@931
    88
static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr )
nkeynes@931
    89
{
nkeynes@931
    90
    return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)));
nkeynes@931
    91
}
nkeynes@931
    92
static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr )
nkeynes@931
    93
{
nkeynes@931
    94
    return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
nkeynes@931
    95
}
nkeynes@931
    96
static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr )
nkeynes@931
    97
{
nkeynes@931
    98
    return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF))));
nkeynes@931
    99
}
nkeynes@931
   100
static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val )
nkeynes@931
   101
{
nkeynes@931
   102
    *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val;
nkeynes@931
   103
}
nkeynes@931
   104
static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val )
nkeynes@931
   105
{
nkeynes@931
   106
    *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val;
nkeynes@931
   107
}
nkeynes@931
   108
static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@931
   109
{
nkeynes@931
   110
    *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val;
nkeynes@931
   111
}
nkeynes@931
   112
static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@931
   113
{
nkeynes@931
   114
    memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 );
nkeynes@931
   115
}
nkeynes@931
   116
static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@931
   117
{
nkeynes@931
   118
    memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 );
nkeynes@931
   119
}
nkeynes@931
   120
nkeynes@931
   121
struct mem_region_fn mem_region_ocram_page0 = {
nkeynes@931
   122
        ocram_page0_read_long, ocram_page0_write_long,
nkeynes@931
   123
        ocram_page0_read_word, ocram_page0_write_word,
nkeynes@931
   124
        ocram_page0_read_byte, ocram_page0_write_byte,
nkeynes@931
   125
        ocram_page0_read_burst, ocram_page0_write_burst };
nkeynes@931
   126
nkeynes@931
   127
static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr )
nkeynes@931
   128
{
nkeynes@931
   129
    return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)));
nkeynes@931
   130
}
nkeynes@931
   131
static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr )
nkeynes@931
   132
{
nkeynes@931
   133
    return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
nkeynes@931
   134
}
nkeynes@931
   135
static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr )
nkeynes@931
   136
{
nkeynes@931
   137
    return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF))));
nkeynes@931
   138
}
nkeynes@931
   139
static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val )
nkeynes@931
   140
{
nkeynes@931
   141
    *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val;
nkeynes@931
   142
}
nkeynes@931
   143
static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val )
nkeynes@931
   144
{
nkeynes@931
   145
    *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val;
nkeynes@931
   146
}
nkeynes@931
   147
static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@931
   148
{
nkeynes@931
   149
    *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val;
nkeynes@931
   150
}
nkeynes@931
   151
static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@931
   152
{
nkeynes@931
   153
    memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 );
nkeynes@931
   154
}
nkeynes@931
   155
static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@931
   156
{
nkeynes@931
   157
    memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 );
nkeynes@931
   158
}
nkeynes@931
   159
nkeynes@931
   160
struct mem_region_fn mem_region_ocram_page1 = {
nkeynes@931
   161
        ocram_page1_read_long, ocram_page1_write_long,
nkeynes@931
   162
        ocram_page1_read_word, ocram_page1_write_word,
nkeynes@931
   163
        ocram_page1_read_byte, ocram_page1_write_byte,
nkeynes@931
   164
        ocram_page1_read_burst, ocram_page1_write_burst };
nkeynes@931
   165
nkeynes@933
   166
/************************** Cache direct access ******************************/
nkeynes@933
   167
nkeynes@933
   168
static int32_t ccn_icache_addr_read( sh4addr_t addr )
nkeynes@933
   169
{
nkeynes@933
   170
    int entry = (addr & 0x00001FE0);
nkeynes@933
   171
    return ccn_icache[entry>>5].tag;
nkeynes@933
   172
}
nkeynes@933
   173
nkeynes@933
   174
static void ccn_icache_addr_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   175
{
nkeynes@933
   176
    int entry = (addr & 0x00003FE0);
nkeynes@933
   177
    struct cache_line *line = &ccn_ocache[entry>>5];
nkeynes@933
   178
    if( addr & 0x08 ) { // Associative
nkeynes@933
   179
        /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */
nkeynes@933
   180
    } else {
nkeynes@933
   181
        line->tag = val & 0x1FFFFC01;
nkeynes@933
   182
        line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
nkeynes@933
   183
    }
nkeynes@933
   184
}
nkeynes@933
   185
nkeynes@933
   186
struct mem_region_fn p4_region_icache_addr = {
nkeynes@933
   187
        ccn_icache_addr_read, ccn_icache_addr_write,
nkeynes@933
   188
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   189
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   190
        unmapped_read_burst, unmapped_write_burst };
nkeynes@933
   191
nkeynes@933
   192
nkeynes@933
   193
static int32_t ccn_icache_data_read( sh4addr_t addr )
nkeynes@933
   194
{
nkeynes@933
   195
    int entry = (addr & 0x00001FFC);
nkeynes@933
   196
    return *(uint32_t *)&ccn_icache_data[entry];
nkeynes@933
   197
}
nkeynes@933
   198
nkeynes@933
   199
static void ccn_icache_data_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   200
{
nkeynes@933
   201
    int entry = (addr & 0x00001FFC);
nkeynes@933
   202
    *(uint32_t *)&ccn_icache_data[entry] = val;    
nkeynes@933
   203
}
nkeynes@933
   204
nkeynes@933
   205
struct mem_region_fn p4_region_icache_data = {
nkeynes@933
   206
        ccn_icache_data_read, ccn_icache_data_write,
nkeynes@933
   207
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   208
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   209
        unmapped_read_burst, unmapped_write_burst };
nkeynes@933
   210
nkeynes@933
   211
nkeynes@933
   212
static int32_t ccn_ocache_addr_read( sh4addr_t addr )
nkeynes@933
   213
{
nkeynes@933
   214
    int entry = (addr & 0x00003FE0);
nkeynes@933
   215
    return ccn_ocache[entry>>5].tag;
nkeynes@933
   216
}
nkeynes@933
   217
nkeynes@933
   218
static void ccn_ocache_addr_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   219
{
nkeynes@933
   220
    int entry = (addr & 0x00003FE0);
nkeynes@933
   221
    struct cache_line *line = &ccn_ocache[entry>>5];
nkeynes@933
   222
    if( addr & 0x08 ) { // Associative
nkeynes@933
   223
    } else {
nkeynes@933
   224
        if( (line->tag & (CACHE_VALID|CACHE_DIRTY)) == (CACHE_VALID|CACHE_DIRTY) ) {
nkeynes@933
   225
            char *cache_data = &ccn_ocache_data[entry&0x00003FE0];
nkeynes@933
   226
            // Cache line is dirty - writeback. 
nkeynes@933
   227
            ext_address_space[line->tag>>12]->write_burst(line->key, cache_data);
nkeynes@933
   228
        }
nkeynes@933
   229
        line->tag = val & 0x1FFFFC03;
nkeynes@933
   230
        line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0);
nkeynes@933
   231
    }
nkeynes@933
   232
}
nkeynes@933
   233
nkeynes@933
   234
struct mem_region_fn p4_region_ocache_addr = {
nkeynes@933
   235
        ccn_ocache_addr_read, ccn_ocache_addr_write,
nkeynes@933
   236
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   237
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   238
        unmapped_read_burst, unmapped_write_burst };
nkeynes@933
   239
nkeynes@933
   240
nkeynes@933
   241
static int32_t ccn_ocache_data_read( sh4addr_t addr )
nkeynes@933
   242
{
nkeynes@933
   243
    int entry = (addr & 0x00003FFC);
nkeynes@933
   244
    return *(uint32_t *)&ccn_ocache_data[entry];
nkeynes@933
   245
}
nkeynes@933
   246
nkeynes@933
   247
static void ccn_ocache_data_write( sh4addr_t addr, uint32_t val )
nkeynes@933
   248
{
nkeynes@933
   249
    int entry = (addr & 0x00003FFC);
nkeynes@933
   250
    *(uint32_t *)&ccn_ocache_data[entry] = val;
nkeynes@933
   251
}
nkeynes@933
   252
nkeynes@933
   253
struct mem_region_fn p4_region_ocache_data = {
nkeynes@933
   254
        ccn_ocache_data_read, ccn_ocache_data_write,
nkeynes@933
   255
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   256
        unmapped_read_long, unmapped_write_long,
nkeynes@933
   257
        unmapped_read_burst, unmapped_write_burst };
nkeynes@933
   258
nkeynes@933
   259
nkeynes@931
   260
/****************** Cache control *********************/
nkeynes@931
   261
nkeynes@931
   262
void CCN_set_cache_control( int reg )
nkeynes@931
   263
{
nkeynes@931
   264
    uint32_t i;
nkeynes@933
   265
    
nkeynes@933
   266
    if( reg & CCR_ICI ) { /* icache invalidate */
nkeynes@933
   267
        for( i=0; i<ICACHE_ENTRY_COUNT; i++ ) {
nkeynes@933
   268
            ccn_icache[i].tag &= ~CACHE_VALID;
nkeynes@933
   269
        }
nkeynes@933
   270
    }
nkeynes@933
   271
    
nkeynes@933
   272
    if( reg & CCR_OCI ) { /* ocache invalidate */
nkeynes@933
   273
        for( i=0; i<OCACHE_ENTRY_COUNT; i++ ) {
nkeynes@933
   274
            ccn_ocache[i].tag &= ~(CACHE_VALID|CACHE_DIRTY);
nkeynes@933
   275
        }
nkeynes@933
   276
    }
nkeynes@933
   277
    
nkeynes@931
   278
    switch( reg & (CCR_OIX|CCR_ORA|CCR_OCE) ) {
nkeynes@931
   279
    case MEM_OC_INDEX0: /* OIX=0 */
nkeynes@931
   280
        for( i=OCRAM_START; i<OCRAM_END; i+=4 ) {
nkeynes@931
   281
            sh4_address_space[i] = &mem_region_ocram_page0;
nkeynes@931
   282
            sh4_address_space[i+1] = &mem_region_ocram_page0;
nkeynes@931
   283
            sh4_address_space[i+2] = &mem_region_ocram_page1;
nkeynes@931
   284
            sh4_address_space[i+3] = &mem_region_ocram_page1;
nkeynes@931
   285
        }
nkeynes@931
   286
        break;
nkeynes@931
   287
    case MEM_OC_INDEX1: /* OIX=1 */
nkeynes@931
   288
        for( i=OCRAM_START; i<OCRAM_MID; i++ )
nkeynes@931
   289
            sh4_address_space[i] = &mem_region_ocram_page0;
nkeynes@931
   290
        for( i=OCRAM_MID; i<OCRAM_END; i++ )
nkeynes@931
   291
            sh4_address_space[i] = &mem_region_ocram_page1;
nkeynes@931
   292
        break;
nkeynes@931
   293
    default: /* disabled */
nkeynes@931
   294
        for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@931
   295
            sh4_address_space[i] = &mem_region_unmapped;
nkeynes@931
   296
        break;
nkeynes@931
   297
    }
nkeynes@931
   298
}
.