sim-card
/
qemu
Archived
10
0
Fork 0

MIPS target (Jocelyn Mayer)

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1464 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2005-07-02 14:58:51 +00:00
parent 6643d27ea0
commit 6af0bf9c7c
22 changed files with 4701 additions and 1 deletions

View File

@ -72,6 +72,10 @@ ifeq ($(ARCH), ppc)
PROGS+=$(QEMU_SYSTEM)
endif
endif # TARGET_ARCH = ppc
ifeq ($(TARGET_ARCH), mips)
ifeq ($(ARCH), i386)
ifdef CONFIG_SOFTMMU
PROGS+=$(QEMU_SYSTEM)
@ -84,7 +88,7 @@ PROGS+=$(QEMU_SYSTEM)
endif
endif # ARCH = x86_64
endif # TARGET_ARCH = ppc
endif # TARGET_ARCH = mips
ifeq ($(TARGET_ARCH), sparc)
@ -263,6 +267,10 @@ ifeq ($(TARGET_ARCH), ppc)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_ARCH), mips)
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
LIBOBJS+= op_helper.o helper.o
endif
@ -288,6 +296,9 @@ endif
ifeq ($(findstring ppc, $(TARGET_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
LIBOBJS+=mips-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
LIBOBJS+=sparc-dis.o
endif
@ -348,6 +359,10 @@ VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o
endif
ifeq ($(TARGET_ARCH), mips)
VL_OBJS+= mips.o mips_r4k.o dma.o vga.o serial.o #ide.o ne2000.o pckbd.o
VL_OBJS+= #i8259.o i8254.o fdc.o m48t59.o
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
VL_OBJS+= sun4u.o m48t08.o magic-load.o slavio_serial.o
@ -455,6 +470,11 @@ op.o: op.c op_template.h op_mem.h
op_helper.o: op_helper_mem.h
endif
ifeq ($(TARGET_ARCH), mips)
op.o: op.c op_template.c op_mem.c
op_helper.o: op_helper_mem.c
endif
mixeng.o: mixeng.c mixeng.h mixeng_template.h
%.o: %.c

View File

@ -617,6 +617,13 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size);
#define cpu_gen_code cpu_ppc_gen_code
#define cpu_signal_handler cpu_ppc_signal_handler
#elif defined(TARGET_MIPS)
#define CPUState CPUMIPSState
#define cpu_init cpu_mips_init
#define cpu_exec cpu_mips_exec
#define cpu_gen_code cpu_mips_gen_code
#define cpu_signal_handler cpu_mips_signal_handler
#else
#error unsupported target CPU

View File

@ -182,6 +182,7 @@ int cpu_exec(CPUState *env1)
saved_regwptr = REGWPTR;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#else
#error unsupported target CPU
#endif
@ -220,6 +221,8 @@ int cpu_exec(CPUState *env1)
env->exception_next_eip, 0);
#elif defined(TARGET_PPC)
do_interrupt(env);
#elif defined(TARGET_MIPS)
do_interrupt(env);
#elif defined(TARGET_SPARC)
do_interrupt(env->exception_index);
#endif
@ -301,6 +304,19 @@ int cpu_exec(CPUState *env1)
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
}
}
#elif defined(TARGET_MIPS)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->CP0_Status & (1 << CP0St_IE)) &&
(env->CP0_Cause & 0x0000FC00) &&
!(env->hflags & MIPS_HFLAG_EXL) &&
!(env->hflags & MIPS_HFLAG_ERL) &&
!(env->hflags & MIPS_HFLAG_DM)) {
/* Raise it */
env->exception_index = EXCP_EXT_INTERRUPT;
env->error_code = 0;
do_interrupt(env);
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
#elif defined(TARGET_SPARC)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
(env->psret != 0)) {
@ -376,6 +392,8 @@ int cpu_exec(CPUState *env1)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_PPC)
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_MIPS)
cpu_dump_state(env, logfile, fprintf, 0);
#else
#error unsupported target CPU
#endif
@ -407,6 +425,10 @@ int cpu_exec(CPUState *env1)
(msr_se << MSR_SE) | (msr_le << MSR_LE);
cs_base = 0;
pc = env->nip;
#elif defined(TARGET_MIPS)
flags = env->hflags & MIPS_HFLAGS_TMASK;
cs_base = NULL;
pc = env->PC;
#else
#error unsupported CPU
#endif
@ -684,6 +706,7 @@ int cpu_exec(CPUState *env1)
REGWPTR = saved_regwptr;
#endif
#elif defined(TARGET_PPC)
#elif defined(TARGET_MIPS)
#else
#error unsupported target CPU
#endif
@ -935,6 +958,57 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
/* never comes here */
return 1;
}
#elif defined (TARGET_MIPS)
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set,
void *puc)
{
TranslationBlock *tb;
int ret;
if (cpu_single_env)
env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address, pc, puc)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_ppc_handle_mmu_fault(env, address, is_write, msr_pr, 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, puc);
}
if (ret == 1) {
#if 0
printf("PF exception: NIP=0x%08x error=0x%x %p\n",
env->nip, env->error_code, tb);
#endif
/* we restore the process signal mask as the sigreturn should
do it (XXX: use sigsetjmp) */
sigprocmask(SIG_SETMASK, old_set, NULL);
do_raise_exception_err(env->exception_index, env->error_code);
} else {
/* activate soft MMU for this block */
cpu_resume_from_signal(env, puc);
}
/* never comes here */
return 1;
}
#else
#error unsupported target CPU
#endif

View File

@ -404,6 +404,8 @@ extern int generic_symbol_at_address
bfd_vma bfd_getl32 (const bfd_byte *addr);
bfd_vma bfd_getb32 (const bfd_byte *addr);
bfd_vma bfd_getl16 (const bfd_byte *addr);
bfd_vma bfd_getb16 (const bfd_byte *addr);
typedef enum bfd_boolean {false, true} boolean;
#endif /* ! defined (DIS_ASM_H) */

26
disas.c
View File

@ -108,6 +108,24 @@ bfd_vma bfd_getb32 (const bfd_byte *addr)
return (bfd_vma) v;
}
bfd_vma bfd_getl16 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0];
v |= (unsigned long) addr[1] << 8;
return (bfd_vma) v;
}
bfd_vma bfd_getb16 (const bfd_byte *addr)
{
unsigned long v;
v = (unsigned long) addr[0] << 24;
v |= (unsigned long) addr[1] << 16;
return (bfd_vma) v;
}
#ifdef TARGET_ARM
static int
print_insn_thumb1(bfd_vma pc, disassemble_info *info)
@ -162,6 +180,8 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags)
if (cpu_single_env->msr[MSR_LE])
disasm_info.endian = BFD_ENDIAN_LITTLE;
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
@ -222,6 +242,10 @@ void disas(FILE *out, void *code, unsigned long size)
print_insn = print_insn_sparc;
#elif defined(__arm__)
print_insn = print_insn_arm;
#elif defined(__MIPSEB__)
print_insn = print_insn_big_mips;
#elif defined(__MIPSEL__)
print_insn = print_insn_little_mips;
#else
fprintf(out, "0x%lx: Asm output not supported on this arch\n",
(long) code);
@ -332,6 +356,8 @@ void monitor_disas(target_ulong pc, int nb_insn, int is_physical, int flags)
print_insn = print_insn_sparc;
#elif defined(TARGET_PPC)
print_insn = print_insn_ppc;
#elif defined(TARGET_MIPS)
print_insn = print_insn_big_mips;
#else
term_printf("0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", pc);

18
elf.h
View File

@ -31,11 +31,29 @@ typedef int64_t Elf64_Sxword;
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7fffffff
#define PT_MIPS_REGINFO 0x70000000
#define PT_MIPS_OPTIONS 0x70000001
/* Flags in the e_flags field of the header */
/* MIPS architecture level. */
#define EF_MIPS_ARCH_1 0x00000000 /* -mips1 code. */
#define EF_MIPS_ARCH_2 0x10000000 /* -mips2 code. */
#define EF_MIPS_ARCH_3 0x20000000 /* -mips3 code. */
#define EF_MIPS_ARCH_4 0x30000000 /* -mips4 code. */
#define EF_MIPS_ARCH_5 0x40000000 /* -mips5 code. */
#define EF_MIPS_ARCH_32 0x50000000 /* MIPS32 code. */
#define EF_MIPS_ARCH_64 0x60000000 /* MIPS64 code. */
/* The ABI of a file. */
#define EF_MIPS_ABI_O32 0x00001000 /* O32 ABI. */
#define EF_MIPS_ABI_O64 0x00002000 /* O32 extended for 64 bit. */
#define EF_MIPS_NOREORDER 0x00000001
#define EF_MIPS_PIC 0x00000002
#define EF_MIPS_CPIC 0x00000004
#define EF_MIPS_ABI2 0x00000020
#define EF_MIPS_OPTIONS_FIRST 0x00000080
#define EF_MIPS_32BITMODE 0x00000100
#define EF_MIPS_ABI 0x0000f000
#define EF_MIPS_ARCH 0xf0000000
/* These constants define the different elf file types */

View File

@ -582,6 +582,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
is_user = ((env->hflags & HF_CPL_MASK) == 3);
#elif defined (TARGET_PPC)
is_user = msr_pr;
#elif defined (TARGET_MIPS)
is_user = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM);
#elif defined (TARGET_SPARC)
is_user = (env->psrs == 0);
#else

309
hw/mips_r4k.c Normal file
View File

