DOSBox-X
|
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