295 lines
6.2 KiB
C
295 lines
6.2 KiB
C
|
/*****************************************************************************
|
||
|
*
|
||
|
* 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.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"
|
||
|
|
||
|
#ifdef CONFIG_DYNCODE
|
||
|
|
||
|
void MB() { Context()->CodeMoveBack = 1; }
|
||
|
void DS() { Context()->CodeDelaySlot = 1; }
|
||
|
|
||
|
void DynCode_Init()
|
||
|
{
|
||
|
Context()->CodeLock = LockCreate();
|
||
|
}
|
||
|
|
||
|
void DynCode_Done()
|
||
|
{
|
||
|
LockDelete(Context()->CodeLock);
|
||
|
Context()->CodeLock = NULL;
|
||
|
}
|
||
|
|
||
|
static void FreeInst()
|
||
|
{
|
||
|
context* c = Context();
|
||
|
dyninst* p;
|
||
|
for (p=(dyninst*)c->CodeInstBegin;p;)
|
||
|
{
|
||
|
dyninst* q = p;
|
||
|
p = p->Next;
|
||
|
if (q->CodeLarge)
|
||
|
free(q->CodeLarge);
|
||
|
free(q);
|
||
|
}
|
||
|
c->CodeInstBegin = NULL;
|
||
|
c->CodeInstEnd = NULL;
|
||
|
LockLeave(c->CodeLock);
|
||
|
}
|
||
|
|
||
|
static void FreeCode(dyncode* p)
|
||
|
{
|
||
|
if (p->Code)
|
||
|
CodeFree(p->Code,p->Allocated);
|
||
|
p->Allocated = 0;
|
||
|
p->Code = NULL;
|
||
|
}
|
||
|
|
||
|
void CodeInit(dyncode* p)
|
||
|
{
|
||
|
p->Code = NULL;
|
||
|
p->Allocated = p->Size = 0;
|
||
|
}
|
||
|
|
||
|
void CodeDone(dyncode* p)
|
||
|
{
|
||
|
FreeCode(p);
|
||
|
}
|
||
|
|
||
|
void CodeStart(dyncode* p)
|
||
|
{
|
||
|
context* c = Context();
|
||
|
LockEnter(c->CodeLock);
|
||
|
|
||
|
p->Size = 0;
|
||
|
|
||
|
c->CodeFailed = 0;
|
||
|
c->CodeMoveBack = 0;
|
||
|
c->CodeDelaySlot = 0;
|
||
|
|
||
|
InstInit();
|
||
|
}
|
||
|
|
||
|
void CodeBuild(dyncode* Code)
|
||
|
{
|
||
|
dyninst* p;
|
||
|
context* c = Context();
|
||
|
|
||
|
Code->Size = 0;
|
||
|
if (c->CodeFailed)
|
||
|
{
|
||
|
FreeInst();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
for (p=(dyninst*)c->CodeInstBegin;p;p=p->Next)
|
||
|
Code->Size += InstSize(p,Code->Size);
|
||
|
|
||
|
if (Code->Size > Code->Allocated)
|
||
|
{
|
||
|
FreeCode(Code);
|
||
|
Code->Allocated = (Code->Size + 511) & ~511;
|
||
|
Code->Code = (char*) CodeAlloc(Code->Allocated);
|
||
|
}
|
||
|
|
||
|
if (Code->Code)
|
||
|
{
|
||
|
char* Addr;
|
||
|
|
||
|
CodeLock(Code->Code,Code->Allocated);
|
||
|
|
||
|
Addr = Code->Code;
|
||
|
for (p=(dyninst*)c->CodeInstBegin;p;p=p->Next)
|
||
|
{
|
||
|
p->Address = Addr;
|
||
|
Addr += InstSize(p,Addr - Code->Code);
|
||
|
}
|
||
|
|
||
|
for (p=(dyninst*)c->CodeInstBegin;p;p=p->Next)
|
||
|
{
|
||
|
if (p->ReAlloc && (!p->ReAlloc->Address || !InstReAlloc(p,p->ReAlloc)))
|
||
|
{
|
||
|
Code->Size = 0;
|
||
|
assert(Code->Size);
|
||
|
break;
|
||
|
}
|
||
|
if (p->CodeLarge)
|
||
|
memcpy(p->Address,p->CodeLarge,p->CodeSize);
|
||
|
else
|
||
|
if (p->CodeSize>0)
|
||
|
{
|
||
|
if (p->CodeSize == sizeof(int32_t))
|
||
|
*(int32_t*)p->Address = p->CodeSmall;
|
||
|
else
|
||
|
if (p->CodeSize == sizeof(int16_t))
|
||
|
*(int16_t*)p->Address = (int16_t)p->CodeSmall;
|
||
|
else
|
||
|
memcpy(p->Address,&p->CodeSmall,p->CodeSize);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (Code->Code)
|
||
|
CodeUnlock(Code->Code,Code->Allocated);
|
||
|
|
||
|
#ifdef DUMPCODE
|
||
|
if (Code->Code)
|
||
|
{
|
||
|
char Name[64];
|
||
|
FILE* f;
|
||
|
sprintf(Name,"\\code%04x.bin",Code->Size);
|
||
|
f = fopen(Name,"wb+");
|
||
|
fwrite(Code->Code,1,Code->Size,f);
|
||
|
fclose(f);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
else
|
||
|
Code->Size = 0;
|
||
|
|
||
|
FreeInst();
|
||
|
}
|
||
|
|
||
|
dyninst* InstCreate(const void* Code,int CodeSize, reg Wr, reg Rd1, reg Rd2, int RdFlags, int WrFlags)
|
||
|
{
|
||
|
dyninst* p = (dyninst*) malloc(sizeof(dyninst));
|
||
|
if (p)
|
||
|
{
|
||
|
p->Tag = 0;
|
||
|
p->Next = NULL;
|
||
|
p->Prev = NULL;
|
||
|
p->Address = 0;
|
||
|
p->Branch = 0;
|
||
|
p->ReAlloc = NULL;
|
||
|
p->RdFlags = RdFlags;
|
||
|
p->WrFlags = WrFlags;
|
||
|
p->RdRegs = 0;
|
||
|
p->WrRegs = 0;
|
||
|
|
||
|
p->CodeSize = CodeSize;
|
||
|
if (CodeSize <= (int)sizeof(p->CodeSmall))
|
||
|
{
|
||
|
p->CodeLarge = NULL;
|
||
|
if (Code)
|
||
|
p->CodeSmall = *(int*)Code;
|
||
|
else
|
||
|
p->CodeSmall = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p->CodeLarge = (char*) malloc(CodeSize);
|
||
|
if (!p->CodeLarge)
|
||
|
{
|
||
|
free(p);
|
||
|
return NULL;
|
||
|
}
|
||
|
if (Code)
|
||
|
memcpy(p->CodeLarge,Code,CodeSize);
|
||
|
else
|
||
|
memset(p->CodeLarge,0,CodeSize);
|
||
|
}
|
||
|
|
||
|
if (Wr != NONE) { if (Wr<32) p->WrRegs |= 1 << Wr; else p->WrFlags |= 256 << (Wr-32); }
|
||
|
if (Rd1 != NONE) { if (Rd1<32) p->RdRegs |= 1 << Rd1; else p->RdFlags |= 256 << (Rd1-32); }
|
||
|
if (Rd2 != NONE) { if (Rd2<32) p->RdRegs |= 1 << Rd2; else p->RdFlags |= 256 << (Rd2-32); }
|
||
|
}
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
dyninst* InstCreate32(int Code32, reg Wr, reg Rd1, reg Rd2, int RdFlags, int WrFlags)
|
||
|
{
|
||
|
return InstCreate(&Code32,4,Wr,Rd1,Rd2,RdFlags,WrFlags);
|
||
|
}
|
||
|
|
||
|
dyninst* InstCreate16(int Code16, reg Wr, reg Rd1, reg Rd2, int RdFlags, int WrFlags)
|
||
|
{
|
||
|
return InstCreate(&Code16,2,Wr,Rd1,Rd2,RdFlags,WrFlags);
|
||
|
}
|
||
|
|
||
|
void InstAdd(dyninst* New,context* c)
|
||
|
{
|
||
|
assert(New);
|
||
|
|
||
|
if (New)
|
||
|
{
|
||
|
dyninst* p = c->CodeInstEnd; //insert after p
|
||
|
|
||
|
if (c->CodeDelaySlot)
|
||
|
{
|
||
|
assert(p && !p->Branch && !InstReadWrite(p,New) && !InstReadWrite(New,p) && !InstBothWrite(p,New));
|
||
|
p->Branch = 1;
|
||
|
p = p->Prev;
|
||
|
}
|
||
|
|
||
|
if (c->CodeMoveBack)
|
||
|
while (p && !p->Branch && !InstReadWrite(p,New) && !InstReadWrite(New,p) && !InstBothWrite(p,New))
|
||
|
p = p->Prev;
|
||
|
|
||
|
if (p)
|
||
|
{
|
||
|
if (p->Next)
|
||
|
p->Next->Prev = New;
|
||
|
else
|
||
|
c->CodeInstEnd = New;
|
||
|
New->Next = p->Next;
|
||
|
New->Prev = p;
|
||
|
p->Next = New;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (c->CodeInstBegin)
|
||
|
((dyninst*)c->CodeInstBegin)->Prev = New;
|
||
|
else
|
||
|
c->CodeInstEnd = New;
|
||
|
New->Next = (dyninst*)c->CodeInstBegin;
|
||
|
New->Prev = NULL;
|
||
|
c->CodeInstBegin = New;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
c->CodeFailed = 1;
|
||
|
|
||
|
c->CodeMoveBack = 0;
|
||
|
c->CodeDelaySlot = 0;
|
||
|
}
|
||
|
|
||
|
dyninst* Label(bool_t DoPost)
|
||
|
{
|
||
|
dyninst* p = InstCreate(NULL,0,NONE,NONE,NONE,0,0);
|
||
|
if (p) p->Branch = 1;
|
||
|
if (DoPost) InstPost(p);
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
void Align(int i)
|
||
|
{
|
||
|
dyninst* p = InstCreate(NULL,-i,NONE,NONE,NONE,0,0);
|
||
|
if (p) p->Branch = 1;
|
||
|
InstPost(p);
|
||
|
}
|
||
|
|
||
|
#else
|
||
|
void DynCode_Init() {}
|
||
|
void DynCode_Done() {}
|
||
|
#endif
|