* [Qemu-devel] [PATCH 01/13] microblaze: Add translation routines. @ 2009-05-20 20:56 Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 02/13] microblaze: Add syscall, signal and termbits defs for linux-user Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-microblaze/cpu.h | 321 ++++++++ target-microblaze/exec.h | 57 ++ target-microblaze/helper.c | 255 ++++++ target-microblaze/helper.h | 19 + target-microblaze/microblaze-decode.h | 52 ++ target-microblaze/op_helper.c | 216 +++++ target-microblaze/translate.c | 1395 +++++++++++++++++++++++++++++++++ 7 files changed, 2315 insertions(+), 0 deletions(-) create mode 100644 target-microblaze/cpu.h create mode 100644 target-microblaze/exec.h create mode 100644 target-microblaze/helper.c create mode 100644 target-microblaze/helper.h create mode 100644 target-microblaze/microblaze-decode.h create mode 100644 target-microblaze/op_helper.c create mode 100644 target-microblaze/translate.c diff --git a/target-microblaze/cpu.h b/target-microblaze/cpu.h new file mode 100644 index 0000000..e2aa3e4 --- /dev/null +++ b/target-microblaze/cpu.h @@ -0,0 +1,321 @@ +/* + * MicroBlaze virtual CPU header + * + * Copyright (c) 2009 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ +#ifndef CPU_MICROBLAZE_H +#define CPU_MICROBLAZE_H + +#define TARGET_LONG_BITS 32 + +#define CPUState struct CPUMBState + +#include "cpu-defs.h" +struct CPUMBState; +#if !defined(CONFIG_USER_ONLY) +#include "mmu.h" +#endif + +#define TARGET_HAS_ICE 1 + +#define ELF_MACHINE EM_XILINX_MICROBLAZE + +#define EXCP_NMI 1 +#define EXCP_MMU 2 +#define EXCP_IRQ 3 +#define EXCP_BREAK 4 +#define EXCP_HW_BREAK 5 + +/* Register aliases. R0 - R15 */ +#define R_SP 1 +#define SR_PC 0 +#define SR_MSR 1 +#define SR_EAR 3 +#define SR_ESR 5 +#define SR_FSR 7 +#define SR_BTR 0xb +#define SR_EDR 0xd + +/* MSR flags. */ +#define MSR_BE (1<<0) /* 0x001 */ +#define MSR_IE (1<<1) /* 0x002 */ +#define MSR_C (1<<2) /* 0x004 */ +#define MSR_BIP (1<<3) /* 0x008 */ +#define MSR_FSL (1<<4) /* 0x010 */ +#define MSR_ICE (1<<5) /* 0x020 */ +#define MSR_DZ (1<<6) /* 0x040 */ +#define MSR_DCE (1<<7) /* 0x080 */ +#define MSR_EE (1<<8) /* 0x100 */ +#define MSR_EIP (1<<9) /* 0x200 */ +#define MSR_CC (1<<31) + +/* Machine State Register (MSR) Fields */ +#define MSR_UM (1<<11) /* User Mode */ +#define MSR_UMS (1<<12) /* User Mode Save */ +#define MSR_VM (1<<13) /* Virtual Mode */ +#define MSR_VMS (1<<14) /* Virtual Mode Save */ + +#define MSR_KERNEL MSR_EE|MSR_VM +//#define MSR_USER MSR_KERNEL|MSR_UM|MSR_IE +#define MSR_KERNEL_VMS MSR_EE|MSR_VMS +//#define MSR_USER_VMS MSR_KERNEL_VMS|MSR_UMS|MSR_IE + +/* Exception State Register (ESR) Fields */ +#define ESR_DIZ (1<<11) /* Zone Protection */ +#define ESR_S (1<<10) /* Store instruction */ + + + +/* Version reg. */ +/* Basic PVR mask */ +#define PVR0_PVR_FULL_MASK 0x80000000 +#define PVR0_USE_BARREL_MASK 0x40000000 +#define PVR0_USE_DIV_MASK 0x20000000 +#define PVR0_USE_HW_MUL_MASK 0x10000000 +#define PVR0_USE_FPU_MASK 0x08000000 +#define PVR0_USE_EXC_MASK 0x04000000 +#define PVR0_USE_ICACHE_MASK 0x02000000 +#define PVR0_USE_DCACHE_MASK 0x01000000 +#define PVR0_USE_MMU 0x00800000 /* new */ +#define PVR0_VERSION_MASK 0x0000FF00 +#define PVR0_USER1_MASK 0x000000FF + +/* User 2 PVR mask */ +#define PVR1_USER2_MASK 0xFFFFFFFF + +/* Configuration PVR masks */ +#define PVR2_D_OPB_MASK 0x80000000 +#define PVR2_D_LMB_MASK 0x40000000 +#define PVR2_I_OPB_MASK 0x20000000 +#define PVR2_I_LMB_MASK 0x10000000 +#define PVR2_INTERRUPT_IS_EDGE_MASK 0x08000000 +#define PVR2_EDGE_IS_POSITIVE_MASK 0x04000000 +#define PVR2_D_PLB_MASK 0x02000000 /* new */ +#define PVR2_I_PLB_MASK 0x01000000 /* new */ +#define PVR2_INTERCONNECT 0x00800000 /* new */ +#define PVR2_USE_EXTEND_FSL 0x00080000 /* new */ +#define PVR2_USE_FSL_EXC 0x00040000 /* new */ +#define PVR2_USE_MSR_INSTR 0x00020000 +#define PVR2_USE_PCMP_INSTR 0x00010000 +#define PVR2_AREA_OPTIMISED 0x00008000 +#define PVR2_USE_BARREL_MASK 0x00004000 +#define PVR2_USE_DIV_MASK 0x00002000 +#define PVR2_USE_HW_MUL_MASK 0x00001000 +#define PVR2_USE_FPU_MASK 0x00000800 +#define PVR2_USE_MUL64_MASK 0x00000400 +#define PVR2_USE_FPU2_MASK 0x00000200 /* new */ +#define PVR2_USE_IPLBEXC 0x00000100 +#define PVR2_USE_DPLBEXC 0x00000080 +#define PVR2_OPCODE_0x0_ILL_MASK 0x00000040 +#define PVR2_UNALIGNED_EXC_MASK 0x00000020 +#define PVR2_ILL_OPCODE_EXC_MASK 0x00000010 +#define PVR2_IOPB_BUS_EXC_MASK 0x00000008 +#define PVR2_DOPB_BUS_EXC_MASK 0x00000004 +#define PVR2_DIV_ZERO_EXC_MASK 0x00000002 +#define PVR2_FPU_EXC_MASK 0x00000001 + +/* Debug and exception PVR masks */ +#define PVR3_DEBUG_ENABLED_MASK 0x80000000 +#define PVR3_NUMBER_OF_PC_BRK_MASK 0x1E000000 +#define PVR3_NUMBER_OF_RD_ADDR_BRK_MASK 0x00380000 +#define PVR3_NUMBER_OF_WR_ADDR_BRK_MASK 0x0000E000 +#define PVR3_FSL_LINKS_MASK 0x00000380 + +/* ICache config PVR masks */ +#define PVR4_USE_ICACHE_MASK 0x80000000 +#define PVR4_ICACHE_ADDR_TAG_BITS_MASK 0x7C000000 +#define PVR4_ICACHE_USE_FSL_MASK 0x02000000 +#define PVR4_ICACHE_ALLOW_WR_MASK 0x01000000 +#define PVR4_ICACHE_LINE_LEN_MASK 0x00E00000 +#define PVR4_ICACHE_BYTE_SIZE_MASK 0x001F0000 + +/* DCache config PVR masks */ +#define PVR5_USE_DCACHE_MASK 0x80000000 +#define PVR5_DCACHE_ADDR_TAG_BITS_MASK 0x7C000000 +#define PVR5_DCACHE_USE_FSL_MASK 0x02000000 +#define PVR5_DCACHE_ALLOW_WR_MASK 0x01000000 +#define PVR5_DCACHE_LINE_LEN_MASK 0x00E00000 +#define PVR5_DCACHE_BYTE_SIZE_MASK 0x001F0000 + +/* ICache base address PVR mask */ +#define PVR6_ICACHE_BASEADDR_MASK 0xFFFFFFFF + +/* ICache high address PVR mask */ +#define PVR7_ICACHE_HIGHADDR_MASK 0xFFFFFFFF + +/* DCache base address PVR mask */ +#define PVR8_DCACHE_BASEADDR_MASK 0xFFFFFFFF + +/* DCache high address PVR mask */ +#define PVR9_DCACHE_HIGHADDR_MASK 0xFFFFFFFF + +/* Target family PVR mask */ +#define PVR10_TARGET_FAMILY_MASK 0xFF000000 + +/* MMU descrtiption */ +#define PVR11_USE_MMU 0xC0000000 +#define PVR11_MMU_ITLB_SIZE 0x38000000 +#define PVR11_MMU_DTLB_SIZE 0x07000000 +#define PVR11_MMU_TLB_ACCESS 0x00C00000 +#define PVR11_MMU_ZONES 0x003C0000 +/* MSR Reset value PVR mask */ +#define PVR11_MSR_RESET_VALUE_MASK 0x000007FF + + + +/* CPU flags. */ + +/* Condition codes. */ +#define CC_GE 5 +#define CC_GT 4 +#define CC_LE 3 +#define CC_LT 2 +#define CC_NE 1 +#define CC_EQ 0 + +#define NB_MMU_MODES 3 +typedef struct CPUMBState { + uint32_t debug; + uint32_t btaken; + uint32_t btarget; + uint32_t bimm; + + uint32_t imm; + uint32_t regs[33]; + uint32_t sregs[24]; + + /* Internal flags. */ +#define IMM_FLAG 4 +#define DRTI_FLAG (1 << 16) +#define DRTE_FLAG (1 << 17) +#define DRTB_FLAG (1 << 18) +#define D_FLAG (1 << 19) /* Bit in ESR. */ +/* TB dependant CPUState. */ +#define IFLAGS_TB_MASK (D_FLAG | IMM_FLAG | DRTI_FLAG | DRTE_FLAG | DRTB_FLAG) + uint32_t iflags; + + struct { + uint32_t regs[16]; + } pvr; + +#if !defined(CONFIG_USER_ONLY) + /* Unified MMU. */ + struct microblaze_mmu mmu; +#endif + + CPU_COMMON + + uint32_t int_flags; + uint32_t int_start; + uint32_t int_end; + int int_count; + int int_cycles; + uint32_t int_maxstart; + uint32_t int_maxend; + int int_maxcount; + int int_maxcycles; +} CPUMBState; + +CPUState *cpu_mb_init(const char *cpu_model); +int cpu_mb_exec(CPUState *s); +void cpu_mb_close(CPUState *s); +void do_interrupt(CPUState *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_mb_signal_handler(int host_signum, void *pinfo, + void *puc); + +enum { + CC_OP_DYNAMIC, /* Use env->cc_op */ + CC_OP_FLAGS, + CC_OP_CMP, +}; + +/* FIXME: MB uses variable pages down to 1K but linux only uses 4k. */ +#define TARGET_PAGE_BITS 12 +#define MMAP_SHIFT TARGET_PAGE_BITS + +#define cpu_init cpu_mb_init +#define cpu_exec cpu_mb_exec +#define cpu_gen_code cpu_mb_gen_code +#define cpu_signal_handler cpu_mb_signal_handler + +#define CPU_SAVE_VERSION 1 + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _nommu +#define MMU_MODE1_SUFFIX _kernel +#define MMU_MODE2_SUFFIX _user +#define MMU_NOMMU_IDX 0 +#define MMU_KERNEL_IDX 1 +#define MMU_USER_IDX 2 +/* See NB_MMU_MODES further up the file. */ + +static inline int cpu_mmu_index (CPUState *env) +{ + /* Are we in nommu mode?. */ + if (!(env->sregs[SR_MSR] & MSR_VM)) + return MMU_NOMMU_IDX; + + if (env->sregs[SR_MSR] & MSR_UM) + return MMU_USER_IDX; + return MMU_KERNEL_IDX; +} + +int cpu_mb_handle_mmu_fault(CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu); + +#if defined(CONFIG_USER_ONLY) +static inline void cpu_clone_regs(CPUState *env, target_ulong newsp) +{ + if (newsp) + env->regs[R_SP] = newsp; + env->regs[3] = 0; +} +#endif + +static inline void cpu_set_tls(CPUState *env, target_ulong newtls) +{ +} + +static inline int cpu_interrupts_enabled(CPUState *env) +{ + return env->sregs[SR_MSR] & MSR_IE; +} + +#include "cpu-all.h" +#include "exec-all.h" + +static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb) +{ + env->sregs[SR_PC] = tb->pc; +} + +static inline target_ulong cpu_get_pc(CPUState *env) +{ + return env->sregs[SR_PC]; +} + +static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc, + target_ulong *cs_base, int *flags) +{ + *pc = env->sregs[SR_PC]; + *cs_base = 0; + *flags = env->iflags & IFLAGS_TB_MASK; +} +#endif diff --git a/target-microblaze/exec.h b/target-microblaze/exec.h new file mode 100644 index 0000000..55045bb --- /dev/null +++ b/target-microblaze/exec.h @@ -0,0 +1,57 @@ +/* + * Microblaze execution defines + * + * Copyright (c) 2009 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ +#include "dyngen-exec.h" + +register struct CPUMBState *env asm(AREG0); + +#include "cpu.h" +#include "exec-all.h" + +static inline void env_to_regs(void) +{ +} + +static inline void regs_to_env(void) +{ +} + +#if !defined(CONFIG_USER_ONLY) +#include "softmmu_exec.h" +#endif + +void cpu_mb_flush_flags(CPUMBState *env, int cc_op); + +static inline int cpu_has_work(CPUState *env) +{ + return (env->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)); +} + +static inline int cpu_halted(CPUState *env) { + if (!env->halted) + return 0; + + /* IRQ, NMI and GURU execeptions wakes us up. */ + if (env->interrupt_request + & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI)) { + env->halted = 0; + return 0; + } + return EXCP_HALTED; +} diff --git a/target-microblaze/helper.c b/target-microblaze/helper.c new file mode 100644 index 0000000..0093659 --- /dev/null +++ b/target-microblaze/helper.c @@ -0,0 +1,255 @@ +/* + * MicroBlaze helper routines. + * + * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#include <stdio.h> +#include <string.h> +#include <assert.h> + +#include "config.h" +#include "cpu.h" +#include "exec-all.h" +#include "host-utils.h" + +#define D(x) +#define DMMU(x) + +#if defined(CONFIG_USER_ONLY) + +void do_interrupt (CPUState *env) +{ + env->exception_index = -1; + env->regs[14] = env->sregs[SR_PC]; +} + +int cpu_mb_handle_mmu_fault(CPUState * env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) +{ + env->exception_index = 0xaa; + cpu_dump_state(env, stderr, fprintf, 0); + return 1; +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + return addr; +} + +#else /* !CONFIG_USER_ONLY */ + +int cpu_mb_handle_mmu_fault (CPUState *env, target_ulong address, int rw, + int mmu_idx, int is_softmmu) +{ + unsigned int hit; + unsigned int mmu_available; + int r = 1; + int prot; + + mmu_available = 0; + if (env->pvr.regs[0] & PVR0_USE_MMU) { + mmu_available = 1; + if ((env->pvr.regs[0] & PVR0_PVR_FULL_MASK) + && (env->pvr.regs[11] & PVR11_USE_MMU) != PVR11_USE_MMU) { + mmu_available = 0; + } + } + + /* Translate if the MMU is available and enabled. */ + if (mmu_available && (env->sregs[SR_MSR] & MSR_VM)) { + target_ulong vaddr, paddr; + struct microblaze_mmu_lookup lu; + + hit = mmu_translate(&env->mmu, &lu, address, rw, mmu_idx); + if (hit) { + vaddr = address & TARGET_PAGE_MASK; + paddr = lu.paddr + vaddr - lu.vaddr; + + DMMU(qemu_log("MMU map mmu=%d v=%x p=%x prot=%x\n", + mmu_idx, vaddr, paddr, lu.prot)); + r = tlb_set_page(env, vaddr, + paddr, lu.prot, mmu_idx, is_softmmu); + } else { + env->sregs[SR_EAR] = address; + DMMU(qemu_log("mmu=%d miss addr=%x\n", mmu_idx, vaddr)); + + switch (lu.err) { + case ERR_PROT: + env->sregs[SR_ESR] = rw == 2 ? 17 : 16; + env->sregs[SR_ESR] |= (rw == 1) << 10; + break; + case ERR_MISS: + env->sregs[SR_ESR] = rw == 2 ? 19 : 18; + env->sregs[SR_ESR] |= (rw == 1) << 10; + break; + default: + abort(); + break; + } + + if (env->exception_index == EXCP_MMU) { + cpu_abort(env, "recursive faults\n"); + } + + /* TLB miss. */ + env->exception_index = EXCP_MMU; + } + } else { + /* MMU disabled or not available. */ + address &= TARGET_PAGE_MASK; + prot = PAGE_BITS; + r = tlb_set_page(env, address, address, prot, mmu_idx, is_softmmu); + } + return r; +} + +void do_interrupt(CPUState *env) +{ + uint32_t t; + + /* IMM flag cannot propagate accross a branch and into the dslot. */ + assert(!((env->iflags & D_FLAG) && (env->iflags & IMM_FLAG))); + assert(!(env->iflags & (DRTI_FLAG | DRTE_FLAG | DRTB_FLAG))); +/* assert(env->sregs[SR_MSR] & (MSR_EE)); Only for HW exceptions. */ + switch (env->exception_index) { + case EXCP_MMU: + env->regs[17] = env->sregs[SR_PC]; + + /* Exception breaks branch + dslot sequence? */ + if (env->iflags & D_FLAG) { + D(qemu_log("D_FLAG set at exception bimm=%d\n", env->bimm)); + env->sregs[SR_ESR] |= 1 << 12 ; + env->sregs[SR_BTR] = env->btarget; + + /* Reexecute the branch. */ + env->regs[17] -= 4; + /* was the branch immprefixed?. */ + if (env->bimm) { + qemu_log_mask(CPU_LOG_INT, + "bimm exception at pc=%x iflags=%x\n", + env->sregs[SR_PC], env->iflags); + env->regs[17] -= 4; + log_cpu_state_mask(CPU_LOG_INT, env, 0); + } + } else if (env->iflags & IMM_FLAG) { + D(qemu_log("IMM_FLAG set at exception\n")); + env->regs[17] -= 4; + } + + /* Disable the MMU. */ + t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; + env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + env->sregs[SR_MSR] |= t; + /* Exception in progress. */ + env->sregs[SR_MSR] |= MSR_EIP; + + qemu_log_mask(CPU_LOG_INT, + "exception at pc=%x ear=%x iflags=%x\n", + env->sregs[SR_PC], env->sregs[SR_EAR], env->iflags); + log_cpu_state_mask(CPU_LOG_INT, env, 0); + env->iflags &= ~(IMM_FLAG | D_FLAG); + env->sregs[SR_PC] = 0x20; + break; + + case EXCP_IRQ: + assert(!(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP))); + assert(env->sregs[SR_MSR] & MSR_IE); + assert(!(env->iflags & D_FLAG)); + + t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; + +#if 0 +#include "disas.h" + +/* Useful instrumentation when debugging interrupt issues in either + the models or in sw. */ + { + const char *sym; + + sym = lookup_symbol(env->sregs[SR_PC]); + if (sym + && (!strcmp("netif_rx", sym) + || !strcmp("process_backlog", sym))) { + + qemu_log( + "interrupt at pc=%x msr=%x %x iflags=%x sym=%s\n", + env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags, + sym); + + log_cpu_state(env, 0); + } + } +#endif + qemu_log_mask(CPU_LOG_INT, + "interrupt at pc=%x msr=%x %x iflags=%x\n", + env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); + + env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM \ + | MSR_UM | MSR_IE); + env->sregs[SR_MSR] |= t; + + env->regs[14] = env->sregs[SR_PC]; + env->sregs[SR_PC] = 0x10; + //log_cpu_state_mask(CPU_LOG_INT, env, 0); + break; + + case EXCP_BREAK: + case EXCP_HW_BREAK: + assert(!(env->iflags & IMM_FLAG)); + assert(!(env->iflags & D_FLAG)); + t = (env->sregs[SR_MSR] & (MSR_VM | MSR_UM)) << 1; + qemu_log_mask(CPU_LOG_INT, + "break at pc=%x msr=%x %x iflags=%x\n", + env->sregs[SR_PC], env->sregs[SR_MSR], t, env->iflags); + log_cpu_state_mask(CPU_LOG_INT, env, 0); + env->sregs[SR_MSR] &= ~(MSR_VMS | MSR_UMS | MSR_VM | MSR_UM); + env->sregs[SR_MSR] |= t; + env->sregs[SR_MSR] |= MSR_BIP; + if (env->exception_index == EXCP_HW_BREAK) { + env->regs[16] = env->sregs[SR_PC]; + env->sregs[SR_MSR] |= MSR_BIP; + env->sregs[SR_PC] = 0x18; + } else + env->sregs[SR_PC] = env->btarget; + break; + default: + cpu_abort(env, "unhandled exception type=%d\n", + env->exception_index); + break; + } +} + +target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr) +{ + target_ulong vaddr, paddr = 0; + struct microblaze_mmu_lookup lu; + unsigned int hit; + + if (env->sregs[SR_MSR] & MSR_VM) { + hit = mmu_translate(&env->mmu, &lu, addr, 0, 0); + if (hit) { + vaddr = addr & TARGET_PAGE_MASK; + paddr = lu.paddr + vaddr - lu.vaddr; + } else + paddr = 0; /* ???. */ + } else + paddr = addr & TARGET_PAGE_MASK; + + return paddr; +} +#endif diff --git a/target-microblaze/helper.h b/target-microblaze/helper.h new file mode 100644 index 0000000..8c5361e --- /dev/null +++ b/target-microblaze/helper.h @@ -0,0 +1,19 @@ +#include "def-helper.h" + +DEF_HELPER_1(raise_exception, void, i32) +DEF_HELPER_0(debug, void) +DEF_HELPER_4(addkc, i32, i32, i32, i32, i32) +DEF_HELPER_4(subkc, i32, i32, i32, i32, i32) +DEF_HELPER_2(cmp, i32, i32, i32) +DEF_HELPER_2(cmpu, i32, i32, i32) + +DEF_HELPER_2(divs, i32, i32, i32) +DEF_HELPER_2(divu, i32, i32, i32) + +DEF_HELPER_FLAGS_2(pcmpbf, TCG_CALL_PURE | TCG_CALL_CONST, i32, i32, i32) +#if !defined(CONFIG_USER_ONLY) +DEF_HELPER_1(mmu_read, i32, i32) +DEF_HELPER_2(mmu_write, void, i32, i32) +#endif + +#include "def-helper.h" diff --git a/target-microblaze/microblaze-decode.h b/target-microblaze/microblaze-decode.h new file mode 100644 index 0000000..27b0128 --- /dev/null +++ b/target-microblaze/microblaze-decode.h @@ -0,0 +1,52 @@ +/* + * MicroBlaze insn decoding macros. + * + * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com> + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +/* Convenient binary macros. */ +#define HEX__(n) 0x##n##LU +#define B8__(x) ((x&0x0000000FLU)?1:0) \ + + ((x&0x000000F0LU)?2:0) \ + + ((x&0x00000F00LU)?4:0) \ + + ((x&0x0000F000LU)?8:0) \ + + ((x&0x000F0000LU)?16:0) \ + + ((x&0x00F00000LU)?32:0) \ + + ((x&0x0F000000LU)?64:0) \ + + ((x&0xF0000000LU)?128:0) +#define B8(d) ((unsigned char)B8__(HEX__(d))) + +/* Decode logic, mask and value. */ +#define DEC_ADD {B8(00000000), B8(00110001)} +#define DEC_SUB {B8(00000001), B8(00110001)} +#define DEC_AND {B8(00100001), B8(00110101)} +#define DEC_XOR {B8(00100010), B8(00110111)} +#define DEC_OR {B8(00100000), B8(00110111)} +#define DEC_BIT {B8(00100100), B8(00111111)} +#define DEC_MSR {B8(00100101), B8(00111111)} + +#define DEC_BARREL {B8(00010001), B8(00110111)} +#define DEC_MUL {B8(00010000), B8(00110111)} +#define DEC_DIV {B8(00010010), B8(00110111)} + +#define DEC_LD {B8(00110000), B8(00110100)} +#define DEC_ST {B8(00110100), B8(00110100)} +#define DEC_IMM {B8(00101100), B8(00111111)} + +#define DEC_BR {B8(00100110), B8(00110111)} +#define DEC_BCC {B8(00100111), B8(00110111)} +#define DEC_RTS {B8(00101101), B8(00111111)} diff --git a/target-microblaze/op_helper.c b/target-microblaze/op_helper.c new file mode 100644 index 0000000..1a0776d --- /dev/null +++ b/target-microblaze/op_helper.c @@ -0,0 +1,216 @@ +/* + * Microblaze helper routines. + * + * Copyright (c) 2009 Edgar E. Iglesias <edgar.iglesias@gmail.com>. + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#include <assert.h> +#include "exec.h" +#include "helper.h" +#include "host-utils.h" + +#define D(x) + +#if !defined(CONFIG_USER_ONLY) +#define MMUSUFFIX _mmu +#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 mmu_idx, 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_mb_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); + if (unlikely(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); + } + } + cpu_loop_exit(); + } + env = saved_env; +} +#endif + +void helper_raise_exception(uint32_t index) +{ + env->exception_index = index; + cpu_loop_exit(); +} + +void helper_debug(void) +{ + int i; + + qemu_log("PC=%8.8x\n", env->sregs[SR_PC]); + for (i = 0; i < 32; i++) { + qemu_log("r%2.2d=%8.8x ", i, env->regs[i]); + if ((i + 1) % 4 == 0) + qemu_log("\n"); + } + qemu_log("\n\n"); +} + +static inline uint32_t compute_carry(uint32_t a, uint32_t b, uint32_t cin) +{ + uint32_t cout = 0; + + if ((b == ~0) && cin) + cout = 1; + else if ((~0 - a) < (b + cin)) + cout = 1; + return cout; +} + +uint32_t helper_cmp(uint32_t a, uint32_t b) +{ + uint32_t t; + + t = b + ~a + 1; + if ((b & 0x80000000) ^ (a & 0x80000000)) + t = (t & 0x7fffffff) | (b & 0x80000000); + return t; +} + +uint32_t helper_cmpu(uint32_t a, uint32_t b) +{ + uint32_t t; + + t = b + ~a + 1; + if ((b & 0x80000000) ^ (a & 0x80000000)) + t = (t & 0x7fffffff) | (a & 0x80000000); + return t; +} + +uint32_t helper_addkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) +{ + uint32_t d, cf = 0, ncf; + + if (c) + cf = env->sregs[SR_MSR] >> 31; + assert(cf == 0 || cf == 1); + d = a + b + cf; + + if (!k) { + ncf = compute_carry(a, b, cf); + assert(ncf == 0 || ncf == 1); + if (ncf) + env->sregs[SR_MSR] |= MSR_C | MSR_CC; + else + env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); + } + D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", + d, a, b, cf, ncf, k, c)); + return d; +} + +uint32_t helper_subkc(uint32_t a, uint32_t b, uint32_t k, uint32_t c) +{ + uint32_t d, cf = 1, ncf; + + if (c) + cf = env->sregs[SR_MSR] >> 31; + assert(cf == 0 || cf == 1); + d = b + ~a + cf; + + if (!k) { + ncf = compute_carry(b, ~a, cf); + assert(ncf == 0 || ncf == 1); + if (ncf) + env->sregs[SR_MSR] |= MSR_C | MSR_CC; + else + env->sregs[SR_MSR] &= ~(MSR_C | MSR_CC); + } + D(qemu_log("%x = %x + %x cf=%d ncf=%d k=%d c=%d\n", + d, a, b, cf, ncf, k, c)); + return d; +} + +static inline int div_prepare(uint32_t a, uint32_t b) +{ + if (b == 0) { + env->sregs[SR_MSR] |= MSR_DZ; + /* FIXME: Raise the div by zero exception. */ + return 0; + } + env->sregs[SR_MSR] &= ~MSR_DZ; + return 1; +} + +uint32_t helper_divs(uint32_t a, uint32_t b) +{ + if (!div_prepare(a, b)) + return 0; + return (int32_t)a / (int32_t)b; +} + +uint32_t helper_divu(uint32_t a, uint32_t b) +{ + if (!div_prepare(a, b)) + return 0; + return a / b; +} + +uint32_t helper_pcmpbf(uint32_t a, uint32_t b) +{ + unsigned int i; + uint32_t mask = 0xff000000; + + for (i = 0; i < 4; i++) { + if ((a & mask) == (b & mask)) + return i + 1; + mask >>= 8; + } + return 0; +} + +#if !defined(CONFIG_USER_ONLY) +/* Writes/reads to the MMU's special regs end up here. */ +uint32_t helper_mmu_read(uint32_t rn) +{ + return mmu_read(env, rn); +} + +void helper_mmu_write(uint32_t rn, uint32_t v) +{ + mmu_write(env, rn, v); +} +#endif diff --git a/target-microblaze/translate.c b/target-microblaze/translate.c new file mode 100644 index 0000000..33fff9c --- /dev/null +++ b/target-microblaze/translate.c @@ -0,0 +1,1395 @@ +/* + * Xilinx MicroBlaze emulation for qemu: main translation routines. + * + * Copyright (c) 2009 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <inttypes.h> +#include <assert.h> + +#include "cpu.h" +#include "exec-all.h" +#include "disas.h" +#include "tcg-op.h" +#include "helper.h" +#include "microblaze-decode.h" +#include "qemu-common.h" + +#define GEN_HELPER 1 +#include "helper.h" + +#define SIM_COMPAT 0 +#define DISAS_GNU 1 +#define DISAS_MB 1 +#if DISAS_MB && !SIM_COMPAT +# define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__) +#else +# define LOG_DIS(...) do { } while (0) +#endif + +#define D(x) + +#define EXTRACT_FIELD(src, start, end) \ + (((src) >> start) & ((1 << (end - start + 1)) - 1)) + +static TCGv env_debug; +static TCGv_ptr cpu_env; +static TCGv cpu_R[32]; +static TCGv cpu_SR[18]; +static TCGv env_imm; +static TCGv env_btaken; +static TCGv env_btarget; +static TCGv env_iflags; + +#include "gen-icount.h" + +/* This is the state at translation time. */ +typedef struct DisasContext { + CPUState *env; + target_ulong pc, ppc; + target_ulong cache_pc; + + /* Decoder. */ + int type_b; + uint32_t ir; + uint8_t opcode; + uint8_t rd, ra, rb; + uint16_t imm; + + unsigned int cpustate_changed; + unsigned int delayed_branch; + unsigned int tb_flags, synced_flags; /* tb dependent flags. */ + unsigned int clear_imm; + int is_jmp; + +#define JMP_NOJMP 0 +#define JMP_DIRECT 1 +#define JMP_INDIRECT 2 + unsigned int jmp; + uint32_t jmp_pc; + + int abort_at_next_insn; + int nr_nops; + struct TranslationBlock *tb; + int singlestep_enabled; +} DisasContext; + +const static char *regnames[] = +{ + "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", + "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", +}; + +const static char *special_regnames[] = +{ + "rpc", "rmsr", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7", + "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15", + "sr16", "sr17", "sr18" +}; + +/* Sign extend at translation time. */ +static inline int sign_extend(unsigned int val, unsigned int width) +{ + int sval; + + /* LSL. */ + val <<= 31 - width; + sval = val; + /* ASR. */ + sval >>= 31 - width; + return sval; +} + +static inline void t_sync_flags(DisasContext *dc) +{ + /* Synch the tb dependant flags between translator and runtime. */ + if (dc->tb_flags != dc->synced_flags) { + tcg_gen_movi_tl(env_iflags, dc->tb_flags); + dc->synced_flags = dc->tb_flags; + } +} + +static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index) +{ + TCGv_i32 tmp = tcg_const_i32(index); + + t_sync_flags(dc); + tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc); + gen_helper_raise_exception(tmp); + tcg_temp_free_i32(tmp); + dc->is_jmp = DISAS_UPDATE; +} + +static void gen_goto_tb(DisasContext *dc, int n, target_ulong dest) +{ + TranslationBlock *tb; + tb = dc->tb; + if ((tb->pc & TARGET_PAGE_MASK) == (dest & TARGET_PAGE_MASK)) { + tcg_gen_goto_tb(n); + tcg_gen_movi_tl(cpu_SR[SR_PC], dest); + tcg_gen_exit_tb((long)tb + n); + } else { + tcg_gen_movi_tl(cpu_SR[SR_PC], dest); + tcg_gen_exit_tb(0); + } +} + +static inline TCGv *dec_alu_op_b(DisasContext *dc) +{ + if (dc->type_b) { + if (dc->tb_flags & IMM_FLAG) + tcg_gen_ori_tl(env_imm, env_imm, dc->imm); + else + tcg_gen_movi_tl(env_imm, (int32_t)((int16_t)dc->imm)); + return &env_imm; + } else + return &cpu_R[dc->rb]; +} + +static void dec_add(DisasContext *dc) +{ + unsigned int k, c; + + k = dc->opcode & 4; + c = dc->opcode & 2; + + LOG_DIS("add%s%s%s r%d r%d r%d\n", + dc->type_b ? "i" : "", k ? "k" : "", c ? "c" : "", + dc->rd, dc->ra, dc->rb); + + if (k && !c && dc->rd) + tcg_gen_add_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); + else if (dc->rd) + gen_helper_addkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)), + tcg_const_tl(k), tcg_const_tl(c)); + else { + TCGv d = tcg_temp_new(); + gen_helper_addkc(d, cpu_R[dc->ra], *(dec_alu_op_b(dc)), + tcg_const_tl(k), tcg_const_tl(c)); + tcg_temp_free(d); + } +} + +static void dec_sub(DisasContext *dc) +{ + unsigned int u, cmp, k, c; + + u = dc->imm & 2; + k = dc->opcode & 4; + c = dc->opcode & 2; + cmp = (dc->imm & 1) && (!dc->type_b) && k; + + if (cmp) { + LOG_DIS("cmp%s r%d, r%d ir=%x\n", u ? "u" : "", dc->rd, dc->ra, dc->ir); + if (dc->rd) { + if (u) + gen_helper_cmpu(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); + else + gen_helper_cmp(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); + } + } else { + LOG_DIS("sub%s%s r%d, r%d r%d\n", + k ? "k" : "", c ? "c" : "", dc->rd, dc->ra, dc->rb); + + if (!k || c) { + TCGv t; + t = tcg_temp_new(); + if (dc->rd) + gen_helper_subkc(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc)), + tcg_const_tl(k), tcg_const_tl(c)); + else + gen_helper_subkc(t, cpu_R[dc->ra], *(dec_alu_op_b(dc)), + tcg_const_tl(k), tcg_const_tl(c)); + tcg_temp_free(t); + } + else if (dc->rd) + tcg_gen_sub_tl(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); + } +} + +static void dec_pattern(DisasContext *dc) +{ + unsigned int mode; + int l1; + + mode = dc->opcode & 3; + switch (mode) { + case 0: + /* pcmpbf. */ + LOG_DIS("pcmpbf r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); + if (dc->rd) + gen_helper_pcmpbf(cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 2: + LOG_DIS("pcmpeq r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); + if (dc->rd) { + TCGv t0 = tcg_temp_local_new(); + l1 = gen_new_label(); + tcg_gen_movi_tl(t0, 1); + tcg_gen_brcond_tl(TCG_COND_EQ, + cpu_R[dc->ra], cpu_R[dc->rb], l1); + tcg_gen_movi_tl(t0, 0); + gen_set_label(l1); + tcg_gen_mov_tl(cpu_R[dc->rd], t0); + tcg_temp_free(t0); + } + break; + case 3: + LOG_DIS("pcmpne r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); + l1 = gen_new_label(); + if (dc->rd) { + TCGv t0 = tcg_temp_local_new(); + tcg_gen_movi_tl(t0, 1); + tcg_gen_brcond_tl(TCG_COND_NE, + cpu_R[dc->ra], cpu_R[dc->rb], l1); + tcg_gen_movi_tl(t0, 0); + gen_set_label(l1); + tcg_gen_mov_tl(cpu_R[dc->rd], t0); + tcg_temp_free(t0); + } + break; + default: + cpu_abort(dc->env, + "unsupported pattern insn opcode=%x\n", dc->opcode); + break; + } +} + +static void dec_and(DisasContext *dc) +{ + unsigned int not; + + if (!dc->type_b && (dc->imm & (1 << 10))) { + dec_pattern(dc); + return; + } + + not = dc->opcode & (1 << 1); + LOG_DIS("and%s\n", not ? "n" : ""); + + if (!dc->rd) + return; + + if (not) { + TCGv t = tcg_temp_new(); + tcg_gen_not_tl(t, *(dec_alu_op_b(dc))); + tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], t); + tcg_temp_free(t); + } else + tcg_gen_and_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); +} + +static void dec_or(DisasContext *dc) +{ + if (!dc->type_b && (dc->imm & (1 << 10))) { + dec_pattern(dc); + return; + } + + LOG_DIS("or r%d r%d r%d imm=%x\n", dc->rd, dc->ra, dc->rb, dc->imm); + if (dc->rd) + tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); +} + +static void dec_xor(DisasContext *dc) +{ + if (!dc->type_b && (dc->imm & (1 << 10))) { + dec_pattern(dc); + return; + } + + LOG_DIS("xor r%d\n", dc->rd); + if (dc->rd) + tcg_gen_xor_tl(cpu_R[dc->rd], cpu_R[dc->ra], *(dec_alu_op_b(dc))); +} + +static void read_carry(DisasContext *dc, TCGv d) +{ + tcg_gen_shri_tl(d, cpu_SR[SR_MSR], 31); +} + +static void write_carry(DisasContext *dc, TCGv v) +{ + TCGv t0 = tcg_temp_new(); + tcg_gen_shli_tl(t0, v, 31); + tcg_gen_sari_tl(t0, t0, 31); + tcg_gen_mov_tl(env_debug, t0); + tcg_gen_andi_tl(t0, t0, (MSR_C | MSR_CC)); + tcg_gen_andi_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], + ~(MSR_C | MSR_CC)); + tcg_gen_or_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], t0); + tcg_temp_free(t0); +} + + +static inline void msr_read(DisasContext *dc, TCGv d) +{ + tcg_gen_mov_tl(d, cpu_SR[SR_MSR]); +} + +static inline void msr_write(DisasContext *dc, TCGv v) +{ + dc->cpustate_changed = 1; + tcg_gen_mov_tl(cpu_SR[SR_MSR], v); + /* PVR, we have a processor version register. */ + tcg_gen_ori_tl(cpu_SR[SR_MSR], cpu_SR[SR_MSR], (1 << 10)); +} + +static void dec_msr(DisasContext *dc) +{ + TCGv t0, t1; + unsigned int sr, to, rn; + + sr = dc->imm & ((1 << 14) - 1); + to = dc->imm & (1 << 14); + dc->type_b = 1; + if (to) + dc->cpustate_changed = 1; + + /* msrclr and msrset. */ + if (!(dc->imm & (1 << 15))) { + unsigned int clr = dc->ir & (1 << 16); + + LOG_DIS("msr%s r%d imm=%x\n", clr ? "clr" : "set", + dc->rd, dc->imm); + if (dc->rd) + msr_read(dc, cpu_R[dc->rd]); + + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + msr_read(dc, t0); + tcg_gen_mov_tl(t1, *(dec_alu_op_b(dc))); + + if (clr) { + tcg_gen_not_tl(t1, t1); + tcg_gen_and_tl(t0, t0, t1); + } else + tcg_gen_or_tl(t0, t0, t1); + msr_write(dc, t0); + tcg_temp_free(t0); + tcg_temp_free(t1); + tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc + 4); + dc->is_jmp = DISAS_UPDATE; + return; + } + +#if !defined(CONFIG_USER_ONLY) + /* Catch read/writes to the mmu block. */ + if ((sr & ~0xff) == 0x1000) { + sr &= 7; + LOG_DIS("m%ss sr%d r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); + if (to) + gen_helper_mmu_write(tcg_const_tl(sr), cpu_R[dc->ra]); + else + gen_helper_mmu_read(cpu_R[dc->rd], tcg_const_tl(sr)); + return; + } +#endif + + if (to) { + LOG_DIS("m%ss sr%x r%d imm=%x\n", to ? "t" : "f", sr, dc->ra, dc->imm); + switch (sr) { + case 0: + break; + case 1: + msr_write(dc, cpu_R[dc->ra]); + break; + case 0x3: + tcg_gen_mov_tl(cpu_SR[SR_EAR], cpu_R[dc->ra]); + break; + case 0x5: + tcg_gen_mov_tl(cpu_SR[SR_ESR], cpu_R[dc->ra]); + break; + case 0x7: + /* Ignored at the moment. */ + break; + default: + cpu_abort(dc->env, "unknown mts reg %x\n", sr); + break; + } + } else { + LOG_DIS("m%ss r%d sr%x imm=%x\n", to ? "t" : "f", dc->rd, sr, dc->imm); + + switch (sr) { + case 0: + tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc); + break; + case 1: + msr_read(dc, cpu_R[dc->rd]); + break; + case 0x3: + tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_EAR]); + break; + case 0x5: + tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_ESR]); + break; + case 0x7: + tcg_gen_movi_tl(cpu_R[dc->rd], 0); + break; + case 0xb: + tcg_gen_mov_tl(cpu_R[dc->rd], cpu_SR[SR_BTR]); + break; + case 0x2000: + case 0x2001: + case 0x2002: + case 0x2003: + case 0x2004: + case 0x2005: + case 0x2006: + case 0x2007: + case 0x2008: + case 0x2009: + case 0x200a: + case 0x200b: + case 0x200c: + rn = sr & 0xf; + tcg_gen_ld_tl(cpu_R[dc->rd], + cpu_env, offsetof(CPUState, pvr.regs[rn])); + break; + default: + cpu_abort(dc->env, "unknown mfs reg %x\n", sr); + break; + } + } +} + +/* 64-bit signed mul, lower result in d and upper in d2. */ +static void t_gen_muls(TCGv d, TCGv d2, TCGv a, TCGv b) +{ + TCGv_i64 t0, t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_ext_i32_i64(t0, a); + tcg_gen_ext_i32_i64(t1, b); + tcg_gen_mul_i64(t0, t0, t1); + + tcg_gen_trunc_i64_i32(d, t0); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(d2, t0); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +/* 64-bit unsigned muls, lower result in d and upper in d2. */ +static void t_gen_mulu(TCGv d, TCGv d2, TCGv a, TCGv b) +{ + TCGv_i64 t0, t1; + + t0 = tcg_temp_new_i64(); + t1 = tcg_temp_new_i64(); + + tcg_gen_extu_i32_i64(t0, a); + tcg_gen_extu_i32_i64(t1, b); + tcg_gen_mul_i64(t0, t0, t1); + + tcg_gen_trunc_i64_i32(d, t0); + tcg_gen_shri_i64(t0, t0, 32); + tcg_gen_trunc_i64_i32(d2, t0); + + tcg_temp_free_i64(t0); + tcg_temp_free_i64(t1); +} + +/* Multiplier unit. */ +static void dec_mul(DisasContext *dc) +{ + TCGv d[2]; + unsigned int subcode; + + subcode = dc->imm & 3; + d[0] = tcg_temp_new(); + d[1] = tcg_temp_new(); + + if (dc->type_b) { + LOG_DIS("muli r%d r%d %x\n", dc->rd, dc->ra, dc->imm); + t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], *(dec_alu_op_b(dc))); + goto done; + } + + switch (subcode) { + case 0: + LOG_DIS("mul r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); + t_gen_mulu(cpu_R[dc->rd], d[1], cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 1: + LOG_DIS("mulh r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); + t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 2: + LOG_DIS("mulhsu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); + t_gen_muls(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); + break; + case 3: + LOG_DIS("mulhu r%d r%d r%d\n", dc->rd, dc->ra, dc->rb); + t_gen_mulu(d[0], cpu_R[dc->rd], cpu_R[dc->ra], cpu_R[dc->rb]); + break; + default: + cpu_abort(dc->env, "unknown MUL insn %x\n", subcode); + break; + } +done: + tcg_temp_free(d[0]); + tcg_temp_free(d[1]); +} + +/* Div unit. */ +static void dec_div(DisasContext *dc) +{ + unsigned int u; + + u = dc->imm & 2; + LOG_DIS("div\n"); + + /* FIXME: support div by zero exceptions. */ + if (u) + gen_helper_divu(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); + else + gen_helper_divs(cpu_R[dc->rd], *(dec_alu_op_b(dc)), cpu_R[dc->ra]); + if (!dc->rd) + tcg_gen_movi_tl(cpu_R[dc->rd], 0); +} + +static void dec_barrel(DisasContext *dc) +{ + TCGv t0; + unsigned int s, t; + + s = dc->imm & (1 << 10); + t = dc->imm & (1 << 9); + + LOG_DIS("bs%s%s r%d r%d r%d\n", + s ? "l" : "r", t ? "a" : "l", dc->rd, dc->ra, dc->rb); + + t0 = tcg_temp_new(); + + tcg_gen_mov_tl(t0, *(dec_alu_op_b(dc))); + tcg_gen_andi_tl(t0, t0, 31); + + if (s) + tcg_gen_shl_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0); + else { + if (t) + tcg_gen_sar_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0); + else + tcg_gen_shr_tl(cpu_R[dc->rd], cpu_R[dc->ra], t0); + } +} + +static void dec_bit(DisasContext *dc) +{ + TCGv t0, t1; + unsigned int op; + + op = dc->ir & ((1 << 8) - 1); + switch (op) { + case 0x21: + /* src. */ + t0 = tcg_temp_new(); + + LOG_DIS("src r%d r%d\n", dc->rd, dc->ra); + tcg_gen_andi_tl(t0, cpu_R[dc->ra], 1); + if (dc->rd) { + t1 = tcg_temp_new(); + read_carry(dc, t1); + tcg_gen_shli_tl(t1, t1, 31); + + tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1); + tcg_gen_or_tl(cpu_R[dc->rd], cpu_R[dc->rd], t1); + tcg_temp_free(t1); + } + + /* Update carry. */ + write_carry(dc, t0); + tcg_temp_free(t0); + break; + + case 0x1: + case 0x41: + /* srl. */ + t0 = tcg_temp_new(); + LOG_DIS("srl r%d r%d\n", dc->rd, dc->ra); + + /* Update carry. */ + tcg_gen_andi_tl(t0, cpu_R[dc->ra], 1); + write_carry(dc, t0); + tcg_temp_free(t0); + if (dc->rd) { + if (op == 0x41) + tcg_gen_shri_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1); + else + tcg_gen_sari_tl(cpu_R[dc->rd], cpu_R[dc->ra], 1); + } + break; + case 0x60: + LOG_DIS("ext8s r%d r%d\n", dc->rd, dc->ra); + tcg_gen_ext8s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); + break; + case 0x61: + LOG_DIS("ext16s r%d r%d\n", dc->rd, dc->ra); + tcg_gen_ext16s_i32(cpu_R[dc->rd], cpu_R[dc->ra]); + break; + case 0x64: + /* wdc. */ + LOG_DIS("wdc r%d\n", dc->ra); + break; + case 0x68: + /* wic. */ + LOG_DIS("wic r%d\n", dc->ra); + break; + default: + cpu_abort(dc->env, "unknown bit oc=%x op=%x rd=%d ra=%d rb=%d\n", + dc->pc, op, dc->rd, dc->ra, dc->rb); + break; + } +} + +static inline void sync_jmpstate(DisasContext *dc) +{ + if (dc->jmp == JMP_DIRECT) { + dc->jmp = JMP_INDIRECT; + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_movi_tl(env_btarget, dc->jmp_pc); + } +} + +static void dec_imm(DisasContext *dc) +{ + LOG_DIS("imm %x\n", dc->imm << 16); + tcg_gen_movi_tl(env_imm, (dc->imm << 16)); + dc->tb_flags |= IMM_FLAG; + dc->clear_imm = 0; +} + +static inline void gen_load(DisasContext *dc, TCGv dst, TCGv addr, + unsigned int size) +{ + int mem_index = cpu_mmu_index(dc->env); + + if (size == 1) { + tcg_gen_qemu_ld8u(dst, addr, mem_index); + } else if (size == 2) { + tcg_gen_qemu_ld16u(dst, addr, mem_index); + } else if (size == 4) { + tcg_gen_qemu_ld32u(dst, addr, mem_index); + } else + cpu_abort(dc->env, "Incorrect load size %d\n", size); +} + +static inline TCGv *compute_ldst_addr(DisasContext *dc, TCGv *t) +{ + unsigned int extimm = dc->tb_flags & IMM_FLAG; + + /* Treat the fast cases first. */ + if (!dc->type_b) { + *t = tcg_temp_new(); + tcg_gen_add_tl(*t, cpu_R[dc->ra], cpu_R[dc->rb]); + return t; + } + /* Immediate. */ + if (!extimm) { + if (dc->imm == 0) { + return &cpu_R[dc->ra]; + } + *t = tcg_temp_new(); + tcg_gen_movi_tl(*t, (int32_t)((int16_t)dc->imm)); + tcg_gen_add_tl(*t, cpu_R[dc->ra], *t); + } else { + *t = tcg_temp_new(); + tcg_gen_add_tl(*t, cpu_R[dc->ra], *(dec_alu_op_b(dc))); + } + + return t; +} + +static void dec_load(DisasContext *dc) +{ + TCGv t, *addr; + unsigned int size; + + size = 1 << (dc->opcode & 3); + + LOG_DIS("l %x %d\n", dc->opcode, size); + t_sync_flags(dc); + addr = compute_ldst_addr(dc, &t); + + /* If we get a fault on a dslot, the jmpstate better be in sync. */ + sync_jmpstate(dc); + if (dc->rd) + gen_load(dc, cpu_R[dc->rd], *addr, size); + else { + gen_load(dc, env_imm, *addr, size); + } + + if (addr == &t) + tcg_temp_free(t); +} + +static void gen_store(DisasContext *dc, TCGv addr, TCGv val, + unsigned int size) +{ + int mem_index = cpu_mmu_index(dc->env); + + if (size == 1) + tcg_gen_qemu_st8(val, addr, mem_index); + else if (size == 2) { + tcg_gen_qemu_st16(val, addr, mem_index); + } else if (size == 4) { + tcg_gen_qemu_st32(val, addr, mem_index); + } else + cpu_abort(dc->env, "Incorrect store size %d\n", size); +} + +static void dec_store(DisasContext *dc) +{ + TCGv t, *addr; + unsigned int size; + + size = 1 << (dc->opcode & 3); + + LOG_DIS("s%d%s\n", size, dc->type_b ? "i" : ""); + t_sync_flags(dc); + /* If we get a fault on a dslot, the jmpstate better be in sync. */ + sync_jmpstate(dc); + addr = compute_ldst_addr(dc, &t); + gen_store(dc, *addr, cpu_R[dc->rd], size); + if (addr == &t) + tcg_temp_free(t); +} + +static inline void eval_cc(DisasContext *dc, unsigned int cc, + TCGv d, TCGv a, TCGv b) +{ + int l1; + + switch (cc) { + case CC_EQ: + l1 = gen_new_label(); + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_brcond_tl(TCG_COND_EQ, a, b, l1); + tcg_gen_movi_tl(env_btaken, 0); + gen_set_label(l1); + break; + case CC_NE: + l1 = gen_new_label(); + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_brcond_tl(TCG_COND_NE, a, b, l1); + tcg_gen_movi_tl(env_btaken, 0); + gen_set_label(l1); + break; + case CC_LT: + l1 = gen_new_label(); + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_brcond_tl(TCG_COND_LT, a, b, l1); + tcg_gen_movi_tl(env_btaken, 0); + gen_set_label(l1); + break; + case CC_LE: + l1 = gen_new_label(); + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_brcond_tl(TCG_COND_LE, a, b, l1); + tcg_gen_movi_tl(env_btaken, 0); + gen_set_label(l1); + break; + case CC_GE: + l1 = gen_new_label(); + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_brcond_tl(TCG_COND_GE, a, b, l1); + tcg_gen_movi_tl(env_btaken, 0); + gen_set_label(l1); + break; + case CC_GT: + l1 = gen_new_label(); + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_brcond_tl(TCG_COND_GT, a, b, l1); + tcg_gen_movi_tl(env_btaken, 0); + gen_set_label(l1); + break; + default: + cpu_abort(dc->env, "Unknown condition code %x.\n", cc); + break; + } +} + +static void eval_cond_jmp(DisasContext *dc, TCGv pc_true, TCGv pc_false) +{ + int l1; + + l1 = gen_new_label(); + /* Conditional jmp. */ + tcg_gen_mov_tl(cpu_SR[SR_PC], pc_false); + tcg_gen_brcondi_tl(TCG_COND_EQ, env_btaken, 0, l1); + tcg_gen_mov_tl(cpu_SR[SR_PC], pc_true); + gen_set_label(l1); +} + +static void dec_bcc(DisasContext *dc) +{ + unsigned int cc; + unsigned int dslot; + + cc = EXTRACT_FIELD(dc->ir, 21, 23); + dslot = dc->ir & (1 << 25); + LOG_DIS("bcc%s r%d %x\n", dslot ? "d" : "", dc->ra, dc->imm); + + dc->delayed_branch = 1; + if (dslot) { + dc->delayed_branch = 2; + dc->tb_flags |= D_FLAG; + tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)), + cpu_env, offsetof(CPUState, bimm)); + } + + tcg_gen_movi_tl(env_btarget, dc->pc); + tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc))); + eval_cc(dc, cc, env_btaken, cpu_R[dc->ra], tcg_const_tl(0)); + dc->jmp = JMP_INDIRECT; +} + +static void dec_br(DisasContext *dc) +{ + unsigned int dslot, link, abs; + + dslot = dc->ir & (1 << 20); + abs = dc->ir & (1 << 19); + link = dc->ir & (1 << 18); + LOG_DIS("br%s%s%s%s imm=%x\n", + abs ? "a" : "", link ? "l" : "", + dc->type_b ? "i" : "", dslot ? "d" : "", + dc->imm); + + dc->delayed_branch = 1; + if (dslot) { + dc->delayed_branch = 2; + dc->tb_flags |= D_FLAG; + tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)), + cpu_env, offsetof(CPUState, bimm)); + } + if (link && dc->rd) + tcg_gen_movi_tl(cpu_R[dc->rd], dc->pc); + + dc->jmp = JMP_INDIRECT; + if (abs) { + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_mov_tl(env_btarget, *(dec_alu_op_b(dc))); + if (link && !(dc->tb_flags & IMM_FLAG) + && (dc->imm == 8 || dc->imm == 0x18)) + t_gen_raise_exception(dc, EXCP_BREAK); + if (dc->imm == 0) + t_gen_raise_exception(dc, EXCP_DEBUG); + } else { + if (dc->tb_flags & IMM_FLAG) { + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_movi_tl(env_btarget, dc->pc); + tcg_gen_add_tl(env_btarget, env_btarget, *(dec_alu_op_b(dc))); + } else { + dc->jmp = JMP_DIRECT; + dc->jmp_pc = dc->pc + (int32_t)((int16_t)dc->imm); + } + } +} + +static inline void do_rti(DisasContext *dc) +{ + TCGv t0, t1; + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + tcg_gen_shri_tl(t0, cpu_SR[SR_MSR], 1); + tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_IE); + tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM)); + + tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM)); + tcg_gen_or_tl(t1, t1, t0); + msr_write(dc, t1); + tcg_temp_free(t1); + tcg_temp_free(t0); + dc->tb_flags &= ~DRTI_FLAG; +} + +static inline void do_rtb(DisasContext *dc) +{ + TCGv t0, t1; + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + tcg_gen_andi_tl(t1, cpu_SR[SR_MSR], ~MSR_BIP); + tcg_gen_shri_tl(t0, t1, 1); + tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM)); + + tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM)); + tcg_gen_or_tl(t1, t1, t0); + msr_write(dc, t1); + tcg_temp_free(t1); + tcg_temp_free(t0); + dc->tb_flags &= ~DRTB_FLAG; +} + +static inline void do_rte(DisasContext *dc) +{ + TCGv t0, t1; + t0 = tcg_temp_new(); + t1 = tcg_temp_new(); + + tcg_gen_ori_tl(t1, cpu_SR[SR_MSR], MSR_EE); + tcg_gen_andi_tl(t1, t1, ~MSR_EIP); + tcg_gen_shri_tl(t0, t1, 1); + tcg_gen_andi_tl(t0, t0, (MSR_VM | MSR_UM)); + + tcg_gen_andi_tl(t1, t1, ~(MSR_VM | MSR_UM)); + tcg_gen_or_tl(t1, t1, t0); + msr_write(dc, t1); + tcg_temp_free(t1); + tcg_temp_free(t0); + dc->tb_flags &= ~DRTE_FLAG; +} + +static void dec_rts(DisasContext *dc) +{ + unsigned int b_bit, i_bit, e_bit; + + i_bit = dc->ir & (1 << 21); + b_bit = dc->ir & (1 << 22); + e_bit = dc->ir & (1 << 23); + + dc->delayed_branch = 2; + dc->tb_flags |= D_FLAG; + tcg_gen_st_tl(tcg_const_tl(dc->type_b && (dc->tb_flags & IMM_FLAG)), + cpu_env, offsetof(CPUState, bimm)); + + if (i_bit) { + LOG_DIS("rtid ir=%x\n", dc->ir); + dc->tb_flags |= DRTI_FLAG; + } else if (b_bit) { + LOG_DIS("rtbd ir=%x\n", dc->ir); + dc->tb_flags |= DRTB_FLAG; + } else if (e_bit) { + LOG_DIS("rted ir=%x\n", dc->ir); + dc->tb_flags |= DRTE_FLAG; + } else + LOG_DIS("rts ir=%x\n", dc->ir); + + tcg_gen_movi_tl(env_btaken, 1); + tcg_gen_add_tl(env_btarget, cpu_R[dc->ra], *(dec_alu_op_b(dc))); +} + +static void dec_null(DisasContext *dc) +{ + qemu_log ("unknown insn pc=%x opc=%x\n", dc->pc, dc->opcode); + dc->abort_at_next_insn = 1; +} + +static struct decoder_info { + struct { + uint32_t bits; + uint32_t mask; + }; + void (*dec)(DisasContext *dc); +} decinfo[] = { + {DEC_ADD, dec_add}, + {DEC_SUB, dec_sub}, + {DEC_AND, dec_and}, + {DEC_XOR, dec_xor}, + {DEC_OR, dec_or}, + {DEC_BIT, dec_bit}, + {DEC_BARREL, dec_barrel}, + {DEC_LD, dec_load}, + {DEC_ST, dec_store}, + {DEC_IMM, dec_imm}, + {DEC_BR, dec_br}, + {DEC_BCC, dec_bcc}, + {DEC_RTS, dec_rts}, + {DEC_MUL, dec_mul}, + {DEC_DIV, dec_div}, + {DEC_MSR, dec_msr}, + {{0, 0}, dec_null} +}; + +static inline void decode(DisasContext *dc) +{ + uint32_t ir; + int i; + + if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP))) + tcg_gen_debug_insn_start(dc->pc); + + dc->ir = ir = ldl_code(dc->pc); + LOG_DIS("%8.8x\t", dc->ir); + + if (dc->ir) + dc->nr_nops = 0; + else { + LOG_DIS("nr_nops=%d\t", dc->nr_nops); + dc->nr_nops++; + if (dc->nr_nops > 4) + cpu_abort(dc->env, "fetching nop sequence\n"); + } + /* bit 2 seems to indicate insn type. */ + dc->type_b = ir & (1 << 29); + + dc->opcode = EXTRACT_FIELD(ir, 26, 31); + dc->rd = EXTRACT_FIELD(ir, 21, 25); + dc->ra = EXTRACT_FIELD(ir, 16, 20); + dc->rb = EXTRACT_FIELD(ir, 11, 15); + dc->imm = EXTRACT_FIELD(ir, 0, 15); + + /* Large switch for all insns. */ + for (i = 0; i < ARRAY_SIZE(decinfo); i++) { + if ((dc->opcode & decinfo[i].mask) == decinfo[i].bits) { + decinfo[i].dec(dc); + break; + } + } +} + + +static void check_breakpoint(CPUState *env, DisasContext *dc) +{ + CPUBreakpoint *bp; + + if (unlikely(!TAILQ_EMPTY(&env->breakpoints))) { + TAILQ_FOREACH(bp, &env->breakpoints, entry) { + if (bp->pc == dc->pc) { + t_gen_raise_exception(dc, EXCP_DEBUG); + dc->is_jmp = DISAS_UPDATE; + } + } + } +} + +/* generate intermediate code for basic block 'tb'. */ +static void +gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb, + int search_pc) +{ + uint16_t *gen_opc_end; + uint32_t pc_start; + int j, lj; + struct DisasContext ctx; + struct DisasContext *dc = &ctx; + uint32_t next_page_start, org_flags; + target_ulong npc; + int num_insns; + int max_insns; + + qemu_log_try_set_file(stderr); + + pc_start = tb->pc; + dc->env = env; + dc->tb = tb; + org_flags = dc->synced_flags = dc->tb_flags = tb->flags; + + gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; + + dc->is_jmp = DISAS_NEXT; + dc->jmp = 0; + dc->delayed_branch = !!(dc->tb_flags & D_FLAG); + dc->ppc = pc_start; + dc->pc = pc_start; + dc->cache_pc = -1; + dc->singlestep_enabled = env->singlestep_enabled; + dc->cpustate_changed = 0; + dc->abort_at_next_insn = 0; + dc->nr_nops = 0; + + if (pc_start & 3) + cpu_abort(env, "Microblaze: unaligned PC=%x\n", pc_start); + + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { +#if !SIM_COMPAT + qemu_log("--------------\n"); + log_cpu_state(env, 0); +#endif + } + + next_page_start = (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + lj = -1; + num_insns = 0; + max_insns = tb->cflags & CF_COUNT_MASK; + if (max_insns == 0) + max_insns = CF_COUNT_MASK; + + gen_icount_start(); + do + { +#if SIM_COMPAT + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + tcg_gen_movi_tl(cpu_SR[SR_PC], dc->pc); + gen_helper_debug(); + } +#endif + check_breakpoint(env, dc); + + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + if (lj < j) { + lj++; + while (lj < j) + gen_opc_instr_start[lj++] = 0; + } + gen_opc_pc[lj] = dc->pc; + gen_opc_instr_start[lj] = 1; + gen_opc_icount[lj] = num_insns; + } + + /* Pretty disas. */ + LOG_DIS("%8.8x:\t", dc->pc); + + if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) + gen_io_start(); + + dc->clear_imm = 1; + decode(dc); + if (dc->clear_imm) + dc->tb_flags &= ~IMM_FLAG; + dc->ppc = dc->pc; + dc->pc += 4; + num_insns++; + + if (dc->delayed_branch) { + dc->delayed_branch--; + if (!dc->delayed_branch) { + if (dc->tb_flags & DRTI_FLAG) + do_rti(dc); + if (dc->tb_flags & DRTB_FLAG) + do_rtb(dc); + if (dc->tb_flags & DRTE_FLAG) + do_rte(dc); + /* Clear the delay slot flag. */ + dc->tb_flags &= ~D_FLAG; + /* If it is a direct jump, try direct chaining. */ + if (dc->jmp != JMP_DIRECT) { + eval_cond_jmp(dc, env_btarget, tcg_const_tl(dc->pc)); + dc->is_jmp = DISAS_JUMP; + } + break; + } + } + if (env->singlestep_enabled) + break; + } while (!dc->is_jmp && !dc->cpustate_changed + && gen_opc_ptr < gen_opc_end + && !singlestep + && (dc->pc < next_page_start) + && num_insns < max_insns); + + npc = dc->pc; + if (dc->jmp == JMP_DIRECT) { + if (dc->tb_flags & D_FLAG) { + dc->is_jmp = DISAS_UPDATE; + tcg_gen_movi_tl(cpu_SR[SR_PC], npc); + sync_jmpstate(dc); + } else + npc = dc->jmp_pc; + } + + if (tb->cflags & CF_LAST_IO) + gen_io_end(); + /* Force an update if the per-tb cpu state has changed. */ + if (dc->is_jmp == DISAS_NEXT + && (dc->cpustate_changed || org_flags != dc->tb_flags)) { + dc->is_jmp = DISAS_UPDATE; + tcg_gen_movi_tl(cpu_SR[SR_PC], npc); + } + t_sync_flags(dc); + + if (unlikely(env->singlestep_enabled)) { + t_gen_raise_exception(dc, EXCP_DEBUG); + if (dc->is_jmp == DISAS_NEXT) + tcg_gen_movi_tl(cpu_SR[SR_PC], npc); + } else { + switch(dc->is_jmp) { + case DISAS_NEXT: + gen_goto_tb(dc, 1, npc); + break; + default: + case DISAS_JUMP: + case DISAS_UPDATE: + /* indicate that the hash table must be used + to find the next TB */ + tcg_gen_exit_tb(0); + break; + case DISAS_TB_JUMP: + /* nothing more to generate */ + break; + } + } + gen_icount_end(tb, num_insns); + *gen_opc_ptr = INDEX_op_end; + if (search_pc) { + j = gen_opc_ptr - gen_opc_buf; + lj++; + while (lj <= j) + gen_opc_instr_start[lj++] = 0; + } else { + tb->size = dc->pc - pc_start; + tb->icount = num_insns; + } + +#ifdef DEBUG_DISAS +#if !SIM_COMPAT + if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { + qemu_log("\n"); +#if DISAS_GNU + log_target_disas(pc_start, dc->pc - pc_start, 0); +#endif + qemu_log("\nisize=%d osize=%zd\n", + dc->pc - pc_start, gen_opc_ptr - gen_opc_buf); + } +#endif +#endif + assert(!dc->abort_at_next_insn); +} + +void gen_intermediate_code (CPUState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 0); +} + +void gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb) +{ + gen_intermediate_code_internal(env, tb, 1); +} + +void cpu_dump_state (CPUState *env, FILE *f, + int (*cpu_fprintf)(FILE *f, const char *fmt, ...), + int flags) +{ + int i; + + if (!env || !f) + return; + + cpu_fprintf(f, "IN: PC=%x %s\n", + env->sregs[SR_PC], lookup_symbol(env->sregs[SR_PC])); + cpu_fprintf(f, "rmsr=%x resr=%x debug[%x] imm=%x iflags=%x\n", + env->sregs[SR_MSR], env->sregs[SR_ESR], + env->debug, env->imm, env->iflags); + cpu_fprintf(f, "btaken=%d btarget=%x mode=%s(saved=%s)\n", + env->btaken, env->btarget, + (env->sregs[SR_MSR] & MSR_UM) ? "user" : "kernel", + (env->sregs[SR_MSR] & MSR_UMS) ? "user" : "kernel"); + for (i = 0; i < 32; i++) { + cpu_fprintf(f, "r%2.2d=%8.8x ", i, env->regs[i]); + if ((i + 1) % 4 == 0) + cpu_fprintf(f, "\n"); + } + cpu_fprintf(f, "\n\n"); +} + +CPUState *cpu_mb_init (const char *cpu_model) +{ + CPUState *env; + static int tcg_initialized = 0; + int i; + + env = qemu_mallocz(sizeof(CPUState)); + + cpu_exec_init(env); + cpu_reset(env); + + env->pvr.regs[0] = PVR0_PVR_FULL_MASK \ + | PVR0_USE_BARREL_MASK \ + | PVR0_USE_DIV_MASK \ + | PVR0_USE_HW_MUL_MASK \ + | PVR0_USE_EXC_MASK \ + | PVR0_USE_ICACHE_MASK \ + | PVR0_USE_DCACHE_MASK \ + | PVR0_USE_MMU \ + | (0xb << 8); + env->pvr.regs[2] = PVR2_D_OPB_MASK \ + | PVR2_D_LMB_MASK \ + | PVR2_I_OPB_MASK \ + | PVR2_I_LMB_MASK \ + | PVR2_USE_MSR_INSTR \ + | PVR2_USE_PCMP_INSTR \ + | PVR2_USE_BARREL_MASK \ + | PVR2_USE_DIV_MASK \ + | PVR2_USE_HW_MUL_MASK \ + | PVR2_USE_MUL64_MASK \ + | 0; + env->pvr.regs[10] = 0x0c000000; /* Default to spartan 3a dsp family. */ + env->pvr.regs[11] = PVR11_USE_MMU; + + if (tcg_initialized) + return env; + + tcg_initialized = 1; + + cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); + + env_debug = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, debug), + "debug0"); + env_iflags = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, iflags), + "iflags"); + env_imm = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, imm), + "imm"); + env_btarget = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, btarget), + "btarget"); + env_btaken = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, btaken), + "btaken"); + for (i = 0; i < ARRAY_SIZE(cpu_R); i++) { + cpu_R[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, regs[i]), + regnames[i]); + } + for (i = 0; i < ARRAY_SIZE(cpu_SR); i++) { + cpu_SR[i] = tcg_global_mem_new(TCG_AREG0, + offsetof(CPUState, sregs[i]), + special_regnames[i]); + } +#define GEN_HELPER 2 +#include "helper.h" + + return env; +} + +void cpu_reset (CPUState *env) +{ + if (qemu_loglevel_mask(CPU_LOG_RESET)) { + qemu_log("CPU Reset (CPU %d)\n", env->cpu_index); + log_cpu_state(env, 0); + } + + memset(env, 0, offsetof(CPUMBState, breakpoints)); + tlb_flush(env, 1); + + env->sregs[SR_MSR] = 0; +#if defined(CONFIG_USER_ONLY) + /* start in user mode with interrupts enabled. */ + env->pvr.regs[10] = 0x0c000000; /* Spartan 3a dsp. */ +#else + mmu_init(&env->mmu); +#endif +} + +void gen_pc_load(CPUState *env, struct TranslationBlock *tb, + unsigned long searched_pc, int pc_pos, void *puc) +{ + env->sregs[SR_PC] = gen_opc_pc[pc_pos]; +} -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 02/13] microblaze: Add syscall, signal and termbits defs for linux-user. 2009-05-20 20:56 [Qemu-devel] [PATCH 01/13] microblaze: Add translation routines Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 03/13] microblaze: linux-user support Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- linux-user/microblaze/syscall.h | 44 ++++ linux-user/microblaze/syscall_nr.h | 369 +++++++++++++++++++++++++++++++++ linux-user/microblaze/target_signal.h | 29 +++ linux-user/microblaze/termbits.h | 213 +++++++++++++++++++ 4 files changed, 655 insertions(+), 0 deletions(-) create mode 100644 linux-user/microblaze/syscall.h create mode 100644 linux-user/microblaze/syscall_nr.h create mode 100644 linux-user/microblaze/target_signal.h create mode 100644 linux-user/microblaze/termbits.h diff --git a/linux-user/microblaze/syscall.h b/linux-user/microblaze/syscall.h new file mode 100644 index 0000000..9863503 --- /dev/null +++ b/linux-user/microblaze/syscall.h @@ -0,0 +1,44 @@ +#define UNAME_MACHINE "microblaze" + +typedef uint32_t microblaze_reg_t; + +struct target_pt_regs { + microblaze_reg_t r0; + microblaze_reg_t r1; + microblaze_reg_t r2; + microblaze_reg_t r3; + microblaze_reg_t r4; + microblaze_reg_t r5; + microblaze_reg_t r6; + microblaze_reg_t r7; + microblaze_reg_t r8; + microblaze_reg_t r9; + microblaze_reg_t r10; + microblaze_reg_t r11; + microblaze_reg_t r12; + microblaze_reg_t r13; + microblaze_reg_t r14; + microblaze_reg_t r15; + microblaze_reg_t r16; + microblaze_reg_t r17; + microblaze_reg_t r18; + microblaze_reg_t r19; + microblaze_reg_t r20; + microblaze_reg_t r21; + microblaze_reg_t r22; + microblaze_reg_t r23; + microblaze_reg_t r24; + microblaze_reg_t r25; + microblaze_reg_t r26; + microblaze_reg_t r27; + microblaze_reg_t r28; + microblaze_reg_t r29; + microblaze_reg_t r30; + microblaze_reg_t r31; + microblaze_reg_t pc; + microblaze_reg_t msr; + microblaze_reg_t ear; + microblaze_reg_t esr; + microblaze_reg_t fsr; + uint32_t kernel_mode; +}; diff --git a/linux-user/microblaze/syscall_nr.h b/linux-user/microblaze/syscall_nr.h new file mode 100644 index 0000000..3e641cd --- /dev/null +++ b/linux-user/microblaze/syscall_nr.h @@ -0,0 +1,369 @@ +#define TARGET_NR_restart_syscall 0 /* ok */ +#define TARGET_NR_exit 1 /* ok */ +#define TARGET_NR_fork 2 /* not for no MMU - weird */ +#define TARGET_NR_read 3 /* ok */ +#define TARGET_NR_write 4 /* ok */ +#define TARGET_NR_open 5 /* openat */ +#define TARGET_NR_close 6 /* ok */ +#define TARGET_NR_waitpid 7 /* waitid */ +#define TARGET_NR_creat 8 /* openat */ +#define TARGET_NR_link 9 /* linkat */ +#define TARGET_NR_unlink 10 /* unlinkat */ +#define TARGET_NR_execve 11 /* ok */ +#define TARGET_NR_chdir 12 /* ok */ +#define TARGET_NR_time 13 /* obsolete -> sys_gettimeofday */ +#define TARGET_NR_mknod 14 /* mknodat */ +#define TARGET_NR_chmod 15 /* fchmodat */ +#define TARGET_NR_lchown 16 /* ok */ +#define TARGET_NR_break 17 /* don't know */ +#define TARGET_NR_oldstat 18 /* remove */ +#define TARGET_NR_lseek 19 /* ok */ +#define TARGET_NR_getpid 20 /* ok */ +#define TARGET_NR_mount 21 /* ok */ +#define TARGET_NR_umount 22 /* ok */ /* use only umount2 */ +#define TARGET_NR_setuid 23 /* ok */ +#define TARGET_NR_getuid 24 /* ok */ +#define TARGET_NR_stime 25 /* obsolete -> sys_settimeofday */ +#define TARGET_NR_ptrace 26 /* ok */ +#define TARGET_NR_alarm 27 /* obsolete -> sys_setitimer */ +#define TARGET_NR_oldfstat 28 /* remove */ +#define TARGET_NR_pause 29 /* obsolete -> sys_rt_sigtimedwait */ +#define TARGET_NR_utime 30 /* obsolete -> sys_utimesat */ +#define TARGET_NR_stty 31 /* remove */ +#define TARGET_NR_gtty 32 /* remove */ +#define TARGET_NR_access 33 /* faccessat */ +#define TARGET_NR_nice 34 /* can be implemented by sys_setpriority */ +#define TARGET_NR_ftime 35 /* remove */ +#define TARGET_NR_sync 36 /* ok */ +#define TARGET_NR_kill 37 /* ok */ +#define TARGET_NR_rename 38 /* renameat */ +#define TARGET_NR_mkdir 39 /* mkdirat */ +#define TARGET_NR_rmdir 40 /* unlinkat */ +#define TARGET_NR_dup 41 /* ok */ +#define TARGET_NR_pipe 42 /* ok */ +#define TARGET_NR_times 43 /* ok */ +#define TARGET_NR_prof 44 /* remove */ +#define TARGET_NR_brk 45 /* ok -mmu, nommu specific */ +#define TARGET_NR_setgid 46 /* ok */ +#define TARGET_NR_getgid 47 /* ok */ +#define TARGET_NR_signal 48 /* obsolete -> sys_rt_sigaction */ +#define TARGET_NR_geteuid 49 /* ok */ +#define TARGET_NR_getegid 50 /* ok */ +#define TARGET_NR_acct 51 /* add it and then I can disable it */ +#define TARGET_NR_umount2 52 /* remove */ +#define TARGET_NR_lock 53 /* remove */ +#define TARGET_NR_ioctl 54 /* ok */ +#define TARGET_NR_fcntl 55 /* ok -> 64bit version*/ +#define TARGET_NR_mpx 56 /* remove */ +#define TARGET_NR_setpgid 57 /* ok */ +#define TARGET_NR_ulimit 58 /* remove */ +#define TARGET_NR_oldolduname 59 /* remove */ +#define TARGET_NR_umask 60 /* ok */ +#define TARGET_NR_chroot 61 /* ok */ +#define TARGET_NR_ustat 62 /* obsolete -> statfs64 */ +#define TARGET_NR_dup2 63 /* ok */ +#define TARGET_NR_getppid 64 /* ok */ +#define TARGET_NR_getpgrp 65 /* obsolete -> sys_getpgid */ +#define TARGET_NR_setsid 66 /* ok */ +#define TARGET_NR_sigaction 67 /* obsolete -> rt_sigaction */ +#define TARGET_NR_sgetmask 68 /* obsolete -> sys_rt_sigprocmask */ +#define TARGET_NR_ssetmask 69 /* obsolete ->sys_rt_sigprocmask */ +#define TARGET_NR_setreuid 70 /* ok */ +#define TARGET_NR_setregid 71 /* ok */ +#define TARGET_NR_sigsuspend 72 /* obsolete -> rt_sigsuspend */ +#define TARGET_NR_sigpending 73 /* obsolete -> sys_rt_sigpending */ +#define TARGET_NR_sethostname 74 /* ok */ +#define TARGET_NR_setrlimit 75 /* ok */ +#define TARGET_NR_getrlimit 76 /* ok Back compatible 2Gig limited rlimit */ +#define TARGET_NR_getrusage 77 /* ok */ +#define TARGET_NR_gettimeofday 78 /* ok */ +#define TARGET_NR_settimeofday 79 /* ok */ +#define TARGET_NR_getgroups 80 /* ok */ +#define TARGET_NR_setgroups 81 /* ok */ +#define TARGET_NR_select 82 /* obsolete -> sys_pselect7 */ +#define TARGET_NR_symlink 83 /* symlinkat */ +#define TARGET_NR_oldlstat 84 /* remove */ +#define TARGET_NR_readlink 85 /* obsolete -> sys_readlinkat */ +#define TARGET_NR_uselib 86 /* remove */ +#define TARGET_NR_swapon 87 /* ok */ +#define TARGET_NR_reboot 88 /* ok */ +#define TARGET_NR_readdir 89 /* remove ? */ +#define TARGET_NR_mmap 90 /* obsolete -> sys_mmap2 */ +#define TARGET_NR_munmap 91 /* ok - mmu and nommu */ +#define TARGET_NR_truncate 92 /* ok or truncate64 */ +#define TARGET_NR_ftruncate 93 /* ok or ftruncate64 */ +#define TARGET_NR_fchmod 94 /* ok */ +#define TARGET_NR_fchown 95 /* ok */ +#define TARGET_NR_getpriority 96 /* ok */ +#define TARGET_NR_setpriority 97 /* ok */ +#define TARGET_NR_profil 98 /* remove */ +#define TARGET_NR_statfs 99 /* ok or statfs64 */ +#define TARGET_NR_fstatfs 100 /* ok or fstatfs64 */ +#define TARGET_NR_ioperm 101 /* remove */ +#define TARGET_NR_socketcall 102 /* remove */ +#define TARGET_NR_syslog 103 /* ok */ +#define TARGET_NR_setitimer 104 /* ok */ +#define TARGET_NR_getitimer 105 /* ok */ +#define TARGET_NR_stat 106 /* remove */ +#define TARGET_NR_lstat 107 /* remove */ +#define TARGET_NR_fstat 108 /* remove */ +#define TARGET_NR_olduname 109 /* remove */ +#define TARGET_NR_iopl 110 /* remove */ +#define TARGET_NR_vhangup 111 /* ok */ +#define TARGET_NR_idle 112 /* remove */ +#define TARGET_NR_vm86old 113 /* remove */ +#define TARGET_NR_wait4 114 /* obsolete -> waitid */ +#define TARGET_NR_swapoff 115 /* ok */ +#define TARGET_NR_sysinfo 116 /* ok */ +#define TARGET_NR_ipc 117 /* remove - direct call */ +#define TARGET_NR_fsync 118 /* ok */ +#define TARGET_NR_sigreturn 119 /* obsolete -> sys_rt_sigreturn */ +#define TARGET_NR_clone 120 /* ok */ +#define TARGET_NR_setdomainname 121 /* ok */ +#define TARGET_NR_uname 122 /* remove */ +#define TARGET_NR_modify_ldt 123 /* remove */ +#define TARGET_NR_adjtimex 124 /* ok */ +#define TARGET_NR_mprotect 125 /* remove */ +#define TARGET_NR_sigprocmask 126 /* obsolete -> sys_rt_sigprocmask */ +#define TARGET_NR_create_module 127 /* remove */ +#define TARGET_NR_init_module 128 /* ok */ +#define TARGET_NR_delete_module 129 /* ok */ +#define TARGET_NR_get_kernel_syms 130 /* remove */ +#define TARGET_NR_quotactl 131 /* ok */ +#define TARGET_NR_getpgid 132 /* ok */ +#define TARGET_NR_fchdir 133 /* ok */ +#define TARGET_NR_bdflush 134 /* remove */ +#define TARGET_NR_sysfs 135 /* needed for busybox */ +#define TARGET_NR_personality 136 /* ok */ +#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */ +#define TARGET_NR_setfsuid 138 /* ok */ +#define TARGET_NR_setfsgid 139 /* ok */ +#define TARGET_NR__llseek 140 /* remove only lseek */ +#define TARGET_NR_getdents 141 /* ok or getdents64 */ +#define TARGET_NR__newselect 142 /* remove */ +#define TARGET_NR_flock 143 /* ok */ +#define TARGET_NR_msync 144 /* remove */ +#define TARGET_NR_readv 145 /* ok */ +#define TARGET_NR_writev 146 /* ok */ +#define TARGET_NR_getsid 147 /* ok */ +#define TARGET_NR_fdatasync 148 /* ok */ +#define TARGET_NR__sysctl 149 /* remove */ +#define TARGET_NR_mlock 150 /* ok - nommu or mmu */ +#define TARGET_NR_munlock 151 /* ok - nommu or mmu */ +#define TARGET_NR_mlockall 152 /* ok - nommu or mmu */ +#define TARGET_NR_munlockall 153 /* ok - nommu or mmu */ +#define TARGET_NR_sched_setparam 154 /* ok */ +#define TARGET_NR_sched_getparam 155 /* ok */ +#define TARGET_NR_sched_setscheduler 156 /* ok */ +#define TARGET_NR_sched_getscheduler 157 /* ok */ +#define TARGET_NR_sched_yield 158 /* ok */ +#define TARGET_NR_sched_get_priority_max 159 /* ok */ +#define TARGET_NR_sched_get_priority_min 160 /* ok */ +#define TARGET_NR_sched_rr_get_interval 161 /* ok */ +#define TARGET_NR_nanosleep 162 /* ok */ +#define TARGET_NR_mremap 163 /* ok - nommu or mmu */ +#define TARGET_NR_setresuid 164 /* ok */ +#define TARGET_NR_getresuid 165 /* ok */ +#define TARGET_NR_vm86 166 /* remove */ +#define TARGET_NR_query_module 167 /* ok */ +#define TARGET_NR_poll 168 /* obsolete -> sys_ppoll */ +#define TARGET_NR_nfsservctl 169 /* ok */ +#define TARGET_NR_setresgid 170 /* ok */ +#define TARGET_NR_getresgid 171 /* ok */ +#define TARGET_NR_prctl 172 /* ok */ +#define TARGET_NR_rt_sigreturn 173 /* ok */ +#define TARGET_NR_rt_sigaction 174 /* ok */ +#define TARGET_NR_rt_sigprocmask 175 /* ok */ +#define TARGET_NR_rt_sigpending 176 /* ok */ +#define TARGET_NR_rt_sigtimedwait 177 /* ok */ +#define TARGET_NR_rt_sigqueueinfo 178 /* ok */ +#define TARGET_NR_rt_sigsuspend 179 /* ok */ +#define TARGET_NR_pread64 180 /* ok */ +#define TARGET_NR_pwrite64 181 /* ok */ +#define TARGET_NR_chown 182 /* obsolete -> fchownat */ +#define TARGET_NR_getcwd 183 /* ok */ +#define TARGET_NR_capget 184 /* ok */ +#define TARGET_NR_capset 185 /* ok */ +#define TARGET_NR_sigaltstack 186 /* remove */ +#define TARGET_NR_sendfile 187 /* ok -> exist 64bit version*/ +#define TARGET_NR_getpmsg 188 /* remove - some people actually want streams */ +#define TARGET_NR_putpmsg 189 /* remove - some people actually want streams */ +#define TARGET_NR_vfork 190 /* for noMMU - group with clone -> maybe remove */ +#define TARGET_NR_ugetrlimit 191 /* remove - SuS compliant getrlimit */ +#define TARGET_NR_mmap2 192 /* ok */ +#define TARGET_NR_truncate64 193 /* ok */ +#define TARGET_NR_ftruncate64 194 /* ok */ +#define TARGET_NR_stat64 195 /* remove _ARCH_WANT_STAT64 */ +#define TARGET_NR_lstat64 196 /* remove _ARCH_WANT_STAT64 */ +#define TARGET_NR_fstat64 197 /* remove _ARCH_WANT_STAT64 */ +#define TARGET_NR_lchown32 198 /* ok - without 32 */ +#define TARGET_NR_getuid32 199 /* ok - without 32 */ +#define TARGET_NR_getgid32 200 /* ok - without 32 */ +#define TARGET_NR_geteuid32 201 /* ok - without 32 */ +#define TARGET_NR_getegid32 202 /* ok - without 32 */ +#define TARGET_NR_setreuid32 203 /* ok - without 32 */ +#define TARGET_NR_setregid32 204 /* ok - without 32 */ +#define TARGET_NR_getgroups32 205 /* ok - without 32 */ +#define TARGET_NR_setgroups32 206 /* ok - without 32 */ +#define TARGET_NR_fchown32 207 /* ok - without 32 */ +#define TARGET_NR_setresuid32 208 /* ok - without 32 */ +#define TARGET_NR_getresuid32 209 /* ok - without 32 */ +#define TARGET_NR_setresgid32 210 /* ok - without 32 */ +#define TARGET_NR_getresgid32 211 /* ok - without 32 */ +#define TARGET_NR_chown32 212 /* ok - without 32 -obsolete -> fchownat */ +#define TARGET_NR_setuid32 213 /* ok - without 32 */ +#define TARGET_NR_setgid32 214 /* ok - without 32 */ +#define TARGET_NR_setfsuid32 215 /* ok - without 32 */ +#define TARGET_NR_setfsgid32 216 /* ok - without 32 */ +#define TARGET_NR_pivot_root 217 /* ok */ +#define TARGET_NR_mincore 218 /* ok */ +#define TARGET_NR_madvise 219 /* ok */ +//#define TARGET_NR_madvise1 219 /* remove delete when C lib stub is removed */ +#define TARGET_NR_getdents64 220 /* ok */ +#define TARGET_NR_fcntl64 221 /* ok */ +/* 223 is unused */ +#define TARGET_NR_gettid 224 /* ok */ +#define TARGET_NR_readahead 225 /* ok */ +#define TARGET_NR_setxattr 226 /* ok */ +#define TARGET_NR_lsetxattr 227 /* ok */ +#define TARGET_NR_fsetxattr 228 /* ok */ +#define TARGET_NR_getxattr 229 /* ok */ +#define TARGET_NR_lgetxattr 230 /* ok */ +#define TARGET_NR_fgetxattr 231 /* ok */ +#define TARGET_NR_listxattr 232 /* ok */ +#define TARGET_NR_llistxattr 233 /* ok */ +#define TARGET_NR_flistxattr 234 /* ok */ +#define TARGET_NR_removexattr 235 /* ok */ +#define TARGET_NR_lremovexattr 236 /* ok */ +#define TARGET_NR_fremovexattr 237 /* ok */ +#define TARGET_NR_tkill 238 /* ok */ +#define TARGET_NR_sendfile64 239 /* ok */ +#define TARGET_NR_futex 240 /* ok */ +#define TARGET_NR_sched_setaffinity 241 /* ok */ +#define TARGET_NR_sched_getaffinity 242 /* ok */ +#define TARGET_NR_set_thread_area 243 /* remove */ +#define TARGET_NR_get_thread_area 244 /* remove */ +#define TARGET_NR_io_setup 245 /* ok */ +#define TARGET_NR_io_destroy 246 /* ok */ +#define TARGET_NR_io_getevents 247 /* ok */ +#define TARGET_NR_io_submit 248 /* ok */ +#define TARGET_NR_io_cancel 249 /* ok */ +#define TARGET_NR_fadvise64 250 /* remove -> sys_fadvise64_64 */ +/* 251 is available for reuse (was briefly sys_set_zone_reclaim) */ +#define TARGET_NR_exit_group 252 /* ok */ +#define TARGET_NR_lookup_dcookie 253 /* ok */ +#define TARGET_NR_epoll_create 254 /* ok */ +#define TARGET_NR_epoll_ctl 255 /* ok */ +#define TARGET_NR_epoll_wait 256 /* obsolete -> sys_epoll_pwait */ +#define TARGET_NR_remap_file_pages 257 /* only for mmu */ +#define TARGET_NR_set_tid_address 258 /* ok */ +#define TARGET_NR_timer_create 259 /* ok */ +#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1) /* 260 */ /* ok */ +#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2) /* 261 */ /* ok */ +#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3) /* 262 */ /* ok */ +#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4) /* 263 */ /* ok */ +#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5) /* 264 */ /* ok */ +#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6) /* 265 */ /* ok */ +#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7) /* 266 */ /* ok */ +#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8) /* 267 */ /* ok */ +#define TARGET_NR_statfs64 268 /* ok */ +#define TARGET_NR_fstatfs64 269 /* ok */ +#define TARGET_NR_tgkill 270 /* ok */ +#define TARGET_NR_utimes 271 /* obsolete -> sys_futimesat */ +#define TARGET_NR_fadvise64_64 272 /* ok */ +#define TARGET_NR_vserver 273 /* ok */ +#define TARGET_NR_mbind 274 /* only for mmu */ +#define TARGET_NR_get_mempolicy 275 /* only for mmu */ +#define TARGET_NR_set_mempolicy 276 /* only for mmu */ +#define TARGET_NR_mq_open 277 /* ok */ +#define TARGET_NR_mq_unlink (TARGET_NR_mq_open+1) /* 278 */ /* ok */ +#define TARGET_NR_mq_timedsend (TARGET_NR_mq_open+2) /* 279 */ /* ok */ +#define TARGET_NR_mq_timedreceive (TARGET_NR_mq_open+3) /* 280 */ /* ok */ +#define TARGET_NR_mq_notify (TARGET_NR_mq_open+4) /* 281 */ /* ok */ +#define TARGET_NR_mq_getsetattr (TARGET_NR_mq_open+5) /* 282 */ /* ok */ +#define TARGET_NR_kexec_load 283 /* ok */ +#define TARGET_NR_waitid 284 /* ok */ +/* #define TARGET_NR_sys_setaltroot 285 */ +#define TARGET_NR_add_key 286 /* ok */ +#define TARGET_NR_request_key 287 /* ok */ +#define TARGET_NR_keyctl 288 /* ok */ +#define TARGET_NR_ioprio_set 289 /* ok */ +#define TARGET_NR_ioprio_get 290 /* ok */ +#define TARGET_NR_inotify_init 291 /* ok */ +#define TARGET_NR_inotify_add_watch 292 /* ok */ +#define TARGET_NR_inotify_rm_watch 293 /* ok */ +#define TARGET_NR_migrate_pages 294 /* mmu */ +#define TARGET_NR_openat 295 /* ok */ +#define TARGET_NR_mkdirat 296 /* ok */ +#define TARGET_NR_mknodat 297 /* ok */ +#define TARGET_NR_fchownat 298 /* ok */ +#define TARGET_NR_futimesat 299 /* obsolete -> sys_utimesat */ +#define TARGET_NR_fstatat64 300 /* stat64 */ +#define TARGET_NR_unlinkat 301 /* ok */ +#define TARGET_NR_renameat 302 /* ok */ +#define TARGET_NR_linkat 303 /* ok */ +#define TARGET_NR_symlinkat 304 /* ok */ +#define TARGET_NR_readlinkat 305 /* ok */ +#define TARGET_NR_fchmodat 306 /* ok */ +#define TARGET_NR_faccessat 307 /* ok */ +#define TARGET_NR_pselect6 308 /* obsolete -> sys_pselect7 */ +#define TARGET_NR_ppoll 309 /* ok */ +#define TARGET_NR_unshare 310 /* ok */ +#define TARGET_NR_set_robust_list 311 /* ok */ +#define TARGET_NR_get_robust_list 312 /* ok */ +#define TARGET_NR_splice 313 /* ok */ +#define TARGET_NR_sync_file_range 314 /* ok */ +#define TARGET_NR_tee 315 /* ok */ +#define TARGET_NR_vmsplice 316 /* ok */ +#define TARGET_NR_move_pages 317 /* mmu */ +#define TARGET_NR_getcpu 318 /* ok */ +#define TARGET_NR_epoll_pwait 319 /* ok */ +#define TARGET_NR_utimensat 320 /* ok */ +#define TARGET_NR_signalfd 321 /* ok */ +#define TARGET_NR_timerfd_create 322 /* ok */ +#define TARGET_NR_eventfd 323 /* ok */ +#define TARGET_NR_fallocate 324 /* ok */ +#define TARGET_NR_semtimedop 325 /* ok - semaphore group */ +#define TARGET_NR_timerfd_settime 326 /* ok */ +#define TARGET_NR_timerfd_gettime 327 /* ok */ +/* sysv ipc syscalls */ +#define TARGET_NR_semctl 328 /* ok */ +#define TARGET_NR_semget 329 /* ok */ +#define TARGET_NR_semop 330 /* ok */ +#define TARGET_NR_msgctl 331 /* ok */ +#define TARGET_NR_msgget 332 /* ok */ +#define TARGET_NR_msgrcv 333 /* ok */ +#define TARGET_NR_msgsnd 334 /* ok */ +#define TARGET_NR_shmat 335 /* ok */ +#define TARGET_NR_shmctl 336 /* ok */ +#define TARGET_NR_shmdt 337 /* ok */ +#define TARGET_NR_shmget 338 /* ok */ + + +#define TARGET_NR_signalfd4 339 /* new */ +#define TARGET_NR_eventfd2 340 /* new */ +#define TARGET_NR_epoll_create1 341 /* new */ +#define TARGET_NR_dup3 342 /* new */ +#define TARGET_NR_pipe2 343 /* new */ +#define TARGET_NR_inotify_init1 344 /* new */ +#define TARGET_NR_socket 345 /* new */ +#define TARGET_NR_socketpair 346 /* new */ +#define TARGET_NR_bind 347 /* new */ +#define TARGET_NR_listen 348 /* new */ +#define TARGET_NR_accept 349 /* new */ +#define TARGET_NR_connect 350 /* new */ +#define TARGET_NR_getsockname 351 /* new */ +#define TARGET_NR_getpeername 352 /* new */ +#define TARGET_NR_sendto 353 /* new */ +#define TARGET_NR_send 354 /* new */ +#define TARGET_NR_recvfrom 355 /* new */ +#define TARGET_NR_recv 356 /* new */ +#define TARGET_NR_setsockopt 357 /* new */ +#define TARGET_NR_getsockopt 358 /* new */ +#define TARGET_NR_shutdown 359 /* new */ +#define TARGET_NR_sendmsg 360 /* new */ +#define TARGET_NR_recvmsg 361 /* new */ +#define TARGET_NR_accept04 362 /* new */ + +#define TARGET_NR_syscalls 363 + diff --git a/linux-user/microblaze/target_signal.h b/linux-user/microblaze/target_signal.h new file mode 100644 index 0000000..3d1f7a7 --- /dev/null +++ b/linux-user/microblaze/target_signal.h @@ -0,0 +1,29 @@ +#ifndef TARGET_SIGNAL_H +#define TARGET_SIGNAL_H + +#include "cpu.h" + +/* this struct defines a stack used during syscall handling */ + +typedef struct target_sigaltstack { + abi_ulong ss_sp; + abi_ulong ss_size; + abi_long ss_flags; +} target_stack_t; + + +/* + * sigaltstack controls + */ +#define TARGET_SS_ONSTACK 1 +#define TARGET_SS_DISABLE 2 + +#define TARGET_MINSIGSTKSZ 2048 +#define TARGET_SIGSTKSZ 8192 + +static inline abi_ulong get_sp_from_cpustate(CPUMBState *state) +{ + return state->regs[14]; +} + +#endif /* TARGET_SIGNAL_H */ diff --git a/linux-user/microblaze/termbits.h b/linux-user/microblaze/termbits.h new file mode 100644 index 0000000..fc82ca0 --- /dev/null +++ b/linux-user/microblaze/termbits.h @@ -0,0 +1,213 @@ +/* from asm/termbits.h */ + +#define TARGET_NCCS 19 + +struct target_termios { + unsigned int c_iflag; /* input mode flags */ + unsigned int c_oflag; /* output mode flags */ + unsigned int c_cflag; /* control mode flags */ + unsigned int c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[TARGET_NCCS]; /* control characters */ +}; + +/* c_iflag bits */ +#define TARGET_IGNBRK 0000001 +#define TARGET_BRKINT 0000002 +#define TARGET_IGNPAR 0000004 +#define TARGET_PARMRK 0000010 +#define TARGET_INPCK 0000020 +#define TARGET_ISTRIP 0000040 +#define TARGET_INLCR 0000100 +#define TARGET_IGNCR 0000200 +#define TARGET_ICRNL 0000400 +#define TARGET_IUCLC 0001000 +#define TARGET_IXON 0002000 +#define TARGET_IXANY 0004000 +#define TARGET_IXOFF 0010000 +#define TARGET_IMAXBEL 0020000 + +/* c_oflag bits */ +#define TARGET_OPOST 0000001 +#define TARGET_OLCUC 0000002 +#define TARGET_ONLCR 0000004 +#define TARGET_OCRNL 0000010 +#define TARGET_ONOCR 0000020 +#define TARGET_ONLRET 0000040 +#define TARGET_OFILL 0000100 +#define TARGET_OFDEL 0000200 +#define TARGET_NLDLY 0000400 +#define TARGET_NL0 0000000 +#define TARGET_NL1 0000400 +#define TARGET_CRDLY 0003000 +#define TARGET_CR0 0000000 +#define TARGET_CR1 0001000 +#define TARGET_CR2 0002000 +#define TARGET_CR3 0003000 +#define TARGET_TABDLY 0014000 +#define TARGET_TAB0 0000000 +#define TARGET_TAB1 0004000 +#define TARGET_TAB2 0010000 +#define TARGET_TAB3 0014000 +#define TARGET_XTABS 0014000 +#define TARGET_BSDLY 0020000 +#define TARGET_BS0 0000000 +#define TARGET_BS1 0020000 +#define TARGET_VTDLY 0040000 +#define TARGET_VT0 0000000 +#define TARGET_VT1 0040000 +#define TARGET_FFDLY 0100000 +#define TARGET_FF0 0000000 +#define TARGET_FF1 0100000 + +/* c_cflag bit meaning */ +#define TARGET_CBAUD 0010017 +#define TARGET_B0 0000000 /* hang up */ +#define TARGET_B50 0000001 +#define TARGET_B75 0000002 +#define TARGET_B110 0000003 +#define TARGET_B134 0000004 +#define TARGET_B150 0000005 +#define TARGET_B200 0000006 +#define TARGET_B300 0000007 +#define TARGET_B600 0000010 +#define TARGET_B1200 0000011 +#define TARGET_B1800 0000012 +#define TARGET_B2400 0000013 +#define TARGET_B4800 0000014 +#define TARGET_B9600 0000015 +#define TARGET_B19200 0000016 +#define TARGET_B38400 0000017 +#define TARGET_EXTA B19200 +#define TARGET_EXTB B38400 +#define TARGET_CSIZE 0000060 +#define TARGET_CS5 0000000 +#define TARGET_CS6 0000020 +#define TARGET_CS7 0000040 +#define TARGET_CS8 0000060 +#define TARGET_CSTOPB 0000100 +#define TARGET_CREAD 0000200 +#define TARGET_PARENB 0000400 +#define TARGET_PARODD 0001000 +#define TARGET_HUPCL 0002000 +#define TARGET_CLOCAL 0004000 +#define TARGET_CBAUDEX 0010000 +#define TARGET_B57600 0010001 +#define TARGET_B115200 0010002 +#define TARGET_B230400 0010003 +#define TARGET_B460800 0010004 +#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */ +#define TARGET_CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define TARGET_ISIG 0000001 +#define TARGET_ICANON 0000002 +#define TARGET_XCASE 0000004 +#define TARGET_ECHO 0000010 +#define TARGET_ECHOE 0000020 +#define TARGET_ECHOK 0000040 +#define TARGET_ECHONL 0000100 +#define TARGET_NOFLSH 0000200 +#define TARGET_TOSTOP 0000400 +#define TARGET_ECHOCTL 0001000 +#define TARGET_ECHOPRT 0002000 +#define TARGET_ECHOKE 0004000 +#define TARGET_FLUSHO 0010000 +#define TARGET_PENDIN 0040000 +#define TARGET_IEXTEN 0100000 + +/* c_cc character offsets */ +#define TARGET_VINTR 0 +#define TARGET_VQUIT 1 +#define TARGET_VERASE 2 +#define TARGET_VKILL 3 +#define TARGET_VEOF 4 +#define TARGET_VTIME 5 +#define TARGET_VMIN 6 +#define TARGET_VSWTC 7 +#define TARGET_VSTART 8 +#define TARGET_VSTOP 9 +#define TARGET_VSUSP 10 +#define TARGET_VEOL 11 +#define TARGET_VREPRINT 12 +#define TARGET_VDISCARD 13 +#define TARGET_VWERASE 14 +#define TARGET_VLNEXT 15 +#define TARGET_VEOL2 16 + +/* ioctls */ + +#define TARGET_TCGETS 0x5401 +#define TARGET_TCSETS 0x5402 +#define TARGET_TCSETSW 0x5403 +#define TARGET_TCSETSF 0x5404 +#define TARGET_TCGETA 0x5405 +#define TARGET_TCSETA 0x5406 +#define TARGET_TCSETAW 0x5407 +#define TARGET_TCSETAF 0x5408 +#define TARGET_TCSBRK 0x5409 +#define TARGET_TCXONC 0x540A +#define TARGET_TCFLSH 0x540B + +#define TARGET_TIOCEXCL 0x540C +#define TARGET_TIOCNXCL 0x540D +#define TARGET_TIOCSCTTY 0x540E +#define TARGET_TIOCGPGRP 0x540F +#define TARGET_TIOCSPGRP 0x5410 +#define TARGET_TIOCOUTQ 0x5411 +#define TARGET_TIOCSTI 0x5412 +#define TARGET_TIOCGWINSZ 0x5413 +#define TARGET_TIOCSWINSZ 0x5414 +#define TARGET_TIOCMGET 0x5415 +#define TARGET_TIOCMBIS 0x5416 +#define TARGET_TIOCMBIC 0x5417 +#define TARGET_TIOCMSET 0x5418 +#define TARGET_TIOCGSOFTCAR 0x5419 +#define TARGET_TIOCSSOFTCAR 0x541A +#define TARGET_FIONREAD 0x541B +#define TARGET_TIOCINQ TARGET_FIONREAD +#define TARGET_TIOCLINUX 0x541C +#define TARGET_TIOCCONS 0x541D +#define TARGET_TIOCGSERIAL 0x541E +#define TARGET_TIOCSSERIAL 0x541F +#define TARGET_TIOCPKT 0x5420 +#define TARGET_FIONBIO 0x5421 +#define TARGET_TIOCNOTTY 0x5422 +#define TARGET_TIOCSETD 0x5423 +#define TARGET_TIOCGETD 0x5424 +#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */ +#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */ +#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define TARGET_FIOCLEX 0x5451 +#define TARGET_FIOASYNC 0x5452 +#define TARGET_TIOCSERCONFIG 0x5453 +#define TARGET_TIOCSERGWILD 0x5454 +#define TARGET_TIOCSERSWILD 0x5455 +#define TARGET_TIOCGLCKTRMIOS 0x5456 +#define TARGET_TIOCSLCKTRMIOS 0x5457 +#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */ +#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */ + +/* Used for packet mode */ +#define TARGET_TIOCPKT_DATA 0 +#define TARGET_TIOCPKT_FLUSHREAD 1 +#define TARGET_TIOCPKT_FLUSHWRITE 2 +#define TARGET_TIOCPKT_STOP 4 +#define TARGET_TIOCPKT_START 8 +#define TARGET_TIOCPKT_NOSTOP 16 +#define TARGET_TIOCPKT_DOSTOP 32 + +#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */ -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 03/13] microblaze: linux-user support. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 02/13] microblaze: Add syscall, signal and termbits defs for linux-user Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 04/13] microblaze: Add disassembler Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- cpu-exec.c | 68 ++++++++++++++- elf.h | 2 + linux-user/elfload.c | 22 +++++ linux-user/main.c | 96 ++++++++++++++++++++ linux-user/signal.c | 216 +++++++++++++++++++++++++++++++++++++++++++++ linux-user/syscall.c | 2 +- linux-user/syscall_defs.h | 73 +++++++++++++++- 7 files changed, 474 insertions(+), 5 deletions(-) diff --git a/cpu-exec.c b/cpu-exec.c index ef378ac..8734337 100644 --- a/cpu-exec.c +++ b/cpu-exec.c @@ -246,6 +246,7 @@ int cpu_exec(CPUState *env1) #elif defined(TARGET_ALPHA) #elif defined(TARGET_ARM) #elif defined(TARGET_PPC) +#elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) #elif defined(TARGET_CRIS) @@ -300,6 +301,8 @@ int cpu_exec(CPUState *env1) env->old_exception = -1; #elif defined(TARGET_PPC) do_interrupt(env); +#elif defined(TARGET_MICROBLAZE) + do_interrupt(env); #elif defined(TARGET_MIPS) do_interrupt(env); #elif defined(TARGET_SPARC) @@ -367,7 +370,8 @@ int cpu_exec(CPUState *env1) cpu_loop_exit(); } #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \ - defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) + defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \ + defined(TARGET_MICROBLAZE) if (interrupt_request & CPU_INTERRUPT_HALT) { env->interrupt_request &= ~CPU_INTERRUPT_HALT; env->halted = 1; @@ -436,6 +440,15 @@ int cpu_exec(CPUState *env1) env->interrupt_request &= ~CPU_INTERRUPT_HARD; next_tb = 0; } +#elif defined(TARGET_MICROBLAZE) + if ((interrupt_request & CPU_INTERRUPT_HARD) + && (env->sregs[SR_MSR] & MSR_IE) + && !(env->sregs[SR_MSR] & (MSR_EIP | MSR_BIP)) + && !(env->iflags & (D_FLAG | IMM_FLAG))) { + env->exception_index = EXCP_IRQ; + do_interrupt(env); + next_tb = 0; + } #elif defined(TARGET_MIPS) if ((interrupt_request & CPU_INTERRUPT_HARD) && (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) && @@ -565,6 +578,8 @@ int cpu_exec(CPUState *env1) env->sr = (env->sr & 0xffe0) | env->cc_dest | (env->cc_x << 4); log_cpu_state(env, 0); +#elif defined(TARGET_MICROBLAZE) + log_cpu_state(env, 0); #elif defined(TARGET_MIPS) log_cpu_state(env, 0); #elif defined(TARGET_SH4) @@ -682,6 +697,7 @@ int cpu_exec(CPUState *env1) env->cc_op = CC_OP_FLAGS; env->sr = (env->sr & 0xffe0) | env->cc_dest | (env->cc_x << 4); +#elif defined(TARGET_MICROBLAZE) #elif defined(TARGET_MIPS) #elif defined(TARGET_SH4) #elif defined(TARGET_ALPHA) @@ -1028,6 +1044,56 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, return 1; } +#elif defined (TARGET_MICROBLAZE) +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(h2g(address), pc, puc)) { + return 1; + } + + /* see if it is an MMU fault */ + ret = cpu_mb_handle_mmu_fault(env, address, is_write, MMU_USER_IDX, 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: PC=0x" TARGET_FMT_lx " error=0x%x %p\n", + env->PC, 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); + cpu_loop_exit(); + } else { + /* activate soft MMU for this block */ + cpu_resume_from_signal(env, puc); + } + /* never comes here */ + return 1; +} + #elif defined (TARGET_SH4) static inline int handle_cpu_signal(unsigned long pc, unsigned long address, int is_write, sigset_t *old_set, diff --git a/elf.h b/elf.h index 861f1d3..182cad9 100644 --- a/elf.h +++ b/elf.h @@ -119,6 +119,8 @@ typedef int64_t Elf64_Sxword; */ #define EM_S390_OLD 0xA390 +#define EM_XILINX_MICROBLAZE 0xBAAB + /* This is the info that is needed to parse the dynamic section of the file */ #define DT_NULL 0 #define DT_NEEDED 1 diff --git a/linux-user/elfload.c b/linux-user/elfload.c index 508cb37..190ad14 100644 --- a/linux-user/elfload.c +++ b/linux-user/elfload.c @@ -453,6 +453,28 @@ static inline void init_thread(struct target_pt_regs *regs, struct image_info *i #endif /* TARGET_MIPS */ +#ifdef TARGET_MICROBLAZE + +#define ELF_START_MMAP 0x80000000 + +#define elf_check_arch(x) ( (x) == EM_XILINX_MICROBLAZE ) + +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2MSB +#define ELF_ARCH EM_MIPS + +static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop) +{ + regs->pc = infop->entry; + regs->r1 = infop->start_stack; + +} + +#define USE_ELF_CORE_DUMP +#define ELF_EXEC_PAGESIZE 4096 + +#endif /* TARGET_MICROBLAZE */ + #ifdef TARGET_SH4 #define ELF_START_MMAP 0x80000000 diff --git a/linux-user/main.c b/linux-user/main.c index 17cdfa6..4832d3f 100644 --- a/linux-user/main.c +++ b/linux-user/main.c @@ -2036,6 +2036,66 @@ void cpu_loop (CPUState *env) } #endif +#ifdef TARGET_MICROBLAZE +void cpu_loop (CPUState *env) +{ + int trapnr, ret; + target_siginfo_t info; + + while (1) { + trapnr = cpu_mb_exec (env); + switch (trapnr) { + case 0xaa: + { + info.si_signo = SIGSEGV; + info.si_errno = 0; + /* XXX: check env->error_code */ + info.si_code = TARGET_SEGV_MAPERR; + info._sifields._sigfault._addr = 0; + queue_signal(env, info.si_signo, &info); + } + break; + case EXCP_INTERRUPT: + /* just indicate that signals should be handled asap */ + break; + case EXCP_BREAK: + /* Return address is 4 bytes after the call. */ + env->regs[14] += 4; + ret = do_syscall(env, + env->regs[12], + env->regs[5], + env->regs[6], + env->regs[7], + env->regs[8], + env->regs[9], + env->regs[10]); + env->regs[3] = ret; + env->sregs[SR_PC] = env->regs[14]; + break; + case EXCP_DEBUG: + { + int sig; + + sig = gdb_handlesig (env, TARGET_SIGTRAP); + if (sig) + { + info.si_signo = sig; + info.si_errno = 0; + info.si_code = TARGET_TRAP_BRKPT; + queue_signal(env, info.si_signo, &info); + } + } + break; + default: + printf ("Unhandled trap: 0x%x\n", trapnr); + cpu_dump_state(env, stderr, fprintf, 0); + exit (1); + } + process_pending_signals (env); + } +} +#endif + #ifdef TARGET_M68K void cpu_loop(CPUM68KState *env) @@ -2698,6 +2758,42 @@ int main(int argc, char **argv, char **envp) env->sr = regs->sr; ts->sim_syscalls = 1; } +#elif defined(TARGET_MICROBLAZE) + { + env->regs[0] = regs->r0; + env->regs[1] = regs->r1; + env->regs[2] = regs->r2; + env->regs[3] = regs->r3; + env->regs[4] = regs->r4; + env->regs[5] = regs->r5; + env->regs[6] = regs->r6; + env->regs[7] = regs->r7; + env->regs[8] = regs->r8; + env->regs[9] = regs->r9; + env->regs[10] = regs->r10; + env->regs[11] = regs->r11; + env->regs[12] = regs->r12; + env->regs[13] = regs->r13; + env->regs[14] = regs->r14; + env->regs[15] = regs->r15; + env->regs[16] = regs->r16; + env->regs[17] = regs->r17; + env->regs[18] = regs->r18; + env->regs[19] = regs->r19; + env->regs[20] = regs->r20; + env->regs[21] = regs->r21; + env->regs[22] = regs->r22; + env->regs[23] = regs->r23; + env->regs[24] = regs->r24; + env->regs[25] = regs->r25; + env->regs[26] = regs->r26; + env->regs[27] = regs->r27; + env->regs[28] = regs->r28; + env->regs[29] = regs->r29; + env->regs[30] = regs->r30; + env->regs[31] = regs->r31; + env->sregs[SR_PC] = regs->pc; + } #elif defined(TARGET_MIPS) { int i; diff --git a/linux-user/signal.c b/linux-user/signal.c index 9c9c7eb..371927e 100644 --- a/linux-user/signal.c +++ b/linux-user/signal.c @@ -3011,6 +3011,222 @@ badframe: force_sig(TARGET_SIGSEGV); return 0; } +#elif defined(TARGET_MICROBLAZE) + +struct target_sigcontext { + struct target_pt_regs regs; /* needs to be first */ + uint32_t oldmask; +}; + +/* Signal frames. */ +struct target_signal_frame { + struct target_sigcontext sc; + uint32_t extramask[TARGET_NSIG_WORDS - 1]; + uint32_t tramp[2]; +}; + +struct rt_signal_frame { + struct siginfo info; + struct ucontext uc; + uint32_t tramp[2]; +}; + +static void setup_sigcontext(struct target_sigcontext *sc, CPUState *env) +{ + __put_user(env->regs[0], &sc->regs.r0); + __put_user(env->regs[1], &sc->regs.r1); + __put_user(env->regs[2], &sc->regs.r2); + __put_user(env->regs[3], &sc->regs.r3); + __put_user(env->regs[4], &sc->regs.r4); + __put_user(env->regs[5], &sc->regs.r5); + __put_user(env->regs[6], &sc->regs.r6); + __put_user(env->regs[7], &sc->regs.r7); + __put_user(env->regs[8], &sc->regs.r8); + __put_user(env->regs[9], &sc->regs.r9); + __put_user(env->regs[10], &sc->regs.r10); + __put_user(env->regs[11], &sc->regs.r11); + __put_user(env->regs[12], &sc->regs.r12); + __put_user(env->regs[13], &sc->regs.r13); + __put_user(env->regs[14], &sc->regs.r14); + __put_user(env->regs[15], &sc->regs.r15); + __put_user(env->regs[16], &sc->regs.r16); + __put_user(env->regs[17], &sc->regs.r17); + __put_user(env->regs[18], &sc->regs.r18); + __put_user(env->regs[19], &sc->regs.r19); + __put_user(env->regs[20], &sc->regs.r20); + __put_user(env->regs[21], &sc->regs.r21); + __put_user(env->regs[22], &sc->regs.r22); + __put_user(env->regs[23], &sc->regs.r23); + __put_user(env->regs[24], &sc->regs.r24); + __put_user(env->regs[25], &sc->regs.r25); + __put_user(env->regs[26], &sc->regs.r26); + __put_user(env->regs[27], &sc->regs.r27); + __put_user(env->regs[28], &sc->regs.r28); + __put_user(env->regs[29], &sc->regs.r29); + __put_user(env->regs[30], &sc->regs.r30); + __put_user(env->regs[31], &sc->regs.r31); + __put_user(env->sregs[SR_PC], &sc->regs.pc); +} + +static void restore_sigcontext(struct target_sigcontext *sc, CPUState *env) +{ + __get_user(env->regs[0], &sc->regs.r0); + __get_user(env->regs[1], &sc->regs.r1); + __get_user(env->regs[2], &sc->regs.r2); + __get_user(env->regs[3], &sc->regs.r3); + __get_user(env->regs[4], &sc->regs.r4); + __get_user(env->regs[5], &sc->regs.r5); + __get_user(env->regs[6], &sc->regs.r6); + __get_user(env->regs[7], &sc->regs.r7); + __get_user(env->regs[8], &sc->regs.r8); + __get_user(env->regs[9], &sc->regs.r9); + __get_user(env->regs[10], &sc->regs.r10); + __get_user(env->regs[11], &sc->regs.r11); + __get_user(env->regs[12], &sc->regs.r12); + __get_user(env->regs[13], &sc->regs.r13); + __get_user(env->regs[14], &sc->regs.r14); + __get_user(env->regs[15], &sc->regs.r15); + __get_user(env->regs[16], &sc->regs.r16); + __get_user(env->regs[17], &sc->regs.r17); + __get_user(env->regs[18], &sc->regs.r18); + __get_user(env->regs[19], &sc->regs.r19); + __get_user(env->regs[20], &sc->regs.r20); + __get_user(env->regs[21], &sc->regs.r21); + __get_user(env->regs[22], &sc->regs.r22); + __get_user(env->regs[23], &sc->regs.r23); + __get_user(env->regs[24], &sc->regs.r24); + __get_user(env->regs[25], &sc->regs.r25); + __get_user(env->regs[26], &sc->regs.r26); + __get_user(env->regs[27], &sc->regs.r27); + __get_user(env->regs[28], &sc->regs.r28); + __get_user(env->regs[29], &sc->regs.r29); + __get_user(env->regs[30], &sc->regs.r30); + __get_user(env->regs[31], &sc->regs.r31); + __get_user(env->sregs[SR_PC], &sc->regs.pc); +} + +static abi_ulong get_sigframe(struct target_sigaction *ka, + CPUState *env, int frame_size) +{ + abi_ulong sp = env->regs[1]; + + if ((ka->sa_flags & SA_ONSTACK) != 0 && !on_sig_stack(sp)) + sp = target_sigaltstack_used.ss_sp + target_sigaltstack_used.ss_size; + + return ((sp - frame_size) & -8UL); +} + +static void setup_frame(int sig, struct target_sigaction *ka, + target_sigset_t *set, CPUState *env) +{ + struct target_signal_frame *frame; + abi_ulong frame_addr; + int err = 0; + int i; + + frame_addr = get_sigframe(ka, env, sizeof *frame); + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) + goto badframe; + + /* Save the mask. */ + err |= __put_user(set->sig[0], &frame->sc.oldmask); + if (err) + goto badframe; + + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__put_user(set->sig[i], &frame->extramask[i - 1])) + goto badframe; + } + + setup_sigcontext(&frame->sc, env); + + /* Set up to return from userspace. If provided, use a stub + already in userspace. */ + /* minus 8 is offset to cater for "rtsd r15,8" offset */ + if (ka->sa_flags & TARGET_SA_RESTORER) { + env->regs[15] = ((unsigned long)ka->sa_restorer)-8; + } else { + uint32_t t; + /* Note, these encodings are _big endian_! */ + /* addi r12, r0, __NR_sigreturn */ + t = 0x31800000UL | TARGET_NR_sigreturn; + err |= __put_user(t, frame->tramp + 0); + /* brki r14, 0x8 */ + t = 0xb9cc0008UL; + err |= __put_user(t, frame->tramp + 1); + + /* Return from sighandler will jump to the tramp. + Negative 8 offset because return is rtsd r15, 8 */ + env->regs[15] = ((unsigned long)frame->tramp) - 8; + } + + if (err) + goto badframe; + + /* Set up registers for signal handler */ + env->regs[1] = (unsigned long) frame; + /* Signal handler args: */ + env->regs[5] = sig; /* Arg 0: signum */ + env->regs[6] = (unsigned long) &frame->sc; /* arg 1: sigcontext */ + + /* Offset of 4 to handle microblaze rtid r14, 0 */ + env->sregs[SR_PC] = (unsigned long)ka->_sa_handler; + + unlock_user_struct(frame, frame_addr, 1); + return; + badframe: + unlock_user_struct(frame, frame_addr, 1); + force_sig(TARGET_SIGSEGV); +} + +static void setup_rt_frame(int sig, struct target_sigaction *ka, + target_siginfo_t *info, + target_sigset_t *set, CPUState *env) +{ + fprintf(stderr, "Microblaze setup_rt_frame: not implemented\n"); +} + +long do_sigreturn(CPUState *env) +{ + struct target_signal_frame *frame; + abi_ulong frame_addr; + target_sigset_t target_set; + sigset_t set; + int i; + + frame_addr = env->regs[R_SP]; + /* Make sure the guest isn't playing games. */ + if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 1)) + goto badframe; + + /* Restore blocked signals */ + if (__get_user(target_set.sig[0], &frame->sc.oldmask)) + goto badframe; + for(i = 1; i < TARGET_NSIG_WORDS; i++) { + if (__get_user(target_set.sig[i], &frame->extramask[i - 1])) + goto badframe; + } + target_to_host_sigset_internal(&set, &target_set); + sigprocmask(SIG_SETMASK, &set, NULL); + + restore_sigcontext(&frame->sc, env); + /* We got here through a sigreturn syscall, our path back is via an + rtb insn so setup r14 for that. */ + env->regs[14] = env->sregs[SR_PC]; + + unlock_user_struct(frame, frame_addr, 0); + return env->regs[10]; + badframe: + unlock_user_struct(frame, frame_addr, 0); + force_sig(TARGET_SIGSEGV); +} + +long do_rt_sigreturn(CPUState *env) +{ + fprintf(stderr, "Microblaze do_rt_sigreturn: not implemented\n"); + return -TARGET_ENOSYS; +} + #elif defined(TARGET_CRIS) struct target_sigcontext { diff --git a/linux-user/syscall.c b/linux-user/syscall.c index b58220d..a0915a4 100644 --- a/linux-user/syscall.c +++ b/linux-user/syscall.c @@ -4854,7 +4854,7 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1, #endif #ifdef TARGET_NR_mmap case TARGET_NR_mmap: -#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) +#if (defined(TARGET_I386) && defined(TARGET_ABI32)) || defined(TARGET_ARM) || defined(TARGET_M68K) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) { abi_ulong *v; abi_ulong v1, v2, v3, v4, v5, v6; diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h index 7f0b0df..e2ba0bb 100644 --- a/linux-user/syscall_defs.h +++ b/linux-user/syscall_defs.h @@ -59,7 +59,8 @@ #define TARGET_IOC_READ 2U #elif defined(TARGET_PPC) || defined(TARGET_ALPHA) || \ - defined(TARGET_SPARC) || defined(TARGET_MIPS) + defined(TARGET_SPARC) || defined(TARGET_MICROBLAZE) || \ + defined(TARGET_MIPS) #define TARGET_IOC_SIZEBITS 13 #define TARGET_IOC_DIRBITS 3 @@ -286,7 +287,7 @@ struct target_sigaction; int do_sigaction(int sig, const struct target_sigaction *act, struct target_sigaction *oact); -#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) +#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || defined(TARGET_MICROBLAZE) #if defined(TARGET_SPARC) #define TARGET_SA_NOCLDSTOP 8u @@ -1170,6 +1171,54 @@ struct __attribute__((__packed__)) target_stat64 { unsigned int __unused5; }; +#elif defined(TARGET_MICROBLAZE) + +struct target_stat { + abi_ulong st_dev; + abi_ulong st_ino; + unsigned int st_mode; + unsigned short st_nlink; + unsigned int st_uid; + unsigned int st_gid; + abi_ulong st_rdev; + abi_ulong st_size; + abi_ulong st_blksize; + abi_ulong st_blocks; + abi_ulong target_st_atime; + abi_ulong target_st_atime_nsec; + abi_ulong target_st_mtime; + abi_ulong target_st_mtime_nsec; + abi_ulong target_st_ctime; + abi_ulong target_st_ctime_nsec; + abi_ulong __unused4; + abi_ulong __unused5; +}; + +/* FIXME: Microblaze no-mmu user-space has a difference stat64 layout... */ +struct __attribute__((__packed__)) target_stat64 { + uint64_t st_dev; + uint64_t st_ino; + uint32_t st_mode; + uint32_t st_nlink; + uint32_t st_uid; + uint32_t st_gid; + uint64_t st_rdev; + uint32_t __pad2; + + int64_t st_size; + int32_t st_blksize; + int64_t st_blocks; /* Number 512-byte blocks allocated. */ + + int target_st_atime; + unsigned int target_st_atime_nsec; + int target_st_mtime; + unsigned int target_st_mtime_nsec; + int target_st_ctime; + unsigned int target_st_ctime_nsec; + uint32_t __unused4; + uint32_t __unused5; +}; + #elif defined(TARGET_M68K) struct target_stat { @@ -1719,6 +1768,24 @@ struct target_statfs64 { #define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ #define TARGET_O_LARGEFILE 0200000 #define TARGET_O_DIRECT 0400000 /* direct disk access hint */ +#elif defined (TARGET_MICROBLAZE) +#define TARGET_O_ACCMODE 0003 +#define TARGET_O_RDONLY 00 +#define TARGET_O_WRONLY 01 +#define TARGET_O_RDWR 02 +#define TARGET_O_CREAT 0100 /* not fcntl */ +#define TARGET_O_EXCL 0200 /* not fcntl */ +#define TARGET_O_NOCTTY 0400 /* not fcntl */ +#define TARGET_O_TRUNC 01000 /* not fcntl */ +#define TARGET_O_APPEND 02000 +#define TARGET_O_NONBLOCK 04000 +#define TARGET_O_NDELAY TARGET_O_NONBLOCK +#define TARGET_O_SYNC 010000 +#define TARGET_FASYNC 020000 /* fcntl, for BSD compatibility */ +#define TARGET_O_DIRECTORY 040000 /* must be a directory */ +#define TARGET_O_NOFOLLOW 0100000 /* don't follow links */ +#define TARGET_O_LARGEFILE 0200000 +#define TARGET_O_DIRECT 0400000 /* direct disk access hint */ #elif defined (TARGET_SPARC) #define TARGET_O_RDONLY 0x0000 #define TARGET_O_WRONLY 0x0001 @@ -1806,7 +1873,7 @@ struct target_flock { struct target_flock64 { short l_type; short l_whence; -#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) || defined(TARGET_SPARC) || defined(TARGET_HPPA) +#if defined(TARGET_PPC) || defined(TARGET_X86_64) || defined(TARGET_MIPS) || defined(TARGET_SPARC) || defined(TARGET_HPPA) || defined (TARGET_MICROBLAZE) int __pad; #endif unsigned long long l_start; -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 04/13] microblaze: Add disassembler. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 03/13] microblaze: linux-user support Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 05/13] microblaze: Add MMU emulation Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- dis-asm.h | 2 + disas.c | 3 + microblaze-dis.c | 859 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 864 insertions(+), 0 deletions(-) create mode 100755 microblaze-dis.c diff --git a/dis-asm.h b/dis-asm.h index 303e23f..251c490 100644 --- a/dis-asm.h +++ b/dis-asm.h @@ -218,6 +218,7 @@ enum bfd_architecture #define bfd_mach_cris_v0_v10 255 #define bfd_mach_cris_v32 32 #define bfd_mach_cris_v10_v32 1032 + bfd_arch_microblaze, /* Xilinx MicroBlaze. */ bfd_arch_last }; #define bfd_mach_s390_31 31 @@ -400,6 +401,7 @@ extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_s390 PARAMS ((bfd_vma, disassemble_info*)); extern int print_insn_crisv32 PARAMS ((bfd_vma, disassemble_info*)); +extern int print_insn_microblaze PARAMS ((bfd_vma, disassemble_info*)); #if 0 /* Fetch the disassembler for a given BFD, if that support is available. */ diff --git a/disas.c b/disas.c index 6ed31e3..af5a9ea 100644 --- a/disas.c +++ b/disas.c @@ -195,6 +195,9 @@ void target_disas(FILE *out, target_ulong code, target_ulong size, int flags) #elif defined(TARGET_CRIS) disasm_info.mach = bfd_mach_cris_v32; print_insn = print_insn_crisv32; +#elif defined(TARGET_MICROBLAZE) + disasm_info.mach = bfd_arch_microblaze; + print_insn = print_insn_microblaze; #else fprintf(out, "0x" TARGET_FMT_lx ": Asm output not supported on this arch\n", code); diff --git a/microblaze-dis.c b/microblaze-dis.c new file mode 100755 index 0000000..af52550 --- /dev/null +++ b/microblaze-dis.c @@ -0,0 +1,859 @@ +/* Disassemble Xilinx microblaze instructions. + Copyright (C) 1993, 1999, 2000 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + */ + + +#include <stdio.h> +#define STATIC_TABLE +#define DEFINE_TABLE + +#ifndef MICROBLAZE_OPC +#define MICROBLAZE_OPC +/* Assembler instructions for Xilinx's microblaze processor + Copyright (C) 1999, 2000 Free Software Foundation, Inc. + + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + */ + + +#ifndef MICROBLAZE_OPCM +#define MICROBLAZE_OPCM + +/* + * Copyright (c) 2001 Xilinx, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Xilinx, Inc. The name of the Company may not be used to endorse + * or promote products derived from this software without specific prior + * written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Xilinx, Inc. + * $Header: + */ + +enum microblaze_instr { + add, rsub, addc, rsubc, addk, rsubk, addkc, rsubkc, cmp, cmpu, + addi, rsubi, addic, rsubic, addik, rsubik, addikc, rsubikc, mul, + idiv, idivu, bsll, bsra, bsrl, get, put, nget, nput, cget, cput, + ncget, ncput, muli, bslli, bsrai, bsrli, mului, or, and, xor, + andn, pcmpbf, pcmpbc, pcmpeq, pcmpne, sra, src, srl, sext8, sext16, wic, wdc, mts, mfs, br, brd, + brld, bra, brad, brald, microblaze_brk, beq, beqd, bne, bned, blt, + bltd, ble, bled, bgt, bgtd, bge, bged, ori, andi, xori, andni, + imm, rtsd, rtid, rtbd, rted, bri, brid, brlid, brai, braid, bralid, + brki, beqi, beqid, bnei, bneid, blti, bltid, blei, bleid, bgti, + bgtid, bgei, bgeid, lbu, lhu, lw, sb, sh, sw, lbui, lhui, lwi, + sbi, shi, swi, msrset, msrclr, tuqula, fadd, frsub, fmul, fdiv, + fcmp_lt, fcmp_eq, fcmp_le, fcmp_gt, fcmp_ne, fcmp_ge, fcmp_un, invalid_inst } ; + +enum microblaze_instr_type { + arithmetic_inst, logical_inst, mult_inst, div_inst, branch_inst, + return_inst, immediate_inst, special_inst, memory_load_inst, + memory_store_inst, barrel_shift_inst, anyware_inst }; + +#define INST_WORD_SIZE 4 + +/* gen purpose regs go from 0 to 31 */ +/* mask is reg num - max_reg_num, ie reg_num - 32 in this case */ + +#define REG_PC_MASK 0x8000 +#define REG_MSR_MASK 0x8001 +#define REG_EAR_MASK 0x8003 +#define REG_ESR_MASK 0x8005 +#define REG_FSR_MASK 0x8007 + +#define MIN_REGNUM 0 +#define MAX_REGNUM 31 + +#define REG_PC 32 /* PC */ +#define REG_MSR 33 /* machine status reg */ +#define REG_EAR 35 /* Exception reg */ +#define REG_ESR 37 /* Exception reg */ +#define REG_FSR 39 /* FPU Status reg */ + +/* alternate names for gen purpose regs */ +#define REG_SP 1 /* stack pointer */ +#define REG_ROSDP 2 /* read-only small data pointer */ +#define REG_RWSDP 13 /* read-write small data pointer */ + +/* Assembler Register - Used in Delay Slot Optimization */ +#define REG_AS 18 +#define REG_ZERO 0 + +#define RD_LOW 21 /* low bit for RD */ +#define RA_LOW 16 /* low bit for RA */ +#define RB_LOW 11 /* low bit for RB */ +#define IMM_LOW 0 /* low bit for immediate */ + +#define RD_MASK 0x03E00000 +#define RA_MASK 0x001F0000 +#define RB_MASK 0x0000F800 +#define IMM_MASK 0x0000FFFF + +// imm mask for barrel shifts +#define IMM5_MASK 0x0000001F + + +// imm mask for get, put instructions +#define IMM12_MASK 0x00000FFF + +// imm mask for msrset, msrclr instructions +#define IMM14_MASK 0x00003FFF + +#endif /* MICROBLAZE-OPCM */ + +#define INST_TYPE_RD_R1_R2 0 +#define INST_TYPE_RD_R1_IMM 1 +#define INST_TYPE_RD_R1_UNSIGNED_IMM 2 +#define INST_TYPE_RD_R1 3 +#define INST_TYPE_RD_R2 4 +#define INST_TYPE_RD_IMM 5 +#define INST_TYPE_R2 6 +#define INST_TYPE_R1_R2 7 +#define INST_TYPE_R1_IMM 8 +#define INST_TYPE_IMM 9 +#define INST_TYPE_SPECIAL_R1 10 +#define INST_TYPE_RD_SPECIAL 11 +#define INST_TYPE_R1 12 + // new instn type for barrel shift imms +#define INST_TYPE_RD_R1_IMM5 13 +#define INST_TYPE_RD_IMM12 14 +#define INST_TYPE_R1_IMM12 15 + + // new insn type for insn cache +#define INST_TYPE_RD_R1_SPECIAL 16 + +// new insn type for msrclr, msrset insns. +#define INST_TYPE_RD_IMM14 17 + +// new insn type for tuqula rd - addik rd, r0, 42 +#define INST_TYPE_RD 18 + +#define INST_TYPE_NONE 25 + + + +#define INST_PC_OFFSET 1 /* instructions where the label address is resolved as a PC offset (for branch label)*/ +#define INST_NO_OFFSET 0 /* instructions where the label address is resolved as an absolute value (for data mem or abs address)*/ + +#define IMMVAL_MASK_NON_SPECIAL 0x0000 +#define IMMVAL_MASK_MTS 0x4000 +#define IMMVAL_MASK_MFS 0x0000 + +#define OPCODE_MASK_H 0xFC000000 /* High 6 bits only */ +#define OPCODE_MASK_H1 0xFFE00000 /* High 11 bits */ +#define OPCODE_MASK_H2 0xFC1F0000 /* High 6 and bits 20-16 */ +#define OPCODE_MASK_H12 0xFFFF0000 /* High 16 */ +#define OPCODE_MASK_H4 0xFC0007FF /* High 6 and low 11 bits */ +#define OPCODE_MASK_H13S 0xFFE0FFF0 /* High 11 and 15:1 bits and last nibble of last byte for spr */ +#define OPCODE_MASK_H23S 0xFC1FFFF0 /* High 6, 20-16 and 15:1 bits and last nibble of last byte for spr */ +#define OPCODE_MASK_H34 0xFC00FFFF /* High 6 and low 16 bits */ +#define OPCODE_MASK_H14 0xFFE007FF /* High 11 and low 11 bits */ +#define OPCODE_MASK_H24 0xFC1F07FF /* High 6, bits 20-16 and low 11 bits */ +#define OPCODE_MASK_H124 0xFFFF07FF /* High 16, and low 11 bits */ +#define OPCODE_MASK_H1234 0xFFFFFFFF /* All 32 bits */ +#define OPCODE_MASK_H3 0xFC000600 /* High 6 bits and bits 21, 22 */ +#define OPCODE_MASK_H32 0xFC00F000 /* High 6 bits and bit 16, 17, 18 and 19*/ +#define OPCODE_MASK_H34B 0xFC0000FF /* High 6 bits and low 8 bits */ + +// New Mask for msrset, msrclr insns. +#define OPCODE_MASK_H23N 0xFC1FC000 /* High 6 and bits 12 - 18 */ + +#define DELAY_SLOT 1 +#define NO_DELAY_SLOT 0 + +#define MAX_OPCODES 149 + +struct op_code_struct { + const char *name; + short inst_type; /* registers and immediate values involved */ + short inst_offset_type; /* immediate vals offset from PC? (= 1 for branches) */ + short delay_slots; /* info about delay slots needed after this instr. */ + short immval_mask; + unsigned long bit_sequence; /* all the fixed bits for the op are set and all the variable bits (reg names, imm vals) are set to 0 */ + unsigned long opcode_mask; /* which bits define the opcode */ + enum microblaze_instr instr; + enum microblaze_instr_type instr_type; + /* more info about output format here */ +} opcodes[MAX_OPCODES] = + +{ + {"add", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x00000000, OPCODE_MASK_H4, add, arithmetic_inst }, + {"rsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H4, rsub, arithmetic_inst }, + {"addc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x08000000, OPCODE_MASK_H4, addc, arithmetic_inst }, + {"rsubc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x0C000000, OPCODE_MASK_H4, rsubc, arithmetic_inst }, + {"addk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x10000000, OPCODE_MASK_H4, addk, arithmetic_inst }, + {"rsubk", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000000, OPCODE_MASK_H4, rsubk, arithmetic_inst }, + {"cmp", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000001, OPCODE_MASK_H4, cmp, arithmetic_inst }, + {"cmpu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x14000003, OPCODE_MASK_H4, cmpu, arithmetic_inst }, + {"addkc", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x18000000, OPCODE_MASK_H4, addkc, arithmetic_inst }, + {"rsubkc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x1C000000, OPCODE_MASK_H4, rsubkc, arithmetic_inst }, + {"addi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x20000000, OPCODE_MASK_H, addi, arithmetic_inst }, + {"rsubi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x24000000, OPCODE_MASK_H, rsubi, arithmetic_inst }, + {"addic", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x28000000, OPCODE_MASK_H, addic, arithmetic_inst }, + {"rsubic",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x2C000000, OPCODE_MASK_H, rsubic, arithmetic_inst }, + {"addik", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, addik, arithmetic_inst }, + {"rsubik",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x34000000, OPCODE_MASK_H, rsubik, arithmetic_inst }, + {"addikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x38000000, OPCODE_MASK_H, addikc, arithmetic_inst }, + {"rsubikc",INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3C000000, OPCODE_MASK_H, rsubikc, arithmetic_inst }, + {"mul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x40000000, OPCODE_MASK_H4, mul, mult_inst }, + {"idiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000000, OPCODE_MASK_H4, idiv, div_inst }, + {"idivu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x48000002, OPCODE_MASK_H4, idivu, div_inst }, + {"bsll", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000400, OPCODE_MASK_H3, bsll, barrel_shift_inst }, + {"bsra", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000200, OPCODE_MASK_H3, bsra, barrel_shift_inst }, + {"bsrl", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x44000000, OPCODE_MASK_H3, bsrl, barrel_shift_inst }, + {"get", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C000000, OPCODE_MASK_H32, get, anyware_inst }, + {"put", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C008000, OPCODE_MASK_H32, put, anyware_inst }, + {"nget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C004000, OPCODE_MASK_H32, nget, anyware_inst }, + {"nput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00C000, OPCODE_MASK_H32, nput, anyware_inst }, + {"cget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C002000, OPCODE_MASK_H32, cget, anyware_inst }, + {"cput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00A000, OPCODE_MASK_H32, cput, anyware_inst }, + {"ncget", INST_TYPE_RD_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C006000, OPCODE_MASK_H32, ncget, anyware_inst }, + {"ncput", INST_TYPE_R1_IMM12, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x6C00E000, OPCODE_MASK_H32, ncput, anyware_inst }, + {"muli", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x60000000, OPCODE_MASK_H, muli, mult_inst }, + {"bslli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000400, OPCODE_MASK_H3, bslli, barrel_shift_inst }, + {"bsrai", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000200, OPCODE_MASK_H3, bsrai, barrel_shift_inst }, + {"bsrli", INST_TYPE_RD_R1_IMM5, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x64000000, OPCODE_MASK_H3, bsrli, barrel_shift_inst }, + {"or", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H4, or, logical_inst }, + {"and", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000000, OPCODE_MASK_H4, and, logical_inst }, + {"xor", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000000, OPCODE_MASK_H4, xor, logical_inst }, + {"andn", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000000, OPCODE_MASK_H4, andn, logical_inst }, + {"pcmpbf",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000400, OPCODE_MASK_H4, pcmpbf, logical_inst }, + {"pcmpbc",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x84000400, OPCODE_MASK_H4, pcmpbc, logical_inst }, + {"pcmpeq",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x88000400, OPCODE_MASK_H4, pcmpeq, logical_inst }, + {"pcmpne",INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x8C000400, OPCODE_MASK_H4, pcmpne, logical_inst }, + {"sra", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000001, OPCODE_MASK_H34, sra, logical_inst }, + {"src", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000021, OPCODE_MASK_H34, src, logical_inst }, + {"srl", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000041, OPCODE_MASK_H34, srl, logical_inst }, + {"sext8", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000060, OPCODE_MASK_H34, sext8, logical_inst }, + {"sext16",INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000061, OPCODE_MASK_H34, sext16, logical_inst }, + {"wic", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000068, OPCODE_MASK_H34B, wic, special_inst }, + {"wdc", INST_TYPE_RD_R1_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x90000064, OPCODE_MASK_H34B, wdc, special_inst }, + {"mts", INST_TYPE_SPECIAL_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MTS, 0x9400C000, OPCODE_MASK_H13S, mts, special_inst }, + {"mfs", INST_TYPE_RD_SPECIAL, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_MFS, 0x94008000, OPCODE_MASK_H23S, mfs, special_inst }, + {"br", INST_TYPE_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98000000, OPCODE_MASK_H124, br, branch_inst }, + {"brd", INST_TYPE_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98100000, OPCODE_MASK_H124, brd, branch_inst }, + {"brld", INST_TYPE_RD_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98140000, OPCODE_MASK_H24, brld, branch_inst }, + {"bra", INST_TYPE_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98080000, OPCODE_MASK_H124, bra, branch_inst }, + {"brad", INST_TYPE_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x98180000, OPCODE_MASK_H124, brad, branch_inst }, + {"brald", INST_TYPE_RD_R2, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x981C0000, OPCODE_MASK_H24, brald, branch_inst }, + {"brk", INST_TYPE_RD_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x980C0000, OPCODE_MASK_H24, microblaze_brk, branch_inst }, + {"beq", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C000000, OPCODE_MASK_H14, beq, branch_inst }, + {"beqd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E000000, OPCODE_MASK_H14, beqd, branch_inst }, + {"bne", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C200000, OPCODE_MASK_H14, bne, branch_inst }, + {"bned", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E200000, OPCODE_MASK_H14, bned, branch_inst }, + {"blt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C400000, OPCODE_MASK_H14, blt, branch_inst }, + {"bltd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E400000, OPCODE_MASK_H14, bltd, branch_inst }, + {"ble", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C600000, OPCODE_MASK_H14, ble, branch_inst }, + {"bled", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E600000, OPCODE_MASK_H14, bled, branch_inst }, + {"bgt", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9C800000, OPCODE_MASK_H14, bgt, branch_inst }, + {"bgtd", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9E800000, OPCODE_MASK_H14, bgtd, branch_inst }, + {"bge", INST_TYPE_R1_R2, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9CA00000, OPCODE_MASK_H14, bge, branch_inst }, + {"bged", INST_TYPE_R1_R2, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x9EA00000, OPCODE_MASK_H14, bged, branch_inst }, + {"ori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA0000000, OPCODE_MASK_H, ori, logical_inst }, + {"andi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA4000000, OPCODE_MASK_H, andi, logical_inst }, + {"xori", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA8000000, OPCODE_MASK_H, xori, logical_inst }, + {"andni", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xAC000000, OPCODE_MASK_H, andni, logical_inst }, + {"imm", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB0000000, OPCODE_MASK_H12, imm, immediate_inst }, + {"rtsd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000000, OPCODE_MASK_H1, rtsd, return_inst }, + {"rtid", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6200000, OPCODE_MASK_H1, rtid, return_inst }, + {"rtbd", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6400000, OPCODE_MASK_H1, rtbd, return_inst }, + {"rted", INST_TYPE_R1_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6800000, OPCODE_MASK_H1, rted, return_inst }, + {"bri", INST_TYPE_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8000000, OPCODE_MASK_H12, bri, branch_inst }, + {"brid", INST_TYPE_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8100000, OPCODE_MASK_H12, brid, branch_inst }, + {"brlid", INST_TYPE_RD_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8140000, OPCODE_MASK_H2, brlid, branch_inst }, + {"brai", INST_TYPE_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8080000, OPCODE_MASK_H12, brai, branch_inst }, + {"braid", INST_TYPE_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB8180000, OPCODE_MASK_H12, braid, branch_inst }, + {"bralid",INST_TYPE_RD_IMM, INST_NO_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB81C0000, OPCODE_MASK_H2, bralid, branch_inst }, + {"brki", INST_TYPE_RD_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB80C0000, OPCODE_MASK_H2, brki, branch_inst }, + {"beqi", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC000000, OPCODE_MASK_H1, beqi, branch_inst }, + {"beqid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE000000, OPCODE_MASK_H1, beqid, branch_inst }, + {"bnei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC200000, OPCODE_MASK_H1, bnei, branch_inst }, + {"bneid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE200000, OPCODE_MASK_H1, bneid, branch_inst }, + {"blti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC400000, OPCODE_MASK_H1, blti, branch_inst }, + {"bltid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE400000, OPCODE_MASK_H1, bltid, branch_inst }, + {"blei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC600000, OPCODE_MASK_H1, blei, branch_inst }, + {"bleid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE600000, OPCODE_MASK_H1, bleid, branch_inst }, + {"bgti", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBC800000, OPCODE_MASK_H1, bgti, branch_inst }, + {"bgtid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBE800000, OPCODE_MASK_H1, bgtid, branch_inst }, + {"bgei", INST_TYPE_R1_IMM, INST_PC_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBCA00000, OPCODE_MASK_H1, bgei, branch_inst }, + {"bgeid", INST_TYPE_R1_IMM, INST_PC_OFFSET, DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xBEA00000, OPCODE_MASK_H1, bgeid, branch_inst }, + {"lbu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC0000000, OPCODE_MASK_H4, lbu, memory_load_inst }, + {"lhu", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC4000000, OPCODE_MASK_H4, lhu, memory_load_inst }, + {"lw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xC8000000, OPCODE_MASK_H4, lw, memory_load_inst }, + {"sb", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD0000000, OPCODE_MASK_H4, sb, memory_store_inst }, + {"sh", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD4000000, OPCODE_MASK_H4, sh, memory_store_inst }, + {"sw", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xD8000000, OPCODE_MASK_H4, sw, memory_store_inst }, + {"lbui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE0000000, OPCODE_MASK_H, lbui, memory_load_inst }, + {"lhui", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE4000000, OPCODE_MASK_H, lhui, memory_load_inst }, + {"lwi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, lwi, memory_load_inst }, + {"sbi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF0000000, OPCODE_MASK_H, sbi, memory_store_inst }, + {"shi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF4000000, OPCODE_MASK_H, shi, memory_store_inst }, + {"swi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, swi, memory_store_inst }, + {"nop", INST_TYPE_NONE, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x80000000, OPCODE_MASK_H1234, invalid_inst, logical_inst }, /* translates to or r0, r0, r0 */ + {"la", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x30000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* la translates to addik */ + {"tuqula",INST_TYPE_RD, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x3000002A, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* tuqula rd translates to addik rd, r0, 42 */ + {"not", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xA800FFFF, OPCODE_MASK_H34, invalid_inst, logical_inst }, /* not translates to xori rd,ra,-1 */ + {"neg", INST_TYPE_RD_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* neg translates to rsub rd, ra, r0 */ + {"rtb", INST_TYPE_R1, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xB6000004, OPCODE_MASK_H1, invalid_inst, return_inst }, /* rtb translates to rts rd, 4 */ + {"sub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x04000000, OPCODE_MASK_H, invalid_inst, arithmetic_inst }, /* sub translates to rsub rd, rb, ra */ + {"lmi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xE8000000, OPCODE_MASK_H, invalid_inst, memory_load_inst }, + {"smi", INST_TYPE_RD_R1_IMM, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0xF8000000, OPCODE_MASK_H, invalid_inst, memory_store_inst }, + {"msrset",INST_TYPE_RD_IMM14, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94100000, OPCODE_MASK_H23N, msrset, special_inst }, + {"msrclr",INST_TYPE_RD_IMM14, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x94110000, OPCODE_MASK_H23N, msrclr, special_inst }, + {"fadd", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000000, OPCODE_MASK_H4, fadd, arithmetic_inst }, + {"frsub", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000080, OPCODE_MASK_H4, frsub, arithmetic_inst }, + {"fmul", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000100, OPCODE_MASK_H4, fmul, arithmetic_inst }, + {"fdiv", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000180, OPCODE_MASK_H4, fdiv, arithmetic_inst }, + {"fcmp.lt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000210, OPCODE_MASK_H4, fcmp_lt, arithmetic_inst }, + {"fcmp.eq", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000220, OPCODE_MASK_H4, fcmp_eq, arithmetic_inst }, + {"fcmp.le", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000230, OPCODE_MASK_H4, fcmp_le, arithmetic_inst }, + {"fcmp.gt", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000240, OPCODE_MASK_H4, fcmp_gt, arithmetic_inst }, + {"fcmp.ne", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000250, OPCODE_MASK_H4, fcmp_ne, arithmetic_inst }, + {"fcmp.ge", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000260, OPCODE_MASK_H4, fcmp_ge, arithmetic_inst }, + {"fcmp.un", INST_TYPE_RD_R1_R2, INST_NO_OFFSET, NO_DELAY_SLOT, IMMVAL_MASK_NON_SPECIAL, 0x58000200, OPCODE_MASK_H4, fcmp_un, arithmetic_inst }, + {""} +}; + +/* prefix for register names */ +char register_prefix[] = "r"; +char special_register_prefix[] = "spr"; +char fsl_register_prefix[] = "rfsl"; + + +/* #defines for valid immediate range */ +#define MIN_IMM 0x80000000 +#define MAX_IMM 0x7fffffff + +#define MIN_IMM12 0x000 +#define MAX_IMM12 0x7ff + +#define MIN_IMM14 0x0000 +#define MAX_IMM14 0x1fff + +#endif /* MICROBLAZE_OPC */ + +#include "dis-asm.h" +#include <strings.h> + +#define get_field_rd(instr) get_field(instr, RD_MASK, RD_LOW) +#define get_field_r1(instr) get_field(instr, RA_MASK, RA_LOW) +#define get_field_r2(instr) get_field(instr, RB_MASK, RB_LOW) +#define get_int_field_imm(instr) ((instr & IMM_MASK) >> IMM_LOW) +#define get_int_field_r1(instr) ((instr & RA_MASK) >> RA_LOW) + +char * +get_field (instr, mask, low) + long instr, mask; + unsigned short low; +{ + char tmpstr[25]; + sprintf(tmpstr, "%s%d", register_prefix, (int)((instr & mask) >> low)); + return(strdup(tmpstr)); +} + +char * +get_field_imm (instr) + long instr; +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +char * +get_field_imm5 (instr) + long instr; +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM5_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +char * +get_field_imm12 (instr) + long instr; +{ + char tmpstr[25]; + sprintf(tmpstr, "%s%d", fsl_register_prefix, (short)((instr & IMM12_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +char * +get_field_imm14 (instr) + long instr; +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (short)((instr & IMM14_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +char * +get_field_unsigned_imm (instr) + long instr; +{ + char tmpstr[25]; + sprintf(tmpstr, "%d", (int)((instr & IMM_MASK) >> IMM_LOW)); + return(strdup(tmpstr)); +} + +/* + char * + get_field_special (instr) + long instr; + { + char tmpstr[25]; + + sprintf(tmpstr, "%s%s", register_prefix, (((instr & IMM_MASK) >> IMM_LOW) & REG_MSR_MASK) == 0 ? "pc" : "msr"); + + return(strdup(tmpstr)); + } +*/ + +char * +get_field_special (instr, op) + long instr; +struct op_code_struct * op; +{ + char tmpstr[25]; + char spr[5]; + + switch ( (((instr & IMM_MASK) >> IMM_LOW) ^ op->immval_mask) ) { + case REG_MSR_MASK : + strcpy(spr, "msr"); + break; + case REG_PC_MASK : + strcpy(spr, "pc"); + break; + case REG_EAR_MASK : + strcpy(spr, "ear"); + break; + case REG_ESR_MASK : + strcpy(spr, "esr"); + break; + case REG_FSR_MASK : + strcpy(spr, "fsr"); + break; + default : + strcpy(spr, "pc"); + break; + } + + sprintf(tmpstr, "%s%s", register_prefix, spr); + return(strdup(tmpstr)); +} + +unsigned long +read_insn_microblaze(memaddr, info, opr) + bfd_vma memaddr; +struct disassemble_info *info; +struct op_code_struct **opr; +{ + unsigned char ibytes[4]; + int status; + struct op_code_struct * op; + unsigned long inst; + + status = info->read_memory_func (memaddr, ibytes, 4, info); + + if (status != 0) + { + info->memory_error_func (status, memaddr, info); + return 0; + } + + if (info->endian == BFD_ENDIAN_BIG) + inst = (ibytes[0] << 24) | (ibytes[1] << 16) | (ibytes[2] << 8) | ibytes[3]; + else if (info->endian == BFD_ENDIAN_LITTLE) + inst = (ibytes[3] << 24) | (ibytes[2] << 16) | (ibytes[1] << 8) | ibytes[0]; + else + abort (); + + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + *opr = op; + return inst; +} + + +int +print_insn_microblaze (memaddr, info) + bfd_vma memaddr; + struct disassemble_info * info; +{ + fprintf_ftype fprintf = info->fprintf_func; + void * stream = info->stream; + unsigned long inst, prev_inst; + struct op_code_struct * op, *pop; + int immval = 0; + boolean immfound = false; + static bfd_vma prev_insn_addr = -1; /*init the prev insn addr */ + static int prev_insn_vma = -1; /*init the prev insn vma */ + int curr_insn_vma = info->buffer_vma; + + info->bytes_per_chunk = 4; + + inst = read_insn_microblaze (memaddr, info, &op); + if (inst == 0) + return -1; + + if (prev_insn_vma == curr_insn_vma) { + if (memaddr-(info->bytes_per_chunk) == prev_insn_addr) { + prev_inst = read_insn_microblaze (prev_insn_addr, info, &pop); + if (prev_inst == 0) + return -1; + if (pop->instr == imm) { + immval = (get_int_field_imm(prev_inst) << 16) & 0xffff0000; + immfound = true; + } + else { + immval = 0; + immfound = false; + } + } + } + /* make curr insn as prev insn */ + prev_insn_addr = memaddr; + prev_insn_vma = curr_insn_vma; + + if (op->name == 0) + fprintf (stream, ".short 0x%04x", inst); + else + { + fprintf (stream, "%s", op->name); + + switch (op->inst_type) + { + case INST_TYPE_RD_R1_R2: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_r2(inst)); + break; + case INST_TYPE_RD_R1_IMM: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm(inst)); + if (info->print_address_func && get_int_field_r1(inst) == 0 && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } + } + break; + case INST_TYPE_RD_R1_IMM5: + fprintf(stream, "\t%s, %s, %s", get_field_rd(inst), get_field_r1(inst), get_field_imm5(inst)); + break; + case INST_TYPE_RD_IMM12: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm12(inst)); + break; + case INST_TYPE_R1_IMM12: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm12(inst)); + break; + case INST_TYPE_RD_SPECIAL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_special(inst, op)); + break; + case INST_TYPE_SPECIAL_R1: + fprintf(stream, "\t%s, %s", get_field_special(inst, op), get_field_r1(inst)); + break; + case INST_TYPE_RD_R1: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r1(inst)); + break; + case INST_TYPE_R1_R2: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_r2(inst)); + break; + case INST_TYPE_R1_IMM: + fprintf(stream, "\t%s, %s", get_field_r1(inst), get_field_imm(inst)); + /* The non-pc relative instructions are returns, which shouldn't + have a label printed */ + if (info->print_address_func && op->inst_offset_type == INST_PC_OFFSET && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + immval += memaddr; + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } else { + fprintf (stream, "\t\t// "); + fprintf (stream, "%x", immval); + } + } + break; + case INST_TYPE_RD_IMM: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm(inst)); + if (info->print_address_func && info->symbol_at_address_func) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + immval += (int) memaddr; + if (info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } + } + break; + case INST_TYPE_IMM: + fprintf(stream, "\t%s", get_field_imm(inst)); + if (info->print_address_func && info->symbol_at_address_func && op->instr != imm) { + if (immfound) + immval |= (get_int_field_imm(inst) & 0x0000ffff); + else { + immval = get_int_field_imm(inst); + if (immval & 0x8000) + immval |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + immval += (int) memaddr; + if (immval > 0 && info->symbol_at_address_func(immval, info)) { + fprintf (stream, "\t// "); + info->print_address_func (immval, info); + } else if (op->inst_offset_type == INST_PC_OFFSET) { + fprintf (stream, "\t\t// "); + fprintf (stream, "%x", immval); + } + } + break; + case INST_TYPE_RD_R2: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst)); + break; + case INST_TYPE_R2: + fprintf(stream, "\t%s", get_field_r2(inst)); + break; + case INST_TYPE_R1: + fprintf(stream, "\t%s", get_field_r1(inst)); + break; + case INST_TYPE_RD_R1_SPECIAL: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_r2(inst)); + break; + case INST_TYPE_RD_IMM14: + fprintf(stream, "\t%s, %s", get_field_rd(inst), get_field_imm14(inst)); + break; + /* For tuqula instruction */ + case INST_TYPE_RD: + fprintf(stream, "\t%s", get_field_rd(inst)); + break; + + default: + /* if the disassembler lags the instruction set */ + fprintf (stream, "\tundecoded operands, inst is 0x%04x", inst); + break; + } + } + + /* Say how many bytes we consumed? */ + return 4; +} + +enum microblaze_instr +get_insn_microblaze( inst, isunsignedimm, insn_type, delay_slots ) + long inst; + boolean *isunsignedimm; + enum microblaze_instr_type *insn_type; + short *delay_slots; +{ + struct op_code_struct * op; + *isunsignedimm = false; + + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + if (op->name == 0) + return invalid_inst; + else { + *isunsignedimm = (op->inst_type == INST_TYPE_RD_R1_UNSIGNED_IMM); + *insn_type = op->instr_type; + *delay_slots = op->delay_slots; + return op->instr; + } +} + +short +get_delay_slots_microblaze ( inst ) + long inst; +{ + boolean isunsignedimm; + enum microblaze_instr_type insn_type; + enum microblaze_instr op; + short delay_slots; + + op = get_insn_microblaze( inst, &isunsignedimm, &insn_type, &delay_slots); + if (op == invalid_inst) + return 0; + else + return delay_slots; +} + +enum microblaze_instr +microblaze_decode_insn (insn, rd, ra, rb, imm) + long insn; +int *rd, *ra, *rb, *imm; +{ + enum microblaze_instr op; + boolean t1; + enum microblaze_instr_type t2; + short t3; + + op = get_insn_microblaze(insn, &t1, &t2, &t3); + *rd = (insn & RD_MASK) >> RD_LOW; + *ra = (insn & RA_MASK) >> RA_LOW; + *rb = (insn & RB_MASK) >> RB_LOW; + t3 = (insn & IMM_MASK) >> IMM_LOW; + *imm = (int) t3; + return (op); +} + +unsigned long +microblaze_get_target_address (inst, immfound, immval, pcval, r1val, r2val, targetvalid, unconditionalbranch) + long inst; + boolean immfound; + int immval; + long pcval; + long r1val; + long r2val; + boolean *targetvalid; + boolean *unconditionalbranch; +{ + struct op_code_struct * op; + long targetaddr = 0; + + *unconditionalbranch = false; + /* Just a linear search of the table. */ + for (op = opcodes; op->name != 0; op ++) + if (op->bit_sequence == (inst & op->opcode_mask)) + break; + + if (op->name == 0) { + *targetvalid = false; + } else if (op->instr_type == branch_inst) { + switch (op->inst_type) { + case INST_TYPE_R2: + *unconditionalbranch = true; + /* fallthru */ + case INST_TYPE_RD_R2: + case INST_TYPE_R1_R2: + targetaddr = r2val; + *targetvalid = true; + if (op->inst_offset_type == INST_PC_OFFSET) + targetaddr += pcval; + break; + case INST_TYPE_IMM: + *unconditionalbranch = true; + /* fallthru */ + case INST_TYPE_RD_IMM: + case INST_TYPE_R1_IMM: + if (immfound) { + targetaddr = (immval << 16) & 0xffff0000; + targetaddr |= (get_int_field_imm(inst) & 0x0000ffff); + } else { + targetaddr = get_int_field_imm(inst); + if (targetaddr & 0x8000) + targetaddr |= 0xFFFF0000; + } + if (op->inst_offset_type == INST_PC_OFFSET) + targetaddr += pcval; + *targetvalid = true; + break; + default: + *targetvalid = false; + break; + } + } else if (op->instr_type == return_inst) { + if (immfound) { + targetaddr = (immval << 16) & 0xffff0000; + targetaddr |= (get_int_field_imm(inst) & 0x0000ffff); + } else { + targetaddr = get_int_field_imm(inst); + if (targetaddr & 0x8000) + targetaddr |= 0xFFFF0000; + } + targetaddr += r1val; + *targetvalid = true; + } else { + *targetvalid = false; + } + return targetaddr; +} -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 05/13] microblaze: Add MMU emulation. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 04/13] microblaze: Add disassembler Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 06/13] microblaze: Add CPU interrupt wrapper logic Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- target-microblaze/mmu.c | 248 +++++++++++++++++++++++++++++++++++++++++++++++ target-microblaze/mmu.h | 88 +++++++++++++++++ 2 files changed, 336 insertions(+), 0 deletions(-) create mode 100644 target-microblaze/mmu.c create mode 100644 target-microblaze/mmu.h diff --git a/target-microblaze/mmu.c b/target-microblaze/mmu.c new file mode 100644 index 0000000..14a1f3d --- /dev/null +++ b/target-microblaze/mmu.c @@ -0,0 +1,248 @@ +/* + * Microblaze MMU emulation for qemu. + * + * Copyright (c) 2009 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "config.h" +#include "cpu.h" +#include "exec-all.h" + +#define D(x) + +static unsigned int tlb_decode_size(unsigned int f) +{ + static const unsigned int sizes[] = { + 1 * 1024, 4 * 1024, 16 * 1024, 64 * 1024, 256 * 1024, + 1 * 1024 * 1024, 4 * 1024 * 1024, 16 * 1024 * 1024 + }; + assert(f < ARRAY_SIZE(sizes)); + return sizes[f]; +} + +static void mmu_flush_idx(CPUState *env, unsigned idx) +{ + struct microblaze_mmu *mmu = &env->mmu; + unsigned int tlb_size; + uint32_t tlb_tag, end, t; + + t = mmu->rams[RAM_TAG][idx]; + if (!(t & TLB_VALID)) + return; + + tlb_tag = t & TLB_EPN_MASK; + tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7); + end = tlb_tag + tlb_size; + + while (tlb_tag < end) { + tlb_flush_page(env, tlb_tag); + tlb_tag += TARGET_PAGE_SIZE; + } +} + +static void mmu_change_pid(CPUState *env, unsigned int newpid) +{ + struct microblaze_mmu *mmu = &env->mmu; + unsigned int i; + unsigned int tlb_size; + uint32_t tlb_tag, mask, t; + + if (newpid & ~0xff) + qemu_log("Illegal rpid=%x\n", newpid); + + for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) { + /* Lookup and decode. */ + t = mmu->rams[RAM_TAG][i]; + if (t & TLB_VALID) { + tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7); + mask = ~(tlb_size - 1); + + tlb_tag = t & TLB_EPN_MASK; + if (mmu->tids[i] && ((mmu->regs[MMU_R_PID] & 0xff) == mmu->tids[i])) + mmu_flush_idx(env, i); + } + } +} + +/* rw - 0 = read, 1 = write, 2 = fetch. */ +unsigned int mmu_translate(struct microblaze_mmu *mmu, + struct microblaze_mmu_lookup *lu, + target_ulong vaddr, int rw, int mmu_idx) +{ + unsigned int i, hit = 0; + unsigned int tlb_ex = 0, tlb_wr = 0, tlb_zsel; + unsigned int tlb_size; + uint32_t tlb_tag, tlb_rpn, mask, t0; + + lu->err = ERR_MISS; + for (i = 0; i < ARRAY_SIZE(mmu->rams[RAM_TAG]); i++) { + uint32_t t, d; + + /* Lookup and decode. */ + t = mmu->rams[RAM_TAG][i]; + D(qemu_log("TLB %d valid=%d\n", i, t & TLB_VALID)); + if (t & TLB_VALID) { + tlb_size = tlb_decode_size((t & TLB_PAGESZ_MASK) >> 7); + if (tlb_size < TARGET_PAGE_SIZE) { + qemu_log("%d pages not supported\n", tlb_size); + abort(); + } + + mask = ~(tlb_size - 1); + tlb_tag = t & TLB_EPN_MASK; + if ((vaddr & mask) != (tlb_tag & mask)) { + D(qemu_log("TLB %d vaddr=%x != tag=%x\n", + i, vaddr & mask, tlb_tag & mask)); + continue; + } + if (mmu->tids[i] + && ((mmu->regs[MMU_R_PID] & 0xff) != mmu->tids[i])) { + D(qemu_log("TLB %d pid=%x != tid=%x\n", + i, mmu->regs[MMU_R_PID], mmu->tids[i])); + continue; + } + + /* Bring in the data part. */ + d = mmu->rams[RAM_DATA][i]; + tlb_ex = d & TLB_EX; + tlb_wr = d & TLB_WR; + + /* Now lets see if there is a zone that overrides the protbits. */ + tlb_zsel = (d >> 4) & 0xf; + t0 = mmu->regs[MMU_R_ZPR] >> (30 - (tlb_zsel * 2)); + t0 &= 0x3; + switch (t0) { + case 0: + if (mmu_idx == MMU_USER_IDX) + continue; + break; + case 2: + if (mmu_idx != MMU_USER_IDX) { + tlb_ex = 1; + tlb_wr = 1; + } + break; + case 3: + tlb_ex = 1; + tlb_wr = 1; + break; + } + + + lu->err = ERR_PROT; + lu->prot = PAGE_READ; + if (tlb_wr) + lu->prot |= PAGE_WRITE; + else if (rw == 1) + goto done; + if (tlb_ex) + lu->prot |=PAGE_EXEC; + else if (rw == 2) { + goto done; + } + + tlb_rpn = d & TLB_RPN_MASK; + + lu->vaddr = tlb_tag; + lu->paddr = tlb_rpn; + lu->size = tlb_size; + lu->err = ERR_HIT; + lu->idx = i; + hit = 1; + goto done; + } + } +done: + D(qemu_log("MMU vaddr=%x rw=%d tlb_wr=%d tlb_ex=%d hit=%d\n", + vaddr, rw, tlb_wr, tlb_ex, hit)); + return hit; +} + +/* Writes/reads to the MMU's special regs end up here. */ +uint32_t mmu_read(CPUState *env, uint32_t rn) +{ + unsigned int i; + uint32_t r; + + switch (rn) { + /* Reads to HI/LO trig reads from the mmu rams. */ + case MMU_R_TLBLO: + case MMU_R_TLBHI: + i = env->mmu.regs[MMU_R_TLBX] & 0xff; + r = env->mmu.rams[rn & 1][i]; + if (rn == MMU_R_TLBHI) + env->mmu.regs[MMU_R_PID] = env->mmu.tids[i]; + break; + default: + r = env->mmu.regs[rn]; + break; + } + D(qemu_log("%s rn=%d=%x\n", __func__, rn, r)); + return r; +} + +void mmu_write(CPUState *env, uint32_t rn, uint32_t v) +{ + unsigned int i; + D(qemu_log("%s rn=%d=%x old=%x\n", __func__, rn, v, env->mmu.regs[rn])); + + switch (rn) { + /* Writes to HI/LO trig writes to the mmu rams. */ + case MMU_R_TLBLO: + case MMU_R_TLBHI: + i = env->mmu.regs[MMU_R_TLBX] & 0xff; + if (rn == MMU_R_TLBHI) { + if (i < 3 && !(v & TLB_VALID) && qemu_loglevel_mask(~0)) + qemu_log("invalidating index %x at pc=%x\n", + i, env->sregs[SR_PC]); + env->mmu.tids[i] = env->mmu.regs[MMU_R_PID] & 0xff; + mmu_flush_idx(env, i); + } + env->mmu.rams[rn & 1][i] = v; + + D(qemu_log("%s ram[%d][%d]=%x\n", __func__, rn & 1, i, v)); + break; + case MMU_R_ZPR: + case MMU_R_PID: + mmu_change_pid(env, v); + env->mmu.regs[rn] = v; + break; + case MMU_R_TLBSX: + { + struct microblaze_mmu_lookup lu; + int hit; + hit = mmu_translate(&env->mmu, &lu, + v & TLB_EPN_MASK, 0, cpu_mmu_index(env)); + if (hit) { + env->mmu.regs[MMU_R_TLBX] = lu.idx; + } else + env->mmu.regs[MMU_R_TLBX] |= 0x80000000; + break; + } + default: + env->mmu.regs[rn] = v; + break; + } +} + +void mmu_init(struct microblaze_mmu *mmu) +{ + memset(mmu, 0, sizeof *mmu); +} diff --git a/target-microblaze/mmu.h b/target-microblaze/mmu.h new file mode 100644 index 0000000..9759333 --- /dev/null +++ b/target-microblaze/mmu.h @@ -0,0 +1,88 @@ +/* + * Microblaze MMU emulation for qemu. + * + * Copyright (c) 2009 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA + */ + +#define MMU_R_PID 0 +#define MMU_R_ZPR 1 +#define MMU_R_TLBX 2 +#define MMU_R_TLBLO 3 +#define MMU_R_TLBHI 4 +#define MMU_R_TLBSX 5 + +#define RAM_DATA 1 +#define RAM_TAG 0 + +/* Tag portion */ +#define TLB_EPN_MASK 0xFFFFFC00 /* Effective Page Number */ +#define TLB_PAGESZ_MASK 0x00000380 +#define TLB_PAGESZ(x) (((x) & 0x7) << 7) +#define PAGESZ_1K 0 +#define PAGESZ_4K 1 +#define PAGESZ_16K 2 +#define PAGESZ_64K 3 +#define PAGESZ_256K 4 +#define PAGESZ_1M 5 +#define PAGESZ_4M 6 +#define PAGESZ_16M 7 +#define TLB_VALID 0x00000040 /* Entry is valid */ + +/* Data portion */ +#define TLB_RPN_MASK 0xFFFFFC00 /* Real Page Number */ +#define TLB_PERM_MASK 0x00000300 +#define TLB_EX 0x00000200 /* Instruction execution allowed */ +#define TLB_WR 0x00000100 /* Writes permitted */ +#define TLB_ZSEL_MASK 0x000000F0 +#define TLB_ZSEL(x) (((x) & 0xF) << 4) +#define TLB_ATTR_MASK 0x0000000F +#define TLB_W 0x00000008 /* Caching is write-through */ +#define TLB_I 0x00000004 /* Caching is inhibited */ +#define TLB_M 0x00000002 /* Memory is coherent */ +#define TLB_G 0x00000001 /* Memory is guarded from prefetch */ + +#define TLB_ENTRIES 64 + +struct microblaze_mmu +{ + /* Data and tag brams. */ + uint32_t rams[2][TLB_ENTRIES]; + /* We keep a separate ram for the tids to avoid the 48 bit tag width. */ + uint8_t tids[TLB_ENTRIES]; + /* Control flops. */ + uint32_t regs[8];; +}; + +struct microblaze_mmu_lookup +{ + uint32_t paddr; + uint32_t vaddr; + unsigned int size; + unsigned int idx; + int prot; + enum { + ERR_PROT, ERR_MISS, ERR_HIT + } err; +}; + +void mmu_flip_um(CPUState *env, unsigned int um); +unsigned int mmu_translate(struct microblaze_mmu *mmu, + struct microblaze_mmu_lookup *lu, + target_ulong vaddr, int rw, int mmu_idx); +uint32_t mmu_read(CPUState *env, uint32_t rn); +void mmu_write(CPUState *env, uint32_t rn, uint32_t v); +void mmu_init(struct microblaze_mmu *mmu); -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 06/13] microblaze: Add CPU interrupt wrapper logic. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 05/13] microblaze: Add MMU emulation Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 07/13] xilinx: Add interrupt controller Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/microblaze_pic_cpu.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 50 insertions(+), 0 deletions(-) create mode 100644 hw/microblaze_pic_cpu.c diff --git a/hw/microblaze_pic_cpu.c b/hw/microblaze_pic_cpu.c new file mode 100644 index 0000000..7c59382 --- /dev/null +++ b/hw/microblaze_pic_cpu.c @@ -0,0 +1,50 @@ +/* + * QEMU MicroBlaze CPU interrupt wrapper logic. + * + * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "hw.h" +#include "pc.h" + +#define D(x) + +void pic_info(Monitor *mon) +{} +void irq_info(Monitor *mon) +{} + +static void microblaze_pic_cpu_handler(void *opaque, int irq, int level) +{ + CPUState *env = (CPUState *)opaque; + int type = irq ? CPU_INTERRUPT_NMI : CPU_INTERRUPT_HARD; + + if (level) + cpu_interrupt(env, type); + else + cpu_reset_interrupt(env, type); +} + +qemu_irq *microblaze_pic_init_cpu(CPUState *env); +qemu_irq *microblaze_pic_init_cpu(CPUState *env) +{ + return qemu_allocate_irqs(microblaze_pic_cpu_handler, env, 2); +} -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 07/13] xilinx: Add interrupt controller. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 06/13] microblaze: Add CPU interrupt wrapper logic Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 08/13] xilinx: Add OPB timer Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/xilinx_intc.c | 167 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 167 insertions(+), 0 deletions(-) create mode 100644 hw/xilinx_intc.c diff --git a/hw/xilinx_intc.c b/hw/xilinx_intc.c new file mode 100644 index 0000000..8407ca2 --- /dev/null +++ b/hw/xilinx_intc.c @@ -0,0 +1,167 @@ +/* + * QEMU Xilinx OPB Interrupt Controller. + * + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "hw.h" + +#define D(x) + +#define R_ISR 0 +#define R_IPR 1 +#define R_IER 2 +#define R_IAR 3 +#define R_SIE 4 +#define R_CIE 5 +#define R_IVR 6 +#define R_MER 7 +#define R_MAX 8 + +struct xlx_pic +{ + SysBusDevice busdev; + qemu_irq parent_irq; + + /* Configuration reg chosen at synthesis-time. QEMU populates + the bits at board-setup. */ + uint32_t c_kind_of_intr; + + /* Runtime control registers. */ + uint32_t regs[R_MAX]; +}; + +static void update_irq(struct xlx_pic *p) +{ + uint32_t i; + /* Update the pending register. */ + p->regs[R_IPR] = p->regs[R_ISR] & p->regs[R_IER]; + + /* Update the vector register. */ + for (i = 0; i < 32; i++) { + if (p->regs[R_IPR] & (1 << i)) + break; + } + if (i == 32) + i = ~0; + + p->regs[R_IVR] = i; + if ((p->regs[R_MER] & 1) && p->regs[R_IPR]) { + qemu_irq_raise(p->parent_irq); + } else { + qemu_irq_lower(p->parent_irq); + } +} + +static uint32_t pic_readl (void *opaque, target_phys_addr_t addr) +{ + struct xlx_pic *p = opaque; + uint32_t r = 0; + + addr >>= 2; + switch (addr) + { + default: + if (addr < ARRAY_SIZE(p->regs)) + r = p->regs[addr]; + break; + + } + D(printf("%s %x=%x\n", __func__, addr * 4, r)); + return r; +} + +static void +pic_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct xlx_pic *p = opaque; + + addr >>= 2; + D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); + switch (addr) + { + case R_IAR: + p->regs[R_ISR] &= ~value; /* ACK. */ + break; + case R_SIE: + p->regs[R_IER] |= value; /* Atomic set ie. */ + break; + case R_CIE: + p->regs[R_IER] &= ~value; /* Atomic clear ie. */ + break; + default: + if (addr < ARRAY_SIZE(p->regs)) + p->regs[addr] = value; + break; + } + update_irq(p); +} + +static CPUReadMemoryFunc *pic_read[] = { + NULL, NULL, + &pic_readl, +}; + +static CPUWriteMemoryFunc *pic_write[] = { + NULL, NULL, + &pic_writel, +}; + +static void irq_handler(void *opaque, int irq, int level) +{ + struct xlx_pic *p = opaque; + + if (!(p->regs[R_MER] & 2)) { + qemu_irq_lower(p->parent_irq); + return; + } + + /* Update source flops. Don't clear unless level triggered. + Edge triggered interrupts only go away when explicitely acked to + the interrupt controller. */ + if (!(p->c_kind_of_intr & (1 << irq)) || level) { + p->regs[R_ISR] &= ~(1 << irq); + p->regs[R_ISR] |= (level << irq); + } + update_irq(p); +} + +static void xilinx_intc_init(SysBusDevice *dev) +{ + struct xlx_pic *p = FROM_SYSBUS(typeof (*p), dev); + int pic_regs; + + p->c_kind_of_intr = qdev_get_prop_int(&dev->qdev, "kind-of-intr", 0); + qdev_init_irq_sink(&dev->qdev, irq_handler, 32); + sysbus_init_irq(dev, &p->parent_irq); + + pic_regs = cpu_register_io_memory(0, pic_read, pic_write, p); + sysbus_init_mmio(dev, R_MAX * 4, pic_regs); +} + +static void xilinx_intc_register(void) +{ + sysbus_register_dev("xilinx,intc", sizeof (struct xlx_pic), + xilinx_intc_init); +} + +device_init(xilinx_intc_register) -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 08/13] xilinx: Add OPB timer. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 07/13] xilinx: Add interrupt controller Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 09/13] xilinx: Add uartlite emulation Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/xilinx_timer.c | 224 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 224 insertions(+), 0 deletions(-) create mode 100644 hw/xilinx_timer.c diff --git a/hw/xilinx_timer.c b/hw/xilinx_timer.c new file mode 100644 index 0000000..6902752 --- /dev/null +++ b/hw/xilinx_timer.c @@ -0,0 +1,224 @@ +/* + * QEMU model of the Xilinx timer block. + * + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "sysemu.h" +#include "qemu-timer.h" + +#define D(x) + +#define R_TCSR 0 +#define R_TLR 1 +#define R_TCR 2 +#define R_MAX 4 + +#define TCSR_MDT (1<<0) +#define TCSR_UDT (1<<1) +#define TCSR_GENT (1<<2) +#define TCSR_CAPT (1<<3) +#define TCSR_ARHT (1<<4) +#define TCSR_LOAD (1<<5) +#define TCSR_ENIT (1<<6) +#define TCSR_ENT (1<<7) +#define TCSR_TINT (1<<8) +#define TCSR_PWMA (1<<9) +#define TCSR_ENALL (1<<10) + +struct xlx_timer +{ + QEMUBH *bh; + ptimer_state *ptimer; + void *parent; + int nr; /* for debug. */ + + unsigned long timer_div; + + uint32_t regs[R_MAX]; +}; + +struct timerblock +{ + SysBusDevice busdev; + qemu_irq irq; + unsigned int nr_timers; + struct xlx_timer *timers; +}; + +static inline unsigned int timer_from_addr(target_phys_addr_t addr) +{ + /* Timers get a 4x32bit control reg area each. */ + return addr >> 2; +} + +static void timer_update_irq(struct timerblock *t) +{ + unsigned int i, irq = 0; + uint32_t csr; + + for (i = 0; i < t->nr_timers; i++) { + csr = t->timers[i].regs[R_TCSR]; + irq |= (csr & TCSR_TINT) && (csr & TCSR_ENIT); + } + + /* All timers within the same slave share a single IRQ line. */ + qemu_set_irq(t->irq, !!irq); +} + +static uint32_t timer_readl (void *opaque, target_phys_addr_t addr) +{ + struct timerblock *t = opaque; + struct xlx_timer *xt; + uint32_t r = 0; + unsigned int timer; + + addr >>= 2; + timer = timer_from_addr(addr); + xt = &t->timers[timer]; + /* Further decoding to address a specific timers reg. */ + addr &= 0x3; + switch (addr) + { + case R_TCR: + r = ptimer_get_count(xt->ptimer); + if (!(xt->regs[R_TCSR] & TCSR_UDT)) + r = ~0 - r; + D(qemu_log("xlx_timer t=%d read counter=%x udt=%d\n", + timer, r, xt->regs[R_TCSR] & TCSR_UDT)); + break; + default: + if (addr < ARRAY_SIZE(xt->regs)) + r = xt->regs[addr]; + break; + + } + D(printf("%s timer=%d %x=%x\n", __func__, timer, addr * 4, r)); + return r; +} + +static void timer_enable(struct xlx_timer *xt) +{ + uint64_t count; + + D(printf("%s timer=%d down=%d\n", __func__, + xt->nr, xt->regs[R_TCSR] & TCSR_UDT)); + + ptimer_stop(xt->ptimer); + + if (xt->regs[R_TCSR] & TCSR_UDT) + count = xt->regs[R_TLR]; + else + count = ~0 - xt->regs[R_TLR]; + ptimer_set_count(xt->ptimer, count); + ptimer_run(xt->ptimer, 1); +} + +static void +timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct timerblock *t = opaque; + struct xlx_timer *xt; + unsigned int timer; + + addr >>= 2; + timer = timer_from_addr(addr); + xt = &t->timers[timer]; + D(printf("%s addr=%x val=%x (timer=%d off=%d)\n", + __func__, addr * 4, value, timer, addr & 3)); + /* Further decoding to address a specific timers reg. */ + addr &= 3; + switch (addr) + { + case R_TCSR: + if (value & TCSR_TINT) + value &= ~TCSR_TINT; + + xt->regs[addr] = value; + if (value & TCSR_ENT) + timer_enable(xt); + break; + + default: + if (addr < ARRAY_SIZE(xt->regs)) + xt->regs[addr] = value; + break; + } + timer_update_irq(t); +} + +static CPUReadMemoryFunc *timer_read[] = { + NULL, NULL, + &timer_readl, +}; + +static CPUWriteMemoryFunc *timer_write[] = { + NULL, NULL, + &timer_writel, +}; + +static void timer_hit(void *opaque) +{ + struct xlx_timer *xt = opaque; + struct timerblock *t = xt->parent; + D(printf("%s %d\n", __func__, timer)); + xt->regs[R_TCSR] |= TCSR_TINT; + + if (xt->regs[R_TCSR] & TCSR_ARHT) + timer_enable(xt); + timer_update_irq(t); +} + +static void xilinx_timer_init(SysBusDevice *dev) +{ + struct timerblock *t = FROM_SYSBUS(typeof (*t), dev); + unsigned int i; + int timer_regs, freq_hz; + + /* All timers share a single irq line. */ + sysbus_init_irq(dev, &t->irq); + + /* Init all the ptimers. */ + freq_hz = qdev_get_prop_int(&dev->qdev, "frequency", 2); + t->nr_timers = qdev_get_prop_int(&dev->qdev, "nr-timers", 2); + t->timers = qemu_mallocz(sizeof t->timers[0] * t->nr_timers); + for (i = 0; i < t->nr_timers; i++) { + struct xlx_timer *xt = &t->timers[i]; + + xt->parent = t; + xt->nr = i; + xt->bh = qemu_bh_new(timer_hit, xt); + xt->ptimer = ptimer_init(xt->bh); + ptimer_set_freq(xt->ptimer, freq_hz); + } + + timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t); + sysbus_init_mmio(dev, R_MAX * 4 * t->nr_timers, timer_regs); +} + +static void xilinx_timer_register(void) +{ + sysbus_register_dev("xilinx,timer", sizeof (struct timerblock), + xilinx_timer_init); +} + +device_init(xilinx_timer_register) -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 09/13] xilinx: Add uartlite emulation. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 08/13] xilinx: Add OPB timer Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 10/13] xilinx: Add ethlite emulation Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/xilinx_uartlite.c | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 216 insertions(+), 0 deletions(-) create mode 100644 hw/xilinx_uartlite.c diff --git a/hw/xilinx_uartlite.c b/hw/xilinx_uartlite.c new file mode 100644 index 0000000..d78f568 --- /dev/null +++ b/hw/xilinx_uartlite.c @@ -0,0 +1,216 @@ +/* + * QEMU model of Xilinx uartlite. + * + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "qemu-char.h" + +#define DUART(x) + +#define R_RX 0 +#define R_TX 1 +#define R_STATUS 2 +#define R_CTRL 3 +#define R_MAX 4 + +#define STATUS_RXVALID 0x01 +#define STATUS_RXFULL 0x02 +#define STATUS_TXEMPTY 0x04 +#define STATUS_TXFULL 0x08 +#define STATUS_IE 0x10 +#define STATUS_OVERRUN 0x20 +#define STATUS_FRAME 0x40 +#define STATUS_PARITY 0x80 + +#define CONTROL_RST_TX 0x01 +#define CONTROL_RST_RX 0x02 +#define CONTROL_IE 0x10 + +struct xlx_uartlite +{ + SysBusDevice busdev; + CharDriverState *chr; + qemu_irq irq; + + uint8_t rx_fifo[8]; + unsigned int rx_fifo_pos; + unsigned int rx_fifo_len; + + uint32_t regs[R_MAX]; +}; + +static void uart_update_irq(struct xlx_uartlite *s) +{ + unsigned int irq; + + if (s->rx_fifo_len) + s->regs[R_STATUS] |= STATUS_IE; + + irq = (s->regs[R_STATUS] & STATUS_IE) && (s->regs[R_CTRL] & CONTROL_IE); + qemu_set_irq(s->irq, irq); +} + +static void uart_update_status(struct xlx_uartlite *s) +{ + uint32_t r; + + r = s->regs[R_STATUS]; + r &= ~7; + r |= 1 << 2; /* Tx fifo is always empty. We are fast :) */ + r |= (s->rx_fifo_len == sizeof (s->rx_fifo)) << 1; + r |= (!!s->rx_fifo_len); + s->regs[R_STATUS] = r; +} + +static uint32_t uart_readl (void *opaque, target_phys_addr_t addr) +{ + struct xlx_uartlite *s = opaque; + uint32_t r = 0; + addr >>= 2; + switch (addr) + { + case R_RX: + r = s->rx_fifo[(s->rx_fifo_pos - s->rx_fifo_len) & 7]; + if (s->rx_fifo_len) + s->rx_fifo_len--; + uart_update_status(s); + uart_update_irq(s); + break; + + default: + if (addr < ARRAY_SIZE(s->regs)) + r = s->regs[addr]; + DUART(qemu_log("%s addr=%x v=%x\n", __func__, addr, r)); + break; + } + return r; +} + +static void +uart_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct xlx_uartlite *s = opaque; + unsigned char ch = value; + + addr >>= 2; + switch (addr) + { + case R_STATUS: + printf("write to UART STATUS?\n"); + abort(); + break; + case R_CTRL: + if (value & CONTROL_RST_RX) { + s->rx_fifo_pos = 0; + s->rx_fifo_len = 0; + } + s->regs[addr] = value; + break; + case R_TX: + if (s->chr) + qemu_chr_write(s->chr, &ch, 1); + + s->regs[addr] = value; + + /* hax. */ + s->regs[R_STATUS] |= STATUS_IE; + break; + default: + DUART(printf("%s addr=%x v=%x\n", __func__, addr, value)); + if (addr < ARRAY_SIZE(s->regs)) + s->regs[addr] = value; + break; + } + uart_update_status(s); + uart_update_irq(s); +} + +static CPUReadMemoryFunc *uart_read[] = { + &uart_readl, + &uart_readl, + &uart_readl, +}; + +static CPUWriteMemoryFunc *uart_write[] = { + &uart_writel, + &uart_writel, + &uart_writel, +}; + +static void uart_rx(void *opaque, const uint8_t *buf, int size) +{ + struct xlx_uartlite *s = opaque; + + /* Got a byte. */ + if (s->rx_fifo_len >= 8) { + printf("WARNING: UART dropped char.\n"); + return; + } + s->rx_fifo[s->rx_fifo_pos] = *buf; + s->rx_fifo_pos++; + s->rx_fifo_pos &= 0x7; + s->rx_fifo_len++; + + uart_update_status(s); + uart_update_irq(s); +} + +static int uart_can_rx(void *opaque) +{ + struct xlx_uartlite *s = opaque; + int r; + + r = s->rx_fifo_len < sizeof(s->rx_fifo); + if (!r) + printf("cannot receive!\n"); + return r; +} + +static void uart_event(void *opaque, int event) +{ + +} + +static void xilinx_uartlite_init(SysBusDevice *dev) +{ + struct xlx_uartlite *s = FROM_SYSBUS(typeof (*s), dev); + int uart_regs; + + sysbus_init_irq(dev, &s->irq); + + uart_update_status(s); + uart_regs = cpu_register_io_memory(0, uart_read, uart_write, s); + sysbus_init_mmio(dev, R_MAX * 4, uart_regs); + + s->chr = qdev_init_chardev(&dev->qdev); + if (s->chr) + qemu_chr_add_handlers(s->chr, uart_can_rx, uart_rx, uart_event, s); +} + +static void xilinx_uart_register(void) +{ + sysbus_register_dev("xilinx,uartlite", sizeof (struct xlx_uartlite), + xilinx_uartlite_init); +} + +device_init(xilinx_uart_register) -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 10/13] xilinx: Add ethlite emulation. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 09/13] xilinx: Add uartlite emulation Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 11/13] microblaze: Add petalogix s3a1800dsp MMU linux ref-design Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/xilinx_ethlite.c | 240 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 240 insertions(+), 0 deletions(-) create mode 100644 hw/xilinx_ethlite.c diff --git a/hw/xilinx_ethlite.c b/hw/xilinx_ethlite.c new file mode 100644 index 0000000..0bb712d --- /dev/null +++ b/hw/xilinx_ethlite.c @@ -0,0 +1,240 @@ +/* + * QEMU model of the Xilinx Ethernet Lite MAC. + * + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "hw.h" +#include "net.h" + +#define D(x) +#define R_TX_BUF0 0 +#define R_TX_LEN0 (0x07f4 / 4) +#define R_TX_GIE0 (0x07f8 / 4) +#define R_TX_CTRL0 (0x07fc / 4) +#define R_TX_BUF1 (0x0800 / 4) +#define R_TX_LEN1 (0x0ff4 / 4) +#define R_TX_CTRL1 (0x0ffc / 4) + +#define R_RX_BUF0 (0x1000 / 4) +#define R_RX_CTRL0 (0x17fc / 4) +#define R_RX_BUF1 (0x1800 / 4) +#define R_RX_CTRL1 (0x1ffc / 4) +#define R_MAX (0x2000 / 4) + +#define GIE_GIE 0x80000000 + +#define CTRL_I 0x8 +#define CTRL_P 0x2 +#define CTRL_S 0x1 + +struct xlx_ethlite +{ + SysBusDevice busdev; + qemu_irq irq; + VLANClientState *vc; + + unsigned int c_tx_pingpong; + unsigned int c_rx_pingpong; + unsigned int txbuf; + unsigned int rxbuf; + + uint8_t macaddr[6]; + uint32_t regs[R_MAX]; +}; + +static inline void eth_pulse_irq(struct xlx_ethlite *s) +{ + /* Only the first gie reg is active. */ + if (s->regs[R_TX_GIE0] & GIE_GIE) { + qemu_irq_pulse(s->irq); + } +} + +static uint32_t eth_readl (void *opaque, target_phys_addr_t addr) +{ + struct xlx_ethlite *s = opaque; + uint32_t r = 0; + + addr >>= 2; + + if (addr >= ARRAY_SIZE(s->regs)) { + qemu_log("%s addr %x out of bounds\n", __func__, addr * 4); + return 0; + } + + switch (addr) + { + case R_TX_GIE0: + case R_TX_LEN0: + case R_TX_LEN1: + case R_TX_CTRL1: + case R_TX_CTRL0: + case R_RX_CTRL1: + case R_RX_CTRL0: + r = s->regs[addr]; + D(qemu_log("%s %x=%x\n", __func__, addr * 4, r)); + break; + /* Remember this is a BE device. */ + default: + r = s->regs[addr]; + break; + } + return r; +} + +static void +eth_writel (void *opaque, target_phys_addr_t addr, uint32_t value) +{ + struct xlx_ethlite *s = opaque; + unsigned int base = 0; + + addr >>= 2; + if (addr >= ARRAY_SIZE(s->regs)) { + qemu_log("%s addr %x out of bounds\n", __func__, addr * 4); + return; + } + + switch (addr) + { + case R_TX_CTRL0: + case R_TX_CTRL1: + if (addr == R_TX_CTRL1) + base = 0x800 / 4; + + D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); + if ((value & (CTRL_P | CTRL_S)) == CTRL_S) { + qemu_send_packet(s->vc, + (void *) &s->regs[base], + s->regs[base + R_TX_LEN0]); + D(qemu_log("eth_tx %d\n", s->regs[base + R_TX_LEN0])); + if (s->regs[base + R_TX_CTRL0] & CTRL_I) + eth_pulse_irq(s); + } else if ((value & (CTRL_P | CTRL_S)) == (CTRL_P | CTRL_S)) { + memcpy(&s->macaddr[0], &s->regs[base], 6); + if (s->regs[base + R_TX_CTRL0] & CTRL_I) + eth_pulse_irq(s); + } + + /* We are fast and get ready pretty much immediately so + we actually never flip the S nor P bits to one. */ + s->regs[addr] = value & ~(CTRL_P | CTRL_S); + break; + + /* Keep these native. */ + case R_TX_LEN0: + case R_TX_LEN1: + case R_TX_GIE0: + case R_RX_CTRL0: + case R_RX_CTRL1: + D(qemu_log("%s addr=%x val=%x\n", __func__, addr * 4, value)); + s->regs[addr] = value; + break; + + /* Packet data, make sure it stays BE. */ + default: + s->regs[addr] = cpu_to_be32(value); + break; + } +} + +static CPUReadMemoryFunc *eth_read[] = { + NULL, NULL, ð_readl, +}; + +static CPUWriteMemoryFunc *eth_write[] = { + NULL, NULL, ð_writel, +}; + +static int eth_can_rx(void *opaque) +{ + struct xlx_ethlite *s = opaque; + int r; + r = !(s->regs[R_RX_CTRL0] & CTRL_S); + qemu_log("%s %d\n", __func__, r); + return r; +} + +static void eth_rx(void *opaque, const uint8_t *buf, int size) +{ + struct xlx_ethlite *s = opaque; + unsigned int rxbase = s->rxbuf * (0x800 / 4); + int i; + + /* DA filter. */ + if (!(buf[0] & 0x80) && memcmp(&s->macaddr[0], buf, 6)) + return; + + if (s->regs[rxbase + R_RX_CTRL0] & CTRL_S) { + D(qemu_log("ethlite lost packet %x\n", s->regs[R_RX_CTRL0])); + return; + } + + D(qemu_log("%s %d rxbase=%x\n", __func__, size, rxbase)); + memcpy(&s->regs[rxbase + R_RX_BUF0], buf, size); + + /* Bring it into host endianess. */ + for (i = 0; i < ((size + 3) / 4); i++) { + uint32_t d = s->regs[rxbase + R_RX_BUF0 + i]; + s->regs[rxbase + R_RX_BUF0 + i] = be32_to_cpu(d); + } + + s->regs[rxbase + R_RX_CTRL0] |= CTRL_S; + if (s->regs[rxbase + R_RX_CTRL0] & CTRL_I) + eth_pulse_irq(s); + + /* If c_rx_pingpong was set flip buffers. */ + s->rxbuf ^= s->c_rx_pingpong; + return; +} + +static void eth_cleanup(VLANClientState *vc) +{ + struct xlx_ethlite *s = vc->opaque; + qemu_free(s); +} + +static void xilinx_ethlite_init(SysBusDevice *dev) +{ + struct xlx_ethlite *s = FROM_SYSBUS(typeof (*s), dev); + int regs; + + sysbus_init_irq(dev, &s->irq); + s->c_tx_pingpong = qdev_get_prop_int(&dev->qdev, "txpingpong", 1); + s->c_rx_pingpong = qdev_get_prop_int(&dev->qdev, "rxpingpong", 1); + s->rxbuf = 0; + + regs = cpu_register_io_memory(0, eth_read, eth_write, s); + sysbus_init_mmio(dev, R_MAX * 4, regs); + + qdev_get_macaddr(&dev->qdev, s->macaddr); + s->vc = qdev_get_vlan_client(&dev->qdev, + eth_rx, eth_can_rx, eth_cleanup, s); +} + +static void xilinx_ethlite_register(void) +{ + sysbus_register_dev("xilinx,ethlite", sizeof (struct xlx_ethlite), + xilinx_ethlite_init); +} + +device_init(xilinx_ethlite_register) -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 11/13] microblaze: Add petalogix s3a1800dsp MMU linux ref-design. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 10/13] xilinx: Add ethlite emulation Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 12/13] microblaze: Add GDB stub support Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias This setup was designed by petalogix and is supported by upstream linux. The design targets a xilinx spartan-3a-1800 dsp board with MMU. Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- hw/boards.h | 3 + hw/petalogix_s3adsp1800_mmu.c | 176 +++++++++++++++++++++++++++++++++++++++++ hw/xilinx.h | 50 ++++++++++++ target-microblaze/machine.c | 16 ++++ 4 files changed, 245 insertions(+), 0 deletions(-) create mode 100644 hw/petalogix_s3adsp1800_mmu.c create mode 100644 hw/xilinx.h create mode 100644 target-microblaze/machine.c diff --git a/hw/boards.h b/hw/boards.h index 9a99a85..7c56354 100644 --- a/hw/boards.h +++ b/hw/boards.h @@ -128,6 +128,9 @@ extern QEMUMachine musicpal_machine; /* tosa.c */ extern QEMUMachine tosapda_machine; +/* microblaze petalogix-s3a1800.c */ +extern QEMUMachine petalogix_s3adsp1800_machine; + /* syborg.c */ extern QEMUMachine syborg_machine; diff --git a/hw/petalogix_s3adsp1800_mmu.c b/hw/petalogix_s3adsp1800_mmu.c new file mode 100644 index 0000000..a7ccf47 --- /dev/null +++ b/hw/petalogix_s3adsp1800_mmu.c @@ -0,0 +1,176 @@ +/* + * Model of Petalogix linux reference design targeting Xilinx Spartan 3ADSP-1800 + * boards. + * + * Copyright (c) 2009 Edgar E. Iglesias. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "sysbus.h" +#include "hw.h" +#include "net.h" +#include "flash.h" +#include "sysemu.h" +#include "devices.h" +#include "boards.h" +#include "device_tree.h" +#include "xilinx.h" + +#define LMB_BRAM_SIZE (128 * 1024) +#define FLASH_SIZE (16 * 1024 * 1024) + +static uint32_t bootstrap_pc; + +static void main_cpu_reset(void *opaque) +{ + CPUState *env = opaque; + cpu_reset(env); + env->sregs[SR_PC] = bootstrap_pc; +} + +#define BINARY_DEVICE_TREE_FILE "petalogix-s3adsp1800.dtb" +static int petalogix_load_device_tree(target_phys_addr_t addr, + uint32_t ramsize, + target_phys_addr_t initrd_base, + target_phys_addr_t initrd_size, + const char *kernel_cmdline) +{ + void *fdt; + char *path = NULL; + int fdt_size; + int pathlen; + int r; + + /* Try the local "mb.dtb" override. */ + fdt = load_device_tree("mb.dtb", &fdt_size); + if (!fdt) { + pathlen = snprintf(NULL, 0, "%s/%s", + bios_dir, BINARY_DEVICE_TREE_FILE) + 1; + path = qemu_malloc(pathlen); + snprintf(path, pathlen, "%s/%s", bios_dir, BINARY_DEVICE_TREE_FILE); + fdt = load_device_tree(BINARY_DEVICE_TREE_FILE, &fdt_size); + free(path); + if (!fdt) + return 0; + } + + r = qemu_devtree_setprop_string(fdt, "/chosen", "bootargs", kernel_cmdline); + if (r < 0) + fprintf(stderr, "couldn't set /chosen/bootargs\n"); + printf("write fdt to addr=%x fdtsize=%d\n", addr, fdt_size); + cpu_physical_memory_write (addr, (void *)fdt, fdt_size); + return fdt_size; +} + +static void +petalogix_s3adsp1800_init(ram_addr_t ram_size, + const char *boot_device, + const char *kernel_filename, + const char *kernel_cmdline, + const char *initrd_filename, const char *cpu_model) +{ + DeviceState *dev; + CPUState *env; + int kernel_size; + int i; + target_phys_addr_t ddr_base = 0x90000000; + ram_addr_t phys_lmb_bram; + ram_addr_t phys_ram; + ram_addr_t phys_flash; + qemu_irq irq[32], *cpu_irq; + + /* init CPUs */ + if (cpu_model == NULL) { + cpu_model = "microblaze"; + } + env = cpu_init(cpu_model); + + env->pvr.regs[10] = 0x0c000000; /* spartan 3a dsp family. */ + qemu_register_reset(main_cpu_reset, env); + + /* Attach emulated BRAM through the LMB. */ + phys_lmb_bram = qemu_ram_alloc(LMB_BRAM_SIZE); + cpu_register_physical_memory(0x00000000, LMB_BRAM_SIZE, + phys_lmb_bram | IO_MEM_RAM); + + phys_ram = qemu_ram_alloc(ram_size); + cpu_register_physical_memory(ddr_base, ram_size, phys_ram | IO_MEM_RAM); + + phys_flash = qemu_ram_alloc(FLASH_SIZE); + i = drive_get_index(IF_PFLASH, 0, 0); + pflash_cfi02_register(0xa0000000, phys_flash, + i != -1 ? drives_table[i].bdrv : NULL, (64 * 1024), + FLASH_SIZE >> 16, + 1, 1, 0x0000, 0x0000, 0x0000, 0x0000, + 0x555, 0x2aa); + + cpu_irq = microblaze_pic_init_cpu(env); + dev = xilinx_intc_create(0x81800000, cpu_irq[0], 2); + for (i = 0; i < 32; i++) { + irq[i] = qdev_get_irq_sink(dev, i); + } + + sysbus_create_simple("xilinx,uartlite", 0x84000000, irq[3]); + /* 2 timers at irq 2 @ 62 Mhz. */ + xilinx_timer_create(0x83c00000, irq[0], 2, 62 * 1000000); + xilinx_ethlite_create(&nd_table[0], 0x81000000, irq[1], 0, 0); + + if (kernel_filename) { + uint64_t entry, low, high; + int kcmdline_len; + uint32_t base32; + + /* Boots a kernel elf binary. */ + kernel_size = load_elf(kernel_filename, 0, + &entry, &low, &high); + base32 = entry; + if (base32 == 0xc0000000) { + kernel_size = load_elf(kernel_filename, -0x30000000LL, + &entry, NULL, NULL); + } + /* Always boot into physical ram. */ + bootstrap_pc = ddr_base + (entry & 0x0fffffff); + if (kernel_size < 0) { + /* If we failed loading ELF's try a raw image. */ + kernel_size = load_image_targphys(kernel_filename, ddr_base, + ram_size); + bootstrap_pc = ddr_base; + } + + env->regs[5] = ddr_base + kernel_size; + if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) { + pstrcpy_targphys(env->regs[5], 256, kernel_cmdline); + } + env->regs[6] = 0; + /* Provide a device-tree. */ + env->regs[7] = ddr_base + kernel_size + 256; + petalogix_load_device_tree(env->regs[7], ram_size, + env->regs[6], 0, + kernel_cmdline); + } + + env->sregs[SR_PC] = bootstrap_pc; +} + +QEMUMachine petalogix_s3adsp1800_machine = { + .name = "petalogix-s3adsp1800", + .desc = "Petalogix linux refdesign for xilinx Spartan 3ADSP1800", + .init = petalogix_s3adsp1800_init, +}; diff --git a/hw/xilinx.h b/hw/xilinx.h new file mode 100644 index 0000000..9707a0e --- /dev/null +++ b/hw/xilinx.h @@ -0,0 +1,50 @@ + +/* OPB Interrupt Controller. */ +qemu_irq *microblaze_pic_init_cpu(CPUState *env); + +static inline DeviceState * +xilinx_intc_create(target_phys_addr_t base, qemu_irq irq, int kind_of_intr) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "xilinx,intc"); + qdev_set_prop_int(dev, "kind-of-intr", kind_of_intr); + qdev_init(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + return dev; +} + +/* OPB Timer/Counter. */ +static inline DeviceState * +xilinx_timer_create(target_phys_addr_t base, qemu_irq irq, int nr, int freq) +{ + DeviceState *dev; + + dev = qdev_create(NULL, "xilinx,timer"); + qdev_set_prop_int(dev, "nr-timers", nr); + qdev_set_prop_int(dev, "frequency", freq); + qdev_init(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + return dev; +} + +/* XPS Ethernet Lite MAC. */ +static inline DeviceState * +xilinx_ethlite_create(NICInfo *nd, target_phys_addr_t base, qemu_irq irq, + int txpingpong, int rxpingpong) +{ + DeviceState *dev; + + qemu_check_nic_model(nd, "xilinx-ethlite"); + + dev = qdev_create(NULL, "xilinx,ethlite"); + qdev_set_netdev(dev, nd); + qdev_set_prop_int(dev, "txpingpong", txpingpong); + qdev_set_prop_int(dev, "rxpingpong", rxpingpong); + qdev_init(dev); + sysbus_mmio_map(sysbus_from_qdev(dev), 0, base); + sysbus_connect_irq(sysbus_from_qdev(dev), 0, irq); + return dev; +} diff --git a/target-microblaze/machine.c b/target-microblaze/machine.c new file mode 100644 index 0000000..144f983 --- /dev/null +++ b/target-microblaze/machine.c @@ -0,0 +1,16 @@ +#include "hw/hw.h" +#include "hw/boards.h" + +void register_machines(void) +{ + qemu_register_machine(&petalogix_s3adsp1800_machine); +} + +void cpu_save(QEMUFile *f, void *opaque) +{ +} + +int cpu_load(QEMUFile *f, void *opaque, int version_id) +{ + return 0; +} -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 12/13] microblaze: Add GDB stub support. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 11/13] microblaze: Add petalogix s3a1800dsp MMU linux ref-design Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 13/13] microblaze: Hook into the build-system Edgar E. Iglesias 0 siblings, 1 reply; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- gdbstub.c | 32 ++++++++++++++++++++++++++++++++ 1 files changed, 32 insertions(+), 0 deletions(-) diff --git a/gdbstub.c b/gdbstub.c index 3c34741..7b32fab 100644 --- a/gdbstub.c +++ b/gdbstub.c @@ -1156,6 +1156,36 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) return 4; } +#elif defined (TARGET_MICROBLAZE) + +#define NUM_CORE_REGS (32 + 5) + +static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n) +{ + if (n < 32) { + GET_REG32(env->regs[n]); + } else { + GET_REG32(env->sregs[n - 32]); + } + return 0; +} + +static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n) +{ + uint32_t tmp; + + if (n > NUM_CORE_REGS) + return 0; + + tmp = ldl_p(mem_buf); + + if (n < 32) { + env->regs[n] = tmp; + } else { + env->sregs[n - 32] = tmp; + } + return 4; +} #elif defined (TARGET_CRIS) #define NUM_CORE_REGS 49 @@ -1528,6 +1558,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc) s->c_cpu->pc = pc; #elif defined (TARGET_MIPS) s->c_cpu->active_tc.PC = pc; +#elif defined (TARGET_MICROBLAZE) + s->c_cpu->sregs[SR_PC] = pc; #elif defined (TARGET_CRIS) s->c_cpu->pc = pc; #elif defined (TARGET_ALPHA) -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [Qemu-devel] [PATCH 13/13] microblaze: Hook into the build-system. 2009-05-20 20:56 ` [Qemu-devel] [PATCH 12/13] microblaze: Add GDB stub support Edgar E. Iglesias @ 2009-05-20 20:56 ` Edgar E. Iglesias 0 siblings, 0 replies; 13+ messages in thread From: Edgar E. Iglesias @ 2009-05-20 20:56 UTC (permalink / raw) To: qemu-devel; +Cc: Edgar E. Iglesias Signed-off-by: Edgar E. Iglesias <edgar.iglesias@gmail.com> --- Makefile.target | 21 +++++++++++++++++++++ configure | 21 ++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletions(-) diff --git a/Makefile.target b/Makefile.target index 60dcf30..85f6883 100644 --- a/Makefile.target +++ b/Makefile.target @@ -183,6 +183,12 @@ endif ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc) LIBOBJS+=ppc-dis.o endif +ifeq ($(findstring microblaze, $(TARGET_BASE_ARCH) $(ARCH)),microblaze) +LIBOBJS+=microblaze-dis.o +ifndef CONFIG_USER_ONLY +LIBOBJS+= mmu.o +endif +endif ifeq ($(findstring mips, $(TARGET_BASE_ARCH) $(ARCH)),mips) LIBOBJS+=mips-dis.o endif @@ -610,6 +616,21 @@ OBJS+= pflash_cfi01.o OBJS+= vmware_vga.o CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE endif +ifeq ($(TARGET_BASE_ARCH), microblaze) +OBJS+= petalogix_s3adsp1800_mmu.o + +OBJS+= microblaze_pic_cpu.o +OBJS+= xilinx_intc.o +OBJS+= xilinx_timer.o +OBJS+= xilinx_uartlite.o +OBJS+= xilinx_ethlite.o + +OBJS+= pflash_cfi02.o +ifdef FDT_LIBS +OBJS+= device_tree.o +LIBS+= $(FDT_LIBS) +endif +endif ifeq ($(TARGET_BASE_ARCH), cris) # Boards OBJS+= cris_pic_cpu.o etraxfs.o axis_dev88.o diff --git a/configure b/configure index 8fdbc1c..0a372c2 100755 --- a/configure +++ b/configure @@ -127,6 +127,9 @@ case "$cpu" in m68k) cpu="m68k" ;; + microblaze) + cpu="microblaze" + ;; mips) cpu="mips" ;; @@ -678,6 +681,7 @@ x86_64-softmmu \ arm-softmmu \ cris-softmmu \ m68k-softmmu \ +microblaze-softmmu \ mips-softmmu \ mipsel-softmmu \ mips64-softmmu \ @@ -700,6 +704,7 @@ arm-linux-user \ armeb-linux-user \ cris-linux-user \ m68k-linux-user \ +microblaze-linux-user \ mips-linux-user \ mipsel-linux-user \ ppc-linux-user \ @@ -1429,6 +1434,10 @@ case "$cpu" in echo "ARCH=m68k" >> $config_mak echo "#define HOST_M68K 1" >> $config_h ;; + microblaze) + echo "ARCH=microblaze" >> $config_mak + echo "#define HOST_MICROBLAZE 1" >> $config_h + ;; mips) echo "ARCH=mips" >> $config_mak echo "#define HOST_MIPS 1" >> $config_h @@ -1734,6 +1743,7 @@ target_cpu=`echo $target | cut -d '-' -f 1` target_bigendian="no" [ "$target_cpu" = "armeb" ] && target_bigendian=yes [ "$target_cpu" = "m68k" ] && target_bigendian=yes +[ "$target_cpu" = "microblaze" ] && target_bigendian=yes [ "$target_cpu" = "mips" ] && target_bigendian=yes [ "$target_cpu" = "mipsn32" ] && target_bigendian=yes [ "$target_cpu" = "mips64" ] && target_bigendian=yes @@ -1899,7 +1909,15 @@ case "$target_cpu" in gdb_xml_files="cf-core.xml cf-fp.xml" target_phys_bits=32 ;; - mips|mipsel) + microblaze) + echo "TARGET_ARCH=microblaze" >> $config_mak + echo "#define TARGET_ARCH \"microblaze\"" >> $config_h + echo "#define TARGET_MICROBLAZE 1" >> $config_h + bflt="yes" + target_nptl="yes" + target_phys_bits=32 + ;; + mips|mipsel) echo "TARGET_ARCH=mips" >> $config_mak echo "#define TARGET_ARCH \"mips\"" >> $config_h echo "#define TARGET_MIPS 1" >> $config_h @@ -2036,6 +2054,7 @@ echo "TARGET_XML_FILES=$list" >> $config_mak if test "$target_cpu" = "arm" \ -o "$target_cpu" = "armeb" \ -o "$target_cpu" = "m68k" \ + -o "$target_cpu" = "microblaze" \ -o "$target_cpu" = "mips" \ -o "$target_cpu" = "mipsel" \ -o "$target_cpu" = "mipsn32" \ -- 1.6.0.6 ^ permalink raw reply related [flat|nested] 13+ messages in thread
end of thread, other threads:[~2009-05-20 20:57 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-05-20 20:56 [Qemu-devel] [PATCH 01/13] microblaze: Add translation routines Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 02/13] microblaze: Add syscall, signal and termbits defs for linux-user Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 03/13] microblaze: linux-user support Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 04/13] microblaze: Add disassembler Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 05/13] microblaze: Add MMU emulation Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 06/13] microblaze: Add CPU interrupt wrapper logic Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 07/13] xilinx: Add interrupt controller Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 08/13] xilinx: Add OPB timer Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 09/13] xilinx: Add uartlite emulation Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 10/13] xilinx: Add ethlite emulation Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 11/13] microblaze: Add petalogix s3a1800dsp MMU linux ref-design Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 12/13] microblaze: Add GDB stub support Edgar E. Iglesias 2009-05-20 20:56 ` [Qemu-devel] [PATCH 13/13] microblaze: Hook into the build-system Edgar E. Iglesias
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).