DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_dynrec/risc_armv8le.h
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 
00021 /* ARMv8 (little endian, 64-bit) backend by M-HT */
00022 
00023 
00024 // some configuring defines that specify the capabilities of this architecture
00025 // or aspects of the recompiling
00026 
00027 // protect FC_ADDR over function calls if necessaray
00028 // #define DRC_PROTECT_ADDR_REG
00029 
00030 // try to use non-flags generating functions if possible
00031 #define DRC_FLAGS_INVALIDATION
00032 // try to replace _simple functions by code
00033 #define DRC_FLAGS_INVALIDATION_DCODE
00034 
00035 // type with the same size as a pointer
00036 #define DRC_PTR_SIZE_IM Bit64u
00037 
00038 // calling convention modifier
00039 #define DRC_CALL_CONV   /* nothing */
00040 #define DRC_FC                  /* nothing */
00041 
00042 // use FC_REGS_ADDR to hold the address of "cpu_regs" and to access it using FC_REGS_ADDR
00043 #define DRC_USE_REGS_ADDR
00044 // use FC_SEGS_ADDR to hold the address of "Segs" and to access it using FC_SEGS_ADDR
00045 #define DRC_USE_SEGS_ADDR
00046 
00047 // register mapping
00048 typedef Bit8u HostReg;
00049 
00050 // registers
00051 #define HOST_r0          0
00052 #define HOST_r1          1
00053 #define HOST_r2          2
00054 #define HOST_r3          3
00055 #define HOST_r4          4
00056 #define HOST_r5          5
00057 #define HOST_r6          6
00058 #define HOST_r7          7
00059 #define HOST_r8          8
00060 #define HOST_r9          9
00061 #define HOST_r10        10
00062 #define HOST_r11        11
00063 #define HOST_r12        12
00064 #define HOST_r13        13
00065 #define HOST_r14        14
00066 #define HOST_r15        15
00067 #define HOST_r16        16
00068 #define HOST_r17        17
00069 #define HOST_r18        18
00070 #define HOST_r19        19
00071 #define HOST_r20        20
00072 #define HOST_r21        21
00073 #define HOST_r22        22
00074 #define HOST_r23        23
00075 #define HOST_r24        24
00076 #define HOST_r25        25
00077 #define HOST_r26        26
00078 #define HOST_r27        27
00079 #define HOST_r28        28
00080 #define HOST_r29        29
00081 #define HOST_r30        30
00082 // special registers
00083 #define HOST_sp         31
00084 #define HOST_zr         31
00085 
00086 // register aliases
00087 // 32-bit registers
00088 #define HOST_w0         HOST_r0
00089 #define HOST_w1         HOST_r1
00090 #define HOST_w2         HOST_r2
00091 #define HOST_w3         HOST_r3
00092 #define HOST_w4         HOST_r4
00093 #define HOST_w5         HOST_r5
00094 #define HOST_w6         HOST_r6
00095 #define HOST_w7         HOST_r7
00096 #define HOST_w8         HOST_r8
00097 #define HOST_w9         HOST_r9
00098 #define HOST_w10        HOST_r10
00099 #define HOST_w11        HOST_r11
00100 #define HOST_w12        HOST_r12
00101 #define HOST_w13        HOST_r13
00102 #define HOST_w14        HOST_r14
00103 #define HOST_w15        HOST_r15
00104 #define HOST_w16        HOST_r16
00105 #define HOST_w17        HOST_r17
00106 #define HOST_w18        HOST_r18
00107 #define HOST_w19        HOST_r19
00108 #define HOST_w20        HOST_r20
00109 #define HOST_w21        HOST_r21
00110 #define HOST_w22        HOST_r22
00111 #define HOST_w23        HOST_r23
00112 #define HOST_w24        HOST_r24
00113 #define HOST_w25        HOST_r25
00114 #define HOST_w26        HOST_r26
00115 #define HOST_w27        HOST_r27
00116 #define HOST_w28        HOST_r28
00117 #define HOST_w29        HOST_r29
00118 #define HOST_w30        HOST_r30
00119 #define HOST_wsp        HOST_sp
00120 #define HOST_wzr        HOST_zr
00121 // 64-bit registers
00122 #define HOST_x0         HOST_r0
00123 #define HOST_x1         HOST_r1
00124 #define HOST_x2         HOST_r2
00125 #define HOST_x3         HOST_r3
00126 #define HOST_x4         HOST_r4
00127 #define HOST_x5         HOST_r5
00128 #define HOST_x6         HOST_r6
00129 #define HOST_x7         HOST_r7
00130 #define HOST_x8         HOST_r8
00131 #define HOST_x9         HOST_r9
00132 #define HOST_x10        HOST_r10
00133 #define HOST_x11        HOST_r11
00134 #define HOST_x12        HOST_r12
00135 #define HOST_x13        HOST_r13
00136 #define HOST_x14        HOST_r14
00137 #define HOST_x15        HOST_r15
00138 #define HOST_x16        HOST_r16
00139 #define HOST_x17        HOST_r17
00140 #define HOST_x18        HOST_r18
00141 #define HOST_x19        HOST_r19
00142 #define HOST_x20        HOST_r20
00143 #define HOST_x21        HOST_r21
00144 #define HOST_x22        HOST_r22
00145 #define HOST_x23        HOST_r23
00146 #define HOST_x24        HOST_r24
00147 #define HOST_x25        HOST_r25
00148 #define HOST_x26        HOST_r26
00149 #define HOST_x27        HOST_r27
00150 #define HOST_x28        HOST_r28
00151 #define HOST_x29        HOST_r29
00152 #define HOST_x30        HOST_r30
00153 #define HOST_xzr        HOST_zr
00154 #define HOST_ip0        HOST_r16
00155 #define HOST_ip1        HOST_r17
00156 #define HOST_fp         HOST_r29
00157 #define HOST_lr         HOST_r30
00158 
00159 
00160 // temporary registers
00161 #define temp1 HOST_r10
00162 #define temp2 HOST_r11
00163 #define temp3 HOST_r12
00164 
00165 // register that holds function return values
00166 #define FC_RETOP HOST_r0
00167 
00168 // register used for address calculations,
00169 #define FC_ADDR HOST_r19                        // has to be saved across calls, see DRC_PROTECT_ADDR_REG
00170 
00171 // register that holds the first parameter
00172 #define FC_OP1 HOST_r0
00173 
00174 // register that holds the second parameter
00175 #define FC_OP2 HOST_r1
00176 
00177 // special register that holds the third parameter for _R3 calls (byte accessible)
00178 #define FC_OP3 HOST_r2
00179 
00180 // register that holds byte-accessible temporary values
00181 #define FC_TMP_BA1 HOST_r0
00182 
00183 // register that holds byte-accessible temporary values
00184 #define FC_TMP_BA2 HOST_r1
00185 
00186 // temporary register for LEA
00187 #define TEMP_REG_DRC HOST_r9
00188 
00189 // used to hold the address of "cpu_regs" - preferably filled in function gen_run_code
00190 #define FC_REGS_ADDR HOST_r20
00191 
00192 // used to hold the address of "Segs" - preferably filled in function gen_run_code
00193 #define FC_SEGS_ADDR HOST_r21
00194 
00195 // used to hold the address of "core_dynrec.readdata" - filled in function gen_run_code
00196 #define readdata_addr HOST_r22
00197 
00198 
00199 // instruction encodings
00200 
00201 // move
00202 // mov dst, src, lsl #imm
00203 #define MOV_REG_LSL_IMM(dst, src, imm) ORR_REG_LSL_IMM(dst, HOST_wzr, src, imm)
00204 // movz dst, #(imm lsl simm)            @       0 <= imm <= 65535       &       simm = 0/16
00205 #define MOVZ(dst, imm, simm) (0x52800000 + (dst) + ((imm) << 5) + ((simm)?0x00200000:0) )
00206 // movn dst, #(imm lsl simm)            @       0 <= imm <= 65535       &       simm = 0/16
00207 #define MOVN(dst, imm, simm) (0x12800000 + (dst) + ((imm) << 5) + ((simm)?0x00200000:0) )
00208 // movk dst, #(imm lsl simm)            @       0 <= imm <= 65535       &       simm = 0/16
00209 #define MOVK(dst, imm, simm) (0x72800000 + (dst) + ((imm) << 5) + ((simm)?0x00200000:0) )
00210 // movz dst, #(imm lsl simm)            @       0 <= imm <= 65535       &       simm = 0/16/32/48
00211 #define MOVZ64(dst, imm, simm) (0xd2800000 + (dst) + ((imm) << 5) + (((simm) >> 4) << 21) )
00212 // movk dst, #(imm lsl simm)            @       0 <= imm <= 65535       &       simm = 0/16/32/48
00213 #define MOVK64(dst, imm, simm) (0xf2800000 + (dst) + ((imm) << 5) + (((simm) >> 4) << 21) )
00214 // lslv dst, src, rreg
00215 #define LSLV(dst, src, rreg) (0x1ac02000 + (dst) + ((src) << 5) + ((rreg) << 16) )
00216 // lsrv dst, src, rreg
00217 #define LSRV(dst, src, rreg) (0x1ac02400 + (dst) + ((src) << 5) + ((rreg) << 16) )
00218 // asrv dst, src, rreg
00219 #define ASRV(dst, src, rreg) (0x1ac02800 + (dst) + ((src) << 5) + ((rreg) << 16) )
00220 // rorv dst, src, rreg
00221 #define RORV(dst, src, rreg) (0x1ac02c00 + (dst) + ((src) << 5) + ((rreg) << 16) )
00222 // lslv dst, src, rreg
00223 #define LSLV64(dst, src, rreg) (0x9ac02000 + (dst) + ((src) << 5) + ((rreg) << 16) )
00224 // lsrv dst, src, rreg
00225 #define LSRV64(dst, src, rreg) (0x9ac02400 + (dst) + ((src) << 5) + ((rreg) << 16) )
00226 // lsr dst, src, #imm
00227 #define LSR64_IMM(dst, src, imm) UBFM64(dst, src, imm, 63)
00228 
00229 // arithmetic
00230 // add dst, src, #(imm lsl simm)                @       0 <= imm <= 4095        &       simm = 0/12
00231 #define ADD_IMM(dst, src, imm, simm) (0x11000000 + (dst) + ((src) << 5) + ((imm) << 10) + ((simm)?0x00400000:0) )
00232 // add dst, src1, src2, lsl #imm
00233 #define ADD_REG_LSL_IMM(dst, src1, src2, imm) (0x0b000000 + (dst) + ((src1) << 5) + ((src2) << 16) + ((imm) << 10) )
00234 // sub dst, src, #(imm lsl simm)                @       0 <= imm <= 4095        &       simm = 0/12
00235 #define SUB_IMM(dst, src, imm, simm) (0x51000000 + (dst) + ((src) << 5) + ((imm) << 10) + ((simm)?0x00400000:0) )
00236 // sub dst, src1, src2, lsl #imm
00237 #define SUB_REG_LSL_IMM(dst, src1, src2, imm) (0x4b000000 + (dst) + ((src1) << 5) + ((src2) << 16) + ((imm) << 10) )
00238 // cmp src, #(imm lsl simm)             @       0 <= imm <= 4095        &       simm = 0/12
00239 #define CMP_IMM(src, imm, simm) (0x7100001f + ((src) << 5) + ((imm) << 10) + ((simm)?0x00400000:0) )
00240 // nop
00241 #define NOP (0xd503201f)
00242 
00243 // logical
00244 // and dst, src1, src2, lsl #imm                @       0 <= imm <= 31
00245 #define AND_REG_LSL_IMM(dst, src1, src2, imm) (0x0a000000 + (dst) + ((src1) << 5) + ((src2) << 16) + ((imm) << 10) )
00246 // orr dst, src1, src2, lsl #imm                @       0 <= imm <= 31
00247 #define ORR_REG_LSL_IMM(dst, src1, src2, imm) (0x2a000000 + (dst) + ((src1) << 5) + ((src2) << 16) + ((imm) << 10) )
00248 // eor dst, src1, src2, lsl #imm                @       0 <= imm <= 31
00249 #define EOR_REG_LSL_IMM(dst, src1, src2, imm) (0x4a000000 + (dst) + ((src1) << 5) + ((src2) << 16) + ((imm) << 10) )
00250 // bic dst, src1, src2, lsl #imm                @       0 <= imm <= 31
00251 #define BIC_REG_LSL_IMM(dst, src1, src2, imm) (0x0a200000 + (dst) + ((src1) << 5) + ((src2) << 16) + ((imm) << 10) )
00252 // and dst, src1, src2, lsl #imm                @       0 <= imm <= 63
00253 #define AND64_REG_LSL_IMM(dst, src1, src2, imm) (0x8a000000 + (dst) + ((src1) << 5) + ((src2) << 16) + ((imm) << 10) )
00254 
00255 // load
00256 // ldr reg, [pc, #imm]          @       -1M <= imm < 1M &       imm mod 4 = 0
00257 #define LDR64_PC(reg, imm) (0x58000000 + (reg) + (((imm) << 3) & 0x00ffffe0) )
00258 // ldp reg1, reg2 [addr, #imm]          @       -512 <= imm < 512       &       imm mod 8 = 0
00259 #define LDP64_IMM(reg1, reg2, addr, imm) (0xa9400000 + (reg1) + ((reg2) << 10) + ((addr) << 5) + ((imm) << 12) )
00260 // ldr reg, [addr, #imm]                @       0 <= imm < 32768        &       imm mod 8 = 0
00261 #define LDR64_IMM(reg, addr, imm) (0xf9400000 + (reg) + ((addr) << 5) + ((imm) << 7) )
00262 // ldr reg, [addr, #imm]                @       0 <= imm < 16384        &       imm mod 4 = 0
00263 #define LDR_IMM(reg, addr, imm) (0xb9400000 + (reg) + ((addr) << 5) + ((imm) << 8) )
00264 // ldrh reg, [addr, #imm]               @       0 <= imm < 8192 &       imm mod 2 = 0
00265 #define LDRH_IMM(reg, addr, imm) (0x79400000 + (reg) + ((addr) << 5) + ((imm) << 9) )
00266 // ldrb reg, [addr, #imm]               @       0 <= imm < 4096
00267 #define LDRB_IMM(reg, addr, imm) (0x39400000 + (reg) + ((addr) << 5) + ((imm) << 10) )
00268 // ldr reg, [addr1, addr2, lsl #imm]            @       imm = 0/2
00269 #define LDR64_REG_LSL_IMM(reg, addr1, addr2, imm) (0xf8606800 + (reg) + ((addr1) << 5) + ((addr2) << 16) + ((imm)?0x00001000:0) )
00270 // ldur reg, [addr, #imm]               @       -256 <= imm < 256
00271 #define LDUR64_IMM(reg, addr, imm) (0xf8400000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00272 // ldur reg, [addr, #imm]               @       -256 <= imm < 256
00273 #define LDUR_IMM(reg, addr, imm) (0xb8400000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00274 // ldurh reg, [addr, #imm]              @       -256 <= imm < 256
00275 #define LDURH_IMM(reg, addr, imm) (0x78400000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00276 // ldurb reg, [addr, #imm]              @       -256 <= imm < 256
00277 #define LDURB_IMM(reg, addr, imm) (0x38400000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00278 
00279 // store
00280 // stp reg1, reg2 [addr, #imm]          @       -512 <= imm < 512       &       imm mod 8 = 0
00281 #define STP64_IMM(reg1, reg2, addr, imm) (0xa9000000 + (reg1) + ((reg2) << 10) + ((addr) << 5) + ((imm) << 12) )
00282 // str reg, [addr, #imm]                @       0 <= imm < 32768        &       imm mod 8 = 0
00283 #define STR64_IMM(reg, addr, imm) (0xf9000000 + (reg) + ((addr) << 5) + ((imm) << 7) )
00284 // str reg, [addr, #imm]                @       0 <= imm < 16384        &       imm mod 4 = 0
00285 #define STR_IMM(reg, addr, imm) (0xb9000000 + (reg) + ((addr) << 5) + ((imm) << 8) )
00286 // strh reg, [addr, #imm]               @       0 <= imm < 8192 &       imm mod 2 = 0
00287 #define STRH_IMM(reg, addr, imm) (0x79000000 + (reg) + ((addr) << 5) + ((imm) << 9) )
00288 // strb reg, [addr, #imm]               @       0 <= imm < 4096
00289 #define STRB_IMM(reg, addr, imm) (0x39000000 + (reg) + ((addr) << 5) + ((imm) << 10) )
00290 // stur reg, [addr, #imm]               @       -256 <= imm < 256
00291 #define STUR64_IMM(reg, addr, imm) (0xf8000000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00292 // stur reg, [addr, #imm]               @       -256 <= imm < 256
00293 #define STUR_IMM(reg, addr, imm) (0xb8000000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00294 // sturh reg, [addr, #imm]              @       -256 <= imm < 256
00295 #define STURH_IMM(reg, addr, imm) (0x78000000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00296 // sturb reg, [addr, #imm]              @       -256 <= imm < 256
00297 #define STURB_IMM(reg, addr, imm) (0x38000000 + (reg) + ((addr) << 5) + (((imm) << 12) & 0x001ff000) )
00298 
00299 // branch
00300 // bgt pc+imm           @       0 <= imm < 1M   &       imm mod 4 = 0
00301 #define BGT_FWD(imm) (0x5400000c + ((imm) << 3) )
00302 // b pc+imm             @       0 <= imm < 128M &       imm mod 4 = 0
00303 #define B_FWD(imm) (0x14000000 + ((imm) >> 2) )
00304 // br reg
00305 #define BR(reg) (0xd61f0000 + ((reg) << 5) )
00306 // blr reg
00307 #define BLR_REG(reg) (0xd63f0000 + ((reg) << 5) )
00308 // cbz reg, pc+imm              @       0 <= imm < 1M   &       imm mod 4 = 0
00309 #define CBZ_FWD(reg, imm) (0x34000000 + (reg) + ((imm) << 3) )
00310 // cbnz reg, pc+imm             @       0 <= imm < 1M   &       imm mod 4 = 0
00311 #define CBNZ_FWD(reg, imm) (0x35000000 + (reg) + ((imm) << 3) )
00312 // ret reg
00313 #define RET_REG(reg) (0xd65f0000 + ((reg) << 5) )
00314 // ret
00315 #define RET RET_REG(HOST_x30)
00316 
00317 // extend
00318 // sxth dst, src
00319 #define SXTH(dst, src) SBFM(dst, src, 0, 15)
00320 // sxtb dst, src
00321 #define SXTB(dst, src) SBFM(dst, src, 0, 7)
00322 // uxth dst, src
00323 #define UXTH(dst, src) UBFM(dst, src, 0, 15)
00324 // uxtb dst, src
00325 #define UXTB(dst, src) UBFM(dst, src, 0, 7)
00326 
00327 // bit field
00328 // bfi dst, src, #lsb, #width           @       lsb >= 0, width >= 1, lsb+width <= 32
00329 #define BFI(dst, src, lsb, width) BFM(dst, src, (32 - (lsb)) & 0x1f, (width) - 1)
00330 // bfm dst, src, #rimm, #simm           @       0 <= rimm < 32, 0 <= simm < 32
00331 #define BFM(dst, src, rimm, simm) (0x33000000 + (dst) + ((src) << 5) + ((rimm) << 16) + ((simm) << 10) )
00332 // sbfm dst, src, #rimm, #simm          @       0 <= rimm < 32, 0 <= simm < 32
00333 #define SBFM(dst, src, rimm, simm) (0x13000000 + (dst) + ((src) << 5) + ((rimm) << 16) + ((simm) << 10) )
00334 // ubfm dst, src, #rimm, #simm          @       0 <= rimm < 32, 0 <= simm < 32
00335 #define UBFM(dst, src, rimm, simm) (0x53000000 + (dst) + ((src) << 5) + ((rimm) << 16) + ((simm) << 10) )
00336 // bfi dst, src, #lsb, #width           @       lsb >= 0, width >= 1, lsb+width <= 64
00337 #define BFI64(dst, src, lsb, width) BFM64(dst, src, (64 - (lsb)) & 0x3f, (width) - 1)
00338 // bfm dst, src, #rimm, #simm           @       0 <= rimm < 64, 0 <= simm < 64
00339 #define BFM64(dst, src, rimm, simm) (0xb3400000 + (dst) + ((src) << 5) + ((rimm) << 16) + ((simm) << 10) )
00340 // ubfm dst, src, #rimm, #simm          @       0 <= rimm < 64, 0 <= simm < 64
00341 #define UBFM64(dst, src, rimm, simm) (0xd3400000 + (dst) + ((src) << 5) + ((rimm) << 16) + ((simm) << 10) )
00342 
00343 
00344 // move a full register from reg_src to reg_dst
00345 static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) {
00346         if(reg_src == reg_dst) return;
00347         cache_addd( MOV_REG_LSL_IMM(reg_dst, reg_src, 0) );      // mov reg_dst, reg_src
00348 }
00349 
00350 // move a 32bit constant value into dest_reg
00351 static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) {
00352         if ( (imm & 0xffff0000) == 0 ) {
00353                 cache_addd( MOVZ(dest_reg, imm, 0) );               // movz dest_reg, #imm
00354         } else if ( (imm & 0x0000ffff) == 0 ) {
00355                 cache_addd( MOVZ(dest_reg, imm >> 16, 16) );        // movz dest_reg, #(imm >> 16), lsl #16
00356         } else if ( ((~imm) & 0xffff0000) == 0 ) {
00357                 cache_addd( MOVN(dest_reg, ~imm, 0) );              // movn dest_reg, #(~imm)
00358         } else if ( ((~imm) & 0x0000ffff) == 0 ) {
00359                 cache_addd( MOVN(dest_reg, (~imm) >> 16, 16) );     // movn dest_reg, #(~imm >> 16), lsl #16
00360         } else {
00361                 cache_addd( MOVZ(dest_reg, imm & 0xffff, 0) );      // movz dest_reg, #(imm & 0xffff)
00362                 cache_addd( MOVK(dest_reg, imm >> 16, 16) );        // movk dest_reg, #(imm >> 16), lsl #16
00363         }
00364 }
00365 
00366 // helper function
00367 static bool gen_mov_memval_to_reg_helper(HostReg dest_reg, Bit64u data, Bitu size, HostReg addr_reg, Bit64u addr_data) {
00368         switch (size) {
00369                 case 8:
00370                         if (((data & 7) == 0) && (data >= addr_data) && (data < addr_data + 32768)) {
00371                                 cache_addd( LDR64_IMM(dest_reg, addr_reg, data - addr_data) );      // ldr dest_reg, [addr_reg, #(data - addr_data)]
00372                                 return true;
00373                         } else if ((data < addr_data + 256) && (data >= addr_data - 256)) {
00374                                 cache_addd( LDUR64_IMM(dest_reg, addr_reg, data - addr_data) );     // ldur dest_reg, [addr_reg, #(data - addr_data)]
00375                                 return true;
00376                         }
00377                         break;
00378                 case 4:
00379                         if (((data & 3) == 0) && (data >= addr_data) && (data < addr_data + 16384)) {
00380                                 cache_addd( LDR_IMM(dest_reg, addr_reg, data - addr_data) );        // ldr dest_reg, [addr_reg, #(data - addr_data)]
00381                                 return true;
00382                         } else if ((data < addr_data + 256) && (data >= addr_data - 256)) {
00383                                 cache_addd( LDUR_IMM(dest_reg, addr_reg, data - addr_data) );       // ldur dest_reg, [addr_reg, #(data - addr_data)]
00384                                 return true;
00385                         }
00386                         break;
00387                 case 2:
00388                         if (((data & 1) == 0) && (data >= addr_data) && (data < addr_data + 8192)) {
00389                                 cache_addd( LDRH_IMM(dest_reg, addr_reg, data - addr_data) );       // ldrh dest_reg, [addr_reg, #(data - addr_data)]
00390                                 return true;
00391                         } else if ((data < addr_data + 256) && (data >= addr_data - 256)) {
00392                                 cache_addd( LDURH_IMM(dest_reg, addr_reg, data - addr_data) );      // ldurh dest_reg, [addr_reg, #(data - addr_data)]
00393                                 return true;
00394                         }
00395                         break;
00396                 case 1:
00397                         if ((data >= addr_data) && (data < addr_data + 4096)) {
00398                                 cache_addd( LDRB_IMM(dest_reg, addr_reg, data - addr_data) );       // ldrb dest_reg, [addr_reg, #(data - addr_data)]
00399                                 return true;
00400                         } else if ((data < addr_data) && (data >= addr_data - 256)) {
00401                                 cache_addd( LDURB_IMM(dest_reg, addr_reg, data - addr_data) );      // ldurb dest_reg, [addr_reg, #(data - addr_data)]
00402                                 return true;
00403                         }
00404                 default:
00405                         break;
00406         }
00407         return false;
00408 }
00409 
00410 // helper function
00411 static bool gen_mov_memval_to_reg(HostReg dest_reg, void *data, Bitu size) {
00412         if (gen_mov_memval_to_reg_helper(dest_reg, (Bit64u)data, size, FC_REGS_ADDR, (Bit64u)&cpu_regs)) return true;
00413         if (gen_mov_memval_to_reg_helper(dest_reg, (Bit64u)data, size, readdata_addr, (Bit64u)&core_dynrec.readdata)) return true;
00414         if (gen_mov_memval_to_reg_helper(dest_reg, (Bit64u)data, size, FC_SEGS_ADDR, (Bit64u)&Segs)) return true;
00415         return false;
00416 }
00417 
00418 // helper function - move a 64bit constant value into dest_reg
00419 static void gen_mov_qword_to_reg_imm(HostReg dest_reg,Bit64u imm) {
00420         bool isfirst = true;
00421 
00422         if ( (imm & 0xffff) != 0 ) {
00423                 cache_addd( MOVZ64(dest_reg, imm & 0xffff, 0) );                // movz dest_reg, #(imm & 0xffff)
00424                 isfirst = false;
00425         }
00426         if ( ((imm >> 16) & 0xffff) != 0 ) {
00427                 if (isfirst) {
00428                         isfirst = false;
00429                         cache_addd( MOVZ64(dest_reg, (imm >> 16) & 0xffff, 16) );   // movz dest_reg, #((imm >> 16) & 0xffff), lsl #16
00430                 } else {
00431                         cache_addd( MOVK64(dest_reg, (imm >> 16) & 0xffff, 16) );   // movk dest_reg, #((imm >> 16) & 0xffff), lsl #16
00432                 }
00433         }
00434         if ( ((imm >> 32) & 0xffff) != 0 ) {
00435                 if (isfirst) {
00436                         isfirst = false;
00437                         cache_addd( MOVZ64(dest_reg, (imm >> 32) & 0xffff, 32) );   // movz dest_reg, #((imm >> 32) & 0xffff), lsl #32
00438                 } else {
00439                         cache_addd( MOVK64(dest_reg, (imm >> 32) & 0xffff, 32) );   // movk dest_reg, #((imm >> 32) & 0xffff), lsl #32
00440                 }
00441         }
00442         if ( ((imm >> 48) & 0xffff) != 0 ) {
00443                 if (isfirst) {
00444                         isfirst = false;
00445                         cache_addd( MOVZ64(dest_reg, (imm >> 48) & 0xffff, 48) );   // movz dest_reg, #((imm >> 48) & 0xffff), lsl #48
00446                 } else {
00447                         cache_addd( MOVK64(dest_reg, (imm >> 48) & 0xffff, 48) );   // movk dest_reg, #((imm >> 48) & 0xffff), lsl #48
00448                 }
00449         }
00450         if (isfirst) {
00451                 cache_addd( MOVZ64(dest_reg, 0, 0) );                           // movz dest_reg, #0
00452         }
00453 }
00454 
00455 // helper function for gen_mov_word_to_reg
00456 static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) {
00457         if (dword) {
00458                 cache_addd( LDR_IMM(dest_reg, data_reg, 0) );       // ldr dest_reg, [data_reg]
00459         } else {
00460                 cache_addd( LDRH_IMM(dest_reg, data_reg, 0) );      // ldrh dest_reg, [data_reg]
00461         }
00462 }
00463 
00464 // move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg
00465 // 16bit moves may destroy the upper 16bit of the destination register
00466 static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) {
00467         if (!gen_mov_memval_to_reg(dest_reg, data, (dword)?4:2)) {
00468                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)data);
00469                 gen_mov_word_to_reg_helper(dest_reg, data, dword, temp1);
00470         }
00471 }
00472 
00473 // move a 16bit constant value into dest_reg
00474 // the upper 16bit of the destination register may be destroyed
00475 static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) {
00476         cache_addd( MOVZ(dest_reg, imm, 0) );   // movz dest_reg, #imm
00477 }
00478 
00479 // helper function
00480 static bool gen_mov_memval_from_reg_helper(HostReg src_reg, Bit64u data, Bitu size, HostReg addr_reg, Bit64u addr_data) {
00481         switch (size) {
00482                 case 8:
00483                         if (((data & 7) == 0) && (data >= addr_data) && (data < addr_data + 32768)) {
00484                                 cache_addd( STR64_IMM(src_reg, addr_reg, data - addr_data) );       // str src_reg, [addr_reg, #(data - addr_data)]
00485                                 return true;
00486                         } else if ((data < addr_data + 256) && (data >= addr_data - 256)) {
00487                                 cache_addd( STUR64_IMM(src_reg, addr_reg, data - addr_data) );      // stur src_reg, [addr_reg, #(data - addr_data)]
00488                                 return true;
00489                         }
00490                         break;
00491                 case 4:
00492                         if (((data & 3) == 0) && (data >= addr_data) && (data < addr_data + 16384)) {
00493                                 cache_addd( STR_IMM(src_reg, addr_reg, data - addr_data) );         // str src_reg, [addr_reg, #(data - addr_data)]
00494                                 return true;
00495                         } else if ((data < addr_data + 256) && (data >= addr_data - 256)) {
00496                                 cache_addd( STUR_IMM(src_reg, addr_reg, data - addr_data) );        // stur src_reg, [addr_reg, #(data - addr_data)]
00497                                 return true;
00498                         }
00499                         break;
00500                 case 2:
00501                         if (((data & 1) == 0) && (data >= addr_data) && (data < addr_data + 8192)) {
00502                                 cache_addd( STRH_IMM(src_reg, addr_reg, data - addr_data) );        // strh src_reg, [addr_reg, #(data - addr_data)]
00503                                 return true;
00504                         } else if ((data < addr_data + 256) && (data >= addr_data - 256)) {
00505                                 cache_addd( STURH_IMM(src_reg, addr_reg, data - addr_data) );       // sturh src_reg, [addr_reg, #(data - addr_data)]
00506                                 return true;
00507                         }
00508                         break;
00509                 case 1:
00510                         if ((data >= addr_data) && (data < addr_data + 4096)) {
00511                                 cache_addd( STRB_IMM(src_reg, addr_reg, data - addr_data) );        // strb src_reg, [addr_reg, #(data - addr_data)]
00512                                 return true;
00513                         } else if ((data < addr_data) && (data >= addr_data - 256)) {
00514                                 cache_addd( STURB_IMM(src_reg, addr_reg, data - addr_data) );       // sturb src_reg, [addr_reg, #(data - addr_data)]
00515                                 return true;
00516                         }
00517                 default:
00518                         break;
00519         }
00520         return false;
00521 }
00522 
00523 // helper function
00524 static bool gen_mov_memval_from_reg(HostReg src_reg, void *dest, Bitu size) {
00525         if (gen_mov_memval_from_reg_helper(src_reg, (Bit64u)dest, size, FC_REGS_ADDR, (Bit64u)&cpu_regs)) return true;
00526         if (gen_mov_memval_from_reg_helper(src_reg, (Bit64u)dest, size, readdata_addr, (Bit64u)&core_dynrec.readdata)) return true;
00527         if (gen_mov_memval_from_reg_helper(src_reg, (Bit64u)dest, size, FC_SEGS_ADDR, (Bit64u)&Segs)) return true;
00528         return false;
00529 }
00530 
00531 // helper function for gen_mov_word_from_reg
00532 static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) {
00533         if (dword) {
00534                 cache_addd( STR_IMM(src_reg, data_reg, 0) );        // str src_reg, [data_reg]
00535         } else {
00536                 cache_addd( STRH_IMM(src_reg, data_reg, 0) );       // strh src_reg, [data_reg]
00537         }
00538 }
00539 
00540 // move 32bit (dword==true) or 16bit (dword==false) of a register into memory
00541 static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) {
00542         if (!gen_mov_memval_from_reg(src_reg, dest, (dword)?4:2)) {
00543                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)dest);
00544                 gen_mov_word_from_reg_helper(src_reg, dest, dword, temp1);
00545         }
00546 }
00547 
00548 // move an 8bit value from memory into dest_reg
00549 // the upper 24bit of the destination register can be destroyed
00550 // this function does not use FC_OP1/FC_OP2 as dest_reg as these
00551 // registers might not be directly byte-accessible on some architectures
00552 static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) {
00553         if (!gen_mov_memval_to_reg(dest_reg, data, 1)) {
00554                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)data);
00555                 cache_addd( LDRB_IMM(dest_reg, temp1, 0) );     // ldrb dest_reg, [temp1]
00556         }
00557 }
00558 
00559 // move an 8bit value from memory into dest_reg
00560 // the upper 24bit of the destination register can be destroyed
00561 // this function can use FC_OP1/FC_OP2 as dest_reg which are
00562 // not directly byte-accessible on some architectures
00563 static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) {
00564         gen_mov_byte_to_reg_low(dest_reg, data);
00565 }
00566 
00567 // move an 8bit constant value into dest_reg
00568 // the upper 24bit of the destination register can be destroyed
00569 // this function does not use FC_OP1/FC_OP2 as dest_reg as these
00570 // registers might not be directly byte-accessible on some architectures
00571 static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) {
00572         cache_addd( MOVZ(dest_reg, imm, 0) );   // movz dest_reg, #imm
00573 }
00574 
00575 // move an 8bit constant value into dest_reg
00576 // the upper 24bit of the destination register can be destroyed
00577 // this function can use FC_OP1/FC_OP2 as dest_reg which are
00578 // not directly byte-accessible on some architectures
00579 static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) {
00580         gen_mov_byte_to_reg_low_imm(dest_reg, imm);
00581 }
00582 
00583 // move the lowest 8bit of a register into memory
00584 static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) {
00585         if (!gen_mov_memval_from_reg(src_reg, dest, 1)) {
00586                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)dest);
00587                 cache_addd( STRB_IMM(src_reg, temp1, 0) );      // strb src_reg, [temp1]
00588         }
00589 }
00590 
00591 
00592 
00593 // convert an 8bit word to a 32bit dword
00594 // the register is zero-extended (sign==false) or sign-extended (sign==true)
00595 static void gen_extend_byte(bool sign,HostReg reg) {
00596         if (sign) {
00597                 cache_addd( SXTB(reg, reg) );      // sxtb reg, reg
00598         } else {
00599                 cache_addd( UXTB(reg, reg) );      // uxtb reg, reg
00600         }
00601 }
00602 
00603 // convert a 16bit word to a 32bit dword
00604 // the register is zero-extended (sign==false) or sign-extended (sign==true)
00605 static void gen_extend_word(bool sign,HostReg reg) {
00606         if (sign) {
00607                 cache_addd( SXTH(reg, reg) );      // sxth reg, reg
00608         } else {
00609                 cache_addd( UXTH(reg, reg) );      // uxth reg, reg
00610         }
00611 }
00612 
00613 // add a 32bit value from memory to a full register
00614 static void gen_add(HostReg reg,void* op) {
00615         gen_mov_word_to_reg(temp3, op, 1);
00616         cache_addd( ADD_REG_LSL_IMM(reg, reg, temp3, 0) );      // add reg, reg, temp3
00617 }
00618 
00619 // add a 32bit constant value to a full register
00620 static void gen_add_imm(HostReg reg,Bit32u imm) {
00621         Bit32u imm2;
00622 
00623         if(!imm) return;
00624 
00625         imm2 = (Bit32u) (-((Bit32s)imm));
00626 
00627         if (imm < 4096) {
00628                 cache_addd( ADD_IMM(reg, reg, imm, 0) );            // add reg, reg, #imm
00629         } else if ((imm & 0xff000fff) == 0) {
00630                 cache_addd( ADD_IMM(reg, reg, imm >> 12, 12) );     // add reg, reg, #(imm >> 12), lsl #12
00631         } else if (imm2 < 4096) {
00632                 cache_addd( SUB_IMM(reg, reg, imm2, 0) );           // sub reg, reg, #(-imm)
00633         } else if ((imm2 & 0xff000fff) == 0) {
00634                 cache_addd( SUB_IMM(reg, reg, imm2 >> 12, 12) );    // sub reg, reg, #(-imm >> 12), lsl #12
00635         } else if (imm2 < 0x10000) {
00636                 cache_addd( MOVZ(temp2, imm2, 0) );                 // movz temp2, #(-imm)
00637                 cache_addd( SUB_REG_LSL_IMM(reg, reg, temp2, 0) );  // sub reg, reg, temp2
00638         } else {
00639                 gen_mov_dword_to_reg_imm(temp2, imm);
00640                 cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) );  // add reg, reg, temp2
00641         }
00642 }
00643 
00644 // and a 32bit constant value with a full register
00645 static void gen_and_imm(HostReg reg,Bit32u imm) {
00646         Bit32u imm2, scale;
00647 
00648         imm2 = ~imm;
00649         if(!imm2) return;
00650 
00651         if (!imm) {
00652                 cache_addd( MOVZ(reg, 0, 0) );                          // movz reg, #0
00653         } else if (imm2 < 0x10000) {
00654                 cache_addd( MOVZ(temp2, imm2, 0) );                     // movz temp2, #(~imm)
00655                 cache_addd( BIC_REG_LSL_IMM(reg, reg, temp2, 0) );      // bic reg, reg, temp2
00656         } else if ((imm2 & 0xffff) == 0) {
00657                 cache_addd( MOVZ(temp2, imm2 >> 16, 16) );              // movz temp2, #(~imm >> 16), lsl #16
00658                 cache_addd( BIC_REG_LSL_IMM(reg, reg, temp2, 0) );      // bic reg, reg, temp2
00659         } else {
00660                 gen_mov_dword_to_reg_imm(temp2, imm);
00661                 cache_addd( AND_REG_LSL_IMM(reg, reg, temp2, 0) );      // and reg, reg, temp2
00662         }
00663 }
00664 
00665 
00666 // move a 32bit constant value into memory
00667 static void gen_mov_direct_dword(void* dest,Bit32u imm) {
00668         gen_mov_dword_to_reg_imm(temp3, imm);
00669         gen_mov_word_from_reg(temp3, dest, 1);
00670 }
00671 
00672 // move an address into memory
00673 static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) {
00674         gen_mov_qword_to_reg_imm(temp3, imm);
00675         if (!gen_mov_memval_from_reg(temp3, dest, 8)) {
00676                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)dest);
00677                 cache_addd( STR64_IMM(temp3, temp1, 0) );       // str temp3, [temp1]
00678         }
00679 }
00680 
00681 // add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value
00682 static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) {
00683         if (!dword) imm &= 0xffff;
00684         if(!imm) return;
00685 
00686         if (!gen_mov_memval_to_reg(temp3, dest, (dword)?4:2)) {
00687                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)dest);
00688                 gen_mov_word_to_reg_helper(temp3, dest, dword, temp1);
00689         }
00690         gen_add_imm(temp3, imm);
00691         if (!gen_mov_memval_from_reg(temp3, dest, (dword)?4:2)) {
00692                 gen_mov_word_from_reg_helper(temp3, dest, dword, temp1);
00693         }
00694 }
00695 
00696 // add an 8bit constant value to a dword memory value
00697 static void gen_add_direct_byte(void* dest,Bit8s imm) {
00698         gen_add_direct_word(dest, (Bit32s)imm, 1);
00699 }
00700 
00701 // subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value
00702 static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) {
00703         Bit32u imm2;
00704 
00705         if (!dword) imm &= 0xffff;
00706         if(!imm) return;
00707 
00708         if (!gen_mov_memval_to_reg(temp3, dest, (dword)?4:2)) {
00709                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)dest);
00710                 gen_mov_word_to_reg_helper(temp3, dest, dword, temp1);
00711         }
00712 
00713         imm2 = (Bit32u) (-((Bit32s)imm));
00714 
00715         if (imm < 4096) {
00716                 cache_addd( SUB_IMM(temp3, temp3, imm, 0) );            // sub temp3, temp3, #imm
00717         } else if ((imm & 0xff000fff) == 0) {
00718                 cache_addd( SUB_IMM(temp3, temp3, imm >> 12, 12) );     // sub temp3, temp3, #(imm >> 12), lsl #12
00719         } else if (imm2 < 4096) {
00720                 cache_addd( ADD_IMM(temp3, temp3, imm2, 0) );           // add temp3, temp3, #(-imm)
00721         } else if ((imm2 & 0xff000fff) == 0) {
00722                 cache_addd( ADD_IMM(temp3, temp3, imm2 >> 12, 12) );    // add temp3, temp3, #(-imm >> 12), lsl #12
00723         } else if (imm2 < 0x10000) {
00724                 cache_addd( MOVZ(temp2, imm2, 0) );                     // movz temp2, #(-imm)
00725                 cache_addd( ADD_REG_LSL_IMM(temp3, temp3, temp2, 0) );  // add temp3, temp3, temp2
00726         } else {
00727                 gen_mov_dword_to_reg_imm(temp2, imm);
00728                 cache_addd( SUB_REG_LSL_IMM(temp3, temp3, temp2, 0) );  // sub temp3, temp3, temp2
00729         }
00730 
00731         if (!gen_mov_memval_from_reg(temp3, dest, (dword)?4:2)) {
00732                 gen_mov_word_from_reg_helper(temp3, dest, dword, temp1);
00733         }
00734 }
00735 
00736 // subtract an 8bit constant value from a dword memory value
00737 static void gen_sub_direct_byte(void* dest,Bit8s imm) {
00738         gen_sub_direct_word(dest, (Bit32s)imm, 1);
00739 }
00740 
00741 // effective address calculation, destination is dest_reg
00742 // scale_reg is scaled by scale (scale_reg*(2^scale)) and
00743 // added to dest_reg, then the immediate value is added
00744 static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) {
00745         cache_addd( ADD_REG_LSL_IMM(dest_reg, dest_reg, scale_reg, scale) );      // add dest_reg, dest_reg, scale_reg, lsl #scale
00746         gen_add_imm(dest_reg, imm);
00747 }
00748 
00749 // effective address calculation, destination is dest_reg
00750 // dest_reg is scaled by scale (dest_reg*(2^scale)),
00751 // then the immediate value is added
00752 static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) {
00753         if (scale) {
00754                 cache_addd( MOV_REG_LSL_IMM(dest_reg, dest_reg, scale) );      // mov dest_reg, dest_reg, lsl #scale
00755         }
00756         gen_add_imm(dest_reg, imm);
00757 }
00758 
00759 // generate a call to a parameterless function
00760 template <typename T> static void INLINE gen_call_function_raw(const T func) {
00761     cache_addd( MOVZ64(temp1, ((Bit64u)func) & 0xffff, 0) );            // movz dest_reg, #(func & 0xffff)
00762     cache_addd( MOVK64(temp1, (((Bit64u)func) >> 16) & 0xffff, 16) );   // movk dest_reg, #((func >> 16) & 0xffff), lsl #16
00763     cache_addd( MOVK64(temp1, (((Bit64u)func) >> 32) & 0xffff, 32) );   // movk dest_reg, #((func >> 32) & 0xffff), lsl #32
00764     cache_addd( MOVK64(temp1, (((Bit64u)func) >> 48) & 0xffff, 48) );   // movk dest_reg, #((func >> 48) & 0xffff), lsl #48
00765     cache_addd( BLR_REG(temp1) );      // blr temp1
00766 }
00767 
00768 // generate a call to a function with paramcount parameters
00769 // note: the parameters are loaded in the architecture specific way
00770 // using the gen_load_param_ functions below
00771 template <typename T> static DRC_PTR_SIZE_IM INLINE gen_call_function_setup(const T func,Bitu paramcount,bool fastcall=false) {
00772     DRC_PTR_SIZE_IM proc_addr = (DRC_PTR_SIZE_IM)cache.pos;
00773         gen_call_function_raw(func);
00774         return proc_addr;
00775 }
00776 
00777 // load an immediate value as param'th function parameter
00778 static void INLINE gen_load_param_imm(Bitu imm,Bitu param) {
00779         gen_mov_qword_to_reg_imm(param, imm);
00780 }
00781 
00782 // load an address as param'th function parameter
00783 static void INLINE gen_load_param_addr(DRC_PTR_SIZE_IM addr,Bitu param) {
00784         gen_mov_qword_to_reg_imm(param, addr);
00785 }
00786 
00787 // load a host-register as param'th function parameter
00788 static void INLINE gen_load_param_reg(Bitu reg,Bitu param) {
00789         gen_mov_regs(param, reg);
00790 }
00791 
00792 // load a value from memory as param'th function parameter
00793 static void INLINE gen_load_param_mem(Bitu mem,Bitu param) {
00794         gen_mov_word_to_reg(param, (void *)mem, 1);
00795 }
00796 
00797 // jump to an address pointed at by ptr, offset is in imm
00798 static void gen_jmp_ptr(void * ptr,Bits imm=0) {
00799         if (!gen_mov_memval_to_reg(temp3, ptr, 8)) {
00800                 gen_mov_qword_to_reg_imm(temp1, (Bit64u)ptr);
00801                 cache_addd( LDR64_IMM(temp3, temp1, 0) );     // ldr temp3, [temp1]
00802         }
00803 
00804         if (((imm & 7) == 0) && (imm >= 0) && (imm < 32768)) {
00805                 cache_addd( LDR64_IMM(temp1, temp3, imm) );                 // ldr temp1, [temp3, #imm]
00806         } else if ((imm < 256) && (imm >= -256)) {
00807                 cache_addd( LDUR64_IMM(temp1, temp3, imm) );                // ldur temp1, [temp3, #imm]
00808         } else {
00809                 gen_mov_qword_to_reg_imm(temp2, imm);
00810                 cache_addd( LDR64_REG_LSL_IMM(temp1, temp3, temp2, 0) );    // ldr temp1, [temp3, temp2]
00811         }
00812 
00813         cache_addd( BR(temp1) );      // br temp1
00814 }
00815 
00816 // short conditional jump (+-127 bytes) if register is zero
00817 // the destination is set by gen_fill_branch() later
00818 static DRC_PTR_SIZE_IM gen_create_branch_on_zero(HostReg reg,bool dword) {
00819         if (dword) {
00820                 cache_addd( CBZ_FWD(reg, 0) );      // cbz reg, j
00821         } else {
00822                 cache_addd( UXTH(temp1, reg) );     // uxth temp1, reg
00823                 cache_addd( CBZ_FWD(temp1, 0) );    // cbz temp1, j
00824         }
00825         return ((DRC_PTR_SIZE_IM)cache.pos-4);
00826 }
00827 
00828 // short conditional jump (+-127 bytes) if register is nonzero
00829 // the destination is set by gen_fill_branch() later
00830 static DRC_PTR_SIZE_IM gen_create_branch_on_nonzero(HostReg reg,bool dword) {
00831         if (dword) {
00832                 cache_addd( CBNZ_FWD(reg, 0) );     // cbnz reg, j
00833         } else {
00834                 cache_addd( UXTH(temp1, reg) );     // uxth temp1, reg
00835                 cache_addd( CBNZ_FWD(temp1, 0) );   // cbnz temp1, j
00836         }
00837         return ((DRC_PTR_SIZE_IM)cache.pos-4);
00838 }
00839 
00840 // calculate relative offset and fill it into the location pointed to by data
00841 static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) {
00842 #if C_DEBUG
00843         Bits len=(Bit64u)cache.pos-data;
00844         if (len<0) len=-len;
00845         if (len>=0x00100000) LOG_MSG("Big jump %d",len);
00846 #endif
00847         *(Bit32u*)data=( (*(Bit32u*)data) & 0xff00001f ) | ( ( ((Bit64u)cache.pos - data) << 3 ) & 0x00ffffe0 );
00848 }
00849 
00850 // conditional jump if register is nonzero
00851 // for isdword==true the 32bit of the register are tested
00852 // for isdword==false the lowest 8bit of the register are tested
00853 static DRC_PTR_SIZE_IM gen_create_branch_long_nonzero(HostReg reg,bool isdword) {
00854         if (isdword) {
00855                 cache_addd( CBZ_FWD(reg, 8) );      // cbz reg, pc+8    // skip next instruction
00856         } else {
00857                 cache_addd( UXTB(temp1, reg) );     // uxtb temp1, reg
00858                 cache_addd( CBZ_FWD(temp1, 8) );    // cbz temp1, pc+8  // skip next instruction
00859         }
00860         cache_addd( B_FWD(0) );         // b j
00861         return ((DRC_PTR_SIZE_IM)cache.pos-4);
00862 }
00863 
00864 // compare 32bit-register against zero and jump if value less/equal than zero
00865 static DRC_PTR_SIZE_IM gen_create_branch_long_leqzero(HostReg reg) {
00866         cache_addd( CMP_IMM(reg, 0, 0) );       // cmp reg, #0
00867         cache_addd( BGT_FWD(8) );               // bgt pc+8 // skip next instruction
00868         cache_addd( B_FWD(0) );                 // b j
00869         return ((DRC_PTR_SIZE_IM)cache.pos-4);
00870 }
00871 
00872 // calculate long relative offset and fill it into the location pointed to by data
00873 static void INLINE gen_fill_branch_long(DRC_PTR_SIZE_IM data) {
00874         // optimize for shorter branches ?
00875         *(Bit32u*)data=( (*(Bit32u*)data) & 0xfc000000 ) | ( ( ((Bit64u)cache.pos - data) >> 2 ) & 0x03ffffff );
00876 }
00877 
00878 static void gen_run_code(void) {
00879         Bit8u *pos1, *pos2, *pos3;
00880 
00881         cache_addd( 0xa9bd7bfd );                                           // stp fp, lr, [sp, #-48]!
00882         cache_addd( 0x910003fd );                                           // mov fp, sp
00883         cache_addd( STP64_IMM(FC_ADDR, FC_REGS_ADDR, HOST_sp, 16) );        // stp FC_ADDR, FC_REGS_ADDR, [sp, #16]
00884         cache_addd( STP64_IMM(FC_SEGS_ADDR, readdata_addr, HOST_sp, 32) );  // stp FC_SEGS_ADDR, readdata_addr, [sp, #32]
00885 
00886         pos1 = cache.pos;
00887         cache_addd( 0 );
00888         pos2 = cache.pos;
00889         cache_addd( 0 );
00890         pos3 = cache.pos;
00891         cache_addd( 0 );
00892 
00893         cache_addd( BR(HOST_x0) );                      // br x0
00894 
00895         // align cache.pos to 32 bytes
00896         if ((((Bitu)cache.pos) & 0x1f) != 0) {
00897                 cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
00898         }
00899 
00900         *(Bit32u *)pos1 = LDR64_PC(FC_SEGS_ADDR, cache.pos - pos1);   // ldr FC_SEGS_ADDR, [pc, #(&Segs)]
00901         cache_addq((Bit64u)&Segs);                      // address of "Segs"
00902 
00903         *(Bit32u *)pos2 = LDR64_PC(FC_REGS_ADDR, cache.pos - pos2);   // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)]
00904         cache_addq((Bit64u)&cpu_regs);                  // address of "cpu_regs"
00905 
00906         *(Bit32u *)pos3 = LDR64_PC(readdata_addr, cache.pos - pos3);  // ldr readdata_addr, [pc, #(&core_dynrec.readdata)]
00907         cache_addq((Bit64u)&core_dynrec.readdata);      // address of "core_dynrec.readdata"
00908 
00909         // align cache.pos to 32 bytes
00910         if ((((Bitu)cache.pos) & 0x1f) != 0) {
00911                 cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f));
00912         }
00913 }
00914 
00915 // return from a function
00916 static void gen_return_function(void) {
00917         cache_addd( LDP64_IMM(FC_ADDR, FC_REGS_ADDR, HOST_sp, 16) );        // ldp FC_ADDR, FC_REGS_ADDR, [sp, #16]
00918         cache_addd( LDP64_IMM(FC_SEGS_ADDR, readdata_addr, HOST_sp, 32) );  // ldp FC_SEGS_ADDR, readdata_addr, [sp, #32]
00919         cache_addd( 0xa8c37bfd );                                           // ldp fp, lr, [sp], #48
00920         cache_addd( RET );                                                  // ret
00921 }
00922 
00923 #ifdef DRC_FLAGS_INVALIDATION
00924 
00925 // called when a call to a function can be replaced by a
00926 // call to a simpler function
00927 static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) {
00928 #ifdef DRC_FLAGS_INVALIDATION_DCODE
00929         // try to avoid function calls but rather directly fill in code
00930         switch (flags_type) {
00931                 case t_ADDb:
00932                 case t_ADDw:
00933                 case t_ADDd:
00934                         *(Bit32u*)pos=NOP;                                      // nop
00935                         *(Bit32u*)(pos+4)=NOP;                          // nop
00936                         *(Bit32u*)(pos+8)=ADD_REG_LSL_IMM(FC_RETOP, HOST_w0, HOST_w1, 0);       // add FC_RETOP, w0, w1
00937                         *(Bit32u*)(pos+12)=NOP;                         // nop
00938                         *(Bit32u*)(pos+16)=NOP;                         // nop
00939                         break;
00940                 case t_ORb:
00941                 case t_ORw:
00942                 case t_ORd:
00943                         *(Bit32u*)pos=NOP;                                      // nop
00944                         *(Bit32u*)(pos+4)=NOP;                          // nop
00945                         *(Bit32u*)(pos+8)=ORR_REG_LSL_IMM(FC_RETOP, HOST_w0, HOST_w1, 0);       // orr FC_RETOP, w0, w1
00946                         *(Bit32u*)(pos+12)=NOP;                         // nop
00947                         *(Bit32u*)(pos+16)=NOP;                         // nop
00948                         break;
00949                 case t_ANDb:
00950                 case t_ANDw:
00951                 case t_ANDd:
00952                         *(Bit32u*)pos=NOP;                                      // nop
00953                         *(Bit32u*)(pos+4)=NOP;                          // nop
00954                         *(Bit32u*)(pos+8)=AND_REG_LSL_IMM(FC_RETOP, HOST_w0, HOST_w1, 0);       // and FC_RETOP, w0, w1
00955                         *(Bit32u*)(pos+12)=NOP;                         // nop
00956                         *(Bit32u*)(pos+16)=NOP;                         // nop
00957                         break;
00958                 case t_SUBb:
00959                 case t_SUBw:
00960                 case t_SUBd:
00961                         *(Bit32u*)pos=NOP;                                      // nop
00962                         *(Bit32u*)(pos+4)=NOP;                          // nop
00963                         *(Bit32u*)(pos+8)=SUB_REG_LSL_IMM(FC_RETOP, HOST_w0, HOST_w1, 0);       // sub FC_RETOP, w0, w1
00964                         *(Bit32u*)(pos+12)=NOP;                         // nop
00965                         *(Bit32u*)(pos+16)=NOP;                         // nop
00966                         break;
00967                 case t_XORb:
00968                 case t_XORw:
00969                 case t_XORd:
00970                         *(Bit32u*)pos=NOP;                                      // nop
00971                         *(Bit32u*)(pos+4)=NOP;                          // nop
00972                         *(Bit32u*)(pos+8)=EOR_REG_LSL_IMM(FC_RETOP, HOST_w0, HOST_w1, 0);       // eor FC_RETOP, w0, w1
00973                         *(Bit32u*)(pos+12)=NOP;                         // nop
00974                         *(Bit32u*)(pos+16)=NOP;                         // nop
00975                         break;
00976                 case t_CMPb:
00977                 case t_CMPw:
00978                 case t_CMPd:
00979                 case t_TESTb:
00980                 case t_TESTw:
00981                 case t_TESTd:
00982                         *(Bit32u*)pos=NOP;                                      // nop
00983                         *(Bit32u*)(pos+4)=NOP;                          // nop
00984                         *(Bit32u*)(pos+8)=NOP;                          // nop
00985                         *(Bit32u*)(pos+12)=NOP;                         // nop
00986                         *(Bit32u*)(pos+16)=NOP;                         // nop
00987                         break;
00988                 case t_INCb:
00989                 case t_INCw:
00990                 case t_INCd:
00991                         *(Bit32u*)pos=NOP;                                      // nop
00992                         *(Bit32u*)(pos+4)=NOP;                          // nop
00993                         *(Bit32u*)(pos+8)=ADD_IMM(FC_RETOP, HOST_w0, 1, 0);     // add FC_RETOP, w0, #1
00994                         *(Bit32u*)(pos+12)=NOP;                         // nop
00995                         *(Bit32u*)(pos+16)=NOP;                         // nop
00996                         break;
00997                 case t_DECb:
00998                 case t_DECw:
00999                 case t_DECd:
01000                         *(Bit32u*)pos=NOP;                                      // nop
01001                         *(Bit32u*)(pos+4)=NOP;                          // nop
01002                         *(Bit32u*)(pos+8)=SUB_IMM(FC_RETOP, HOST_w0, 1, 0);     // sub FC_RETOP, w0, #1
01003                         *(Bit32u*)(pos+12)=NOP;                         // nop
01004                         *(Bit32u*)(pos+16)=NOP;                         // nop
01005                         break;
01006                 case t_SHLb:
01007                 case t_SHLw:
01008                 case t_SHLd:
01009                         *(Bit32u*)pos=NOP;                                      // nop
01010                         *(Bit32u*)(pos+4)=NOP;                          // nop
01011                         *(Bit32u*)(pos+8)=LSLV(FC_RETOP, HOST_w0, HOST_w1);     // lslv FC_RETOP, w0, w1
01012                         *(Bit32u*)(pos+12)=NOP;                         // nop
01013                         *(Bit32u*)(pos+16)=NOP;                         // nop
01014                         break;
01015                 case t_SHRb:
01016                         *(Bit32u*)pos=NOP;                                      // nop
01017                         *(Bit32u*)(pos+4)=UXTB(FC_RETOP, HOST_w0);                              // uxtb FC_RETOP, w0
01018                         *(Bit32u*)(pos+8)=NOP;                          // nop
01019                         *(Bit32u*)(pos+12)=LSRV(FC_RETOP, FC_RETOP, HOST_w1);   // lsrv FC_RETOP, FC_RETOP, w1
01020                         *(Bit32u*)(pos+16)=NOP;                         // nop
01021                         break;
01022                 case t_SHRw:
01023                         *(Bit32u*)pos=NOP;                                      // nop
01024                         *(Bit32u*)(pos+4)=UXTH(FC_RETOP, HOST_w0);                              // uxth FC_RETOP, w0
01025                         *(Bit32u*)(pos+8)=NOP;                          // nop
01026                         *(Bit32u*)(pos+12)=LSRV(FC_RETOP, FC_RETOP, HOST_w1);   // lsrv FC_RETOP, FC_RETOP, w1
01027                         *(Bit32u*)(pos+16)=NOP;                         // nop
01028                         break;
01029                 case t_SHRd:
01030                         *(Bit32u*)pos=NOP;                                      // nop
01031                         *(Bit32u*)(pos+4)=NOP;                          // nop
01032                         *(Bit32u*)(pos+8)=LSRV(FC_RETOP, HOST_w0, HOST_w1);     // lsrv FC_RETOP, w0, w1
01033                         *(Bit32u*)(pos+12)=NOP;                         // nop
01034                         *(Bit32u*)(pos+16)=NOP;                         // nop
01035                         break;
01036                 case t_SARb:
01037                         *(Bit32u*)pos=NOP;                                      // nop
01038                         *(Bit32u*)(pos+4)=SXTB(FC_RETOP, HOST_w0);                              // sxtb FC_RETOP, w0
01039                         *(Bit32u*)(pos+8)=NOP;                          // nop
01040                         *(Bit32u*)(pos+12)=ASRV(FC_RETOP, FC_RETOP, HOST_w1);   // asrv FC_RETOP, FC_RETOP, w1
01041                         *(Bit32u*)(pos+16)=NOP;                         // nop
01042                         break;
01043                 case t_SARw:
01044                         *(Bit32u*)pos=NOP;                                      // nop
01045                         *(Bit32u*)(pos+4)=SXTH(FC_RETOP, HOST_w0);                              // sxth FC_RETOP, w0
01046                         *(Bit32u*)(pos+8)=NOP;                          // nop
01047                         *(Bit32u*)(pos+12)=ASRV(FC_RETOP, FC_RETOP, HOST_w1);   // asrv FC_RETOP, FC_RETOP, w1
01048                         *(Bit32u*)(pos+16)=NOP;                         // nop
01049                         break;
01050                 case t_SARd:
01051                         *(Bit32u*)pos=NOP;                                      // nop
01052                         *(Bit32u*)(pos+4)=NOP;                          // nop
01053                         *(Bit32u*)(pos+8)=ASRV(FC_RETOP, HOST_w0, HOST_w1);     // asrv FC_RETOP, w0, w1
01054                         *(Bit32u*)(pos+12)=NOP;                         // nop
01055                         *(Bit32u*)(pos+16)=NOP;                         // nop
01056                         break;
01057                 case t_RORb:
01058                         *(Bit32u*)pos=NOP;                                      // nop
01059                         *(Bit32u*)(pos+4)=BFI(HOST_w0, HOST_w0, 8, 8);                  // bfi w0, w0, 8, 8
01060                         *(Bit32u*)(pos+8)=BFI(HOST_w0, HOST_w0, 16, 16);                // bfi w0, w0, 16, 16
01061                         *(Bit32u*)(pos+12)=RORV(FC_RETOP, HOST_w0, HOST_w1);    // rorv FC_RETOP, w0, w1
01062                         *(Bit32u*)(pos+16)=NOP;                         // nop
01063                         break;
01064                 case t_RORw:
01065                         *(Bit32u*)pos=NOP;                                      // nop
01066                         *(Bit32u*)(pos+4)=BFI(HOST_w0, HOST_w0, 16, 16);                // bfi w0, w0, 16, 16
01067                         *(Bit32u*)(pos+8)=NOP;                          // nop
01068                         *(Bit32u*)(pos+12)=RORV(FC_RETOP, HOST_w0, HOST_w1);    // rorv FC_RETOP, w0, w1
01069                         *(Bit32u*)(pos+16)=NOP;                         // nop
01070                         break;
01071                 case t_RORd:
01072                         *(Bit32u*)pos=NOP;                                      // nop
01073                         *(Bit32u*)(pos+4)=NOP;                          // nop
01074                         *(Bit32u*)(pos+8)=RORV(FC_RETOP, HOST_w0, HOST_w1);     // rorv FC_RETOP, w0, w1
01075                         *(Bit32u*)(pos+12)=NOP;                         // nop
01076                         *(Bit32u*)(pos+16)=NOP;                         // nop
01077                         break;
01078                 case t_ROLb:
01079                         *(Bit32u*)pos=MOVZ(HOST_w2, 32, 0);                                                                     // movz w2, #32
01080                         *(Bit32u*)(pos+4)=BFI(HOST_w0, HOST_w0, 8, 8);                                          // bfi w0, w0, 8, 8
01081                         *(Bit32u*)(pos+8)=SUB_REG_LSL_IMM(HOST_w2, HOST_w2, HOST_w1, 0);        // sub w2, w2, w1
01082                         *(Bit32u*)(pos+12)=BFI(HOST_w0, HOST_w0, 16, 16);                                       // bfi w0, w0, 16, 16
01083                         *(Bit32u*)(pos+16)=RORV(FC_RETOP, HOST_w0, HOST_w2);                            // rorv FC_RETOP, w0, w2
01084                         break;
01085                 case t_ROLw:
01086                         *(Bit32u*)pos=MOVZ(HOST_w2, 32, 0);                                                                     // movz w2, #32
01087                         *(Bit32u*)(pos+4)=BFI(HOST_w0, HOST_w0, 16, 16);                                        // bfi w0, w0, 16, 16
01088                         *(Bit32u*)(pos+8)=SUB_REG_LSL_IMM(HOST_w2, HOST_w2, HOST_w1, 0);        // sub w2, w2, w1
01089                         *(Bit32u*)(pos+12)=NOP;                         // nop
01090                         *(Bit32u*)(pos+16)=RORV(FC_RETOP, HOST_w0, HOST_w2);                            // rorv FC_RETOP, w0, w2
01091                         break;
01092                 case t_ROLd:
01093                         *(Bit32u*)pos=NOP;                                      // nop
01094                         *(Bit32u*)(pos+4)=MOVZ(HOST_w2, 32, 0);                                                         // movz w2, #32
01095                         *(Bit32u*)(pos+8)=SUB_REG_LSL_IMM(HOST_w2, HOST_w2, HOST_w1, 0);        // sub w2, w2, w1
01096                         *(Bit32u*)(pos+12)=RORV(FC_RETOP, HOST_w0, HOST_w2);                            // rorv FC_RETOP, w0, w2
01097                         *(Bit32u*)(pos+16)=NOP;                         // nop
01098                         break;
01099                 case t_NEGb:
01100                 case t_NEGw:
01101                 case t_NEGd:
01102                         *(Bit32u*)pos=NOP;                                      // nop
01103                         *(Bit32u*)(pos+4)=NOP;                          // nop
01104                         *(Bit32u*)(pos+8)=SUB_REG_LSL_IMM(FC_RETOP, HOST_wzr, HOST_w0, 0);      // sub FC_RETOP, wzr, w0
01105                         *(Bit32u*)(pos+12)=NOP;                         // nop
01106                         *(Bit32u*)(pos+16)=NOP;                         // nop
01107                         break;
01108                 case t_DSHLd:
01109                         *(Bit32u*)pos=MOVZ64(HOST_x3, 0x1f, 0);                                                         // movz x3, #0x1f
01110                         *(Bit32u*)(pos+4)=BFI64(HOST_x1, HOST_x0, 32, 32);                                      // bfi x1, x0, 32, 32
01111                         *(Bit32u*)(pos+8)=AND64_REG_LSL_IMM(HOST_x2, HOST_x2, HOST_x3, 0);      // and x2, x2, x3
01112                         *(Bit32u*)(pos+12)=LSLV64(FC_RETOP, HOST_x1, HOST_x2);                          // lslv FC_RETOP, x1, x2
01113                         *(Bit32u*)(pos+16)=LSR64_IMM(FC_RETOP, FC_RETOP, 32);                           // lsr FC_RETOP, FC_RETOP, #32
01114                         break;
01115                 case t_DSHRd:
01116                         *(Bit32u*)pos=MOVZ64(HOST_x3, 0x1f, 0);                                                         // movz x3, #0x1f
01117                         *(Bit32u*)(pos+4)=BFI64(HOST_x0, HOST_x1, 32, 32);                                      // bfi x0, x1, 32, 32
01118                         *(Bit32u*)(pos+8)=AND64_REG_LSL_IMM(HOST_x2, HOST_x2, HOST_x3, 0);      // and x2, x2, x3
01119                         *(Bit32u*)(pos+12)=NOP;                                                                                         // nop
01120                         *(Bit32u*)(pos+16)=LSRV64(FC_RETOP, HOST_x0, HOST_x2);                          // lsrv FC_RETOP, x0, x2
01121                         break;
01122                 default:
01123                         *(Bit32u*)pos=MOVZ64(temp1, ((Bit64u)fct_ptr) & 0xffff, 0);                 // movz temp1, #(fct_ptr & 0xffff)
01124                         *(Bit32u*)(pos+4)=MOVK64(temp1, (((Bit64u)fct_ptr) >> 16) & 0xffff, 16);    // movk temp1, #((fct_ptr >> 16) & 0xffff), lsl #16
01125                         *(Bit32u*)(pos+8)=MOVK64(temp1, (((Bit64u)fct_ptr) >> 32) & 0xffff, 32);    // movk temp1, #((fct_ptr >> 32) & 0xffff), lsl #32
01126                         *(Bit32u*)(pos+12)=MOVK64(temp1, (((Bit64u)fct_ptr) >> 48) & 0xffff, 48);   // movk temp1, #((fct_ptr >> 48) & 0xffff), lsl #48
01127                         break;
01128 
01129         }
01130 #else
01131         *(Bit32u*)pos=MOVZ64(temp1, ((Bit64u)fct_ptr) & 0xffff, 0);                 // movz temp1, #(fct_ptr & 0xffff)
01132         *(Bit32u*)(pos+4)=MOVK64(temp1, (((Bit64u)fct_ptr) >> 16) & 0xffff, 16);    // movk temp1, #((fct_ptr >> 16) & 0xffff), lsl #16
01133         *(Bit32u*)(pos+8)=MOVK64(temp1, (((Bit64u)fct_ptr) >> 32) & 0xffff, 32);    // movk temp1, #((fct_ptr >> 32) & 0xffff), lsl #32
01134         *(Bit32u*)(pos+12)=MOVK64(temp1, (((Bit64u)fct_ptr) >> 48) & 0xffff, 48);   // movk temp1, #((fct_ptr >> 48) & 0xffff), lsl #48
01135 #endif
01136 }
01137 #endif
01138 
01139 static void cache_block_closing(Bit8u* block_start,Bitu block_size) {
01140 #ifdef _MSC_VER
01141     //flush cache - Win32 API for MSVC
01142     FlushInstructionCache(GetCurrentProcess(), block_start, block_size);
01143 #else
01144         //flush cache - GCC/LLVM builtin
01145         __builtin___clear_cache((char *)block_start, (char *)(block_start+block_size));
01146 #endif
01147 }
01148 
01149 static void cache_block_before_close(void) { }
01150 
01151 #ifdef DRC_USE_SEGS_ADDR
01152 
01153 // mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero)
01154 // 16bit moves may destroy the upper 16bit of the destination register
01155 static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) {
01156         cache_addd( LDRH_IMM(dest_reg, FC_SEGS_ADDR, index) );      // ldrh dest_reg, [FC_SEGS_ADDR, #index]
01157 }
01158 
01159 // mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero)
01160 static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) {
01161         cache_addd( LDR_IMM(dest_reg, FC_SEGS_ADDR, index) );      // ldr dest_reg, [FC_SEGS_ADDR, #index]
01162 }
01163 
01164 // add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero)
01165 static void gen_add_seg32_to_reg(HostReg reg,Bitu index) {
01166         cache_addd( LDR_IMM(temp1, FC_SEGS_ADDR, index) );      // ldr temp1, [FC_SEGS_ADDR, #index]
01167         cache_addd( ADD_REG_LSL_IMM(reg, reg, temp1, 0) );      // add reg, reg, temp1
01168 }
01169 
01170 #endif
01171 
01172 #ifdef DRC_USE_REGS_ADDR
01173 
01174 // mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero)
01175 // 16bit moves may destroy the upper 16bit of the destination register
01176 static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) {
01177         cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) );      // ldrh dest_reg, [FC_REGS_ADDR, #index]
01178 }
01179 
01180 // mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero)
01181 static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) {
01182         cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) );      // ldr dest_reg, [FC_REGS_ADDR, #index]
01183 }
01184 
01185 // move a 32bit (dword==true) or 16bit (dword==false) value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
01186 // 16bit moves may destroy the upper 16bit of the destination register
01187 static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) {
01188         if (dword) {
01189                 cache_addd( LDR_IMM(dest_reg, FC_REGS_ADDR, index) );      // ldr dest_reg, [FC_REGS_ADDR, #index]
01190         } else {
01191                 cache_addd( LDRH_IMM(dest_reg, FC_REGS_ADDR, index) );      // ldrh dest_reg, [FC_REGS_ADDR, #index]
01192         }
01193 }
01194 
01195 // move an 8bit value from cpu_regs[index]  into dest_reg using FC_REGS_ADDR
01196 // the upper 24bit of the destination register can be destroyed
01197 // this function does not use FC_OP1/FC_OP2 as dest_reg as these
01198 // registers might not be directly byte-accessible on some architectures
01199 static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) {
01200         cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) );      // ldrb dest_reg, [FC_REGS_ADDR, #index]
01201 }
01202 
01203 // move an 8bit value from cpu_regs[index]  into dest_reg using FC_REGS_ADDR
01204 // the upper 24bit of the destination register can be destroyed
01205 // this function can use FC_OP1/FC_OP2 as dest_reg which are
01206 // not directly byte-accessible on some architectures
01207 static void gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) {
01208         cache_addd( LDRB_IMM(dest_reg, FC_REGS_ADDR, index) );      // ldrb dest_reg, [FC_REGS_ADDR, #index]
01209 }
01210 
01211 
01212 // add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero)
01213 static void gen_add_regval32_to_reg(HostReg reg,Bitu index) {
01214         cache_addd( LDR_IMM(temp2, FC_REGS_ADDR, index) );      // ldr temp2, [FC_REGS_ADDR, #index]
01215         cache_addd( ADD_REG_LSL_IMM(reg, reg, temp2, 0) );      // add reg, reg, temp2
01216 }
01217 
01218 
01219 // move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero)
01220 static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) {
01221         cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) );      // strh src_reg, [FC_REGS_ADDR, #index]
01222 }
01223 
01224 // move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero)
01225 static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) {
01226         cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) );      // str src_reg, [FC_REGS_ADDR, #index]
01227 }
01228 
01229 // move 32bit (dword==true) or 16bit (dword==false) of a register into cpu_regs[index] using FC_REGS_ADDR (if dword==true index modulo 4 must be zero) (if dword==false index modulo 2 must be zero)
01230 static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) {
01231         if (dword) {
01232                 cache_addd( STR_IMM(src_reg, FC_REGS_ADDR, index) );      // str src_reg, [FC_REGS_ADDR, #index]
01233         } else {
01234                 cache_addd( STRH_IMM(src_reg, FC_REGS_ADDR, index) );      // strh src_reg, [FC_REGS_ADDR, #index]
01235         }
01236 }
01237 
01238 // move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR
01239 static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) {
01240         cache_addd( STRB_IMM(src_reg, FC_REGS_ADDR, index) );      // strb src_reg, [FC_REGS_ADDR, #index]
01241 }
01242 
01243 #endif