nkeynes@953: /** nkeynes@953: * $Id$ nkeynes@953: * Implements the on-chip operand cache, instruction cache, and store queue. nkeynes@953: * nkeynes@953: * Copyright (c) 2008 Nathan Keynes. nkeynes@953: * nkeynes@953: * This program is free software; you can redistribute it and/or modify nkeynes@953: * it under the terms of the GNU General Public License as published by nkeynes@953: * the Free Software Foundation; either version 2 of the License, or nkeynes@953: * (at your option) any later version. nkeynes@953: * nkeynes@953: * This program is distributed in the hope that it will be useful, nkeynes@953: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@953: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@953: * GNU General Public License for more details. nkeynes@953: */ nkeynes@953: nkeynes@953: #define MODULE sh4_module nkeynes@953: nkeynes@953: #include nkeynes@953: #include "dream.h" nkeynes@953: #include "mem.h" nkeynes@953: #include "mmio.h" nkeynes@971: #include "clock.h" nkeynes@953: #include "sh4/sh4core.h" nkeynes@953: #include "sh4/sh4mmio.h" nkeynes@953: #include "sh4/mmu.h" nkeynes@953: nkeynes@953: #define OCRAM_START (0x7C000000>>LXDREAM_PAGE_BITS) nkeynes@953: #define OCRAM_MID (0x7E000000>>LXDREAM_PAGE_BITS) nkeynes@953: #define OCRAM_END (0x80000000>>LXDREAM_PAGE_BITS) nkeynes@953: nkeynes@953: #define CACHE_VALID 1 nkeynes@953: #define CACHE_DIRTY 2 nkeynes@953: nkeynes@953: #define ICACHE_ENTRY_COUNT 256 nkeynes@953: #define OCACHE_ENTRY_COUNT 512 nkeynes@953: nkeynes@953: struct cache_line { nkeynes@953: uint32_t key; // Fast address match - bits 5..28 for valid entry, -1 for invalid entry nkeynes@953: uint32_t tag; // tag + flags value from the address field nkeynes@953: }; nkeynes@953: nkeynes@953: nkeynes@953: static struct cache_line ccn_icache[ICACHE_ENTRY_COUNT]; nkeynes@971: struct cache_line ccn_ocache[OCACHE_ENTRY_COUNT]; nkeynes@953: static unsigned char ccn_icache_data[ICACHE_ENTRY_COUNT*32]; nkeynes@971: unsigned char ccn_ocache_data[OCACHE_ENTRY_COUNT*32]; nkeynes@953: nkeynes@953: nkeynes@953: /*********************** General module requirements ********************/ nkeynes@953: nkeynes@971: void CCN_reset() nkeynes@971: { nkeynes@971: /* Clear everything for consistency */ nkeynes@971: memset( ccn_icache, 0, sizeof(ccn_icache) ); nkeynes@971: memset( ccn_ocache, 0, sizeof(ccn_icache) ); nkeynes@971: memset( ccn_icache_data, 0, sizeof(ccn_icache) ); nkeynes@971: memset( ccn_ocache_data, 0, sizeof(ccn_icache) ); nkeynes@971: } nkeynes@971: nkeynes@953: void CCN_save_state( FILE *f ) nkeynes@953: { nkeynes@953: fwrite( &ccn_icache, sizeof(ccn_icache), 1, f ); nkeynes@953: fwrite( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ); nkeynes@953: fwrite( &ccn_ocache, sizeof(ccn_ocache), 1, f); nkeynes@953: fwrite( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f); nkeynes@953: } nkeynes@953: nkeynes@953: int CCN_load_state( FILE *f ) nkeynes@953: { nkeynes@953: /* Setup the cache mode according to the saved register value nkeynes@953: * (mem_load runs before this point to load all MMIO data) nkeynes@953: */ nkeynes@953: mmio_region_MMU_write( CCR, MMIO_READ(MMU, CCR) ); nkeynes@953: nkeynes@953: if( fread( &ccn_icache, sizeof(ccn_icache), 1, f ) != 1 ) { nkeynes@953: return 1; nkeynes@953: } nkeynes@953: if( fread( &ccn_icache_data, sizeof(ccn_icache_data), 1, f ) != 1 ) { nkeynes@953: return 1; nkeynes@953: } nkeynes@953: if( fread( &ccn_ocache, sizeof(ccn_ocache), 1, f ) != 1 ) { nkeynes@953: return 1; nkeynes@953: } nkeynes@953: if( fread( &ccn_ocache_data, sizeof(ccn_ocache_data), 1, f ) != 1 ) { nkeynes@953: return 1; nkeynes@953: } nkeynes@953: return 0; nkeynes@953: } nkeynes@953: nkeynes@953: /************************* OCRAM memory address space ************************/ nkeynes@953: nkeynes@953: #define OCRAMPAGE0 (&ccn_ocache_data[4096]) /* Lines 128-255 */ nkeynes@953: #define OCRAMPAGE1 (&ccn_ocache_data[12288]) /* Lines 384-511 */ nkeynes@953: nkeynes@953: static int32_t FASTCALL ocram_page0_read_long( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return *((int32_t *)(OCRAMPAGE0 + (addr&0x00000FFF))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ocram_page0_read_word( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT16(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ocram_page0_read_byte( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT8(*((int16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)))); nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page0_write_long( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint32_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = val; nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page0_write_word( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint16_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint16_t)val; nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page0_write_byte( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint8_t *)(OCRAMPAGE0 + (addr&0x00000FFF)) = (uint8_t)val; nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page0_read_burst( unsigned char *dest, sh4addr_t addr ) nkeynes@953: { nkeynes@953: memcpy( dest, OCRAMPAGE0+(addr&0x00000FFF), 32 ); nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page0_write_burst( sh4addr_t addr, unsigned char *src ) nkeynes@953: { nkeynes@953: memcpy( OCRAMPAGE0+(addr&0x00000FFF), src, 32 ); nkeynes@953: } nkeynes@953: nkeynes@953: struct mem_region_fn mem_region_ocram_page0 = { nkeynes@953: ocram_page0_read_long, ocram_page0_write_long, nkeynes@953: ocram_page0_read_word, ocram_page0_write_word, nkeynes@953: ocram_page0_read_byte, ocram_page0_write_byte, nkeynes@953: ocram_page0_read_burst, ocram_page0_write_burst, nkeynes@975: unmapped_prefetch, ocram_page0_read_byte }; nkeynes@953: nkeynes@953: static int32_t FASTCALL ocram_page1_read_long( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return *((int32_t *)(OCRAMPAGE1 + (addr&0x00000FFF))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ocram_page1_read_word( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT16(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)))); nkeynes@953: } nkeynes@953: static int32_t FASTCALL ocram_page1_read_byte( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return SIGNEXT8(*((int16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)))); nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page1_write_long( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint32_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = val; nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page1_write_word( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint16_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint16_t)val; nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page1_write_byte( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: *(uint8_t *)(OCRAMPAGE1 + (addr&0x00000FFF)) = (uint8_t)val; nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page1_read_burst( unsigned char *dest, sh4addr_t addr ) nkeynes@953: { nkeynes@953: memcpy( dest, OCRAMPAGE1+(addr&0x00000FFF), 32 ); nkeynes@953: } nkeynes@953: static void FASTCALL ocram_page1_write_burst( sh4addr_t addr, unsigned char *src ) nkeynes@953: { nkeynes@953: memcpy( OCRAMPAGE1+(addr&0x00000FFF), src, 32 ); nkeynes@953: } nkeynes@953: nkeynes@953: struct mem_region_fn mem_region_ocram_page1 = { nkeynes@953: ocram_page1_read_long, ocram_page1_write_long, nkeynes@953: ocram_page1_read_word, ocram_page1_write_word, nkeynes@953: ocram_page1_read_byte, ocram_page1_write_byte, nkeynes@953: ocram_page1_read_burst, ocram_page1_write_burst, nkeynes@975: unmapped_prefetch, ocram_page1_read_byte }; nkeynes@953: nkeynes@971: /**************************** Cache functions ********************************/ nkeynes@971: char ccn_cache_map[16 MB]; // 24 bits of address space nkeynes@971: nkeynes@971: /** nkeynes@971: * Load a 32-byte cache line from external memory at the given ext address. nkeynes@971: * @param addr external address pre-masked to 1FFFFFFE0 nkeynes@971: */ nkeynes@971: sh4addr_t FASTCALL ccn_ocache_load_line( sh4addr_t addr ) nkeynes@971: { nkeynes@971: int entry = addr & 0x00003FE0; nkeynes@971: struct cache_line *line = &ccn_ocache[entry>>5]; nkeynes@980: unsigned char *cache_data = &ccn_ocache_data[entry]; nkeynes@971: sh4addr_t old_addr = line->tag; nkeynes@971: line->tag = addr & 0x1FFFFFE0; nkeynes@971: char oldstate = ccn_cache_map[old_addr>>5]; nkeynes@971: ccn_cache_map[old_addr>>5] = 0; nkeynes@971: ccn_cache_map[addr>>5] = CACHE_VALID; nkeynes@971: if( oldstate == (CACHE_VALID|CACHE_DIRTY) ) { nkeynes@971: // Cache line is dirty - writeback. nkeynes@971: ext_address_space[old_addr>>12]->write_burst(old_addr, cache_data); nkeynes@971: } nkeynes@971: ext_address_space[addr>>12]->read_burst(cache_data, addr & 0x1FFFFFE0); nkeynes@971: return addr; nkeynes@971: } nkeynes@971: nkeynes@971: /* Long read through the operand cache */ nkeynes@971: /* nkeynes@971: int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr ); nkeynes@971: int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr ); nkeynes@971: int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr ); nkeynes@971: void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t val ); nkeynes@971: void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t val ); nkeynes@971: void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t val ); nkeynes@971: nkeynes@971: */ nkeynes@971: static int32_t FASTCALL ccn_ocache_read_long( sh4addr_t addr ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) { nkeynes@971: ccn_ocache_load_line(addr); nkeynes@971: } nkeynes@971: return *(int32_t *)&ccn_ocache_data[addr & 0x3FFF]; nkeynes@971: } nkeynes@971: nkeynes@971: static int32_t FASTCALL ccn_ocache_read_word( sh4addr_t addr ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) { nkeynes@971: ccn_ocache_load_line(addr); nkeynes@971: } nkeynes@971: return SIGNEXT16(*(int16_t *)&ccn_ocache_data[addr&0x3FFF]); nkeynes@971: } nkeynes@971: nkeynes@971: static int32_t FASTCALL ccn_ocache_read_byte( sh4addr_t addr ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) { nkeynes@971: ccn_ocache_load_line(addr); nkeynes@971: } nkeynes@971: return SIGNEXT8(ccn_ocache_data[addr&0x3FFF]); nkeynes@971: } nkeynes@971: nkeynes@971: static void FASTCALL ccn_ocache_write_long_copyback( sh4addr_t addr, uint32_t value ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) { nkeynes@971: ccn_ocache_load_line(addr); nkeynes@971: } nkeynes@971: ccn_cache_map[addr>>5] |= CACHE_DIRTY; nkeynes@971: *(uint32_t *)&ccn_ocache_data[addr&0x3FFF] = value; nkeynes@971: } nkeynes@971: nkeynes@971: static void FASTCALL ccn_ocache_write_word_copyback( sh4addr_t addr, uint32_t value ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) { nkeynes@971: ccn_ocache_load_line(addr); nkeynes@971: } nkeynes@971: ccn_cache_map[addr>>5] |= CACHE_DIRTY; nkeynes@971: *(uint16_t *)&ccn_ocache_data[addr&0x3FFF] = (uint16_t)value; nkeynes@971: } nkeynes@971: nkeynes@971: static void FASTCALL ccn_ocache_write_byte_copyback( sh4addr_t addr, uint32_t value ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) { nkeynes@971: ccn_ocache_load_line(addr); nkeynes@971: } nkeynes@971: ccn_cache_map[addr>>5] |= CACHE_DIRTY; nkeynes@971: ccn_ocache_data[addr&0x3FFF] = (uint8_t)value; nkeynes@971: } nkeynes@971: nkeynes@971: static void FASTCALL ccn_ocache_prefetch( sh4addr_t addr ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: if( (ccn_cache_map[addr>>5] & CACHE_VALID) == 0 ) { nkeynes@971: ccn_ocache_load_line(addr); nkeynes@971: } nkeynes@971: } nkeynes@971: nkeynes@971: void FASTCALL ccn_ocache_invalidate( sh4addr_t addr ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: ccn_cache_map[addr>>5] &= ~CACHE_VALID; nkeynes@971: } nkeynes@971: nkeynes@971: void FASTCALL ccn_ocache_purge( sh4addr_t addr ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFE0; nkeynes@971: int oldflags = ccn_cache_map[addr>>5]; nkeynes@971: ccn_cache_map[addr>>5] &= ~CACHE_VALID; nkeynes@971: if( oldflags == (CACHE_VALID|CACHE_DIRTY) ) { nkeynes@980: unsigned char *cache_data = &ccn_ocache_data[addr & 0x3FE0]; nkeynes@971: ext_address_space[addr>>12]->write_burst(addr, cache_data); nkeynes@971: } nkeynes@971: } nkeynes@971: nkeynes@971: void FASTCALL ccn_ocache_writeback( sh4addr_t addr ) nkeynes@971: { nkeynes@971: addr &= 0x1FFFFFE0; nkeynes@971: if( ccn_cache_map[addr>>5] == (CACHE_VALID|CACHE_DIRTY) ) { nkeynes@971: ccn_cache_map[addr>>5] &= ~CACHE_DIRTY; nkeynes@980: unsigned char *cache_data = &ccn_ocache_data[addr & 0x3FE0]; nkeynes@971: ext_address_space[addr>>12]->write_burst(addr, cache_data); nkeynes@971: } nkeynes@971: } nkeynes@971: nkeynes@971: struct mem_region_fn ccn_ocache_cb_region = { nkeynes@971: ccn_ocache_read_long, ccn_ocache_write_long_copyback, nkeynes@971: ccn_ocache_read_word, ccn_ocache_write_word_copyback, nkeynes@971: ccn_ocache_read_byte, ccn_ocache_write_byte_copyback, nkeynes@971: unmapped_read_burst, unmapped_write_burst, nkeynes@975: ccn_ocache_prefetch, ccn_ocache_read_byte }; nkeynes@971: nkeynes@971: nkeynes@953: /************************** Cache direct access ******************************/ nkeynes@953: nkeynes@968: static int32_t FASTCALL ccn_icache_addr_read( sh4addr_t addr ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00001FE0); nkeynes@953: return ccn_icache[entry>>5].tag; nkeynes@953: } nkeynes@953: nkeynes@968: static void FASTCALL ccn_icache_addr_write( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00003FE0); nkeynes@953: struct cache_line *line = &ccn_ocache[entry>>5]; nkeynes@953: if( addr & 0x08 ) { // Associative nkeynes@953: /* FIXME: implement this - requires ITLB lookups, with exception in case of multi-hit */ nkeynes@953: } else { nkeynes@953: line->tag = val & 0x1FFFFC01; nkeynes@953: line->key = (val & 0x1FFFFC00)|(entry & 0x000003E0); nkeynes@953: } nkeynes@953: } nkeynes@953: nkeynes@953: struct mem_region_fn p4_region_icache_addr = { nkeynes@953: ccn_icache_addr_read, ccn_icache_addr_write, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_burst, unmapped_write_burst, nkeynes@975: unmapped_prefetch, unmapped_read_long }; nkeynes@953: nkeynes@953: nkeynes@968: static int32_t FASTCALL ccn_icache_data_read( sh4addr_t addr ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00001FFC); nkeynes@953: return *(uint32_t *)&ccn_icache_data[entry]; nkeynes@953: } nkeynes@953: nkeynes@968: static void FASTCALL ccn_icache_data_write( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00001FFC); nkeynes@953: *(uint32_t *)&ccn_icache_data[entry] = val; nkeynes@953: } nkeynes@953: nkeynes@953: struct mem_region_fn p4_region_icache_data = { nkeynes@953: ccn_icache_data_read, ccn_icache_data_write, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_burst, unmapped_write_burst, nkeynes@975: unmapped_prefetch, unmapped_read_long }; nkeynes@953: nkeynes@968: static int32_t FASTCALL ccn_ocache_addr_read( sh4addr_t addr ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00003FE0); nkeynes@971: sh4addr_t tag = ccn_ocache[entry>>5].tag; nkeynes@971: return (tag&0x1FFFFC00) | ccn_cache_map[tag>>5]; nkeynes@953: } nkeynes@953: nkeynes@968: static void FASTCALL ccn_ocache_addr_write( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00003FE0); nkeynes@953: struct cache_line *line = &ccn_ocache[entry>>5]; nkeynes@953: if( addr & 0x08 ) { // Associative nkeynes@953: } else { nkeynes@971: sh4addr_t tag = line->tag; nkeynes@971: if( ccn_cache_map[tag>>5] == (CACHE_VALID|CACHE_DIRTY) ) { nkeynes@953: // Cache line is dirty - writeback. nkeynes@971: unsigned char *cache_data = &ccn_ocache_data[entry]; nkeynes@971: ext_address_space[tag>>12]->write_burst(tag, cache_data); nkeynes@953: } nkeynes@971: line->tag = tag = (val & 0x1FFFFC00) | (addr & 0x3E0); nkeynes@971: ccn_cache_map[tag>>5] = val & 0x03; nkeynes@953: } nkeynes@953: } nkeynes@953: nkeynes@953: struct mem_region_fn p4_region_ocache_addr = { nkeynes@953: ccn_ocache_addr_read, ccn_ocache_addr_write, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_burst, unmapped_write_burst, nkeynes@975: unmapped_prefetch, unmapped_read_long }; nkeynes@953: nkeynes@953: nkeynes@968: static int32_t FASTCALL ccn_ocache_data_read( sh4addr_t addr ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00003FFC); nkeynes@953: return *(uint32_t *)&ccn_ocache_data[entry]; nkeynes@953: } nkeynes@953: nkeynes@968: static void FASTCALL ccn_ocache_data_write( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: int entry = (addr & 0x00003FFC); nkeynes@953: *(uint32_t *)&ccn_ocache_data[entry] = val; nkeynes@953: } nkeynes@953: nkeynes@953: struct mem_region_fn p4_region_ocache_data = { nkeynes@953: ccn_ocache_data_read, ccn_ocache_data_write, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_long, unmapped_write_long, nkeynes@953: unmapped_read_burst, unmapped_write_burst, nkeynes@975: unmapped_prefetch, unmapped_read_long }; nkeynes@953: nkeynes@953: nkeynes@953: /****************** Cache control *********************/ nkeynes@953: nkeynes@953: void CCN_set_cache_control( int reg ) nkeynes@953: { nkeynes@953: uint32_t i; nkeynes@953: nkeynes@953: if( reg & CCR_ICI ) { /* icache invalidate */ nkeynes@953: for( i=0; i>12]->read_long(addr); nkeynes@971: } nkeynes@971: int32_t FASTCALL ccn_uncached_read_word( sh4addr_t addr ) nkeynes@971: { nkeynes@971: sh4r.slice_cycle += (4*sh4_bus_period); nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: return ext_address_space[addr>>12]->read_word(addr); nkeynes@971: } nkeynes@971: int32_t FASTCALL ccn_uncached_read_byte( sh4addr_t addr ) nkeynes@971: { nkeynes@971: sh4r.slice_cycle += (4*sh4_bus_period); nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: return ext_address_space[addr>>12]->read_byte(addr); nkeynes@971: } nkeynes@971: void FASTCALL ccn_uncached_write_long( sh4addr_t addr, uint32_t val ) nkeynes@971: { nkeynes@971: sh4r.slice_cycle += (4*sh4_bus_period); nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: return ext_address_space[addr>>12]->write_long(addr, val); nkeynes@971: } nkeynes@971: void FASTCALL ccn_uncached_write_word( sh4addr_t addr, uint32_t val ) nkeynes@971: { nkeynes@971: sh4r.slice_cycle += (4*sh4_bus_period); nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: return ext_address_space[addr>>12]->write_word(addr, val); nkeynes@971: } nkeynes@971: void FASTCALL ccn_uncached_write_byte( sh4addr_t addr, uint32_t val ) nkeynes@971: { nkeynes@971: sh4r.slice_cycle += (4*sh4_bus_period); nkeynes@971: addr &= 0x1FFFFFFF; nkeynes@971: return ext_address_space[addr>>12]->write_byte(addr, val); nkeynes@971: } nkeynes@953: void FASTCALL ccn_uncached_prefetch( sh4addr_t addr ) nkeynes@953: { nkeynes@953: } nkeynes@971: nkeynes@971: struct mem_region_fn ccn_uncached_region = { nkeynes@971: ccn_uncached_read_long, ccn_uncached_write_long, nkeynes@971: ccn_uncached_read_word, ccn_uncached_write_word, nkeynes@971: ccn_uncached_read_byte, ccn_uncached_write_byte, nkeynes@971: unmapped_read_burst, unmapped_write_burst, nkeynes@975: ccn_uncached_prefetch, ccn_uncached_read_byte }; nkeynes@971: nkeynes@971: nkeynes@953: /********************************* Store-queue *******************************/ nkeynes@953: /* nkeynes@953: * The storequeue is strictly speaking part of the cache, but most of nkeynes@953: * the complexity is actually around its addressing (ie in the MMU). The nkeynes@953: * methods here can assume we've already passed SQMD protection and the TLB nkeynes@953: * lookups (where appropriate). nkeynes@953: */ nkeynes@953: void FASTCALL ccn_storequeue_write_long( sh4addr_t addr, uint32_t val ) nkeynes@953: { nkeynes@953: sh4r.store_queue[(addr>>2)&0xF] = val; nkeynes@953: } nkeynes@953: int32_t FASTCALL ccn_storequeue_read_long( sh4addr_t addr ) nkeynes@953: { nkeynes@953: return sh4r.store_queue[(addr>>2)&0xF]; nkeynes@953: } nkeynes@953: nkeynes@953: /** nkeynes@953: * Variant used when tlb is disabled - address will be the original prefetch nkeynes@953: * address (ie 0xE0001234). Due to the way the SQ addressing is done, it can't nkeynes@953: * be hardcoded on 4K page boundaries, so we manually decode it here. nkeynes@953: */ nkeynes@953: void FASTCALL ccn_storequeue_prefetch( sh4addr_t addr ) nkeynes@953: { nkeynes@953: int queue = (addr&0x20)>>2; nkeynes@953: sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue]; nkeynes@953: uint32_t hi = MMIO_READ( MMU, QACR0 + (queue>>1)) << 24; nkeynes@953: sh4addr_t target = (addr&0x03FFFFE0) | hi; nkeynes@953: ext_address_space[target>>12]->write_burst( target, src ); nkeynes@953: } nkeynes@953: nkeynes@953: /** nkeynes@953: * Variant used when tlb is enabled - address in this case is already nkeynes@953: * mapped to the external target address. nkeynes@953: */ nkeynes@953: void FASTCALL ccn_storequeue_prefetch_tlb( sh4addr_t addr ) nkeynes@953: { nkeynes@953: int queue = (addr&0x20)>>2; nkeynes@953: sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue]; nkeynes@953: ext_address_space[addr>>12]->write_burst( (addr & 0x1FFFFFE0), src ); nkeynes@953: } nkeynes@971: