www.pudn.com > coremp4-1.0.zip > DynamicARMCode.cpp


/***************************************************************************** 
 * 
 * This program is free software ; you can redistribute it and/or modify 
 * it under the terms of the GNU General Public License as published by 
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version. 
 * 
 * This program is distributed in the hope that it will be useful, 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
 * GNU General Public License for more details. 
 * 
 * You should have received a copy of the GNU General Public License 
 * along with this program; if not, write to the Free Software 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA 
 * 
 * The Core Pocket Media Player 
 * Copyright (c) 2004-2005 Gabor Kovacs 
 * 
 ****************************************************************************/ 
 
 
#if defined __SYMBIAN32__ 
#include  
#elif defined _WIN32_WCE 
#include  
#endif 
 
//---------------------------- 
 
#include "DynamicArmCode.h" 
#include "Util.h" 
#include "C_buffer.h" 
 
//mode 
//1: I2 rd:16,rn:12 
//2: I2C rd:16,rn:12,imm[3]:0 
//4: I3 rd:0,rnlo:12,rnhi:16 
//6: I2 rd:12,rn:16 
//7: I3 rd:12,rn:16,rm:0 
//8: I3C rd:12,rn:16,rm:0,imm[3]:20 
//9: I2C rd:12,rn:16,imm[8]:0|20 
//F: I2C,I1P rd:12,rn:16,imm[8]:0 (w or q *4) 
//---------------------------- 
 
void *CodeAlloc(int size){ 
#if defined __SYMBIAN32__ || defined __PALMOS__ 
                              //Symbian 
   return new(true) byte[size]; 
#elif defined _WIN32_WCE 
   return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_EXECUTE_READ); 
#else 
#error 
#endif 
} 
 
//---------------------------- 
 
void CodeFree(void *code, int size){ 
#if defined __SYMBIAN32__ || defined __PALMOS__ 
                              //Symbian 
   delete[] (byte*)code; 
#elif defined _WIN32_WCE 
	VirtualFree(code, size, MEM_DECOMMIT); 
	VirtualFree(code, 0, MEM_RELEASE); 
#else 
#error 
#endif 
} 
 
//---------------------------- 
 
void CodeLock(void *code, int size){ 
#if defined _WIN32_WCE 
   DWORD protect; 
	VirtualProtect(code, size, PAGE_READWRITE | PAGE_NOCACHE, &protect); 
#endif 
} 
 
//---------------------------- 
 
void CodeUnlock(void *code, int size){ 
 
                              //flush cache 
#ifdef __SYMBIAN32__ 
   User::IMB_Range(code, (byte*)code+size); 
#elif defined _WIN32_WCE 
	DWORD protect; 
	VirtualProtect(code, size, PAGE_EXECUTE_READ, &protect); 
 
   static void (WINAPI *FuncCacheSync)(DWORD); 
   static HMODULE CoreDLL; 
 
   if(!FuncCacheSync && !CoreDLL){ 
      CoreDLL = LoadLibrary(L"coredll.dll"); 
      if(CoreDLL) 
         *(FARPROC*)&FuncCacheSync = GetProcAddress(CoreDLL, L"CacheSync"); 
   } 
   if(FuncCacheSync) 
      FuncCacheSync(2); 
#elif defined __PALMOS__ 
   byte *mem = new byte[65536]; 
   if(mem){ 
      MemCpy(mem, mem, 65536); 
      delete[] mem; 
   } 
#else 
#error 
#endif 
} 
 
//---------------------------- 
                              //detect caps 
dword C_dyn_code::GetCpuCaps(){ 
 
   dword caps = 0; 
 
#if defined _WIN32_WCE 
   HINSTANCE hi = LoadLibrary(L"Coredll.dll"); 
   if(hi){ 
      typedef BOOL (t_IsProcessorFeaturePresent)(DWORD); 
      t_IsProcessorFeaturePresent *fp = (t_IsProcessorFeaturePresent*)GetProcAddress(hi, L"IsProcessorFeaturePresent"); 
      if(fp){ 
         const dword _PF_ARM_INTEL_WMMX = 0x80010003; 
         if((*fp)(_PF_ARM_INTEL_WMMX) != 0) 
            caps |= CPU_WIRELESS_MMX; 
      } 
      FreeLibrary(hi); 
   } 
#endif 
   return caps; 
} 
 
//---------------------------- 
//---------------------------- 
 
class C_dyn_code_imp: public C_dyn_code{ 
 
   struct S_instruction{ 
      S_instruction *next, *prev; 
      int tag; 
      int read_flags; 
      int write_flags; 
      dword read_regs; 
      dword write_regs; 
      S_instruction *realloc; 
      bool branch;            //branch label 
      bool is_function; 
      dword code_small; 
      byte *code_large; 
      int code_size; 
      byte *address; 
 
