diff options
-rw-r--r-- | target-cris/cpu.h | 256 | ||||
-rw-r--r-- | target-cris/exec.h | 68 | ||||
-rw-r--r-- | target-cris/helper.c | 173 | ||||
-rw-r--r-- | target-cris/op_helper.c | 76 | ||||
-rw-r--r-- | target-cris/op_mem.c | 59 | ||||
-rw-r--r-- | target-cris/op_template.h | 48 |
6 files changed, 680 insertions, 0 deletions
diff --git a/target-cris/cpu.h b/target-cris/cpu.h new file mode 100644 index 0000000000..11652c50fb --- /dev/null +++ b/target-cris/cpu.h @@ -0,0 +1,256 @@ +/* + * CRIS virtual CPU header + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias + * + * 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 + * 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 + */ +#ifndef CPU_CRIS_H +#define CPU_CRIS_H + +#define TARGET_LONG_BITS 32 + +#include "cpu-defs.h" + +#include "softfloat.h" + +#define TARGET_HAS_ICE 1 + +#define ELF_MACHINE EM_CRIS + +#define EXCP_MMU_EXEC 0 +#define EXCP_MMU_READ 1 +#define EXCP_MMU_WRITE 2 +#define EXCP_MMU_FLUSH 3 +#define EXCP_MMU_MISS 4 +#define EXCP_BREAK 16 /* trap. */ + +/* CPU flags. */ +#define S_FLAG 0x200 +#define R_FLAG 0x100 +#define P_FLAG 0x80 +#define U_FLAG 0x40 +#define P_FLAG 0x80 +#define U_FLAG 0x40 +#define I_FLAG 0x20 +#define X_FLAG 0x10 +#define N_FLAG 0x08 +#define Z_FLAG 0x04 +#define V_FLAG 0x02 +#define C_FLAG 0x01 +#define ALU_FLAGS 0x1F + +/* Condition codes. */ +#define CC_CC 0 +#define CC_CS 1 +#define CC_NE 2 +#define CC_EQ 3 +#define CC_VC 4 +#define CC_VS 5 +#define CC_PL 6 +#define CC_MI 7 +#define CC_LS 8 +#define CC_HI 9 +#define CC_GE 10 +#define CC_LT 11 +#define CC_GT 12 +#define CC_LE 13 +#define CC_A 14 +#define CC_P 15 + +/* Internal flags for the implementation. */ +#define F_DELAYSLOT 1 + +typedef struct CPUCRISState { + uint32_t debug1; + uint32_t debug2; + uint32_t debug3; + + /* + * We just store the stores to the tlbset here for later evaluation + * when the hw needs access to them. + * + * One for I and another for D. + */ + struct + { + uint32_t hi; + uint32_t lo; + } tlbsets[2][4][16]; + + uint32_t sregs[256][16]; /* grrr why so many?? */ + uint32_t regs[16]; + uint32_t pregs[16]; + uint32_t pc; + uint32_t sr; + uint32_t flag_mask; /* Per insn mask of affected flags. */ + + /* SSP and USP. */ + int current_sp; + uint32_t sp[2]; + + /* These are setup up by the guest code just before transfering the + control back to the host. */ + int jmp; + uint32_t btarget; + int btaken; + + /* for traps. */ + int trapnr; + + /* Condition flag tracking. */ + uint32_t cc_op; + uint32_t cc_mask; + uint32_t cc_dest; + uint32_t cc_src; + uint32_t cc_result; + + /* size of the operation, 1 = byte, 2 = word, 4 = dword. */ + int cc_size; + + /* extended arithmetics. */ + int cc_x_live; + int cc_x; + + int features; + + uint64_t pending_interrupts; + int interrupt_request; + int exception_index; + int user_mode_only; + int halted; + + struct + { + int exec_insns; + int exec_loads; + int exec_stores; + } stats; + + + jmp_buf jmp_env; + CPU_COMMON +} CPUCRISState; + +CPUCRISState *cpu_cris_init(void); +int cpu_cris_exec(CPUCRISState *s); +void cpu_cris_close(CPUCRISState *s); +void do_interrupt(CPUCRISState *env); +/* 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. */ +int cpu_cris_signal_handler(int host_signum, void *pinfo, + void *puc); +void cpu_cris_flush_flags(CPUCRISState *, int); + + +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int is_asi); + +enum { + CC_OP_DYNAMIC, /* Use env->cc_op */ + CC_OP_FLAGS, + CC_OP_LOGIC, + CC_OP_CMP, + CC_OP_MOVE, + CC_OP_MOVE_PD, + CC_OP_MOVE_SD, + CC_OP_ADD, + CC_OP_ADDC, + CC_OP_MCP, + CC_OP_ADDU, + CC_OP_SUB, + CC_OP_SUBU, + CC_OP_NEG, + CC_OP_BTST, + CC_OP_MULS, + CC_OP_MULU, + CC_OP_DSTEP, + CC_OP_BOUND, + + CC_OP_OR, + CC_OP_AND, + CC_OP_XOR, + CC_OP_LSL, + CC_OP_LSR, + CC_OP_ASR, + CC_OP_LZ +}; + +#define CCF_C 0x01 +#define CCF_V 0x02 +#define CCF_Z 0x04 +#define CCF_N 0x08 +#define CCF_X 0x10 + +#define CRIS_SSP 0 +#define CRIS_USP 1 + +typedef struct cris_def_t cris_def_t; + +int cpu_cris_set_model(CPUCRISState *env, const char * name); + +void cris_set_irq_level(CPUCRISState *env, int level, uint8_t vector); +void cris_set_macsr(CPUCRISState *env, uint32_t val); +void cris_switch_sp(CPUCRISState *env); + +void do_cris_semihosting(CPUCRISState *env, int nr); + +enum cris_features { + CRIS_FEATURE_CF_ISA_MUL, +}; + +static inline int cris_feature(CPUCRISState *env, int feature) +{ + return (env->features & (1u << feature)) != 0; +} + +void register_cris_insns (CPUCRISState *env); + +/* CRIS uses 8k pages. */ +#define TARGET_PAGE_BITS 13 + +#define CPUState CPUCRISState +#define cpu_init cpu_cris_init +#define cpu_exec cpu_cris_exec +#define cpu_gen_code cpu_cris_gen_code +#define cpu_signal_handler cpu_cris_signal_handler + +#include "cpu-all.h" + +/* Register aliases. */ +#define REG_SP 14 +#define REG_ACR 15 +#define REG_MOF 7 + +/* Support regs. */ +#define SR_PID 2 +#define SR_SRS 3 +#define SR_EBP 9 +#define SR_ERP 10 +#define SR_CCS 13 + +/* Support func regs. */ +#define SFR_RW_GC_CFG 0][0 +#define SFR_RW_MM_CFG 1][0 +#define SFR_RW_MM_KBASE_LO 1][1 +#define SFR_RW_MM_KBASE_HI 1][2 +#define SFR_R_MM_CAUSE 1][3 +#define SFR_RW_MM_TLB_SEL 1][4 +#define SFR_RW_MM_TLB_LO 1][5 +#define SFR_RW_MM_TLB_HI 1][6 + +#endif diff --git a/target-cris/exec.h b/target-cris/exec.h new file mode 100644 index 0000000000..a4f555eb28 --- /dev/null +++ b/target-cris/exec.h @@ -0,0 +1,68 @@ +/* + * CRIS execution defines + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias + * + * 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 + * 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 "dyngen-exec.h" + +#if 1 +register struct CPUCRISState *env asm(AREG0); +/* This is only used for tb lookup. */ +register uint32_t T0 asm(AREG1); +register uint32_t T1 asm(AREG2); +#else +struct CPUCRISState *env; +/* This is only used for tb lookup. */ +uint32_t T0; +uint32_t T1; +#endif +#include "cpu.h" +#include "exec-all.h" + +#define RETURN() __asm__ __volatile__("" : : : "memory"); + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu); +void tlb_fill (target_ulong addr, int is_write, int is_user, void *retaddr); + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +void cpu_cris_flush_flags(CPUCRISState *env, int cc_op); +void helper_movec(CPUCRISState *env, int reg, uint32_t val); + +void cpu_loop_exit(void); + +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} diff --git a/target-cris/helper.c b/target-cris/helper.c new file mode 100644 index 0000000000..3db3bea08d --- /dev/null +++ b/target-cris/helper.c @@ -0,0 +1,173 @@ +/* + * CRIS helper routines. + * + * Copyright (c) 2007 AXIS Communications AB + * Written by Edgar E. Iglesias. + * + * 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 <stdio.h> +#include <string.h> + +#include "config.h" +#include "cpu.h" +#include "mmu.h" +#include "exec-all.h" + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; +} + +int cpu_cris_handle_mmu_fault(CPUState * env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + env->exception_index = 0xaa; + env->debug1 = address; + cpu_dump_state(env, stderr, fprintf, 0); + printf("%s addr=%x env->pc=%x\n", __func__, address, env->pc); + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + return addr; +} + +#else /* !CONFIG_USER_ONLY */ + +int cpu_cris_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int is_user, int is_softmmu) +{ + struct cris_mmu_result_t res; + int prot, miss; + target_ulong phy; + + address &= TARGET_PAGE_MASK; + prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC; +// printf ("%s pc=%x %x w=%d smmu=%d\n", __func__, env->pc, address, rw, is_softmmu); + miss = cris_mmu_translate(&res, env, address, rw, is_user); + if (miss) + { + /* handle the miss. */ + phy = 0; + env->exception_index = EXCP_MMU_MISS; + } + else + { + phy = res.phy; + } +// printf ("a=%x phy=%x\n", address, phy); + return tlb_set_page(env, address, phy, prot, is_user, is_softmmu); +} + + +static void cris_shift_ccs(CPUState *env) +{ + uint32_t ccs; + /* Apply the ccs shift. */ + ccs = env->pregs[SR_CCS]; + ccs = (ccs & 0xc0000000) | ((ccs << 12) >> 2); +// printf ("ccs=%x %x\n", env->pregs[SR_CCS], ccs); + env->pregs[SR_CCS] = ccs; +} + +void do_interrupt(CPUState *env) +{ + uint32_t ebp, isr; + int irqnum; + + fflush(NULL); + +#if 0 + printf ("exception index=%d interrupt_req=%d\n", + env->exception_index, + env->interrupt_request); +#endif + + switch (env->exception_index) + { + case EXCP_BREAK: +// printf ("BREAK! %d\n", env->trapnr); + irqnum = env->trapnr; + ebp = env->pregs[SR_EBP]; + isr = ldl_code(ebp + irqnum * 4); + env->pregs[SR_ERP] = env->pc + 2; + env->pc = isr; + + cris_shift_ccs(env); + + break; + case EXCP_MMU_MISS: +// printf ("MMU miss\n"); + irqnum = 4; + ebp = env->pregs[SR_EBP]; + isr = ldl_code(ebp + irqnum * 4); + env->pregs[SR_ERP] = env->pc; + env->pc = isr; + cris_shift_ccs(env); + break; + + default: + { + /* Maybe the irq was acked by sw before we got a + change to take it. */ + if (env->interrupt_request & CPU_INTERRUPT_HARD) { + if (!env->pending_interrupts) + return; + if (!(env->pregs[SR_CCS] & I_FLAG)) { + return; + } + + irqnum = 31 - + __builtin_clz(env->pending_interrupts); + irqnum += 0x30; + ebp = env->pregs[SR_EBP]; + isr = ldl_code(ebp + irqnum * 4); + env->pregs[SR_ERP] = env->pc; + env->pc = isr; + + cris_shift_ccs(env); +#if 0 + printf ("%s ebp=%x %x isr=%x %d" + " ir=%x pending=%x\n", + __func__, + ebp, ebp + irqnum * 4, + isr, env->exception_index, + env->interrupt_request, + env->pending_interrupts); +#endif + } + + } + break; + } +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ +// printf ("%s\n", __func__); + uint32_t phy = addr; + struct cris_mmu_result_t res; + int miss; + miss = cris_mmu_translate(&res, env, addr, 0, 0); + if (!miss) + phy = res.phy; + return phy; +} +#endif diff --git a/target-cris/op_helper.c b/target-cris/op_helper.c new file mode 100644 index 0000000000..f84ceb9da0 --- /dev/null +++ b/target-cris/op_helper.c @@ -0,0 +1,76 @@ +/* + * CRIS helper routines + * + * Copyright (c) 2007 AXIS Communications + * Written by Edgar E. Iglesias + * + * 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 <assert.h> +#include "exec.h" + +#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_cris_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; +} + +void do_unassigned_access(target_phys_addr_t addr, int is_write, int is_exec, + int is_asi) +{ + +} diff --git a/target-cris/op_mem.c b/target-cris/op_mem.c new file mode 100644 index 0000000000..50ed10b57b --- /dev/null +++ b/target-cris/op_mem.c @@ -0,0 +1,59 @@ +/* + * CRIS memory access (load and store) micro operations. + * + * Copyright (c) 2007 Edgar E. Iglesias, Axis Communications AB. + * + * 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 + */ + +void glue(op_ldb_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldsb, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_ldub_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldub, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stb_T0_T1, MEMSUFFIX) (void) { + glue(stb, MEMSUFFIX) (T0, T1); + RETURN(); +} + +void glue(op_ldw_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldsw, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_lduw_T0_T0, MEMSUFFIX) (void) { + T0 = glue(lduw, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stw_T0_T1, MEMSUFFIX) (void) { + glue(stw, MEMSUFFIX) (T0, T1); + RETURN(); +} + +void glue(op_ldl_T0_T0, MEMSUFFIX) (void) { + T0 = glue(ldl, MEMSUFFIX) (T0); + RETURN(); +} + +void glue(op_stl_T0_T1, MEMSUFFIX) (void) { + glue(stl, MEMSUFFIX) (T0, T1); + RETURN(); +} diff --git a/target-cris/op_template.h b/target-cris/op_template.h new file mode 100644 index 0000000000..370fbf3958 --- /dev/null +++ b/target-cris/op_template.h @@ -0,0 +1,48 @@ +/* + * CRIS micro operations (templates for various register related + * operations) + * + * Copyright (c) 2003 Fabrice Bellard + * + * 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 + */ + +#ifndef SET_REG +#define SET_REG(x) REG = x +#endif + +void OPPROTO glue(op_movl_T0_, REGNAME)(void) +{ + T0 = REG; +} + +void OPPROTO glue(op_movl_T1_, REGNAME)(void) +{ + T1 = REG; +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T0)(void) +{ + SET_REG (T0); +} + +void OPPROTO glue(glue(op_movl_, REGNAME), _T1)(void) +{ + SET_REG (T1); +} + +#undef REG +#undef REGNAME +#undef SET_REG |