📄 armemu.c
字号:
/* armemu.c -- Main instruction emulation: ARM7 Instruction Emulator.
Copyright (C) 1994 Advanced RISC Machines Ltd.
Modifications to add arch. v4 support by <jsmith@cygnus.com>.
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 "armos.h"
//#include "iwmmxt.h"
//chy 2003-07-11: for debug instrs
//extern int skyeye_instr_debug;
extern FILE *skyeye_logfd;
static ARMword GetDPRegRHS (ARMul_State *, ARMword);
static ARMword GetDPSRegRHS (ARMul_State *, ARMword);
static void WriteR15 (ARMul_State *, ARMword);
static void WriteSR15 (ARMul_State *, ARMword);
static void WriteR15Branch (ARMul_State *, ARMword);
static ARMword GetLSRegRHS (ARMul_State *, ARMword);
static ARMword GetLS7RHS (ARMul_State *, ARMword);
static unsigned LoadWord (ARMul_State *, ARMword, ARMword);
static unsigned LoadHalfWord (ARMul_State *, ARMword, ARMword, int);
static unsigned LoadByte (ARMul_State *, ARMword, ARMword, int);
static unsigned StoreWord (ARMul_State *, ARMword, ARMword);
static unsigned StoreHalfWord (ARMul_State *, ARMword, ARMword);
static unsigned StoreByte (ARMul_State *, ARMword, ARMword);
static void LoadMult (ARMul_State *, ARMword, ARMword, ARMword);
static void StoreMult (ARMul_State *, ARMword, ARMword, ARMword);
static void LoadSMult (ARMul_State *, ARMword, ARMword, ARMword);
static void StoreSMult (ARMul_State *, ARMword, ARMword, ARMword);
static unsigned Multiply64 (ARMul_State *, ARMword, int, int);
static unsigned MultiplyAdd64 (ARMul_State *, ARMword, int, int);
static void Handle_Load_Double (ARMul_State *, ARMword);
static void Handle_Store_Double (ARMul_State *, ARMword);
#define LUNSIGNED (0) /* unsigned operation */
#define LSIGNED (1) /* signed operation */
#define LDEFAULT (0) /* default : do nothing */
#define LSCC (1) /* set condition codes on result */
#ifdef NEED_UI_LOOP_HOOK
/* How often to run the ui_loop update, when in use. */
#define UI_LOOP_POLL_INTERVAL 0x32000
/* Counter for the ui_loop_hook update. */
static long ui_loop_hook_counter = UI_LOOP_POLL_INTERVAL;
/* Actual hook to call to run through gdb's gui event loop. */
extern int (*ui_loop_hook) (int);
#endif /* NEED_UI_LOOP_HOOK */
extern int stop_simulator;
/* Short-hand macros for LDR/STR. */
/* Store post decrement writeback. */
#define SHDOWNWB() \
lhs = LHS ; \
if (StoreHalfWord (state, instr, lhs)) \
LSBase = lhs - GetLS7RHS (state, instr);
/* Store post increment writeback. */
#define SHUPWB() \
lhs = LHS ; \
if (StoreHalfWord (state, instr, lhs)) \
LSBase = lhs + GetLS7RHS (state, instr);
/* Store pre decrement. */
#define SHPREDOWN() \
(void)StoreHalfWord (state, instr, LHS - GetLS7RHS (state, instr));
/* Store pre decrement writeback. */
#define SHPREDOWNWB() \
temp = LHS - GetLS7RHS (state, instr); \
if (StoreHalfWord (state, instr, temp)) \
LSBase = temp;
/* Store pre increment. */
#define SHPREUP() \
(void)StoreHalfWord (state, instr, LHS + GetLS7RHS (state, instr));
/* Store pre increment writeback. */
#define SHPREUPWB() \
temp = LHS + GetLS7RHS (state, instr); \
if (StoreHalfWord (state, instr, temp)) \
LSBase = temp;
/* Load post decrement writeback. */
#define LHPOSTDOWN() \
{ \
int done = 1; \
lhs = LHS; \
temp = lhs - GetLS7RHS (state, instr); \
\
switch (BITS (5, 6)) \
{ \
case 1: /* H */ \
if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \
LSBase = temp; \
break; \
case 2: /* SB */ \
if (LoadByte (state, instr, lhs, LSIGNED)) \
LSBase = temp; \
break; \
case 3: /* SH */ \
if (LoadHalfWord (state, instr, lhs, LSIGNED)) \
LSBase = temp; \
break; \
case 0: /* SWP handled elsewhere. */ \
default: \
done = 0; \
break; \
} \
if (done) \
break; \
}
/* Load post increment writeback. */
#define LHPOSTUP() \
{ \
int done = 1; \
lhs = LHS; \
temp = lhs + GetLS7RHS (state, instr); \
\
switch (BITS (5, 6)) \
{ \
case 1: /* H */ \
if (LoadHalfWord (state, instr, lhs, LUNSIGNED)) \
LSBase = temp; \
break; \
case 2: /* SB */ \
if (LoadByte (state, instr, lhs, LSIGNED)) \
LSBase = temp; \
break; \
case 3: /* SH */ \
if (LoadHalfWord (state, instr, lhs, LSIGNED)) \
LSBase = temp; \
break; \
case 0: /* SWP handled elsewhere. */ \
default: \
done = 0; \
break; \
} \
if (done) \
break; \
}
/* Load pre decrement. */
#define LHPREDOWN() \
{ \
int done = 1; \
\
temp = LHS - GetLS7RHS (state, instr); \
switch (BITS (5, 6)) \
{ \
case 1: /* H */ \
(void) LoadHalfWord (state, instr, temp, LUNSIGNED); \
break; \
case 2: /* SB */ \
(void) LoadByte (state, instr, temp, LSIGNED); \
break; \
case 3: /* SH */ \
(void) LoadHalfWord (state, instr, temp, LSIGNED); \
break; \
case 0: \
/* SWP handled elsewhere. */ \
default: \
done = 0; \
break; \
} \
if (done) \
break; \
}
/* Load pre decrement writeback. */
#define LHPREDOWNWB() \
{ \
int done = 1; \
\
temp = LHS - GetLS7RHS (state, instr); \
switch (BITS (5, 6)) \
{ \
case 1: /* H */ \
if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \
LSBase = temp; \
break; \
case 2: /* SB */ \
if (LoadByte (state, instr, temp, LSIGNED)) \
LSBase = temp; \
break; \
case 3: /* SH */ \
if (LoadHalfWord (state, instr, temp, LSIGNED)) \
LSBase = temp; \
break; \
case 0: \
/* SWP handled elsewhere. */ \
default: \
done = 0; \
break; \
} \
if (done) \
break; \
}
/* Load pre increment. */
#define LHPREUP() \
{ \
int done = 1; \
\
temp = LHS + GetLS7RHS (state, instr); \
switch (BITS (5, 6)) \
{ \
case 1: /* H */ \
(void) LoadHalfWord (state, instr, temp, LUNSIGNED); \
break; \
case 2: /* SB */ \
(void) LoadByte (state, instr, temp, LSIGNED); \
break; \
case 3: /* SH */ \
(void) LoadHalfWord (state, instr, temp, LSIGNED); \
break; \
case 0: \
/* SWP handled elsewhere. */ \
default: \
done = 0; \
break; \
} \
if (done) \
break; \
}
/* Load pre increment writeback. */
#define LHPREUPWB() \
{ \
int done = 1; \
\
temp = LHS + GetLS7RHS (state, instr); \
switch (BITS (5, 6)) \
{ \
case 1: /* H */ \
if (LoadHalfWord (state, instr, temp, LUNSIGNED)) \
LSBase = temp; \
break; \
case 2: /* SB */ \
if (LoadByte (state, instr, temp, LSIGNED)) \
LSBase = temp; \
break; \
case 3: /* SH */ \
if (LoadHalfWord (state, instr, temp, LSIGNED)) \
LSBase = temp; \
break; \
case 0: \
/* SWP handled elsewhere. */ \
default: \
done = 0; \
break; \
} \
if (done) \
break; \
}
/*ywc 2005-03-31*/
//teawater add for arm2x86 2005.02.17-------------------------------------------
#include "dbct/tb.h"
#ifndef NO_DBCT
#include "dbct/arm2x86_self.h"
#endif
//AJ2D--------------------------------------------------------------------------
/* EMULATION of ARM6. */
/* The PC pipeline value depends on whether ARM
or Thumb instructions are being executed. */
ARMword isize;
#ifdef MODE32
/*
void chy_debug()
{
printf("SkyEye chy_deubeg begin\n");
}
*/
ARMword
ARMul_Emulate32 (ARMul_State * state)
#else
ARMword
ARMul_Emulate26 (ARMul_State * state)
#endif
{
ARMword instr; /* The current instruction. */
ARMword dest = 0; /* Almost the DestBus. */
ARMword temp; /* Ubiquitous third hand. */
ARMword pc = 0; /* The address of the current instruction. */
ARMword lhs; /* Almost the ABus and BBus. */
ARMword rhs;
ARMword decoded = 0; /* Instruction pipeline. */
ARMword loaded = 0;
/* Execute the next instruction. */
if (state->NextInstr < PRIMEPIPE)
{
decoded = state->decoded;
loaded = state->loaded;
pc = state->pc;
}
do
{
/* Just keep going. */
isize = INSN_SIZE;
switch (state->NextInstr)
{
case SEQ:
/* Advance the pipeline, and an S cycle. */
state->Reg[15] += isize;
pc += isize;
instr = decoded;
decoded = loaded;
loaded = ARMul_LoadInstrS (state, pc + (isize * 2), isize);
break;
case NONSEQ:
/* Advance the pipeline, and an N cycle. */
state->Reg[15] += isize;
pc += isize;
instr = decoded;
decoded = loaded;
loaded = ARMul_LoadInstrN (state, pc + (isize * 2), isize);
NORMALCYCLE;
break;
case PCINCEDSEQ:
/* Program counter advanced, and an S cycle. */
pc += isize;
instr = decoded;
decoded = loaded;
loaded = ARMul_LoadInstrS (state, pc + (isize * 2), isize);
NORMALCYCLE;
break;
case PCINCEDNONSEQ:
/* Program counter advanced, and an N cycle. */
pc += isize;
instr = decoded;
decoded = loaded;
loaded = ARMul_LoadInstrN (state, pc + (isize * 2), isize);
NORMALCYCLE;
break;
case RESUME:
/* The program counter has been changed. */
pc = state->Reg[15];
#ifndef MODE32
pc = pc & R15PCBITS;
#endif
state->Reg[15] = pc + (isize * 2);
state->Aborted = 0;
//chy 2004-05-25, fix bug provided by Carl van Schaik<cvansch@cse.unsw.EDU.AU>
state->AbortAddr = 1;
instr = ARMul_ReLoadInstr (state, pc, isize);
decoded = ARMul_ReLoadInstr (state, pc + isize, isize);
loaded = ARMul_ReLoadInstr (state, pc + isize * 2, isize);
NORMALCYCLE;
break;
default:
/* The program counter has been changed. */
pc = state->Reg[15];
#ifndef MODE32
pc = pc & R15PCBITS;
#endif
state->Reg[15] = pc + (isize * 2);
state->Aborted = 0;
//chy 2004-05-25, fix bug provided by Carl van Schaik<cvansch@cse.unsw.EDU.AU>
state->AbortAddr = 1;
instr = ARMul_LoadInstrN (state, pc, isize);
decoded = ARMul_LoadInstrS (state, pc + (isize), isize);
loaded = ARMul_LoadInstrS (state, pc + (isize * 2), isize);
NORMALCYCLE;
break;
}
if (state->EventSet)
ARMul_EnvokeEvent (state);
//2003-07-11 chy: for test
if (skyeye_config.log.logon >= 1)
{
if (state->NumInstrs >= skyeye_config.log.start &&
state->NumInstrs <= skyeye_config.log.end)
{
static int mybegin = 0;
static int myinstrnum = 0;
if (mybegin == 0)
mybegin = 1;
#if 0
if (state->NumInstrs == 3695)
{
printf ("***********SKYEYE: numinstr = 3695\n");
}
static int mybeg2 = 0;
static int mybeg3 = 0;
static int mybeg4 = 0;
static int mybeg5 = 0;
if (pc == 0xa0008000)
{
//mybegin=1;
printf
("************SKYEYE: real vmlinux begin now numinstr is %llu ****************\n",
state->NumInstrs);
}
//chy 2003-09-02 test fiq
if (state->NumInstrs == 67347000)
{
printf
("***********SKYEYE: numinstr = 67347000, begin log\n");
mybegin = 1;
}
if (pc == 0xc00087b4)
{ //numinstr=67348714
mybegin = 1;
printf
("************SKYEYE: test irq now numinstr is %llu ****************\n",
state->NumInstrs);
}
if (pc == 0xc00087b8)
{ //in start_kernel::sti()
mybeg4 = 1;
printf
("************SKYEYE: startkerenl: sti now numinstr is %llu ********\n",
state->NumInstrs);
}
//if(pc==0xc001e4f4||pc==0xc001e4f8||pc==0xc001e4fc||pc==0xc001e500||pc==0xffff0004) { //MRA instr
if (pc == 0xc001e500)
{ //MRA instr
mybeg5 = 1;
printf
("************SKYEYE: MRA instr now numinstr is %llu ********\n",
state->NumInstrs);
}
if (pc >= 0xc0000000 && mybeg2 == 0)
{
mybeg2 = 1;
printf
("************SKYEYE: enable mmu&cache, now numinstr is %llu **************\n",
state->NumInstrs);
SKYEYE_OUTREGS (stderr);
printf
("************************************************************************\n");
}
//chy 2003-09-01 test after tlb-flush
if (pc == 0xc00261ac)
{
//sleep(2);
mybeg3 = 1;
printf
("************SKYEYE: after tlb-flush numinstr is %llu ****************\n",
state->NumInstrs);
}
if (mybeg3 == 1)
{
SKYEYE_OUTREGS (skyeye_logfd);
SKYEYE_OUTMOREREGS (skyeye_logfd);
fprintf (skyeye_logfd, "\n");
}
#endif
if (mybegin == 1)
{
//fprintf(skyeye_logfd,"p %x,i %x,d %x,l %x,",pc,instr,decoded,loaded);
//chy for test 20050729
/*if(state->NumInstrs>=3302294) {
if(pc==0x100c9d4 && instr==0xe1b0f00e){
chy_debug();
printf("*********************************************\n");
printf("******SKYEYE N %llx :p %x,i %x\n SKYEYE******\n",state->NumInstrs,pc,instr);
printf("*********************************************\n");
}
*/
if (skyeye_config.log.logon >= 1)
fprintf (skyeye_logfd, "N %llx :p %x,i %x,",
state->NumInstrs, pc, instr);
if (skyeye_config.log.logon >= 2)
SKYEYE_OUTREGS (skyeye_logfd);
if (skyeye_config.log.logon >= 3)
SKYEYE_OUTMOREREGS (skyeye_logfd);
fprintf (skyeye_logfd, "\n");
if (skyeye_config.log.length > 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -