Commit c570fd16 authored by ths's avatar ths

Preliminiary MIPS64 support, disabled by default due to performance impact.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2250 c046a42c-6fe2-441c-8c8c-71466251a162
parent 328a4240
......@@ -11,10 +11,10 @@
#define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin"
#define KERNEL_LOAD_ADDR 0x80010000
#define INITRD_LOAD_ADDR 0x80800000
#define KERNEL_LOAD_ADDR SIGN_EXTEND32(0x80010000)
#define INITRD_LOAD_ADDR SIGN_EXTEND32(0x80800000)
#define VIRT_TO_PHYS_ADDEND (-0x80000000LL)
#define VIRT_TO_PHYS_ADDEND (-SIGN_EXTEND32(0x80000000LL))
static const int ide_iobase[2] = { 0x1f0, 0x170 };
static const int ide_iobase2[2] = { 0x3f6, 0x376 };
......@@ -74,9 +74,11 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
long kernel_size, initrd_size;
kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
if (kernel_size >= 0)
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = SIGN_EXTEND32(entry);
env->PC = entry;
else {
} else {
kernel_size = load_image(kernel_filename,
phys_ram_base + KERNEL_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
if (kernel_size < 0) {
......@@ -103,7 +105,7 @@ void load_kernel (CPUState *env, int ram_size, const char *kernel_filename,
if (initrd_size > 0) {
int ret;
ret = sprintf(phys_ram_base + (16 << 20) - 256,
"rd_start=0x%08x rd_size=%li ",
"rd_start=0x" TLSZ " rd_size=%li ",
INITRD_LOAD_ADDR,
initrd_size);
strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
......
......@@ -15,6 +15,16 @@ typedef unsigned char uint_fast8_t;
typedef unsigned int uint_fast16_t;
#endif
#ifdef MIPS_HAS_MIPS64
#define SIGN_EXTEND32(val) (((((uint64_t)(val)) & 0xFFFFFFFF) ^ 0x80000000) - 0x80000000)
/* target_ulong size spec */
#define TLSZ "%016llx"
#else
#define SIGN_EXTEND32(val) (val)
/* target_ulong size spec */
#define TLSZ "%08x"
#endif
typedef union fpr_t fpr_t;
union fpr_t {
float64 fd; /* ieee double precision */
......@@ -55,7 +65,12 @@ struct CPUMIPSState {
target_ulong gpr[32];
/* Special registers */
target_ulong PC;
uint32_t HI, LO;
#if TARGET_LONG_BITS > HOST_LONG_BITS
target_ulong t0;
target_ulong t1;
target_ulong t2;
#endif
target_ulong HI, LO;
uint32_t DCR; /* ? */
#if defined(MIPS_USES_FPU)
/* Floating point registers */
......@@ -106,7 +121,7 @@ struct CPUMIPSState {
uint32_t CP0_PageGrain;
uint32_t CP0_Wired;
uint32_t CP0_HWREna;
uint32_t CP0_BadVAddr;
target_ulong CP0_BadVAddr;
uint32_t CP0_Count;
uint64_t CP0_EntryHi;
uint32_t CP0_Compare;
......@@ -145,9 +160,9 @@ struct CPUMIPSState {
#define CP0Ca_WP 22
#define CP0Ca_IP 8
#define CP0Ca_EC 2
uint32_t CP0_EPC;
target_ulong CP0_EPC;
uint32_t CP0_PRid;
uint32_t CP0_EBase;
target_ulong CP0_EBase;
uint32_t CP0_Config0;
#define CP0C0_M 31
#define CP0C0_K23 28
......@@ -197,7 +212,7 @@ struct CPUMIPSState {
#define CP0C3_MT 2
#define CP0C3_SM 1
#define CP0C3_TL 0
uint32_t CP0_LLAddr;
target_ulong CP0_LLAddr;
uint32_t CP0_WatchLo;
uint32_t CP0_WatchHi;
uint32_t CP0_XContext;
......@@ -221,13 +236,13 @@ struct CPUMIPSState {
#define CP0DB_DDBL 2
#define CP0DB_DBp 1
#define CP0DB_DSS 0
uint32_t CP0_DEPC;
target_ulong CP0_DEPC;
uint32_t CP0_Performance0;
uint32_t CP0_TagLo;
uint32_t CP0_DataLo;
uint32_t CP0_TagHi;
uint32_t CP0_DataHi;
uint32_t CP0_ErrorEPC;
target_ulong CP0_ErrorEPC;
uint32_t CP0_DESAVE;
/* Qemu */
int interrupt_request;
......
......@@ -3,6 +3,7 @@
//#define DEBUG_OP
#include "config.h"
#include "mips-defs.h"
#include "dyngen-exec.h"
......@@ -16,9 +17,15 @@ typedef int32_t host_int_t;
typedef uint32_t host_uint_t;
#endif
#if TARGET_LONG_BITS > HOST_LONG_BITS
#define T0 (env->t0)
#define T1 (env->t1)
#define T2 (env->t2)
#else
register host_uint_t T0 asm(AREG1);
register host_uint_t T1 asm(AREG2);
register host_uint_t T2 asm(AREG3);
#endif
#if defined (USE_HOST_FLOAT_REGS)
#error "implement me."
......@@ -58,13 +65,36 @@ static inline void regs_to_env(void)
{
}
#if (HOST_LONG_BITS == 32)
#ifdef MIPS_HAS_MIPS64
#if TARGET_LONG_BITS > HOST_LONG_BITS
void do_dsll (void);
void do_dsll32 (void);
void do_dsra (void);
void do_dsra32 (void);
void do_dsrl (void);
void do_dsrl32 (void);
void do_drotr (void);
void do_drotr32 (void);
void do_dsllv (void);
void do_dsrav (void);
void do_dsrlv (void);
void do_drotrv (void);
#endif
#endif
#if TARGET_LONG_BITS > HOST_LONG_BITS
void do_mult (void);
void do_multu (void);
void do_madd (void);
void do_maddu (void);
void do_msub (void);
void do_msubu (void);
void do_ddiv (void);
void do_ddivu (void);
#endif
#ifdef MIPS_HAS_MIPS64
void do_dmult (void);
void do_dmultu (void);
#endif
void do_mfc0_random(void);
void do_mfc0_count(void);
......@@ -86,6 +116,12 @@ void do_lwl_raw (uint32_t);
void do_lwr_raw (uint32_t);
uint32_t do_swl_raw (uint32_t);
uint32_t do_swr_raw (uint32_t);
#ifdef MIPS_HAS_MIPS64
void do_ldl_raw (uint64_t);
void do_ldr_raw (uint64_t);
uint64_t do_sdl_raw (uint64_t);
uint64_t do_sdr_raw (uint64_t);
#endif
#if !defined(CONFIG_USER_ONLY)
void do_lwl_user (uint32_t);
void do_lwl_kernel (uint32_t);
......@@ -95,6 +131,16 @@ uint32_t do_swl_user (uint32_t);
uint32_t do_swl_kernel (uint32_t);
uint32_t do_swr_user (uint32_t);
uint32_t do_swr_kernel (uint32_t);
#ifdef MIPS_HAS_MIPS64
void do_ldl_user (uint64_t);
void do_ldl_kernel (uint64_t);
void do_ldr_user (uint64_t);
void do_ldr_kernel (uint64_t);
uint64_t do_sdl_user (uint64_t);
uint64_t do_sdl_kernel (uint64_t);
uint64_t do_sdr_user (uint64_t);
uint64_t do_sdr_kernel (uint64_t);
#endif
#endif
void do_pmon (int function);
......
......@@ -96,4 +96,5 @@ SET_RESET(DT0, _DT0)
SET_RESET(DT1, _DT1)
SET_RESET(DT2, _DT2)
#undef SET_RESET
#endif
......@@ -86,7 +86,7 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
#endif
if (user_mode && address > 0x7FFFFFFFUL)
return TLBRET_BADADDR;
if (address < 0x80000000UL) {
if (address < SIGN_EXTEND32(0x80000000UL)) {
if (!(env->hflags & MIPS_HFLAG_ERL)) {
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
......@@ -98,17 +98,17 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
}
} else if (address < 0xA0000000UL) {
} else if (address < SIGN_EXTEND32(0xA0000000UL)) {
/* kseg0 */
/* XXX: check supervisor mode */
*physical = address - 0x80000000UL;
*physical = address - SIGN_EXTEND32(0x80000000UL);
*prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xC0000000UL) {
} else if (address < SIGN_EXTEND32(0xC0000000UL)) {
/* kseg1 */
/* XXX: check supervisor mode */
*physical = address - 0xA0000000UL;
*physical = address - SIGN_EXTEND32(0xA0000000UL);
*prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xE0000000UL) {
} else if (address < SIGN_EXTEND32(0xE0000000UL)) {
/* kseg2 */
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
......@@ -129,8 +129,8 @@ static int get_physical_address (CPUState *env, target_ulong *physical,
}
#if 0
if (logfile) {
fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
access_type, *physical, *prot, ret);
fprintf(logfile, TLSZ " %d %d => " TLSZ " %d (%d)\n",
address, rw, access_type, *physical, *prot, ret);
}
#endif
......@@ -171,7 +171,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
#if 0
cpu_dump_state(env, logfile, fprintf, 0);
#endif
fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
fprintf(logfile, "%s pc " TLSZ " ad " TLSZ " rw %d is_user %d smmu %d\n",
__func__, env->PC, address, rw, is_user, is_softmmu);
}
......@@ -189,7 +189,7 @@ int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
ret = get_physical_address(env, &physical, &prot,
address, rw, access_type);
if (logfile) {
fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
fprintf(logfile, "%s address=" TLSZ " ret %d physical " TLSZ " prot %d\n",
__func__, address, ret, physical, prot);
}
if (ret == TLBRET_MATCH) {
......@@ -255,7 +255,7 @@ void do_interrupt (CPUState *env)
int cause = -1;
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
fprintf(logfile, "%s enter: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index);
}
if (env->exception_index == EXCP_EXT_INTERRUPT &&
......@@ -299,7 +299,7 @@ void do_interrupt (CPUState *env)
enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM;
/* EJTAG probe trap enable is not implemented... */
env->PC = 0xBFC00480;
env->PC = SIGN_EXTEND32(0xBFC00480);
break;
case EXCP_RESET:
cpu_reset(env);
......@@ -321,7 +321,7 @@ void do_interrupt (CPUState *env)
}
env->hflags |= MIPS_HFLAG_ERL;
env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
env->PC = 0xBFC00000;
env->PC = SIGN_EXTEND32(0xBFC00000);
break;
case EXCP_MCHECK:
cause = 24;
......@@ -389,9 +389,9 @@ void do_interrupt (CPUState *env)
env->CP0_Cause &= ~0x80000000;
}
if (env->CP0_Status & (1 << CP0St_BEV)) {
env->PC = 0xBFC00200;
env->PC = SIGN_EXTEND32(0xBFC00200);
} else {
env->PC = 0x80000000;
env->PC = SIGN_EXTEND32(0x80000000);
}
env->hflags |= MIPS_HFLAG_EXL;
env->CP0_Status |= (1 << CP0St_EXL);
......@@ -407,8 +407,8 @@ void do_interrupt (CPUState *env)
exit(1);
}
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n"
" S %08x C %08x A %08x D %08x\n",
fprintf(logfile, "%s: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n"
" S %08x C %08x A " TLSZ " D " TLSZ "\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index,
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
......
......@@ -14,7 +14,8 @@
#if (MIPS_CPU == MIPS_R4Kc)
/* 32 bits target */
#define TARGET_LONG_BITS 32
#undef MIPS_HAS_MIPS64
//#define MIPS_HAS_MIPS64 1
/* real pages are variable size... */
#define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx enhancements to MIPS32 architecture */
......@@ -69,7 +70,7 @@
(0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
#elif (MIPS_CPU == MIPS_R4Kp)
/* 32 bits target */
#define TARGET_LONG_BITS 32
#undef MIPS_HAS_MIPS64
/* real pages are variable size... */
#define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx enhancements to MIPS32 architecture */
......@@ -79,8 +80,14 @@
#else
#error "MIPS CPU not defined"
/* Reminder for other flags */
//#define TARGET_MIPS64
//#undef MIPS_HAS_MIPS64
//#define MIPS_USES_FPU
#endif
#ifdef MIPS_HAS_MIPS64
#define TARGET_LONG_BITS 64
#else
#define TARGET_LONG_BITS 32
#endif
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
......@@ -140,13 +140,7 @@ CALL_FROM_TB2(func, arg0, arg1);
#include "op_template.c"
#undef REG
#define TN T0
#include "op_template.c"
#undef TN
#define TN T1
#include "op_template.c"
#undef TN
#define TN T2
#define TN
#include "op_template.c"
#undef TN
......@@ -334,7 +328,7 @@ void op_store_LO (void)
/* Arithmetic */
void op_add (void)
{
T0 += T1;
T0 = SIGN_EXTEND32((int32_t)T0 + (int32_t)T1);
RETURN();
}
......@@ -342,18 +336,19 @@ void op_addo (void)
{
target_ulong tmp;
tmp = T0;
T0 += T1;
tmp = (int32_t)T0;
T0 = (int32_t)T0 + (int32_t)T1;
if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) {
/* operands of same sign, result different sign */
/* operands of same sign, result different sign */
CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
}
T0 = SIGN_EXTEND32(T0);
RETURN();
}
void op_sub (void)
{
T0 -= T1;
T0 = SIGN_EXTEND32((int32_t)T0 - (int32_t)T1);
RETURN();
}
......@@ -361,31 +356,110 @@ void op_subo (void)
{
target_ulong tmp;
tmp = T0;
tmp = (int32_t)T0;
T0 = (int32_t)T0 - (int32_t)T1;
if (((tmp ^ T1) & (tmp ^ T0)) >> 31) {
/* operands of different sign, first operand and result different sign */
/* operands of different sign, first operand and result different sign */
CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
}
T0 = SIGN_EXTEND32(T0);
RETURN();
}
void op_mul (void)
{
T0 = (int32_t)T0 * (int32_t)T1;
T0 = SIGN_EXTEND32((int32_t)T0 * (int32_t)T1);
RETURN();
}
void op_div (void)
{
if (T1 != 0) {
env->LO = (int32_t)T0 / (int32_t)T1;
env->HI = (int32_t)T0 % (int32_t)T1;
env->LO = SIGN_EXTEND32((int32_t)T0 / (int32_t)T1);
env->HI = SIGN_EXTEND32((int32_t)T0 % (int32_t)T1);
}
RETURN();
}
void op_divu (void)
{
if (T1 != 0) {
env->LO = SIGN_EXTEND32((uint32_t)T0 / (uint32_t)T1);
env->HI = SIGN_EXTEND32((uint32_t)T0 % (uint32_t)T1);
}
RETURN();
}
#ifdef MIPS_HAS_MIPS64
/* Arithmetic */
void op_dadd (void)
{
T0 += T1;
RETURN();
}
void op_daddo (void)
{
target_long tmp;
tmp = T0;
T0 += T1;
if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 63) {
/* operands of same sign, result different sign */
CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
}
RETURN();
}
void op_dsub (void)
{
T0 -= T1;
RETURN();
}
void op_dsubo (void)
{
target_long tmp;
tmp = T0;
T0 = (int64_t)T0 - (int64_t)T1;
if (((tmp ^ T1) & (tmp ^ T0)) >> 63) {
/* operands of different sign, first operand and result different sign */
CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
}
RETURN();
}
void op_dmul (void)
{
T0 = (int64_t)T0 * (int64_t)T1;
RETURN();
}
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* Those might call libgcc functions. */
void op_ddiv (void)
{
do_ddiv();
RETURN();
}
void op_ddivu (void)
{
do_ddivu();
RETURN();
}
#else
void op_ddiv (void)
{
if (T1 != 0) {
env->LO = (int64_t)T0 / (int64_t)T1;
env->HI = (int64_t)T0 % (int64_t)T1;
}
RETURN();
}
void op_ddivu (void)
{
if (T1 != 0) {
env->LO = T0 / T1;
......@@ -393,6 +467,8 @@ void op_divu (void)
}
RETURN();
}
#endif
#endif /* MIPS_HAS_MIPS64 */
/* Logical */
void op_and (void)
......@@ -421,19 +497,19 @@ void op_xor (void)
void op_sll (void)
{
T0 = T0 << T1;
T0 = SIGN_EXTEND32((uint32_t)T0 << (uint32_t)T1);
RETURN();
}
void op_sra (void)
{
T0 = (int32_t)T0 >> T1;
T0 = SIGN_EXTEND32((int32_t)T0 >> (uint32_t)T1);
RETURN();
}
void op_srl (void)
{
T0 = T0 >> T1;
T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1);
RETURN();
}
......@@ -442,8 +518,8 @@ void op_rotr (void)
target_ulong tmp;
if (T1) {
tmp = T0 << (0x20 - T1);
T0 = (T0 >> T1) | tmp;
tmp = SIGN_EXTEND32((uint32_t)T0 << (0x20 - (uint32_t)T1));
T0 = SIGN_EXTEND32((uint32_t)T0 >> (uint32_t)T1) | tmp;
} else
T0 = T1;
RETURN();
......@@ -451,19 +527,19 @@ void op_rotr (void)
void op_sllv (void)
{
T0 = T1 << (T0 & 0x1F);
T0 = SIGN_EXTEND32((uint32_t)T1 << ((uint32_t)T0 & 0x1F));
RETURN();
}
void op_srav (void)
{
T0 = (int32_t)T1 >> (T0 & 0x1F);
T0 = SIGN_EXTEND32((int32_t)T1 >> (T0 & 0x1F));
RETURN();
}
void op_srlv (void)
{
T0 = T1 >> (T0 & 0x1F);
T0 = SIGN_EXTEND32((uint32_t)T1 >> (T0 & 0x1F));
RETURN();
}
......@@ -473,8 +549,8 @@ void op_rotrv (void)
T0 &= 0x1F;
if (T0) {
tmp = T1 << (0x20 - T0);
T0 = (T1 >> T0) | tmp;
tmp = SIGN_EXTEND32((uint32_t)T1 << (0x20 - T0));
T0 = SIGN_EXTEND32((uint32_t)T1 >> T0) | tmp;
} else
T0 = T1;
RETURN();
......@@ -484,7 +560,7 @@ void op_clo (void)
{
int n;
if (T0 == (target_ulong)-1) {
if (T0 == ~((target_ulong)0)) {
T0 = 32;
} else {
for (n = 0; n < 32; n++) {
......@@ -514,67 +590,213 @@ void op_clz (void)
RETURN();
}
/* 64 bits arithmetic */
#if (HOST_LONG_BITS == 64)
static inline uint64_t get_HILO (void)
#ifdef MIPS_HAS_MIPS64
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* Those might call libgcc functions. */
void op_dsll (void)
{
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
CALL_FROM_TB0(do_dsll);
RETURN();
}
static inline void set_HILO (uint64_t HILO)
void op_dsll32 (void)
{
env->LO = HILO & 0xFFFFFFFF;
env->HI = HILO >> 32;
CALL_FROM_TB0(do_dsll32);
RETURN();
}
void op_mult (void)
void op_dsra (void)
{
set_HILO((int64_t)(int32_t)T0 * (int64_t)(int32_t)T1);
CALL_FROM_TB0(do_dsra);
RETURN();
}
void op_multu (void)
void op_dsra32 (void)
{
set_HILO((uint64_t)T0 * (uint64_t)T1);