@ -0,0 +1,309 @@
#include "vl.h"
#define DEBUG_IRQ_COUNT
#define BIOS_FILENAME "mips_bios.bin"
//#define BIOS_FILENAME "system.bin"
#define KERNEL_LOAD_ADDR 0x80010000
#define INITRD_LOAD_ADDR 0x80800000
/* MIPS R4K IRQ controler */
#if defined(DEBUG_IRQ_COUNT)
static uint64_t irq_count[16];
#endif
extern FILE *logfile;
void mips_set_irq (int n_IRQ, int level)
{
uint32_t mask;
if (n_IRQ < 0 || n_IRQ >= 8)
return;
mask = 0x100 << n_IRQ;
if (level != 0) {
#if 1
if (logfile) {
fprintf(logfile, "%s n %d l %d mask %08x %08x\n",
__func__, n_IRQ, level, mask, cpu_single_env->CP0_Status);
}
#endif
cpu_single_env->CP0_Cause |= mask;
if ((cpu_single_env->CP0_Status & 0x00000001) &&
(cpu_single_env->CP0_Status & mask)) {
#if defined(DEBUG_IRQ_COUNT)
irq_count[n_IRQ]++;
#endif
#if 1
if (logfile)
fprintf(logfile, "%s raise IRQ\n", __func__);
#endif
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
}
} else {
cpu_single_env->CP0_Cause &= ~mask;
}
}
void pic_set_irq (int n_IRQ, int level)
{
mips_set_irq(n_IRQ + 2, level);
}
void pic_info (void)
{
term_printf("IRQ asserted: %02x mask: %02x\n",
(cpu_single_env->CP0_Cause >> 8) & 0xFF,
(cpu_single_env->CP0_Status >> 8) & 0xFF);
}
void irq_info (void)
{
#if !defined(DEBUG_IRQ_COUNT)
term_printf("irq statistic code not compiled.\n");
#else
int i;
int64_t count;
term_printf("IRQ statistics:\n");
for (i = 0; i < 8; i++) {
count = irq_count[i];
if (count > 0)
term_printf("%2d: %lld\n", i, count);
}
#endif
}
void cpu_mips_irqctrl_init (void)
{
}
/* MIPS R4K timer */
uint32_t cpu_mips_get_random (CPUState *env)
{
uint64_t now = qemu_get_clock(vm_clock);
return (uint32_t)now & 0x0000000F;
}
uint32_t cpu_mips_get_count (CPUState *env)
{
return env->CP0_Count +
(uint32_t)muldiv64(qemu_get_clock(vm_clock),
100 * 1000 * 1000, ticks_per_sec);
}
static void cpu_mips_update_count (CPUState *env, uint32_t count,
uint32_t compare)
{
uint64_t now, next;
uint32_t tmp;
tmp = count;
if (count == compare)
tmp++;
now = qemu_get_clock(vm_clock);
next = now + muldiv64(compare - tmp, ticks_per_sec, 100 * 1000 * 1000);
if (next == now)
next++;
#if 1
if (logfile) {
fprintf(logfile, "%s: 0x%08llx %08x %08x => 0x%08llx\n",
__func__, now, count, compare, next - now);
}
#endif
/* Store new count and compare registers */
env->CP0_Compare = compare;
env->CP0_Count =
count - (uint32_t)muldiv64(now, 100 * 1000 * 1000, ticks_per_sec);
/* Adjust timer */
qemu_mod_timer(env->timer, next);
}
void cpu_mips_store_count (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, value, env->CP0_Compare);
}
void cpu_mips_store_compare (CPUState *env, uint32_t value)
{
cpu_mips_update_count(env, cpu_mips_get_count(env), value);
pic_set_irq(5, 0);
}
static void mips_timer_cb (void *opaque)
{
CPUState *env;
env = opaque;
#if 1
if (logfile) {
fprintf(logfile, "%s\n", __func__);
}
#endif
cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
pic_set_irq(5, 1);
}
void cpu_mips_clock_init (CPUState *env)
{
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
env->CP0_Compare = 0;
cpu_mips_update_count(env, 1, 0);
}
static void io_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
cpu_outb(NULL, addr & 0xffff, value);
}
static uint32_t io_readb (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inb(NULL, addr & 0xffff);
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap16(value);
#endif
cpu_outw(NULL, addr & 0xffff, value);
}
static uint32_t io_readw (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inw(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap16(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
static void io_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, value);
#ifdef TARGET_WORDS_BIGENDIAN
value = bswap32(value);
#endif
cpu_outl(NULL, addr & 0xffff, value);
}
static uint32_t io_readl (void *opaque, target_phys_addr_t addr)
{
uint32_t ret = cpu_inl(NULL, addr & 0xffff);
#ifdef TARGET_WORDS_BIGENDIAN
ret = bswap32(ret);
#endif
if (logfile)
fprintf(logfile, "%s: addr %08x val %08x\n", __func__, addr, ret);
return ret;
}
CPUWriteMemoryFunc *io_write[] = {
&io_writeb,
&io_writew,
&io_writel,
};
CPUReadMemoryFunc *io_read[] = {
&io_readb,
&io_readw,
&io_readl,
};
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
const char *initrd_filename)
{
char buf[1024];
target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
unsigned long bios_offset;
int io_memory;
int linux_boot;
int ret;
printf("%s: start\n", __func__);
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
bios_offset = ram_size + vga_ram_size;
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
printf("%s: load BIOS '%s' size %d\n", __func__, buf, BIOS_SIZE);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != BIOS_SIZE) {
fprintf(stderr, "qemu: could not load MIPS bios '%s'\n", buf);
exit(1);
}
cpu_register_physical_memory((uint32_t)(0x1fc00000),
BIOS_SIZE, bios_offset | IO_MEM_ROM);
#if 0
memcpy(phys_ram_base + 0x10000, phys_ram_base + bios_offset, BIOS_SIZE);
cpu_single_env->PC = 0x80010004;
#else
cpu_single_env->PC = 0xBFC00004;
#endif
if (linux_boot) {
kernel_base = KERNEL_LOAD_ADDR;
/* now we can load the kernel */
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
kernel_filename);
exit(1);
}
/* load initrd */
if (initrd_filename) {
initrd_base = INITRD_LOAD_ADDR;
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
exit(1);
}
} else {
initrd_base = 0;
initrd_size = 0;
}
cpu_single_env->PC = KERNEL_LOAD_ADDR;
} else {
kernel_base = 0;
kernel_size = 0;
initrd_base = 0;
initrd_size = 0;
}
/* XXX: should not be ! */
printf("%s: init VGA\n", __func__);
vga_initialize(NULL, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size);
/* Init internal devices */
cpu_mips_clock_init(cpu_single_env);
cpu_mips_irqctrl_init();
isa_mem_base = 0x78000000;
/* Register 64 KB of ISA IO space at random address */
io_memory = cpu_register_io_memory(0, io_read, io_write, NULL);
cpu_register_physical_memory(0x70000000, 0x00010000, io_memory);
serial_init(0x3f8, 4, serial_hds[0]);
printf("%s: done\n", __func__);
}
QEMUMachine mips_machine = {
"mips",
"mips r4k platform",
mips_r4k_init,
};

View File

@ -55,6 +55,8 @@
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#elif defined (TARGET_PPC)
#define CPU_MEM_INDEX (msr_pr)
#elif defined (TARGET_MIPS)
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
#elif defined (TARGET_SPARC)
#define CPU_MEM_INDEX ((env->psrs) == 0)
#endif
@ -66,6 +68,8 @@
#define CPU_MEM_INDEX ((env->hflags & HF_CPL_MASK) == 3)
#elif defined (TARGET_PPC)
#define CPU_MEM_INDEX (msr_pr)
#elif defined (TARGET_MIPS)
#define CPU_MEM_INDEX ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM)
#elif defined (TARGET_SPARC)
#define CPU_MEM_INDEX ((env->psrs) == 0)
#endif

415
target-mips/cpu.h Normal file
View File

