📄 arm7100_mmu.c
字号:
/* 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 "armdefs.h"#ifdef CACHE#undef CACHE#endif /* */#ifdef TLB#undef TLB#endif /* */#define CACHE() (&state->mmu.u.arm7100_mmu.cache_t)#define TLB() (&state->mmu.u.arm7100_mmu.tlb_t)static fault_t a71_mmu_read (ARMul_State * state, ARMword virt_addr, ARMword * data, ARMword datatype);static fault_t a71_mmu_write (ARMul_State * state, ARMword virt_addr, ARMword data, ARMword datatype);static inta71_mmu_init (ARMul_State * state){ 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; if (mmu_cache_init (CACHE (), 16, 4, 128, CACHE_WRITE_THROUGH)) { err_msg ("cache init %d\n", -1); goto cache_error; } if (mmu_tlb_init (TLB (), 64)) { err_msg ("tlb init %d\n", -1); goto tlb_error; }; return 0; tlb_error:mmu_cache_exit (CACHE ()); cache_error:return -1;}static voida71_mmu_exit (ARMul_State * state){ mmu_cache_exit (CACHE ()); mmu_tlb_exit (TLB ());} static fault_ta71_mmu_read_byte (ARMul_State * state, ARMword virt_addr, ARMword * data){ //ARMword temp,offset; fault_t fault; fault = a71_mmu_read (state, virt_addr, data, ARM_BYTE_TYPE); return fault;}static fault_ta71_mmu_read_halfword (ARMul_State * state, ARMword virt_addr, ARMword * data){ //ARMword temp,offset; fault_t fault; fault = a71_mmu_read (state, virt_addr, data, ARM_HALFWORD_TYPE); return fault;}static fault_ta71_mmu_read_word (ARMul_State * state, ARMword virt_addr, ARMword * data){ return a71_mmu_read (state, virt_addr, data, ARM_WORD_TYPE);}static fault_ta71_mmu_read (ARMul_State * state, ARMword virt_addr, ARMword * data, ARMword datatype){ tlb_entry_t *tlb; ARMword phys_addr; ARMword temp, offset; fault_t fault; if (!(state->mmu.control & CONTROL_MMU)) {// *data = mem_read_word(state, virt_addr);//#if 0 if (datatype == ARM_BYTE_TYPE) *data = mem_read_byte (state, virt_addr); else if (datatype == ARM_HALFWORD_TYPE) *data = mem_read_halfword (state, virt_addr); else if (datatype == ARM_WORD_TYPE) *data = mem_read_word (state, virt_addr); else { printf ("SKYEYE:1 a71_mmu_read error: unknown data type %d\n", datatype); skyeye_exit (-1); }//#endif return NO_FAULT; }#if 0/* XXX */ if (hack && (virt_addr >= 0xc0000000) && (virt_addr < 0xc0200000)) { printf ("0x%08x\n", virt_addr); }#endif /* */ if ((virt_addr & 3) && (datatype == ARM_WORD_TYPE) && (state->mmu.control & CONTROL_ALIGN_FAULT) || (virt_addr & 1) && (datatype == ARM_HALFWORD_TYPE) && (state->mmu.control & CONTROL_ALIGN_FAULT)) { fprintf (stderr, "SKYEYE, a71_mmu_read ALIGNMENT_FAULT\n"); return ALIGNMENT_FAULT; } if (state->mmu.control & CONTROL_CACHE) { cache_line_t *cache; cache = mmu_cache_search (state, CACHE (), virt_addr); if (cache) { if (datatype == ARM_WORD_TYPE) *data = cache->data[(virt_addr >> 2) & 3]; else if (datatype == ARM_HALFWORD_TYPE) { temp = cache->data[(virt_addr >> 2) & 3]; offset = (((ARMword) state->bigendSig * 2) ^ (virt_addr & 2)) << 3; /* bit offset into the word */ *data = (temp >> offset) & 0xffff; } else if (datatype == ARM_BYTE_TYPE) { temp = cache->data[(virt_addr >> 2) & 3]; offset = (((ARMword) state->bigendSig * 3) ^ (virt_addr & 3)) << 3; /* bit offset into the word */ *data = (temp >> offset & 0xffL); } return NO_FAULT; } } fault = translate (state, virt_addr, TLB (), &tlb); if (fault) { return fault; } fault = check_access (state, virt_addr, tlb, 1); if (fault) { return fault; } phys_addr = (tlb->phys_addr & tlb_masks[tlb->mapping]) | (virt_addr & ~tlb_masks[tlb->mapping]); /* allocate to the cache if cacheable */ if ((tlb->perms & 0x08) && (state->mmu.control & CONTROL_CACHE)) { cache_line_t *cache; ARMword fetch; int i; cache = mmu_cache_alloc (state, CACHE (), virt_addr, 0); fetch = phys_addr & 0xFFFFFFF0; for (i = 0; i < 4; i++) { cache->data[i] = mem_read_word (state, fetch); fetch += 4; } cache->tag = va_cache_align (virt_addr, CACHE ()) | TAG_VALID_FLAG; //*data = cache->data[(virt_addr >> 2) & 3]; if (datatype == ARM_WORD_TYPE) *data = cache->data[(virt_addr >> 2) & 3]; else if (datatype == ARM_HALFWORD_TYPE) { temp = cache->data[(virt_addr >> 2) & 3]; offset = (((ARMword) state->bigendSig * 2) ^ (virt_addr & 2)) << 3; /* bit offset into the word */ *data = (temp >> offset) & 0xffff; } else if (datatype == ARM_BYTE_TYPE) { temp = cache->data[(virt_addr >> 2) & 3]; offset = (((ARMword) state->bigendSig * 3) ^ (virt_addr & 3)) << 3; /* bit offset into the word */ *data = (temp >> offset & 0xffL); } return NO_FAULT; } else { if (datatype == ARM_BYTE_TYPE) *data = mem_read_byte (state, phys_addr); else if (datatype == ARM_HALFWORD_TYPE) *data = mem_read_halfword (state, phys_addr); else if (datatype == ARM_WORD_TYPE) *data = mem_read_word (state, phys_addr); else { printf ("SKYEYE:2 a71_mmu_read error: unknown data type %d\n", datatype); skyeye_exit (-1); } return NO_FAULT; }}static fault_ta71_mmu_write_byte (ARMul_State * state, ARMword virt_addr, ARMword data){ return a71_mmu_write (state, virt_addr, data, ARM_BYTE_TYPE);}static fault_ta71_mmu_write_halfword (ARMul_State * state, ARMword virt_addr, ARMword data){ return a71_mmu_write (state, virt_addr, data, ARM_HALFWORD_TYPE);}static fault_ta71_mmu_write_word (ARMul_State * state, ARMword virt_addr, ARMword data){ return a71_mmu_write (state, virt_addr, data, ARM_WORD_TYPE);}static fault_ta71_mmu_write (ARMul_State * state, ARMword virt_addr, ARMword data, ARMword datatype){ tlb_entry_t *tlb; ARMword phys_addr; fault_t fault; ARMword temp, offset; if (!(state->mmu.control & CONTROL_MMU)) { if (datatype == ARM_BYTE_TYPE) mem_write_byte (state, virt_addr, data); else if (datatype == ARM_HALFWORD_TYPE) mem_write_halfword (state, virt_addr, data); else if (datatype == ARM_WORD_TYPE) mem_write_word (state, virt_addr, data); else { printf ("SKYEYE:1 a71_mmu_write error: unknown data type %d\n", datatype); skyeye_exit (-1); } return NO_FAULT; }// if ((virt_addr & 3) && (state->mmu.control & CONTROL_ALIGN_FAULT)) { if ((virt_addr & 3) && (datatype == ARM_WORD_TYPE) && (state->mmu.control & CONTROL_ALIGN_FAULT) || (virt_addr & 1) && (datatype == ARM_HALFWORD_TYPE) && (state->mmu.control & CONTROL_ALIGN_FAULT)) { fprintf (stderr, "SKYEYE, a71_mmu_write ALIGNMENT_FAULT\n"); return ALIGNMENT_FAULT; } if (state->mmu.control & CONTROL_CACHE) { cache_line_t *cache; cache = mmu_cache_search (state, CACHE (), virt_addr); if (cache) { if (datatype == ARM_WORD_TYPE) cache->data[(virt_addr >> 2) & 3] = data; else if (datatype == ARM_HALFWORD_TYPE) { temp = cache->data[(virt_addr >> 2) & 3]; offset = (((ARMword) state->bigendSig * 2) ^ (virt_addr & 2)) << 3; /* bit offset into the word */ cache->data[(virt_addr >> 2) & 3] = (temp & ~(0xffffL << offset)) | ((data & 0xffffL) << offset); } else if (datatype == ARM_BYTE_TYPE) { temp = cache->data[(virt_addr >> 2) & 3]; offset = (((ARMword) state->bigendSig * 3) ^ (virt_addr & 3)) << 3; /* bit offset into the word */ cache->data[(virt_addr >> 2) & 3] = (temp & ~(0xffL << offset)) | ((data & 0xffL) << offset); } } } fault = translate (state, virt_addr, TLB (), &tlb); if (fault) { return fault; } fault = check_access (state, virt_addr, tlb, 0); if (fault) { return fault; } phys_addr = (tlb->phys_addr & tlb_masks[tlb->mapping]) | (virt_addr & ~tlb_masks[tlb->mapping]); if (datatype == ARM_BYTE_TYPE) mem_write_byte (state, phys_addr, data); else if (datatype == ARM_HALFWORD_TYPE) mem_write_halfword (state, phys_addr, data); else if (datatype == ARM_WORD_TYPE) mem_write_word (state, phys_addr, data); else { printf ("SKYEYE:2 a71_mmu_write error: unknown data type %d \n", datatype); skyeye_exit (-1); } return NO_FAULT;}static ARMworda71_mmu_mrc (ARMul_State * state, ARMword instr, ARMword * value){ mmu_regnum_t creg = BITS (16, 19) & 15; ARMword data; switch (creg) { case MMU_ID:// printf("mmu_mrc read ID ");#if 0#ifdef MMU_V4 data = 0x41018100; /* v4 */#else /* */ data = 0x41007100; /* v3 */#endif /* */#endif /* */ //data = 0x41007100; 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; 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;}static voida71_mmu_mcr (ARMul_State * state, ARMword instr, ARMword value){ mmu_regnum_t creg = 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) & 0xFFFF; 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;//#ifdef MMU_V4 case MMU_FAULT_STATUS: state->mmu.fault_status = value & 0xFF; break; case MMU_FAULT_ADDRESS: state->mmu.fault_address = value; break; case MMU_V4_CACHE_OPS: /* incomplete */ if ((BITS (5, 7) & 7) == 0) { mmu_cache_invalidate_all (state, CACHE ()); } break; case MMU_V4_TLB_OPS: /* incomplete */ switch (BITS (5, 7) & 7) { case 0: mmu_tlb_invalidate_all (state, TLB ()); break; case 1: mmu_tlb_invalidate_entry (state, TLB (), value); break; } break; default: printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); break; }//#else } else { switch (creg) { case MMU_CONTROL: state->mmu.control = (value | 0x70) & 0xFFFF; break; case MMU_TRANSLATION_TABLE_BASE: state->mmu.translation_table_base = value & 0xFFFFC000; break; case MMU_DOMAIN_ACCESS_CONTROL: state->mmu.domain_access_control = value; break; case MMU_V3_FLUSH_TLB:// printf("mmu_mcr wrote FLUSH_TLB "); mmu_tlb_invalidate_all (state, TLB ()); break; case MMU_V3_FLUSH_TLB_ENTRY:// printf("mmu_mcr wrote FLUSH_TLB_ENTRY"); mmu_tlb_invalidate_entry (state, TLB (), value); break; case MMU_V3_FLUSH_CACHE:// printf("mmu_mcr wrote FLUSH_CACHE "); mmu_cache_invalidate_all (state, CACHE ()); break; default: printf ("mmu_mcr wrote UNKNOWN - reg %d\n", creg); break;//#endif } }// printf("\t\t\t\tpc = 0x%08x\n", state->Reg[15]);}static inta71_mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr){ tlb_entry_t *tlb; ARMword temp, offset; fault_t fault; ARMword datatype = ARM_WORD_TYPE; int ret = -1; if ((virt_addr & 3) && (datatype == ARM_WORD_TYPE) && (state->mmu.control & CONTROL_ALIGN_FAULT) || (virt_addr & 1) && (datatype == ARM_HALFWORD_TYPE) && (state->mmu.control & CONTROL_ALIGN_FAULT)) { fprintf (stderr, "SKYEYE, a71_mmu_read ALIGNMENT_FAULT\n"); goto out; } if (!(state->mmu.control & CONTROL_MMU)) { *phys_addr = virt_addr; } else { fault = translate (state, virt_addr, TLB (), &tlb); if (fault) { goto out; } fault = check_access (state, virt_addr, tlb, 1); if (fault) { goto out; } *phys_addr = (tlb->phys_addr & tlb_masks[tlb->mapping]) | (virt_addr & ~tlb_masks[tlb->mapping]); } ret = 0; out:return (ret);}#undef CACHE#undef TLBmmu_ops_t arm7100_mmu_ops = { a71_mmu_init, a71_mmu_exit, a71_mmu_read_byte, a71_mmu_write_byte, a71_mmu_read_halfword, a71_mmu_write_halfword, a71_mmu_read_word, a71_mmu_write_word, a71_mmu_read_word, // load instr a71_mmu_mcr, a71_mmu_mrc, a71_mmu_v2p_dbct // ywc 2005-04-16 test};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -