Commit 0633879f authored by pbrook's avatar pbrook
Browse files

m68k/ColdFire system emulation.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2851 c046a42c-6fe2-441c-8c8c-71466251a162
parent 9daea906
......@@ -308,7 +308,7 @@ LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), m68k)
LIBOBJS+= helper.o
LIBOBJS+= op_helper.o helper.o
endif
ifeq ($(TARGET_BASE_ARCH), alpha)
......@@ -466,6 +466,9 @@ endif
ifeq ($(TARGET_BASE_ARCH), sh4)
VL_OBJS+= shix.o sh7750.o sh7750_regnames.o tc58128.o
endif
ifeq ($(TARGET_BASE_ARCH), m68k)
VL_OBJS+= an5206.o mcf5206.o ptimer.o
endif
ifdef CONFIG_GDBSTUB
VL_OBJS+=gdbstub.o
endif
......
......@@ -467,7 +467,7 @@ fi
if test -z "$target_list" ; then
# these targets are portable
if [ "$softmmu" = "yes" ] ; then
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu "
target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu m68k-softmmu"
fi
# the following are Linux specific
if [ "$linux_user" = "yes" ] ; then
......
......@@ -196,7 +196,7 @@ static inline TranslationBlock *tb_find_fast(void)
cs_base = 0;
pc = env->PC;
#elif defined(TARGET_M68K)
flags = env->fpcr & M68K_FPCR_PREC;
flags = (env->fpcr & M68K_FPCR_PREC) | (env->sr & SR_S);
cs_base = 0;
pc = env->pc;
#elif defined(TARGET_SH4)
......@@ -297,7 +297,7 @@ int cpu_exec(CPUState *env1)
return EXCP_HALTED;
}
}
#elif defined(TARGET_ALPHA)
#elif defined(TARGET_ALPHA) || defined(TARGET_M68K)
if (env1->halted) {
if (env1->interrupt_request & CPU_INTERRUPT_HARD) {
env1->halted = 0;
......@@ -390,6 +390,8 @@ int cpu_exec(CPUState *env1)
do_interrupt(env);
#elif defined(TARGET_ALPHA)
do_interrupt(env);
#elif defined(TARGET_M68K)
do_interrupt(0);
#endif
}
env->exception_index = -1;
......@@ -542,6 +544,18 @@ int cpu_exec(CPUState *env1)
if (interrupt_request & CPU_INTERRUPT_HARD) {
do_interrupt(env);
}
#elif defined(TARGET_M68K)
if (interrupt_request & CPU_INTERRUPT_HARD
&& ((env->sr & SR_I) >> SR_I_SHIFT)
< env->pending_level) {
/* Real hardware gets the interrupt vector via an
IACK cycle at this point. Current emulated
hardware doesn't rely on this, so we
provide/save the vector when the interrupt is
first signalled. */
env->exception_index = env->pending_vector;
do_interrupt(1);
}
#endif
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
......
......@@ -584,6 +584,8 @@ static inline target_ulong get_phys_addr_code(CPUState *env, target_ulong addr)
is_user = ((env->sr & SR_MD) == 0);
#elif defined (TARGET_ALPHA)
is_user = ((env->ps >> 3) & 3);
#elif defined (TARGET_M68K)
is_user = ((env->sr & SR_S) == 0);
#else
#error unimplemented CPU
#endif
......
/*
* Arnewsh 5206 ColdFire system emulation.
*
* Copyright (c) 2007 CodeSourcery.
*
* This code is licenced under the GPL
*/
#include "vl.h"
#define KERNEL_LOAD_ADDR 0x10000
#define AN5206_MBAR_ADDR 0x10000000
#define AN5206_RAMBAR_ADDR 0x20000000
/* Stub functions for hardware that doesn't exist. */
void pic_info(void)
{
}
void irq_info(void)
{
}
void DMA_run (void)
{
}
/* Board init. */
static void an5206_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, const char *cpu_model)
{
CPUState *env;
int kernel_size;
uint64_t elf_entry;
target_ulong entry;
env = cpu_init();
if (!cpu_model)
cpu_model = "m5206";
cpu_m68k_set_model(env, cpu_model);
/* Initialize CPU registers. */
env->vbr = 0;
/* TODO: allow changing MBAR and RAMBAR. */
env->mbar = AN5206_MBAR_ADDR | 1;
env->rambar0 = AN5206_RAMBAR_ADDR | 1;
/* DRAM at address zero */
cpu_register_physical_memory(0, ram_size,
qemu_ram_alloc(ram_size) | IO_MEM_RAM);
/* Internal SRAM. */
cpu_register_physical_memory(AN5206_RAMBAR_ADDR, 512,
qemu_ram_alloc(512) | IO_MEM_RAM);
mcf5206_init(AN5206_MBAR_ADDR, env);
/* Load kernel. */
if (!kernel_filename) {
fprintf(stderr, "Kernel image must be specified\n");
exit(1);
}
kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
entry = elf_entry;
if (kernel_size < 0) {
kernel_size = load_uboot(kernel_filename, &entry, NULL);
}
if (kernel_size < 0) {
kernel_size = load_image(kernel_filename,
phys_ram_base + KERNEL_LOAD_ADDR);
entry = KERNEL_LOAD_ADDR;
}
if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
exit(1);
}
env->pc = entry;
}
QEMUMachine an5206_machine = {
"an5206",
"Arnewsh 5206",
an5206_init,
};
This diff is collapsed.
......@@ -1977,13 +1977,12 @@ int main(int argc, char **argv)
}
#elif defined(TARGET_M68K)
{
m68k_def_t *def;
def = m68k_find_by_name("cfv4e");
if (def == NULL) {
if (cpu_model == NULL)
cpu_model = "cfv4e";
if (cpu_m68k_set_model(env, cpu_model)) {
cpu_abort(cpu_single_env,
"Unable to find m68k CPU definition\n");
}
cpu_m68k_register(cpu_single_env, def);
env->pc = regs->pc;
env->dregs[0] = regs->d0;
env->dregs[1] = regs->d1;
......
......@@ -65,6 +65,8 @@
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
#elif defined (TARGET_ALPHA)
#define CPU_MEM_INDEX ((env->ps >> 3) & 3)
#elif defined (TARGET_M68K)
#define CPU_MEM_INDEX ((env->sr & SR_S) == 0)
#else
#error unsupported CPU
#endif
......@@ -86,6 +88,8 @@
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
#elif defined (TARGET_ALPHA)
#define CPU_MEM_INDEX ((env->ps >> 3) & 3)
#elif defined (TARGET_M68K)
#define CPU_MEM_INDEX ((env->sr & SR_S) == 0)
#else
#error unsupported CPU
#endif
......
/*
* m68k virtual CPU header
*
* Copyright (c) 2005-2006 CodeSourcery
* Copyright (c) 2005-2007 CodeSourcery
* Written by Paul Brook
*
* This library is free software; you can redistribute it and/or
......@@ -50,6 +50,8 @@
#define EXCP_UNSUPPORTED 61
#define EXCP_ICE 13
#define EXCP_RTE 0x100
typedef struct CPUM68KState {
uint32_t dregs[8];
uint32_t aregs[8];
......@@ -76,6 +78,12 @@ typedef struct CPUM68KState {
struct {
uint32_t ar;
} mmu;
/* Control registers. */
uint32_t vbr;
uint32_t mbar;
uint32_t rambar0;
/* ??? remove this. */
uint32_t t1;
......@@ -84,7 +92,10 @@ typedef struct CPUM68KState {
int exception_index;
int interrupt_request;
int user_mode_only;
uint32_t address;
int halted;
int pending_vector;
int pending_level;
uint32_t qregs[MAX_QREGS];
......@@ -94,6 +105,7 @@ typedef struct CPUM68KState {
CPUM68KState *cpu_m68k_init(void);
int cpu_m68k_exec(CPUM68KState *s);
void cpu_m68k_close(CPUM68KState *s);
void do_interrupt(int is_hw);
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
......@@ -120,12 +132,19 @@ enum {
#define CCF_V 0x02
#define CCF_Z 0x04
#define CCF_N 0x08
#define CCF_X 0x01
#define CCF_X 0x10
#define SR_I_SHIFT 8
#define SR_I 0x0700
#define SR_M 0x1000
#define SR_S 0x2000
#define SR_T 0x8000
typedef struct m68k_def_t m68k_def_t;
m68k_def_t *m68k_find_by_name(const char *);
void cpu_m68k_register(CPUM68KState *, m68k_def_t *);
int cpu_m68k_set_model(CPUM68KState *env, const char * name);
void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector);
#define M68K_FPCR_PREC (1 << 6)
......
......@@ -40,8 +40,12 @@ static inline void regs_to_env(void)
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu);
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
#endif
void cpu_m68k_flush_flags(CPUM68KState *env, int cc_op);
float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1);
void helper_movec(CPUM68KState *env, int reg, uint32_t val);
void cpu_loop_exit(void);
/*
* m68k op helpers
*
* Copyright (c) 2006 CodeSourcery
* Copyright (c) 2006-2007 CodeSourcery
* Written by Paul Brook
*
* This library is free software; you can redistribute it and/or
......@@ -147,3 +147,65 @@ float64 helper_sub_cmpf64(CPUM68KState *env, float64 src0, float64 src1)
}
return res;
}
void helper_movec(CPUM68KState *env, int reg, uint32_t val)
{
switch (reg) {
case 0x02: /* CACR */
/* Ignored. */
break;
case 0x801: /* VBR */
env->vbr = val;
break;
/* TODO: Implement control registers. */
default:
cpu_abort(env, "Unimplemented control register write 0x%x = 0x%x\n",
reg, val);
}
}
/* MMU */
/* TODO: This will need fixing once the MMU is implemented. */
target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
#if defined(CONFIG_USER_ONLY)
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu)
{
env->exception_index = EXCP_ACCESS;
env->mmu.ar = address;
return 1;
}
#else
int cpu_m68k_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu)
{
int prot;
address &= TARGET_PAGE_MASK;
prot = PAGE_READ | PAGE_WRITE;
return tlb_set_page(env, address, address, prot, is_user, is_softmmu);
}
/* Notify CPU of a pending interrupt. Prioritization and vectoring should
be handled by the interrupt controller. Real hardware only requests
the vector when the interrupt is acknowledged by the CPU. For
simplicitly we calculate it when the interrupt is signalled. */
void m68k_set_irq_level(CPUM68KState *env, int level, uint8_t vector)
{
env->pending_level = level;
env->pending_vector = vector;
if (level)
cpu_interrupt(env, CPU_INTERRUPT_HARD);
else
cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
}
#endif
......@@ -27,16 +27,38 @@ static inline int gen_im32(uint32_t i)
return qreg;
}
static inline void gen_op_ldf32(int dest, int addr)
static inline void gen_op_ldf32_raw(int dest, int addr)
{
gen_op_ld32(dest, addr);
gen_op_ld32_raw(dest, addr);
}
static inline void gen_op_stf32(int addr, int dest)
static inline void gen_op_stf32_raw(int addr, int dest)
{
gen_op_st32(addr, dest);
gen_op_st32_raw(addr, dest);
}
#if !defined(CONFIG_USER_ONLY)
static inline void gen_op_ldf32_user(int dest, int addr)
{
gen_op_ld32_user(dest, addr);
}
static inline void gen_op_stf32_user(int addr, int dest)
{
gen_op_st32_user(addr, dest);
}
static inline void gen_op_ldf32_kernel(int dest, int addr)
{
gen_op_ld32_kernel(dest, addr);
}
static inline void gen_op_stf32_kernel(int addr, int dest)
{
gen_op_st32_kernel(addr, dest);
}
#endif
static inline void gen_op_pack_32_f32(int dest, int src)
{
gen_op_mov32(dest, src);
......
/*
* m68k micro operations
*
* Copyright (c) 2006 CodeSourcery
* Copyright (c) 2006-2007 CodeSourcery
* Written by Paul Brook
*
* This library is free software; you can redistribute it and/or
......@@ -86,7 +86,7 @@ void set_opf64(int qreg, float64 val)
}
}
#define OP(name) void OPPROTO op_##name (void)
#define OP(name) void OPPROTO glue(op_,name) (void)
OP(mov32)
{
......@@ -316,77 +316,6 @@ OP(ext16s32)
FORCE_RET();
}
/* Load/store ops. */
OP(ld8u32)
{
uint32_t addr = get_op(PARAM2);
set_op(PARAM1, ldub(addr));
FORCE_RET();
}
OP(ld8s32)
{
uint32_t addr = get_op(PARAM2);
set_op(PARAM1, ldsb(addr));
FORCE_RET();
}
OP(ld16u32)
{
uint32_t addr = get_op(PARAM2);
set_op(PARAM1, lduw(addr));
FORCE_RET();
}
OP(ld16s32)
{
uint32_t addr = get_op(PARAM2);
set_op(PARAM1, ldsw(addr));
FORCE_RET();
}
OP(ld32)
{
uint32_t addr = get_op(PARAM2);
set_op(PARAM1, ldl(addr));
FORCE_RET();
}
OP(st8)
{
uint32_t addr = get_op(PARAM1);
stb(addr, get_op(PARAM2));
FORCE_RET();
}
OP(st16)
{
uint32_t addr = get_op(PARAM1);
stw(addr, get_op(PARAM2));
FORCE_RET();
}
OP(st32)
{
uint32_t addr = get_op(PARAM1);
stl(addr, get_op(PARAM2));
FORCE_RET();
}
OP(ldf64)
{
uint32_t addr = get_op(PARAM2);
set_opf64(PARAM1, ldfq(addr));
FORCE_RET();
}
OP(stf64)
{
uint32_t addr = get_op(PARAM1);
stfq(addr, get_opf64(PARAM2));
FORCE_RET();
}
OP(flush_flags)
{
int cc_op = PARAM1;
......@@ -454,6 +383,13 @@ OP(divs)
FORCE_RET();
}
OP(halt)
{
env->halted = 1;
RAISE_EXCEPTION(EXCP_HLT);
FORCE_RET();
}
OP(raise_exception)
{
RAISE_EXCEPTION(PARAM1);
......@@ -679,3 +615,22 @@ OP(compare_quietf64)
set_op(PARAM1, float64_compare_quiet(op0, op1, &CPU_FP_STATUS));
FORCE_RET();
}
OP(movec)
{
int op1 = get_op(PARAM1);
uint32_t op2 = get_op(PARAM2);
helper_movec(env, op1, op2);
}
/* Memory access. */
#define MEMSUFFIX _raw
#include "op_mem.h"
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
#include "op_mem.h"
#define MEMSUFFIX _kernel
#include "op_mem.h"
#endif
/*
* M68K helper routines
*
* Copyright (c) 2007 CodeSourcery
*
* 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"
#if defined(CONFIG_USER_ONLY)
void do_interrupt(int is_hw)
{
env->exception_index = -1;
}
#else
#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"
/* Try to fill the TLB and return an exception if error. If retaddr is
NULL, it means that the function was called in C code (i.e. not
from generated code or from helper.c) */
/* XXX: fix it to restore all registers */
void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr)
{
TranslationBlock *tb;
CPUState *saved_env;
target_phys_addr_t 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_m68k_handle_mmu_fault(env, addr, is_write, is_user, 1);
if (__builtin_expect(ret, 0)) {
if (retaddr) {
/* now we have a real cpu fault */
pc = (target_phys_addr_t)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);
}
}
cpu_loop_exit();
}
env = saved_env;
}
static void do_rte(void)
{
uint32_t sp;
uint32_t fmt;
sp = env->aregs[7];
fmt = ldl_kernel(sp);
env->pc = ldl_kernel(sp + 4);
sp |= (fmt >> 28) & 3;
env->sr = fmt & 0xffff;
env->aregs[7] = sp + 8;
}