@ -0,0 +1,415 @@
#if !defined (__MIPS_CPU_H__)
#define __MIPS_CPU_H__
#include "mips-defs.h"
#include "cpu-defs.h"
#include "config.h"
#include "softfloat.h"
typedef union fpr_t fpr_t;
union fpr_t {
double d;
float f;
uint32_t u[2];
};
#if defined(MIPS_USES_R4K_TLB)
typedef struct tlb_t tlb_t;
struct tlb_t {
target_ulong VPN;
target_ulong end;
uint8_t ASID;
uint8_t G;
uint8_t C[2];
uint8_t V[2];
uint8_t D[2];
target_ulong PFN[2];
};
#endif
typedef struct CPUMIPSState CPUMIPSState;
struct CPUMIPSState {
/* General integer registers */
target_ulong gpr[32];
/* Special registers */
target_ulong PC;
uint32_t HI, LO;
uint32_t DCR; /* ? */
#if defined(MIPS_USES_FPU)
/* Floating point registers */
fpr_t fpr[16];
/* Floating point special purpose registers */
uint32_t fcr0;
uint32_t fcr25;
uint32_t fcr26;
uint32_t fcr28;
uint32_t fcsr;
#endif
#if defined(MIPS_USES_R4K_TLB)
tlb_t tlb[16];
#endif
uint32_t CP0_index;
uint32_t CP0_random;
uint32_t CP0_EntryLo0;
uint32_t CP0_EntryLo1;
uint32_t CP0_Context;
uint32_t CP0_PageMask;
uint32_t CP0_Wired;
uint32_t CP0_BadVAddr;
uint32_t CP0_Count;
uint32_t CP0_EntryHi;
uint32_t CP0_Compare;
uint32_t CP0_Status;
#define CP0St_CU3 31
#define CP0St_CU2 30
#define CP0St_CU1 29
#define CP0St_CU0 28
#define CP0St_RP 27
#define CP0St_RE 25
#define CP0St_BEV 22
#define CP0St_TS 21
#define CP0St_SR 20
#define CP0St_NMI 19
#define CP0St_IM 8
#define CP0St_UM 4
#define CP0St_ERL 2
#define CP0St_EXL 1
#define CP0St_IE 0
uint32_t CP0_Cause;
#define CP0Ca_IV 23
uint32_t CP0_EPC;
uint32_t CP0_PRid;
uint32_t CP0_Config0;
#define CP0C0_M 31
#define CP0C0_K23 28
#define CP0C0_KU 25
#define CP0C0_MDU 20
#define CP0C0_MM 17
#define CP0C0_BM 16
#define CP0C0_BE 15
#define CP0C0_AT 13
#define CP0C0_AR 10
#define CP0C0_MT 7
#define CP0C0_K0 0
uint32_t CP0_Config1;
#define CP0C1_MMU 25
#define CP0C1_IS 22
#define CP0C1_IL 19
#define CP0C1_IA 16
#define CP0C1_DS 13
#define CP0C1_DL 10
#define CP0C1_DA 7
#define CP0C1_PC 4
#define CP0C1_WR 3
#define CP0C1_CA 2
#define CP0C1_EP 1
#define CP0C1_FP 0
uint32_t CP0_LLAddr;
uint32_t CP0_WatchLo;
uint32_t CP0_WatchHi;
uint32_t CP0_Debug;
#define CPDB_DBD 31
#define CP0DB_DM 30
#define CP0DB_LSNM 28
#define CP0DB_Doze 27
#define CP0DB_Halt 26
#define CP0DB_CNT 25
#define CP0DB_IBEP 24
#define CP0DB_DBEP 21
#define CP0DB_IEXI 20
#define CP0DB_VER 15
#define CP0DB_DEC 10
#define CP0DB_SSt 8
#define CP0DB_DINT 5
#define CP0DB_DIB 4
#define CP0DB_DDBS 3
#define CP0DB_DDBL 2
#define CP0DB_DBp 1
#define CP0DB_DSS 0
uint32_t CP0_DEPC;
uint32_t CP0_TagLo;
uint32_t CP0_DataLo;
uint32_t CP0_ErrorEPC;
uint32_t CP0_DESAVE;
/* Qemu */
#if defined (USE_HOST_FLOAT_REGS) && defined(MIPS_USES_FPU)
double ft0, ft1, ft2;
#endif
struct QEMUTimer *timer; /* Internal timer */
int interrupt_request;
jmp_buf jmp_env;
int exception_index;
int error_code;
int user_mode_only; /* user mode only simulation */
uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */
#define MIPS_HFLAGS_TMASK 0x00FF
#define MIPS_HFLAG_MODE 0x001F /* execution modes */
#define MIPS_HFLAG_UM 0x0001 /* user mode */
#define MIPS_HFLAG_ERL 0x0002 /* Error mode */
#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */
#define MIPS_HFLAG_DM 0x0008 /* Debug mode */
#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */
#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */
#define MIPS_HFLAG_DS 0x0080 /* In / out of delay slot */
/* Those flags keep the branch state if the translation is interrupted
* between the branch instruction and the delay slot
*/
#define MIPS_HFLAG_BMASK 0x0F00
#define MIPS_HFLAG_B 0x0100 /* Unconditional branch */
#define MIPS_HFLAG_BC 0x0200 /* Conditional branch */
#define MIPS_HFLAG_BL 0x0400 /* Likely branch */
#define MIPS_HFLAG_BR 0x0800 /* branch to register (can't link TB) */
target_ulong btarget; /* Jump / branch target */
int bcond; /* Branch condition (if needed) */
struct TranslationBlock *current_tb; /* currently executing TB */
/* soft mmu support */
/* in order to avoid passing too many arguments to the memory
write helpers, we store some rarely used information in the CPU
context) */
target_ulong mem_write_pc; /* host pc at which the memory was
written */
unsigned long mem_write_vaddr; /* target virtual addr at which the
memory was written */
/* 0 = kernel, 1 = user (may have 2 = kernel code, 3 = user code ?) */
CPUTLBEntry tlb_read[2][CPU_TLB_SIZE];
CPUTLBEntry tlb_write[2][CPU_TLB_SIZE];
/* ice debug support */
target_ulong breakpoints[MAX_BREAKPOINTS];
int nb_breakpoints;
int singlestep_enabled; /* XXX: should use CPU single step mode instead */
/* user data */
void *opaque;
};
#include "cpu-all.h"
/* Memory access type :
* may be needed for precise access rights control and precise exceptions.
*/
enum {
/* 1 bit to define user level / supervisor access */
ACCESS_USER = 0x00,
ACCESS_SUPER = 0x01,
/* 1 bit to indicate direction */
ACCESS_STORE = 0x02,
/* Type of instruction that generated the access */
ACCESS_CODE = 0x10, /* Code fetch access */
ACCESS_INT = 0x20, /* Integer load/store access */
ACCESS_FLOAT = 0x30, /* floating point load/store access */
};
/* Exceptions */
enum {
EXCP_NONE = -1,
EXCP_RESET = 0,
EXCP_SRESET,
EXCP_DSS,
EXCP_DINT,
EXCP_NMI,
EXCP_MCHECK,
EXCP_EXT_INTERRUPT,
EXCP_DFWATCH,
EXCP_DIB, /* 8 */
EXCP_IWATCH,
EXCP_AdEL,
EXCP_AdES,
EXCP_TLBF,
EXCP_IBE,
EXCP_DBp,
EXCP_SYSCALL,
EXCP_BREAK,
EXCP_CpU, /* 16 */
EXCP_RI,
EXCP_OVERFLOW,
EXCP_TRAP,
EXCP_DDBS,
EXCP_DWATCH,
EXCP_LAE, /* 22 */
EXCP_SAE,
EXCP_LTLBL,
EXCP_TLBL,
EXCP_TLBS,
EXCP_DBE,
EXCP_DDBL,
EXCP_MTCP0 = 0x104, /* mtmsr instruction: */
/* may change privilege level */
EXCP_BRANCH = 0x108, /* branch instruction */
EXCP_ERET = 0x10C, /* return from interrupt */
EXCP_SYSCALL_USER = 0x110, /* System call in user mode only */
EXCP_FLUSH = 0x109,
};
/* MIPS opcodes */
#define EXT_SPECIAL 0x100
#define EXT_SPECIAL2 0x200
#define EXT_REGIMM 0x300
#define EXT_CP0 0x400
#define EXT_CP1 0x500
#define EXT_CP2 0x600
#define EXT_CP3 0x700
enum {
/* indirect opcode tables */
OPC_SPECIAL = 0x00,
OPC_BREGIMM = 0x01,
OPC_CP0 = 0x10,
OPC_CP1 = 0x11,
OPC_CP2 = 0x12,
OPC_CP3 = 0x13,
OPC_SPECIAL2 = 0x1C,
/* arithmetic with immediate */
OPC_ADDI = 0x08,
OPC_ADDIU = 0x09,
OPC_SLTI = 0x0A,
OPC_SLTIU = 0x0B,
OPC_ANDI = 0x0C,
OPC_ORI = 0x0D,
OPC_XORI = 0x0E,
OPC_LUI = 0x0F,
/* Jump and branches */
OPC_J = 0x02,
OPC_JAL = 0x03,
OPC_BEQ = 0x04, /* Unconditional if rs = rt = 0 (B) */
OPC_BEQL = 0x14,
OPC_BNE = 0x05,
OPC_BNEL = 0x15,
OPC_BLEZ = 0x06,
OPC_BLEZL = 0x16,
OPC_BGTZ = 0x07,
OPC_BGTZL = 0x17,
OPC_JALX = 0x1D, /* MIPS 16 only */
/* Load and stores */
OPC_LB = 0x20,
OPC_LH = 0x21,
OPC_LWL = 0x22,
OPC_LW = 0x23,
OPC_LBU = 0x24,
OPC_LHU = 0x25,
OPC_LWR = 0x26,
OPC_SB = 0x28,
OPC_SH = 0x29,
OPC_SWL = 0x2A,
OPC_SW = 0x2B,
OPC_SWR = 0x2E,
OPC_LL = 0x30,
OPC_SC = 0x38,
/* Floating point load/store */
OPC_LWC1 = 0x31,
OPC_LWC2 = 0x32,
OPC_LDC1 = 0x35,
OPC_LDC2 = 0x36,
OPC_SWC1 = 0x39,
OPC_SWC2 = 0x3A,
OPC_SDC1 = 0x3D,
OPC_SDC2 = 0x3E,
/* Cache and prefetch */
OPC_CACHE = 0x2F,
OPC_PREF = 0x33,
};
/* MIPS special opcodes */
enum {
/* Shifts */
OPC_SLL = 0x00 | EXT_SPECIAL,
/* NOP is SLL r0, r0, 0 */
/* SSNOP is SLL r0, r0, 1 */
OPC_SRL = 0x02 | EXT_SPECIAL,
OPC_SRA = 0x03 | EXT_SPECIAL,
OPC_SLLV = 0x04 | EXT_SPECIAL,
OPC_SRLV = 0x06 | EXT_SPECIAL,
OPC_SRAV = 0x07 | EXT_SPECIAL,
/* Multiplication / division */
OPC_MULT = 0x18 | EXT_SPECIAL,
OPC_MULTU = 0x19 | EXT_SPECIAL,
OPC_DIV = 0x1A | EXT_SPECIAL,
OPC_DIVU = 0x1B | EXT_SPECIAL,
/* 2 registers arithmetic / logic */
OPC_ADD = 0x20 | EXT_SPECIAL,
OPC_ADDU = 0x21 | EXT_SPECIAL,
OPC_SUB = 0x22 | EXT_SPECIAL,
OPC_SUBU = 0x23 | EXT_SPECIAL,
OPC_AND = 0x24 | EXT_SPECIAL,
OPC_OR = 0x25 | EXT_SPECIAL,
OPC_XOR = 0x26 | EXT_SPECIAL,
OPC_NOR = 0x27 | EXT_SPECIAL,
OPC_SLT = 0x2A | EXT_SPECIAL,
OPC_SLTU = 0x2B | EXT_SPECIAL,
/* Jumps */
OPC_JR = 0x08 | EXT_SPECIAL,
OPC_JALR = 0x09 | EXT_SPECIAL,
/* Traps */
OPC_TGE = 0x30 | EXT_SPECIAL,
OPC_TGEU = 0x31 | EXT_SPECIAL,
OPC_TLT = 0x32 | EXT_SPECIAL,
OPC_TLTU = 0x33 | EXT_SPECIAL,
OPC_TEQ = 0x34 | EXT_SPECIAL,
OPC_TNE = 0x36 | EXT_SPECIAL,
/* HI / LO registers load & stores */
OPC_MFHI = 0x10 | EXT_SPECIAL,
OPC_MTHI = 0x11 | EXT_SPECIAL,
OPC_MFLO = 0x12 | EXT_SPECIAL,
OPC_MTLO = 0x13 | EXT_SPECIAL,
/* Conditional moves */
OPC_MOVZ = 0x0A | EXT_SPECIAL,
OPC_MOVN = 0x0B | EXT_SPECIAL,
OPC_MOVCI = 0x01 | EXT_SPECIAL,
/* Special */
OPC_PMON = 0x05 | EXT_SPECIAL,
OPC_SYSCALL = 0x0C | EXT_SPECIAL,
OPC_BREAK = 0x0D | EXT_SPECIAL,
OPC_SYNC = 0x0F | EXT_SPECIAL,
};
enum {
/* Mutiply & xxx operations */
OPC_MADD = 0x00 | EXT_SPECIAL2,
OPC_MADDU = 0x01 | EXT_SPECIAL2,
OPC_MUL = 0x02 | EXT_SPECIAL2,
OPC_MSUB = 0x04 | EXT_SPECIAL2,
OPC_MSUBU = 0x05 | EXT_SPECIAL2,
/* Misc */
OPC_CLZ = 0x20 | EXT_SPECIAL2,
OPC_CLO = 0x21 | EXT_SPECIAL2,
/* Special */
OPC_SDBBP = 0x3F | EXT_SPECIAL2,
};
/* Branch REGIMM */
enum {
OPC_BLTZ = 0x00 | EXT_REGIMM,
OPC_BLTZL = 0x02 | EXT_REGIMM,
OPC_BGEZ = 0x01 | EXT_REGIMM,
OPC_BGEZL = 0x03 | EXT_REGIMM,
OPC_BLTZAL = 0x10 | EXT_REGIMM,
OPC_BLTZALL = 0x12 | EXT_REGIMM,
OPC_BGEZAL = 0x11 | EXT_REGIMM,
OPC_BGEZALL = 0x13 | EXT_REGIMM,
OPC_TGEI = 0x08 | EXT_REGIMM,
OPC_TGEIU = 0x09 | EXT_REGIMM,
OPC_TLTI = 0x0A | EXT_REGIMM,
OPC_TLTIU = 0x0B | EXT_REGIMM,
OPC_TEQI = 0x0C | EXT_REGIMM,
OPC_TNEI = 0x0E | EXT_REGIMM,
};
enum {
/* Coprocessor 0 (MMU) */
OPC_MFC0 = 0x00 | EXT_CP0,
OPC_MTC0 = 0x04 | EXT_CP0,
OPC_TLBR = 0x01 | EXT_CP0,
OPC_TLBWI = 0x02 | EXT_CP0,
OPC_TLBWR = 0x06 | EXT_CP0,
OPC_TLBP = 0x08 | EXT_CP0,
OPC_ERET = 0x18 | EXT_CP0,
OPC_DERET = 0x1F | EXT_CP0,
OPC_WAIT = 0x20 | EXT_CP0,
};
int cpu_mips_exec(CPUMIPSState *s);
CPUMIPSState *cpu_mips_init(void);
uint32_t cpu_mips_get_clock (void);
#endif /* !defined (__MIPS_CPU_H__) */

