9 changed files with 2582 additions and 166 deletions
-
8src/core/core.vcxproj
-
20src/core/core.vcxproj.filters
-
21src/core/src/arm/armemu.cpp
-
15src/core/src/arm/armemu.h
-
163src/core/src/arm/arminit.cpp
-
146src/core/src/arm/armmmu.cpp
-
742src/core/src/arm/armos.cpp
-
953src/core/src/arm/armsupp.cpp
-
680src/core/src/arm/armvirt.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;
|
||||
|
//}
|
||||
@ -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); |
||||
|
} |
||||
@ -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; |
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue