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 /* ARMv4 (little endian) backend by M-HT (thumb version) */ 00022 00023 00024 // temporary "lo" registers 00025 #define templo1 HOST_v3 00026 #define templo2 HOST_v4 00027 #define templo3 HOST_v2 00028 00029 // register that holds function return values 00030 #define FC_RETOP HOST_a1 00031 00032 // register used for address calculations, 00033 #define FC_ADDR HOST_v1 // has to be saved across calls, see DRC_PROTECT_ADDR_REG 00034 00035 // register that holds the first parameter 00036 #define FC_OP1 HOST_a1 00037 00038 // register that holds the second parameter 00039 #define FC_OP2 HOST_a2 00040 00041 // special register that holds the third parameter for _R3 calls (byte accessible) 00042 #define FC_OP3 HOST_a4 00043 00044 // register that holds byte-accessible temporary values 00045 #define FC_TMP_BA1 HOST_a1 00046 00047 // register that holds byte-accessible temporary values 00048 #define FC_TMP_BA2 HOST_a2 00049 00050 // temporary register for LEA 00051 #define TEMP_REG_DRC HOST_a4 00052 00053 // used to hold the address of "cpu_regs" - preferably filled in function gen_run_code 00054 #define FC_REGS_ADDR HOST_v7 00055 00056 // used to hold the address of "Segs" - preferably filled in function gen_run_code 00057 #define FC_SEGS_ADDR HOST_v8 00058 00059 // used to hold the address of "core_dynrec.readdata" - filled in function gen_run_code 00060 #define readdata_addr HOST_v5 00061 00062 00063 // instruction encodings 00064 00065 // move 00066 // mov dst, #imm @ 0 <= imm <= 255 00067 #define MOV_IMM(dst, imm) (0x2000 + ((dst) << 8) + (imm) ) 00068 // mov dst, src 00069 #define MOV_REG(dst, src) ADD_IMM3(dst, src, 0) 00070 // mov dst, src 00071 #define MOV_LO_HI(dst, src) (0x4640 + (dst) + (((src) - HOST_r8) << 3) ) 00072 // mov dst, src 00073 #define MOV_HI_LO(dst, src) (0x4680 + ((dst) - HOST_r8) + ((src) << 3) ) 00074 00075 // arithmetic 00076 // add dst, src, #imm @ 0 <= imm <= 7 00077 #define ADD_IMM3(dst, src, imm) (0x1c00 + (dst) + ((src) << 3) + ((imm) << 6) ) 00078 // add dst, #imm @ 0 <= imm <= 255 00079 #define ADD_IMM8(dst, imm) (0x3000 + ((dst) << 8) + (imm) ) 00080 // add dst, src1, src2 00081 #define ADD_REG(dst, src1, src2) (0x1800 + (dst) + ((src1) << 3) + ((src2) << 6) ) 00082 // add dst, pc, #imm @ 0 <= imm < 1024 & imm mod 4 = 0 00083 #define ADD_LO_PC_IMM(dst, imm) (0xa000 + ((dst) << 8) + ((imm) >> 2) ) 00084 // sub dst, src1, src2 00085 #define SUB_REG(dst, src1, src2) (0x1a00 + (dst) + ((src1) << 3) + ((src2) << 6) ) 00086 // sub dst, src, #imm @ 0 <= imm <= 7 00087 #define SUB_IMM3(dst, src, imm) (0x1e00 + (dst) + ((src) << 3) + ((imm) << 6) ) 00088 // sub dst, #imm @ 0 <= imm <= 255 00089 #define SUB_IMM8(dst, imm) (0x3800 + ((dst) << 8) + (imm) ) 00090 // neg dst, src 00091 #define NEG(dst, src) (0x4240 + (dst) + ((src) << 3) ) 00092 // cmp dst, #imm @ 0 <= imm <= 255 00093 #define CMP_IMM(dst, imm) (0x2800 + ((dst) << 8) + (imm) ) 00094 // nop 00095 #define NOP (0x46c0) 00096 00097 // logical 00098 // and dst, src 00099 #define AND(dst, src) (0x4000 + (dst) + ((src) << 3) ) 00100 // bic dst, src 00101 #define BIC(dst, src) (0x4380 + (dst) + ((src) << 3) ) 00102 // eor dst, src 00103 #define EOR(dst, src) (0x4040 + (dst) + ((src) << 3) ) 00104 // orr dst, src 00105 #define ORR(dst, src) (0x4300 + (dst) + ((src) << 3) ) 00106 // mvn dst, src 00107 #define MVN(dst, src) (0x43c0 + (dst) + ((src) << 3) ) 00108 00109 // shift/rotate 00110 // lsl dst, src, #imm 00111 #define LSL_IMM(dst, src, imm) (0x0000 + (dst) + ((src) << 3) + ((imm) << 6) ) 00112 // lsl dst, reg 00113 #define LSL_REG(dst, reg) (0x4080 + (dst) + ((reg) << 3) ) 00114 // lsr dst, src, #imm 00115 #define LSR_IMM(dst, src, imm) (0x0800 + (dst) + ((src) << 3) + ((imm) << 6) ) 00116 // lsr dst, reg 00117 #define LSR_REG(dst, reg) (0x40c0 + (dst) + ((reg) << 3) ) 00118 // asr dst, src, #imm 00119 #define ASR_IMM(dst, src, imm) (0x1000 + (dst) + ((src) << 3) + ((imm) << 6) ) 00120 // asr dst, reg 00121 #define ASR_REG(dst, reg) (0x4100 + (dst) + ((reg) << 3) ) 00122 // ror dst, reg 00123 #define ROR_REG(dst, reg) (0x41c0 + (dst) + ((reg) << 3) ) 00124 00125 // load 00126 // ldr reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 00127 #define LDR_IMM(reg, addr, imm) (0x6800 + (reg) + ((addr) << 3) + ((imm) << 4) ) 00128 // ldrh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 00129 #define LDRH_IMM(reg, addr, imm) (0x8800 + (reg) + ((addr) << 3) + ((imm) << 5) ) 00130 // ldrb reg, [addr, #imm] @ 0 <= imm < 32 00131 #define LDRB_IMM(reg, addr, imm) (0x7800 + (reg) + ((addr) << 3) + ((imm) << 6) ) 00132 // ldr reg, [pc, #imm] @ 0 <= imm < 1024 & imm mod 4 = 0 00133 #define LDR_PC_IMM(reg, imm) (0x4800 + ((reg) << 8) + ((imm) >> 2) ) 00134 // ldr reg, [addr1, addr2] 00135 #define LDR_REG(reg, addr1, addr2) (0x5800 + (reg) + ((addr1) << 3) + ((addr2) << 6) ) 00136 00137 // store 00138 // str reg, [addr, #imm] @ 0 <= imm < 128 & imm mod 4 = 0 00139 #define STR_IMM(reg, addr, imm) (0x6000 + (reg) + ((addr) << 3) + ((imm) << 4) ) 00140 // strh reg, [addr, #imm] @ 0 <= imm < 64 & imm mod 2 = 0 00141 #define STRH_IMM(reg, addr, imm) (0x8000 + (reg) + ((addr) << 3) + ((imm) << 5) ) 00142 // strb reg, [addr, #imm] @ 0 <= imm < 32 00143 #define STRB_IMM(reg, addr, imm) (0x7000 + (reg) + ((addr) << 3) + ((imm) << 6) ) 00144 00145 // branch 00146 // beq pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 00147 #define BEQ_FWD(imm) (0xd000 + ((imm) >> 1) ) 00148 // bne pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 00149 #define BNE_FWD(imm) (0xd100 + ((imm) >> 1) ) 00150 // bgt pc+imm @ 0 <= imm < 256 & imm mod 2 = 0 00151 #define BGT_FWD(imm) (0xdc00 + ((imm) >> 1) ) 00152 // b pc+imm @ 0 <= imm < 2048 & imm mod 2 = 0 00153 #define B_FWD(imm) (0xe000 + ((imm) >> 1) ) 00154 // bx reg 00155 #define BX(reg) (0x4700 + ((reg) << 3) ) 00156 00157 00158 // arm instructions 00159 00160 // arithmetic 00161 // add dst, src, #(imm ror rimm) @ 0 <= imm <= 255 & rimm mod 2 = 0 00162 #define ARM_ADD_IMM(dst, src, imm, rimm) (0xe2800000 + ((dst) << 12) + ((src) << 16) + (imm) + ((rimm) << 7) ) 00163 00164 // load 00165 // ldr reg, [addr, #imm] @ 0 <= imm < 4096 00166 #define ARM_LDR_IMM(reg, addr, imm) (0xe5900000 + ((reg) << 12) + ((addr) << 16) + (imm) ) 00167 00168 // store 00169 // str reg, [addr, #-(imm)]! @ 0 <= imm < 4096 00170 #define ARM_STR_IMM_M_W(reg, addr, imm) (0xe5200000 + ((reg) << 12) + ((addr) << 16) + (imm) ) 00171 00172 // branch 00173 // bx reg 00174 #define ARM_BX(reg) (0xe12fff10 + (reg) ) 00175 00176 00177 // move a full register from reg_src to reg_dst 00178 static void gen_mov_regs(HostReg reg_dst,HostReg reg_src) { 00179 if(reg_src == reg_dst) return; 00180 cache_addw( MOV_REG(reg_dst, reg_src) ); // mov reg_dst, reg_src 00181 } 00182 00183 // helper function 00184 static bool val_single_shift(Bit32u value, Bit32u *val_shift) { 00185 Bit32u shift; 00186 00187 if (GCC_UNLIKELY(value == 0)) { 00188 *val_shift = 0; 00189 return true; 00190 } 00191 00192 shift = 0; 00193 while ((value & 1) == 0) { 00194 value>>=1; 00195 shift+=1; 00196 } 00197 00198 if ((value >> 8) != 0) return false; 00199 00200 *val_shift = shift; 00201 return true; 00202 } 00203 00204 // move a 32bit constant value into dest_reg 00205 static void gen_mov_dword_to_reg_imm(HostReg dest_reg,Bit32u imm) { 00206 Bit32u scale; 00207 00208 if (imm < 256) { 00209 cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #imm 00210 } else if ((~imm) < 256) { 00211 cache_addw( MOV_IMM(dest_reg, ~imm) ); // mov dest_reg, #(~imm) 00212 cache_addw( MVN(dest_reg, dest_reg) ); // mvn dest_reg, dest_reg 00213 } else if (val_single_shift(imm, &scale)) { 00214 cache_addw( MOV_IMM(dest_reg, imm >> scale) ); // mov dest_reg, #(imm >> scale) 00215 cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #scale 00216 } else { 00217 Bit32u diff; 00218 00219 diff = imm - ((Bit32u)cache.pos+4); 00220 00221 if ((diff < 1024) && ((imm & 0x03) == 0)) { 00222 if (((Bit32u)cache.pos & 0x03) == 0) { 00223 cache_addw( ADD_LO_PC_IMM(dest_reg, diff) ); // add dest_reg, pc, #(diff >> 2) 00224 } else { 00225 cache_addw( NOP ); // nop 00226 cache_addw( ADD_LO_PC_IMM(dest_reg, diff - 2) ); // add dest_reg, pc, #((diff - 2) >> 2) 00227 } 00228 } else { 00229 if (((Bit32u)cache.pos & 0x03) == 0) { 00230 cache_addw( LDR_PC_IMM(dest_reg, 0) ); // ldr dest_reg, [pc, #0] 00231 cache_addw( B_FWD(2) ); // b next_code (pc+2) 00232 cache_addd(imm); // .int imm 00233 // next_code: 00234 } else { 00235 cache_addw( LDR_PC_IMM(dest_reg, 4) ); // ldr dest_reg, [pc, #4] 00236 cache_addw( B_FWD(4) ); // b next_code (pc+4) 00237 cache_addw( NOP ); // nop 00238 cache_addd(imm); // .int imm 00239 // next_code: 00240 } 00241 } 00242 } 00243 } 00244 00245 // helper function 00246 static bool gen_mov_memval_to_reg_helper(HostReg dest_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) { 00247 switch (size) { 00248 case 4: 00249 #if !defined(C_UNALIGNED_MEMORY) 00250 if ((data & 3) == 0) 00251 #endif 00252 { 00253 if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) { 00254 cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg 00255 cache_addw( LDR_IMM(dest_reg, templo2, data - addr_data) ); // ldr dest_reg, [templo2, #(data - addr_data)] 00256 return true; 00257 } 00258 } 00259 break; 00260 case 2: 00261 #if !defined(C_UNALIGNED_MEMORY) 00262 if ((data & 1) == 0) 00263 #endif 00264 { 00265 if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) { 00266 cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg 00267 cache_addw( LDRH_IMM(dest_reg, templo2, data - addr_data) ); // ldrh dest_reg, [templo2, #(data - addr_data)] 00268 return true; 00269 } 00270 } 00271 break; 00272 case 1: 00273 if ((data >= addr_data) && (data < addr_data + 32)) { 00274 cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg 00275 cache_addw( LDRB_IMM(dest_reg, templo2, data - addr_data) ); // ldrb dest_reg, [templo2, #(data - addr_data)] 00276 return true; 00277 } 00278 default: 00279 break; 00280 } 00281 return false; 00282 } 00283 00284 // helper function 00285 static bool gen_mov_memval_to_reg(HostReg dest_reg, void *data, Bitu size) { 00286 if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true; 00287 if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true; 00288 if (gen_mov_memval_to_reg_helper(dest_reg, (Bit32u)data, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true; 00289 return false; 00290 } 00291 00292 // helper function for gen_mov_word_to_reg 00293 static void gen_mov_word_to_reg_helper(HostReg dest_reg,void* data,bool dword,HostReg data_reg) { 00294 // alignment.... 00295 if (dword) { 00296 #if !defined(C_UNALIGNED_MEMORY) 00297 if ((Bit32u)data & 3) { 00298 if ( ((Bit32u)data & 3) == 2 ) { 00299 cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] 00300 cache_addw( LDRH_IMM(templo1, data_reg, 2) ); // ldrh templo1, [data_reg, #2] 00301 cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 00302 cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 00303 } else { 00304 cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] 00305 cache_addw( ADD_IMM3(templo1, data_reg, 1) ); // add templo1, data_reg, #1 00306 cache_addw( LDRH_IMM(templo1, templo1, 0) ); // ldrh templo1, [templo1] 00307 cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 00308 cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 00309 cache_addw( LDRB_IMM(templo1, data_reg, 3) ); // ldrb templo1, [data_reg, #3] 00310 cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 00311 cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 00312 } 00313 } else 00314 #endif 00315 { 00316 cache_addw( LDR_IMM(dest_reg, data_reg, 0) ); // ldr dest_reg, [data_reg] 00317 } 00318 } else { 00319 #if !defined(C_UNALIGNED_MEMORY) 00320 if ((Bit32u)data & 1) { 00321 cache_addw( LDRB_IMM(dest_reg, data_reg, 0) ); // ldrb dest_reg, [data_reg] 00322 cache_addw( LDRB_IMM(templo1, data_reg, 1) ); // ldrb templo1, [data_reg, #1] 00323 cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 00324 cache_addw( ORR(dest_reg, templo1) ); // orr dest_reg, templo1 00325 } else 00326 #endif 00327 { 00328 cache_addw( LDRH_IMM(dest_reg, data_reg, 0) ); // ldrh dest_reg, [data_reg] 00329 } 00330 } 00331 } 00332 00333 // move a 32bit (dword==true) or 16bit (dword==false) value from memory into dest_reg 00334 // 16bit moves may destroy the upper 16bit of the destination register 00335 static void gen_mov_word_to_reg(HostReg dest_reg,void* data,bool dword) { 00336 if (!gen_mov_memval_to_reg(dest_reg, data, (dword)?4:2)) { 00337 gen_mov_dword_to_reg_imm(templo2, (Bit32u)data); 00338 gen_mov_word_to_reg_helper(dest_reg, data, dword, templo2); 00339 } 00340 } 00341 00342 // move a 16bit constant value into dest_reg 00343 // the upper 16bit of the destination register may be destroyed 00344 static void INLINE gen_mov_word_to_reg_imm(HostReg dest_reg,Bit16u imm) { 00345 gen_mov_dword_to_reg_imm(dest_reg, (Bit32u)imm); 00346 } 00347 00348 // helper function 00349 static bool gen_mov_memval_from_reg_helper(HostReg src_reg, Bit32u data, Bitu size, HostReg addr_reg, Bit32u addr_data) { 00350 switch (size) { 00351 case 4: 00352 #if !defined(C_UNALIGNED_MEMORY) 00353 if ((data & 3) == 0) 00354 #endif 00355 { 00356 if ((data >= addr_data) && (data < addr_data + 128) && (((data - addr_data) & 3) == 0)) { 00357 cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg 00358 cache_addw( STR_IMM(src_reg, templo2, data - addr_data) ); // str src_reg, [templo2, #(data - addr_data)] 00359 return true; 00360 } 00361 } 00362 break; 00363 case 2: 00364 #if !defined(C_UNALIGNED_MEMORY) 00365 if ((data & 1) == 0) 00366 #endif 00367 { 00368 if ((data >= addr_data) && (data < addr_data + 64) && (((data - addr_data) & 1) == 0)) { 00369 cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg 00370 cache_addw( STRH_IMM(src_reg, templo2, data - addr_data) ); // strh src_reg, [templo2, #(data - addr_data)] 00371 return true; 00372 } 00373 } 00374 break; 00375 case 1: 00376 if ((data >= addr_data) && (data < addr_data + 32)) { 00377 cache_addw( MOV_LO_HI(templo2, addr_reg) ); // mov templo2, addr_reg 00378 cache_addw( STRB_IMM(src_reg, templo2, data - addr_data) ); // strb src_reg, [templo2, #(data - addr_data)] 00379 return true; 00380 } 00381 default: 00382 break; 00383 } 00384 return false; 00385 } 00386 00387 // helper function 00388 static bool gen_mov_memval_from_reg(HostReg src_reg, void *dest, Bitu size) { 00389 if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_REGS_ADDR, (Bit32u)&cpu_regs)) return true; 00390 if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, readdata_addr, (Bit32u)&core_dynrec.readdata)) return true; 00391 if (gen_mov_memval_from_reg_helper(src_reg, (Bit32u)dest, size, FC_SEGS_ADDR, (Bit32u)&Segs)) return true; 00392 return false; 00393 } 00394 00395 // helper function for gen_mov_word_from_reg 00396 static void gen_mov_word_from_reg_helper(HostReg src_reg,void* dest,bool dword, HostReg data_reg) { 00397 // alignment.... 00398 if (dword) { 00399 #if !defined(C_UNALIGNED_MEMORY) 00400 if ((Bit32u)dest & 3) { 00401 if ( ((Bit32u)dest & 3) == 2 ) { 00402 cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] 00403 cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg 00404 cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 00405 cache_addw( STRH_IMM(templo1, data_reg, 2) ); // strh templo1, [data_reg, #2] 00406 } else { 00407 cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] 00408 cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg 00409 cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 00410 cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] 00411 cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg 00412 cache_addw( LSR_IMM(templo1, templo1, 16) ); // lsr templo1, templo1, #16 00413 cache_addw( STRB_IMM(templo1, data_reg, 2) ); // strb templo1, [data_reg, #2] 00414 cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg 00415 cache_addw( LSR_IMM(templo1, templo1, 24) ); // lsr templo1, templo1, #24 00416 cache_addw( STRB_IMM(templo1, data_reg, 3) ); // strb templo1, [data_reg, #3] 00417 } 00418 } else 00419 #endif 00420 { 00421 cache_addw( STR_IMM(src_reg, data_reg, 0) ); // str src_reg, [data_reg] 00422 } 00423 } else { 00424 #if !defined(C_UNALIGNED_MEMORY) 00425 if ((Bit32u)dest & 1) { 00426 cache_addw( STRB_IMM(src_reg, data_reg, 0) ); // strb src_reg, [data_reg] 00427 cache_addw( MOV_REG(templo1, src_reg) ); // mov templo1, src_reg 00428 cache_addw( LSR_IMM(templo1, templo1, 8) ); // lsr templo1, templo1, #8 00429 cache_addw( STRB_IMM(templo1, data_reg, 1) ); // strb templo1, [data_reg, #1] 00430 } else 00431 #endif 00432 { 00433 cache_addw( STRH_IMM(src_reg, data_reg, 0) ); // strh src_reg, [data_reg] 00434 } 00435 } 00436 } 00437 00438 // move 32bit (dword==true) or 16bit (dword==false) of a register into memory 00439 static void gen_mov_word_from_reg(HostReg src_reg,void* dest,bool dword) { 00440 if (!gen_mov_memval_from_reg(src_reg, dest, (dword)?4:2)) { 00441 gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); 00442 gen_mov_word_from_reg_helper(src_reg, dest, dword, templo2); 00443 } 00444 } 00445 00446 // move an 8bit value from memory into dest_reg 00447 // the upper 24bit of the destination register can be destroyed 00448 // this function does not use FC_OP1/FC_OP2 as dest_reg as these 00449 // registers might not be directly byte-accessible on some architectures 00450 static void gen_mov_byte_to_reg_low(HostReg dest_reg,void* data) { 00451 if (!gen_mov_memval_to_reg(dest_reg, data, 1)) { 00452 gen_mov_dword_to_reg_imm(templo1, (Bit32u)data); 00453 cache_addw( LDRB_IMM(dest_reg, templo1, 0) ); // ldrb dest_reg, [templo1] 00454 } 00455 } 00456 00457 // move an 8bit value from memory into dest_reg 00458 // the upper 24bit of the destination register can be destroyed 00459 // this function can use FC_OP1/FC_OP2 as dest_reg which are 00460 // not directly byte-accessible on some architectures 00461 static void INLINE gen_mov_byte_to_reg_low_canuseword(HostReg dest_reg,void* data) { 00462 gen_mov_byte_to_reg_low(dest_reg, data); 00463 } 00464 00465 // move an 8bit constant value into dest_reg 00466 // the upper 24bit of the destination register can be destroyed 00467 // this function does not use FC_OP1/FC_OP2 as dest_reg as these 00468 // registers might not be directly byte-accessible on some architectures 00469 static void gen_mov_byte_to_reg_low_imm(HostReg dest_reg,Bit8u imm) { 00470 cache_addw( MOV_IMM(dest_reg, imm) ); // mov dest_reg, #(imm) 00471 } 00472 00473 // move an 8bit constant value into dest_reg 00474 // the upper 24bit of the destination register can be destroyed 00475 // this function can use FC_OP1/FC_OP2 as dest_reg which are 00476 // not directly byte-accessible on some architectures 00477 static void INLINE gen_mov_byte_to_reg_low_imm_canuseword(HostReg dest_reg,Bit8u imm) { 00478 gen_mov_byte_to_reg_low_imm(dest_reg, imm); 00479 } 00480 00481 // move the lowest 8bit of a register into memory 00482 static void gen_mov_byte_from_reg_low(HostReg src_reg,void* dest) { 00483 if (!gen_mov_memval_from_reg(src_reg, dest, 1)) { 00484 gen_mov_dword_to_reg_imm(templo1, (Bit32u)dest); 00485 cache_addw( STRB_IMM(src_reg, templo1, 0) ); // strb src_reg, [templo1] 00486 } 00487 } 00488 00489 00490 00491 // convert an 8bit word to a 32bit dword 00492 // the register is zero-extended (sign==false) or sign-extended (sign==true) 00493 static void gen_extend_byte(bool sign,HostReg reg) { 00494 cache_addw( LSL_IMM(reg, reg, 24) ); // lsl reg, reg, #24 00495 00496 if (sign) { 00497 cache_addw( ASR_IMM(reg, reg, 24) ); // asr reg, reg, #24 00498 } else { 00499 cache_addw( LSR_IMM(reg, reg, 24) ); // lsr reg, reg, #24 00500 } 00501 } 00502 00503 // convert a 16bit word to a 32bit dword 00504 // the register is zero-extended (sign==false) or sign-extended (sign==true) 00505 static void gen_extend_word(bool sign,HostReg reg) { 00506 cache_addw( LSL_IMM(reg, reg, 16) ); // lsl reg, reg, #16 00507 00508 if (sign) { 00509 cache_addw( ASR_IMM(reg, reg, 16) ); // asr reg, reg, #16 00510 } else { 00511 cache_addw( LSR_IMM(reg, reg, 16) ); // lsr reg, reg, #16 00512 } 00513 } 00514 00515 // add a 32bit value from memory to a full register 00516 static void gen_add(HostReg reg,void* op) { 00517 gen_mov_word_to_reg(templo3, op, 1); 00518 cache_addw( ADD_REG(reg, reg, templo3) ); // add reg, reg, templo3 00519 } 00520 00521 // add a 32bit constant value to a full register 00522 static void gen_add_imm(HostReg reg,Bit32u imm) { 00523 Bit32u imm2, scale; 00524 00525 if(!imm) return; 00526 00527 imm2 = (Bit32u) (-((Bit32s)imm)); 00528 00529 if (imm <= 255) { 00530 cache_addw( ADD_IMM8(reg, imm) ); // add reg, #imm 00531 } else if (imm2 <= 255) { 00532 cache_addw( SUB_IMM8(reg, imm2) ); // sub reg, #(-imm) 00533 } else { 00534 if (val_single_shift(imm2, &scale)) { 00535 cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale) 00536 if (scale) { 00537 cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale 00538 } 00539 cache_addw( SUB_REG(reg, reg, templo1) ); // sub reg, reg, templo1 00540 } else { 00541 gen_mov_dword_to_reg_imm(templo1, imm); 00542 cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 00543 } 00544 } 00545 } 00546 00547 // and a 32bit constant value with a full register 00548 static void gen_and_imm(HostReg reg,Bit32u imm) { 00549 Bit32u imm2, scale; 00550 00551 imm2 = ~imm; 00552 if(!imm2) return; 00553 00554 if (!imm) { 00555 cache_addw( MOV_IMM(reg, 0) ); // mov reg, #0 00556 } else { 00557 if (val_single_shift(imm2, &scale)) { 00558 cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale) 00559 if (scale) { 00560 cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale 00561 } 00562 cache_addw( BIC(reg, templo1) ); // bic reg, templo1 00563 } else { 00564 gen_mov_dword_to_reg_imm(templo1, imm); 00565 cache_addw( AND(reg, templo1) ); // and reg, templo1 00566 } 00567 } 00568 } 00569 00570 00571 // move a 32bit constant value into memory 00572 static void gen_mov_direct_dword(void* dest,Bit32u imm) { 00573 gen_mov_dword_to_reg_imm(templo3, imm); 00574 gen_mov_word_from_reg(templo3, dest, 1); 00575 } 00576 00577 // move an address into memory 00578 static void INLINE gen_mov_direct_ptr(void* dest,DRC_PTR_SIZE_IM imm) { 00579 gen_mov_direct_dword(dest,(Bit32u)imm); 00580 } 00581 00582 // add a 32bit (dword==true) or 16bit (dword==false) constant value to a memory value 00583 static void gen_add_direct_word(void* dest,Bit32u imm,bool dword) { 00584 if (!dword) imm &= 0xffff; 00585 if(!imm) return; 00586 00587 if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) { 00588 gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); 00589 gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); 00590 } 00591 gen_add_imm(templo3, imm); 00592 if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) { 00593 gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); 00594 } 00595 } 00596 00597 // add an 8bit constant value to a dword memory value 00598 static void gen_add_direct_byte(void* dest,Bit8s imm) { 00599 gen_add_direct_word(dest, (Bit32s)imm, 1); 00600 } 00601 00602 // subtract a 32bit (dword==true) or 16bit (dword==false) constant value from a memory value 00603 static void gen_sub_direct_word(void* dest,Bit32u imm,bool dword) { 00604 Bit32u imm2, scale; 00605 00606 if (!dword) imm &= 0xffff; 00607 if(!imm) return; 00608 00609 if (!gen_mov_memval_to_reg(templo3, dest, (dword)?4:2)) { 00610 gen_mov_dword_to_reg_imm(templo2, (Bit32u)dest); 00611 gen_mov_word_to_reg_helper(templo3, dest, dword, templo2); 00612 } 00613 00614 imm2 = (Bit32u) (-((Bit32s)imm)); 00615 00616 if (imm <= 255) { 00617 cache_addw( SUB_IMM8(templo3, imm) ); // sub templo3, #imm 00618 } else if (imm2 <= 255) { 00619 cache_addw( ADD_IMM8(templo3, imm2) ); // add templo3, #(-imm) 00620 } else { 00621 if (val_single_shift(imm2, &scale)) { 00622 cache_addw( MOV_IMM(templo1, imm2 >> scale) ); // mov templo1, #(~imm >> scale) 00623 if (scale) { 00624 cache_addw( LSL_IMM(templo1, templo1, scale) ); // lsl templo1, templo1, #scale 00625 } 00626 cache_addw( ADD_REG(templo3, templo3, templo1) ); // add templo3, templo3, templo1 00627 } else { 00628 gen_mov_dword_to_reg_imm(templo1, imm); 00629 cache_addw( SUB_REG(templo3, templo3, templo1) ); // sub templo3, templo3, templo1 00630 } 00631 } 00632 00633 if (!gen_mov_memval_from_reg(templo3, dest, (dword)?4:2)) { 00634 gen_mov_word_from_reg_helper(templo3, dest, dword, templo2); 00635 } 00636 } 00637 00638 // subtract an 8bit constant value from a dword memory value 00639 static void gen_sub_direct_byte(void* dest,Bit8s imm) { 00640 gen_sub_direct_word(dest, (Bit32s)imm, 1); 00641 } 00642 00643 // effective address calculation, destination is dest_reg 00644 // scale_reg is scaled by scale (scale_reg*(2^scale)) and 00645 // added to dest_reg, then the immediate value is added 00646 static INLINE void gen_lea(HostReg dest_reg,HostReg scale_reg,Bitu scale,Bits imm) { 00647 if (scale) { 00648 cache_addw( LSL_IMM(templo1, scale_reg, scale) ); // lsl templo1, scale_reg, #(scale) 00649 cache_addw( ADD_REG(dest_reg, dest_reg, templo1) ); // add dest_reg, dest_reg, templo1 00650 } else { 00651 cache_addw( ADD_REG(dest_reg, dest_reg, scale_reg) ); // add dest_reg, dest_reg, scale_reg 00652 } 00653 gen_add_imm(dest_reg, imm); 00654 } 00655 00656 // effective address calculation, destination is dest_reg 00657 // dest_reg is scaled by scale (dest_reg*(2^scale)), 00658 // then the immediate value is added 00659 static INLINE void gen_lea(HostReg dest_reg,Bitu scale,Bits imm) { 00660 if (scale) { 00661 cache_addw( LSL_IMM(dest_reg, dest_reg, scale) ); // lsl dest_reg, dest_reg, #(scale) 00662 } 00663 gen_add_imm(dest_reg, imm); 00664 } 00665 00666 // generate a call to a parameterless function 00667 template <typename T> static void INLINE gen_call_function_raw(const T func) { 00668 if (((Bit32u)cache.pos & 0x03) == 0) { 00669 cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] 00670 cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) 00671 cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 00672 cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state 00673 } else { 00674 cache_addw( LDR_PC_IMM(templo1, 8) ); // ldr templo1, [pc, #8] 00675 cache_addw( ADD_LO_PC_IMM(templo2, 8) ); // adr templo2, after_call (add templo2, pc, #8) 00676 cache_addw( MOV_HI_LO(HOST_lr, templo2) ); // mov lr, templo2 00677 cache_addw( BX(templo1) ); // bx templo1 --- switch to arm state 00678 cache_addw( NOP ); // nop 00679 } 00680 cache_addd((Bit32u)func); // .int func 00681 // after_call: 00682 00683 // switch from arm to thumb state 00684 cache_addd(0xe2800000 + (templo1 << 12) + (HOST_pc << 16) + (1)); // add templo1, pc, #1 00685 cache_addd(0xe12fff10 + (templo1)); // bx templo1 00686 00687 // thumb state from now on 00688 } 00689 00690 // generate a call to a function with paramcount parameters 00691 // note: the parameters are loaded in the architecture specific way 00692 // using the gen_load_param_ functions below 00693 template <typename T> static Bit32u INLINE gen_call_function_setup(const T func,Bitu paramcount,bool fastcall=false) { 00694 Bit32u proc_addr = (Bit32u)cache.pos; 00695 gen_call_function_raw(func); 00696 return proc_addr; 00697 // if proc_addr is on word boundary ((proc_addr & 0x03) == 0) 00698 // then length of generated code is 20 bytes 00699 // otherwise length of generated code is 22 bytes 00700 } 00701 00702 #if (1) 00703 // max of 4 parameters in a1-a4 00704 00705 // load an immediate value as param'th function parameter 00706 static void INLINE gen_load_param_imm(Bitu imm,Bitu param) { 00707 gen_mov_dword_to_reg_imm(param, imm); 00708 } 00709 00710 // load an address as param'th function parameter 00711 static void INLINE gen_load_param_addr(Bitu addr,Bitu param) { 00712 gen_mov_dword_to_reg_imm(param, addr); 00713 } 00714 00715 // load a host-register as param'th function parameter 00716 static void INLINE gen_load_param_reg(Bitu reg,Bitu param) { 00717 gen_mov_regs(param, reg); 00718 } 00719 00720 // load a value from memory as param'th function parameter 00721 static void INLINE gen_load_param_mem(Bitu mem,Bitu param) { 00722 gen_mov_word_to_reg(param, (void *)mem, 1); 00723 } 00724 #else 00725 other arm abis 00726 #endif 00727 00728 // jump to an address pointed at by ptr, offset is in imm 00729 static void gen_jmp_ptr(void * ptr,Bits imm=0) { 00730 gen_mov_word_to_reg(templo3, ptr, 1); 00731 00732 #if !defined(C_UNALIGNED_MEMORY) 00733 // (*ptr) should be word aligned 00734 if ((imm & 0x03) == 0) { 00735 #endif 00736 if ((imm >= 0) && (imm < 128) && ((imm & 3) == 0)) { 00737 cache_addw( LDR_IMM(templo2, templo3, imm) ); // ldr templo2, [templo3, #imm] 00738 } else { 00739 gen_mov_dword_to_reg_imm(templo2, imm); 00740 cache_addw( LDR_REG(templo2, templo3, templo2) ); // ldr templo2, [templo3, templo2] 00741 } 00742 #if !defined(C_UNALIGNED_MEMORY) 00743 } else { 00744 gen_add_imm(templo3, imm); 00745 00746 cache_addw( LDRB_IMM(templo2, templo3, 0) ); // ldrb templo2, [templo3] 00747 cache_addw( LDRB_IMM(templo1, templo3, 1) ); // ldrb templo1, [templo3, #1] 00748 cache_addw( LSL_IMM(templo1, templo1, 8) ); // lsl templo1, templo1, #8 00749 cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 00750 cache_addw( LDRB_IMM(templo1, templo3, 2) ); // ldrb templo1, [templo3, #2] 00751 cache_addw( LSL_IMM(templo1, templo1, 16) ); // lsl templo1, templo1, #16 00752 cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 00753 cache_addw( LDRB_IMM(templo1, templo3, 3) ); // ldrb templo1, [templo3, #3] 00754 cache_addw( LSL_IMM(templo1, templo1, 24) ); // lsl templo1, templo1, #24 00755 cache_addw( ORR(templo2, templo1) ); // orr templo2, templo1 00756 } 00757 #endif 00758 00759 // increase jmp address to keep thumb state 00760 cache_addw( ADD_IMM3(templo2, templo2, 1) ); // add templo2, templo2, #1 00761 00762 cache_addw( BX(templo2) ); // bx templo2 00763 } 00764 00765 // short conditional jump (+-127 bytes) if register is zero 00766 // the destination is set by gen_fill_branch() later 00767 static Bit32u gen_create_branch_on_zero(HostReg reg,bool dword) { 00768 if (dword) { 00769 cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 00770 } else { 00771 cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 00772 } 00773 cache_addw( BEQ_FWD(0) ); // beq j 00774 return ((Bit32u)cache.pos-2); 00775 } 00776 00777 // short conditional jump (+-127 bytes) if register is nonzero 00778 // the destination is set by gen_fill_branch() later 00779 static Bit32u gen_create_branch_on_nonzero(HostReg reg,bool dword) { 00780 if (dword) { 00781 cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 00782 } else { 00783 cache_addw( LSL_IMM(templo1, reg, 16) ); // lsl templo1, reg, #16 00784 } 00785 cache_addw( BNE_FWD(0) ); // bne j 00786 return ((Bit32u)cache.pos-2); 00787 } 00788 00789 // calculate relative offset and fill it into the location pointed to by data 00790 static void INLINE gen_fill_branch(DRC_PTR_SIZE_IM data) { 00791 #if C_DEBUG 00792 Bits len=(Bit32u)cache.pos-(data+4); 00793 if (len<0) len=-len; 00794 if (len>252) LOG_MSG("Big jump %d",len); 00795 #endif 00796 *(Bit8u*)data=(Bit8u)( ((Bit32u)cache.pos-(data+4)) >> 1 ); 00797 } 00798 00799 // conditional jump if register is nonzero 00800 // for isdword==true the 32bit of the register are tested 00801 // for isdword==false the lowest 8bit of the register are tested 00802 static Bit32u gen_create_branch_long_nonzero(HostReg reg,bool isdword) { 00803 if (isdword) { 00804 cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 00805 } else { 00806 cache_addw( LSL_IMM(templo2, reg, 24) ); // lsl templo2, reg, #24 00807 } 00808 if (((Bit32u)cache.pos & 0x03) == 0) { 00809 cache_addw( BEQ_FWD(8) ); // beq nobranch (pc+8) 00810 cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] 00811 cache_addw( BX(templo1) ); // bx templo1 00812 cache_addw( NOP ); // nop 00813 } else { 00814 cache_addw( BEQ_FWD(6) ); // beq nobranch (pc+6) 00815 cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0] 00816 cache_addw( BX(templo1) ); // bx templo1 00817 } 00818 cache_addd(0); // fill j 00819 // nobranch: 00820 return ((Bit32u)cache.pos-4); 00821 } 00822 00823 // compare 32bit-register against zero and jump if value less/equal than zero 00824 static Bit32u gen_create_branch_long_leqzero(HostReg reg) { 00825 cache_addw( CMP_IMM(reg, 0) ); // cmp reg, #0 00826 if (((Bit32u)cache.pos & 0x03) == 0) { 00827 cache_addw( BGT_FWD(8) ); // bgt nobranch (pc+8) 00828 cache_addw( LDR_PC_IMM(templo1, 4) ); // ldr templo1, [pc, #4] 00829 cache_addw( BX(templo1) ); // bx templo1 00830 cache_addw( NOP ); // nop 00831 } else { 00832 cache_addw( BGT_FWD(6) ); // bgt nobranch (pc+6) 00833 cache_addw( LDR_PC_IMM(templo1, 0) ); // ldr templo1, [pc, #0] 00834 cache_addw( BX(templo1) ); // bx templo1 00835 } 00836 cache_addd(0); // fill j 00837 // nobranch: 00838 return ((Bit32u)cache.pos-4); 00839 } 00840 00841 // calculate long relative offset and fill it into the location pointed to by data 00842 static void INLINE gen_fill_branch_long(Bit32u data) { 00843 // this is an absolute branch 00844 *(Bit32u*)data=((Bit32u)cache.pos) + 1; // add 1 to keep processor in thumb state 00845 } 00846 00847 static void gen_run_code(void) { 00848 Bit8u *pos1, *pos2, *pos3; 00849 00850 #if (__ARM_EABI__) 00851 // 8-byte stack alignment 00852 cache_addd(0xe92d4ff0); // stmfd sp!, {v1-v8,lr} 00853 #else 00854 cache_addd(0xe92d4df0); // stmfd sp!, {v1-v5,v7,v8,lr} 00855 #endif 00856 00857 cache_addd( ARM_ADD_IMM(HOST_r0, HOST_r0, 1, 0) ); // add r0, r0, #1 00858 00859 pos1 = cache.pos; 00860 cache_addd( 0 ); 00861 pos2 = cache.pos; 00862 cache_addd( 0 ); 00863 pos3 = cache.pos; 00864 cache_addd( 0 ); 00865 00866 cache_addd( ARM_ADD_IMM(HOST_lr, HOST_pc, 4, 0) ); // add lr, pc, #4 00867 cache_addd( ARM_STR_IMM_M_W(HOST_lr, HOST_sp, 4) ); // str lr, [sp, #-4]! 00868 cache_addd( ARM_BX(HOST_r0) ); // bx r0 00869 00870 #if (__ARM_EABI__) 00871 cache_addd(0xe8bd4ff0); // ldmfd sp!, {v1-v8,lr} 00872 #else 00873 cache_addd(0xe8bd4df0); // ldmfd sp!, {v1-v5,v7,v8,lr} 00874 #endif 00875 cache_addd( ARM_BX(HOST_lr) ); // bx lr 00876 00877 // align cache.pos to 32 bytes 00878 if ((((Bitu)cache.pos) & 0x1f) != 0) { 00879 cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f)); 00880 } 00881 00882 *(Bit32u*)pos1 = ARM_LDR_IMM(FC_SEGS_ADDR, HOST_pc, cache.pos - (pos1 + 8)); // ldr FC_SEGS_ADDR, [pc, #(&Segs)] 00883 cache_addd((Bit32u)&Segs); // address of "Segs" 00884 00885 *(Bit32u*)pos2 = ARM_LDR_IMM(FC_REGS_ADDR, HOST_pc, cache.pos - (pos2 + 8)); // ldr FC_REGS_ADDR, [pc, #(&cpu_regs)] 00886 cache_addd((Bit32u)&cpu_regs); // address of "cpu_regs" 00887 00888 *(Bit32u*)pos3 = ARM_LDR_IMM(readdata_addr, HOST_pc, cache.pos - (pos3 + 8)); // ldr readdata_addr, [pc, #(&core_dynrec.readdata)] 00889 cache_addd((Bit32u)&core_dynrec.readdata); // address of "core_dynrec.readdata" 00890 00891 // align cache.pos to 32 bytes 00892 if ((((Bitu)cache.pos) & 0x1f) != 0) { 00893 cache.pos = cache.pos + (32 - (((Bitu)cache.pos) & 0x1f)); 00894 } 00895 } 00896 00897 // return from a function 00898 static void gen_return_function(void) { 00899 cache_addw(0xbc08); // pop {r3} 00900 cache_addw( BX(HOST_r3) ); // bx r3 00901 } 00902 00903 #ifdef DRC_FLAGS_INVALIDATION 00904 00905 // called when a call to a function can be replaced by a 00906 // call to a simpler function 00907 static void gen_fill_function_ptr(Bit8u * pos,void* fct_ptr,Bitu flags_type) { 00908 #ifdef DRC_FLAGS_INVALIDATION_DCODE 00909 if (((Bit32u)pos & 0x03) == 0) 00910 { 00911 // try to avoid function calls but rather directly fill in code 00912 switch (flags_type) { 00913 case t_ADDb: 00914 case t_ADDw: 00915 case t_ADDd: 00916 *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 00917 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00918 break; 00919 case t_ORb: 00920 case t_ORw: 00921 case t_ORd: 00922 *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 00923 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00924 break; 00925 case t_ANDb: 00926 case t_ANDw: 00927 case t_ANDd: 00928 *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 00929 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00930 break; 00931 case t_SUBb: 00932 case t_SUBw: 00933 case t_SUBd: 00934 *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 00935 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00936 break; 00937 case t_XORb: 00938 case t_XORw: 00939 case t_XORd: 00940 *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 00941 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00942 break; 00943 case t_CMPb: 00944 case t_CMPw: 00945 case t_CMPd: 00946 case t_TESTb: 00947 case t_TESTw: 00948 case t_TESTd: 00949 *(Bit16u*)pos=B_FWD(16); // b after_call (pc+16) 00950 break; 00951 case t_INCb: 00952 case t_INCw: 00953 case t_INCd: 00954 *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 00955 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00956 break; 00957 case t_DECb: 00958 case t_DECw: 00959 case t_DECd: 00960 *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 00961 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00962 break; 00963 case t_SHLb: 00964 case t_SHLw: 00965 case t_SHLd: 00966 *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 00967 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00968 break; 00969 case t_SHRb: 00970 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 00971 *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 00972 *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 00973 *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) 00974 break; 00975 case t_SHRw: 00976 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 00977 *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 00978 *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 00979 *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) 00980 break; 00981 case t_SHRd: 00982 *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 00983 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 00984 break; 00985 case t_SARb: 00986 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 00987 *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 00988 *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 00989 *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) 00990 break; 00991 case t_SARw: 00992 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 00993 *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 00994 *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 00995 *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) 00996 break; 00997 case t_SARd: 00998 *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 00999 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 01000 break; 01001 case t_RORb: 01002 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 01003 *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 01004 *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 01005 *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01006 *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 01007 *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01008 *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4) 01009 break; 01010 case t_RORw: 01011 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 01012 *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01013 *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 01014 *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01015 *(Bit16u*)(pos+8)=B_FWD(8); // b after_call (pc+8) 01016 break; 01017 case t_RORd: 01018 *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01019 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 01020 break; 01021 case t_ROLb: 01022 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 01023 *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 01024 *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 01025 *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 01026 *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 01027 *(Bit16u*)(pos+10)=NOP; // nop 01028 *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01029 *(Bit16u*)(pos+14)=NOP; // nop 01030 *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1 01031 *(Bit16u*)(pos+18)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01032 break; 01033 case t_ROLw: 01034 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 01035 *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 01036 *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01037 *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 01038 *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 01039 *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01040 *(Bit16u*)(pos+12)=B_FWD(4); // b after_call (pc+4) 01041 break; 01042 case t_ROLd: 01043 *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 01044 *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 01045 *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01046 *(Bit16u*)(pos+6)=B_FWD(10); // b after_call (pc+10) 01047 break; 01048 case t_NEGb: 01049 case t_NEGw: 01050 case t_NEGd: 01051 *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 01052 *(Bit16u*)(pos+2)=B_FWD(14); // b after_call (pc+14) 01053 break; 01054 default: 01055 *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func 01056 break; 01057 } 01058 } 01059 else 01060 { 01061 // try to avoid function calls but rather directly fill in code 01062 switch (flags_type) { 01063 case t_ADDb: 01064 case t_ADDw: 01065 case t_ADDd: 01066 *(Bit16u*)pos=ADD_REG(HOST_a1, HOST_a1, HOST_a2); // add a1, a1, a2 01067 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01068 break; 01069 case t_ORb: 01070 case t_ORw: 01071 case t_ORd: 01072 *(Bit16u*)pos=ORR(HOST_a1, HOST_a2); // orr a1, a2 01073 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01074 break; 01075 case t_ANDb: 01076 case t_ANDw: 01077 case t_ANDd: 01078 *(Bit16u*)pos=AND(HOST_a1, HOST_a2); // and a1, a2 01079 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01080 break; 01081 case t_SUBb: 01082 case t_SUBw: 01083 case t_SUBd: 01084 *(Bit16u*)pos=SUB_REG(HOST_a1, HOST_a1, HOST_a2); // sub a1, a1, a2 01085 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01086 break; 01087 case t_XORb: 01088 case t_XORw: 01089 case t_XORd: 01090 *(Bit16u*)pos=EOR(HOST_a1, HOST_a2); // eor a1, a2 01091 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01092 break; 01093 case t_CMPb: 01094 case t_CMPw: 01095 case t_CMPd: 01096 case t_TESTb: 01097 case t_TESTw: 01098 case t_TESTd: 01099 *(Bit16u*)pos=B_FWD(18); // b after_call (pc+18) 01100 break; 01101 case t_INCb: 01102 case t_INCw: 01103 case t_INCd: 01104 *(Bit16u*)pos=ADD_IMM3(HOST_a1, HOST_a1, 1); // add a1, a1, #1 01105 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01106 break; 01107 case t_DECb: 01108 case t_DECw: 01109 case t_DECd: 01110 *(Bit16u*)pos=SUB_IMM3(HOST_a1, HOST_a1, 1); // sub a1, a1, #1 01111 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01112 break; 01113 case t_SHLb: 01114 case t_SHLw: 01115 case t_SHLd: 01116 *(Bit16u*)pos=LSL_REG(HOST_a1, HOST_a2); // lsl a1, a2 01117 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01118 break; 01119 case t_SHRb: 01120 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 01121 *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 24); // lsr a1, a1, #24 01122 *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 01123 *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) 01124 break; 01125 case t_SHRw: 01126 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 01127 *(Bit16u*)(pos+2)=LSR_IMM(HOST_a1, HOST_a1, 16); // lsr a1, a1, #16 01128 *(Bit16u*)(pos+4)=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 01129 *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) 01130 break; 01131 case t_SHRd: 01132 *(Bit16u*)pos=LSR_REG(HOST_a1, HOST_a2); // lsr a1, a2 01133 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01134 break; 01135 case t_SARb: 01136 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 01137 *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 24); // asr a1, a1, #24 01138 *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 01139 *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) 01140 break; 01141 case t_SARw: 01142 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 01143 *(Bit16u*)(pos+2)=ASR_IMM(HOST_a1, HOST_a1, 16); // asr a1, a1, #16 01144 *(Bit16u*)(pos+4)=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 01145 *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) 01146 break; 01147 case t_SARd: 01148 *(Bit16u*)pos=ASR_REG(HOST_a1, HOST_a2); // asr a1, a2 01149 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01150 break; 01151 case t_RORb: 01152 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 01153 *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 01154 *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 01155 *(Bit16u*)(pos+6)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01156 *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 01157 *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01158 *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6) 01159 break; 01160 case t_RORw: 01161 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 01162 *(Bit16u*)(pos+2)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01163 *(Bit16u*)(pos+4)=ORR(HOST_a1, templo1); // orr a1, templo1 01164 *(Bit16u*)(pos+6)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01165 *(Bit16u*)(pos+8)=B_FWD(10); // b after_call (pc+10) 01166 break; 01167 case t_RORd: 01168 *(Bit16u*)pos=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01169 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01170 break; 01171 case t_ROLb: 01172 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 24); // lsl a1, a1, #24 01173 *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 01174 *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 8); // lsr templo1, a1, #8 01175 *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 01176 *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 01177 *(Bit16u*)(pos+10)=NOP; // nop 01178 *(Bit16u*)(pos+12)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01179 *(Bit16u*)(pos+14)=NOP; // nop 01180 *(Bit16u*)(pos+16)=ORR(HOST_a1, templo1); // orr a1, templo1 01181 *(Bit16u*)(pos+18)=NOP; // nop 01182 *(Bit16u*)(pos+20)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01183 break; 01184 case t_ROLw: 01185 *(Bit16u*)pos=LSL_IMM(HOST_a1, HOST_a1, 16); // lsl a1, a1, #16 01186 *(Bit16u*)(pos+2)=NEG(HOST_a2, HOST_a2); // neg a2, a2 01187 *(Bit16u*)(pos+4)=LSR_IMM(templo1, HOST_a1, 16); // lsr templo1, a1, #16 01188 *(Bit16u*)(pos+6)=ADD_IMM8(HOST_a2, 32); // add a2, #32 01189 *(Bit16u*)(pos+8)=ORR(HOST_a1, templo1); // orr a1, templo1 01190 *(Bit16u*)(pos+10)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01191 *(Bit16u*)(pos+12)=B_FWD(6); // b after_call (pc+6) 01192 break; 01193 case t_ROLd: 01194 *(Bit16u*)pos=NEG(HOST_a2, HOST_a2); // neg a2, a2 01195 *(Bit16u*)(pos+2)=ADD_IMM8(HOST_a2, 32); // add a2, #32 01196 *(Bit16u*)(pos+4)=ROR_REG(HOST_a1, HOST_a2); // ror a1, a2 01197 *(Bit16u*)(pos+6)=B_FWD(12); // b after_call (pc+12) 01198 break; 01199 case t_NEGb: 01200 case t_NEGw: 01201 case t_NEGd: 01202 *(Bit16u*)pos=NEG(HOST_a1, HOST_a1); // neg a1, a1 01203 *(Bit16u*)(pos+2)=B_FWD(16); // b after_call (pc+16) 01204 break; 01205 default: 01206 *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func 01207 break; 01208 } 01209 01210 } 01211 #else 01212 if (((Bit32u)pos & 0x03) == 0) 01213 { 01214 *(Bit32u*)(pos+8)=(Bit32u)fct_ptr; // simple_func 01215 } 01216 else 01217 { 01218 *(Bit32u*)(pos+10)=(Bit32u)fct_ptr; // simple_func 01219 } 01220 #endif 01221 } 01222 #endif 01223 01224 static void cache_block_before_close(void) { 01225 if ((((Bit32u)cache.pos) & 3) != 0) { 01226 cache_addw( NOP ); // nop 01227 } 01228 } 01229 01230 #ifdef DRC_USE_SEGS_ADDR 01231 01232 // mov 16bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 2 must be zero) 01233 // 16bit moves may destroy the upper 16bit of the destination register 01234 static void gen_mov_seg16_to_reg(HostReg dest_reg,Bitu index) { 01235 cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR 01236 cache_addw( LDRH_IMM(dest_reg, templo1, index) ); // ldrh dest_reg, [templo1, #index] 01237 } 01238 01239 // mov 32bit value from Segs[index] into dest_reg using FC_SEGS_ADDR (index modulo 4 must be zero) 01240 static void gen_mov_seg32_to_reg(HostReg dest_reg,Bitu index) { 01241 cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR 01242 cache_addw( LDR_IMM(dest_reg, templo1, index) ); // ldr dest_reg, [templo1, #index] 01243 } 01244 01245 // add a 32bit value from Segs[index] to a full register using FC_SEGS_ADDR (index modulo 4 must be zero) 01246 static void gen_add_seg32_to_reg(HostReg reg,Bitu index) { 01247 cache_addw( MOV_LO_HI(templo1, FC_SEGS_ADDR) ); // mov templo1, FC_SEGS_ADDR 01248 cache_addw( LDR_IMM(templo2, templo1, index) ); // ldr templo2, [templo1, #index] 01249 cache_addw( ADD_REG(reg, reg, templo2) ); // add reg, reg, templo2 01250 } 01251 01252 #endif 01253 01254 #ifdef DRC_USE_REGS_ADDR 01255 01256 // mov 16bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 2 must be zero) 01257 // 16bit moves may destroy the upper 16bit of the destination register 01258 static void gen_mov_regval16_to_reg(HostReg dest_reg,Bitu index) { 01259 cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR 01260 cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] 01261 } 01262 01263 // mov 32bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR (index modulo 4 must be zero) 01264 static void gen_mov_regval32_to_reg(HostReg dest_reg,Bitu index) { 01265 cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR 01266 cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] 01267 } 01268 01269 // 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) 01270 // 16bit moves may destroy the upper 16bit of the destination register 01271 static void gen_mov_regword_to_reg(HostReg dest_reg,Bitu index,bool dword) { 01272 cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR 01273 if (dword) { 01274 cache_addw( LDR_IMM(dest_reg, templo2, index) ); // ldr dest_reg, [templo2, #index] 01275 } else { 01276 cache_addw( LDRH_IMM(dest_reg, templo2, index) ); // ldrh dest_reg, [templo2, #index] 01277 } 01278 } 01279 01280 // move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR 01281 // the upper 24bit of the destination register can be destroyed 01282 // this function does not use FC_OP1/FC_OP2 as dest_reg as these 01283 // registers might not be directly byte-accessible on some architectures 01284 static void gen_mov_regbyte_to_reg_low(HostReg dest_reg,Bitu index) { 01285 cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR 01286 cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] 01287 } 01288 01289 // move an 8bit value from cpu_regs[index] into dest_reg using FC_REGS_ADDR 01290 // the upper 24bit of the destination register can be destroyed 01291 // this function can use FC_OP1/FC_OP2 as dest_reg which are 01292 // not directly byte-accessible on some architectures 01293 static void INLINE gen_mov_regbyte_to_reg_low_canuseword(HostReg dest_reg,Bitu index) { 01294 cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR 01295 cache_addw( LDRB_IMM(dest_reg, templo2, index) ); // ldrb dest_reg, [templo2, #index] 01296 } 01297 01298 01299 // add a 32bit value from cpu_regs[index] to a full register using FC_REGS_ADDR (index modulo 4 must be zero) 01300 static void gen_add_regval32_to_reg(HostReg reg,Bitu index) { 01301 cache_addw( MOV_LO_HI(templo2, FC_REGS_ADDR) ); // mov templo2, FC_REGS_ADDR 01302 cache_addw( LDR_IMM(templo1, templo2, index) ); // ldr templo1, [templo2, #index] 01303 cache_addw( ADD_REG(reg, reg, templo1) ); // add reg, reg, templo1 01304 } 01305 01306 01307 // move 16bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 2 must be zero) 01308 static void gen_mov_regval16_from_reg(HostReg src_reg,Bitu index) { 01309 cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR 01310 cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] 01311 } 01312 01313 // move 32bit of register into cpu_regs[index] using FC_REGS_ADDR (index modulo 4 must be zero) 01314 static void gen_mov_regval32_from_reg(HostReg src_reg,Bitu index) { 01315 cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR 01316 cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] 01317 } 01318 01319 // 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) 01320 static void gen_mov_regword_from_reg(HostReg src_reg,Bitu index,bool dword) { 01321 cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR 01322 if (dword) { 01323 cache_addw( STR_IMM(src_reg, templo1, index) ); // str src_reg, [templo1, #index] 01324 } else { 01325 cache_addw( STRH_IMM(src_reg, templo1, index) ); // strh src_reg, [templo1, #index] 01326 } 01327 } 01328 01329 // move the lowest 8bit of a register into cpu_regs[index] using FC_REGS_ADDR 01330 static void gen_mov_regbyte_from_reg_low(HostReg src_reg,Bitu index) { 01331 cache_addw( MOV_LO_HI(templo1, FC_REGS_ADDR) ); // mov templo1, FC_REGS_ADDR 01332 cache_addw( STRB_IMM(src_reg, templo1, index) ); // strb src_reg, [templo1, #index] 01333 } 01334 01335 #endif