183
target-mips/exec.h Normal file
View File

@ -0,0 +1,183 @@
#if !defined(__QEMU_MIPS_EXEC_H__)
#define __QEMU_MIPS_EXEC_H__
#define DEBUG_OP
#include "mips-defs.h"
#include "dyngen-exec.h"
register struct CPUMIPSState *env asm(AREG0);
#if defined (USE_64BITS_REGS)
typedef int64_t host_int_t;
typedef uint64_t host_uint_t;
#else
typedef int32_t host_int_t;
typedef uint32_t host_uint_t;
#endif
register host_uint_t T0 asm(AREG1);
register host_uint_t T1 asm(AREG2);
register host_uint_t T2 asm(AREG3);
register host_int_t Ts0 asm(AREG1);
register host_int_t Ts1 asm(AREG2);
register host_int_t Ts2 asm(AREG3);
#define PARAM(n) ((uint32_t)PARAM##n)
#define SPARAM(n) ((int32_t)PARAM##n)
#if defined (USE_HOST_FLOAT_REGS)
register double FT0 asm(FREG0);
register double FT1 asm(FREG1);
register double FT2 asm(FREG2);
register float FTS0 asm(FREG0);
register float FTS1 asm(FREG1);
register float FTS2 asm(FREG2);
#else
#define FT0 (env->ft0.d)
#define FT1 (env->ft1.d)
#define FT2 (env->ft2.d)
#define FTS0 (env->ft0.f)
#define FTS1 (env->ft1.f)
#define FTS2 (env->ft2.f)
#endif
#if defined (DEBUG_OP)
#define RETURN() __asm__ __volatile__("nop");
#else
#define RETURN() __asm__ __volatile__("");
#endif
#include "cpu.h"
#include "exec-all.h"
#if !defined(CONFIG_USER_ONLY)
#define ldul_user ldl_user
#define ldul_kernel ldl_kernel
#define ACCESS_TYPE 0
#define MEMSUFFIX _kernel
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#define ACCESS_TYPE 1
#define MEMSUFFIX _user
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
/* these access are slower, they must be as rare as possible */
#define ACCESS_TYPE 2
#define MEMSUFFIX _data
#define DATA_SIZE 1
#include "softmmu_header.h"
#define DATA_SIZE 2
#include "softmmu_header.h"
#define DATA_SIZE 4
#include "softmmu_header.h"
#define DATA_SIZE 8
#include "softmmu_header.h"
#undef ACCESS_TYPE
#undef MEMSUFFIX
#define ldub(p) ldub_data(p)
#define ldsb(p) ldsb_data(p)
#define lduw(p) lduw_data(p)
#define ldsw(p) ldsw_data(p)
#define ldl(p) ldl_data(p)
#define ldq(p) ldq_data(p)
#define stb(p, v) stb_data(p, v)
#define stw(p, v) stw_data(p, v)
#define stl(p, v) stl_data(p, v)
#define stq(p, v) stq_data(p, v)
#endif /* !defined(CONFIG_USER_ONLY) */
static inline void env_to_regs(void)
{
}
static inline void regs_to_env(void)
{
}
#if (HOST_LONG_BITS == 32)
void do_mult (void);
void do_multu (void);
void do_madd (void);
void do_maddu (void);
void do_msub (void);
void do_msubu (void);
#endif
__attribute__ (( regparm(2) ))
void do_mfc0(int reg, int sel);
__attribute__ (( regparm(2) ))
void do_mtc0(int reg, int sel);
void do_tlbwi (void);
void do_tlbwr (void);
void do_tlbp (void);
void do_tlbr (void);
void do_lwl_raw (void);
void do_lwr_raw (void);
void do_swl_raw (void);
void do_swr_raw (void);
#if !defined(CONFIG_USER_ONLY)
void do_lwl_user (void);
void do_lwl_kernel (void);
void do_lwr_user (void);
void do_lwr_kernel (void);
void do_swl_user (void);
void do_swl_kernel (void);
void do_swr_user (void);
void do_swr_kernel (void);
#endif
__attribute__ (( regparm(1) ))
void do_pmon (int function);
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu);
void do_interrupt (CPUState *env);
void cpu_loop_exit(void);
__attribute__ (( regparm(2) ))
void do_raise_exception_err (uint32_t exception, int error_code);
__attribute__ (( regparm(1) ))
void do_raise_exception (uint32_t exception);
void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
void cpu_mips_irqctrl_init (void);
uint32_t cpu_mips_get_random (CPUState *env);
uint32_t cpu_mips_get_count (CPUState *env);
void cpu_mips_store_count (CPUState *env, uint32_t value);
void cpu_mips_store_compare (CPUState *env, uint32_t value);
void cpu_mips_clock_init (CPUState *env);
#endif /* !defined(__QEMU_MIPS_EXEC_H__) */

461
target-mips/helper.c Normal file
View File