      S_instruction(): 
         tag(0), 
         next(NULL), 
         prev(NULL), 
         read_flags(0), 
         write_flags(0), 
         read_regs(0), 
         write_regs(0), 
         realloc(NULL), 
         branch(false), 
         is_function(false), 
         code_small(0), 
         code_large(NULL), 
         address(NULL) 
      {} 
   }; 
 
   E_CONDITION next_cond; 
   bool next_set, 
      next_byte, 
      next_half, 
      next_sign; 
   dword max_align; 
 
//---------------------------- 
 
   struct S_dynamic_code{ 
      byte *alloc_base; 
      dword alloc_size; 
      byte *code; 
      //dword size; 
      S_dynamic_code(): 
         alloc_base(NULL), 
         code(NULL), 
         //size(0), 
         alloc_size(0) 
      {} 
      ~S_dynamic_code(){ 
         Free(); 
      } 
 
      void Free(){ 
         if(alloc_base) 
            CodeFree(alloc_base, alloc_size); 
         alloc_base = NULL; 
         code = NULL; 
         //size =  
         alloc_size = 0; 
      } 
      C_buffer functions; 
   } dynamic_code; 
 
//---------------------------- 
 
   S_instruction *inst_begin, *inst_end; 
   bool move_back; 
   //bool delay_slot; 
   dword local_vars_size; 
 
//---------------------------- 
 
   void InstInit(); 
 
//---------------------------- 
 
   inline void StoreReg(dword ®s, dword reg){ 
 
      if(reg != NONE){ 
         if(reg<32) 
            regs |= 1 << reg; 
         else 
            regs |= 256 << (reg-32);  
      } 
   } 
 
//---------------------------- 
 
   S_instruction *InstCreate(const void *code, int code_size, byte write_reg, byte read_reg_1, byte read_reg_2, int read_flags, int write_flags); 
 
//---------------------------- 
 
   static bool InstReadWrite(const S_instruction *a, const S_instruction *b){ 
      return ((a->read_flags&b->write_flags) || (a->read_regs&b->write_regs)); 
   } 
 
   static bool InstBothWrite(const S_instruction *a, const S_instruction *b){ 
      return ((a->write_flags&b->write_flags) || (a->write_regs&b->write_regs)); 
   } 
 
//---------------------------- 
 
   static int InstructionSize(const S_instruction *p, int pos){ 
 
      if(p->code_size >= 0) 
         return p->code_size; 
      pos = pos % -p->code_size; 
      if(pos) 
         pos = -p->code_size - pos; 
      return pos; 
   } 
 
   static byte *InstCode(S_instruction *p){ 
      return p->code_large ? p->code_large : (byte*)&p->code_small; 
   } 
 
 
//---------------------------- 
 
   void InstAdd(S_instruction *ins){ 
 
      assert(ins); 
 
      S_instruction *p = inst_end; //insert after p 
      /* 
      if(delay_slot){ 
         assert(p && !p->branch && !InstReadWrite(p, ins) && !InstReadWrite(ins, p) && !InstBothWrite(p, ins)); 
         p->branch = true; 
         p = p->prev; 
         delay_slot = false; 
      } 
      */ 
      if(move_back){ 
         while(p && !p->branch && !p->is_function && !InstReadWrite(p, ins) && !InstReadWrite(ins, p) && !InstBothWrite(p, ins)) 
            p = p->prev; 
         move_back = false; 
      } 
       
      if(p){ 
         if(p->next)  
            p->next->prev = ins; 
         else 
            inst_end = ins; 
         ins->next = p->next; 
         ins->prev = p; 
         p->next = ins; 
      }else{ 
         if(inst_begin) 
            inst_begin->prev = ins; 
         else 
            inst_end = ins; 
         ins->next = inst_begin; 
         ins->prev = NULL; 
         inst_begin = ins; 
      } 
   } 
 
//---------------------------- 
 
   S_instruction *InstCreate32(int Code32, byte write_reg = NONE, byte read_reg_1 = NONE, byte read_reg_2 = NONE, int read_flags = 0, int write_flags = 0){ 
      return InstCreate(&Code32, 4, write_reg, read_reg_1, read_reg_2, read_flags, write_flags); 
   } 
 
   /* 
   S_instruction *InstCreate16(int Code16, byte write_reg, byte read_reg_1, byte read_reg_2, int read_flags, int write_flags){ 
      return InstCreate(&Code16, 2, write_reg, read_reg_1, read_reg_2, read_flags, write_flags); 
   } 
   */ 
 
//---------------------------- 
 
   void FreeInstructions(); 
 
//---------------------------- 
 
   bool InstReAlloc(S_instruction *p, const S_instruction *realloc); 
 
//---------------------------- 
 
