diff options
author | bunnei <ericbunnie@gmail.com> | 2014-03-30 03:53:07 +0200 |
---|---|---|
committer | bunnei <ericbunnie@gmail.com> | 2014-03-30 03:53:07 +0200 |
commit | 6b255111d5c130e49846b1727302111f423cb157 (patch) | |
tree | 335ba0e8c06480b4f8f777651e83525ba647317f | |
parent | added a GetPointer function to Memory for use with ELF loading (diff) | |
download | yuzu-6b255111d5c130e49846b1727302111f423cb157.tar yuzu-6b255111d5c130e49846b1727302111f423cb157.tar.gz yuzu-6b255111d5c130e49846b1727302111f423cb157.tar.bz2 yuzu-6b255111d5c130e49846b1727302111f423cb157.tar.lz yuzu-6b255111d5c130e49846b1727302111f423cb157.tar.xz yuzu-6b255111d5c130e49846b1727302111f423cb157.tar.zst yuzu-6b255111d5c130e49846b1727302111f423cb157.zip |
-rw-r--r-- | src/core/core.vcxproj | 8 | ||||
-rw-r--r-- | src/core/core.vcxproj.filters | 20 | ||||
-rw-r--r-- | src/core/src/arm/armemu.cpp | 21 | ||||
-rw-r--r-- | src/core/src/arm/armemu.h | 15 | ||||
-rw-r--r-- | src/core/src/arm/arminit.cpp | 163 | ||||
-rw-r--r-- | src/core/src/arm/armmmu.cpp | 146 | ||||
-rw-r--r-- | src/core/src/arm/armos.cpp | 742 | ||||
-rw-r--r-- | src/core/src/arm/armsupp.cpp | 953 | ||||
-rw-r--r-- | src/core/src/arm/armvirt.cpp | 680 |
9 files changed, 2582 insertions, 166 deletions
diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index 9d6c28216..a774f9e4b 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -139,9 +139,14 @@ <ItemGroup> <ClCompile Include="src\arm\armemu.cpp" /> <ClCompile Include="src\arm\arminit.cpp" /> + <ClCompile Include="src\arm\armmmu.cpp" /> + <ClCompile Include="src\arm\armos.cpp" /> + <ClCompile Include="src\arm\armsupp.cpp" /> + <ClCompile Include="src\arm\armvirt.cpp" /> <ClCompile Include="src\arm\disassembler\arm_disasm.cpp" /> <ClCompile Include="src\core.cpp" /> <ClCompile Include="src\core_timing.cpp" /> + <ClCompile Include="src\elf\elf_reader.cpp" /> <ClCompile Include="src\file_sys\directory_file_system.cpp" /> <ClCompile Include="src\file_sys\meta_file_system.cpp" /> <ClCompile Include="src\loader.cpp" /> @@ -165,7 +170,8 @@ <ClInclude Include="src\arm\skyeye_defs.h" /> <ClInclude Include="src\core.h" /> <ClInclude Include="src\core_timing.h" /> - <ClInclude Include="src\elf\elf.h" /> + <ClInclude Include="src\elf\elf_reader.h" /> + <ClInclude Include="src\elf\elf_types.h" /> <ClInclude Include="src\file_sys\directory_file_system.h" /> <ClInclude Include="src\file_sys\file_sys.h" /> <ClInclude Include="src\file_sys\meta_file_system.h" /> diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index 4d1ec576c..50d0cbc71 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -22,6 +22,21 @@ </ClCompile> <ClCompile Include="src\system.cpp" /> <ClCompile Include="src\core_timing.cpp" /> + <ClCompile Include="src\elf\elf_reader.cpp"> + <Filter>elf</Filter> + </ClCompile> + <ClCompile Include="src\arm\armsupp.cpp"> + <Filter>arm</Filter> + </ClCompile> + <ClCompile Include="src\arm\armvirt.cpp"> + <Filter>arm</Filter> + </ClCompile> + <ClCompile Include="src\arm\armmmu.cpp"> + <Filter>arm</Filter> + </ClCompile> + <ClCompile Include="src\arm\armos.cpp"> + <Filter>arm</Filter> + </ClCompile> </ItemGroup> <ItemGroup> <Filter Include="arm"> @@ -94,7 +109,10 @@ </ClInclude> <ClInclude Include="src\system.h" /> <ClInclude Include="src\core_timing.h" /> - <ClInclude Include="src\elf\elf.h"> + <ClInclude Include="src\elf\elf_reader.h"> + <Filter>elf</Filter> + </ClInclude> + <ClInclude Include="src\elf\elf_types.h"> <Filter>elf</Filter> </ClInclude> </ItemGroup> diff --git a/src/core/src/arm/armemu.cpp b/src/core/src/arm/armemu.cpp index e5c287236..362ae0fd1 100644 --- a/src/core/src/arm/armemu.cpp +++ b/src/core/src/arm/armemu.cpp @@ -21,6 +21,19 @@ #include "armemu.h" #include "armos.h" +void +XScale_set_fsr_far(ARMul_State * state, ARMword fsr, ARMword _far) +{ + _dbg_assert_msg_(ARM11, false, "ImplementMe: XScale_set_fsr_far!"); + //if (!state->is_XScale || (read_cp14_reg(10) & (1UL << 31)) == 0) + // return; + // + //write_cp15_reg(state, 5, 0, 0, fsr); + //write_cp15_reg(state, 6, 0, 0, _far); +} + +#define ARMul_Debug(x,y,z) 0 // Disabling this /bunnei + //#include "skyeye_callback.h" //#include "skyeye_bus.h" //#include "sim_control.h" @@ -2174,10 +2187,10 @@ ARMul_Emulate26 (ARMul_State * state) (state, ARMul_CP15_R5_MMU_EXCPT, pc); - if (!XScale_debug_moe - (state, - ARMul_CP14_R10_MOE_BT)) - break; + //if (!XScale_debug_moe + // (state, + // ARMul_CP14_R10_MOE_BT)) + // break; // Disabled /bunnei } /* Force the next instruction to be refetched. */ diff --git a/src/core/src/arm/armemu.h b/src/core/src/arm/armemu.h index ae5c35aee..d4afa8e22 100644 --- a/src/core/src/arm/armemu.h +++ b/src/core/src/arm/armemu.h @@ -73,6 +73,7 @@ extern ARMword isize; #define ASSIGNT(res) state->TFlag = res #define INSN_SIZE (TFLAG ? 2 : 4) #else +#define TBIT (1L << 5) #define INSN_SIZE 4 #define TFLAG 0 #endif @@ -229,12 +230,12 @@ extern ARMword isize; } \ while (0) -#ifndef MODE32 +//#ifndef MODE32 #define VECTORS 0x20 #define LEGALADDR 0x03ffffff #define VECTORACCESS(address) (address < VECTORS && ARMul_MODE26BIT && state->prog32Sig) #define ADDREXCEPT(address) (address > LEGALADDR && !state->data32Sig) -#endif +//#endif #define INTERNALABORT(address) \ do \ @@ -409,10 +410,12 @@ extern ARMword isize; || (! (STATE)->is_XScale) \ || (read_cp15_reg (15, 0, 1) & (1 << (CP)))) */ -#define CP_ACCESS_ALLOWED(STATE, CP) \ - ( ((CP) >= 14) \ - || (! (STATE)->is_XScale) \ - || (xscale_cp15_cp_access_allowed(STATE,15,CP))) +//#define CP_ACCESS_ALLOWED(STATE, CP) \ +// (((CP) >= 14) \ +// || (!(STATE)->is_XScale) \ +// || (xscale_cp15_cp_access_allowed(STATE, 15, CP))) + +#define CP_ACCESS_ALLOWED(STATE, CP) false // Disabled coprocessor shit /bunnei /* Macro to rotate n right by b bits. */ #define ROTATER(n, b) (((n) >> (b)) | ((n) << (32 - (b)))) diff --git a/src/core/src/arm/arminit.cpp b/src/core/src/arm/arminit.cpp index 9327f8f6a..d394be66c 100644 --- a/src/core/src/arm/arminit.cpp +++ b/src/core/src/arm/arminit.cpp @@ -271,7 +271,7 @@ below line sould be in skyeye_mach_XXX.c 's XXX_mach_init function /* Only initialse the coprocessor support once we know what kind of chip we are dealing with. */ - ARMul_CoProInit (state); + //ARMul_CoProInit (state); Commented out /bunnei } @@ -318,7 +318,7 @@ ARMul_Reset (ARMul_State * state) state->NumFcycles = 0; //fprintf(stderr,"armul_reset 3: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); - mmu_reset (state); + //mmu_reset (state); Commented out /bunnei //fprintf(stderr,"armul_reset 4: state-> Cpsr 0x%x, Mode %d\n",state->Cpsr,state->Mode); //mem_reset (state); /* move to memory/ram.c */ @@ -436,7 +436,8 @@ ARMul_DoProg (ARMul_State * state) } else { - pc = ARMul_Emulate26 (state); + //pc = ARMul_Emulate26 (state); Commented out /bunnei + ERROR_LOG(ARM11, "Unsupported ARM 26-bit Mode!"); } //chy 2006-02-22, should test debugmode first //chy 2006-04-14, put below codes in ARMul_Emulate @@ -489,8 +490,10 @@ ARMul_DoInstr (ARMul_State * state) #endif } - else - pc = ARMul_Emulate26 (state); + else { + //pc = ARMul_Emulate26 (state); Commented out /bunnei + ERROR_LOG(ARM11, "Unsupported ARM 26-bit Mode!"); + } return (pc); } @@ -501,78 +504,78 @@ ARMul_DoInstr (ARMul_State * state) * appropriate vector's memory address (0,4,8 ....) * \***************************************************************************/ -//void -//ARMul_Abort (ARMul_State * state, ARMword vector) -//{ -// ARMword temp; -// int isize = INSN_SIZE; -// int esize = (TFLAG ? 0 : 4); -// int e2size = (TFLAG ? -4 : 0); -// -// state->Aborted = FALSE; -// -// if (state->prog32Sig) -// if (ARMul_MODE26BIT) -// temp = R15PC; -// else -// temp = state->Reg[15]; -// else -// temp = R15PC | ECC | ER15INT | EMODE; -// -// switch (vector) { -// case ARMul_ResetV: /* RESET */ -// SETABORT (INTBITS, state->prog32Sig ? SVC32MODE : SVC26MODE, -// 0); -// break; -// case ARMul_UndefinedInstrV: /* Undefined Instruction */ -// SETABORT (IBIT, state->prog32Sig ? UNDEF32MODE : SVC26MODE, -// isize); -// break; -// case ARMul_SWIV: /* Software Interrupt */ -// SETABORT (IBIT, state->prog32Sig ? SVC32MODE : SVC26MODE, -// isize); -// break; -// case ARMul_PrefetchAbortV: /* Prefetch Abort */ -// state->AbortAddr = 1; -// SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, -// esize); -// break; -// case ARMul_DataAbortV: /* Data Abort */ -// SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, -// e2size); -// break; -// case ARMul_AddrExceptnV: /* Address Exception */ -// SETABORT (IBIT, SVC26MODE, isize); -// break; -// case ARMul_IRQV: /* IRQ */ -// //chy 2003-09-02 the if sentence seems no use -//#if 0 -// if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) -// || (temp & ARMul_CP13_R0_IRQ)) -//#endif -// SETABORT (IBIT, -// state->prog32Sig ? IRQ32MODE : IRQ26MODE, -// esize); -// break; -// case ARMul_FIQV: /* FIQ */ -// //chy 2003-09-02 the if sentence seems no use -//#if 0 -// if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) -// || (temp & ARMul_CP13_R0_FIQ)) -//#endif -// SETABORT (INTBITS, -// state->prog32Sig ? FIQ32MODE : FIQ26MODE, -// esize); -// break; -// } -// -// if (ARMul_MODE32BIT) { -// if (state->mmu.control & CONTROL_VECTOR) -// vector += 0xffff0000; //for v4 high exception address -// if (state->vector_remap_flag) -// vector += state->vector_remap_addr; /* support some remap function in LPC processor */ -// ARMul_SetR15 (state, vector); -// } -// else -// ARMul_SetR15 (state, R15CCINTMODE | vector); -//} +void +ARMul_Abort (ARMul_State * state, ARMword vector) +{ + ARMword temp; + int isize = INSN_SIZE; + int esize = (TFLAG ? 0 : 4); + int e2size = (TFLAG ? -4 : 0); + + state->Aborted = FALSE; + + if (state->prog32Sig) + if (ARMul_MODE26BIT) + temp = R15PC; + else + temp = state->Reg[15]; + else + temp = R15PC | ECC | ER15INT | EMODE; + + switch (vector) { + case ARMul_ResetV: /* RESET */ + SETABORT (INTBITS, state->prog32Sig ? SVC32MODE : SVC26MODE, + 0); + break; + case ARMul_UndefinedInstrV: /* Undefined Instruction */ + SETABORT (IBIT, state->prog32Sig ? UNDEF32MODE : SVC26MODE, + isize); + break; + case ARMul_SWIV: /* Software Interrupt */ + SETABORT (IBIT, state->prog32Sig ? SVC32MODE : SVC26MODE, + isize); + break; + case ARMul_PrefetchAbortV: /* Prefetch Abort */ + state->AbortAddr = 1; + SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, + esize); + break; + case ARMul_DataAbortV: /* Data Abort */ + SETABORT (IBIT, state->prog32Sig ? ABORT32MODE : SVC26MODE, + e2size); + break; + case ARMul_AddrExceptnV: /* Address Exception */ + SETABORT (IBIT, SVC26MODE, isize); + break; + case ARMul_IRQV: /* IRQ */ + //chy 2003-09-02 the if sentence seems no use +#if 0 + if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) + || (temp & ARMul_CP13_R0_IRQ)) +#endif + SETABORT (IBIT, + state->prog32Sig ? IRQ32MODE : IRQ26MODE, + esize); + break; + case ARMul_FIQV: /* FIQ */ + //chy 2003-09-02 the if sentence seems no use +#if 0 + if (!state->is_XScale || !state->CPRead[13] (state, 0, &temp) + || (temp & ARMul_CP13_R0_FIQ)) +#endif + SETABORT (INTBITS, + state->prog32Sig ? FIQ32MODE : FIQ26MODE, + esize); + break; + } + + if (ARMul_MODE32BIT) { + if (state->mmu.control & CONTROL_VECTOR) + vector += 0xffff0000; //for v4 high exception address + if (state->vector_remap_flag) + vector += state->vector_remap_addr; /* support some remap function in LPC processor */ + ARMul_SetR15 (state, vector); + } + else + ARMul_SetR15 (state, R15CCINTMODE | vector); +} diff --git a/src/core/src/arm/armmmu.cpp b/src/core/src/arm/armmmu.cpp index 5ba81b52a..476f8051d 100644 --- a/src/core/src/arm/armmmu.cpp +++ b/src/core/src/arm/armmmu.cpp @@ -45,55 +45,51 @@ mmu_init (ARMul_State * state) state->mmu.process_id = 0; switch (state->cpu->cpu_val & state->cpu->cpu_mask) { - case SA1100: - case SA1110: - SKYEYE_INFO("SKYEYE: use sa11xx mmu ops\n"); - state->mmu.ops = sa_mmu_ops; - break; - case PXA250: - case PXA270: //xscale - SKYEYE_INFO ("SKYEYE: use xscale mmu ops\n"); - state->mmu.ops = xscale_mmu_ops; - break; - case 0x41807200: //arm720t - case 0x41007700: //arm7tdmi - case 0x41007100: //arm7100 - SKYEYE_INFO ( "SKYEYE: use arm7100 mmu ops\n"); - state->mmu.ops = arm7100_mmu_ops; - break; - case 0x41009200: - SKYEYE_INFO ("SKYEYE: use arm920t mmu ops\n"); - state->mmu.ops = arm920t_mmu_ops; - break; - case 0x41069260: - SKYEYE_INFO ("SKYEYE: use arm926ejs mmu ops\n"); - state->mmu.ops = arm926ejs_mmu_ops; - break; + //case SA1100: + //case SA1110: + // NOTICE_LOG(ARM11, "SKYEYE: use sa11xx mmu ops\n"); + // state->mmu.ops = sa_mmu_ops; + // break; + //case PXA250: + //case PXA270: //xscale + // NOTICE_LOG(ARM11, "SKYEYE: use xscale mmu ops\n"); + // state->mmu.ops = xscale_mmu_ops; + // break; + //case 0x41807200: //arm720t + //case 0x41007700: //arm7tdmi + //case 0x41007100: //arm7100 + // NOTICE_LOG(ARM11, "SKYEYE: use arm7100 mmu ops\n"); + // state->mmu.ops = arm7100_mmu_ops; + // break; + //case 0x41009200: + // NOTICE_LOG(ARM11, "SKYEYE: use arm920t mmu ops\n"); + // state->mmu.ops = arm920t_mmu_ops; + // break; + //case 0x41069260: + // NOTICE_LOG(ARM11, "SKYEYE: use arm926ejs mmu ops\n"); + // state->mmu.ops = arm926ejs_mmu_ops; + // break; /* case 0x560f5810: */ case 0x0007b000: - SKYEYE_INFO ("SKYEYE: use arm11jzf-s mmu ops\n"); - state->mmu.ops = arm1176jzf_s_mmu_ops; + NOTICE_LOG(ARM11, "SKYEYE: use arm11jzf-s mmu ops\n"); + //state->mmu.ops = arm1176jzf_s_mmu_ops; + _dbg_assert_msg_(ARM11, false, "ImplementMe: arm1176jzf_s_mmu_ops!"); break; - case 0xc090: - SKYEYE_INFO ("SKYEYE: use cortex_a9 mmu ops\n"); - state->mmu.ops = cortex_a9_mmu_ops; - break; default: - fprintf (stderr, + ERROR_LOG (ARM11, "SKYEYE: armmmu.c : mmu_init: unknown cpu_val&cpu_mask 0x%x\n", state->cpu->cpu_val & state->cpu->cpu_mask); - skyeye_exit (-1); break; }; ret = state->mmu.ops.init (state); state->mmu_inited = (ret == 0); /* initialize mmu_read and mmu_write for disassemble */ - skyeye_config_t *config = get_current_config(); - generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name); - arch_instance->mmu_read = arm_mmu_read; - arch_instance->mmu_write = arm_mmu_write; + //skyeye_config_t *config = get_current_config(); + //generic_arch_t *arch_instance = get_arch_instance(config->arch->arch_name); + //arch_instance->mmu_read = arm_mmu_read; + //arch_instance->mmu_write = arm_mmu_write; return ret; } @@ -201,41 +197,43 @@ mmu_v2p_dbct (ARMul_State * state, ARMword virt_addr, ARMword * phys_addr) return (MMU_OPS.v2p_dbct (state, virt_addr, phys_addr)); } -/* dis_mmu_read for disassemble */ -exception_t arm_mmu_read(short size, generic_address_t addr, uint32_t * value) -{ - ARMul_State *state; - ARM_CPU_State *cpu = get_current_cpu(); - state = &cpu->core[0]; - switch(size){ - case 8: - MMU_OPS.read_byte (state, addr, value); - break; - case 16: - case 32: - break; - default: - printf("In %s error size %d Line %d\n", __func__, size, __LINE__); - break; - } - return No_exp; -} -/* dis_mmu_write for disassemble */ -exception_t arm_mmu_write(short size, generic_address_t addr, uint32_t *value) -{ - ARMul_State *state; - ARM_CPU_State *cpu = get_current_cpu(); - state = &cpu->core[0]; - switch(size){ - case 8: - MMU_OPS.write_byte (state, addr, value); - break; - case 16: - case 32: - break; - default: - printf("In %s error size %d Line %d\n", __func__, size, __LINE__); - break; - } - return No_exp; -} +// +// +///* dis_mmu_read for disassemble */ +//exception_t arm_mmu_read(short size, uint32_t addr, uint32_t * value) +//{ +// ARMul_State *state; +// ARM_CPU_State *cpu = get_current_cpu(); +// state = &cpu->core[0]; +// switch(size){ +// case 8: +// MMU_OPS.read_byte (state, addr, value); +// break; +// case 16: +// case 32: +// break; +// default: +// ERROR_LOG(ARM11, "Error size %d", size); +// break; +// } +// return No_exp; +//} +///* dis_mmu_write for disassemble */ +//exception_t arm_mmu_write(short size, uint32_t addr, uint32_t *value) +//{ +// ARMul_State *state; +// ARM_CPU_State *cpu = get_current_cpu(); +// state = &cpu->core[0]; +// switch(size){ +// case 8: +// MMU_OPS.write_byte (state, addr, value); +// break; +// case 16: +// case 32: +// break; +// default: +// printf("In %s error size %d Line %d\n", __func__, size, __LINE__); +// break; +// } +// return No_exp; +//} diff --git a/src/core/src/arm/armos.cpp b/src/core/src/arm/armos.cpp new file mode 100644 index 000000000..43484ee5f --- /dev/null +++ b/src/core/src/arm/armos.cpp @@ -0,0 +1,742 @@ +/* armos.c -- ARMulator OS interface: ARM6 Instruction Emulator. + Copyright (C) 1994 Advanced RISC Machines Ltd. + + 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. */ + +/* This file contains a model of Demon, ARM Ltd's Debug Monitor, +including all the SWI's required to support the C library. The code in +it is not really for the faint-hearted (especially the abort handling +code), but it is a complete example. Defining NOOS will disable all the +fun, and definign VAILDATE will define SWI 1 to enter SVC mode, and SWI +0x11 to halt the emulator. */ + +//chy 2005-09-12 disable below line +//#include "config.h" + +#include <time.h> +#include <errno.h> +#include <string.h> +#include "skyeye_defs.h" +#ifndef __USE_LARGEFILE64 +#define __USE_LARGEFILE64 /* When use 64 bit large file need define it! for stat64*/ +#endif +#include <fcntl.h> +#include <sys/stat.h> + + +#ifndef O_RDONLY +#define O_RDONLY 0 +#endif +#ifndef O_WRONLY +#define O_WRONLY 1 +#endif +#ifndef O_RDWR +#define O_RDWR 2 +#endif +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#ifdef __STDC__ +#define unlink(s) remove(s) +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> /* For SEEK_SET etc */ +#endif + +#ifdef __riscos +extern int _fisatty (FILE *); +#define isatty_(f) _fisatty(f) +#else +#ifdef __ZTC__ +#include <io.h> +#define isatty_(f) isatty((f)->_file) +#else +#ifdef macintosh +#include <ioctl.h> +#define isatty_(f) (~ioctl ((f)->_file, FIOINTERACTIVE, NULL)) +#else +#define isatty_(f) isatty (fileno (f)) +#endif +#endif +#endif + +#include "armdefs.h" +#include "armos.h" +#include "armemu.h" + +#ifndef NOOS +#ifndef VALIDATE +/* #ifndef ASIM */ +//chy 2005-09-12 disable below line +//#include "armfpe.h" +/* #endif */ +#endif +#endif + +#define DUMP_SYSCALL 0 +#define dump(...) do { if (DUMP_SYSCALL) printf(__VA_ARGS__); } while(0) +//#define debug(...) printf(__VA_ARGS__); +#define debug(...) ; + +extern unsigned ARMul_OSHandleSWI (ARMul_State * state, ARMword number); + +#ifndef FOPEN_MAX +#define FOPEN_MAX 64 +#endif + +/***************************************************************************\ +* OS private Information * +\***************************************************************************/ + +unsigned arm_dyncom_SWI(ARMul_State * state, ARMword number) +{ + return ARMul_OSHandleSWI(state, number); +} + +//mmap_area_t *mmap_global = NULL; + +static int translate_open_mode[] = { + O_RDONLY, /* "r" */ + O_RDONLY + O_BINARY, /* "rb" */ + O_RDWR, /* "r+" */ + O_RDWR + O_BINARY, /* "r+b" */ + O_WRONLY + O_CREAT + O_TRUNC, /* "w" */ + O_WRONLY + O_BINARY + O_CREAT + O_TRUNC, /* "wb" */ + O_RDWR + O_CREAT + O_TRUNC, /* "w+" */ + O_RDWR + O_BINARY + O_CREAT + O_TRUNC, /* "w+b" */ + O_WRONLY + O_APPEND + O_CREAT, /* "a" */ + O_WRONLY + O_BINARY + O_APPEND + O_CREAT, /* "ab" */ + O_RDWR + O_APPEND + O_CREAT, /* "a+" */ + O_RDWR + O_BINARY + O_APPEND + O_CREAT /* "a+b" */ +}; +// +//static void +//SWIWrite0 (ARMul_State * state, ARMword addr) +//{ +// ARMword temp; +// +// //while ((temp = ARMul_ReadByte (state, addr++)) != 0) +// while(1){ +// mem_read(8, addr++, &temp); +// if(temp != 0) +// (void) fputc ((char) temp, stdout); +// else +// break; +// } +//} +// +//static void +//WriteCommandLineTo (ARMul_State * state, ARMword addr) +//{ +// ARMword temp; +// char *cptr = state->CommandLine; +// if (cptr == NULL) +// cptr = "\0"; +// do { +// temp = (ARMword) * cptr++; +// //ARMul_WriteByte (state, addr++, temp); +// mem_write(8, addr++, temp); +// } +// while (temp != 0); +//} +// +//static void +//SWIopen (ARMul_State * state, ARMword name, ARMword SWIflags) +//{ +// char dummy[2000]; +// int flags; +// int i; +// +// for (i = 0; (dummy[i] = ARMul_ReadByte (state, name + i)); i++); +// assert(SWIflags< (sizeof(translate_open_mode)/ sizeof(translate_open_mode[0]))); +// /* Now we need to decode the Demon open mode */ +// flags = translate_open_mode[SWIflags]; +// flags = SWIflags; +// +// /* Filename ":tt" is special: it denotes stdin/out */ +// if (strcmp (dummy, ":tt") == 0) { +// if (flags == O_RDONLY) /* opening tty "r" */ +// state->Reg[0] = 0; /* stdin */ +// else +// state->Reg[0] = 1; /* stdout */ +// } +// else { +// state->Reg[0] = (int) open (dummy, flags, 0666); +// } +//} +// +//static void +//SWIread (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) +//{ +// int res; +// int i; +// char *local = (char*) malloc (len); +// +// if (local == NULL) { +// fprintf (stderr, +// "sim: Unable to read 0x%ulx bytes - out of memory\n", +// len); +// return; +// } +// +// res = read (f, local, len); +// if (res > 0) +// for (i = 0; i < res; i++) +// //ARMul_WriteByte (state, ptr + i, local[i]); +// mem_write(8, ptr + i, local[i]); +// free (local); +// //state->Reg[0] = res == -1 ? -1 : len - res; +// state->Reg[0] = res; +//} +// +//static void +//SWIwrite (ARMul_State * state, ARMword f, ARMword ptr, ARMword len) +//{ +// int res; +// ARMword i; +// char *local = malloc (len); +// +// if (local == NULL) { +// fprintf (stderr, +// "sim: Unable to write 0x%lx bytes - out of memory\n", +// (long unsigned int) len); +// return; +// } +// +// for (i = 0; i < len; i++){ +// //local[i] = ARMul_ReadByte (state, ptr + i); +// ARMword data; +// mem_read(8, ptr + i, &data); +// local[i] = data & 0xFF; +// } +// +// res = write (f, local, len); +// //state->Reg[0] = res == -1 ? -1 : len - res; +// state->Reg[0] = res; +// free (local); +//} + +//static void +//SWIflen (ARMul_State * state, ARMword fh) +//{ +// ARMword addr; +// +// if (fh == 0 || fh > FOPEN_MAX) { +// state->Reg[0] = -1L; +// return; +// } +// +// addr = lseek (fh, 0, SEEK_CUR); +// +// state->Reg[0] = lseek (fh, 0L, SEEK_END); +// (void) lseek (fh, addr, SEEK_SET); +// +//} + +/***************************************************************************\ +* The emulator calls this routine when a SWI instruction is encuntered. The * +* parameter passed is the SWI number (lower 24 bits of the instruction). * +\***************************************************************************/ +/* ahe-ykl information is retrieved from elf header and the starting value of + brk_static is in sky_info_t */ + +/* brk static hold the value of brk */ +static uint32_t brk_static = -1; + +unsigned +ARMul_OSHandleSWI (ARMul_State * state, ARMword number) +{ + number &= 0xfffff; + ARMword addr, temp; + + switch (number) { +// case SWI_Syscall: +// if (state->Reg[7] != 0) +// return ARMul_OSHandleSWI(state, state->Reg[7]); +// else +// return FALSE; +// case SWI_Read: +// SWIread (state, state->Reg[0], state->Reg[1], state->Reg[2]); +// return TRUE; +// +// case SWI_GetUID32: +// state->Reg[0] = getuid(); +// return TRUE; +// +// case SWI_GetGID32: +// state->Reg[0] = getgid(); +// return TRUE; +// +// case SWI_GetEUID32: +// state->Reg[0] = geteuid(); +// return TRUE; +// +// case SWI_GetEGID32: +// state->Reg[0] = getegid(); +// return TRUE; +// +// case SWI_Write: +// SWIwrite (state, state->Reg[0], state->Reg[1], state->Reg[2]); +// return TRUE; +// +// case SWI_Open: +// SWIopen (state, state->Reg[0], state->Reg[1]); +// return TRUE; +// +// case SWI_Close: +// state->Reg[0] = close (state->Reg[0]); +// return TRUE; +// +// case SWI_Seek:{ +// /* We must return non-zero for failure */ +// state->Reg[0] = +// lseek (state->Reg[0], state->Reg[1], +// SEEK_SET); +// return TRUE; +// } +// +// case SWI_ExitGroup: +// case SWI_Exit: +// { +// struct timeval tv; +// //gettimeofday(&tv,NULL); +// //printf("In %s, %d sec, %d usec\n", __FUNCTION__, tv.tv_sec, tv.tv_usec); +// printf("passed %d sec, %lld usec\n", get_clock_sec(), get_clock_us()); +// +// /* quit here */ +// run_command("quit"); +// return TRUE; +// } +// case SWI_Times:{ +// uint32_t dest = state->Reg[0]; +// struct tms now; +// struct target_tms32 nowret; +// +// uint32_t ret = times(&now); +// +// if (ret == -1){ +// debug("syscall %s error %d\n", "SWI_Times", ret); +// state->Reg[0] = ret; +// return FALSE; +// } +// +// nowret.tms_cstime = now.tms_cstime; +// nowret.tms_cutime = now.tms_cutime; +// nowret.tms_stime = now.tms_stime; +// nowret.tms_utime = now.tms_utime; +// +// uint32_t offset; +// for (offset = 0; offset < sizeof(nowret); offset++) { +// bus_write(8, dest + offset, *((uint8_t *) &nowret + offset)); +// } +// +// state->Reg[0] = ret; +// return TRUE; +// } +// +// case SWI_Gettimeofday: { +// uint32_t dest1 = state->Reg[0]; +// uint32_t dest2 = state->Reg[1]; // Unsure of this +// struct timeval val; +// struct timezone zone; +// struct target_timeval32 valret; +// struct target_timezone32 zoneret; +// +// uint32_t ret = gettimeofday(&val, &zone); +// valret.tv_sec = val.tv_sec; +// valret.tv_usec = val.tv_usec; +// zoneret.tz_dsttime = zoneret.tz_dsttime; +// zoneret.tz_minuteswest = zoneret.tz_minuteswest; +// +// if (ret == -1){ +// debug("syscall %s error %d\n", "SWI_Gettimeofday", ret); +// state->Reg[0] = ret; +// return FALSE; +// } +// +// uint32_t offset; +// if (dest1) { +// for (offset = 0; offset < sizeof(valret); offset++) { +// bus_write(8, dest1 + offset, *((uint8_t *) &valret + offset)); +// } +// state->Reg[0] = ret; +// } +// if (dest2) { +// for (offset = 0; offset < sizeof(zoneret); offset++) { +// bus_write(8, dest2 + offset, *((uint8_t *) &zoneret + offset)); +// } +// state->Reg[0] = ret; +// } +// +// return TRUE; +// } +// case SWI_Brk: +// /* initialize brk value */ +// /* suppose that brk_static doesn't reach 0xffffffff... */ +// if (brk_static == -1) { +// brk_static = (get_skyeye_pref()->info).brk; +// } +// +// /* FIXME there might be a need to do a mmap */ +// +// if(state->Reg[0]){ +// if (get_skyeye_exec_info()->mmap_access) { +// /* if new brk is greater than current brk, allocate memory */ +// if (state->Reg[0] > brk_static) { +// uint32_t ret = mmap( (void *) brk_static, state->Reg[0] - brk_static, +// PROT_WRITE, MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0 ); +// if (ret != MAP_FAILED) +// brk_static = ret; +// } +// } +// brk_static = state->Reg[0]; +// //state->Reg[0] = 0; /* FIXME return value of brk set to be the address on success */ +// } else { +// state->Reg[0] = brk_static; +// } +// return TRUE; +// +// case SWI_Break: +// state->Emulate = FALSE; +// return TRUE; +// +// case SWI_Mmap:{ +// int addr = state->Reg[0]; +// int len = state->Reg[1]; +// int prot = state->Reg[2]; +// int flag = state->Reg[3]; +// int fd = state->Reg[4]; +// int offset = state->Reg[5]; +// mmap_area_t *area = new_mmap_area(addr, len); +// state->Reg[0] = area->bank.addr; +// //printf("syscall %d mmap(0x%x,%x,0x%x,0x%x,%d,0x%x) = 0x%x\n",\ +// SWI_Mmap, addr, len, prot, flag, fd, offset, state->Reg[0]); +// return TRUE; +// } +// +// case SWI_Munmap: +// state->Reg[0] = 0; +// return TRUE; +// +// case SWI_Mmap2:{ +// int addr = state->Reg[0]; +// int len = state->Reg[1]; +// int prot = state->Reg[2]; +// int flag = state->Reg[3]; +// int fd = state->Reg[4]; +// int offset = state->Reg[5] * 4096; /* page offset */ +// mmap_area_t *area = new_mmap_area(addr, len); +// state->Reg[0] = area->bank.addr; +// +// return TRUE; +// } +// +// case SWI_Breakpoint: +// //chy 2005-09-12 change below line +// //state->EndCondition = RDIError_BreakpointReached; +// //printf ("SKYEYE: in armos.c : should not come here!!!!\n"); +// state->EndCondition = 0; +// /*modified by ksh to support breakpoiont*/ +// state->Emulate = STOP; +// return (TRUE); +// case SWI_Uname: +// { +// struct utsname *uts = (uintptr_t) state->Reg[0]; /* uname should write data in this address */ +// struct utsname utsbuf; +// //printf("Uname size is %x\n", sizeof(utsbuf)); +// char *buf; +// uintptr_t sp ; /* used as a temporary address */ +// +//#define COPY_UTS_STRING(addr) \ +// buf = addr; \ +// while(*buf != NULL) { \ +// bus_write(8, sp, *buf); \ +// sp++; \ +// buf++; \ +// } +//#define COPY_UTS(field) /*printf("%s: %s at %p\n", #field, utsbuf.field, uts->field);*/ \ +// sp = (uintptr_t) uts->field; \ +// COPY_UTS_STRING((&utsbuf)->field); +// +// if (uname(&utsbuf) < 0) { +// printf("syscall uname: utsname error\n"); +// state->Reg[0] = -1; +// return FALSE; +// } +// +// /* FIXME for now, this is just the host system call +// Some data should be missing, as it depends on +// the version of utsname */ +// COPY_UTS(sysname); +// COPY_UTS(nodename); +// COPY_UTS(release); +// COPY_UTS(version); +// COPY_UTS(machine); +// +// state->Reg[0] = 0; +// return TRUE; +// } +// case SWI_Fcntl: +// { +// uint32_t fd = state->Reg[0]; +// uint32_t cmd = state->Reg[1]; +// uint32_t arg = state->Reg[2]; +// uint32_t ret; +// +// switch(cmd){ +// case (F_GETFD): +// { +// ret = fcntl(fd, cmd, arg); +// //printf("syscall fcntl for getfd not implemented, ret %d\n", ret); +// state->Reg[0] = ret; +// return FALSE; +// } +// default: +// break; +// } +// +// printf("syscall fcntl unimplemented fd %x cmd %x\n", fd, cmd); +// state->Reg[0] = -1; +// return FALSE; +// +// } +// case SWI_Fstat64: +// { +// uint32_t dest = state->Reg[1]; +// uint32_t fd = state->Reg[0]; +// struct stat64 statbuf; +// struct target_stat64 statret; +// memset(&statret, 0, sizeof(struct target_stat64)); +// uint32_t ret = fstat64(fd, &statbuf); +// +// if (ret == -1){ +// printf("syscall %s returned error\n", "SWI_Fstat"); +// state->Reg[0] = ret; +// return FALSE; +// } +// +// /* copy statbuf to the process memory space +// FIXME can't say if endian has an effect here */ +// uint32_t offset; +// //printf("Fstat system is size %x\n", sizeof(statbuf)); +// //printf("Fstat target is size %x\n", sizeof(statret)); +// +// /* we copy system structure data stat64 into arm fixed size structure target_stat64 */ +// statret.st_dev = statbuf.st_dev; +// statret.st_ino = statbuf.st_ino; +// statret.st_mode = statbuf.st_mode; +// statret.st_nlink = statbuf.st_nlink; +// statret.st_uid = statbuf.st_uid; +// statret.st_gid = statbuf.st_gid; +// statret.st_rdev = statbuf.st_rdev; +// statret.st_size = statbuf.st_size; +// statret.st_blksize = statbuf.st_blksize; +// statret.st_blocks = statbuf.st_blocks; +// statret.st32_atime = statbuf.st_atime; +// statret.st32_mtime = statbuf.st_mtime; +// statret.st32_ctime = statbuf.st_ctime; +// +// for (offset = 0; offset < sizeof(statret); offset++) { +// bus_write(8, dest + offset, *((uint8_t *) &statret + offset)); +// } +// +// state->Reg[0] = ret; +// return TRUE; +// } +// case SWI_Set_tls: +// { +// //printf("syscall set_tls unimplemented\n"); +// state->mmu.thread_uro_id = state->Reg[0]; +// state->CP15[CP15_THREAD_URO - CP15_BASE] = state->Reg[0]; +// state->Reg[0] = 0; +// return FALSE; +// } +//#if 0 +// case SWI_Clock: +// /* return number of centi-seconds... */ +// state->Reg[0] = +//#ifdef CLOCKS_PER_SEC +// (CLOCKS_PER_SEC >= 100) +// ? (ARMword) (clock () / (CLOCKS_PER_SEC / 100)) +// : (ARMword) ((clock () * 100) / CLOCKS_PER_SEC); +//#else +// /* presume unix... clock() returns microseconds */ +// (ARMword) (clock () / 10000); +//#endif +// return (TRUE); +// +// case SWI_Time: +// state->Reg[0] = (ARMword) time (NULL); +// return (TRUE); +// case SWI_Flen: +// SWIflen (state, state->Reg[0]); +// return (TRUE); +// +//#endif + default: + + _dbg_assert_msg_(ARM11, false, "ImplementMe: ARMul_OSHandleSWI!"); + + return (FALSE); + } +} +// +///** +// * @brief For mmap syscall.A mmap_area is a memory bank. Get from ppc. +// */ +//static mmap_area_t* new_mmap_area(int sim_addr, int len){ +// mmap_area_t *area = (mmap_area_t *)malloc(sizeof(mmap_area_t)); +// if(area == NULL){ +// printf("error, failed %s\n",__FUNCTION__); +// exit(0); +// } +//#if FAST_MEMORY +// if (mmap_next_base == -1) +// { +// mmap_next_base = get_skyeye_exec_info()->brk; +// } +//#endif +// +// memset(area, 0x0, sizeof(mmap_area_t)); +// area->bank.addr = mmap_next_base; +// area->bank.len = len; +// area->bank.bank_write = mmap_mem_write; +// area->bank.bank_read = mmap_mem_read; +// area->bank.type = MEMTYPE_RAM; +// area->bank.objname = "mmap"; +// addr_mapping(&area->bank); +// +//#if FAST_MEMORY +// if (get_skyeye_exec_info()->mmap_access) +// { +// /* FIXME check proper flags */ +// /* FIXME we may delete the need of banks up there */ +// uint32_t ret = mmap(mmap_next_base, len, PROT_WRITE | PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); +// mmap_next_base = ret; +// } +// area->mmap_addr = (uint8_t*)get_dma_addr(mmap_next_base); +//#else +// area->mmap_addr = malloc(len); +// if(area->mmap_addr == NULL){ +// printf("error mmap malloc\n"); +// exit(0); +// } +// memset(area->mmap_addr, 0x0, len); +//#endif +// +// area->next = NULL; +// if(mmap_global){ +// area->next = mmap_global->next; +// mmap_global->next = area; +// }else{ +// mmap_global = area; +// } +// mmap_next_base = mmap_next_base + len; +// return area; +//} +// +//static mmap_area_t *get_mmap_area(int addr){ +// mmap_area_t *tmp = mmap_global; +// while(tmp){ +// if ((tmp->bank.addr <= addr) && (tmp->bank.addr + tmp->bank.len > addr)){ +// return tmp; +// } +// tmp = tmp->next; +// } +// printf("cannot get mmap area:addr=0x%x\n", addr); +// return NULL; +//} +// +///** +// * @brief the mmap_area bank write function. Get from ppc. +// * +// * @param size size to write, 8/16/32 +// * @param addr address to write +// * @param value value to write +// * +// * @return sucess return 1,otherwise 0. +// */ +//static char mmap_mem_write(short size, int addr, uint32_t value){ +// mmap_area_t *area_tmp = get_mmap_area(addr); +// mem_bank_t *bank_tmp = &area_tmp->bank; +// int offset = addr - bank_tmp->addr; +// switch(size){ +// case 8:{ +// //uint8_t value_endian = value; +// uint8_t value_endian = (uint8_t)value; +// *(uint8_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); +// break; +// } +// case 16:{ +// //uint16_t value_endian = half_to_BE((uint16_t)value); +// uint16_t value_endian = ((uint16_t)value); +// *(uint16_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); +// break; +// } +// case 32:{ +// //uint32_t value_endian = word_to_BE((uint32_t)value); +// uint32_t value_endian = ((uint32_t)value); +// *(uint32_t *)&(((char *)area_tmp->mmap_addr)[offset]) = value_endian; +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,value_endian); +// break; +// } +// default: +// printf("invalid size %d\n",size); +// return 0; +// } +// return 1; +//} +// +///** +// * @brief the mmap_area bank read function. Get from ppc. +// * +// * @param size size to read, 8/16/32 +// * @param addr address to read +// * @param value value to read +// * +// * @return sucess return 1,otherwise 0. +// */ +//static char mmap_mem_read(short size, int addr, uint32_t * value){ +// mmap_area_t *area_tmp = get_mmap_area(addr); +// mem_bank_t *bank_tmp = &area_tmp->bank; +// int offset = addr - bank_tmp->addr; +// switch(size){ +// case 8:{ +// //*(uint8_t *)value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); +// *value = *(uint8_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset]); +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); +// break; +// } +// case 16:{ +// //*(uint16_t *)value = half_from_BE(*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// *value = (*(uint16_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint16_t*)value); +// break; +// } +// case 32: +// //*value = (uint32_t)word_from_BE(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// *value = (uint32_t)(*(uint32_t *)&(((uint8_t *)area_tmp->mmap_addr)[offset])); +// debug("in %s,size=%d,addr=0x%x,value=0x%x\n",__FUNCTION__,size,addr,*(uint32_t*)value); +// break; +// default: +// printf("invalid size %d\n",size); +// return 0; +// } +// return 1; +//} diff --git a/src/core/src/arm/armsupp.cpp b/src/core/src/arm/armsupp.cpp new file mode 100644 index 000000000..c2b8399c9 --- /dev/null +++ b/src/core/src/arm/armsupp.cpp @@ -0,0 +1,953 @@ +/* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator. + Copyright (C) 1994 Advanced RISC Machines Ltd. + + 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 "armdefs.h" +#include "armemu.h" +//#include "ansidecl.h" +#include "skyeye_defs.h" +unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, + unsigned cpnum); +//extern int skyeye_instr_debug; +/* Definitions for the support routines. */ + +static ARMword ModeToBank (ARMword); +static void EnvokeList (ARMul_State *, unsigned int, unsigned int); + +struct EventNode +{ /* An event list node. */ + unsigned (*func) (ARMul_State *); /* The function to call. */ + struct EventNode *next; +}; + +/* This routine returns the value of a register from a mode. */ + +ARMword +ARMul_GetReg (ARMul_State * state, unsigned mode, unsigned reg) +{ + mode &= MODEBITS; + if (mode != state->Mode) + return (state->RegBank[ModeToBank ((ARMword) mode)][reg]); + else + return (state->Reg[reg]); +} + +/* This routine sets the value of a register for a mode. */ + +void +ARMul_SetReg (ARMul_State * state, unsigned mode, unsigned reg, ARMword value) +{ + mode &= MODEBITS; + if (mode != state->Mode) + state->RegBank[ModeToBank ((ARMword) mode)][reg] = value; + else + state->Reg[reg] = value; +} + +/* This routine returns the value of the PC, mode independently. */ + +ARMword +ARMul_GetPC (ARMul_State * state) +{ + if (state->Mode > SVC26MODE) + return state->Reg[15]; + else + return R15PC; +} + +/* This routine returns the value of the PC, mode independently. */ + +ARMword +ARMul_GetNextPC (ARMul_State * state) +{ + if (state->Mode > SVC26MODE) + return state->Reg[15] + isize; + else + return (state->Reg[15] + isize) & R15PCBITS; +} + +/* This routine sets the value of the PC. */ + +void +ARMul_SetPC (ARMul_State * state, ARMword value) +{ + if (ARMul_MODE32BIT) + state->Reg[15] = value & PCBITS; + else + state->Reg[15] = R15CCINTMODE | (value & R15PCBITS); + FLUSHPIPE; +} + +/* This routine returns the value of register 15, mode independently. */ + +ARMword +ARMul_GetR15 (ARMul_State * state) +{ + if (state->Mode > SVC26MODE) + return (state->Reg[15]); + else + return (R15PC | ECC | ER15INT | EMODE); +} + +/* This routine sets the value of Register 15. */ + +void +ARMul_SetR15 (ARMul_State * state, ARMword value) +{ + if (ARMul_MODE32BIT) + state->Reg[15] = value & PCBITS; + else { + state->Reg[15] = value; + ARMul_R15Altered (state); + } + FLUSHPIPE; +} + +/* This routine returns the value of the CPSR. */ + +ARMword +ARMul_GetCPSR (ARMul_State * state) +{ + //chy 2003-08-20: below is from gdb20030716, maybe isn't suitable for system simulator + //return (CPSR | state->Cpsr); for gdb20030716 + return (CPSR); //had be tested in old skyeye with gdb5.0-5.3 +} + +/* This routine sets the value of the CPSR. */ + +void +ARMul_SetCPSR (ARMul_State * state, ARMword value) +{ + state->Cpsr = value; + ARMul_CPSRAltered (state); +} + +/* This routine does all the nasty bits involved in a write to the CPSR, + including updating the register bank, given a MSR instruction. */ + +void +ARMul_FixCPSR (ARMul_State * state, ARMword instr, ARMword rhs) +{ + state->Cpsr = ARMul_GetCPSR (state); + //chy 2006-02-16 , should not consider system mode, don't conside 26bit mode + if (state->Mode != USER26MODE && state->Mode != USER32MODE ) { + /* In user mode, only write flags. */ + if (BIT (16)) + SETPSR_C (state->Cpsr, rhs); + if (BIT (17)) + SETPSR_X (state->Cpsr, rhs); + if (BIT (18)) + SETPSR_S (state->Cpsr, rhs); + } + if (BIT (19)) + SETPSR_F (state->Cpsr, rhs); + ARMul_CPSRAltered (state); +} + +/* Get an SPSR from the specified mode. */ + +ARMword +ARMul_GetSPSR (ARMul_State * state, ARMword mode) +{ + ARMword bank = ModeToBank (mode & MODEBITS); + + if (!BANK_CAN_ACCESS_SPSR (bank)) + return ARMul_GetCPSR (state); + + return state->Spsr[bank]; +} + +/* This routine does a write to an SPSR. */ + +void +ARMul_SetSPSR (ARMul_State * state, ARMword mode, ARMword value) +{ + ARMword bank = ModeToBank (mode & MODEBITS); + + if (BANK_CAN_ACCESS_SPSR (bank)) + state->Spsr[bank] = value; +} + +/* This routine does a write to the current SPSR, given an MSR instruction. */ + +void +ARMul_FixSPSR (ARMul_State * state, ARMword instr, ARMword rhs) +{ + if (BANK_CAN_ACCESS_SPSR (state->Bank)) { + if (BIT (16)) + SETPSR_C (state->Spsr[state->Bank], rhs); + if (BIT (17)) + SETPSR_X (state->Spsr[state->Bank], rhs); + if (BIT (18)) + SETPSR_S (state->Spsr[state->Bank], rhs); + if (BIT (19)) + SETPSR_F (state->Spsr[state->Bank], rhs); + } +} + +/* This routine updates the state of the emulator after the Cpsr has been + changed. Both the processor flags and register bank are updated. */ + +void +ARMul_CPSRAltered (ARMul_State * state) +{ + ARMword oldmode; + + if (state->prog32Sig == LOW) + state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS); + + oldmode = state->Mode; + + if (state->Mode != (state->Cpsr & MODEBITS)) { + state->Mode = + ARMul_SwitchMode (state, state->Mode, + state->Cpsr & MODEBITS); + + state->NtransSig = (state->Mode & 3) ? HIGH : LOW; + } + //state->Cpsr &= ~MODEBITS; + + ASSIGNINT (state->Cpsr & INTBITS); + //state->Cpsr &= ~INTBITS; + ASSIGNN ((state->Cpsr & NBIT) != 0); + //state->Cpsr &= ~NBIT; + ASSIGNZ ((state->Cpsr & ZBIT) != 0); + //state->Cpsr &= ~ZBIT; + ASSIGNC ((state->Cpsr & CBIT) != 0); + //state->Cpsr &= ~CBIT; + ASSIGNV ((state->Cpsr & VBIT) != 0); + //state->Cpsr &= ~VBIT; + ASSIGNS ((state->Cpsr & SBIT) != 0); + //state->Cpsr &= ~SBIT; +#ifdef MODET + ASSIGNT ((state->Cpsr & TBIT) != 0); + //state->Cpsr &= ~TBIT; +#endif + + if (oldmode > SVC26MODE) { + if (state->Mode <= SVC26MODE) { + state->Emulate = CHANGEMODE; + state->Reg[15] = ECC | ER15INT | EMODE | R15PC; + } + } + else { + if (state->Mode > SVC26MODE) { + state->Emulate = CHANGEMODE; + state->Reg[15] = R15PC; + } + else + state->Reg[15] = ECC | ER15INT | EMODE | R15PC; + } +} + +/* This routine updates the state of the emulator after register 15 has + been changed. Both the processor flags and register bank are updated. + This routine should only be called from a 26 bit mode. */ + +void +ARMul_R15Altered (ARMul_State * state) +{ + if (state->Mode != R15MODE) { + state->Mode = ARMul_SwitchMode (state, state->Mode, R15MODE); + state->NtransSig = (state->Mode & 3) ? HIGH : LOW; + } + + if (state->Mode > SVC26MODE) + state->Emulate = CHANGEMODE; + + ASSIGNR15INT (R15INT); + + ASSIGNN ((state->Reg[15] & NBIT) != 0); + ASSIGNZ ((state->Reg[15] & ZBIT) != 0); + ASSIGNC ((state->Reg[15] & CBIT) != 0); + ASSIGNV ((state->Reg[15] & VBIT) != 0); +} + +/* This routine controls the saving and restoring of registers across mode + changes. The regbank matrix is largely unused, only rows 13 and 14 are + used across all modes, 8 to 14 are used for FIQ, all others use the USER + column. It's easier this way. old and new parameter are modes numbers. + Notice the side effect of changing the Bank variable. */ + +ARMword +ARMul_SwitchMode (ARMul_State * state, ARMword oldmode, ARMword newmode) +{ + unsigned i; + ARMword oldbank; + ARMword newbank; + static int revision_value = 53; + + oldbank = ModeToBank (oldmode); + newbank = state->Bank = ModeToBank (newmode); + + /* Do we really need to do it? */ + if (oldbank != newbank) { + if (oldbank == 3 && newbank == 2) { + //printf("icounter is %d PC is %x MODE CHANGED : %d --> %d\n", state->NumInstrs, state->pc, oldbank, newbank); + if (state->NumInstrs >= 5832487) { +// printf("%d, ", state->NumInstrs + revision_value); +// printf("revision_value : %d\n", revision_value); + revision_value ++; + } + } + /* Save away the old registers. */ + switch (oldbank) { + case USERBANK: + case IRQBANK: + case SVCBANK: + case ABORTBANK: + case UNDEFBANK: + if (newbank == FIQBANK) + for (i = 8; i < 13; i++) + state->RegBank[USERBANK][i] = + state->Reg[i]; + state->RegBank[oldbank][13] = state->Reg[13]; + state->RegBank[oldbank][14] = state->Reg[14]; + break; + case FIQBANK: + for (i = 8; i < 15; i++) + state->RegBank[FIQBANK][i] = state->Reg[i]; + break; + case DUMMYBANK: + for (i = 8; i < 15; i++) + state->RegBank[DUMMYBANK][i] = 0; + break; + default: + abort (); + } + + /* Restore the new registers. */ + switch (newbank) { + case USERBANK: + case IRQBANK: + case SVCBANK: + case ABORTBANK: + case UNDEFBANK: + if (oldbank == FIQBANK) + for (i = 8; i < 13; i++) + state->Reg[i] = + state->RegBank[USERBANK][i]; + state->Reg[13] = state->RegBank[newbank][13]; + state->Reg[14] = state->RegBank[newbank][14]; + break; + case FIQBANK: + for (i = 8; i < 15; i++) + state->Reg[i] = state->RegBank[FIQBANK][i]; + break; + case DUMMYBANK: + for (i = 8; i < 15; i++) + state->Reg[i] = 0; + break; + default: + abort (); + } + } + + return newmode; +} + +/* Given a processor mode, this routine returns the + register bank that will be accessed in that mode. */ + +static ARMword +ModeToBank (ARMword mode) +{ + static ARMword bankofmode[] = { + USERBANK, FIQBANK, IRQBANK, SVCBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, + USERBANK, FIQBANK, IRQBANK, SVCBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK, + DUMMYBANK, DUMMYBANK, DUMMYBANK, SYSTEMBANK + }; + + if (mode >= (sizeof (bankofmode) / sizeof (bankofmode[0]))) + return DUMMYBANK; + + return bankofmode[mode]; +} + +/* Returns the register number of the nth register in a reg list. */ + +unsigned +ARMul_NthReg (ARMword instr, unsigned number) +{ + unsigned bit, upto; + + for (bit = 0, upto = 0; upto <= number; bit++) + if (BIT (bit)) + upto++; + + return (bit - 1); +} + +/* Assigns the N and Z flags depending on the value of result. */ + +void +ARMul_NegZero (ARMul_State * state, ARMword result) +{ + if (NEG (result)) { + SETN; + CLEARZ; + } + else if (result == 0) { + CLEARN; + SETZ; + } + else { + CLEARN; + CLEARZ; + } +} + +/* Compute whether an addition of A and B, giving RESULT, overflowed. */ + +int +AddOverflow (ARMword a, ARMword b, ARMword result) +{ + return ((NEG (a) && NEG (b) && POS (result)) + || (POS (a) && POS (b) && NEG (result))); +} + +/* Compute whether a subtraction of A and B, giving RESULT, overflowed. */ + +int +SubOverflow (ARMword a, ARMword b, ARMword result) +{ + return ((NEG (a) && POS (b) && POS (result)) + || (POS (a) && NEG (b) && NEG (result))); +} + +/* Assigns the C flag after an addition of a and b to give result. */ + +void +ARMul_AddCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNC ((NEG (a) && NEG (b)) || + (NEG (a) && POS (result)) || (NEG (b) && POS (result))); +} + +/* Assigns the V flag after an addition of a and b to give result. */ + +void +ARMul_AddOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNV (AddOverflow (a, b, result)); +} + +/* Assigns the C flag after an subtraction of a and b to give result. */ + +void +ARMul_SubCarry (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNC ((NEG (a) && POS (b)) || + (NEG (a) && POS (result)) || (POS (b) && POS (result))); +} + +/* Assigns the V flag after an subtraction of a and b to give result. */ + +void +ARMul_SubOverflow (ARMul_State * state, ARMword a, ARMword b, ARMword result) +{ + ASSIGNV (SubOverflow (a, b, result)); +} + +/* This function does the work of generating the addresses used in an + LDC instruction. The code here is always post-indexed, it's up to the + caller to get the input address correct and to handle base register + modification. It also handles the Busy-Waiting. */ + +void +ARMul_LDC (ARMul_State * state, ARMword instr, ARMword address) +{ + unsigned cpab; + ARMword data; + + UNDEF_LSCPCBaseWb; + //printf("SKYEYE ARMul_LDC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); +/*chy 2004-05-23 should update this function in the future,should concern dataabort*/ +// chy 2004-05-25 , fix it now,so needn't printf +// printf("SKYEYE ARMul_LDC, should update this function!!!!!\n"); + //exit(-1); + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + /* + printf + ("SKYEYE ARMul_LDC,NOT ALLOW, underinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + ARMul_UndefInstr (state, instr); + return; + } + + if (ADDREXCEPT (address)) + INTERNALABORT (address); + + cpab = (state->LDC[CPNum]) (state, ARMul_FIRST, instr, 0); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + + if (IntPending (state)) { + cpab = (state->LDC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return; + } + else + cpab = (state->LDC[CPNum]) (state, ARMul_BUSY, instr, + 0); + } + if (cpab == ARMul_CANT) { + /* + printf + ("SKYEYE ARMul_LDC,NOT CAN, underinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + CPTAKEABORT; + return; + } + + cpab = (state->LDC[CPNum]) (state, ARMul_TRANSFER, instr, 0); + data = ARMul_LoadWordN (state, address); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_ldc_takeabort; + + BUSUSEDINCPCN; +//chy 2004-05-25 +/* + if (BIT (21)) + LSBase = state->Base; +*/ + + cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); + + while (cpab == ARMul_INC) { + address += 4; + data = ARMul_LoadWordN (state, address); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_ldc_takeabort; + + cpab = (state->LDC[CPNum]) (state, ARMul_DATA, instr, data); + } + +//chy 2004-05-25 + L_ldc_takeabort: + if (BIT (21)) { + if (! + ((state->abortSig || state->Aborted) + && state->lateabtSig == LOW)) + LSBase = state->Base; + } + + if (state->abortSig || state->Aborted) + TAKEABORT; +} + +/* This function does the work of generating the addresses used in an + STC instruction. The code here is always post-indexed, it's up to the + caller to get the input address correct and to handle base register + modification. It also handles the Busy-Waiting. */ + +void +ARMul_STC (ARMul_State * state, ARMword instr, ARMword address) +{ + unsigned cpab; + ARMword data; + + UNDEF_LSCPCBaseWb; + + //printf("SKYEYE ARMul_STC, CPnum is %x, instr %x, addr %x\n",CPNum, instr, address); + /*chy 2004-05-23 should update this function in the future,should concern dataabort */ +// skyeye_instr_debug=0;printf("SKYEYE debug end!!!!\n"); +// chy 2004-05-25 , fix it now,so needn't printf +// printf("SKYEYE ARMul_STC, should update this function!!!!!\n"); + + //exit(-1); + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + /* + printf + ("SKYEYE ARMul_STC,NOT ALLOW, undefinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + ARMul_UndefInstr (state, instr); + return; + } + + if (ADDREXCEPT (address) || VECTORACCESS (address)) + INTERNALABORT (address); + + cpab = (state->STC[CPNum]) (state, ARMul_FIRST, instr, &data); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->STC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return; + } + else + cpab = (state->STC[CPNum]) (state, ARMul_BUSY, instr, + &data); + } + + if (cpab == ARMul_CANT) { + /* + printf + ("SKYEYE ARMul_STC,CANT, undefinstr, CPnum is %x, instr %x, addr %x\n", + CPNum, instr, address); + */ + CPTAKEABORT; + return; + } +#ifndef MODE32 + if (ADDREXCEPT (address) || VECTORACCESS (address)) + INTERNALABORT (address); +#endif + BUSUSEDINCPCN; +//chy 2004-05-25 +/* + if (BIT (21)) + LSBase = state->Base; +*/ + cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); + ARMul_StoreWordN (state, address, data); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_stc_takeabort; + + while (cpab == ARMul_INC) { + address += 4; + cpab = (state->STC[CPNum]) (state, ARMul_DATA, instr, &data); + ARMul_StoreWordN (state, address, data); + //chy 2004-05-25 + if (state->abortSig || state->Aborted) + goto L_stc_takeabort; + } +//chy 2004-05-25 + L_stc_takeabort: + if (BIT (21)) { + if (! + ((state->abortSig || state->Aborted) + && state->lateabtSig == LOW)) + LSBase = state->Base; + } + + if (state->abortSig || state->Aborted) + TAKEABORT; +} + +/* This function does the Busy-Waiting for an MCR instruction. */ + +void +ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source) +{ + unsigned cpab; + + //printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source); + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + //chy 2004-07-19 should fix in the future ????!!!! + //printf("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source); + ARMul_UndefInstr (state, instr); + return; + } + + cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source); + + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + + if (IntPending (state)) { + cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return; + } + else + cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, + source); + } + + if (cpab == ARMul_CANT) { + printf ("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source); + ARMul_Abort (state, ARMul_UndefinedInstrV); + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + } +} + +/* This function does the Busy-Waiting for an MCRR instruction. */ + +void +ARMul_MCRR (ARMul_State * state, ARMword instr, ARMword source1, ARMword source2) +{ + unsigned cpab; + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + ARMul_UndefInstr (state, instr); + return; + } + + cpab = (state->MCRR[CPNum]) (state, ARMul_FIRST, instr, source1, source2); + + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + + if (IntPending (state)) { + cpab = (state->MCRR[CPNum]) (state, ARMul_INTERRUPT, + instr, 0, 0); + return; + } + else + cpab = (state->MCRR[CPNum]) (state, ARMul_BUSY, instr, + source1, source2); + } + if (cpab == ARMul_CANT) { + printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x, source %x %x\n", __FUNCTION__, CPNum, instr, source1, source2); + ARMul_Abort (state, ARMul_UndefinedInstrV); + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + } +} + +/* This function does the Busy-Waiting for an MRC instruction. */ + +ARMword +ARMul_MRC (ARMul_State * state, ARMword instr) +{ + unsigned cpab; + ARMword result = 0; + + //printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr); + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + //chy 2004-07-19 should fix in the future????!!!! + //printf("SKYEYE ARMul_MRC,NOT ALLOWed UndefInstr CPnum is %x, instr %x\n",CPNum, instr); + ARMul_UndefInstr (state, instr); + return -1; + } + + cpab = (state->MRC[CPNum]) (state, ARMul_FIRST, instr, &result); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->MRC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0); + return (0); + } + else + cpab = (state->MRC[CPNum]) (state, ARMul_BUSY, instr, + &result); + } + if (cpab == ARMul_CANT) { + printf ("SKYEYE ARMul_MRC,CANT UndefInstr CPnum is %x, instr %x\n", CPNum, instr); + ARMul_Abort (state, ARMul_UndefinedInstrV); + /* Parent will destroy the flags otherwise. */ + result = ECC; + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + ARMul_Icycles (state, 1, 0); + } + + return result; +} + +/* This function does the Busy-Waiting for an MRRC instruction. (to verify) */ + +void +ARMul_MRRC (ARMul_State * state, ARMword instr, ARMword * dest1, ARMword * dest2) +{ + unsigned cpab; + ARMword result1 = 0; + ARMword result2 = 0; + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + ARMul_UndefInstr (state, instr); + return; + } + + cpab = (state->MRRC[CPNum]) (state, ARMul_FIRST, instr, &result1, &result2); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->MRRC[CPNum]) (state, ARMul_INTERRUPT, + instr, 0, 0); + return; + } + else + cpab = (state->MRRC[CPNum]) (state, ARMul_BUSY, instr, + &result1, &result2); + } + if (cpab == ARMul_CANT) { + printf ("In %s, CoProcesscor returned CANT, CPnum is %x, instr %x\n", __FUNCTION__, CPNum, instr); + ARMul_Abort (state, ARMul_UndefinedInstrV); + } + else { + BUSUSEDINCPCN; + ARMul_Ccycles (state, 1, 0); + ARMul_Icycles (state, 1, 0); + } + + *dest1 = result1; + *dest2 = result2; +} + +/* This function does the Busy-Waiting for an CDP instruction. */ + +void +ARMul_CDP (ARMul_State * state, ARMword instr) +{ + unsigned cpab; + + if (!CP_ACCESS_ALLOWED (state, CPNum)) { + ARMul_UndefInstr (state, instr); + return; + } + cpab = (state->CDP[CPNum]) (state, ARMul_FIRST, instr); + while (cpab == ARMul_BUSY) { + ARMul_Icycles (state, 1, 0); + if (IntPending (state)) { + cpab = (state->CDP[CPNum]) (state, ARMul_INTERRUPT, + instr); + return; + } + else + cpab = (state->CDP[CPNum]) (state, ARMul_BUSY, instr); + } + if (cpab == ARMul_CANT) + ARMul_Abort (state, ARMul_UndefinedInstrV); + else + BUSUSEDN; +} + +/* This function handles Undefined instructions, as CP isntruction. */ + +void +ARMul_UndefInstr (ARMul_State * state, ARMword instr) +{ + ERROR_LOG(ARM11, "Undefined instruction!! Instr: 0x%x", instr); + ARMul_Abort (state, ARMul_UndefinedInstrV); +} + +/* Return TRUE if an interrupt is pending, FALSE otherwise. */ + +unsigned +IntPending (ARMul_State * state) +{ + /* Any exceptions. */ + if (state->NresetSig == LOW) { + ARMul_Abort (state, ARMul_ResetV); + return TRUE; + } + else if (!state->NfiqSig && !FFLAG) { + ARMul_Abort (state, ARMul_FIQV); + return TRUE; + } + else if (!state->NirqSig && !IFLAG) { + ARMul_Abort (state, ARMul_IRQV); + return TRUE; + } + + return FALSE; +} + +/* Align a word access to a non word boundary. */ + +ARMword +ARMul_Align (ARMul_State *state, ARMword address, ARMword data) +{ + /* This code assumes the address is really unaligned, + as a shift by 32 is undefined in C. */ + + address = (address & 3) << 3; /* Get the word address. */ + return ((data >> address) | (data << (32 - address))); /* rot right */ +} + +/* This routine is used to call another routine after a certain number of + cycles have been executed. The first parameter is the number of cycles + delay before the function is called, the second argument is a pointer + to the function. A delay of zero doesn't work, just call the function. */ + +void +ARMul_ScheduleEvent (ARMul_State * state, unsigned int delay, + unsigned (*what) (ARMul_State *)) +{ + unsigned int when; + struct EventNode *event; + + if (state->EventSet++ == 0) + state->Now = ARMul_Time (state); + when = (state->Now + delay) % EVENTLISTSIZE; + event = (struct EventNode *) malloc (sizeof (struct EventNode)); + + _dbg_assert_msg_(ARM11, event, "SKYEYE:ARMul_ScheduleEvent: malloc event error\n"); + + event->func = what; + event->next = *(state->EventPtr + when); + *(state->EventPtr + when) = event; +} + +/* This routine is called at the beginning of + every cycle, to envoke scheduled events. */ + +void +ARMul_EnvokeEvent (ARMul_State * state) +{ + static unsigned int then; + + then = state->Now; + state->Now = ARMul_Time (state) % EVENTLISTSIZE; + if (then < state->Now) + /* Schedule events. */ + EnvokeList (state, then, state->Now); + else if (then > state->Now) { + /* Need to wrap around the list. */ + EnvokeList (state, then, EVENTLISTSIZE - 1L); + EnvokeList (state, 0L, state->Now); + } +} + +/* Envokes all the entries in a range. */ + +static void +EnvokeList (ARMul_State * state, unsigned int from, unsigned int to) +{ + for (; from <= to; from++) { + struct EventNode *anevent; + + anevent = *(state->EventPtr + from); + while (anevent) { + (anevent->func) (state); + state->EventSet--; + anevent = anevent->next; + } + *(state->EventPtr + from) = NULL; + } +} + +/* This routine is returns the number of clock ticks since the last reset. */ + +unsigned int +ARMul_Time (ARMul_State * state) +{ + return (state->NumScycles + state->NumNcycles + + state->NumIcycles + state->NumCcycles + state->NumFcycles); +} diff --git a/src/core/src/arm/armvirt.cpp b/src/core/src/arm/armvirt.cpp new file mode 100644 index 000000000..a072b73be --- /dev/null +++ b/src/core/src/arm/armvirt.cpp @@ -0,0 +1,680 @@ +/* armvirt.c -- ARMulator virtual memory interace: ARM6 Instruction Emulator. + Copyright (C) 1994 Advanced RISC Machines Ltd. + + 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. */ + +/* This file contains a complete ARMulator memory model, modelling a +"virtual memory" system. A much simpler model can be found in armfast.c, +and that model goes faster too, but has a fixed amount of memory. This +model's memory has 64K pages, allocated on demand from a 64K entry page +table. The routines PutWord and GetWord implement this. Pages are never +freed as they might be needed again. A single area of memory may be +defined to generate aborts. */ + +#include "armdefs.h" +#include "skyeye_defs.h" +//#include "code_cov.h" + +#ifdef VALIDATE /* for running the validate suite */ +#define TUBE 48 * 1024 * 1024 /* write a char on the screen */ +#define ABORTS 1 +#endif + +/* #define ABORTS */ + +#ifdef ABORTS /* the memory system will abort */ +/* For the old test suite Abort between 32 Kbytes and 32 Mbytes + For the new test suite Abort between 8 Mbytes and 26 Mbytes */ +/* #define LOWABORT 32 * 1024 +#define HIGHABORT 32 * 1024 * 1024 */ +#define LOWABORT 8 * 1024 * 1024 +#define HIGHABORT 26 * 1024 * 1024 + +#endif + +#define NUMPAGES 64 * 1024 +#define PAGESIZE 64 * 1024 +#define PAGEBITS 16 +#define OFFSETBITS 0xffff +//chy 2003-08-19: seems no use ???? +int SWI_vector_installed = FALSE; +extern ARMword skyeye_cachetype; + +/***************************************************************************\ +* Get a byte into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +GetByte (ARMul_State * state, ARMword address, ARMword * data) +{ + fault_t fault; + + fault = mmu_read_byte (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: GetByte fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Get a halfword into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +GetHalfWord (ARMul_State * state, ARMword address, ARMword * data) +{ + fault_t fault; + + fault = mmu_read_halfword (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: GetHalfWord fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Get a Word from Virtual Memory, maybe allocating the page * +\***************************************************************************/ + +static fault_t +GetWord (ARMul_State * state, ARMword address, ARMword * data) +{ + fault_t fault; + + fault = mmu_read_word (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +#if 0 +/* XXX */ extern int hack; + hack = 1; +#endif +#if 0 + printf ("mmu_read_word at 0x%08x: ", address); + switch (fault) { + case ALIGNMENT_FAULT: + printf ("ALIGNMENT_FAULT"); + break; + case SECTION_TRANSLATION_FAULT: + printf ("SECTION_TRANSLATION_FAULT"); + break; + case PAGE_TRANSLATION_FAULT: + printf ("PAGE_TRANSLATION_FAULT"); + break; + case SECTION_DOMAIN_FAULT: + printf ("SECTION_DOMAIN_FAULT"); + break; + case SECTION_PERMISSION_FAULT: + printf ("SECTION_PERMISSION_FAULT"); + break; + case SUBPAGE_PERMISSION_FAULT: + printf ("SUBPAGE_PERMISSION_FAULT"); + break; + default: + printf ("Unrecognized fault number!"); + } + printf ("\tpc = 0x%08x\n", state->Reg[15]); +#endif + } + return fault; +} + +//2003-07-10 chy: lyh change +/****************************************************************************\ + * Load a Instrion Word into Virtual Memory * +\****************************************************************************/ +static fault_t +LoadInstr (ARMul_State * state, ARMword address, ARMword * instr) +{ + fault_t fault; + fault = mmu_load_instr (state, address, instr); + return fault; + //if (fault) + // log_msg("load_instr fault = %d, address = %x\n", fault, address); +} + +/***************************************************************************\ +* Put a byte into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +PutByte (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + + fault = mmu_write_byte (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: PutByte fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Put a halfword into Virtual Memory, maybe allocating the page * +\***************************************************************************/ +static fault_t +PutHalfWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + + fault = mmu_write_halfword (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +// printf("SKYEYE: PutHalfWord fault %d \n", fault); + } + return fault; +} + +/***************************************************************************\ +* Put a Word into Virtual Memory, maybe allocating the page * +\***************************************************************************/ + +static fault_t +PutWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + + fault = mmu_write_word (state, address, data); + if (fault) { +//chy 2003-07-11: sometime has fault, but linux can continue running !!!!???? +#if 0 +/* XXX */ extern int hack; + hack = 1; +#endif +#if 0 + printf ("mmu_write_word at 0x%08x: ", address); + switch (fault) { + case ALIGNMENT_FAULT: + printf ("ALIGNMENT_FAULT"); + break; + case SECTION_TRANSLATION_FAULT: + printf ("SECTION_TRANSLATION_FAULT"); + break; + case PAGE_TRANSLATION_FAULT: + printf ("PAGE_TRANSLATION_FAULT"); + break; + case SECTION_DOMAIN_FAULT: + printf ("SECTION_DOMAIN_FAULT"); + break; + case SECTION_PERMISSION_FAULT: + printf ("SECTION_PERMISSION_FAULT"); + break; + case SUBPAGE_PERMISSION_FAULT: + printf ("SUBPAGE_PERMISSION_FAULT"); + break; + default: + printf ("Unrecognized fault number!"); + } + printf ("\tpc = 0x%08x\n", state->Reg[15]); +#endif + } + return fault; +} + +/***************************************************************************\ +* Initialise the memory interface * +\***************************************************************************/ + +unsigned +ARMul_MemoryInit (ARMul_State * state, unsigned int initmemsize) +{ + return TRUE; +} + +/***************************************************************************\ +* Remove the memory interface * +\***************************************************************************/ + +void +ARMul_MemoryExit (ARMul_State * state) +{ +} + +/***************************************************************************\ +* ReLoad Instruction * +\***************************************************************************/ + +ARMword +ARMul_ReLoadInstr (ARMul_State * state, ARMword address, ARMword isize) +{ + ARMword data; + fault_t fault; + +#ifdef ABORTS + if (address >= LOWABORT && address < HIGHABORT) { + ARMul_PREFETCHABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } +#endif +#if 0 + /* do profiling for code coverage */ + if (skyeye_config.code_cov.prof_on) + cov_prof(EXEC_FLAG, address); +#endif +#if 1 + if ((isize == 2) && (address & 0x2)) { + ARMword lo, hi; + if (!(skyeye_cachetype == INSTCACHE)) + fault = GetHalfWord (state, address, &lo); + else + fault = LoadInstr (state, address, &lo); +#if 0 + if (!fault) { + if (!(skyeye_cachetype == INSTCACHE)) + fault = GetHalfWord (state, address + isize, &hi); + else + fault = LoadInstr (state, address + isize, &hi); + + } +#endif + if (fault) { + ARMul_PREFETCHABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + return lo; +#if 0 + if (state->bigendSig == HIGH) + return (lo << 16) | (hi >> 16); + else + return ((hi & 0xFFFF) << 16) | (lo >> 16); +#endif + } +#endif + if (!(skyeye_cachetype == INSTCACHE)) + fault = GetWord (state, address, &data); + else + fault = LoadInstr (state, address, &data); + + if (fault) { + + /* dyf add for s3c6410 no instcache temporary 2010.9.17 */ + if (!(skyeye_cachetype == INSTCACHE)) { + /* set translation fault on prefetch abort */ + state->mmu.fault_statusi = fault & 0xFF; + state->mmu.fault_address = address; + } + /* add end */ + + ARMul_PREFETCHABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + + return data; +} + +/***************************************************************************\ +* Load Instruction, Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadInstrS (ARMul_State * state, ARMword address, ARMword isize) +{ + state->NumScycles++; + +#ifdef HOURGLASS + if ((state->NumScycles & HOURGLASS_RATE) == 0) { + HOURGLASS; + } +#endif + + return ARMul_ReLoadInstr (state, address, isize); +} + +/***************************************************************************\ +* Load Instruction, Non Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadInstrN (ARMul_State * state, ARMword address, ARMword isize) +{ + state->NumNcycles++; + + return ARMul_ReLoadInstr (state, address, isize); +} + +/***************************************************************************\ +* Read Word (but don't tell anyone!) * +\***************************************************************************/ + +ARMword +ARMul_ReadWord (ARMul_State * state, ARMword address) +{ + ARMword data; + fault_t fault; + +#ifdef ABORTS + if (address >= LOWABORT && address < HIGHABORT) { + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } +#endif + + fault = GetWord (state, address, &data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + return data; +} + +/***************************************************************************\ +* Load Word, Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadWordS (ARMul_State * state, ARMword address) +{ + state->NumScycles++; + + return ARMul_ReadWord (state, address); +} + +/***************************************************************************\ +* Load Word, Non Sequential Cycle * +\***************************************************************************/ + +ARMword +ARMul_LoadWordN (ARMul_State * state, ARMword address) +{ + state->NumNcycles++; + + return ARMul_ReadWord (state, address); +} + +/***************************************************************************\ +* Load Halfword, (Non Sequential Cycle) * +\***************************************************************************/ + +ARMword +ARMul_LoadHalfWord (ARMul_State * state, ARMword address) +{ + ARMword data; + fault_t fault; + + state->NumNcycles++; + fault = GetHalfWord (state, address, &data); + + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + + return data; + +} + +/***************************************************************************\ +* Read Byte (but don't tell anyone!) * +\***************************************************************************/ +int ARMul_ICE_ReadByte(ARMul_State * state, ARMword address, ARMword *presult) +{ + ARMword data; + fault_t fault; + fault = GetByte (state, address, &data); + if (fault) { + *presult=-1; fault=ALIGNMENT_FAULT; return fault; + }else{ + *(char *)presult=(unsigned char)(data & 0xff); fault=NO_FAULT; return fault; + } +} + + +ARMword +ARMul_ReadByte (ARMul_State * state, ARMword address) +{ + ARMword data; + fault_t fault; + + fault = GetByte (state, address, &data); + + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return ARMul_ABORTWORD; + } + else { + ARMul_CLEARABORT; + } + + return data; + +} + +/***************************************************************************\ +* Load Byte, (Non Sequential Cycle) * +\***************************************************************************/ + +ARMword +ARMul_LoadByte (ARMul_State * state, ARMword address) +{ + state->NumNcycles++; + + return ARMul_ReadByte (state, address); +} + +/***************************************************************************\ +* Write Word (but don't tell anyone!) * +\***************************************************************************/ + +void +ARMul_WriteWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + +#ifdef ABORTS + if (address >= LOWABORT && address < HIGHABORT) { + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +#endif + + fault = PutWord (state, address, data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +} + +/***************************************************************************\ +* Store Word, Sequential Cycle * +\***************************************************************************/ + +void +ARMul_StoreWordS (ARMul_State * state, ARMword address, ARMword data) +{ + state->NumScycles++; + + ARMul_WriteWord (state, address, data); +} + +/***************************************************************************\ +* Store Word, Non Sequential Cycle * +\***************************************************************************/ + +void +ARMul_StoreWordN (ARMul_State * state, ARMword address, ARMword data) +{ + state->NumNcycles++; + + ARMul_WriteWord (state, address, data); +} + +/***************************************************************************\ +* Store HalfWord, (Non Sequential Cycle) * +\***************************************************************************/ + +void +ARMul_StoreHalfWord (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + state->NumNcycles++; + fault = PutHalfWord (state, address, data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +} + +//chy 2006-04-15 +int ARMul_ICE_WriteByte (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + fault = PutByte (state, address, data); + if (fault) + return 1; + else + return 0; +} +/***************************************************************************\ +* Write Byte (but don't tell anyone!) * +\***************************************************************************/ +//chy 2003-07-10, add real write byte fun +void +ARMul_WriteByte (ARMul_State * state, ARMword address, ARMword data) +{ + fault_t fault; + fault = PutByte (state, address, data); + if (fault) { + state->mmu.fault_status = + (fault | (state->mmu.last_domain << 4)) & 0xFF; + state->mmu.fault_address = address; + ARMul_DATAABORT (address); + return; + } + else { + ARMul_CLEARABORT; + } +} + +/***************************************************************************\ +* Store Byte, (Non Sequential Cycle) * +\***************************************************************************/ + +void +ARMul_StoreByte (ARMul_State * state, ARMword address, ARMword data) +{ + state->NumNcycles++; + +#ifdef VALIDATE + if (address == TUBE) { + if (data == 4) + state->Emulate = FALSE; + else + (void) putc ((char) data, stderr); /* Write Char */ + return; + } +#endif + + ARMul_WriteByte (state, address, data); +} + +/***************************************************************************\ +* Swap Word, (Two Non Sequential Cycles) * +\***************************************************************************/ + +ARMword +ARMul_SwapWord (ARMul_State * state, ARMword address, ARMword data) +{ + ARMword temp; + + state->NumNcycles++; + + temp = ARMul_ReadWord (state, address); + + state->NumNcycles++; + + PutWord (state, address, data); + + return temp; +} + +/***************************************************************************\ +* Swap Byte, (Two Non Sequential Cycles) * +\***************************************************************************/ + +ARMword +ARMul_SwapByte (ARMul_State * state, ARMword address, ARMword data) +{ + ARMword temp; + + temp = ARMul_LoadByte (state, address); + ARMul_StoreByte (state, address, data); + + return temp; +} + +/***************************************************************************\ +* Count I Cycles * +\***************************************************************************/ + +void +ARMul_Icycles (ARMul_State * state, unsigned number, + ARMword address) +{ + state->NumIcycles += number; + ARMul_CLEARABORT; +} + +/***************************************************************************\ +* Count C Cycles * +\***************************************************************************/ + +void +ARMul_Ccycles (ARMul_State * state, unsigned number, + ARMword address) +{ + state->NumCcycles += number; + ARMul_CLEARABORT; +} |