@ -0,0 +1,461 @@
/*
* MIPS emulation helpers for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "exec.h"
/* MIPS32 4K MMU emulation */
#if MIPS_USES_4K_TLB
static int map_address (CPUState *env, target_ulong *physical, int *prot,
target_ulong address, int rw, int access_type)
{
tlb_t *tlb;
target_ulong tag;
uint8_t ASID;
int i, n;
int ret;
ret = -2;
tag = (address & 0xFFFFE000);
ASID = env->CP0_EntryHi & 0x000000FF;
for (i = 0; i < 16; i++) {
tlb = &env->tlb[i];
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) &&
tlb->VPN == tag && address < tlb->end) {
/* TLB match */
n = (address >> 12) & 1;
/* Check access rights */
if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) {
*physical = tlb->PFN[n] | (address & 0xFFF);
*prot = PROT_READ;
if (tlb->D[n])
*prot |= PROT_WRITE;
return 0;
} else if (!(tlb->V[n] & 2)) {
return -3;
} else {
return -4;
}
}
}
return ret;
}
#endif
int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
target_ulong address, int rw, int access_type)
{
int user_mode;
int ret;
/* User mode can only access useg */
user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0;
#if 0
if (logfile) {
fprintf(logfile, "user mode %d h %08x\n",
user_mode, env->hflags);
}
#endif
if (user_mode && address > 0x7FFFFFFFUL)
return -1;
ret = 0;
if (address < 0x80000000UL) {
if (user_mode || !(env->hflags & MIPS_HFLAG_ERL)) {
#if MIPS_USES_4K_TLB
ret = map_address(env, physical, prot, address, rw);
#else
*physical = address + 0x40000000UL;
*prot = PAGE_READ | PAGE_WRITE;
#endif
} else {
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
}
} else if (address < 0xA0000000UL) {
/* kseg0 */
/* XXX: check supervisor mode */
*physical = address - 0x80000000UL;
*prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xC0000000UL) {
/* kseg1 */
/* XXX: check supervisor mode */
*physical = address - 0xA0000000UL;
*prot = PAGE_READ | PAGE_WRITE;
} else if (address < 0xE0000000UL) {
/* kseg2 */
#if MIPS_USES_4K_TLB
ret = map_address(env, physical, prot, address, rw);
#else
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
#endif
} else {
/* kseg3 */
/* XXX: check supervisor mode */
/* XXX: debug segment is not emulated */
#if MIPS_USES_4K_TLB
ret = map_address(env, physical, prot, address, rw);
#else
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
#endif
}
#if 0
if (logfile) {
fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
access_type, *physical, *prot, ret);
}
#endif
return ret;
}
#if defined(CONFIG_USER_ONLY)
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
#else
target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
target_ulong phys_addr;
int prot;
if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
return -1;
return phys_addr;
}
#endif
#if !defined(CONFIG_USER_ONLY)
#define MMUSUFFIX _mmu
#define GETPC() (__builtin_return_address(0))
#define SHIFT 0
#include "softmmu_template.h"
#define SHIFT 1
#include "softmmu_template.h"
#define SHIFT 2
#include "softmmu_template.h"
#define SHIFT 3
#include "softmmu_template.h"
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
{
TranslationBlock *tb;
CPUState *saved_env;
unsigned long pc;
int ret;
/* XXX: hack to restore env in all cases, even if not called from
generated code */
saved_env = env;
env = cpu_single_env;
ret = cpu_mips_handle_mmu_fault(env, addr, is_write, is_user, 1);
if (ret) {
if (retaddr) {
/* now we have a real cpu fault */
pc = (unsigned long)retaddr;
tb = tb_find_pc(pc);
if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, NULL);
}
}
do_raise_exception_err(env->exception_index, env->error_code);
}
env = saved_env;
}
void cpu_mips_init_mmu (CPUState *env)
{
}
#endif /* !defined(CONFIG_USER_ONLY) */
int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu)
{
target_ulong physical;
int prot;
int exception = 0, error_code = 0;
int access_type;
int ret = 0;
if (logfile) {
cpu_dump_state(env, logfile, fprintf, 0);
fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
__func__, env->PC, address, rw, is_user, is_softmmu);
}
/* data access */
/* XXX: put correct access by using cpu_restore_state()
correctly */
access_type = ACCESS_INT;
if (env->user_mode_only) {
/* user mode only emulation */
ret = -2;
goto do_fault;
}
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",
__func__, address, ret, physical, prot);
}
if (ret == 0) {
ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot,
is_user, is_softmmu);
} else if (ret < 0) {
do_fault:
switch (ret) {
default:
case -1:
/* Reference to kernel address from user mode or supervisor mode */
/* Reference to supervisor address from user mode */
if (rw)
exception = EXCP_AdES;
else
exception = EXCP_AdEL;
break;
case -2:
/* No TLB match for a mapped address */
if (rw)
exception = EXCP_TLBS;
else
exception = EXCP_TLBL;
error_code = 1;
break;
case -3:
/* TLB match with no valid bit */
if (rw)
exception = EXCP_TLBS;
else
exception = EXCP_TLBL;
error_code = 0;
break;
case -4:
/* TLB match but 'D' bit is cleared */
exception = EXCP_LTLBL;
break;
}
if (ret == -2) {
exception = EXCP_AdEL;
}
/* Raise exception */
env->CP0_BadVAddr = address;
env->CP0_Context =
(env->CP0_Context & 0x00000FFF) | (address & 0xFFFFF000);
env->CP0_EntryHi =
(env->CP0_EntryHi & 0x00000FFF) | (address & 0xFFFFF000);
env->exception_index = exception;
env->error_code = error_code;
ret = 1;
}
return ret;
}
void do_interrupt (CPUState *env)
{
target_ulong pc, offset;
int cause = -1;
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index);
}
if (env->exception_index == EXCP_EXT_INTERRUPT &&
(env->hflags & MIPS_HFLAG_DM))
env->exception_index = EXCP_DINT;
offset = 0x180;
switch (env->exception_index) {
case EXCP_DSS:
env->CP0_Debug |= 1 << CP0DB_DSS;
/* Debug single step cannot be raised inside a delay slot and
* resume will always occur on the next instruction
* (but we assume the pc has always been updated during
* code translation).
*/
env->CP0_DEPC = env->PC;
goto enter_debug_mode;
case EXCP_DINT:
env->CP0_Debug |= 1 << CP0DB_DINT;
goto set_DEPC;
case EXCP_DIB:
env->CP0_Debug |= 1 << CP0DB_DIB;
goto set_DEPC;
case EXCP_DBp:
env->CP0_Debug |= 1 << CP0DB_DBp;
goto set_DEPC;
case EXCP_DDBS:
env->CP0_Debug |= 1 << CP0DB_DDBS;
goto set_DEPC;
case EXCP_DDBL:
env->CP0_Debug |= 1 << CP0DB_DDBL;
goto set_DEPC;
set_DEPC:
if (env->hflags & MIPS_HFLAG_DS) {
/* If the exception was raised from a delay slot,
* come back to the jump
*/
env->CP0_DEPC = env->PC - 4;
} else {
env->CP0_DEPC = env->PC;
}
enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM;
/* EJTAG probe trap enable is not implemented... */
pc = 0xBFC00480;
break;
case EXCP_RESET:
#if defined (MIPS_USES_R4K_TLB)
env->CP0_random = MIPS_TLB_NB - 1;
#endif
env->CP0_Wired = 0;
env->CP0_Config0 = MIPS_CONFIG0;
#if defined (MIPS_CONFIG1)
env->CP0_Config1 = MIPS_CONFIG1;
#endif
#if defined (MIPS_CONFIG2)
env->CP0_Config2 = MIPS_CONFIG2;
#endif
#if defined (MIPS_CONFIG3)
env->CP0_Config3 = MIPS_CONFIG3;
#endif
env->CP0_WatchLo = 0;
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
goto set_error_EPC;
case EXCP_SRESET:
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
(1 << CP0St_SR);
env->CP0_WatchLo = 0;
goto set_error_EPC;
case EXCP_NMI:
env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
(1 << CP0St_NMI);
set_error_EPC:
env->hflags = MIPS_HFLAG_ERL;
if (env->hflags & MIPS_HFLAG_DS) {
/* If the exception was raised from a delay slot,
* come back to the jump
*/
env->CP0_ErrorEPC = env->PC - 4;
} else {
env->CP0_ErrorEPC = env->PC;
}
pc = 0xBFC00000;
break;
case EXCP_MCHECK:
cause = 24;
goto set_EPC;
case EXCP_EXT_INTERRUPT:
cause = 0;
if (env->CP0_Cause & (1 << CP0Ca_IV))
offset = 0x200;
goto set_EPC;
case EXCP_DWATCH:
cause = 23;
/* XXX: TODO: manage defered watch exceptions */
goto set_EPC;
case EXCP_AdEL:
case EXCP_AdES:
cause = 4;
goto set_EPC;
case EXCP_TLBL:
case EXCP_TLBF:
cause = 2;
if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
offset = 0x000;
goto set_EPC;
case EXCP_IBE:
cause = 6;
goto set_EPC;
case EXCP_DBE:
cause = 7;
goto set_EPC;
case EXCP_SYSCALL:
cause = 8;
goto set_EPC;
case EXCP_BREAK:
cause = 9;
goto set_EPC;
case EXCP_RI:
cause = 10;
goto set_EPC;
case EXCP_CpU:
cause = 11;
/* XXX: fill in the faulty unit number */
goto set_EPC;
case EXCP_OVERFLOW:
cause = 12;
goto set_EPC;
case EXCP_TRAP:
cause = 13;
goto set_EPC;
case EXCP_LTLBL:
cause = 1;
goto set_EPC;
case EXCP_TLBS:
cause = 3;
set_EPC:
if (env->CP0_Status & (1 << CP0St_BEV)) {
pc = 0xBFC00200;
} else {
pc = 0x80000000;
}
env->hflags |= MIPS_HFLAG_EXL;
pc += offset;
env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
if (env->hflags & MIPS_HFLAG_DS) {
/* If the exception was raised from a delay slot,
* come back to the jump
*/
env->CP0_EPC = env->PC - 4;
env->CP0_Cause |= 0x80000000;
} else {
env->CP0_EPC = env->PC;
env->CP0_Cause &= ~0x80000000;
}
break;
default:
if (logfile) {
fprintf(logfile, "Invalid MIPS exception %d. Exiting\n",
env->exception_index);
}
printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
exit(1);
}
env->PC = pc;
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",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index,
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
}
env->exception_index = EXCP_NONE;
}

58
target-mips/mips-defs.h Normal file
View File

@ -0,0 +1,58 @@
#if !defined (__QEMU_MIPS_DEFS_H__)
#define __QEMU_MIPS_DEFS_H__
/* If we want to use 64 bits host regs... */
//#define USE_64BITS_REGS
/* If we want to use host float regs... */
//#define USE_HOST_FLOAT_REGS
enum {
MIPS_R4Kc = 0x00018000,
MIPS_R4Kp = 0x00018300,
};
/* Emulate MIPS R4Kc for now */
#define MIPS_CPU MIPS_R4Kc
#if (MIPS_CPU == MIPS_R4Kc)
/* 32 bits target */
#define TARGET_LONG_BITS 32
/* real pages are variable size... */
#define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
#define MIPS_USES_R4K_EXT
/* Uses MIPS R4Kc TLB model */
#define MIPS_USES_R4K_TLB
#define MIPS_TLB_NB 16
/* Have config1, runs in big-endian mode, uses TLB */
#define MIPS_CONFIG0 \
((1 << CP0C0_M) | (0x000 << CP0C0_K23) | (0x000 << CP0C0_KU) | \
(1 << CP0C0_BE) | (0x001 << CP0C0_MT) | (0x010 << CP0C0_K0))
/* 16 TLBs, 64 sets Icache, 16 bytes Icache line, 2-way Icache,
* 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
* no performance counters, watch registers present, no code compression,
* EJTAG present, no FPU
*/
#define MIPS_CONFIG1 \
((15 << CP0C1_MMU) | \
(0x000 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x01 << CP0C1_IA) | \
(0x000 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x01 << CP0C1_DA) | \
(0 << CP0C1_PC) | (1 << CP0C1_WR) | (0 << CP0C1_CA) | \
(1 << CP0C1_EP) | (0 << CP0C1_FP))
#elif defined (MIPS_CPU == MIPS_R4Kp)
/* 32 bits target */
#define TARGET_LONG_BITS 32
/* real pages are variable size... */
#define TARGET_PAGE_BITS 12
/* Uses MIPS R4Kx ehancements to MIPS32 architecture */
#define MIPS_USES_R4K_EXT
/* Uses MIPS R4Km FPM MMU model */
#define MIPS_USES_R4K_FPM
#else
#error "MIPS CPU not defined"
/* Remainder for other flags */
//#define TARGET_MIPS64
//define MIPS_USES_FPU
#endif
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */

641
target-mips/op.c Normal file
View File

