Search
lxdream.org :: lxdream/src/sh4/mmu.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/mmu.c
changeset 550:a27e31340147
next559:06714bc64271
next586:2a3ba82cf243
author nkeynes
date Tue Jan 01 04:49:57 2008 +0000 (16 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Add command line option to control default log level
file annotate diff log raw
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.3 @@ -0,0 +1,333 @@
1.4 +/**
1.5 + * $Id: mmu.c,v 1.15 2007-11-08 11:54:16 nkeynes Exp $
1.6 + *
1.7 + * MMU implementation
1.8 + *
1.9 + * Copyright (c) 2005 Nathan Keynes.
1.10 + *
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.15 + *
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.20 + */
1.21 +#define MODULE sh4_module
1.22 +
1.23 +#include <stdio.h>
1.24 +#include "sh4/sh4mmio.h"
1.25 +#include "sh4/sh4core.h"
1.26 +#include "mem.h"
1.27 +
1.28 +#define OCRAM_START (0x1C000000>>PAGE_BITS)
1.29 +#define OCRAM_END (0x20000000>>PAGE_BITS)
1.30 +
1.31 +#define ITLB_ENTRY_COUNT 4
1.32 +#define UTLB_ENTRY_COUNT 64
1.33 +
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.47 +
1.48 +
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.53 + uint32_t flags;
1.54 +};
1.55 +
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.60 + uint32_t flags;
1.61 + uint32_t pcmcia; // extra pcmcia data - not used
1.62 +};
1.63 +
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.69 +
1.70 +static sh4ptr_t cache = NULL;
1.71 +
1.72 +static void mmu_invalidate_tlb();
1.73 +
1.74 +
1.75 +int32_t mmio_region_MMU_read( uint32_t reg )
1.76 +{
1.77 + switch( reg ) {
1.78 + case MMUCR:
1.79 + return MMIO_READ( MMU, MMUCR) | (mmu_urc<<10) | (mmu_urb<<18) | (mmu_lrui<<26);
1.80 + default:
1.81 + return MMIO_READ( MMU, reg );
1.82 + }
1.83 +}
1.84 +
1.85 +void mmio_region_MMU_write( uint32_t reg, uint32_t val )
1.86 +{
1.87 + switch(reg) {
1.88 + case PTEH:
1.89 + val &= 0xFFFFFCFF;
1.90 + break;
1.91 + case PTEL:
1.92 + val &= 0x1FFFFDFF;
1.93 + break;
1.94 + case PTEA:
1.95 + val &= 0x0000000F;
1.96 + break;
1.97 + case MMUCR:
1.98 + if( val & MMUCR_TI ) {
1.99 + mmu_invalidate_tlb();
1.100 + }
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.105 + break;
1.106 + case CCR:
1.107 + mmu_set_cache_mode( val & (CCR_OIX|CCR_ORA) );
1.108 + break;
1.109 + default:
1.110 + break;
1.111 + }
1.112 + MMIO_WRITE( MMU, reg, val );
1.113 +}
1.114 +
1.115 +
1.116 +void MMU_init()
1.117 +{
1.118 + cache = mem_alloc_pages(2);
1.119 +}
1.120 +
1.121 +void MMU_reset()
1.122 +{
1.123 + mmio_region_MMU_write( CCR, 0 );
1.124 +}
1.125 +
1.126 +void MMU_save_state( FILE *f )
1.127 +{
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.131 +}
1.132 +
1.133 +int MMU_load_state( FILE *f )
1.134 +{
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.137 + */
1.138 + mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
1.139 + if( fread( cache, 4096, 2, f ) != 2 ) {
1.140 + return 1;
1.141 + }
1.142 + if( fread( &mmu_itlb, sizeof(mmu_itlb), 1, f ) != 1 ) {
1.143 + return 1;
1.144 + }
1.145 + if( fread( &mmu_utlb, sizeof(mmu_utlb), 1, f ) != 1 ) {
1.146 + return 1;
1.147 + }
1.148 + return 0;
1.149 +}
1.150 +
1.151 +void mmu_set_cache_mode( int mode )
1.152 +{
1.153 + uint32_t i;
1.154 + switch( 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.158 + break;
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.162 + break;
1.163 + default: /* disabled */
1.164 + for( i=OCRAM_START; i<OCRAM_END; i++ )
1.165 + page_map[i] = NULL;
1.166 + break;
1.167 + }
1.168 +}
1.169 +
1.170 +/* TLB maintanence */
1.171 +
1.172 +/**
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.175 + */
1.176 +void MMU_ldtlb()
1.177 +{
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.183 +}
1.184 +
1.185 +uint64_t mmu_translate_read( sh4addr_t addr )
1.186 +{
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.192 + break;
1.193 + case 0xE0000000:
1.194 + /* Non-translated read P4 */
1.195 + break;
1.196 + default:
1.197 + if( mmucr&MMUCR_AT ) {
1.198 + } else {
1.199 + // direct read
1.200 + }
1.201 + }
1.202 + } else {
1.203 + if( addr & 0x80000000 ) {
1.204 + if( ((addr&0xFC000000) == 0xE0000000 ) &&
1.205 + ((mmucr&MMUCR_SQMD) == 0) ) {
1.206 + // Store queue
1.207 + return 0;
1.208 + }
1.209 +// MMU_READ_ADDR_ERROR();
1.210 + }
1.211 + if( mmucr&MMUCR_AT ) {
1.212 + uint32_t vpn = addr & 0xFFFFFC00;
1.213 + uint32_t asid = MMIO_READ(MMU,PTEH)&0xFF;
1.214 + } else {
1.215 + // direct read
1.216 + }
1.217 + }
1.218 +}
1.219 +
1.220 +static void mmu_invalidate_tlb()
1.221 +{
1.222 + int i;
1.223 + for( i=0; i<ITLB_ENTRY_COUNT; i++ ) {
1.224 + mmu_itlb[i].flags &= (~TLB_VALID);
1.225 + }
1.226 + for( i=0; i<UTLB_ENTRY_COUNT; i++ ) {
1.227 + mmu_utlb[i].flags &= (~TLB_VALID);
1.228 + }
1.229 +}
1.230 +
1.231 +#define ITLB_ENTRY(addr) ((addr>>7)&0x03)
1.232 +
1.233 +int32_t mmu_itlb_addr_read( sh4addr_t addr )
1.234 +{
1.235 + struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
1.236 + return ent->vpn | ent->asid | (ent->flags & TLB_VALID);
1.237 +}
1.238 +int32_t mmu_itlb_data_read( sh4addr_t addr )
1.239 +{
1.240 + struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
1.241 + return ent->ppn | ent->flags;
1.242 +}
1.243 +
1.244 +void mmu_itlb_addr_write( sh4addr_t addr, uint32_t val )
1.245 +{
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.250 +}
1.251 +
1.252 +void mmu_itlb_data_write( sh4addr_t addr, uint32_t val )
1.253 +{
1.254 + struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
1.255 + ent->ppn = val & 0x1FFFFC00;
1.256 + ent->flags = val & 0x00001DA;
1.257 +}
1.258 +
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.262 +
1.263 +int32_t mmu_utlb_addr_read( sh4addr_t addr )
1.264 +{
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.268 +}
1.269 +int32_t mmu_utlb_data_read( sh4addr_t addr )
1.270 +{
1.271 + struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
1.272 + if( UTLB_DATA2(addr) ) {
1.273 + return ent->pcmcia;
1.274 + } else {
1.275 + return ent->ppn | ent->flags;
1.276 + }
1.277 +}
1.278 +
1.279 +void mmu_utlb_addr_write( sh4addr_t addr, uint32_t val )
1.280 +{
1.281 + if( UTLB_ASSOC(addr) ) {
1.282 + } else {
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.289 + }
1.290 +}
1.291 +
1.292 +void mmu_utlb_data_write( sh4addr_t addr, uint32_t val )
1.293 +{
1.294 + struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
1.295 + if( UTLB_DATA2(addr) ) {
1.296 + ent->pcmcia = val & 0x0000000F;
1.297 + } else {
1.298 + ent->ppn = (val & 0x1FFFFC00);
1.299 + ent->flags = (val & 0x000001FF);
1.300 + }
1.301 +}
1.302 +
1.303 +/* Cache access - not implemented */
1.304 +
1.305 +int32_t mmu_icache_addr_read( sh4addr_t addr )
1.306 +{
1.307 + return 0; // not implemented
1.308 +}
1.309 +int32_t mmu_icache_data_read( sh4addr_t addr )
1.310 +{
1.311 + return 0; // not implemented
1.312 +}
1.313 +int32_t mmu_ocache_addr_read( sh4addr_t addr )
1.314 +{
1.315 + return 0; // not implemented
1.316 +}
1.317 +int32_t mmu_ocache_data_read( sh4addr_t addr )
1.318 +{
1.319 + return 0; // not implemented
1.320 +}
1.321 +
1.322 +void mmu_icache_addr_write( sh4addr_t addr, uint32_t val )
1.323 +{
1.324 +}
1.325 +
1.326 +void mmu_icache_data_write( sh4addr_t addr, uint32_t val )
1.327 +{
1.328 +}
1.329 +
1.330 +void mmu_ocache_addr_write( sh4addr_t addr, uint32_t val )
1.331 +{
1.332 +}
1.333 +
1.334 +void mmu_ocache_data_write( sh4addr_t addr, uint32_t val )
1.335 +{
1.336 +}
.