Search
lxdream.org :: lxdream/src/sh4/mmu.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/mmu.c
changeset 550:a27e31340147
next559:06714bc64271
next586:2a3ba82cf243
author nkeynes
date Thu Dec 06 10:43:30 2007 +0000 (13 years ago)
permissions -rw-r--r--
last change Add support for the MMIO side of the TLB (and LDTLB)
view annotate diff log raw
     1 /**
     2  * $Id: mmu.c,v 1.15 2007-11-08 11:54:16 nkeynes Exp $
     3  * 
     4  * MMU implementation
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    18 #define MODULE sh4_module
    20 #include <stdio.h>
    21 #include "sh4/sh4mmio.h"
    22 #include "sh4/sh4core.h"
    23 #include "mem.h"
    25 #define OCRAM_START (0x1C000000>>PAGE_BITS)
    26 #define OCRAM_END   (0x20000000>>PAGE_BITS)
    28 #define ITLB_ENTRY_COUNT 4
    29 #define UTLB_ENTRY_COUNT 64
    31 /* Entry address */
    32 #define TLB_VALID     0x00000100
    33 #define TLB_USERMODE  0x00000040
    34 #define TLB_WRITABLE  0x00000020
    35 #define TLB_SIZE_MASK 0x00000090
    36 #define TLB_SIZE_1K   0x00000000
    37 #define TLB_SIZE_4K   0x00000010
    38 #define TLB_SIZE_64K  0x00000080
    39 #define TLB_SIZE_1M   0x00000090
    40 #define TLB_CACHEABLE 0x00000008
    41 #define TLB_DIRTY     0x00000004
    42 #define TLB_SHARE     0x00000002
    43 #define TLB_WRITETHRU 0x00000001
    46 struct itlb_entry {
    47     sh4addr_t vpn; // Virtual Page Number
    48     uint32_t asid; // Process ID
    49     sh4addr_t ppn; // Physical Page Number
    50     uint32_t flags;
    51 };
    53 struct utlb_entry {
    54     sh4addr_t vpn; // Virtual Page Number
    55     uint32_t asid; // Process ID
    56     sh4addr_t ppn; // Physical Page Number
    57     uint32_t flags;
    58     uint32_t pcmcia; // extra pcmcia data - not used
    59 };
    61 static struct itlb_entry mmu_itlb[ITLB_ENTRY_COUNT];
    62 static struct utlb_entry mmu_utlb[UTLB_ENTRY_COUNT];
    63 static uint32_t mmu_urc;
    64 static uint32_t mmu_urb;
    65 static uint32_t mmu_lrui;
    67 static sh4ptr_t cache = NULL;
    69 static void mmu_invalidate_tlb();
    72 int32_t mmio_region_MMU_read( uint32_t reg )
    73 {
    74     switch( reg ) {
    75     case MMUCR:
    76 	return MMIO_READ( MMU, MMUCR) | (mmu_urc<<10) | (mmu_urb<<18) | (mmu_lrui<<26);
    77     default:
    78 	return MMIO_READ( MMU, reg );
    79     }
    80 }
    82 void mmio_region_MMU_write( uint32_t reg, uint32_t val )
    83 {
    84     switch(reg) {
    85     case PTEH:
    86 	val &= 0xFFFFFCFF;
    87 	break;
    88     case PTEL:
    89 	val &= 0x1FFFFDFF;
    90 	break;
    91     case PTEA:
    92 	val &= 0x0000000F;
    93 	break;
    94     case MMUCR:
    95 	if( val & MMUCR_TI ) {
    96 	    mmu_invalidate_tlb();
    97 	}
    98 	mmu_urc = (val >> 10) & 0x3F;
    99 	mmu_urb = (val >> 18) & 0x3F;
   100 	mmu_lrui = (val >> 26) & 0x3F;
   101 	val &= 0x00000301;
   102 	break;
   103     case CCR:
   104 	mmu_set_cache_mode( val & (CCR_OIX|CCR_ORA) );
   105 	break;
   106     default:
   107 	break;
   108     }
   109     MMIO_WRITE( MMU, reg, val );
   110 }
   113 void MMU_init() 
   114 {
   115     cache = mem_alloc_pages(2);
   116 }
   118 void MMU_reset()
   119 {
   120     mmio_region_MMU_write( CCR, 0 );
   121 }
   123 void MMU_save_state( FILE *f )
   124 {
   125     fwrite( cache, 4096, 2, f );
   126     fwrite( &mmu_itlb, sizeof(mmu_itlb), 1, f );
   127     fwrite( &mmu_utlb, sizeof(mmu_utlb), 1, f );
   128 }
   130 int MMU_load_state( FILE *f )
   131 {
   132     /* Setup the cache mode according to the saved register value
   133      * (mem_load runs before this point to load all MMIO data)
   134      */
   135     mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) );
   136     if( fread( cache, 4096, 2, f ) != 2 ) {
   137 	return 1;
   138     }
   139     if( fread( &mmu_itlb, sizeof(mmu_itlb), 1, f ) != 1 ) {
   140 	return 1;
   141     }
   142     if( fread( &mmu_utlb, sizeof(mmu_utlb), 1, f ) != 1 ) {
   143 	return 1;
   144     }
   145     return 0;
   146 }
   148 void mmu_set_cache_mode( int mode )
   149 {
   150     uint32_t i;
   151     switch( mode ) {
   152         case MEM_OC_INDEX0: /* OIX=0 */
   153             for( i=OCRAM_START; i<OCRAM_END; i++ )
   154                 page_map[i] = cache + ((i&0x02)<<(PAGE_BITS-1));
   155             break;
   156         case MEM_OC_INDEX1: /* OIX=1 */
   157             for( i=OCRAM_START; i<OCRAM_END; i++ )
   158                 page_map[i] = cache + ((i&0x02000000)>>(25-PAGE_BITS));
   159             break;
   160         default: /* disabled */
   161             for( i=OCRAM_START; i<OCRAM_END; i++ )
   162                 page_map[i] = NULL;
   163             break;
   164     }
   165 }
   167 /* TLB maintanence */
   169 /**
   170  * LDTLB instruction implementation. Copies PTEH, PTEL and PTEA into the UTLB
   171  * entry identified by MMUCR.URC. Does not modify MMUCR or the ITLB.
   172  */
   173 void MMU_ldtlb()
   174 {
   175     mmu_utlb[mmu_urc].vpn = MMIO_READ(MMU, PTEH) & 0xFFFFFC00;
   176     mmu_utlb[mmu_urc].asid = MMIO_READ(MMU, PTEH) & 0x000000FF;
   177     mmu_utlb[mmu_urc].ppn = MMIO_READ(MMU, PTEL) & 0x1FFFFC00;
   178     mmu_utlb[mmu_urc].flags = MMIO_READ(MMU, PTEL) & 0x00001FF;
   179     mmu_utlb[mmu_urc].pcmcia = MMIO_READ(MMU, PTEA);
   180 }
   182 uint64_t mmu_translate_read( sh4addr_t addr )
   183 {
   184     uint32_t mmucr = MMIO_READ(MMU,MMUCR);
   185     if( IS_SH4_PRIVMODE() ) {
   186 	switch( addr & 0xE0000000 ) {
   187 	case 0x80000000: case 0xA0000000:
   188 	    /* Non-translated read P1,P2 */
   189 	    break;
   190 	case 0xE0000000:
   191 	    /* Non-translated read P4 */
   192 	    break;
   193 	default:
   194 	    if( mmucr&MMUCR_AT ) {
   195 	    } else {
   196 		// direct read
   197 	    }
   198 	}
   199     } else {
   200 	if( addr & 0x80000000 ) {
   201 	    if( ((addr&0xFC000000) == 0xE0000000 ) &&
   202 		((mmucr&MMUCR_SQMD) == 0) ) { 
   203 		// Store queue
   204 		return 0;
   205 	    }
   206 //	    MMU_READ_ADDR_ERROR();
   207 	}
   208 	if( mmucr&MMUCR_AT ) {
   209 	    uint32_t vpn = addr & 0xFFFFFC00;
   210 	    uint32_t asid = MMIO_READ(MMU,PTEH)&0xFF;
   211 	} else {
   212 	    // direct read
   213 	}
   214     }
   215 }
   217 static void mmu_invalidate_tlb()
   218 {
   219     int i;
   220     for( i=0; i<ITLB_ENTRY_COUNT; i++ ) {
   221 	mmu_itlb[i].flags &= (~TLB_VALID);
   222     }
   223     for( i=0; i<UTLB_ENTRY_COUNT; i++ ) {
   224 	mmu_utlb[i].flags &= (~TLB_VALID);
   225     }
   226 }
   228 #define ITLB_ENTRY(addr) ((addr>>7)&0x03)
   230 int32_t mmu_itlb_addr_read( sh4addr_t addr )
   231 {
   232     struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
   233     return ent->vpn | ent->asid | (ent->flags & TLB_VALID);
   234 }
   235 int32_t mmu_itlb_data_read( sh4addr_t addr )
   236 {
   237     struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
   238     return ent->ppn | ent->flags;
   239 }
   241 void mmu_itlb_addr_write( sh4addr_t addr, uint32_t val )
   242 {
   243     struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
   244     ent->vpn = val & 0xFFFFFC00;
   245     ent->asid = val & 0x000000FF;
   246     ent->flags = (ent->flags & ~(TLB_VALID)) | (val&TLB_VALID);
   247 }
   249 void mmu_itlb_data_write( sh4addr_t addr, uint32_t val )
   250 {
   251     struct itlb_entry *ent = &mmu_itlb[ITLB_ENTRY(addr)];
   252     ent->ppn = val & 0x1FFFFC00;
   253     ent->flags = val & 0x00001DA;
   254 }
   256 #define UTLB_ENTRY(addr) ((addr>>8)&0x3F)
   257 #define UTLB_ASSOC(addr) (addr&0x80)
   258 #define UTLB_DATA2(addr) (addr&0x00800000)
   260 int32_t mmu_utlb_addr_read( sh4addr_t addr )
   261 {
   262     struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
   263     return ent->vpn | ent->asid | (ent->flags & TLB_VALID) |
   264 	((ent->flags & TLB_DIRTY)<<7);
   265 }
   266 int32_t mmu_utlb_data_read( sh4addr_t addr )
   267 {
   268     struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
   269     if( UTLB_DATA2(addr) ) {
   270 	return ent->pcmcia;
   271     } else {
   272 	return ent->ppn | ent->flags;
   273     }
   274 }
   276 void mmu_utlb_addr_write( sh4addr_t addr, uint32_t val )
   277 {
   278     if( UTLB_ASSOC(addr) ) {
   279     } else {
   280 	struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
   281 	ent->vpn = (val & 0xFFFFFC00);
   282 	ent->asid = (val & 0xFF);
   283 	ent->flags = (ent->flags & ~(TLB_DIRTY|TLB_VALID));
   284 	ent->flags |= (val & TLB_VALID);
   285 	ent->flags |= ((val & 0x200)>>7);
   286     }
   287 }
   289 void mmu_utlb_data_write( sh4addr_t addr, uint32_t val )
   290 {
   291     struct utlb_entry *ent = &mmu_utlb[UTLB_ENTRY(addr)];
   292     if( UTLB_DATA2(addr) ) {
   293 	ent->pcmcia = val & 0x0000000F;
   294     } else {
   295 	ent->ppn = (val & 0x1FFFFC00);
   296 	ent->flags = (val & 0x000001FF);
   297     }
   298 }
   300 /* Cache access - not implemented */
   302 int32_t mmu_icache_addr_read( sh4addr_t addr )
   303 {
   304     return 0; // not implemented
   305 }
   306 int32_t mmu_icache_data_read( sh4addr_t addr )
   307 {
   308     return 0; // not implemented
   309 }
   310 int32_t mmu_ocache_addr_read( sh4addr_t addr )
   311 {
   312     return 0; // not implemented
   313 }
   314 int32_t mmu_ocache_data_read( sh4addr_t addr )
   315 {
   316     return 0; // not implemented
   317 }
   319 void mmu_icache_addr_write( sh4addr_t addr, uint32_t val )
   320 {
   321 }
   323 void mmu_icache_data_write( sh4addr_t addr, uint32_t val )
   324 {
   325 }
   327 void mmu_ocache_addr_write( sh4addr_t addr, uint32_t val )
   328 {
   329 }
   331 void mmu_ocache_data_write( sh4addr_t addr, uint32_t val )
   332 {
   333 }
.