gps/GPSResources/tcpmp/common/dyncode/dyncode_mips.c

390 lines
11 KiB
C
Executable File

/*****************************************************************************
*
* 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
*
* $Id: dyncode_mips.c 585 2006-01-16 09:48:55Z picard $
*
* The Core Pocket Media Player
* Copyright (c) 2004-2005 Gabor Kovacs
*
****************************************************************************/
#include "../common.h"
#include "dyncode.h"
#if defined(MIPS) && defined(CONFIG_DYNCODE)
//format coded in 'code' at 8bit position
//00: rs,rt,offset(s16<<2) (branch)
//01: rs,rt,rd
//02: rs,rt,immd(s16) write rt
//03: rs,offset(s16<<2)
//04: rs,rt ->lo,hi
//05: rt,rd,sa
//06: rt,rs,rd
//07: addr(s26<<2)
//08: rs,rt (branch)
//09: rs (branch)
//0A: rs,immd(s16)
//0B: rd <-> lo,hi
//0C: rs,rt,immd(s16) read rt
#define LO 1
#define HI 2
static const reg SaveRegs[11] =
{
R16,R17,R18,R19,R20,R21,R22,R23,
R30,R28,R31
};
void InstInit()
{
}
static INLINE int Format(int i) { return (i >> 8) & 15; }
static INLINE int C(int i) { return i & ~0xFF00; }
void I3(int Code, reg Dest, reg Op1, reg Op2)
{
dyninst* p = NULL;
if (Format(Code)==1)
p = InstCreate32(C(Code) | (Dest << 11) | (Op1 << 21) | (Op2 << 16),Dest,Op1,Op2,0,0);
if (Format(Code)==6)
p = InstCreate32(C(Code) | (Dest << 11) | (Op2 << 21) | (Op1 << 16),Dest,Op1,Op2,0,0);
InstPost(p);
}
void I2C(int Code, reg Dest, reg Op1, int Const)
{
dyninst* p = NULL;
if (Code == DSLL && Const < 0)
{
Code = DSRL;
Const = -Const;
}
if (Code == DSRL && Const < 0)
{
Code = DSLL;
Const = -Const;
}
if (Code == SLL && Const < 0)
{
Code = SRL;
Const = -Const;
}
if (Code == SRL && Const < 0)
{
Code = SLL;
Const = -Const;
}
if (Code == SRA && Const < 0)
{
Code = SLL;
Const = -Const;
}
if (Code == DSLL && Const >= 32)
{
Code = DSLL32;
Const -= 32;
}
if (Code == DSRA && Const >= 32)
{
Code = DSRA32;
Const -= 32;
}
if (Code == DSRL && Const >= 32)
{
Code = DSRL32;
Const -= 32;
}
assert(Format(Code)!=4 || Const==0);
if (Format(Code)==4 && Const == 0)
{
p = InstCreate32(C(Code) | (Dest << 21) | (Op1 << 16),NONE,Dest,Op1,0,LO|HI);
}
assert(Format(Code)!=8 || Const==0);
if (Format(Code)==8 && Const == 0)
{
p = InstCreate32(C(Code) | (Dest << 11) | (Op1 << 21),Dest,Op1,NONE,0,0);
if (p)
p->Branch = 1;
}
assert(Format(Code)!=5 || (Const >= 0 && Const < 32));
if (Format(Code)==5 && Const >= 0 && Const < 32)
{
p = InstCreate32(C(Code) | (Dest << 11) | (Op1 << 16) | (Const << 6),Dest,Op1,NONE,0,0);
}
if ((Code == ANDI || Code == ORI || Code == XORI) && Const >= 32768)
Const -= 65536;
assert(Format(Code)!=2 || (Const >= -32768 && Const < 32768));
if (Format(Code)==2 && Const >= -32768 && Const < 32768)
{
p = InstCreate32(C(Code) | (Dest << 16) | (Op1 << 21) | (Const & 0xFFFF),Dest,Op1,NONE,0,0);
}
assert(Format(Code)!=12 || (Const >= -32768 && Const < 32768));
if (Format(Code)==12 && Const >= -32768 && Const < 32768)
{
p = InstCreate32(C(Code) | (Dest << 16) | (Op1 << 21) | (Const & 0xFFFF),NONE,Op1,Dest,0,0);
}
InstPost(p);
}
void I2(int Code, reg Rm, reg Rn)
{
I2C(Code,Rm,Rn,0);
}
void I2P(int Code, reg Op1, reg Op2, dyninst* Block)
{
dyninst* p = NULL;
if (Format(Code)==0)
{
p = InstCreate32(C(Code) | (Op2 << 16) | (Op1 << 21),NONE,Op1,Op2,0,0);
if (p)
{
p->Tag = Format(Code);
p->ReAlloc = Block;
p->Branch = 1;
}
}
InstPost(p);
}
void I1C(int Code, reg Reg, int Const)
{
dyninst* p = NULL;
if (Format(Code)==10 && Const >= -32768 && Const < 32768)
{
p = InstCreate32(C(Code) | (Reg << 16) | (Const & 0xFFFF),Reg,NONE,NONE,0,0);
}
if (Format(Code)==11 && Const==0)
{
if (Code == MFHI) p = InstCreate32(C(Code) | (Reg << 11),Reg,NONE,NONE,HI,0);
if (Code == MFLO) p = InstCreate32(C(Code) | (Reg << 11),Reg,NONE,NONE,LO,0);
if (Code == MTHI) p = InstCreate32(C(Code) | (Reg << 21),NONE,Reg,NONE,0,HI);
if (Code == MTLO) p = InstCreate32(C(Code) | (Reg << 21),NONE,Reg,NONE,0,LO);
}
if (Format(Code)==9 && Const==0)
{
p = InstCreate32(C(Code) | (Reg << 21),NONE,Reg,NONE,0,0);
if (p)
p->Branch = 1;
}
InstPost(p);
}
void I1(int Code, reg Rn)
{
I1C(Code,Rn,0);
}
void I1P(int Code, reg Reg, dyninst* Block, int Ofs)
{
dyninst* p = NULL;
if (Format(Code)==3)
{
p = InstCreate32(C(Code) | (Reg << 21),NONE,Reg,NONE,0,0);
if (p)
{
p->Tag = Format(Code);
p->ReAlloc = Block;
}
}
InstPost(p);
}
bool_t InstReAlloc(dyninst* p,dyninst* ReAlloc)
{
int Diff = ReAlloc->Address - (p->Address+4);
int* Code = (int*) InstCode(p);
if (p->CodeSize > 4)
{
// address table
int i;
for (i=0;i<p->CodeSize;i+=4,++Code)
*Code += (int)ReAlloc->Address;
return 1;
}
Diff >>= 2;
assert(Diff <= 32767 && Diff >= -32768);
if (Diff > 32767 || Diff < -32768)
{
DEBUG_MSG1(-1,T("Realloc failed %d"),Diff);
return 0;
}
assert(p->Tag==0 || p->Tag==3);
if (p->Tag == 0)
{
*Code &= ~0xFFFF;
*Code |= (uint16_t)Diff;
return 1;
}
else
if (p->Tag == 3)
{
*Code &= ~0xFFFF;
*Code |= (uint16_t)Diff;
return 1;
}
DEBUG_MSG(-1,T("Realloc failed unknown tag"));
return 0;
}
void CodeBegin(int Save,int Local,bool_t Align64)
{
int i;
assert(Save <= 11);
if (Align64)
{
I3(OR,R2,SP,SP);
I2C(ADDIU,SP,SP,-8);
I2C(ANDI,R8,SP,4);
I3(ADDU,SP,SP,R8);
I2C(SW,R8,SP,0);
}
if (Save || Local)
{
I2C(ADDIU,SP,SP,-Save*4-Local);
for (i=0;i<Save;++i)
I2C(SW,SaveRegs[i],SP,i*4+Local);
}
}
void CodeEnd(int Save,int Local,bool_t Align64)
{
if (Save || Local)
{
int i;
assert(Save <= 11);
for (i=Save-1;i>=0;--i)
I2C(LW,SaveRegs[i],SP,i*4+Local);
I2C(ADDIU,SP,SP,Save*4+Local);
}
if (Align64)
{
I2C(LW,R8,SP,0);
I3(SUBU,SP,SP,R8);
I2C(ADDIU,SP,SP,8);
}
DS(); I1(JR,RA);
}
void NOP()
{
dyninst* p = InstCreate32(0,NONE,NONE,NONE,0,0);
if (p)
p->Branch = 1;
InstPost(p);
}
void Break()
{
dyninst* p = InstCreate32(0x0000000D,NONE,NONE,NONE,0,0);
if (p)
p->Branch = 1;
InstPost(p);
}
void InstPost(dyninst* p)
{
context* c = Context();
InstAdd(p,c);
}
void IConst(reg Dst,int Const)
{
I1C(LUI,Dst,Const >> 16);
I2C(ORI,Dst,Dst,(int16_t)Const);
}
reg IMul(reg Op1, int Mul, reg Tmp1, reg Tmp2, reg Tmp3, bool_t* Neg)
{
reg Result = Tmp3;
if (Neg)
*Neg = 0;
if (Mul>=0)
switch (Mul)
{
case 0: Result=ZERO; break;
case 1: Result=Op1; break;
case 2: I3(ADDU,Result,Op1,Op1); break;
case 3: I2C(SLL,Tmp1,Op1,1); I3(ADDU,Result,Tmp1,Op1); break;
case 4: I2C(SLL,Result,Op1,2); break;
case 5: I2C(SLL,Tmp1,Op1,2); I3(ADDU,Result,Tmp1,Op1); break;
case 6: I2C(SLL,Tmp1,Op1,2); I2C(SLL,Tmp2,Op1,1); I3(ADDU,Result,Tmp1,Tmp2); break;
case 7: I2C(SLL,Tmp1,Op1,3); I3(SUBU,Result,Tmp1,Op1); break;
case 8: I2C(SLL,Result,Op1,3); break;
case 9: I2C(SLL,Tmp1,Op1,3); I3(ADDU,Result,Tmp1,Op1); break;
case 10: I2C(SLL,Tmp1,Op1,3); I2C(SLL,Tmp2,Op1,1); I3(ADDU,Result,Tmp1,Tmp2); break;
case 11: I2C(SLL,Tmp1,Op1,3); I2C(SLL,Tmp2,Op1,1); I3(ADDU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); break;
case 12: I2C(SLL,Tmp1,Op1,3); I2C(SLL,Tmp2,Op1,2); I3(ADDU,Result,Tmp1,Tmp2); break;
case 13: I2C(SLL,Tmp1,Op1,3); I2C(SLL,Tmp2,Op1,2); I3(ADDU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); break;
case 14: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,1); I3(SUBU,Result,Tmp1,Tmp2); break;
case 15: I2C(SLL,Tmp1,Op1,4); I3(SUBU,Result,Tmp1,Op1); break;
case 16: I2C(SLL,Result,Op1,4); break;
case 17: I2C(SLL,Tmp1,Op1,4); I3(ADDU,Result,Tmp1,Op1); break;
case 18: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,1); I3(ADDU,Result,Tmp1,Tmp2); break;
case 19: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,1); I3(ADDU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); break;
case 20: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,2); I3(ADDU,Result,Tmp1,Tmp2); break;
case 21: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,2); I3(ADDU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); break;
case 22: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,2); I3(ADDU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); I3(ADDU,Result,Result,Op1); break;
case 23: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,3); I3(ADDU,Result,Tmp1,Tmp2); I3(SUBU,Result,Result,Op1); break;
case 24: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,3); I3(ADDU,Result,Tmp1,Tmp2); break;
case 25: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,3); I3(ADDU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); break;
case 26: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,3); I3(ADDU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); I3(ADDU,Result,Result,Op1); break;
case 27: I2C(SLL,Tmp1,Op1,5); I2C(SLL,Tmp2,Op1,2); I3(SUBU,Result,Tmp1,Tmp2); I3(SUBU,Result,Result,Op1); break;
case 28: I2C(SLL,Tmp1,Op1,5); I2C(SLL,Tmp2,Op1,2); I3(SUBU,Result,Tmp1,Tmp2); break;
case 29: I2C(SLL,Tmp1,Op1,5); I2C(SLL,Tmp2,Op1,2); I3(SUBU,Result,Tmp1,Tmp2); I3(ADDU,Result,Result,Op1); break;
case 30: I2C(SLL,Tmp1,Op1,5); I2C(SLL,Tmp2,Op1,1); I3(SUBU,Result,Tmp1,Tmp2); break;
case 31: I2C(SLL,Tmp1,Op1,5); I3(SUBU,Result,Tmp1,Op1); break;
default: I2C(SLL,Result,Op1,5); break;
}
else
switch (Mul)
{
case -1: I3(SUBU,Result,ZERO,Op1); break;
case -3: I2C(SLL,Tmp1,Op1,2); I3(SUBU,Result,Op1,Tmp1); break;
case -6: I2C(SLL,Tmp1,Op1,1); I2C(SLL,Tmp2,Op1,3); I3(SUBU,Result,Tmp1,Tmp2); break;
case -7: I2C(SLL,Tmp1,Op1,3); I3(SUBU,Result,Op1,Tmp1); break;
case -11: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,2); I3(ADDU,Tmp2,Tmp2,Op1); I3(SUBU,Result,Tmp2,Tmp1); break;
case -12: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,2); I3(SUBU,Result,Tmp2,Tmp1); break;
case -13: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,1); I3(ADDU,Tmp2,Tmp2,Op1); I3(SUBU,Result,Tmp2,Tmp1); break;
case -14: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,1); I3(SUBU,Result,Tmp2,Tmp1); break;
case -15: I2C(SLL,Tmp1,Op1,4); I3(SUBU,Result,Op1,Tmp1); break;
case -19: I2C(SLL,Tmp1,Op1,4); I2C(SLL,Tmp2,Op1,2); I3(SUBU,Result,Op1,Tmp1); I3(SUBU,Result,Result,Tmp2); break;
default:
Result = IMul(Op1,-Mul,Tmp1,Tmp2,Tmp3,NULL);
if (Neg)
*Neg = 1;
else
I3(SUBU,Result,ZERO,Result);
break;
}
return Result;
}
#endif