All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH 00/17] LatticeMico32 target
@ 2011-01-31  0:30 Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 01/17] LatticeMico32 target support Michael Walle
                   ` (17 more replies)
  0 siblings, 18 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Alexander Graf

This patchset adds support for the LatticeMico32 softcore processor by
Lattice Semiconductor.

This is the first part of a larger patchset. It adds target support and two
simple BSPs. The second part will add support for the milkymist hardware
platform.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 01/17] LatticeMico32 target support
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 02/17] lm32: translation routines Michael Walle
                   ` (16 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for the LatticeMico32 softcore processor by Lattice
Semiconductor.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target    |    5 +
 arch_init.c        |    2 +
 arch_init.h        |   13 ++--
 cpu-exec.c         |   13 +++-
 elf.h              |    1 +
 poison.h           |    1 +
 target-lm32/cpu.h  |  244 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 target-lm32/exec.h |   50 +++++++++++
 8 files changed, 322 insertions(+), 7 deletions(-)
 create mode 100644 target-lm32/cpu.h
 create mode 100644 target-lm32/exec.h

diff --git a/Makefile.target b/Makefile.target
index cd2abde..c9a61a0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -247,6 +247,11 @@ obj-ppc-y += xilinx_timer.o
 obj-ppc-y += xilinx_uartlite.o
 obj-ppc-y += xilinx_ethlite.o
 
+# LM32 peripherals
+obj-lm32-y += lm32_pic.o
+obj-lm32-y += lm32_pic_cpu.o
+obj-lm32-y += lm32_juart.o
+
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
 obj-mips-y += vga.o i8259.o
diff --git a/arch_init.c b/arch_init.c
index e32e289..15a5c60 100644
--- a/arch_init.c
+++ b/arch_init.c
@@ -64,6 +64,8 @@ const char arch_config_name[] = CONFIG_QEMU_CONFDIR "/target-" TARGET_ARCH ".con
 #define QEMU_ARCH QEMU_ARCH_I386
 #elif defined(TARGET_M68K)
 #define QEMU_ARCH QEMU_ARCH_M68K
+#elif defined(TARGET_LM32)
+#define QEMU_ARCH QEMU_ARCH_LM32
 #elif defined(TARGET_MICROBLAZE)
 #define QEMU_ARCH QEMU_ARCH_MICROBLAZE
 #elif defined(TARGET_MIPS)
diff --git a/arch_init.h b/arch_init.h
index 682890c..88fefd1 100644
--- a/arch_init.h
+++ b/arch_init.h
@@ -10,12 +10,13 @@ enum {
     QEMU_ARCH_CRIS = 4,
     QEMU_ARCH_I386 = 8,
     QEMU_ARCH_M68K = 16,
-    QEMU_ARCH_MICROBLAZE = 32,
-    QEMU_ARCH_MIPS = 64,
-    QEMU_ARCH_PPC = 128,
-    QEMU_ARCH_S390X = 256,
-    QEMU_ARCH_SH4 = 512,
-    QEMU_ARCH_SPARC = 1024,
+    QEMU_ARCH_LM32 = 32,
+    QEMU_ARCH_MICROBLAZE = 64,
+    QEMU_ARCH_MIPS = 128,
+    QEMU_ARCH_PPC = 256,
+    QEMU_ARCH_S390X = 512,
+    QEMU_ARCH_SH4 = 1024,
+    QEMU_ARCH_SPARC = 2048,
 };
 
 extern const uint32_t arch_type;
diff --git a/cpu-exec.c b/cpu-exec.c
index 8c9fb8b..b20465a 100644
--- a/cpu-exec.c
+++ b/cpu-exec.c
@@ -263,6 +263,7 @@ int cpu_exec(CPUState *env1)
 #elif defined(TARGET_ALPHA)
 #elif defined(TARGET_ARM)
 #elif defined(TARGET_PPC)
+#elif defined(TARGET_LM32)
 #elif defined(TARGET_MICROBLAZE)
 #elif defined(TARGET_MIPS)
 #elif defined(TARGET_SH4)
@@ -318,6 +319,8 @@ int cpu_exec(CPUState *env1)
                     env->old_exception = -1;
 #elif defined(TARGET_PPC)
                     do_interrupt(env);
+#elif defined(TARGET_LM32)
+                    do_interrupt(env);
 #elif defined(TARGET_MICROBLAZE)
                     do_interrupt(env);
 #elif defined(TARGET_MIPS)
@@ -363,7 +366,7 @@ int cpu_exec(CPUState *env1)
                     }
 #if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_MIPS) || \
     defined(TARGET_PPC) || defined(TARGET_ALPHA) || defined(TARGET_CRIS) || \
-    defined(TARGET_MICROBLAZE)
+    defined(TARGET_MICROBLAZE) || defined(TARGET_LM32)
                     if (interrupt_request & CPU_INTERRUPT_HALT) {
                         env->interrupt_request &= ~CPU_INTERRUPT_HALT;
                         env->halted = 1;
@@ -443,6 +446,13 @@ int cpu_exec(CPUState *env1)
                             env->interrupt_request &= ~CPU_INTERRUPT_HARD;
                         next_tb = 0;
                     }
+#elif defined(TARGET_LM32)
+                    if ((interrupt_request & CPU_INTERRUPT_HARD)
+                        && (env->ie & IE_IE)) {
+                        env->exception_index = EXCP_IRQ;
+                        do_interrupt(env);
+                        next_tb = 0;
+                    }
 #elif defined(TARGET_MICROBLAZE)
                     if ((interrupt_request & CPU_INTERRUPT_HARD)
                         && (env->sregs[SR_MSR] & MSR_IE)
@@ -655,6 +665,7 @@ int cpu_exec(CPUState *env1)
     /* XXX: Save/restore host fpu exception state?.  */
 #elif defined(TARGET_SPARC)
 #elif defined(TARGET_PPC)
+#elif defined(TARGET_LM32)
 #elif defined(TARGET_M68K)
     cpu_m68k_flush_flags(env, env->cc_op);
     env->cc_op = CC_OP_FLAGS;
diff --git a/elf.h b/elf.h
index 7067c90..2361649 100644
--- a/elf.h
+++ b/elf.h
@@ -104,6 +104,7 @@ typedef int64_t  Elf64_Sxword;
 
 #define EM_H8_300H      47      /* Hitachi H8/300H */
 #define EM_H8S          48      /* Hitachi H8S     */
+#define EM_LATTICEMICO32 138    /* LatticeMico32 */
 
 /*
  * This is an interim value that we will use until the committee comes
diff --git a/poison.h b/poison.h
index d7db7f4..93c75fa 100644
--- a/poison.h
+++ b/poison.h
@@ -10,6 +10,7 @@
 #pragma GCC poison TARGET_ALPHA
 #pragma GCC poison TARGET_ARM
 #pragma GCC poison TARGET_CRIS
+#pragma GCC poison TARGET_LM32
 #pragma GCC poison TARGET_M68K
 #pragma GCC poison TARGET_MIPS
 #pragma GCC poison TARGET_MIPS64
diff --git a/target-lm32/cpu.h b/target-lm32/cpu.h
new file mode 100644
index 0000000..575dee9
--- /dev/null
+++ b/target-lm32/cpu.h
@@ -0,0 +1,244 @@
+/*
+ *  LatticeMico32 virtual CPU header.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef CPU_LM32_H
+#define CPU_LM32_H
+
+#define TARGET_LONG_BITS 32
+
+#define CPUState struct CPULM32State
+
+#include "qemu-common.h"
+#include "cpu-defs.h"
+struct CPULM32State;
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE EM_LATTICEMICO32
+
+#define NB_MMU_MODES 1
+#define TARGET_PAGE_BITS 12
+static inline int cpu_mmu_index(CPUState *env)
+{
+    return 0;
+}
+
+#define TARGET_PHYS_ADDR_SPACE_BITS 32
+#define TARGET_VIRT_ADDR_SPACE_BITS 32
+
+/* Exceptions indices */
+enum {
+    EXCP_RESET = 0,
+    EXCP_BREAKPOINT,
+    EXCP_INSN_BUS_ERROR,
+    EXCP_WATCHPOINT,
+    EXCP_DATA_BUS_ERROR,
+    EXCP_DIVIDE_BY_ZERO,
+    EXCP_IRQ,
+    EXCP_SYSTEMCALL
+};
+
+/* Registers */
+enum {
+    R_R0 = 0, R_R1, R_R2, R_R3, R_R4, R_R5, R_R6, R_R7, R_R8, R_R9, R_R10,
+    R_R11, R_R12, R_R13, R_R14, R_R15, R_R16, R_R17, R_R18, R_R19, R_R20,
+    R_R21, R_R22, R_R23, R_R24, R_R25, R_R26, R_R27, R_R28, R_R29, R_R30,
+    R_R31
+};
+
+/* Register aliases */
+enum {
+    R_GP = R_R26,
+    R_FP = R_R27,
+    R_SP = R_R28,
+    R_RA = R_R29,
+    R_EA = R_R30,
+    R_BA = R_R31
+};
+
+/* IE flags */
+enum {
+    IE_IE  = (1<<0),
+    IE_EIE = (1<<1),
+    IE_BIE = (1<<2),
+};
+
+/* DC flags */
+enum {
+    DC_SS  = (1<<0),
+    DC_RE  = (1<<1),
+    DC_C0  = (1<<2),
+    DC_C1  = (1<<3),
+    DC_C2  = (1<<4),
+    DC_C3  = (1<<5),
+};
+
+/* CFG mask */
+enum {
+    CFG_M         = (1<<0),
+    CFG_D         = (1<<1),
+    CFG_S         = (1<<2),
+    CFG_U         = (1<<3),
+    CFG_X         = (1<<4),
+    CFG_CC        = (1<<5),
+    CFG_IC        = (1<<6),
+    CFG_DC        = (1<<7),
+    CFG_G         = (1<<8),
+    CFG_H         = (1<<9),
+    CFG_R         = (1<<10),
+    CFG_J         = (1<<11),
+    CFG_INT_SHIFT = 12,
+    CFG_BP_SHIFT  = 18,
+    CFG_WP_SHIFT  = 22,
+    CFG_REV_SHIFT = 26,
+};
+
+/* CSRs */
+enum {
+    CSR_IE   = 0x00,
+    CSR_IM   = 0x01,
+    CSR_IP   = 0x02,
+    CSR_ICC  = 0x03,
+    CSR_DCC  = 0x04,
+    CSR_CC   = 0x05,
+    CSR_CFG  = 0x06,
+    CSR_EBA  = 0x07,
+    CSR_DC   = 0x08,
+    CSR_DEBA = 0x09,
+    CSR_JTX  = 0x0e,
+    CSR_JRX  = 0x0f,
+    CSR_BP0  = 0x10,
+    CSR_BP1  = 0x11,
+    CSR_BP2  = 0x12,
+    CSR_BP3  = 0x13,
+    CSR_WP0  = 0x18,
+    CSR_WP1  = 0x19,
+    CSR_WP2  = 0x1a,
+    CSR_WP3  = 0x1b,
+};
+
+enum {
+    LM32_FEATURE_MULTIPLY     =  1,
+    LM32_FEATURE_DIVIDE       =  2,
+    LM32_FEATURE_SHIFT        =  4,
+    LM32_FEATURE_SIGN_EXTEND  =  8,
+    LM32_FEATURE_I_CACHE      = 16,
+    LM32_FEATURE_D_CACHE      = 32,
+    LM32_FEATURE_CYCLE_COUNT  = 64,
+};
+
+enum {
+    LM32_FLAG_IGNORE_MSB = 1,
+};
+
+typedef struct CPULM32State {
+    /* general registers */
+    uint32_t regs[32];
+
+    /* special registers */
+    uint32_t pc;        /* program counter */
+    uint32_t ie;        /* interrupt enable */
+    uint32_t icc;       /* instruction cache control */
+    uint32_t dcc;       /* data cache control */
+    uint32_t cc;        /* cycle counter */
+    uint32_t cfg;       /* configuration */
+
+    /* debug registers */
+    uint32_t dc;        /* debug control */
+    uint32_t bp[4];     /* breakpoint addresses */
+    uint32_t wp[4];     /* watchpoint addresses */
+
+    CPU_COMMON
+
+    uint32_t eba;       /* exception base address */
+    uint32_t deba;      /* debug exception base address */
+
+    /* interrupt controller handle for callbacks */
+    struct LM32PicState *pic_env;
+    /* JTAG UART handle for callbacks */
+    struct LM32JuartState *juart_env;
+
+    /* processor core features */
+    uint32_t features;
+    uint32_t flags;
+    uint8_t num_bps;
+    uint8_t num_wps;
+
+} CPULM32State;
+
+
+CPUState *cpu_lm32_init(const char *cpu_model);
+void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf);
+int cpu_lm32_exec(CPUState *s);
+void cpu_lm32_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_lm32_signal_handler(int host_signum, void *pinfo,
+                          void *puc);
+void lm32_translate_init(void);
+void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value);
+
+#define cpu_list cpu_lm32_list
+#define cpu_init cpu_lm32_init
+#define cpu_exec cpu_lm32_exec
+#define cpu_gen_code cpu_lm32_gen_code
+#define cpu_signal_handler cpu_lm32_signal_handler
+
+#define CPU_SAVE_VERSION 1
+
+int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                            int mmu_idx, int is_softmmu);
+#define cpu_handle_mmu_fault cpu_lm32_handle_mmu_fault
+
+#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[R_R1] = 0;
+}
+#endif
+
+static inline void cpu_set_tls(CPUState *env, target_ulong newtls)
+{
+}
+
+static inline int cpu_interrupts_enabled(CPUState *env)
+{
+    return env->ie & IE_IE;
+}
+
+#include "cpu-all.h"
+
+static inline target_ulong cpu_get_pc(CPUState *env)
+{
+    return env->pc;
+}
+
+static inline void cpu_get_tb_cpu_state(CPUState *env, target_ulong *pc,
+                                        target_ulong *cs_base, int *flags)
+{
+    *pc = env->pc;
+    *cs_base = 0;
+    *flags = 0;
+}
+#endif
diff --git a/target-lm32/exec.h b/target-lm32/exec.h
new file mode 100644
index 0000000..348b723
--- /dev/null
+++ b/target-lm32/exec.h
@@ -0,0 +1,50 @@
+/*
+ *  LatticeMico32 execution defines.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dyngen-exec.h"
+
+register struct CPULM32State *env asm(AREG0);
+
+#include "cpu.h"
+#include "exec-all.h"
+
+static inline int cpu_has_work(CPUState *env)
+{
+    return env->interrupt_request & CPU_INTERRUPT_HARD;
+}
+
+static inline int cpu_halted(CPUState *env)
+{
+    if (!env->halted) {
+        return 0;
+    }
+
+    /* IRQ execeptions wakes us up.  */
+    if (cpu_has_work(env)) {
+        env->halted = 0;
+        return 0;
+    }
+    return EXCP_HALTED;
+}
+
+static inline void cpu_pc_from_tb(CPUState *env, TranslationBlock *tb)
+{
+    env->pc = tb->pc;
+}
+
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 02/17] lm32: translation routines
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 01/17] LatticeMico32 target support Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-02-07 18:41   ` [Qemu-devel] " Edgar E. Iglesias
  2011-02-08 17:32   ` [Qemu-devel] " Richard Henderson
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 03/17] lm32: translation code helper Michael Walle
                   ` (15 subsequent siblings)
  17 siblings, 2 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds the main translation routine. All opcodes of the
LatticeMico32 processor are supported and translated to TCG ops.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 target-lm32/helper.c      |  259 +++++++++
 target-lm32/lm32-decode.h |   78 +++
 target-lm32/translate.c   | 1331 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1668 insertions(+), 0 deletions(-)
 create mode 100644 target-lm32/helper.c
 create mode 100644 target-lm32/lm32-decode.h
 create mode 100644 target-lm32/translate.c

diff --git a/target-lm32/helper.c b/target-lm32/helper.c
new file mode 100644
index 0000000..0b508c6
--- /dev/null
+++ b/target-lm32/helper.c
@@ -0,0 +1,259 @@
+/*
+ *  LatticeMico32 helper routines.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "config.h"
+#include "cpu.h"
+#include "exec-all.h"
+#include "host-utils.h"
+
+int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
+                               int mmu_idx, int is_softmmu)
+{
+    int prot;
+
+    address &= TARGET_PAGE_MASK;
+    prot = PAGE_BITS;
+    if (env->flags & LM32_FLAG_IGNORE_MSB) {
+        tlb_set_page(env, address, address & 0x7fffffff, prot, mmu_idx,
+                TARGET_PAGE_SIZE);
+    } else {
+        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
+    }
+
+    return 0;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+{
+    return addr & TARGET_PAGE_MASK;
+}
+
+void do_interrupt(CPUState *env)
+{
+    qemu_log_mask(CPU_LOG_INT,
+            "exception at pc=%x type=%x\n", env->pc, env->exception_index);
+
+    switch (env->exception_index) {
+    case EXCP_INSN_BUS_ERROR:
+    case EXCP_DATA_BUS_ERROR:
+    case EXCP_DIVIDE_BY_ZERO:
+    case EXCP_IRQ:
+    case EXCP_SYSTEMCALL:
+        /* non-debug exceptions */
+        env->regs[R_EA] = env->pc;
+        env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
+        env->ie &= ~IE_IE;
+        if (env->dc & DC_RE) {
+            env->pc = env->deba + (env->exception_index * 32);
+        } else {
+            env->pc = env->eba + (env->exception_index * 32);
+        }
+        log_cpu_state_mask(CPU_LOG_INT, env, 0);
+        break;
+    case EXCP_BREAKPOINT:
+    case EXCP_WATCHPOINT:
+        /* debug exceptions */
+        env->regs[R_BA] = env->pc;
+        env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
+        env->ie &= ~IE_IE;
+        if (env->dc & DC_RE) {
+            env->pc = env->deba + (env->exception_index * 32);
+        } else {
+            env->pc = env->eba + (env->exception_index * 32);
+        }
+        log_cpu_state_mask(CPU_LOG_INT, env, 0);
+        break;
+    default:
+        cpu_abort(env, "unhandled exception type=%d\n",
+                  env->exception_index);
+        break;
+    }
+}
+
+typedef struct {
+    const char *name;
+    uint32_t revision;
+    uint8_t num_interrupts;
+    uint8_t num_breakpoints;
+    uint8_t num_watchpoints;
+    uint32_t features;
+} lm32_def_t;
+
+static lm32_def_t lm32_defs[] = {
+    {
+        .name = "lm32-basic",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_CYCLE_COUNT),
+    },
+    {
+        .name = "lm32-standard",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_MULTIPLY
+                     | LM32_FEATURE_DIVIDE
+                     | LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_I_CACHE
+                     | LM32_FEATURE_CYCLE_COUNT),
+    },
+    {
+        .name = "lm32-full",
+        .revision = 3,
+        .num_interrupts = 32,
+        .num_breakpoints = 4,
+        .num_watchpoints = 4,
+        .features = (LM32_FEATURE_MULTIPLY
+                     | LM32_FEATURE_DIVIDE
+                     | LM32_FEATURE_SHIFT
+                     | LM32_FEATURE_SIGN_EXTEND
+                     | LM32_FEATURE_I_CACHE
+                     | LM32_FEATURE_D_CACHE
+                     | LM32_FEATURE_CYCLE_COUNT),
+    }
+};
+
+void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf)
+{
+    int i;
+
+    cpu_fprintf(f, "Available CPUs:\n");
+    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
+        cpu_fprintf(f, "  %s\n", lm32_defs[i].name);
+    }
+}
+
+static const lm32_def_t *cpu_lm32_find_by_name(const char *name)
+{
+    int i;
+
+    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
+        if (strcasecmp(name, lm32_defs[i].name) == 0) {
+            return &lm32_defs[i];
+        }
+    }
+
+    return NULL;
+}
+
+static uint32_t cfg_by_def(const lm32_def_t *def)
+{
+    uint32_t cfg = 0;
+
+    if (def->features & LM32_FEATURE_MULTIPLY) {
+        cfg |= CFG_M;
+    }
+
+    if (def->features & LM32_FEATURE_DIVIDE) {
+        cfg |= CFG_D;
+    }
+
+    if (def->features & LM32_FEATURE_SHIFT) {
+        cfg |= CFG_S;
+    }
+
+    if (def->features & LM32_FEATURE_SIGN_EXTEND) {
+        cfg |= CFG_X;
+    }
+
+    if (def->features & LM32_FEATURE_I_CACHE) {
+        cfg |= CFG_IC;
+    }
+
+    if (def->features & LM32_FEATURE_D_CACHE) {
+        cfg |= CFG_DC;
+    }
+
+    if (def->features & LM32_FEATURE_CYCLE_COUNT) {
+        cfg |= CFG_CC;
+    }
+
+    cfg |= (def->num_interrupts << CFG_INT_SHIFT);
+    cfg |= (def->num_breakpoints << CFG_BP_SHIFT);
+    cfg |= (def->num_watchpoints << CFG_WP_SHIFT);
+    cfg |= (def->revision << CFG_REV_SHIFT);
+
+    return cfg;
+}
+
+CPUState *cpu_lm32_init(const char *cpu_model)
+{
+    CPUState *env;
+    const lm32_def_t *def;
+    static int tcg_initialized;
+
+    def = cpu_lm32_find_by_name(cpu_model);
+    if (!def) {
+        return NULL;
+    }
+
+    env = qemu_mallocz(sizeof(CPUState));
+
+    env->features = def->features;
+    env->num_bps = def->num_breakpoints;
+    env->num_wps = def->num_watchpoints;
+    env->cfg = cfg_by_def(def);
+    env->flags = 0;
+
+    cpu_exec_init(env);
+    cpu_reset(env);
+
+    if (!tcg_initialized) {
+        tcg_initialized = 1;
+        lm32_translate_init();
+    }
+
+    return env;
+}
+
+/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory
+ * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
+ * 0x80000000-0xffffffff is not cached and used to access IO devices. */
+void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value)
+{
+    if (value) {
+        env->flags |= LM32_FLAG_IGNORE_MSB;
+    } else {
+        env->flags &= ~LM32_FLAG_IGNORE_MSB;
+    }
+}
+
+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);
+    }
+
+    tlb_flush(env, 1);
+
+    /* reset cpu state */
+    memset(env, 0, offsetof(CPULM32State, breakpoints));
+}
+
diff --git a/target-lm32/lm32-decode.h b/target-lm32/lm32-decode.h
new file mode 100644
index 0000000..f745b39
--- /dev/null
+++ b/target-lm32/lm32-decode.h
@@ -0,0 +1,78 @@
+/*
+ *  LatticeMico32 instruction decoding macros.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/* 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, value and mask.  */
+#define DEC_ADD     {B8(00001101), B8(00011111)}
+#define DEC_AND     {B8(00001000), B8(00011111)}
+#define DEC_ANDHI   {B8(00011000), B8(00111111)}
+#define DEC_B       {B8(00110000), B8(00111111)}
+#define DEC_BI      {B8(00111000), B8(00111111)}
+#define DEC_BE      {B8(00010001), B8(00111111)}
+#define DEC_BG      {B8(00010010), B8(00111111)}
+#define DEC_BGE     {B8(00010011), B8(00111111)}
+#define DEC_BGEU    {B8(00010100), B8(00111111)}
+#define DEC_BGU     {B8(00010101), B8(00111111)}
+#define DEC_BNE     {B8(00010111), B8(00111111)}
+#define DEC_CALL    {B8(00110110), B8(00111111)}
+#define DEC_CALLI   {B8(00111110), B8(00111111)}
+#define DEC_CMPE    {B8(00011001), B8(00011111)}
+#define DEC_CMPG    {B8(00011010), B8(00011111)}
+#define DEC_CMPGE   {B8(00011011), B8(00011111)}
+#define DEC_CMPGEU  {B8(00011100), B8(00011111)}
+#define DEC_CMPGU   {B8(00011101), B8(00011111)}
+#define DEC_CMPNE   {B8(00011111), B8(00011111)}
+#define DEC_DIVU    {B8(00100011), B8(00111111)}
+#define DEC_LB      {B8(00000100), B8(00111111)}
+#define DEC_LBU     {B8(00010000), B8(00111111)}
+#define DEC_LH      {B8(00000111), B8(00111111)}
+#define DEC_LHU     {B8(00001011), B8(00111111)}
+#define DEC_LW      {B8(00001010), B8(00111111)}
+#define DEC_MODU    {B8(00110001), B8(00111111)}
+#define DEC_MUL     {B8(00000010), B8(00011111)}
+#define DEC_NOR     {B8(00000001), B8(00011111)}
+#define DEC_OR      {B8(00001110), B8(00011111)}
+#define DEC_ORHI    {B8(00011110), B8(00111111)}
+#define DEC_RAISE   {B8(00101011), B8(00111111)}
+#define DEC_RCSR    {B8(00100100), B8(00111111)}
+#define DEC_SB      {B8(00001100), B8(00111111)}
+#define DEC_SEXTB   {B8(00101100), B8(00111111)}
+#define DEC_SEXTH   {B8(00110111), B8(00111111)}
+#define DEC_SH      {B8(00000011), B8(00111111)}
+#define DEC_SL      {B8(00001111), B8(00011111)}
+#define DEC_SR      {B8(00000101), B8(00011111)}
+#define DEC_SRU     {B8(00000000), B8(00011111)}
+#define DEC_SUB     {B8(00110010), B8(00111111)}
+#define DEC_SW      {B8(00010110), B8(00111111)}
+#define DEC_USER    {B8(00110011), B8(00111111)}
+#define DEC_WCSR    {B8(00110100), B8(00111111)}
+#define DEC_XNOR    {B8(00001001), B8(00011111)}
+#define DEC_XOR     {B8(00000110), B8(00011111)}
+
diff --git a/target-lm32/translate.c b/target-lm32/translate.c
new file mode 100644
index 0000000..d49f798
--- /dev/null
+++ b/target-lm32/translate.c
@@ -0,0 +1,1331 @@
+/*
+ *  LatticeMico32 main translation routines.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#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 "helper.h"
+#include "tcg-op.h"
+#include "lm32-decode.h"
+#include "qemu-common.h"
+
+#include "hw/lm32_pic.h"
+
+#define GEN_HELPER 1
+#include "helper.h"
+
+#define DISAS_LM32 1
+#if DISAS_LM32
+#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
+#else
+#  define LOG_DIS(...) do { } while (0)
+#endif
+
+#define EXTRACT_FIELD(src, start, end) \
+            (((src) >> start) & ((1 << (end - start + 1)) - 1))
+
+#define MEM_INDEX 0
+
+static TCGv_ptr cpu_env;
+static TCGv cpu_R[32];
+static TCGv cpu_pc;
+static TCGv cpu_ie;
+static TCGv cpu_icc;
+static TCGv cpu_dcc;
+static TCGv cpu_cc;
+static TCGv cpu_cfg;
+static TCGv cpu_eba;
+static TCGv cpu_dc;
+static TCGv cpu_deba;
+static TCGv cpu_bp[4];
+static TCGv cpu_wp[4];
+
+#include "gen-icount.h"
+
+enum {
+    OP_FMT_RI,
+    OP_FMT_RR,
+    OP_FMT_CR,
+    OP_FMT_I
+};
+
+#define JMP_NOJMP    0
+#define JMP_DIRECT   1
+#define JMP_INDIRECT 2
+
+/* This is the state at translation time.  */
+typedef struct DisasContext {
+    CPUState *env;
+    target_ulong pc;
+
+    /* Decoder.  */
+    int format;
+    uint32_t ir;
+    uint8_t opcode;
+    uint8_t r0, r1, r2, csr;
+    uint16_t imm5;
+    uint16_t imm16;
+    uint32_t imm26;
+
+    unsigned int delayed_branch;
+    unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
+    int is_jmp;
+
+    unsigned int jmp;
+    uint32_t jmp_pc;
+
+    int nr_nops;
+    struct TranslationBlock *tb;
+    int singlestep_enabled;
+} DisasContext;
+
+static const 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/gp", "r27/fp", "r28/sp", "r29/ra",
+    "r30/ea", "r31/ba", "bp0", "bp1", "bp2", "bp3", "wp0",
+    "wp1", "wp2", "wp3"
+};
+
+static inline int zero_extend(unsigned int val, int width)
+{
+    return val & ((1 << width) - 1);
+}
+
+static inline int sign_extend(unsigned int val, int width)
+{
+    int sval;
+
+    /* LSL.  */
+    val <<= 32 - width;
+    sval = val;
+    /* ASR.  */
+    sval >>= 32 - width;
+
+    return sval;
+}
+
+static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
+{
+    TCGv_i32 tmp = tcg_const_i32(index);
+
+    gen_helper_raise_exception(tmp);
+    tcg_temp_free_i32(tmp);
+}
+
+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) &&
+            likely(!dc->singlestep_enabled)) {
+        tcg_gen_goto_tb(n);
+        tcg_gen_movi_tl(cpu_pc, dest);
+        tcg_gen_exit_tb((long)tb + n);
+    } else {
+        tcg_gen_movi_tl(cpu_pc, dest);
+        if (dc->singlestep_enabled) {
+            t_gen_raise_exception(dc, EXCP_DEBUG);
+        }
+        tcg_gen_exit_tb(0);
+    }
+}
+
+static void dec_add(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        if (dc->r0 == R_R0) {
+            if (dc->r1 == R_R0 && dc->imm16 == 0) {
+                LOG_DIS("nop\n");
+            } else {
+                LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16));
+            }
+        } else {
+            LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0,
+                    sign_extend(dc->imm16, 16));
+        }
+    } else {
+        LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_and(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("andi r%d, r%d, %d\n", dc->r1, dc->r0,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("and r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else  {
+        if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) {
+            tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+            gen_helper_hlt();
+        } else {
+            tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+        }
+    }
+}
+
+static void dec_andhi(DisasContext *dc)
+{
+    LOG_DIS("andhi r%d, r%d, %d\n", dc->r2, dc->r0, dc->imm16);
+
+    tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
+}
+
+static void dec_b(DisasContext *dc)
+{
+    if (dc->r0 == R_RA) {
+        LOG_DIS("ret\n");
+    } else if (dc->r0 == R_EA) {
+        LOG_DIS("eret\n");
+    } else if (dc->r0 == R_BA) {
+        LOG_DIS("bret\n");
+    } else {
+        LOG_DIS("b r%d\n", dc->r0);
+    }
+
+    /* restore IE.IE in case of an eret */
+    if (dc->r0 == R_EA) {
+        TCGv t0 = tcg_temp_new();
+        int l1 = gen_new_label();
+        tcg_gen_andi_tl(t0, cpu_ie, IE_EIE);
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_EIE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
+        gen_set_label(l1);
+        tcg_temp_free(t0);
+    } else if (dc->r0 == R_BA) {
+        TCGv t0 = tcg_temp_new();
+        int l1 = gen_new_label();
+        tcg_gen_andi_tl(t0, cpu_ie, IE_BIE);
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_BIE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
+        gen_set_label(l1);
+        tcg_temp_free(t0);
+    }
+    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
+
+    dc->is_jmp = DISAS_JUMP;
+}
+
+static void dec_bi(DisasContext *dc)
+{
+    LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26));
+
+    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
+
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static inline void gen_cond_branch(DisasContext *dc, int cond)
+{
+    int l1;
+
+    l1 = gen_new_label();
+    tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1);
+    gen_goto_tb(dc, 0, dc->pc + 4);
+    gen_set_label(l1);
+    gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16)));
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static void dec_be(DisasContext *dc)
+{
+    LOG_DIS("be r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_EQ);
+}
+
+static void dec_bg(DisasContext *dc)
+{
+    LOG_DIS("bg r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16 * 4));
+
+    gen_cond_branch(dc, TCG_COND_GT);
+}
+
+static void dec_bge(DisasContext *dc)
+{
+    LOG_DIS("bge r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GE);
+}
+
+static void dec_bgeu(DisasContext *dc)
+{
+    LOG_DIS("bgeu r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GEU);
+}
+
+static void dec_bgu(DisasContext *dc)
+{
+    LOG_DIS("bgu r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_GTU);
+}
+
+static void dec_bne(DisasContext *dc)
+{
+    LOG_DIS("bne r%d, r%d, %d\n", dc->r0, dc->r1,
+            sign_extend(dc->imm16, 16) * 4);
+
+    gen_cond_branch(dc, TCG_COND_NE);
+}
+
+static void dec_call(DisasContext *dc)
+{
+    LOG_DIS("call r%d\n", dc->r0);
+
+    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
+    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
+
+    dc->is_jmp = DISAS_JUMP;
+}
+
+static void dec_calli(DisasContext *dc)
+{
+    LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4);
+
+    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
+    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
+
+    dc->is_jmp = DISAS_TB_JUMP;
+}
+
+static inline void gen_compare(DisasContext *dc, int cond)
+{
+    int rX = (dc->format == OP_FMT_RR) ? dc->r2 : dc->r1;
+    int rY = (dc->format == OP_FMT_RR) ? dc->r0 : dc->r0;
+    int rZ = (dc->format == OP_FMT_RR) ? dc->r1 : -1;
+
+    int l1, l2;
+
+    l1 = gen_new_label();
+    l2 = gen_new_label();
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_brcondi_tl(cond, cpu_R[rY], sign_extend(dc->imm16, 16), l1);
+    } else {
+        tcg_gen_brcond_tl(cond, cpu_R[rY], cpu_R[rZ], l1);
+    }
+    tcg_gen_movi_tl(cpu_R[rX], 0);
+    tcg_gen_br(l2);
+    gen_set_label(l1);
+    tcg_gen_movi_tl(cpu_R[rX], 1);
+    gen_set_label(l2);
+}
+
+static void dec_cmpe(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpe r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_EQ);
+}
+
+static void dec_cmpg(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgi r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpg r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GT);
+}
+
+static void dec_cmpge(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpge r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GE);
+}
+
+static void dec_cmpgeu(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgeui r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpgeu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GEU);
+}
+
+static void dec_cmpgu(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpgui r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpgu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_GTU);
+}
+
+static void dec_cmpne(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("cmpnei r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("cmpne r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    gen_compare(dc, TCG_COND_NE);
+}
+
+static void dec_divu(DisasContext *dc)
+{
+    int l1;
+
+    LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+
+    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+        cpu_abort(dc->env, "hardware divider is not available\n");
+    }
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
+    gen_set_label(l1);
+    tcg_gen_divu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_lb(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lb r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld8s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lbu(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lbu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld8u(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lh(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lh r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld16s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lhu(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lhu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld16u(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_lw(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16));
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_modu(DisasContext *dc)
+{
+    int l1;
+
+    LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
+
+    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
+        cpu_abort(dc->env, "hardware divider is not available\n");
+    }
+
+    l1 = gen_new_label();
+    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
+    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
+    gen_set_label(l1);
+    tcg_gen_remu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_mul(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("muli r%d, r%d, %d\n", dc->r0, dc->r1,
+                sign_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
+        cpu_abort(dc->env, "hardware multiplier is not available\n");
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_muli_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                sign_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_mul_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_nor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("nori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("nor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_movi_tl(t0, zero_extend(dc->imm16, 16));
+        tcg_gen_nor_tl(cpu_R[dc->r1], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    } else {
+        tcg_gen_nor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_or(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("ori r%d, r%d, %d\n", dc->r1, dc->r0,
+                zero_extend(dc->imm16, 16));
+    } else {
+        if (dc->r1 == R_R0) {
+            LOG_DIS("mv r%d, r%d\n", dc->r2, dc->r0);
+        } else {
+            LOG_DIS("or r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_or_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static void dec_orhi(DisasContext *dc)
+{
+    if (dc->r0 == R_R0) {
+        LOG_DIS("mvhi r%d, %d\n", dc->r1, dc->imm16);
+    } else {
+        LOG_DIS("orhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16);
+    }
+
+    tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
+}
+
+static void dec_raise(DisasContext *dc)
+{
+    TCGv t0;
+    int l1;
+
+    if (dc->imm5 == 7) {
+        LOG_DIS("scall\n");
+    } else if (dc->imm5 == 2) {
+        LOG_DIS("break\n");
+    } else {
+        cpu_abort(dc->env, "invalid opcode\n");
+    }
+
+    t0 = tcg_temp_new();
+    l1 = gen_new_label();
+
+    /* save IE.IE */
+    tcg_gen_andi_tl(t0, cpu_ie, IE_IE);
+
+    /* IE.IE = 0 */
+    tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
+
+    if (dc->imm5 == 7) {
+        /* IE.EIE = IE.IE */
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_EIE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_EIE);
+        gen_set_label(l1);
+
+        /* gpr[ea] = PC */
+        tcg_gen_movi_tl(cpu_R[R_EA], dc->pc);
+        tcg_temp_free(t0);
+
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
+    } else {
+        /* IE.BIE = IE.IE */
+        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_BIE);
+        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1);
+        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_BIE);
+        gen_set_label(l1);
+
+        /* gpr[ba] = PC */
+        tcg_gen_movi_tl(cpu_R[R_BA], dc->pc);
+        tcg_temp_free(t0);
+
+        tcg_gen_movi_tl(cpu_pc, dc->pc);
+        t_gen_raise_exception(dc, EXCP_BREAKPOINT);
+    }
+}
+
+static void dec_rcsr(DisasContext *dc)
+{
+    LOG_DIS("rcsr r%d, %d\n", dc->r2, dc->csr);
+
+    switch (dc->csr) {
+    case CSR_IE:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie);
+        break;
+    case CSR_IM:
+        gen_helper_rcsr_im(cpu_R[dc->r2]);
+        break;
+    case CSR_IP:
+        gen_helper_rcsr_ip(cpu_R[dc->r2]);
+        break;
+    case CSR_CC:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc);
+        break;
+    case CSR_CFG:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cfg);
+        break;
+    case CSR_EBA:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_eba);
+        break;
+    case CSR_DC:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_dc);
+        break;
+    case CSR_DEBA:
+        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba);
+        break;
+    case CSR_JTX:
+        gen_helper_rcsr_jtx(cpu_R[dc->r2]);
+        break;
+    case CSR_JRX:
+        gen_helper_rcsr_jrx(cpu_R[dc->r2]);
+        break;
+    case CSR_ICC:
+    case CSR_DCC:
+    case CSR_BP0:
+    case CSR_BP1:
+    case CSR_BP2:
+    case CSR_BP3:
+    case CSR_WP0:
+    case CSR_WP1:
+    case CSR_WP2:
+    case CSR_WP3:
+        cpu_abort(dc->env, "invalid read access csr=%x\n", dc->csr);
+        break;
+    default:
+        cpu_abort(dc->env, "read_csr: unknown csr=%x\n", dc->csr);
+        break;
+    }
+}
+
+static void dec_sb(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sb (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st8(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_sextb(DisasContext *dc)
+{
+    LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
+
+    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+        cpu_abort(dc->env, "hardware sign extender is not available\n");
+    }
+
+    tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
+}
+
+static void dec_sexth(DisasContext *dc)
+{
+    LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
+
+    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
+        cpu_abort(dc->env, "hardware sign extender is not available\n");
+    }
+
+    tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
+}
+
+static void dec_sh(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sh (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st16(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_sl(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("sli r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        cpu_abort(dc->env, "hardware shifter is not available\n");
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_shli_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_shl_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sr(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("sri r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        if (dc->format == OP_FMT_RI) {
+            /* TODO: check r1 == 1 during runtime */
+        } else {
+            if (dc->imm5 != 1) {
+                cpu_abort(dc->env, "hardware shifter is not available\n");
+            }
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sru(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("srui r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
+    } else {
+        LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
+        if (dc->format == OP_FMT_RI) {
+            /* TODO: check r1 == 1 during runtime */
+        } else {
+            if (dc->imm5 != 1) {
+                cpu_abort(dc->env, "hardware shifter is not available\n");
+            }
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
+    } else {
+        TCGv t0 = tcg_temp_new();
+        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
+        tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
+        tcg_temp_free(t0);
+    }
+}
+
+static void dec_sub(DisasContext *dc)
+{
+    LOG_DIS("sub r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+
+    tcg_gen_sub_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+}
+
+static void dec_sw(DisasContext *dc)
+{
+    TCGv t0;
+
+    LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1);
+
+    t0 = tcg_temp_new();
+    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
+    tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX);
+    tcg_temp_free(t0);
+}
+
+static void dec_user(DisasContext *dc)
+{
+    LOG_DIS("user");
+
+    cpu_abort(dc->env, "user insn undefined\n");
+}
+
+static void dec_wcsr(DisasContext *dc)
+{
+    int no;
+
+    LOG_DIS("wcsr r%d, %d\n", dc->r1, dc->csr);
+
+    switch (dc->csr) {
+    case CSR_IE:
+        tcg_gen_mov_tl(cpu_ie, cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_IM:
+        /* mark as an io operation because it could cause an interrupt */
+        if (use_icount) {
+            gen_io_start();
+        }
+        gen_helper_wcsr_im(cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        if (use_icount) {
+            gen_io_end();
+        }
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_IP:
+        /* mark as an io operation because it could cause an interrupt */
+        if (use_icount) {
+            gen_io_start();
+        }
+        gen_helper_wcsr_ip(cpu_R[dc->r1]);
+        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
+        if (use_icount) {
+            gen_io_end();
+        }
+        dc->is_jmp = DISAS_UPDATE;
+        break;
+    case CSR_ICC:
+        /* TODO */
+        break;
+    case CSR_DCC:
+        /* TODO */
+        break;
+    case CSR_EBA:
+        tcg_gen_mov_tl(cpu_eba, cpu_R[dc->r1]);
+        break;
+    case CSR_DEBA:
+        tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]);
+        break;
+    case CSR_JTX:
+        gen_helper_wcsr_jtx(cpu_R[dc->r1]);
+        break;
+    case CSR_JRX:
+        gen_helper_wcsr_jrx(cpu_R[dc->r1]);
+        break;
+    case CSR_DC:
+        tcg_gen_mov_tl(cpu_dc, cpu_R[dc->r1]);
+        break;
+    case CSR_BP0:
+    case CSR_BP1:
+    case CSR_BP2:
+    case CSR_BP3:
+        no = dc->csr - CSR_BP0;
+        if (dc->env->num_bps <= no) {
+            cpu_abort(dc->env, "breakpoint #%i is not available\n", no);
+        }
+        tcg_gen_mov_tl(cpu_bp[no], cpu_R[dc->r1]);
+        break;
+    case CSR_WP0:
+    case CSR_WP1:
+    case CSR_WP2:
+    case CSR_WP3:
+        no = dc->csr - CSR_WP0;
+        if (dc->env->num_wps <= no) {
+            cpu_abort(dc->env, "watchpoint #%i is not available\n", no);
+        }
+        tcg_gen_mov_tl(cpu_wp[no], cpu_R[dc->r1]);
+        break;
+    case CSR_CC:
+    case CSR_CFG:
+        cpu_abort(dc->env, "invalid write access csr=%x\n", dc->csr);
+        break;
+    default:
+        cpu_abort(dc->env, "write_csr unknown csr=%x\n", dc->csr);
+        break;
+    }
+}
+
+static void dec_xnor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("xnori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        if (dc->r1 == R_R0) {
+            LOG_DIS("not r%d, r%d\n", dc->r2, dc->r0);
+        } else {
+            LOG_DIS("xnor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+        }
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+        tcg_gen_not_tl(cpu_R[dc->r1], cpu_R[dc->r1]);
+    } else {
+        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+        tcg_gen_not_tl(cpu_R[dc->r2], cpu_R[dc->r2]);
+    }
+}
+
+static void dec_xor(DisasContext *dc)
+{
+    if (dc->format == OP_FMT_RI) {
+        LOG_DIS("xori r%d, r%d, %d\n", dc->r0, dc->r1,
+                zero_extend(dc->imm16, 16));
+    } else {
+        LOG_DIS("xor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
+    }
+
+    if (dc->format == OP_FMT_RI) {
+        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
+                zero_extend(dc->imm16, 16));
+    } else {
+        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
+    }
+}
+
+static struct decoder_info {
+    struct {
+        uint32_t bits;
+        uint32_t mask;
+    };
+    void (*dec)(DisasContext *dc);
+} decinfo[] = {
+    {DEC_ADD, dec_add},
+    {DEC_AND, dec_and},
+    {DEC_ANDHI, dec_andhi},
+    {DEC_B, dec_b},
+    {DEC_BI, dec_bi},
+    {DEC_BE, dec_be},
+    {DEC_BG, dec_bg},
+    {DEC_BGE, dec_bge},
+    {DEC_BGEU, dec_bgeu},
+    {DEC_BGU, dec_bgu},
+    {DEC_BNE, dec_bne},
+    {DEC_CALL, dec_call},
+    {DEC_CALLI, dec_calli},
+    {DEC_CMPE, dec_cmpe},
+    {DEC_CMPG, dec_cmpg},
+    {DEC_CMPGE, dec_cmpge},
+    {DEC_CMPGEU, dec_cmpgeu},
+    {DEC_CMPGU, dec_cmpgu},
+    {DEC_CMPNE, dec_cmpne},
+    {DEC_DIVU, dec_divu},
+    {DEC_LB, dec_lb},
+    {DEC_LBU, dec_lbu},
+    {DEC_LH, dec_lh},
+    {DEC_LHU, dec_lhu},
+    {DEC_LW, dec_lw},
+    {DEC_MODU, dec_modu},
+    {DEC_MUL, dec_mul},
+    {DEC_NOR, dec_nor},
+    {DEC_OR, dec_or},
+    {DEC_ORHI, dec_orhi},
+    {DEC_RAISE, dec_raise},
+    {DEC_RCSR, dec_rcsr},
+    {DEC_SB, dec_sb},
+    {DEC_SEXTB, dec_sextb},
+    {DEC_SEXTH, dec_sexth},
+    {DEC_SH, dec_sh},
+    {DEC_SL, dec_sl},
+    {DEC_SR, dec_sr},
+    {DEC_SRU, dec_sru},
+    {DEC_SUB, dec_sub},
+    {DEC_SW, dec_sw},
+    {DEC_USER, dec_user},
+    {DEC_WCSR, dec_wcsr},
+    {DEC_XNOR, dec_xnor},
+    {DEC_XOR, dec_xor},
+};
+
+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);
+
+    /* try guessing 'empty' instruction memory, although it may be a valid
+     * instruction sequence (eg. srui r0, r0, 0) */
+    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");
+        }
+    }
+
+    dc->opcode = EXTRACT_FIELD(ir, 26, 31);
+
+    dc->imm5 = EXTRACT_FIELD(ir, 0, 4);
+    dc->imm16 = EXTRACT_FIELD(ir, 0, 15);
+    dc->imm26 = EXTRACT_FIELD(ir, 0, 25);
+
+    dc->csr = EXTRACT_FIELD(ir, 21, 25);
+    dc->r0 = EXTRACT_FIELD(ir, 21, 25);
+    dc->r1 = EXTRACT_FIELD(ir, 16, 20);
+    dc->r2 = EXTRACT_FIELD(ir, 11, 15);
+
+    /* bit 31 seems to indicate insn type.  */
+    if (ir & (1 << 31)) {
+        dc->format = OP_FMT_RR;
+    } else {
+        dc->format = OP_FMT_RI;
+    }
+
+    /* 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(!QTAILQ_EMPTY(&env->breakpoints))) {
+        QTAILQ_FOREACH(bp, &env->breakpoints, entry) {
+            if (bp->pc == dc->pc) {
+                tcg_gen_movi_tl(cpu_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)
+{
+    struct DisasContext ctx, *dc = &ctx;
+    uint16_t *gen_opc_end;
+    uint32_t pc_start;
+    int j, lj;
+    uint32_t next_page_start;
+    int num_insns;
+    int max_insns;
+
+    qemu_log_try_set_file(stderr);
+
+    pc_start = tb->pc;
+    dc->env = env;
+    dc->tb = tb;
+
+    gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+
+    dc->is_jmp = DISAS_NEXT;
+    dc->jmp = 0;
+    dc->pc = pc_start;
+    dc->singlestep_enabled = env->singlestep_enabled;
+    dc->nr_nops = 0;
+
+    if (pc_start & 3) {
+        cpu_abort(env, "LM32: unaligned PC=%x\n", pc_start);
+    }
+
+    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("-----------------------------------------\n");
+        log_cpu_state(env, 0);
+    }
+
+    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 {
+        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();
+        }
+
+        decode(dc);
+        dc->pc += 4;
+        num_insns++;
+
+    } while (!dc->is_jmp
+         && gen_opc_ptr < gen_opc_end
+         && !env->singlestep_enabled
+         && !singlestep
+         && (dc->pc < next_page_start)
+         && num_insns < max_insns);
+
+    if (tb->cflags & CF_LAST_IO) {
+        gen_io_end();
+    }
+
+    if (unlikely(env->singlestep_enabled)) {
+        if (dc->is_jmp == DISAS_NEXT) {
+            tcg_gen_movi_tl(cpu_pc, dc->pc);
+        }
+        t_gen_raise_exception(dc, EXCP_DEBUG);
+    } else {
+        switch (dc->is_jmp) {
+        case DISAS_NEXT:
+            gen_goto_tb(dc, 1, dc->pc);
+            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 (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) {
+        qemu_log("\n");
+        log_target_disas(pc_start, dc->pc - pc_start, 0);
+        qemu_log("\nisize=%d osize=%zd\n",
+            dc->pc - pc_start, gen_opc_ptr - gen_opc_buf);
+    }
+#endif
+}
+
+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, fprintf_function cpu_fprintf,
+                     int flags)
+{
+    int i;
+
+    if (!env || !f) {
+        return;
+    }
+
+    cpu_fprintf(f, "IN: PC=%x %s\n",
+                env->pc, lookup_symbol(env->pc));
+
+    cpu_fprintf(f, "ie=%8.8x (IE=%x EIE=%x BIE=%x) im=%8.8x ip=%8.8x\n",
+             env->ie,
+             (env->ie & IE_IE) ? 1 : 0,
+             (env->ie & IE_EIE) ? 1 : 0,
+             (env->ie & IE_BIE) ? 1 : 0,
+             lm32_pic_get_im(env),
+             lm32_pic_get_ip(env));
+    cpu_fprintf(f, "eba=%8.8x deba=%8.8x\n",
+             env->eba,
+             env->deba);
+
+    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");
+}
+
+void gen_pc_load(CPUState *env, struct TranslationBlock *tb,
+                 unsigned long searched_pc, int pc_pos, void *puc)
+{
+    env->pc = gen_opc_pc[pc_pos];
+}
+
+void lm32_translate_init(void)
+{
+    int i;
+
+    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env");
+
+    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_bp); i++) {
+        cpu_bp[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, bp[i]),
+                          regnames[32+i]);
+    }
+
+    for (i = 0; i < ARRAY_SIZE(cpu_wp); i++) {
+        cpu_wp[i] = tcg_global_mem_new(TCG_AREG0,
+                          offsetof(CPUState, wp[i]),
+                          regnames[36+i]);
+    }
+
+    cpu_pc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, pc),
+                    "pc");
+    cpu_ie = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, ie),
+                    "ie");
+    cpu_icc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, icc),
+                    "icc");
+    cpu_dcc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, dcc),
+                    "dcc");
+    cpu_cc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, cc),
+                    "cc");
+    cpu_cfg = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, cfg),
+                    "cfg");
+    cpu_eba = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, eba),
+                    "eba");
+    cpu_dc = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, dc),
+                    "dc");
+    cpu_deba = tcg_global_mem_new(TCG_AREG0,
+                    offsetof(CPUState, deba),
+                    "deba");
+}
+
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 03/17] lm32: translation code helper
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 01/17] LatticeMico32 target support Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 02/17] lm32: translation routines Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 04/17] lm32: machine state loading/saving Michael Walle
                   ` (14 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds translation helper functions.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 target-lm32/helper.h    |   14 ++++++
 target-lm32/op_helper.c |  106 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 120 insertions(+), 0 deletions(-)
 create mode 100644 target-lm32/helper.h
 create mode 100644 target-lm32/op_helper.c

diff --git a/target-lm32/helper.h b/target-lm32/helper.h
new file mode 100644
index 0000000..9d335ef
--- /dev/null
+++ b/target-lm32/helper.h
@@ -0,0 +1,14 @@
+#include "def-helper.h"
+
+DEF_HELPER_1(raise_exception, void, i32)
+DEF_HELPER_0(hlt, void)
+DEF_HELPER_1(wcsr_im, void, i32)
+DEF_HELPER_1(wcsr_ip, void, i32)
+DEF_HELPER_1(wcsr_jtx, void, i32)
+DEF_HELPER_1(wcsr_jrx, void, i32)
+DEF_HELPER_0(rcsr_im, i32)
+DEF_HELPER_0(rcsr_ip, i32)
+DEF_HELPER_0(rcsr_jtx, i32)
+DEF_HELPER_0(rcsr_jrx, i32)
+
+#include "def-helper.h"
diff --git a/target-lm32/op_helper.c b/target-lm32/op_helper.c
new file mode 100644
index 0000000..38200cf
--- /dev/null
+++ b/target-lm32/op_helper.c
@@ -0,0 +1,106 @@
+#include <assert.h>
+#include "exec.h"
+#include "helper.h"
+#include "host-utils.h"
+
+#include "hw/lm32_pic.h"
+#include "hw/lm32_juart.h"
+
+#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"
+
+void helper_raise_exception(uint32_t index)
+{
+    env->exception_index = index;
+    cpu_loop_exit();
+}
+
+void helper_hlt(void)
+{
+    env->halted = 1;
+    env->exception_index = EXCP_HLT;
+    cpu_loop_exit();
+}
+
+void helper_wcsr_im(uint32_t im)
+{
+    lm32_pic_set_im(env, im);
+}
+
+void helper_wcsr_ip(uint32_t im)
+{
+    lm32_pic_set_ip(env, im);
+}
+
+void helper_wcsr_jtx(uint32_t jtx)
+{
+    lm32_juart_set_jtx(env, jtx);
+}
+
+void helper_wcsr_jrx(uint32_t jrx)
+{
+    lm32_juart_set_jrx(env, jrx);
+}
+
+uint32_t helper_rcsr_im(void)
+{
+    return lm32_pic_get_im(env);
+}
+
+uint32_t helper_rcsr_ip(void)
+{
+    return lm32_pic_get_ip(env);
+}
+
+uint32_t helper_rcsr_jtx(void)
+{
+    return lm32_juart_get_jtx(env);
+}
+
+uint32_t helper_rcsr_jrx(void)
+{
+    return lm32_juart_get_jrx(env);
+}
+
+/* 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_lm32_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
+
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 04/17] lm32: machine state loading/saving
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (2 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 03/17] lm32: translation code helper Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 05/17] lm32: gdbstub support Michael Walle
                   ` (13 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for saving and loading the processor state.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 target-lm32/machine.c |   33 +++++++++++++++++++++++++++++++++
 1 files changed, 33 insertions(+), 0 deletions(-)
 create mode 100644 target-lm32/machine.c

diff --git a/target-lm32/machine.c b/target-lm32/machine.c
new file mode 100644
index 0000000..70ca52a
--- /dev/null
+++ b/target-lm32/machine.c
@@ -0,0 +1,33 @@
+#include "hw/hw.h"
+#include "hw/boards.h"
+
+static const VMStateDescription vmstate_cpu = {
+    .name = "cpu",
+    .version_id = CPU_SAVE_VERSION,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, CPUState, 32),
+        VMSTATE_UINT32(pc, CPUState),
+        VMSTATE_UINT32(ie, CPUState),
+        VMSTATE_UINT32(icc, CPUState),
+        VMSTATE_UINT32(dcc, CPUState),
+        VMSTATE_UINT32(cc, CPUState),
+        VMSTATE_UINT32(eba, CPUState),
+        VMSTATE_UINT32(dc, CPUState),
+        VMSTATE_UINT32(deba, CPUState),
+        VMSTATE_UINT32_ARRAY(bp, CPUState, 4),
+        VMSTATE_UINT32_ARRAY(wp, CPUState, 4),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+void cpu_save(QEMUFile *f, void *opaque)
+{
+    vmstate_save_state(f, &vmstate_cpu, opaque);
+}
+
+int cpu_load(QEMUFile *f, void *opaque, int version_id)
+{
+    return vmstate_load_state(f, &vmstate_cpu, opaque, version_id);
+}
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 05/17] lm32: gdbstub support
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (3 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 04/17] lm32: machine state loading/saving Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 06/17] lm32: interrupt controller model Michael Walle
                   ` (12 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds lm32 support to the gdbstub.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 gdbstub.c |   76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 76 insertions(+), 0 deletions(-)

diff --git a/gdbstub.c b/gdbstub.c
index d6556c9..a4b37b7 100644
--- a/gdbstub.c
+++ b/gdbstub.c
@@ -1462,6 +1462,80 @@ static int cpu_gdb_write_register(CPUState *env, uint8_t *mem_buf, int n)
 
     return r;
 }
+#elif defined (TARGET_LM32)
+
+#include "hw/lm32_pic.h"
+#define NUM_CORE_REGS (32 + 7)
+
+static int cpu_gdb_read_register(CPUState *env, uint8_t *mem_buf, int n)
+{
+    if (n < 32) {
+        GET_REG32(env->regs[n]);
+    } else {
+        switch (n) {
+        case 32:
+            GET_REG32(env->pc);
+            break;
+        /* FIXME: put in right exception ID */
+        case 33:
+            GET_REG32(0);
+            break;
+        case 34:
+            GET_REG32(env->eba);
+            break;
+        case 35:
+            GET_REG32(env->deba);
+            break;
+        case 36:
+            GET_REG32(env->ie);
+            break;
+        case 37:
+            GET_REG32(lm32_pic_get_im(env));
+            break;
+        case 38:
+            GET_REG32(lm32_pic_get_ip(env));
+            break;
+        }
+    }
+    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 {
+        switch (n) {
+        case 32:
+            env->pc = tmp;
+            break;
+        case 34:
+            env->eba = tmp;
+            break;
+        case 35:
+            env->deba = tmp;
+            break;
+        case 36:
+            env->ie = tmp;
+            break;
+        case 37:
+            lm32_pic_set_im(env, tmp);
+            break;
+        case 38:
+            lm32_pic_set_ip(env, tmp);
+            break;
+        }
+    }
+    return 4;
+}
 #else
 
 #define NUM_CORE_REGS 0
@@ -1737,6 +1811,8 @@ static void gdb_set_cpu_pc(GDBState *s, target_ulong pc)
 #elif defined (TARGET_S390X)
     cpu_synchronize_state(s->c_cpu);
     s->c_cpu->psw.addr = pc;
