DOSBox-X
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
src/cpu/core_dynrec/risc_armv4le-thumb.h
00001 /*
00002  *  Copyright (C) 2002-2020  The DOSBox Team
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License along
00015  *  with this program; if not, write to the Free Software Foundation, Inc.,
00016  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 
00020 
00021 /* 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