   void IPLD(int *code, byte *dest); 
 
//---------------------------- 
 
public: 
   C_dyn_code_imp(): 
      move_back(false), 
      local_vars_size(0), 
      inst_begin(NULL), 
      inst_end(NULL), 
      max_align(0) 
   { 
      InstInit(); 
   } 
   ~C_dyn_code_imp(){ 
      Close(); 
   } 
 
   void Close(){ 
      FreeInstructions(); 
      dynamic_code.Free(); 
   } 
 
//---------------------------- 
 
   virtual void Byte(){ 
      next_byte = true; 
      next_sign = false; 
   } 
 
   virtual void Half(){ 
      next_half = true; 
      next_sign = false; 
   } 
 
   virtual void SByte(){ 
      next_byte = true; 
      next_sign = true; 
   } 
 
   virtual void SHalf(){ 
      next_half = true; 
      next_sign = true; 
   } 
 
   virtual void Cond(E_CONDITION c){ 
      next_cond = c; 
   } 
 
   virtual void Set(){ 
      next_set = true; 
   } 
   virtual void MoveBack(){ move_back = true; }      //was: MB() 
   //void DS(){ delay_slot = true; } 
 
   void InstPost(S_instruction *p){ 
      InstAdd(p); 
      InstInit(); 
   } 
 
//---------------------------- 
 
   virtual void *Label(bool do_post){ 
      S_instruction *p = InstCreate(NULL, 0, NONE, NONE, NONE, 0, 0); 
      p->branch = true; 
      if(do_post) 
         InstPost(p); 
      return p; 
   } 
 
//---------------------------- 
 
   virtual void PutLabel(void *label){ 
      S_instruction *ins = (S_instruction*)label; 
                              //make sure it was not already posted 
      assert(!ins->next); 
      InstPost(ins); 
   } 
 
//---------------------------- 
 
   virtual void *DeclareData(void *data, dword data_size){ 
      S_instruction *p = InstCreate(data, data_size, NONE, NONE, NONE, 0, 0); 
      p->branch = true; 
      return p; 
   } 
 
//---------------------------- 
 
   virtual void StoreLabelAddress(void *label){ 
 
      S_instruction *p = InstCreate32(NULL, NONE, NONE, NONE, 0, 0); 
      p->realloc = (S_instruction*)label; 
      p->branch = true; 
      InstPost(p); 
   } 
 
//---------------------------- 
 
   virtual void Align(dword bytes){ 
      S_instruction *p = InstCreate(NULL, -(int)bytes, NONE, NONE, NONE, 0, 0); 
      p->branch = true; 
      InstPost(p); 
      max_align = Max(max_align, bytes); 
   } 
 
//---------------------------- 
 
   /* 
   void Break(){ 
 
      S_instruction *p = InstCreate32((next_cond << 28) | (15 << 24)); 
      p->branch = true; 
      InstPost(p); 
   } 
   */ 
 
//---------------------------- 
 
   virtual void FunctionBegin(dword _local_vars_size){ 
                              // stmfd sp!, { r4 - r11, lr } 
      S_instruction *p = InstCreate32(0xe92d4ff0, sp); 
      p->is_function = true; 
      for(int i=4; i<16; ++i) 
         p->read_regs |= 1 << i; 
      InstPost(p); 
                              //allocate space for local variables 
      local_vars_size = _local_vars_size; 
      if(local_vars_size) 
         I2C(SUB, sp, sp, local_vars_size); 
   } 
 
//---------------------------- 
 
   virtual void FunctionEnd(){ 
 
      if(local_vars_size){ 
         I2C(ADD, sp, sp, local_vars_size); 
         local_vars_size = 0; 
      } 
                              // ldmfd sp!, { r4 - r11, pc } 
      S_instruction *p = InstCreate32(0xe8bd8ff0, sp); 
      for(int i=4;i<16;++i) 
         p->write_regs |= 1 << i; 
      InstPost(p); 
   } 
 
//---------------------------- 
 
   virtual void CodeBuild(); 
 
//---------------------------- 
 
   virtual void I3C(int code, byte Dest, byte op_1, byte Op2, int constant); 
   virtual void I3(int code, byte Dest, byte op_1, byte Op2); 
   virtual void I3S(int code, byte Dest, byte op_1, byte Op2, E_SHIFT_TYPE ShiftType, int Shift); 
   virtual void I4(int code, byte Dest, byte op_1, byte Op2, byte Op3); 
   virtual void IConst(byte Dest, int constant); 
   virtual void I2(int code, byte Dest, byte op_1); 
   virtual void I2C(int code, byte Dest, byte op_1, int constant); 
   virtual void I1P(int code, byte Dest, void *block, int Ofs); 
   virtual void I0P(int code, int Cond, void *target); 
 
