| /* |
| * Copyright (c) 2014, Red Hat Inc. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code 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 |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| * |
| */ |
| |
| #ifndef _CPU_STATE_H |
| #define _CPU_STATE_H |
| |
| #include <sys/types.h> |
| |
| /* |
| * symbolic names used to identify general registers which also match |
| * the registers indices in machine code |
| * |
| * We have 32 general registers which can be read/written as 32 bit or |
| * 64 bit sources/sinks and are appropriately referred to as Wn or Xn |
| * in the assembly code. Some instructions mix these access modes |
| * (e.g. ADD X0, X1, W2) so the implementation of the instruction |
| * needs to *know* which type of read or write access is required. |
| */ |
| enum GReg { |
| R0, |
| R1, |
| R2, |
| R3, |
| R4, |
| R5, |
| R6, |
| R7, |
| R8, |
| R9, |
| R10, |
| R11, |
| R12, |
| R13, |
| R14, |
| R15, |
| R16, |
| R17, |
| R18, |
| R19, |
| R20, |
| R21, |
| R22, |
| R23, |
| R24, |
| R25, |
| R26, |
| R27, |
| R28, |
| R29, |
| R30, |
| R31, |
| // and now the aliases |
| RSCRATCH1=R8, |
| RSCRATCH2=R9, |
| RMETHOD=R12, |
| RESP=R20, |
| RDISPATCH=R21, |
| RBCP=R22, |
| RLOCALS=R24, |
| RMONITORS=R25, |
| RCPOOL=R26, |
| RHEAPBASE=R27, |
| RTHREAD=R28, |
| FP = R29, |
| LR = R30, |
| SP = R31, |
| ZR = R31 |
| }; |
| |
| /* |
| * symbolic names used to refer to floating point registers which also |
| * match the registers indices in machine code |
| * |
| * We have 32 FP registers which can be read/written as 8, 16, 32, 64 |
| * and 128 bit sources/sinks and are appropriately referred to as Bn, |
| * Hn, Sn, Dn and Qn in the assembly code. Some instructions mix these |
| * access modes (e.g. FCVT S0, D0) so the implementation of the |
| * instruction needs to *know* which type of read or write access is |
| * required. |
| */ |
| |
| enum VReg { |
| V0, |
| V1, |
| V2, |
| V3, |
| V4, |
| V5, |
| V6, |
| V7, |
| V8, |
| V9, |
| V10, |
| V11, |
| V12, |
| V13, |
| V14, |
| V15, |
| V16, |
| V17, |
| V18, |
| V19, |
| V20, |
| V21, |
| V22, |
| V23, |
| V24, |
| V25, |
| V26, |
| V27, |
| V28, |
| V29, |
| V30, |
| V31, |
| }; |
| |
| /** |
| * all the different integer bit patterns for the components of a |
| * general register are overlaid here using a union so as to allow all |
| * reading and writing of the desired bits. |
| * |
| * n.b. the ARM spec says that when you write a 32 bit register you |
| * are supposed to write the low 32 bits and zero the high 32 |
| * bits. But we don't actually have to care about this because Java |
| * will only ever consume the 32 bits value as a 64 bit quantity after |
| * an explicit extend. |
| */ |
| union GRegisterValue |
| { |
| int8_t s8; |
| int16_t s16; |
| int32_t s32; |
| int64_t s64; |
| u_int8_t u8; |
| u_int16_t u16; |
| u_int32_t u32; |
| u_int64_t u64; |
| }; |
| |
| class GRegister |
| { |
| public: |
| GRegisterValue value; |
| }; |
| |
| /* |
| * float registers provide for storage of a single, double or quad |
| * word format float in the same register. single floats are not |
| * paired within each double register as per 32 bit arm. instead each |
| * 128 bit register Vn embeds the bits for Sn, and Dn in the lower |
| * quarter and half, respectively, of the bits for Qn. |
| * |
| * The upper bits can also be accessed as single or double floats by |
| * the float vector operations using indexing e.g. V1.D[1], V1.S[3] |
| * etc and, for SIMD operations using a horrible index range notation. |
| * |
| * The spec also talks about accessing float registers as half words |
| * and bytes with Hn and Bn providing access to the low 16 and 8 bits |
| * of Vn but it is not really clear what these bits represent. We can |
| * probably ignore this for Java anyway. However, we do need to access |
| * the raw bits at 32 and 64 bit resolution to load to/from integer |
| * registers. |
| */ |
| |
| union FRegisterValue |
| { |
| float s; |
| double d; |
| long double q; |
| // eventually we will need to be able to access the data as a vector |
| // the integral array elements allow us to access the bits in s, d, |
| // q, vs and vd at an appropriate level of granularity |
| u_int8_t vb[16]; |
| u_int16_t vh[8]; |
| u_int32_t vw[4]; |
| u_int64_t vx[2]; |
| float vs[4]; |
| double vd[2]; |
| }; |
| |
| class FRegister |
| { |
| public: |
| FRegisterValue value; |
| }; |
| |
| /* |
| * CPSR register -- this does not exist as a directly accessible |
| * register but we need to store the flags so we can implement |
| * flag-seting and flag testing operations |
| * |
| * we can possibly use injected x86 asm to report the outcome of flag |
| * setting operations. if so we will need to grab the flags |
| * immediately after the operation in order to ensure we don't lose |
| * them because of the actions of the simulator. so we still need |
| * somewhere to store the condition codes. |
| */ |
| |
| class CPSRRegister |
| { |
| public: |
| u_int32_t value; |
| |
| /* |
| * condition register bit select values |
| * |
| * the order of bits here is important because some of |
| * the flag setting conditional instructions employ a |
| * bit field to populate the flags when a false condition |
| * bypasses execution of the operation and we want to |
| * be able to assign the flags register using the |
| * supplied value. |
| */ |
| |
| enum CPSRIdx { |
| V_IDX, |
| C_IDX, |
| Z_IDX, |
| N_IDX |
| }; |
| |
| enum CPSRMask { |
| V = 1 << V_IDX, |
| C = 1 << C_IDX, |
| Z = 1 << Z_IDX, |
| N = 1 << N_IDX |
| }; |
| |
| static const int CPSR_ALL_FLAGS = (V | C | Z | N); |
| }; |
| |
| // auxiliary function to assemble the relevant bits from |
| // the x86 EFLAGS register into an ARM CPSR value |
| |
| #define X86_V_IDX 11 |
| #define X86_C_IDX 0 |
| #define X86_Z_IDX 6 |
| #define X86_N_IDX 7 |
| |
| #define X86_V (1 << X86_V_IDX) |
| #define X86_C (1 << X86_C_IDX) |
| #define X86_Z (1 << X86_Z_IDX) |
| #define X86_N (1 << X86_N_IDX) |
| |
| inline u_int32_t convertX86Flags(u_int32_t x86flags) |
| { |
| u_int32_t flags; |
| // set N flag |
| flags = ((x86flags & X86_N) >> X86_N_IDX); |
| // shift then or in Z flag |
| flags <<= 1; |
| flags |= ((x86flags & X86_Z) >> X86_Z_IDX); |
| // shift then or in C flag |
| flags <<= 1; |
| flags |= ((x86flags & X86_C) >> X86_C_IDX); |
| // shift then or in V flag |
| flags <<= 1; |
| flags |= ((x86flags & X86_V) >> X86_V_IDX); |
| |
| return flags; |
| } |
| |
| inline u_int32_t convertX86FlagsFP(u_int32_t x86flags) |
| { |
| // x86 flags set by fcomi(x,y) are ZF:PF:CF |
| // (yes, that's PF for parity, WTF?) |
| // where |
| // 0) 0:0:0 means x > y |
| // 1) 0:0:1 means x < y |
| // 2) 1:0:0 means x = y |
| // 3) 1:1:1 means x and y are unordered |
| // note that we don't have to check PF so |
| // we really have a simple 2-bit case switch |
| // the corresponding ARM64 flags settings |
| // in hi->lo bit order are |
| // 0) --C- |
| // 1) N--- |
| // 2) -ZC- |
| // 3) --CV |
| |
| static u_int32_t armFlags[] = { |
| 0b0010, |
| 0b1000, |
| 0b0110, |
| 0b0011 |
| }; |
| // pick out the ZF and CF bits |
| u_int32_t zc = ((x86flags & X86_Z) >> X86_Z_IDX); |
| zc <<= 1; |
| zc |= ((x86flags & X86_C) >> X86_C_IDX); |
| |
| return armFlags[zc]; |
| } |
| |
| /* |
| * FPSR register -- floating point status register |
| |
| * this register includes IDC, IXC, UFC, OFC, DZC, IOC and QC bits, |
| * and the floating point N, Z, C, V bits but the latter are unused in |
| * aarch64 mode. the sim ignores QC for now. |
| * |
| * bit positions are as per the ARMv7 FPSCR register |
| * |
| * IDC : 7 ==> Input Denormal (cumulative exception bit) |
| * IXC : 4 ==> Inexact |
| * UFC : 3 ==> Underflow |
| * OFC : 2 ==> Overflow |
| * DZC : 1 ==> Division by Zero |
| * IOC : 0 ==> Invalid Operation |
| */ |
| |
| class FPSRRegister |
| { |
| public: |
| u_int32_t value; |
| // indices for bits in the FPSR register value |
| enum FPSRIdx { |
| IO_IDX = 0, |
| DZ_IDX = 1, |
| OF_IDX = 2, |
| UF_IDX = 3, |
| IX_IDX = 4, |
| ID_IDX = 7 |
| }; |
| // corresponding bits as numeric values |
| enum FPSRMask { |
| IO = (1 << IO_IDX), |
| DZ = (1 << DZ_IDX), |
| OF = (1 << OF_IDX), |
| UF = (1 << UF_IDX), |
| IX = (1 << IX_IDX), |
| ID = (1 << ID_IDX) |
| }; |
| static const int FPSR_ALL_FPSRS = (IO | DZ | OF | UF | IX | ID); |
| }; |
| |
| // debugger support |
| |
| enum PrintFormat |
| { |
| FMT_DECIMAL, |
| FMT_HEX, |
| FMT_SINGLE, |
| FMT_DOUBLE, |
| FMT_QUAD, |
| FMT_MULTI |
| }; |
| |
| /* |
| * model of the registers and other state associated with the cpu |
| */ |
| class CPUState |
| { |
| friend class AArch64Simulator; |
| private: |
| // this is the PC of the instruction being executed |
| u_int64_t pc; |
| // this is the PC of the instruction to be executed next |
| // it is defaulted to pc + 4 at instruction decode but |
| // execute may reset it |
| |
| u_int64_t nextpc; |
| GRegister gr[33]; // extra register at index 32 is used |
| // to hold zero value |
| FRegister fr[32]; |
| CPSRRegister cpsr; |
| FPSRRegister fpsr; |
| |
| public: |
| |
| CPUState() { |
| gr[20].value.u64 = 0; // establish initial condition for |
| // checkAssertions() |
| trace_counter = 0; |
| } |
| |
| // General Register access macros |
| |
| // only xreg or xregs can be used as an lvalue in order to update a |
| // register. this ensures that the top part of a register is always |
| // assigned when it is written by the sim. |
| |
| inline u_int64_t &xreg(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.u64; |
| } else { |
| return gr[reg].value.u64; |
| } |
| } |
| |
| inline int64_t &xregs(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.s64; |
| } else { |
| return gr[reg].value.s64; |
| } |
| } |
| |
| inline u_int32_t wreg(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.u32; |
| } else { |
| return gr[reg].value.u32; |
| } |
| } |
| |
| inline int32_t wregs(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.s32; |
| } else { |
| return gr[reg].value.s32; |
| } |
| } |
| |
| inline u_int32_t hreg(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.u16; |
| } else { |
| return gr[reg].value.u16; |
| } |
| } |
| |
| inline int32_t hregs(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.s16; |
| } else { |
| return gr[reg].value.s16; |
| } |
| } |
| |
| inline u_int32_t breg(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.u8; |
| } else { |
| return gr[reg].value.u8; |
| } |
| } |
| |
| inline int32_t bregs(GReg reg, int r31_is_sp) { |
| if (reg == R31 && !r31_is_sp) { |
| return gr[32].value.s8; |
| } else { |
| return gr[reg].value.s8; |
| } |
| } |
| |
| // FP Register access macros |
| |
| // all non-vector accessors return a reference so we can both read |
| // and assign |
| |
| inline float &sreg(VReg reg) { |
| return fr[reg].value.s; |
| } |
| |
| inline double &dreg(VReg reg) { |
| return fr[reg].value.d; |
| } |
| |
| inline long double &qreg(VReg reg) { |
| return fr[reg].value.q; |
| } |
| |
| // all vector register accessors return a pointer |
| |
| inline float *vsreg(VReg reg) { |
| return &fr[reg].value.vs[0]; |
| } |
| |
| inline double *vdreg(VReg reg) { |
| return &fr[reg].value.vd[0]; |
| } |
| |
| inline u_int8_t *vbreg(VReg reg) { |
| return &fr[reg].value.vb[0]; |
| } |
| |
| inline u_int16_t *vhreg(VReg reg) { |
| return &fr[reg].value.vh[0]; |
| } |
| |
| inline u_int32_t *vwreg(VReg reg) { |
| return &fr[reg].value.vw[0]; |
| } |
| |
| inline u_int64_t *vxreg(VReg reg) { |
| return &fr[reg].value.vx[0]; |
| } |
| |
| union GRegisterValue prev_sp, prev_fp; |
| |
| static const int trace_size = 256; |
| u_int64_t trace_buffer[trace_size]; |
| int trace_counter; |
| |
| bool checkAssertions() |
| { |
| // Make sure that SP is 16-aligned |
| // Also make sure that ESP is above SP. |
| // We don't care about checking ESP if it is null, i.e. it hasn't |
| // been used yet. |
| if (gr[31].value.u64 & 0x0f) { |
| asm volatile("nop"); |
| return false; |
| } |
| return true; |
| } |
| |
| // pc register accessors |
| |
| // this instruction can be used to fetch the current PC |
| u_int64_t getPC(); |
| // instead of setting the current PC directly you can |
| // first set the next PC (either absolute or PC-relative) |
| // and later copy the next PC into the current PC |
| // this supports a default increment by 4 at instruction |
| // fetch with an optional reset by control instructions |
| u_int64_t getNextPC(); |
| void setNextPC(u_int64_t next); |
| void offsetNextPC(int64_t offset); |
| // install nextpc as current pc |
| void updatePC(); |
| |
| // this instruction can be used to save the next PC to LR |
| // just before installing a branch PC |
| inline void saveLR() { gr[LR].value.u64 = nextpc; } |
| |
| // cpsr register accessors |
| u_int32_t getCPSRRegister(); |
| void setCPSRRegister(u_int32_t flags); |
| // read a specific subset of the flags as a bit pattern |
| // mask should be composed using elements of enum FlagMask |
| u_int32_t getCPSRBits(u_int32_t mask); |
| // assign a specific subset of the flags as a bit pattern |
| // mask and value should be composed using elements of enum FlagMask |
| void setCPSRBits(u_int32_t mask, u_int32_t value); |
| // test the value of a single flag returned as 1 or 0 |
| u_int32_t testCPSR(CPSRRegister::CPSRIdx idx); |
| // set a single flag |
| void setCPSR(CPSRRegister::CPSRIdx idx); |
| // clear a single flag |
| void clearCPSR(CPSRRegister::CPSRIdx idx); |
| // utility method to set ARM CSPR flags from an x86 bit mask generated by integer arithmetic |
| void setCPSRRegisterFromX86(u_int64_t x86Flags); |
| // utility method to set ARM CSPR flags from an x86 bit mask generated by floating compare |
| void setCPSRRegisterFromX86FP(u_int64_t x86Flags); |
| |
| // fpsr register accessors |
| u_int32_t getFPSRRegister(); |
| void setFPSRRegister(u_int32_t flags); |
| // read a specific subset of the fprs bits as a bit pattern |
| // mask should be composed using elements of enum FPSRRegister::FlagMask |
| u_int32_t getFPSRBits(u_int32_t mask); |
| // assign a specific subset of the flags as a bit pattern |
| // mask and value should be composed using elements of enum FPSRRegister::FlagMask |
| void setFPSRBits(u_int32_t mask, u_int32_t value); |
| // test the value of a single flag returned as 1 or 0 |
| u_int32_t testFPSR(FPSRRegister::FPSRIdx idx); |
| // set a single flag |
| void setFPSR(FPSRRegister::FPSRIdx idx); |
| // clear a single flag |
| void clearFPSR(FPSRRegister::FPSRIdx idx); |
| |
| // debugger support |
| void printPC(int pending, const char *trailing = "\n"); |
| void printInstr(u_int32_t instr, void (*dasm)(u_int64_t), const char *trailing = "\n"); |
| void printGReg(GReg reg, PrintFormat format = FMT_HEX, const char *trailing = "\n"); |
| void printVReg(VReg reg, PrintFormat format = FMT_HEX, const char *trailing = "\n"); |
| void printCPSR(const char *trailing = "\n"); |
| void printFPSR(const char *trailing = "\n"); |
| void dumpState(); |
| }; |
| |
| #endif // ifndef _CPU_STATE_H |