diff options
author | bunnei <ericbunnie@gmail.com> | 2014-05-16 05:39:06 +0200 |
---|---|---|
committer | bunnei <ericbunnie@gmail.com> | 2014-05-16 05:39:06 +0200 |
commit | 9a642caee770db2632f4daa842b10801b47ffbfc (patch) | |
tree | 5a1c63014d08d7200bc69c96549c49ba75553f2d /src/core | |
parent | fixed armmmu imports (diff) | |
download | yuzu-9a642caee770db2632f4daa842b10801b47ffbfc.tar yuzu-9a642caee770db2632f4daa842b10801b47ffbfc.tar.gz yuzu-9a642caee770db2632f4daa842b10801b47ffbfc.tar.bz2 yuzu-9a642caee770db2632f4daa842b10801b47ffbfc.tar.lz yuzu-9a642caee770db2632f4daa842b10801b47ffbfc.tar.xz yuzu-9a642caee770db2632f4daa842b10801b47ffbfc.tar.zst yuzu-9a642caee770db2632f4daa842b10801b47ffbfc.zip |
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/core/arm/interpreter/armmmu.h | 18 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/cache.cpp | 370 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/rb.cpp | 126 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/sa_mmu.cpp | 864 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/sa_mmu.h | 58 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/tlb.cpp | 307 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/tlb.h | 9 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/wb.cpp | 149 | ||||
-rw-r--r-- | src/core/arm/interpreter/mmu/xscale_copro.cpp | 1388 | ||||
-rw-r--r-- | src/core/core.vcxproj | 19 | ||||
-rw-r--r-- | src/core/core.vcxproj.filters | 63 |
12 files changed, 3333 insertions, 44 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 0d4a0ca7a..35ef1c7b3 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -19,6 +19,12 @@ set(SRCS core.cpp arm/interpreter/vfp/vfpinsr.cpp arm/interpreter/vfp/vfpsingle.cpp arm/interpreter/mmu/arm1176jzf_s_mmu.cpp + arm/interpreter/mmu/cache.cpp + arm/interpreter/mmu/sa_mmu.cpp + arm/interpreter/mmu/rb.cpp + arm/interpreter/mmu/tlb.cpp + arm/interpreter/mmu/wb.cpp + arm/interpreter/mmu/xscale_copro.cpp elf/elf_reader.cpp file_sys/directory_file_system.cpp file_sys/meta_file_system.cpp diff --git a/src/core/arm/interpreter/armmmu.h b/src/core/arm/interpreter/armmmu.h index 2ceaa7c64..818108c9c 100644 --- a/src/core/arm/interpreter/armmmu.h +++ b/src/core/arm/interpreter/armmmu.h @@ -178,12 +178,12 @@ typedef struct mmu_ops_s #include "core/arm/interpreter/mmu/cache.h" /*special process mmu.h*/ -//#include "core/arm/mmu/sa_mmu.h" -//#include "core/arm/mmu/arm7100_mmu.h" -//#include "core/arm/mmu/arm920t_mmu.h" -//#include "core/arm/mmu/arm926ejs_mmu.h" +#include "core/arm/interpreter/mmu/sa_mmu.h" +//#include "core/arm/interpreter/mmu/arm7100_mmu.h" +//#include "core/arm/interpreter/mmu/arm920t_mmu.h" +//#include "core/arm/interpreter/mmu/arm926ejs_mmu.h" #include "core/arm/interpreter/mmu/arm1176jzf_s_mmu.h" -//#include "core/arm/mmu/cortex_a9_mmu.h" +//#include "core/arm/interpreter/mmu/cortex_a9_mmu.h" typedef struct mmu_state_t { @@ -213,13 +213,13 @@ typedef struct mmu_state_t ARMword copro_access; // 15 mmu_ops_t ops; - //union - //{ - //sa_mmu_t sa_mmu; + union + { + sa_mmu_t sa_mmu; //arm7100_mmu_t arm7100_mmu; //arm920t_mmu_t arm920t_mmu; //arm926ejs_mmu_t arm926ejs_mmu; - //} u; + } u; } mmu_state_t; int mmu_init (ARMul_State * state); diff --git a/src/core/arm/interpreter/mmu/cache.cpp b/src/core/arm/interpreter/mmu/cache.cpp new file mode 100644 index 000000000..f3c4e0531 --- /dev/null +++ b/src/core/arm/interpreter/mmu/cache.cpp @@ -0,0 +1,370 @@ +#include "core/arm/interpreter/armdefs.h" + +/* mmu cache init + * + * @cache_t :cache_t to init + * @width :cache line width in byte + * @way :way of each cache set + * @set :cache set num + * + * $ -1: error + * 0: sucess + */ +int +mmu_cache_init (cache_s * cache_t, int width, int way, int set, int w_mode) +{ + int i, j; + cache_set_t *sets; + cache_line_t *lines; + + /*alloc cache set */ + sets = NULL; + lines = NULL; + //fprintf(stderr, "mmu_cache_init: mallloc beg size %d,sets 0x%x\n", sizeof(cache_set_t) * set,sets); + //exit(-1); + sets = (cache_set_t *) malloc (sizeof (cache_set_t) * set); + if (sets == NULL) { + ERROR_LOG(ARM11, "set malloc size %d\n", sizeof (cache_set_t) * set); + goto sets_error; + } + //fprintf(stderr, "mmu_cache_init: mallloc end sets 0x%x\n", sets); + cache_t->sets = sets; + + /*init cache set */ + for (i = 0; i < set; i++) { + /*alloc cache line */ + lines = (cache_line_t *) malloc (sizeof (cache_line_t) * way); + if (lines == NULL) { + ERROR_LOG(ARM11, "line malloc size %d\n", + sizeof (cache_line_t) * way); + goto lines_error; + } + /*init cache line */ + for (j = 0; j < way; j++) { + lines[j].tag = 0; //invalid + lines[j].data = (ARMword *) malloc (width); + if (lines[j].data == NULL) { + ERROR_LOG(ARM11, "data alloc size %d\n", width); + goto data_error; + } + } + + sets[i].lines = lines; + sets[i].cycle = 0; + + } + cache_t->width = width; + cache_t->set = set; + cache_t->way = way; + cache_t->w_mode = w_mode; + return 0; + + data_error: + /*free data */ + while (j-- > 0) + free (lines[j].data); + /*free data error line */ + free (lines); + lines_error: + /*free lines already alloced */ + while (i-- > 0) { + for (j = 0; j < way; j++) + free (sets[i].lines[j].data); + free (sets[i].lines); + } + /*free sets */ + free (sets); + sets_error: + return -1; +}; + +/* free a cache_t's inner data, the ptr self is not freed, + * when needed do like below: + * mmu_cache_exit(cache); + * free(cache_t); + * + * @cache_t : the cache_t to free + */ + +void +mmu_cache_exit (cache_s * cache_t) +{ + int i, j; + cache_set_t *sets, *set; + cache_line_t *lines, *line; + + /*free all set */ + sets = cache_t->sets; + for (set = sets, i = 0; i < cache_t->set; i++, set++) { + /*free all line */ + lines = set->lines; + for (line = lines, j = 0; j < cache_t->way; j++, line++) + free (line->data); + free (lines); + } + free (sets); +} + +/* mmu cache search + * + * @state :ARMul_State + * @cache_t :cache_t to search + * @va :virtual address + * + * $ NULL: no cache match + * cache :cache matched + */ +cache_line_t * +mmu_cache_search (ARMul_State * state, cache_s * cache_t, ARMword va) +{ + int i; + int set = va_cache_set (va, cache_t); + ARMword tag = va_cache_align (va, cache_t); + cache_line_t *cache; + + cache_set_t *cache_set = cache_t->sets + set; + for (i = 0, cache = cache_set->lines; i < cache_t->way; i++, cache++) { + if ((cache->tag & TAG_VALID_FLAG) + && (tag == va_cache_align (cache->tag, cache_t))) + return cache; + } + return NULL; +} + +/* mmu cache search by set/index + * + * @state :ARMul_State + * @cache_t :cache_t to search + * @index :set/index value. + * + * $ NULL: no cache match + * cache :cache matched + */ +cache_line_t * +mmu_cache_search_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index) +{ + int way = cache_t->way; + int set_v = index_cache_set (index, cache_t); + int i = 0, index_v = 0; + cache_set_t *set; + + while ((way >>= 1) >= 1) + i++; + index_v = index >> (32 - i); + set = cache_t->sets + set_v; + + return set->lines + index_v; +} + + +/* mmu cache alloc + * + * @state :ARMul_State + * @cache_t :cache_t to alloc from + * @va :virtual address that require cache alloc, need not cache aligned + * @pa :physical address of va + * + * $ cache_alloced, always alloc OK + */ +cache_line_t * +mmu_cache_alloc (ARMul_State * state, cache_s * cache_t, ARMword va, + ARMword pa) +{ + cache_line_t *cache; + cache_set_t *set; + int i; + + va = va_cache_align (va, cache_t); + pa = va_cache_align (pa, cache_t); + + set = &cache_t->sets[va_cache_set (va, cache_t)]; + + /*robin-round */ + cache = &set->lines[set->cycle++]; + if (set->cycle == cache_t->way) + set->cycle = 0; + + if (cache_t->w_mode == CACHE_WRITE_BACK) { + ARMword t; + + /*if cache valid, try to write back */ + if (cache->tag & TAG_VALID_FLAG) { + mmu_cache_write_back (state, cache_t, cache); + } + /*read in cache_line */ + t = pa; + for (i = 0; i < (cache_t->width >> WORD_SHT); + i++, t += WORD_SIZE) { + //cache->data[i] = mem_read_word (state, t); + bus_read(32, t, &cache->data[i]); + } + } + /*store tag and pa */ + cache->tag = va | TAG_VALID_FLAG; + cache->pa = pa; + + return cache; +}; + +/* mmu_cache_write_back write cache data to memory + * @state + * @cache_t :cache_t of the cache line + * @cache : cache line + */ +void +mmu_cache_write_back (ARMul_State * state, cache_s * cache_t, + cache_line_t * cache) +{ + ARMword pa = cache->pa; + int nw = cache_t->width >> WORD_SHT; + ARMword *data = cache->data; + int i; + int t0, t1, t2; + + if ((cache->tag & 1) == 0) + return; + + switch (cache-> + tag & ~1 & (TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY)) { + case 0: + return; + case TAG_FIRST_HALF_DIRTY: + nw /= 2; + break; + case TAG_LAST_HALF_DIRTY: + nw /= 2; + pa += nw << WORD_SHT; + data += nw; + break; + case TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY: + break; + } + for (i = 0; i < nw; i++, data++, pa += WORD_SIZE) + //mem_write_word (state, pa, *data); + bus_write(32, pa, *data); + + cache->tag &= ~(TAG_FIRST_HALF_DIRTY | TAG_LAST_HALF_DIRTY); +}; + + +/* mmu_cache_clean: clean a cache of va in cache_t + * + * @state :ARMul_State + * @cache_t :cache_t to clean + * @va :virtaul address + */ +void +mmu_cache_clean (ARMul_State * state, cache_s * cache_t, ARMword va) +{ + cache_line_t *cache; + + cache = mmu_cache_search (state, cache_t, va); + if (cache) + mmu_cache_write_back (state, cache_t, cache); +} + +/* mmu_cache_clean_by_index: clean a cache by set/index format value + * + * @state :ARMul_State + * @cache_t :cache_t to clean + * @va :set/index format value + */ +void +mmu_cache_clean_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index) +{ + cache_line_t *cache; + + cache = mmu_cache_search_by_index (state, cache_t, index); + if (cache) + mmu_cache_write_back (state, cache_t, cache); +} + +/* mmu_cache_invalidate : invalidate a cache of va + * + * @state :ARMul_State + * @cache_t :cache_t to invalid + * @va :virt_addr to invalid + */ +void +mmu_cache_invalidate (ARMul_State * state, cache_s * cache_t, ARMword va) +{ + cache_line_t *cache; + + cache = mmu_cache_search (state, cache_t, va); + if (cache) { + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; + } +} + +/* mmu_cache_invalidate_by_index : invalidate a cache by index format + * + * @state :ARMul_State + * @cache_t :cache_t to invalid + * @index :set/index data + */ +void +mmu_cache_invalidate_by_index (ARMul_State * state, cache_s * cache_t, + ARMword index) +{ + cache_line_t *cache; + + cache = mmu_cache_search_by_index (state, cache_t, index); + if (cache) { + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; + } +} + +/* mmu_cache_invalidate_all + * + * @state: + * @cache_t + * */ +void +mmu_cache_invalidate_all (ARMul_State * state, cache_s * cache_t) +{ + int i, j; + cache_set_t *set; + cache_line_t *cache; + + set = cache_t->sets; + for (i = 0; i < cache_t->set; i++, set++) { + cache = set->lines; + for (j = 0; j < cache_t->way; j++, cache++) { + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; + } + } +}; + +void +mmu_cache_soft_flush (ARMul_State * state, cache_s * cache_t, ARMword pa) +{ + ARMword set, way; + cache_line_t *cache; + pa = (pa / cache_t->width); + way = pa & (cache_t->way - 1); + set = (pa / cache_t->way) & (cache_t->set - 1); + cache = &cache_t->sets[set].lines[way]; + + mmu_cache_write_back (state, cache_t, cache); + cache->tag = 0; +} + +cache_line_t* mmu_cache_dirty_cache(ARMul_State *state,cache_s *cache){ + int i; + int j; + cache_line_t *cache_line = NULL; + cache_set_t *cache_set = cache->sets; + int sets = cache->set; + for (i = 0; i < sets; i++){ + for(j = 0,cache_line = &cache_set[i].lines[0]; j < cache->way; j++,cache_line++){ + if((cache_line->tag & TAG_FIRST_HALF_DIRTY) || (cache_line->tag & TAG_LAST_HALF_DIRTY)) + return cache_line; + } + } + return NULL; +} diff --git a/src/core/arm/interpreter/mmu/rb.cpp b/src/core/arm/interpreter/mmu/rb.cpp new file mode 100644 index 000000000..07b11e311 --- /dev/null +++ b/src/core/arm/interpreter/mmu/rb.cpp @@ -0,0 +1,126 @@ +#include "core/arm/interpreter/armdefs.h" + +/*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu*/ +ARMword rb_masks[] = { + 0x0, //RB_INVALID + 4, //RB_1 + 16, //RB_4 + 32, //RB_8 +}; + +/*mmu_rb_init + * @rb_t :rb_t to init + * @num :number of entry + * */ +int +mmu_rb_init (rb_s * rb_t, int num) +{ + int i; + rb_entry_t *entrys; + + entrys = (rb_entry_t *) malloc (sizeof (*entrys) * num); + if (entrys == NULL) { + printf ("SKYEYE:mmu_rb_init malloc error\n"); + return -1; + } + for (i = 0; i < num; i++) { + entrys[i].type = RB_INVALID; + entrys[i].fault = NO_FAULT; + } + + rb_t->entrys = entrys; + rb_t->num = num; + return 0; +} + +/*mmu_rb_exit*/ +void +mmu_rb_exit (rb_s * rb_t) +{ + free (rb_t->entrys); +}; + +/*mmu_rb_search + * @rb_t :rb_t to serach + * @va :va address to math + * + * $ NULL :not match + * NO-NULL: + * */ +rb_entry_t * +mmu_rb_search (rb_s * rb_t, ARMword va) +{ + int i; + rb_entry_t *rb = rb_t->entrys; + + DEBUG_LOG(ARM11, "va = %x\n", va); + for (i = 0; i < rb_t->num; i++, rb++) { + //2004-06-06 lyh bug from wenye@cs.ucsb.edu + if (rb->type) { + if ((va >= rb->va) + && (va < (rb->va + rb_masks[rb->type]))) + return rb; + } + } + return NULL; +}; + +void +mmu_rb_invalidate_entry (rb_s * rb_t, int i) +{ + rb_t->entrys[i].type = RB_INVALID; +} + +void +mmu_rb_invalidate_all (rb_s * rb_t) +{ + int i; + + for (i = 0; i < rb_t->num; i++) + mmu_rb_invalidate_entry (rb_t, i); +}; + +void +mmu_rb_load (ARMul_State * state, rb_s * rb_t, int i_rb, int type, ARMword va) +{ + rb_entry_t *rb; + int i; + ARMword max_start, min_end; + fault_t fault; + tlb_entry_t *tlb; + + /*align va according to type */ + va &= ~(rb_masks[type] - 1); + /*invalidate all RB match [va, va + rb_masks[type]] */ + for (rb = rb_t->entrys, i = 0; i < rb_t->num; i++, rb++) { + if (rb->type) { + max_start = max (va, rb->va); + min_end = + min (va + rb_masks[type], + rb->va + rb_masks[rb->type]); + if (max_start < min_end) + rb->type = RB_INVALID; + } + } + /*load word */ + rb = &rb_t->entrys[i_rb]; + rb->type = type; + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + rb->fault = fault; + return; + } + fault = check_access (state, va, tlb, 1); + if (fault) { + rb->fault = fault; + return; + } + + rb->fault = NO_FAULT; + va = tlb_va_to_pa (tlb, va); + //2004-06-06 lyh bug from wenye@cs.ucsb.edu + for (i = 0; i < (rb_masks[type] / 4); i++, va += WORD_SIZE) { + //rb->data[i] = mem_read_word (state, va); + bus_read(32, va, &rb->data[i]); + }; +} diff --git a/src/core/arm/interpreter/mmu/sa_mmu.cpp b/src/core/arm/interpreter/mmu/sa_mmu.cpp new file mode 100644 index 000000000..eff5002de --- /dev/null +++ b/src/core/arm/interpreter/mmu/sa_mmu.cpp @@ -0,0 +1,864 @@ +/* + armmmu.c - Memory Management Unit emulation. + ARMulator extensions for the ARM7100 family. + Copyright (C) 1999 Ben Williamson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <assert.h> +#include <string.h> + +#include "core/arm/interpreter/armdefs.h" + +/** + * The interface of read data from bus + */ +int bus_read(short size, int addr, uint32_t * value) { + ERROR_LOG(ARM11, "unimplemented bus_read"); + return 0; +} + +/** + * The interface of write data from bus + */ +int bus_write(short size, int addr, uint32_t value) { + ERROR_LOG(ARM11, "unimplemented bus_write"); + return 0; +} + + +typedef struct sa_mmu_desc_s +{ + int i_tlb; + cache_desc_t i_cache; + + int d_tlb; + cache_desc_t main_d_cache; + cache_desc_t mini_d_cache; + int rb; + wb_desc_t wb; +} sa_mmu_desc_t; + +static sa_mmu_desc_t sa11xx_mmu_desc = { + 32, + {32, 32, 16, CACHE_WRITE_BACK}, + + 32, + {32, 32, 8, CACHE_WRITE_BACK}, + {32, 2, 8, CACHE_WRITE_BACK}, + 4, + //{8, 4}, for word size + {8, 16}, //for byte size, chy 2003-07-11 +}; + +static fault_t sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, + ARMword datatype); +static fault_t sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, + ARMword datatype); +static fault_t update_cache (ARMul_State * state, ARMword va, ARMword data, + ARMword datatype, cache_line_t * cache, + cache_s * cache_t, ARMword real_va); + +void +mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, + ARMbyte * data, int n); +int +sa_mmu_init (ARMul_State * state) +{ + sa_mmu_desc_t *desc; + cache_desc_t *c_desc; + + state->mmu.control = 0x70; + state->mmu.translation_table_base = 0xDEADC0DE; + state->mmu.domain_access_control = 0xDEADC0DE; + state->mmu.fault_status = 0; + state->mmu.fault_address = 0; + state->mmu.process_id = 0; + + desc = &sa11xx_mmu_desc; + if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { + ERROR_LOG(ARM11, "i_tlb init %d\n", -1); + goto i_tlb_init_error; + } + + c_desc = &desc->i_cache; + if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "i_cache init %d\n", -1); + goto i_cache_init_error; + } + + if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { + ERROR_LOG(ARM11, "d_tlb init %d\n", -1); + goto d_tlb_init_error; + } + + c_desc = &desc->main_d_cache; + if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); + goto main_d_cache_init_error; + } + + c_desc = &desc->mini_d_cache; + if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); + goto mini_d_cache_init_error; + } + + if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { + ERROR_LOG(ARM11, "wb init %d\n", -1); + goto wb_init_error; + } + + if (mmu_rb_init (RB (), desc->rb)) { + ERROR_LOG(ARM11, "rb init %d\n", -1); + goto rb_init_error; + } + return 0; + + rb_init_error: + mmu_wb_exit (WB ()); + wb_init_error: + mmu_cache_exit (MINI_D_CACHE ()); + mini_d_cache_init_error: + mmu_cache_exit (MAIN_D_CACHE ()); + main_d_cache_init_error: + mmu_tlb_exit (D_TLB ()); + d_tlb_init_error: + mmu_cache_exit (I_CACHE ()); + i_cache_init_error: + mmu_tlb_exit (I_TLB ()); + i_tlb_init_error: + return -1; +} + +void +sa_mmu_exit (ARMul_State * state) +{ + mmu_rb_exit (RB ()); + mmu_wb_exit (WB ()); + mmu_cache_exit (MINI_D_CACHE ()); + mmu_cache_exit (MAIN_D_CACHE ()); + mmu_tlb_exit (D_TLB ()); + mmu_cache_exit (I_CACHE ()); + mmu_tlb_exit (I_TLB ()); +}; + + +static fault_t +sa_mmu_load_instr (ARMul_State * state, ARMword va, ARMword * instr) +{ + fault_t fault; + tlb_entry_t *tlb; + cache_line_t *cache; + int c; //cache bit + ARMword pa; //physical addr + + static int debug_count = 0; //used for debug + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + if (MMU_Enabled) { + /*align check */ + if ((va & (WORD_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + va &= ~(WORD_SIZE - 1); + + /*translate tlb */ + fault = translate (state, va, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, va, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + + /*search cache no matter MMU enabled/disabled */ + cache = mmu_cache_search (state, I_CACHE (), va); + if (cache) { + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + return NO_FAULT; + } + + /*if MMU disabled or C flag is set alloc cache */ + if (MMU_Disabled) { + c = 1; + pa = va; + } + else { + c = tlb_c_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + } + + if (c) { + int index; + + debug_count++; + cache = mmu_cache_alloc (state, I_CACHE (), va, pa); + index = va_cache_index (va, I_CACHE ()); + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + } + else + //*instr = mem_read_word (state, pa); + bus_read(32, pa, instr); + + return NO_FAULT; +}; + + + +static fault_t +sa_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = sa_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); + return fault; +} + +static fault_t +sa_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = sa_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); + return fault; +} + +static fault_t +sa_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data) +{ + return sa_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); +} + + + + +static fault_t +sa_mmu_read (ARMul_State * state, ARMword va, ARMword * data, + ARMword datatype) +{ + fault_t fault; + rb_entry_t *rb; + tlb_entry_t *tlb; + cache_line_t *cache; + ARMword pa, real_va, temp, offset; + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + real_va = va; + /*if MMU disabled, memory_read */ + if (MMU_Disabled) { + //*data = mem_read_word(state, va); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, va); + bus_read(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, va); + bus_read(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, va); + bus_read(32, va, data); + else { + printf ("SKYEYE:1 sa_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + + /*align check */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } // else + + va &= ~(WORD_SIZE - 1); + + /*translate va to tlb */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*check access permission */ + fault = check_access (state, va, tlb, 1); + if (fault) + return fault; + /*search in read buffer */ + rb = mmu_rb_search (RB (), va); + if (rb) { + if (rb->fault) + return rb->fault; + *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; + goto datatrans; + //return 0; + }; + /*search main cache */ + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; + goto datatrans; + //return 0; + } + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; + goto datatrans; + //return 0; + } + + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, va); + if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { + if (tlb_c_flag (tlb)) { + if (tlb_b_flag (tlb)) { + mmu_cache_soft_flush (state, MAIN_D_CACHE (), + pa); + } + else { + mmu_cache_soft_flush (state, MINI_D_CACHE (), + pa); + } + } + return NO_FAULT; + } + + /*if Buffer, drain Write Buffer first */ + if (tlb_b_flag (tlb)) + mmu_wb_drain_all (state, WB ()); + + /*alloc cache or mem_read */ + if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { + cache_s *cache_t; + + if (tlb_b_flag (tlb)) + cache_t = MAIN_D_CACHE (); + else + cache_t = MINI_D_CACHE (); + cache = mmu_cache_alloc (state, cache_t, va, pa); + *data = cache->data[va_cache_index (va, cache_t)]; + } + else { + //*data = mem_read_word(state, pa); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, pa | (real_va & 3)); + bus_read(8, pa | (real_va & 3), data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, pa | (real_va & 2)); + bus_read(16, pa | (real_va & 2), data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, pa); + bus_read(32, pa, data); + else { + printf ("SKYEYE:2 sa_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + return NO_FAULT; + } + + + datatrans: + if (datatype == ARM_HALFWORD_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + *data = (temp >> offset) & 0xffff; + } + else if (datatype == ARM_BYTE_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + *data = (temp >> offset & 0xffL); + } + end: + return NO_FAULT; +} + + +static fault_t +sa_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + return sa_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); +} + +static fault_t +sa_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + return sa_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); +} + +static fault_t +sa_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data) +{ + return sa_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); +} + + + +static fault_t +sa_mmu_write (ARMul_State * state, ARMword va, ARMword data, ARMword datatype) +{ + tlb_entry_t *tlb; + cache_line_t *cache; + int b; + ARMword pa, real_va; + fault_t fault; + + DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); + va = mmu_pid_va_map (va); + real_va = va; + + /*search instruction cache */ + cache = mmu_cache_search (state, I_CACHE (), va); + if (cache) { + update_cache (state, va, data, datatype, cache, I_CACHE (), + real_va); + } + + if (MMU_Disabled) { + //mem_write_word(state, va, data); + if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, va, data); + bus_write(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, va, data); + bus_write(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, va, data); + bus_write(32, va, data); + else { + printf ("SKYEYE:1 sa_mmu_write error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + /*align check */ + //if ((va & (WORD_SIZE - 1)) && MMU_Aligned){ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } //else + va &= ~(WORD_SIZE - 1); + /*tlb translate */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*tlb check access */ + fault = check_access (state, va, tlb, 0); + if (fault) { + DEBUG_LOG(ARM11, "check_access\n"); + return fault; + } + /*search main cache */ + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + update_cache (state, va, data, datatype, cache, + MAIN_D_CACHE (), real_va); + } + else { + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + update_cache (state, va, data, datatype, cache, + MINI_D_CACHE (), real_va); + } + } + + if (!cache) { + b = tlb_b_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + if (b) { + if (MMU_WBEnabled) { + if (datatype == ARM_WORD_TYPE) + mmu_wb_write_bytes (state, WB (), pa, + (ARMbyte*)&data, 4); + else if (datatype == ARM_HALFWORD_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | + (real_va & 2)), + (ARMbyte*)&data, 2); + else if (datatype == ARM_BYTE_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | + (real_va & 3)), + (ARMbyte*)&data, 1); + + } + else { + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + /* + mem_write_halfword (state, + (pa | + (real_va & 2)), + data); + */ + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + /* + mem_write_byte (state, + (pa | (real_va & 3)), + data); + */ + bus_write(8, pa | (real_va & 3), data); + } + } + else { + mmu_wb_drain_all (state, WB ()); + + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + /* + mem_write_halfword (state, + (pa | (real_va & 2)), + data); + */ + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + /* + mem_write_byte (state, (pa | (real_va & 3)), + data); + */ + bus_write(8, pa | (real_va & 3), data); + } + } + return NO_FAULT; +} + +static fault_t +update_cache (ARMul_State * state, ARMword va, ARMword data, ARMword datatype, + cache_line_t * cache, cache_s * cache_t, ARMword real_va) +{ + ARMword temp, offset; + + ARMword index = va_cache_index (va, cache_t); + + //cache->data[index] = data; + + if (datatype == ARM_WORD_TYPE) + cache->data[index] = data; + else if (datatype == ARM_HALFWORD_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << + offset); + } + else if (datatype == ARM_BYTE_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffL << offset)) | ((data & 0xffL) << + offset); + } + + if (index < (cache_t->width >> (WORD_SHT + 1))) + cache->tag |= TAG_FIRST_HALF_DIRTY; + else + cache->tag |= TAG_LAST_HALF_DIRTY; + + return NO_FAULT; +} + +ARMword +sa_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) +{ + mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); + ARMword data; + + switch (creg) { + case MMU_ID: +// printf("mmu_mrc read ID "); + data = 0x41007100; /* v3 */ + data = state->cpu->cpu_val; + break; + case MMU_CONTROL: +// printf("mmu_mrc read CONTROL"); + data = state->mmu.control; + break; + case MMU_TRANSLATION_TABLE_BASE: +// printf("mmu_mrc read TTB "); + data = state->mmu.translation_table_base; + break; + case MMU_DOMAIN_ACCESS_CONTROL: +// printf("mmu_mrc read DACR "); + data = state->mmu.domain_access_control; + break; + case MMU_FAULT_STATUS: +// printf("mmu_mrc read FSR "); + data = state->mmu.fault_status; + break; + case MMU_FAULT_ADDRESS: +// printf("mmu_mrc read FAR "); + data = state->mmu.fault_address; + break; + case MMU_PID: + data = state->mmu.process_id; + default: + printf ("mmu_mrc read UNKNOWN - reg %d\n", creg); + data = 0; + break; + } +// printf("\t\t\t\t\tpc = 0x%08x\n", state->Reg[15]); + *value = data; + return data; +} + +void +sa_mmu_cache_ops (ARMul_State * state, ARMword instr, ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + if (OPC_2 == 0 && CRm == 7) { + mmu_cache_invalidate_all (state, I_CACHE ()); + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + mmu_cache_invalidate_all (state, MINI_D_CACHE ()); + return; + } + + if (OPC_2 == 0 && CRm == 5) { + mmu_cache_invalidate_all (state, I_CACHE ()); + return; + } + + if (OPC_2 == 0 && CRm == 6) { + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + mmu_cache_invalidate_all (state, MINI_D_CACHE ()); + return; + } + + if (OPC_2 == 1 && CRm == 6) { + mmu_cache_invalidate (state, MAIN_D_CACHE (), value); + mmu_cache_invalidate (state, MINI_D_CACHE (), value); + return; + } + + if (OPC_2 == 1 && CRm == 0xa) { + mmu_cache_clean (state, MAIN_D_CACHE (), value); + mmu_cache_clean (state, MINI_D_CACHE (), value); + return; + } + + if (OPC_2 == 4 && CRm == 0xa) { + mmu_wb_drain_all (state, WB ()); + return; + } + ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); +} + +static void +sa_mmu_tlb_ops (ARMul_State * state, ARMword instr, ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + + if (OPC_2 == 0 && CRm == 0x7) { + mmu_tlb_invalidate_all (state, I_TLB ()); + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 0 && CRm == 0x5) { + mmu_tlb_invalidate_all (state, I_TLB ()); + return; + } + + if (OPC_2 == 0 && CRm == 0x6) { + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 1 && CRm == 0x6) { + mmu_tlb_invalidate_entry (state, D_TLB (), value); + return; + } + + ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); +} + +static void +sa_mmu_rb_ops (ARMul_State * state, ARMword instr, ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + if (OPC_2 == 0x0 && CRm == 0x0) { + mmu_rb_invalidate_all (RB ()); + return; + } + + if (OPC_2 == 0x2) { + int idx = CRm & 0x3; + int type = ((CRm >> 2) & 0x3) + 1; + + if ((idx < 4) && (type < 4)) + mmu_rb_load (state, RB (), idx, type, value); + return; + } + + if ((OPC_2 == 1) && (CRm < 4)) { + mmu_rb_invalidate_entry (RB (), CRm); + return; + } + + ERROR_LOG(ARM11, "Unknow OPC_2 = %x CRm = %x\n", OPC_2, CRm); +} + +static ARMword +sa_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) +{ + mmu_regnum_t creg = (mmu_regnum_t)(BITS (16, 19) & 15); + if (!strncmp (state->cpu->cpu_arch_name, "armv4", 5)) { + switch (creg) { + case MMU_CONTROL: +// printf("mmu_mcr wrote CONTROL "); + state->mmu.control = (value | 0x70) & 0xFFFD; + break; + case MMU_TRANSLATION_TABLE_BASE: +// printf("mmu_mcr wrote TTB "); + state->mmu.translation_table_base = + value & 0xFFFFC000; + break; + case MMU_DOMAIN_ACCESS_CONTROL: +// printf("mmu_mcr wrote DACR "); + state->mmu.domain_access_control = value; + break; + + case MMU_FAULT_STATUS: + state->mmu.fault_status = value & 0xFF; + break; + case MMU_FAULT_ADDRESS: + state->mmu.fault_address = value; + break; + + case MMU_CACHE_OPS: + sa_mmu_cache_ops (state, instr, value); + break; + case MMU_TLB_OPS: + sa_mmu_tlb_ops (state, instr, value); + break; + case MMU_SA_RB_OPS: + sa_mmu_rb_ops (state, instr, value); + break; + case MMU_SA_DEBUG: + break; + case MMU_SA_CP15_R15: + break; + case MMU_PID: + //2004-06-06 lyh, bug provided by wen ye wenye@cs.ucsb.edu + state->mmu.process_id = value & 0x7e000000; + break; + + default: + printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); + break; + } + } + return 0; +} + +//teawater add for arm2x86 2005.06.24------------------------------------------- +static int +sa_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) +{ + fault_t fault; + tlb_entry_t *tlb; + + virt_addr = mmu_pid_va_map (virt_addr); + if (MMU_Enabled) { + + /*align check */ + if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + virt_addr &= ~(WORD_SIZE - 1); + + /*translate tlb */ + fault = translate (state, virt_addr, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, virt_addr, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + + if (MMU_Disabled) { + *phys_addr = virt_addr; + } + else { + *phys_addr = tlb_va_to_pa (tlb, virt_addr); + } + + return (0); +} + +//AJ2D-------------------------------------------------------------------------- + +/*sa mmu_ops_t*/ +mmu_ops_t sa_mmu_ops = { + sa_mmu_init, + sa_mmu_exit, + sa_mmu_read_byte, + sa_mmu_write_byte, + sa_mmu_read_halfword, + sa_mmu_write_halfword, + sa_mmu_read_word, + sa_mmu_write_word, + sa_mmu_load_instr, + sa_mmu_mcr, + sa_mmu_mrc, +//teawater add for arm2x86 2005.06.24------------------------------------------- + sa_mmu_v2p_dbct, +//AJ2D-------------------------------------------------------------------------- +}; diff --git a/src/core/arm/interpreter/mmu/sa_mmu.h b/src/core/arm/interpreter/mmu/sa_mmu.h new file mode 100644 index 000000000..64b1c5470 --- /dev/null +++ b/src/core/arm/interpreter/mmu/sa_mmu.h @@ -0,0 +1,58 @@ +/* + sa_mmu.h - StrongARM Memory Management Unit emulation. + ARMulator extensions for SkyEye. + <lyhost@263.net> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _SA_MMU_H_ +#define _SA_MMU_H_ + + +/** + * The interface of read data from bus + */ +int bus_read(short size, int addr, uint32_t * value); + +/** + * The interface of write data from bus + */ +int bus_write(short size, int addr, uint32_t value); + + +typedef struct sa_mmu_s +{ + tlb_s i_tlb; + cache_s i_cache; + + tlb_s d_tlb; + cache_s main_d_cache; + cache_s mini_d_cache; + rb_s rb_t; + wb_s wb_t; +} sa_mmu_t; + +#define I_TLB() (&state->mmu.u.sa_mmu.i_tlb) +#define I_CACHE() (&state->mmu.u.sa_mmu.i_cache) + +#define D_TLB() (&state->mmu.u.sa_mmu.d_tlb) +#define MAIN_D_CACHE() (&state->mmu.u.sa_mmu.main_d_cache) +#define MINI_D_CACHE() (&state->mmu.u.sa_mmu.mini_d_cache) +#define WB() (&state->mmu.u.sa_mmu.wb_t) +#define RB() (&state->mmu.u.sa_mmu.rb_t) + +extern mmu_ops_t sa_mmu_ops; +#endif /*_SA_MMU_H_*/ diff --git a/src/core/arm/interpreter/mmu/tlb.cpp b/src/core/arm/interpreter/mmu/tlb.cpp new file mode 100644 index 000000000..ca60ac1a1 --- /dev/null +++ b/src/core/arm/interpreter/mmu/tlb.cpp @@ -0,0 +1,307 @@ +#include <assert.h> + +#include "core/arm/interpreter/armdefs.h" + +ARMword tlb_masks[] = { + 0x00000000, /* TLB_INVALID */ + 0xFFFFF000, /* TLB_SMALLPAGE */ + 0xFFFF0000, /* TLB_LARGEPAGE */ + 0xFFF00000, /* TLB_SECTION */ + 0xFFFFF000, /*TLB_ESMALLPAGE, have TEX attirbute, only for XScale */ + 0xFFFFFC00 /* TLB_TINYPAGE */ +}; + +/* This function encodes table 8-2 Interpreting AP bits, + returning non-zero if access is allowed. */ +static int +check_perms (ARMul_State * state, int ap, int read) +{ + int s, r, user; + + s = state->mmu.control & CONTROL_SYSTEM; + r = state->mmu.control & CONTROL_ROM; + //chy 2006-02-15 , should consider system mode, don't conside 26bit mode + user = (state->Mode == USER32MODE) || (state->Mode == USER26MODE) || (state->Mode == SYSTEM32MODE); + + switch (ap) { + case 0: + return read && ((s && !user) || r); + case 1: + return !user; + case 2: + return read || !user; + case 3: + return 1; + } + return 0; +} + +fault_t +check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, + int read) +{ + int access; + + state->mmu.last_domain = tlb->domain; + access = (state->mmu.domain_access_control >> (tlb->domain * 2)) & 3; + if ((access == 0) || (access == 2)) { + /* It's unclear from the documentation whether this + should always raise a section domain fault, or if + it should be a page domain fault in the case of an + L1 that describes a page table. In the ARM710T + datasheets, "Figure 8-9: Sequence for checking faults" + seems to indicate the former, while "Table 8-4: Priority + encoding of fault status" gives a value for FS[3210] in + the event of a domain fault for a page. Hmm. */ + return SECTION_DOMAIN_FAULT; + } + if (access == 1) { + /* client access - check perms */ + int subpage, ap; + + switch (tlb->mapping) { + /*ks 2004-05-09 + * only for XScale + * Extend Small Page(ESP) Format + * 31-12 bits the base addr of ESP + * 11-10 bits SBZ + * 9-6 bits TEX + * 5-4 bits AP + * 3 bit C + * 2 bit B + * 1-0 bits 11 + * */ + case TLB_ESMALLPAGE: //xj + subpage = 0; + //printf("TLB_ESMALLPAGE virt_addr=0x%x \n",virt_addr ); + break; + + case TLB_TINYPAGE: + subpage = 0; + //printf("TLB_TINYPAGE virt_addr=0x%x \n",virt_addr ); + break; + + case TLB_SMALLPAGE: + subpage = (virt_addr >> 10) & 3; + break; + case TLB_LARGEPAGE: + subpage = (virt_addr >> 14) & 3; + break; + case TLB_SECTION: + subpage = 3; + break; + default: + assert (0); + subpage = 0; /* cleans a warning */ + } + ap = (tlb->perms >> (subpage * 2 + 4)) & 3; + if (!check_perms (state, ap, read)) { + if (tlb->mapping == TLB_SECTION) { + return SECTION_PERMISSION_FAULT; + } + else { + return SUBPAGE_PERMISSION_FAULT; + } + } + } + else { /* access == 3 */ + /* manager access - don't check perms */ + } + return NO_FAULT; +} + +fault_t +translate (ARMul_State * state, ARMword virt_addr, tlb_s * tlb_t, + tlb_entry_t ** tlb) +{ + *tlb = mmu_tlb_search (state, tlb_t, virt_addr); + if (!*tlb) { + /* walk the translation tables */ + ARMword l1addr, l1desc; + tlb_entry_t entry; + + l1addr = state->mmu.translation_table_base & 0xFFFFC000; + l1addr = (l1addr | (virt_addr >> 18)) & ~3; + //l1desc = mem_read_word (state, l1addr); + bus_read(32, l1addr, &l1desc); + switch (l1desc & 3) { + case 0: + /* + * according to Figure 3-9 Sequence for checking faults in arm manual, + * section translation fault should be returned here. + */ + { + return SECTION_TRANSLATION_FAULT; + } + case 3: + /* fine page table */ + // dcl 2006-01-08 + { + ARMword l2addr, l2desc; + + l2addr = l1desc & 0xFFFFF000; + l2addr = (l2addr | + ((virt_addr & 0x000FFC00) >> 8)) & + ~3; + //l2desc = mem_read_word (state, l2addr); + bus_read(32, l2addr, &l2desc); + + entry.virt_addr = virt_addr; + entry.phys_addr = l2desc; + entry.perms = l2desc & 0x00000FFC; + entry.domain = (l1desc >> 5) & 0x0000000F; + switch (l2desc & 3) { + case 0: + state->mmu.last_domain = entry.domain; + return PAGE_TRANSLATION_FAULT; + case 3: + entry.mapping = TLB_TINYPAGE; + break; + case 1: + // this is untested + entry.mapping = TLB_LARGEPAGE; + break; + case 2: + // this is untested + entry.mapping = TLB_SMALLPAGE; + break; + } + } + break; + case 1: + /* coarse page table */ + { + ARMword l2addr, l2desc; + + l2addr = l1desc & 0xFFFFFC00; + l2addr = (l2addr | + ((virt_addr & 0x000FF000) >> 10)) & + ~3; + //l2desc = mem_read_word (state, l2addr); + bus_read(32, l2addr, &l2desc); + + entry.virt_addr = virt_addr; + entry.phys_addr = l2desc; + entry.perms = l2desc & 0x00000FFC; + entry.domain = (l1desc >> 5) & 0x0000000F; + //printf("SKYEYE:PAGE virt_addr = %x,l1desc=%x,phys_addr=%x\n",virt_addr,l1desc,entry.phys_addr); + //chy 2003-09-02 for xscale + switch (l2desc & 3) { + case 0: + state->mmu.last_domain = entry.domain; + return PAGE_TRANSLATION_FAULT; + case 3: + if (!state->is_XScale) { + state->mmu.last_domain = + entry.domain; + return PAGE_TRANSLATION_FAULT; + }; + //ks 2004-05-09 xscale shold use Extend Small Page + //entry.mapping = TLB_SMALLPAGE; + entry.mapping = TLB_ESMALLPAGE; //xj + break; + case 1: + entry.mapping = TLB_LARGEPAGE; + break; + case 2: + entry.mapping = TLB_SMALLPAGE; + break; + } + } + break; + case 2: + /* section */ + //printf("SKYEYE:WARNING: not implement section mapping incompletely\n"); + //printf("SKYEYE:SECTION virt_addr = %x,l1desc=%x\n",virt_addr,l1desc); + //return SECTION_DOMAIN_FAULT; + //#if 0 + entry.virt_addr = virt_addr; + entry.phys_addr = l1desc; + entry.perms = l1desc & 0x00000C0C; + entry.domain = (l1desc >> 5) & 0x0000000F; + entry.mapping = TLB_SECTION; + break; + //#endif + } + entry.virt_addr &= tlb_masks[entry.mapping]; + entry.phys_addr &= tlb_masks[entry.mapping]; + + /* place entry in the tlb */ + *tlb = &tlb_t->entrys[tlb_t->cycle]; + tlb_t->cycle = (tlb_t->cycle + 1) % tlb_t->num; + **tlb = entry; + } + state->mmu.last_domain = (*tlb)->domain; + return NO_FAULT; +} + +int +mmu_tlb_init (tlb_s * tlb_t, int num) +{ + tlb_entry_t *e; + int i; + + e = (tlb_entry_t *) malloc (sizeof (*e) * num); + if (e == NULL) { + ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*e) * num); + goto tlb_malloc_error; + } + tlb_t->entrys = e; + for (i = 0; i < num; i++, e++) + e->mapping = TLB_INVALID; + tlb_t->cycle = 0; + tlb_t->num = num; + return 0; + + tlb_malloc_error: + return -1; +} + +void +mmu_tlb_exit (tlb_s * tlb_t) +{ + free (tlb_t->entrys); +}; + +void +mmu_tlb_invalidate_all (ARMul_State * state, tlb_s * tlb_t) +{ + int entry; + + for (entry = 0; entry < tlb_t->num; entry++) { + tlb_t->entrys[entry].mapping = TLB_INVALID; + } + tlb_t->cycle = 0; +} + +void +mmu_tlb_invalidate_entry (ARMul_State * state, tlb_s * tlb_t, ARMword addr) +{ + tlb_entry_t *tlb; + + tlb = mmu_tlb_search (state, tlb_t, addr); + if (tlb) { + tlb->mapping = TLB_INVALID; + } +} + +tlb_entry_t * +mmu_tlb_search (ARMul_State * state, tlb_s * tlb_t, ARMword virt_addr) +{ + int entry; + + for (entry = 0; entry < tlb_t->num; entry++) { + tlb_entry_t *tlb; + ARMword mask; + + tlb = &(tlb_t->entrys[entry]); + if (tlb->mapping == TLB_INVALID) { + continue; + } + mask = tlb_masks[tlb->mapping]; + if ((virt_addr & mask) == (tlb->virt_addr & mask)) { + return tlb; + } + } + return NULL; +} diff --git a/src/core/arm/interpreter/mmu/tlb.h b/src/core/arm/interpreter/mmu/tlb.h index 938c01786..40856567b 100644 --- a/src/core/arm/interpreter/mmu/tlb.h +++ b/src/core/arm/interpreter/mmu/tlb.h @@ -63,14 +63,7 @@ typedef struct tlb_s #define tlb_b_flag(tlb) \ ((tlb)->perms & 0x4) -#define tlb_va_to_pa(tlb, va) \ -(\ - {\ - ARMword mask = tlb_masks[tlb->mapping]; \ - (tlb->phys_addr & mask) | (va & ~mask);\ - }\ -) - +#define tlb_va_to_pa(tlb, va) ((tlb->phys_addr & tlb_masks[tlb->mapping]) | (va & ~tlb_masks[tlb->mapping])) fault_t check_access (ARMul_State * state, ARMword virt_addr, tlb_entry_t * tlb, int read); diff --git a/src/core/arm/interpreter/mmu/wb.cpp b/src/core/arm/interpreter/mmu/wb.cpp new file mode 100644 index 000000000..82c0cec02 --- /dev/null +++ b/src/core/arm/interpreter/mmu/wb.cpp @@ -0,0 +1,149 @@ +#include "core/arm/interpreter/armdefs.h" + +/* wb_init + * @wb_t :wb_t to init + * @num :num of entrys + * @nb :num of byte of each entry + * + * $ -1:error + * 0:ok + * */ +int +mmu_wb_init (wb_s * wb_t, int num, int nb) +{ + int i; + wb_entry_t *entrys, *wb; + + entrys = (wb_entry_t *) malloc (sizeof (*entrys) * num); + if (entrys == NULL) { + ERROR_LOG(ARM11, "malloc size %d\n", sizeof (*entrys) * num); + goto entrys_malloc_error; + } + + for (wb = entrys, i = 0; i < num; i++, wb++) { + /*chy 2004-06-06, fix bug found by wenye@cs.ucsb.edu */ + //wb->data = (ARMword *)malloc(sizeof(ARMword) * nb); + wb->data = (ARMbyte *) malloc (nb); + if (wb->data == NULL) { + ERROR_LOG(ARM11, "malloc size of %d\n", nb); + goto data_malloc_error; + } + + }; + + wb_t->first = wb_t->last = wb_t->used = 0; + wb_t->num = num; + wb_t->nb = nb; + wb_t->entrys = entrys; + return 0; + + data_malloc_error: + while (--i >= 0) + free (entrys[i].data); + free (entrys); + entrys_malloc_error: + return -1; +}; + +/* wb_exit + * @wb_t :wb_t to exit + * */ +void +mmu_wb_exit (wb_s * wb_t) +{ + int i; + wb_entry_t *wb; + + wb = wb_t->entrys; + for (i = 0; i < wb_t->num; i++, wb++) { + free (wb->data); + } + free (wb_t->entrys); +}; + +/* wb_write_words :put words in Write Buffer + * @state: ARMul_State + * @wb_t: write buffer + * @pa: physical address + * @data: data ptr + * @n number of word to write + * + * Note: write buffer merge is not implemented, can be done late + * */ +void +mmu_wb_write_bytes (ARMul_State * state, wb_s * wb_t, ARMword pa, + ARMbyte * data, int n) +{ + int i; + wb_entry_t *wb; + + while (n) { + if (wb_t->num == wb_t->used) { + /*clean the last wb entry */ + ARMword t; + + wb = &wb_t->entrys[wb_t->last]; + t = wb->pa; + for (i = 0; i < wb->nb; i++) { + //mem_write_byte (state, t, wb->data[i]); + bus_write(8, t, wb->data[i]); + //t += WORD_SIZE; + t++; + } + wb_t->last++; + if (wb_t->last == wb_t->num) + wb_t->last = 0; + wb_t->used--; + } + + wb = &wb_t->entrys[wb_t->first]; + i = (n < wb_t->nb) ? n : wb_t->nb; + + wb->pa = pa; + //pa += i << WORD_SHT; + pa += i; + + wb->nb = i; + //memcpy(wb->data, data, i << WORD_SHT); + memcpy (wb->data, data, i); + data += i; + n -= i; + wb_t->first++; + if (wb_t->first == wb_t->num) + wb_t->first = 0; + wb_t->used++; + }; +//teawater add for set_dirty fflash cache function 2005.07.18------------------- +#ifdef DBCT + if (!skyeye_config.no_dbct) { + tb_setdirty (state, pa, NULL); + } +#endif +//AJ2D-------------------------------------------------------------------------- +} + +/* wb_drain_all + * @wb_t wb_t to drain + * */ +void +mmu_wb_drain_all (ARMul_State * state, wb_s * wb_t) +{ + ARMword pa; + wb_entry_t *wb; + int i; + + while (wb_t->used) { + wb = &wb_t->entrys[wb_t->last]; + pa = wb->pa; + for (i = 0; i < wb->nb; i++) { + //mem_write_byte (state, pa, wb->data[i]); + bus_write(8, pa, wb->data[i]); + //pa += WORD_SIZE; + pa++; + } + wb_t->last++; + if (wb_t->last == wb_t->num) + wb_t->last = 0; + wb_t->used--; + }; +} diff --git a/src/core/arm/interpreter/mmu/xscale_copro.cpp b/src/core/arm/interpreter/mmu/xscale_copro.cpp new file mode 100644 index 000000000..99cd77737 --- /dev/null +++ b/src/core/arm/interpreter/mmu/xscale_copro.cpp @@ -0,0 +1,1388 @@ +/* + armmmu.c - Memory Management Unit emulation. + ARMulator extensions for the ARM7100 family. + Copyright (C) 1999 Ben Williamson + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <assert.h> +#include <string.h> + +#include "core/arm/interpreter/armdefs.h" +#include "core/arm/interpreter/armemu.h" + +/*#include "pxa.h" */ + +/* chy 2005-09-19 */ + +/* extern pxa270_io_t pxa270_io; */ +/* chy 2005-09-19 -----end */ + +typedef struct xscale_mmu_desc_s +{ + int i_tlb; + cache_desc_t i_cache; + + int d_tlb; + cache_desc_t main_d_cache; + cache_desc_t mini_d_cache; + //int rb; xscale has no read buffer + wb_desc_t wb; +} xscale_mmu_desc_t; + +static xscale_mmu_desc_t pxa_mmu_desc = { + 32, + {32, 32, 32, CACHE_WRITE_BACK}, + + 32, + {32, 32, 32, CACHE_WRITE_BACK}, + {32, 2, 8, CACHE_WRITE_BACK}, + {8, 16}, //for byte size, +}; + +//chy 2005-09-19 for cp6 +#define CR0_ICIP 0 +#define CR1_ICMR 1 +//chy 2005-09-19 ---end +//----------- for cp14----------------- +#define CCLKCFG 6 +#define PWRMODE 7 +typedef struct xscale_cp14_reg_s +{ + unsigned cclkcfg; //reg6 + unsigned pwrmode; //reg7 +} xscale_cp14_reg_s; + +xscale_cp14_reg_s pxa_cp14_regs; + +//-------------------------------------- + +static fault_t xscale_mmu_write (ARMul_State * state, ARMword va, + ARMword data, ARMword datatype); +static fault_t xscale_mmu_read (ARMul_State * state, ARMword va, + ARMword * data, ARMword datatype); + +ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value); +ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value); + + +/* jeff add 2010.9.26 for pxa270 cp6*/ +#define PXA270_ICMR 0x40D00004 +#define PXA270_ICPR 0x40D00010 +#define PXA270_ICLR 0x40D00008 +//chy 2005-09-19 for xscale pxa27x cp6 +//unsigned +//xscale_cp6_mrc (ARMul_State * state, unsigned type, ARMword instr, +// ARMword * data) +//{ +// unsigned opcode_2 = BITS (5, 7); +// unsigned CRm = BITS (0, 3); +// unsigned reg = BITS (16, 19); +// unsigned result; +// +// //printf("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,state->Reg[15], instr); +// +// switch (reg) { +// case CR0_ICIP: { // cp 6 reg 0 +// //printf("cp6_mrc cr0 ICIP \n"); +// /* *data = (pxa270_io.icmr & pxa270_io.icpr) & ~pxa270_io.iclr; */ +// /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ +// int icmr, icpr, iclr; +// bus_read(32, PXA270_ICMR, &icmr); +// bus_read(32, PXA270_ICPR, &icpr); +// bus_read(32, PXA270_ICLR, &iclr); +// *data = (icmr & icpr) & ~iclr; +// } +// break; +// case CR1_ICMR: { // cp 6 reg 1 +// //printf("cp6_mrc cr1 ICMR\n"); +// /* *data = pxa270_io.icmr; */ +// int icmr; +// /* use bus_read get the pxa270 machine registers 2010.9.26 jeff*/ +// bus_read(32, PXA270_ICMR, &icmr); +// *data = icmr; +// } +// break; +// default: +// *data = 0; +// printf ("SKYEYE:cp6_mrc unknown cp6 regs!!!!!!\n"); +// printf ("SKYEYE: xscale_cp6_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n", opcode_2, CRm, reg, state->Reg[15], instr); +// break; +// } +// return 0; +//} +// +////chy 2005-09-19 end +////xscale cp13 ---------------------------------------------------- +//unsigned +//xscale_cp13_init (ARMul_State * state) +//{ +// //printf("SKYEYE: xscale_cp13_init: begin\n"); +// return 0; +//} +// +//unsigned +//xscale_cp13_exit (ARMul_State * state) +//{ +// //printf("SKYEYE: xscale_cp13_exit: begin\n"); +// return 0; +//} +// +//unsigned +//xscale_cp13_ldc (ARMul_State * state, unsigned type, ARMword instr, +// ARMword data) +//{ +// printf ("SKYEYE: xscale_cp13_ldc: ERROR isn't existed,"); +// SKYEYE_OUTREGS (stderr); +// fprintf (stderr, "\n"); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +//unsigned +//xscale_cp13_stc (ARMul_State * state, unsigned type, ARMword instr, +// ARMword * data) +//{ +// printf ("SKYEYE: xscale_cp13_stc: ERROR isn't existed,"); +// SKYEYE_OUTREGS (stderr); +// fprintf (stderr, "\n"); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +//unsigned +//xscale_cp13_mrc (ARMul_State * state, unsigned type, ARMword instr, +// ARMword * data) +//{ +// printf ("SKYEYE: xscale_cp13_mrc: ERROR isn't existed,"); +// SKYEYE_OUTREGS (stderr); +// fprintf (stderr, "\n"); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +//unsigned +//xscale_cp13_mcr (ARMul_State * state, unsigned type, ARMword instr, +// ARMword data) +//{ +// printf ("SKYEYE: xscale_cp13_mcr: ERROR isn't existed,"); +// SKYEYE_OUTREGS (stderr); +// fprintf (stderr, "\n"); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +//unsigned +//xscale_cp13_cdp (ARMul_State * state, unsigned type, ARMword instr) +//{ +// printf ("SKYEYE: xscale_cp13_cdp: ERROR isn't existed,"); +// SKYEYE_OUTREGS (stderr); +// fprintf (stderr, "\n"); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +//unsigned +//xscale_cp13_read_reg (ARMul_State * state, unsigned reg, ARMword * data) +//{ +// printf ("SKYEYE: xscale_cp13_read_reg: ERROR isn't existed,"); +// SKYEYE_OUTREGS (stderr); +// fprintf (stderr, "\n"); +// return 0; +// //exit(-1); +//} +// +//unsigned +//xscale_cp13_write_reg (ARMul_State * state, unsigned reg, ARMword data) +//{ +// printf ("SKYEYE: xscale_cp13_write_reg: ERROR isn't existed,"); +// SKYEYE_OUTREGS (stderr); +// fprintf (stderr, "\n"); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +////------------------------------------------------------------------ +////xscale cp14 ---------------------------------------------------- +//unsigned +//xscale_cp14_init (ARMul_State * state) +//{ +// //printf("SKYEYE: xscale_cp14_init: begin\n"); +// pxa_cp14_regs.cclkcfg = 0; +// pxa_cp14_regs.pwrmode = 0; +// return 0; +//} +// +//unsigned +//xscale_cp14_exit (ARMul_State * state) +//{ +// //printf("SKYEYE: xscale_cp14_exit: begin\n"); +// return 0; +//} +// +//unsigned +//xscale_cp14_ldc (ARMul_State * state, unsigned type, ARMword instr, +// ARMword data) +//{ +// printf ("SKYEYE: xscale_cp14_ldc: ERROR isn't existed, reg15 0x%x\n", +// state->Reg[15]); +// SKYEYE_OUTREGS (stderr); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +//unsigned +//xscale_cp14_stc (ARMul_State * state, unsigned type, ARMword instr, +// ARMword * data) +//{ +// printf ("SKYEYE: xscale_cp14_stc: ERROR isn't existed, reg15 0x%x\n", +// state->Reg[15]); +// SKYEYE_OUTREGS (stderr); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +// +//unsigned +//xscale_cp14_mrc (ARMul_State * state, unsigned type, ARMword instr, +// ARMword * data) +//{ +// unsigned opcode_2 = BITS (5, 7); +// unsigned CRm = BITS (0, 3); +// unsigned reg = BITS (16, 19); +// unsigned result; +// +// //printf("SKYEYE: xscale_cp14_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ +// state->Reg[15], instr); +// +// switch (reg) { +// case CCLKCFG: // cp 14 reg 6 +// //printf("cp14_mrc cclkcfg \n"); +// *data = pxa_cp14_regs.cclkcfg; +// break; +// case PWRMODE: // cp 14 reg 7 +// //printf("cp14_mrc pwrmode \n"); +// *data = pxa_cp14_regs.pwrmode; +// break; +// default: +// *data = 0; +// printf ("SKYEYE:cp14_mrc unknown cp14 regs!!!!!!\n"); +// break; +// } +// return 0; +//} +//unsigned xscale_cp14_mcr (ARMul_State * state, unsigned type, ARMword instr, +// ARMword data) +//{ +// unsigned opcode_2 = BITS (5, 7); +// unsigned CRm = BITS (0, 3); +// unsigned reg = BITS (16, 19); +// unsigned result; +// +// //printf("SKYEYE: xscale_cp14_mcr:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ +// state->Reg[15], instr); +// +// switch (reg) { +// case CCLKCFG: // cp 14 reg 6 +// //printf("cp14_mcr cclkcfg \n"); +// pxa_cp14_regs.cclkcfg = data & 0xf; +// break; +// case PWRMODE: // cp 14 reg 7 +// //printf("cp14_mcr pwrmode \n"); +// pxa_cp14_regs.pwrmode = data & 0x3; +// break; +// default:printf ("SKYEYE: cp14_mcr unknown cp14 regs!!!!!!\n"); +// break; +// } +// return 0; +//} +//unsigned xscale_cp14_cdp (ARMul_State * state, unsigned type, ARMword instr) +//{ +// printf ("SKYEYE: xscale_cp14_cdp: ERROR isn't existed, reg15 0x%x\n", +// state->Reg[15]); +// SKYEYE_OUTREGS (stderr); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +//unsigned xscale_cp14_read_reg (ARMul_State * state, unsigned reg, +// ARMword * data) +//{ +// printf ("SKYEYE: xscale_cp14_read_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); +// SKYEYE_OUTREGS (stderr); +// // skyeye_exit (-1); +// return 0; //No matter return value, only for compiler. +//} +//unsigned xscale_cp14_write_reg (ARMul_State * state, unsigned reg, +// ARMword data) +//{ +// printf ("SKYEYE: xscale_cp14_write_reg: ERROR isn't existed, reg15 0x%x\n", state->Reg[15]); +// SKYEYE_OUTREGS (stderr); +// // skyeye_exit (-1); +// +// return 0; //No matter return value, only for compiler. +//} + +//------------------------------------------------------------------ +//cp15 ------------------------------------- +unsigned xscale_cp15_ldc (ARMul_State * state, unsigned type, ARMword instr, + ARMword data) +{ + printf ("SKYEYE: xscale_cp15_ldc: ERROR isn't existed\n"); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp15_stc (ARMul_State * state, unsigned type, ARMword instr, + ARMword * data) +{ + printf ("SKYEYE: xscale_cp15_stc: ERROR isn't existed\n"); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp15_cdp (ARMul_State * state, unsigned type, ARMword instr) +{ + printf ("SKYEYE: xscale_cp15_cdp: ERROR isn't existed\n"); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} +unsigned xscale_cp15_read_reg (ARMul_State * state, unsigned reg, + ARMword * data) +{ +//chy 2003-09-03: for xsacle_cp15_cp_access_allowed + if (reg == 15) { + *data = state->mmu.copro_access; + //printf("SKYEYE: xscale_cp15_read_reg: reg 0x%x,data %x\n",reg,*data); + return 0; + } + printf ("SKYEYE: xscale_cp15_read_reg: reg 0x%x, ERROR isn't existed\n", reg); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + + return 0; //No matter return value, only for compiler. +} + +//chy 2003-09-03 used by macro CP_ACCESS_ALLOWED in armemu.h +unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, + unsigned cpnum) +{ + unsigned data; + + xscale_cp15_read_reg (state, reg, &data); + //printf("SKYEYE: cp15_cp_access_allowed data %x, cpnum %x, result %x\n", data, cpnum, (data & 1<<cpnum)); + if (data & 1 << cpnum) + return 1; + else + return 0; +} + +unsigned xscale_cp15_write_reg (ARMul_State * state, unsigned reg, + ARMword value) +{ + switch (reg) { + case MMU_FAULT_STATUS: + //printf("SKYEYE:cp15_write_reg wrote FS val 0x%x \n",value); + state->mmu.fault_status = value & 0x6FF; + break; + case MMU_FAULT_ADDRESS: + //printf("SKYEYE:cp15_write_reg wrote FA val 0x%x \n",value); + state->mmu.fault_address = value; + break; + default: + printf ("SKYEYE: xscale_cp15_write_reg: reg 0x%x R15 %x ERROR isn't existed\n", reg, state->Reg[15]); + SKYEYE_OUTREGS (stderr); + // skyeye_exit (-1); + } + return 0; +} + +int xscale_cp15_init (ARMul_State * state) +{ + xscale_mmu_desc_t *desc; + cache_desc_t *c_desc; + + state->mmu.control = 0; + state->mmu.translation_table_base = 0xDEADC0DE; + state->mmu.domain_access_control = 0xDEADC0DE; + state->mmu.fault_status = 0; + state->mmu.fault_address = 0; + state->mmu.process_id = 0; + state->mmu.cache_type = 0xB1AA1AA; //0000 1011 0001 1010 1010 0001 1010 1010 + state->mmu.aux_control = 0; + + desc = &pxa_mmu_desc; + + if (mmu_tlb_init (I_TLB (), desc->i_tlb)) { + ERROR_LOG(ARM11, "i_tlb init %d\n", -1); + goto i_tlb_init_error; + } + + c_desc = &desc->i_cache; + if (mmu_cache_init (I_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "i_cache init %d\n", -1); + goto i_cache_init_error; + } + + if (mmu_tlb_init (D_TLB (), desc->d_tlb)) { + ERROR_LOG(ARM11, "d_tlb init %d\n", -1); + goto d_tlb_init_error; + } + + c_desc = &desc->main_d_cache; + if (mmu_cache_init (MAIN_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "main_d_cache init %d\n", -1); + goto main_d_cache_init_error; + } + + c_desc = &desc->mini_d_cache; + if (mmu_cache_init (MINI_D_CACHE (), c_desc->width, c_desc->way, + c_desc->set, c_desc->w_mode)) { + ERROR_LOG(ARM11, "mini_d_cache init %d\n", -1); + goto mini_d_cache_init_error; + } + + if (mmu_wb_init (WB (), desc->wb.num, desc->wb.nb)) { + ERROR_LOG(ARM11, "wb init %d\n", -1); + goto wb_init_error; + } +#if 0 + if (mmu_rb_init (RB (), desc->rb)) { + ERROR_LOG(ARM11, "rb init %d\n", -1); + goto rb_init_error; + } +#endif + + return 0; +#if 0 + rb_init_error: + mmu_wb_exit (WB ()); +#endif + wb_init_error: + mmu_cache_exit (MINI_D_CACHE ()); + mini_d_cache_init_error: + mmu_cache_exit (MAIN_D_CACHE ()); + main_d_cache_init_error: + mmu_tlb_exit (D_TLB ()); + d_tlb_init_error: + mmu_cache_exit (I_CACHE ()); + i_cache_init_error: + mmu_tlb_exit (I_TLB ()); + i_tlb_init_error: + return -1; +} + +void xscale_cp15_exit (ARMul_State * state) +{ + //mmu_rb_exit(RB()); + mmu_wb_exit (WB ()); + mmu_cache_exit (MINI_D_CACHE ()); + mmu_cache_exit (MAIN_D_CACHE ()); + mmu_tlb_exit (D_TLB ()); + mmu_cache_exit (I_CACHE ()); + mmu_tlb_exit (I_TLB ()); +}; + + +static fault_t + xscale_mmu_load_instr (ARMul_State * state, ARMword va, + ARMword * instr) +{ + fault_t fault; + tlb_entry_t *tlb; + cache_line_t *cache; + int c; //cache bit + ARMword pa; //physical addr + + static int debug_count = 0; //used for debug + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + if (MMU_Enabled) { + /*align check */ + if ((va & (INSN_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + va &= ~(INSN_SIZE - 1); + + /*translate tlb */ + fault = translate (state, va, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, va, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + //chy 2003-09-02 for test, don't use cache ????? +#if 0 + /*search cache no matter MMU enabled/disabled */ + cache = mmu_cache_search (state, I_CACHE (), va); + if (cache) { + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + return 0; + } +#endif + /*if MMU disabled or C flag is set alloc cache */ + if (MMU_Disabled) { + c = 1; + pa = va; + } + else { + c = tlb_c_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + } + + //chy 2003-09-03 only read mem, don't use cache now,will change later ???? + //*instr = mem_read_word (state, pa); + bus_read(32, pa, instr); +#if 0 +//----------------------------------------------------------- + //chy 2003-09-02 for test???? + if (pa >= 0xa01c8000 && pa <= 0xa01c8020) { + printf ("SKYEYE:load_instr: pa %x, va %x,instr %x, R15 %x\n", + pa, va, *instr, state->Reg[15]); + } + +//---------------------------------------------------------------------- +#endif + return NO_FAULT; + + if (c) { + int index; + + debug_count++; + cache = mmu_cache_alloc (state, I_CACHE (), va, pa); + index = va_cache_index (va, I_CACHE ()); + *instr = cache->data[va_cache_index (va, I_CACHE ())]; + } + else + //*instr = mem_read_word (state, pa); + bus_read(32, pa, instr); + + return NO_FAULT; +}; + + + +static fault_t + xscale_mmu_read_byte (ARMul_State * state, ARMword virt_addr, + ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = xscale_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); + return fault; +} + +static fault_t + xscale_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, + ARMword * data) +{ + //ARMword temp,offset; + fault_t fault; + fault = xscale_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); + return fault; +} + +static fault_t + xscale_mmu_read_word (ARMul_State * state, ARMword virt_addr, + ARMword * data) +{ + return xscale_mmu_read (state, virt_addr, data, ARM_WORD_TYPE); +} + + + + +static fault_t + xscale_mmu_read (ARMul_State * state, ARMword va, ARMword * data, + ARMword datatype) +{ + fault_t fault; +// rb_entry_t *rb; + tlb_entry_t *tlb; + cache_line_t *cache; + ARMword pa, real_va, temp, offset; + //chy 2003-09-02 for test ???? + static unsigned chyst1 = 0, chyst2 = 0; + + DEBUG_LOG(ARM11, "va = %x\n", va); + + va = mmu_pid_va_map (va); + real_va = va; + /*if MMU disabled, memory_read */ + if (MMU_Disabled) { + //*data = mem_read_word(state, va); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, va); + bus_read(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, va); + bus_read(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, va); + bus_read(32, va, data); + else { + printf ("SKYEYE:1 xscale_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + + /*align check */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } // else + + va &= ~(WORD_SIZE - 1); + + /*translate va to tlb */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*check access permission */ + fault = check_access (state, va, tlb, 1); + if (fault) + return fault; + +#if 0 +//------------------------------------------------ +//chy 2003-09-02 for test only ,should commit ???? + if (datatype == ARM_WORD_TYPE) { + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + pa = tlb_va_to_pa (tlb, va); + *data = mem_read_word (state, pa); + chyst1++; + printf ("**SKYEYE:mmu_read word %d: pa %x, va %x, data %x, R15 %x\n", chyst1, pa, real_va, *data, state->Reg[15]); + /* + cache==mmu_cache_search(state,MAIN_D_CACHE(),va); + if(cache){ + *data = cache->data[va_cache_index(va, MAIN_D_CACHE())]; + printf("cached data %x\n",*data); + }else printf("no cached data\n"); + */ + } + } +//------------------------------------------------- +#endif +#if 0 + /*search in read buffer */ + rb = mmu_rb_search (RB (), va); + if (rb) { + if (rb->fault) + return rb->fault; + *data = rb->data[(va & (rb_masks[rb->type] - 1)) >> WORD_SHT]; + goto datatrans; + //return 0; + }; +#endif + + /*2004-07-19 chy: add support of xscale MMU CacheDisabled option */ + if (MMU_CacheDisabled) { + //if(1){ can be used to test cache error + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, real_va); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, pa); + bus_read(8, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, pa); + bus_read(16, pa, data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, pa); + bus_read(32, pa, data); + else { + printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + return NO_FAULT; + } + + + /*search main cache */ + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MAIN_D_CACHE ())]; +#if 0 +//------------------------------------------------------------------------ +//chy 2003-09-02 for test only ,should commit ???? + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + pa = tlb_va_to_pa (tlb, va); + chyst2++; + printf ("**SKYEYE:mmu_read wordk:cache %d: pa %x, va %x, data %x, R15 %x\n", chyst2, pa, real_va, *data, state->Reg[15]); + } +//------------------------------------------------------------------- +#endif + goto datatrans; + //return 0; + } + //chy 2003-08-24, now maybe we don't need minidcache ???? +#if 0 + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + *data = cache->data[va_cache_index (va, MINI_D_CACHE ())]; + goto datatrans; + //return 0; + } +#endif + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, va); + //chy 2003-08-24 , in xscale it means what ????? +#if 0 + if ((pa >= 0xe0000000) && (pa < 0xe8000000)) { + + if (tlb_c_flag (tlb)) { + if (tlb_b_flag (tlb)) { + mmu_cache_soft_flush (state, MAIN_D_CACHE (), + pa); + } + else { + mmu_cache_soft_flush (state, MINI_D_CACHE (), + pa); + } + } + return 0; + } +#endif + //chy 2003-08-24, check phy addr + //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address + /* + if(pa >= 0xb0000000){ + printf("SKYEYE:xscale_mmu_read: phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); + return 0; + } + */ + + //chy 2003-08-24, now maybe we don't need wb ???? +#if 0 + /*if Buffer, drain Write Buffer first */ + if (tlb_b_flag (tlb)) + mmu_wb_drain_all (state, WB ()); +#endif + /*alloc cache or mem_read */ + if (tlb_c_flag (tlb) && MMU_DCacheEnabled) { + cache_s *cache_t; + + if (tlb_b_flag (tlb)) + cache_t = MAIN_D_CACHE (); + else + cache_t = MINI_D_CACHE (); + cache = mmu_cache_alloc (state, cache_t, va, pa); + *data = cache->data[va_cache_index (va, cache_t)]; + } + else { + //*data = mem_read_word(state, pa); + if (datatype == ARM_BYTE_TYPE) + //*data = mem_read_byte (state, pa | (real_va & 3)); + bus_read(8, pa | (real_va & 3), data); + else if (datatype == ARM_HALFWORD_TYPE) + //*data = mem_read_halfword (state, pa | (real_va & 2)); + bus_read(16, pa | (real_va & 2), data); + else if (datatype == ARM_WORD_TYPE) + //*data = mem_read_word (state, pa); + bus_read(32, pa, data); + else { + printf ("SKYEYE:2 xscale_mmu_read error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + return NO_FAULT; + } + + + datatrans: + if (datatype == ARM_HALFWORD_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + *data = (temp >> offset) & 0xffff; + } + else if (datatype == ARM_BYTE_TYPE) { + temp = *data; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + *data = (temp >> offset & 0xffL); + } + end: + return NO_FAULT; +} + + +static fault_t + xscale_mmu_write_byte (ARMul_State * state, ARMword virt_addr, + ARMword data) +{ + return xscale_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE); +} + +static fault_t + xscale_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, + ARMword data) +{ + return xscale_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE); +} + +static fault_t + xscale_mmu_write_word (ARMul_State * state, ARMword virt_addr, + ARMword data) +{ + return xscale_mmu_write (state, virt_addr, data, ARM_WORD_TYPE); +} + + + +static fault_t + xscale_mmu_write (ARMul_State * state, ARMword va, ARMword data, + ARMword datatype) +{ + tlb_entry_t *tlb; + cache_line_t *cache; + cache_s *cache_t; + int b; + ARMword pa, real_va, temp, offset; + fault_t fault; + + ARMword index; +//chy 2003-09-02 for test ???? +// static unsigned chyst1=0,chyst2=0; + + DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); + va = mmu_pid_va_map (va); + real_va = va; + + if (MMU_Disabled) { + //mem_write_word(state, va, data); + if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, va, data); + bus_write(8, va, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, va, data); + bus_write(16, va, data); + else if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, va, data); + bus_write(32, va, data); + else { + printf ("SKYEYE:1 xscale_mmu_write error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + /*align check */ + if (((va & 3) && (datatype == ARM_WORD_TYPE) && MMU_Aligned) || + ((va & 1) && (datatype == ARM_HALFWORD_TYPE) && MMU_Aligned)) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } //else + va &= ~(WORD_SIZE - 1); + /*tlb translate */ + fault = translate (state, va, D_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + /*tlb check access */ + fault = check_access (state, va, tlb, 0); + if (fault) { + DEBUG_LOG(ARM11, "check_access\n"); + return fault; + } + + /*2004-07-19 chy: add support for xscale MMU_CacheDisabled */ + if (MMU_CacheDisabled) { + //if(1){ can be used to test the cache error + /*get phy_addr */ + pa = tlb_va_to_pa (tlb, real_va); + if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, pa, data); + bus_write(8, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, pa, data); + bus_write(16, pa, data); + else if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa , data); + else { + printf ("SKYEYE:MMU_CacheDisabled xscale_mmu_write error: unknown data type %d\n", datatype); + // skyeye_exit (-1); + } + + return NO_FAULT; + } + + /*search main cache */ + b = tlb_b_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + cache = mmu_cache_search (state, MAIN_D_CACHE (), va); + if (cache) { + cache_t = MAIN_D_CACHE (); + goto has_cache; + } + //chy 2003-08-24, now maybe we don't need minidcache ???? +#if 0 + /*search mini cache */ + cache = mmu_cache_search (state, MINI_D_CACHE (), va); + if (cache) { + cache_t = MINI_D_CACHE (); + goto has_cache; + } +#endif + b = tlb_b_flag (tlb); + pa = tlb_va_to_pa (tlb, va); + //chy 2003-08-24, check phy addr 0xa0000000, size 0x04000000 + //ywc 2004-11-30, inactive this check because of using 0xc0000000 as the framebuffer start address + /* + if(pa >= 0xb0000000){ + printf("SKYEYE:xscale_mmu_write phy address 0x%x error,reg[15] 0x%x\n",pa,state->Reg[15]); + return 0; + } + */ + + //chy 2003-08-24, now maybe we don't need WB ???? +#if 0 + if (b) { + if (MMU_WBEnabled) { + if (datatype == ARM_WORD_TYPE) + mmu_wb_write_bytes (state, WB (), pa, &data, + 4); + else if (datatype == ARM_HALFWORD_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | (real_va & 2)), + &data, 2); + else if (datatype == ARM_BYTE_TYPE) + mmu_wb_write_bytes (state, WB (), + (pa | (real_va & 3)), + &data, 1); + + } + else { + if (datatype == ARM_WORD_TYPE) + mem_write_word (state, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + mem_write_halfword (state, + (pa | (real_va & 2)), + data); + else if (datatype == ARM_BYTE_TYPE) + mem_write_byte (state, (pa | (real_va & 3)), + data); + } + } + else { + + mmu_wb_drain_all (state, WB ()); + + if (datatype == ARM_WORD_TYPE) + mem_write_word (state, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + mem_write_halfword (state, (pa | (real_va & 2)), + data); + else if (datatype == ARM_BYTE_TYPE) + mem_write_byte (state, (pa | (real_va & 3)), data); + } +#endif + //chy 2003-08-24, just write phy addr + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, (pa | (real_va & 2)), data); + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, (pa | (real_va & 3)), data); + bus_write(8, (pa | (real_va & 3)), data); +#if 0 +//------------------------------------------------------------- +//chy 2003-09-02 for test ???? + if (datatype == ARM_WORD_TYPE) { + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + printf ("**SKYEYE:mmu_write word: pa %x, va %x, data %x, R15 %x \n", pa, real_va, data, state->Reg[15]); + } + } +//-------------------------------------------------------------- +#endif + return NO_FAULT; + + has_cache: + index = va_cache_index (va, cache_t); + //cache->data[index] = data; + + if (datatype == ARM_WORD_TYPE) + cache->data[index] = data; + else if (datatype == ARM_HALFWORD_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 2) ^ (real_va & 2)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << + offset); + } + else if (datatype == ARM_BYTE_TYPE) { + temp = cache->data[index]; + offset = (((ARMword) state->bigendSig * 3) ^ (real_va & 3)) << 3; /* bit offset into the word */ + cache->data[index] = + (temp & ~(0xffL << offset)) | ((data & 0xffL) << + offset); + } + + if (index < (cache_t->width >> (WORD_SHT + 1))) + cache->tag |= TAG_FIRST_HALF_DIRTY; + else + cache->tag |= TAG_LAST_HALF_DIRTY; +//------------------------------------------------------------- +//chy 2003-09-03 be sure the changed value will be in memory as soon as possible, so I cache can get the newest value +#if 0 + { + if (datatype == ARM_WORD_TYPE) + mem_write_word (state, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + mem_write_halfword (state, (pa | (real_va & 2)), + data); + else if (datatype == ARM_BYTE_TYPE) + mem_write_byte (state, (pa | (real_va & 3)), data); + } +#endif +#if 0 +//chy 2003-09-02 for test ???? + if (datatype == ARM_WORD_TYPE) { + if (real_va >= 0xffff0000 && real_va <= 0xffff0020) { + printf ("**SKYEYE:mmu_write word:cache: pa %x, va %x, data %x, R15 %x\n", pa, real_va, data, state->Reg[15]); + } + } +//------------------------------------------------------------- +#endif + if (datatype == ARM_WORD_TYPE) + //mem_write_word (state, pa, data); + bus_write(32, pa, data); + else if (datatype == ARM_HALFWORD_TYPE) + //mem_write_halfword (state, (pa | (real_va & 2)), data); + bus_write(16, pa | (real_va & 2), data); + else if (datatype == ARM_BYTE_TYPE) + //mem_write_byte (state, (pa | (real_va & 3)), data); + bus_write(8, (pa | (real_va & 3)), data); + return NO_FAULT; +} + +ARMword xscale_cp15_mrc (ARMul_State * state, + unsigned type, ARMword instr, ARMword * value) +{ + return xscale_mmu_mrc (state, instr, value); +} + +ARMword xscale_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value) +{ + ARMword data; + unsigned opcode_2 = BITS (5, 7); + unsigned CRm = BITS (0, 3); + unsigned reg = BITS (16, 19); + unsigned result; + mmu_regnum_t creg = (mmu_regnum_t)reg; + +/* + printf("SKYEYE: xscale_cp15_mrc:opcode_2 0x%x, CRm 0x%x, reg 0x%x,reg[15] 0x%x, instr %x\n",opcode_2,CRm,reg,\ + state->Reg[15], instr); +*/ + switch (creg) { + case MMU_ID: //XSCALE_CP15 + //printf("mmu_mrc read ID \n"); + data = (opcode_2 ? state->mmu.cache_type : state->cpu-> + cpu_val); + break; + case MMU_CONTROL: //XSCALE_CP15_AUX_CONTROL + //printf("mmu_mrc read CONTROL \n"); + data = (opcode_2 ? state->mmu.aux_control : state->mmu. + control); + break; + case MMU_TRANSLATION_TABLE_BASE: + //printf("mmu_mrc read TTB \n"); + data = state->mmu.translation_table_base; + break; + case MMU_DOMAIN_ACCESS_CONTROL: + //printf("mmu_mrc read DACR \n"); + data = state->mmu.domain_access_control; + break; + case MMU_FAULT_STATUS: + //printf("mmu_mrc read FSR \n"); + data = state->mmu.fault_status; + break; + case MMU_FAULT_ADDRESS: + //printf("mmu_mrc read FAR \n"); + data = state->mmu.fault_address; + break; + case MMU_PID: + //printf("mmu_mrc read PID \n"); + data = state->mmu.process_id; + case XSCALE_CP15_COPRO_ACCESS: + //printf("xscale cp15 read coprocessor access\n"); + data = state->mmu.copro_access; + break; + default: + data = 0; + printf ("SKYEYE: xscale_cp15_mrc read UNKNOWN - reg %d, pc 0x%x\n", creg, state->Reg[15]); + // skyeye_exit (-1); + break; + } + *value = data; + //printf("SKYEYE: xscale_cp15_mrc:end value 0x%x\n",data); + return ARMul_DONE; +} + +void xscale_cp15_cache_ops (ARMul_State * state, ARMword instr, ARMword value) +{ +//chy: 2003-08-24 now, the BTB isn't simualted ....???? + + unsigned CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + //err_msg("SKYEYE: xscale cp15_cache_ops:OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm,state->Reg[15]); + + if (OPC_2 == 0 && CRm == 7) { + mmu_cache_invalidate_all (state, I_CACHE ()); + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + return; + } + + if (OPC_2 == 0 && CRm == 5) { + mmu_cache_invalidate_all (state, I_CACHE ()); + return; + } + if (OPC_2 == 1 && CRm == 5) { + mmu_cache_invalidate (state, I_CACHE (), value); + return; + } + + if (OPC_2 == 0 && CRm == 6) { + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + return; + } + + if (OPC_2 == 1 && CRm == 6) { + mmu_cache_invalidate (state, MAIN_D_CACHE (), value); + return; + } + + if (OPC_2 == 1 && CRm == 0xa) { + mmu_cache_clean (state, MAIN_D_CACHE (), value); + return; + } + + if (OPC_2 == 4 && CRm == 0xa) { + mmu_wb_drain_all (state, WB ()); + return; + } + + if (OPC_2 == 6 && CRm == 5) { + //chy 2004-07-19 shoud fix in the future????!!!! + //printf("SKYEYE: xscale_cp15_cache_ops:invalidate BTB CANT!!!!!!!!!!\n"); + //exit(-1); + return; + } + + if (OPC_2 == 5 && CRm == 2) { + //printf("SKYEYE: cp15_c_o: A L in D C, value %x, reg15 %x\n",value, state->Reg[15]); + //exit(-1); + //chy 2003-09-01 for test + mmu_cache_invalidate_all (state, MAIN_D_CACHE ()); + return; + } + + ERROR_LOG(ARM11, "SKYEYE: xscale cp15_cache_ops:Unknown OPC_2 = 0x%x CRm = 0x%x, Reg15 0x%x\n", OPC_2, CRm, state->Reg[15]); + // skyeye_exit (-1); +} + +static void + xscale_cp15_tlb_ops (ARMul_State * state, ARMword instr, + ARMword value) +{ + int CRm, OPC_2; + + CRm = BITS (0, 3); + OPC_2 = BITS (5, 7); + + + //err_msg("SKYEYE:xscale_cp15_tlb_ops:OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm,state->Reg[15]); + if (OPC_2 == 0 && CRm == 0x7) { + mmu_tlb_invalidate_all (state, I_TLB ()); + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 0 && CRm == 0x5) { + mmu_tlb_invalidate_all (state, I_TLB ()); + return; + } + + if (OPC_2 == 1 && CRm == 0x5) { + mmu_tlb_invalidate_entry (state, I_TLB (), value); + return; + } + + if (OPC_2 == 0 && CRm == 0x6) { + mmu_tlb_invalidate_all (state, D_TLB ()); + return; + } + + if (OPC_2 == 1 && CRm == 0x6) { + mmu_tlb_invalidate_entry (state, D_TLB (), value); + return; + } + + ERROR_LOG(ARM11, "SKYEYE:xscale_cp15_tlb_ops:Unknow OPC_2 = 0x%x CRm = 0x%x,Reg[15] 0x%x\n", OPC_2, CRm, state->Reg[15]); + // skyeye_exit (-1); +} + + +ARMword xscale_cp15_mcr (ARMul_State * state, + unsigned type, ARMword instr, ARMword value) +{ + return xscale_mmu_mcr (state, instr, value); +} + +ARMword xscale_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value) +{ + ARMword data; + unsigned opcode_2 = BITS (5, 7); + unsigned CRm = BITS (0, 3); + unsigned reg = BITS (16, 19); + unsigned result; + mmu_regnum_t creg = (mmu_regnum_t)reg; + + //printf("SKYEYE: xscale_cp15_mcr: opcode_2 0x%x, CRm 0x%x, reg ox%x, value 0x%x, reg[15] 0x%x, instr 0x%x\n",opcode_2,CRm,reg, value, state->Reg[15], instr); + + switch (creg) { + case MMU_CONTROL: + //printf("mmu_mcr wrote CONTROL val 0x%x \n",value); + state->mmu.control = + (opcode_2 ? (value & 0x33) : (value & 0x3FFF)); + break; + case MMU_TRANSLATION_TABLE_BASE: + //printf("mmu_mcr wrote TTB val 0x%x \n",value); + state->mmu.translation_table_base = value & 0xFFFFC000; + break; + case MMU_DOMAIN_ACCESS_CONTROL: + //printf("mmu_mcr wrote DACR val 0x%x \n",value); + state->mmu.domain_access_control = value; + break; + + case MMU_FAULT_STATUS: + //printf("mmu_mcr wrote FS val 0x%x \n",value); + state->mmu.fault_status = value & 0x6FF; + break; + case MMU_FAULT_ADDRESS: + //printf("mmu_mcr wrote FA val 0x%x \n",value); + state->mmu.fault_address = value; + break; + + case MMU_CACHE_OPS: +// printf("mmu_mcr wrote CO val 0x%x \n",value); + xscale_cp15_cache_ops (state, instr, value); + break; + case MMU_TLB_OPS: + //printf("mmu_mcr wrote TO val 0x%x \n",value); + xscale_cp15_tlb_ops (state, instr, value); + break; + case MMU_PID: + //printf("mmu_mcr wrote PID val 0x%x \n",value); + state->mmu.process_id = value & 0xfe000000; + break; + case XSCALE_CP15_COPRO_ACCESS: + //printf("xscale cp15 write coprocessor access val 0x %x\n",value); + state->mmu.copro_access = value & 0x3ff; + break; + + default: + printf ("SKYEYE: xscale_cp15_mcr wrote UNKNOWN - reg %d, reg15 0x%x\n", creg, state->Reg[15]); + break; + } + //printf("SKYEYE: xscale_cp15_mcr wrote val 0x%x\n", value); + return 0; +} + +//teawater add for arm2x86 2005.06.24------------------------------------------- +static int xscale_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, + ARMword * phys_addr) +{ + fault_t fault; + tlb_entry_t *tlb; + + virt_addr = mmu_pid_va_map (virt_addr); + if (MMU_Enabled) { + + /*align check */ + if ((virt_addr & (WORD_SIZE - 1)) && MMU_Aligned) { + DEBUG_LOG(ARM11, "align\n"); + return ALIGNMENT_FAULT; + } + else + virt_addr &= ~(WORD_SIZE - 1); + + /*translate tlb */ + fault = translate (state, virt_addr, I_TLB (), &tlb); + if (fault) { + DEBUG_LOG(ARM11, "translate\n"); + return fault; + } + + /*check access */ + fault = check_access (state, virt_addr, tlb, 1); + if (fault) { + DEBUG_LOG(ARM11, "check_fault\n"); + return fault; + } + } + + if (MMU_Disabled) { + *phys_addr = virt_addr; + } + else { + *phys_addr = tlb_va_to_pa (tlb, virt_addr); + } + + return (0); +} + +//AJ2D-------------------------------------------------------------------------- + +/*xscale mmu_ops_t*/ +mmu_ops_t xscale_mmu_ops = { + xscale_cp15_init, + xscale_cp15_exit, + xscale_mmu_read_byte, + xscale_mmu_write_byte, + xscale_mmu_read_halfword, + xscale_mmu_write_halfword, + xscale_mmu_read_word, + xscale_mmu_write_word, + xscale_mmu_load_instr, xscale_mmu_mcr, xscale_mmu_mrc, +//teawater add for arm2x86 2005.06.24------------------------------------------- + xscale_mmu_v2p_dbct, +//AJ2D-------------------------------------------------------------------------- +}; diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 1aaf28eee..02d0387af 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -146,12 +146,18 @@ <ClCompile Include="arm\interpreter\armsupp.cpp" /> <ClCompile Include="arm\interpreter\armvirt.cpp" /> <ClCompile Include="arm\interpreter\arm_interpreter.cpp" /> + <ClCompile Include="arm\interpreter\mmu\arm1176jzf_s_mmu.cpp" /> + <ClCompile Include="arm\interpreter\mmu\cache.cpp" /> + <ClCompile Include="arm\interpreter\mmu\rb.cpp" /> + <ClCompile Include="arm\interpreter\mmu\sa_mmu.cpp" /> + <ClCompile Include="arm\interpreter\mmu\tlb.cpp" /> + <ClCompile Include="arm\interpreter\mmu\wb.cpp" /> + <ClCompile Include="arm\interpreter\mmu\xscale_copro.cpp" /> <ClCompile Include="arm\interpreter\thumbemu.cpp" /> <ClCompile Include="arm\interpreter\vfp\vfp.cpp" /> <ClCompile Include="arm\interpreter\vfp\vfpdouble.cpp" /> <ClCompile Include="arm\interpreter\vfp\vfpinstr.cpp" /> <ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp" /> - <ClCompile Include="arm\mmu\arm1176jzf_s_mmu.cpp" /> <ClCompile Include="core.cpp" /> <ClCompile Include="core_timing.cpp" /> <ClCompile Include="elf\elf_reader.cpp" /> @@ -185,15 +191,16 @@ <ClInclude Include="arm\interpreter\armos.h" /> <ClInclude Include="arm\interpreter\arm_interpreter.h" /> <ClInclude Include="arm\interpreter\arm_regformat.h" /> + <ClInclude Include="arm\interpreter\mmu\arm1176jzf_s_mmu.h" /> + <ClInclude Include="arm\interpreter\mmu\cache.h" /> + <ClInclude Include="arm\interpreter\mmu\rb.h" /> + <ClInclude Include="arm\interpreter\mmu\sa_mmu.h" /> + <ClInclude Include="arm\interpreter\mmu\tlb.h" /> + <ClInclude Include="arm\interpreter\mmu\wb.h" /> <ClInclude Include="arm\interpreter\skyeye_defs.h" /> <ClInclude Include="arm\interpreter\vfp\asm_vfp.h" /> <ClInclude Include="arm\interpreter\vfp\vfp.h" /> <ClInclude Include="arm\interpreter\vfp\vfp_helper.h" /> - <ClInclude Include="arm\mmu\arm1176jzf_s_mmu.h" /> - <ClInclude Include="arm\mmu\cache.h" /> - <ClInclude Include="arm\mmu\rb.h" /> - <ClInclude Include="arm\mmu\tlb.h" /> - <ClInclude Include="arm\mmu\wb.h" /> <ClInclude Include="core.h" /> <ClInclude Include="core_timing.h" /> <ClInclude Include="elf\elf_reader.h" /> diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 7436b9ed0..dba6b6f67 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -7,9 +7,6 @@ <Filter Include="arm\disassembler"> <UniqueIdentifier>{61100188-a726-4024-ab16-95ee242b446e}</UniqueIdentifier> </Filter> - <Filter Include="arm\mmu"> - <UniqueIdentifier>{a64d3c8a-747a-491b-b782-6e2622bedf24}</UniqueIdentifier> - </Filter> <Filter Include="file_sys"> <UniqueIdentifier>{7f618562-73d1-4f55-9628-887497c27654}</UniqueIdentifier> </Filter> @@ -31,6 +28,9 @@ <Filter Include="arm\interpreter\vfp"> <UniqueIdentifier>{de62238f-a28e-4a33-8495-23fed6784588}</UniqueIdentifier> </Filter> + <Filter Include="arm\interpreter\mmu"> + <UniqueIdentifier>{13ef9860-2ba0-47e9-a93d-b4052adab269}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClCompile Include="arm\disassembler\arm_disasm.cpp"> @@ -60,9 +60,6 @@ <ClCompile Include="arm\interpreter\thumbemu.cpp"> <Filter>arm\interpreter</Filter> </ClCompile> - <ClCompile Include="arm\mmu\arm1176jzf_s_mmu.cpp"> - <Filter>arm\mmu</Filter> - </ClCompile> <ClCompile Include="file_sys\directory_file_system.cpp"> <Filter>file_sys</Filter> </ClCompile> @@ -129,6 +126,27 @@ <ClCompile Include="arm\interpreter\vfp\vfpsingle.cpp"> <Filter>arm\interpreter\vfp</Filter> </ClCompile> + <ClCompile Include="arm\interpreter\mmu\arm1176jzf_s_mmu.cpp"> + <Filter>arm\interpreter\mmu</Filter> + </ClCompile> + <ClCompile Include="arm\interpreter\mmu\xscale_copro.cpp"> + <Filter>arm\interpreter\mmu</Filter> + </ClCompile> + <ClCompile Include="arm\interpreter\mmu\sa_mmu.cpp"> + <Filter>arm\interpreter\mmu</Filter> + </ClCompile> + <ClCompile Include="arm\interpreter\mmu\cache.cpp"> + <Filter>arm\interpreter\mmu</Filter> + </ClCompile> + <ClCompile Include="arm\interpreter\mmu\rb.cpp"> + <Filter>arm\interpreter\mmu</Filter> + </ClCompile> + <ClCompile Include="arm\interpreter\mmu\tlb.cpp"> + <Filter>arm\interpreter\mmu</Filter> + </ClCompile> + <ClCompile Include="arm\interpreter\mmu\wb.cpp"> + <Filter>arm\interpreter\mmu</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <ClInclude Include="arm\disassembler\arm_disasm.h"> @@ -158,21 +176,6 @@ <ClInclude Include="arm\interpreter\skyeye_defs.h"> <Filter>arm\interpreter</Filter> </ClInclude> - <ClInclude Include="arm\mmu\arm1176jzf_s_mmu.h"> - <Filter>arm\mmu</Filter> - </ClInclude> - <ClInclude Include="arm\mmu\cache.h"> - <Filter>arm\mmu</Filter> - </ClInclude> - <ClInclude Include="arm\mmu\rb.h"> - <Filter>arm\mmu</Filter> - </ClInclude> - <ClInclude Include="arm\mmu\tlb.h"> - <Filter>arm\mmu</Filter> - </ClInclude> - <ClInclude Include="arm\mmu\wb.h"> - <Filter>arm\mmu</Filter> - </ClInclude> <ClInclude Include="file_sys\directory_file_system.h"> <Filter>file_sys</Filter> </ClInclude> @@ -247,6 +250,24 @@ <ClInclude Include="arm\interpreter\vfp\vfp_helper.h"> <Filter>arm\interpreter\vfp</Filter> </ClInclude> + <ClInclude Include="arm\interpreter\mmu\arm1176jzf_s_mmu.h"> + <Filter>arm\interpreter\mmu</Filter> + </ClInclude> + <ClInclude Include="arm\interpreter\mmu\cache.h"> + <Filter>arm\interpreter\mmu</Filter> + </ClInclude> + <ClInclude Include="arm\interpreter\mmu\rb.h"> + <Filter>arm\interpreter\mmu</Filter> + </ClInclude> + <ClInclude Include="arm\interpreter\mmu\tlb.h"> + <Filter>arm\interpreter\mmu</Filter> + </ClInclude> + <ClInclude Include="arm\interpreter\mmu\wb.h"> + <Filter>arm\interpreter\mmu</Filter> + </ClInclude> + <ClInclude Include="arm\interpreter\mmu\sa_mmu.h"> + <Filter>arm\interpreter\mmu</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <Text Include="CMakeLists.txt" /> |