@ -0,0 +1,641 @@
/*
* MIPS emulation micro-operations for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
#include "exec.h"
#define REG 1
#include "op_template.c"
#undef REG
#define REG 2
#include "op_template.c"
#undef REG
#define REG 3
#include "op_template.c"
#undef REG
#define REG 4
#include "op_template.c"
#undef REG
#define REG 5
#include "op_template.c"
#undef REG
#define REG 6
#include "op_template.c"
#undef REG
#define REG 7
#include "op_template.c"
#undef REG
#define REG 8
#include "op_template.c"
#undef REG
#define REG 9
#include "op_template.c"
#undef REG
#define REG 10
#include "op_template.c"
#undef REG
#define REG 11
#include "op_template.c"
#undef REG
#define REG 12
#include "op_template.c"
#undef REG
#define REG 13
#include "op_template.c"
#undef REG
#define REG 14
#include "op_template.c"
#undef REG
#define REG 15
#include "op_template.c"
#undef REG
#define REG 16
#include "op_template.c"
#undef REG
#define REG 17
#include "op_template.c"
#undef REG
#define REG 18
#include "op_template.c"
#undef REG
#define REG 19
#include "op_template.c"
#undef REG
#define REG 20
#include "op_template.c"
#undef REG
#define REG 21
#include "op_template.c"
#undef REG
#define REG 22
#include "op_template.c"
#undef REG
#define REG 23
#include "op_template.c"
#undef REG
#define REG 24
#include "op_template.c"
#undef REG
#define REG 25
#include "op_template.c"
#undef REG
#define REG 26
#include "op_template.c"
#undef REG
#define REG 27
#include "op_template.c"
#undef REG
#define REG 28
#include "op_template.c"
#undef REG
#define REG 29
#include "op_template.c"
#undef REG
#define REG 30
#include "op_template.c"
#undef REG
#define REG 31
#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
#include "op_template.c"
#undef TN
void op_dup_T0 (void)
{
T2 = T0;
RETURN();
}
void op_load_HI (void)
{
T0 = env->HI;
RETURN();
}
void op_store_HI (void)
{
env->HI = T0;
RETURN();
}
void op_load_LO (void)
{
T0 = env->LO;
RETURN();
}
void op_store_LO (void)
{
env->LO = T0;
RETURN();
}
/* Load and store */
#define MEMSUFFIX _raw
#include "op_mem.c"
#undef MEMSUFFIX
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
#include "op_mem.c"
#undef MEMSUFFIX
#define MEMSUFFIX _kernel
#include "op_mem.c"
#undef MEMSUFFIX
#endif
/* Arithmetic */
void op_add (void)
{
T0 += T1;
RETURN();
}
void op_addo (void)
{
target_ulong tmp;
tmp = T0;
T0 += T1;
if ((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31)) {
CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
RETURN();
}
void op_sub (void)
{
T0 -= T1;
RETURN();
}
void op_subo (void)
{
target_ulong tmp;
tmp = T0;
T0 = (int32_t)T0 - (int32_t)T1;
if (!((T0 >> 31) ^ (T1 >> 31) ^ (tmp >> 31))) {
CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
RETURN();
}
void op_mul (void)
{
T0 = (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;
}
RETURN();
}
void op_divu (void)
{
if (T1 != 0) {
env->LO = T0 / T1;
env->HI = T0 % T1;
}
RETURN();
}
/* Logical */
void op_and (void)
{
T0 &= T1;
RETURN();
}
void op_nor (void)
{
T0 = ~(T0 | T1);
RETURN();
}
void op_or (void)
{
T0 |= T1;
RETURN();
}
void op_xor (void)
{
T0 ^= T1;
RETURN();
}
void op_sll (void)
{
T0 = T0 << T1;
RETURN();
}
void op_sra (void)
{
T0 = (int32_t)T0 >> T1;
RETURN();
}
void op_srl (void)
{
T0 = T0 >> T1;
RETURN();
}
void op_sllv (void)
{
T0 = T1 << (T0 & 0x1F);
RETURN();
}
void op_srav (void)
{
T0 = (int32_t)T1 >> (T0 & 0x1F);
RETURN();
}
void op_srlv (void)
{
T0 = T1 >> (T0 & 0x1F);
RETURN();
}
void op_clo (void)
{
int n;
if (T0 == (target_ulong)-1) {
T0 = 32;
} else {
for (n = 0; n < 32; n++) {
if (!(T0 & (1 << 31)))
break;
T0 = T0 << 1;
}
T0 = n;
}
RETURN();
}
void op_clz (void)
{
int n;
if (T0 == 0) {
T0 = 32;
} else {
for (n = 0; n < 32; n++) {
if (T0 & (1 << 31))
break;
T0 = T0 << 1;
}
T0 = n;
}
RETURN();
}
/* 64 bits arithmetic */
#if (HOST_LONG_BITS == 64)
static inline uint64_t get_HILO (void)
{
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
}
static inline void set_HILO (uint64_t HILO)
{
env->LO = HILO & 0xFFFFFFFF;
env->HI = HILO >> 32;
}
void op_mult (void)
{
set_HILO((int64_t)T0 * (int64_t)T1);
RETURN();
}
void op_multu (void)
{
set_HILO((uint64_t)T0 * (uint64_t)T1);
RETURN();
}
void op_madd (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() + tmp);
RETURN();
}
void op_maddu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() + tmp);
RETURN();
}
void op_msub (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() - tmp);
RETURN();
}
void op_msubu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() - tmp);
RETURN();
}
#else
void op_mult (void)
{
CALL_FROM_TB0(do_mult);
RETURN();
}
void op_multu (void)
{
CALL_FROM_TB0(do_multu);
RETURN();
}
void op_madd (void)
{
CALL_FROM_TB0(do_madd);
RETURN();
}
void op_maddu (void)
{
CALL_FROM_TB0(do_maddu);
RETURN();
}
void op_msub (void)
{
CALL_FROM_TB0(do_msub);
RETURN();
}
void op_msubu (void)
{
CALL_FROM_TB0(do_msubu);
RETURN();
}
#endif
/* Conditional moves */
void op_movn (void)
{
if (T1 != 0)
env->gpr[PARAM1] = T0;
RETURN();
}
void op_movz (void)
{
if (T1 == 0)
env->gpr[PARAM1] = T0;
RETURN();
}
/* Tests */
#define OP_COND(name, cond) \
void glue(op_, name) (void) \
{ \
if (cond) { \
T0 = 1; \
} else { \
T0 = 0; \
} \
RETURN(); \
}
OP_COND(eq, T0 == T1);
OP_COND(ne, T0 != T1);
OP_COND(ge, (int32_t)T0 >= (int32_t)T1);
OP_COND(geu, T0 >= T1);
OP_COND(lt, (int32_t)T0 < (int32_t)T1);
OP_COND(ltu, T0 < T1);
OP_COND(gez, (int32_t)T0 >= 0);
OP_COND(gtz, (int32_t)T0 > 0);
OP_COND(lez, (int32_t)T0 <= 0);
OP_COND(ltz, (int32_t)T0 < 0);
/* Branchs */
//#undef USE_DIRECT_JUMP
#define EIP env->PC
/* Branch to register */
void op_save_breg_target (void)
{
env->btarget = T2;
}
void op_restore_breg_target (void)
{
T2 = env->btarget;
}
void op_breg (void)
{
env->PC = T2;
RETURN();
}
/* Unconditional branch */
void op_branch (void)
{
JUMP_TB(branch, PARAM1, 0, PARAM2);
RETURN();
}
void op_save_btarget (void)
{
env->btarget = PARAM1;
RETURN();
}
/* Conditional branch */
void op_set_bcond (void)
{
T2 = T0;
RETURN();
}
void op_save_bcond (void)
{
env->bcond = T2;
RETURN();
}
void op_restore_bcond (void)
{
T2 = env->bcond;
RETURN();
}
void op_bcond (void)
{
if (T2) {
JUMP_TB(bcond, PARAM1, 0, PARAM2);
} else {
JUMP_TB(bcond, PARAM1, 1, PARAM3);
}
RETURN();
}
/* Likely branch (used to skip the delay slot) */
void op_blikely (void)
{
/* If the test is false, skip the delay slot */
if (T2 == 0) {
env->hflags = PARAM3;
JUMP_TB(blikely, PARAM1, 1, PARAM2);
}
RETURN();
}
/* CP0 functions */
void op_mfc0 (void)
{
CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
RETURN();
}
void op_mtc0 (void)
{
CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
RETURN();
}
#if defined(MIPS_USES_R4K_TLB)
void op_tlbwi (void)
{
CALL_FROM_TB0(do_tlbwi);
RETURN();
}
void op_tlbwr (void)
{
CALL_FROM_TB0(do_tlbwr);
RETURN();
}
void op_tlbp (void)
{
CALL_FROM_TB0(do_tlbp);
RETURN();
}
void op_tlbr (void)
{
CALL_FROM_TB0(do_tlbr);
RETURN();
}
#endif
/* Specials */
void op_pmon (void)
{
CALL_FROM_TB1(do_pmon, PARAM1);
}
void op_trap (void)
{
if (T0) {
CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
}
RETURN();
}
void op_set_lladdr (void)
{
env->CP0_LLAddr = T2;
}
void debug_eret (void);
void op_eret (void)
{
CALL_FROM_TB0(debug_eret);
if (env->hflags & MIPS_HFLAG_ERL)
env->PC = env->CP0_ErrorEPC;
else
env->PC = env->CP0_EPC;
env->CP0_LLAddr = 1;
}
void op_deret (void)
{
CALL_FROM_TB0(debug_eret);
env->PC = env->CP0_DEPC;
}
void op_save_state (void)
{
env->hflags = PARAM1;
RETURN();
}
void op_save_pc (void)
{
env->PC = PARAM1;
RETURN();
}
void op_raise_exception (void)
{
CALL_FROM_TB1(do_raise_exception, PARAM1);
RETURN();
}
void op_raise_exception_err (void)
{
CALL_FROM_TB2(do_raise_exception_err, PARAM1, PARAM2);
RETURN();
}
void op_exit_tb (void)
{
EXIT_TB();
}

634
target-mips/op_helper.c Normal file
View File