   virtual void MulC(E_REGISTER dst, E_REGISTER src, int constant); 
 
//---------------------------- 
 
   virtual void *Code(dword fnc_index) const{ 
 
      if(fnc_index >= dynamic_code.functions.Size()) 
         return NULL; 
      return dynamic_code.functions[fnc_index]; 
   } 
}; 
 
//---------------------------- 
 
void C_dyn_code_imp::InstInit(){ 
   next_cond = AL; 
   next_set = false; 
   next_byte = false; 
   next_half = false; 
   next_sign = false; 
} 
 
//---------------------------- 
 
C_dyn_code_imp::S_instruction *C_dyn_code_imp::InstCreate(const void *code, int code_size, byte write_reg, byte read_reg_1, byte read_reg_2, int read_flags, int write_flags){ 
 
   S_instruction *p = new(true) S_instruction(); 
   p->read_flags = read_flags; 
   p->write_flags = write_flags; 
 
   p->code_size = code_size; 
   if(code_size <= (int)sizeof(p->code_small)){ 
      if(code) 
         p->code_small = *(dword*)code; 
   }else{ 
      p->code_large = new(true) byte[code_size]; 
      if(code) 
         MemCpy(p->code_large, code, code_size); 
      else 
         MemSet(p->code_large, 0, code_size); 
   } 
       
   StoreReg(p->write_regs, write_reg); 
   StoreReg(p->read_regs, read_reg_1); 
   StoreReg(p->read_regs, read_reg_2); 
   /* 
   if(write_reg != NONE){ 
      if(write_reg<32) 
         p->write_regs |= 1 << write_reg; 
      else 
         p->write_flags |= 256 << (write_reg-32);  
   } 
   if(read_reg_1 != NONE){ 
      if(read_reg_1<32) 
         p->read_regs |= 1 << read_reg_1; 
      else 
         p->read_flags |= 256 << (read_reg_1-32); 
   } 
   if(read_reg_2 != NONE){ 
      if(read_reg_2<32) 
         p->read_regs |= 1 << read_reg_2; 
      else 
         p->read_flags |= 256 << (read_reg_2-32); 
   } 
   */ 
   return p; 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::FreeInstructions(){ 
 
   for(S_instruction *p = inst_begin; p; ){ 
      S_instruction *q = p; 
      p = p->next; 
      if(q->code_large) 
         delete[] q->code_large; 
      delete q; 
   } 
   inst_begin = NULL; 
   inst_end = NULL; 
} 
 
//---------------------------- 
 
bool C_dyn_code_imp::InstReAlloc(S_instruction *p, const S_instruction *realloc){ 
 
   int Diff = realloc->address - (p->address+8); 
   int *code = (int*)InstCode(p); 
 
   if(((*code >> 25) & 7) == 6){ //wldr,wstr 
      int Ofs = Diff + p->tag; 
      int OfsUnsigned = 1; 
      if(Ofs < 0){ 
         Ofs = -Ofs; 
         OfsUnsigned = 0; 
      } 
      if(*code & 256){ 
         if(Ofs & 3) 
            Ofs = 256; 
         else 
            Ofs >>= 2; 
      } 
      if(Ofs < 256){ 
         *code &= ~(1<<23); 
         *code |= OfsUnsigned<<23; 
         *code &= ~255; 
         *code |= Ofs; 
         return true; 
      } 
      //DEBUG_MSG1(-1,T("Realloc failed for wldr,wstr %d"),Ofs); 
   }else 
   if(((*code >> 25) & 7) == 5){ 
                           //branch 
      *code &= 0xff000000; 
      *code |= (Diff >> 2) & ~0xff000000; 
      return true; 
   }else 
   if(((*code >> 25) & 7) == 1){ //add dest,pc,#const 
      int Shift; 
      int Ofs = Diff + p->tag; 
 
      *code &= ~((15 << 21)|4095); 
 
      if(Ofs < 0){ 
         Ofs = -Ofs; 
         *code |= (SUB << 21); 
      }else 
         *code |= (ADD << 21); 
 
      for(Shift = 0;Shift<32;Shift+=2){ 
         if (Ofs >= 0 && Ofs <= 255) 
            break; 
         Ofs = (Ofs << 2) | ((Ofs >> 30) & 3); 
      } 
      if(Ofs >= 0 && Ofs <= 255){ 
         *code |= (Shift << 7) | Ofs; 
         return true; 
      } 
      //DEBUG_MSG1(-1,T("Realloc failed for add dest,pc,#const %d"),Ofs); 
   }else 
   if(((*code >> 25) & 7) == 2){ //ldr,str 
      int Ofs = Diff + p->tag; 
      int OfsUnsigned = 1; 
      if(Ofs < 0){ 
         Ofs = -Ofs; 
         OfsUnsigned = 0; 
      } 
      if(Ofs < 4096){ 
         *code &= ~(1<<23); 
         *code |= OfsUnsigned<<23; 
         *code &= ~4095; 
         *code |= Ofs; 
         return true; 
      } 
      //DEBUG_MSG1(-1,T("Realloc failed for ldr,str %d"),Ofs); 
   }else 
   if(!*code){ 
                              //plain address instantiation 
      *code = (int)realloc->address; 
      return true; 
   } 
   return false; 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::IPLD(int *code, byte *dest){ 
 
   switch(*code){ 
   case PLD: 
      next_cond = NV; next_byte = true; *code = LDR; *dest = pc; break; 
   case PLD_PRE: 
      next_cond = NV; next_byte = true; *code = LDR_PRE; *dest = pc; break; 
   case PLD_POST: 
      next_cond = NV; next_byte = true; *code = LDR_POST; *dest = pc; break; 
   case PLD_PRESUB: 
      next_cond = NV; next_byte = true; *code = LDR_PRESUB; *dest = pc; break; 
   case PLD_POSTSUB: 
      next_cond = NV; next_byte = true; *code = LDR_POSTSUB; *dest = pc; break; 
   } 
} 
 
//---------------------------- 
 
#define MODE(x) ((dword)(x) >> 28) 
#define MODEMASK ~0xF0000000 
 
void C_dyn_code_imp::I3C(int code, byte Dest, byte op_1, byte Op2, int constant){ 
 
   S_instruction *p = NULL; 
   if(MODE(code) == 8 && constant>=0 && constant<8){ 
      p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | ((Op2 & 15) << 0) | (constant << 20),  
         Dest, op_1, Op2, (next_cond != AL)?1:0, 0); 
   } 
   InstPost(p); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::I3(int code, byte Dest, byte op_1, byte Op2){ 
 
   if(MODE(code) == 4){ 
      S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 0) | ((op_1 & 15) << 12) | ((Op2 & 15) << 16), 
            Dest, op_1, Op2, (next_cond != AL)?1:0, 0); 
      InstPost(p); 
   }else 
   if(MODE(code) == 7){ 
      S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | ((Op2 & 15) << 0), 
            Dest, op_1, Op2, (next_cond != AL)?1:0, 0); 
      InstPost(p); 
   }else 
      I3S(code,Dest,op_1,Op2, LSL, 0); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::I3S(int code, byte Dest, byte op_1, byte Op2, E_SHIFT_TYPE ShiftType, int Shift){ 
 
   S_instruction *p = NULL; 
 
   //if(Shift == 0) 
      //ShiftType = LSL; 
 
   if(ShiftType == LSL && Shift < 0){ 
      ShiftType = LSR; 
      Shift = -Shift; 
   } 
   if((ShiftType == LSR || ShiftType == ASR) && Shift < 0){ 
      ShiftType = LSL; 
      Shift = -Shift; 
   } 
   if(ShiftType == ROR && Shift < 0) 
      Shift = Shift & 31; 
 
   assert(Shift >= 0 && Shift < 32); 
   if(code >= 0 && code < 16){ 
      if (code == CMP || code == TST || code == CMN || code == TEQ)  
         next_set = 1; 
 
      p = InstCreate32((next_cond << 28) | (code << 21) | ((next_set?1:0)<<20) | 
         ((op_1==NONE ? r0 : op_1) << 16) | ((Dest==NONE ? r0 : Dest) << 12) | (Shift << 7) | (ShiftType << 5) | (Op2), 
         Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); 
   } 
   if (Shift == 0){ 
      if (code == MUL && Dest != op_1){ 
         p = InstCreate32((next_cond << 28) | ((next_set?1:0)<<20) | 
            (Dest << 16) | (Op2 << 8) | 0x90 | (op_1), 
            Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); 
      } 
      if (code >= QADD && code <= QDSUB){ 
         p = InstCreate32((next_cond << 28) |  
            (Dest << 12) | (op_1) | (Op2 << 16) | (0x5 << 4) | (1<<24) | ((code-QADD)<<21), 
            Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); 
      } 
   } 
 
   IPLD(&code, &Dest); 
 
   if (code == LDR || code == STR ||  
      code == LDR_PRE || code == STR_PRE ||  
      code == LDR_POST|| code == STR_POST || 
      code == LDR_PRESUB || code == STR_PRESUB ||  
      code == LDR_POSTSUB || code == STR_POSTSUB) 
   { 
      bool pre = (code != LDR_POST) && (code != STR_POST) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); 
      bool pre_write = (code == LDR_PRE) || (code == STR_PRE) || (code == LDR_PRESUB) || (code == STR_PRESUB); 
      bool load = (code == LDR) || (code == LDR_PRE) || (code == LDR_POST) || (code == LDR_PRESUB) || (code == LDR_POSTSUB); 
      bool un_signed = (code != LDR_PRESUB) && (code != STR_PRESUB) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); 
 
      if(next_half || next_sign){ 
         if(Shift==0 && (next_half || next_byte)){ 
            p = InstCreate32((next_cond << 28) |  
               ((pre ? 1 : 0)<<24) | (un_signed<<23) |  
               ((pre_write ? 1 : 0)<<21) | (load<<20) | (next_sign << 6) | (next_half << 5) | 
               (op_1 << 16) | (Dest << 12) | (9 << 4) | Op2, 
               NONE, op_1, Op2, (next_cond != AL)?1:0, 0); 
         } 
      }else{ 
         p = InstCreate32((next_cond << 28) | (3 << 25) | 
            ((pre ? 1 : 0)<<24) | (un_signed<<23) | (next_byte<<22) | 
            ((pre_write ? 1 : 0)<<21) | (load<<20) | 
            (op_1 << 16) | (Dest << 12) | (Shift << 7) | (ShiftType << 5) | Op2, 
            NONE, op_1, Op2, (next_cond != AL)?1:0, 0); 
      } 
      if(p){ 
         if(load) 
            p->write_regs |= 1 << Dest; 
         else 
            p->read_regs |= 1 << Dest; 
         if(!pre || pre_write) 
            p->write_regs |= 1 << op_1; 
      } 
   } 
   InstPost(p); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::I4(int code, byte Dest, byte op_1, byte Op2, byte Op3){ 
 
   S_instruction *p = NULL; 
   if (code == MLA){ 
      p = InstCreate32((next_cond << 28) | (1 << 21) | ((next_set?1:0)<<20) | 
         (Dest << 16) | (Op3 << 12) | (Op2 << 8) | 0x90 | (op_1), 
         Dest, op_1, Op2, (next_cond != AL)?1:0, next_set?1:0); 
 
      p->read_regs |= 1 << Op3; 
   } 
   InstPost(p); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::MulC(E_REGISTER dst, E_REGISTER src, int constant){ 
 
   if(dst == src){ 
      assert(0); 
      InstPost(NULL); 
   } 
   switch(constant){ 
   case  0: Mov(dst, 0); break; 
   case  1: Mov(dst, src); break; 
   case  2: Mov(dst, src, LSL, 1); break; 
   case  3: Add(dst, src, src, LSL, 1); break; 
   case  4: Mov(dst, src, LSL, 2); break; 
   case  5: Add(dst, src, src, LSL, 2); break; 
   case  6: Mov(dst, src, LSL, 1); Add(dst, dst, dst, LSL, 1); break; //2*3 
   case  7: Rsb(dst, src, src, LSL, 3); break; 
   case  8: Mov(dst, src, LSL, 3); break; 
   case  9: Add(dst, src, src, LSL, 3); break; 
   case 10: Mov(dst, src, LSL, 1); Add(dst, dst, dst, LSL, 2); break; //2*5 
   case 11: Rsb(dst, src, src, LSL, 3); Add(dst, dst, src, LSL, 2); break;  //7+4 
   case 12: Add(dst, src, src, LSL, 1); Mov(dst, dst, LSL, 2); break; //3*4 
   case 13: Add(dst, src, src, LSL, 3); Add(dst, dst, src, LSL, 2); break;  //9+4 
   case 14: Rsb(dst, src, src, LSL, 3); Add(dst, dst, dst); break;  //7*2 
   case 15: Rsb(dst, src, src, LSL, 4); break; 
   case 16: Mov(dst, src, LSL, 4); break; 
   case 17: Add(dst, src, src, LSL, 4); break; 
   default: Mov(dst, constant); Mul(dst, src, dst); break; 
   } 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::IConst(byte Dest, int constant){ 
 
   S_instruction *p = NULL; 
   int Shift,code; 
 
   if(constant < 0){ 
      code = MVN; 
      constant = -constant-1; 
   }else 
      code = MOV; 
 
   constant = (constant << 8) | ((constant >> 24) & 255); 
   for(Shift=8;Shift<=32;Shift+=2){ 
      if(constant & 0xC0) 
         break; 
      constant = (constant << 2) | ((constant >> 30) & 3); 
   } 
   Shift &= 31; 
   constant &= 255; 
 
   p = InstCreate32((next_cond << 28) | (1<<25) | (code << 21) | ((next_set?1:0)<<20) | 
      (Dest << 12) | (Shift << 7) | constant, Dest, NONE, NONE, (next_cond != AL)?1:0, next_set?1:0); 
 
   InstPost(p); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::I2(int code, byte Dest, byte op_1){ 
   if (MODE(code) == 1){ 
      S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 16) | ((op_1 & 15) << 12), 
            Dest, op_1, NONE, (next_cond != AL)?1:0, 0); 
      InstPost(p); 
   } 
   else 
   if (MODE(code) == 6){ 
      S_instruction *p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16), 
            Dest, op_1, NONE, (next_cond != AL)?1:0, 0); 
      InstPost(p); 
   }else 
      I2C(code,Dest,op_1,0); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::I2C(int code, byte Dest, byte op_1, int constant){ 
 
   S_instruction *p = NULL; 
 
   if(MODE(code) == 2 && constant>=0 && constant<8){ 
      p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 16) | ((op_1 & 15) << 12) | (constant << 0), 
            Dest, op_1, NONE, (next_cond != AL)?1:0, 0); 
   } 
 
   if(MODE(code) == 9 && constant>=0 && constant<256){ 
      p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | ((constant & 15) << 0) | ((constant & 0xF0) << 16), 
            Dest, op_1, NONE, (next_cond != AL)?1:0, 0); 
   } 
 
   if(MODE(code) == 15){ 
      if(constant<0){ 
         code ^= (1<<23); 
         constant = -constant; 
      } 
      if(code & 256){ // dword or qword 
         if(constant & 3) 
            constant = -1; 
         else 
            constant >>= 2; 
      } 
      if(constant>=0 && constant<256){ 
         p = InstCreate32((next_cond << 28) | (code & MODEMASK) | ((Dest & 15) << 12) | ((op_1 & 15) << 16) | (constant << 0), 
               NONE, op_1, NONE, (next_cond != AL)?1:0, 0); 
 
         if(code & (1<<20)) 
            p->write_regs |= 1 << Dest; 
         else 
            p->read_regs |= 1 << Dest; 
 
         if(!(code & (1<<24)) || (code & (1<<21))) 
            p->write_regs |= 1 << op_1; 
      } 
   } 
 
   if(code >= 0 && code < 16){ 
      if(code==MOV && constant<0){ 
         code = MVN; 
         constant = -constant-1; 
      }else 
      if(code==ADD && constant<0){ 
         code = SUB; 
         constant = -constant; 
      } 
      else 
      if(code==SUB && constant<0){ 
         code = ADD; 
         constant = -constant; 
      } 
 
      if(code == CMP || code == TST || code == CMN || code == TEQ)  
         next_set = 1; 
 
      int shift; 
      for(shift = 0; shift<32; shift+=2){ 
         if(constant>=0 && constant<=255) 
            break; 
         constant = (constant << 2) | ((constant >> 30) & 3); 
      } 
      if(constant >= 0 && constant <= 255){ 
         p = InstCreate32((next_cond << 28) | (1<<25) | (code << 21) | ((next_set?1:0)<<20) | 
            ((op_1==NONE ? r0 : op_1) << 16) | ((Dest==NONE ? r0 : Dest) << 12) | (shift << 7) | constant, 
            Dest, op_1, NONE, (next_cond != AL)?1:0, next_set?1:0); 
      } 
   } 
    
   IPLD(&code,&Dest); 
 
   if(code == LDR || code == STR ||  
      code == LDR_PRE || code == STR_PRE ||  
      code == LDR_POST|| code == STR_POST || 
      code == LDR_PRESUB || code == STR_PRESUB ||  
      code == LDR_POSTSUB || code == STR_POSTSUB){ 
 
      bool pre = (code != LDR_POST) && (code != STR_POST) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); 
      bool pre_write = (code == LDR_PRE) || (code == STR_PRE) || (code == LDR_PRESUB) || (code == STR_PRESUB); 
      bool load = (code == LDR) || (code == LDR_PRE) || (code == LDR_POST) || (code == LDR_PRESUB) || (code == LDR_POSTSUB); 
      bool un_signed = (code != LDR_PRESUB) && (code != STR_PRESUB) && (code != LDR_POSTSUB) && (code != STR_POSTSUB); 
 
      if(constant == 0){ 
         pre = true; 
         pre_write = false; 
      } 
      if(constant < 0){ 
         constant = -constant; 
         un_signed = !un_signed; 
      } 
 
      if(next_half || next_sign){ 
         if (constant >= 0 && constant < 256 && (next_half || next_byte)) 
            p = InstCreate32((next_cond << 28) |  
               ((pre ? 1 : 0)<<24) | (un_signed<<23) | (1 << 22) | 
               ((pre_write ? 1 : 0)<<21) | (load<<20) | (next_sign << 6) | (next_half << 5) | 
               (op_1 << 16) | (Dest << 12) | ((constant >> 4) << 8) | (9 << 4) | (constant & 15), 
               NONE, op_1, NONE, (next_cond != AL)?1:0, 0); 
      }else 
      if(constant >= 0 && constant < 4096){ 
         p = InstCreate32((next_cond << 28) | (1 << 26) | 
            ((pre ? 1 : 0)<<24) | (un_signed<<23) | (next_byte<<22) | 
            ((pre_write ? 1 : 0)<<21) | (load<<20) | 
            (op_1 << 16) | (Dest << 12) | constant, 
            NONE, op_1, NONE, (next_cond != AL)?1:0, 0); 
      } 
      if(p){ 
         if(load) 
            p->write_regs |= 1 << Dest; 
         else 
            p->read_regs |= 1 << Dest; 
         if(!pre || pre_write) 
            p->write_regs |= 1 << op_1; 
      } 
   } 
   InstPost(p); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::I1P(int code, byte Dest, void *block, int Ofs){ 
 
   S_instruction *p = NULL; 
 
   if(MODE(code)==15){ 
      p = InstCreate32((next_cond << 28) | (code & MODEMASK) | (pc << 16) | ((Dest & 15) << 12), Dest, pc, NONE, (next_cond != AL)?1:0, 0); 
 
      p->tag = Ofs; 
      p->realloc = (S_instruction*)block; 
   } 
 
   if(code == LDR || code == STR){ 
      int load = (code == LDR); 
 
      p = InstCreate32((next_cond << 28) | (1 << 26) | (1<<24) | (next_byte<<22) | (load<<20) | (pc << 16) | (Dest << 12), 
         Dest, pc, NONE, (next_cond != AL)?1:0, 0); 
 
      p->tag = Ofs; 
      p->realloc = (S_instruction*)block; 
   }else 
   if(code == MOV){ // ADD|SUB,Dst,R15,Ofs 
      p = InstCreate32((next_cond << 28) | (1<<25) | (pc << 16) | (Dest << 12), Dest, pc, NONE, (next_cond != AL)?1:0, 0); 
 
      p->tag = Ofs; 
      p->realloc = (S_instruction*)block; 
   } 
   InstPost(p); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::I0P(int code, int Cond, void *target){ 
 
   S_instruction *p = NULL; 
   if(code == B || code == BL){ 
      p = InstCreate32((Cond << 28) | (5 << 25) | ((code == BL?1:0)<<24), pc, NONE, NONE, (Cond != AL)?1:0, 0); 
       
      if(code == BL) 
         p->write_regs |= 1 << lr; 
      p->realloc = (S_instruction*)target; 
      p->branch = true; 
   } 
   InstPost(p); 
} 
 
//---------------------------- 
 
void C_dyn_code_imp::CodeBuild(){ 
 
                              //determine code size 
   int code_size = 0; 
   int num_functions = 0; 
   for(S_instruction *p=inst_begin; p; p=p->next){ 
      code_size += InstructionSize(p, code_size); 
      if(p->is_function) 
         ++num_functions; 
   } 
   dynamic_code.functions.Resize(num_functions); 
                              //allocate code 
   //if(code_size > dynamic_code.allocated){ 
      dynamic_code.Free(); 
      dynamic_code.alloc_size = code_size; 
      if(max_align) 
         dynamic_code.alloc_size += max_align-1; 
      dynamic_code.alloc_base = (byte*)CodeAlloc(dynamic_code.alloc_size); 
      if(!dynamic_code.alloc_base) 
         return; 
      dynamic_code.code = dynamic_code.alloc_base; 
      if(max_align) 
         dynamic_code.code = (byte*)((dword(dynamic_code.alloc_base)+max_align-1) & -max_align); 
   //} 
   //dynamic_code.size = code_size; 
   //if(dynamic_code.code) 
   { 
      int fnc_index = 0; 
      CodeLock(dynamic_code.alloc_base, dynamic_code.alloc_size); 
 
      byte *addr = dynamic_code.code; 
      S_instruction *p; 
      for(p=inst_begin; p; p=p->next){ 
         p->address = addr; 
         if(p->is_function) 
            dynamic_code.functions[fnc_index++] = addr; 
         addr += InstructionSize(p, addr - dynamic_code.code); 
      } 
      for(p=inst_begin; p; p=p->next){ 
         if(p->realloc && (!p->realloc->address || !InstReAlloc(p, p->realloc))){ 
            //dynamic_code.size = 0; 
            assert(0); 
            break; 
         } 
         if(p->code_large) 
            MemCpy(p->address, p->code_large, p->code_size); 
         else 
         if(p->code_size>0){ 
            if(p->code_size == sizeof(dword)) 
               *(dword*)p->address = p->code_small; 
            else{ 
               assert(0); 
            } 
         } 
      } 
      CodeUnlock(dynamic_code.alloc_base, dynamic_code.alloc_size); 
   }//else 
      //dynamic_code.size = 0; 
   FreeInstructions(); 
} 
 
//---------------------------- 
 
C_dyn_code *C_dyn_code::Create(){ 
   return new(true) C_dyn_code_imp; 
} 
 
//----------------------------