+#elif defined (TARGET_LM32)
+    s->c_cpu->pc = pc;
 #endif
 }
 
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 06/17] lm32: interrupt controller model
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (4 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 05/17] lm32: gdbstub support Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 07/17] lm32: juart model Michael Walle
                   ` (11 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds the interrupt controller of the lm32. Because the PIC is
accessed through special control registers and opcodes, there are callbacks
from the lm32 translation code to this model.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 hw/lm32_pic.c     |  191 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/lm32_pic.h     |   10 +++
 hw/lm32_pic_cpu.c |   37 ++++++++++
 trace-events      |    9 +++
 4 files changed, 247 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm32_pic.c
 create mode 100644 hw/lm32_pic.h
 create mode 100644 hw/lm32_pic_cpu.c

diff --git a/hw/lm32_pic.c b/hw/lm32_pic.c
new file mode 100644
index 0000000..dbef535
--- /dev/null
+++ b/hw/lm32_pic.c
@@ -0,0 +1,191 @@
+/*
+ *  LatticeMico32 CPU interrupt controller logic.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <assert.h>
+
+#include "hw.h"
+#include "pc.h"
+#include "monitor.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "lm32_pic.h"
+
+struct LM32PicState {
+    SysBusDevice busdev;
+    qemu_irq parent_irq;
+    uint32_t im;        /* interrupt mask */
+    uint32_t ip;        /* interrupt pending */
+    uint32_t irq_state;
+
+    /* statistics */
+    uint32_t stats_irq_count[32];
+};
+typedef struct LM32PicState LM32PicState;
+
+static LM32PicState *pic;
+void pic_info(Monitor *mon)
+{
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "lm32-pic: im=%08x ip=%08x irq_state=%08x\n",
+            pic->im, pic->ip, pic->irq_state);
+}
+
+void irq_info(Monitor *mon)
+{
+    int i;
+    uint32_t count;
+
+    if (pic == NULL) {
+        return;
+    }
+
+    monitor_printf(mon, "IRQ statistics:\n");
+    for (i = 0; i < 32; i++) {
+        count = pic->stats_irq_count[i];
+        if (count > 0) {
+            monitor_printf(mon, "%2d: %u\n", i, count);
+        }
+    }
+}
+
+static void update_irq(LM32PicState *s)
+{
+    s->ip |= s->irq_state;
+
+    if (s->ip & s->im) {
+        trace_lm32_pic_raise_irq();
+        qemu_irq_raise(s->parent_irq);
+    } else {
+        trace_lm32_pic_lower_irq();
+        qemu_irq_lower(s->parent_irq);
+    }
+}
+
+static void irq_handler(void *opaque, int irq, int level)
+{
+    LM32PicState *s = opaque;
+
+    assert(irq < 32);
+    trace_lm32_pic_interrupt(irq, level);
+
+    if (level) {
+        s->irq_state |= (1 << irq);
+        s->stats_irq_count[irq]++;
+    } else {
+        s->irq_state &= ~(1 << irq);
+    }
+
+    update_irq(s);
+}
+
+void lm32_pic_set_im(CPUState *env, uint32_t im)
+{
+    LM32PicState *s = env->pic_env;
+
+    trace_lm32_pic_set_im(im);
+    s->im = im;
+
+    update_irq(s);
+}
+
+void lm32_pic_set_ip(CPUState *env, uint32_t ip)
+{
+    LM32PicState *s = env->pic_env;
+
+    trace_lm32_pic_set_ip(ip);
+
+    /* ack interrupt */
+    s->ip &= ~ip;
+
+    update_irq(s);
+}
+
+uint32_t lm32_pic_get_im(CPUState *env)
+{
+    LM32PicState *s = env->pic_env;
+
+    trace_lm32_pic_get_im(s->im);
+    return s->im;
+}
+
+uint32_t lm32_pic_get_ip(CPUState *env)
+{
+    LM32PicState *s = env->pic_env;
+
+    trace_lm32_pic_get_ip(s->ip);
+    return s->ip;
+}
+
+static void pic_reset(void *opaque)
+{
+    LM32PicState *s = opaque;
+    int i;
+
+    s->im = 0;
+    s->ip = 0;
+    s->irq_state = 0;
+    for (i = 0; i < 32; i++) {
+        s->stats_irq_count[i] = 0;
+    }
+    qemu_irq_lower(s->parent_irq);
+}
+
+static int lm32_pic_init(SysBusDevice *dev)
+{
+    LM32PicState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    qdev_init_gpio_in(&dev->qdev, irq_handler, 32);
+    sysbus_init_irq(dev, &s->parent_irq);
+    qemu_register_reset(pic_reset, s);
+
+    pic = s;
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_pic = {
+    .name = "lm32-pic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(im, LM32PicState),
+        VMSTATE_UINT32(ip, LM32PicState),
+        VMSTATE_UINT32(irq_state, LM32PicState),
+        VMSTATE_UINT32_ARRAY(stats_irq_count, LM32PicState, 32),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_pic_info = {
+    .init = lm32_pic_init,
+    .qdev.name = "lm32-pic",
+    .qdev.size = sizeof(LM32PicState),
+    .qdev.vmsd  = &vmstate_lm32_pic,
+};
+
+static void lm32_pic_register(void)
+{
+    sysbus_register_withprop(&lm32_pic_info);
+}
+
+device_init(lm32_pic_register)
diff --git a/hw/lm32_pic.h b/hw/lm32_pic.h
new file mode 100644
index 0000000..ce39ac7
--- /dev/null
+++ b/hw/lm32_pic.h
@@ -0,0 +1,10 @@
+#ifndef __LM32_PIC
+#define __LM32_PIC
+
+#include "qemu-common.h"
+
+uint32_t lm32_pic_get_ip(CPUState *env);
+uint32_t lm32_pic_get_im(CPUState *env);
+void lm32_pic_set_ip(CPUState *env, uint32_t ip);
+void lm32_pic_set_im(CPUState *env, uint32_t im);
+#endif
diff --git a/hw/lm32_pic_cpu.c b/hw/lm32_pic_cpu.c
new file mode 100644
index 0000000..8bbeccc
--- /dev/null
+++ b/hw/lm32_pic_cpu.c
@@ -0,0 +1,37 @@
+/*
+ *  LatticeMico32 CPU interrupt wrapper logic.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+
+static void lm32_pic_cpu_handler(void *opaque, int irq, int level)
+{
+    CPUState *env = (CPUState *)opaque;
+
+    if (level) {
+        cpu_interrupt(env, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+    }
+}
+
+qemu_irq *lm32_pic_init_cpu(CPUState *env);
+qemu_irq *lm32_pic_init_cpu(CPUState *env)
+{
+    return qemu_allocate_irqs(lm32_pic_cpu_handler, env, 1);
+}
diff --git a/trace-events b/trace-events
index e8fed0f..377bc25 100644
--- a/trace-events
+++ b/trace-events
@@ -213,3 +213,12 @@ disable qed_aio_write_data(void *s, void *acb, int ret, uint64_t offset, size_t
 disable qed_aio_write_prefill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
 disable qed_aio_write_postfill(void *s, void *acb, uint64_t start, size_t len, uint64_t offset) "s %p acb %p start %"PRIu64" len %zu offset %"PRIu64""
 disable qed_aio_write_main(void *s, void *acb, int ret, uint64_t offset, size_t len) "s %p acb %p ret %d offset %"PRIu64" len %zu"
+
+# hw/lm32_pic.c
+disable lm32_pic_raise_irq(void) "Raise CPU interrupt"
+disable lm32_pic_lower_irq(void) "Lower CPU interrupt"
+disable lm32_pic_interrupt(int irq, int level) "Set IRQ%d %d"
+disable lm32_pic_set_im(uint32_t im) "im=%08x"
+disable lm32_pic_set_ip(uint32_t ip) "ip=%08x"
+disable lm32_pic_get_im(uint32_t im) "im=%08x"
+disable lm32_pic_get_ip(uint32_t ip) "ip=%08x"
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 07/17] lm32: juart model
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (5 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 06/17] lm32: interrupt controller model Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 08/17] lm32: pic and juart helper functions Michael Walle
                   ` (10 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds the JTAG UART model. It is accessed through special control
registers and opcodes. Therefore the translation uses callbacks to this
model.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 hw/lm32_juart.c |  151 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 hw/lm32_juart.h |   10 ++++
 trace-events    |    6 ++
 3 files changed, 167 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm32_juart.c
 create mode 100644 hw/lm32_juart.h

diff --git a/hw/lm32_juart.c b/hw/lm32_juart.c
new file mode 100644
index 0000000..fdeeefd
--- /dev/null
+++ b/hw/lm32_juart.c
@@ -0,0 +1,151 @@
+/*
+ *  LatticeMico32 JTAG UART model.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+
+#include "lm32_juart.h"
+
+enum {
+    LM32_JUART_MIN_SAVE_VERSION = 0,
+    LM32_JUART_CURRENT_SAVE_VERSION = 0,
+    LM32_JUART_MAX_SAVE_VERSION = 0,
+};
+
+enum {
+    JTX_FULL = (1<<8),
+};
+
+enum {
+    JRX_FULL = (1<<8),
+};
+
+struct LM32JuartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+
+    uint32_t jtx;
+    uint32_t jrx;
+};
+typedef struct LM32JuartState LM32JuartState;
+
+uint32_t lm32_juart_get_jtx(CPUState *env)
+{
+    LM32JuartState *s = env->juart_env;
+
+    trace_lm32_juart_get_jtx(s->jtx);
+    return s->jtx;
+}
+
+uint32_t lm32_juart_get_jrx(CPUState *env)
+{
+    LM32JuartState *s = env->juart_env;
+
+    trace_lm32_juart_get_jrx(s->jrx);
+    return s->jrx;
+}
+
+void lm32_juart_set_jtx(CPUState *env, uint32_t jtx)
+{
+    LM32JuartState *s = env->juart_env;
+    unsigned char ch = jtx & 0xff;
+
+    trace_lm32_juart_set_jtx(s->jtx);
+
+    s->jtx = jtx;
+    if (s->chr) {
+        qemu_chr_write(s->chr, &ch, 1);
+    }
+}
+
+void lm32_juart_set_jrx(CPUState *env, uint32_t jtx)
+{
+    LM32JuartState *s = env->juart_env;
+
+    trace_lm32_juart_set_jrx(s->jrx);
+    env->juart_env->jrx &= ~JRX_FULL;
+}
+
+static void juart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    LM32JuartState *s = opaque;
+
+    s->jrx = *buf | JRX_FULL;
+}
+
+static int juart_can_rx(void *opaque)
+{
+    LM32JuartState *s = opaque;
+
+    return !(s->jrx & JRX_FULL);
+}
+
+static void juart_event(void *opaque, int event)
+{
+}
+
+static void juart_reset(void *opaque)
+{
+    LM32JuartState *s = opaque;
+
+    s->jtx = 0;
+    s->jrx = 0;
+}
+
+static int lm32_juart_init(SysBusDevice *dev)
+{
+    LM32JuartState *s = FROM_SYSBUS(typeof(*s), dev);
+
+    s->chr = qdev_init_chardev(&dev->qdev);
+    if (s->chr) {
+        qemu_chr_add_handlers(s->chr, juart_can_rx, juart_rx, juart_event, s);
+    }
+
+    qemu_register_reset(juart_reset, s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_juart = {
+    .name = "lm32-juart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32(jtx, LM32JuartState),
+        VMSTATE_UINT32(jrx, LM32JuartState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_juart_info = {
+    .init = lm32_juart_init,
+    .qdev.name = "lm32-juart",
+    .qdev.size = sizeof(LM32JuartState),
+    .qdev.vmsd  = &vmstate_lm32_juart,
+};
+
+static void lm32_juart_register(void)
+{
+    sysbus_register_withprop(&lm32_juart_info);
+}
+
+device_init(lm32_juart_register)
diff --git a/hw/lm32_juart.h b/hw/lm32_juart.h
new file mode 100644
index 0000000..5dc0338
--- /dev/null
+++ b/hw/lm32_juart.h
@@ -0,0 +1,10 @@
+#ifndef __LM32_JUART
+#define __LM32_JUART
+
+#include "qemu-common.h"
+
+uint32_t lm32_juart_get_jtx(CPUState *env);
+uint32_t lm32_juart_get_jrx(CPUState *env);
+void lm32_juart_set_jtx(CPUState *env, uint32_t jtx);
+void lm32_juart_set_jrx(CPUState *env, uint32_t jrx);
+#endif
diff --git a/trace-events b/trace-events
index 377bc25..c82588f 100644
--- a/trace-events
+++ b/trace-events
@@ -222,3 +222,9 @@ disable lm32_pic_set_im(uint32_t im) "im=%08x"
 disable lm32_pic_set_ip(uint32_t ip) "ip=%08x"
 disable lm32_pic_get_im(uint32_t im) "im=%08x"
 disable lm32_pic_get_ip(uint32_t ip) "ip=%08x"
+
+# hw/lm32_juart.c
+disable lm32_juart_get_jtx(uint32_t value) "value=%08x"
+disable lm32_juart_set_jtx(uint32_t value) "value=%08x"
+disable lm32_juart_get_jrx(uint32_t value) "value=%08x"
+disable lm32_juart_set_jrx(uint32_t value) "value=%08x"
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 08/17] lm32: pic and juart helper functions
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (6 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 07/17] lm32: juart model Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 09/17] lm32: timer model Michael Walle
                   ` (9 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds init functions for the PIC and JTAG UART commonly used
in the board initialization.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 hw/lm32.h |   31 +++++++++++++++++++++++++++++++
 1 files changed, 31 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm32.h

diff --git a/hw/lm32.h b/hw/lm32.h
new file mode 100644
index 0000000..9369499
--- /dev/null
+++ b/hw/lm32.h
@@ -0,0 +1,31 @@
+
+#include "qemu-common.h"
+
+static inline DeviceState *lm32_pic_init(CPUState *env, qemu_irq cpu_irq)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+
+    dev = qdev_create(NULL, "lm32-pic");
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+    sysbus_connect_irq(d, 0, cpu_irq);
+
+    env->pic_env = (struct LM32PicState *)dev;
+
+    return dev;
+}
+
+static inline DeviceState *lm32_juart_init(CPUState *env)
+{
+    DeviceState *dev;
+    SysBusDevice *d;
+
+    dev = qdev_create(NULL, "lm32-juart");
+    qdev_init_nofail(dev);
+    d = sysbus_from_qdev(dev);
+
+    env->juart_env = (struct LM32JuartState *)dev;
+
+    return dev;
+}
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 09/17] lm32: timer model
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (7 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 08/17] lm32: pic and juart helper functions Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 10/17] lm32: uart model Michael Walle
                   ` (8 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for the LatticeMico32 system timer.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target |    1 +
 hw/lm32_timer.c |  227 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events    |    6 ++
 3 files changed, 234 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm32_timer.c

diff --git a/Makefile.target b/Makefile.target
index c9a61a0..04c4214 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -251,6 +251,7 @@ obj-ppc-y += xilinx_ethlite.o
 obj-lm32-y += lm32_pic.o
 obj-lm32-y += lm32_pic_cpu.o
 obj-lm32-y += lm32_juart.o
+obj-lm32-y += lm32_timer.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/lm32_timer.c b/hw/lm32_timer.c
new file mode 100644
index 0000000..3bfc29d
--- /dev/null
+++ b/hw/lm32_timer.c
@@ -0,0 +1,227 @@
+/*
+ *  QEMU model of the LatticeMico32 timer block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.latticesemi.com/documents/mico32timer.pdf
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-timer.h"
+
+#define DEFAULT_FREQUENCY (50*1000000)
+
+enum {
+    R_SR = 0,
+    R_CR,
+    R_PERIOD,
+    R_SNAPSHOT,
+    R_MAX
+};
+
+enum {
+    SR_TO    = (1 << 0),
+    SR_RUN   = (1 << 1),
+};
+
+enum {
+    CR_ITO   = (1 << 0),
+    CR_CONT  = (1 << 1),
+    CR_START = (1 << 2),
+    CR_STOP  = (1 << 3),
+};
+
+struct LM32TimerState {
+    SysBusDevice busdev;
+
+    QEMUBH *bh;
+    ptimer_state *ptimer;
+
+    qemu_irq irq;
+    uint32_t freq_hz;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32TimerState LM32TimerState;
+
+static void timer_update_irq(LM32TimerState *s)
+{
+    int state = s->regs[R_SR] & SR_TO && s->regs[R_CR] & CR_ITO;
+
+    trace_lm32_timer_irq_state(state);
+    qemu_set_irq(s->irq, state);
+}
+
+static uint32_t timer_read(void *opaque, target_phys_addr_t addr)
+{
+    LM32TimerState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+    case R_CR:
+    case R_PERIOD:
+        r = s->regs[addr];
+        break;
+    case R_SNAPSHOT:
+        r = (uint32_t)ptimer_get_count(s->ptimer);
+        break;
+
+    default:
+        hw_error("lm32_timer: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    }
+
+    trace_lm32_timer_memory_read(addr << 2, r);
+    return r;
+}
+
+static void timer_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_SR:
+        s->regs[R_SR] &= ~SR_TO;
+        break;
+    case R_CR:
+        s->regs[R_CR] = value;
+        if (s->regs[R_CR] & CR_START) {
+            ptimer_run(s->ptimer, 1);
+        }
+        if (s->regs[R_CR] & CR_STOP) {
+            ptimer_stop(s->ptimer);
+        }
+        break;
+    case R_PERIOD:
+        s->regs[R_PERIOD] = value;
+        ptimer_set_count(s->ptimer, value);
+        break;
+    case R_SNAPSHOT:
+        hw_error("lm32_timer: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        hw_error("lm32_timer: write access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    timer_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const timer_read_fn[] = {
+    NULL,
+    NULL,
+    &timer_read,
+};
+
+static CPUWriteMemoryFunc * const timer_write_fn[] = {
+    NULL,
+    NULL,
+    &timer_write,
+};
+
+static void timer_hit(void *opaque)
+{
+    LM32TimerState *s = opaque;
+
+    trace_lm32_timer_hit();
+
+    s->regs[R_SR] |= SR_TO;
+
+    if (s->regs[R_CR] & CR_CONT) {
+        ptimer_set_count(s->ptimer, s->regs[R_PERIOD]);
+        ptimer_run(s->ptimer, 1);
+    }
+
+    timer_update_irq(s);
+}
+
+static void timer_reset(void *opaque)
+{
+    LM32TimerState *s = opaque;
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    ptimer_stop(s->ptimer);
+    qemu_irq_lower(s->irq);
+}
+
+static int lm32_timer_init(SysBusDevice *dev)
+{
+    LM32TimerState *s = FROM_SYSBUS(typeof(*s), dev);
+    int timer_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    s->bh = qemu_bh_new(timer_hit, s);
+    s->ptimer = ptimer_init(s->bh);
+    ptimer_set_freq(s->ptimer, s->freq_hz);
+
+    timer_regs = cpu_register_io_memory(timer_read_fn, timer_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, timer_regs);
+
+    qemu_register_reset(timer_reset, s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_timer = {
+    .name = "lm32-timer",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_PTIMER(ptimer, LM32TimerState),
+        VMSTATE_UINT32(freq_hz, LM32TimerState),
+        VMSTATE_UINT32_ARRAY(regs, LM32TimerState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_timer_info = {
+    .init = lm32_timer_init,
+    .qdev.name  = "lm32-timer",
+    .qdev.size  = sizeof(LM32TimerState),
+    .qdev.vmsd  = &vmstate_lm32_timer,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32(
+                "frequency", LM32TimerState, freq_hz, DEFAULT_FREQUENCY
+        ),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lm32_timer_register(void)
+{
+    sysbus_register_withprop(&lm32_timer_info);
+}
+
+device_init(lm32_timer_register)
diff --git a/trace-events b/trace-events
index c82588f..357c5f7 100644
--- a/trace-events
+++ b/trace-events
@@ -228,3 +228,9 @@ disable lm32_juart_get_jtx(uint32_t value) "value=%08x"
 disable lm32_juart_set_jtx(uint32_t value) "value=%08x"
 disable lm32_juart_get_jrx(uint32_t value) "value=%08x"
 disable lm32_juart_set_jrx(uint32_t value) "value=%08x"
+
+# hw/lm32_timer.c
+disable lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+disable lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+disable lm32_timer_hit(void) "Timer hit"
+disable lm32_timer_irq_state(int level) "Timer IRQ state %d"
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 10/17] lm32: uart model
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (8 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 09/17] lm32: timer model Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 11/17] lm32: system control model Michael Walle
                   ` (7 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch add support for the LatticeMico32 UART.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target |    1 +
 hw/lm32_uart.c  |  292 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events    |    5 +
 3 files changed, 298 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm32_uart.c

diff --git a/Makefile.target b/Makefile.target
index 04c4214..b5f2b2e 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -252,6 +252,7 @@ obj-lm32-y += lm32_pic.o
 obj-lm32-y += lm32_pic_cpu.o
 obj-lm32-y += lm32_juart.o
 obj-lm32-y += lm32_timer.o
+obj-lm32-y += lm32_uart.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/lm32_uart.c b/hw/lm32_uart.c
new file mode 100644
index 0000000..7c9c55c
--- /dev/null
+++ b/hw/lm32_uart.c
@@ -0,0 +1,292 @@
+/*
+ *  QEMU model of the LatticeMico32 UART block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Specification available at:
+ *   http://www.latticesemi.com/documents/mico32uart.pdf
+ */
+
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-char.h"
+
+enum {
+    R_RXTX = 0,
+    R_IER,
+    R_IIR,
+    R_LCR,
+    R_MCR,
+    R_LSR,
+    R_MSR,
+    R_DIV,
+    R_MAX
+};
+
+enum {
+    IER_RBRI = (1<<0),
+    IER_THRI = (1<<1),
+    IER_RLSI = (1<<2),
+    IER_MSI  = (1<<3),
+};
+
+enum {
+    IIR_STAT = (1<<0),
+    IIR_ID0  = (1<<1),
+    IIR_ID1  = (1<<2),
+};
+
+enum {
+    LCR_WLS0 = (1<<0),
+    LCR_WLS1 = (1<<1),
+    LCR_STB  = (1<<2),
+    LCR_PEN  = (1<<3),
+    LCR_EPS  = (1<<4),
+    LCR_SP   = (1<<5),
+    LCR_SB   = (1<<6),
+};
+
+enum {
+    MCR_DTR  = (1<<0),
+    MCR_RTS  = (1<<1),
+};
+
+enum {
+    LSR_DR   = (1<<0),
+    LSR_OE   = (1<<1),
+    LSR_PE   = (1<<2),
+    LSR_FE   = (1<<3),
+    LSR_BI   = (1<<4),
+    LSR_THRE = (1<<5),
+    LSR_TEMT = (1<<6),
+};
+
+enum {
+    MSR_DCTS = (1<<0),
+    MSR_DDSR = (1<<1),
+    MSR_TERI = (1<<2),
+    MSR_DDCD = (1<<3),
+    MSR_CTS  = (1<<4),
+    MSR_DSR  = (1<<5),
+    MSR_RI   = (1<<6),
+    MSR_DCD  = (1<<7),
+};
+
+struct LM32UartState {
+    SysBusDevice busdev;
+    CharDriverState *chr;
+    qemu_irq irq;
+
+    uint32_t regs[R_MAX];
+};
+typedef struct LM32UartState LM32UartState;
+
+static void uart_update_irq(LM32UartState *s)
+{
+    unsigned int irq;
+
+    if ((s->regs[R_LSR] & (LSR_OE | LSR_PE | LSR_FE | LSR_BI))
+            && (s->regs[R_IER] & IER_RLSI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1 | IIR_ID0;
+    } else if ((s->regs[R_LSR] & LSR_DR) && (s->regs[R_IER] & IER_RBRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID1;
+    } else if ((s->regs[R_LSR] & LSR_THRE) && (s->regs[R_IER] & IER_THRI)) {
+        irq = 1;
+        s->regs[R_IIR] = IIR_ID0;
+    } else if ((s->regs[R_MSR] & 0x0f) && (s->regs[R_IER] & IER_MSI)) {
+        irq = 1;
+        s->regs[R_IIR] = 0;
+    } else {
+        irq = 0;
+        s->regs[R_IIR] = IIR_STAT;
+    }
+
+    trace_lm32_uart_irq_state(irq);
+    qemu_set_irq(s->irq, irq);
+}
+
+static uint32_t uart_read(void *opaque, target_phys_addr_t addr)
+{
+    LM32UartState *s = opaque;
+    uint32_t r = 0;
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        r = s->regs[R_RXTX];
+        s->regs[R_LSR] &= ~LSR_DR;
+        uart_update_irq(s);
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        r = s->regs[addr];
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        hw_error("lm32_uart: read access to write only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        hw_error("lm32_uart: read access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+
+    trace_lm32_uart_memory_read(addr << 2, r);
+
+    return r;
+}
+
+static void uart_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32UartState *s = opaque;
+    unsigned char ch = value;
+
+    trace_lm32_uart_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_RXTX:
+        if (s->chr) {
+            qemu_chr_write(s->chr, &ch, 1);
+        }
+        break;
+    case R_IER:
+    case R_LCR:
+    case R_MCR:
+    case R_DIV:
+        s->regs[addr] = value;
+        break;
+    case R_IIR:
+    case R_LSR:
+    case R_MSR:
+        hw_error("lm32_uart: write access to read only register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+
+    default:
+        hw_error("lm32_uart: write access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+    uart_update_irq(s);
+}
+
+static CPUReadMemoryFunc * const uart_read_fn[] = {
+    NULL,
+    NULL,
+    &uart_read,
+};
+
+static CPUWriteMemoryFunc * const uart_write_fn[] = {
+    NULL,
+    NULL,
+    &uart_write,
+};
+
+static void uart_rx(void *opaque, const uint8_t *buf, int size)
+{
+    LM32UartState *s = opaque;
+
+    if (s->regs[R_LSR] & LSR_DR) {
+        s->regs[R_LSR] |= LSR_OE;
+    }
+
+    s->regs[R_LSR] |= LSR_DR;
+    s->regs[R_RXTX] = *buf;
+
+    uart_update_irq(s);
+}
+
+static int uart_can_rx(void *opaque)
+{
+    LM32UartState *s = opaque;
+
+    return !(s->regs[R_LSR] & LSR_DR);
+}
+
+static void uart_event(void *opaque, int event)
+{
+}
+
+static void uart_reset(void *opaque)
+{
+    LM32UartState *s = opaque;
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    qemu_irq_lower(s->irq);
+
+    /* defaults */
+    s->regs[R_LSR] = LSR_THRE | LSR_TEMT;
+}
+
+static int lm32_uart_init(SysBusDevice *dev)
+{
+    LM32UartState *s = FROM_SYSBUS(typeof(*s), dev);
+    int uart_regs;
+
+    sysbus_init_irq(dev, &s->irq);
+
+    uart_regs = cpu_register_io_memory(uart_read_fn, uart_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    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);
+    }
+
+    qemu_register_reset(uart_reset, s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_uart = {
+    .name = "lm32-uart",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32UartState, R_MAX),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_uart_info = {
+    .init = lm32_uart_init,
+    .qdev.name  = "lm32-uart",
+    .qdev.size  = sizeof(LM32UartState),
+    .qdev.vmsd  = &vmstate_lm32_uart,
+};
+
+static void lm32_uart_register(void)
+{
+    sysbus_register_withprop(&lm32_uart_info);
+}
+
+device_init(lm32_uart_register)
diff --git a/trace-events b/trace-events
index 357c5f7..7875cdb 100644
--- a/trace-events
+++ b/trace-events
@@ -234,3 +234,8 @@ disable lm32_timer_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=
 disable lm32_timer_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
 disable lm32_timer_hit(void) "Timer hit"
 disable lm32_timer_irq_state(int level) "Timer IRQ state %d"
+
+# hw/lm32_uart.c
+disable lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+disable lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
+disable lm32_uart_irq_state(int level) "UART IRQ state %d"
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 11/17] lm32: system control model
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (9 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 10/17] lm32: uart model Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 12/17] lm32: support for creating device tree Michael Walle
                   ` (6 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch add support for a system control block. It is supposed to
act as helper for the emulated program. E.g. shutting down the VM or
printing test results. This model is intended for testing purposes only and
doesn't fit to any real hardware. Therefore, it is not added to any board
by default. Instead a user has to add it explicitly with the '-device'
commandline parameter.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target |    1 +
 hw/lm32_sys.c   |  156 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 trace-events    |    3 +
 3 files changed, 160 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm32_sys.c

diff --git a/Makefile.target b/Makefile.target
index b5f2b2e..3eefdf0 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -253,6 +253,7 @@ obj-lm32-y += lm32_pic_cpu.o
 obj-lm32-y += lm32_juart.o
 obj-lm32-y += lm32_timer.o
 obj-lm32-y += lm32_uart.o
+obj-lm32-y += lm32_sys.o
 
 obj-mips-y = mips_r4k.o mips_jazz.o mips_malta.o mips_mipssim.o
 obj-mips-y += mips_addr.o mips_timer.o mips_int.o
diff --git a/hw/lm32_sys.c b/hw/lm32_sys.c
new file mode 100644
index 0000000..66c23a5
--- /dev/null
+++ b/hw/lm32_sys.c
@@ -0,0 +1,156 @@
+/*
+ *  QEMU model of the LatticeMico32 system control block.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This model is mainly intended for testing purposes and doesn't fit to any
+ * real hardware. On the one hand it provides a control register (R_CTRL) on
+ * the other hand it supports the lm32 tests.
+ *
+ * A write to the control register causes a system shutdown.
+ * Tests first write the pointer to a test name to the test name register
+ * (R_TESTNAME) and then write a zero to the pass/fail register (R_PASSFAIL) if
+ * the test is passed or any non-zero value to it if the test is failed.
+ */
+
+#include "hw.h"
+#include "sysbus.h"
+#include "trace.h"
+#include "qemu-log.h"
+#include "sysemu.h"
+#include "qemu-log.h"
+
+enum {
+    R_CTRL = 0,
+    R_PASSFAIL,
+    R_TESTNAME,
+    R_MAX
+};
+
+#define MAX_TESTNAME_LEN 16
+
+struct LM32SysState {
+    SysBusDevice busdev;
+    uint32_t base;
+    uint32_t regs[R_MAX];
+    uint8_t testname[MAX_TESTNAME_LEN];
+};
+typedef struct LM32SysState LM32SysState;
+
+static void copy_testname(LM32SysState *s)
+{
+    cpu_physical_memory_read(s->regs[R_TESTNAME], s->testname,
+            MAX_TESTNAME_LEN);
+    s->testname[MAX_TESTNAME_LEN - 1] = '\0';
+}
+
+static void sys_write(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+    LM32SysState *s = opaque;
+    char *testname;
+
+    trace_lm32_sys_memory_write(addr, value);
+
+    addr >>= 2;
+    switch (addr) {
+    case R_CTRL:
+        qemu_system_shutdown_request();
+        break;
+    case R_PASSFAIL:
+        s->regs[addr] = value;
+        testname = (char *)s->testname;
+        qemu_log("TC  %-16s %s\n", testname, (value) ? "FAILED" : "OK");
+        break;
+    case R_TESTNAME:
+        s->regs[addr] = value;
+        copy_testname(s);
+        break;
+
+    default:
+        hw_error("lm32_sys: write access to unkown register 0x"
+                TARGET_FMT_plx, addr << 2);
+        break;
+    }
+}
+
+static CPUReadMemoryFunc * const sys_read_fn[] = {
+    NULL,
+    NULL,
+    NULL,
+};
+
+static CPUWriteMemoryFunc * const sys_write_fn[] = {
+    NULL,
+    NULL,
+    &sys_write,
+};
+
+static void sys_reset(void *opaque)
+{
+    LM32SysState *s = opaque;
+    int i;
+
+    for (i = 0; i < R_MAX; i++) {
+        s->regs[i] = 0;
+    }
+    memset(s->testname, 0, MAX_TESTNAME_LEN);
+}
+
+static int lm32_sys_init(SysBusDevice *dev)
+{
+    LM32SysState *s = FROM_SYSBUS(typeof(*s), dev);
+    int sys_regs;
+
+    sys_regs = cpu_register_io_memory(sys_read_fn, sys_write_fn, s,
+            DEVICE_NATIVE_ENDIAN);
+    sysbus_init_mmio(dev, R_MAX * 4, sys_regs);
+    sysbus_mmio_map(dev, 0, s->base);
+    qemu_register_reset(sys_reset, s);
+
+    return 0;
+}
+
+static const VMStateDescription vmstate_lm32_sys = {
+    .name = "lm32-sys",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .minimum_version_id_old = 1,
+    .fields      = (VMStateField[]) {
+        VMSTATE_UINT32_ARRAY(regs, LM32SysState, R_MAX),
+        VMSTATE_BUFFER(testname, LM32SysState),
+        VMSTATE_END_OF_LIST()
+    }
+};
+
+static SysBusDeviceInfo lm32_sys_info = {
+    .init = lm32_sys_init,
+    .qdev.name  = "lm32-sys",
+    .qdev.size  = sizeof(LM32SysState),
+    .qdev.vmsd  = &vmstate_lm32_sys,
+    .qdev.props = (Property[]) {
+        DEFINE_PROP_UINT32("base", LM32SysState, base, 0xffff0000),
+        DEFINE_PROP_END_OF_LIST(),
+    }
+};
+
+static void lm32_sys_register(void)
+{
+    sysbus_register_withprop(&lm32_sys_info);
+}
+
+device_init(lm32_sys_register)
diff --git a/trace-events b/trace-events
index 7875cdb..4c8c5cd 100644
--- a/trace-events
+++ b/trace-events
@@ -239,3 +239,6 @@ disable lm32_timer_irq_state(int level) "Timer IRQ state %d"
 disable lm32_uart_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
 disable lm32_uart_memory_read(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
 disable lm32_uart_irq_state(int level) "UART IRQ state %d"
+
+# hw/lm32_sys.c
+disable lm32_sys_memory_write(uint32_t addr, uint32_t value) "addr=%08x value=%08x"
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 12/17] lm32: support for creating device tree
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (10 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 11/17] lm32: system control model Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 13/17] lm32: EVR32 and uclinux BSP Michael Walle
                   ` (5 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds helper functions to create a ROM, which contains a hardware
description of a board. This is used in Theobromas LM32 Linux port.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 hw/lm32_hwsetup.h |  172 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 172 insertions(+), 0 deletions(-)
 create mode 100644 hw/lm32_hwsetup.h

diff --git a/hw/lm32_hwsetup.h b/hw/lm32_hwsetup.h
new file mode 100644
index 0000000..c7d4e05
--- /dev/null
+++ b/hw/lm32_hwsetup.h
@@ -0,0 +1,172 @@
+/*
+ *  LatticeMico32 hwsetup helper functions.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * These are helper functions for creating the hardware description blob used
+ * in the Theobroma's uClinux port.
+ */
+
+#include "qemu-common.h"
+#include "loader.h"
+
+struct hwsetup {
+    void *data;
+    void *ptr;
+};
+
+enum hwsetup_tag {
+    HWSETUP_TAG_EOL         = 0,
+    HWSETUP_TAG_CPU         = 1,
+    HWSETUP_TAG_ASRAM       = 2,
+    HWSETUP_TAG_FLASH       = 3,
+    HWSETUP_TAG_SDRAM       = 4,
+    HWSETUP_TAG_OCM         = 5,
+    HWSETUP_TAG_DDR_SDRAM   = 6,
+    HWSETUP_TAG_DDR2_SDRAM  = 7,
+    HWSETUP_TAG_TIMER       = 8,
+    HWSETUP_TAG_UART        = 9,
+    HWSETUP_TAG_GPIO        = 10,
+    HWSETUP_TAG_TRISPEEDMAC = 11,
+    HWSETUP_TAG_I2CM        = 12,
+    HWSETUP_TAG_LEDS        = 13,
+    HWSETUP_TAG_7SEG        = 14,
+    HWSETUP_TAG_SPI_S       = 15,
+    HWSETUP_TAG_SPI_M       = 16,
+};
+
+static inline struct hwsetup *hwsetup_init(void)
+{
+    struct hwsetup *hw;
+
+    hw = qemu_malloc(sizeof(struct hwsetup));
+    hw->data = qemu_mallocz(TARGET_PAGE_SIZE);
+    hw->ptr = hw->data;
+
+    return hw;
+}
+
+static inline void hwsetup_free(struct hwsetup *hw)
+{
+    qemu_free(hw->data);
+    qemu_free(hw);
+}
+
+static inline void hwsetup_create_rom(struct hwsetup *hw, ram_addr_t base)
+{
+    rom_add_blob("hwsetup", hw->data, TARGET_PAGE_SIZE, base);
+}
+
+static inline void hwsetup_add_u8(struct hwsetup *hw, uint8_t u)
+{
+    stb_p(hw->ptr, u);
+    hw->ptr += 1;
+}
+
+static inline void hwsetup_add_u32(struct hwsetup *hw, uint32_t u)
+{
+    stl_p(hw->ptr, u);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_tag(struct hwsetup *hw, enum hwsetup_tag t)
+{
+    stl_p(hw->ptr, t);
+    hw->ptr += 4;
+}
+
+static inline void hwsetup_add_str(struct hwsetup *hw, const char *str)
+{
+    strncpy(hw->ptr, str, 31); /* make sure last byte is zero */
+    hw->ptr += 32;
+}
+
+static inline void hwsetup_add_trailer(struct hwsetup *hw)
+{
+    hwsetup_add_u32(hw, 8); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_EOL);
+}
+
+static inline void hwsetup_add_cpu(struct hwsetup *hw,
+        const char *name, uint32_t frequency)
+{
+    hwsetup_add_u32(hw, 44); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_CPU);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, frequency);
+}
+
+static inline void hwsetup_add_flash(struct hwsetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 52); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_FLASH);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+    hwsetup_add_u8(hw, 8); /* read latency */
+    hwsetup_add_u8(hw, 8); /* write latency */
+    hwsetup_add_u8(hw, 25); /* address width */
+    hwsetup_add_u8(hw, 32); /* data width */
+}
+
+static inline void hwsetup_add_ddr_sdram(struct hwsetup *hw,
+        const char *name, uint32_t base, uint32_t size)
+{
+    hwsetup_add_u32(hw, 48); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_DDR_SDRAM);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, size);
+}
+
+static inline void hwsetup_add_timer(struct hwsetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_TIMER);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u8(hw, 1); /* wr_tickcount */
+    hwsetup_add_u8(hw, 1); /* rd_tickcount */
+    hwsetup_add_u8(hw, 1); /* start_stop_control */
+    hwsetup_add_u8(hw, 32); /* counter_width */
+    hwsetup_add_u32(hw, 20); /* reload_ticks */
+    hwsetup_add_u8(hw, irq);
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+    hwsetup_add_u8(hw, 0); /* padding */
+}
+
+static inline void hwsetup_add_uart(struct hwsetup *hw,
+        const char *name, uint32_t base, uint32_t irq)
+{
+    hwsetup_add_u32(hw, 56); /* size */
+    hwsetup_add_tag(hw, HWSETUP_TAG_UART);
+    hwsetup_add_str(hw, name);
+    hwsetup_add_u32(hw, base);
+    hwsetup_add_u32(hw, 115200); /* baudrate */
+    hwsetup_add_u8(hw, 8); /* databits */
+    hwsetup_add_u8(hw, 1); /* stopbits */
+    hwsetup_add_u8(hw, 1); /* use_interrupt */
+    hwsetup_add_u8(hw, 1); /* block_on_transmit */
+    hwsetup_add_u8(hw, 1); /* block_on_receive */
+    hwsetup_add_u8(hw, 4); /* rx_buffer_size */
+    hwsetup_add_u8(hw, 4); /* tx_buffer_size */
+    hwsetup_add_u8(hw, irq);
+}
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 13/17] lm32: EVR32 and uclinux BSP
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (11 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 12/17] lm32: support for creating device tree Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 14/17] lm32: todo and documentation Michael Walle
                   ` (4 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds support for the following two BSPs:
 - LM32 EVR32 BSP (as used by RTEMS)
 - uclinux BSP by Theobroma Systems

Signed-off-by: Michael Walle <michael@walle.cc>
---
 Makefile.target                  |    3 +
 default-configs/lm32-softmmu.mak |    4 +
 hw/lm32_boards.c                 |  295 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 302 insertions(+), 0 deletions(-)
 create mode 100644 default-configs/lm32-softmmu.mak
 create mode 100644 hw/lm32_boards.c

diff --git a/Makefile.target b/Makefile.target
index 3eefdf0..b78f038 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -247,6 +247,9 @@ obj-ppc-y += xilinx_timer.o
 obj-ppc-y += xilinx_uartlite.o
 obj-ppc-y += xilinx_ethlite.o
 
+# LM32 boards
+obj-lm32-y += lm32_boards.o
+
 # LM32 peripherals
 obj-lm32-y += lm32_pic.o
 obj-lm32-y += lm32_pic_cpu.o
diff --git a/default-configs/lm32-softmmu.mak b/default-configs/lm32-softmmu.mak
new file mode 100644
index 0000000..ab774a2
--- /dev/null
+++ b/default-configs/lm32-softmmu.mak
@@ -0,0 +1,4 @@
+# Default configuration for lm32-softmmu
+
+CONFIG_PTIMER=y
+CONFIG_PFLASH_CFI02=y
diff --git a/hw/lm32_boards.c b/hw/lm32_boards.c
new file mode 100644
index 0000000..c174c17
--- /dev/null
+++ b/hw/lm32_boards.c
@@ -0,0 +1,295 @@
+/*
+ *  QEMU models for LatticeMico32 uclinux and evr32 boards.
+ *
+ *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "sysbus.h"
+#include "hw.h"
+#include "net.h"
+#include "flash.h"
+#include "sysemu.h"
+#include "devices.h"
+#include "boards.h"
+#include "loader.h"
+#include "blockdev.h"
+#include "elf.h"
+#include "lm32_hwsetup.h"
+#include "lm32.h"
+
+struct reset_info {
+    CPUState *env;
+    uint32_t bootstrap_pc;
+    uint32_t flash_base;
+    uint32_t hwsetup_base;
+    uint32_t initrd_base;
+    uint32_t initrd_size;
+    uint32_t cmdline_base;
+};
+
+qemu_irq *lm32_pic_init_cpu(CPUState *env);
+
+static void main_cpu_reset(void *opaque)
+{
+    struct reset_info *reset_info = opaque;
+    CPUState *env = reset_info->env;
+
+    cpu_reset(env);
+
+    /* init defaults */
+    env->pc = reset_info->bootstrap_pc;
+    env->regs[R_R1] = reset_info->hwsetup_base;
+    env->regs[R_R2] = reset_info->cmdline_base;
+    env->regs[R_R3] = reset_info->initrd_base;
+    env->regs[R_R4] = reset_info->initrd_base + reset_info->initrd_size;
+    env->eba = reset_info->flash_base;
+    env->deba = reset_info->flash_base;
+}
+
+static void lm32_evr_init(ram_addr_t ram_size_not_used,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    DriveInfo *dinfo;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq *cpu_irq, irq[32];
+    DeviceState *dev;
+    struct reset_info *reset_info;
+    int i;
+
+    /* memory map */
+    ram_addr_t flash_base    = 0x04000000;
+    size_t flash_sector_size = 256 * 1024;
+    size_t flash_size        = 32 * 1024 * 1024;
+    ram_addr_t ram_base      = 0x08000000;
+    size_t ram_size          = 64 * 1024 * 1024;
+    ram_addr_t timer0_base   = 0x80002000;
+    ram_addr_t uart0_base    = 0x80006000;
+    ram_addr_t timer1_base   = 0x8000a000;
+    int uart0_irq            = 0;
+    int timer0_irq           = 1;
+    int timer1_irq           = 3;
+
+    reset_info = qemu_mallocz(sizeof(struct reset_info));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    reset_info->flash_base = flash_base;
+
+    phys_ram = qemu_ram_alloc(NULL, "lm32_evr.sdram", ram_size);
+    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "lm32_evr.flash", flash_size);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
+
+    cpu_irq = lm32_pic_init_cpu(env);
+    dev = lm32_pic_init(env, *cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+
+    /* make sure juart isn't the first chardev */
+    lm32_juart_init(env);
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static void lm32_uclinux_init(ram_addr_t ram_size_not_used,
+                          const char *boot_device,
+                          const char *kernel_filename,
+                          const char *kernel_cmdline,
+                          const char *initrd_filename, const char *cpu_model)
+{
+    CPUState *env;
+    DriveInfo *dinfo;
+    ram_addr_t phys_ram;
+    ram_addr_t phys_flash;
+    qemu_irq *cpu_irq, irq[32];
+    DeviceState *dev;
+    struct hwsetup *hw;
+    struct reset_info *reset_info;
+    int i;
+
+    /* memory map */
+    ram_addr_t flash_base    = 0x04000000;
+    size_t flash_sector_size = 256 * 1024;
+    size_t flash_size        = 32 * 1024 * 1024;
+    ram_addr_t ram_base      = 0x08000000;
+    size_t ram_size          = 64 * 1024 * 1024;
+    ram_addr_t uart0_base    = 0x80000000;
+    ram_addr_t timer0_base   = 0x80002000;
+    ram_addr_t timer1_base   = 0x80010000;
+    ram_addr_t timer2_base   = 0x80012000;
+    int uart0_irq            = 0;
+    int timer0_irq           = 1;
+    int timer1_irq           = 20;
+    int timer2_irq           = 21;
+    ram_addr_t hwsetup_base  = 0x0bffe000;
+    ram_addr_t cmdline_base  = 0x0bfff000;
+    ram_addr_t initrd_base   = 0x08400000;
+    size_t initrd_max        = 0x01000000;
+
+    reset_info = qemu_mallocz(sizeof(struct reset_info));
+
+    if (cpu_model == NULL) {
+        cpu_model = "lm32-full";
+    }
+    env = cpu_init(cpu_model);
+    reset_info->env = env;
+
+    reset_info->flash_base = flash_base;
+
+    phys_ram = qemu_ram_alloc(NULL, "lm32_uclinux.sdram", ram_size);
+    cpu_register_physical_memory(ram_base, ram_size, phys_ram | IO_MEM_RAM);
+
+    phys_flash = qemu_ram_alloc(NULL, "lm32_uclinux.flash", flash_size);
+    dinfo = drive_get(IF_PFLASH, 0, 0);
+    /* Spansion S29NS128P */
+    pflash_cfi02_register(flash_base, phys_flash,
+                          dinfo ? dinfo->bdrv : NULL, flash_sector_size,
+                          flash_size / flash_sector_size, 1, 2,
+                          0x01, 0x7e, 0x43, 0x00, 0x555, 0x2aa, 1);
+
+    cpu_irq = lm32_pic_init_cpu(env);
+    dev = lm32_pic_init(env, *cpu_irq);
+    for (i = 0; i < 32; i++) {
+        irq[i] = qdev_get_gpio_in(dev, i);
+    }
+
+    sysbus_create_simple("lm32-uart", uart0_base, irq[uart0_irq]);
+    sysbus_create_simple("lm32-timer", timer0_base, irq[timer0_irq]);
+    sysbus_create_simple("lm32-timer", timer1_base, irq[timer1_irq]);
+    sysbus_create_simple("lm32-timer", timer2_base, irq[timer2_irq]);
+
+    /* make sure juart isn't the first chardev */
+    lm32_juart_init(env);
+
+    reset_info->bootstrap_pc = flash_base;
+
+    if (kernel_filename) {
+        uint64_t entry;
+        int kernel_size;
+
+        kernel_size = load_elf(kernel_filename, NULL, NULL, &entry, NULL, NULL,
+                               1, ELF_MACHINE, 0);
+        reset_info->bootstrap_pc = entry;
+
+        if (kernel_size < 0) {
+            kernel_size = load_image_targphys(kernel_filename, ram_base,
+                                              ram_size);
+            reset_info->bootstrap_pc = ram_base;
+        }
+
+        if (kernel_size < 0) {
+            fprintf(stderr, "qemu: could not load kernel '%s'\n",
+                    kernel_filename);
+            exit(1);
+        }
+    }
+
+    /* generate a rom with the hardware description */
+    hw = hwsetup_init();
+    hwsetup_add_cpu(hw, "LM32", 75000000);
+    hwsetup_add_flash(hw, "flash", flash_base, flash_size);
+    hwsetup_add_ddr_sdram(hw, "ddr_sdram", ram_base, ram_size);
+    hwsetup_add_timer(hw, "timer0", timer0_base, timer0_irq);
+    hwsetup_add_timer(hw, "timer1_dev_only", timer1_base, timer1_irq);
+    hwsetup_add_timer(hw, "timer2_dev_only", timer2_base, timer2_irq);
+    hwsetup_add_uart(hw, "uart", uart0_base, uart0_irq);
+    hwsetup_add_trailer(hw);
+    hwsetup_create_rom(hw, hwsetup_base);
+    hwsetup_free(hw);
+
+    reset_info->hwsetup_base = (uint32_t)hwsetup_base;
+
+    if (kernel_cmdline && strlen(kernel_cmdline)) {
+        pstrcpy_targphys("cmdline", cmdline_base, TARGET_PAGE_SIZE,
+                kernel_cmdline);
+        reset_info->cmdline_base = (uint32_t)cmdline_base;
+    }
+
+    if (initrd_filename) {
+        size_t initrd_size;
+        initrd_size = load_image_targphys(initrd_filename, initrd_base,
+                initrd_max);
+        reset_info->initrd_base = (uint32_t)initrd_base;
+        reset_info->initrd_size = (uint32_t)initrd_size;
+    }
+
+    qemu_register_reset(main_cpu_reset, reset_info);
+}
+
+static QEMUMachine lm32_evr_machine = {
+    .name = "lm32-evr",
+    .desc = "LatticeMico32 EVR32 eval system",
+    .init = lm32_evr_init,
+    .is_default = 1
+};
+
+static QEMUMachine lm32_uclinux_machine = {
+    .name = "lm32-uclinux",
+    .desc = "lm32 platform for uClinux and u-boot by Theobroma Systems",
+    .init = lm32_uclinux_init,
+    .is_default = 0
+};
+
+static void lm32_machine_init(void)
+{
+    qemu_register_machine(&lm32_uclinux_machine);
+    qemu_register_machine(&lm32_evr_machine);
+}
+
+machine_init(lm32_machine_init);
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 14/17] lm32: todo and documentation
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (12 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 13/17] lm32: EVR32 and uclinux BSP Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 15/17] lm32: opcode testsuite Michael Walle
                   ` (3 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch adds general target documentation and a todo list.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 target-lm32/README |   46 ++++++++++++++++++++++++++++++++++++++++++++++
 target-lm32/TODO   |    3 +++
 2 files changed, 49 insertions(+), 0 deletions(-)
 create mode 100644 target-lm32/README
 create mode 100644 target-lm32/TODO

diff --git a/target-lm32/README b/target-lm32/README
new file mode 100644
index 0000000..a1c2c7e
--- /dev/null
+++ b/target-lm32/README
@@ -0,0 +1,46 @@
+LatticeMico32 target
+--------------------
+
+General
+-------
+All opcodes including the JUART CSRs are supported.
+
+
+JTAG UART
+---------
+JTAG UART is routed to a serial console device. For the current boards it
+is the second one. Ie to enable it in the qemu virtual console window use
+the following command line parameters:
+  -serial vc -serial vc
+This will make serial0 (the lm32_uart) and serial1 (the JTAG UART)
+available as virtual consoles.
+
+
+Programmatically terminate the emulator
+----------------------------------------
+Originally neither the LatticeMico32 nor its peripherals support a
+mechanism to shut down the machine. Emulation aware programs can write to a
+to a special register within the system control block to shut down the
+virtual machine.  For more details see hw/lm32_sys.c. The lm32-evr is the
+first BSP which instantiate this model. A (32 bit) write to 0xfff0000
+causes a vm shutdown.
+
+
+Special instructions
+--------------------
+The translation recognizes one special instruction to halt the cpu:
+  and r0, r0, r0
+On real hardware this instruction is a nop. It is not used by GCC and
+should (hopefully) not be used within hand-crafted assembly.
+Insert this instruction in your idle loop to reduce the cpu load on the
+host.
+
+
+Ignoring the MSB of the address bus
+-----------------------------------
+Some SoC ignores the MSB on the address bus. Thus creating a shadow memory
+area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
+0x80000000-0xffffffff is not cached and used to access IO devices. This
+behaviour can be enabled with:
+  cpu_lm32_set_phys_msb_ignore(env, 1);
+
diff --git a/target-lm32/TODO b/target-lm32/TODO
new file mode 100644
index 0000000..b9ea0c8
--- /dev/null
+++ b/target-lm32/TODO
@@ -0,0 +1,3 @@
+* disassembler (lm32-dis.c)
+* linux-user emulation
+* native bp/wp emulation (?)
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 15/17] lm32: opcode testsuite
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (13 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 14/17] lm32: todo and documentation Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 16/17] Add lm32 target to configure Michael Walle
                   ` (2 subsequent siblings)
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

This patch creates tests/lm32 directory and adds tests for every
LatticeMico32 opcode.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 tests/Makefile            |    4 ++
 tests/lm32/Makefile       |  102 +++++++++++++++++++++++++++++++++++++++++++++
 tests/lm32/crt.S          |   84 +++++++++++++++++++++++++++++++++++++
 tests/lm32/linker.ld      |   55 ++++++++++++++++++++++++
 tests/lm32/macros.inc     |   79 ++++++++++++++++++++++++++++++++++
 tests/lm32/test_add.S     |   75 +++++++++++++++++++++++++++++++++
 tests/lm32/test_addi.S    |   56 ++++++++++++++++++++++++
 tests/lm32/test_and.S     |   45 ++++++++++++++++++++
 tests/lm32/test_andhi.S   |   35 +++++++++++++++
 tests/lm32/test_andi.S    |   35 +++++++++++++++
 tests/lm32/test_b.S       |   13 ++++++
 tests/lm32/test_be.S      |   48 +++++++++++++++++++++
 tests/lm32/test_bg.S      |   78 ++++++++++++++++++++++++++++++++++
 tests/lm32/test_bge.S     |   78 ++++++++++++++++++++++++++++++++++
 tests/lm32/test_bgeu.S    |   78 ++++++++++++++++++++++++++++++++++
 tests/lm32/test_bgu.S     |   78 ++++++++++++++++++++++++++++++++++
 tests/lm32/test_bi.S      |   23 ++++++++++
 tests/lm32/test_bne.S     |   48 +++++++++++++++++++++
 tests/lm32/test_break.S   |   20 +++++++++
 tests/lm32/test_bret.S    |   38 +++++++++++++++++
 tests/lm32/test_call.S    |   16 +++++++
 tests/lm32/test_calli.S   |   15 +++++++
 tests/lm32/test_cmpe.S    |   40 +++++++++++++++++
 tests/lm32/test_cmpei.S   |   35 +++++++++++++++
 tests/lm32/test_cmpg.S    |   64 ++++++++++++++++++++++++++++
 tests/lm32/test_cmpge.S   |   64 ++++++++++++++++++++++++++++
 tests/lm32/test_cmpgei.S  |   55 ++++++++++++++++++++++++
 tests/lm32/test_cmpgeu.S  |   64 ++++++++++++++++++++++++++++
 tests/lm32/test_cmpgeui.S |   55 ++++++++++++++++++++++++
 tests/lm32/test_cmpgi.S   |   55 ++++++++++++++++++++++++
 tests/lm32/test_cmpgu.S   |   64 ++++++++++++++++++++++++++++
 tests/lm32/test_cmpgui.S  |   55 ++++++++++++++++++++++++
 tests/lm32/test_cmpne.S   |   40 +++++++++++++++++
 tests/lm32/test_cmpnei.S  |   35 +++++++++++++++
 tests/lm32/test_divu.S    |   29 +++++++++++++
 tests/lm32/test_eret.S    |   38 +++++++++++++++++
 tests/lm32/test_lb.S      |   45 ++++++++++++++++++++
 tests/lm32/test_lbu.S     |   45 ++++++++++++++++++++
 tests/lm32/test_lh.S      |   45 ++++++++++++++++++++
 tests/lm32/test_lhu.S     |   45 ++++++++++++++++++++
 tests/lm32/test_lw.S      |   30 +++++++++++++
 tests/lm32/test_modu.S    |   35 +++++++++++++++
 tests/lm32/test_mul.S     |   70 +++++++++++++++++++++++++++++++
 tests/lm32/test_muli.S    |   45 ++++++++++++++++++++
 tests/lm32/test_nor.S     |   51 ++++++++++++++++++++++
 tests/lm32/test_nori.S    |   35 +++++++++++++++
 tests/lm32/test_or.S      |   51 ++++++++++++++++++++++
 tests/lm32/test_orhi.S    |   35 +++++++++++++++
 tests/lm32/test_ori.S     |   35 +++++++++++++++
 tests/lm32/test_ret.S     |   14 ++++++
 tests/lm32/test_sb.S      |   30 +++++++++++++
 tests/lm32/test_scall.S   |   20 +++++++++
 tests/lm32/test_sextb.S   |   20 +++++++++
 tests/lm32/test_sexth.S   |   20 +++++++++
 tests/lm32/test_sh.S      |   30 +++++++++++++
 tests/lm32/test_sl.S      |   45 ++++++++++++++++++++
 tests/lm32/test_sli.S     |   30 +++++++++++++
 tests/lm32/test_sr.S      |   57 +++++++++++++++++++++++++
 tests/lm32/test_sri.S     |   40 +++++++++++++++++
 tests/lm32/test_sru.S     |   57 +++++++++++++++++++++++++
 tests/lm32/test_srui.S    |   40 +++++++++++++++++
 tests/lm32/test_sub.S     |   75 +++++++++++++++++++++++++++++++++
 tests/lm32/test_sw.S      |   35 +++++++++++++++
 tests/lm32/test_xnor.S    |   51 ++++++++++++++++++++++
 tests/lm32/test_xnori.S   |   35 +++++++++++++++
 tests/lm32/test_xor.S     |   51 ++++++++++++++++++++++
 tests/lm32/test_xori.S    |   35 +++++++++++++++
 67 files changed, 3048 insertions(+), 0 deletions(-)
 create mode 100644 tests/lm32/Makefile
 create mode 100644 tests/lm32/crt.S
 create mode 100644 tests/lm32/linker.ld
 create mode 100644 tests/lm32/macros.inc
 create mode 100644 tests/lm32/test_add.S
 create mode 100644 tests/lm32/test_addi.S
 create mode 100644 tests/lm32/test_and.S
 create mode 100644 tests/lm32/test_andhi.S
 create mode 100644 tests/lm32/test_andi.S
 create mode 100644 tests/lm32/test_b.S
 create mode 100644 tests/lm32/test_be.S
 create mode 100644 tests/lm32/test_bg.S
 create mode 100644 tests/lm32/test_bge.S
 create mode 100644 tests/lm32/test_bgeu.S
 create mode 100644 tests/lm32/test_bgu.S
 create mode 100644 tests/lm32/test_bi.S
 create mode 100644 tests/lm32/test_bne.S
 create mode 100644 tests/lm32/test_break.S
 create mode 100644 tests/lm32/test_bret.S
 create mode 100644 tests/lm32/test_call.S
 create mode 100644 tests/lm32/test_calli.S
 create mode 100644 tests/lm32/test_cmpe.S
 create mode 100644 tests/lm32/test_cmpei.S
 create mode 100644 tests/lm32/test_cmpg.S
 create mode 100644 tests/lm32/test_cmpge.S
 create mode 100644 tests/lm32/test_cmpgei.S
 create mode 100644 tests/lm32/test_cmpgeu.S
 create mode 100644 tests/lm32/test_cmpgeui.S
 create mode 100644 tests/lm32/test_cmpgi.S
 create mode 100644 tests/lm32/test_cmpgu.S
 create mode 100644 tests/lm32/test_cmpgui.S
 create mode 100644 tests/lm32/test_cmpne.S
 create mode 100644 tests/lm32/test_cmpnei.S
 create mode 100644 tests/lm32/test_divu.S
 create mode 100644 tests/lm32/test_eret.S
 create mode 100644 tests/lm32/test_lb.S
 create mode 100644 tests/lm32/test_lbu.S
 create mode 100644 tests/lm32/test_lh.S
 create mode 100644 tests/lm32/test_lhu.S
 create mode 100644 tests/lm32/test_lw.S
 create mode 100644 tests/lm32/test_modu.S
 create mode 100644 tests/lm32/test_mul.S
 create mode 100644 tests/lm32/test_muli.S
 create mode 100644 tests/lm32/test_nor.S
 create mode 100644 tests/lm32/test_nori.S
 create mode 100644 tests/lm32/test_or.S
 create mode 100644 tests/lm32/test_orhi.S
 create mode 100644 tests/lm32/test_ori.S
 create mode 100644 tests/lm32/test_ret.S
 create mode 100644 tests/lm32/test_sb.S
 create mode 100644 tests/lm32/test_scall.S
 create mode 100644 tests/lm32/test_sextb.S
 create mode 100644 tests/lm32/test_sexth.S
 create mode 100644 tests/lm32/test_sh.S
 create mode 100644 tests/lm32/test_sl.S
 create mode 100644 tests/lm32/test_sli.S
 create mode 100644 tests/lm32/test_sr.S
 create mode 100644 tests/lm32/test_sri.S
 create mode 100644 tests/lm32/test_sru.S
 create mode 100644 tests/lm32/test_srui.S
 create mode 100644 tests/lm32/test_sub.S
 create mode 100644 tests/lm32/test_sw.S
 create mode 100644 tests/lm32/test_xnor.S
 create mode 100644 tests/lm32/test_xnori.S
 create mode 100644 tests/lm32/test_xor.S
 create mode 100644 tests/lm32/test_xori.S

diff --git a/tests/Makefile b/tests/Makefile
index 9ded4b7..430e0c1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -142,6 +142,10 @@ hello-mipsel: hello-mips.c
 test-cris:
 	$(MAKE) -C cris check
 
+# testsuite for the LM32 port.
+test-lm32:
+	$(MAKE) -C lm32 check
+
 clean:
 	rm -f *~ *.o test-i386.out test-i386.ref \
            test-x86_64.log test-x86_64.ref qruncom $(TESTS)
diff --git a/tests/lm32/Makefile b/tests/lm32/Makefile
new file mode 100644
index 0000000..03a1abb
--- /dev/null
+++ b/tests/lm32/Makefile
@@ -0,0 +1,102 @@
+-include ../../config-host.mak
+
+CROSS=lm32-elf-
+
+SIM = qemu-system-lm32
+SIMFLAGS = -M lm32-evr -nographic -device lm32-sys -net none -kernel
+
+CC      = $(CROSS)gcc
+AS      = $(CROSS)as
+AS      = $(CC) -x assembler
+SIZE    = $(CROSS)size
+LD      = $(CC)
+OBJCOPY = $(CROSS)objcopy
+
+LDFLAGS = -Tlinker.ld
+
+CRT        = crt.o
+TESTCASES += test_add.tst
+TESTCASES += test_addi.tst
+TESTCASES += test_and.tst
+TESTCASES += test_andhi.tst
+TESTCASES += test_andi.tst
+TESTCASES += test_b.tst
+TESTCASES += test_be.tst
+TESTCASES += test_bg.tst
+TESTCASES += test_bge.tst
+TESTCASES += test_bgeu.tst
+TESTCASES += test_bgu.tst
+TESTCASES += test_bi.tst
+TESTCASES += test_bne.tst
+TESTCASES += test_break.tst
+TESTCASES += test_bret.tst
+TESTCASES += test_call.tst
+TESTCASES += test_calli.tst
+TESTCASES += test_cmpe.tst
+TESTCASES += test_cmpei.tst
+TESTCASES += test_cmpg.tst
+TESTCASES += test_cmpgi.tst
+TESTCASES += test_cmpge.tst
+TESTCASES += test_cmpgei.tst
+TESTCASES += test_cmpgeu.tst
+TESTCASES += test_cmpgeui.tst
+TESTCASES += test_cmpgu.tst
+TESTCASES += test_cmpgui.tst
+TESTCASES += test_cmpne.tst
+TESTCASES += test_cmpnei.tst
+TESTCASES += test_divu.tst
+TESTCASES += test_eret.tst
+TESTCASES += test_lb.tst
+TESTCASES += test_lbu.tst
+TESTCASES += test_lh.tst
+TESTCASES += test_lhu.tst
+TESTCASES += test_lw.tst
+TESTCASES += test_modu.tst
+TESTCASES += test_mul.tst
+TESTCASES += test_muli.tst
+TESTCASES += test_nor.tst
+TESTCASES += test_nori.tst
+TESTCASES += test_or.tst
+TESTCASES += test_ori.tst
+TESTCASES += test_orhi.tst
+#TESTCASES += test_rcsr.tst
+TESTCASES += test_ret.tst
+TESTCASES += test_sb.tst
+TESTCASES += test_scall.tst
+TESTCASES += test_sextb.tst
+TESTCASES += test_sexth.tst
+TESTCASES += test_sh.tst
+TESTCASES += test_sl.tst
+TESTCASES += test_sli.tst
+TESTCASES += test_sr.tst
+TESTCASES += test_sri.tst
+TESTCASES += test_sru.tst
+TESTCASES += test_srui.tst
+TESTCASES += test_sub.tst
+TESTCASES += test_sw.tst
+#TESTCASES += test_wcsr.tst
+TESTCASES += test_xnor.tst
+TESTCASES += test_xnori.tst
+TESTCASES += test_xor.tst
+TESTCASES += test_xori.tst
+
+all: build
+
+%.o: $(SRC_PATH)/tests/lm32/%.c
+	$(CC) $(CFLAGS) -c $< -o $@
+
+%.o: $(SRC_PATH)/tests/lm32/%.S
+	$(AS) $(ASFLAGS) -c $< -o $@
+
+%.tst: %.o macros.inc $(CRT)
+	$(LD) $(LDFLAGS) $(NOSTDFLAGS) $(CRT) $< -o $@
+
+build: $(CRT) $(TESTCASES)
+
+check: $(CRT) $(SYS) $(TESTCASES)
+	@for case in $(TESTCASES); do \
+		$(SIM) $(SIMFLAGS) ./$$case; \
+	done
+
+clean:
+	$(RM) -fr $(TESTCASES) $(CRT)
diff --git a/tests/lm32/crt.S b/tests/lm32/crt.S
new file mode 100644
index 0000000..5f9cfd9
--- /dev/null
+++ b/tests/lm32/crt.S
@@ -0,0 +1,84 @@
+.text
+.global _start
+
+_start:
+_reset_handler:
+	xor r0, r0, r0
+	mvhi r1, hi(_start)
+	ori r1, r1, lo(_start)
+	wcsr eba, r1
+	wcsr deba, r1
+	bi _main
+	nop
+	nop
+
+_breakpoint_handler:
+	ori r25, r25, 1
+	addi ra, ba, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_instruction_bus_error_handler:
+	ori r25, r25, 2
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_watchpoint_handler:
+	ori r25, r25, 4
+	addi ra, ba, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_data_bus_error_handler:
+	ori r25, r25, 8
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_divide_by_zero_handler:
+	ori r25, r25, 16
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_interrupt_handler:
+	ori r25, r25, 32
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
+_system_call_handler:
+	ori r25, r25, 64
+	addi ra, ea, 4
+	ret
+	nop
+	nop
+	nop
+	nop
+	nop
+
diff --git a/tests/lm32/linker.ld b/tests/lm32/linker.ld
new file mode 100644
index 0000000..52d43a4
--- /dev/null
+++ b/tests/lm32/linker.ld
@@ -0,0 +1,55 @@
+OUTPUT_FORMAT("elf32-lm32")
+ENTRY(_start)
+
+__DYNAMIC = 0;
+
+MEMORY {
+	ram : ORIGIN = 0x08000000, LENGTH = 0x04000000  /* 64M */
+}
+
+SECTIONS
+{
+	.text :
+	{
+		_ftext = .;
+		*(.text .stub .text.* .gnu.linkonce.t.*)
+		_etext = .;
+	} > ram
+
+	.rodata :
+	{
+		. = ALIGN(4);
+		_frodata = .;
+		*(.rodata .rodata.* .gnu.linkonce.r.*)
+		*(.rodata1)
+		_erodata = .;
+	} > ram
+
+	.data :
+	{
+		. = ALIGN(4);
+		_fdata = .;
+		*(.data .data.* .gnu.linkonce.d.*)
+		*(.data1)
+		_gp = ALIGN(16);
+		*(.sdata .sdata.* .gnu.linkonce.s.*)
+		_edata = .;
+	} > ram
+
+	.bss :
+	{
+		. = ALIGN(4);
+		_fbss = .;
+		*(.dynsbss)
+		*(.sbss .sbss.* .gnu.linkonce.sb.*)
+		*(.scommon)
+		*(.dynbss)
+		*(.bss .bss.* .gnu.linkonce.b.*)
+		*(COMMON)
+		_ebss = .;
+		_end = .;
+	} > ram
+}
+
+PROVIDE(_fstack = ORIGIN(ram) + LENGTH(ram) - 4);
+
diff --git a/tests/lm32/macros.inc b/tests/lm32/macros.inc
new file mode 100644
index 0000000..367c7c5
--- /dev/null
+++ b/tests/lm32/macros.inc
@@ -0,0 +1,79 @@
+
+.macro test_name name
+	.data
+tn_\name:
+	.asciz "\name"
+	.text
+	mvhi r13, hi(tn_\name)
+	ori r13, r13, lo(tn_\name)
+	sw (r12+8), r13
+.endm
+
+.macro load reg val
+	mvhi \reg, hi(\val)
+	ori \reg, \reg, lo(\val)
+.endm
+
+.macro tc_pass
+	mvi r13, 0
+	sw (r12+4), r13
+.endm
+
+.macro tc_fail
+	mvi r13, 1
+	sw (r12+4), r13
+.endm
+
+.macro check_r3 val
+	mvhi r13, hi(\val)
+	ori r13, r13, lo(\val)
+	be r3, r13, 1f
+	tc_fail
+	bi 2f
+1:
+	tc_pass
+2:
+.endm
+
+.macro check_mem adr val
+	mvhi r13, hi(\adr)
+	ori r13, r13, lo(\adr)
+	mvhi r14, hi(\val)
+	ori r14, r14, lo(\val)
+	lw r13, (r13+0)
+	be r13, r14, 1f
+	tc_fail
+	bi 2f
+1:
+	tc_pass
+2:
+.endm
+
+.macro check_excp excp
+	andi r13, r25, \excp
+	bne r13, r0, 1f
+	tc_fail
+	bi 2f
+1:
+	tc_pass
+2:
+.endm
+
+.macro start
+	.global _main
+	.text
+_main:
+	mvhi r12, hi(0xffff0000)      # base address of test block
+	ori r12, r12, lo(0xffff0000)
+.endm
+
+.macro end
+	sw (r12+0), r0
+1:
+	bi 1b
+.endm
+
+# base +
+#  0  ctrl
+#  4  pass/fail
+#  8  ptr to test name
diff --git a/tests/lm32/test_add.S b/tests/lm32/test_add.S
new file mode 100644
index 0000000..030ad19
--- /dev/null
+++ b/tests/lm32/test_add.S
@@ -0,0 +1,75 @@
+.include "macros.inc"
+
+start
+
+test_name ADD_1
+mvi r1, 0
+mvi r2, 0
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_2
+mvi r1, 0
+mvi r2, 1
+add r3, r1, r2
+check_r3 1
+
+test_name ADD_3
+mvi r1, 1
+mvi r2, 0
+add r3, r1, r2
+check_r3 1
+
+test_name ADD_4
+mvi r1, 1
+mvi r2, -1
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_5
+mvi r1, -1
+mvi r2, 1
+add r3, r1, r2
+check_r3 0
+
+test_name ADD_6
+mvi r1, -1
+mvi r2, 0
+add r3, r1, r2
+check_r3 -1
+
+test_name ADD_7
+mvi r1, 0
+mvi r2, -1
+add r3, r1, r2
+check_r3 -1
+
+test_name ADD_8
+mvi r3, 2
+add r3, r3, r3
+check_r3 4
+
+test_name ADD_9
+mvi r1, 4
+mvi r3, 2
+add r3, r1, r3
+check_r3 6
+
+test_name ADD_10
+mvi r1, 4
+mvi r3, 2
+add r3, r3, r1
+check_r3 6
+
+test_name ADD_11
+mvi r1, 4
+add r3, r1, r1
+check_r3 8
+
+test_name ADD_12
+load r1 0x12345678
+load r2 0xabcdef97
+add r3, r1, r2
+check_r3 0xbe02460f
+
+end
diff --git a/tests/lm32/test_addi.S b/tests/lm32/test_addi.S
new file mode 100644
index 0000000..68e766d
--- /dev/null
+++ b/tests/lm32/test_addi.S
@@ -0,0 +1,56 @@
+.include "macros.inc"
+
+start
+
+test_name ADDI_1
+mvi r1, 0
+addi r3, r1, 0
+check_r3 0
+
+test_name ADDI_2
+mvi r1, 0
+addi r3, r1, 1
+check_r3 1
+
+test_name ADDI_3
+mvi r1, 1
+addi r3, r1, 0
+check_r3 1
+
+test_name ADDI_4
+mvi r1, 1
+addi r3, r1, -1
+check_r3 0
+
+test_name ADDI_5
+mvi r1, -1
+addi r3, r1, 1
+check_r3 0
+
+test_name ADDI_6
+mvi r1, -1
+addi r3, r1, 0
+check_r3 -1
+
+test_name ADDI_7
+mvi r1, 0
+addi r3, r1, -1
+check_r3 -1
+
+test_name ADDI_8
+mvi r3, 4
+addi r3, r3, 4
+check_r3 8
+
+test_name ADDI_9
+mvi r3, 4
+addi r3, r3, -4
+check_r3 0
+
+test_name ADDI_10
+mvi r3, 4
+addi r3, r3, -5
+check_r3 -1
+
+end
+
diff --git a/tests/lm32/test_and.S b/tests/lm32/test_and.S
new file mode 100644
index 0000000..80962ce
--- /dev/null
+++ b/tests/lm32/test_and.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name AND_1
+mvi r1, 0
+mvi r2, 0
+and r3, r1, r2
+check_r3 0
+
+test_name AND_2
+mvi r1, 0
+mvi r2, 1
+and r3, r1, r2
+check_r3 0
+
+test_name AND_3
+mvi r1, 1
+mvi r2, 1
+and r3, r1, r2
+check_r3 1
+
+test_name AND_4
+mvi r3, 7
+and r3, r3, r3
+check_r3 7
+
+test_name AND_5
+mvi r1, 7
+and r3, r1, r1
+check_r3 7
+
+test_name AND_6
+mvi r1, 7
+mvi r3, 0
+and r3, r1, r3
+check_r3 0
+
+test_name AND_7
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+and r3, r1, r2
+check_r3 0
+
+end
diff --git a/tests/lm32/test_andhi.S b/tests/lm32/test_andhi.S
new file mode 100644
index 0000000..4f73af5
--- /dev/null
+++ b/tests/lm32/test_andhi.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ANDHI_1
+mvi r1, 0
+andhi r3, r1, 0
+check_r3 0
+
+test_name ANDHI_2
+mvi r1, 1
+andhi r3, r1, 1
+check_r3 0
+
+test_name ANDHI_3
+load r1 0x000f0000
+andhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ANDHI_4
+load r1 0xffffffff
+andhi r3, r1, 0xffff
+check_r3 0xffff0000
+
+test_name ANDHI_5
+load r1 0xffffffff
+andhi r3, r1, 0
+check_r3 0
+
+test_name ANDHI_6
+load r3 0x55aaffff
+andhi r3, r3, 0xaaaa
+check_r3 0x00aa0000
+
+end
diff --git a/tests/lm32/test_andi.S b/tests/lm32/test_andi.S
new file mode 100644
index 0000000..da1b0a3
--- /dev/null
+++ b/tests/lm32/test_andi.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ANDI_1
+mvi r1, 0
+andi r3, r1, 0
+check_r3 0
+
+test_name ANDI_2
+mvi r1, 1
+andi r3, r1, 1
+check_r3 1
+
+test_name ANDI_3
+load r1 0x000f0000
+andi r3, r1, 1
+check_r3 0
+
+test_name ANDI_4
+load r1 0xffffffff
+andi r3, r1, 0xffff
+check_r3 0xffff
+
+test_name ANDI_5
+load r1 0xffffffff
+andi r3, r1, 0
+check_r3 0
+
+test_name ANDI_6
+load r3 0xffff55aa
+andi r3, r3, 0xaaaa
+check_r3 0x000000aa
+
+end
diff --git a/tests/lm32/test_b.S b/tests/lm32/test_b.S
new file mode 100644
index 0000000..98172d8
--- /dev/null
+++ b/tests/lm32/test_b.S
@@ -0,0 +1,13 @@
+.include "macros.inc"
+
+start
+
+test_name B_1
+load r1 jump
+b r1
+tc_fail
+end
+
+jump:
+tc_pass
+end
diff --git a/tests/lm32/test_be.S b/tests/lm32/test_be.S
new file mode 100644
index 0000000..635caba
--- /dev/null
+++ b/tests/lm32/test_be.S
@@ -0,0 +1,48 @@
+.include "macros.inc"
+
+start
+
+test_name BE_1
+mvi r1, 0
+mvi r2, 0
+be r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BE_2
+mvi r1, 1
+mvi r2, 0
+be r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BE_3
+mvi r1, 0
+mvi r2, 1
+be r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BE_4
+mvi r1, 1
+mvi r2, 1
+be r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bg.S b/tests/lm32/test_bg.S
new file mode 100644
index 0000000..81823c2
--- /dev/null
+++ b/tests/lm32/test_bg.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BG_1
+mvi r1, 0
+mvi r2, 0
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_2
+mvi r1, 1
+mvi r2, 0
+bg r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BG_3
+mvi r1, 0
+mvi r2, 1
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_4
+mvi r1, 0
+mvi r2, -1
+bg r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BG_5
+mvi r1, -1
+mvi r2, 0
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BG_6
+mvi r1, -1
+mvi r2, -1
+bg r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BG_7
+mvi r1, 1
+mvi r2, 0
+bg r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bge.S b/tests/lm32/test_bge.S
new file mode 100644
index 0000000..6684d15
--- /dev/null
+++ b/tests/lm32/test_bge.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGE_1
+mvi r1, 0
+mvi r2, 0
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_2
+mvi r1, 1
+mvi r2, 0
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_3
+mvi r1, 0
+mvi r2, 1
+bge r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGE_4
+mvi r1, 0
+mvi r2, -1
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGE_5
+mvi r1, -1
+mvi r2, 0
+bge r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGE_6
+mvi r1, -1
+mvi r2, -1
+bge r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGE_7
+mvi r1, 1
+mvi r2, 0
+bge r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bgeu.S b/tests/lm32/test_bgeu.S
new file mode 100644
index 0000000..be44030
--- /dev/null
+++ b/tests/lm32/test_bgeu.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGEU_1
+mvi r1, 0
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_2
+mvi r1, 1
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_3
+mvi r1, 0
+mvi r2, 1
+bgeu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGEU_4
+mvi r1, 0
+mvi r2, -1
+bgeu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGEU_5
+mvi r1, -1
+mvi r2, 0
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGEU_6
+mvi r1, -1
+mvi r2, -1
+bgeu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGEU_7
+mvi r1, 1
+mvi r2, 0
+bgeu r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bgu.S b/tests/lm32/test_bgu.S
new file mode 100644
index 0000000..8cc695b
--- /dev/null
+++ b/tests/lm32/test_bgu.S
@@ -0,0 +1,78 @@
+.include "macros.inc"
+
+start
+
+test_name BGU_1
+mvi r1, 0
+mvi r2, 0
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_2
+mvi r1, 1
+mvi r2, 0
+bgu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGU_3
+mvi r1, 0
+mvi r2, 1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_4
+mvi r1, 0
+mvi r2, -1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BGU_5
+mvi r1, -1
+mvi r2, 0
+bgu r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BGU_6
+mvi r1, -1
+mvi r2, -1
+bgu r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+bi 2f
+1:
+tc_pass
+bi 3f
+2:
+test_name BGU_7
+mvi r1, 1
+mvi r2, 0
+bgu r1, r2, 1b
+tc_fail
+3:
+
+end
+
diff --git a/tests/lm32/test_bi.S b/tests/lm32/test_bi.S
new file mode 100644
index 0000000..a1fbd6f
--- /dev/null
+++ b/tests/lm32/test_bi.S
@@ -0,0 +1,23 @@
+.include "macros.inc"
+
+start
+
+test_name BI_1
+bi jump
+tc_fail
+end
+
+jump_back:
+tc_pass
+end
+
+jump:
+tc_pass
+
+test_name BI_2
+bi jump_back
+tc_fail
+
+end
+
+
diff --git a/tests/lm32/test_bne.S b/tests/lm32/test_bne.S
new file mode 100644
index 0000000..871a006
--- /dev/null
+++ b/tests/lm32/test_bne.S
@@ -0,0 +1,48 @@
+.include "macros.inc"
+
+start
+
+test_name BNE_1
+mvi r1, 0
+mvi r2, 0
+bne r1, r2, 1f
+tc_pass
+bi 2f
+1:
+tc_fail
+2:
+
+test_name BNE_2
+mvi r1, 1
+mvi r2, 0
+bne r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+test_name BNE_3
+mvi r1, 0
+mvi r2, 1
+bne r1, r2, 1f
+tc_fail
+bi 2f
+1:
+tc_pass
+2:
+
+bi 2f
+1:
+tc_fail
+bi 3f
+2:
+test_name BNE_4
+mvi r1, 1
+mvi r2, 1
+bne r1, r2, 1b
+tc_pass
+3:
+
+end
+
diff --git a/tests/lm32/test_break.S b/tests/lm32/test_break.S
new file mode 100644
index 0000000..0384fc6
--- /dev/null
+++ b/tests/lm32/test_break.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name BREAK_1
+mvi r1, 1
+wcsr IE, r1
+insn:
+break
+check_excp 1
+
+test_name BREAK_2
+mv r3, ba
+check_r3 insn
+
+test_name BREAK_3
+rcsr r3, IE
+check_r3 4
+
+end
diff --git a/tests/lm32/test_bret.S b/tests/lm32/test_bret.S
new file mode 100644
index 0000000..645210e
--- /dev/null
+++ b/tests/lm32/test_bret.S
@@ -0,0 +1,38 @@
+.include "macros.inc"
+
+start
+
+test_name BRET_1
+mvi r1, 4
+wcsr IE, r1
+load ba mark
+bret
+tc_fail
+bi 1f
+
+mark:
+tc_pass
+
+1:
+test_name BRET_2
+rcsr r3, IE
+check_r3 5
+
+test_name BRET_3
+mvi r1, 0
+wcsr IE, r1
+load ba mark2
+bret
+tc_fail
+bi 1f
+
+mark2:
+tc_pass
+
+1:
+test_name BRET_4
+rcsr r3, IE
+check_r3 0
+
+end
+
diff --git a/tests/lm32/test_call.S b/tests/lm32/test_call.S
new file mode 100644
index 0000000..1b91a5f
--- /dev/null
+++ b/tests/lm32/test_call.S
@@ -0,0 +1,16 @@
+.include "macros.inc"
+
+start
+
+test_name CALL_1
+load r1 mark
+call r1
+return:
+
+tc_fail
+end
+
+mark:
+mv r3, ra
+check_r3 return
+end
diff --git a/tests/lm32/test_calli.S b/tests/lm32/test_calli.S
new file mode 100644
index 0000000..1d87ae6
--- /dev/null
+++ b/tests/lm32/test_calli.S
@@ -0,0 +1,15 @@
+.include "macros.inc"
+
+start
+
+test_name CALLI_1
+calli mark
+return:
+
+tc_fail
+end
+
+mark:
+mv r3, ra
+check_r3 return
+end
diff --git a/tests/lm32/test_cmpe.S b/tests/lm32/test_cmpe.S
new file mode 100644
index 0000000..60a8855
--- /dev/null
+++ b/tests/lm32/test_cmpe.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name CMPE_1
+mvi r1, 0
+mvi r2, 0
+cmpe r3, r1, r2
+check_r3 1
+
+test_name CMPE_2
+mvi r1, 0
+mvi r2, 1
+cmpe r3, r1, r2
+check_r3 0
+
+test_name CMPE_3
+mvi r1, 1
+mvi r2, 0
+cmpe r3, r1, r2
+check_r3 0
+
+test_name CMPE_4
+mvi r3, 0
+mvi r2, 1
+cmpe r3, r3, r2
+check_r3 0
+
+test_name CMPE_5
+mvi r3, 0
+mvi r2, 0
+cmpe r3, r3, r2
+check_r3 1
+
+test_name CMPE_6
+mvi r3, 0
+cmpe r3, r3, r3
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpei.S b/tests/lm32/test_cmpei.S
new file mode 100644
index 0000000..c3d3566
--- /dev/null
+++ b/tests/lm32/test_cmpei.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name CMPEI_1
+mvi r1, 0
+cmpei r3, r1, 0
+check_r3 1
+
+test_name CMPEI_2
+mvi r1, 0
+cmpei r3, r1, 1
+check_r3 0
+
+test_name CMPEI_3
+mvi r1, 1
+cmpei r3, r1, 0
+check_r3 0
+
+test_name CMPEI_4
+load r1 0xffffffff
+cmpei r3, r1, -1
+check_r3 1
+
+test_name CMPEI_5
+mvi r3, 0
+cmpei r3, r3, 0
+check_r3 1
+
+test_name CMPEI_6
+mvi r3, 0
+cmpei r3, r3, 1
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpg.S b/tests/lm32/test_cmpg.S
new file mode 100644
index 0000000..0124078
--- /dev/null
+++ b/tests/lm32/test_cmpg.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPG_1
+mvi r1, 0
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_2
+mvi r1, 0
+mvi r2, 1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_3
+mvi r1, 1
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 1
+
+test_name CMPG_4
+mvi r1, 1
+mvi r2, 1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_5
+mvi r1, 0
+mvi r2, -1
+cmpg r3, r1, r2
+check_r3 1
+
+test_name CMPG_6
+mvi r1, -1
+mvi r2, 0
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_7
+mvi r1, -1
+mvi r2, -1
+cmpg r3, r1, r2
+check_r3 0
+
+test_name CMPG_8
+mvi r3, 0
+mvi r2, 1
+cmpg r3, r3, r2
+check_r3 0
+
+test_name CMPG_9
+mvi r3, 1
+mvi r2, 0
+cmpg r3, r3, r2
+check_r3 1
+
+test_name CMPG_10
+mvi r3, 0
+cmpg r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpge.S b/tests/lm32/test_cmpge.S
new file mode 100644
index 0000000..84620a0
--- /dev/null
+++ b/tests/lm32/test_cmpge.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGE_1
+mvi r1, 0
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_2
+mvi r1, 0
+mvi r2, 1
+cmpge r3, r1, r2
+check_r3 0
+
+test_name CMPGE_3
+mvi r1, 1
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_4
+mvi r1, 1
+mvi r2, 1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_5
+mvi r1, 0
+mvi r2, -1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_6
+mvi r1, -1
+mvi r2, 0
+cmpge r3, r1, r2
+check_r3 0
+
+test_name CMPGE_7
+mvi r1, -1
+mvi r2, -1
+cmpge r3, r1, r2
+check_r3 1
+
+test_name CMPGE_8
+mvi r3, 0
+mvi r2, 1
+cmpge r3, r3, r2
+check_r3 0
+
+test_name CMPGE_9
+mvi r3, 1
+mvi r2, 0
+cmpge r3, r3, r2
+check_r3 1
+
+test_name CMPGE_10
+mvi r3, 0
+cmpge r3, r3, r3
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgei.S b/tests/lm32/test_cmpgei.S
new file mode 100644
index 0000000..6a8870f
--- /dev/null
+++ b/tests/lm32/test_cmpgei.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEI_1
+mvi r1, 0
+cmpgei r3, r1, 0
+check_r3 1
+
+test_name CMPGEI_2
+mvi r1, 0
+cmpgei r3, r1, 1
+check_r3 0
+
+test_name CMPGEI_3
+mvi r1, 1
+cmpgei r3, r1, 0
+check_r3 1
+
+test_name CMPGEI_4
+mvi r1, 1
+cmpgei r3, r1, 1
+check_r3 1
+
+test_name CMPGEI_5
+mvi r1, 0
+cmpgei r3, r1, -1
+check_r3 1
+
+test_name CMPGEI_6
+mvi r1, -1
+cmpgei r3, r1, 0
+check_r3 0
+
+test_name CMPGEI_7
+mvi r1, -1
+cmpgei r3, r1, -1
+check_r3 1
+
+test_name CMPGEI_8
+mvi r3, 0
+cmpgei r3, r3, 1
+check_r3 0
+
+test_name CMPGEI_9
+mvi r3, 1
+cmpgei r3, r3, 0
+check_r3 1
+
+test_name CMPGEI_10
+mvi r3, 0
+cmpgei r3, r3, 0
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgeu.S b/tests/lm32/test_cmpgeu.S
new file mode 100644
index 0000000..2110ccb
--- /dev/null
+++ b/tests/lm32/test_cmpgeu.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEU_1
+mvi r1, 0
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_2
+mvi r1, 0
+mvi r2, 1
+cmpgeu r3, r1, r2
+check_r3 0
+
+test_name CMPGEU_3
+mvi r1, 1
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_4
+mvi r1, 1
+mvi r2, 1
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_5
+mvi r1, 0
+mvi r2, -1
+cmpgeu r3, r1, r2
+check_r3 0
+
+test_name CMPGEU_6
+mvi r1, -1
+mvi r2, 0
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_7
+mvi r1, -1
+mvi r2, -1
+cmpgeu r3, r1, r2
+check_r3 1
+
+test_name CMPGEU_8
+mvi r3, 0
+mvi r2, 1
+cmpgeu r3, r3, r2
+check_r3 0
+
+test_name CMPGEU_9
+mvi r3, 1
+mvi r2, 0
+cmpgeu r3, r3, r2
+check_r3 1
+
+test_name CMPGEU_10
+mvi r3, 0
+cmpgeu r3, r3, r3
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgeui.S b/tests/lm32/test_cmpgeui.S
new file mode 100644
index 0000000..b9d1755
--- /dev/null
+++ b/tests/lm32/test_cmpgeui.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGEUI_1
+mvi r1, 0
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_2
+mvi r1, 0
+cmpgeui r3, r1, 1
+check_r3 0
+
+test_name CMPGEUI_3
+mvi r1, 1
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_4
+mvi r1, 1
+cmpgeui r3, r1, 1
+check_r3 1
+
+test_name CMPGEUI_5
+mvi r1, 0
+cmpgeui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGEUI_6
+mvi r1, -1
+cmpgeui r3, r1, 0
+check_r3 1
+
+test_name CMPGEUI_7
+mvi r1, -1
+cmpgeui r3, r1, 0xffff
+check_r3 1
+
+test_name CMPGEUI_8
+mvi r3, 0
+cmpgeui r3, r3, 1
+check_r3 0
+
+test_name CMPGEUI_9
+mvi r3, 1
+cmpgeui r3, r3, 0
+check_r3 1
+
+test_name CMPGEUI_10
+mvi r3, 0
+cmpgeui r3, r3, 0
+check_r3 1
+
+end
diff --git a/tests/lm32/test_cmpgi.S b/tests/lm32/test_cmpgi.S
new file mode 100644
index 0000000..1f622d2
--- /dev/null
+++ b/tests/lm32/test_cmpgi.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGI_1
+mvi r1, 0
+cmpgi r3, r1, 0
+check_r3 0
+
+test_name CMPGI_2
+mvi r1, 0
+cmpgi r3, r1, 1
+check_r3 0
+
+test_name CMPGI_3
+mvi r1, 1
+cmpgi r3, r1, 0
+check_r3 1
+
+test_name CMPGI_4
+mvi r1, 1
+cmpgi r3, r1, 1
+check_r3 0
+
+test_name CMPGI_5
+mvi r1, 0
+cmpgi r3, r1, -1
+check_r3 1
+
+test_name CMPGI_6
+mvi r1, -1
+cmpgi r3, r1, 0
+check_r3 0
+
+test_name CMPGI_7
+mvi r1, -1
+cmpgi r3, r1, -1
+check_r3 0
+
+test_name CMPGI_8
+mvi r3, 0
+cmpgi r3, r3, 1
+check_r3 0
+
+test_name CMPGI_9
+mvi r3, 1
+cmpgi r3, r3, 0
+check_r3 1
+
+test_name CMPGI_10
+mvi r3, 0
+cmpgi r3, r3, 0
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpgu.S b/tests/lm32/test_cmpgu.S
new file mode 100644
index 0000000..dd46547
--- /dev/null
+++ b/tests/lm32/test_cmpgu.S
@@ -0,0 +1,64 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGU_1
+mvi r1, 0
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_2
+mvi r1, 0
+mvi r2, 1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_3
+mvi r1, 1
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 1
+
+test_name CMPGU_4
+mvi r1, 1
+mvi r2, 1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_5
+mvi r1, 0
+mvi r2, -1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_6
+mvi r1, -1
+mvi r2, 0
+cmpgu r3, r1, r2
+check_r3 1
+
+test_name CMPGU_7
+mvi r1, -1
+mvi r2, -1
+cmpgu r3, r1, r2
+check_r3 0
+
+test_name CMPGU_8
+mvi r3, 0
+mvi r2, 1
+cmpgu r3, r3, r2
+check_r3 0
+
+test_name CMPGU_9
+mvi r3, 1
+mvi r2, 0
+cmpgu r3, r3, r2
+check_r3 1
+
+test_name CMPGU_10
+mvi r3, 0
+cmpgu r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpgui.S b/tests/lm32/test_cmpgui.S
new file mode 100644
index 0000000..759bb64
--- /dev/null
+++ b/tests/lm32/test_cmpgui.S
@@ -0,0 +1,55 @@
+.include "macros.inc"
+
+start
+
+test_name CMPGUI_1
+mvi r1, 0
+cmpgui r3, r1, 0
+check_r3 0
+
+test_name CMPGUI_2
+mvi r1, 0
+cmpgui r3, r1, 1
+check_r3 0
+
+test_name CMPGUI_3
+mvi r1, 1
+cmpgui r3, r1, 0
+check_r3 1
+
+test_name CMPGUI_4
+mvi r1, 1
+cmpgui r3, r1, 1
+check_r3 0
+
+test_name CMPGUI_5
+mvi r1, 0
+cmpgui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGUI_6
+mvi r1, -1
+cmpgui r3, r1, 0
+check_r3 1
+
+test_name CMPGUI_7
+mvi r1, -1
+cmpgui r3, r1, 0xffff
+check_r3 0
+
+test_name CMPGUI_8
+mvi r3, 0
+cmpgui r3, r3, 1
+check_r3 0
+
+test_name CMPGUI_9
+mvi r3, 1
+cmpgui r3, r3, 0
+check_r3 1
+
+test_name CMPGUI_10
+mvi r3, 0
+cmpgui r3, r3, 0
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpne.S b/tests/lm32/test_cmpne.S
new file mode 100644
index 0000000..0f10781
--- /dev/null
+++ b/tests/lm32/test_cmpne.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name CMPNE_1
+mvi r1, 0
+mvi r2, 0
+cmpne r3, r1, r2
+check_r3 0
+
+test_name CMPNE_2
+mvi r1, 0
+mvi r2, 1
+cmpne r3, r1, r2
+check_r3 1
+
+test_name CMPNE_3
+mvi r1, 1
+mvi r2, 0
+cmpne r3, r1, r2
+check_r3 1
+
+test_name CMPNE_4
+mvi r3, 0
+mvi r2, 1
+cmpne r3, r3, r2
+check_r3 1
+
+test_name CMPNE_5
+mvi r3, 0
+mvi r2, 0
+cmpne r3, r3, r2
+check_r3 0
+
+test_name CMPNE_6
+mvi r3, 0
+cmpne r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_cmpnei.S b/tests/lm32/test_cmpnei.S
new file mode 100644
index 0000000..060dd9d
--- /dev/null
+++ b/tests/lm32/test_cmpnei.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name CMPNEI_1
+mvi r1, 0
+cmpnei r3, r1, 0
+check_r3 0
+
+test_name CMPNEI_2
+mvi r1, 0
+cmpnei r3, r1, 1
+check_r3 1
+
+test_name CMPNEI_3
+mvi r1, 1
+cmpnei r3, r1, 0
+check_r3 1
+
+test_name CMPNEI_4
+load r1 0xffffffff
+cmpnei r3, r1, -1
+check_r3 0
+
+test_name CMPNEI_5
+mvi r3, 0
+cmpnei r3, r3, 0
+check_r3 0
+
+test_name CMPNEI_6
+mvi r3, 0
+cmpnei r3, r3, 1
+check_r3 1
+
+end
diff --git a/tests/lm32/test_divu.S b/tests/lm32/test_divu.S
new file mode 100644
index 0000000..f381d09
--- /dev/null
+++ b/tests/lm32/test_divu.S
@@ -0,0 +1,29 @@
+.include "macros.inc"
+
+start
+
+test_name DIVU_1
+mvi r1, 0
+mvi r2, 1
+divu r3, r1, r2
+check_r3 0
+
+test_name DIVU_2
+mvi r1, 1
+mvi r2, 1
+divu r3, r1, r2
+check_r3 1
+
+test_name DIVU_3
+mvi r1, 0
+mvi r2, 0
+divu r3, r1, r2
+check_excp 16
+
+test_name DIVU_4
+load r1 0xabcdef12
+load r2 0x12345
+divu r3, r1, r2
+check_r3 0x9700
+
+end
diff --git a/tests/lm32/test_eret.S b/tests/lm32/test_eret.S
new file mode 100644
index 0000000..6830bd1
--- /dev/null
+++ b/tests/lm32/test_eret.S
@@ -0,0 +1,38 @@
+.include "macros.inc"
+
+start
+
+test_name ERET_1
+mvi r1, 2
+wcsr IE, r1
+load ea mark
+eret
+tc_fail
+bi 1f
+
+mark:
+tc_pass
+
+1:
+test_name ERET_2
+rcsr r3, IE
+check_r3 3
+
+test_name ERET_3
+mvi r1, 0
+wcsr IE, r1
+load ea mark2
+eret
+tc_fail
+bi 1f
+
+mark2:
+tc_pass
+
+1:
+test_name ERET_4
+rcsr r3, IE
+check_r3 0
+
+end
+
diff --git a/tests/lm32/test_lb.S b/tests/lm32/test_lb.S
new file mode 100644
index 0000000..f84d21e
--- /dev/null
+++ b/tests/lm32/test_lb.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LB_1
+load r1 data
+lb r3, (r1+0)
+check_r3 0x7e
+
+test_name LB_2
+lb r3, (r1+1)
+check_r3 0x7f
+
+test_name LB_3
+lb r3, (r1+-1)
+check_r3 0x7d
+
+test_name LB_4
+load r1 data_msb
+lb r3, (r1+0)
+check_r3 0xfffffffe
+
+test_name LB_5
+lb r3, (r1+1)
+check_r3 0xffffffff
+
+test_name LB_6
+lb r3, (r1+-1)
+check_r3 0xfffffffd
+
+test_name LB_7
+load r3 data
+lb r3, (r3+0)
+check_r3 0x7e
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lbu.S b/tests/lm32/test_lbu.S
new file mode 100644
index 0000000..4c1786a
--- /dev/null
+++ b/tests/lm32/test_lbu.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LBU_1
+load r1 data
+lbu r3, (r1+0)
+check_r3 0x7e
+
+test_name LBU_2
+lbu r3, (r1+1)
+check_r3 0x7f
+
+test_name LBU_3
+lbu r3, (r1+-1)
+check_r3 0x7d
+
+test_name LBU_4
+load r1 data_msb
+lbu r3, (r1+0)
+check_r3 0xfe
+
+test_name LBU_5
+lbu r3, (r1+1)
+check_r3 0xff
+
+test_name LBU_6
+lbu r3, (r1+-1)
+check_r3 0xfd
+
+test_name LBU_7
+load r3 data
+lbu r3, (r3+0)
+check_r3 0x7e
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lh.S b/tests/lm32/test_lh.S
new file mode 100644
index 0000000..e57d9e3
--- /dev/null
+++ b/tests/lm32/test_lh.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LH_1
+load r1 data
+lh r3, (r1+0)
+check_r3 0x7e7f
+
+test_name LH_2
+lh r3, (r1+2)
+check_r3 0x7071
+
+test_name LH_3
+lh r3, (r1+-2)
+check_r3 0x7c7d
+
+test_name LH_4
+load r1 data_msb
+lh r3, (r1+0)
+check_r3 0xfffffeff
+
+test_name LH_5
+lh r3, (r1+2)
+check_r3 0xfffff0f1
+
+test_name LH_6
+lh r3, (r1+-2)
+check_r3 0xfffffcfd
+
+test_name LH_7
+load r3 data
+lh r3, (r3+0)
+check_r3 0x7e7f
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lhu.S b/tests/lm32/test_lhu.S
new file mode 100644
index 0000000..e648775
--- /dev/null
+++ b/tests/lm32/test_lhu.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name LHU_1
+load r1 data
+lhu r3, (r1+0)
+check_r3 0x7e7f
+
+test_name LHU_2
+lhu r3, (r1+2)
+check_r3 0x7071
+
+test_name LHU_3
+lhu r3, (r1+-2)
+check_r3 0x7c7d
+
+test_name LHU_4
+load r1 data_msb
+lhu r3, (r1+0)
+check_r3 0xfeff
+
+test_name LHU_5
+lhu r3, (r1+2)
+check_r3 0xf0f1
+
+test_name LHU_6
+lhu r3, (r1+-2)
+check_r3 0xfcfd
+
+test_name LHU_7
+load r3 data
+lhu r3, (r3+0)
+check_r3 0x7e7f
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0xfa, 0xfb, 0xfc, 0xfd
+data_msb:
+	.byte 0xfe, 0xff, 0xf0, 0xf1
diff --git a/tests/lm32/test_lw.S b/tests/lm32/test_lw.S
new file mode 100644
index 0000000..f8c919d
--- /dev/null
+++ b/tests/lm32/test_lw.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name LW_1
+load r1 data
+lw r3, (r1+0)
+check_r3 0x7e7f7071
+
+test_name LW_2
+lw r3, (r1+4)
+check_r3 0x72737475
+
+test_name LW_3
+lw r3, (r1+-4)
+check_r3 0x7a7b7c7d
+
+test_name LW_4
+load r3 data
+lw r3, (r3+0)
+check_r3 0x7e7f7071
+
+end
+
+.data
+	.align 4
+	.byte 0x7a, 0x7b, 0x7c, 0x7d
+data:
+	.byte 0x7e, 0x7f, 0x70, 0x71
+	.byte 0x72, 0x73, 0x74, 0x75
diff --git a/tests/lm32/test_modu.S b/tests/lm32/test_modu.S
new file mode 100644
index 0000000..4248690
--- /dev/null
+++ b/tests/lm32/test_modu.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name MODU_1
+mvi r1, 0
+mvi r2, 1
+modu r3, r1, r2
+check_r3 0
+
+test_name MODU_2
+mvi r1, 1
+mvi r2, 1
+modu r3, r1, r2
+check_r3 0
+
+test_name MODU_3
+mvi r1, 3
+mvi r2, 2
+modu r3, r1, r2
+check_r3 1
+
+test_name MODU_4
+mvi r1, 0
+mvi r2, 0
+modu r3, r1, r2
+check_excp 16
+
+test_name MODU_5
+load r1 0xabcdef12
+load r2 0x12345
+modu r3, r1, r2
+check_r3 0x3c12
+
+end
diff --git a/tests/lm32/test_mul.S b/tests/lm32/test_mul.S
new file mode 100644
index 0000000..e9b937e
--- /dev/null
+++ b/tests/lm32/test_mul.S
@@ -0,0 +1,70 @@
+.include "macros.inc"
+
+start
+
+test_name MUL_1
+mvi r1, 0
+mvi r2, 0
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_2
+mvi r1, 1
+mvi r2, 0
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_3
+mvi r1, 0
+mvi r2, 1
+mul r3, r1, r2
+check_r3 0
+
+test_name MUL_4
+mvi r1, 1
+mvi r2, 1
+mul r3, r1, r2
+check_r3 1
+
+test_name MUL_5
+mvi r1, 2
+mvi r2, -1
+mul r3, r1, r2
+check_r3 -2
+
+test_name MUL_6
+mvi r1, -2
+mvi r2, -1
+mul r3, r1, r2
+check_r3 2
+
+test_name MUL_7
+mvi r1, 0x1234
+mvi r2, 0x789
+mul r3, r1, r2
+check_r3 0x8929d4
+
+test_name MUL_8
+mvi r3, 4
+mul r3, r3, r3
+check_r3 16
+
+test_name MUL_9
+mvi r2, 2
+mvi r3, 4
+mul r3, r3, r2
+check_r3 8
+
+test_name MUL_10
+load r1 0x12345678
+load r2 0x7bcdef12
+mul r3, r1, r2
+check_r3 0xa801c70
+
+test_name MUL_11
+load r1 0x12345678
+load r2 0xabcdef12
+mul r3, r1, r2
+check_r3 0x8a801c70
+
+end
diff --git a/tests/lm32/test_muli.S b/tests/lm32/test_muli.S
new file mode 100644
index 0000000..d6dd4a0
--- /dev/null
+++ b/tests/lm32/test_muli.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name MULI_1
+mvi r1, 0
+muli r3, r1, 0
+check_r3 0
+
+test_name MULI_2
+mvi r1, 1
+muli r3, r1, 0
+check_r3 0
+
+test_name MULI_3
+mvi r1, 0
+muli r3, r1, 1
+check_r3 0
+
+test_name MULI_4
+mvi r1, 1
+muli r3, r1, 1
+check_r3 1
+
+test_name MULI_5
+mvi r1, 2
+muli r3, r1, -1
+check_r3 -2
+
+test_name MULI_6
+mvi r1, -2
+muli r3, r1, -1
+check_r3 2
+
+test_name MULI_7
+mvi r1, 0x1234
+muli r3, r1, 0x789
+check_r3 0x8929d4
+
+test_name MULI_8
+mvi r3, 4
+muli r3, r3, 4
+check_r3 16
+
+end
diff --git a/tests/lm32/test_nor.S b/tests/lm32/test_nor.S
new file mode 100644
index 0000000..74d7592
--- /dev/null
+++ b/tests/lm32/test_nor.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name NOR_1
+mvi r1, 0
+mvi r2, 0
+nor r3, r1, r2
+check_r3 0xffffffff
+
+test_name NOR_2
+mvi r1, 0
+mvi r2, 1
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_3
+mvi r1, 1
+mvi r2, 1
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_4
+mvi r1, 1
+mvi r2, 0
+nor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name NOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+nor r3, r1, r2
+check_r3 0
+
+test_name NOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+nor r3, r1, r2
+check_r3 0x55aa55aa
+
+test_name NOR_7
+load r1 0xaa55aa55
+nor r3, r1, r1
+check_r3 0x55aa55aa
+
+test_name NOR_8
+load r3 0xaa55aa55
+nor r3, r3, r3
+check_r3 0x55aa55aa
+
+end
diff --git a/tests/lm32/test_nori.S b/tests/lm32/test_nori.S
new file mode 100644
index 0000000..d00309c
--- /dev/null
+++ b/tests/lm32/test_nori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name NORI_1
+mvi r1, 0
+nori r3, r1, 0
+check_r3 0xffffffff
+
+test_name NORI_2
+mvi r1, 0
+nori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name NORI_3
+mvi r1, 1
+nori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name NORI_4
+mvi r1, 1
+nori r3, r1, 0
+check_r3 0xfffffffe
+
+test_name NORI_5
+load r1 0xaa55aa55
+nori r3, r1, 0x55aa
+check_r3 0x55aa0000
+
+test_name NORI_6
+load r3 0xaa55aa55
+nori r3, r3, 0x55aa
+check_r3 0x55aa0000
+
+end
diff --git a/tests/lm32/test_or.S b/tests/lm32/test_or.S
new file mode 100644
index 0000000..4ed2923
--- /dev/null
+++ b/tests/lm32/test_or.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name OR_1
+mvi r1, 0
+mvi r2, 0
+or r3, r1, r2
+check_r3 0
+
+test_name OR_2
+mvi r1, 0
+mvi r2, 1
+or r3, r1, r2
+check_r3 1
+
+test_name OR_3
+mvi r1, 1
+mvi r2, 1
+or r3, r1, r2
+check_r3 1
+
+test_name OR_4
+mvi r1, 1
+mvi r2, 0
+or r3, r1, r2
+check_r3 1
+
+test_name OR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+or r3, r1, r2
+check_r3 0xffffffff
+
+test_name OR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+or r3, r1, r2
+check_r3 0xaa55aa55
+
+test_name OR_7
+load r1 0xaa55aa55
+or r3, r1, r1
+check_r3 0xaa55aa55
+
+test_name OR_8
+load r3 0xaa55aa55
+or r3, r3, r3
+check_r3 0xaa55aa55
+
+end
diff --git a/tests/lm32/test_orhi.S b/tests/lm32/test_orhi.S
new file mode 100644
index 0000000..78b7600
--- /dev/null
+++ b/tests/lm32/test_orhi.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ORHI_1
+mvi r1, 0
+orhi r3, r1, 0
+check_r3 0
+
+test_name ORHI_2
+mvi r1, 0
+orhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ORHI_3
+load r1 0x00010000
+orhi r3, r1, 1
+check_r3 0x00010000
+
+test_name ORHI_4
+mvi r1, 1
+orhi r3, r1, 0
+check_r3 1
+
+test_name ORHI_5
+load r1 0xaa55aa55
+orhi r3, r1, 0x55aa
+check_r3 0xffffaa55
+
+test_name ORHI_6
+load r3 0xaa55aa55
+orhi r3, r3, 0x55aa
+check_r3 0xffffaa55
+
+end
diff --git a/tests/lm32/test_ori.S b/tests/lm32/test_ori.S
new file mode 100644
index 0000000..3d576cd
--- /dev/null
+++ b/tests/lm32/test_ori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name ORI_1
+mvi r1, 0
+ori r3, r1, 0
+check_r3 0
+
+test_name ORI_2
+mvi r1, 0
+ori r3, r1, 1
+check_r3 1
+
+test_name ORI_3
+mvi r1, 1
+ori r3, r1, 1
+check_r3 1
+
+test_name ORI_4
+mvi r1, 1
+ori r3, r1, 0
+check_r3 1
+
+test_name ORI_5
+load r1 0xaa55aa55
+ori r3, r1, 0x55aa
+check_r3 0xaa55ffff
+
+test_name ORI_6
+load r3 0xaa55aa55
+ori r3, r3, 0x55aa
+check_r3 0xaa55ffff
+
+end
diff --git a/tests/lm32/test_ret.S b/tests/lm32/test_ret.S
new file mode 100644
index 0000000..320264f
--- /dev/null
+++ b/tests/lm32/test_ret.S
@@ -0,0 +1,14 @@
+.include "macros.inc"
+
+start
+
+test_name RET_1
+load ra mark
+ret
+
+tc_fail
+end
+
+mark:
+tc_pass
+end
diff --git a/tests/lm32/test_sb.S b/tests/lm32/test_sb.S
new file mode 100644
index 0000000..89e39d6
--- /dev/null
+++ b/tests/lm32/test_sb.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SB_1
+load r1 data
+load r2 0xf0f1f2aa
+sb (r1+0), r2
+check_mem data 0xaa000000
+
+test_name SB_2
+load r2 0xf0f1f2bb
+sb (r1+1), r2
+check_mem data 0xaabb0000
+
+test_name SB_3
+load r2 0xf0f1f2cc
+sb (r1+-1), r2
+check_mem data0 0x000000cc
+
+end
+
+.data
+	.align 4
+data0:
+	.byte 0, 0, 0, 0
+data:
+	.byte 0, 0, 0, 0
+data1:
+	.byte 0, 0, 0, 0
diff --git a/tests/lm32/test_scall.S b/tests/lm32/test_scall.S
new file mode 100644
index 0000000..b442e32
--- /dev/null
+++ b/tests/lm32/test_scall.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SCALL_1
+mvi r1, 1
+wcsr IE, r1
+insn:
+scall
+check_excp 64
+
+test_name SCALL_2
+mv r3, ea
+check_r3 insn
+
+test_name SCALL_3
+rcsr r3, IE
+check_r3 2
+
+end
diff --git a/tests/lm32/test_sextb.S b/tests/lm32/test_sextb.S
new file mode 100644
index 0000000..58db8ee
--- /dev/null
+++ b/tests/lm32/test_sextb.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SEXTB_1
+mvi r1, 0
+sextb r3, r1
+check_r3 0
+
+test_name SEXTB_2
+mvi r1, 0x7f
+sextb r3, r1
+check_r3 0x0000007f
+
+test_name SEXTB_3
+mvi r1, 0x80
+sextb r3, r1
+check_r3 0xffffff80
+
+end
diff --git a/tests/lm32/test_sexth.S b/tests/lm32/test_sexth.S
new file mode 100644
index 0000000..a059ec3
--- /dev/null
+++ b/tests/lm32/test_sexth.S
@@ -0,0 +1,20 @@
+.include "macros.inc"
+
+start
+
+test_name SEXTH_1
+mvi r1, 0
+sexth r3, r1
+check_r3 0
+
+test_name SEXTH_2
+load r1 0x7fff
+sexth r3, r1
+check_r3 0x00007fff
+
+test_name SEXTH_3
+load r1 0x8000
+sexth r3, r1
+check_r3 0xffff8000
+
+end
diff --git a/tests/lm32/test_sh.S b/tests/lm32/test_sh.S
new file mode 100644
index 0000000..ea8b3f2
--- /dev/null
+++ b/tests/lm32/test_sh.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SH_1
+load r1 data
+load r2 0xf0f1aaaa
+sh (r1+0), r2
+check_mem data 0xaaaa0000
+
+test_name SH_2
+load r2 0xf0f1bbbb
+sh (r1+2), r2
+check_mem data 0xaaaabbbb
+
+test_name SH_3
+load r2 0xf0f1cccc
+sh (r1+-2), r2
+check_mem data0 0x0000cccc
+
+end
+
+.data
+	.align 4
+data0:
+	.byte 0, 0, 0, 0
+data:
+	.byte 0, 0, 0, 0
+data1:
+	.byte 0, 0, 0, 0
diff --git a/tests/lm32/test_sl.S b/tests/lm32/test_sl.S
new file mode 100644
index 0000000..0aee17f
--- /dev/null
+++ b/tests/lm32/test_sl.S
@@ -0,0 +1,45 @@
+.include "macros.inc"
+
+start
+
+test_name SL_1
+mvi r1, 1
+mvi r2, 0
+sl r3, r1, r2
+check_r3 1
+
+test_name SL_2
+mvi r1, 0
+mvi r2, 1
+sl r3, r1, r2
+check_r3 0
+
+test_name SL_3
+mvi r1, 1
+mvi r2, 31
+sl r3, r1, r2
+check_r3 0x80000000
+
+test_name SL_4
+mvi r1, 16
+mvi r2, 31
+sl r3, r1, r2
+check_r3 0
+
+test_name SL_5
+mvi r1, 1
+mvi r2, 34
+sl r3, r1, r2
+check_r3 4
+
+test_name SL_6
+mvi r1, 2
+sl r3, r1, r1
+check_r3 8
+
+test_name SL_7
+mvi r3, 2
+sl r3, r3, r3
+check_r3 8
+
+end
diff --git a/tests/lm32/test_sli.S b/tests/lm32/test_sli.S
new file mode 100644
index 0000000..a421de9
--- /dev/null
+++ b/tests/lm32/test_sli.S
@@ -0,0 +1,30 @@
+.include "macros.inc"
+
+start
+
+test_name SLI_1
+mvi r1, 1
+sli r3, r1, 0
+check_r3 1
+
+test_name SLI_2
+mvi r1, 0
+sli r3, r1, 1
+check_r3 0
+
+test_name SLI_3
+mvi r1, 1
+sli r3, r1, 31
+check_r3 0x80000000
+
+test_name SLI_4
+mvi r1, 16
+sli r3, r1, 31
+check_r3 0
+
+test_name SLI_7
+mvi r3, 2
+sli r3, r3, 2
+check_r3 8
+
+end
diff --git a/tests/lm32/test_sr.S b/tests/lm32/test_sr.S
new file mode 100644
index 0000000..62431a9
--- /dev/null
+++ b/tests/lm32/test_sr.S
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+start
+
+test_name SR_1
+mvi r1, 1
+mvi r2, 0
+sr r3, r1, r2
+check_r3 1
+
+test_name SR_2
+mvi r1, 0
+mvi r2, 1
+sr r3, r1, r2
+check_r3 0
+
+test_name SR_3
+load r1 0x40000000
+mvi r2, 30
+sr r3, r1, r2
+check_r3 1
+
+test_name SR_4
+load r1 0x40000000
+mvi r2, 31
+sr r3, r1, r2
+check_r3 0
+
+test_name SR_5
+mvi r1, 16
+mvi r2, 34
+sr r3, r1, r2
+check_r3 4
+
+test_name SR_6
+mvi r1, 2
+sr r3, r1, r1
+check_r3 0
+
+test_name SR_7
+mvi r3, 2
+sr r3, r3, r3
+check_r3 0
+
+test_name SR_8
+mvi r1, 0xfffffff0
+mvi r2, 2
+sr r3, r1, r2
+check_r3 0xfffffffc
+
+test_name SR_9
+mvi r1, 0xfffffff0
+mvi r2, 4
+sr r3, r1, r2
+check_r3 0xffffffff
+
+end
diff --git a/tests/lm32/test_sri.S b/tests/lm32/test_sri.S
new file mode 100644
index 0000000..c1be907
--- /dev/null
+++ b/tests/lm32/test_sri.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name SRI_1
+mvi r1, 1
+sri r3, r1, 0
+check_r3 1
+
+test_name SRI_2
+mvi r1, 0
+sri r3, r1, 1
+check_r3 0
+
+test_name SRI_3
+load r1 0x40000000
+sri r3, r1, 30
+check_r3 1
+
+test_name SRI_4
+load r1 0x40000000
+sri r3, r1, 31
+check_r3 0
+
+test_name SRI_5
+mvi r3, 2
+sri r3, r3, 2
+check_r3 0
+
+test_name SRI_6
+mvi r1, 0xfffffff0
+sri r3, r1, 2
+check_r3 0xfffffffc
+
+test_name SRI_7
+mvi r1, 0xfffffff0
+sri r3, r1, 4
+check_r3 0xffffffff
+
+end
diff --git a/tests/lm32/test_sru.S b/tests/lm32/test_sru.S
new file mode 100644
index 0000000..2ab0b54
--- /dev/null
+++ b/tests/lm32/test_sru.S
@@ -0,0 +1,57 @@
+.include "macros.inc"
+
+start
+
+test_name SRU_1
+mvi r1, 1
+mvi r2, 0
+sru r3, r1, r2
+check_r3 1
+
+test_name SRU_2
+mvi r1, 0
+mvi r2, 1
+sru r3, r1, r2
+check_r3 0
+
+test_name SRU_3
+load r1 0x40000000
+mvi r2, 30
+sru r3, r1, r2
+check_r3 1
+
+test_name SRU_4
+load r1 0x40000000
+mvi r2, 31
+sru r3, r1, r2
+check_r3 0
+
+test_name SRU_5
+mvi r1, 16
+mvi r2, 34
+sru r3, r1, r2
+check_r3 4
+
+test_name SRU_6
+mvi r1, 2
+sru r3, r1, r1
+check_r3 0
+
+test_name SRU_7
+mvi r3, 2
+sru r3, r3, r3
+check_r3 0
+
+test_name SRU_8
+mvi r1, 0xfffffff0
+mvi r2, 2
+sru r3, r1, r2
+check_r3 0x3ffffffc
+
+test_name SRU_9
+mvi r1, 0xfffffff0
+mvi r2, 4
+sru r3, r1, r2
+check_r3 0x0fffffff
+
+end
diff --git a/tests/lm32/test_srui.S b/tests/lm32/test_srui.S
new file mode 100644
index 0000000..872c374
--- /dev/null
+++ b/tests/lm32/test_srui.S
@@ -0,0 +1,40 @@
+.include "macros.inc"
+
+start
+
+test_name SRUI_1
+mvi r1, 1
+srui r3, r1, 0
+check_r3 1
+
+test_name SRUI_2
+mvi r1, 0
+srui r3, r1, 1
+check_r3 0
+
+test_name SRUI_3
+load r1 0x40000000
+srui r3, r1, 30
+check_r3 1
+
+test_name SRUI_4
+load r1 0x40000000
+srui r3, r1, 31
+check_r3 0
+
+test_name SRUI_5
+mvi r3, 2
+srui r3, r3, 2
+check_r3 0
+
+test_name SRUI_6
+mvi r1, 0xfffffff0
+srui r3, r1, 2
+check_r3 0x3ffffffc
+
+test_name SRUI_7
+mvi r1, 0xfffffff0
+srui r3, r1, 4
+check_r3 0x0fffffff
+
+end
diff --git a/tests/lm32/test_sub.S b/tests/lm32/test_sub.S
new file mode 100644
index 0000000..44b74a9
--- /dev/null
+++ b/tests/lm32/test_sub.S
@@ -0,0 +1,75 @@
+.include "macros.inc"
+
+start
+
+test_name SUB_1
+mvi r1, 0
+mvi r2, 0
+sub r3, r1, r2
+check_r3 0
+
+test_name SUB_2
+mvi r1, 0
+mvi r2, 1
+sub r3, r1, r2
+check_r3 -1
+
+test_name SUB_3
+mvi r1, 1
+mvi r2, 0
+sub r3, r1, r2
+check_r3 1
+
+test_name SUB_4
+mvi r1, 1
+mvi r2, -1
+sub r3, r1, r2
+check_r3 2
+
+test_name SUB_5
+mvi r1, -1
+mvi r2, 1
+sub r3, r1, r2
+check_r3 -2
+
+test_name SUB_6
+mvi r1, -1
+mvi r2, 0
+sub r3, r1, r2
+check_r3 -1
+
+test_name SUB_7
+mvi r1, 0
+mvi r2, -1
+sub r3, r1, r2
+check_r3 1
+
+test_name SUB_8
+mvi r3, 2
+sub r3, r3, r3
+check_r3 0
+
+test_name SUB_9
+mvi r1, 4
+mvi r3, 2
+sub r3, r1, r3
+check_r3 2
+
+test_name SUB_10
+mvi r1, 4
+mvi r3, 2
+sub r3, r3, r1
+check_r3 -2
+
+test_name SUB_11
+mvi r1, 4
+sub r3, r1, r1
+check_r3 0
+
+test_name SUB_12
+load r1 0x12345678
+load r2 0xabcdef97
+sub r3, r1, r2
+check_r3 0x666666e1
+
+end
diff --git a/tests/lm32/test_sw.S b/tests/lm32/test_sw.S
new file mode 100644
index 0000000..d1fdadc
--- /dev/null
+++ b/tests/lm32/test_sw.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name SW_1
+load r1 data
+load r2 0xaabbccdd
+sw (r1+0), r2
+check_mem data 0xaabbccdd
+
+test_name SW_2
+load r2 0x00112233
+sw (r1+4), r2
+check_mem data1 0x00112233
+
+test_name SW_3
+load r2 0x44556677
+sw (r1+-4), r2
+check_mem data0 0x44556677
+
+test_name SW_4
+sw (r1+0), r1
+lw r3, (r1+0)
+check_r3 data
+
+end
+
+.data
+	.align 4
+data0:
+	.byte 0, 0, 0, 0
+data:
+	.byte 0, 0, 0, 0
+data1:
+	.byte 0, 0, 0, 0
diff --git a/tests/lm32/test_xnor.S b/tests/lm32/test_xnor.S
new file mode 100644
index 0000000..14a6207
--- /dev/null
+++ b/tests/lm32/test_xnor.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name XNOR_1
+mvi r1, 0
+mvi r2, 0
+xnor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XNOR_2
+mvi r1, 0
+mvi r2, 1
+xnor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name XNOR_3
+mvi r1, 1
+mvi r2, 1
+xnor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XNOR_4
+mvi r1, 1
+mvi r2, 0
+xnor r3, r1, r2
+check_r3 0xfffffffe
+
+test_name XNOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+xnor r3, r1, r2
+check_r3 0
+
+test_name XNOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+xnor r3, r1, r2
+check_r3 0x55aa55aa
+
+test_name XNOR_7
+load r1 0xaa55aa55
+xnor r3, r1, r1
+check_r3 0xffffffff
+
+test_name XNOR_8
+load r3 0xaa55aa55
+xnor r3, r3, r3
+check_r3 0xffffffff
+
+end
diff --git a/tests/lm32/test_xnori.S b/tests/lm32/test_xnori.S
new file mode 100644
index 0000000..9d9c3c6
--- /dev/null
+++ b/tests/lm32/test_xnori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name XNORI_1
+mvi r1, 0
+xnori r3, r1, 0
+check_r3 0xffffffff
+
+test_name XNORI_2
+mvi r1, 0
+xnori r3, r1, 1
+check_r3 0xfffffffe
+
+test_name XNORI_3
+mvi r1, 1
+xnori r3, r1, 1
+check_r3 0xffffffff
+
+test_name XNORI_4
+mvi r1, 1
+xnori r3, r1, 0
+check_r3 0xfffffffe
+
+test_name XNORI_5
+load r1 0xaa55aa55
+xnori r3, r1, 0x5555
+check_r3 0x55aa00ff
+
+test_name XNORI_6
+load r3 0xaa55aa55
+xnori r3, r3, 0x5555
+check_r3 0x55aa00ff
+
+end
diff --git a/tests/lm32/test_xor.S b/tests/lm32/test_xor.S
new file mode 100644
index 0000000..6c6e712
--- /dev/null
+++ b/tests/lm32/test_xor.S
@@ -0,0 +1,51 @@
+.include "macros.inc"
+
+start
+
+test_name XOR_1
+mvi r1, 0
+mvi r2, 0
+xor r3, r1, r2
+check_r3 0
+
+test_name XOR_2
+mvi r1, 0
+mvi r2, 1
+xor r3, r1, r2
+check_r3 1
+
+test_name XOR_3
+mvi r1, 1
+mvi r2, 1
+xor r3, r1, r2
+check_r3 0
+
+test_name XOR_4
+mvi r1, 1
+mvi r2, 0
+xor r3, r1, r2
+check_r3 1
+
+test_name XOR_5
+load r1 0xaa55aa55
+load r2 0x55aa55aa
+xor r3, r1, r2
+check_r3 0xffffffff
+
+test_name XOR_6
+load r1 0xaa550000
+load r2 0x0000aa55
+xor r3, r1, r2
+check_r3 0xaa55aa55
+
+test_name XOR_7
+load r1 0xaa55aa55
+xor r3, r1, r1
+check_r3 0
+
+test_name XOR_8
+load r3 0xaa55aa55
+xor r3, r3, r3
+check_r3 0
+
+end
diff --git a/tests/lm32/test_xori.S b/tests/lm32/test_xori.S
new file mode 100644
index 0000000..2051699
--- /dev/null
+++ b/tests/lm32/test_xori.S
@@ -0,0 +1,35 @@
+.include "macros.inc"
+
+start
+
+test_name XORI_1
+mvi r1, 0
+xori r3, r1, 0
+check_r3 0
+
+test_name XORI_2
+mvi r1, 0
+xori r3, r1, 1
+check_r3 1
+
+test_name XORI_3
+mvi r1, 1
+xori r3, r1, 1
+check_r3 0
+
+test_name XORI_4
+mvi r1, 1
+xori r3, r1, 0
+check_r3 1
+
+test_name XORI_5
+load r1 0xaa55aa55
+xori r3, r1, 0x5555
+check_r3 0xaa55ff00
+
+test_name XORI_6
+load r3 0xaa55aa55
+xori r3, r3, 0x5555
+check_r3 0xaa55ff00
+
+end
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 16/17] Add lm32 target to configure
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (14 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 15/17] lm32: opcode testsuite Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 17/17] MAINTAINERS: add LatticeMico32 maintainer Michael Walle
  2011-02-07 16:28 ` [Qemu-devel] Re: [PATCH 00/17] LatticeMico32 target Alexander Graf
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

Signed-off-by: Michael Walle <michael@walle.cc>
---
 configure |   10 +++++++---
 1 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/configure b/configure
index 210670c..c378773 100755
--- a/configure
+++ b/configure
@@ -280,7 +280,7 @@ else
 fi
 
 case "$cpu" in
-  alpha|cris|ia64|m68k|microblaze|ppc|ppc64|sparc64)
+  alpha|cris|ia64|lm32|m68k|microblaze|ppc|ppc64|sparc64)
     cpu="$cpu"
   ;;
   i386|i486|i586|i686|i86pc|BePC)
@@ -981,6 +981,7 @@ i386-softmmu \
 x86_64-softmmu \
 arm-softmmu \
 cris-softmmu \
+lm32-softmmu \
 m68k-softmmu \
 microblaze-softmmu \
 mips-softmmu \
@@ -2478,7 +2479,7 @@ echo "docdir=$docdir" >> $config_host_mak
 echo "confdir=$confdir" >> $config_host_mak
 
 case "$cpu" in
-  i386|x86_64|alpha|cris|hppa|ia64|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64)
+  i386|x86_64|alpha|cris|hppa|ia64|lm32|m68k|microblaze|mips|mips64|ppc|ppc64|s390|s390x|sparc|sparc64)
     ARCH=$cpu
   ;;
   armv4b|armv4l)
@@ -2825,7 +2826,7 @@ target_arch2=`echo $target | cut -d '-' -f 1`
 target_bigendian="no"
 
 case "$target_arch2" in
-  armeb|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus)
+  armeb|lm32|m68k|microblaze|mips|mipsn32|mips64|ppc|ppcemb|ppc64|ppc64abi32|s390x|sh4eb|sparc|sparc64|sparc32plus)
   target_bigendian=yes
   ;;
 esac
@@ -2913,6 +2914,9 @@ case "$target_arch2" in
     target_nptl="yes"
     target_phys_bits=32
   ;;
+  lm32)
+    target_phys_bits=32
+  ;;
   m68k)
     bflt="yes"
     gdb_xml_files="cf-core.xml cf-fp.xml"
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] [PATCH 17/17] MAINTAINERS: add LatticeMico32 maintainer
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (15 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 16/17] Add lm32 target to configure Michael Walle
@ 2011-01-31  0:30 ` Michael Walle
  2011-02-07 16:28 ` [Qemu-devel] Re: [PATCH 00/17] LatticeMico32 target Alexander Graf
  17 siblings, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-01-31  0:30 UTC (permalink / raw)
  To: qemu-devel; +Cc: Edgar E. Iglesias, Michael Walle, Alexander Graf

Add me as the lm32-target and machines maintainer.

Signed-off-by: Michael Walle <michael@walle.cc>
---
 MAINTAINERS |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/MAINTAINERS b/MAINTAINERS
index 98db322..698a503 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -70,6 +70,11 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
 F: target-cris/
 
+LM32
+M: Michael Walle <michael@walle.cc>
+S: Maintained
+F: target-lm32/
+
 M68K
 M: Paul Brook <paul@codesourcery.com>
 S: Maintained
@@ -202,6 +207,13 @@ M: Edgar E. Iglesias <edgar.iglesias@gmail.com>
 S: Maintained
 F: hw/etraxfs.c
 
+LM32 Machines
+-------------
+EVR32 and uclinux BSP
+M: Michael Walle <michael@walle.cc>
+S: Maintained
+F: hw/lm32_boards.c
+
 M68K Machines
 -------------
 an5206
-- 
1.7.2.3

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [Qemu-devel] Re: [PATCH 00/17] LatticeMico32 target
  2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
                   ` (16 preceding siblings ...)
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 17/17] MAINTAINERS: add LatticeMico32 maintainer Michael Walle
@ 2011-02-07 16:28 ` Alexander Graf
  17 siblings, 0 replies; 27+ messages in thread
From: Alexander Graf @ 2011-02-07 16:28 UTC (permalink / raw)
  To: Michael Walle; +Cc: Edgar E. Iglesias, qemu-devel


On 31.01.2011, at 01:30, Michael Walle wrote:

> This patchset adds support for the LatticeMico32 softcore processor by
> Lattice Semiconductor.
> 
> This is the first part of a larger patchset. It adds target support and two
> simple BSPs. The second part will add support for the milkymist hardware
> platform.
> 
> 

Acked-by: Alexander Graf <agraf@suse.de>

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Qemu-devel] Re: [PATCH 02/17] lm32: translation routines
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 02/17] lm32: translation routines Michael Walle
@ 2011-02-07 18:41   ` Edgar E. Iglesias
  2011-02-07 22:00     ` Michael Walle
  2011-02-08 17:32   ` [Qemu-devel] " Richard Henderson
  1 sibling, 1 reply; 27+ messages in thread
From: Edgar E. Iglesias @ 2011-02-07 18:41 UTC (permalink / raw)
  To: Michael Walle; +Cc: qemu-devel, Alexander Graf

On Mon, Jan 31, 2011 at 01:30:31AM +0100, Michael Walle wrote:
> This patch adds the main translation routine. All opcodes of the
> LatticeMico32 processor are supported and translated to TCG ops.
> 
> Signed-off-by: Michael Walle <michael@walle.cc>

Hi Michael,

Your port looks very nice. I've only got a couple of very small comments.


> ---
>  target-lm32/helper.c      |  259 +++++++++
>  target-lm32/lm32-decode.h |   78 +++
>  target-lm32/translate.c   | 1331 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1668 insertions(+), 0 deletions(-)
>  create mode 100644 target-lm32/helper.c
>  create mode 100644 target-lm32/lm32-decode.h
>  create mode 100644 target-lm32/translate.c
> 
> diff --git a/target-lm32/helper.c b/target-lm32/helper.c
> new file mode 100644
> index 0000000..0b508c6
> --- /dev/null
> +++ b/target-lm32/helper.c
> @@ -0,0 +1,259 @@
> +/*
> + *  LatticeMico32 helper routines.
> + *
> + *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <stdio.h>
> +#include <string.h>
> +#include <assert.h>
> +
> +#include "config.h"
> +#include "cpu.h"
> +#include "exec-all.h"
> +#include "host-utils.h"
> +
> +int cpu_lm32_handle_mmu_fault(CPUState *env, target_ulong address, int rw,
> +                               int mmu_idx, int is_softmmu)
> +{
> +    int prot;
> +
> +    address &= TARGET_PAGE_MASK;
> +    prot = PAGE_BITS;
> +    if (env->flags & LM32_FLAG_IGNORE_MSB) {
> +        tlb_set_page(env, address, address & 0x7fffffff, prot, mmu_idx,
> +                TARGET_PAGE_SIZE);
> +    } else {
> +        tlb_set_page(env, address, address, prot, mmu_idx, TARGET_PAGE_SIZE);
> +    }
> +
> +    return 0;
> +}
> +
> +target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
> +{
> +    return addr & TARGET_PAGE_MASK;
> +}
> +
> +void do_interrupt(CPUState *env)
> +{
> +    qemu_log_mask(CPU_LOG_INT,
> +            "exception at pc=%x type=%x\n", env->pc, env->exception_index);
> +
> +    switch (env->exception_index) {
> +    case EXCP_INSN_BUS_ERROR:
> +    case EXCP_DATA_BUS_ERROR:
> +    case EXCP_DIVIDE_BY_ZERO:
> +    case EXCP_IRQ:
> +    case EXCP_SYSTEMCALL:
> +        /* non-debug exceptions */
> +        env->regs[R_EA] = env->pc;
> +        env->ie |= (env->ie & IE_IE) ? IE_EIE : 0;
> +        env->ie &= ~IE_IE;
> +        if (env->dc & DC_RE) {
> +            env->pc = env->deba + (env->exception_index * 32);
> +        } else {
> +            env->pc = env->eba + (env->exception_index * 32);
> +        }
> +        log_cpu_state_mask(CPU_LOG_INT, env, 0);
> +        break;
> +    case EXCP_BREAKPOINT:
> +    case EXCP_WATCHPOINT:
> +        /* debug exceptions */
> +        env->regs[R_BA] = env->pc;
> +        env->ie |= (env->ie & IE_IE) ? IE_BIE : 0;
> +        env->ie &= ~IE_IE;
> +        if (env->dc & DC_RE) {
> +            env->pc = env->deba + (env->exception_index * 32);
> +        } else {
> +            env->pc = env->eba + (env->exception_index * 32);
> +        }
> +        log_cpu_state_mask(CPU_LOG_INT, env, 0);
> +        break;
> +    default:
> +        cpu_abort(env, "unhandled exception type=%d\n",
> +                  env->exception_index);
> +        break;
> +    }
> +}
> +
> +typedef struct {
> +    const char *name;
> +    uint32_t revision;
> +    uint8_t num_interrupts;
> +    uint8_t num_breakpoints;
> +    uint8_t num_watchpoints;
> +    uint32_t features;
> +} lm32_def_t;
> +
> +static lm32_def_t lm32_defs[] = {
> +    {
> +        .name = "lm32-basic",
> +        .revision = 3,
> +        .num_interrupts = 32,
> +        .num_breakpoints = 4,
> +        .num_watchpoints = 4,
> +        .features = (LM32_FEATURE_SHIFT
> +                     | LM32_FEATURE_SIGN_EXTEND
> +                     | LM32_FEATURE_CYCLE_COUNT),
> +    },
> +    {
> +        .name = "lm32-standard",
> +        .revision = 3,
> +        .num_interrupts = 32,
> +        .num_breakpoints = 4,
> +        .num_watchpoints = 4,
> +        .features = (LM32_FEATURE_MULTIPLY
> +                     | LM32_FEATURE_DIVIDE
> +                     | LM32_FEATURE_SHIFT
> +                     | LM32_FEATURE_SIGN_EXTEND
> +                     | LM32_FEATURE_I_CACHE
> +                     | LM32_FEATURE_CYCLE_COUNT),
> +    },
> +    {
> +        .name = "lm32-full",
> +        .revision = 3,
> +        .num_interrupts = 32,
> +        .num_breakpoints = 4,
> +        .num_watchpoints = 4,
> +        .features = (LM32_FEATURE_MULTIPLY
> +                     | LM32_FEATURE_DIVIDE
> +                     | LM32_FEATURE_SHIFT
> +                     | LM32_FEATURE_SIGN_EXTEND
> +                     | LM32_FEATURE_I_CACHE
> +                     | LM32_FEATURE_D_CACHE
> +                     | LM32_FEATURE_CYCLE_COUNT),
> +    }
> +};
> +
> +void cpu_lm32_list(FILE *f, fprintf_function cpu_fprintf)
> +{
> +    int i;
> +
> +    cpu_fprintf(f, "Available CPUs:\n");
> +    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
> +        cpu_fprintf(f, "  %s\n", lm32_defs[i].name);
> +    }
> +}
> +
> +static const lm32_def_t *cpu_lm32_find_by_name(const char *name)
> +{
> +    int i;
> +
> +    for (i = 0; i < ARRAY_SIZE(lm32_defs); i++) {
> +        if (strcasecmp(name, lm32_defs[i].name) == 0) {
> +            return &lm32_defs[i];
> +        }
> +    }
> +
> +    return NULL;
> +}
> +
> +static uint32_t cfg_by_def(const lm32_def_t *def)
> +{
> +    uint32_t cfg = 0;
> +
> +    if (def->features & LM32_FEATURE_MULTIPLY) {
> +        cfg |= CFG_M;
> +    }
> +
> +    if (def->features & LM32_FEATURE_DIVIDE) {
> +        cfg |= CFG_D;
> +    }
> +
> +    if (def->features & LM32_FEATURE_SHIFT) {
> +        cfg |= CFG_S;
> +    }
> +
> +    if (def->features & LM32_FEATURE_SIGN_EXTEND) {
> +        cfg |= CFG_X;
> +    }
> +
> +    if (def->features & LM32_FEATURE_I_CACHE) {
> +        cfg |= CFG_IC;
> +    }
> +
> +    if (def->features & LM32_FEATURE_D_CACHE) {
> +        cfg |= CFG_DC;
> +    }
> +
> +    if (def->features & LM32_FEATURE_CYCLE_COUNT) {
> +        cfg |= CFG_CC;
> +    }
> +
> +    cfg |= (def->num_interrupts << CFG_INT_SHIFT);
> +    cfg |= (def->num_breakpoints << CFG_BP_SHIFT);
> +    cfg |= (def->num_watchpoints << CFG_WP_SHIFT);
> +    cfg |= (def->revision << CFG_REV_SHIFT);
> +
> +    return cfg;
> +}
> +
> +CPUState *cpu_lm32_init(const char *cpu_model)
> +{
> +    CPUState *env;
> +    const lm32_def_t *def;
> +    static int tcg_initialized;
> +
> +    def = cpu_lm32_find_by_name(cpu_model);
> +    if (!def) {
> +        return NULL;
> +    }
> +
> +    env = qemu_mallocz(sizeof(CPUState));
> +
> +    env->features = def->features;
> +    env->num_bps = def->num_breakpoints;
> +    env->num_wps = def->num_watchpoints;
> +    env->cfg = cfg_by_def(def);
> +    env->flags = 0;
> +
> +    cpu_exec_init(env);
> +    cpu_reset(env);
> +
> +    if (!tcg_initialized) {
> +        tcg_initialized = 1;
> +        lm32_translate_init();
> +    }
> +
> +    return env;
> +}
> +
> +/* Some soc ignores the MSB on the address bus. Thus creating a shadow memory
> + * area. As a general rule, 0x00000000-0x7fffffff is cached, whereas
> + * 0x80000000-0xffffffff is not cached and used to access IO devices. */
> +void cpu_lm32_set_phys_msb_ignore(CPUState *env, int value)
> +{
> +    if (value) {
> +        env->flags |= LM32_FLAG_IGNORE_MSB;
> +    } else {
> +        env->flags &= ~LM32_FLAG_IGNORE_MSB;
> +    }
> +}
> +
> +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);
> +    }
> +
> +    tlb_flush(env, 1);
> +
> +    /* reset cpu state */
> +    memset(env, 0, offsetof(CPULM32State, breakpoints));
> +}
> +
> diff --git a/target-lm32/lm32-decode.h b/target-lm32/lm32-decode.h
> new file mode 100644
> index 0000000..f745b39
> --- /dev/null
> +++ b/target-lm32/lm32-decode.h
> @@ -0,0 +1,78 @@
> +/*
> + *  LatticeMico32 instruction decoding macros.
> + *
> + *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +/* 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, value and mask.  */
> +#define DEC_ADD     {B8(00001101), B8(00011111)}
> +#define DEC_AND     {B8(00001000), B8(00011111)}
> +#define DEC_ANDHI   {B8(00011000), B8(00111111)}
> +#define DEC_B       {B8(00110000), B8(00111111)}
> +#define DEC_BI      {B8(00111000), B8(00111111)}
> +#define DEC_BE      {B8(00010001), B8(00111111)}
> +#define DEC_BG      {B8(00010010), B8(00111111)}
> +#define DEC_BGE     {B8(00010011), B8(00111111)}
> +#define DEC_BGEU    {B8(00010100), B8(00111111)}
> +#define DEC_BGU     {B8(00010101), B8(00111111)}
> +#define DEC_BNE     {B8(00010111), B8(00111111)}
> +#define DEC_CALL    {B8(00110110), B8(00111111)}
> +#define DEC_CALLI   {B8(00111110), B8(00111111)}
> +#define DEC_CMPE    {B8(00011001), B8(00011111)}
> +#define DEC_CMPG    {B8(00011010), B8(00011111)}
> +#define DEC_CMPGE   {B8(00011011), B8(00011111)}
> +#define DEC_CMPGEU  {B8(00011100), B8(00011111)}
> +#define DEC_CMPGU   {B8(00011101), B8(00011111)}
> +#define DEC_CMPNE   {B8(00011111), B8(00011111)}
> +#define DEC_DIVU    {B8(00100011), B8(00111111)}
> +#define DEC_LB      {B8(00000100), B8(00111111)}
> +#define DEC_LBU     {B8(00010000), B8(00111111)}
> +#define DEC_LH      {B8(00000111), B8(00111111)}
> +#define DEC_LHU     {B8(00001011), B8(00111111)}
> +#define DEC_LW      {B8(00001010), B8(00111111)}
> +#define DEC_MODU    {B8(00110001), B8(00111111)}
> +#define DEC_MUL     {B8(00000010), B8(00011111)}
> +#define DEC_NOR     {B8(00000001), B8(00011111)}
> +#define DEC_OR      {B8(00001110), B8(00011111)}
> +#define DEC_ORHI    {B8(00011110), B8(00111111)}
> +#define DEC_RAISE   {B8(00101011), B8(00111111)}
> +#define DEC_RCSR    {B8(00100100), B8(00111111)}
> +#define DEC_SB      {B8(00001100), B8(00111111)}
> +#define DEC_SEXTB   {B8(00101100), B8(00111111)}
> +#define DEC_SEXTH   {B8(00110111), B8(00111111)}
> +#define DEC_SH      {B8(00000011), B8(00111111)}
> +#define DEC_SL      {B8(00001111), B8(00011111)}
> +#define DEC_SR      {B8(00000101), B8(00011111)}
> +#define DEC_SRU     {B8(00000000), B8(00011111)}
> +#define DEC_SUB     {B8(00110010), B8(00111111)}
> +#define DEC_SW      {B8(00010110), B8(00111111)}
> +#define DEC_USER    {B8(00110011), B8(00111111)}
> +#define DEC_WCSR    {B8(00110100), B8(00111111)}
> +#define DEC_XNOR    {B8(00001001), B8(00011111)}
> +#define DEC_XOR     {B8(00000110), B8(00011111)}
> +
> diff --git a/target-lm32/translate.c b/target-lm32/translate.c
> new file mode 100644
> index 0000000..d49f798
> --- /dev/null
> +++ b/target-lm32/translate.c
> @@ -0,0 +1,1331 @@
> +/*
> + *  LatticeMico32 main translation routines.
> + *
> + *  Copyright (c) 2010 Michael Walle <michael@walle.cc>
> + *
> + * 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, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#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 "helper.h"
> +#include "tcg-op.h"
> +#include "lm32-decode.h"
> +#include "qemu-common.h"
> +
> +#include "hw/lm32_pic.h"
> +
> +#define GEN_HELPER 1
> +#include "helper.h"
> +
> +#define DISAS_LM32 1
> +#if DISAS_LM32
> +#  define LOG_DIS(...) qemu_log_mask(CPU_LOG_TB_IN_ASM, ## __VA_ARGS__)
> +#else
> +#  define LOG_DIS(...) do { } while (0)
> +#endif
> +
> +#define EXTRACT_FIELD(src, start, end) \
> +            (((src) >> start) & ((1 << (end - start + 1)) - 1))
> +
> +#define MEM_INDEX 0
> +
> +static TCGv_ptr cpu_env;
> +static TCGv cpu_R[32];
> +static TCGv cpu_pc;
> +static TCGv cpu_ie;
> +static TCGv cpu_icc;
> +static TCGv cpu_dcc;
> +static TCGv cpu_cc;
> +static TCGv cpu_cfg;
> +static TCGv cpu_eba;
> +static TCGv cpu_dc;
> +static TCGv cpu_deba;
> +static TCGv cpu_bp[4];
> +static TCGv cpu_wp[4];
> +
> +#include "gen-icount.h"
> +
> +enum {
> +    OP_FMT_RI,
> +    OP_FMT_RR,
> +    OP_FMT_CR,
> +    OP_FMT_I
> +};
> +
> +#define JMP_NOJMP    0
> +#define JMP_DIRECT   1
> +#define JMP_INDIRECT 2

These don't seem to be used, can we remove them?


> +
> +/* This is the state at translation time.  */
> +typedef struct DisasContext {
> +    CPUState *env;
> +    target_ulong pc;
> +
> +    /* Decoder.  */
> +    int format;
> +    uint32_t ir;
> +    uint8_t opcode;
> +    uint8_t r0, r1, r2, csr;
> +    uint16_t imm5;
> +    uint16_t imm16;
> +    uint32_t imm26;
> +
> +    unsigned int delayed_branch;
> +    unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
> +    int is_jmp;
> +
> +    unsigned int jmp;
> +    uint32_t jmp_pc;

These too.


> +
> +    int nr_nops;

This should probably go aswell..

> +    struct TranslationBlock *tb;
> +    int singlestep_enabled;
> +} DisasContext;
> +
> +static const 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/gp", "r27/fp", "r28/sp", "r29/ra",
> +    "r30/ea", "r31/ba", "bp0", "bp1", "bp2", "bp3", "wp0",
> +    "wp1", "wp2", "wp3"
> +};
> +
> +static inline int zero_extend(unsigned int val, int width)
> +{
> +    return val & ((1 << width) - 1);
> +}
> +
> +static inline int sign_extend(unsigned int val, int width)
> +{
> +    int sval;
> +
> +    /* LSL.  */
> +    val <<= 32 - width;
> +    sval = val;
> +    /* ASR.  */
> +    sval >>= 32 - width;
> +
> +    return sval;
> +}
> +
> +static inline void t_gen_raise_exception(DisasContext *dc, uint32_t index)
> +{
> +    TCGv_i32 tmp = tcg_const_i32(index);
> +
> +    gen_helper_raise_exception(tmp);
> +    tcg_temp_free_i32(tmp);
> +}
> +
> +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) &&
> +            likely(!dc->singlestep_enabled)) {
> +        tcg_gen_goto_tb(n);
> +        tcg_gen_movi_tl(cpu_pc, dest);
> +        tcg_gen_exit_tb((long)tb + n);
> +    } else {
> +        tcg_gen_movi_tl(cpu_pc, dest);
> +        if (dc->singlestep_enabled) {
> +            t_gen_raise_exception(dc, EXCP_DEBUG);
> +        }
> +        tcg_gen_exit_tb(0);
> +    }
> +}
> +
> +static void dec_add(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        if (dc->r0 == R_R0) {
> +            if (dc->r1 == R_R0 && dc->imm16 == 0) {
> +                LOG_DIS("nop\n");
> +            } else {
> +                LOG_DIS("mvi r%d, %d\n", dc->r1, sign_extend(dc->imm16, 16));
> +            }
> +        } else {
> +            LOG_DIS("addi r%d, r%d, %d\n", dc->r1, dc->r0,
> +                    sign_extend(dc->imm16, 16));
> +        }
> +    } else {
> +        LOG_DIS("add r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_addi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        tcg_gen_add_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +    }
> +}
> +
> +static void dec_and(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("andi r%d, r%d, %d\n", dc->r1, dc->r0,
> +                zero_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("and r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0],
> +                zero_extend(dc->imm16, 16));
> +    } else  {
> +        if (dc->r0 == 0 && dc->r1 == 0 && dc->r2 == 0) {
> +            tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
> +            gen_helper_hlt();
> +        } else {
> +            tcg_gen_and_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +        }
> +    }
> +}
> +
> +static void dec_andhi(DisasContext *dc)
> +{
> +    LOG_DIS("andhi r%d, r%d, %d\n", dc->r2, dc->r0, dc->imm16);
> +
> +    tcg_gen_andi_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
> +}
> +
> +static void dec_b(DisasContext *dc)
> +{
> +    if (dc->r0 == R_RA) {
> +        LOG_DIS("ret\n");
> +    } else if (dc->r0 == R_EA) {
> +        LOG_DIS("eret\n");
> +    } else if (dc->r0 == R_BA) {
> +        LOG_DIS("bret\n");
> +    } else {
> +        LOG_DIS("b r%d\n", dc->r0);
> +    }
> +
> +    /* restore IE.IE in case of an eret */
> +    if (dc->r0 == R_EA) {
> +        TCGv t0 = tcg_temp_new();
> +        int l1 = gen_new_label();
> +        tcg_gen_andi_tl(t0, cpu_ie, IE_EIE);
> +        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
> +        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_EIE, l1);
> +        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
> +        gen_set_label(l1);
> +        tcg_temp_free(t0);
> +    } else if (dc->r0 == R_BA) {
> +        TCGv t0 = tcg_temp_new();
> +        int l1 = gen_new_label();
> +        tcg_gen_andi_tl(t0, cpu_ie, IE_BIE);
> +        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_IE);
> +        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_BIE, l1);
> +        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
> +        gen_set_label(l1);
> +        tcg_temp_free(t0);
> +    }
> +    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
> +
> +    dc->is_jmp = DISAS_JUMP;
> +}
> +
> +static void dec_bi(DisasContext *dc)
> +{
> +    LOG_DIS("bi %d\n", sign_extend(dc->imm26 << 2, 26));
> +
> +    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
> +
> +    dc->is_jmp = DISAS_TB_JUMP;
> +}
> +
> +static inline void gen_cond_branch(DisasContext *dc, int cond)
> +{
> +    int l1;
> +
> +    l1 = gen_new_label();
> +    tcg_gen_brcond_tl(cond, cpu_R[dc->r0], cpu_R[dc->r1], l1);
> +    gen_goto_tb(dc, 0, dc->pc + 4);
> +    gen_set_label(l1);
> +    gen_goto_tb(dc, 1, dc->pc + (sign_extend(dc->imm16 << 2, 16)));
> +    dc->is_jmp = DISAS_TB_JUMP;
> +}
> +
> +static void dec_be(DisasContext *dc)
> +{
> +    LOG_DIS("be r%d, r%d, %d\n", dc->r0, dc->r1,
> +            sign_extend(dc->imm16, 16) * 4);
> +
> +    gen_cond_branch(dc, TCG_COND_EQ);
> +}
> +
> +static void dec_bg(DisasContext *dc)
> +{
> +    LOG_DIS("bg r%d, r%d, %d\n", dc->r0, dc->r1,
> +            sign_extend(dc->imm16, 16 * 4));
> +
> +    gen_cond_branch(dc, TCG_COND_GT);
> +}
> +
> +static void dec_bge(DisasContext *dc)
> +{
> +    LOG_DIS("bge r%d, r%d, %d\n", dc->r0, dc->r1,
> +            sign_extend(dc->imm16, 16) * 4);
> +
> +    gen_cond_branch(dc, TCG_COND_GE);
> +}
> +
> +static void dec_bgeu(DisasContext *dc)
> +{
> +    LOG_DIS("bgeu r%d, r%d, %d\n", dc->r0, dc->r1,
> +            sign_extend(dc->imm16, 16) * 4);
> +
> +    gen_cond_branch(dc, TCG_COND_GEU);
> +}
> +
> +static void dec_bgu(DisasContext *dc)
> +{
> +    LOG_DIS("bgu r%d, r%d, %d\n", dc->r0, dc->r1,
> +            sign_extend(dc->imm16, 16) * 4);
> +
> +    gen_cond_branch(dc, TCG_COND_GTU);
> +}
> +
> +static void dec_bne(DisasContext *dc)
> +{
> +    LOG_DIS("bne r%d, r%d, %d\n", dc->r0, dc->r1,
> +            sign_extend(dc->imm16, 16) * 4);
> +
> +    gen_cond_branch(dc, TCG_COND_NE);
> +}
> +
> +static void dec_call(DisasContext *dc)
> +{
> +    LOG_DIS("call r%d\n", dc->r0);
> +
> +    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
> +    tcg_gen_mov_tl(cpu_pc, cpu_R[dc->r0]);
> +
> +    dc->is_jmp = DISAS_JUMP;
> +}
> +
> +static void dec_calli(DisasContext *dc)
> +{
> +    LOG_DIS("calli %d\n", sign_extend(dc->imm26, 26) * 4);
> +
> +    tcg_gen_movi_tl(cpu_R[R_RA], dc->pc + 4);
> +    gen_goto_tb(dc, 0, dc->pc + (sign_extend(dc->imm26 << 2, 26)));
> +
> +    dc->is_jmp = DISAS_TB_JUMP;
> +}
> +
> +static inline void gen_compare(DisasContext *dc, int cond)
> +{
> +    int rX = (dc->format == OP_FMT_RR) ? dc->r2 : dc->r1;
> +    int rY = (dc->format == OP_FMT_RR) ? dc->r0 : dc->r0;
> +    int rZ = (dc->format == OP_FMT_RR) ? dc->r1 : -1;
> +
> +    int l1, l2;
> +
> +    l1 = gen_new_label();
> +    l2 = gen_new_label();
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_brcondi_tl(cond, cpu_R[rY], sign_extend(dc->imm16, 16), l1);
> +    } else {
> +        tcg_gen_brcond_tl(cond, cpu_R[rY], cpu_R[rZ], l1);
> +    }
> +    tcg_gen_movi_tl(cpu_R[rX], 0);
> +    tcg_gen_br(l2);
> +    gen_set_label(l1);
> +    tcg_gen_movi_tl(cpu_R[rX], 1);
> +    gen_set_label(l2);
> +}
> +
> +static void dec_cmpe(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("cmpei r%d, r%d, %d\n", dc->r0, dc->r1,
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("cmpe r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    gen_compare(dc, TCG_COND_EQ);
> +}
> +
> +static void dec_cmpg(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("cmpgi r%d, r%d, %d\n", dc->r0, dc->r1,
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("cmpg r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    gen_compare(dc, TCG_COND_GT);
> +}
> +
> +static void dec_cmpge(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("cmpgei r%d, r%d, %d\n", dc->r0, dc->r1,
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("cmpge r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    gen_compare(dc, TCG_COND_GE);
> +}
> +
> +static void dec_cmpgeu(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("cmpgeui r%d, r%d, %d\n", dc->r0, dc->r1,
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("cmpgeu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    gen_compare(dc, TCG_COND_GEU);
> +}
> +
> +static void dec_cmpgu(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("cmpgui r%d, r%d, %d\n", dc->r0, dc->r1,
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("cmpgu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    gen_compare(dc, TCG_COND_GTU);
> +}
> +
> +static void dec_cmpne(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("cmpnei r%d, r%d, %d\n", dc->r0, dc->r1,
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("cmpne r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    gen_compare(dc, TCG_COND_NE);
> +}
> +
> +static void dec_divu(DisasContext *dc)
> +{
> +    int l1;
> +
> +    LOG_DIS("divu r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +
> +    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
> +        cpu_abort(dc->env, "hardware divider is not available\n");
> +    }
> +
> +    l1 = gen_new_label();
> +    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
> +    tcg_gen_movi_tl(cpu_pc, dc->pc);
> +    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
> +    gen_set_label(l1);
> +    tcg_gen_divu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +}
> +
> +static void dec_lb(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("lb r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_ld8s(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_lbu(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("lbu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_ld8u(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_lh(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("lh r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_ld16s(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_lhu(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("lhu r%d, (r%d+%d)\n", dc->r1, dc->r0, dc->imm16);
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_ld16u(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_lw(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("lw r%d, (r%d+%d)\n", dc->r1, dc->r0, sign_extend(dc->imm16, 16));
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_ld32s(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_modu(DisasContext *dc)
> +{
> +    int l1;
> +
> +    LOG_DIS("modu r%d, r%d, %d\n", dc->r2, dc->r0, dc->r1);
> +
> +    if (!(dc->env->features & LM32_FEATURE_DIVIDE)) {
> +        cpu_abort(dc->env, "hardware divider is not available\n");
> +    }
> +
> +    l1 = gen_new_label();
> +    tcg_gen_brcondi_tl(TCG_COND_NE, cpu_R[dc->r1], 0, l1);
> +    tcg_gen_movi_tl(cpu_pc, dc->pc);
> +    t_gen_raise_exception(dc, EXCP_DIVIDE_BY_ZERO);
> +    gen_set_label(l1);
> +    tcg_gen_remu_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +}
> +
> +static void dec_mul(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("muli r%d, r%d, %d\n", dc->r0, dc->r1,
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("mul r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
> +        cpu_abort(dc->env, "hardware multiplier is not available\n");
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_muli_tl(cpu_R[dc->r1], cpu_R[dc->r0],
> +                sign_extend(dc->imm16, 16));
> +    } else {
> +        tcg_gen_mul_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +    }
> +}
> +
> +static void dec_nor(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("nori r%d, r%d, %d\n", dc->r0, dc->r1,
> +                zero_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("nor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        TCGv t0 = tcg_temp_new();
> +        tcg_gen_movi_tl(t0, zero_extend(dc->imm16, 16));
> +        tcg_gen_nor_tl(cpu_R[dc->r1], cpu_R[dc->r0], t0);
> +        tcg_temp_free(t0);
> +    } else {
> +        tcg_gen_nor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +    }
> +}
> +
> +static void dec_or(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("ori r%d, r%d, %d\n", dc->r1, dc->r0,
> +                zero_extend(dc->imm16, 16));
> +    } else {
> +        if (dc->r1 == R_R0) {
> +            LOG_DIS("mv r%d, r%d\n", dc->r2, dc->r0);
> +        } else {
> +            LOG_DIS("or r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +        }
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
> +                zero_extend(dc->imm16, 16));
> +    } else {
> +        tcg_gen_or_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +    }
> +}
> +
> +static void dec_orhi(DisasContext *dc)
> +{
> +    if (dc->r0 == R_R0) {
> +        LOG_DIS("mvhi r%d, %d\n", dc->r1, dc->imm16);
> +    } else {
> +        LOG_DIS("orhi r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm16);
> +    }
> +
> +    tcg_gen_ori_tl(cpu_R[dc->r1], cpu_R[dc->r0], (dc->imm16 << 16));
> +}
> +
> +static void dec_raise(DisasContext *dc)
> +{
> +    TCGv t0;
> +    int l1;
> +
> +    if (dc->imm5 == 7) {
> +        LOG_DIS("scall\n");
> +    } else if (dc->imm5 == 2) {
> +        LOG_DIS("break\n");
> +    } else {
> +        cpu_abort(dc->env, "invalid opcode\n");
> +    }
> +
> +    t0 = tcg_temp_new();
> +    l1 = gen_new_label();
> +
> +    /* save IE.IE */
> +    tcg_gen_andi_tl(t0, cpu_ie, IE_IE);
> +
> +    /* IE.IE = 0 */
> +    tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_IE);
> +
> +    if (dc->imm5 == 7) {
> +        /* IE.EIE = IE.IE */
> +        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_EIE);
> +        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1);
> +        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_EIE);
> +        gen_set_label(l1);
> +
> +        /* gpr[ea] = PC */
> +        tcg_gen_movi_tl(cpu_R[R_EA], dc->pc);
> +        tcg_temp_free(t0);
> +
> +        tcg_gen_movi_tl(cpu_pc, dc->pc);
> +        t_gen_raise_exception(dc, EXCP_SYSTEMCALL);
> +    } else {
> +        /* IE.BIE = IE.IE */
> +        tcg_gen_ori_tl(cpu_ie, cpu_ie, IE_BIE);
> +        tcg_gen_brcondi_tl(TCG_COND_EQ, t0, IE_IE, l1);
> +        tcg_gen_andi_tl(cpu_ie, cpu_ie, ~IE_BIE);
> +        gen_set_label(l1);
> +
> +        /* gpr[ba] = PC */
> +        tcg_gen_movi_tl(cpu_R[R_BA], dc->pc);
> +        tcg_temp_free(t0);
> +
> +        tcg_gen_movi_tl(cpu_pc, dc->pc);
> +        t_gen_raise_exception(dc, EXCP_BREAKPOINT);
> +    }
> +}
> +
> +static void dec_rcsr(DisasContext *dc)
> +{
> +    LOG_DIS("rcsr r%d, %d\n", dc->r2, dc->csr);
> +
> +    switch (dc->csr) {
> +    case CSR_IE:
> +        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_ie);
> +        break;
> +    case CSR_IM:
> +        gen_helper_rcsr_im(cpu_R[dc->r2]);
> +        break;
> +    case CSR_IP:
> +        gen_helper_rcsr_ip(cpu_R[dc->r2]);
> +        break;
> +    case CSR_CC:
> +        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cc);
> +        break;
> +    case CSR_CFG:
> +        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_cfg);
> +        break;
> +    case CSR_EBA:
> +        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_eba);
> +        break;
> +    case CSR_DC:
> +        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_dc);
> +        break;
> +    case CSR_DEBA:
> +        tcg_gen_mov_tl(cpu_R[dc->r2], cpu_deba);
> +        break;
> +    case CSR_JTX:
> +        gen_helper_rcsr_jtx(cpu_R[dc->r2]);
> +        break;
> +    case CSR_JRX:
> +        gen_helper_rcsr_jrx(cpu_R[dc->r2]);
> +        break;
> +    case CSR_ICC:
> +    case CSR_DCC:
> +    case CSR_BP0:
> +    case CSR_BP1:
> +    case CSR_BP2:
> +    case CSR_BP3:
> +    case CSR_WP0:
> +    case CSR_WP1:
> +    case CSR_WP2:
> +    case CSR_WP3:
> +        cpu_abort(dc->env, "invalid read access csr=%x\n", dc->csr);
> +        break;
> +    default:
> +        cpu_abort(dc->env, "read_csr: unknown csr=%x\n", dc->csr);
> +        break;
> +    }
> +}
> +
> +static void dec_sb(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("sb (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_st8(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_sextb(DisasContext *dc)
> +{
> +    LOG_DIS("sextb r%d, r%d\n", dc->r2, dc->r0);
> +
> +    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
> +        cpu_abort(dc->env, "hardware sign extender is not available\n");
> +    }
> +
> +    tcg_gen_ext8s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
> +}
> +
> +static void dec_sexth(DisasContext *dc)
> +{
> +    LOG_DIS("sexth r%d, r%d\n", dc->r2, dc->r0);
> +
> +    if (!(dc->env->features & LM32_FEATURE_SIGN_EXTEND)) {
> +        cpu_abort(dc->env, "hardware sign extender is not available\n");
> +    }
> +
> +    tcg_gen_ext16s_tl(cpu_R[dc->r2], cpu_R[dc->r0]);
> +}
> +
> +static void dec_sh(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("sh (r%d+%d), r%d\n", dc->r0, dc->imm16, dc->r1);
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_st16(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_sl(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("sli r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
> +    } else {
> +        LOG_DIS("sl r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
> +        cpu_abort(dc->env, "hardware shifter is not available\n");
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_shli_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
> +    } else {
> +        TCGv t0 = tcg_temp_new();
> +        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
> +        tcg_gen_shl_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
> +        tcg_temp_free(t0);
> +    }
> +}
> +
> +static void dec_sr(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("sri r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
> +    } else {
> +        LOG_DIS("sr r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
> +        if (dc->format == OP_FMT_RI) {
> +            /* TODO: check r1 == 1 during runtime */
> +        } else {
> +            if (dc->imm5 != 1) {
> +                cpu_abort(dc->env, "hardware shifter is not available\n");
> +            }
> +        }
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_sari_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
> +    } else {
> +        TCGv t0 = tcg_temp_new();
> +        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
> +        tcg_gen_sar_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
> +        tcg_temp_free(t0);
> +    }
> +}
> +
> +static void dec_sru(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("srui r%d, r%d, %d\n", dc->r1, dc->r0, dc->imm5);
> +    } else {
> +        LOG_DIS("sru r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (!(dc->env->features & LM32_FEATURE_SHIFT)) {
> +        if (dc->format == OP_FMT_RI) {
> +            /* TODO: check r1 == 1 during runtime */
> +        } else {
> +            if (dc->imm5 != 1) {
> +                cpu_abort(dc->env, "hardware shifter is not available\n");
> +            }
> +        }
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_shri_tl(cpu_R[dc->r1], cpu_R[dc->r0], dc->imm5);
> +    } else {
> +        TCGv t0 = tcg_temp_new();
> +        tcg_gen_andi_tl(t0, cpu_R[dc->r1], 0x1f);
> +        tcg_gen_shr_tl(cpu_R[dc->r2], cpu_R[dc->r0], t0);
> +        tcg_temp_free(t0);
> +    }
> +}
> +
> +static void dec_sub(DisasContext *dc)
> +{
> +    LOG_DIS("sub r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +
> +    tcg_gen_sub_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +}
> +
> +static void dec_sw(DisasContext *dc)
> +{
> +    TCGv t0;
> +
> +    LOG_DIS("sw (r%d+%d), r%d\n", dc->r0, sign_extend(dc->imm16, 16), dc->r1);
> +
> +    t0 = tcg_temp_new();
> +    tcg_gen_addi_tl(t0, cpu_R[dc->r0], sign_extend(dc->imm16, 16));
> +    tcg_gen_qemu_st32(cpu_R[dc->r1], t0, MEM_INDEX);
> +    tcg_temp_free(t0);
> +}
> +
> +static void dec_user(DisasContext *dc)
> +{
> +    LOG_DIS("user");
> +
> +    cpu_abort(dc->env, "user insn undefined\n");
> +}
> +
> +static void dec_wcsr(DisasContext *dc)
> +{
> +    int no;
> +
> +    LOG_DIS("wcsr r%d, %d\n", dc->r1, dc->csr);
> +
> +    switch (dc->csr) {
> +    case CSR_IE:
> +        tcg_gen_mov_tl(cpu_ie, cpu_R[dc->r1]);
> +        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
> +        dc->is_jmp = DISAS_UPDATE;
> +        break;
> +    case CSR_IM:
> +        /* mark as an io operation because it could cause an interrupt */
> +        if (use_icount) {
> +            gen_io_start();
> +        }
> +        gen_helper_wcsr_im(cpu_R[dc->r1]);
> +        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
> +        if (use_icount) {
> +            gen_io_end();
> +        }
> +        dc->is_jmp = DISAS_UPDATE;
> +        break;
> +    case CSR_IP:
> +        /* mark as an io operation because it could cause an interrupt */
> +        if (use_icount) {
> +            gen_io_start();
> +        }
> +        gen_helper_wcsr_ip(cpu_R[dc->r1]);
> +        tcg_gen_movi_tl(cpu_pc, dc->pc + 4);
> +        if (use_icount) {
> +            gen_io_end();
> +        }
> +        dc->is_jmp = DISAS_UPDATE;
> +        break;
> +    case CSR_ICC:
> +        /* TODO */
> +        break;
> +    case CSR_DCC:
> +        /* TODO */
> +        break;
> +    case CSR_EBA:
> +        tcg_gen_mov_tl(cpu_eba, cpu_R[dc->r1]);
> +        break;
> +    case CSR_DEBA:
> +        tcg_gen_mov_tl(cpu_deba, cpu_R[dc->r1]);
> +        break;
> +    case CSR_JTX:
> +        gen_helper_wcsr_jtx(cpu_R[dc->r1]);
> +        break;
> +    case CSR_JRX:
> +        gen_helper_wcsr_jrx(cpu_R[dc->r1]);
> +        break;
> +    case CSR_DC:
> +        tcg_gen_mov_tl(cpu_dc, cpu_R[dc->r1]);
> +        break;
> +    case CSR_BP0:
> +    case CSR_BP1:
> +    case CSR_BP2:
> +    case CSR_BP3:
> +        no = dc->csr - CSR_BP0;
> +        if (dc->env->num_bps <= no) {
> +            cpu_abort(dc->env, "breakpoint #%i is not available\n", no);
> +        }
> +        tcg_gen_mov_tl(cpu_bp[no], cpu_R[dc->r1]);
> +        break;
> +    case CSR_WP0:
> +    case CSR_WP1:
> +    case CSR_WP2:
> +    case CSR_WP3:
> +        no = dc->csr - CSR_WP0;
> +        if (dc->env->num_wps <= no) {
> +            cpu_abort(dc->env, "watchpoint #%i is not available\n", no);
> +        }
> +        tcg_gen_mov_tl(cpu_wp[no], cpu_R[dc->r1]);
> +        break;
> +    case CSR_CC:
> +    case CSR_CFG:
> +        cpu_abort(dc->env, "invalid write access csr=%x\n", dc->csr);
> +        break;
> +    default:
> +        cpu_abort(dc->env, "write_csr unknown csr=%x\n", dc->csr);
> +        break;
> +    }
> +}
> +
> +static void dec_xnor(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("xnori r%d, r%d, %d\n", dc->r0, dc->r1,
> +                zero_extend(dc->imm16, 16));
> +    } else {
> +        if (dc->r1 == R_R0) {
> +            LOG_DIS("not r%d, r%d\n", dc->r2, dc->r0);
> +        } else {
> +            LOG_DIS("xnor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +        }
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
> +                zero_extend(dc->imm16, 16));
> +        tcg_gen_not_tl(cpu_R[dc->r1], cpu_R[dc->r1]);
> +    } else {
> +        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +        tcg_gen_not_tl(cpu_R[dc->r2], cpu_R[dc->r2]);
> +    }
> +}
> +
> +static void dec_xor(DisasContext *dc)
> +{
> +    if (dc->format == OP_FMT_RI) {
> +        LOG_DIS("xori r%d, r%d, %d\n", dc->r0, dc->r1,
> +                zero_extend(dc->imm16, 16));
> +    } else {
> +        LOG_DIS("xor r%d, r%d, r%d\n", dc->r2, dc->r0, dc->r1);
> +    }
> +
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_xori_tl(cpu_R[dc->r1], cpu_R[dc->r0],
> +                zero_extend(dc->imm16, 16));
> +    } else {
> +        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +    }
> +}
> +
> +static struct decoder_info {
> +    struct {
> +        uint32_t bits;
> +        uint32_t mask;
> +    };
> +    void (*dec)(DisasContext *dc);
> +} decinfo[] = {
> +    {DEC_ADD, dec_add},
> +    {DEC_AND, dec_and},
> +    {DEC_ANDHI, dec_andhi},
> +    {DEC_B, dec_b},
> +    {DEC_BI, dec_bi},
> +    {DEC_BE, dec_be},
> +    {DEC_BG, dec_bg},
> +    {DEC_BGE, dec_bge},
> +    {DEC_BGEU, dec_bgeu},
> +    {DEC_BGU, dec_bgu},
> +    {DEC_BNE, dec_bne},
> +    {DEC_CALL, dec_call},
> +    {DEC_CALLI, dec_calli},
> +    {DEC_CMPE, dec_cmpe},
> +    {DEC_CMPG, dec_cmpg},
> +    {DEC_CMPGE, dec_cmpge},
> +    {DEC_CMPGEU, dec_cmpgeu},
> +    {DEC_CMPGU, dec_cmpgu},
> +    {DEC_CMPNE, dec_cmpne},
> +    {DEC_DIVU, dec_divu},
> +    {DEC_LB, dec_lb},
> +    {DEC_LBU, dec_lbu},
> +    {DEC_LH, dec_lh},
> +    {DEC_LHU, dec_lhu},
> +    {DEC_LW, dec_lw},
> +    {DEC_MODU, dec_modu},
> +    {DEC_MUL, dec_mul},
> +    {DEC_NOR, dec_nor},
> +    {DEC_OR, dec_or},
> +    {DEC_ORHI, dec_orhi},
> +    {DEC_RAISE, dec_raise},
> +    {DEC_RCSR, dec_rcsr},
> +    {DEC_SB, dec_sb},
> +    {DEC_SEXTB, dec_sextb},
> +    {DEC_SEXTH, dec_sexth},
> +    {DEC_SH, dec_sh},
> +    {DEC_SL, dec_sl},
> +    {DEC_SR, dec_sr},
> +    {DEC_SRU, dec_sru},
> +    {DEC_SUB, dec_sub},
> +    {DEC_SW, dec_sw},
> +    {DEC_USER, dec_user},
> +    {DEC_WCSR, dec_wcsr},
> +    {DEC_XNOR, dec_xnor},
> +    {DEC_XOR, dec_xor},
> +};
> +
> +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);
> +
> +    /* try guessing 'empty' instruction memory, although it may be a valid
> +     * instruction sequence (eg. srui r0, r0, 0) */
> +    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");
> +        }
> +    }

This nop sequence detection should probably go away. A reminder for
me too to remove it from the microblaze port (from where I guess you
inherited it)..

Cheers

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Qemu-devel] Re: [PATCH 02/17] lm32: translation routines
  2011-02-07 18:41   ` [Qemu-devel] " Edgar E. Iglesias
@ 2011-02-07 22:00     ` Michael Walle
  2011-02-07 22:20       ` Edgar E. Iglesias
  0 siblings, 1 reply; 27+ messages in thread
From: Michael Walle @ 2011-02-07 22:00 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel, Alexander Graf

Hi Edgar.

first of all let me thank you for the review.

On Mon, Feb 07 2011, 19:41:25, Edgar E. Iglesias wrote:
> > +#define JMP_NOJMP    0
> > +#define JMP_DIRECT   1
> > +#define JMP_INDIRECT 2
> 
> These don't seem to be used, can we remove them?
Good catch :) I'll remove them.

> > +
> > +/* This is the state at translation time.  */
> > +typedef struct DisasContext {
> > +    CPUState *env;
> > +    target_ulong pc;
> > +
> > +    /* Decoder.  */
> > +    int format;
> > +    uint32_t ir;
> > +    uint8_t opcode;
> > +    uint8_t r0, r1, r2, csr;
> > +    uint16_t imm5;
> > +    uint16_t imm16;
> > +    uint32_t imm26;
> > +
> > +    unsigned int delayed_branch;
> > +    unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
> > +    int is_jmp;
> > +
> > +    unsigned int jmp;
> > +    uint32_t jmp_pc;
> 
> These too.
Ditto.

> > +
> > +    int nr_nops;
> 
> This should probably go aswell..
See below.

> > +    /* try guessing 'empty' instruction memory, although it may be a
> > valid +     * instruction sequence (eg. srui r0, r0, 0) */
> > +    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");
> > +        }
> > +    }
> 
> This nop sequence detection should probably go away. A reminder for
> me too to remove it from the microblaze port (from where I guess you
> inherited it)..
I've always found this 'feature' handy, esp when you are porting new software. 
Is there any particular reason why this should be removed? Besides the fact 
that it won't match the real hardware if those instructions are executed. In 
the case of the LM32, these are really nonsense instructions (shift r0 right 
by 0, r0 is by definition 0).

-- 
Michael

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Qemu-devel] Re: [PATCH 02/17] lm32: translation routines
  2011-02-07 22:00     ` Michael Walle
@ 2011-02-07 22:20       ` Edgar E. Iglesias
  2011-02-07 22:55         ` Michael Walle
  0 siblings, 1 reply; 27+ messages in thread
From: Edgar E. Iglesias @ 2011-02-07 22:20 UTC (permalink / raw)
  To: Michael Walle; +Cc: qemu-devel, Alexander Graf

On Mon, Feb 07, 2011 at 11:00:38PM +0100, Michael Walle wrote:
> Hi Edgar.
> 
> first of all let me thank you for the review.
> 
> On Mon, Feb 07 2011, 19:41:25, Edgar E. Iglesias wrote:
> > > +#define JMP_NOJMP    0
> > > +#define JMP_DIRECT   1
> > > +#define JMP_INDIRECT 2
> > 
> > These don't seem to be used, can we remove them?
> Good catch :) I'll remove them.
> 
> > > +
> > > +/* This is the state at translation time.  */
> > > +typedef struct DisasContext {
> > > +    CPUState *env;
> > > +    target_ulong pc;
> > > +
> > > +    /* Decoder.  */
> > > +    int format;
> > > +    uint32_t ir;
> > > +    uint8_t opcode;
> > > +    uint8_t r0, r1, r2, csr;
> > > +    uint16_t imm5;
> > > +    uint16_t imm16;
> > > +    uint32_t imm26;
> > > +
> > > +    unsigned int delayed_branch;
> > > +    unsigned int tb_flags, synced_flags; /* tb dependent flags.  */
> > > +    int is_jmp;
> > > +
> > > +    unsigned int jmp;
> > > +    uint32_t jmp_pc;
> > 
> > These too.
> Ditto.
> 
> > > +
> > > +    int nr_nops;
> > 
> > This should probably go aswell..
> See below.
> 
> > > +    /* try guessing 'empty' instruction memory, although it may be a
> > > valid +     * instruction sequence (eg. srui r0, r0, 0) */
> > > +    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");
> > > +        }
> > > +    }
> > 
> > This nop sequence detection should probably go away. A reminder for
> > me too to remove it from the microblaze port (from where I guess you
> > inherited it)..
> I've always found this 'feature' handy, esp when you are porting new software. 
> Is there any particular reason why this should be removed? Besides the fact 
> that it won't match the real hardware if those instructions are executed. In 
> the case of the LM32, these are really nonsense instructions (shift r0 right 
> by 0, r0 is by definition 0).

Yes, I found the nop tracking handy too but It exposes a way for guests
to completely abort the vm with valid code. On microblaze, even guest
userspace can trig the cpu_abort. Your port doesn't have an MMU so guest
userland can probably kill the vm anyway, so it might be less of an issue.

Maybe the event could be logged instead of cpu_abort:ed?

Anyway, I don't think this is a showstopper preventing your port from
going upstream. If you insist and none of the other maintainers feel
strongly about it, I'm ok with it too.

Cheers

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Qemu-devel] Re: [PATCH 02/17] lm32: translation routines
  2011-02-07 22:20       ` Edgar E. Iglesias
@ 2011-02-07 22:55         ` Michael Walle
  2011-02-07 23:01           ` Alexander Graf
  0 siblings, 1 reply; 27+ messages in thread
From: Michael Walle @ 2011-02-07 22:55 UTC (permalink / raw)
  To: Edgar E. Iglesias; +Cc: qemu-devel, Alexander Graf

On Mon, Feb 07 2011, 23:20:33, Edgar E. Iglesias wrote:
> Yes, I found the nop tracking handy too but It exposes a way for guests
> to completely abort the vm with valid code. On microblaze, even guest
> userspace can trig the cpu_abort. Your port doesn't have an MMU so guest
> userland can probably kill the vm anyway, so it might be less of an issue.
> 
> Maybe the event could be logged instead of cpu_abort:ed?
If the program jumps to uninitialized memory, it'll likely execute until the 
end of the memory and then kill the VM.
Maybe we can add some kind of runtime configuration option for 
enabling/disabling this?


-- 
Michael

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Qemu-devel] Re: [PATCH 02/17] lm32: translation routines
  2011-02-07 22:55         ` Michael Walle
@ 2011-02-07 23:01           ` Alexander Graf
  0 siblings, 0 replies; 27+ messages in thread
From: Alexander Graf @ 2011-02-07 23:01 UTC (permalink / raw)
  To: Michael Walle; +Cc: Edgar E. Iglesias, qemu-devel


On 07.02.2011, at 23:55, Michael Walle wrote:

> On Mon, Feb 07 2011, 23:20:33, Edgar E. Iglesias wrote:
>> Yes, I found the nop tracking handy too but It exposes a way for guests
>> to completely abort the vm with valid code. On microblaze, even guest
>> userspace can trig the cpu_abort. Your port doesn't have an MMU so guest
>> userland can probably kill the vm anyway, so it might be less of an issue.
>> 
>> Maybe the event could be logged instead of cpu_abort:ed?
> If the program jumps to uninitialized memory, it'll likely execute until the 
> end of the memory and then kill the VM.
> Maybe we can add some kind of runtime configuration option for 
> enabling/disabling this?

During the first few reviews I stumbled over this too and actually found it a pretty slick hack. I agree though that it'd be nice to have a machine switch. Don't we have some machine config options these days? Alternatively, it could even be a -cpu flag.


Alex

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH 02/17] lm32: translation routines
  2011-01-31  0:30 ` [Qemu-devel] [PATCH 02/17] lm32: translation routines Michael Walle
  2011-02-07 18:41   ` [Qemu-devel] " Edgar E. Iglesias
@ 2011-02-08 17:32   ` Richard Henderson
  2011-02-08 20:00     ` Edgar E. Iglesias
  2011-02-08 21:32     ` Michael Walle
  1 sibling, 2 replies; 27+ messages in thread
From: Richard Henderson @ 2011-02-08 17:32 UTC (permalink / raw)
  To: Michael Walle; +Cc: Edgar E. Iglesias, qemu-devel, Alexander Graf

On 01/30/2011 04:30 PM, Michael Walle wrote:
> +    if (dc->format == OP_FMT_RI) {
> +        tcg_gen_brcondi_tl(cond, cpu_R[rY], sign_extend(dc->imm16, 16), l1);
> +    } else {
> +        tcg_gen_brcond_tl(cond, cpu_R[rY], cpu_R[rZ], l1);
> +    }
> +    tcg_gen_movi_tl(cpu_R[rX], 0);
> +    tcg_gen_br(l2);
> +    gen_set_label(l1);
> +    tcg_gen_movi_tl(cpu_R[rX], 1);
> +    gen_set_label(l2);

This is tcg_gen_setcond_tl.

BTW, why the extensive extra LOG_DIS code?  Why not just run the regular 
disassembler, like other ports?

> +    if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
> +        cpu_abort(dc->env, "hardware multiplier is not available\n");
> +    }

Aborting the VM, rather than raising an exception?

> +        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> +        tcg_gen_not_tl(cpu_R[dc->r2], cpu_R[dc->r2]);

This is tcg_gen_eqv_tl.

> +    /* 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;
> +        }
> +    }
> +}

No check that *some* opcode matched?  It would seem like a "return"
here instead of a break, and then an illegal opcode exception after
the loop would be in order.



r~

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH 02/17] lm32: translation routines
  2011-02-08 17:32   ` [Qemu-devel] " Richard Henderson
@ 2011-02-08 20:00     ` Edgar E. Iglesias
  2011-02-08 21:32     ` Michael Walle
  1 sibling, 0 replies; 27+ messages in thread
From: Edgar E. Iglesias @ 2011-02-08 20:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Michael Walle, qemu-devel, Alexander Graf

On Tue, Feb 08, 2011 at 09:32:57AM -0800, Richard Henderson wrote:
> On 01/30/2011 04:30 PM, Michael Walle wrote:
> > +    if (dc->format == OP_FMT_RI) {
> > +        tcg_gen_brcondi_tl(cond, cpu_R[rY], sign_extend(dc->imm16, 16), l1);
> > +    } else {
> > +        tcg_gen_brcond_tl(cond, cpu_R[rY], cpu_R[rZ], l1);
> > +    }
> > +    tcg_gen_movi_tl(cpu_R[rX], 0);
> > +    tcg_gen_br(l2);
> > +    gen_set_label(l1);
> > +    tcg_gen_movi_tl(cpu_R[rX], 1);
> > +    gen_set_label(l2);
> 
> This is tcg_gen_setcond_tl.
> 
> BTW, why the extensive extra LOG_DIS code?  Why not just run the regular 
> disassembler, like other ports?

FWIW, I used the same macros in the CRIS & MicroBlaze translators because
I found using the translators decoding useful to compare with the regular
disassembler's when looking for decoding errors. Also, some times I used
the translators disasm because it is faster (it doesn't have to decode
the insns twice), although not as readable. It was a while ago though...


> > +    if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
> > +        cpu_abort(dc->env, "hardware multiplier is not available\n");
> > +    }
> 
> Aborting the VM, rather than raising an exception?
> 
> > +        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> > +        tcg_gen_not_tl(cpu_R[dc->r2], cpu_R[dc->r2]);
> 
> This is tcg_gen_eqv_tl.
> 
> > +    /* 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;
> > +        }
> > +    }
> > +}
> 
> No check that *some* opcode matched?  It would seem like a "return"
> here instead of a break, and then an illegal opcode exception after
> the loop would be in order.

Good catch!

Other ports using the same decoding approach have a "match all" entry
in the decinfo table to catch illegal insns..

Cheers

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Qemu-devel] [PATCH 02/17] lm32: translation routines
  2011-02-08 17:32   ` [Qemu-devel] " Richard Henderson
  2011-02-08 20:00     ` Edgar E. Iglesias
@ 2011-02-08 21:32     ` Michael Walle
  1 sibling, 0 replies; 27+ messages in thread
From: Michael Walle @ 2011-02-08 21:32 UTC (permalink / raw)
  To: Richard Henderson; +Cc: Edgar E. Iglesias, qemu-devel, Alexander Graf

Am Dienstag 08 Februar 2011, 18:32:57 schrieb Richard Henderson:
> On 01/30/2011 04:30 PM, Michael Walle wrote:
> > +    if (dc->format == OP_FMT_RI) {
> > +        tcg_gen_brcondi_tl(cond, cpu_R[rY], sign_extend(dc->imm16, 16),
> > l1); +    } else {
> > +        tcg_gen_brcond_tl(cond, cpu_R[rY], cpu_R[rZ], l1);
> > +    }
> > +    tcg_gen_movi_tl(cpu_R[rX], 0);
> > +    tcg_gen_br(l2);
> > +    gen_set_label(l1);
> > +    tcg_gen_movi_tl(cpu_R[rX], 1);
> > +    gen_set_label(l2);
> 
> This is tcg_gen_setcond_tl.
fixed, thanks

> BTW, why the extensive extra LOG_DIS code?  Why not just run the regular
> disassembler, like other ports?
There is no built in disassembler for qemu (yet). The lm32 binutils port uses 
cgen for parsing, so the lm32-dis.c is not self contained. Either i need to 
embed cgen into the lm32-dis.c, write my own disassembler or qemu needs to 
link again libopcodes). I didn't like any of these solutions :)

> > +    if (!(dc->env->features & LM32_FEATURE_MULTIPLY)) {
> > +        cpu_abort(dc->env, "hardware multiplier is not available\n");
> > +    }
> 
> Aborting the VM, rather than raising an exception?
The LM32 processor does not raise an exception in that case. If there is an 
unknown opcode its behaviour is undefined on real hardware.

> 
> > +        tcg_gen_xor_tl(cpu_R[dc->r2], cpu_R[dc->r0], cpu_R[dc->r1]);
> > +        tcg_gen_not_tl(cpu_R[dc->r2], cpu_R[dc->r2]);
> 
> This is tcg_gen_eqv_tl.
fixed too, unfortunately there is no variant with an immediate.

> > +    /* 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;
> > +        }
> > +    }
> > +}
> 
> No check that *some* opcode matched?  It would seem like a "return"
> here instead of a break, and then an illegal opcode exception after
> the loop would be in order.
fixed too. Again, if there is no match, the VM will be killed.

-- 
thanks michael

^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2011-02-08 21:32 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-31  0:30 [Qemu-devel] [PATCH 00/17] LatticeMico32 target Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 01/17] LatticeMico32 target support Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 02/17] lm32: translation routines Michael Walle
2011-02-07 18:41   ` [Qemu-devel] " Edgar E. Iglesias
2011-02-07 22:00     ` Michael Walle
2011-02-07 22:20       ` Edgar E. Iglesias
2011-02-07 22:55         ` Michael Walle
2011-02-07 23:01           ` Alexander Graf
2011-02-08 17:32   ` [Qemu-devel] " Richard Henderson
2011-02-08 20:00     ` Edgar E. Iglesias
2011-02-08 21:32     ` Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 03/17] lm32: translation code helper Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 04/17] lm32: machine state loading/saving Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 05/17] lm32: gdbstub support Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 06/17] lm32: interrupt controller model Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 07/17] lm32: juart model Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 08/17] lm32: pic and juart helper functions Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 09/17] lm32: timer model Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 10/17] lm32: uart model Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 11/17] lm32: system control model Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 12/17] lm32: support for creating device tree Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 13/17] lm32: EVR32 and uclinux BSP Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 14/17] lm32: todo and documentation Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 15/17] lm32: opcode testsuite Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 16/17] Add lm32 target to configure Michael Walle
2011-01-31  0:30 ` [Qemu-devel] [PATCH 17/17] MAINTAINERS: add LatticeMico32 maintainer Michael Walle
2011-02-07 16:28 ` [Qemu-devel] Re: [PATCH 00/17] LatticeMico32 target Alexander Graf

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.