@ -0,0 +1,634 @@
/*
* MIPS emulation helpers for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <math.h>
#include "exec.h"
#define MIPS_DEBUG_DISAS
/*****************************************************************************/
/* Exceptions processing helpers */
void cpu_loop_exit(void)
{
longjmp(env->jmp_env, 1);
}
__attribute__ (( regparm(2) ))
void do_raise_exception_err (uint32_t exception, int error_code)
{
#if 1
if (logfile && exception < 0x100)
fprintf(logfile, "%s: %d %d\n", __func__, exception, error_code);
#endif
env->exception_index = exception;
env->error_code = error_code;
T0 = 0;
cpu_loop_exit();
}
__attribute__ (( regparm(1) ))
void do_raise_exception (uint32_t exception)
{
do_raise_exception_err(exception, 0);
}
#define MEMSUFFIX _raw
#include "op_helper_mem.c"
#undef MEMSUFFIX
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
#include "op_helper_mem.c"
#undef MEMSUFFIX
#define MEMSUFFIX _kernel
#include "op_helper_mem.c"
#undef MEMSUFFIX
#endif
/* 64 bits arithmetic for 32 bits hosts */
#if (HOST_LONG_BITS == 32)
static inline uint64_t get_HILO (void)
{
return ((uint64_t)env->HI << 32) | (uint64_t)env->LO;
}
static inline void set_HILO (uint64_t HILO)
{
env->LO = HILO & 0xFFFFFFFF;
env->HI = HILO >> 32;
}
void do_mult (void)
{
set_HILO((int64_t)T0 * (int64_t)T1);
}
void do_multu (void)
{
set_HILO((uint64_t)T0 * (uint64_t)T1);
}
void do_madd (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() + tmp);
}
void do_maddu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() + tmp);
}
void do_msub (void)
{
int64_t tmp;
tmp = ((int64_t)T0 * (int64_t)T1);
set_HILO((int64_t)get_HILO() - tmp);
}
void do_msubu (void)
{
uint64_t tmp;
tmp = ((uint64_t)T0 * (uint64_t)T1);
set_HILO(get_HILO() - tmp);
}
#endif
/* CP0 helpers */
__attribute__ (( regparm(2) ))
void do_mfc0 (int reg, int sel)
{
const unsigned char *rn;
if (sel != 0 && reg != 16 && reg != 28) {
rn = "invalid";
goto print;
}
switch (reg) {
case 0:
T0 = env->CP0_index;
rn = "Index";
break;
case 1:
T0 = cpu_mips_get_random(env);
rn = "Random";
break;
case 2:
T0 = env->CP0_EntryLo0;
rn = "EntryLo0";
break;
case 3:
T0 = env->CP0_EntryLo1;
rn = "EntryLo1";
break;
case 4:
T0 = env->CP0_Context;
rn = "Context";
break;
case 5:
T0 = env->CP0_PageMask;
rn = "PageMask";
break;
case 6:
T0 = env->CP0_Wired;
rn = "Wired";
break;
case 8:
T0 = env->CP0_BadVAddr;
rn = "BadVaddr";
break;
case 9:
T0 = cpu_mips_get_count(env);
rn = "Count";
break;
case 10:
T0 = env->CP0_EntryHi;
rn = "EntryHi";
break;
case 11:
T0 = env->CP0_Compare;
rn = "Compare";
break;
case 12:
T0 = env->CP0_Status;
if (env->hflags & MIPS_HFLAG_UM)
T0 |= CP0St_UM;
if (env->hflags & MIPS_HFLAG_ERL)
T0 |= CP0St_ERL;
if (env->hflags & MIPS_HFLAG_EXL)
T0 |= CP0St_EXL;
rn = "Status";
break;
case 13:
T0 = env->CP0_Cause;
rn = "Cause";
break;
case 14:
T0 = env->CP0_EPC;
rn = "EPC";
break;
case 15:
T0 = env->CP0_PRid;
rn = "PRid";
break;
case 16:
switch (sel) {
case 0:
T0 = env->CP0_Config0;
rn = "Config";
break;
case 1:
T0 = env->CP0_Config1;
rn = "Config1";
break;
default:
rn = "Unknown config register";
break;
}
break;
case 17:
T0 = env->CP0_LLAddr >> 4;
rn = "LLAddr";
break;
case 18:
T0 = env->CP0_WatchLo;
rn = "WatchLo";
break;
case 19:
T0 = env->CP0_WatchHi;
rn = "WatchHi";
break;
case 23:
T0 = env->CP0_Debug;
if (env->hflags & MIPS_HFLAG_DM)
T0 |= 1 << CP0DB_DM;
rn = "Debug";
break;
case 24:
T0 = env->CP0_DEPC;
rn = "DEPC";
break;
case 28:
switch (sel) {
case 0:
T0 = env->CP0_TagLo;
rn = "TagLo";
break;
case 1:
T0 = env->CP0_DataLo;
rn = "DataLo";
break;
default:
rn = "unknown sel";
break;
}
break;
case 30:
T0 = env->CP0_ErrorEPC;
rn = "ErrorEPC";
break;
case 31:
T0 = env->CP0_DESAVE;
rn = "DESAVE";
break;
default:
rn = "unknown";
break;
}
print:
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
env->PC, rn, T0, reg, sel);
}
#endif
return;
}
__attribute__ (( regparm(2) ))
void do_mtc0 (int reg, int sel)
{
const unsigned char *rn;
uint32_t val, old, mask;
int i, raise;
if (sel != 0 && reg != 16 && reg != 28) {
val = -1;
old = -1;
rn = "invalid";
goto print;
}
switch (reg) {
case 0:
val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
old = env->CP0_index;
env->CP0_index = val;
rn = "Index";
break;
case 2:
val = T0 & 0x03FFFFFFF;
old = env->CP0_EntryLo0;
env->CP0_EntryLo0 = val;
rn = "EntryLo0";
break;
case 3:
val = T0 & 0x03FFFFFFF;
old = env->CP0_EntryLo1;
env->CP0_EntryLo1 = val;
rn = "EntryLo1";
break;
case 4:
val = (env->CP0_Context & 0xFF000000) | (T0 & 0x00FFFFF0);
old = env->CP0_Context;
env->CP0_Context = val;
rn = "Context";
break;
case 5:
val = T0 & 0x01FFE000;
old = env->CP0_PageMask;
env->CP0_PageMask = val;
rn = "PageMask";
break;
case 6:
val = T0 & 0x0000000F;
old = env->CP0_Wired;
env->CP0_Wired = val;
rn = "Wired";
break;
case 9:
val = T0;
old = cpu_mips_get_count(env);
cpu_mips_store_count(env, val);
rn = "Count";
break;
case 10:
val = T0 & 0xFFFFF0FF;
old = env->CP0_EntryHi;
env->CP0_EntryHi = val;
rn = "EntryHi";
break;
case 11:
val = T0;
old = env->CP0_Compare;
cpu_mips_store_compare(env, val);
rn = "Compare";
break;
case 12:
val = T0 & 0xFA78FF01;
if (T0 & (1 << CP0St_UM))
env->hflags |= MIPS_HFLAG_UM;
else
env->hflags &= ~MIPS_HFLAG_UM;
if (T0 & (1 << CP0St_ERL))
env->hflags |= MIPS_HFLAG_ERL;
else
env->hflags &= ~MIPS_HFLAG_ERL;
if (T0 & (1 << CP0St_EXL))
env->hflags |= MIPS_HFLAG_EXL;
else
env->hflags &= ~MIPS_HFLAG_EXL;
old = env->CP0_Status;
env->CP0_Status = val;
/* If we unmasked an asserted IRQ, raise it */
mask = 0x0000FC00;
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
old, val, env->CP0_Cause, old & mask, val & mask,
env->CP0_Cause & mask);
}
#if 1
if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
!(env->hflags & MIPS_HFLAG_EXL) &&
!(env->hflags & MIPS_HFLAG_ERL) &&
!(env->hflags & MIPS_HFLAG_DM) &&
(env->CP0_Cause & mask)) {
if (logfile)
fprintf(logfile, "Raise pending IRQs\n");
env->interrupt_request |= CPU_INTERRUPT_HARD;
do_raise_exception(EXCP_EXT_INTERRUPT);
} else if (!(val & 0x00000001) && (old & 0x00000001)) {
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
}
#endif
rn = "Status";
break;
case 13:
val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
old = env->CP0_Cause;
env->CP0_Cause = val;
#if 0
/* Check if we ever asserted a software IRQ */
for (i = 0; i < 2; i++) {
mask = 0x100 << i;
if ((val & mask) & !(old & mask))
mips_set_irq(i);
}
#endif
rn = "Cause";
break;
case 14:
val = T0;
old = env->CP0_EPC;
env->CP0_EPC = val;
rn = "EPC";
break;
case 16:
switch (sel) {
case 0:
#if defined(MIPS_USES_R4K_TLB)
val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
#else
val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
#endif
old = env->CP0_Config0;
env->CP0_Config0 = val;
rn = "Config0";
break;
default:
val = -1;
old = -1;
rn = "bad config selector";
break;
}
break;
case 18:
val = T0;
old = env->CP0_WatchLo;
env->CP0_WatchLo = val;
rn = "WatchLo";
break;
case 19:
val = T0 & 0x40FF0FF8;
old = env->CP0_WatchHi;
env->CP0_WatchHi = val;
rn = "WatchHi";
break;
case 23:
val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
if (T0 & (1 << CP0DB_DM))
env->hflags |= MIPS_HFLAG_DM;
else
env->hflags &= ~MIPS_HFLAG_DM;
old = env->CP0_Debug;
env->CP0_Debug = val;
rn = "Debug";
break;
case 24:
val = T0;
old = env->CP0_DEPC;
env->CP0_DEPC = val;
rn = "DEPC";
break;
case 28:
switch (sel) {
case 0:
val = T0 & 0xFFFFFCF6;
old = env->CP0_TagLo;
env->CP0_TagLo = val;
rn = "TagLo";
break;
default:
val = -1;
old = -1;
rn = "invalid sel";
break;
}
break;
case 30:
val = T0;
old = env->CP0_ErrorEPC;
env->CP0_ErrorEPC = val;
rn = "EPC";
break;
case 31:
val = T0;
old = env->CP0_DESAVE;
env->CP0_DESAVE = val;
rn = "DESAVE";
break;
default:
val = -1;
old = -1;
rn = "unknown";
break;
}
print:
#if defined MIPS_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
env->PC, rn, T0, val, reg, sel, old);
}
#endif
return;
}
/* TLB management */
#if defined(MIPS_USES_R4K_TLB)
__attribute__ (( regparm(1) ))
static void invalidate_tb (int idx)
{
tlb_t *tlb;
target_ulong addr, end;
tlb = &env->tlb[idx];
if (tlb->V[0]) {
addr = tlb->PFN[0];
end = addr + (tlb->end - tlb->VPN);
tb_invalidate_page_range(addr, end);
}
if (tlb->V[1]) {
addr = tlb->PFN[1];
end = addr + (tlb->end - tlb->VPN);
tb_invalidate_page_range(addr, end);
}
}
__attribute__ (( regparm(1) ))
static void fill_tb (int idx)
{
tlb_t *tlb;
int size;
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
tlb = &env->tlb[idx];
tlb->VPN = env->CP0_EntryHi & 0xFFFFE000;
tlb->ASID = env->CP0_EntryHi & 0x000000FF;
size = env->CP0_PageMask >> 13;
size = 4 * (size + 1);
tlb->end = tlb->VPN + (1 << (8 + size));
tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
tlb->V[0] = env->CP0_EntryLo0 & 2;
tlb->D[0] = env->CP0_EntryLo0 & 4;
tlb->C[0] = (env->CP0_EntryLo0 >> 3) & 0x7;
tlb->PFN[0] = (env->CP0_EntryLo0 >> 6) << 12;
tlb->V[1] = env->CP0_EntryLo1 & 2;
tlb->D[1] = env->CP0_EntryLo1 & 4;
tlb->C[1] = (env->CP0_EntryLo1 >> 3) & 0x7;
tlb->PFN[1] = (env->CP0_EntryLo1 >> 6) << 12;
}
void do_tlbwi (void)
{
invalidate_tb(env->CP0_index & 0xF);
fill_tb(env->CP0_index & 0xF);
}
void do_tlbwr (void)
{
int r = cpu_mips_get_random(env);
invalidate_tb(r);
fill_tb(r);
}
void do_tlbp (void)
{
tlb_t *tlb;
target_ulong tag;
uint8_t ASID;
int i;
tag = (env->CP0_EntryHi & 0xFFFFE000);
ASID = env->CP0_EntryHi & 0x000000FF;
for (i = 0; i < 16; i++) {
tlb = &env->tlb[i];
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
/* TLB match */
env->CP0_index = i;
break;
}
}
if (i == 16) {
env->CP0_index |= 0x80000000;
}
}
void do_tlbr (void)
{
tlb_t *tlb;
int size;
tlb = &env->tlb[env->CP0_index & 0xF];
env->CP0_EntryHi = tlb->VPN | tlb->ASID;
size = (tlb->end - tlb->VPN) >> 12;
env->CP0_PageMask = (size - 1) << 13;
env->CP0_EntryLo0 = tlb->V[0] | tlb->D[0] | (tlb->C[0] << 3) |
(tlb->PFN[0] >> 6);
env->CP0_EntryLo1 = tlb->V[1] | tlb->D[1] | (tlb->C[1] << 3) |
(tlb->PFN[1] >> 6);
}
#endif
__attribute__ (( regparm(1) ))
void op_dump_ldst (const unsigned char *func)
{
if (loglevel)
fprintf(logfile, "%s => %08x %08x\n", __func__, T0, T1);
}
void dump_sc (void)
{
if (loglevel) {
fprintf(logfile, "%s %08x at %08x (%08x)\n", __func__,
T1, T0, env->CP0_LLAddr);
}
}
void debug_eret (void)
{
if (loglevel) {
fprintf(logfile, "ERET: pc %08x EPC %08x ErrorEPC %08x (%d)\n",
env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
}
}
__attribute__ (( regparm(1) ))
void do_pmon (int function)
{
function /= 2;
switch (function) {
case 2: /* TODO: char inbyte(int waitflag); */
if (env->gpr[4] == 0)
env->gpr[2] = -1;
/* Fall through */
case 11: /* TODO: char inbyte (void); */
env->gpr[2] = -1;
break;
case 3:
case 12:
printf("%c", env->gpr[4] & 0xFF);
break;
case 17:
break;
case 158:
{
unsigned char *fmt = (void *)env->gpr[4];
printf("%s", fmt);
}
break;
}
}

143
target-mips/op_helper_mem.c Normal file
View File

@ -0,0 +1,143 @@
void glue(do_lwl, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav = T0;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
T0 = tmp;
break;
case 1:
T0 = (tmp << 8) | (T1 & 0x000000FF);
break;
case 2:
T0 = (tmp << 16) | (T1 & 0x0000FFFF);
break;
case 3:
T0 = (tmp << 24) | (T1 & 0x00FFFFFF);
break;
}
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, sav, tmp, T1, T0);
}
#endif
RETURN();
}
void glue(do_lwr, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav = T0;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
T0 = (tmp >> 24) | (T1 & 0xFFFFFF00);
break;
case 1:
T0 = (tmp >> 16) | (T1 & 0xFFFF0000);
break;
case 2:
T0 = (tmp >> 8) | (T1 & 0xFF000000);
break;
case 3:
T0 = tmp;
break;
}
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, sav, tmp, T1, T0);
}
#endif
RETURN();
}
void glue(do_swl, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
#if defined (DEBUG_OP)
sav = tmp;
#endif
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
tmp = T1;
break;
case 1:
tmp = (tmp & 0xFF000000) | (T1 >> 8);
break;
case 2:
tmp = (tmp & 0xFFFF0000) | (T1 >> 16);
break;
case 3:
tmp = (tmp & 0xFFFFFF00) | (T1 >> 24);
break;
}
glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, T0, sav, T1, tmp);
}
#endif
RETURN();
}
void glue(do_swr, MEMSUFFIX) (void)
{
#if defined (DEBUG_OP)
target_ulong sav;
#endif
uint32_t tmp;
tmp = glue(ldl, MEMSUFFIX)(T0 & ~3);
#if defined (DEBUG_OP)
sav = tmp;
#endif
/* XXX: this is valid only in big-endian mode
* should be reverted for little-endian...
*/
switch (T0 & 3) {
case 0:
tmp = (tmp & 0x00FFFFFF) | (T1 << 24);
break;
case 1:
tmp = (tmp & 0x0000FFFF) | (T1 << 16);
break;
case 2:
tmp = (tmp & 0x000000FF) | (T1 << 8);
break;
case 3:
tmp = T1;
break;
}
glue(stl, MEMSUFFIX)(T0 & ~3, tmp);
#if defined (DEBUG_OP)
if (logfile) {
fprintf(logfile, "%s: %08x - %08x %08x => %08x\n",
__func__, T0, sav, T1, tmp);
}
#endif
RETURN();
}

