# HG changeset patch # User nkeynes # Date 1231207088 0 # Node ID d41ee7994db799418da77dc916c8da487abb1b5f # Parent 787729653236a5c43f8d5d026a76ccc6c521ac58 Fully integrate SQ with the new address space code - added additional 'prefetch' memory accessor. TLB is utterly untested, but non-TLB at least still works. --- a/src/mem.c Mon Jan 05 04:19:46 2009 +0000 +++ b/src/mem.c Tue Jan 06 01:58:08 2009 +0000 @@ -78,11 +78,17 @@ { } +void FASTCALL unmapped_prefetch( sh4addr_t addr ) +{ + /* No effect */ +} + struct mem_region_fn mem_region_unmapped = { unmapped_read_long, unmapped_write_long, unmapped_read_long, unmapped_write_long, unmapped_read_long, unmapped_write_long, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; void *mem_alloc_pages( int n ) { @@ -319,6 +325,7 @@ mem_rgn[num_mem_rgns].name = name; mem_rgn[num_mem_rgns].mem = mem; mem_rgn[num_mem_rgns].fn = fn; + fn->prefetch = unmapped_prefetch; num_mem_rgns++; do { --- a/src/mem.h Mon Jan 05 04:19:46 2009 +0000 +++ b/src/mem.h Tue Jan 06 01:58:08 2009 +0000 @@ -33,31 +33,38 @@ typedef FASTCALL void (*mem_write_fn_t)(sh4addr_t, uint32_t); typedef FASTCALL void (*mem_read_burst_fn_t)(unsigned char *,sh4addr_t); typedef FASTCALL void (*mem_write_burst_fn_t)(sh4addr_t,unsigned char *); +typedef FASTCALL void (*mem_prefetch_fn_t)(sh4addr_t); typedef FASTCALL int32_t (*mem_read_exc_fn_t)(sh4addr_t, void *); typedef FASTCALL void (*mem_write_exc_fn_t)(sh4addr_t, uint32_t, void *); typedef FASTCALL void (*mem_read_burst_exc_fn_t)(unsigned char *,sh4addr_t, void *); typedef FASTCALL void (*mem_write_burst_exc_fn_t)(sh4addr_t,unsigned char *, void *); +typedef FASTCALL void (*mem_prefetch_exc_fn_t)(sh4addr_t, void *); /** * Basic memory region vtable - read/write at byte, word, long, and burst * (32-byte) sizes. */ typedef struct mem_region_fn { - FASTCALL int32_t (*read_long)(sh4addr_t addr); - FASTCALL void (*write_long)(sh4addr_t addr, uint32_t val); - FASTCALL int32_t (*read_word)(sh4addr_t addr); - FASTCALL void (*write_word)(sh4addr_t addr, uint32_t val); - FASTCALL int32_t (*read_byte)(sh4addr_t addr); - FASTCALL void (*write_byte)(sh4addr_t addr, uint32_t val); - FASTCALL void (*read_burst)(unsigned char *dest, sh4addr_t addr); - FASTCALL void (*write_burst)(sh4addr_t addr, unsigned char *src); + mem_read_fn_t read_long; + mem_write_fn_t write_long; + mem_read_fn_t read_word; + mem_write_fn_t write_word; + mem_read_fn_t read_byte; + mem_write_fn_t write_byte; + mem_read_burst_fn_t read_burst; + mem_write_burst_fn_t write_burst; + /* Prefetch is provided as a convenience for the SH4 - external memory + * spaces are automatically forced to unmapped_prefetch by mem.c + */ + mem_prefetch_fn_t prefetch; } *mem_region_fn_t; int32_t FASTCALL unmapped_read_long( sh4addr_t addr ); void FASTCALL unmapped_write_long( sh4addr_t addr, uint32_t val ); void FASTCALL unmapped_read_burst( unsigned char *dest, sh4addr_t addr ); void FASTCALL unmapped_write_burst( sh4addr_t addr, unsigned char *src ); +void FASTCALL unmapped_prefetch( sh4addr_t addr ); extern struct mem_region_fn mem_region_unmapped; typedef struct mem_region { --- a/src/mmio.h Mon Jan 05 04:19:46 2009 +0000 +++ b/src/mmio.h Tue Jan 06 01:58:08 2009 +0000 @@ -112,7 +112,7 @@ #undef MMIO_REGION_LIST_BEGIN #undef MMIO_REGION #undef MMIO_REGION_LIST_END -#define MMIO_REGION_BEGIN(b,id,d) struct mmio_region mmio_region_##id = { #id, d, b, {mmio_region_##id##_read, mmio_region_##id##_write,mmio_region_##id##_read, mmio_region_##id##_write,mmio_region_##id##_read, mmio_region_##id##_write,NULL, NULL}, 0, 0, { +#define MMIO_REGION_BEGIN(b,id,d) struct mmio_region mmio_region_##id = { #id, d, b, {mmio_region_##id##_read, mmio_region_##id##_write,mmio_region_##id##_read, mmio_region_##id##_write,mmio_region_##id##_read, mmio_region_##id##_write,NULL, NULL, unmapped_prefetch}, 0, 0, { #define LONG_PORT( o,id,f,def,d ) { #id, d, 32, o, def, f }, #define WORD_PORT( o,id,f,def,d ) { #id, d, 16, o, def, f }, #define BYTE_PORT( o,id,f,def,d ) { #id, d, 8, o, def, f }, --- a/src/sh4/cache.c Mon Jan 05 04:19:46 2009 +0000 +++ b/src/sh4/cache.c Tue Jan 06 01:58:08 2009 +0000 @@ -24,6 +24,7 @@ #include "sh4/sh4core.h" #include "sh4/sh4mmio.h" #include "sh4/xltcache.h" +#include "sh4/mmu.h" #define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS) #define OCRAM_MID (0x7E000000>>LXDREAM_PAGE_BITS) @@ -79,7 +80,6 @@ return 0; } - /************************* OCRAM memory address space ************************/ #define OCRAMPAGE0 (&ccn_ocache_data[4096]) /* Lines 128-255 */ @@ -122,7 +122,8 @@ ocram_page0_read_long, ocram_page0_write_long, ocram_page0_read_word, ocram_page0_write_word, ocram_page0_read_byte, ocram_page0_write_byte, - ocram_page0_read_burst, ocram_page0_write_burst }; + ocram_page0_read_burst, ocram_page0_write_burst, + unmapped_prefetch }; static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr ) { @@ -161,7 +162,8 @@ ocram_page1_read_long, ocram_page1_write_long, ocram_page1_read_word, ocram_page1_write_word, ocram_page1_read_byte, ocram_page1_write_byte, - ocram_page1_read_burst, ocram_page1_write_burst }; + ocram_page1_read_burst, ocram_page1_write_burst, + unmapped_prefetch }; /************************** Cache direct access ******************************/ @@ -187,7 +189,8 @@ ccn_icache_addr_read, ccn_icache_addr_write, unmapped_read_long, unmapped_write_long, unmapped_read_long, unmapped_write_long, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; static int32_t ccn_icache_data_read( sh4addr_t addr ) @@ -206,7 +209,8 @@ ccn_icache_data_read, ccn_icache_data_write, unmapped_read_long, unmapped_write_long, unmapped_read_long, unmapped_write_long, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; static int32_t ccn_ocache_addr_read( sh4addr_t addr ) @@ -235,7 +239,8 @@ ccn_ocache_addr_read, ccn_ocache_addr_write, unmapped_read_long, unmapped_write_long, unmapped_read_long, unmapped_write_long, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; static int32_t ccn_ocache_data_read( sh4addr_t addr ) @@ -254,7 +259,8 @@ ccn_ocache_data_read, ccn_ocache_data_write, unmapped_read_long, unmapped_write_long, unmapped_read_long, unmapped_write_long, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; /****************** Cache control *********************/ @@ -297,19 +303,58 @@ } } +/** + * Prefetch for non-storequeue regions + */ +void FASTCALL ccn_prefetch( sh4addr_t addr ) +{ + +} -/***** Store-queue (considered part of the cache by the SH7750 manual) ******/ -static void FASTCALL p4_storequeue_write_long( sh4addr_t addr, uint32_t val ) +/** + * Prefetch for non-cached regions. Oddly enough, this does nothing whatsoever. + */ +void FASTCALL ccn_uncached_prefetch( sh4addr_t addr ) +{ + +} +/********************************* Store-queue *******************************/ +/* + * The storequeue is strictly speaking part of the cache, but most of + * the complexity is actually around its addressing (ie in the MMU). The + * methods here can assume we've already passed SQMD protection and the TLB + * lookups (where appropriate). + */ +void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val ) { sh4r.store_queue[(addr>>2)&0xF] = val; } -static int32_t FASTCALL p4_storequeue_read_long( sh4addr_t addr ) +int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr ) { return sh4r.store_queue[(addr>>2)&0xF]; } -struct mem_region_fn p4_region_storequeue = { - p4_storequeue_read_long, p4_storequeue_write_long, - p4_storequeue_read_long, p4_storequeue_write_long, - p4_storequeue_read_long, p4_storequeue_write_long, - unmapped_read_burst, unmapped_write_burst }; // No burst access. +/** + * Variant used when tlb is disabled - address will be the original prefetch + * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't + * be hardcoded on 4K page boundaries, so we manually decode it here. + */ +void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr ) +{ + int queue = (addr&0x20)>>2; + sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue]; + uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24; + sh4addr_t target = (addr&0x03FFFFE0) | hi; + ext_address_space[target>>12]->write_burst( target, src ); +} + +/** + * Variant used when tlb is enabled - address in this case is already + * mapped to the external target address. + */ +void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr ) +{ + int queue = (addr&0x20)>>2; + sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue]; + ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src ); +} --- a/src/sh4/mmu.c Mon Jan 05 04:19:46 2009 +0000 +++ b/src/sh4/mmu.c Tue Jan 06 01:58:08 2009 +0000 @@ -47,10 +47,6 @@ mem_region_fn_t *sh4_address_space; mem_region_fn_t *sh4_user_address_space; -/* MMU-mapped storequeue targets. Only used with TLB on */ -mem_region_fn_t *storequeue_address_space; -mem_region_fn_t *storequeue_user_address_space; - /* Accessed from the UTLB accessor methods */ uint32_t mmu_urc; uint32_t mmu_urb; @@ -61,6 +57,7 @@ static struct utlb_page_entry mmu_utlb_pages[UTLB_ENTRY_COUNT]; static uint32_t mmu_lrui; static uint32_t mmu_asid; // current asid +static struct utlb_default_regions *mmu_user_storequeue_regions; /* Structures for 1K page handling */ static struct utlb_1k_entry mmu_utlb_1k_pages[UTLB_ENTRY_COUNT]; @@ -77,7 +74,7 @@ static void mmu_register_user_mem_region( uint32_t start, uint32_t end, mem_region_fn_t fn ); static void mmu_set_tlb_enabled( int tlb_on ); static void mmu_set_tlb_asid( uint32_t asid ); -static void mmu_set_storequeue_protected( int protected ); +static void mmu_set_storequeue_protected( int protected, int tlb_on ); static gboolean mmu_utlb_map_pages( mem_region_fn_t priv_page, mem_region_fn_t user_page, sh4addr_t start_addr, int npages ); static void mmu_utlb_remap_pages( gboolean remap_priv, gboolean remap_user, int entryNo ); static gboolean mmu_utlb_unmap_pages( gboolean unmap_priv, gboolean unmap_user, sh4addr_t start_addr, int npages ); @@ -86,12 +83,23 @@ static struct utlb_1k_entry *mmu_utlb_1k_alloc(); static void mmu_utlb_1k_free( struct utlb_1k_entry *entry ); +static void FASTCALL tlb_miss_read( sh4addr_t addr, void *exc ); static int32_t FASTCALL tlb_protected_read( sh4addr_t addr, void *exc ); static void FASTCALL tlb_protected_write( sh4addr_t addr, uint32_t val, void *exc ); static void FASTCALL tlb_initial_write( sh4addr_t addr, uint32_t val, void *exc ); static uint32_t get_tlb_size_mask( uint32_t flags ); static uint32_t get_tlb_size_pages( uint32_t flags ); +#define DEFAULT_REGIONS 0 +#define DEFAULT_STOREQUEUE_REGIONS 1 +#define DEFAULT_STOREQUEUE_SQMD_REGIONS 2 + +static struct utlb_default_regions mmu_default_regions[3] = { + { &mem_region_tlb_miss, &mem_region_tlb_protected, &mem_region_tlb_multihit }, + { &p4_region_storequeue_miss, &p4_region_storequeue_protected, &p4_region_storequeue_multihit }, + { &p4_region_storequeue_sqmd_miss, &p4_region_storequeue_sqmd_protected, &p4_region_storequeue_sqmd_multihit } }; + +#define IS_STOREQUEUE_PROTECTED() (mmu_user_storequeue_regions == &mmu_default_regions[DEFAULT_STOREQUEUE_SQMD_REGIONS]) /*********************** Module public functions ****************************/ @@ -104,12 +112,11 @@ { sh4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 ); sh4_user_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 ); - storequeue_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 4 ); - storequeue_user_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 4 ); + mmu_user_storequeue_regions = &mmu_default_regions[DEFAULT_STOREQUEUE_REGIONS]; mmu_set_tlb_enabled(0); mmu_register_user_mem_region( 0x80000000, 0x00000000, &mem_region_address_error ); - mmu_register_user_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue); + mmu_register_user_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue ); /* Setup P4 tlb/cache access regions */ mmu_register_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue ); @@ -186,7 +193,7 @@ uint32_t mmucr = MMIO_READ(MMU,MMUCR); mmu_set_tlb_enabled(mmucr&MMUCR_AT); - mmu_set_storequeue_protected(mmucr&MMUCR_SQMD); + mmu_set_storequeue_protected(mmucr&MMUCR_SQMD, mmucr&MMUCR_AT); return 0; } @@ -262,7 +269,7 @@ val &= 0x00000301; tmp = MMIO_READ( MMU, MMUCR ); if( (val ^ tmp) & (MMUCR_SQMD) ) { - mmu_set_storequeue_protected( val & MMUCR_SQMD ); + mmu_set_storequeue_protected( val & MMUCR_SQMD, val&MMUCR_AT ); } if( (val ^ tmp) & (MMUCR_AT) ) { // AT flag has changed state - flush the xlt cache as all bets @@ -387,15 +394,16 @@ mem_region_fn_t *ptr, *uptr; int i; + /* Reset the storequeue area */ + if( tlb_on ) { mmu_register_mem_region(0x00000000, 0x80000000, &mem_region_tlb_miss ); mmu_register_mem_region(0xC0000000, 0xE0000000, &mem_region_tlb_miss ); mmu_register_user_mem_region(0x00000000, 0x80000000, &mem_region_tlb_miss ); - for( i=0, ptr = storequeue_address_space, uptr = storequeue_user_address_space; - i<0x04000000; i+= LXDREAM_PAGE_SIZE ) { - *ptr++ = &mem_region_tlb_miss; - *uptr++ = &mem_region_tlb_miss; - } + + /* Default SQ prefetch goes to TLB miss (?) */ + mmu_register_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue_miss ); + mmu_register_user_mem_region( 0xE0000000, 0xE4000000, mmu_user_storequeue_regions->tlb_miss ); mmu_utlb_register_all(); } else { for( i=0, ptr = sh4_address_space; i<7; i++, ptr += LXDREAM_PAGE_TABLE_ENTRIES ) { @@ -404,16 +412,45 @@ for( i=0, ptr = sh4_user_address_space; i<4; i++, ptr += LXDREAM_PAGE_TABLE_ENTRIES ) { memcpy( ptr, ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES ); } + + mmu_register_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue ); + if( IS_STOREQUEUE_PROTECTED() ) { + mmu_register_user_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue_sqmd ); + } else { + mmu_register_user_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue ); + } } + } -static void mmu_set_storequeue_protected( int protected ) +/** + * Flip the SQMD switch - this is rather expensive, so will need to be changed if + * anything expects to do this frequently. + */ +static void mmu_set_storequeue_protected( int protected, int tlb_on ) { + mem_region_fn_t nontlb_region; + int i; + if( protected ) { - mmu_register_user_mem_region( 0xE0000000, 0xE4000000, &mem_region_address_error ); + mmu_user_storequeue_regions = &mmu_default_regions[DEFAULT_STOREQUEUE_SQMD_REGIONS]; + nontlb_region = &p4_region_storequeue_sqmd; } else { - mmu_register_user_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue ); + mmu_user_storequeue_regions = &mmu_default_regions[DEFAULT_STOREQUEUE_REGIONS]; + nontlb_region = &p4_region_storequeue; } + + if( tlb_on ) { + mmu_register_user_mem_region( 0xE0000000, 0xE4000000, mmu_user_storequeue_regions->tlb_miss ); + for( i=0; i> 12]; mem_region_fn_t *uptr = &sh4_user_address_space[start_addr >> 12]; + struct utlb_default_regions *privdefs = &mmu_default_regions[DEFAULT_REGIONS]; + struct utlb_default_regions *userdefs = privdefs; + gboolean mapping_ok = TRUE; int i; if( (start_addr & 0xFC000000) == 0xE0000000 ) { /* Storequeue mapping */ - ptr = &storequeue_address_space[(start_addr-0xE0000000) >> 12]; - uptr = &storequeue_user_address_space[(start_addr-0xE0000000) >> 12]; + privdefs = &mmu_default_regions[DEFAULT_STOREQUEUE_REGIONS]; + userdefs = mmu_user_storequeue_regions; } else if( (start_addr & 0xE0000000) == 0xC0000000 ) { user_page = NULL; /* No user access to P3 region */ } else if( start_addr >= 0x80000000 ) { @@ -518,58 +558,47 @@ } if( priv_page != NULL ) { - if( ent->subpages[idx] == &mem_region_tlb_miss ) { + if( ent->subpages[idx] == privdefs->tlb_miss ) { ent->subpages[idx] = priv_page; } else { mapping_ok = FALSE; - ent->subpages[idx] = &mem_region_tlb_multihit; + ent->subpages[idx] = privdefs->tlb_multihit; } } if( user_page != NULL ) { - if( ent->user_subpages[idx] == &mem_region_tlb_miss ) { + if( ent->user_subpages[idx] == userdefs->tlb_miss ) { ent->user_subpages[idx] = user_page; } else { mapping_ok = FALSE; - ent->user_subpages[idx] = &mem_region_tlb_multihit; + ent->user_subpages[idx] = userdefs->tlb_multihit; } } } else { if( priv_page != NULL ) { - if( user_page != NULL ) { - for( i=0; itlb_miss ) { + *ptr++ = priv_page; + } else { + mapping_ok = FALSE; + *ptr++ = privdefs->tlb_multihit; } } - } else if( user_page != NULL ) { + } + if( user_page != NULL ) { /* User mapping only (eg ASID change remap w/ SV=1) */ for( i=0; itlb_miss ) { *uptr++ = user_page; } else { mapping_ok = FALSE; - *uptr++ = &mem_region_tlb_multihit; + *uptr++ = userdefs->tlb_multihit; } } } } + return mapping_ok; } @@ -621,13 +650,16 @@ { mem_region_fn_t *ptr = &sh4_address_space[start_addr >> 12]; mem_region_fn_t *uptr = &sh4_user_address_space[start_addr >> 12]; + struct utlb_default_regions *privdefs = &mmu_default_regions[DEFAULT_REGIONS]; + struct utlb_default_regions *userdefs = privdefs; + gboolean unmapping_ok = TRUE; int i; if( (start_addr & 0xFC000000) == 0xE0000000 ) { /* Storequeue mapping */ - ptr = &storequeue_address_space[(start_addr-0xE0000000) >> 12]; - uptr = &storequeue_user_address_space[(start_addr-0xE0000000) >> 12]; + privdefs = &mmu_default_regions[DEFAULT_STOREQUEUE_REGIONS]; + userdefs = mmu_user_storequeue_regions; } else if( (start_addr & 0xE0000000) == 0xC0000000 ) { unmap_user = FALSE; } else if( start_addr >= 0x80000000 ) { @@ -638,13 +670,13 @@ assert( IS_1K_PAGE_ENTRY( *ptr ) ); struct utlb_1k_entry *ent = (struct utlb_1k_entry *)*ptr; int i, idx = (start_addr >> 10) & 0x03, mergeable=1; - if( ent->subpages[idx] == &mem_region_tlb_multihit ) { + if( ent->subpages[idx] == privdefs->tlb_multihit ) { unmapping_ok = FALSE; } if( unmap_priv ) - ent->subpages[idx] = &mem_region_tlb_miss; + ent->subpages[idx] = privdefs->tlb_miss; if( unmap_user ) - ent->user_subpages[idx] = &mem_region_tlb_miss; + ent->user_subpages[idx] = userdefs->tlb_miss; /* If all 4 subpages have the same content, merge them together and * release the 1K entry @@ -664,30 +696,21 @@ } } else { if( unmap_priv ) { - if( unmap_user ) { - for( i=0; itlb_multihit ) { unmapping_ok = FALSE; } - *uptr++ = &mem_region_tlb_miss; + *ptr++ = privdefs->tlb_miss; + } + } + if( unmap_user ) { + /* User (un)mapping */ + for( i=0; itlb_multihit ) { + unmapping_ok = FALSE; + } + *uptr++ = userdefs->tlb_miss; } } } @@ -703,28 +726,47 @@ sh4addr_t start_addr = ent->vpn & ent->mask; int npages = get_tlb_size_pages(ent->flags); - if( (ent->flags & TLB_USERMODE) == 0 ) { - upage = &mem_region_user_protected; - } else { - upage = page; + if( (start_addr & 0xFC000000) == 0xE0000000 ) { + /* Store queue mappings are a bit different - normal access is fixed to + * the store queue register block, and we only map prefetches through + * the TLB + */ + mmu_utlb_init_storequeue_vtable( ent, &mmu_utlb_pages[entry] ); + + if( (ent->flags & TLB_USERMODE) == 0 ) { + upage = mmu_user_storequeue_regions->tlb_prot; + } else if( IS_STOREQUEUE_PROTECTED() ) { + upage = &p4_region_storequeue_sqmd; + } else { + upage = page; + } + + } else { + + if( (ent->flags & TLB_USERMODE) == 0 ) { + upage = &mem_region_tlb_protected; + } else { + upage = page; + } + + if( (ent->flags & TLB_WRITABLE) == 0 ) { + page->write_long = (mem_write_fn_t)tlb_protected_write; + page->write_word = (mem_write_fn_t)tlb_protected_write; + page->write_byte = (mem_write_fn_t)tlb_protected_write; + page->write_burst = (mem_write_burst_fn_t)tlb_protected_write; + mmu_utlb_init_vtable( ent, &mmu_utlb_pages[entry], FALSE ); + } else if( (ent->flags & TLB_DIRTY) == 0 ) { + page->write_long = (mem_write_fn_t)tlb_initial_write; + page->write_word = (mem_write_fn_t)tlb_initial_write; + page->write_byte = (mem_write_fn_t)tlb_initial_write; + page->write_burst = (mem_write_burst_fn_t)tlb_initial_write; + mmu_utlb_init_vtable( ent, &mmu_utlb_pages[entry], FALSE ); + } else { + mmu_utlb_init_vtable( ent, &mmu_utlb_pages[entry], TRUE ); + } } + mmu_utlb_pages[entry].user_fn = upage; - - if( (ent->flags & TLB_WRITABLE) == 0 ) { - page->write_long = (mem_write_fn_t)tlb_protected_write; - page->write_word = (mem_write_fn_t)tlb_protected_write; - page->write_byte = (mem_write_fn_t)tlb_protected_write; - page->write_burst = (mem_write_burst_fn_t)tlb_protected_write; - mmu_utlb_init_vtable( ent, &mmu_utlb_pages[entry], FALSE ); - } else if( (ent->flags & TLB_DIRTY) == 0 ) { - page->write_long = (mem_write_fn_t)tlb_initial_write; - page->write_word = (mem_write_fn_t)tlb_initial_write; - page->write_byte = (mem_write_fn_t)tlb_initial_write; - page->write_burst = (mem_write_burst_fn_t)tlb_initial_write; - mmu_utlb_init_vtable( ent, &mmu_utlb_pages[entry], FALSE ); - } else { - mmu_utlb_init_vtable( ent, &mmu_utlb_pages[entry], TRUE ); - } /* Is page visible? */ if( (ent->flags & TLB_SHARE) || ent->asid == mmu_asid ) { @@ -1124,24 +1166,6 @@ } } -void FASTCALL sh4_flush_store_queue( sh4addr_t addr ) -{ - int queue = (addr&0x20)>>2; - uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24; - sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue]; - sh4addr_t target = (addr&0x03FFFFE0) | hi; - ext_address_space[target>>12]->write_burst( target, src ); -} - -void FASTCALL sh4_flush_store_queue_mmu( sh4addr_t addr, void *exc ) -{ - int queue = (addr&0x20)>>2; - sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue]; - sh4addr_t target; - /* Store queue operation */ - storequeue_address_space[(addr&0x03FFFFFE0)>>12]->write_burst( addr, src); -} - /********************** TLB Direct-Access Regions ***************************/ #ifdef HAVE_FRAME_ADDRESS #define EXCEPTION_EXIT() do{ *(((void **)__builtin_frame_address(0))+1) = exc; return; } while(0) @@ -1308,22 +1332,26 @@ mmu_itlb_addr_read, mmu_itlb_addr_write, mmu_itlb_addr_read, mmu_itlb_addr_write, mmu_itlb_addr_read, mmu_itlb_addr_write, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; struct mem_region_fn p4_region_itlb_data = { mmu_itlb_data_read, mmu_itlb_data_write, mmu_itlb_data_read, mmu_itlb_data_write, mmu_itlb_data_read, mmu_itlb_data_write, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; struct mem_region_fn p4_region_utlb_addr = { mmu_utlb_addr_read, (mem_write_fn_t)mmu_utlb_addr_write, mmu_utlb_addr_read, (mem_write_fn_t)mmu_utlb_addr_write, mmu_utlb_addr_read, (mem_write_fn_t)mmu_utlb_addr_write, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; struct mem_region_fn p4_region_utlb_data = { mmu_utlb_data_read, mmu_utlb_data_write, mmu_utlb_data_read, mmu_utlb_data_write, mmu_utlb_data_read, mmu_utlb_data_write, - unmapped_read_burst, unmapped_write_burst }; + unmapped_read_burst, unmapped_write_burst, + unmapped_prefetch }; /********************** Error regions **************************/ @@ -1417,25 +1445,92 @@ (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, - (mem_read_burst_fn_t)address_error_read_burst, (mem_write_burst_fn_t)address_error_write }; + (mem_read_burst_fn_t)address_error_read_burst, (mem_write_burst_fn_t)address_error_write, + unmapped_prefetch }; struct mem_region_fn mem_region_tlb_miss = { (mem_read_fn_t)tlb_miss_read, (mem_write_fn_t)tlb_miss_write, (mem_read_fn_t)tlb_miss_read, (mem_write_fn_t)tlb_miss_write, (mem_read_fn_t)tlb_miss_read, (mem_write_fn_t)tlb_miss_write, - (mem_read_burst_fn_t)tlb_miss_read_burst, (mem_write_burst_fn_t)tlb_miss_write }; + (mem_read_burst_fn_t)tlb_miss_read_burst, (mem_write_burst_fn_t)tlb_miss_write, + unmapped_prefetch }; -struct mem_region_fn mem_region_user_protected = { +struct mem_region_fn mem_region_tlb_protected = { (mem_read_fn_t)tlb_protected_read, (mem_write_fn_t)tlb_protected_write, (mem_read_fn_t)tlb_protected_read, (mem_write_fn_t)tlb_protected_write, (mem_read_fn_t)tlb_protected_read, (mem_write_fn_t)tlb_protected_write, - (mem_read_burst_fn_t)tlb_protected_read_burst, (mem_write_burst_fn_t)tlb_protected_write }; + (mem_read_burst_fn_t)tlb_protected_read_burst, (mem_write_burst_fn_t)tlb_protected_write, + unmapped_prefetch }; struct mem_region_fn mem_region_tlb_multihit = { (mem_read_fn_t)tlb_multi_hit_read, (mem_write_fn_t)tlb_multi_hit_write, (mem_read_fn_t)tlb_multi_hit_read, (mem_write_fn_t)tlb_multi_hit_write, (mem_read_fn_t)tlb_multi_hit_read, (mem_write_fn_t)tlb_multi_hit_write, - (mem_read_burst_fn_t)tlb_multi_hit_read_burst, (mem_write_burst_fn_t)tlb_multi_hit_write }; + (mem_read_burst_fn_t)tlb_multi_hit_read_burst, (mem_write_burst_fn_t)tlb_multi_hit_write, + (mem_prefetch_fn_t)tlb_multi_hit_read }; + +/* Store-queue regions */ +/* These are a bit of a pain - the first 8 fields are controlled by SQMD, while + * the final (prefetch) is controlled by the actual TLB settings (plus SQMD in + * some cases), in contrast to the ordinary fields above. + * + * There is probably a simpler way to do this. + */ + +struct mem_region_fn p4_region_storequeue = { + ccn_storequeue_read_long, ccn_storequeue_write_long, + unmapped_read_long, unmapped_write_long, /* TESTME: Officially only long access is supported */ + unmapped_read_long, unmapped_write_long, + unmapped_read_burst, unmapped_write_burst, + ccn_storequeue_prefetch }; + +struct mem_region_fn p4_region_storequeue_miss = { + ccn_storequeue_read_long, ccn_storequeue_write_long, + unmapped_read_long, unmapped_write_long, /* TESTME: Officially only long access is supported */ + unmapped_read_long, unmapped_write_long, + unmapped_read_burst, unmapped_write_burst, + (mem_prefetch_fn_t)tlb_miss_read }; + +struct mem_region_fn p4_region_storequeue_multihit = { + ccn_storequeue_read_long, ccn_storequeue_write_long, + unmapped_read_long, unmapped_write_long, /* TESTME: Officially only long access is supported */ + unmapped_read_long, unmapped_write_long, + unmapped_read_burst, unmapped_write_burst, + (mem_prefetch_fn_t)tlb_multi_hit_read }; + +struct mem_region_fn p4_region_storequeue_protected = { + ccn_storequeue_read_long, ccn_storequeue_write_long, + unmapped_read_long, unmapped_write_long, + unmapped_read_long, unmapped_write_long, + unmapped_read_burst, unmapped_write_burst, + (mem_prefetch_fn_t)tlb_protected_read }; + +struct mem_region_fn p4_region_storequeue_sqmd = { + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_burst_fn_t)address_error_read_burst, (mem_write_burst_fn_t)address_error_write, + (mem_prefetch_fn_t)address_error_read }; - \ No newline at end of file +struct mem_region_fn p4_region_storequeue_sqmd_miss = { + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_burst_fn_t)address_error_read_burst, (mem_write_burst_fn_t)address_error_write, + (mem_prefetch_fn_t)tlb_miss_read }; + +struct mem_region_fn p4_region_storequeue_sqmd_multihit = { + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_burst_fn_t)address_error_read_burst, (mem_write_burst_fn_t)address_error_write, + (mem_prefetch_fn_t)tlb_multi_hit_read }; + +struct mem_region_fn p4_region_storequeue_sqmd_protected = { + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_fn_t)address_error_read, (mem_write_fn_t)address_error_write, + (mem_read_burst_fn_t)address_error_read_burst, (mem_write_burst_fn_t)address_error_write, + (mem_prefetch_fn_t)tlb_protected_read }; + --- a/src/sh4/mmu.h Mon Jan 05 04:19:46 2009 +0000 +++ b/src/sh4/mmu.h Tue Jan 06 01:58:08 2009 +0000 @@ -87,9 +87,9 @@ struct utlb_page_entry { struct mem_region_fn fn; - mem_region_fn_t user_fn; + struct mem_region_fn *user_fn; mem_region_fn_t target; - unsigned char code[TLB_FUNC_SIZE*8]; + unsigned char code[TLB_FUNC_SIZE*9]; }; struct utlb_1k_entry { @@ -97,11 +97,19 @@ struct mem_region_fn user_fn; struct mem_region_fn *subpages[4]; struct mem_region_fn *user_subpages[4]; - unsigned char code[TLB_FUNC_SIZE*16]; + unsigned char code[TLB_FUNC_SIZE*18]; }; +struct utlb_default_regions { + mem_region_fn_t tlb_miss; + mem_region_fn_t tlb_prot; + mem_region_fn_t tlb_multihit; +}; + + void mmu_utlb_init_vtable( struct utlb_entry *ent, struct utlb_page_entry *page, gboolean writable ); void mmu_utlb_1k_init_vtable( struct utlb_1k_entry *ent ); +void mmu_utlb_init_storequeue_vtable( struct utlb_entry *ent, struct utlb_page_entry *page ); extern uint32_t mmu_urc; extern uint32_t mmu_urb; @@ -114,12 +122,36 @@ extern struct mem_region_fn **sh4_address_space; extern struct mem_region_fn **sh4_user_address_space; -/** Store-queue (prefetch) address space (privileged and user access) - * Page map (4KB) of the 0xE0000000..0xE4000000 region - * Same caveats apply as for the primary address space above. - */ -extern struct mem_region_fn **storequeue_address_space; -extern struct mem_region_fn **storequeue_user_address_space; +/************ Storequeue/cache functions ***********/ +void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val ); +int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr ); + +/** Default storequeue prefetch when TLB is disabled */ +void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr ); + +/** TLB-enabled variant of the storequeue prefetch */ +void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr ); + +/** Non-storequeue prefetch */ +void FASTCALL ccn_prefetch( sh4addr_t addr ); + +/** Non-cached prefetch (ie, no-op) */ +void FASTCALL ccn_uncached_prefetch( sh4addr_t addr ); + + +extern struct mem_region_fn mem_region_address_error; +extern struct mem_region_fn mem_region_tlb_miss; +extern struct mem_region_fn mem_region_tlb_multihit; +extern struct mem_region_fn mem_region_tlb_protected; + +extern struct mem_region_fn p4_region_storequeue; +extern struct mem_region_fn p4_region_storequeue_multihit; +extern struct mem_region_fn p4_region_storequeue_miss; +extern struct mem_region_fn p4_region_storequeue_protected; +extern struct mem_region_fn p4_region_storequeue_sqmd; +extern struct mem_region_fn p4_region_storequeue_sqmd_miss; +extern struct mem_region_fn p4_region_storequeue_sqmd_multihit; +extern struct mem_region_fn p4_region_storequeue_sqmd_protected; #ifdef __cplusplus } --- a/src/sh4/mmux86.c Mon Jan 05 04:19:46 2009 +0000 +++ b/src/sh4/mmux86.c Tue Jan 06 01:58:08 2009 +0000 @@ -49,7 +49,7 @@ uint8_t **fn = (uint8_t **)ext_address_space[ppn>>12]; uint8_t **out = (uint8_t **)&page->fn; - for( i=0; i<8; i+= inc, fn += inc, out += inc ) { + for( i=0; i<9; i+= inc, fn += inc, out += inc ) { *out = xlat_output; #if SIZEOF_VOID_P == 8 MOV_imm64_r32((uintptr_t)&mmu_urc, R_EAX ); @@ -69,6 +69,25 @@ JMP_r32disp8(R_ECX, (((uintptr_t)out) - ((uintptr_t)&page->fn)) ); // 3 } } + + page->fn.prefetch = unmapped_prefetch; // FIXME +} + +void mmu_utlb_init_storequeue_vtable( struct utlb_entry *ent, struct utlb_page_entry *page ) +{ + uint32_t mask = ent->mask; + uint32_t vpn = ent->vpn & mask; + uint32_t ppn = ent->ppn & mask; + + xlat_output = page->code; + + memcpy( page, &p4_region_storequeue, sizeof(struct mem_region_fn) ); + + /* TESTME: Does a PREF increment the URC counter? */ + page->fn.prefetch = (mem_prefetch_fn_t)xlat_output; + ADD_imm32_r32( ppn-vpn, ARG1 ); + int rel = ((uint8_t *)ccn_storequeue_prefetch_tlb) - xlat_output; + JMP_rel( rel ); } void mmu_utlb_1k_init_vtable( struct utlb_1k_entry *entry ) @@ -77,7 +96,7 @@ int i; uint8_t **out = (uint8_t **)&entry->fn; - for( i=0; i<8; i++, out++ ) { + for( i=0; i<9; i++, out++ ) { *out = xlat_output; MOV_r32_r32( ARG1, R_ECX ); SHR_imm8_r32( 10, R_ECX ); @@ -92,7 +111,7 @@ } out = (uint8_t **)&entry->user_fn; - for( i=0; i<8; i++, out++ ) { + for( i=0; i<9; i++, out++ ) { *out = xlat_output; MOV_r32_r32( ARG1, R_ECX ); SHR_imm8_r32( 10, R_ECX ); --- a/src/sh4/sh4core.h Mon Jan 05 04:19:46 2009 +0000 +++ b/src/sh4/sh4core.h Tue Jan 06 01:58:08 2009 +0000 @@ -281,7 +281,6 @@ #define FPULi (sh4r.fpul.i) /**************** SH4 internal memory regions *****************/ -extern struct mem_region_fn p4_region_storequeue; extern struct mem_region_fn p4_region_itlb_addr; extern struct mem_region_fn p4_region_itlb_data; extern struct mem_region_fn p4_region_utlb_addr; @@ -290,10 +289,7 @@ extern struct mem_region_fn p4_region_icache_data; extern struct mem_region_fn p4_region_ocache_addr; extern struct mem_region_fn p4_region_ocache_data; -extern struct mem_region_fn mem_region_address_error; -extern struct mem_region_fn mem_region_tlb_miss; -extern struct mem_region_fn mem_region_tlb_multihit; -extern struct mem_region_fn mem_region_user_protected; + #ifdef __cplusplus --- a/src/sh4/sh4core.in Mon Jan 05 04:19:46 2009 +0000 +++ b/src/sh4/sh4core.in Tue Jan 06 01:58:08 2009 +0000 @@ -176,6 +176,7 @@ #define MEM_WRITE_BYTE( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_byte)((addr), (val), &&except) #define MEM_WRITE_WORD( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_word)((addr), (val), &&except) #define MEM_WRITE_LONG( addr, val ) ((mem_write_exc_fn_t)ADDRSPACE[(addr)>>12]->write_long)((addr), (val), &&except) +#define MEM_PREFETCH( addr ) ((mem_prefetch_exc_fn_t)ADDRSPACE[(addr)>>12]->prefetch)((addr), &&except) #else #define INIT_EXCEPTIONS(label) #define MEM_READ_BYTE( addr, val ) val = ADDRSPACE[(addr)>>12]->read_byte(addr) @@ -184,6 +185,7 @@ #define MEM_WRITE_BYTE( addr, val ) ADDRSPACE[(addr)>>12]->write_byte(addr, val) #define MEM_WRITE_WORD( addr, val ) ADDRSPACE[(addr)>>12]->write_word(addr, val) #define MEM_WRITE_LONG( addr, val ) ADDRSPACE[(addr)>>12]->write_long(addr, val) +#define MEM_PREFETCH( addr ) ADDRSPACE[(addr)>>12]->prefetch(addr) #endif @@ -354,10 +356,7 @@ NOP {: /* NOP */ :} PREF @Rn {: - tmp = sh4r.r[Rn]; - if( (tmp & 0xFC000000) == 0xE0000000 ) { - sh4_flush_store_queue(tmp); - } + MEM_PREFETCH(sh4r.r[Rn]); :} OCBI @Rn {: :} OCBP @Rn {: :} --- a/src/sh4/sh4x86.in Mon Jan 05 04:19:46 2009 +0000 +++ b/src/sh4/sh4x86.in Tue Jan 06 01:58:08 2009 +0000 @@ -311,6 +311,7 @@ #define MEM_WRITE_BYTE( addr_reg, value_reg ) decode_address(addr_reg); _CALL_WRITE(addr_reg, value_reg, write_byte) #define MEM_WRITE_WORD( addr_reg, value_reg ) decode_address(addr_reg); _CALL_WRITE(addr_reg, value_reg, write_word) #define MEM_WRITE_LONG( addr_reg, value_reg ) decode_address(addr_reg); _CALL_WRITE(addr_reg, value_reg, write_long) +#define MEM_PREFETCH( addr_reg ) decode_address(addr_reg); _CALL_READ(addr_reg, prefetch) #define SLOTILLEGAL() JMP_exc(EXC_SLOT_ILLEGAL); sh4_x86.in_delay_slot = DELAY_NONE; return 2; @@ -2501,18 +2502,7 @@ PREF @Rn {: COUNT_INST(I_PREF); load_reg( R_EAX, Rn ); - MOV_r32_r32( R_EAX, R_ECX ); - AND_imm32_r32( 0xFC000000, R_ECX ); - CMP_imm32_r32( 0xE0000000, R_ECX ); - JNE_rel8(end); - if( sh4_x86.tlb_on ) { - call_func1( sh4_flush_store_queue_mmu, R_EAX ); - TEST_r32_r32( R_EAX, R_EAX ); - JE_exc(-1); - } else { - call_func1( sh4_flush_store_queue, R_EAX ); - } - JMP_TARGET(end); + MEM_PREFETCH( R_EAX ); sh4_x86.tstate = TSTATE_NONE; :} SLEEP {: