1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/sh4/mmu.c Tue Jan 01 04:49:57 2008 +0000
1.5 + * $Id: mmu.c,v 1.15 2007-11-08 11:54:16 nkeynes Exp $
1.7 + * MMU implementation
1.9 + * Copyright (c) 2005 Nathan Keynes.
1.11 + * This program is free software; you can redistribute it and/or modify
1.12 + * it under the terms of the GNU General Public License as published by
1.13 + * the Free Software Foundation; either version 2 of the License, or
1.14 + * (at your option) any later version.
1.16 + * This program is distributed in the hope that it will be useful,
1.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
1.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1.19 + * GNU General Public License for more details.
1.21 +#define MODULE sh4_module
1.24 +#include "sh4/sh4mmio.h"
1.25 +#include "sh4/sh4core.h"
1.28 +#define OCRAM_START (0x1C000000>>PAGE_BITS)
1.29 +#define OCRAM_END (0x20000000>>PAGE_BITS)
1.31 +#define ITLB_ENTRY_COUNT 4
1.32 +#define UTLB_ENTRY_COUNT 64
1.34 +/* Entry address */
1.35 +#define TLB_VALID 0x00000100
1.36 +#define TLB_USERMODE 0x00000040
1.37 +#define TLB_WRITABLE 0x00000020
1.38 +#define TLB_SIZE_MASK 0x00000090
1.39 +#define TLB_SIZE_1K 0x00000000
1.40 +#define TLB_SIZE_4K 0x00000010
1.41 +#define TLB_SIZE_64K 0x00000080
1.42 +#define TLB_SIZE_1M 0x00000090
1.43 +#define TLB_CACHEABLE 0x00000008
1.44 +#define TLB_DIRTY 0x00000004
1.45 +#define TLB_SHARE 0x00000002
1.46 +#define TLB_WRITETHRU 0x00000001
1.49 +struct itlb_entry {
1.50 + sh4addr_t vpn; // Virtual Page Number
1.51 + uint32_t asid; // Process ID
1.52 + sh4addr_t ppn; // Physical Page Number
1.56 +struct utlb_entry {
1.57 + sh4addr_t vpn; // Virtual Page Number
1.58 + uint32_t asid; // Process ID
1.59 + sh4addr_t ppn; // Physical Page Number
1.61 + uint32_t pcmcia; // extra pcmcia data - not used
1.64 +static struct itlb_entry mmu_itlb[ITLB_ENTRY_COUNT];
1.65 +static struct utlb_entry mmu_utlb[UTLB_ENTRY_COUNT];
1.66 +static uint32_t mmu_urc;
1.67 +static uint32_t mmu_urb;
1.68 +static uint32_t mmu_lrui;
1.70 +static sh4ptr_t cache = NULL;
1.72 +static void mmu_invalidate_tlb();
1.75 +int32_t mmio_region_MMU_read( uint32_t reg )
1.79 + return MMIO_READ( MMU, MMUCR) | (mmu_urc<<10) | (mmu_urb<<18) | (mmu_lrui<<26);
1.81 + return MMIO_READ( MMU, reg );
1.85 +void mmio_region_MMU_write( uint32_t reg, uint32_t val )
1.89 + val &= 0xFFFFFCFF;
1.92 + val &= 0x1FFFFDFF;
1.95 + val &= 0x0000000F;
1.98 + if( val & MMUCR_TI ) {
1.99 + mmu_invalidate_tlb();
1.101 + mmu_urc = (val >> 10) & 0x3F;
1.102 + mmu_urb = (val >> 18) & 0x3F;
1.103 + mmu_lrui = (val >> 26) & 0x3F;
1.104 + val &= 0x00000301;
1.107 + mmu_set_cache_mode( val & (CCR_OIX|CCR_ORA) );
1.112 + MMIO_WRITE( MMU, reg, val );
1.118 + cache = mem_alloc_pages(2);
1.123 + mmio_region_MMU_write( CCR, 0 );
1.126 +void MMU_save_state( FILE *f )
1.128 + fwrite( cache, 4096, 2, f );
1.129 + fwrite( &mmu_itlb, sizeof(mmu_itlb), 1, f );
1.130 + fwrite( &mmu_utlb, sizeof(mmu_utlb), 1, f );
1.133 +int MMU_load_state( FILE *f )
1.135 + /* Setup the cache mode according to the saved register value
1.136 + * (mem_load runs before this point to load all MMIO data)
1.138 + mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
1.139 + if( fread( cache, 4096, 2, f ) != 2 ) {
1.142 + if( fread( &mmu_itlb, sizeof(mmu_itlb), 1, f ) != 1 ) {
1.145 + if( fread( &mmu_utlb, sizeof(mmu_utlb), 1, f ) != 1 ) {
1.151 +void mmu_set_cache_mode( int mode )
1.155 + case MEM_OC_INDEX0: /* OIX=0 */
1.156 + for( i=OCRAM_START; i<OCRAM_END; i++ )
1.157 + page_map[i] = cache + ((i&0x02)<<(PAGE_BITS-1));
1.159 + case MEM_OC_INDEX1: /* OIX=1 */
1.160 + for( i=OCRAM_START; i<OCRAM_END; i++ )
1.161 + page_map[i] = cache + ((i&0x02000000)>>(25-PAGE_BITS));
1.163 + default: /* disabled */
1.164 + for( i=OCRAM_START; i<OCRAM_END; i++ )
1.165 + page_map[i] = NULL;
1.170 +/* TLB maintanence */
1.173 + * LDTLB instruction implementation. Copies PTEH, PTEL and PTEA into the UTLB
1.174 + * entry identified by MMUCR.URC. Does not modify MMUCR or the ITLB.
1.178 + mmu_utlb[mmu_urc].vpn = MMIO_READ(MMU, PTEH) & 0xFFFFFC00;
1.179 + mmu_utlb[mmu_urc].asid = MMIO_READ(MMU, PTEH) & 0x000000FF;
1.180 + mmu_utlb[mmu_urc].ppn = MMIO_READ(MMU, PTEL) & 0x1FFFFC00;
1.181 + mmu_utlb[mmu_urc].flags = MMIO_READ(MMU, PTEL) & 0x00001FF;
1.182 + mmu_utlb[mmu_urc].pcmcia = MMIO_READ(MMU, PTEA);
1.185 +uint64_t mmu_translate_read( sh4addr_t addr )
1.187 + uint32_t mmucr = MMIO_READ(MMU,MMUCR);
1.188 + if( IS_SH4_PRIVMODE() ) {
1.189 + switch( addr & 0xE0000000 ) {
1.190 + case 0x80000000: case 0xA0000000:
1.191 + /* Non-translated read P1,P2 */
1.194 + /* Non-translated read P4 */
1.197 + if( mmucr&MMUCR_AT ) {
1.203 + if( addr & 0x80000000 ) {
1.204 + if( ((addr&0xFC000000) == 0xE0000000 ) &&
1.205 + ((mmucr&MMUCR_SQMD) == 0) ) {
1.209 +// MMU_READ_ADDR_ERROR();
1.211 + if( mmucr&MMUCR_AT ) {
1.212 + uint32_t vpn = addr & 0xFFFFFC00;
1.213 + uint32_t asid = MMIO_READ(MMU,PTEH)&0xFF;
1.220 +static void mmu_invalidate_tlb()
1.223 + for( i=0; i<ITLB_ENTRY_COUNT; i++ ) {
1.224 + mmu_itlb[i].flags &= (~TLB_VALID);
1.226 + for( i=0; i<UTLB_ENTRY_COUNT; i++ ) {
1.227 + mmu_utlb[i].flags &= (~TLB_VALID);
1.231 +#define ITLB_ENTRY(addr) ((addr>>7)&0x03)
1.233 +int32_t mmu_itlb_addr_read( sh4addr_t addr )
1.235 + struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
1.236 + return ent->vpn | ent->asid | (ent->flags & TLB_VALID);
1.238 +int32_t mmu_itlb_data_read( sh4addr_t addr )
1.240 + struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
1.241 + return ent->ppn | ent->flags;
1.244 +void mmu_itlb_addr_write( sh4addr_t addr, uint32_t val )
1.246 + struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
1.247 + ent->vpn = val & 0xFFFFFC00;
1.248 + ent->asid = val & 0x000000FF;
1.249 + ent->flags = (ent->flags & ~(TLB_VALID)) | (val&TLB_VALID);
1.252 +void mmu_itlb_data_write( sh4addr_t addr, uint32_t val )
1.254 + struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
1.255 + ent->ppn = val & 0x1FFFFC00;
1.256 + ent->flags = val & 0x00001DA;
1.259 +#define UTLB_ENTRY(addr) ((addr>>8)&0x3F)
1.260 +#define UTLB_ASSOC(addr) (addr&0x80)
1.261 +#define UTLB_DATA2(addr) (addr&0x00800000)
1.263 +int32_t mmu_utlb_addr_read( sh4addr_t addr )
1.265 + struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
1.266 + return ent->vpn | ent->asid | (ent->flags & TLB_VALID) |
1.267 + ((ent->flags & TLB_DIRTY)<<7);
1.269 +int32_t mmu_utlb_data_read( sh4addr_t addr )
1.271 + struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
1.272 + if( UTLB_DATA2(addr) ) {
1.273 + return ent->pcmcia;
1.275 + return ent->ppn | ent->flags;
1.279 +void mmu_utlb_addr_write( sh4addr_t addr, uint32_t val )
1.281 + if( UTLB_ASSOC(addr) ) {
1.283 + struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
1.284 + ent->vpn = (val & 0xFFFFFC00);
1.285 + ent->asid = (val & 0xFF);
1.286 + ent->flags = (ent->flags & ~(TLB_DIRTY|TLB_VALID));
1.287 + ent->flags |= (val & TLB_VALID);
1.288 + ent->flags |= ((val & 0x200)>>7);
1.292 +void mmu_utlb_data_write( sh4addr_t addr, uint32_t val )
1.294 + struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
1.295 + if( UTLB_DATA2(addr) ) {
1.296 + ent->pcmcia = val & 0x0000000F;
1.298 + ent->ppn = (val & 0x1FFFFC00);
1.299 + ent->flags = (val & 0x000001FF);
1.303 +/* Cache access - not implemented */
1.305 +int32_t mmu_icache_addr_read( sh4addr_t addr )
1.307 + return 0; // not implemented
1.309 +int32_t mmu_icache_data_read( sh4addr_t addr )
1.311 + return 0; // not implemented
1.313 +int32_t mmu_ocache_addr_read( sh4addr_t addr )
1.315 + return 0; // not implemented
1.317 +int32_t mmu_ocache_data_read( sh4addr_t addr )
1.319 + return 0; // not implemented
1.322 +void mmu_icache_addr_write( sh4addr_t addr, uint32_t val )
1.326 +void mmu_icache_data_write( sh4addr_t addr, uint32_t val )
1.330 +void mmu_ocache_addr_write( sh4addr_t addr, uint32_t val )
1.334 +void mmu_ocache_data_write( sh4addr_t addr, uint32_t val )