113
target-mips/op_mem.c Normal file
View File

@ -0,0 +1,113 @@
/*
* MIPS emulation memory micro-operations for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Standard loads and stores */
void glue(op_lb, MEMSUFFIX) (void)
{
T0 = glue(ldsb, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_lbu, MEMSUFFIX) (void)
{
T0 = glue(ldub, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_sb, MEMSUFFIX) (void)
{
glue(stb, MEMSUFFIX)(T0, T1);
RETURN();
}
void glue(op_lh, MEMSUFFIX) (void)
{
T0 = glue(ldsw, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_lhu, MEMSUFFIX) (void)
{
T0 = glue(lduw, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_sh, MEMSUFFIX) (void)
{
glue(stw, MEMSUFFIX)(T0, T1);
RETURN();
}
void glue(op_lw, MEMSUFFIX) (void)
{
T0 = glue(ldl, MEMSUFFIX)(T0);
RETURN();
}
void glue(op_sw, MEMSUFFIX) (void)
{
glue(stl, MEMSUFFIX)(T0, T1);
RETURN();
}
/* "half" load and stores */
void glue(op_lwl, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_lwl, MEMSUFFIX));
RETURN();
}
void glue(op_lwr, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_lwr, MEMSUFFIX));
RETURN();
}
void glue(op_swl, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_swl, MEMSUFFIX));
RETURN();
}
void glue(op_swr, MEMSUFFIX) (void)
{
CALL_FROM_TB0(glue(do_swr, MEMSUFFIX));
RETURN();
}
void glue(op_ll, MEMSUFFIX) (void)
{
T1 = T0;
T0 = glue(ldl, MEMSUFFIX)(T0);
env->CP0_LLAddr = T1;
RETURN();
}
void glue(op_sc, MEMSUFFIX) (void)
{
CALL_FROM_TB0(dump_sc);
if (T0 == env->CP0_LLAddr) {
glue(stl, MEMSUFFIX)(T0, T1);
T0 = 1;
} else {
T0 = 0;
}
RETURN();
}

65
target-mips/op_template.c Normal file
View File

@ -0,0 +1,65 @@
/*
* MIPS emulation micro-operations templates for reg load & store for qemu.
*
* Copyright (c) 2004-2005 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#if defined(REG)
void glue(op_load_gpr_T0_gpr, REG) (void)
{
T0 = env->gpr[REG];
RETURN();
}
void glue(op_store_T0_gpr_gpr, REG) (void)
{
env->gpr[REG] = T0;
RETURN();
}
void glue(op_load_gpr_T1_gpr, REG) (void)
{
T1 = env->gpr[REG];
RETURN();
}
void glue(op_store_T1_gpr_gpr, REG) (void)
{
env->gpr[REG] = T1;
RETURN();
}
void glue(op_load_gpr_T2_gpr, REG) (void)
{
T2 = env->gpr[REG];
RETURN();
}
#endif
#if defined (TN)
void glue(op_set_, TN) (void)
{
TN = PARAM1;
RETURN();
}
void glue (op_reset_, TN) (void)
{
TN = 0;
RETURN();
}
#endif

1505
target-mips/translate.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -300,6 +300,8 @@ int cpu_restore_state(TranslationBlock *tb,
}
env->access_type = type;
}
#elif defined(TARGET_MIPS)
env->PC = gen_opc_pc[j];
#endif
return 0;
}

13
vl.c
View File

@ -2348,6 +2348,17 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
{
return 0;
}
#elif defined(TARGET_MIPS)
void cpu_save(QEMUFile *f, void *opaque)
{
}
int cpu_load(QEMUFile *f, void *opaque, int version_id)
{
return 0;
}
#elif defined(TARGET_SPARC)
void cpu_save(QEMUFile *f, void *opaque)
{
@ -3058,6 +3069,8 @@ void register_machines(void)
qemu_register_machine(&heathrow_machine);
qemu_register_machine(&core99_machine);
qemu_register_machine(&prep_machine);
#elif defined(TARGET_MIPS)
qemu_register_machine(&mips_machine);
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
qemu_register_machine(&sun4u_machine);

5
vl.h
View File

@ -138,6 +138,8 @@ extern int win2k_install_hack;
/* XXX: make it dynamic */
#if defined (TARGET_PPC)
#define BIOS_SIZE (512 * 1024)
#elif defined(TARGET_MIPS)
#define BIOS_SIZE (128 * 1024)
#else
#define BIOS_SIZE ((256 + 64) * 1024)
#endif
@ -715,6 +717,9 @@ extern QEMUMachine prep_machine;
extern QEMUMachine core99_machine;
extern QEMUMachine heathrow_machine;
/* mips_r4k.c */
extern QEMUMachine mips_machine;
#ifdef TARGET_PPC
ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq);
#endif