Skip to content
Snippets Groups Projects
Commit 9a642cae authored by bunnei's avatar bunnei
Browse files

added missing skyeye mmu code

parent 56846a42
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
......@@ -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);
......
#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;
}
#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]);
};
}
/*
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--------------------------------------------------------------------------
};
/*
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_*/
#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;
}
......@@ -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);
......
#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--;
};
}
/*
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--------------------------------------------------------------------------
};
......@@ -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" />
......
......@@ -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" />
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment