diff options
Diffstat (limited to 'target-xtensa')
| -rw-r--r-- | target-xtensa/Makefile.objs | 6 | ||||
| -rw-r--r-- | target-xtensa/core-dc232b.c | 49 | ||||
| -rw-r--r-- | target-xtensa/core-dc232b/core-isa.h | 423 | ||||
| -rw-r--r-- | target-xtensa/core-dc232b/gdb-config.c | 261 | ||||
| -rw-r--r-- | target-xtensa/core-dc233c.c | 50 | ||||
| -rw-r--r-- | target-xtensa/core-dc233c/core-isa.h | 474 | ||||
| -rw-r--r-- | target-xtensa/core-dc233c/gdb-config.c | 145 | ||||
| -rw-r--r-- | target-xtensa/core-fsf.c | 48 | ||||
| -rw-r--r-- | target-xtensa/core-fsf/core-isa.h | 361 | ||||
| -rw-r--r-- | target-xtensa/cpu-qom.h | 99 | ||||
| -rw-r--r-- | target-xtensa/cpu.c | 182 | ||||
| -rw-r--r-- | target-xtensa/cpu.h | 556 | ||||
| -rw-r--r-- | target-xtensa/gdbstub.c | 126 | ||||
| -rw-r--r-- | target-xtensa/helper.c | 729 | ||||
| -rw-r--r-- | target-xtensa/helper.h | 58 | ||||
| -rwxr-xr-x | target-xtensa/import_core.sh | 51 | ||||
| -rw-r--r-- | target-xtensa/op_helper.c | 981 | ||||
| -rw-r--r-- | target-xtensa/overlay_tool.h | 597 | ||||
| -rw-r--r-- | target-xtensa/translate.c | 3221 | ||||
| -rw-r--r-- | target-xtensa/xtensa-semi.c | 321 | 
20 files changed, 8738 insertions, 0 deletions
diff --git a/target-xtensa/Makefile.objs b/target-xtensa/Makefile.objs new file mode 100644 index 00000000..5c150a87 --- /dev/null +++ b/target-xtensa/Makefile.objs @@ -0,0 +1,6 @@ +obj-y += xtensa-semi.o +obj-y += core-dc232b.o +obj-y += core-dc233c.o +obj-y += core-fsf.o +obj-y += translate.o op_helper.o helper.o cpu.o +obj-y += gdbstub.o diff --git a/target-xtensa/core-dc232b.c b/target-xtensa/core-dc232b.c new file mode 100644 index 00000000..06826c04 --- /dev/null +++ b/target-xtensa/core-dc232b.c @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/gdbstub.h" +#include "qemu/host-utils.h" + +#include "core-dc232b/core-isa.h" +#include "overlay_tool.h" + +static XtensaConfig dc232b __attribute__((unused)) = { +    .name = "dc232b", +    .gdb_regmap = { +        .num_regs = 120, +        .num_core_regs = 52, +        .reg = { +#include "core-dc232b/gdb-config.c" +        } +    }, +    .clock_freq_khz = 10000, +    DEFAULT_SECTIONS +}; + +REGISTER_CORE(dc232b) diff --git a/target-xtensa/core-dc232b/core-isa.h b/target-xtensa/core-dc232b/core-isa.h new file mode 100644 index 00000000..69f10655 --- /dev/null +++ b/target-xtensa/core-dc232b/core-isa.h @@ -0,0 +1,423 @@ +/* + * Xtensa processor core configuration information. + * + * This file is subject to the terms and conditions of the GNU General Public + * License.  See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (c) 1999-2007 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** +            Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + *  configured, and a value of 0 otherwise.  These macros are always defined. + */ + + +/*---------------------------------------------------------------------- +                                ISA +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE                   0       /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED             1       /* windowed registers option */ +#define XCHAL_NUM_AREGS                 32      /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2            5       /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE      3       /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG                1       /* debug option */ +#define XCHAL_HAVE_DENSITY              1       /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS                1       /* zero-overhead loops */ +#define XCHAL_HAVE_NSA                  1       /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX               1       /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT                 1       /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS               1       /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16                1       /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32                1       /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH           0       /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32                1       /* QUOS/QUOU/REMS/REMU insns */ +#define XCHAL_HAVE_L32R                 1       /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS    1       /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16              0       /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX                 1       /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES        0       /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES   0       /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12           1       /* (obsolete option) */ +#define XCHAL_HAVE_ABS                  1       /* ABS instruction */ +/*#define XCHAL_HAVE_POPC               0*/     /* POPC instruction */ +/*#define XCHAL_HAVE_CRC                0*/     /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC         1       /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I               1       /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION          0       /* speculation */ +#define XCHAL_HAVE_FULL_RESET           1       /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS              1       /* */ +#define XCHAL_NUM_MISC_REGS             2       /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER           0       /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID                 1       /* processor ID register */ +#define XCHAL_HAVE_THREADPTR            1       /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS             0       /* boolean registers */ +#define XCHAL_HAVE_CP                   1       /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG                 8       /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16                1       /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005        0       /* vector floating-point pkg */ +#define XCHAL_HAVE_FP                   0       /* floating point pkg */ +#define XCHAL_HAVE_VECTRA1              0       /* Vectra I  pkg */ +#define XCHAL_HAVE_VECTRALX             0       /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFI2                0       /* HiFi2 Audio Engine pkg */ + + +/*---------------------------------------------------------------------- +                                MISC +  ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES   8       /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH          4       /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH                4       /* data width in bytes */ +/*  In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION  1       /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1       /* unaligned stores cause exc.*/ + +#define XCHAL_SW_VERSION                701001  /* sw version of this header */ + +#define XCHAL_CORE_ID                   "dc232b"        /* alphanum core name +                                                   (CoreID) set in the Xtensa +                                                   Processor Generator */ + +#define XCHAL_CORE_DESCRIPTION          "Diamond 232L Standard Core Rev.B (LE)" +#define XCHAL_BUILD_UNIQUE_ID           0x0000BEEF      /* 22-bit sw build ID */ + +/* + *  These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0              0xC56307FE      /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1              0x0D40BEEF      /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME           "LX2.1.1"       /* full version name */ +#define XCHAL_HW_VERSION_MAJOR          2210    /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR          1       /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION                221001  /* major*100+minor */ +#define XCHAL_HW_REL_LX2                1 +#define XCHAL_HW_REL_LX2_1              1 +#define XCHAL_HW_REL_LX2_1_1            1 +#define XCHAL_HW_CONFIGID_RELIABLE      1 +/*  If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR      2210    /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR      1       /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION            221001  /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR      2210    /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR      1       /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION            221001  /* latest targeted hw */ + + +/*---------------------------------------------------------------------- +                                CACHE +  ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE           32      /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE           32      /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH          5       /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH          5       /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE               16384   /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE               16384   /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK       1       /* writeback feature */ + + + + +/**************************************************************************** +    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- +                                CACHE +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF                  1       /* any outbound PIF present */ + +/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */ + +/*  Number of cache sets in log2(lines per way):  */ +#define XCHAL_ICACHE_SETWIDTH           7 +#define XCHAL_DCACHE_SETWIDTH           7 + +/*  Cache set associativity (number of ways):  */ +#define XCHAL_ICACHE_WAYS               4 +#define XCHAL_DCACHE_WAYS               4 + +/*  Cache features:  */ +#define XCHAL_ICACHE_LINE_LOCKABLE      1 +#define XCHAL_DCACHE_LINE_LOCKABLE      1 +#define XCHAL_ICACHE_ECC_PARITY         0 +#define XCHAL_DCACHE_ECC_PARITY         0 + +/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */ +#define XCHAL_CA_BITS                   4 + + +/*---------------------------------------------------------------------- +                        INTERNAL I/D RAM/ROMs and XLMI +  ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM               0       /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM               0       /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM               0       /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM               0       /* number of core data RAMs */ +#define XCHAL_NUM_URAM                  0       /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI                  0       /* number of core XLMI ports */ + + +/*---------------------------------------------------------------------- +                        INTERRUPTS and TIMERS +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS           1       /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS   1       /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI                  1       /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT               1       /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS                3       /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS            22      /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2       5       /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS         17      /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS             6       /* number of interrupt levels +                                                   (not including level zero) */ +#define XCHAL_EXCM_LEVEL                3       /* level masked by PS.EXCM */ +        /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/*  Masks of interrupts at each interrupt level:  */ +#define XCHAL_INTLEVEL1_MASK            0x001F80FF +#define XCHAL_INTLEVEL2_MASK            0x00000100 +#define XCHAL_INTLEVEL3_MASK            0x00200E00 +#define XCHAL_INTLEVEL4_MASK            0x00001000 +#define XCHAL_INTLEVEL5_MASK            0x00002000 +#define XCHAL_INTLEVEL6_MASK            0x00000000 +#define XCHAL_INTLEVEL7_MASK            0x00004000 + +/*  Masks of interrupts at each range 1..n of interrupt levels:  */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK   0x001F80FF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK   0x001F81FF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK   0x003F8FFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK   0x003F9FFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK   0x003FBFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK   0x003FBFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK   0x003FFFFF + +/*  Level of each interrupt:  */ +#define XCHAL_INT0_LEVEL                1 +#define XCHAL_INT1_LEVEL                1 +#define XCHAL_INT2_LEVEL                1 +#define XCHAL_INT3_LEVEL                1 +#define XCHAL_INT4_LEVEL                1 +#define XCHAL_INT5_LEVEL                1 +#define XCHAL_INT6_LEVEL                1 +#define XCHAL_INT7_LEVEL                1 +#define XCHAL_INT8_LEVEL                2 +#define XCHAL_INT9_LEVEL                3 +#define XCHAL_INT10_LEVEL               3 +#define XCHAL_INT11_LEVEL               3 +#define XCHAL_INT12_LEVEL               4 +#define XCHAL_INT13_LEVEL               5 +#define XCHAL_INT14_LEVEL               7 +#define XCHAL_INT15_LEVEL               1 +#define XCHAL_INT16_LEVEL               1 +#define XCHAL_INT17_LEVEL               1 +#define XCHAL_INT18_LEVEL               1 +#define XCHAL_INT19_LEVEL               1 +#define XCHAL_INT20_LEVEL               1 +#define XCHAL_INT21_LEVEL               3 +#define XCHAL_DEBUGLEVEL                6       /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT     1       /* OCD external db interrupt */ +#define XCHAL_NMILEVEL                  7       /* NMI "level" (for use with +                                                   EXCSAVE/EPS/EPC_n, RFI n) */ + +/*  Type of each interrupt:  */ +#define XCHAL_INT0_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE         XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE         XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT8_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT10_TYPE        XTHAL_INTTYPE_TIMER +#define XCHAL_INT11_TYPE        XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT12_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT13_TYPE        XTHAL_INTTYPE_TIMER +#define XCHAL_INT14_TYPE        XTHAL_INTTYPE_NMI +#define XCHAL_INT15_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT16_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT17_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT18_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT19_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT20_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT21_TYPE        XTHAL_INTTYPE_EXTERN_EDGE + +/*  Masks of interrupts for each type of interrupt:  */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFC00000 +#define XCHAL_INTTYPE_MASK_SOFTWARE     0x00000880 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE  0x003F8000 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000133F +#define XCHAL_INTTYPE_MASK_TIMER        0x00002440 +#define XCHAL_INTTYPE_MASK_NMI          0x00004000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR  0x00000000 + +/*  Interrupt numbers assigned to specific interrupt sources:  */ +#define XCHAL_TIMER0_INTERRUPT          6       /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT          10      /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT          13      /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT          XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT             14      /* non-maskable interrupt */ + +/*  Interrupt numbers for levels at which only one interrupt is configured:  */ +#define XCHAL_INTLEVEL2_NUM             8 +#define XCHAL_INTLEVEL4_NUM             12 +#define XCHAL_INTLEVEL5_NUM             13 +#define XCHAL_INTLEVEL7_NUM             14 +/*  (There are many interrupts each at level(s) 1, 3.)  */ + + +/* + *  External interrupt vectors/levels. + *  These macros describe how Xtensa processor interrupt numbers + *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + *  map to external BInterrupt<n> pins, for those interrupts + *  configured as external (level-triggered, edge-triggered, or NMI). + *  See the Xtensa processor databook for more details. + */ + +/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */ +#define XCHAL_EXTINT0_NUM               0       /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM               1       /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM               2       /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM               3       /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM               4       /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM               5       /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM               8       /* (intlevel 2) */ +#define XCHAL_EXTINT7_NUM               9       /* (intlevel 3) */ +#define XCHAL_EXTINT8_NUM               12      /* (intlevel 4) */ +#define XCHAL_EXTINT9_NUM               14      /* (intlevel 7) */ +#define XCHAL_EXTINT10_NUM              15      /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM              16      /* (intlevel 1) */ +#define XCHAL_EXTINT12_NUM              17      /* (intlevel 1) */ +#define XCHAL_EXTINT13_NUM              18      /* (intlevel 1) */ +#define XCHAL_EXTINT14_NUM              19      /* (intlevel 1) */ +#define XCHAL_EXTINT15_NUM              20      /* (intlevel 1) */ +#define XCHAL_EXTINT16_NUM              21      /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- +                        EXCEPTIONS and VECTORS +  ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION               2       /* Xtensa Exception Architecture +                                                   number: 1 == XEA1 (old) +                                                           2 == XEA2 (new) +                                                           0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1                 0       /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2                 1       /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX                 0       /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS           1       /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY       0       /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT        1       /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE              1       /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR       0xD0000000  /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR       0x00000000 +#define XCHAL_RESET_VECBASE_OVERLAP     0 + +#define XCHAL_RESET_VECTOR0_VADDR       0xFE000000 +#define XCHAL_RESET_VECTOR0_PADDR       0xFE000000 +#define XCHAL_RESET_VECTOR1_VADDR       0xD8000500 +#define XCHAL_RESET_VECTOR1_PADDR       0x00000500 +#define XCHAL_RESET_VECTOR_VADDR        0xFE000000 +#define XCHAL_RESET_VECTOR_PADDR        0xFE000000 +#define XCHAL_USER_VECOFS               0x00000340 +#define XCHAL_USER_VECTOR_VADDR         0xD0000340 +#define XCHAL_USER_VECTOR_PADDR         0x00000340 +#define XCHAL_KERNEL_VECOFS             0x00000300 +#define XCHAL_KERNEL_VECTOR_VADDR       0xD0000300 +#define XCHAL_KERNEL_VECTOR_PADDR       0x00000300 +#define XCHAL_DOUBLEEXC_VECOFS          0x000003C0 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR    0xD00003C0 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR    0x000003C0 +#define XCHAL_WINDOW_OF4_VECOFS         0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS         0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS         0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS         0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS        0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS        0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR      0xD0000000 +#define XCHAL_WINDOW_VECTORS_PADDR      0x00000000 +#define XCHAL_INTLEVEL2_VECOFS          0x00000180 +#define XCHAL_INTLEVEL2_VECTOR_VADDR    0xD0000180 +#define XCHAL_INTLEVEL2_VECTOR_PADDR    0x00000180 +#define XCHAL_INTLEVEL3_VECOFS          0x000001C0 +#define XCHAL_INTLEVEL3_VECTOR_VADDR    0xD00001C0 +#define XCHAL_INTLEVEL3_VECTOR_PADDR    0x000001C0 +#define XCHAL_INTLEVEL4_VECOFS          0x00000200 +#define XCHAL_INTLEVEL4_VECTOR_VADDR    0xD0000200 +#define XCHAL_INTLEVEL4_VECTOR_PADDR    0x00000200 +#define XCHAL_INTLEVEL5_VECOFS          0x00000240 +#define XCHAL_INTLEVEL5_VECTOR_VADDR    0xD0000240 +#define XCHAL_INTLEVEL5_VECTOR_PADDR    0x00000240 +#define XCHAL_INTLEVEL6_VECOFS          0x00000280 +#define XCHAL_INTLEVEL6_VECTOR_VADDR    0xD0000280 +#define XCHAL_INTLEVEL6_VECTOR_PADDR    0x00000280 +#define XCHAL_DEBUG_VECOFS              XCHAL_INTLEVEL6_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR        XCHAL_INTLEVEL6_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR        XCHAL_INTLEVEL6_VECTOR_PADDR +#define XCHAL_NMI_VECOFS                0x000002C0 +#define XCHAL_NMI_VECTOR_VADDR          0xD00002C0 +#define XCHAL_NMI_VECTOR_PADDR          0x000002C0 +#define XCHAL_INTLEVEL7_VECOFS          XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL7_VECTOR_VADDR    XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL7_VECTOR_PADDR    XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- +                                DEBUG +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD                  1       /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK                2       /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK                2       /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY        1       /* faster OCD option */ + + +/*---------------------------------------------------------------------- +                                MMU +  ----------------------------------------------------------------------*/ + +/*  See core-matmap.h header file for more details.  */ + +#define XCHAL_HAVE_TLBS                 1       /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY         0       /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP         0       /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR            0       /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR      0       /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR        0       /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU              1       /* full MMU (with page table +                                                   [autorefill] and protection) +                                                   usable for an MMU-based OS */ +/*  If none of the above last 4 are set, it's a custom TLB configuration.  */ +#define XCHAL_ITLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */ +#define XCHAL_DTLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */ + +#define XCHAL_MMU_ASID_BITS             8       /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS                 4       /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS             2       /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ diff --git a/target-xtensa/core-dc232b/gdb-config.c b/target-xtensa/core-dc232b/gdb-config.c new file mode 100644 index 00000000..13aba5ed --- /dev/null +++ b/target-xtensa/core-dc232b/gdb-config.c @@ -0,0 +1,261 @@ +/* Configuration for the Xtensa architecture for GDB, the GNU debugger. + +   Copyright (C) 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. + +   This file is part of GDB. + +   This program is free software; you can redistribute it and/or modify +   it under the terms of the GNU General Public License as published by +   the Free Software Foundation; either version 2 of the License, or +   (at your option) any later version. + +   This program is distributed in the hope that it will be useful, +   but WITHOUT ANY WARRANTY; without even the implied warranty of +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +   GNU General Public License for more details. + +   You should have received a copy of the GNU General Public License +   along with this program; if not, write to the Free Software +   Foundation, Inc., 51 Franklin Street, Fifth Floor, +   Boston, MA 02110-1301, USA.  */ + +  XTREG(0,   0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc, +          0, 0, 0, 0, 0, 0) +  XTREG(1,   4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0, +          0, 0, 0, 0, 0, 0) +  XTREG(2,   8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1, +          0, 0, 0, 0, 0, 0) +  XTREG(3,  12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2, +          0, 0, 0, 0, 0, 0) +  XTREG(4,  16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3, +          0, 0, 0, 0, 0, 0) +  XTREG(5,  20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4, +          0, 0, 0, 0, 0, 0) +  XTREG(6,  24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5, +          0, 0, 0, 0, 0, 0) +  XTREG(7,  28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6, +          0, 0, 0, 0, 0, 0) +  XTREG(8,  32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7, +          0, 0, 0, 0, 0, 0) +  XTREG(9,  36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8, +          0, 0, 0, 0, 0, 0) +  XTREG(10,  40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9, +          0, 0, 0, 0, 0, 0) +  XTREG(11,  44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10, +          0, 0, 0, 0, 0, 0) +  XTREG(12,  48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11, +          0, 0, 0, 0, 0, 0) +  XTREG(13,  52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12, +          0, 0, 0, 0, 0, 0) +  XTREG(14,  56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13, +          0, 0, 0, 0, 0, 0) +  XTREG(15,  60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14, +          0, 0, 0, 0, 0, 0) +  XTREG(16,  64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15, +          0, 0, 0, 0, 0, 0) +  XTREG(17,  68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16, +          0, 0, 0, 0, 0, 0) +  XTREG(18,  72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17, +          0, 0, 0, 0, 0, 0) +  XTREG(19,  76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18, +          0, 0, 0, 0, 0, 0) +  XTREG(20,  80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19, +          0, 0, 0, 0, 0, 0) +  XTREG(21,  84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20, +          0, 0, 0, 0, 0, 0) +  XTREG(22,  88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21, +          0, 0, 0, 0, 0, 0) +  XTREG(23,  92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22, +          0, 0, 0, 0, 0, 0) +  XTREG(24,  96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23, +          0, 0, 0, 0, 0, 0) +  XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24, +          0, 0, 0, 0, 0, 0) +  XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25, +          0, 0, 0, 0, 0, 0) +  XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26, +          0, 0, 0, 0, 0, 0) +  XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27, +          0, 0, 0, 0, 0, 0) +  XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28, +          0, 0, 0, 0, 0, 0) +  XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29, +          0, 0, 0, 0, 0, 0) +  XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30, +          0, 0, 0, 0, 0, 0) +  XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31, +          0, 0, 0, 0, 0, 0) +  XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg, +          0, 0, 0, 0, 0, 0) +  XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend, +          0, 0, 0, 0, 0, 0) +  XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount, +          0, 0, 0, 0, 0, 0) +  XTREG(36, 144,  6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar, +          0, 0, 0, 0, 0, 0) +  XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase, +          0, 0, 0, 0, 0, 0) +  XTREG(38, 152,  3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase, +          0, 0, 0, 0, 0, 0) +  XTREG(39, 156,  8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart, +          0, 0, 0, 0, 0, 0) +  XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176, +          0, 0, 0, 0, 0, 0) +  XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208, +          0, 0, 0, 0, 0, 0) +  XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps, +          0, 0, 0, 0, 0, 0) +  XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr, +          0, 0, 0, 0, 0, 0) +  XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1, +          0, 0, 0, 0, 0, 0) +  XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo, +          0, 0, 0, 0, 0, 0) +  XTREG(46, 184,  8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi, +          0, 0, 0, 0, 0, 0) +  XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0, +          0, 0, 0, 0, 0, 0) +  XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1, +          0, 0, 0, 0, 0, 0) +  XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2, +          0, 0, 0, 0, 0, 0) +  XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3, +          0, 0, 0, 0, 0, 0) +  XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate, +          0, 0, 0, 0, 0, 0) +  XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr, +          0, 0, 0, 0, 0, 0) +  XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid, +          0, 0, 0, 0, 0, 0) +  XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid, +          0, 0, 0, 0, 0, 0) +  XTREG(55, 220, 18, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg, +          0, 0, 0, 0, 0, 0) +  XTREG(56, 224, 18, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg, +          0, 0, 0, 0, 0, 0) +  XTREG(57, 228,  2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable, +          0, 0, 0, 0, 0, 0) +  XTREG(58, 232, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr, +          0, 0, 0, 0, 0, 0) +  XTREG(59, 236, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0, +          0, 0, 0, 0, 0, 0) +  XTREG(60, 240, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1, +          0, 0, 0, 0, 0, 0) +  XTREG(61, 244, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0, +          0, 0, 0, 0, 0, 0) +  XTREG(62, 248, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1, +          0, 0, 0, 0, 0, 0) +  XTREG(63, 252, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0, +          0, 0, 0, 0, 0, 0) +  XTREG(64, 256, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1, +          0, 0, 0, 0, 0, 0) +  XTREG(65, 260, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1, +          0, 0, 0, 0, 0, 0) +  XTREG(66, 264, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2, +          0, 0, 0, 0, 0, 0) +  XTREG(67, 268, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3, +          0, 0, 0, 0, 0, 0) +  XTREG(68, 272, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4, +          0, 0, 0, 0, 0, 0) +  XTREG(69, 276, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5, +          0, 0, 0, 0, 0, 0) +  XTREG(70, 280, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6, +          0, 0, 0, 0, 0, 0) +  XTREG(71, 284, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7, +          0, 0, 0, 0, 0, 0) +  XTREG(72, 288, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc, +          0, 0, 0, 0, 0, 0) +  XTREG(73, 292, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2, +          0, 0, 0, 0, 0, 0) +  XTREG(74, 296, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3, +          0, 0, 0, 0, 0, 0) +  XTREG(75, 300, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4, +          0, 0, 0, 0, 0, 0) +  XTREG(76, 304, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5, +          0, 0, 0, 0, 0, 0) +  XTREG(77, 308, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6, +          0, 0, 0, 0, 0, 0) +  XTREG(78, 312, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7, +          0, 0, 0, 0, 0, 0) +  XTREG(79, 316, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1, +          0, 0, 0, 0, 0, 0) +  XTREG(80, 320, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2, +          0, 0, 0, 0, 0, 0) +  XTREG(81, 324, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3, +          0, 0, 0, 0, 0, 0) +  XTREG(82, 328, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4, +          0, 0, 0, 0, 0, 0) +  XTREG(83, 332, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5, +          0, 0, 0, 0, 0, 0) +  XTREG(84, 336, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6, +          0, 0, 0, 0, 0, 0) +  XTREG(85, 340, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7, +          0, 0, 0, 0, 0, 0) +  XTREG(86, 344,  8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable, +          0, 0, 0, 0, 0, 0) +  XTREG(87, 348, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt, +          0, 0, 0, 0, 0, 0) +  XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset, +          0, 0, 0, 0, 0, 0) +  XTREG(89, 356, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear, +          0, 0, 0, 0, 0, 0) +  XTREG(90, 360, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable, +          0, 0, 0, 0, 0, 0) +  XTREG(91, 364, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase, +          0, 0, 0, 0, 0, 0) +  XTREG(92, 368,  6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause, +          0, 0, 0, 0, 0, 0) +  XTREG(93, 372, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause, +          0, 0, 0, 0, 0, 0) +  XTREG(94, 376, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount, +          0, 0, 0, 0, 0, 0) +  XTREG(95, 380, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid, +          0, 0, 0, 0, 0, 0) +  XTREG(96, 384, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount, +          0, 0, 0, 0, 0, 0) +  XTREG(97, 388,  4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel, +          0, 0, 0, 0, 0, 0) +  XTREG(98, 392, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr, +          0, 0, 0, 0, 0, 0) +  XTREG(99, 396, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0, +          0, 0, 0, 0, 0, 0) +  XTREG(100, 400, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1, +          0, 0, 0, 0, 0, 0) +  XTREG(101, 404, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2, +          0, 0, 0, 0, 0, 0) +  XTREG(102, 408, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0, +          0, 0, 0, 0, 0, 0) +  XTREG(103, 412, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1, +          0, 0, 0, 0, 0, 0) +  XTREG(104, 416, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0, +          0, 0, 0, 0, 0, 0) +  XTREG(105, 420, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1, +          0, 0, 0, 0, 0, 0) +  XTREG(106, 424, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2, +          0, 0, 0, 0, 0, 0) +  XTREG(107, 428, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3, +          0, 0, 0, 0, 0, 0) +  XTREG(108, 432, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4, +          0, 0, 0, 0, 0, 0) +  XTREG(109, 436, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5, +          0, 0, 0, 0, 0, 0) +  XTREG(110, 440, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6, +          0, 0, 0, 0, 0, 0) +  XTREG(111, 444, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7, +          0, 0, 0, 0, 0, 0) +  XTREG(112, 448, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8, +          0, 0, 0, 0, 0, 0) +  XTREG(113, 452, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9, +          0, 0, 0, 0, 0, 0) +  XTREG(114, 456, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10, +          0, 0, 0, 0, 0, 0) +  XTREG(115, 460, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11, +          0, 0, 0, 0, 0, 0) +  XTREG(116, 464, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12, +          0, 0, 0, 0, 0, 0) +  XTREG(117, 468, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13, +          0, 0, 0, 0, 0, 0) +  XTREG(118, 472, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14, +          0, 0, 0, 0, 0, 0) +  XTREG(119, 476, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15, +          0, 0, 0, 0, 0, 0) diff --git a/target-xtensa/core-dc233c.c b/target-xtensa/core-dc233c.c new file mode 100644 index 00000000..8daf7d9f --- /dev/null +++ b/target-xtensa/core-dc233c.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2012, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/gdbstub.h" +#include "qemu-common.h" +#include "qemu/host-utils.h" + +#include "core-dc233c/core-isa.h" +#include "overlay_tool.h" + +static XtensaConfig dc233c __attribute__((unused)) = { +    .name = "dc233c", +    .gdb_regmap = { +        .num_regs = 121, +        .num_core_regs = 52, +        .reg = { +#include "core-dc233c/gdb-config.c" +        } +    }, +    .clock_freq_khz = 10000, +    DEFAULT_SECTIONS +}; + +REGISTER_CORE(dc233c) diff --git a/target-xtensa/core-dc233c/core-isa.h b/target-xtensa/core-dc233c/core-isa.h new file mode 100644 index 00000000..e82c3cbe --- /dev/null +++ b/target-xtensa/core-dc233c/core-isa.h @@ -0,0 +1,474 @@ +/* + * xtensa/config/core-isa.h -- HAL definitions that are dependent on Xtensa + *                              processor CORE configuration + * + *  See <xtensa/config/core.h>, which includes this file, for more details. + */ + +/* Xtensa processor core configuration information. + +   Copyright (c) 1999-2010 Tensilica Inc. + +   Permission is hereby granted, free of charge, to any person obtaining +   a copy of this software and associated documentation files (the +   "Software"), to deal in the Software without restriction, including +   without limitation the rights to use, copy, modify, merge, publish, +   distribute, sublicense, and/or sell copies of the Software, and to +   permit persons to whom the Software is furnished to do so, subject to +   the following conditions: + +   The above copyright notice and this permission notice shall be included +   in all copies or substantial portions of the Software. + +   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ + +#ifndef _XTENSA_CORE_CONFIGURATION_H +#define _XTENSA_CORE_CONFIGURATION_H + + +/**************************************************************************** +            Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + *  configured, and a value of 0 otherwise.  These macros are always defined. + */ + + +/*---------------------------------------------------------------------- +                                ISA +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE                   0       /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED             1       /* windowed registers option */ +#define XCHAL_NUM_AREGS                 32      /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2            5       /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE      3       /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG                1       /* debug option */ +#define XCHAL_HAVE_DENSITY              1       /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS                1       /* zero-overhead loops */ +#define XCHAL_HAVE_NSA                  1       /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX               1       /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT                 1       /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS               1       /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16                1       /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32                1       /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH           0       /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_DIV32                1       /* QUOS/QUOU/REMS/REMU instructions */ +#define XCHAL_HAVE_L32R                 1       /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS    1       /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16              0       /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX                 1       /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES        0       /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES   0       /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12           1       /* (obsolete option) */ +#define XCHAL_HAVE_ABS                  1       /* ABS instruction */ +/*#define XCHAL_HAVE_POPC               0*/     /* POPC instruction */ +/*#define XCHAL_HAVE_CRC                0*/     /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC         1       /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I               1       /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION          0       /* speculation */ +#define XCHAL_HAVE_FULL_RESET           1       /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS              1       /* */ +#define XCHAL_NUM_MISC_REGS             2       /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER           0       /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID                 1       /* processor ID register */ +#define XCHAL_HAVE_EXTERN_REGS          1       /* WER/RER instructions */ +#define XCHAL_HAVE_MP_INTERRUPTS        0       /* interrupt distributor port */ +#define XCHAL_HAVE_MP_RUNSTALL          0       /* core RunStall control port */ +#define XCHAL_HAVE_THREADPTR            1       /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS             0       /* boolean registers */ +#define XCHAL_HAVE_CP                   1       /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG                 8       /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16                1       /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005        0       /* vector floating-point pkg */ +#define XCHAL_HAVE_FP                   0       /* floating point pkg */ +#define XCHAL_HAVE_DFP                  0       /* double precision FP pkg */ +#define XCHAL_HAVE_DFP_accel            0       /* double precision FP acceleration pkg */ +#define XCHAL_HAVE_VECTRA1              0       /* Vectra I  pkg */ +#define XCHAL_HAVE_VECTRALX             0       /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFIPRO              0       /* HiFiPro Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2                0       /* HiFi2 Audio Engine pkg */ +#define XCHAL_HAVE_HIFI2EP      0       /* HiFi2EP */ +#define XCHAL_HAVE_CONNXD2              0       /* ConnX D2 pkg */ +#define XCHAL_HAVE_BBE16                0       /* ConnX BBE16 pkg */ +#define XCHAL_HAVE_BBE16_RSQRT          0       /* BBE16 & vector recip sqrt */ +#define XCHAL_HAVE_BBE16_VECDIV         0       /* BBE16 & vector divide */ +#define XCHAL_HAVE_BBE16_DESPREAD       0       /* BBE16 & despread */ +#define XCHAL_HAVE_BSP3                 0       /* ConnX BSP3 pkg */ +#define XCHAL_HAVE_SSP16                0       /* ConnX SSP16 pkg */ +#define XCHAL_HAVE_SSP16_VITERBI        0       /* SSP16 & viterbi */ +#define XCHAL_HAVE_TURBO16              0       /* ConnX Turbo16 pkg */ +#define XCHAL_HAVE_BBP16                0       /* ConnX BBP16 pkg */ + + +/*---------------------------------------------------------------------- +                                MISC +  ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES   8       /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH          4       /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH                4       /* data width in bytes */ +/*  In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION  1       /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1       /* unaligned stores cause exc.*/ +#define XCHAL_UNALIGNED_LOAD_HW         0       /* unaligned loads work in hw */ +#define XCHAL_UNALIGNED_STORE_HW        0       /* unaligned stores work in hw*/ + +#define XCHAL_SW_VERSION                900001  /* sw version of this header */ + +#define XCHAL_CORE_ID                   "dc233c"        /* alphanum core name +(CoreID) set in the Xtensa +Processor Generator */ + +#define XCHAL_CORE_DESCRIPTION          "dc233c" +#define XCHAL_BUILD_UNIQUE_ID           0x00004B21      /* 22-bit sw build ID */ + +/* + *  These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0              0xC56707FE      /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1              0x14404B21      /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME           "LX4.0.1"       /* full version name */ +#define XCHAL_HW_VERSION_MAJOR          2400    /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR          1       /* minor ver# of targeted hw */ +#define XCHAL_HW_VERSION                240001  /* major*100+minor */ +#define XCHAL_HW_REL_LX4                1 +#define XCHAL_HW_REL_LX4_0              1 +#define XCHAL_HW_REL_LX4_0_1            1 +#define XCHAL_HW_CONFIGID_RELIABLE      1 +/*  If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR      2400    /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR      1       /* minor v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION            240001  /* earliest targeted hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR      2400    /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR      1       /* minor v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION            240001  /* latest targeted hw */ + + +/*---------------------------------------------------------------------- +                                CACHE +  ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE           32      /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE           32      /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH          5       /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH          5       /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE               16384   /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE               16384   /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK       1       /* writeback feature */ +#define XCHAL_DCACHE_IS_COHERENT        0       /* MP coherence feature */ + +#define XCHAL_HAVE_PREFETCH             0       /* PREFCTL register */ + + + + +/**************************************************************************** +    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- +                                CACHE +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF                  1       /* any outbound PIF present */ + +/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */ + +/*  Number of cache sets in log2(lines per way):  */ +#define XCHAL_ICACHE_SETWIDTH           7 +#define XCHAL_DCACHE_SETWIDTH           7 + +/*  Cache set associativity (number of ways):  */ +#define XCHAL_ICACHE_WAYS               4 +#define XCHAL_DCACHE_WAYS               4 + +/*  Cache features:  */ +#define XCHAL_ICACHE_LINE_LOCKABLE      1 +#define XCHAL_DCACHE_LINE_LOCKABLE      1 +#define XCHAL_ICACHE_ECC_PARITY         0 +#define XCHAL_DCACHE_ECC_PARITY         0 + +/*  Cache access size in bytes (affects operation of SICW instruction):  */ +#define XCHAL_ICACHE_ACCESS_SIZE        4 +#define XCHAL_DCACHE_ACCESS_SIZE        4 + +/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */ +#define XCHAL_CA_BITS                   4 + + +/*---------------------------------------------------------------------- +                        INTERNAL I/D RAM/ROMs and XLMI +  ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM               0       /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM               0       /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM               0       /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM               0       /* number of core data RAMs */ +#define XCHAL_NUM_URAM                  0       /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI                  0       /* number of core XLMI ports */ + +#define XCHAL_HAVE_IMEM_LOADSTORE       1       /* can load/store to IROM/IRAM*/ + + +/*---------------------------------------------------------------------- +                        INTERRUPTS and TIMERS +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS           1       /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS   1       /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI                  1       /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT               1       /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS                3       /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS            22      /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2       5       /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS         17      /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS             6       /* number of interrupt levels +(not including level zero) */ +#define XCHAL_EXCM_LEVEL                3       /* level masked by PS.EXCM */ +/* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/*  Masks of interrupts at each interrupt level:  */ +#define XCHAL_INTLEVEL1_MASK            0x001F80FF +#define XCHAL_INTLEVEL2_MASK            0x00000100 +#define XCHAL_INTLEVEL3_MASK            0x00200E00 +#define XCHAL_INTLEVEL4_MASK            0x00001000 +#define XCHAL_INTLEVEL5_MASK            0x00002000 +#define XCHAL_INTLEVEL6_MASK            0x00000000 +#define XCHAL_INTLEVEL7_MASK            0x00004000 + +/*  Masks of interrupts at each range 1..n of interrupt levels:  */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK   0x001F80FF +#define XCHAL_INTLEVEL2_ANDBELOW_MASK   0x001F81FF +#define XCHAL_INTLEVEL3_ANDBELOW_MASK   0x003F8FFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK   0x003F9FFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK   0x003FBFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK   0x003FBFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK   0x003FFFFF + +/*  Level of each interrupt:  */ +#define XCHAL_INT0_LEVEL                1 +#define XCHAL_INT1_LEVEL                1 +#define XCHAL_INT2_LEVEL                1 +#define XCHAL_INT3_LEVEL                1 +#define XCHAL_INT4_LEVEL                1 +#define XCHAL_INT5_LEVEL                1 +#define XCHAL_INT6_LEVEL                1 +#define XCHAL_INT7_LEVEL                1 +#define XCHAL_INT8_LEVEL                2 +#define XCHAL_INT9_LEVEL                3 +#define XCHAL_INT10_LEVEL               3 +#define XCHAL_INT11_LEVEL               3 +#define XCHAL_INT12_LEVEL               4 +#define XCHAL_INT13_LEVEL               5 +#define XCHAL_INT14_LEVEL               7 +#define XCHAL_INT15_LEVEL               1 +#define XCHAL_INT16_LEVEL               1 +#define XCHAL_INT17_LEVEL               1 +#define XCHAL_INT18_LEVEL               1 +#define XCHAL_INT19_LEVEL               1 +#define XCHAL_INT20_LEVEL               1 +#define XCHAL_INT21_LEVEL               3 +#define XCHAL_DEBUGLEVEL                6       /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT     1       /* OCD external db interrupt */ +#define XCHAL_NMILEVEL                  7       /* NMI "level" (for use with +EXCSAVE/EPS/EPC_n, RFI n) */ + +/*  Type of each interrupt:  */ +#define XCHAL_INT0_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE         XTHAL_INTTYPE_TIMER +#define XCHAL_INT7_TYPE         XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT8_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT9_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT10_TYPE        XTHAL_INTTYPE_TIMER +#define XCHAL_INT11_TYPE        XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT12_TYPE        XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT13_TYPE        XTHAL_INTTYPE_TIMER +#define XCHAL_INT14_TYPE        XTHAL_INTTYPE_NMI +#define XCHAL_INT15_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT16_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT17_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT18_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT19_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT20_TYPE        XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT21_TYPE        XTHAL_INTTYPE_EXTERN_EDGE + +/*  Masks of interrupts for each type of interrupt:  */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFC00000 +#define XCHAL_INTTYPE_MASK_SOFTWARE     0x00000880 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE  0x003F8000 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000133F +#define XCHAL_INTTYPE_MASK_TIMER        0x00002440 +#define XCHAL_INTTYPE_MASK_NMI          0x00004000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR  0x00000000 + +/*  Interrupt numbers assigned to specific interrupt sources:  */ +#define XCHAL_TIMER0_INTERRUPT          6       /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT          10      /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT          13      /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT          XTHAL_TIMER_UNCONFIGURED +#define XCHAL_NMI_INTERRUPT             14      /* non-maskable interrupt */ + +/*  Interrupt numbers for levels at which only one interrupt is configured:  */ +#define XCHAL_INTLEVEL2_NUM             8 +#define XCHAL_INTLEVEL4_NUM             12 +#define XCHAL_INTLEVEL5_NUM             13 +#define XCHAL_INTLEVEL7_NUM             14 +/*  (There are many interrupts each at level(s) 1, 3.)  */ + + +/* + *  External interrupt vectors/levels. + *  These macros describe how Xtensa processor interrupt numbers + *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + *  map to external BInterrupt<n> pins, for those interrupts + *  configured as external (level-triggered, edge-triggered, or NMI). + *  See the Xtensa processor databook for more details. + */ + +/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */ +#define XCHAL_EXTINT0_NUM               0       /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM               1       /* (intlevel 1) */ +#define XCHAL_EXTINT2_NUM               2       /* (intlevel 1) */ +#define XCHAL_EXTINT3_NUM               3       /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM               4       /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM               5       /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM               8       /* (intlevel 2) */ +#define XCHAL_EXTINT7_NUM               9       /* (intlevel 3) */ +#define XCHAL_EXTINT8_NUM               12      /* (intlevel 4) */ +#define XCHAL_EXTINT9_NUM               14      /* (intlevel 7) */ +#define XCHAL_EXTINT10_NUM              15      /* (intlevel 1) */ +#define XCHAL_EXTINT11_NUM              16      /* (intlevel 1) */ +#define XCHAL_EXTINT12_NUM              17      /* (intlevel 1) */ +#define XCHAL_EXTINT13_NUM              18      /* (intlevel 1) */ +#define XCHAL_EXTINT14_NUM              19      /* (intlevel 1) */ +#define XCHAL_EXTINT15_NUM              20      /* (intlevel 1) */ +#define XCHAL_EXTINT16_NUM              21      /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- +                        EXCEPTIONS and VECTORS +  ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION               2       /* Xtensa Exception Architecture +number: 1 == XEA1 (old) +2 == XEA2 (new) +0 == XEAX (extern) or TX */ +#define XCHAL_HAVE_XEA1                 0       /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2                 1       /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX                 0       /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS           1       /* exception option */ +#define XCHAL_HAVE_HALT                 0       /* halt architecture option */ +#define XCHAL_HAVE_BOOTLOADER           0       /* boot loader (for TX) */ +#define XCHAL_HAVE_MEM_ECC_PARITY       0       /* local memory ECC/parity */ +#define XCHAL_HAVE_VECTOR_SELECT        1       /* relocatable vectors */ +#define XCHAL_HAVE_VECBASE              1       /* relocatable vectors */ +#define XCHAL_VECBASE_RESET_VADDR       0x00002000  /* VECBASE reset value */ +#define XCHAL_VECBASE_RESET_PADDR       0x00002000 +#define XCHAL_RESET_VECBASE_OVERLAP     0 + +#define XCHAL_RESET_VECTOR0_VADDR       0xFE000000 +#define XCHAL_RESET_VECTOR0_PADDR       0xFE000000 +#define XCHAL_RESET_VECTOR1_VADDR       0x00001000 +#define XCHAL_RESET_VECTOR1_PADDR       0x00001000 +#define XCHAL_RESET_VECTOR_VADDR        0xFE000000 +#define XCHAL_RESET_VECTOR_PADDR        0xFE000000 +#define XCHAL_USER_VECOFS               0x00000340 +#define XCHAL_USER_VECTOR_VADDR         0x00002340 +#define XCHAL_USER_VECTOR_PADDR         0x00002340 +#define XCHAL_KERNEL_VECOFS             0x00000300 +#define XCHAL_KERNEL_VECTOR_VADDR       0x00002300 +#define XCHAL_KERNEL_VECTOR_PADDR       0x00002300 +#define XCHAL_DOUBLEEXC_VECOFS          0x000003C0 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR    0x000023C0 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR    0x000023C0 +#define XCHAL_WINDOW_OF4_VECOFS         0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS         0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS         0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS         0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS        0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS        0x00000140 +#define XCHAL_WINDOW_VECTORS_VADDR      0x00002000 +#define XCHAL_WINDOW_VECTORS_PADDR      0x00002000 +#define XCHAL_INTLEVEL2_VECOFS          0x00000180 +#define XCHAL_INTLEVEL2_VECTOR_VADDR    0x00002180 +#define XCHAL_INTLEVEL2_VECTOR_PADDR    0x00002180 +#define XCHAL_INTLEVEL3_VECOFS          0x000001C0 +#define XCHAL_INTLEVEL3_VECTOR_VADDR    0x000021C0 +#define XCHAL_INTLEVEL3_VECTOR_PADDR    0x000021C0 +#define XCHAL_INTLEVEL4_VECOFS          0x00000200 +#define XCHAL_INTLEVEL4_VECTOR_VADDR    0x00002200 +#define XCHAL_INTLEVEL4_VECTOR_PADDR    0x00002200 +#define XCHAL_INTLEVEL5_VECOFS          0x00000240 +#define XCHAL_INTLEVEL5_VECTOR_VADDR    0x00002240 +#define XCHAL_INTLEVEL5_VECTOR_PADDR    0x00002240 +#define XCHAL_INTLEVEL6_VECOFS          0x00000280 +#define XCHAL_INTLEVEL6_VECTOR_VADDR    0x00002280 +#define XCHAL_INTLEVEL6_VECTOR_PADDR    0x00002280 +#define XCHAL_DEBUG_VECOFS              XCHAL_INTLEVEL6_VECOFS +#define XCHAL_DEBUG_VECTOR_VADDR        XCHAL_INTLEVEL6_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR        XCHAL_INTLEVEL6_VECTOR_PADDR +#define XCHAL_NMI_VECOFS                0x000002C0 +#define XCHAL_NMI_VECTOR_VADDR          0x000022C0 +#define XCHAL_NMI_VECTOR_PADDR          0x000022C0 +#define XCHAL_INTLEVEL7_VECOFS          XCHAL_NMI_VECOFS +#define XCHAL_INTLEVEL7_VECTOR_VADDR    XCHAL_NMI_VECTOR_VADDR +#define XCHAL_INTLEVEL7_VECTOR_PADDR    XCHAL_NMI_VECTOR_PADDR + + +/*---------------------------------------------------------------------- +                                DEBUG +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD                  1       /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK                2       /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK                2       /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY        1       /* faster OCD option */ + + +/*---------------------------------------------------------------------- +                                MMU +  ----------------------------------------------------------------------*/ + +/*  See core-matmap.h header file for more details.  */ + +#define XCHAL_HAVE_TLBS                 1       /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY         1       /* one way maps I+D 4GB vaddr */ +#define XCHAL_SPANNING_WAY              6       /* TLB spanning way number */ +#define XCHAL_HAVE_IDENTITY_MAP         0       /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR            0       /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR      0       /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR        0       /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU              1       /* full MMU (with page table +[autorefill] and protection) +usable for an MMU-based OS */ +/*  If none of the above last 4 are set, it's a custom TLB configuration.  */ +#define XCHAL_ITLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */ +#define XCHAL_DTLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */ + +#define XCHAL_MMU_ASID_BITS             8       /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS                 4       /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS             2       /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ diff --git a/target-xtensa/core-dc233c/gdb-config.c b/target-xtensa/core-dc233c/gdb-config.c new file mode 100644 index 00000000..b632341b --- /dev/null +++ b/target-xtensa/core-dc233c/gdb-config.c @@ -0,0 +1,145 @@ +/* Configuration for the Xtensa architecture for GDB, the GNU debugger. + +   Copyright (c) 2003-2010 Tensilica Inc. + +   Permission is hereby granted, free of charge, to any person obtaining +   a copy of this software and associated documentation files (the +   "Software"), to deal in the Software without restriction, including +   without limitation the rights to use, copy, modify, merge, publish, +   distribute, sublicense, and/or sell copies of the Software, and to +   permit persons to whom the Software is furnished to do so, subject to +   the following conditions: + +   The above copyright notice and this permission notice shall be included +   in all copies or substantial portions of the Software. + +   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */ + +/*    idx ofs bi sz al targno  flags cp typ group name  */ +XTREG(0,  0, 32, 4, 4, 0x0020, 0x0006, -2, 9, 0x0100, pc,          0, 0, 0, 0, 0, 0) +XTREG(1,  4, 32, 4, 4, 0x0100, 0x0006, -2, 1, 0x0002, ar0,         0, 0, 0, 0, 0, 0) +XTREG(2,  8, 32, 4, 4, 0x0101, 0x0006, -2, 1, 0x0002, ar1,         0, 0, 0, 0, 0, 0) +XTREG(3, 12, 32, 4, 4, 0x0102, 0x0006, -2, 1, 0x0002, ar2,         0, 0, 0, 0, 0, 0) +XTREG(4, 16, 32, 4, 4, 0x0103, 0x0006, -2, 1, 0x0002, ar3,         0, 0, 0, 0, 0, 0) +XTREG(5, 20, 32, 4, 4, 0x0104, 0x0006, -2, 1, 0x0002, ar4,         0, 0, 0, 0, 0, 0) +XTREG(6, 24, 32, 4, 4, 0x0105, 0x0006, -2, 1, 0x0002, ar5,         0, 0, 0, 0, 0, 0) +XTREG(7, 28, 32, 4, 4, 0x0106, 0x0006, -2, 1, 0x0002, ar6,         0, 0, 0, 0, 0, 0) +XTREG(8, 32, 32, 4, 4, 0x0107, 0x0006, -2, 1, 0x0002, ar7,         0, 0, 0, 0, 0, 0) +XTREG(9, 36, 32, 4, 4, 0x0108, 0x0006, -2, 1, 0x0002, ar8,         0, 0, 0, 0, 0, 0) +XTREG(10, 40, 32, 4, 4, 0x0109, 0x0006, -2, 1, 0x0002, ar9,         0, 0, 0, 0, 0, 0) +XTREG(11, 44, 32, 4, 4, 0x010a, 0x0006, -2, 1, 0x0002, ar10,        0, 0, 0, 0, 0, 0) +XTREG(12, 48, 32, 4, 4, 0x010b, 0x0006, -2, 1, 0x0002, ar11,        0, 0, 0, 0, 0, 0) +XTREG(13, 52, 32, 4, 4, 0x010c, 0x0006, -2, 1, 0x0002, ar12,        0, 0, 0, 0, 0, 0) +XTREG(14, 56, 32, 4, 4, 0x010d, 0x0006, -2, 1, 0x0002, ar13,        0, 0, 0, 0, 0, 0) +XTREG(15, 60, 32, 4, 4, 0x010e, 0x0006, -2, 1, 0x0002, ar14,        0, 0, 0, 0, 0, 0) +XTREG(16, 64, 32, 4, 4, 0x010f, 0x0006, -2, 1, 0x0002, ar15,        0, 0, 0, 0, 0, 0) +XTREG(17, 68, 32, 4, 4, 0x0110, 0x0006, -2, 1, 0x0002, ar16,        0, 0, 0, 0, 0, 0) +XTREG(18, 72, 32, 4, 4, 0x0111, 0x0006, -2, 1, 0x0002, ar17,        0, 0, 0, 0, 0, 0) +XTREG(19, 76, 32, 4, 4, 0x0112, 0x0006, -2, 1, 0x0002, ar18,        0, 0, 0, 0, 0, 0) +XTREG(20, 80, 32, 4, 4, 0x0113, 0x0006, -2, 1, 0x0002, ar19,        0, 0, 0, 0, 0, 0) +XTREG(21, 84, 32, 4, 4, 0x0114, 0x0006, -2, 1, 0x0002, ar20,        0, 0, 0, 0, 0, 0) +XTREG(22, 88, 32, 4, 4, 0x0115, 0x0006, -2, 1, 0x0002, ar21,        0, 0, 0, 0, 0, 0) +XTREG(23, 92, 32, 4, 4, 0x0116, 0x0006, -2, 1, 0x0002, ar22,        0, 0, 0, 0, 0, 0) +XTREG(24, 96, 32, 4, 4, 0x0117, 0x0006, -2, 1, 0x0002, ar23,        0, 0, 0, 0, 0, 0) +XTREG(25, 100, 32, 4, 4, 0x0118, 0x0006, -2, 1, 0x0002, ar24,        0, 0, 0, 0, 0, 0) +XTREG(26, 104, 32, 4, 4, 0x0119, 0x0006, -2, 1, 0x0002, ar25,        0, 0, 0, 0, 0, 0) +XTREG(27, 108, 32, 4, 4, 0x011a, 0x0006, -2, 1, 0x0002, ar26,        0, 0, 0, 0, 0, 0) +XTREG(28, 112, 32, 4, 4, 0x011b, 0x0006, -2, 1, 0x0002, ar27,        0, 0, 0, 0, 0, 0) +XTREG(29, 116, 32, 4, 4, 0x011c, 0x0006, -2, 1, 0x0002, ar28,        0, 0, 0, 0, 0, 0) +XTREG(30, 120, 32, 4, 4, 0x011d, 0x0006, -2, 1, 0x0002, ar29,        0, 0, 0, 0, 0, 0) +XTREG(31, 124, 32, 4, 4, 0x011e, 0x0006, -2, 1, 0x0002, ar30,        0, 0, 0, 0, 0, 0) +XTREG(32, 128, 32, 4, 4, 0x011f, 0x0006, -2, 1, 0x0002, ar31,        0, 0, 0, 0, 0, 0) +XTREG(33, 132, 32, 4, 4, 0x0200, 0x0006, -2, 2, 0x1100, lbeg,        0, 0, 0, 0, 0, 0) +XTREG(34, 136, 32, 4, 4, 0x0201, 0x0006, -2, 2, 0x1100, lend,        0, 0, 0, 0, 0, 0) +XTREG(35, 140, 32, 4, 4, 0x0202, 0x0006, -2, 2, 0x1100, lcount,      0, 0, 0, 0, 0, 0) +XTREG(36, 144, 6, 4, 4, 0x0203, 0x0006, -2, 2, 0x1100, sar,         0, 0, 0, 0, 0, 0) +XTREG(37, 148, 32, 4, 4, 0x0205, 0x0006, -2, 2, 0x1100, litbase,     0, 0, 0, 0, 0, 0) +XTREG(38, 152, 3, 4, 4, 0x0248, 0x0006, -2, 2, 0x1002, windowbase,  0, 0, 0, 0, 0, 0) +XTREG(39, 156, 8, 4, 4, 0x0249, 0x0006, -2, 2, 0x1002, windowstart, 0, 0, 0, 0, 0, 0) +XTREG(40, 160, 32, 4, 4, 0x02b0, 0x0002, -2, 2, 0x1000, sr176,       0, 0, 0, 0, 0, 0) +XTREG(41, 164, 32, 4, 4, 0x02d0, 0x0002, -2, 2, 0x1000, sr208,       0, 0, 0, 0, 0, 0) +XTREG(42, 168, 19, 4, 4, 0x02e6, 0x0006, -2, 2, 0x1100, ps,          0, 0, 0, 0, 0, 0) +XTREG(43, 172, 32, 4, 4, 0x03e7, 0x0006, -2, 3, 0x0110, threadptr,   0, 0, 0, 0, 0, 0) +XTREG(44, 176, 32, 4, 4, 0x020c, 0x0006, -1, 2, 0x1100, scompare1,   0, 0, 0, 0, 0, 0) +XTREG(45, 180, 32, 4, 4, 0x0210, 0x0006, -1, 2, 0x1100, acclo,       0, 0, 0, 0, 0, 0) +XTREG(46, 184, 8, 4, 4, 0x0211, 0x0006, -1, 2, 0x1100, acchi,       0, 0, 0, 0, 0, 0) +XTREG(47, 188, 32, 4, 4, 0x0220, 0x0006, -1, 2, 0x1100, m0,          0, 0, 0, 0, 0, 0) +XTREG(48, 192, 32, 4, 4, 0x0221, 0x0006, -1, 2, 0x1100, m1,          0, 0, 0, 0, 0, 0) +XTREG(49, 196, 32, 4, 4, 0x0222, 0x0006, -1, 2, 0x1100, m2,          0, 0, 0, 0, 0, 0) +XTREG(50, 200, 32, 4, 4, 0x0223, 0x0006, -1, 2, 0x1100, m3,          0, 0, 0, 0, 0, 0) +XTREG(51, 204, 32, 4, 4, 0x03e6, 0x000e, -1, 3, 0x0110, expstate,    0, 0, 0, 0, 0, 0) +XTREG(52, 208, 32, 4, 4, 0x0253, 0x0007, -2, 2, 0x1000, ptevaddr,    0, 0, 0, 0, 0, 0) +XTREG(53, 212, 32, 4, 4, 0x0259, 0x000d, -2, 2, 0x1000, mmid,        0, 0, 0, 0, 0, 0) +XTREG(54, 216, 32, 4, 4, 0x025a, 0x0007, -2, 2, 0x1000, rasid,       0, 0, 0, 0, 0, 0) +XTREG(55, 220, 25, 4, 4, 0x025b, 0x0007, -2, 2, 0x1000, itlbcfg,     0, 0, 0, 0, 0, 0) +XTREG(56, 224, 25, 4, 4, 0x025c, 0x0007, -2, 2, 0x1000, dtlbcfg,     0, 0, 0, 0, 0, 0) +XTREG(57, 228, 2, 4, 4, 0x0260, 0x0007, -2, 2, 0x1000, ibreakenable, 0, 0, 0, 0, 0, 0) +XTREG(58, 232, 6, 4, 4, 0x0263, 0x0007, -2, 2, 0x1000, atomctl,     0, 0, 0, 0, 0, 0) +XTREG(59, 236, 32, 4, 4, 0x0268, 0x0007, -2, 2, 0x1000, ddr,         0, 0, 0, 0, 0, 0) +XTREG(60, 240, 32, 4, 4, 0x0280, 0x0007, -2, 2, 0x1000, ibreaka0,    0, 0, 0, 0, 0, 0) +XTREG(61, 244, 32, 4, 4, 0x0281, 0x0007, -2, 2, 0x1000, ibreaka1,    0, 0, 0, 0, 0, 0) +XTREG(62, 248, 32, 4, 4, 0x0290, 0x0007, -2, 2, 0x1000, dbreaka0,    0, 0, 0, 0, 0, 0) +XTREG(63, 252, 32, 4, 4, 0x0291, 0x0007, -2, 2, 0x1000, dbreaka1,    0, 0, 0, 0, 0, 0) +XTREG(64, 256, 32, 4, 4, 0x02a0, 0x0007, -2, 2, 0x1000, dbreakc0,    0, 0, 0, 0, 0, 0) +XTREG(65, 260, 32, 4, 4, 0x02a1, 0x0007, -2, 2, 0x1000, dbreakc1,    0, 0, 0, 0, 0, 0) +XTREG(66, 264, 32, 4, 4, 0x02b1, 0x0007, -2, 2, 0x1000, epc1,        0, 0, 0, 0, 0, 0) +XTREG(67, 268, 32, 4, 4, 0x02b2, 0x0007, -2, 2, 0x1000, epc2,        0, 0, 0, 0, 0, 0) +XTREG(68, 272, 32, 4, 4, 0x02b3, 0x0007, -2, 2, 0x1000, epc3,        0, 0, 0, 0, 0, 0) +XTREG(69, 276, 32, 4, 4, 0x02b4, 0x0007, -2, 2, 0x1000, epc4,        0, 0, 0, 0, 0, 0) +XTREG(70, 280, 32, 4, 4, 0x02b5, 0x0007, -2, 2, 0x1000, epc5,        0, 0, 0, 0, 0, 0) +XTREG(71, 284, 32, 4, 4, 0x02b6, 0x0007, -2, 2, 0x1000, epc6,        0, 0, 0, 0, 0, 0) +XTREG(72, 288, 32, 4, 4, 0x02b7, 0x0007, -2, 2, 0x1000, epc7,        0, 0, 0, 0, 0, 0) +XTREG(73, 292, 32, 4, 4, 0x02c0, 0x0007, -2, 2, 0x1000, depc,        0, 0, 0, 0, 0, 0) +XTREG(74, 296, 19, 4, 4, 0x02c2, 0x0007, -2, 2, 0x1000, eps2,        0, 0, 0, 0, 0, 0) +XTREG(75, 300, 19, 4, 4, 0x02c3, 0x0007, -2, 2, 0x1000, eps3,        0, 0, 0, 0, 0, 0) +XTREG(76, 304, 19, 4, 4, 0x02c4, 0x0007, -2, 2, 0x1000, eps4,        0, 0, 0, 0, 0, 0) +XTREG(77, 308, 19, 4, 4, 0x02c5, 0x0007, -2, 2, 0x1000, eps5,        0, 0, 0, 0, 0, 0) +XTREG(78, 312, 19, 4, 4, 0x02c6, 0x0007, -2, 2, 0x1000, eps6,        0, 0, 0, 0, 0, 0) +XTREG(79, 316, 19, 4, 4, 0x02c7, 0x0007, -2, 2, 0x1000, eps7,        0, 0, 0, 0, 0, 0) +XTREG(80, 320, 32, 4, 4, 0x02d1, 0x0007, -2, 2, 0x1000, excsave1,    0, 0, 0, 0, 0, 0) +XTREG(81, 324, 32, 4, 4, 0x02d2, 0x0007, -2, 2, 0x1000, excsave2,    0, 0, 0, 0, 0, 0) +XTREG(82, 328, 32, 4, 4, 0x02d3, 0x0007, -2, 2, 0x1000, excsave3,    0, 0, 0, 0, 0, 0) +XTREG(83, 332, 32, 4, 4, 0x02d4, 0x0007, -2, 2, 0x1000, excsave4,    0, 0, 0, 0, 0, 0) +XTREG(84, 336, 32, 4, 4, 0x02d5, 0x0007, -2, 2, 0x1000, excsave5,    0, 0, 0, 0, 0, 0) +XTREG(85, 340, 32, 4, 4, 0x02d6, 0x0007, -2, 2, 0x1000, excsave6,    0, 0, 0, 0, 0, 0) +XTREG(86, 344, 32, 4, 4, 0x02d7, 0x0007, -2, 2, 0x1000, excsave7,    0, 0, 0, 0, 0, 0) +XTREG(87, 348, 8, 4, 4, 0x02e0, 0x0007, -2, 2, 0x1000, cpenable,    0, 0, 0, 0, 0, 0) +XTREG(88, 352, 22, 4, 4, 0x02e2, 0x000b, -2, 2, 0x1000, interrupt,   0, 0, 0, 0, 0, 0) +XTREG(89, 356, 22, 4, 4, 0x02e2, 0x000d, -2, 2, 0x1000, intset,      0, 0, 0, 0, 0, 0) +XTREG(90, 360, 22, 4, 4, 0x02e3, 0x000d, -2, 2, 0x1000, intclear,    0, 0, 0, 0, 0, 0) +XTREG(91, 364, 22, 4, 4, 0x02e4, 0x0007, -2, 2, 0x1000, intenable,   0, 0, 0, 0, 0, 0) +XTREG(92, 368, 32, 4, 4, 0x02e7, 0x0007, -2, 2, 0x1000, vecbase,     0, 0, 0, 0, 0, 0) +XTREG(93, 372, 6, 4, 4, 0x02e8, 0x0007, -2, 2, 0x1000, exccause,    0, 0, 0, 0, 0, 0) +XTREG(94, 376, 12, 4, 4, 0x02e9, 0x0003, -2, 2, 0x1000, debugcause,  0, 0, 0, 0, 0, 0) +XTREG(95, 380, 32, 4, 4, 0x02ea, 0x000f, -2, 2, 0x1000, ccount,      0, 0, 0, 0, 0, 0) +XTREG(96, 384, 32, 4, 4, 0x02eb, 0x0003, -2, 2, 0x1000, prid,        0, 0, 0, 0, 0, 0) +XTREG(97, 388, 32, 4, 4, 0x02ec, 0x000f, -2, 2, 0x1000, icount,      0, 0, 0, 0, 0, 0) +XTREG(98, 392, 4, 4, 4, 0x02ed, 0x0007, -2, 2, 0x1000, icountlevel, 0, 0, 0, 0, 0, 0) +XTREG(99, 396, 32, 4, 4, 0x02ee, 0x0007, -2, 2, 0x1000, excvaddr,    0, 0, 0, 0, 0, 0) +XTREG(100, 400, 32, 4, 4, 0x02f0, 0x000f, -2, 2, 0x1000, ccompare0,   0, 0, 0, 0, 0, 0) +XTREG(101, 404, 32, 4, 4, 0x02f1, 0x000f, -2, 2, 0x1000, ccompare1,   0, 0, 0, 0, 0, 0) +XTREG(102, 408, 32, 4, 4, 0x02f2, 0x000f, -2, 2, 0x1000, ccompare2,   0, 0, 0, 0, 0, 0) +XTREG(103, 412, 32, 4, 4, 0x02f4, 0x0007, -2, 2, 0x1000, misc0,       0, 0, 0, 0, 0, 0) +XTREG(104, 416, 32, 4, 4, 0x02f5, 0x0007, -2, 2, 0x1000, misc1,       0, 0, 0, 0, 0, 0) +XTREG(105, 420, 32, 4, 4, 0x0000, 0x0006, -2, 8, 0x0100, a0,          0, 0, 0, 0, 0, 0) +XTREG(106, 424, 32, 4, 4, 0x0001, 0x0006, -2, 8, 0x0100, a1,          0, 0, 0, 0, 0, 0) +XTREG(107, 428, 32, 4, 4, 0x0002, 0x0006, -2, 8, 0x0100, a2,          0, 0, 0, 0, 0, 0) +XTREG(108, 432, 32, 4, 4, 0x0003, 0x0006, -2, 8, 0x0100, a3,          0, 0, 0, 0, 0, 0) +XTREG(109, 436, 32, 4, 4, 0x0004, 0x0006, -2, 8, 0x0100, a4,          0, 0, 0, 0, 0, 0) +XTREG(110, 440, 32, 4, 4, 0x0005, 0x0006, -2, 8, 0x0100, a5,          0, 0, 0, 0, 0, 0) +XTREG(111, 444, 32, 4, 4, 0x0006, 0x0006, -2, 8, 0x0100, a6,          0, 0, 0, 0, 0, 0) +XTREG(112, 448, 32, 4, 4, 0x0007, 0x0006, -2, 8, 0x0100, a7,          0, 0, 0, 0, 0, 0) +XTREG(113, 452, 32, 4, 4, 0x0008, 0x0006, -2, 8, 0x0100, a8,          0, 0, 0, 0, 0, 0) +XTREG(114, 456, 32, 4, 4, 0x0009, 0x0006, -2, 8, 0x0100, a9,          0, 0, 0, 0, 0, 0) +XTREG(115, 460, 32, 4, 4, 0x000a, 0x0006, -2, 8, 0x0100, a10,         0, 0, 0, 0, 0, 0) +XTREG(116, 464, 32, 4, 4, 0x000b, 0x0006, -2, 8, 0x0100, a11,         0, 0, 0, 0, 0, 0) +XTREG(117, 468, 32, 4, 4, 0x000c, 0x0006, -2, 8, 0x0100, a12,         0, 0, 0, 0, 0, 0) +XTREG(118, 472, 32, 4, 4, 0x000d, 0x0006, -2, 8, 0x0100, a13,         0, 0, 0, 0, 0, 0) +XTREG(119, 476, 32, 4, 4, 0x000e, 0x0006, -2, 8, 0x0100, a14,         0, 0, 0, 0, 0, 0) +XTREG(120, 480, 32, 4, 4, 0x000f, 0x0006, -2, 8, 0x0100, a15,         0, 0, 0, 0, 0, 0) diff --git a/target-xtensa/core-fsf.c b/target-xtensa/core-fsf.c new file mode 100644 index 00000000..f6ea6b94 --- /dev/null +++ b/target-xtensa/core-fsf.c @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/gdbstub.h" +#include "qemu/host-utils.h" + +#include "core-fsf/core-isa.h" +#include "overlay_tool.h" + +static XtensaConfig fsf __attribute__((unused)) = { +    .name = "fsf", +    .gdb_regmap = { +    /* GDB for this core is not supported currently */ +        .reg = { +            XTREG_END +        }, +    }, +    .clock_freq_khz = 10000, +    DEFAULT_SECTIONS +}; + +REGISTER_CORE(fsf) diff --git a/target-xtensa/core-fsf/core-isa.h b/target-xtensa/core-fsf/core-isa.h new file mode 100644 index 00000000..b519d6c7 --- /dev/null +++ b/target-xtensa/core-fsf/core-isa.h @@ -0,0 +1,361 @@ +/* + * Xtensa processor core configuration information. + * + * This file is subject to the terms and conditions of the GNU General Public + * License.  See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 1999-2006 Tensilica Inc. + */ + +#ifndef _XTENSA_CORE_H +#define _XTENSA_CORE_H + + +/**************************************************************************** +            Parameters Useful for Any Code, USER or PRIVILEGED + ****************************************************************************/ + +/* + *  Note:  Macros of the form XCHAL_HAVE_*** have a value of 1 if the option is + *  configured, and a value of 0 otherwise.  These macros are always defined. + */ + + +/*---------------------------------------------------------------------- +                                ISA +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_BE                   1       /* big-endian byte ordering */ +#define XCHAL_HAVE_WINDOWED             1       /* windowed registers option */ +#define XCHAL_NUM_AREGS                 64      /* num of physical addr regs */ +#define XCHAL_NUM_AREGS_LOG2            6       /* log2(XCHAL_NUM_AREGS) */ +#define XCHAL_MAX_INSTRUCTION_SIZE      3       /* max instr bytes (3..8) */ +#define XCHAL_HAVE_DEBUG                1       /* debug option */ +#define XCHAL_HAVE_DENSITY              1       /* 16-bit instructions */ +#define XCHAL_HAVE_LOOPS                1       /* zero-overhead loops */ +#define XCHAL_HAVE_NSA                  1       /* NSA/NSAU instructions */ +#define XCHAL_HAVE_MINMAX               0       /* MIN/MAX instructions */ +#define XCHAL_HAVE_SEXT                 0       /* SEXT instruction */ +#define XCHAL_HAVE_CLAMPS               0       /* CLAMPS instruction */ +#define XCHAL_HAVE_MUL16                0       /* MUL16S/MUL16U instructions */ +#define XCHAL_HAVE_MUL32                0       /* MULL instruction */ +#define XCHAL_HAVE_MUL32_HIGH           0       /* MULUH/MULSH instructions */ +#define XCHAL_HAVE_L32R                 1       /* L32R instruction */ +#define XCHAL_HAVE_ABSOLUTE_LITERALS    1       /* non-PC-rel (extended) L32R */ +#define XCHAL_HAVE_CONST16              0       /* CONST16 instruction */ +#define XCHAL_HAVE_ADDX                 1       /* ADDX#/SUBX# instructions */ +#define XCHAL_HAVE_WIDE_BRANCHES        0       /* B*.W18 or B*.W15 instr's */ +#define XCHAL_HAVE_PREDICTED_BRANCHES   0       /* B[EQ/EQZ/NE/NEZ]T instr's */ +#define XCHAL_HAVE_CALL4AND12           1       /* (obsolete option) */ +#define XCHAL_HAVE_ABS                  1       /* ABS instruction */ +/*#define XCHAL_HAVE_POPC               0*/     /* POPC instruction */ +/*#define XCHAL_HAVE_CRC                0*/     /* CRC instruction */ +#define XCHAL_HAVE_RELEASE_SYNC         0       /* L32AI/S32RI instructions */ +#define XCHAL_HAVE_S32C1I               0       /* S32C1I instruction */ +#define XCHAL_HAVE_SPECULATION          0       /* speculation */ +#define XCHAL_HAVE_FULL_RESET           1       /* all regs/state reset */ +#define XCHAL_NUM_CONTEXTS              1       /* */ +#define XCHAL_NUM_MISC_REGS             2       /* num of scratch regs (0..4) */ +#define XCHAL_HAVE_TAP_MASTER           0       /* JTAG TAP control instr's */ +#define XCHAL_HAVE_PRID                 1       /* processor ID register */ +#define XCHAL_HAVE_THREADPTR            1       /* THREADPTR register */ +#define XCHAL_HAVE_BOOLEANS             0       /* boolean registers */ +#define XCHAL_HAVE_CP                   0       /* CPENABLE reg (coprocessor) */ +#define XCHAL_CP_MAXCFG                 0       /* max allowed cp id plus one */ +#define XCHAL_HAVE_MAC16                0       /* MAC16 package */ +#define XCHAL_HAVE_VECTORFPU2005        0       /* vector floating-point pkg */ +#define XCHAL_HAVE_FP                   0       /* floating point pkg */ +#define XCHAL_HAVE_VECTRA1              0       /* Vectra I  pkg */ +#define XCHAL_HAVE_VECTRALX             0       /* Vectra LX pkg */ +#define XCHAL_HAVE_HIFI2                0       /* HiFi2 Audio Engine pkg */ + + +/*---------------------------------------------------------------------- +                                MISC +  ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_WRITEBUFFER_ENTRIES   4       /* size of write buffer */ +#define XCHAL_INST_FETCH_WIDTH          4       /* instr-fetch width in bytes */ +#define XCHAL_DATA_WIDTH                4       /* data width in bytes */ +/*  In T1050, applies to selected core load and store instructions (see ISA): */ +#define XCHAL_UNALIGNED_LOAD_EXCEPTION  1       /* unaligned loads cause exc. */ +#define XCHAL_UNALIGNED_STORE_EXCEPTION 1       /* unaligned stores cause exc.*/ + +#define XCHAL_SW_VERSION                800002  /* sw version of this header */ + +#define XCHAL_CORE_ID                   "fsf"   /* alphanum core name +                                                   (CoreID) set in the Xtensa +                                                   Processor Generator */ + +#define XCHAL_CORE_DESCRIPTION          "fsf standard core" +#define XCHAL_BUILD_UNIQUE_ID           0x00006700      /* 22-bit sw build ID */ + +/* + *  These definitions describe the hardware targeted by this software. + */ +#define XCHAL_HW_CONFIGID0              0xC103C3FF      /* ConfigID hi 32 bits*/ +#define XCHAL_HW_CONFIGID1              0x0C006700      /* ConfigID lo 32 bits*/ +#define XCHAL_HW_VERSION_NAME           "LX2.0.0"       /* full version name */ +#define XCHAL_HW_VERSION_MAJOR          2200    /* major ver# of targeted hw */ +#define XCHAL_HW_VERSION_MINOR          0       /* minor ver# of targeted hw */ +#define XTHAL_HW_REL_LX2                1 +#define XTHAL_HW_REL_LX2_0              1 +#define XTHAL_HW_REL_LX2_0_0            1 +#define XCHAL_HW_CONFIGID_RELIABLE      1 +/*  If software targets a *range* of hardware versions, these are the bounds: */ +#define XCHAL_HW_MIN_VERSION_MAJOR      2200    /* major v of earliest tgt hw */ +#define XCHAL_HW_MIN_VERSION_MINOR      0       /* minor v of earliest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MAJOR      2200    /* major v of latest tgt hw */ +#define XCHAL_HW_MAX_VERSION_MINOR      0       /* minor v of latest tgt hw */ + + +/*---------------------------------------------------------------------- +                                CACHE +  ----------------------------------------------------------------------*/ + +#define XCHAL_ICACHE_LINESIZE           16      /* I-cache line size in bytes */ +#define XCHAL_DCACHE_LINESIZE           16      /* D-cache line size in bytes */ +#define XCHAL_ICACHE_LINEWIDTH          4       /* log2(I line size in bytes) */ +#define XCHAL_DCACHE_LINEWIDTH          4       /* log2(D line size in bytes) */ + +#define XCHAL_ICACHE_SIZE               8192    /* I-cache size in bytes or 0 */ +#define XCHAL_DCACHE_SIZE               8192    /* D-cache size in bytes or 0 */ + +#define XCHAL_DCACHE_IS_WRITEBACK       0       /* writeback feature */ + + + + +/**************************************************************************** +    Parameters Useful for PRIVILEGED (Supervisory or Non-Virtualized) Code + ****************************************************************************/ + + +#ifndef XTENSA_HAL_NON_PRIVILEGED_ONLY + +/*---------------------------------------------------------------------- +                                CACHE +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_PIF                  1       /* any outbound PIF present */ + +/*  If present, cache size in bytes == (ways * 2^(linewidth + setwidth)).  */ + +/*  Number of cache sets in log2(lines per way):  */ +#define XCHAL_ICACHE_SETWIDTH           8 +#define XCHAL_DCACHE_SETWIDTH           8 + +/*  Cache set associativity (number of ways):  */ +#define XCHAL_ICACHE_WAYS               2 +#define XCHAL_DCACHE_WAYS               2 + +/*  Cache features:  */ +#define XCHAL_ICACHE_LINE_LOCKABLE      0 +#define XCHAL_DCACHE_LINE_LOCKABLE      0 +#define XCHAL_ICACHE_ECC_PARITY         0 +#define XCHAL_DCACHE_ECC_PARITY         0 + +/*  Number of encoded cache attr bits (see <xtensa/hal.h> for decoded bits):  */ +#define XCHAL_CA_BITS                   4 + + +/*---------------------------------------------------------------------- +                        INTERNAL I/D RAM/ROMs and XLMI +  ----------------------------------------------------------------------*/ + +#define XCHAL_NUM_INSTROM               0       /* number of core instr. ROMs */ +#define XCHAL_NUM_INSTRAM               0       /* number of core instr. RAMs */ +#define XCHAL_NUM_DATAROM               0       /* number of core data ROMs */ +#define XCHAL_NUM_DATARAM               0       /* number of core data RAMs */ +#define XCHAL_NUM_URAM                  0       /* number of core unified RAMs*/ +#define XCHAL_NUM_XLMI                  0       /* number of core XLMI ports */ + + +/*---------------------------------------------------------------------- +                        INTERRUPTS and TIMERS +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_INTERRUPTS           1       /* interrupt option */ +#define XCHAL_HAVE_HIGHPRI_INTERRUPTS   1       /* med/high-pri. interrupts */ +#define XCHAL_HAVE_NMI                  0       /* non-maskable interrupt */ +#define XCHAL_HAVE_CCOUNT               1       /* CCOUNT reg. (timer option) */ +#define XCHAL_NUM_TIMERS                3       /* number of CCOMPAREn regs */ +#define XCHAL_NUM_INTERRUPTS            17      /* number of interrupts */ +#define XCHAL_NUM_INTERRUPTS_LOG2       5       /* ceil(log2(NUM_INTERRUPTS)) */ +#define XCHAL_NUM_EXTINTERRUPTS         10      /* num of external interrupts */ +#define XCHAL_NUM_INTLEVELS             4       /* number of interrupt levels +                                                   (not including level zero) */ +#define XCHAL_EXCM_LEVEL                1       /* level masked by PS.EXCM */ +        /* (always 1 in XEA1; levels 2 .. EXCM_LEVEL are "medium priority") */ + +/*  Masks of interrupts at each interrupt level:  */ +#define XCHAL_INTLEVEL1_MASK            0x000064F9 +#define XCHAL_INTLEVEL2_MASK            0x00008902 +#define XCHAL_INTLEVEL3_MASK            0x00011204 +#define XCHAL_INTLEVEL4_MASK            0x00000000 +#define XCHAL_INTLEVEL5_MASK            0x00000000 +#define XCHAL_INTLEVEL6_MASK            0x00000000 +#define XCHAL_INTLEVEL7_MASK            0x00000000 + +/*  Masks of interrupts at each range 1..n of interrupt levels:  */ +#define XCHAL_INTLEVEL1_ANDBELOW_MASK   0x000064F9 +#define XCHAL_INTLEVEL2_ANDBELOW_MASK   0x0000EDFB +#define XCHAL_INTLEVEL3_ANDBELOW_MASK   0x0001FFFF +#define XCHAL_INTLEVEL4_ANDBELOW_MASK   0x0001FFFF +#define XCHAL_INTLEVEL5_ANDBELOW_MASK   0x0001FFFF +#define XCHAL_INTLEVEL6_ANDBELOW_MASK   0x0001FFFF +#define XCHAL_INTLEVEL7_ANDBELOW_MASK   0x0001FFFF + +/*  Level of each interrupt:  */ +#define XCHAL_INT0_LEVEL                1 +#define XCHAL_INT1_LEVEL                2 +#define XCHAL_INT2_LEVEL                3 +#define XCHAL_INT3_LEVEL                1 +#define XCHAL_INT4_LEVEL                1 +#define XCHAL_INT5_LEVEL                1 +#define XCHAL_INT6_LEVEL                1 +#define XCHAL_INT7_LEVEL                1 +#define XCHAL_INT8_LEVEL                2 +#define XCHAL_INT9_LEVEL                3 +#define XCHAL_INT10_LEVEL               1 +#define XCHAL_INT11_LEVEL               2 +#define XCHAL_INT12_LEVEL               3 +#define XCHAL_INT13_LEVEL               1 +#define XCHAL_INT14_LEVEL               1 +#define XCHAL_INT15_LEVEL               2 +#define XCHAL_INT16_LEVEL               3 +#define XCHAL_DEBUGLEVEL                4       /* debug interrupt level */ +#define XCHAL_HAVE_DEBUG_EXTERN_INT     0       /* OCD external db interrupt */ + +/*  Type of each interrupt:  */ +#define XCHAL_INT0_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT1_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT2_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT3_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT4_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT5_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT6_TYPE         XTHAL_INTTYPE_EXTERN_LEVEL +#define XCHAL_INT7_TYPE         XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT8_TYPE         XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT9_TYPE         XTHAL_INTTYPE_EXTERN_EDGE +#define XCHAL_INT10_TYPE        XTHAL_INTTYPE_TIMER +#define XCHAL_INT11_TYPE        XTHAL_INTTYPE_TIMER +#define XCHAL_INT12_TYPE        XTHAL_INTTYPE_TIMER +#define XCHAL_INT13_TYPE        XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT14_TYPE        XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT15_TYPE        XTHAL_INTTYPE_SOFTWARE +#define XCHAL_INT16_TYPE        XTHAL_INTTYPE_SOFTWARE + +/*  Masks of interrupts for each type of interrupt:  */ +#define XCHAL_INTTYPE_MASK_UNCONFIGURED 0xFFFE0000 +#define XCHAL_INTTYPE_MASK_SOFTWARE     0x0001E000 +#define XCHAL_INTTYPE_MASK_EXTERN_EDGE  0x00000380 +#define XCHAL_INTTYPE_MASK_EXTERN_LEVEL 0x0000007F +#define XCHAL_INTTYPE_MASK_TIMER        0x00001C00 +#define XCHAL_INTTYPE_MASK_NMI          0x00000000 +#define XCHAL_INTTYPE_MASK_WRITE_ERROR  0x00000000 + +/*  Interrupt numbers assigned to specific interrupt sources:  */ +#define XCHAL_TIMER0_INTERRUPT          10      /* CCOMPARE0 */ +#define XCHAL_TIMER1_INTERRUPT          11      /* CCOMPARE1 */ +#define XCHAL_TIMER2_INTERRUPT          12      /* CCOMPARE2 */ +#define XCHAL_TIMER3_INTERRUPT          XTHAL_TIMER_UNCONFIGURED + +/*  Interrupt numbers for levels at which only one interrupt is configured:  */ +/*  (There are many interrupts each at level(s) 1, 2, 3.)  */ + + +/* + *  External interrupt vectors/levels. + *  These macros describe how Xtensa processor interrupt numbers + *  (as numbered internally, eg. in INTERRUPT and INTENABLE registers) + *  map to external BInterrupt<n> pins, for those interrupts + *  configured as external (level-triggered, edge-triggered, or NMI). + *  See the Xtensa processor databook for more details. + */ + +/*  Core interrupt numbers mapped to each EXTERNAL interrupt number:  */ +#define XCHAL_EXTINT0_NUM               0       /* (intlevel 1) */ +#define XCHAL_EXTINT1_NUM               1       /* (intlevel 2) */ +#define XCHAL_EXTINT2_NUM               2       /* (intlevel 3) */ +#define XCHAL_EXTINT3_NUM               3       /* (intlevel 1) */ +#define XCHAL_EXTINT4_NUM               4       /* (intlevel 1) */ +#define XCHAL_EXTINT5_NUM               5       /* (intlevel 1) */ +#define XCHAL_EXTINT6_NUM               6       /* (intlevel 1) */ +#define XCHAL_EXTINT7_NUM               7       /* (intlevel 1) */ +#define XCHAL_EXTINT8_NUM               8       /* (intlevel 2) */ +#define XCHAL_EXTINT9_NUM               9       /* (intlevel 3) */ + + +/*---------------------------------------------------------------------- +                        EXCEPTIONS and VECTORS +  ----------------------------------------------------------------------*/ + +#define XCHAL_XEA_VERSION               2       /* Xtensa Exception Architecture +                                                   number: 1 == XEA1 (old) +                                                           2 == XEA2 (new) +                                                           0 == XEAX (extern) */ +#define XCHAL_HAVE_XEA1                 0       /* Exception Architecture 1 */ +#define XCHAL_HAVE_XEA2                 1       /* Exception Architecture 2 */ +#define XCHAL_HAVE_XEAX                 0       /* External Exception Arch. */ +#define XCHAL_HAVE_EXCEPTIONS           1       /* exception option */ +#define XCHAL_HAVE_MEM_ECC_PARITY       0       /* local memory ECC/parity */ + +#define XCHAL_RESET_VECTOR_VADDR        0xFE000020 +#define XCHAL_RESET_VECTOR_PADDR        0xFE000020 +#define XCHAL_USER_VECTOR_VADDR         0xD0000220 +#define XCHAL_USER_VECTOR_PADDR         0x00000220 +#define XCHAL_KERNEL_VECTOR_VADDR       0xD0000200 +#define XCHAL_KERNEL_VECTOR_PADDR       0x00000200 +#define XCHAL_DOUBLEEXC_VECTOR_VADDR    0xD0000290 +#define XCHAL_DOUBLEEXC_VECTOR_PADDR    0x00000290 +#define XCHAL_WINDOW_VECTORS_VADDR      0xD0000000 +#define XCHAL_WINDOW_VECTORS_PADDR      0x00000000 +#define XCHAL_INTLEVEL2_VECTOR_VADDR    0xD0000240 +#define XCHAL_INTLEVEL2_VECTOR_PADDR    0x00000240 +#define XCHAL_INTLEVEL3_VECTOR_VADDR    0xD0000250 +#define XCHAL_INTLEVEL3_VECTOR_PADDR    0x00000250 +#define XCHAL_INTLEVEL4_VECTOR_VADDR    0xFE000520 +#define XCHAL_INTLEVEL4_VECTOR_PADDR    0xFE000520 +#define XCHAL_DEBUG_VECTOR_VADDR        XCHAL_INTLEVEL4_VECTOR_VADDR +#define XCHAL_DEBUG_VECTOR_PADDR        XCHAL_INTLEVEL4_VECTOR_PADDR + + +/*---------------------------------------------------------------------- +                                DEBUG +  ----------------------------------------------------------------------*/ + +#define XCHAL_HAVE_OCD                  1       /* OnChipDebug option */ +#define XCHAL_NUM_IBREAK                2       /* number of IBREAKn regs */ +#define XCHAL_NUM_DBREAK                2       /* number of DBREAKn regs */ +#define XCHAL_HAVE_OCD_DIR_ARRAY        1       /* faster OCD option */ + + +/*---------------------------------------------------------------------- +                                MMU +  ----------------------------------------------------------------------*/ + +/*  See <xtensa/config/core-matmap.h> header file for more details.  */ + +#define XCHAL_HAVE_TLBS                 1       /* inverse of HAVE_CACHEATTR */ +#define XCHAL_HAVE_SPANNING_WAY         0       /* one way maps I+D 4GB vaddr */ +#define XCHAL_HAVE_IDENTITY_MAP         0       /* vaddr == paddr always */ +#define XCHAL_HAVE_CACHEATTR            0       /* CACHEATTR register present */ +#define XCHAL_HAVE_MIMIC_CACHEATTR      0       /* region protection */ +#define XCHAL_HAVE_XLT_CACHEATTR        0       /* region prot. w/translation */ +#define XCHAL_HAVE_PTP_MMU              1       /* full MMU (with page table +                                                   [autorefill] and protection) +                                                   usable for an MMU-based OS */ +/*  If none of the above last 4 are set, it's a custom TLB configuration.  */ +#define XCHAL_ITLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */ +#define XCHAL_DTLB_ARF_ENTRIES_LOG2     2       /* log2(autorefill way size) */ + +#define XCHAL_MMU_ASID_BITS             8       /* number of bits in ASIDs */ +#define XCHAL_MMU_RINGS                 4       /* number of rings (1..4) */ +#define XCHAL_MMU_RING_BITS             2       /* num of bits in RING field */ + +#endif /* !XTENSA_HAL_NON_PRIVILEGED_ONLY */ + + +#endif /* _XTENSA_CORE_CONFIGURATION_H */ diff --git a/target-xtensa/cpu-qom.h b/target-xtensa/cpu-qom.h new file mode 100644 index 00000000..2258224d --- /dev/null +++ b/target-xtensa/cpu-qom.h @@ -0,0 +1,99 @@ +/* + * QEMU Xtensa CPU + * + * Copyright (c) 2012 SUSE LINUX Products GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef QEMU_XTENSA_CPU_QOM_H +#define QEMU_XTENSA_CPU_QOM_H + +#include "qom/cpu.h" +#include "cpu.h" + +#define TYPE_XTENSA_CPU "xtensa-cpu" + +#define XTENSA_CPU_CLASS(class) \ +    OBJECT_CLASS_CHECK(XtensaCPUClass, (class), TYPE_XTENSA_CPU) +#define XTENSA_CPU(obj) \ +    OBJECT_CHECK(XtensaCPU, (obj), TYPE_XTENSA_CPU) +#define XTENSA_CPU_GET_CLASS(obj) \ +    OBJECT_GET_CLASS(XtensaCPUClass, (obj), TYPE_XTENSA_CPU) + +/** + * XtensaCPUClass: + * @parent_realize: The parent class' realize handler. + * @parent_reset: The parent class' reset handler. + * @config: The CPU core configuration. + * + * An Xtensa CPU model. + */ +typedef struct XtensaCPUClass { +    /*< private >*/ +    CPUClass parent_class; +    /*< public >*/ + +    DeviceRealize parent_realize; +    void (*parent_reset)(CPUState *cpu); + +    const XtensaConfig *config; +} XtensaCPUClass; + +/** + * XtensaCPU: + * @env: #CPUXtensaState + * + * An Xtensa CPU. + */ +typedef struct XtensaCPU { +    /*< private >*/ +    CPUState parent_obj; +    /*< public >*/ + +    CPUXtensaState env; +} XtensaCPU; + +static inline XtensaCPU *xtensa_env_get_cpu(const CPUXtensaState *env) +{ +    return container_of(env, XtensaCPU, env); +} + +#define ENV_GET_CPU(e) CPU(xtensa_env_get_cpu(e)) + +#define ENV_OFFSET offsetof(XtensaCPU, env) + +void xtensa_cpu_do_interrupt(CPUState *cpu); +bool xtensa_cpu_exec_interrupt(CPUState *cpu, int interrupt_request); +void xtensa_cpu_do_unassigned_access(CPUState *cpu, hwaddr addr, +                                     bool is_write, bool is_exec, int opaque, +                                     unsigned size); +void xtensa_cpu_dump_state(CPUState *cpu, FILE *f, +                           fprintf_function cpu_fprintf, int flags); +hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cpu, vaddr addr); +int xtensa_cpu_gdb_read_register(CPUState *cpu, uint8_t *buf, int reg); +int xtensa_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); +void xtensa_cpu_do_unaligned_access(CPUState *cpu, vaddr addr, +                                    int is_write, int is_user, uintptr_t retaddr); + +#endif diff --git a/target-xtensa/cpu.c b/target-xtensa/cpu.c new file mode 100644 index 00000000..4e49bee9 --- /dev/null +++ b/target-xtensa/cpu.c @@ -0,0 +1,182 @@ +/* + * QEMU Xtensa CPU + * + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * Copyright (c) 2012 SUSE LINUX Products GmbH + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu.h" +#include "qemu-common.h" +#include "migration/vmstate.h" + + +static void xtensa_cpu_set_pc(CPUState *cs, vaddr value) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); + +    cpu->env.pc = value; +} + +static bool xtensa_cpu_has_work(CPUState *cs) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); + +    return cpu->env.pending_irq_level; +} + +/* CPUClass::reset() */ +static void xtensa_cpu_reset(CPUState *s) +{ +    XtensaCPU *cpu = XTENSA_CPU(s); +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(cpu); +    CPUXtensaState *env = &cpu->env; + +    xcc->parent_reset(s); + +    env->exception_taken = 0; +    env->pc = env->config->exception_vector[EXC_RESET]; +    env->sregs[LITBASE] &= ~1; +    env->sregs[PS] = xtensa_option_enabled(env->config, +            XTENSA_OPTION_INTERRUPT) ? 0x1f : 0x10; +    env->sregs[VECBASE] = env->config->vecbase; +    env->sregs[IBREAKENABLE] = 0; +    env->sregs[CACHEATTR] = 0x22222222; +    env->sregs[ATOMCTL] = xtensa_option_enabled(env->config, +            XTENSA_OPTION_ATOMCTL) ? 0x28 : 0x15; +    env->sregs[CONFIGID0] = env->config->configid[0]; +    env->sregs[CONFIGID1] = env->config->configid[1]; + +    env->pending_irq_level = 0; +    reset_mmu(env); +} + +static ObjectClass *xtensa_cpu_class_by_name(const char *cpu_model) +{ +    ObjectClass *oc; +    char *typename; + +    if (cpu_model == NULL) { +        return NULL; +    } + +    typename = g_strdup_printf("%s-" TYPE_XTENSA_CPU, cpu_model); +    oc = object_class_by_name(typename); +    g_free(typename); +    if (oc == NULL || !object_class_dynamic_cast(oc, TYPE_XTENSA_CPU) || +        object_class_is_abstract(oc)) { +        return NULL; +    } +    return oc; +} + +static void xtensa_cpu_realizefn(DeviceState *dev, Error **errp) +{ +    CPUState *cs = CPU(dev); +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(dev); + +    cs->gdb_num_regs = xcc->config->gdb_regmap.num_regs; + +    qemu_init_vcpu(cs); + +    xcc->parent_realize(dev, errp); +} + +static void xtensa_cpu_initfn(Object *obj) +{ +    CPUState *cs = CPU(obj); +    XtensaCPU *cpu = XTENSA_CPU(obj); +    XtensaCPUClass *xcc = XTENSA_CPU_GET_CLASS(obj); +    CPUXtensaState *env = &cpu->env; +    static bool tcg_inited; + +    cs->env_ptr = env; +    env->config = xcc->config; +    cpu_exec_init(cs, &error_abort); + +    if (tcg_enabled() && !tcg_inited) { +        tcg_inited = true; +        xtensa_translate_init(); +    } +} + +static const VMStateDescription vmstate_xtensa_cpu = { +    .name = "cpu", +    .unmigratable = 1, +}; + +static void xtensa_cpu_class_init(ObjectClass *oc, void *data) +{ +    DeviceClass *dc = DEVICE_CLASS(oc); +    CPUClass *cc = CPU_CLASS(oc); +    XtensaCPUClass *xcc = XTENSA_CPU_CLASS(cc); + +    xcc->parent_realize = dc->realize; +    dc->realize = xtensa_cpu_realizefn; + +    xcc->parent_reset = cc->reset; +    cc->reset = xtensa_cpu_reset; + +    cc->class_by_name = xtensa_cpu_class_by_name; +    cc->has_work = xtensa_cpu_has_work; +    cc->do_interrupt = xtensa_cpu_do_interrupt; +    cc->cpu_exec_interrupt = xtensa_cpu_exec_interrupt; +    cc->dump_state = xtensa_cpu_dump_state; +    cc->set_pc = xtensa_cpu_set_pc; +    cc->gdb_read_register = xtensa_cpu_gdb_read_register; +    cc->gdb_write_register = xtensa_cpu_gdb_write_register; +    cc->gdb_stop_before_watchpoint = true; +#ifndef CONFIG_USER_ONLY +    cc->do_unaligned_access = xtensa_cpu_do_unaligned_access; +    cc->get_phys_page_debug = xtensa_cpu_get_phys_page_debug; +    cc->do_unassigned_access = xtensa_cpu_do_unassigned_access; +#endif +    cc->debug_excp_handler = xtensa_breakpoint_handler; +    dc->vmsd = &vmstate_xtensa_cpu; + +    /* +     * Reason: xtensa_cpu_initfn() calls cpu_exec_init(), which saves +     * the object in cpus -> dangling pointer after final +     * object_unref(). +     */ +    dc->cannot_destroy_with_object_finalize_yet = true; +} + +static const TypeInfo xtensa_cpu_type_info = { +    .name = TYPE_XTENSA_CPU, +    .parent = TYPE_CPU, +    .instance_size = sizeof(XtensaCPU), +    .instance_init = xtensa_cpu_initfn, +    .abstract = true, +    .class_size = sizeof(XtensaCPUClass), +    .class_init = xtensa_cpu_class_init, +}; + +static void xtensa_cpu_register_types(void) +{ +    type_register_static(&xtensa_cpu_type_info); +} + +type_init(xtensa_cpu_register_types) diff --git a/target-xtensa/cpu.h b/target-xtensa/cpu.h new file mode 100644 index 00000000..96bfc82e --- /dev/null +++ b/target-xtensa/cpu.h @@ -0,0 +1,556 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef CPU_XTENSA_H +#define CPU_XTENSA_H + +#define ALIGNED_ONLY +#define TARGET_LONG_BITS 32 +#define ELF_MACHINE EM_XTENSA + +#define CPUArchState struct CPUXtensaState + +#include "config.h" +#include "qemu-common.h" +#include "exec/cpu-defs.h" +#include "fpu/softfloat.h" + +#define NB_MMU_MODES 4 + +#define TARGET_PHYS_ADDR_SPACE_BITS 32 +#define TARGET_VIRT_ADDR_SPACE_BITS 32 +#define TARGET_PAGE_BITS 12 + +enum { +    /* Additional instructions */ +    XTENSA_OPTION_CODE_DENSITY, +    XTENSA_OPTION_LOOP, +    XTENSA_OPTION_EXTENDED_L32R, +    XTENSA_OPTION_16_BIT_IMUL, +    XTENSA_OPTION_32_BIT_IMUL, +    XTENSA_OPTION_32_BIT_IMUL_HIGH, +    XTENSA_OPTION_32_BIT_IDIV, +    XTENSA_OPTION_MAC16, +    XTENSA_OPTION_MISC_OP_NSA, +    XTENSA_OPTION_MISC_OP_MINMAX, +    XTENSA_OPTION_MISC_OP_SEXT, +    XTENSA_OPTION_MISC_OP_CLAMPS, +    XTENSA_OPTION_COPROCESSOR, +    XTENSA_OPTION_BOOLEAN, +    XTENSA_OPTION_FP_COPROCESSOR, +    XTENSA_OPTION_MP_SYNCHRO, +    XTENSA_OPTION_CONDITIONAL_STORE, +    XTENSA_OPTION_ATOMCTL, + +    /* Interrupts and exceptions */ +    XTENSA_OPTION_EXCEPTION, +    XTENSA_OPTION_RELOCATABLE_VECTOR, +    XTENSA_OPTION_UNALIGNED_EXCEPTION, +    XTENSA_OPTION_INTERRUPT, +    XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT, +    XTENSA_OPTION_TIMER_INTERRUPT, + +    /* Local memory */ +    XTENSA_OPTION_ICACHE, +    XTENSA_OPTION_ICACHE_TEST, +    XTENSA_OPTION_ICACHE_INDEX_LOCK, +    XTENSA_OPTION_DCACHE, +    XTENSA_OPTION_DCACHE_TEST, +    XTENSA_OPTION_DCACHE_INDEX_LOCK, +    XTENSA_OPTION_IRAM, +    XTENSA_OPTION_IROM, +    XTENSA_OPTION_DRAM, +    XTENSA_OPTION_DROM, +    XTENSA_OPTION_XLMI, +    XTENSA_OPTION_HW_ALIGNMENT, +    XTENSA_OPTION_MEMORY_ECC_PARITY, + +    /* Memory protection and translation */ +    XTENSA_OPTION_REGION_PROTECTION, +    XTENSA_OPTION_REGION_TRANSLATION, +    XTENSA_OPTION_MMU, +    XTENSA_OPTION_CACHEATTR, + +    /* Other */ +    XTENSA_OPTION_WINDOWED_REGISTER, +    XTENSA_OPTION_PROCESSOR_INTERFACE, +    XTENSA_OPTION_MISC_SR, +    XTENSA_OPTION_THREAD_POINTER, +    XTENSA_OPTION_PROCESSOR_ID, +    XTENSA_OPTION_DEBUG, +    XTENSA_OPTION_TRACE_PORT, +}; + +enum { +    THREADPTR = 231, +    FCR = 232, +    FSR = 233, +}; + +enum { +    LBEG = 0, +    LEND = 1, +    LCOUNT = 2, +    SAR = 3, +    BR = 4, +    LITBASE = 5, +    SCOMPARE1 = 12, +    ACCLO = 16, +    ACCHI = 17, +    MR = 32, +    WINDOW_BASE = 72, +    WINDOW_START = 73, +    PTEVADDR = 83, +    RASID = 90, +    ITLBCFG = 91, +    DTLBCFG = 92, +    IBREAKENABLE = 96, +    CACHEATTR = 98, +    ATOMCTL = 99, +    IBREAKA = 128, +    DBREAKA = 144, +    DBREAKC = 160, +    CONFIGID0 = 176, +    EPC1 = 177, +    DEPC = 192, +    EPS2 = 194, +    CONFIGID1 = 208, +    EXCSAVE1 = 209, +    CPENABLE = 224, +    INTSET = 226, +    INTCLEAR = 227, +    INTENABLE = 228, +    PS = 230, +    VECBASE = 231, +    EXCCAUSE = 232, +    DEBUGCAUSE = 233, +    CCOUNT = 234, +    PRID = 235, +    ICOUNT = 236, +    ICOUNTLEVEL = 237, +    EXCVADDR = 238, +    CCOMPARE = 240, +    MISC = 244, +}; + +#define PS_INTLEVEL 0xf +#define PS_INTLEVEL_SHIFT 0 + +#define PS_EXCM 0x10 +#define PS_UM 0x20 + +#define PS_RING 0xc0 +#define PS_RING_SHIFT 6 + +#define PS_OWB 0xf00 +#define PS_OWB_SHIFT 8 + +#define PS_CALLINC 0x30000 +#define PS_CALLINC_SHIFT 16 +#define PS_CALLINC_LEN 2 + +#define PS_WOE 0x40000 + +#define DEBUGCAUSE_IC 0x1 +#define DEBUGCAUSE_IB 0x2 +#define DEBUGCAUSE_DB 0x4 +#define DEBUGCAUSE_BI 0x8 +#define DEBUGCAUSE_BN 0x10 +#define DEBUGCAUSE_DI 0x20 +#define DEBUGCAUSE_DBNUM 0xf00 +#define DEBUGCAUSE_DBNUM_SHIFT 8 + +#define DBREAKC_SB 0x80000000 +#define DBREAKC_LB 0x40000000 +#define DBREAKC_SB_LB (DBREAKC_SB | DBREAKC_LB) +#define DBREAKC_MASK 0x3f + +#define MAX_NAREG 64 +#define MAX_NINTERRUPT 32 +#define MAX_NLEVEL 6 +#define MAX_NNMI 1 +#define MAX_NCCOMPARE 3 +#define MAX_TLB_WAY_SIZE 8 +#define MAX_NDBREAK 2 + +#define REGION_PAGE_MASK 0xe0000000 + +#define PAGE_CACHE_MASK    0x700 +#define PAGE_CACHE_SHIFT   8 +#define PAGE_CACHE_INVALID 0x000 +#define PAGE_CACHE_BYPASS  0x100 +#define PAGE_CACHE_WT      0x200 +#define PAGE_CACHE_WB      0x400 +#define PAGE_CACHE_ISOLATE 0x600 + +enum { +    /* Static vectors */ +    EXC_RESET, +    EXC_MEMORY_ERROR, + +    /* Dynamic vectors */ +    EXC_WINDOW_OVERFLOW4, +    EXC_WINDOW_UNDERFLOW4, +    EXC_WINDOW_OVERFLOW8, +    EXC_WINDOW_UNDERFLOW8, +    EXC_WINDOW_OVERFLOW12, +    EXC_WINDOW_UNDERFLOW12, +    EXC_IRQ, +    EXC_KERNEL, +    EXC_USER, +    EXC_DOUBLE, +    EXC_DEBUG, +    EXC_MAX +}; + +enum { +    ILLEGAL_INSTRUCTION_CAUSE = 0, +    SYSCALL_CAUSE, +    INSTRUCTION_FETCH_ERROR_CAUSE, +    LOAD_STORE_ERROR_CAUSE, +    LEVEL1_INTERRUPT_CAUSE, +    ALLOCA_CAUSE, +    INTEGER_DIVIDE_BY_ZERO_CAUSE, +    PRIVILEGED_CAUSE = 8, +    LOAD_STORE_ALIGNMENT_CAUSE, + +    INSTR_PIF_DATA_ERROR_CAUSE = 12, +    LOAD_STORE_PIF_DATA_ERROR_CAUSE, +    INSTR_PIF_ADDR_ERROR_CAUSE, +    LOAD_STORE_PIF_ADDR_ERROR_CAUSE, + +    INST_TLB_MISS_CAUSE, +    INST_TLB_MULTI_HIT_CAUSE, +    INST_FETCH_PRIVILEGE_CAUSE, +    INST_FETCH_PROHIBITED_CAUSE = 20, +    LOAD_STORE_TLB_MISS_CAUSE = 24, +    LOAD_STORE_TLB_MULTI_HIT_CAUSE, +    LOAD_STORE_PRIVILEGE_CAUSE, +    LOAD_PROHIBITED_CAUSE = 28, +    STORE_PROHIBITED_CAUSE, + +    COPROCESSOR0_DISABLED = 32, +}; + +typedef enum { +    INTTYPE_LEVEL, +    INTTYPE_EDGE, +    INTTYPE_NMI, +    INTTYPE_SOFTWARE, +    INTTYPE_TIMER, +    INTTYPE_DEBUG, +    INTTYPE_WRITE_ERR, +    INTTYPE_PROFILING, +    INTTYPE_MAX +} interrupt_type; + +typedef struct xtensa_tlb_entry { +    uint32_t vaddr; +    uint32_t paddr; +    uint8_t asid; +    uint8_t attr; +    bool variable; +} xtensa_tlb_entry; + +typedef struct xtensa_tlb { +    unsigned nways; +    const unsigned way_size[10]; +    bool varway56; +    unsigned nrefillentries; +} xtensa_tlb; + +typedef struct XtensaGdbReg { +    int targno; +    int type; +    int group; +    unsigned size; +} XtensaGdbReg; + +typedef struct XtensaGdbRegmap { +    int num_regs; +    int num_core_regs; +    /* PC + a + ar + sr + ur */ +    XtensaGdbReg reg[1 + 16 + 64 + 256 + 256]; +} XtensaGdbRegmap; + +typedef struct XtensaConfig { +    const char *name; +    uint64_t options; +    XtensaGdbRegmap gdb_regmap; +    unsigned nareg; +    int excm_level; +    int ndepc; +    uint32_t vecbase; +    uint32_t exception_vector[EXC_MAX]; +    unsigned ninterrupt; +    unsigned nlevel; +    uint32_t interrupt_vector[MAX_NLEVEL + MAX_NNMI + 1]; +    uint32_t level_mask[MAX_NLEVEL + MAX_NNMI + 1]; +    uint32_t inttype_mask[INTTYPE_MAX]; +    struct { +        uint32_t level; +        interrupt_type inttype; +    } interrupt[MAX_NINTERRUPT]; +    unsigned nccompare; +    uint32_t timerint[MAX_NCCOMPARE]; +    unsigned nextint; +    unsigned extint[MAX_NINTERRUPT]; + +    unsigned debug_level; +    unsigned nibreak; +    unsigned ndbreak; + +    uint32_t configid[2]; + +    uint32_t clock_freq_khz; + +    xtensa_tlb itlb; +    xtensa_tlb dtlb; +} XtensaConfig; + +typedef struct XtensaConfigList { +    const XtensaConfig *config; +    struct XtensaConfigList *next; +} XtensaConfigList; + +#ifdef HOST_WORDS_BIGENDIAN +enum { +    FP_F32_HIGH, +    FP_F32_LOW, +}; +#else +enum { +    FP_F32_LOW, +    FP_F32_HIGH, +}; +#endif + +typedef struct CPUXtensaState { +    const XtensaConfig *config; +    uint32_t regs[16]; +    uint32_t pc; +    uint32_t sregs[256]; +    uint32_t uregs[256]; +    uint32_t phys_regs[MAX_NAREG]; +    union { +        float32 f32[2]; +        float64 f64; +    } fregs[16]; +    float_status fp_status; + +    xtensa_tlb_entry itlb[7][MAX_TLB_WAY_SIZE]; +    xtensa_tlb_entry dtlb[10][MAX_TLB_WAY_SIZE]; +    unsigned autorefill_idx; + +    int pending_irq_level; /* level of last raised IRQ */ +    void **irq_inputs; +    QEMUTimer *ccompare_timer; +    uint32_t wake_ccount; +    int64_t halt_clock; + +    int exception_taken; + +    /* Watchpoints for DBREAK registers */ +    struct CPUWatchpoint *cpu_watchpoint[MAX_NDBREAK]; + +    CPU_COMMON +} CPUXtensaState; + +#include "cpu-qom.h" + +#define cpu_exec cpu_xtensa_exec +#define cpu_gen_code cpu_xtensa_gen_code +#define cpu_signal_handler cpu_xtensa_signal_handler +#define cpu_list xtensa_cpu_list + +#ifdef TARGET_WORDS_BIGENDIAN +#define XTENSA_DEFAULT_CPU_MODEL "fsf" +#else +#define XTENSA_DEFAULT_CPU_MODEL "dc232b" +#endif + +XtensaCPU *cpu_xtensa_init(const char *cpu_model); + +#define cpu_init(cpu_model) CPU(cpu_xtensa_init(cpu_model)) + +void xtensa_translate_init(void); +void xtensa_breakpoint_handler(CPUState *cs); +int cpu_xtensa_exec(CPUState *cpu); +void xtensa_finalize_config(XtensaConfig *config); +void xtensa_register_core(XtensaConfigList *node); +void check_interrupts(CPUXtensaState *s); +void xtensa_irq_init(CPUXtensaState *env); +void *xtensa_get_extint(CPUXtensaState *env, unsigned extint); +void xtensa_advance_ccount(CPUXtensaState *env, uint32_t d); +void xtensa_timer_irq(CPUXtensaState *env, uint32_t id, uint32_t active); +void xtensa_rearm_ccompare_timer(CPUXtensaState *env); +int cpu_xtensa_signal_handler(int host_signum, void *pinfo, void *puc); +void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf); +void xtensa_sync_window_from_phys(CPUXtensaState *env); +void xtensa_sync_phys_from_window(CPUXtensaState *env); +uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t way); +void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb, +        uint32_t *vpn, uint32_t wi, uint32_t *ei); +int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb, +        uint32_t *pwi, uint32_t *pei, uint8_t *pring); +void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env, +        xtensa_tlb_entry *entry, bool dtlb, +        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte); +void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, +        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte); +int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, +        uint32_t vaddr, int is_write, int mmu_idx, +        uint32_t *paddr, uint32_t *page_size, unsigned *access); +void reset_mmu(CPUXtensaState *env); +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env); +void debug_exception_env(CPUXtensaState *new_env, uint32_t cause); + + +#define XTENSA_OPTION_BIT(opt) (((uint64_t)1) << (opt)) +#define XTENSA_OPTION_ALL (~(uint64_t)0) + +static inline bool xtensa_option_bits_enabled(const XtensaConfig *config, +        uint64_t opt) +{ +    return (config->options & opt) != 0; +} + +static inline bool xtensa_option_enabled(const XtensaConfig *config, int opt) +{ +    return xtensa_option_bits_enabled(config, XTENSA_OPTION_BIT(opt)); +} + +static inline int xtensa_get_cintlevel(const CPUXtensaState *env) +{ +    int level = (env->sregs[PS] & PS_INTLEVEL) >> PS_INTLEVEL_SHIFT; +    if ((env->sregs[PS] & PS_EXCM) && env->config->excm_level > level) { +        level = env->config->excm_level; +    } +    return level; +} + +static inline int xtensa_get_ring(const CPUXtensaState *env) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT; +    } else { +        return 0; +    } +} + +static inline int xtensa_get_cring(const CPUXtensaState *env) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) && +            (env->sregs[PS] & PS_EXCM) == 0) { +        return (env->sregs[PS] & PS_RING) >> PS_RING_SHIFT; +    } else { +        return 0; +    } +} + +static inline xtensa_tlb_entry *xtensa_tlb_get_entry(CPUXtensaState *env, +        bool dtlb, unsigned wi, unsigned ei) +{ +    return dtlb ? +        env->dtlb[wi] + ei : +        env->itlb[wi] + ei; +} + +static inline uint32_t xtensa_replicate_windowstart(CPUXtensaState *env) +{ +    return env->sregs[WINDOW_START] | +        (env->sregs[WINDOW_START] << env->config->nareg / 4); +} + +/* MMU modes definitions */ +#define MMU_MODE0_SUFFIX _ring0 +#define MMU_MODE1_SUFFIX _ring1 +#define MMU_MODE2_SUFFIX _ring2 +#define MMU_MODE3_SUFFIX _ring3 + +static inline int cpu_mmu_index(CPUXtensaState *env) +{ +    return xtensa_get_cring(env); +} + +#define XTENSA_TBFLAG_RING_MASK 0x3 +#define XTENSA_TBFLAG_EXCM 0x4 +#define XTENSA_TBFLAG_LITBASE 0x8 +#define XTENSA_TBFLAG_DEBUG 0x10 +#define XTENSA_TBFLAG_ICOUNT 0x20 +#define XTENSA_TBFLAG_CPENABLE_MASK 0x3fc0 +#define XTENSA_TBFLAG_CPENABLE_SHIFT 6 +#define XTENSA_TBFLAG_EXCEPTION 0x4000 +#define XTENSA_TBFLAG_WINDOW_MASK 0x18000 +#define XTENSA_TBFLAG_WINDOW_SHIFT 15 + +static inline void cpu_get_tb_cpu_state(CPUXtensaState *env, target_ulong *pc, +        target_ulong *cs_base, int *flags) +{ +    CPUState *cs = CPU(xtensa_env_get_cpu(env)); + +    *pc = env->pc; +    *cs_base = 0; +    *flags = 0; +    *flags |= xtensa_get_ring(env); +    if (env->sregs[PS] & PS_EXCM) { +        *flags |= XTENSA_TBFLAG_EXCM; +    } +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_EXTENDED_L32R) && +            (env->sregs[LITBASE] & 1)) { +        *flags |= XTENSA_TBFLAG_LITBASE; +    } +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_DEBUG)) { +        if (xtensa_get_cintlevel(env) < env->config->debug_level) { +            *flags |= XTENSA_TBFLAG_DEBUG; +        } +        if (xtensa_get_cintlevel(env) < env->sregs[ICOUNTLEVEL]) { +            *flags |= XTENSA_TBFLAG_ICOUNT; +        } +    } +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_COPROCESSOR)) { +        *flags |= env->sregs[CPENABLE] << XTENSA_TBFLAG_CPENABLE_SHIFT; +    } +    if (cs->singlestep_enabled && env->exception_taken) { +        *flags |= XTENSA_TBFLAG_EXCEPTION; +    } +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_WINDOWED_REGISTER) && +        (env->sregs[PS] & (PS_WOE | PS_EXCM)) == PS_WOE) { +        uint32_t windowstart = xtensa_replicate_windowstart(env) >> +            (env->sregs[WINDOW_BASE] + 1); +        uint32_t w = ctz32(windowstart | 0x8); + +        *flags |= w << XTENSA_TBFLAG_WINDOW_SHIFT; +    } else { +        *flags |= 3 << XTENSA_TBFLAG_WINDOW_SHIFT; +    } +} + +#include "exec/cpu-all.h" +#include "exec/exec-all.h" + +#endif diff --git a/target-xtensa/gdbstub.c b/target-xtensa/gdbstub.c new file mode 100644 index 00000000..bc2e1b55 --- /dev/null +++ b/target-xtensa/gdbstub.c @@ -0,0 +1,126 @@ +/* + * Xtensa gdb server stub + * + * Copyright (c) 2003-2005 Fabrice Bellard + * Copyright (c) 2013 SUSE LINUX Products GmbH + * + * 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 "config.h" +#include "qemu-common.h" +#include "exec/gdbstub.h" + +int xtensa_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; +    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; +    unsigned i; + +    if (n < 0 || n >= env->config->gdb_regmap.num_regs) { +        return 0; +    } + +    switch (reg->type) { +    case 9: /*pc*/ +        return gdb_get_reg32(mem_buf, env->pc); + +    case 1: /*ar*/ +        xtensa_sync_phys_from_window(env); +        return gdb_get_reg32(mem_buf, env->phys_regs[(reg->targno & 0xff) +                                                     % env->config->nareg]); + +    case 2: /*SR*/ +        return gdb_get_reg32(mem_buf, env->sregs[reg->targno & 0xff]); + +    case 3: /*UR*/ +        return gdb_get_reg32(mem_buf, env->uregs[reg->targno & 0xff]); + +    case 4: /*f*/ +        i = reg->targno & 0x0f; +        switch (reg->size) { +        case 4: +            return gdb_get_reg32(mem_buf, +                                 float32_val(env->fregs[i].f32[FP_F32_LOW])); +        case 8: +            return gdb_get_reg64(mem_buf, float64_val(env->fregs[i].f64)); +        default: +            return 0; +        } + +    case 8: /*a*/ +        return gdb_get_reg32(mem_buf, env->regs[reg->targno & 0x0f]); + +    default: +        qemu_log("%s from reg %d of unsupported type %d\n", +                 __func__, n, reg->type); +        return 0; +    } +} + +int xtensa_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; +    uint32_t tmp; +    const XtensaGdbReg *reg = env->config->gdb_regmap.reg + n; + +    if (n < 0 || n >= env->config->gdb_regmap.num_regs) { +        return 0; +    } + +    tmp = ldl_p(mem_buf); + +    switch (reg->type) { +    case 9: /*pc*/ +        env->pc = tmp; +        break; + +    case 1: /*ar*/ +        env->phys_regs[(reg->targno & 0xff) % env->config->nareg] = tmp; +        xtensa_sync_window_from_phys(env); +        break; + +    case 2: /*SR*/ +        env->sregs[reg->targno & 0xff] = tmp; +        break; + +    case 3: /*UR*/ +        env->uregs[reg->targno & 0xff] = tmp; +        break; + +    case 4: /*f*/ +        switch (reg->size) { +        case 4: +            env->fregs[reg->targno & 0x0f].f32[FP_F32_LOW] = make_float32(tmp); +            return 4; +        case 8: +            env->fregs[reg->targno & 0x0f].f64 = make_float64(tmp); +            return 8; +        default: +            return 0; +        } + +    case 8: /*a*/ +        env->regs[reg->targno & 0x0f] = tmp; +        break; + +    default: +        qemu_log("%s to reg %d of unsupported type %d\n", +                 __func__, n, reg->type); +        return 0; +    } + +    return 4; +} diff --git a/target-xtensa/helper.c b/target-xtensa/helper.c new file mode 100644 index 00000000..76be50d0 --- /dev/null +++ b/target-xtensa/helper.c @@ -0,0 +1,729 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/gdbstub.h" +#include "qemu/host-utils.h" +#if !defined(CONFIG_USER_ONLY) +#include "hw/loader.h" +#endif + +static struct XtensaConfigList *xtensa_cores; + +static void xtensa_core_class_init(ObjectClass *oc, void *data) +{ +    CPUClass *cc = CPU_CLASS(oc); +    XtensaCPUClass *xcc = XTENSA_CPU_CLASS(oc); +    const XtensaConfig *config = data; + +    xcc->config = config; + +    /* Use num_core_regs to see only non-privileged registers in an unmodified +     * gdb. Use num_regs to see all registers. gdb modification is required +     * for that: reset bit 0 in the 'flags' field of the registers definitions +     * in the gdb/xtensa-config.c inside gdb source tree or inside gdb overlay. +     */ +    cc->gdb_num_core_regs = config->gdb_regmap.num_regs; +} + +void xtensa_finalize_config(XtensaConfig *config) +{ +    unsigned i, n = 0; + +    if (config->gdb_regmap.num_regs) { +        return; +    } + +    for (i = 0; config->gdb_regmap.reg[i].targno >= 0; ++i) { +        n += (config->gdb_regmap.reg[i].type != 6); +    } +    config->gdb_regmap.num_regs = n; +} + +void xtensa_register_core(XtensaConfigList *node) +{ +    TypeInfo type = { +        .parent = TYPE_XTENSA_CPU, +        .class_init = xtensa_core_class_init, +        .class_data = (void *)node->config, +    }; + +    node->next = xtensa_cores; +    xtensa_cores = node; +    type.name = g_strdup_printf("%s-" TYPE_XTENSA_CPU, node->config->name); +    type_register(&type); +    g_free((gpointer)type.name); +} + +static uint32_t check_hw_breakpoints(CPUXtensaState *env) +{ +    unsigned i; + +    for (i = 0; i < env->config->ndbreak; ++i) { +        if (env->cpu_watchpoint[i] && +                env->cpu_watchpoint[i]->flags & BP_WATCHPOINT_HIT) { +            return DEBUGCAUSE_DB | (i << DEBUGCAUSE_DBNUM_SHIFT); +        } +    } +    return 0; +} + +void xtensa_breakpoint_handler(CPUState *cs) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; + +    if (cs->watchpoint_hit) { +        if (cs->watchpoint_hit->flags & BP_CPU) { +            uint32_t cause; + +            cs->watchpoint_hit = NULL; +            cause = check_hw_breakpoints(env); +            if (cause) { +                debug_exception_env(env, cause); +            } +            cpu_resume_from_signal(cs, NULL); +        } +    } +} + +XtensaCPU *cpu_xtensa_init(const char *cpu_model) +{ +    ObjectClass *oc; +    XtensaCPU *cpu; +    CPUXtensaState *env; + +    oc = cpu_class_by_name(TYPE_XTENSA_CPU, cpu_model); +    if (oc == NULL) { +        return NULL; +    } + +    cpu = XTENSA_CPU(object_new(object_class_get_name(oc))); +    env = &cpu->env; + +    xtensa_irq_init(env); + +    object_property_set_bool(OBJECT(cpu), true, "realized", NULL); + +    return cpu; +} + + +void xtensa_cpu_list(FILE *f, fprintf_function cpu_fprintf) +{ +    XtensaConfigList *core = xtensa_cores; +    cpu_fprintf(f, "Available CPUs:\n"); +    for (; core; core = core->next) { +        cpu_fprintf(f, "  %s\n", core->config->name); +    } +} + +hwaddr xtensa_cpu_get_phys_page_debug(CPUState *cs, vaddr addr) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    uint32_t paddr; +    uint32_t page_size; +    unsigned access; + +    if (xtensa_get_physical_addr(&cpu->env, false, addr, 0, 0, +                &paddr, &page_size, &access) == 0) { +        return paddr; +    } +    if (xtensa_get_physical_addr(&cpu->env, false, addr, 2, 0, +                &paddr, &page_size, &access) == 0) { +        return paddr; +    } +    return ~0; +} + +static uint32_t relocated_vector(CPUXtensaState *env, uint32_t vector) +{ +    if (xtensa_option_enabled(env->config, +                XTENSA_OPTION_RELOCATABLE_VECTOR)) { +        return vector - env->config->vecbase + env->sregs[VECBASE]; +    } else { +        return vector; +    } +} + +/*! + * Handle penging IRQ. + * For the high priority interrupt jump to the corresponding interrupt vector. + * For the level-1 interrupt convert it to either user, kernel or double + * exception with the 'level-1 interrupt' exception cause. + */ +static void handle_interrupt(CPUXtensaState *env) +{ +    int level = env->pending_irq_level; + +    if (level > xtensa_get_cintlevel(env) && +            level <= env->config->nlevel && +            (env->config->level_mask[level] & +             env->sregs[INTSET] & +             env->sregs[INTENABLE])) { +        CPUState *cs = CPU(xtensa_env_get_cpu(env)); + +        if (level > 1) { +            env->sregs[EPC1 + level - 1] = env->pc; +            env->sregs[EPS2 + level - 2] = env->sregs[PS]; +            env->sregs[PS] = +                (env->sregs[PS] & ~PS_INTLEVEL) | level | PS_EXCM; +            env->pc = relocated_vector(env, +                    env->config->interrupt_vector[level]); +        } else { +            env->sregs[EXCCAUSE] = LEVEL1_INTERRUPT_CAUSE; + +            if (env->sregs[PS] & PS_EXCM) { +                if (env->config->ndepc) { +                    env->sregs[DEPC] = env->pc; +                } else { +                    env->sregs[EPC1] = env->pc; +                } +                cs->exception_index = EXC_DOUBLE; +            } else { +                env->sregs[EPC1] = env->pc; +                cs->exception_index = +                    (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL; +            } +            env->sregs[PS] |= PS_EXCM; +        } +        env->exception_taken = 1; +    } +} + +void xtensa_cpu_do_interrupt(CPUState *cs) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; + +    if (cs->exception_index == EXC_IRQ) { +        qemu_log_mask(CPU_LOG_INT, +                "%s(EXC_IRQ) level = %d, cintlevel = %d, " +                "pc = %08x, a0 = %08x, ps = %08x, " +                "intset = %08x, intenable = %08x, " +                "ccount = %08x\n", +                __func__, env->pending_irq_level, xtensa_get_cintlevel(env), +                env->pc, env->regs[0], env->sregs[PS], +                env->sregs[INTSET], env->sregs[INTENABLE], +                env->sregs[CCOUNT]); +        handle_interrupt(env); +    } + +    switch (cs->exception_index) { +    case EXC_WINDOW_OVERFLOW4: +    case EXC_WINDOW_UNDERFLOW4: +    case EXC_WINDOW_OVERFLOW8: +    case EXC_WINDOW_UNDERFLOW8: +    case EXC_WINDOW_OVERFLOW12: +    case EXC_WINDOW_UNDERFLOW12: +    case EXC_KERNEL: +    case EXC_USER: +    case EXC_DOUBLE: +    case EXC_DEBUG: +        qemu_log_mask(CPU_LOG_INT, "%s(%d) " +                "pc = %08x, a0 = %08x, ps = %08x, ccount = %08x\n", +                __func__, cs->exception_index, +                env->pc, env->regs[0], env->sregs[PS], env->sregs[CCOUNT]); +        if (env->config->exception_vector[cs->exception_index]) { +            env->pc = relocated_vector(env, +                    env->config->exception_vector[cs->exception_index]); +            env->exception_taken = 1; +        } else { +            qemu_log("%s(pc = %08x) bad exception_index: %d\n", +                    __func__, env->pc, cs->exception_index); +        } +        break; + +    case EXC_IRQ: +        break; + +    default: +        qemu_log("%s(pc = %08x) unknown exception_index: %d\n", +                __func__, env->pc, cs->exception_index); +        break; +    } +    check_interrupts(env); +} + +bool xtensa_cpu_exec_interrupt(CPUState *cs, int interrupt_request) +{ +    if (interrupt_request & CPU_INTERRUPT_HARD) { +        cs->exception_index = EXC_IRQ; +        xtensa_cpu_do_interrupt(cs); +        return true; +    } +    return false; +} + +static void reset_tlb_mmu_all_ways(CPUXtensaState *env, +        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) +{ +    unsigned wi, ei; + +    for (wi = 0; wi < tlb->nways; ++wi) { +        for (ei = 0; ei < tlb->way_size[wi]; ++ei) { +            entry[wi][ei].asid = 0; +            entry[wi][ei].variable = true; +        } +    } +} + +static void reset_tlb_mmu_ways56(CPUXtensaState *env, +        const xtensa_tlb *tlb, xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) +{ +    if (!tlb->varway56) { +        static const xtensa_tlb_entry way5[] = { +            { +                .vaddr = 0xd0000000, +                .paddr = 0, +                .asid = 1, +                .attr = 7, +                .variable = false, +            }, { +                .vaddr = 0xd8000000, +                .paddr = 0, +                .asid = 1, +                .attr = 3, +                .variable = false, +            } +        }; +        static const xtensa_tlb_entry way6[] = { +            { +                .vaddr = 0xe0000000, +                .paddr = 0xf0000000, +                .asid = 1, +                .attr = 7, +                .variable = false, +            }, { +                .vaddr = 0xf0000000, +                .paddr = 0xf0000000, +                .asid = 1, +                .attr = 3, +                .variable = false, +            } +        }; +        memcpy(entry[5], way5, sizeof(way5)); +        memcpy(entry[6], way6, sizeof(way6)); +    } else { +        uint32_t ei; +        for (ei = 0; ei < 8; ++ei) { +            entry[6][ei].vaddr = ei << 29; +            entry[6][ei].paddr = ei << 29; +            entry[6][ei].asid = 1; +            entry[6][ei].attr = 3; +        } +    } +} + +static void reset_tlb_region_way0(CPUXtensaState *env, +        xtensa_tlb_entry entry[][MAX_TLB_WAY_SIZE]) +{ +    unsigned ei; + +    for (ei = 0; ei < 8; ++ei) { +        entry[0][ei].vaddr = ei << 29; +        entry[0][ei].paddr = ei << 29; +        entry[0][ei].asid = 1; +        entry[0][ei].attr = 2; +        entry[0][ei].variable = true; +    } +} + +void reset_mmu(CPUXtensaState *env) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        env->sregs[RASID] = 0x04030201; +        env->sregs[ITLBCFG] = 0; +        env->sregs[DTLBCFG] = 0; +        env->autorefill_idx = 0; +        reset_tlb_mmu_all_ways(env, &env->config->itlb, env->itlb); +        reset_tlb_mmu_all_ways(env, &env->config->dtlb, env->dtlb); +        reset_tlb_mmu_ways56(env, &env->config->itlb, env->itlb); +        reset_tlb_mmu_ways56(env, &env->config->dtlb, env->dtlb); +    } else { +        reset_tlb_region_way0(env, env->itlb); +        reset_tlb_region_way0(env, env->dtlb); +    } +} + +static unsigned get_ring(const CPUXtensaState *env, uint8_t asid) +{ +    unsigned i; +    for (i = 0; i < 4; ++i) { +        if (((env->sregs[RASID] >> i * 8) & 0xff) == asid) { +            return i; +        } +    } +    return 0xff; +} + +/*! + * Lookup xtensa TLB for the given virtual address. + * See ISA, 4.6.2.2 + * + * \param pwi: [out] way index + * \param pei: [out] entry index + * \param pring: [out] access ring + * \return 0 if ok, exception cause code otherwise + */ +int xtensa_tlb_lookup(const CPUXtensaState *env, uint32_t addr, bool dtlb, +        uint32_t *pwi, uint32_t *pei, uint8_t *pring) +{ +    const xtensa_tlb *tlb = dtlb ? +        &env->config->dtlb : &env->config->itlb; +    const xtensa_tlb_entry (*entry)[MAX_TLB_WAY_SIZE] = dtlb ? +        env->dtlb : env->itlb; + +    int nhits = 0; +    unsigned wi; + +    for (wi = 0; wi < tlb->nways; ++wi) { +        uint32_t vpn; +        uint32_t ei; +        split_tlb_entry_spec_way(env, addr, dtlb, &vpn, wi, &ei); +        if (entry[wi][ei].vaddr == vpn && entry[wi][ei].asid) { +            unsigned ring = get_ring(env, entry[wi][ei].asid); +            if (ring < 4) { +                if (++nhits > 1) { +                    return dtlb ? +                        LOAD_STORE_TLB_MULTI_HIT_CAUSE : +                        INST_TLB_MULTI_HIT_CAUSE; +                } +                *pwi = wi; +                *pei = ei; +                *pring = ring; +            } +        } +    } +    return nhits ? 0 : +        (dtlb ? LOAD_STORE_TLB_MISS_CAUSE : INST_TLB_MISS_CAUSE); +} + +/*! + * Convert MMU ATTR to PAGE_{READ,WRITE,EXEC} mask. + * See ISA, 4.6.5.10 + */ +static unsigned mmu_attr_to_access(uint32_t attr) +{ +    unsigned access = 0; + +    if (attr < 12) { +        access |= PAGE_READ; +        if (attr & 0x1) { +            access |= PAGE_EXEC; +        } +        if (attr & 0x2) { +            access |= PAGE_WRITE; +        } + +        switch (attr & 0xc) { +        case 0: +            access |= PAGE_CACHE_BYPASS; +            break; + +        case 4: +            access |= PAGE_CACHE_WB; +            break; + +        case 8: +            access |= PAGE_CACHE_WT; +            break; +        } +    } else if (attr == 13) { +        access |= PAGE_READ | PAGE_WRITE | PAGE_CACHE_ISOLATE; +    } +    return access; +} + +/*! + * Convert region protection ATTR to PAGE_{READ,WRITE,EXEC} mask. + * See ISA, 4.6.3.3 + */ +static unsigned region_attr_to_access(uint32_t attr) +{ +    static const unsigned access[16] = { +         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT, +         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT, +         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS, +         [3] =                          PAGE_EXEC | PAGE_CACHE_WB, +         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, +         [5] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, +        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE, +    }; + +    return access[attr & 0xf]; +} + +/*! + * Convert cacheattr to PAGE_{READ,WRITE,EXEC} mask. + * See ISA, A.2.14 The Cache Attribute Register + */ +static unsigned cacheattr_attr_to_access(uint32_t attr) +{ +    static const unsigned access[16] = { +         [0] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_WT, +         [1] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WT, +         [2] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_BYPASS, +         [3] =                          PAGE_EXEC | PAGE_CACHE_WB, +         [4] = PAGE_READ | PAGE_WRITE | PAGE_EXEC | PAGE_CACHE_WB, +        [14] = PAGE_READ | PAGE_WRITE             | PAGE_CACHE_ISOLATE, +    }; + +    return access[attr & 0xf]; +} + +static bool is_access_granted(unsigned access, int is_write) +{ +    switch (is_write) { +    case 0: +        return access & PAGE_READ; + +    case 1: +        return access & PAGE_WRITE; + +    case 2: +        return access & PAGE_EXEC; + +    default: +        return 0; +    } +} + +static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte); + +static int get_physical_addr_mmu(CPUXtensaState *env, bool update_tlb, +        uint32_t vaddr, int is_write, int mmu_idx, +        uint32_t *paddr, uint32_t *page_size, unsigned *access, +        bool may_lookup_pt) +{ +    bool dtlb = is_write != 2; +    uint32_t wi; +    uint32_t ei; +    uint8_t ring; +    uint32_t vpn; +    uint32_t pte; +    const xtensa_tlb_entry *entry = NULL; +    xtensa_tlb_entry tmp_entry; +    int ret = xtensa_tlb_lookup(env, vaddr, dtlb, &wi, &ei, &ring); + +    if ((ret == INST_TLB_MISS_CAUSE || ret == LOAD_STORE_TLB_MISS_CAUSE) && +            may_lookup_pt && get_pte(env, vaddr, &pte) == 0) { +        ring = (pte >> 4) & 0x3; +        wi = 0; +        split_tlb_entry_spec_way(env, vaddr, dtlb, &vpn, wi, &ei); + +        if (update_tlb) { +            wi = ++env->autorefill_idx & 0x3; +            xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, pte); +            env->sregs[EXCVADDR] = vaddr; +            qemu_log("%s: autorefill(%08x): %08x -> %08x\n", +                    __func__, vaddr, vpn, pte); +        } else { +            xtensa_tlb_set_entry_mmu(env, &tmp_entry, dtlb, wi, ei, vpn, pte); +            entry = &tmp_entry; +        } +        ret = 0; +    } +    if (ret != 0) { +        return ret; +    } + +    if (entry == NULL) { +        entry = xtensa_tlb_get_entry(env, dtlb, wi, ei); +    } + +    if (ring < mmu_idx) { +        return dtlb ? +            LOAD_STORE_PRIVILEGE_CAUSE : +            INST_FETCH_PRIVILEGE_CAUSE; +    } + +    *access = mmu_attr_to_access(entry->attr) & +        ~(dtlb ? PAGE_EXEC : PAGE_READ | PAGE_WRITE); +    if (!is_access_granted(*access, is_write)) { +        return dtlb ? +            (is_write ? +             STORE_PROHIBITED_CAUSE : +             LOAD_PROHIBITED_CAUSE) : +            INST_FETCH_PROHIBITED_CAUSE; +    } + +    *paddr = entry->paddr | (vaddr & ~xtensa_tlb_get_addr_mask(env, dtlb, wi)); +    *page_size = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1; + +    return 0; +} + +static int get_pte(CPUXtensaState *env, uint32_t vaddr, uint32_t *pte) +{ +    CPUState *cs = CPU(xtensa_env_get_cpu(env)); +    uint32_t paddr; +    uint32_t page_size; +    unsigned access; +    uint32_t pt_vaddr = +        (env->sregs[PTEVADDR] | (vaddr >> 10)) & 0xfffffffc; +    int ret = get_physical_addr_mmu(env, false, pt_vaddr, 0, 0, +            &paddr, &page_size, &access, false); + +    qemu_log("%s: trying autorefill(%08x) -> %08x\n", __func__, +            vaddr, ret ? ~0 : paddr); + +    if (ret == 0) { +        *pte = ldl_phys(cs->as, paddr); +    } +    return ret; +} + +static int get_physical_addr_region(CPUXtensaState *env, +        uint32_t vaddr, int is_write, int mmu_idx, +        uint32_t *paddr, uint32_t *page_size, unsigned *access) +{ +    bool dtlb = is_write != 2; +    uint32_t wi = 0; +    uint32_t ei = (vaddr >> 29) & 0x7; +    const xtensa_tlb_entry *entry = +        xtensa_tlb_get_entry(env, dtlb, wi, ei); + +    *access = region_attr_to_access(entry->attr); +    if (!is_access_granted(*access, is_write)) { +        return dtlb ? +            (is_write ? +             STORE_PROHIBITED_CAUSE : +             LOAD_PROHIBITED_CAUSE) : +            INST_FETCH_PROHIBITED_CAUSE; +    } + +    *paddr = entry->paddr | (vaddr & ~REGION_PAGE_MASK); +    *page_size = ~REGION_PAGE_MASK + 1; + +    return 0; +} + +/*! + * Convert virtual address to physical addr. + * MMU may issue pagewalk and change xtensa autorefill TLB way entry. + * + * \return 0 if ok, exception cause code otherwise + */ +int xtensa_get_physical_addr(CPUXtensaState *env, bool update_tlb, +        uint32_t vaddr, int is_write, int mmu_idx, +        uint32_t *paddr, uint32_t *page_size, unsigned *access) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        return get_physical_addr_mmu(env, update_tlb, +                vaddr, is_write, mmu_idx, paddr, page_size, access, true); +    } else if (xtensa_option_bits_enabled(env->config, +                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | +                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION))) { +        return get_physical_addr_region(env, vaddr, is_write, mmu_idx, +                paddr, page_size, access); +    } else { +        *paddr = vaddr; +        *page_size = TARGET_PAGE_SIZE; +        *access = cacheattr_attr_to_access( +                env->sregs[CACHEATTR] >> ((vaddr & 0xe0000000) >> 27)); +        return 0; +    } +} + +static void dump_tlb(FILE *f, fprintf_function cpu_fprintf, +        CPUXtensaState *env, bool dtlb) +{ +    unsigned wi, ei; +    const xtensa_tlb *conf = +        dtlb ? &env->config->dtlb : &env->config->itlb; +    unsigned (*attr_to_access)(uint32_t) = +        xtensa_option_enabled(env->config, XTENSA_OPTION_MMU) ? +        mmu_attr_to_access : region_attr_to_access; + +    for (wi = 0; wi < conf->nways; ++wi) { +        uint32_t sz = ~xtensa_tlb_get_addr_mask(env, dtlb, wi) + 1; +        const char *sz_text; +        bool print_header = true; + +        if (sz >= 0x100000) { +            sz >>= 20; +            sz_text = "MB"; +        } else { +            sz >>= 10; +            sz_text = "KB"; +        } + +        for (ei = 0; ei < conf->way_size[wi]; ++ei) { +            const xtensa_tlb_entry *entry = +                xtensa_tlb_get_entry(env, dtlb, wi, ei); + +            if (entry->asid) { +                static const char * const cache_text[8] = { +                    [PAGE_CACHE_BYPASS >> PAGE_CACHE_SHIFT] = "Bypass", +                    [PAGE_CACHE_WT >> PAGE_CACHE_SHIFT] = "WT", +                    [PAGE_CACHE_WB >> PAGE_CACHE_SHIFT] = "WB", +                    [PAGE_CACHE_ISOLATE >> PAGE_CACHE_SHIFT] = "Isolate", +                }; +                unsigned access = attr_to_access(entry->attr); +                unsigned cache_idx = (access & PAGE_CACHE_MASK) >> +                    PAGE_CACHE_SHIFT; + +                if (print_header) { +                    print_header = false; +                    cpu_fprintf(f, "Way %u (%d %s)\n", wi, sz, sz_text); +                    cpu_fprintf(f, +                            "\tVaddr       Paddr       ASID  Attr RWX Cache\n" +                            "\t----------  ----------  ----  ---- --- -------\n"); +                } +                cpu_fprintf(f, +                        "\t0x%08x  0x%08x  0x%02x  0x%02x %c%c%c %-7s\n", +                        entry->vaddr, +                        entry->paddr, +                        entry->asid, +                        entry->attr, +                        (access & PAGE_READ) ? 'R' : '-', +                        (access & PAGE_WRITE) ? 'W' : '-', +                        (access & PAGE_EXEC) ? 'X' : '-', +                        cache_text[cache_idx] ? cache_text[cache_idx] : +                            "Invalid"); +            } +        } +    } +} + +void dump_mmu(FILE *f, fprintf_function cpu_fprintf, CPUXtensaState *env) +{ +    if (xtensa_option_bits_enabled(env->config, +                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | +                XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION) | +                XTENSA_OPTION_BIT(XTENSA_OPTION_MMU))) { + +        cpu_fprintf(f, "ITLB:\n"); +        dump_tlb(f, cpu_fprintf, env, false); +        cpu_fprintf(f, "\nDTLB:\n"); +        dump_tlb(f, cpu_fprintf, env, true); +    } else { +        cpu_fprintf(f, "No TLB for this CPU core\n"); +    } +} diff --git a/target-xtensa/helper.h b/target-xtensa/helper.h new file mode 100644 index 00000000..5ea9c5be --- /dev/null +++ b/target-xtensa/helper.h @@ -0,0 +1,58 @@ +DEF_HELPER_2(exception, noreturn, env, i32) +DEF_HELPER_3(exception_cause, noreturn, env, i32, i32) +DEF_HELPER_4(exception_cause_vaddr, noreturn, env, i32, i32, i32) +DEF_HELPER_3(debug_exception, noreturn, env, i32, i32) + +DEF_HELPER_FLAGS_1(nsa, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_FLAGS_1(nsau, TCG_CALL_NO_RWG_SE, i32, i32) +DEF_HELPER_2(wsr_windowbase, void, env, i32) +DEF_HELPER_4(entry, void, env, i32, i32, i32) +DEF_HELPER_2(retw, i32, env, i32) +DEF_HELPER_2(rotw, void, env, i32) +DEF_HELPER_3(window_check, noreturn, env, i32, i32) +DEF_HELPER_1(restore_owb, void, env) +DEF_HELPER_2(movsp, void, env, i32) +DEF_HELPER_2(wsr_lbeg, void, env, i32) +DEF_HELPER_2(wsr_lend, void, env, i32) +DEF_HELPER_1(simcall, void, env) +DEF_HELPER_1(dump_state, void, env) + +DEF_HELPER_3(waiti, void, env, i32, i32) +DEF_HELPER_3(timer_irq, void, env, i32, i32) +DEF_HELPER_2(advance_ccount, void, env, i32) +DEF_HELPER_1(check_interrupts, void, env) +DEF_HELPER_3(check_atomctl, void, env, i32, i32) + +DEF_HELPER_2(itlb_hit_test, void, env, i32) +DEF_HELPER_2(wsr_rasid, void, env, i32) +DEF_HELPER_FLAGS_3(rtlb0, TCG_CALL_NO_RWG_SE, i32, env, i32, i32) +DEF_HELPER_FLAGS_3(rtlb1, TCG_CALL_NO_RWG_SE, i32, env, i32, i32) +DEF_HELPER_3(itlb, void, env, i32, i32) +DEF_HELPER_3(ptlb, i32, env, i32, i32) +DEF_HELPER_4(wtlb, void, env, i32, i32, i32) + +DEF_HELPER_2(wsr_ibreakenable, void, env, i32) +DEF_HELPER_3(wsr_ibreaka, void, env, i32, i32) +DEF_HELPER_3(wsr_dbreaka, void, env, i32, i32) +DEF_HELPER_3(wsr_dbreakc, void, env, i32, i32) + +DEF_HELPER_2(wur_fcr, void, env, i32) +DEF_HELPER_FLAGS_1(abs_s, TCG_CALL_NO_RWG_SE, f32, f32) +DEF_HELPER_FLAGS_1(neg_s, TCG_CALL_NO_RWG_SE, f32, f32) +DEF_HELPER_3(add_s, f32, env, f32, f32) +DEF_HELPER_3(sub_s, f32, env, f32, f32) +DEF_HELPER_3(mul_s, f32, env, f32, f32) +DEF_HELPER_4(madd_s, f32, env, f32, f32, f32) +DEF_HELPER_4(msub_s, f32, env, f32, f32, f32) +DEF_HELPER_FLAGS_3(ftoi, TCG_CALL_NO_RWG_SE, i32, f32, i32, i32) +DEF_HELPER_FLAGS_3(ftoui, TCG_CALL_NO_RWG_SE, i32, f32, i32, i32) +DEF_HELPER_3(itof, f32, env, i32, i32) +DEF_HELPER_3(uitof, f32, env, i32, i32) + +DEF_HELPER_4(un_s, void, env, i32, f32, f32) +DEF_HELPER_4(oeq_s, void, env, i32, f32, f32) +DEF_HELPER_4(ueq_s, void, env, i32, f32, f32) +DEF_HELPER_4(olt_s, void, env, i32, f32, f32) +DEF_HELPER_4(ult_s, void, env, i32, f32, f32) +DEF_HELPER_4(ole_s, void, env, i32, f32, f32) +DEF_HELPER_4(ule_s, void, env, i32, f32, f32) diff --git a/target-xtensa/import_core.sh b/target-xtensa/import_core.sh new file mode 100755 index 00000000..351bee41 --- /dev/null +++ b/target-xtensa/import_core.sh @@ -0,0 +1,51 @@ +#! /bin/bash -e + +OVERLAY="$1" +NAME="$2" +FREQ=40000 +BASE=$(dirname "$0") +TARGET="$BASE"/core-$NAME + +[ $# -ge 2 -a -f "$OVERLAY" ] || { cat <<EOF +Usage: $0 overlay-archive-to-import core-name [frequency-in-KHz] +    overlay-archive-to-import:  file name of xtensa-config-overlay.tar.gz +                                to import configuration from. +    core-name:                  QEMU name of the imported core. Must be valid +                                C identifier. +    frequency-in-KHz:           core frequency (40MHz if not specified). +EOF +exit +} + +[ $# -ge 3 ] && FREQ="$3" +mkdir -p "$TARGET" +tar -xf "$OVERLAY" -C "$TARGET" --strip-components=1 \ +    --xform='s/core/core-isa/' config/core.h +tar -xf "$OVERLAY" -O gdb/xtensa-config.c | \ +    sed -n '1,/*\//p;/XTREG/,/XTREG_END/p' > "$TARGET"/gdb-config.c + +cat <<EOF > "${TARGET}.c" +#include "cpu.h" +#include "exec/exec-all.h" +#include "exec/gdbstub.h" +#include "qemu/host-utils.h" + +#include "core-$NAME/core-isa.h" +#include "overlay_tool.h" + +static XtensaConfig $NAME __attribute__((unused)) = { +    .name = "$NAME", +    .gdb_regmap = { +        .reg = { +#include "core-$NAME/gdb-config.c" +        } +    }, +    .clock_freq_khz = $FREQ, +    DEFAULT_SECTIONS +}; + +REGISTER_CORE($NAME) +EOF + +grep -q core-${NAME}.o "$BASE"/Makefile.objs || \ +    echo "obj-y += core-${NAME}.o" >> "$BASE"/Makefile.objs diff --git a/target-xtensa/op_helper.c b/target-xtensa/op_helper.c new file mode 100644 index 00000000..be657e61 --- /dev/null +++ b/target-xtensa/op_helper.c @@ -0,0 +1,981 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "cpu.h" +#include "exec/helper-proto.h" +#include "qemu/host-utils.h" +#include "exec/cpu_ldst.h" +#include "exec/address-spaces.h" +#include "qemu/timer.h" + +void xtensa_cpu_do_unaligned_access(CPUState *cs, +        vaddr addr, int is_write, int is_user, uintptr_t retaddr) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; + +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_UNALIGNED_EXCEPTION) && +            !xtensa_option_enabled(env->config, XTENSA_OPTION_HW_ALIGNMENT)) { +        cpu_restore_state(CPU(cpu), retaddr); +        HELPER(exception_cause_vaddr)(env, +                env->pc, LOAD_STORE_ALIGNMENT_CAUSE, addr); +    } +} + +void tlb_fill(CPUState *cs, +              target_ulong vaddr, int is_write, int mmu_idx, uintptr_t retaddr) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; +    uint32_t paddr; +    uint32_t page_size; +    unsigned access; +    int ret = xtensa_get_physical_addr(env, true, vaddr, is_write, mmu_idx, +            &paddr, &page_size, &access); + +    qemu_log("%s(%08x, %d, %d) -> %08x, ret = %d\n", __func__, +            vaddr, is_write, mmu_idx, paddr, ret); + +    if (ret == 0) { +        tlb_set_page(cs, +                     vaddr & TARGET_PAGE_MASK, +                     paddr & TARGET_PAGE_MASK, +                     access, mmu_idx, page_size); +    } else { +        cpu_restore_state(cs, retaddr); +        HELPER(exception_cause_vaddr)(env, env->pc, ret, vaddr); +    } +} + +void xtensa_cpu_do_unassigned_access(CPUState *cs, hwaddr addr, +                                     bool is_write, bool is_exec, int opaque, +                                     unsigned size) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; + +    HELPER(exception_cause_vaddr)(env, env->pc, +                                  is_exec ? +                                  INSTR_PIF_ADDR_ERROR_CAUSE : +                                  LOAD_STORE_PIF_ADDR_ERROR_CAUSE, +                                  is_exec ? addr : cs->mem_io_vaddr); +} + +static void tb_invalidate_virtual_addr(CPUXtensaState *env, uint32_t vaddr) +{ +    uint32_t paddr; +    uint32_t page_size; +    unsigned access; +    int ret = xtensa_get_physical_addr(env, false, vaddr, 2, 0, +            &paddr, &page_size, &access); +    if (ret == 0) { +        tb_invalidate_phys_addr(&address_space_memory, paddr); +    } +} + +void HELPER(exception)(CPUXtensaState *env, uint32_t excp) +{ +    CPUState *cs = CPU(xtensa_env_get_cpu(env)); + +    cs->exception_index = excp; +    if (excp == EXCP_DEBUG) { +        env->exception_taken = 0; +    } +    cpu_loop_exit(cs); +} + +void HELPER(exception_cause)(CPUXtensaState *env, uint32_t pc, uint32_t cause) +{ +    uint32_t vector; + +    env->pc = pc; +    if (env->sregs[PS] & PS_EXCM) { +        if (env->config->ndepc) { +            env->sregs[DEPC] = pc; +        } else { +            env->sregs[EPC1] = pc; +        } +        vector = EXC_DOUBLE; +    } else { +        env->sregs[EPC1] = pc; +        vector = (env->sregs[PS] & PS_UM) ? EXC_USER : EXC_KERNEL; +    } + +    env->sregs[EXCCAUSE] = cause; +    env->sregs[PS] |= PS_EXCM; + +    HELPER(exception)(env, vector); +} + +void HELPER(exception_cause_vaddr)(CPUXtensaState *env, +        uint32_t pc, uint32_t cause, uint32_t vaddr) +{ +    env->sregs[EXCVADDR] = vaddr; +    HELPER(exception_cause)(env, pc, cause); +} + +void debug_exception_env(CPUXtensaState *env, uint32_t cause) +{ +    if (xtensa_get_cintlevel(env) < env->config->debug_level) { +        HELPER(debug_exception)(env, env->pc, cause); +    } +} + +void HELPER(debug_exception)(CPUXtensaState *env, uint32_t pc, uint32_t cause) +{ +    unsigned level = env->config->debug_level; + +    env->pc = pc; +    env->sregs[DEBUGCAUSE] = cause; +    env->sregs[EPC1 + level - 1] = pc; +    env->sregs[EPS2 + level - 2] = env->sregs[PS]; +    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | PS_EXCM | +        (level << PS_INTLEVEL_SHIFT); +    HELPER(exception)(env, EXC_DEBUG); +} + +uint32_t HELPER(nsa)(uint32_t v) +{ +    if (v & 0x80000000) { +        v = ~v; +    } +    return v ? clz32(v) - 1 : 31; +} + +uint32_t HELPER(nsau)(uint32_t v) +{ +    return v ? clz32(v) : 32; +} + +static void copy_window_from_phys(CPUXtensaState *env, +        uint32_t window, uint32_t phys, uint32_t n) +{ +    assert(phys < env->config->nareg); +    if (phys + n <= env->config->nareg) { +        memcpy(env->regs + window, env->phys_regs + phys, +                n * sizeof(uint32_t)); +    } else { +        uint32_t n1 = env->config->nareg - phys; +        memcpy(env->regs + window, env->phys_regs + phys, +                n1 * sizeof(uint32_t)); +        memcpy(env->regs + window + n1, env->phys_regs, +                (n - n1) * sizeof(uint32_t)); +    } +} + +static void copy_phys_from_window(CPUXtensaState *env, +        uint32_t phys, uint32_t window, uint32_t n) +{ +    assert(phys < env->config->nareg); +    if (phys + n <= env->config->nareg) { +        memcpy(env->phys_regs + phys, env->regs + window, +                n * sizeof(uint32_t)); +    } else { +        uint32_t n1 = env->config->nareg - phys; +        memcpy(env->phys_regs + phys, env->regs + window, +                n1 * sizeof(uint32_t)); +        memcpy(env->phys_regs, env->regs + window + n1, +                (n - n1) * sizeof(uint32_t)); +    } +} + + +static inline unsigned windowbase_bound(unsigned a, const CPUXtensaState *env) +{ +    return a & (env->config->nareg / 4 - 1); +} + +static inline unsigned windowstart_bit(unsigned a, const CPUXtensaState *env) +{ +    return 1 << windowbase_bound(a, env); +} + +void xtensa_sync_window_from_phys(CPUXtensaState *env) +{ +    copy_window_from_phys(env, 0, env->sregs[WINDOW_BASE] * 4, 16); +} + +void xtensa_sync_phys_from_window(CPUXtensaState *env) +{ +    copy_phys_from_window(env, env->sregs[WINDOW_BASE] * 4, 0, 16); +} + +static void rotate_window_abs(CPUXtensaState *env, uint32_t position) +{ +    xtensa_sync_phys_from_window(env); +    env->sregs[WINDOW_BASE] = windowbase_bound(position, env); +    xtensa_sync_window_from_phys(env); +} + +static void rotate_window(CPUXtensaState *env, uint32_t delta) +{ +    rotate_window_abs(env, env->sregs[WINDOW_BASE] + delta); +} + +void HELPER(wsr_windowbase)(CPUXtensaState *env, uint32_t v) +{ +    rotate_window_abs(env, v); +} + +void HELPER(entry)(CPUXtensaState *env, uint32_t pc, uint32_t s, uint32_t imm) +{ +    int callinc = (env->sregs[PS] & PS_CALLINC) >> PS_CALLINC_SHIFT; +    if (s > 3 || ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) { +        qemu_log("Illegal entry instruction(pc = %08x), PS = %08x\n", +                pc, env->sregs[PS]); +        HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE); +    } else { +        uint32_t windowstart = xtensa_replicate_windowstart(env) >> +            (env->sregs[WINDOW_BASE] + 1); + +        if (windowstart & ((1 << callinc) - 1)) { +            HELPER(window_check)(env, pc, callinc); +        } +        env->regs[(callinc << 2) | (s & 3)] = env->regs[s] - (imm << 3); +        rotate_window(env, callinc); +        env->sregs[WINDOW_START] |= +            windowstart_bit(env->sregs[WINDOW_BASE], env); +    } +} + +void HELPER(window_check)(CPUXtensaState *env, uint32_t pc, uint32_t w) +{ +    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env); +    uint32_t windowstart = xtensa_replicate_windowstart(env) >> +        (env->sregs[WINDOW_BASE] + 1); +    uint32_t n = ctz32(windowstart) + 1; + +    assert(n <= w); + +    rotate_window(env, n); +    env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) | +        (windowbase << PS_OWB_SHIFT) | PS_EXCM; +    env->sregs[EPC1] = env->pc = pc; + +    switch (ctz32(windowstart >> n)) { +    case 0: +        HELPER(exception)(env, EXC_WINDOW_OVERFLOW4); +        break; +    case 1: +        HELPER(exception)(env, EXC_WINDOW_OVERFLOW8); +        break; +    default: +        HELPER(exception)(env, EXC_WINDOW_OVERFLOW12); +        break; +    } +} + +uint32_t HELPER(retw)(CPUXtensaState *env, uint32_t pc) +{ +    int n = (env->regs[0] >> 30) & 0x3; +    int m = 0; +    uint32_t windowbase = windowbase_bound(env->sregs[WINDOW_BASE], env); +    uint32_t windowstart = env->sregs[WINDOW_START]; +    uint32_t ret_pc = 0; + +    if (windowstart & windowstart_bit(windowbase - 1, env)) { +        m = 1; +    } else if (windowstart & windowstart_bit(windowbase - 2, env)) { +        m = 2; +    } else if (windowstart & windowstart_bit(windowbase - 3, env)) { +        m = 3; +    } + +    if (n == 0 || (m != 0 && m != n) || +            ((env->sregs[PS] & (PS_WOE | PS_EXCM)) ^ PS_WOE) != 0) { +        qemu_log("Illegal retw instruction(pc = %08x), " +                "PS = %08x, m = %d, n = %d\n", +                pc, env->sregs[PS], m, n); +        HELPER(exception_cause)(env, pc, ILLEGAL_INSTRUCTION_CAUSE); +    } else { +        int owb = windowbase; + +        ret_pc = (pc & 0xc0000000) | (env->regs[0] & 0x3fffffff); + +        rotate_window(env, -n); +        if (windowstart & windowstart_bit(env->sregs[WINDOW_BASE], env)) { +            env->sregs[WINDOW_START] &= ~windowstart_bit(owb, env); +        } else { +            /* window underflow */ +            env->sregs[PS] = (env->sregs[PS] & ~PS_OWB) | +                (windowbase << PS_OWB_SHIFT) | PS_EXCM; +            env->sregs[EPC1] = env->pc = pc; + +            if (n == 1) { +                HELPER(exception)(env, EXC_WINDOW_UNDERFLOW4); +            } else if (n == 2) { +                HELPER(exception)(env, EXC_WINDOW_UNDERFLOW8); +            } else if (n == 3) { +                HELPER(exception)(env, EXC_WINDOW_UNDERFLOW12); +            } +        } +    } +    return ret_pc; +} + +void HELPER(rotw)(CPUXtensaState *env, uint32_t imm4) +{ +    rotate_window(env, imm4); +} + +void HELPER(restore_owb)(CPUXtensaState *env) +{ +    rotate_window_abs(env, (env->sregs[PS] & PS_OWB) >> PS_OWB_SHIFT); +} + +void HELPER(movsp)(CPUXtensaState *env, uint32_t pc) +{ +    if ((env->sregs[WINDOW_START] & +            (windowstart_bit(env->sregs[WINDOW_BASE] - 3, env) | +             windowstart_bit(env->sregs[WINDOW_BASE] - 2, env) | +             windowstart_bit(env->sregs[WINDOW_BASE] - 1, env))) == 0) { +        HELPER(exception_cause)(env, pc, ALLOCA_CAUSE); +    } +} + +void HELPER(wsr_lbeg)(CPUXtensaState *env, uint32_t v) +{ +    if (env->sregs[LBEG] != v) { +        tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1); +        env->sregs[LBEG] = v; +    } +} + +void HELPER(wsr_lend)(CPUXtensaState *env, uint32_t v) +{ +    if (env->sregs[LEND] != v) { +        tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1); +        env->sregs[LEND] = v; +        tb_invalidate_virtual_addr(env, env->sregs[LEND] - 1); +    } +} + +void HELPER(dump_state)(CPUXtensaState *env) +{ +    XtensaCPU *cpu = xtensa_env_get_cpu(env); + +    cpu_dump_state(CPU(cpu), stderr, fprintf, 0); +} + +void HELPER(waiti)(CPUXtensaState *env, uint32_t pc, uint32_t intlevel) +{ +    CPUState *cpu; + +    env->pc = pc; +    env->sregs[PS] = (env->sregs[PS] & ~PS_INTLEVEL) | +        (intlevel << PS_INTLEVEL_SHIFT); +    check_interrupts(env); +    if (env->pending_irq_level) { +        cpu_loop_exit(CPU(xtensa_env_get_cpu(env))); +        return; +    } + +    cpu = CPU(xtensa_env_get_cpu(env)); +    env->halt_clock = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); +    cpu->halted = 1; +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_TIMER_INTERRUPT)) { +        xtensa_rearm_ccompare_timer(env); +    } +    HELPER(exception)(env, EXCP_HLT); +} + +void HELPER(timer_irq)(CPUXtensaState *env, uint32_t id, uint32_t active) +{ +    xtensa_timer_irq(env, id, active); +} + +void HELPER(advance_ccount)(CPUXtensaState *env, uint32_t d) +{ +    xtensa_advance_ccount(env, d); +} + +void HELPER(check_interrupts)(CPUXtensaState *env) +{ +    check_interrupts(env); +} + +void HELPER(itlb_hit_test)(CPUXtensaState *env, uint32_t vaddr) +{ +    get_page_addr_code(env, vaddr); +} + +/*! + * Check vaddr accessibility/cache attributes and raise an exception if + * specified by the ATOMCTL SR. + * + * Note: local memory exclusion is not implemented + */ +void HELPER(check_atomctl)(CPUXtensaState *env, uint32_t pc, uint32_t vaddr) +{ +    uint32_t paddr, page_size, access; +    uint32_t atomctl = env->sregs[ATOMCTL]; +    int rc = xtensa_get_physical_addr(env, true, vaddr, 1, +            xtensa_get_cring(env), &paddr, &page_size, &access); + +    /* +     * s32c1i never causes LOAD_PROHIBITED_CAUSE exceptions, +     * see opcode description in the ISA +     */ +    if (rc == 0 && +            (access & (PAGE_READ | PAGE_WRITE)) != (PAGE_READ | PAGE_WRITE)) { +        rc = STORE_PROHIBITED_CAUSE; +    } + +    if (rc) { +        HELPER(exception_cause_vaddr)(env, pc, rc, vaddr); +    } + +    /* +     * When data cache is not configured use ATOMCTL bypass field. +     * See ISA, 4.3.12.4 The Atomic Operation Control Register (ATOMCTL) +     * under the Conditional Store Option. +     */ +    if (!xtensa_option_enabled(env->config, XTENSA_OPTION_DCACHE)) { +        access = PAGE_CACHE_BYPASS; +    } + +    switch (access & PAGE_CACHE_MASK) { +    case PAGE_CACHE_WB: +        atomctl >>= 2; +        /* fall through */ +    case PAGE_CACHE_WT: +        atomctl >>= 2; +        /* fall through */ +    case PAGE_CACHE_BYPASS: +        if ((atomctl & 0x3) == 0) { +            HELPER(exception_cause_vaddr)(env, pc, +                    LOAD_STORE_ERROR_CAUSE, vaddr); +        } +        break; + +    case PAGE_CACHE_ISOLATE: +        HELPER(exception_cause_vaddr)(env, pc, +                LOAD_STORE_ERROR_CAUSE, vaddr); +        break; + +    default: +        break; +    } +} + +void HELPER(wsr_rasid)(CPUXtensaState *env, uint32_t v) +{ +    XtensaCPU *cpu = xtensa_env_get_cpu(env); + +    v = (v & 0xffffff00) | 0x1; +    if (v != env->sregs[RASID]) { +        env->sregs[RASID] = v; +        tlb_flush(CPU(cpu), 1); +    } +} + +static uint32_t get_page_size(const CPUXtensaState *env, bool dtlb, uint32_t way) +{ +    uint32_t tlbcfg = env->sregs[dtlb ? DTLBCFG : ITLBCFG]; + +    switch (way) { +    case 4: +        return (tlbcfg >> 16) & 0x3; + +    case 5: +        return (tlbcfg >> 20) & 0x1; + +    case 6: +        return (tlbcfg >> 24) & 0x1; + +    default: +        return 0; +    } +} + +/*! + * Get bit mask for the virtual address bits translated by the TLB way + */ +uint32_t xtensa_tlb_get_addr_mask(const CPUXtensaState *env, bool dtlb, uint32_t way) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        bool varway56 = dtlb ? +            env->config->dtlb.varway56 : +            env->config->itlb.varway56; + +        switch (way) { +        case 4: +            return 0xfff00000 << get_page_size(env, dtlb, way) * 2; + +        case 5: +            if (varway56) { +                return 0xf8000000 << get_page_size(env, dtlb, way); +            } else { +                return 0xf8000000; +            } + +        case 6: +            if (varway56) { +                return 0xf0000000 << (1 - get_page_size(env, dtlb, way)); +            } else { +                return 0xf0000000; +            } + +        default: +            return 0xfffff000; +        } +    } else { +        return REGION_PAGE_MASK; +    } +} + +/*! + * Get bit mask for the 'VPN without index' field. + * See ISA, 4.6.5.6, data format for RxTLB0 + */ +static uint32_t get_vpn_mask(const CPUXtensaState *env, bool dtlb, uint32_t way) +{ +    if (way < 4) { +        bool is32 = (dtlb ? +                env->config->dtlb.nrefillentries : +                env->config->itlb.nrefillentries) == 32; +        return is32 ? 0xffff8000 : 0xffffc000; +    } else if (way == 4) { +        return xtensa_tlb_get_addr_mask(env, dtlb, way) << 2; +    } else if (way <= 6) { +        uint32_t mask = xtensa_tlb_get_addr_mask(env, dtlb, way); +        bool varway56 = dtlb ? +            env->config->dtlb.varway56 : +            env->config->itlb.varway56; + +        if (varway56) { +            return mask << (way == 5 ? 2 : 3); +        } else { +            return mask << 1; +        } +    } else { +        return 0xfffff000; +    } +} + +/*! + * Split virtual address into VPN (with index) and entry index + * for the given TLB way + */ +void split_tlb_entry_spec_way(const CPUXtensaState *env, uint32_t v, bool dtlb, +        uint32_t *vpn, uint32_t wi, uint32_t *ei) +{ +    bool varway56 = dtlb ? +        env->config->dtlb.varway56 : +        env->config->itlb.varway56; + +    if (!dtlb) { +        wi &= 7; +    } + +    if (wi < 4) { +        bool is32 = (dtlb ? +                env->config->dtlb.nrefillentries : +                env->config->itlb.nrefillentries) == 32; +        *ei = (v >> 12) & (is32 ? 0x7 : 0x3); +    } else { +        switch (wi) { +        case 4: +            { +                uint32_t eibase = 20 + get_page_size(env, dtlb, wi) * 2; +                *ei = (v >> eibase) & 0x3; +            } +            break; + +        case 5: +            if (varway56) { +                uint32_t eibase = 27 + get_page_size(env, dtlb, wi); +                *ei = (v >> eibase) & 0x3; +            } else { +                *ei = (v >> 27) & 0x1; +            } +            break; + +        case 6: +            if (varway56) { +                uint32_t eibase = 29 - get_page_size(env, dtlb, wi); +                *ei = (v >> eibase) & 0x7; +            } else { +                *ei = (v >> 28) & 0x1; +            } +            break; + +        default: +            *ei = 0; +            break; +        } +    } +    *vpn = v & xtensa_tlb_get_addr_mask(env, dtlb, wi); +} + +/*! + * Split TLB address into TLB way, entry index and VPN (with index). + * See ISA, 4.6.5.5 - 4.6.5.8 for the TLB addressing format + */ +static void split_tlb_entry_spec(CPUXtensaState *env, uint32_t v, bool dtlb, +        uint32_t *vpn, uint32_t *wi, uint32_t *ei) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        *wi = v & (dtlb ? 0xf : 0x7); +        split_tlb_entry_spec_way(env, v, dtlb, vpn, *wi, ei); +    } else { +        *vpn = v & REGION_PAGE_MASK; +        *wi = 0; +        *ei = (v >> 29) & 0x7; +    } +} + +static xtensa_tlb_entry *get_tlb_entry(CPUXtensaState *env, +        uint32_t v, bool dtlb, uint32_t *pwi) +{ +    uint32_t vpn; +    uint32_t wi; +    uint32_t ei; + +    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei); +    if (pwi) { +        *pwi = wi; +    } +    return xtensa_tlb_get_entry(env, dtlb, wi, ei); +} + +uint32_t HELPER(rtlb0)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        uint32_t wi; +        const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi); +        return (entry->vaddr & get_vpn_mask(env, dtlb, wi)) | entry->asid; +    } else { +        return v & REGION_PAGE_MASK; +    } +} + +uint32_t HELPER(rtlb1)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) +{ +    const xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, NULL); +    return entry->paddr | entry->attr; +} + +void HELPER(itlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        uint32_t wi; +        xtensa_tlb_entry *entry = get_tlb_entry(env, v, dtlb, &wi); +        if (entry->variable && entry->asid) { +            tlb_flush_page(CPU(xtensa_env_get_cpu(env)), entry->vaddr); +            entry->asid = 0; +        } +    } +} + +uint32_t HELPER(ptlb)(CPUXtensaState *env, uint32_t v, uint32_t dtlb) +{ +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        uint32_t wi; +        uint32_t ei; +        uint8_t ring; +        int res = xtensa_tlb_lookup(env, v, dtlb, &wi, &ei, &ring); + +        switch (res) { +        case 0: +            if (ring >= xtensa_get_ring(env)) { +                return (v & 0xfffff000) | wi | (dtlb ? 0x10 : 0x8); +            } +            break; + +        case INST_TLB_MULTI_HIT_CAUSE: +        case LOAD_STORE_TLB_MULTI_HIT_CAUSE: +            HELPER(exception_cause_vaddr)(env, env->pc, res, v); +            break; +        } +        return 0; +    } else { +        return (v & REGION_PAGE_MASK) | 0x1; +    } +} + +void xtensa_tlb_set_entry_mmu(const CPUXtensaState *env, +        xtensa_tlb_entry *entry, bool dtlb, +        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte) +{ +    entry->vaddr = vpn; +    entry->paddr = pte & xtensa_tlb_get_addr_mask(env, dtlb, wi); +    entry->asid = (env->sregs[RASID] >> ((pte >> 1) & 0x18)) & 0xff; +    entry->attr = pte & 0xf; +} + +void xtensa_tlb_set_entry(CPUXtensaState *env, bool dtlb, +        unsigned wi, unsigned ei, uint32_t vpn, uint32_t pte) +{ +    XtensaCPU *cpu = xtensa_env_get_cpu(env); +    CPUState *cs = CPU(cpu); +    xtensa_tlb_entry *entry = xtensa_tlb_get_entry(env, dtlb, wi, ei); + +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_MMU)) { +        if (entry->variable) { +            if (entry->asid) { +                tlb_flush_page(cs, entry->vaddr); +            } +            xtensa_tlb_set_entry_mmu(env, entry, dtlb, wi, ei, vpn, pte); +            tlb_flush_page(cs, entry->vaddr); +        } else { +            qemu_log("%s %d, %d, %d trying to set immutable entry\n", +                    __func__, dtlb, wi, ei); +        } +    } else { +        tlb_flush_page(cs, entry->vaddr); +        if (xtensa_option_enabled(env->config, +                    XTENSA_OPTION_REGION_TRANSLATION)) { +            entry->paddr = pte & REGION_PAGE_MASK; +        } +        entry->attr = pte & 0xf; +    } +} + +void HELPER(wtlb)(CPUXtensaState *env, uint32_t p, uint32_t v, uint32_t dtlb) +{ +    uint32_t vpn; +    uint32_t wi; +    uint32_t ei; +    split_tlb_entry_spec(env, v, dtlb, &vpn, &wi, &ei); +    xtensa_tlb_set_entry(env, dtlb, wi, ei, vpn, p); +} + + +void HELPER(wsr_ibreakenable)(CPUXtensaState *env, uint32_t v) +{ +    uint32_t change = v ^ env->sregs[IBREAKENABLE]; +    unsigned i; + +    for (i = 0; i < env->config->nibreak; ++i) { +        if (change & (1 << i)) { +            tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]); +        } +    } +    env->sregs[IBREAKENABLE] = v & ((1 << env->config->nibreak) - 1); +} + +void HELPER(wsr_ibreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) +{ +    if (env->sregs[IBREAKENABLE] & (1 << i) && env->sregs[IBREAKA + i] != v) { +        tb_invalidate_virtual_addr(env, env->sregs[IBREAKA + i]); +        tb_invalidate_virtual_addr(env, v); +    } +    env->sregs[IBREAKA + i] = v; +} + +static void set_dbreak(CPUXtensaState *env, unsigned i, uint32_t dbreaka, +        uint32_t dbreakc) +{ +    CPUState *cs = CPU(xtensa_env_get_cpu(env)); +    int flags = BP_CPU | BP_STOP_BEFORE_ACCESS; +    uint32_t mask = dbreakc | ~DBREAKC_MASK; + +    if (env->cpu_watchpoint[i]) { +        cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); +    } +    if (dbreakc & DBREAKC_SB) { +        flags |= BP_MEM_WRITE; +    } +    if (dbreakc & DBREAKC_LB) { +        flags |= BP_MEM_READ; +    } +    /* contiguous mask after inversion is one less than some power of 2 */ +    if ((~mask + 1) & ~mask) { +        qemu_log("DBREAKC mask is not contiguous: 0x%08x\n", dbreakc); +        /* cut mask after the first zero bit */ +        mask = 0xffffffff << (32 - clo32(mask)); +    } +    if (cpu_watchpoint_insert(cs, dbreaka & mask, ~mask + 1, +            flags, &env->cpu_watchpoint[i])) { +        env->cpu_watchpoint[i] = NULL; +        qemu_log("Failed to set data breakpoint at 0x%08x/%d\n", +                dbreaka & mask, ~mask + 1); +    } +} + +void HELPER(wsr_dbreaka)(CPUXtensaState *env, uint32_t i, uint32_t v) +{ +    uint32_t dbreakc = env->sregs[DBREAKC + i]; + +    if ((dbreakc & DBREAKC_SB_LB) && +            env->sregs[DBREAKA + i] != v) { +        set_dbreak(env, i, v, dbreakc); +    } +    env->sregs[DBREAKA + i] = v; +} + +void HELPER(wsr_dbreakc)(CPUXtensaState *env, uint32_t i, uint32_t v) +{ +    if ((env->sregs[DBREAKC + i] ^ v) & (DBREAKC_SB_LB | DBREAKC_MASK)) { +        if (v & DBREAKC_SB_LB) { +            set_dbreak(env, i, env->sregs[DBREAKA + i], v); +        } else { +            if (env->cpu_watchpoint[i]) { +                CPUState *cs = CPU(xtensa_env_get_cpu(env)); + +                cpu_watchpoint_remove_by_ref(cs, env->cpu_watchpoint[i]); +                env->cpu_watchpoint[i] = NULL; +            } +        } +    } +    env->sregs[DBREAKC + i] = v; +} + +void HELPER(wur_fcr)(CPUXtensaState *env, uint32_t v) +{ +    static const int rounding_mode[] = { +        float_round_nearest_even, +        float_round_to_zero, +        float_round_up, +        float_round_down, +    }; + +    env->uregs[FCR] = v & 0xfffff07f; +    set_float_rounding_mode(rounding_mode[v & 3], &env->fp_status); +} + +float32 HELPER(abs_s)(float32 v) +{ +    return float32_abs(v); +} + +float32 HELPER(neg_s)(float32 v) +{ +    return float32_chs(v); +} + +float32 HELPER(add_s)(CPUXtensaState *env, float32 a, float32 b) +{ +    return float32_add(a, b, &env->fp_status); +} + +float32 HELPER(sub_s)(CPUXtensaState *env, float32 a, float32 b) +{ +    return float32_sub(a, b, &env->fp_status); +} + +float32 HELPER(mul_s)(CPUXtensaState *env, float32 a, float32 b) +{ +    return float32_mul(a, b, &env->fp_status); +} + +float32 HELPER(madd_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) +{ +    return float32_muladd(b, c, a, 0, +            &env->fp_status); +} + +float32 HELPER(msub_s)(CPUXtensaState *env, float32 a, float32 b, float32 c) +{ +    return float32_muladd(b, c, a, float_muladd_negate_product, +            &env->fp_status); +} + +uint32_t HELPER(ftoi)(float32 v, uint32_t rounding_mode, uint32_t scale) +{ +    float_status fp_status = {0}; + +    set_float_rounding_mode(rounding_mode, &fp_status); +    return float32_to_int32( +            float32_scalbn(v, scale, &fp_status), &fp_status); +} + +uint32_t HELPER(ftoui)(float32 v, uint32_t rounding_mode, uint32_t scale) +{ +    float_status fp_status = {0}; +    float32 res; + +    set_float_rounding_mode(rounding_mode, &fp_status); + +    res = float32_scalbn(v, scale, &fp_status); + +    if (float32_is_neg(v) && !float32_is_any_nan(v)) { +        return float32_to_int32(res, &fp_status); +    } else { +        return float32_to_uint32(res, &fp_status); +    } +} + +float32 HELPER(itof)(CPUXtensaState *env, uint32_t v, uint32_t scale) +{ +    return float32_scalbn(int32_to_float32(v, &env->fp_status), +            (int32_t)scale, &env->fp_status); +} + +float32 HELPER(uitof)(CPUXtensaState *env, uint32_t v, uint32_t scale) +{ +    return float32_scalbn(uint32_to_float32(v, &env->fp_status), +            (int32_t)scale, &env->fp_status); +} + +static inline void set_br(CPUXtensaState *env, bool v, uint32_t br) +{ +    if (v) { +        env->sregs[BR] |= br; +    } else { +        env->sregs[BR] &= ~br; +    } +} + +void HELPER(un_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) +{ +    set_br(env, float32_unordered_quiet(a, b, &env->fp_status), br); +} + +void HELPER(oeq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) +{ +    set_br(env, float32_eq_quiet(a, b, &env->fp_status), br); +} + +void HELPER(ueq_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) +{ +    int v = float32_compare_quiet(a, b, &env->fp_status); +    set_br(env, v == float_relation_equal || v == float_relation_unordered, br); +} + +void HELPER(olt_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) +{ +    set_br(env, float32_lt_quiet(a, b, &env->fp_status), br); +} + +void HELPER(ult_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) +{ +    int v = float32_compare_quiet(a, b, &env->fp_status); +    set_br(env, v == float_relation_less || v == float_relation_unordered, br); +} + +void HELPER(ole_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) +{ +    set_br(env, float32_le_quiet(a, b, &env->fp_status), br); +} + +void HELPER(ule_s)(CPUXtensaState *env, uint32_t br, float32 a, float32 b) +{ +    int v = float32_compare_quiet(a, b, &env->fp_status); +    set_br(env, v != float_relation_greater, br); +} diff --git a/target-xtensa/overlay_tool.h b/target-xtensa/overlay_tool.h new file mode 100644 index 00000000..eda03aac --- /dev/null +++ b/target-xtensa/overlay_tool.h @@ -0,0 +1,597 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define XTREG(idx, ofs, bi, sz, al, no, flags, cp, typ, grp, name, \ +        a1, a2, a3, a4, a5, a6) \ +    { .targno = (no), .type = (typ), .group = (grp), .size = (sz) }, +#define XTREG_END { .targno = -1 }, + +#ifndef XCHAL_HAVE_DIV32 +#define XCHAL_HAVE_DIV32 0 +#endif + +#ifndef XCHAL_UNALIGNED_LOAD_HW +#define XCHAL_UNALIGNED_LOAD_HW 0 +#endif + +#ifndef XCHAL_HAVE_VECBASE +#define XCHAL_HAVE_VECBASE 0 +#define XCHAL_VECBASE_RESET_VADDR 0 +#endif + +#ifndef XCHAL_HW_MIN_VERSION +#define XCHAL_HW_MIN_VERSION 0 +#endif + +#define XCHAL_OPTION(xchal, qemu) ((xchal) ? XTENSA_OPTION_BIT(qemu) : 0) + +#define XTENSA_OPTIONS ( \ +    XCHAL_OPTION(XCHAL_HAVE_DENSITY, XTENSA_OPTION_CODE_DENSITY) | \ +    XCHAL_OPTION(XCHAL_HAVE_LOOPS, XTENSA_OPTION_LOOP) | \ +    XCHAL_OPTION(XCHAL_HAVE_ABSOLUTE_LITERALS, XTENSA_OPTION_EXTENDED_L32R) | \ +    XCHAL_OPTION(XCHAL_HAVE_MUL16, XTENSA_OPTION_16_BIT_IMUL) | \ +    XCHAL_OPTION(XCHAL_HAVE_MUL32, XTENSA_OPTION_32_BIT_IMUL) | \ +    XCHAL_OPTION(XCHAL_HAVE_MUL32_HIGH, XTENSA_OPTION_32_BIT_IMUL_HIGH) | \ +    XCHAL_OPTION(XCHAL_HAVE_DIV32, XTENSA_OPTION_32_BIT_IDIV) | \ +    XCHAL_OPTION(XCHAL_HAVE_MAC16, XTENSA_OPTION_MAC16) | \ +    XCHAL_OPTION(XCHAL_HAVE_NSA, XTENSA_OPTION_MISC_OP_NSA) | \ +    XCHAL_OPTION(XCHAL_HAVE_MINMAX, XTENSA_OPTION_MISC_OP_MINMAX) | \ +    XCHAL_OPTION(XCHAL_HAVE_SEXT, XTENSA_OPTION_MISC_OP_SEXT) | \ +    XCHAL_OPTION(XCHAL_HAVE_CLAMPS, XTENSA_OPTION_MISC_OP_CLAMPS) | \ +    XCHAL_OPTION(XCHAL_HAVE_CP, XTENSA_OPTION_COPROCESSOR) | \ +    XCHAL_OPTION(XCHAL_HAVE_BOOLEANS, XTENSA_OPTION_BOOLEAN) | \ +    XCHAL_OPTION(XCHAL_HAVE_FP, XTENSA_OPTION_FP_COPROCESSOR) | \ +    XCHAL_OPTION(XCHAL_HAVE_RELEASE_SYNC, XTENSA_OPTION_MP_SYNCHRO) | \ +    XCHAL_OPTION(XCHAL_HAVE_S32C1I, XTENSA_OPTION_CONDITIONAL_STORE) | \ +    XCHAL_OPTION(XCHAL_HAVE_S32C1I && XCHAL_HW_MIN_VERSION >= 230000, \ +        XTENSA_OPTION_ATOMCTL) | \ +    /* Interrupts and exceptions */ \ +    XCHAL_OPTION(XCHAL_HAVE_EXCEPTIONS, XTENSA_OPTION_EXCEPTION) | \ +    XCHAL_OPTION(XCHAL_HAVE_VECBASE, XTENSA_OPTION_RELOCATABLE_VECTOR) | \ +    XCHAL_OPTION(XCHAL_UNALIGNED_LOAD_EXCEPTION, \ +        XTENSA_OPTION_UNALIGNED_EXCEPTION) | \ +    XCHAL_OPTION(XCHAL_HAVE_INTERRUPTS, XTENSA_OPTION_INTERRUPT) | \ +    XCHAL_OPTION(XCHAL_HAVE_HIGHPRI_INTERRUPTS, \ +        XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT) | \ +    XCHAL_OPTION(XCHAL_HAVE_CCOUNT, XTENSA_OPTION_TIMER_INTERRUPT) | \ +    /* Local memory, TODO */ \ +    XCHAL_OPTION(XCHAL_ICACHE_WAYS, XTENSA_OPTION_ICACHE) | \ +    XCHAL_OPTION(XCHAL_ICACHE_LINE_LOCKABLE, \ +            XTENSA_OPTION_ICACHE_INDEX_LOCK) | \ +    XCHAL_OPTION(XCHAL_DCACHE_WAYS, XTENSA_OPTION_DCACHE) | \ +    XCHAL_OPTION(XCHAL_DCACHE_LINE_LOCKABLE, \ +            XTENSA_OPTION_DCACHE_INDEX_LOCK) | \ +    XCHAL_OPTION(XCHAL_UNALIGNED_LOAD_HW, XTENSA_OPTION_HW_ALIGNMENT) | \ +    /* Memory protection and translation */ \ +    XCHAL_OPTION(XCHAL_HAVE_MIMIC_CACHEATTR, \ +            XTENSA_OPTION_REGION_PROTECTION) | \ +    XCHAL_OPTION(XCHAL_HAVE_XLT_CACHEATTR, \ +            XTENSA_OPTION_REGION_TRANSLATION) | \ +    XCHAL_OPTION(XCHAL_HAVE_PTP_MMU, XTENSA_OPTION_MMU) | \ +    XCHAL_OPTION(XCHAL_HAVE_CACHEATTR, XTENSA_OPTION_CACHEATTR) | \ +    /* Other, TODO */ \ +    XCHAL_OPTION(XCHAL_HAVE_WINDOWED, XTENSA_OPTION_WINDOWED_REGISTER) | \ +    XCHAL_OPTION(XCHAL_HAVE_DEBUG, XTENSA_OPTION_DEBUG) |\ +    XCHAL_OPTION(XCHAL_NUM_MISC_REGS > 0, XTENSA_OPTION_MISC_SR) | \ +    XCHAL_OPTION(XCHAL_HAVE_THREADPTR, XTENSA_OPTION_THREAD_POINTER) | \ +    XCHAL_OPTION(XCHAL_HAVE_PRID, XTENSA_OPTION_PROCESSOR_ID)) + +#ifndef XCHAL_WINDOW_OF4_VECOFS +#define XCHAL_WINDOW_OF4_VECOFS         0x00000000 +#define XCHAL_WINDOW_UF4_VECOFS         0x00000040 +#define XCHAL_WINDOW_OF8_VECOFS         0x00000080 +#define XCHAL_WINDOW_UF8_VECOFS         0x000000C0 +#define XCHAL_WINDOW_OF12_VECOFS        0x00000100 +#define XCHAL_WINDOW_UF12_VECOFS        0x00000140 +#endif + +#if XCHAL_HAVE_WINDOWED +#define WINDOW_VECTORS \ +   [EXC_WINDOW_OVERFLOW4] = XCHAL_WINDOW_OF4_VECOFS + \ +       XCHAL_WINDOW_VECTORS_VADDR, \ +   [EXC_WINDOW_UNDERFLOW4] = XCHAL_WINDOW_UF4_VECOFS + \ +       XCHAL_WINDOW_VECTORS_VADDR, \ +   [EXC_WINDOW_OVERFLOW8] = XCHAL_WINDOW_OF8_VECOFS + \ +       XCHAL_WINDOW_VECTORS_VADDR, \ +   [EXC_WINDOW_UNDERFLOW8] = XCHAL_WINDOW_UF8_VECOFS + \ +       XCHAL_WINDOW_VECTORS_VADDR, \ +   [EXC_WINDOW_OVERFLOW12] = XCHAL_WINDOW_OF12_VECOFS + \ +       XCHAL_WINDOW_VECTORS_VADDR, \ +   [EXC_WINDOW_UNDERFLOW12] = XCHAL_WINDOW_UF12_VECOFS + \ +       XCHAL_WINDOW_VECTORS_VADDR, +#else +#define WINDOW_VECTORS +#endif + +#define EXCEPTION_VECTORS { \ +        [EXC_RESET] = XCHAL_RESET_VECTOR_VADDR, \ +        WINDOW_VECTORS \ +        [EXC_KERNEL] = XCHAL_KERNEL_VECTOR_VADDR, \ +        [EXC_USER] = XCHAL_USER_VECTOR_VADDR, \ +        [EXC_DOUBLE] = XCHAL_DOUBLEEXC_VECTOR_VADDR, \ +        [EXC_DEBUG] = XCHAL_DEBUG_VECTOR_VADDR, \ +    } + +#define INTERRUPT_VECTORS { \ +        0, \ +        0, \ +        XCHAL_INTLEVEL2_VECTOR_VADDR, \ +        XCHAL_INTLEVEL3_VECTOR_VADDR, \ +        XCHAL_INTLEVEL4_VECTOR_VADDR, \ +        XCHAL_INTLEVEL5_VECTOR_VADDR, \ +        XCHAL_INTLEVEL6_VECTOR_VADDR, \ +        XCHAL_INTLEVEL7_VECTOR_VADDR, \ +    } + +#define LEVEL_MASKS { \ +        [1] = XCHAL_INTLEVEL1_MASK, \ +        [2] = XCHAL_INTLEVEL2_MASK, \ +        [3] = XCHAL_INTLEVEL3_MASK, \ +        [4] = XCHAL_INTLEVEL4_MASK, \ +        [5] = XCHAL_INTLEVEL5_MASK, \ +        [6] = XCHAL_INTLEVEL6_MASK, \ +        [7] = XCHAL_INTLEVEL7_MASK, \ +    } + +#define INTTYPE_MASKS { \ +        [INTTYPE_EDGE] = XCHAL_INTTYPE_MASK_EXTERN_EDGE, \ +        [INTTYPE_NMI] = XCHAL_INTTYPE_MASK_NMI, \ +        [INTTYPE_SOFTWARE] = XCHAL_INTTYPE_MASK_SOFTWARE, \ +    } + +#define XTHAL_INTTYPE_EXTERN_LEVEL INTTYPE_LEVEL +#define XTHAL_INTTYPE_EXTERN_EDGE INTTYPE_EDGE +#define XTHAL_INTTYPE_NMI INTTYPE_NMI +#define XTHAL_INTTYPE_SOFTWARE INTTYPE_SOFTWARE +#define XTHAL_INTTYPE_TIMER INTTYPE_TIMER +#define XTHAL_INTTYPE_TBD1 INTTYPE_DEBUG +#define XTHAL_INTTYPE_TBD2 INTTYPE_WRITE_ERR +#define XTHAL_INTTYPE_WRITE_ERROR INTTYPE_WRITE_ERR +#define XTHAL_INTTYPE_PROFILING INTTYPE_PROFILING + + +#define INTERRUPT(i) { \ +        .level = XCHAL_INT ## i ## _LEVEL, \ +        .inttype = XCHAL_INT ## i ## _TYPE, \ +    } + +#define INTERRUPTS { \ +        [0] = INTERRUPT(0), \ +        [1] = INTERRUPT(1), \ +        [2] = INTERRUPT(2), \ +        [3] = INTERRUPT(3), \ +        [4] = INTERRUPT(4), \ +        [5] = INTERRUPT(5), \ +        [6] = INTERRUPT(6), \ +        [7] = INTERRUPT(7), \ +        [8] = INTERRUPT(8), \ +        [9] = INTERRUPT(9), \ +        [10] = INTERRUPT(10), \ +        [11] = INTERRUPT(11), \ +        [12] = INTERRUPT(12), \ +        [13] = INTERRUPT(13), \ +        [14] = INTERRUPT(14), \ +        [15] = INTERRUPT(15), \ +        [16] = INTERRUPT(16), \ +        [17] = INTERRUPT(17), \ +        [18] = INTERRUPT(18), \ +        [19] = INTERRUPT(19), \ +        [20] = INTERRUPT(20), \ +        [21] = INTERRUPT(21), \ +        [22] = INTERRUPT(22), \ +        [23] = INTERRUPT(23), \ +        [24] = INTERRUPT(24), \ +        [25] = INTERRUPT(25), \ +        [26] = INTERRUPT(26), \ +        [27] = INTERRUPT(27), \ +        [28] = INTERRUPT(28), \ +        [29] = INTERRUPT(29), \ +        [30] = INTERRUPT(30), \ +        [31] = INTERRUPT(31), \ +    } + +#define TIMERINTS { \ +        [0] = XCHAL_TIMER0_INTERRUPT, \ +        [1] = XCHAL_TIMER1_INTERRUPT, \ +        [2] = XCHAL_TIMER2_INTERRUPT, \ +    } + +#define EXTINTS { \ +        [0] = XCHAL_EXTINT0_NUM, \ +        [1] = XCHAL_EXTINT1_NUM, \ +        [2] = XCHAL_EXTINT2_NUM, \ +        [3] = XCHAL_EXTINT3_NUM, \ +        [4] = XCHAL_EXTINT4_NUM, \ +        [5] = XCHAL_EXTINT5_NUM, \ +        [6] = XCHAL_EXTINT6_NUM, \ +        [7] = XCHAL_EXTINT7_NUM, \ +        [8] = XCHAL_EXTINT8_NUM, \ +        [9] = XCHAL_EXTINT9_NUM, \ +        [10] = XCHAL_EXTINT10_NUM, \ +        [11] = XCHAL_EXTINT11_NUM, \ +        [12] = XCHAL_EXTINT12_NUM, \ +        [13] = XCHAL_EXTINT13_NUM, \ +        [14] = XCHAL_EXTINT14_NUM, \ +        [15] = XCHAL_EXTINT15_NUM, \ +        [16] = XCHAL_EXTINT16_NUM, \ +        [17] = XCHAL_EXTINT17_NUM, \ +        [18] = XCHAL_EXTINT18_NUM, \ +        [19] = XCHAL_EXTINT19_NUM, \ +        [20] = XCHAL_EXTINT20_NUM, \ +        [21] = XCHAL_EXTINT21_NUM, \ +        [22] = XCHAL_EXTINT22_NUM, \ +        [23] = XCHAL_EXTINT23_NUM, \ +        [24] = XCHAL_EXTINT24_NUM, \ +        [25] = XCHAL_EXTINT25_NUM, \ +        [26] = XCHAL_EXTINT26_NUM, \ +        [27] = XCHAL_EXTINT27_NUM, \ +        [28] = XCHAL_EXTINT28_NUM, \ +        [29] = XCHAL_EXTINT29_NUM, \ +        [30] = XCHAL_EXTINT30_NUM, \ +        [31] = XCHAL_EXTINT31_NUM, \ +    } + +#define EXCEPTIONS_SECTION \ +    .excm_level = XCHAL_EXCM_LEVEL, \ +    .vecbase = XCHAL_VECBASE_RESET_VADDR, \ +    .exception_vector = EXCEPTION_VECTORS + +#define INTERRUPTS_SECTION \ +    .ninterrupt = XCHAL_NUM_INTERRUPTS, \ +    .nlevel = XCHAL_NUM_INTLEVELS, \ +    .interrupt_vector = INTERRUPT_VECTORS, \ +    .level_mask = LEVEL_MASKS, \ +    .inttype_mask = INTTYPE_MASKS, \ +    .interrupt = INTERRUPTS, \ +    .nccompare = XCHAL_NUM_TIMERS, \ +    .timerint = TIMERINTS, \ +    .nextint = XCHAL_NUM_EXTINTERRUPTS, \ +    .extint = EXTINTS + +#if XCHAL_HAVE_PTP_MMU + +#define TLB_TEMPLATE(ways, refill_way_size, way56) { \ +        .nways = ways, \ +        .way_size = { \ +            (refill_way_size), (refill_way_size), \ +            (refill_way_size), (refill_way_size), \ +            4, (way56) ? 4 : 2, (way56) ? 8 : 2, 1, 1, 1, \ +        }, \ +        .varway56 = (way56), \ +        .nrefillentries = (refill_way_size) * 4, \ +    } + +#define ITLB(varway56) \ +    TLB_TEMPLATE(7, 1 << XCHAL_ITLB_ARF_ENTRIES_LOG2, varway56) + +#define DTLB(varway56) \ +    TLB_TEMPLATE(10, 1 << XCHAL_DTLB_ARF_ENTRIES_LOG2, varway56) + +#define TLB_SECTION \ +    .itlb = ITLB(XCHAL_HAVE_SPANNING_WAY), \ +    .dtlb = DTLB(XCHAL_HAVE_SPANNING_WAY) + +#elif XCHAL_HAVE_XLT_CACHEATTR || XCHAL_HAVE_MIMIC_CACHEATTR + +#define TLB_TEMPLATE { \ +        .nways = 1, \ +        .way_size = { \ +            8, \ +        } \ +    } + +#define TLB_SECTION \ +    .itlb = TLB_TEMPLATE, \ +    .dtlb = TLB_TEMPLATE + +#endif + +#if (defined(TARGET_WORDS_BIGENDIAN) != 0) == (XCHAL_HAVE_BE != 0) +#define REGISTER_CORE(core) \ +    static void __attribute__((constructor)) register_core(void) \ +    { \ +        static XtensaConfigList node = { \ +            .config = &core, \ +        }; \ +        xtensa_finalize_config(&core); \ +        xtensa_register_core(&node); \ +    } +#else +#define REGISTER_CORE(core) +#endif + +#define DEBUG_SECTION \ +    .debug_level = XCHAL_DEBUGLEVEL, \ +    .nibreak = XCHAL_NUM_IBREAK, \ +    .ndbreak = XCHAL_NUM_DBREAK + +#define CONFIG_SECTION \ +    .configid = { \ +        XCHAL_HW_CONFIGID0, \ +        XCHAL_HW_CONFIGID1, \ +    } + +#define DEFAULT_SECTIONS \ +    .options = XTENSA_OPTIONS, \ +    .nareg = XCHAL_NUM_AREGS, \ +    .ndepc = (XCHAL_XEA_VERSION >= 2), \ +    EXCEPTIONS_SECTION, \ +    INTERRUPTS_SECTION, \ +    TLB_SECTION, \ +    DEBUG_SECTION, \ +    CONFIG_SECTION + + +#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 2 +#define XCHAL_INTLEVEL2_VECTOR_VADDR 0 +#endif +#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 3 +#define XCHAL_INTLEVEL3_VECTOR_VADDR 0 +#endif +#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 4 +#define XCHAL_INTLEVEL4_VECTOR_VADDR 0 +#endif +#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 5 +#define XCHAL_INTLEVEL5_VECTOR_VADDR 0 +#endif +#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 6 +#define XCHAL_INTLEVEL6_VECTOR_VADDR 0 +#endif +#if XCHAL_NUM_INTLEVELS + XCHAL_HAVE_NMI + 1 <= 7 +#define XCHAL_INTLEVEL7_VECTOR_VADDR 0 +#endif + + +#if XCHAL_NUM_INTERRUPTS <= 0 +#define XCHAL_INT0_LEVEL 0 +#define XCHAL_INT0_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 1 +#define XCHAL_INT1_LEVEL 0 +#define XCHAL_INT1_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 2 +#define XCHAL_INT2_LEVEL 0 +#define XCHAL_INT2_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 3 +#define XCHAL_INT3_LEVEL 0 +#define XCHAL_INT3_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 4 +#define XCHAL_INT4_LEVEL 0 +#define XCHAL_INT4_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 5 +#define XCHAL_INT5_LEVEL 0 +#define XCHAL_INT5_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 6 +#define XCHAL_INT6_LEVEL 0 +#define XCHAL_INT6_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 7 +#define XCHAL_INT7_LEVEL 0 +#define XCHAL_INT7_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 8 +#define XCHAL_INT8_LEVEL 0 +#define XCHAL_INT8_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 9 +#define XCHAL_INT9_LEVEL 0 +#define XCHAL_INT9_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 10 +#define XCHAL_INT10_LEVEL 0 +#define XCHAL_INT10_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 11 +#define XCHAL_INT11_LEVEL 0 +#define XCHAL_INT11_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 12 +#define XCHAL_INT12_LEVEL 0 +#define XCHAL_INT12_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 13 +#define XCHAL_INT13_LEVEL 0 +#define XCHAL_INT13_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 14 +#define XCHAL_INT14_LEVEL 0 +#define XCHAL_INT14_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 15 +#define XCHAL_INT15_LEVEL 0 +#define XCHAL_INT15_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 16 +#define XCHAL_INT16_LEVEL 0 +#define XCHAL_INT16_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 17 +#define XCHAL_INT17_LEVEL 0 +#define XCHAL_INT17_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 18 +#define XCHAL_INT18_LEVEL 0 +#define XCHAL_INT18_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 19 +#define XCHAL_INT19_LEVEL 0 +#define XCHAL_INT19_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 20 +#define XCHAL_INT20_LEVEL 0 +#define XCHAL_INT20_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 21 +#define XCHAL_INT21_LEVEL 0 +#define XCHAL_INT21_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 22 +#define XCHAL_INT22_LEVEL 0 +#define XCHAL_INT22_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 23 +#define XCHAL_INT23_LEVEL 0 +#define XCHAL_INT23_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 24 +#define XCHAL_INT24_LEVEL 0 +#define XCHAL_INT24_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 25 +#define XCHAL_INT25_LEVEL 0 +#define XCHAL_INT25_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 26 +#define XCHAL_INT26_LEVEL 0 +#define XCHAL_INT26_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 27 +#define XCHAL_INT27_LEVEL 0 +#define XCHAL_INT27_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 28 +#define XCHAL_INT28_LEVEL 0 +#define XCHAL_INT28_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 29 +#define XCHAL_INT29_LEVEL 0 +#define XCHAL_INT29_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 30 +#define XCHAL_INT30_LEVEL 0 +#define XCHAL_INT30_TYPE 0 +#endif +#if XCHAL_NUM_INTERRUPTS <= 31 +#define XCHAL_INT31_LEVEL 0 +#define XCHAL_INT31_TYPE 0 +#endif + + +#if XCHAL_NUM_EXTINTERRUPTS <= 0 +#define XCHAL_EXTINT0_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 1 +#define XCHAL_EXTINT1_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 2 +#define XCHAL_EXTINT2_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 3 +#define XCHAL_EXTINT3_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 4 +#define XCHAL_EXTINT4_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 5 +#define XCHAL_EXTINT5_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 6 +#define XCHAL_EXTINT6_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 7 +#define XCHAL_EXTINT7_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 8 +#define XCHAL_EXTINT8_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 9 +#define XCHAL_EXTINT9_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 10 +#define XCHAL_EXTINT10_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 11 +#define XCHAL_EXTINT11_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 12 +#define XCHAL_EXTINT12_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 13 +#define XCHAL_EXTINT13_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 14 +#define XCHAL_EXTINT14_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 15 +#define XCHAL_EXTINT15_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 16 +#define XCHAL_EXTINT16_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 17 +#define XCHAL_EXTINT17_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 18 +#define XCHAL_EXTINT18_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 19 +#define XCHAL_EXTINT19_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 20 +#define XCHAL_EXTINT20_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 21 +#define XCHAL_EXTINT21_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 22 +#define XCHAL_EXTINT22_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 23 +#define XCHAL_EXTINT23_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 24 +#define XCHAL_EXTINT24_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 25 +#define XCHAL_EXTINT25_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 26 +#define XCHAL_EXTINT26_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 27 +#define XCHAL_EXTINT27_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 28 +#define XCHAL_EXTINT28_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 29 +#define XCHAL_EXTINT29_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 30 +#define XCHAL_EXTINT30_NUM 0 +#endif +#if XCHAL_NUM_EXTINTERRUPTS <= 31 +#define XCHAL_EXTINT31_NUM 0 +#endif + + +#define XTHAL_TIMER_UNCONFIGURED 0 diff --git a/target-xtensa/translate.c b/target-xtensa/translate.c new file mode 100644 index 00000000..7a074e0e --- /dev/null +++ b/target-xtensa/translate.c @@ -0,0 +1,3221 @@ +/* + * Xtensa ISA: + * http://www.tensilica.com/products/literature-docs/documentation/xtensa-isa-databook.htm + * + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> + +#include "cpu.h" +#include "exec/exec-all.h" +#include "disas/disas.h" +#include "tcg-op.h" +#include "qemu/log.h" +#include "sysemu/sysemu.h" +#include "exec/cpu_ldst.h" +#include "exec/semihost.h" + +#include "exec/helper-proto.h" +#include "exec/helper-gen.h" + +#include "trace-tcg.h" + + +typedef struct DisasContext { +    const XtensaConfig *config; +    TranslationBlock *tb; +    uint32_t pc; +    uint32_t next_pc; +    int cring; +    int ring; +    uint32_t lbeg; +    uint32_t lend; +    TCGv_i32 litbase; +    int is_jmp; +    int singlestep_enabled; + +    bool sar_5bit; +    bool sar_m32_5bit; +    bool sar_m32_allocated; +    TCGv_i32 sar_m32; + +    uint32_t ccount_delta; +    unsigned window; + +    bool debug; +    bool icount; +    TCGv_i32 next_icount; + +    unsigned cpenable; +} DisasContext; + +static TCGv_ptr cpu_env; +static TCGv_i32 cpu_pc; +static TCGv_i32 cpu_R[16]; +static TCGv_i32 cpu_FR[16]; +static TCGv_i32 cpu_SR[256]; +static TCGv_i32 cpu_UR[256]; + +#include "exec/gen-icount.h" + +typedef struct XtensaReg { +    const char *name; +    uint64_t opt_bits; +    enum { +        SR_R = 1, +        SR_W = 2, +        SR_X = 4, +        SR_RW = 3, +        SR_RWX = 7, +    } access; +} XtensaReg; + +#define XTENSA_REG_ACCESS(regname, opt, acc) { \ +        .name = (regname), \ +        .opt_bits = XTENSA_OPTION_BIT(opt), \ +        .access = (acc), \ +    } + +#define XTENSA_REG(regname, opt) XTENSA_REG_ACCESS(regname, opt, SR_RWX) + +#define XTENSA_REG_BITS_ACCESS(regname, opt, acc) { \ +        .name = (regname), \ +        .opt_bits = (opt), \ +        .access = (acc), \ +    } + +#define XTENSA_REG_BITS(regname, opt) \ +    XTENSA_REG_BITS_ACCESS(regname, opt, SR_RWX) + +static const XtensaReg sregnames[256] = { +    [LBEG] = XTENSA_REG("LBEG", XTENSA_OPTION_LOOP), +    [LEND] = XTENSA_REG("LEND", XTENSA_OPTION_LOOP), +    [LCOUNT] = XTENSA_REG("LCOUNT", XTENSA_OPTION_LOOP), +    [SAR] = XTENSA_REG_BITS("SAR", XTENSA_OPTION_ALL), +    [BR] = XTENSA_REG("BR", XTENSA_OPTION_BOOLEAN), +    [LITBASE] = XTENSA_REG("LITBASE", XTENSA_OPTION_EXTENDED_L32R), +    [SCOMPARE1] = XTENSA_REG("SCOMPARE1", XTENSA_OPTION_CONDITIONAL_STORE), +    [ACCLO] = XTENSA_REG("ACCLO", XTENSA_OPTION_MAC16), +    [ACCHI] = XTENSA_REG("ACCHI", XTENSA_OPTION_MAC16), +    [MR] = XTENSA_REG("MR0", XTENSA_OPTION_MAC16), +    [MR + 1] = XTENSA_REG("MR1", XTENSA_OPTION_MAC16), +    [MR + 2] = XTENSA_REG("MR2", XTENSA_OPTION_MAC16), +    [MR + 3] = XTENSA_REG("MR3", XTENSA_OPTION_MAC16), +    [WINDOW_BASE] = XTENSA_REG("WINDOW_BASE", XTENSA_OPTION_WINDOWED_REGISTER), +    [WINDOW_START] = XTENSA_REG("WINDOW_START", +            XTENSA_OPTION_WINDOWED_REGISTER), +    [PTEVADDR] = XTENSA_REG("PTEVADDR", XTENSA_OPTION_MMU), +    [RASID] = XTENSA_REG("RASID", XTENSA_OPTION_MMU), +    [ITLBCFG] = XTENSA_REG("ITLBCFG", XTENSA_OPTION_MMU), +    [DTLBCFG] = XTENSA_REG("DTLBCFG", XTENSA_OPTION_MMU), +    [IBREAKENABLE] = XTENSA_REG("IBREAKENABLE", XTENSA_OPTION_DEBUG), +    [CACHEATTR] = XTENSA_REG("CACHEATTR", XTENSA_OPTION_CACHEATTR), +    [ATOMCTL] = XTENSA_REG("ATOMCTL", XTENSA_OPTION_ATOMCTL), +    [IBREAKA] = XTENSA_REG("IBREAKA0", XTENSA_OPTION_DEBUG), +    [IBREAKA + 1] = XTENSA_REG("IBREAKA1", XTENSA_OPTION_DEBUG), +    [DBREAKA] = XTENSA_REG("DBREAKA0", XTENSA_OPTION_DEBUG), +    [DBREAKA + 1] = XTENSA_REG("DBREAKA1", XTENSA_OPTION_DEBUG), +    [DBREAKC] = XTENSA_REG("DBREAKC0", XTENSA_OPTION_DEBUG), +    [DBREAKC + 1] = XTENSA_REG("DBREAKC1", XTENSA_OPTION_DEBUG), +    [CONFIGID0] = XTENSA_REG_BITS_ACCESS("CONFIGID0", XTENSA_OPTION_ALL, SR_R), +    [EPC1] = XTENSA_REG("EPC1", XTENSA_OPTION_EXCEPTION), +    [EPC1 + 1] = XTENSA_REG("EPC2", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPC1 + 2] = XTENSA_REG("EPC3", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPC1 + 3] = XTENSA_REG("EPC4", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPC1 + 4] = XTENSA_REG("EPC5", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPC1 + 5] = XTENSA_REG("EPC6", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPC1 + 6] = XTENSA_REG("EPC7", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [DEPC] = XTENSA_REG("DEPC", XTENSA_OPTION_EXCEPTION), +    [EPS2] = XTENSA_REG("EPS2", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPS2 + 1] = XTENSA_REG("EPS3", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPS2 + 2] = XTENSA_REG("EPS4", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPS2 + 3] = XTENSA_REG("EPS5", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPS2 + 4] = XTENSA_REG("EPS6", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EPS2 + 5] = XTENSA_REG("EPS7", XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [CONFIGID1] = XTENSA_REG_BITS_ACCESS("CONFIGID1", XTENSA_OPTION_ALL, SR_R), +    [EXCSAVE1] = XTENSA_REG("EXCSAVE1", XTENSA_OPTION_EXCEPTION), +    [EXCSAVE1 + 1] = XTENSA_REG("EXCSAVE2", +            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EXCSAVE1 + 2] = XTENSA_REG("EXCSAVE3", +            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EXCSAVE1 + 3] = XTENSA_REG("EXCSAVE4", +            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EXCSAVE1 + 4] = XTENSA_REG("EXCSAVE5", +            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EXCSAVE1 + 5] = XTENSA_REG("EXCSAVE6", +            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [EXCSAVE1 + 6] = XTENSA_REG("EXCSAVE7", +            XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT), +    [CPENABLE] = XTENSA_REG("CPENABLE", XTENSA_OPTION_COPROCESSOR), +    [INTSET] = XTENSA_REG_ACCESS("INTSET", XTENSA_OPTION_INTERRUPT, SR_RW), +    [INTCLEAR] = XTENSA_REG_ACCESS("INTCLEAR", XTENSA_OPTION_INTERRUPT, SR_W), +    [INTENABLE] = XTENSA_REG("INTENABLE", XTENSA_OPTION_INTERRUPT), +    [PS] = XTENSA_REG_BITS("PS", XTENSA_OPTION_ALL), +    [VECBASE] = XTENSA_REG("VECBASE", XTENSA_OPTION_RELOCATABLE_VECTOR), +    [EXCCAUSE] = XTENSA_REG("EXCCAUSE", XTENSA_OPTION_EXCEPTION), +    [DEBUGCAUSE] = XTENSA_REG_ACCESS("DEBUGCAUSE", XTENSA_OPTION_DEBUG, SR_R), +    [CCOUNT] = XTENSA_REG("CCOUNT", XTENSA_OPTION_TIMER_INTERRUPT), +    [PRID] = XTENSA_REG_ACCESS("PRID", XTENSA_OPTION_PROCESSOR_ID, SR_R), +    [ICOUNT] = XTENSA_REG("ICOUNT", XTENSA_OPTION_DEBUG), +    [ICOUNTLEVEL] = XTENSA_REG("ICOUNTLEVEL", XTENSA_OPTION_DEBUG), +    [EXCVADDR] = XTENSA_REG("EXCVADDR", XTENSA_OPTION_EXCEPTION), +    [CCOMPARE] = XTENSA_REG("CCOMPARE0", XTENSA_OPTION_TIMER_INTERRUPT), +    [CCOMPARE + 1] = XTENSA_REG("CCOMPARE1", +            XTENSA_OPTION_TIMER_INTERRUPT), +    [CCOMPARE + 2] = XTENSA_REG("CCOMPARE2", +            XTENSA_OPTION_TIMER_INTERRUPT), +    [MISC] = XTENSA_REG("MISC0", XTENSA_OPTION_MISC_SR), +    [MISC + 1] = XTENSA_REG("MISC1", XTENSA_OPTION_MISC_SR), +    [MISC + 2] = XTENSA_REG("MISC2", XTENSA_OPTION_MISC_SR), +    [MISC + 3] = XTENSA_REG("MISC3", XTENSA_OPTION_MISC_SR), +}; + +static const XtensaReg uregnames[256] = { +    [THREADPTR] = XTENSA_REG("THREADPTR", XTENSA_OPTION_THREAD_POINTER), +    [FCR] = XTENSA_REG("FCR", XTENSA_OPTION_FP_COPROCESSOR), +    [FSR] = XTENSA_REG("FSR", XTENSA_OPTION_FP_COPROCESSOR), +}; + +void xtensa_translate_init(void) +{ +    static const char * const regnames[] = { +        "ar0", "ar1", "ar2", "ar3", +        "ar4", "ar5", "ar6", "ar7", +        "ar8", "ar9", "ar10", "ar11", +        "ar12", "ar13", "ar14", "ar15", +    }; +    static const char * const fregnames[] = { +        "f0", "f1", "f2", "f3", +        "f4", "f5", "f6", "f7", +        "f8", "f9", "f10", "f11", +        "f12", "f13", "f14", "f15", +    }; +    int i; + +    cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); +    cpu_pc = tcg_global_mem_new_i32(TCG_AREG0, +            offsetof(CPUXtensaState, pc), "pc"); + +    for (i = 0; i < 16; i++) { +        cpu_R[i] = tcg_global_mem_new_i32(TCG_AREG0, +                offsetof(CPUXtensaState, regs[i]), +                regnames[i]); +    } + +    for (i = 0; i < 16; i++) { +        cpu_FR[i] = tcg_global_mem_new_i32(TCG_AREG0, +                offsetof(CPUXtensaState, fregs[i].f32[FP_F32_LOW]), +                fregnames[i]); +    } + +    for (i = 0; i < 256; ++i) { +        if (sregnames[i].name) { +            cpu_SR[i] = tcg_global_mem_new_i32(TCG_AREG0, +                    offsetof(CPUXtensaState, sregs[i]), +                    sregnames[i].name); +        } +    } + +    for (i = 0; i < 256; ++i) { +        if (uregnames[i].name) { +            cpu_UR[i] = tcg_global_mem_new_i32(TCG_AREG0, +                    offsetof(CPUXtensaState, uregs[i]), +                    uregnames[i].name); +        } +    } +} + +static inline bool option_bits_enabled(DisasContext *dc, uint64_t opt) +{ +    return xtensa_option_bits_enabled(dc->config, opt); +} + +static inline bool option_enabled(DisasContext *dc, int opt) +{ +    return xtensa_option_enabled(dc->config, opt); +} + +static void init_litbase(DisasContext *dc) +{ +    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { +        dc->litbase = tcg_temp_local_new_i32(); +        tcg_gen_andi_i32(dc->litbase, cpu_SR[LITBASE], 0xfffff000); +    } +} + +static void reset_litbase(DisasContext *dc) +{ +    if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { +        tcg_temp_free(dc->litbase); +    } +} + +static void init_sar_tracker(DisasContext *dc) +{ +    dc->sar_5bit = false; +    dc->sar_m32_5bit = false; +    dc->sar_m32_allocated = false; +} + +static void reset_sar_tracker(DisasContext *dc) +{ +    if (dc->sar_m32_allocated) { +        tcg_temp_free(dc->sar_m32); +    } +} + +static void gen_right_shift_sar(DisasContext *dc, TCGv_i32 sa) +{ +    tcg_gen_andi_i32(cpu_SR[SAR], sa, 0x1f); +    if (dc->sar_m32_5bit) { +        tcg_gen_discard_i32(dc->sar_m32); +    } +    dc->sar_5bit = true; +    dc->sar_m32_5bit = false; +} + +static void gen_left_shift_sar(DisasContext *dc, TCGv_i32 sa) +{ +    TCGv_i32 tmp = tcg_const_i32(32); +    if (!dc->sar_m32_allocated) { +        dc->sar_m32 = tcg_temp_local_new_i32(); +        dc->sar_m32_allocated = true; +    } +    tcg_gen_andi_i32(dc->sar_m32, sa, 0x1f); +    tcg_gen_sub_i32(cpu_SR[SAR], tmp, dc->sar_m32); +    dc->sar_5bit = false; +    dc->sar_m32_5bit = true; +    tcg_temp_free(tmp); +} + +static void gen_advance_ccount(DisasContext *dc) +{ +    if (dc->ccount_delta > 0) { +        TCGv_i32 tmp = tcg_const_i32(dc->ccount_delta); +        gen_helper_advance_ccount(cpu_env, tmp); +        tcg_temp_free(tmp); +    } +    dc->ccount_delta = 0; +} + +static void gen_exception(DisasContext *dc, int excp) +{ +    TCGv_i32 tmp = tcg_const_i32(excp); +    gen_advance_ccount(dc); +    gen_helper_exception(cpu_env, tmp); +    tcg_temp_free(tmp); +} + +static void gen_exception_cause(DisasContext *dc, uint32_t cause) +{ +    TCGv_i32 tpc = tcg_const_i32(dc->pc); +    TCGv_i32 tcause = tcg_const_i32(cause); +    gen_advance_ccount(dc); +    gen_helper_exception_cause(cpu_env, tpc, tcause); +    tcg_temp_free(tpc); +    tcg_temp_free(tcause); +    if (cause == ILLEGAL_INSTRUCTION_CAUSE || +            cause == SYSCALL_CAUSE) { +        dc->is_jmp = DISAS_UPDATE; +    } +} + +static void gen_exception_cause_vaddr(DisasContext *dc, uint32_t cause, +        TCGv_i32 vaddr) +{ +    TCGv_i32 tpc = tcg_const_i32(dc->pc); +    TCGv_i32 tcause = tcg_const_i32(cause); +    gen_advance_ccount(dc); +    gen_helper_exception_cause_vaddr(cpu_env, tpc, tcause, vaddr); +    tcg_temp_free(tpc); +    tcg_temp_free(tcause); +} + +static void gen_debug_exception(DisasContext *dc, uint32_t cause) +{ +    TCGv_i32 tpc = tcg_const_i32(dc->pc); +    TCGv_i32 tcause = tcg_const_i32(cause); +    gen_advance_ccount(dc); +    gen_helper_debug_exception(cpu_env, tpc, tcause); +    tcg_temp_free(tpc); +    tcg_temp_free(tcause); +    if (cause & (DEBUGCAUSE_IB | DEBUGCAUSE_BI | DEBUGCAUSE_BN)) { +        dc->is_jmp = DISAS_UPDATE; +    } +} + +static bool gen_check_privilege(DisasContext *dc) +{ +    if (dc->cring) { +        gen_exception_cause(dc, PRIVILEGED_CAUSE); +        dc->is_jmp = DISAS_UPDATE; +        return false; +    } +    return true; +} + +static bool gen_check_cpenable(DisasContext *dc, unsigned cp) +{ +    if (option_enabled(dc, XTENSA_OPTION_COPROCESSOR) && +            !(dc->cpenable & (1 << cp))) { +        gen_exception_cause(dc, COPROCESSOR0_DISABLED + cp); +        dc->is_jmp = DISAS_UPDATE; +        return false; +    } +    return true; +} + +static void gen_jump_slot(DisasContext *dc, TCGv dest, int slot) +{ +    tcg_gen_mov_i32(cpu_pc, dest); +    gen_advance_ccount(dc); +    if (dc->icount) { +        tcg_gen_mov_i32(cpu_SR[ICOUNT], dc->next_icount); +    } +    if (dc->singlestep_enabled) { +        gen_exception(dc, EXCP_DEBUG); +    } else { +        if (slot >= 0) { +            tcg_gen_goto_tb(slot); +            tcg_gen_exit_tb((uintptr_t)dc->tb + slot); +        } else { +            tcg_gen_exit_tb(0); +        } +    } +    dc->is_jmp = DISAS_UPDATE; +} + +static void gen_jump(DisasContext *dc, TCGv dest) +{ +    gen_jump_slot(dc, dest, -1); +} + +static void gen_jumpi(DisasContext *dc, uint32_t dest, int slot) +{ +    TCGv_i32 tmp = tcg_const_i32(dest); +    if (((dc->tb->pc ^ dest) & TARGET_PAGE_MASK) != 0) { +        slot = -1; +    } +    gen_jump_slot(dc, tmp, slot); +    tcg_temp_free(tmp); +} + +static void gen_callw_slot(DisasContext *dc, int callinc, TCGv_i32 dest, +        int slot) +{ +    TCGv_i32 tcallinc = tcg_const_i32(callinc); + +    tcg_gen_deposit_i32(cpu_SR[PS], cpu_SR[PS], +            tcallinc, PS_CALLINC_SHIFT, PS_CALLINC_LEN); +    tcg_temp_free(tcallinc); +    tcg_gen_movi_i32(cpu_R[callinc << 2], +            (callinc << 30) | (dc->next_pc & 0x3fffffff)); +    gen_jump_slot(dc, dest, slot); +} + +static void gen_callw(DisasContext *dc, int callinc, TCGv_i32 dest) +{ +    gen_callw_slot(dc, callinc, dest, -1); +} + +static void gen_callwi(DisasContext *dc, int callinc, uint32_t dest, int slot) +{ +    TCGv_i32 tmp = tcg_const_i32(dest); +    if (((dc->tb->pc ^ dest) & TARGET_PAGE_MASK) != 0) { +        slot = -1; +    } +    gen_callw_slot(dc, callinc, tmp, slot); +    tcg_temp_free(tmp); +} + +static bool gen_check_loop_end(DisasContext *dc, int slot) +{ +    if (option_enabled(dc, XTENSA_OPTION_LOOP) && +            !(dc->tb->flags & XTENSA_TBFLAG_EXCM) && +            dc->next_pc == dc->lend) { +        TCGLabel *label = gen_new_label(); + +        gen_advance_ccount(dc); +        tcg_gen_brcondi_i32(TCG_COND_EQ, cpu_SR[LCOUNT], 0, label); +        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_SR[LCOUNT], 1); +        gen_jumpi(dc, dc->lbeg, slot); +        gen_set_label(label); +        gen_jumpi(dc, dc->next_pc, -1); +        return true; +    } +    return false; +} + +static void gen_jumpi_check_loop_end(DisasContext *dc, int slot) +{ +    if (!gen_check_loop_end(dc, slot)) { +        gen_jumpi(dc, dc->next_pc, slot); +    } +} + +static void gen_brcond(DisasContext *dc, TCGCond cond, +        TCGv_i32 t0, TCGv_i32 t1, uint32_t offset) +{ +    TCGLabel *label = gen_new_label(); + +    gen_advance_ccount(dc); +    tcg_gen_brcond_i32(cond, t0, t1, label); +    gen_jumpi_check_loop_end(dc, 0); +    gen_set_label(label); +    gen_jumpi(dc, dc->pc + offset, 1); +} + +static void gen_brcondi(DisasContext *dc, TCGCond cond, +        TCGv_i32 t0, uint32_t t1, uint32_t offset) +{ +    TCGv_i32 tmp = tcg_const_i32(t1); +    gen_brcond(dc, cond, t0, tmp, offset); +    tcg_temp_free(tmp); +} + +static bool gen_check_sr(DisasContext *dc, uint32_t sr, unsigned access) +{ +    if (!xtensa_option_bits_enabled(dc->config, sregnames[sr].opt_bits)) { +        if (sregnames[sr].name) { +            qemu_log("SR %s is not configured\n", sregnames[sr].name); +        } else { +            qemu_log("SR %d is not implemented\n", sr); +        } +        gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +        return false; +    } else if (!(sregnames[sr].access & access)) { +        static const char * const access_text[] = { +            [SR_R] = "rsr", +            [SR_W] = "wsr", +            [SR_X] = "xsr", +        }; +        assert(access < ARRAY_SIZE(access_text) && access_text[access]); +        qemu_log("SR %s is not available for %s\n", sregnames[sr].name, +                access_text[access]); +        gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +        return false; +    } +    return true; +} + +static void gen_rsr_ccount(DisasContext *dc, TCGv_i32 d, uint32_t sr) +{ +    gen_advance_ccount(dc); +    tcg_gen_mov_i32(d, cpu_SR[sr]); +} + +static void gen_rsr_ptevaddr(DisasContext *dc, TCGv_i32 d, uint32_t sr) +{ +    tcg_gen_shri_i32(d, cpu_SR[EXCVADDR], 10); +    tcg_gen_or_i32(d, d, cpu_SR[sr]); +    tcg_gen_andi_i32(d, d, 0xfffffffc); +} + +static void gen_rsr(DisasContext *dc, TCGv_i32 d, uint32_t sr) +{ +    static void (* const rsr_handler[256])(DisasContext *dc, +            TCGv_i32 d, uint32_t sr) = { +        [CCOUNT] = gen_rsr_ccount, +        [PTEVADDR] = gen_rsr_ptevaddr, +    }; + +    if (rsr_handler[sr]) { +        rsr_handler[sr](dc, d, sr); +    } else { +        tcg_gen_mov_i32(d, cpu_SR[sr]); +    } +} + +static void gen_wsr_lbeg(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ +    gen_helper_wsr_lbeg(cpu_env, s); +    gen_jumpi_check_loop_end(dc, 0); +} + +static void gen_wsr_lend(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ +    gen_helper_wsr_lend(cpu_env, s); +    gen_jumpi_check_loop_end(dc, 0); +} + +static void gen_wsr_sar(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ +    tcg_gen_andi_i32(cpu_SR[sr], s, 0x3f); +    if (dc->sar_m32_5bit) { +        tcg_gen_discard_i32(dc->sar_m32); +    } +    dc->sar_5bit = false; +    dc->sar_m32_5bit = false; +} + +static void gen_wsr_br(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ +    tcg_gen_andi_i32(cpu_SR[sr], s, 0xffff); +} + +static void gen_wsr_litbase(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ +    tcg_gen_andi_i32(cpu_SR[sr], s, 0xfffff001); +    /* This can change tb->flags, so exit tb */ +    gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_acchi(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ +    tcg_gen_ext8s_i32(cpu_SR[sr], s); +} + +static void gen_wsr_windowbase(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    gen_helper_wsr_windowbase(cpu_env, v); +    /* This can change tb->flags, so exit tb */ +    gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_windowstart(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_andi_i32(cpu_SR[sr], v, (1 << dc->config->nareg / 4) - 1); +    /* This can change tb->flags, so exit tb */ +    gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_ptevaddr(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_andi_i32(cpu_SR[sr], v, 0xffc00000); +} + +static void gen_wsr_rasid(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    gen_helper_wsr_rasid(cpu_env, v); +    /* This can change tb->flags, so exit tb */ +    gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_tlbcfg(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_andi_i32(cpu_SR[sr], v, 0x01130000); +} + +static void gen_wsr_ibreakenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    gen_helper_wsr_ibreakenable(cpu_env, v); +    gen_jumpi_check_loop_end(dc, 0); +} + +static void gen_wsr_atomctl(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_andi_i32(cpu_SR[sr], v, 0x3f); +} + +static void gen_wsr_ibreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    unsigned id = sr - IBREAKA; + +    if (id < dc->config->nibreak) { +        TCGv_i32 tmp = tcg_const_i32(id); +        gen_helper_wsr_ibreaka(cpu_env, tmp, v); +        tcg_temp_free(tmp); +        gen_jumpi_check_loop_end(dc, 0); +    } +} + +static void gen_wsr_dbreaka(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    unsigned id = sr - DBREAKA; + +    if (id < dc->config->ndbreak) { +        TCGv_i32 tmp = tcg_const_i32(id); +        gen_helper_wsr_dbreaka(cpu_env, tmp, v); +        tcg_temp_free(tmp); +    } +} + +static void gen_wsr_dbreakc(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    unsigned id = sr - DBREAKC; + +    if (id < dc->config->ndbreak) { +        TCGv_i32 tmp = tcg_const_i32(id); +        gen_helper_wsr_dbreakc(cpu_env, tmp, v); +        tcg_temp_free(tmp); +    } +} + +static void gen_wsr_cpenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_andi_i32(cpu_SR[sr], v, 0xff); +    /* This can change tb->flags, so exit tb */ +    gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_intset(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_andi_i32(cpu_SR[sr], v, +            dc->config->inttype_mask[INTTYPE_SOFTWARE]); +    gen_helper_check_interrupts(cpu_env); +    gen_jumpi_check_loop_end(dc, 0); +} + +static void gen_wsr_intclear(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    TCGv_i32 tmp = tcg_temp_new_i32(); + +    tcg_gen_andi_i32(tmp, v, +            dc->config->inttype_mask[INTTYPE_EDGE] | +            dc->config->inttype_mask[INTTYPE_NMI] | +            dc->config->inttype_mask[INTTYPE_SOFTWARE]); +    tcg_gen_andc_i32(cpu_SR[INTSET], cpu_SR[INTSET], tmp); +    tcg_temp_free(tmp); +    gen_helper_check_interrupts(cpu_env); +} + +static void gen_wsr_intenable(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_mov_i32(cpu_SR[sr], v); +    gen_helper_check_interrupts(cpu_env); +    gen_jumpi_check_loop_end(dc, 0); +} + +static void gen_wsr_ps(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    uint32_t mask = PS_WOE | PS_CALLINC | PS_OWB | +        PS_UM | PS_EXCM | PS_INTLEVEL; + +    if (option_enabled(dc, XTENSA_OPTION_MMU)) { +        mask |= PS_RING; +    } +    tcg_gen_andi_i32(cpu_SR[sr], v, mask); +    gen_helper_check_interrupts(cpu_env); +    /* This can change mmu index and tb->flags, so exit tb */ +    gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_icount(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    if (dc->icount) { +        tcg_gen_mov_i32(dc->next_icount, v); +    } else { +        tcg_gen_mov_i32(cpu_SR[sr], v); +    } +} + +static void gen_wsr_icountlevel(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    tcg_gen_andi_i32(cpu_SR[sr], v, 0xf); +    /* This can change tb->flags, so exit tb */ +    gen_jumpi_check_loop_end(dc, -1); +} + +static void gen_wsr_ccompare(DisasContext *dc, uint32_t sr, TCGv_i32 v) +{ +    uint32_t id = sr - CCOMPARE; +    if (id < dc->config->nccompare) { +        uint32_t int_bit = 1 << dc->config->timerint[id]; +        gen_advance_ccount(dc); +        tcg_gen_mov_i32(cpu_SR[sr], v); +        tcg_gen_andi_i32(cpu_SR[INTSET], cpu_SR[INTSET], ~int_bit); +        gen_helper_check_interrupts(cpu_env); +    } +} + +static void gen_wsr(DisasContext *dc, uint32_t sr, TCGv_i32 s) +{ +    static void (* const wsr_handler[256])(DisasContext *dc, +            uint32_t sr, TCGv_i32 v) = { +        [LBEG] = gen_wsr_lbeg, +        [LEND] = gen_wsr_lend, +        [SAR] = gen_wsr_sar, +        [BR] = gen_wsr_br, +        [LITBASE] = gen_wsr_litbase, +        [ACCHI] = gen_wsr_acchi, +        [WINDOW_BASE] = gen_wsr_windowbase, +        [WINDOW_START] = gen_wsr_windowstart, +        [PTEVADDR] = gen_wsr_ptevaddr, +        [RASID] = gen_wsr_rasid, +        [ITLBCFG] = gen_wsr_tlbcfg, +        [DTLBCFG] = gen_wsr_tlbcfg, +        [IBREAKENABLE] = gen_wsr_ibreakenable, +        [ATOMCTL] = gen_wsr_atomctl, +        [IBREAKA] = gen_wsr_ibreaka, +        [IBREAKA + 1] = gen_wsr_ibreaka, +        [DBREAKA] = gen_wsr_dbreaka, +        [DBREAKA + 1] = gen_wsr_dbreaka, +        [DBREAKC] = gen_wsr_dbreakc, +        [DBREAKC + 1] = gen_wsr_dbreakc, +        [CPENABLE] = gen_wsr_cpenable, +        [INTSET] = gen_wsr_intset, +        [INTCLEAR] = gen_wsr_intclear, +        [INTENABLE] = gen_wsr_intenable, +        [PS] = gen_wsr_ps, +        [ICOUNT] = gen_wsr_icount, +        [ICOUNTLEVEL] = gen_wsr_icountlevel, +        [CCOMPARE] = gen_wsr_ccompare, +        [CCOMPARE + 1] = gen_wsr_ccompare, +        [CCOMPARE + 2] = gen_wsr_ccompare, +    }; + +    if (wsr_handler[sr]) { +        wsr_handler[sr](dc, sr, s); +    } else { +        tcg_gen_mov_i32(cpu_SR[sr], s); +    } +} + +static void gen_wur(uint32_t ur, TCGv_i32 s) +{ +    switch (ur) { +    case FCR: +        gen_helper_wur_fcr(cpu_env, s); +        break; + +    case FSR: +        tcg_gen_andi_i32(cpu_UR[ur], s, 0xffffff80); +        break; + +    default: +        tcg_gen_mov_i32(cpu_UR[ur], s); +        break; +    } +} + +static void gen_load_store_alignment(DisasContext *dc, int shift, +        TCGv_i32 addr, bool no_hw_alignment) +{ +    if (!option_enabled(dc, XTENSA_OPTION_UNALIGNED_EXCEPTION)) { +        tcg_gen_andi_i32(addr, addr, ~0 << shift); +    } else if (option_enabled(dc, XTENSA_OPTION_HW_ALIGNMENT) && +            no_hw_alignment) { +        TCGLabel *label = gen_new_label(); +        TCGv_i32 tmp = tcg_temp_new_i32(); +        tcg_gen_andi_i32(tmp, addr, ~(~0 << shift)); +        tcg_gen_brcondi_i32(TCG_COND_EQ, tmp, 0, label); +        gen_exception_cause_vaddr(dc, LOAD_STORE_ALIGNMENT_CAUSE, addr); +        gen_set_label(label); +        tcg_temp_free(tmp); +    } +} + +static void gen_waiti(DisasContext *dc, uint32_t imm4) +{ +    TCGv_i32 pc = tcg_const_i32(dc->next_pc); +    TCGv_i32 intlevel = tcg_const_i32(imm4); +    gen_advance_ccount(dc); +    gen_helper_waiti(cpu_env, pc, intlevel); +    tcg_temp_free(pc); +    tcg_temp_free(intlevel); +} + +static bool gen_window_check1(DisasContext *dc, unsigned r1) +{ +    if (r1 / 4 > dc->window) { +        TCGv_i32 pc = tcg_const_i32(dc->pc); +        TCGv_i32 w = tcg_const_i32(r1 / 4); + +        gen_advance_ccount(dc); +        gen_helper_window_check(cpu_env, pc, w); +        dc->is_jmp = DISAS_UPDATE; +        return false; +    } +    return true; +} + +static bool gen_window_check2(DisasContext *dc, unsigned r1, unsigned r2) +{ +    return gen_window_check1(dc, r1 > r2 ? r1 : r2); +} + +static bool gen_window_check3(DisasContext *dc, unsigned r1, unsigned r2, +        unsigned r3) +{ +    return gen_window_check2(dc, r1, r2 > r3 ? r2 : r3); +} + +static TCGv_i32 gen_mac16_m(TCGv_i32 v, bool hi, bool is_unsigned) +{ +    TCGv_i32 m = tcg_temp_new_i32(); + +    if (hi) { +        (is_unsigned ? tcg_gen_shri_i32 : tcg_gen_sari_i32)(m, v, 16); +    } else { +        (is_unsigned ? tcg_gen_ext16u_i32 : tcg_gen_ext16s_i32)(m, v); +    } +    return m; +} + +static inline unsigned xtensa_op0_insn_len(unsigned op0) +{ +    return op0 >= 8 ? 2 : 3; +} + +static void disas_xtensa_insn(CPUXtensaState *env, DisasContext *dc) +{ +#define HAS_OPTION_BITS(opt) do { \ +        if (!option_bits_enabled(dc, opt)) { \ +            qemu_log("Option is not enabled %s:%d\n", \ +                    __FILE__, __LINE__); \ +            goto invalid_opcode; \ +        } \ +    } while (0) + +#define HAS_OPTION(opt) HAS_OPTION_BITS(XTENSA_OPTION_BIT(opt)) + +#define TBD() qemu_log("TBD(pc = %08x): %s:%d\n", dc->pc, __FILE__, __LINE__) +#define RESERVED() do { \ +        qemu_log("RESERVED(pc = %08x, %02x%02x%02x): %s:%d\n", \ +                dc->pc, b0, b1, b2, __FILE__, __LINE__); \ +        goto invalid_opcode; \ +    } while (0) + + +#ifdef TARGET_WORDS_BIGENDIAN +#define OP0 (((b0) & 0xf0) >> 4) +#define OP1 (((b2) & 0xf0) >> 4) +#define OP2 ((b2) & 0xf) +#define RRR_R ((b1) & 0xf) +#define RRR_S (((b1) & 0xf0) >> 4) +#define RRR_T ((b0) & 0xf) +#else +#define OP0 (((b0) & 0xf)) +#define OP1 (((b2) & 0xf)) +#define OP2 (((b2) & 0xf0) >> 4) +#define RRR_R (((b1) & 0xf0) >> 4) +#define RRR_S (((b1) & 0xf)) +#define RRR_T (((b0) & 0xf0) >> 4) +#endif +#define RRR_X ((RRR_R & 0x4) >> 2) +#define RRR_Y ((RRR_T & 0x4) >> 2) +#define RRR_W (RRR_R & 0x3) + +#define RRRN_R RRR_R +#define RRRN_S RRR_S +#define RRRN_T RRR_T + +#define RRI4_R RRR_R +#define RRI4_S RRR_S +#define RRI4_T RRR_T +#ifdef TARGET_WORDS_BIGENDIAN +#define RRI4_IMM4 ((b2) & 0xf) +#else +#define RRI4_IMM4 (((b2) & 0xf0) >> 4) +#endif + +#define RRI8_R RRR_R +#define RRI8_S RRR_S +#define RRI8_T RRR_T +#define RRI8_IMM8 (b2) +#define RRI8_IMM8_SE ((((b2) & 0x80) ? 0xffffff00 : 0) | RRI8_IMM8) + +#ifdef TARGET_WORDS_BIGENDIAN +#define RI16_IMM16 (((b1) << 8) | (b2)) +#else +#define RI16_IMM16 (((b2) << 8) | (b1)) +#endif + +#ifdef TARGET_WORDS_BIGENDIAN +#define CALL_N (((b0) & 0xc) >> 2) +#define CALL_OFFSET ((((b0) & 0x3) << 16) | ((b1) << 8) | (b2)) +#else +#define CALL_N (((b0) & 0x30) >> 4) +#define CALL_OFFSET ((((b0) & 0xc0) >> 6) | ((b1) << 2) | ((b2) << 10)) +#endif +#define CALL_OFFSET_SE \ +    (((CALL_OFFSET & 0x20000) ? 0xfffc0000 : 0) | CALL_OFFSET) + +#define CALLX_N CALL_N +#ifdef TARGET_WORDS_BIGENDIAN +#define CALLX_M ((b0) & 0x3) +#else +#define CALLX_M (((b0) & 0xc0) >> 6) +#endif +#define CALLX_S RRR_S + +#define BRI12_M CALLX_M +#define BRI12_S RRR_S +#ifdef TARGET_WORDS_BIGENDIAN +#define BRI12_IMM12 ((((b1) & 0xf) << 8) | (b2)) +#else +#define BRI12_IMM12 ((((b1) & 0xf0) >> 4) | ((b2) << 4)) +#endif +#define BRI12_IMM12_SE (((BRI12_IMM12 & 0x800) ? 0xfffff000 : 0) | BRI12_IMM12) + +#define BRI8_M BRI12_M +#define BRI8_R RRI8_R +#define BRI8_S RRI8_S +#define BRI8_IMM8 RRI8_IMM8 +#define BRI8_IMM8_SE RRI8_IMM8_SE + +#define RSR_SR (b1) + +    uint8_t b0 = cpu_ldub_code(env, dc->pc); +    uint8_t b1 = cpu_ldub_code(env, dc->pc + 1); +    uint8_t b2 = 0; +    unsigned len = xtensa_op0_insn_len(OP0); + +    static const uint32_t B4CONST[] = { +        0xffffffff, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256 +    }; + +    static const uint32_t B4CONSTU[] = { +        32768, 65536, 2, 3, 4, 5, 6, 7, 8, 10, 12, 16, 32, 64, 128, 256 +    }; + +    switch (len) { +    case 2: +        HAS_OPTION(XTENSA_OPTION_CODE_DENSITY); +        break; + +    case 3: +        b2 = cpu_ldub_code(env, dc->pc + 2); +        break; + +    default: +        RESERVED(); +    } +    dc->next_pc = dc->pc + len; + +    switch (OP0) { +    case 0: /*QRST*/ +        switch (OP1) { +        case 0: /*RST0*/ +            switch (OP2) { +            case 0: /*ST0*/ +                if ((RRR_R & 0xc) == 0x8) { +                    HAS_OPTION(XTENSA_OPTION_BOOLEAN); +                } + +                switch (RRR_R) { +                case 0: /*SNM0*/ +                    switch (CALLX_M) { +                    case 0: /*ILL*/ +                        gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +                        break; + +                    case 1: /*reserved*/ +                        RESERVED(); +                        break; + +                    case 2: /*JR*/ +                        switch (CALLX_N) { +                        case 0: /*RET*/ +                        case 2: /*JX*/ +                            if (gen_window_check1(dc, CALLX_S)) { +                                gen_jump(dc, cpu_R[CALLX_S]); +                            } +                            break; + +                        case 1: /*RETWw*/ +                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                            { +                                TCGv_i32 tmp = tcg_const_i32(dc->pc); +                                gen_advance_ccount(dc); +                                gen_helper_retw(tmp, cpu_env, tmp); +                                gen_jump(dc, tmp); +                                tcg_temp_free(tmp); +                            } +                            break; + +                        case 3: /*reserved*/ +                            RESERVED(); +                            break; +                        } +                        break; + +                    case 3: /*CALLX*/ +                        if (!gen_window_check2(dc, CALLX_S, CALLX_N << 2)) { +                            break; +                        } +                        switch (CALLX_N) { +                        case 0: /*CALLX0*/ +                            { +                                TCGv_i32 tmp = tcg_temp_new_i32(); +                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]); +                                tcg_gen_movi_i32(cpu_R[0], dc->next_pc); +                                gen_jump(dc, tmp); +                                tcg_temp_free(tmp); +                            } +                            break; + +                        case 1: /*CALLX4w*/ +                        case 2: /*CALLX8w*/ +                        case 3: /*CALLX12w*/ +                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                            { +                                TCGv_i32 tmp = tcg_temp_new_i32(); + +                                tcg_gen_mov_i32(tmp, cpu_R[CALLX_S]); +                                gen_callw(dc, CALLX_N, tmp); +                                tcg_temp_free(tmp); +                            } +                            break; +                        } +                        break; +                    } +                    break; + +                case 1: /*MOVSPw*/ +                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                    if (gen_window_check2(dc, RRR_T, RRR_S)) { +                        TCGv_i32 pc = tcg_const_i32(dc->pc); +                        gen_advance_ccount(dc); +                        gen_helper_movsp(cpu_env, pc); +                        tcg_gen_mov_i32(cpu_R[RRR_T], cpu_R[RRR_S]); +                        tcg_temp_free(pc); +                    } +                    break; + +                case 2: /*SYNC*/ +                    switch (RRR_T) { +                    case 0: /*ISYNC*/ +                        break; + +                    case 1: /*RSYNC*/ +                        break; + +                    case 2: /*ESYNC*/ +                        break; + +                    case 3: /*DSYNC*/ +                        break; + +                    case 8: /*EXCW*/ +                        HAS_OPTION(XTENSA_OPTION_EXCEPTION); +                        break; + +                    case 12: /*MEMW*/ +                        break; + +                    case 13: /*EXTW*/ +                        break; + +                    case 15: /*NOP*/ +                        break; + +                    default: /*reserved*/ +                        RESERVED(); +                        break; +                    } +                    break; + +                case 3: /*RFEIx*/ +                    switch (RRR_T) { +                    case 0: /*RFETx*/ +                        HAS_OPTION(XTENSA_OPTION_EXCEPTION); +                        switch (RRR_S) { +                        case 0: /*RFEx*/ +                            if (gen_check_privilege(dc)) { +                                tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); +                                gen_helper_check_interrupts(cpu_env); +                                gen_jump(dc, cpu_SR[EPC1]); +                            } +                            break; + +                        case 1: /*RFUEx*/ +                            RESERVED(); +                            break; + +                        case 2: /*RFDEx*/ +                            if (gen_check_privilege(dc)) { +                                gen_jump(dc, cpu_SR[ +                                         dc->config->ndepc ? DEPC : EPC1]); +                            } +                            break; + +                        case 4: /*RFWOw*/ +                        case 5: /*RFWUw*/ +                            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                            if (gen_check_privilege(dc)) { +                                TCGv_i32 tmp = tcg_const_i32(1); + +                                tcg_gen_andi_i32( +                                        cpu_SR[PS], cpu_SR[PS], ~PS_EXCM); +                                tcg_gen_shl_i32(tmp, tmp, cpu_SR[WINDOW_BASE]); + +                                if (RRR_S == 4) { +                                    tcg_gen_andc_i32(cpu_SR[WINDOW_START], +                                            cpu_SR[WINDOW_START], tmp); +                                } else { +                                    tcg_gen_or_i32(cpu_SR[WINDOW_START], +                                            cpu_SR[WINDOW_START], tmp); +                                } + +                                gen_helper_restore_owb(cpu_env); +                                gen_helper_check_interrupts(cpu_env); +                                gen_jump(dc, cpu_SR[EPC1]); + +                                tcg_temp_free(tmp); +                            } +                            break; + +                        default: /*reserved*/ +                            RESERVED(); +                            break; +                        } +                        break; + +                    case 1: /*RFIx*/ +                        HAS_OPTION(XTENSA_OPTION_HIGH_PRIORITY_INTERRUPT); +                        if (RRR_S >= 2 && RRR_S <= dc->config->nlevel) { +                            if (gen_check_privilege(dc)) { +                                tcg_gen_mov_i32(cpu_SR[PS], +                                                cpu_SR[EPS2 + RRR_S - 2]); +                                gen_helper_check_interrupts(cpu_env); +                                gen_jump(dc, cpu_SR[EPC1 + RRR_S - 1]); +                            } +                        } else { +                            qemu_log("RFI %d is illegal\n", RRR_S); +                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +                        } +                        break; + +                    case 2: /*RFME*/ +                        TBD(); +                        break; + +                    default: /*reserved*/ +                        RESERVED(); +                        break; + +                    } +                    break; + +                case 4: /*BREAKx*/ +                    HAS_OPTION(XTENSA_OPTION_DEBUG); +                    if (dc->debug) { +                        gen_debug_exception(dc, DEBUGCAUSE_BI); +                    } +                    break; + +                case 5: /*SYSCALLx*/ +                    HAS_OPTION(XTENSA_OPTION_EXCEPTION); +                    switch (RRR_S) { +                    case 0: /*SYSCALLx*/ +                        gen_exception_cause(dc, SYSCALL_CAUSE); +                        break; + +                    case 1: /*SIMCALL*/ +                        if (semihosting_enabled()) { +                            if (gen_check_privilege(dc)) { +                                gen_helper_simcall(cpu_env); +                            } +                        } else { +                            qemu_log("SIMCALL but semihosting is disabled\n"); +                            gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +                        } +                        break; + +                    default: +                        RESERVED(); +                        break; +                    } +                    break; + +                case 6: /*RSILx*/ +                    HAS_OPTION(XTENSA_OPTION_INTERRUPT); +                    if (gen_check_privilege(dc) && +                        gen_window_check1(dc, RRR_T)) { +                        tcg_gen_mov_i32(cpu_R[RRR_T], cpu_SR[PS]); +                        tcg_gen_andi_i32(cpu_SR[PS], cpu_SR[PS], ~PS_INTLEVEL); +                        tcg_gen_ori_i32(cpu_SR[PS], cpu_SR[PS], RRR_S); +                        gen_helper_check_interrupts(cpu_env); +                        gen_jumpi_check_loop_end(dc, 0); +                    } +                    break; + +                case 7: /*WAITIx*/ +                    HAS_OPTION(XTENSA_OPTION_INTERRUPT); +                    if (gen_check_privilege(dc)) { +                        gen_waiti(dc, RRR_S); +                    } +                    break; + +                case 8: /*ANY4p*/ +                case 9: /*ALL4p*/ +                case 10: /*ANY8p*/ +                case 11: /*ALL8p*/ +                    HAS_OPTION(XTENSA_OPTION_BOOLEAN); +                    { +                        const unsigned shift = (RRR_R & 2) ? 8 : 4; +                        TCGv_i32 mask = tcg_const_i32( +                                ((1 << shift) - 1) << RRR_S); +                        TCGv_i32 tmp = tcg_temp_new_i32(); + +                        tcg_gen_and_i32(tmp, cpu_SR[BR], mask); +                        if (RRR_R & 1) { /*ALL*/ +                            tcg_gen_addi_i32(tmp, tmp, 1 << RRR_S); +                        } else { /*ANY*/ +                            tcg_gen_add_i32(tmp, tmp, mask); +                        } +                        tcg_gen_shri_i32(tmp, tmp, RRR_S + shift); +                        tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], +                                tmp, RRR_T, 1); +                        tcg_temp_free(mask); +                        tcg_temp_free(tmp); +                    } +                    break; + +                default: /*reserved*/ +                    RESERVED(); +                    break; + +                } +                break; + +            case 1: /*AND*/ +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    tcg_gen_and_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                } +                break; + +            case 2: /*OR*/ +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    tcg_gen_or_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                } +                break; + +            case 3: /*XOR*/ +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    tcg_gen_xor_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                } +                break; + +            case 4: /*ST1*/ +                switch (RRR_R) { +                case 0: /*SSR*/ +                    if (gen_window_check1(dc, RRR_S)) { +                        gen_right_shift_sar(dc, cpu_R[RRR_S]); +                    } +                    break; + +                case 1: /*SSL*/ +                    if (gen_window_check1(dc, RRR_S)) { +                        gen_left_shift_sar(dc, cpu_R[RRR_S]); +                    } +                    break; + +                case 2: /*SSA8L*/ +                    if (gen_window_check1(dc, RRR_S)) { +                        TCGv_i32 tmp = tcg_temp_new_i32(); +                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); +                        gen_right_shift_sar(dc, tmp); +                        tcg_temp_free(tmp); +                    } +                    break; + +                case 3: /*SSA8B*/ +                    if (gen_window_check1(dc, RRR_S)) { +                        TCGv_i32 tmp = tcg_temp_new_i32(); +                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], 3); +                        gen_left_shift_sar(dc, tmp); +                        tcg_temp_free(tmp); +                    } +                    break; + +                case 4: /*SSAI*/ +                    { +                        TCGv_i32 tmp = tcg_const_i32( +                                RRR_S | ((RRR_T & 1) << 4)); +                        gen_right_shift_sar(dc, tmp); +                        tcg_temp_free(tmp); +                    } +                    break; + +                case 6: /*RER*/ +                    TBD(); +                    break; + +                case 7: /*WER*/ +                    TBD(); +                    break; + +                case 8: /*ROTWw*/ +                    HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                    if (gen_check_privilege(dc)) { +                        TCGv_i32 tmp = tcg_const_i32( +                                RRR_T | ((RRR_T & 8) ? 0xfffffff0 : 0)); +                        gen_helper_rotw(cpu_env, tmp); +                        tcg_temp_free(tmp); +                        /* This can change tb->flags, so exit tb */ +                        gen_jumpi_check_loop_end(dc, -1); +                    } +                    break; + +                case 14: /*NSAu*/ +                    HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA); +                    if (gen_window_check2(dc, RRR_S, RRR_T)) { +                        gen_helper_nsa(cpu_R[RRR_T], cpu_R[RRR_S]); +                    } +                    break; + +                case 15: /*NSAUu*/ +                    HAS_OPTION(XTENSA_OPTION_MISC_OP_NSA); +                    if (gen_window_check2(dc, RRR_S, RRR_T)) { +                        gen_helper_nsau(cpu_R[RRR_T], cpu_R[RRR_S]); +                    } +                    break; + +                default: /*reserved*/ +                    RESERVED(); +                    break; +                } +                break; + +            case 5: /*TLB*/ +                HAS_OPTION_BITS( +                        XTENSA_OPTION_BIT(XTENSA_OPTION_MMU) | +                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_PROTECTION) | +                        XTENSA_OPTION_BIT(XTENSA_OPTION_REGION_TRANSLATION)); +                if (gen_check_privilege(dc) && +                    gen_window_check2(dc, RRR_S, RRR_T)) { +                    TCGv_i32 dtlb = tcg_const_i32((RRR_R & 8) != 0); + +                    switch (RRR_R & 7) { +                    case 3: /*RITLB0*/ /*RDTLB0*/ +                        gen_helper_rtlb0(cpu_R[RRR_T], +                                cpu_env, cpu_R[RRR_S], dtlb); +                        break; + +                    case 4: /*IITLB*/ /*IDTLB*/ +                        gen_helper_itlb(cpu_env, cpu_R[RRR_S], dtlb); +                        /* This could change memory mapping, so exit tb */ +                        gen_jumpi_check_loop_end(dc, -1); +                        break; + +                    case 5: /*PITLB*/ /*PDTLB*/ +                        tcg_gen_movi_i32(cpu_pc, dc->pc); +                        gen_helper_ptlb(cpu_R[RRR_T], +                                cpu_env, cpu_R[RRR_S], dtlb); +                        break; + +                    case 6: /*WITLB*/ /*WDTLB*/ +                        gen_helper_wtlb( +                                cpu_env, cpu_R[RRR_T], cpu_R[RRR_S], dtlb); +                        /* This could change memory mapping, so exit tb */ +                        gen_jumpi_check_loop_end(dc, -1); +                        break; + +                    case 7: /*RITLB1*/ /*RDTLB1*/ +                        gen_helper_rtlb1(cpu_R[RRR_T], +                                cpu_env, cpu_R[RRR_S], dtlb); +                        break; + +                    default: +                        tcg_temp_free(dtlb); +                        RESERVED(); +                        break; +                    } +                    tcg_temp_free(dtlb); +                } +                break; + +            case 6: /*RT0*/ +                if (!gen_window_check2(dc, RRR_R, RRR_T)) { +                    break; +                } +                switch (RRR_S) { +                case 0: /*NEG*/ +                    tcg_gen_neg_i32(cpu_R[RRR_R], cpu_R[RRR_T]); +                    break; + +                case 1: /*ABS*/ +                    { +                        TCGv_i32 zero = tcg_const_i32(0); +                        TCGv_i32 neg = tcg_temp_new_i32(); + +                        tcg_gen_neg_i32(neg, cpu_R[RRR_T]); +                        tcg_gen_movcond_i32(TCG_COND_GE, cpu_R[RRR_R], +                                cpu_R[RRR_T], zero, cpu_R[RRR_T], neg); +                        tcg_temp_free(neg); +                        tcg_temp_free(zero); +                    } +                    break; + +                default: /*reserved*/ +                    RESERVED(); +                    break; +                } +                break; + +            case 7: /*reserved*/ +                RESERVED(); +                break; + +            case 8: /*ADD*/ +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    tcg_gen_add_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                } +                break; + +            case 9: /*ADD**/ +            case 10: +            case 11: +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    TCGv_i32 tmp = tcg_temp_new_i32(); +                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 8); +                    tcg_gen_add_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]); +                    tcg_temp_free(tmp); +                } +                break; + +            case 12: /*SUB*/ +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    tcg_gen_sub_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                } +                break; + +            case 13: /*SUB**/ +            case 14: +            case 15: +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    TCGv_i32 tmp = tcg_temp_new_i32(); +                    tcg_gen_shli_i32(tmp, cpu_R[RRR_S], OP2 - 12); +                    tcg_gen_sub_i32(cpu_R[RRR_R], tmp, cpu_R[RRR_T]); +                    tcg_temp_free(tmp); +                } +                break; +            } +            break; + +        case 1: /*RST1*/ +            switch (OP2) { +            case 0: /*SLLI*/ +            case 1: +                if (gen_window_check2(dc, RRR_R, RRR_S)) { +                    tcg_gen_shli_i32(cpu_R[RRR_R], cpu_R[RRR_S], +                                     32 - (RRR_T | ((OP2 & 1) << 4))); +                } +                break; + +            case 2: /*SRAI*/ +            case 3: +                if (gen_window_check2(dc, RRR_R, RRR_T)) { +                    tcg_gen_sari_i32(cpu_R[RRR_R], cpu_R[RRR_T], +                                     RRR_S | ((OP2 & 1) << 4)); +                } +                break; + +            case 4: /*SRLI*/ +                if (gen_window_check2(dc, RRR_R, RRR_T)) { +                    tcg_gen_shri_i32(cpu_R[RRR_R], cpu_R[RRR_T], RRR_S); +                } +                break; + +            case 6: /*XSR*/ +                if (gen_check_sr(dc, RSR_SR, SR_X) && +                    (RSR_SR < 64 || gen_check_privilege(dc)) && +                    gen_window_check1(dc, RRR_T)) { +                    TCGv_i32 tmp = tcg_temp_new_i32(); + +                    tcg_gen_mov_i32(tmp, cpu_R[RRR_T]); +                    gen_rsr(dc, cpu_R[RRR_T], RSR_SR); +                    gen_wsr(dc, RSR_SR, tmp); +                    tcg_temp_free(tmp); +                } +                break; + +                /* +                 * Note: 64 bit ops are used here solely because SAR values +                 * have range 0..63 +                 */ +#define gen_shift_reg(cmd, reg) do { \ +                    TCGv_i64 tmp = tcg_temp_new_i64(); \ +                    tcg_gen_extu_i32_i64(tmp, reg); \ +                    tcg_gen_##cmd##_i64(v, v, tmp); \ +                    tcg_gen_trunc_i64_i32(cpu_R[RRR_R], v); \ +                    tcg_temp_free_i64(v); \ +                    tcg_temp_free_i64(tmp); \ +                } while (0) + +#define gen_shift(cmd) gen_shift_reg(cmd, cpu_SR[SAR]) + +            case 8: /*SRC*/ +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    TCGv_i64 v = tcg_temp_new_i64(); +                    tcg_gen_concat_i32_i64(v, cpu_R[RRR_T], cpu_R[RRR_S]); +                    gen_shift(shr); +                } +                break; + +            case 9: /*SRL*/ +                if (!gen_window_check2(dc, RRR_R, RRR_T)) { +                    break; +                } +                if (dc->sar_5bit) { +                    tcg_gen_shr_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); +                } else { +                    TCGv_i64 v = tcg_temp_new_i64(); +                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_T]); +                    gen_shift(shr); +                } +                break; + +            case 10: /*SLL*/ +                if (!gen_window_check2(dc, RRR_R, RRR_S)) { +                    break; +                } +                if (dc->sar_m32_5bit) { +                    tcg_gen_shl_i32(cpu_R[RRR_R], cpu_R[RRR_S], dc->sar_m32); +                } else { +                    TCGv_i64 v = tcg_temp_new_i64(); +                    TCGv_i32 s = tcg_const_i32(32); +                    tcg_gen_sub_i32(s, s, cpu_SR[SAR]); +                    tcg_gen_andi_i32(s, s, 0x3f); +                    tcg_gen_extu_i32_i64(v, cpu_R[RRR_S]); +                    gen_shift_reg(shl, s); +                    tcg_temp_free(s); +                } +                break; + +            case 11: /*SRA*/ +                if (!gen_window_check2(dc, RRR_R, RRR_T)) { +                    break; +                } +                if (dc->sar_5bit) { +                    tcg_gen_sar_i32(cpu_R[RRR_R], cpu_R[RRR_T], cpu_SR[SAR]); +                } else { +                    TCGv_i64 v = tcg_temp_new_i64(); +                    tcg_gen_ext_i32_i64(v, cpu_R[RRR_T]); +                    gen_shift(sar); +                } +                break; +#undef gen_shift +#undef gen_shift_reg + +            case 12: /*MUL16U*/ +                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    TCGv_i32 v1 = tcg_temp_new_i32(); +                    TCGv_i32 v2 = tcg_temp_new_i32(); +                    tcg_gen_ext16u_i32(v1, cpu_R[RRR_S]); +                    tcg_gen_ext16u_i32(v2, cpu_R[RRR_T]); +                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2); +                    tcg_temp_free(v2); +                    tcg_temp_free(v1); +                } +                break; + +            case 13: /*MUL16S*/ +                HAS_OPTION(XTENSA_OPTION_16_BIT_IMUL); +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    TCGv_i32 v1 = tcg_temp_new_i32(); +                    TCGv_i32 v2 = tcg_temp_new_i32(); +                    tcg_gen_ext16s_i32(v1, cpu_R[RRR_S]); +                    tcg_gen_ext16s_i32(v2, cpu_R[RRR_T]); +                    tcg_gen_mul_i32(cpu_R[RRR_R], v1, v2); +                    tcg_temp_free(v2); +                    tcg_temp_free(v1); +                } +                break; + +            default: /*reserved*/ +                RESERVED(); +                break; +            } +            break; + +        case 2: /*RST2*/ +            if (OP2 >= 8 && !gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                break; +            } + +            if (OP2 >= 12) { +                HAS_OPTION(XTENSA_OPTION_32_BIT_IDIV); +                TCGLabel *label = gen_new_label(); +                tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0, label); +                gen_exception_cause(dc, INTEGER_DIVIDE_BY_ZERO_CAUSE); +                gen_set_label(label); +            } + +            switch (OP2) { +#define BOOLEAN_LOGIC(fn, r, s, t) \ +                do { \ +                    HAS_OPTION(XTENSA_OPTION_BOOLEAN); \ +                    TCGv_i32 tmp1 = tcg_temp_new_i32(); \ +                    TCGv_i32 tmp2 = tcg_temp_new_i32(); \ +                    \ +                    tcg_gen_shri_i32(tmp1, cpu_SR[BR], s); \ +                    tcg_gen_shri_i32(tmp2, cpu_SR[BR], t); \ +                    tcg_gen_##fn##_i32(tmp1, tmp1, tmp2); \ +                    tcg_gen_deposit_i32(cpu_SR[BR], cpu_SR[BR], tmp1, r, 1); \ +                    tcg_temp_free(tmp1); \ +                    tcg_temp_free(tmp2); \ +                } while (0) + +            case 0: /*ANDBp*/ +                BOOLEAN_LOGIC(and, RRR_R, RRR_S, RRR_T); +                break; + +            case 1: /*ANDBCp*/ +                BOOLEAN_LOGIC(andc, RRR_R, RRR_S, RRR_T); +                break; + +            case 2: /*ORBp*/ +                BOOLEAN_LOGIC(or, RRR_R, RRR_S, RRR_T); +                break; + +            case 3: /*ORBCp*/ +                BOOLEAN_LOGIC(orc, RRR_R, RRR_S, RRR_T); +                break; + +            case 4: /*XORBp*/ +                BOOLEAN_LOGIC(xor, RRR_R, RRR_S, RRR_T); +                break; + +#undef BOOLEAN_LOGIC + +            case 8: /*MULLi*/ +                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL); +                tcg_gen_mul_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                break; + +            case 10: /*MULUHi*/ +            case 11: /*MULSHi*/ +                HAS_OPTION(XTENSA_OPTION_32_BIT_IMUL_HIGH); +                { +                    TCGv lo = tcg_temp_new(); + +                    if (OP2 == 10) { +                        tcg_gen_mulu2_i32(lo, cpu_R[RRR_R], +                                          cpu_R[RRR_S], cpu_R[RRR_T]); +                    } else { +                        tcg_gen_muls2_i32(lo, cpu_R[RRR_R], +                                          cpu_R[RRR_S], cpu_R[RRR_T]); +                    } +                    tcg_temp_free(lo); +                } +                break; + +            case 12: /*QUOUi*/ +                tcg_gen_divu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                break; + +            case 13: /*QUOSi*/ +            case 15: /*REMSi*/ +                { +                    TCGLabel *label1 = gen_new_label(); +                    TCGLabel *label2 = gen_new_label(); + +                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_S], 0x80000000, +                            label1); +                    tcg_gen_brcondi_i32(TCG_COND_NE, cpu_R[RRR_T], 0xffffffff, +                            label1); +                    tcg_gen_movi_i32(cpu_R[RRR_R], +                            OP2 == 13 ? 0x80000000 : 0); +                    tcg_gen_br(label2); +                    gen_set_label(label1); +                    if (OP2 == 13) { +                        tcg_gen_div_i32(cpu_R[RRR_R], +                                cpu_R[RRR_S], cpu_R[RRR_T]); +                    } else { +                        tcg_gen_rem_i32(cpu_R[RRR_R], +                                cpu_R[RRR_S], cpu_R[RRR_T]); +                    } +                    gen_set_label(label2); +                } +                break; + +            case 14: /*REMUi*/ +                tcg_gen_remu_i32(cpu_R[RRR_R], cpu_R[RRR_S], cpu_R[RRR_T]); +                break; + +            default: /*reserved*/ +                RESERVED(); +                break; +            } +            break; + +        case 3: /*RST3*/ +            switch (OP2) { +            case 0: /*RSR*/ +                if (gen_check_sr(dc, RSR_SR, SR_R) && +                    (RSR_SR < 64 || gen_check_privilege(dc)) && +                    gen_window_check1(dc, RRR_T)) { +                    gen_rsr(dc, cpu_R[RRR_T], RSR_SR); +                } +                break; + +            case 1: /*WSR*/ +                if (gen_check_sr(dc, RSR_SR, SR_W) && +                    (RSR_SR < 64 || gen_check_privilege(dc)) && +                    gen_window_check1(dc, RRR_T)) { +                    gen_wsr(dc, RSR_SR, cpu_R[RRR_T]); +                } +                break; + +            case 2: /*SEXTu*/ +                HAS_OPTION(XTENSA_OPTION_MISC_OP_SEXT); +                if (gen_window_check2(dc, RRR_R, RRR_S)) { +                    int shift = 24 - RRR_T; + +                    if (shift == 24) { +                        tcg_gen_ext8s_i32(cpu_R[RRR_R], cpu_R[RRR_S]); +                    } else if (shift == 16) { +                        tcg_gen_ext16s_i32(cpu_R[RRR_R], cpu_R[RRR_S]); +                    } else { +                        TCGv_i32 tmp = tcg_temp_new_i32(); +                        tcg_gen_shli_i32(tmp, cpu_R[RRR_S], shift); +                        tcg_gen_sari_i32(cpu_R[RRR_R], tmp, shift); +                        tcg_temp_free(tmp); +                    } +                } +                break; + +            case 3: /*CLAMPSu*/ +                HAS_OPTION(XTENSA_OPTION_MISC_OP_CLAMPS); +                if (gen_window_check2(dc, RRR_R, RRR_S)) { +                    TCGv_i32 tmp1 = tcg_temp_new_i32(); +                    TCGv_i32 tmp2 = tcg_temp_new_i32(); +                    TCGv_i32 zero = tcg_const_i32(0); + +                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 24 - RRR_T); +                    tcg_gen_xor_i32(tmp2, tmp1, cpu_R[RRR_S]); +                    tcg_gen_andi_i32(tmp2, tmp2, 0xffffffff << (RRR_T + 7)); + +                    tcg_gen_sari_i32(tmp1, cpu_R[RRR_S], 31); +                    tcg_gen_xori_i32(tmp1, tmp1, 0xffffffff >> (25 - RRR_T)); + +                    tcg_gen_movcond_i32(TCG_COND_EQ, cpu_R[RRR_R], tmp2, zero, +                            cpu_R[RRR_S], tmp1); +                    tcg_temp_free(tmp1); +                    tcg_temp_free(tmp2); +                    tcg_temp_free(zero); +                } +                break; + +            case 4: /*MINu*/ +            case 5: /*MAXu*/ +            case 6: /*MINUu*/ +            case 7: /*MAXUu*/ +                HAS_OPTION(XTENSA_OPTION_MISC_OP_MINMAX); +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    static const TCGCond cond[] = { +                        TCG_COND_LE, +                        TCG_COND_GE, +                        TCG_COND_LEU, +                        TCG_COND_GEU +                    }; +                    tcg_gen_movcond_i32(cond[OP2 - 4], cpu_R[RRR_R], +                            cpu_R[RRR_S], cpu_R[RRR_T], +                            cpu_R[RRR_S], cpu_R[RRR_T]); +                } +                break; + +            case 8: /*MOVEQZ*/ +            case 9: /*MOVNEZ*/ +            case 10: /*MOVLTZ*/ +            case 11: /*MOVGEZ*/ +                if (gen_window_check3(dc, RRR_R, RRR_S, RRR_T)) { +                    static const TCGCond cond[] = { +                        TCG_COND_EQ, +                        TCG_COND_NE, +                        TCG_COND_LT, +                        TCG_COND_GE, +                    }; +                    TCGv_i32 zero = tcg_const_i32(0); + +                    tcg_gen_movcond_i32(cond[OP2 - 8], cpu_R[RRR_R], +                            cpu_R[RRR_T], zero, cpu_R[RRR_S], cpu_R[RRR_R]); +                    tcg_temp_free(zero); +                } +                break; + +            case 12: /*MOVFp*/ +            case 13: /*MOVTp*/ +                HAS_OPTION(XTENSA_OPTION_BOOLEAN); +                if (gen_window_check2(dc, RRR_R, RRR_S)) { +                    TCGv_i32 zero = tcg_const_i32(0); +                    TCGv_i32 tmp = tcg_temp_new_i32(); + +                    tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T); +                    tcg_gen_movcond_i32(OP2 & 1 ? TCG_COND_NE : TCG_COND_EQ, +                            cpu_R[RRR_R], tmp, zero, +                            cpu_R[RRR_S], cpu_R[RRR_R]); + +                    tcg_temp_free(tmp); +                    tcg_temp_free(zero); +                } +                break; + +            case 14: /*RUR*/ +                if (gen_window_check1(dc, RRR_R)) { +                    int st = (RRR_S << 4) + RRR_T; +                    if (uregnames[st].name) { +                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_UR[st]); +                    } else { +                        qemu_log("RUR %d not implemented, ", st); +                        TBD(); +                    } +                } +                break; + +            case 15: /*WUR*/ +                if (gen_window_check1(dc, RRR_T)) { +                    if (uregnames[RSR_SR].name) { +                        gen_wur(RSR_SR, cpu_R[RRR_T]); +                    } else { +                        qemu_log("WUR %d not implemented, ", RSR_SR); +                        TBD(); +                    } +                } +                break; + +            } +            break; + +        case 4: /*EXTUI*/ +        case 5: +            if (gen_window_check2(dc, RRR_R, RRR_T)) { +                int shiftimm = RRR_S | ((OP1 & 1) << 4); +                int maskimm = (1 << (OP2 + 1)) - 1; + +                TCGv_i32 tmp = tcg_temp_new_i32(); +                tcg_gen_shri_i32(tmp, cpu_R[RRR_T], shiftimm); +                tcg_gen_andi_i32(cpu_R[RRR_R], tmp, maskimm); +                tcg_temp_free(tmp); +            } +            break; + +        case 6: /*CUST0*/ +            RESERVED(); +            break; + +        case 7: /*CUST1*/ +            RESERVED(); +            break; + +        case 8: /*LSCXp*/ +            switch (OP2) { +            case 0: /*LSXf*/ +            case 1: /*LSXUf*/ +            case 4: /*SSXf*/ +            case 5: /*SSXUf*/ +                HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); +                if (gen_window_check2(dc, RRR_S, RRR_T) && +                    gen_check_cpenable(dc, 0)) { +                    TCGv_i32 addr = tcg_temp_new_i32(); +                    tcg_gen_add_i32(addr, cpu_R[RRR_S], cpu_R[RRR_T]); +                    gen_load_store_alignment(dc, 2, addr, false); +                    if (OP2 & 0x4) { +                        tcg_gen_qemu_st32(cpu_FR[RRR_R], addr, dc->cring); +                    } else { +                        tcg_gen_qemu_ld32u(cpu_FR[RRR_R], addr, dc->cring); +                    } +                    if (OP2 & 0x1) { +                        tcg_gen_mov_i32(cpu_R[RRR_S], addr); +                    } +                    tcg_temp_free(addr); +                } +                break; + +            default: /*reserved*/ +                RESERVED(); +                break; +            } +            break; + +        case 9: /*LSC4*/ +            if (!gen_window_check2(dc, RRR_S, RRR_T)) { +                break; +            } +            switch (OP2) { +            case 0: /*L32E*/ +                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                if (gen_check_privilege(dc) && +                    gen_window_check2(dc, RRR_S, RRR_T)) { +                    TCGv_i32 addr = tcg_temp_new_i32(); +                    tcg_gen_addi_i32(addr, cpu_R[RRR_S], +                            (0xffffffc0 | (RRR_R << 2))); +                    tcg_gen_qemu_ld32u(cpu_R[RRR_T], addr, dc->ring); +                    tcg_temp_free(addr); +                } +                break; + +            case 4: /*S32E*/ +                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                if (gen_check_privilege(dc) && +                    gen_window_check2(dc, RRR_S, RRR_T)) { +                    TCGv_i32 addr = tcg_temp_new_i32(); +                    tcg_gen_addi_i32(addr, cpu_R[RRR_S], +                            (0xffffffc0 | (RRR_R << 2))); +                    tcg_gen_qemu_st32(cpu_R[RRR_T], addr, dc->ring); +                    tcg_temp_free(addr); +                } +                break; + +            default: +                RESERVED(); +                break; +            } +            break; + +        case 10: /*FP0*/ +            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); +            switch (OP2) { +            case 0: /*ADD.Sf*/ +                if (gen_check_cpenable(dc, 0)) { +                    gen_helper_add_s(cpu_FR[RRR_R], cpu_env, +                                     cpu_FR[RRR_S], cpu_FR[RRR_T]); +                } +                break; + +            case 1: /*SUB.Sf*/ +                if (gen_check_cpenable(dc, 0)) { +                    gen_helper_sub_s(cpu_FR[RRR_R], cpu_env, +                                     cpu_FR[RRR_S], cpu_FR[RRR_T]); +                } +                break; + +            case 2: /*MUL.Sf*/ +                if (gen_check_cpenable(dc, 0)) { +                    gen_helper_mul_s(cpu_FR[RRR_R], cpu_env, +                                     cpu_FR[RRR_S], cpu_FR[RRR_T]); +                } +                break; + +            case 4: /*MADD.Sf*/ +                if (gen_check_cpenable(dc, 0)) { +                    gen_helper_madd_s(cpu_FR[RRR_R], cpu_env, +                                      cpu_FR[RRR_R], cpu_FR[RRR_S], +                                      cpu_FR[RRR_T]); +                } +                break; + +            case 5: /*MSUB.Sf*/ +                if (gen_check_cpenable(dc, 0)) { +                    gen_helper_msub_s(cpu_FR[RRR_R], cpu_env, +                                      cpu_FR[RRR_R], cpu_FR[RRR_S], +                                      cpu_FR[RRR_T]); +                } +                break; + +            case 8: /*ROUND.Sf*/ +            case 9: /*TRUNC.Sf*/ +            case 10: /*FLOOR.Sf*/ +            case 11: /*CEIL.Sf*/ +            case 14: /*UTRUNC.Sf*/ +                if (gen_window_check1(dc, RRR_R) && +                    gen_check_cpenable(dc, 0)) { +                    static const unsigned rounding_mode_const[] = { +                        float_round_nearest_even, +                        float_round_to_zero, +                        float_round_down, +                        float_round_up, +                        [6] = float_round_to_zero, +                    }; +                    TCGv_i32 rounding_mode = tcg_const_i32( +                            rounding_mode_const[OP2 & 7]); +                    TCGv_i32 scale = tcg_const_i32(RRR_T); + +                    if (OP2 == 14) { +                        gen_helper_ftoui(cpu_R[RRR_R], cpu_FR[RRR_S], +                                rounding_mode, scale); +                    } else { +                        gen_helper_ftoi(cpu_R[RRR_R], cpu_FR[RRR_S], +                                rounding_mode, scale); +                    } + +                    tcg_temp_free(rounding_mode); +                    tcg_temp_free(scale); +                } +                break; + +            case 12: /*FLOAT.Sf*/ +            case 13: /*UFLOAT.Sf*/ +                if (gen_window_check1(dc, RRR_S) && +                    gen_check_cpenable(dc, 0)) { +                    TCGv_i32 scale = tcg_const_i32(-RRR_T); + +                    if (OP2 == 13) { +                        gen_helper_uitof(cpu_FR[RRR_R], cpu_env, +                                cpu_R[RRR_S], scale); +                    } else { +                        gen_helper_itof(cpu_FR[RRR_R], cpu_env, +                                cpu_R[RRR_S], scale); +                    } +                    tcg_temp_free(scale); +                } +                break; + +            case 15: /*FP1OP*/ +                switch (RRR_T) { +                case 0: /*MOV.Sf*/ +                    if (gen_check_cpenable(dc, 0)) { +                        tcg_gen_mov_i32(cpu_FR[RRR_R], cpu_FR[RRR_S]); +                    } +                    break; + +                case 1: /*ABS.Sf*/ +                    if (gen_check_cpenable(dc, 0)) { +                        gen_helper_abs_s(cpu_FR[RRR_R], cpu_FR[RRR_S]); +                    } +                    break; + +                case 4: /*RFRf*/ +                    if (gen_window_check1(dc, RRR_R) && +                        gen_check_cpenable(dc, 0)) { +                        tcg_gen_mov_i32(cpu_R[RRR_R], cpu_FR[RRR_S]); +                    } +                    break; + +                case 5: /*WFRf*/ +                    if (gen_window_check1(dc, RRR_S) && +                        gen_check_cpenable(dc, 0)) { +                        tcg_gen_mov_i32(cpu_FR[RRR_R], cpu_R[RRR_S]); +                    } +                    break; + +                case 6: /*NEG.Sf*/ +                    if (gen_check_cpenable(dc, 0)) { +                        gen_helper_neg_s(cpu_FR[RRR_R], cpu_FR[RRR_S]); +                    } +                    break; + +                default: /*reserved*/ +                    RESERVED(); +                    break; +                } +                break; + +            default: /*reserved*/ +                RESERVED(); +                break; +            } +            break; + +        case 11: /*FP1*/ +            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); + +#define gen_compare(rel, br, a, b) \ +    do { \ +        if (gen_check_cpenable(dc, 0)) { \ +            TCGv_i32 bit = tcg_const_i32(1 << br); \ +            \ +            gen_helper_##rel(cpu_env, bit, cpu_FR[a], cpu_FR[b]); \ +            tcg_temp_free(bit); \ +        } \ +    } while (0) + +            switch (OP2) { +            case 1: /*UN.Sf*/ +                gen_compare(un_s, RRR_R, RRR_S, RRR_T); +                break; + +            case 2: /*OEQ.Sf*/ +                gen_compare(oeq_s, RRR_R, RRR_S, RRR_T); +                break; + +            case 3: /*UEQ.Sf*/ +                gen_compare(ueq_s, RRR_R, RRR_S, RRR_T); +                break; + +            case 4: /*OLT.Sf*/ +                gen_compare(olt_s, RRR_R, RRR_S, RRR_T); +                break; + +            case 5: /*ULT.Sf*/ +                gen_compare(ult_s, RRR_R, RRR_S, RRR_T); +                break; + +            case 6: /*OLE.Sf*/ +                gen_compare(ole_s, RRR_R, RRR_S, RRR_T); +                break; + +            case 7: /*ULE.Sf*/ +                gen_compare(ule_s, RRR_R, RRR_S, RRR_T); +                break; + +#undef gen_compare + +            case 8: /*MOVEQZ.Sf*/ +            case 9: /*MOVNEZ.Sf*/ +            case 10: /*MOVLTZ.Sf*/ +            case 11: /*MOVGEZ.Sf*/ +                if (gen_window_check1(dc, RRR_T) && +                    gen_check_cpenable(dc, 0)) { +                    static const TCGCond cond[] = { +                        TCG_COND_EQ, +                        TCG_COND_NE, +                        TCG_COND_LT, +                        TCG_COND_GE, +                    }; +                    TCGv_i32 zero = tcg_const_i32(0); + +                    tcg_gen_movcond_i32(cond[OP2 - 8], cpu_FR[RRR_R], +                            cpu_R[RRR_T], zero, cpu_FR[RRR_S], cpu_FR[RRR_R]); +                    tcg_temp_free(zero); +                } +                break; + +            case 12: /*MOVF.Sf*/ +            case 13: /*MOVT.Sf*/ +                HAS_OPTION(XTENSA_OPTION_BOOLEAN); +                if (gen_check_cpenable(dc, 0)) { +                    TCGv_i32 zero = tcg_const_i32(0); +                    TCGv_i32 tmp = tcg_temp_new_i32(); + +                    tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRR_T); +                    tcg_gen_movcond_i32(OP2 & 1 ? TCG_COND_NE : TCG_COND_EQ, +                            cpu_FR[RRR_R], tmp, zero, +                            cpu_FR[RRR_S], cpu_FR[RRR_R]); + +                    tcg_temp_free(tmp); +                    tcg_temp_free(zero); +                } +                break; + +            default: /*reserved*/ +                RESERVED(); +                break; +            } +            break; + +        default: /*reserved*/ +            RESERVED(); +            break; +        } +        break; + +    case 1: /*L32R*/ +        if (gen_window_check1(dc, RRR_T)) { +            TCGv_i32 tmp = tcg_const_i32( +                    ((dc->tb->flags & XTENSA_TBFLAG_LITBASE) ? +                     0 : ((dc->pc + 3) & ~3)) + +                    (0xfffc0000 | (RI16_IMM16 << 2))); + +            if (dc->tb->flags & XTENSA_TBFLAG_LITBASE) { +                tcg_gen_add_i32(tmp, tmp, dc->litbase); +            } +            tcg_gen_qemu_ld32u(cpu_R[RRR_T], tmp, dc->cring); +            tcg_temp_free(tmp); +        } +        break; + +    case 2: /*LSAI*/ +#define gen_load_store(type, shift) do { \ +            if (gen_window_check2(dc, RRI8_S, RRI8_T)) { \ +                TCGv_i32 addr = tcg_temp_new_i32(); \ +                \ +                tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << shift); \ +                if (shift) { \ +                    gen_load_store_alignment(dc, shift, addr, false); \ +                } \ +                tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \ +                tcg_temp_free(addr); \ +            } \ +        } while (0) + +        switch (RRI8_R) { +        case 0: /*L8UI*/ +            gen_load_store(ld8u, 0); +            break; + +        case 1: /*L16UI*/ +            gen_load_store(ld16u, 1); +            break; + +        case 2: /*L32I*/ +            gen_load_store(ld32u, 2); +            break; + +        case 4: /*S8I*/ +            gen_load_store(st8, 0); +            break; + +        case 5: /*S16I*/ +            gen_load_store(st16, 1); +            break; + +        case 6: /*S32I*/ +            gen_load_store(st32, 2); +            break; + +#define gen_dcache_hit_test(w, shift) do { \ +            if (gen_window_check1(dc, RRI##w##_S)) { \ +                TCGv_i32 addr = tcg_temp_new_i32(); \ +                TCGv_i32 res = tcg_temp_new_i32(); \ +                tcg_gen_addi_i32(addr, cpu_R[RRI##w##_S], \ +                                 RRI##w##_IMM##w << shift); \ +                tcg_gen_qemu_ld8u(res, addr, dc->cring); \ +                tcg_temp_free(addr); \ +                tcg_temp_free(res); \ +            } \ +        } while (0) + +#define gen_dcache_hit_test4() gen_dcache_hit_test(4, 4) +#define gen_dcache_hit_test8() gen_dcache_hit_test(8, 2) + +        case 7: /*CACHEc*/ +            if (RRI8_T < 8) { +                HAS_OPTION(XTENSA_OPTION_DCACHE); +            } + +            switch (RRI8_T) { +            case 0: /*DPFRc*/ +                gen_window_check1(dc, RRI8_S); +                break; + +            case 1: /*DPFWc*/ +                gen_window_check1(dc, RRI8_S); +                break; + +            case 2: /*DPFROc*/ +                gen_window_check1(dc, RRI8_S); +                break; + +            case 3: /*DPFWOc*/ +                gen_window_check1(dc, RRI8_S); +                break; + +            case 4: /*DHWBc*/ +                gen_dcache_hit_test8(); +                break; + +            case 5: /*DHWBIc*/ +                gen_dcache_hit_test8(); +                break; + +            case 6: /*DHIc*/ +                if (gen_check_privilege(dc)) { +                    gen_dcache_hit_test8(); +                } +                break; + +            case 7: /*DIIc*/ +                if (gen_check_privilege(dc)) { +                    gen_window_check1(dc, RRI8_S); +                } +                break; + +            case 8: /*DCEc*/ +                switch (OP1) { +                case 0: /*DPFLl*/ +                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); +                    if (gen_check_privilege(dc)) { +                        gen_dcache_hit_test4(); +                    } +                    break; + +                case 2: /*DHUl*/ +                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); +                    if (gen_check_privilege(dc)) { +                        gen_dcache_hit_test4(); +                    } +                    break; + +                case 3: /*DIUl*/ +                    HAS_OPTION(XTENSA_OPTION_DCACHE_INDEX_LOCK); +                    if (gen_check_privilege(dc)) { +                        gen_window_check1(dc, RRI4_S); +                    } +                    break; + +                case 4: /*DIWBc*/ +                    HAS_OPTION(XTENSA_OPTION_DCACHE); +                    if (gen_check_privilege(dc)) { +                        gen_window_check1(dc, RRI4_S); +                    } +                    break; + +                case 5: /*DIWBIc*/ +                    HAS_OPTION(XTENSA_OPTION_DCACHE); +                    if (gen_check_privilege(dc)) { +                        gen_window_check1(dc, RRI4_S); +                    } +                    break; + +                default: /*reserved*/ +                    RESERVED(); +                    break; + +                } +                break; + +#undef gen_dcache_hit_test +#undef gen_dcache_hit_test4 +#undef gen_dcache_hit_test8 + +#define gen_icache_hit_test(w, shift) do { \ +            if (gen_window_check1(dc, RRI##w##_S)) { \ +                TCGv_i32 addr = tcg_temp_new_i32(); \ +                tcg_gen_movi_i32(cpu_pc, dc->pc); \ +                tcg_gen_addi_i32(addr, cpu_R[RRI##w##_S], \ +                                 RRI##w##_IMM##w << shift); \ +                gen_helper_itlb_hit_test(cpu_env, addr); \ +                tcg_temp_free(addr); \ +            }\ +        } while (0) + +#define gen_icache_hit_test4() gen_icache_hit_test(4, 4) +#define gen_icache_hit_test8() gen_icache_hit_test(8, 2) + +            case 12: /*IPFc*/ +                HAS_OPTION(XTENSA_OPTION_ICACHE); +                gen_window_check1(dc, RRI8_S); +                break; + +            case 13: /*ICEc*/ +                switch (OP1) { +                case 0: /*IPFLl*/ +                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); +                    if (gen_check_privilege(dc)) { +                        gen_icache_hit_test4(); +                    } +                    break; + +                case 2: /*IHUl*/ +                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); +                    if (gen_check_privilege(dc)) { +                        gen_icache_hit_test4(); +                    } +                    break; + +                case 3: /*IIUl*/ +                    HAS_OPTION(XTENSA_OPTION_ICACHE_INDEX_LOCK); +                    if (gen_check_privilege(dc)) { +                        gen_window_check1(dc, RRI4_S); +                    } +                    break; + +                default: /*reserved*/ +                    RESERVED(); +                    break; +                } +                break; + +            case 14: /*IHIc*/ +                HAS_OPTION(XTENSA_OPTION_ICACHE); +                gen_icache_hit_test8(); +                break; + +            case 15: /*IIIc*/ +                HAS_OPTION(XTENSA_OPTION_ICACHE); +                if (gen_check_privilege(dc)) { +                    gen_window_check1(dc, RRI8_S); +                } +                break; + +            default: /*reserved*/ +                RESERVED(); +                break; +            } +            break; + +#undef gen_icache_hit_test +#undef gen_icache_hit_test4 +#undef gen_icache_hit_test8 + +        case 9: /*L16SI*/ +            gen_load_store(ld16s, 1); +            break; +#undef gen_load_store + +        case 10: /*MOVI*/ +            if (gen_window_check1(dc, RRI8_T)) { +                tcg_gen_movi_i32(cpu_R[RRI8_T], +                                 RRI8_IMM8 | (RRI8_S << 8) | +                                 ((RRI8_S & 0x8) ? 0xfffff000 : 0)); +            } +            break; + +#define gen_load_store_no_hw_align(type) do { \ +            if (gen_window_check2(dc, RRI8_S, RRI8_T)) { \ +                TCGv_i32 addr = tcg_temp_local_new_i32(); \ +                tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); \ +                gen_load_store_alignment(dc, 2, addr, true); \ +                tcg_gen_qemu_##type(cpu_R[RRI8_T], addr, dc->cring); \ +                tcg_temp_free(addr); \ +            } \ +        } while (0) + +        case 11: /*L32AIy*/ +            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); +            gen_load_store_no_hw_align(ld32u); /*TODO acquire?*/ +            break; + +        case 12: /*ADDI*/ +            if (gen_window_check2(dc, RRI8_S, RRI8_T)) { +                tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], RRI8_IMM8_SE); +            } +            break; + +        case 13: /*ADDMI*/ +            if (gen_window_check2(dc, RRI8_S, RRI8_T)) { +                tcg_gen_addi_i32(cpu_R[RRI8_T], cpu_R[RRI8_S], +                                 RRI8_IMM8_SE << 8); +            } +            break; + +        case 14: /*S32C1Iy*/ +            HAS_OPTION(XTENSA_OPTION_CONDITIONAL_STORE); +            if (gen_window_check2(dc, RRI8_S, RRI8_T)) { +                TCGLabel *label = gen_new_label(); +                TCGv_i32 tmp = tcg_temp_local_new_i32(); +                TCGv_i32 addr = tcg_temp_local_new_i32(); +                TCGv_i32 tpc; + +                tcg_gen_mov_i32(tmp, cpu_R[RRI8_T]); +                tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); +                gen_load_store_alignment(dc, 2, addr, true); + +                gen_advance_ccount(dc); +                tpc = tcg_const_i32(dc->pc); +                gen_helper_check_atomctl(cpu_env, tpc, addr); +                tcg_gen_qemu_ld32u(cpu_R[RRI8_T], addr, dc->cring); +                tcg_gen_brcond_i32(TCG_COND_NE, cpu_R[RRI8_T], +                        cpu_SR[SCOMPARE1], label); + +                tcg_gen_qemu_st32(tmp, addr, dc->cring); + +                gen_set_label(label); +                tcg_temp_free(tpc); +                tcg_temp_free(addr); +                tcg_temp_free(tmp); +            } +            break; + +        case 15: /*S32RIy*/ +            HAS_OPTION(XTENSA_OPTION_MP_SYNCHRO); +            gen_load_store_no_hw_align(st32); /*TODO release?*/ +            break; +#undef gen_load_store_no_hw_align + +        default: /*reserved*/ +            RESERVED(); +            break; +        } +        break; + +    case 3: /*LSCIp*/ +        switch (RRI8_R) { +        case 0: /*LSIf*/ +        case 4: /*SSIf*/ +        case 8: /*LSIUf*/ +        case 12: /*SSIUf*/ +            HAS_OPTION(XTENSA_OPTION_FP_COPROCESSOR); +            if (gen_window_check1(dc, RRI8_S) && +                gen_check_cpenable(dc, 0)) { +                TCGv_i32 addr = tcg_temp_new_i32(); +                tcg_gen_addi_i32(addr, cpu_R[RRI8_S], RRI8_IMM8 << 2); +                gen_load_store_alignment(dc, 2, addr, false); +                if (RRI8_R & 0x4) { +                    tcg_gen_qemu_st32(cpu_FR[RRI8_T], addr, dc->cring); +                } else { +                    tcg_gen_qemu_ld32u(cpu_FR[RRI8_T], addr, dc->cring); +                } +                if (RRI8_R & 0x8) { +                    tcg_gen_mov_i32(cpu_R[RRI8_S], addr); +                } +                tcg_temp_free(addr); +            } +            break; + +        default: /*reserved*/ +            RESERVED(); +            break; +        } +        break; + +    case 4: /*MAC16d*/ +        HAS_OPTION(XTENSA_OPTION_MAC16); +        { +            enum { +                MAC16_UMUL = 0x0, +                MAC16_MUL  = 0x4, +                MAC16_MULA = 0x8, +                MAC16_MULS = 0xc, +                MAC16_NONE = 0xf, +            } op = OP1 & 0xc; +            bool is_m1_sr = (OP2 & 0x3) == 2; +            bool is_m2_sr = (OP2 & 0xc) == 0; +            uint32_t ld_offset = 0; + +            if (OP2 > 9) { +                RESERVED(); +            } + +            switch (OP2 & 2) { +            case 0: /*MACI?/MACC?*/ +                is_m1_sr = true; +                ld_offset = (OP2 & 1) ? -4 : 4; + +                if (OP2 >= 8) { /*MACI/MACC*/ +                    if (OP1 == 0) { /*LDINC/LDDEC*/ +                        op = MAC16_NONE; +                    } else { +                        RESERVED(); +                    } +                } else if (op != MAC16_MULA) { /*MULA.*.*.LDINC/LDDEC*/ +                    RESERVED(); +                } +                break; + +            case 2: /*MACD?/MACA?*/ +                if (op == MAC16_UMUL && OP2 != 7) { /*UMUL only in MACAA*/ +                    RESERVED(); +                } +                break; +            } + +            if (op != MAC16_NONE) { +                if (!is_m1_sr && !gen_window_check1(dc, RRR_S)) { +                    break; +                } +                if (!is_m2_sr && !gen_window_check1(dc, RRR_T)) { +                    break; +                } +            } + +            if (ld_offset && !gen_window_check1(dc, RRR_S)) { +                break; +            } + +            { +                TCGv_i32 vaddr = tcg_temp_new_i32(); +                TCGv_i32 mem32 = tcg_temp_new_i32(); + +                if (ld_offset) { +                    tcg_gen_addi_i32(vaddr, cpu_R[RRR_S], ld_offset); +                    gen_load_store_alignment(dc, 2, vaddr, false); +                    tcg_gen_qemu_ld32u(mem32, vaddr, dc->cring); +                } +                if (op != MAC16_NONE) { +                    TCGv_i32 m1 = gen_mac16_m( +                            is_m1_sr ? cpu_SR[MR + RRR_X] : cpu_R[RRR_S], +                            OP1 & 1, op == MAC16_UMUL); +                    TCGv_i32 m2 = gen_mac16_m( +                            is_m2_sr ? cpu_SR[MR + 2 + RRR_Y] : cpu_R[RRR_T], +                            OP1 & 2, op == MAC16_UMUL); + +                    if (op == MAC16_MUL || op == MAC16_UMUL) { +                        tcg_gen_mul_i32(cpu_SR[ACCLO], m1, m2); +                        if (op == MAC16_UMUL) { +                            tcg_gen_movi_i32(cpu_SR[ACCHI], 0); +                        } else { +                            tcg_gen_sari_i32(cpu_SR[ACCHI], cpu_SR[ACCLO], 31); +                        } +                    } else { +                        TCGv_i32 lo = tcg_temp_new_i32(); +                        TCGv_i32 hi = tcg_temp_new_i32(); + +                        tcg_gen_mul_i32(lo, m1, m2); +                        tcg_gen_sari_i32(hi, lo, 31); +                        if (op == MAC16_MULA) { +                            tcg_gen_add2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], +                                             cpu_SR[ACCLO], cpu_SR[ACCHI], +                                             lo, hi); +                        } else { +                            tcg_gen_sub2_i32(cpu_SR[ACCLO], cpu_SR[ACCHI], +                                             cpu_SR[ACCLO], cpu_SR[ACCHI], +                                             lo, hi); +                        } +                        tcg_gen_ext8s_i32(cpu_SR[ACCHI], cpu_SR[ACCHI]); + +                        tcg_temp_free_i32(lo); +                        tcg_temp_free_i32(hi); +                    } +                    tcg_temp_free(m1); +                    tcg_temp_free(m2); +                } +                if (ld_offset) { +                    tcg_gen_mov_i32(cpu_R[RRR_S], vaddr); +                    tcg_gen_mov_i32(cpu_SR[MR + RRR_W], mem32); +                } +                tcg_temp_free(vaddr); +                tcg_temp_free(mem32); +            } +        } +        break; + +    case 5: /*CALLN*/ +        switch (CALL_N) { +        case 0: /*CALL0*/ +            tcg_gen_movi_i32(cpu_R[0], dc->next_pc); +            gen_jumpi(dc, (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0); +            break; + +        case 1: /*CALL4w*/ +        case 2: /*CALL8w*/ +        case 3: /*CALL12w*/ +            HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +            if (gen_window_check1(dc, CALL_N << 2)) { +                gen_callwi(dc, CALL_N, +                           (dc->pc & ~3) + (CALL_OFFSET_SE << 2) + 4, 0); +            } +            break; +        } +        break; + +    case 6: /*SI*/ +        switch (CALL_N) { +        case 0: /*J*/ +            gen_jumpi(dc, dc->pc + 4 + CALL_OFFSET_SE, 0); +            break; + +        case 1: /*BZ*/ +            if (gen_window_check1(dc, BRI12_S)) { +                static const TCGCond cond[] = { +                    TCG_COND_EQ, /*BEQZ*/ +                    TCG_COND_NE, /*BNEZ*/ +                    TCG_COND_LT, /*BLTZ*/ +                    TCG_COND_GE, /*BGEZ*/ +                }; + +                gen_brcondi(dc, cond[BRI12_M & 3], cpu_R[BRI12_S], 0, +                        4 + BRI12_IMM12_SE); +            } +            break; + +        case 2: /*BI0*/ +            if (gen_window_check1(dc, BRI8_S)) { +                static const TCGCond cond[] = { +                    TCG_COND_EQ, /*BEQI*/ +                    TCG_COND_NE, /*BNEI*/ +                    TCG_COND_LT, /*BLTI*/ +                    TCG_COND_GE, /*BGEI*/ +                }; + +                gen_brcondi(dc, cond[BRI8_M & 3], +                        cpu_R[BRI8_S], B4CONST[BRI8_R], 4 + BRI8_IMM8_SE); +            } +            break; + +        case 3: /*BI1*/ +            switch (BRI8_M) { +            case 0: /*ENTRYw*/ +                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                { +                    TCGv_i32 pc = tcg_const_i32(dc->pc); +                    TCGv_i32 s = tcg_const_i32(BRI12_S); +                    TCGv_i32 imm = tcg_const_i32(BRI12_IMM12); +                    gen_advance_ccount(dc); +                    gen_helper_entry(cpu_env, pc, s, imm); +                    tcg_temp_free(imm); +                    tcg_temp_free(s); +                    tcg_temp_free(pc); +                    /* This can change tb->flags, so exit tb */ +                    gen_jumpi_check_loop_end(dc, -1); +                } +                break; + +            case 1: /*B1*/ +                switch (BRI8_R) { +                case 0: /*BFp*/ +                case 1: /*BTp*/ +                    HAS_OPTION(XTENSA_OPTION_BOOLEAN); +                    { +                        TCGv_i32 tmp = tcg_temp_new_i32(); +                        tcg_gen_andi_i32(tmp, cpu_SR[BR], 1 << RRI8_S); +                        gen_brcondi(dc, +                                BRI8_R == 1 ? TCG_COND_NE : TCG_COND_EQ, +                                tmp, 0, 4 + RRI8_IMM8_SE); +                        tcg_temp_free(tmp); +                    } +                    break; + +                case 8: /*LOOP*/ +                case 9: /*LOOPNEZ*/ +                case 10: /*LOOPGTZ*/ +                    HAS_OPTION(XTENSA_OPTION_LOOP); +                    if (gen_window_check1(dc, RRI8_S)) { +                        uint32_t lend = dc->pc + RRI8_IMM8 + 4; +                        TCGv_i32 tmp = tcg_const_i32(lend); + +                        tcg_gen_subi_i32(cpu_SR[LCOUNT], cpu_R[RRI8_S], 1); +                        tcg_gen_movi_i32(cpu_SR[LBEG], dc->next_pc); +                        gen_helper_wsr_lend(cpu_env, tmp); +                        tcg_temp_free(tmp); + +                        if (BRI8_R > 8) { +                            TCGLabel *label = gen_new_label(); +                            tcg_gen_brcondi_i32( +                                    BRI8_R == 9 ? TCG_COND_NE : TCG_COND_GT, +                                    cpu_R[RRI8_S], 0, label); +                            gen_jumpi(dc, lend, 1); +                            gen_set_label(label); +                        } + +                        gen_jumpi(dc, dc->next_pc, 0); +                    } +                    break; + +                default: /*reserved*/ +                    RESERVED(); +                    break; + +                } +                break; + +            case 2: /*BLTUI*/ +            case 3: /*BGEUI*/ +                if (gen_window_check1(dc, BRI8_S)) { +                    gen_brcondi(dc, BRI8_M == 2 ? TCG_COND_LTU : TCG_COND_GEU, +                                cpu_R[BRI8_S], B4CONSTU[BRI8_R], +                                4 + BRI8_IMM8_SE); +                } +                break; +            } +            break; + +        } +        break; + +    case 7: /*B*/ +        { +            TCGCond eq_ne = (RRI8_R & 8) ? TCG_COND_NE : TCG_COND_EQ; + +            switch (RRI8_R & 7) { +            case 0: /*BNONE*/ /*BANY*/ +                if (gen_window_check2(dc, RRI8_S, RRI8_T)) { +                    TCGv_i32 tmp = tcg_temp_new_i32(); +                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); +                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); +                    tcg_temp_free(tmp); +                } +                break; + +            case 1: /*BEQ*/ /*BNE*/ +            case 2: /*BLT*/ /*BGE*/ +            case 3: /*BLTU*/ /*BGEU*/ +                if (gen_window_check2(dc, RRI8_S, RRI8_T)) { +                    static const TCGCond cond[] = { +                        [1] = TCG_COND_EQ, +                        [2] = TCG_COND_LT, +                        [3] = TCG_COND_LTU, +                        [9] = TCG_COND_NE, +                        [10] = TCG_COND_GE, +                        [11] = TCG_COND_GEU, +                    }; +                    gen_brcond(dc, cond[RRI8_R], cpu_R[RRI8_S], cpu_R[RRI8_T], +                            4 + RRI8_IMM8_SE); +                } +                break; + +            case 4: /*BALL*/ /*BNALL*/ +                if (gen_window_check2(dc, RRI8_S, RRI8_T)) { +                    TCGv_i32 tmp = tcg_temp_new_i32(); +                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], cpu_R[RRI8_T]); +                    gen_brcond(dc, eq_ne, tmp, cpu_R[RRI8_T], +                            4 + RRI8_IMM8_SE); +                    tcg_temp_free(tmp); +                } +                break; + +            case 5: /*BBC*/ /*BBS*/ +                if (gen_window_check2(dc, RRI8_S, RRI8_T)) { +#ifdef TARGET_WORDS_BIGENDIAN +                    TCGv_i32 bit = tcg_const_i32(0x80000000); +#else +                    TCGv_i32 bit = tcg_const_i32(0x00000001); +#endif +                    TCGv_i32 tmp = tcg_temp_new_i32(); +                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_T], 0x1f); +#ifdef TARGET_WORDS_BIGENDIAN +                    tcg_gen_shr_i32(bit, bit, tmp); +#else +                    tcg_gen_shl_i32(bit, bit, tmp); +#endif +                    tcg_gen_and_i32(tmp, cpu_R[RRI8_S], bit); +                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); +                    tcg_temp_free(tmp); +                    tcg_temp_free(bit); +                } +                break; + +            case 6: /*BBCI*/ /*BBSI*/ +            case 7: +                if (gen_window_check1(dc, RRI8_S)) { +                    TCGv_i32 tmp = tcg_temp_new_i32(); +                    tcg_gen_andi_i32(tmp, cpu_R[RRI8_S], +#ifdef TARGET_WORDS_BIGENDIAN +                            0x80000000 >> (((RRI8_R & 1) << 4) | RRI8_T)); +#else +                            0x00000001 << (((RRI8_R & 1) << 4) | RRI8_T)); +#endif +                    gen_brcondi(dc, eq_ne, tmp, 0, 4 + RRI8_IMM8_SE); +                    tcg_temp_free(tmp); +                } +                break; + +            } +        } +        break; + +#define gen_narrow_load_store(type) do { \ +            if (gen_window_check2(dc, RRRN_S, RRRN_T)) { \ +                TCGv_i32 addr = tcg_temp_new_i32(); \ +                tcg_gen_addi_i32(addr, cpu_R[RRRN_S], RRRN_R << 2); \ +                gen_load_store_alignment(dc, 2, addr, false); \ +                tcg_gen_qemu_##type(cpu_R[RRRN_T], addr, dc->cring); \ +                tcg_temp_free(addr); \ +            } \ +        } while (0) + +    case 8: /*L32I.Nn*/ +        gen_narrow_load_store(ld32u); +        break; + +    case 9: /*S32I.Nn*/ +        gen_narrow_load_store(st32); +        break; +#undef gen_narrow_load_store + +    case 10: /*ADD.Nn*/ +        if (gen_window_check3(dc, RRRN_R, RRRN_S, RRRN_T)) { +            tcg_gen_add_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], cpu_R[RRRN_T]); +        } +        break; + +    case 11: /*ADDI.Nn*/ +        if (gen_window_check2(dc, RRRN_R, RRRN_S)) { +            tcg_gen_addi_i32(cpu_R[RRRN_R], cpu_R[RRRN_S], +                             RRRN_T ? RRRN_T : -1); +        } +        break; + +    case 12: /*ST2n*/ +        if (!gen_window_check1(dc, RRRN_S)) { +            break; +        } +        if (RRRN_T < 8) { /*MOVI.Nn*/ +            tcg_gen_movi_i32(cpu_R[RRRN_S], +                    RRRN_R | (RRRN_T << 4) | +                    ((RRRN_T & 6) == 6 ? 0xffffff80 : 0)); +        } else { /*BEQZ.Nn*/ /*BNEZ.Nn*/ +            TCGCond eq_ne = (RRRN_T & 4) ? TCG_COND_NE : TCG_COND_EQ; + +            gen_brcondi(dc, eq_ne, cpu_R[RRRN_S], 0, +                    4 + (RRRN_R | ((RRRN_T & 3) << 4))); +        } +        break; + +    case 13: /*ST3n*/ +        switch (RRRN_R) { +        case 0: /*MOV.Nn*/ +            if (gen_window_check2(dc, RRRN_S, RRRN_T)) { +                tcg_gen_mov_i32(cpu_R[RRRN_T], cpu_R[RRRN_S]); +            } +            break; + +        case 15: /*S3*/ +            switch (RRRN_T) { +            case 0: /*RET.Nn*/ +                gen_jump(dc, cpu_R[0]); +                break; + +            case 1: /*RETW.Nn*/ +                HAS_OPTION(XTENSA_OPTION_WINDOWED_REGISTER); +                { +                    TCGv_i32 tmp = tcg_const_i32(dc->pc); +                    gen_advance_ccount(dc); +                    gen_helper_retw(tmp, cpu_env, tmp); +                    gen_jump(dc, tmp); +                    tcg_temp_free(tmp); +                } +                break; + +            case 2: /*BREAK.Nn*/ +                HAS_OPTION(XTENSA_OPTION_DEBUG); +                if (dc->debug) { +                    gen_debug_exception(dc, DEBUGCAUSE_BN); +                } +                break; + +            case 3: /*NOP.Nn*/ +                break; + +            case 6: /*ILL.Nn*/ +                gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +                break; + +            default: /*reserved*/ +                RESERVED(); +                break; +            } +            break; + +        default: /*reserved*/ +            RESERVED(); +            break; +        } +        break; + +    default: /*reserved*/ +        RESERVED(); +        break; +    } + +    if (dc->is_jmp == DISAS_NEXT) { +        gen_check_loop_end(dc, 0); +    } +    dc->pc = dc->next_pc; + +    return; + +invalid_opcode: +    qemu_log("INVALID(pc = %08x)\n", dc->pc); +    gen_exception_cause(dc, ILLEGAL_INSTRUCTION_CAUSE); +#undef HAS_OPTION +} + +static inline unsigned xtensa_insn_len(CPUXtensaState *env, DisasContext *dc) +{ +    uint8_t b0 = cpu_ldub_code(env, dc->pc); +    return xtensa_op0_insn_len(OP0); +} + +static void check_breakpoint(CPUXtensaState *env, DisasContext *dc) +{ +    CPUState *cs = CPU(xtensa_env_get_cpu(env)); +    CPUBreakpoint *bp; + +    if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { +        QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { +            if (bp->pc == dc->pc) { +                tcg_gen_movi_i32(cpu_pc, dc->pc); +                gen_exception(dc, EXCP_DEBUG); +                dc->is_jmp = DISAS_UPDATE; +             } +        } +    } +} + +static void gen_ibreak_check(CPUXtensaState *env, DisasContext *dc) +{ +    unsigned i; + +    for (i = 0; i < dc->config->nibreak; ++i) { +        if ((env->sregs[IBREAKENABLE] & (1 << i)) && +                env->sregs[IBREAKA + i] == dc->pc) { +            gen_debug_exception(dc, DEBUGCAUSE_IB); +            break; +        } +    } +} + +static inline +void gen_intermediate_code_internal(XtensaCPU *cpu, +                                    TranslationBlock *tb, bool search_pc) +{ +    CPUState *cs = CPU(cpu); +    CPUXtensaState *env = &cpu->env; +    DisasContext dc; +    int insn_count = 0; +    int j, lj = -1; +    int max_insns = tb->cflags & CF_COUNT_MASK; +    uint32_t pc_start = tb->pc; +    uint32_t next_page_start = +        (pc_start & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE; + +    if (max_insns == 0) { +        max_insns = CF_COUNT_MASK; +    } + +    dc.config = env->config; +    dc.singlestep_enabled = cs->singlestep_enabled; +    dc.tb = tb; +    dc.pc = pc_start; +    dc.ring = tb->flags & XTENSA_TBFLAG_RING_MASK; +    dc.cring = (tb->flags & XTENSA_TBFLAG_EXCM) ? 0 : dc.ring; +    dc.lbeg = env->sregs[LBEG]; +    dc.lend = env->sregs[LEND]; +    dc.is_jmp = DISAS_NEXT; +    dc.ccount_delta = 0; +    dc.debug = tb->flags & XTENSA_TBFLAG_DEBUG; +    dc.icount = tb->flags & XTENSA_TBFLAG_ICOUNT; +    dc.cpenable = (tb->flags & XTENSA_TBFLAG_CPENABLE_MASK) >> +        XTENSA_TBFLAG_CPENABLE_SHIFT; +    dc.window = ((tb->flags & XTENSA_TBFLAG_WINDOW_MASK) >> +                 XTENSA_TBFLAG_WINDOW_SHIFT); + +    init_litbase(&dc); +    init_sar_tracker(&dc); +    if (dc.icount) { +        dc.next_icount = tcg_temp_local_new_i32(); +    } + +    gen_tb_start(tb); + +    if (tb->flags & XTENSA_TBFLAG_EXCEPTION) { +        tcg_gen_movi_i32(cpu_pc, dc.pc); +        gen_exception(&dc, EXCP_DEBUG); +    } + +    do { +        check_breakpoint(env, &dc); + +        if (search_pc) { +            j = tcg_op_buf_count(); +            if (lj < j) { +                lj++; +                while (lj < j) { +                    tcg_ctx.gen_opc_instr_start[lj++] = 0; +                } +            } +            tcg_ctx.gen_opc_pc[lj] = dc.pc; +            tcg_ctx.gen_opc_instr_start[lj] = 1; +            tcg_ctx.gen_opc_icount[lj] = insn_count; +        } + +        if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { +            tcg_gen_debug_insn_start(dc.pc); +        } + +        ++dc.ccount_delta; + +        if (insn_count + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { +            gen_io_start(); +        } + +        if (dc.icount) { +            TCGLabel *label = gen_new_label(); + +            tcg_gen_addi_i32(dc.next_icount, cpu_SR[ICOUNT], 1); +            tcg_gen_brcondi_i32(TCG_COND_NE, dc.next_icount, 0, label); +            tcg_gen_mov_i32(dc.next_icount, cpu_SR[ICOUNT]); +            if (dc.debug) { +                gen_debug_exception(&dc, DEBUGCAUSE_IC); +            } +            gen_set_label(label); +        } + +        if (dc.debug) { +            gen_ibreak_check(env, &dc); +        } + +        disas_xtensa_insn(env, &dc); +        ++insn_count; +        if (dc.icount) { +            tcg_gen_mov_i32(cpu_SR[ICOUNT], dc.next_icount); +        } +        if (cs->singlestep_enabled) { +            tcg_gen_movi_i32(cpu_pc, dc.pc); +            gen_exception(&dc, EXCP_DEBUG); +            break; +        } +    } while (dc.is_jmp == DISAS_NEXT && +            insn_count < max_insns && +            dc.pc < next_page_start && +            dc.pc + xtensa_insn_len(env, &dc) <= next_page_start && +            !tcg_op_buf_full()); + +    reset_litbase(&dc); +    reset_sar_tracker(&dc); +    if (dc.icount) { +        tcg_temp_free(dc.next_icount); +    } + +    if (tb->cflags & CF_LAST_IO) { +        gen_io_end(); +    } + +    if (dc.is_jmp == DISAS_NEXT) { +        gen_jumpi(&dc, dc.pc, 0); +    } +    gen_tb_end(tb, insn_count); + +#ifdef DEBUG_DISAS +    if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { +        qemu_log("----------------\n"); +        qemu_log("IN: %s\n", lookup_symbol(pc_start)); +        log_target_disas(cs, pc_start, dc.pc - pc_start, 0); +        qemu_log("\n"); +    } +#endif +    if (search_pc) { +        j = tcg_op_buf_count(); +        memset(tcg_ctx.gen_opc_instr_start + lj + 1, 0, +                (j - lj) * sizeof(tcg_ctx.gen_opc_instr_start[0])); +    } else { +        tb->size = dc.pc - pc_start; +        tb->icount = insn_count; +    } +} + +void gen_intermediate_code(CPUXtensaState *env, TranslationBlock *tb) +{ +    gen_intermediate_code_internal(xtensa_env_get_cpu(env), tb, false); +} + +void gen_intermediate_code_pc(CPUXtensaState *env, TranslationBlock *tb) +{ +    gen_intermediate_code_internal(xtensa_env_get_cpu(env), tb, true); +} + +void xtensa_cpu_dump_state(CPUState *cs, FILE *f, +                           fprintf_function cpu_fprintf, int flags) +{ +    XtensaCPU *cpu = XTENSA_CPU(cs); +    CPUXtensaState *env = &cpu->env; +    int i, j; + +    cpu_fprintf(f, "PC=%08x\n\n", env->pc); + +    for (i = j = 0; i < 256; ++i) { +        if (xtensa_option_bits_enabled(env->config, sregnames[i].opt_bits)) { +            cpu_fprintf(f, "%12s=%08x%c", sregnames[i].name, env->sregs[i], +                    (j++ % 4) == 3 ? '\n' : ' '); +        } +    } + +    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); + +    for (i = j = 0; i < 256; ++i) { +        if (xtensa_option_bits_enabled(env->config, uregnames[i].opt_bits)) { +            cpu_fprintf(f, "%s=%08x%c", uregnames[i].name, env->uregs[i], +                    (j++ % 4) == 3 ? '\n' : ' '); +        } +    } + +    cpu_fprintf(f, (j % 4) == 0 ? "\n" : "\n\n"); + +    for (i = 0; i < 16; ++i) { +        cpu_fprintf(f, " A%02d=%08x%c", i, env->regs[i], +                (i % 4) == 3 ? '\n' : ' '); +    } + +    cpu_fprintf(f, "\n"); + +    for (i = 0; i < env->config->nareg; ++i) { +        cpu_fprintf(f, "AR%02d=%08x%c", i, env->phys_regs[i], +                (i % 4) == 3 ? '\n' : ' '); +    } + +    if (xtensa_option_enabled(env->config, XTENSA_OPTION_FP_COPROCESSOR)) { +        cpu_fprintf(f, "\n"); + +        for (i = 0; i < 16; ++i) { +            cpu_fprintf(f, "F%02d=%08x (%+10.8e)%c", i, +                    float32_val(env->fregs[i].f32[FP_F32_LOW]), +                    *(float *)(env->fregs[i].f32 + FP_F32_LOW), +                    (i % 2) == 1 ? '\n' : ' '); +        } +    } +} + +void restore_state_to_opc(CPUXtensaState *env, TranslationBlock *tb, int pc_pos) +{ +    env->pc = tcg_ctx.gen_opc_pc[pc_pos]; +} diff --git a/target-xtensa/xtensa-semi.c b/target-xtensa/xtensa-semi.c new file mode 100644 index 00000000..16e9d8c7 --- /dev/null +++ b/target-xtensa/xtensa-semi.c @@ -0,0 +1,321 @@ +/* + * Copyright (c) 2011, Max Filippov, Open Source and Linux Lab. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + *     * Redistributions of source code must retain the above copyright + *       notice, this list of conditions and the following disclaimer. + *     * Redistributions in binary form must reproduce the above copyright + *       notice, this list of conditions and the following disclaimer in the + *       documentation and/or other materials provided with the distribution. + *     * Neither the name of the Open Source and Linux Lab nor the + *       names of its contributors may be used to endorse or promote products + *       derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <stddef.h> +#include "cpu.h" +#include "exec/helper-proto.h" +#include "qemu/log.h" + +enum { +    TARGET_SYS_exit = 1, +    TARGET_SYS_read = 3, +    TARGET_SYS_write = 4, +    TARGET_SYS_open = 5, +    TARGET_SYS_close = 6, +    TARGET_SYS_lseek = 19, +    TARGET_SYS_select_one = 29, + +    TARGET_SYS_argc = 1000, +    TARGET_SYS_argv_sz = 1001, +    TARGET_SYS_argv = 1002, +    TARGET_SYS_memset = 1004, +}; + +enum { +    SELECT_ONE_READ   = 1, +    SELECT_ONE_WRITE  = 2, +    SELECT_ONE_EXCEPT = 3, +}; + +enum { +    TARGET_EPERM        =  1, +    TARGET_ENOENT       =  2, +    TARGET_ESRCH        =  3, +    TARGET_EINTR        =  4, +    TARGET_EIO          =  5, +    TARGET_ENXIO        =  6, +    TARGET_E2BIG        =  7, +    TARGET_ENOEXEC      =  8, +    TARGET_EBADF        =  9, +    TARGET_ECHILD       = 10, +    TARGET_EAGAIN       = 11, +    TARGET_ENOMEM       = 12, +    TARGET_EACCES       = 13, +    TARGET_EFAULT       = 14, +    TARGET_ENOTBLK      = 15, +    TARGET_EBUSY        = 16, +    TARGET_EEXIST       = 17, +    TARGET_EXDEV        = 18, +    TARGET_ENODEV       = 19, +    TARGET_ENOTDIR      = 20, +    TARGET_EISDIR       = 21, +    TARGET_EINVAL       = 22, +    TARGET_ENFILE       = 23, +    TARGET_EMFILE       = 24, +    TARGET_ENOTTY       = 25, +    TARGET_ETXTBSY      = 26, +    TARGET_EFBIG        = 27, +    TARGET_ENOSPC       = 28, +    TARGET_ESPIPE       = 29, +    TARGET_EROFS        = 30, +    TARGET_EMLINK       = 31, +    TARGET_EPIPE        = 32, +    TARGET_EDOM         = 33, +    TARGET_ERANGE       = 34, +    TARGET_ENOSYS       = 88, +    TARGET_ELOOP        = 92, +}; + +static uint32_t errno_h2g(int host_errno) +{ +    static const uint32_t guest_errno[] = { +        [EPERM]         = TARGET_EPERM, +        [ENOENT]        = TARGET_ENOENT, +        [ESRCH]         = TARGET_ESRCH, +        [EINTR]         = TARGET_EINTR, +        [EIO]           = TARGET_EIO, +        [ENXIO]         = TARGET_ENXIO, +        [E2BIG]         = TARGET_E2BIG, +        [ENOEXEC]       = TARGET_ENOEXEC, +        [EBADF]         = TARGET_EBADF, +        [ECHILD]        = TARGET_ECHILD, +        [EAGAIN]        = TARGET_EAGAIN, +        [ENOMEM]        = TARGET_ENOMEM, +        [EACCES]        = TARGET_EACCES, +        [EFAULT]        = TARGET_EFAULT, +#ifdef ENOTBLK +        [ENOTBLK]       = TARGET_ENOTBLK, +#endif +        [EBUSY]         = TARGET_EBUSY, +        [EEXIST]        = TARGET_EEXIST, +        [EXDEV]         = TARGET_EXDEV, +        [ENODEV]        = TARGET_ENODEV, +        [ENOTDIR]       = TARGET_ENOTDIR, +        [EISDIR]        = TARGET_EISDIR, +        [EINVAL]        = TARGET_EINVAL, +        [ENFILE]        = TARGET_ENFILE, +        [EMFILE]        = TARGET_EMFILE, +        [ENOTTY]        = TARGET_ENOTTY, +#ifdef ETXTBSY +        [ETXTBSY]       = TARGET_ETXTBSY, +#endif +        [EFBIG]         = TARGET_EFBIG, +        [ENOSPC]        = TARGET_ENOSPC, +        [ESPIPE]        = TARGET_ESPIPE, +        [EROFS]         = TARGET_EROFS, +        [EMLINK]        = TARGET_EMLINK, +        [EPIPE]         = TARGET_EPIPE, +        [EDOM]          = TARGET_EDOM, +        [ERANGE]        = TARGET_ERANGE, +        [ENOSYS]        = TARGET_ENOSYS, +#ifdef ELOOP +        [ELOOP]         = TARGET_ELOOP, +#endif +    }; + +    if (host_errno == 0) { +        return 0; +    } else if (host_errno > 0 && host_errno < ARRAY_SIZE(guest_errno) && +            guest_errno[host_errno]) { +        return guest_errno[host_errno]; +    } else { +        return TARGET_EINVAL; +    } +} + +void HELPER(simcall)(CPUXtensaState *env) +{ +    CPUState *cs = CPU(xtensa_env_get_cpu(env)); +    uint32_t *regs = env->regs; + +    switch (regs[2]) { +    case TARGET_SYS_exit: +        qemu_log("exit(%d) simcall\n", regs[3]); +        exit(regs[3]); +        break; + +    case TARGET_SYS_read: +    case TARGET_SYS_write: +        { +            bool is_write = regs[2] == TARGET_SYS_write; +            uint32_t fd = regs[3]; +            uint32_t vaddr = regs[4]; +            uint32_t len = regs[5]; + +            while (len > 0) { +                hwaddr paddr = cpu_get_phys_page_debug(cs, vaddr); +                uint32_t page_left = +                    TARGET_PAGE_SIZE - (vaddr & (TARGET_PAGE_SIZE - 1)); +                uint32_t io_sz = page_left < len ? page_left : len; +                hwaddr sz = io_sz; +                void *buf = cpu_physical_memory_map(paddr, &sz, is_write); + +                if (buf) { +                    vaddr += io_sz; +                    len -= io_sz; +                    regs[2] = is_write ? +                        write(fd, buf, io_sz) : +                        read(fd, buf, io_sz); +                    regs[3] = errno_h2g(errno); +                    cpu_physical_memory_unmap(buf, sz, is_write, sz); +                    if (regs[2] == -1) { +                        break; +                    } +                } else { +                    regs[2] = -1; +                    regs[3] = TARGET_EINVAL; +                    break; +                } +            } +        } +        break; + +    case TARGET_SYS_open: +        { +            char name[1024]; +            int rc; +            int i; + +            for (i = 0; i < ARRAY_SIZE(name); ++i) { +                rc = cpu_memory_rw_debug(cs, regs[3] + i, +                                         (uint8_t *)name + i, 1, 0); +                if (rc != 0 || name[i] == 0) { +                    break; +                } +            } + +            if (rc == 0 && i < ARRAY_SIZE(name)) { +                regs[2] = open(name, regs[4], regs[5]); +                regs[3] = errno_h2g(errno); +            } else { +                regs[2] = -1; +                regs[3] = TARGET_EINVAL; +            } +        } +        break; + +    case TARGET_SYS_close: +        if (regs[3] < 3) { +            regs[2] = regs[3] = 0; +        } else { +            regs[2] = close(regs[3]); +            regs[3] = errno_h2g(errno); +        } +        break; + +    case TARGET_SYS_lseek: +        regs[2] = lseek(regs[3], (off_t)(int32_t)regs[4], regs[5]); +        regs[3] = errno_h2g(errno); +        break; + +    case TARGET_SYS_select_one: +        { +            uint32_t fd = regs[3]; +            uint32_t rq = regs[4]; +            uint32_t target_tv = regs[5]; +            uint32_t target_tvv[2]; + +            struct timeval tv = {0}; +            fd_set fdset; + +            FD_ZERO(&fdset); +            FD_SET(fd, &fdset); + +            if (target_tv) { +                cpu_memory_rw_debug(cs, target_tv, +                        (uint8_t *)target_tvv, sizeof(target_tvv), 0); +                tv.tv_sec = (int32_t)tswap32(target_tvv[0]); +                tv.tv_usec = (int32_t)tswap32(target_tvv[1]); +            } +            regs[2] = select(fd + 1, +                    rq == SELECT_ONE_READ   ? &fdset : NULL, +                    rq == SELECT_ONE_WRITE  ? &fdset : NULL, +                    rq == SELECT_ONE_EXCEPT ? &fdset : NULL, +                    target_tv ? &tv : NULL); +            regs[3] = errno_h2g(errno); +        } +        break; + +    case TARGET_SYS_argc: +        regs[2] = 1; +        regs[3] = 0; +        break; + +    case TARGET_SYS_argv_sz: +        regs[2] = 128; +        regs[3] = 0; +        break; + +    case TARGET_SYS_argv: +        { +            struct Argv { +                uint32_t argptr[2]; +                char text[120]; +            } argv = { +                {0, 0}, +                "test" +            }; + +            argv.argptr[0] = tswap32(regs[3] + offsetof(struct Argv, text)); +            cpu_memory_rw_debug(cs, +                                regs[3], (uint8_t *)&argv, sizeof(argv), 1); +        } +        break; + +    case TARGET_SYS_memset: +        { +            uint32_t base = regs[3]; +            uint32_t sz = regs[5]; + +            while (sz) { +                hwaddr len = sz; +                void *buf = cpu_physical_memory_map(base, &len, 1); + +                if (buf && len) { +                    memset(buf, regs[4], len); +                    cpu_physical_memory_unmap(buf, len, 1, len); +                } else { +                    len = 1; +                } +                base += len; +                sz -= len; +            } +            regs[2] = regs[3]; +            regs[3] = 0; +        } +        break; + +    default: +        qemu_log("%s(%d): not implemented\n", __func__, regs[2]); +        regs[2] = -1; +        regs[3] = TARGET_ENOSYS; +        break; +    } +}  | 
