mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Added MIPS assembler
This commit is contained in:
parent
1f9991dbec
commit
0a78a2d160
@ -937,6 +937,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/MIPS/MIPSVFPUUtils.h
|
||||
Core/MIPS/MIPSAsmTables.cpp
|
||||
Core/MIPS/MIPSAsmTables.h
|
||||
Core/MIPS/MIPSAsm.cpp
|
||||
Core/MIPS/MIPSAsm.h
|
||||
Core/MemMap.cpp
|
||||
Core/MemMap.h
|
||||
Core/MemMapFunctions.cpp
|
||||
|
@ -311,6 +311,7 @@
|
||||
<ClCompile Include="MIPS\JitCommon\JitCommon.cpp" />
|
||||
<ClCompile Include="Mips\MIPS.cpp" />
|
||||
<ClCompile Include="Mips\MIPSAnalyst.cpp" />
|
||||
<ClCompile Include="MIPS\MIPSAsm.cpp" />
|
||||
<ClCompile Include="MIPS\MIPSAsmTables.cpp" />
|
||||
<ClCompile Include="Mips\MIPSCodeUtils.cpp" />
|
||||
<ClCompile Include="MIPS\MIPSDebugInterface.cpp" />
|
||||
@ -464,6 +465,7 @@
|
||||
<ClInclude Include="MIPS\JitCommon\JitCommon.h" />
|
||||
<ClInclude Include="Mips\MIPS.h" />
|
||||
<ClInclude Include="Mips\MIPSAnalyst.h" />
|
||||
<ClInclude Include="MIPS\MIPSAsm.h" />
|
||||
<ClInclude Include="MIPS\MIPSAsmTables.h" />
|
||||
<ClInclude Include="Mips\MIPSCodeUtils.h" />
|
||||
<ClInclude Include="MIPS\MIPSDebugInterface.h" />
|
||||
|
@ -445,6 +445,9 @@
|
||||
<ClCompile Include="MIPS\MIPSAsmTables.cpp">
|
||||
<Filter>MIPS</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MIPS\MIPSAsm.cpp">
|
||||
<Filter>MIPS</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
@ -825,6 +828,9 @@
|
||||
<ClInclude Include="MIPS\MIPSAsmTables.h">
|
||||
<Filter>MIPS</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MIPS\MIPSAsm.h">
|
||||
<Filter>MIPS</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
|
408
Core/MIPS/MIPSAsm.cpp
Normal file
408
Core/MIPS/MIPSAsm.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
#include "stdafx.h"
|
||||
#include "MIPSAsm.h"
|
||||
|
||||
namespace MIPSAsm
|
||||
{
|
||||
|
||||
void SplitLine(const char* Line, char* Name, char* Arguments)
|
||||
{
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
while (*Line != ' ')
|
||||
{
|
||||
if (*Line == 0)
|
||||
{
|
||||
*Name = 0;
|
||||
*Arguments = 0;
|
||||
return;
|
||||
}
|
||||
*Name++ = *Line++;
|
||||
}
|
||||
*Name = 0;
|
||||
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
|
||||
while (*Line != 0)
|
||||
{
|
||||
*Arguments++ = *Line++;
|
||||
}
|
||||
*Arguments = 0;
|
||||
}
|
||||
|
||||
bool MipsAssembleOpcode(std::string& line, DebugInterface* cpu, u32 address, u32& dest)
|
||||
{
|
||||
char name[64],args[256];
|
||||
SplitLine(line.c_str(),name,args);
|
||||
|
||||
CMipsInstruction Opcode(cpu);
|
||||
if (cpu == NULL || Opcode.Load(name,args,(int)address) == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (Opcode.Validate() == false)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Opcode.Encode();
|
||||
dest = Opcode.getEncoding();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int MipsGetRegister(char* source, int& RetLen)
|
||||
{
|
||||
for (int z = 0; MipsRegister[z].name != NULL; z++)
|
||||
{
|
||||
int len = MipsRegister[z].len;
|
||||
if (strncmp(MipsRegister[z].name,source,len) == 0) // erstmal in ordnung
|
||||
{
|
||||
if (source[len] == ',' || source[len] == '\n' || source[len] == 0
|
||||
|| source[len] == ')' || source[len] == '(' || source[len] == '-') // eins hiervon MUSS nach nem register kommen
|
||||
{
|
||||
RetLen = len;
|
||||
return MipsRegister[z].num;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int MipsGetFloatRegister(char* source, int& RetLen)
|
||||
{
|
||||
for (int z = 0; MipsFloatRegister[z].name != NULL; z++)
|
||||
{
|
||||
int len = MipsFloatRegister[z].len;
|
||||
if (strncmp(MipsFloatRegister[z].name,source,len) == 0) // erstmal in ordnung
|
||||
{
|
||||
if (source[len] == ',' || source[len] == '\n' || source[len] == 0
|
||||
|| source[len] == ')' || source[len] == '(' || source[len] == '-') // eins hiervon MUSS nach nem register kommen
|
||||
{
|
||||
RetLen = len;
|
||||
return MipsFloatRegister[z].num;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool MipsCheckImmediate(char* Source, char* Dest, int& RetLen)
|
||||
{
|
||||
int BufferPos = 0;
|
||||
int l;
|
||||
|
||||
if (MipsGetRegister(Source,l) != -1) // fehler ende
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int SourceLen = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (*Source == '\'' && *(Source+2) == '\'')
|
||||
{
|
||||
Dest[BufferPos++] = *Source++;
|
||||
Dest[BufferPos++] = *Source++;
|
||||
Dest[BufferPos++] = *Source++;
|
||||
SourceLen+=3;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*Source == 0 || *Source == '\n' || *Source == ',')
|
||||
{
|
||||
Dest[BufferPos] = 0;
|
||||
break;
|
||||
}
|
||||
if ( *Source == ' ' || *Source == '\t')
|
||||
{
|
||||
Source++;
|
||||
SourceLen++;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (*Source == '(') // könnte auch durch ne klammer kommen
|
||||
{
|
||||
if (MipsGetRegister(Source+1,l) != -1) // ende
|
||||
{
|
||||
Dest[BufferPos] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Dest[BufferPos++] = *Source++;
|
||||
SourceLen++;
|
||||
}
|
||||
|
||||
if (BufferPos == 0) return false;
|
||||
|
||||
RetLen = SourceLen;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CMipsInstruction::Load(char* Name, char* Params, int RamPos)
|
||||
{
|
||||
bool paramfail = false;
|
||||
NoCheckError = false;
|
||||
this->RamPos = RamPos;
|
||||
|
||||
for (int z = 0; MipsOpcodes[z].name != NULL; z++)
|
||||
{
|
||||
if (strcmp(Name,MipsOpcodes[z].name) == 0)
|
||||
{
|
||||
if (LoadEncoding(MipsOpcodes[z],Params) == true)
|
||||
{
|
||||
Loaded = true;
|
||||
return true;
|
||||
}
|
||||
paramfail = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (NoCheckError == false)
|
||||
{
|
||||
if (paramfail == true)
|
||||
{
|
||||
// PrintError(ERROR_ERROR,"Parameter failure \"%s\"",Params);
|
||||
} else {
|
||||
// PrintError(ERROR_ERROR,"Invalid opcode \"%s\"",Name);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CMipsInstruction::LoadEncoding(const tMipsOpcode& SourceOpcode, char* Line)
|
||||
{
|
||||
char ImmediateBuffer[512];
|
||||
|
||||
int RetLen;
|
||||
bool Immediate = false;
|
||||
|
||||
char* SourceEncoding = SourceOpcode.encoding;
|
||||
char* OriginalLine = Line;
|
||||
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
|
||||
if (!(*SourceEncoding == 0 && *Line == 0))
|
||||
{
|
||||
while (*SourceEncoding != NULL)
|
||||
{
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
if (*Line == 0) return false;
|
||||
|
||||
switch (*SourceEncoding)
|
||||
{
|
||||
case 'T': // float reg
|
||||
if ((Vars.rt = MipsGetFloatRegister(Line,RetLen)) == -1) return false;
|
||||
Line += RetLen;
|
||||
SourceEncoding++;
|
||||
break;
|
||||
case 'D': // float reg
|
||||
if ((Vars.rd = MipsGetFloatRegister(Line,RetLen)) == -1) return false;
|
||||
Line += RetLen;
|
||||
SourceEncoding++;
|
||||
break;
|
||||
case 'S': // float reg
|
||||
if ((Vars.rs = MipsGetFloatRegister(Line,RetLen)) == -1) return false;
|
||||
Line += RetLen;
|
||||
SourceEncoding++;
|
||||
break;
|
||||
case 't':
|
||||
if ((Vars.rt = MipsGetRegister(Line,RetLen)) == -1) return false;
|
||||
Line += RetLen;
|
||||
SourceEncoding++;
|
||||
break;
|
||||
case 'd':
|
||||
if ((Vars.rd = MipsGetRegister(Line,RetLen)) == -1) return false;
|
||||
Line += RetLen;
|
||||
SourceEncoding++;
|
||||
break;
|
||||
case 's':
|
||||
if ((Vars.rs = MipsGetRegister(Line,RetLen)) == -1) return false;
|
||||
Line += RetLen;
|
||||
SourceEncoding++;
|
||||
break;
|
||||
case 'i': // 16 bit immediate
|
||||
case 'I': // 32 bit immediate
|
||||
case 'a': // 5 bit immediate
|
||||
case 'b': // 20 bit immediate
|
||||
if (MipsCheckImmediate(Line,ImmediateBuffer,RetLen) == false) return false;
|
||||
Immediate = true;
|
||||
Line += RetLen;
|
||||
SourceEncoding++;
|
||||
break;
|
||||
case 'r': // forced register
|
||||
if (MipsGetRegister(Line,RetLen) != *(SourceEncoding+1)) return false;
|
||||
Line += RetLen;
|
||||
SourceEncoding += 2;
|
||||
break;
|
||||
default: // alles andere
|
||||
if (*SourceEncoding++ != *Line++) return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (*Line == ' ' || *Line == '\t') Line++;
|
||||
if (*Line != 0) return false; // da ist noch mehr, nicht gut
|
||||
|
||||
// opcode ist ok - jetzt noch alle weiteren flags setzen
|
||||
Opcode = SourceOpcode;
|
||||
|
||||
if (Immediate == true)
|
||||
{
|
||||
u32 imm;
|
||||
PostfixExpression postfix;
|
||||
if (cpu->initExpression(ImmediateBuffer,postfix) == false) return false;
|
||||
if (cpu->parseExpression(postfix,imm) == false) return false;
|
||||
|
||||
Vars.Immediate = (int) imm;
|
||||
if (Opcode.flags & O_I5)
|
||||
{
|
||||
Vars.ImmediateType = MIPS_IMMEDIATE5;
|
||||
} else if (Opcode.flags & O_I16)
|
||||
{
|
||||
Vars.ImmediateType = MIPS_IMMEDIATE16;
|
||||
} else if (Opcode.flags & O_I20)
|
||||
{
|
||||
Vars.ImmediateType = MIPS_IMMEDIATE20;
|
||||
} else if (Opcode.flags & O_I26)
|
||||
{
|
||||
Vars.ImmediateType = MIPS_IMMEDIATE26;
|
||||
}
|
||||
} else {
|
||||
Vars.ImmediateType = MIPS_NOIMMEDIATE;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CMipsInstruction::Validate()
|
||||
{
|
||||
if (RamPos % 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// immediates prüfen
|
||||
if (Vars.ImmediateType != MIPS_NOIMMEDIATE)
|
||||
{
|
||||
Vars.OriginalImmediate = Vars.Immediate;
|
||||
|
||||
if (Opcode.flags & O_IPCA) // absolute value >> 2)
|
||||
{
|
||||
Vars.Immediate = (Vars.Immediate >> 2) & 0x3FFFFFF;
|
||||
} else if (Opcode.flags & O_IPCR) // relativer 16 bit wert
|
||||
{
|
||||
int num = (Vars.Immediate-RamPos-4);
|
||||
|
||||
if (num > 0x20000 || num < (-0x20000))
|
||||
{
|
||||
//QueueError(ERROR_ERROR,"Branch target %08X out of range",Vars.Immediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate = num >> 2;
|
||||
}
|
||||
|
||||
switch (Vars.ImmediateType)
|
||||
{
|
||||
case MIPS_IMMEDIATE5:
|
||||
if (Vars.Immediate > 0x1F)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %02X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
Vars.Immediate &= 0x1F;
|
||||
break;
|
||||
case MIPS_IMMEDIATE16:
|
||||
if (abs(Vars.Immediate) > 0xFFFF)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %04X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate &= 0xFFFF;
|
||||
break;
|
||||
case MIPS_IMMEDIATE20:
|
||||
if (abs(Vars.Immediate) > 0xFFFFF)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %08X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate &= 0xFFFFF;
|
||||
break;
|
||||
case MIPS_IMMEDIATE26:
|
||||
if (abs(Vars.Immediate) > 0x3FFFFFF)
|
||||
{
|
||||
// QueueError(ERROR_ERROR,"Immediate value %08X out of range",Vars.OriginalImmediate);
|
||||
return false;
|
||||
}
|
||||
Vars.Immediate &= 0x3FFFFFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CMipsInstruction::Encode()
|
||||
{
|
||||
encoding = (u32) Opcode.destencoding;
|
||||
|
||||
if (Opcode.flags & O_RS) encoding |= (Vars.rs << 21); // source reg
|
||||
if (Opcode.flags & O_RT) encoding |= (Vars.rt << 16); // target reg
|
||||
if (Opcode.flags & O_RD) encoding |= (Vars.rd << 11); // dest reg
|
||||
if (Opcode.flags & O_RSD) // s = d & s
|
||||
{
|
||||
encoding |= (Vars.rs << 21);
|
||||
encoding |= (Vars.rs << 11);
|
||||
}
|
||||
if (Opcode.flags & O_RST) // s = t & s
|
||||
{
|
||||
encoding |= (Vars.rs << 21);
|
||||
encoding |= (Vars.rs << 16);
|
||||
}
|
||||
if (Opcode.flags & O_RDT) // d = t & d
|
||||
{
|
||||
encoding |= (Vars.rd << 16);
|
||||
encoding |= (Vars.rd << 11);
|
||||
}
|
||||
|
||||
if (Opcode.flags & MO_FRT) encoding |= (Vars.rt << 16); // float target
|
||||
if (Opcode.flags & MO_FRS) encoding |= (Vars.rs << 11); // float source
|
||||
if (Opcode.flags & MO_FRD) encoding |= (Vars.rd << 6); // float target
|
||||
if (Opcode.flags & MO_FRSD) // s = d & s
|
||||
{
|
||||
encoding |= (Vars.rs << 6);
|
||||
encoding |= (Vars.rs << 11);
|
||||
}
|
||||
if (Opcode.flags & MO_FRST) // s = t & s
|
||||
{
|
||||
encoding |= (Vars.rs << 11);
|
||||
encoding |= (Vars.rs << 16);
|
||||
}
|
||||
if (Opcode.flags & MO_FRDT) // d = t & d
|
||||
{
|
||||
encoding |= (Vars.rd << 6);
|
||||
encoding |= (Vars.rd << 16);
|
||||
}
|
||||
|
||||
switch (Vars.ImmediateType)
|
||||
{
|
||||
case MIPS_IMMEDIATE5:
|
||||
encoding |= ((Vars.Immediate & 0x1F) << 6);
|
||||
break;
|
||||
case MIPS_IMMEDIATE16:
|
||||
encoding |= (Vars.Immediate & 0xFFFF);
|
||||
break;
|
||||
case MIPS_IMMEDIATE20:
|
||||
encoding |= (Vars.Immediate & 0xFFFFF) << 6;
|
||||
break;
|
||||
case MIPS_IMMEDIATE26:
|
||||
encoding |= Vars.Immediate & 0x3FFFFFF;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
42
Core/MIPS/MIPSAsm.h
Normal file
42
Core/MIPS/MIPSAsm.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
#include "../../Globals.h"
|
||||
#include "../Debugger/DebugInterface.h"
|
||||
#include "MIPSAsmTables.h"
|
||||
|
||||
namespace MIPSAsm
|
||||
{
|
||||
|
||||
bool MipsAssembleOpcode(std::string& line, DebugInterface* cpu, u32 address, u32& dest);
|
||||
|
||||
typedef enum eMipsImmediateType { MIPS_NOIMMEDIATE, MIPS_IMMEDIATE5,
|
||||
MIPS_IMMEDIATE16, MIPS_IMMEDIATE20, MIPS_IMMEDIATE26 };
|
||||
|
||||
typedef struct {
|
||||
int rs; // source reg
|
||||
int rt; // target reg
|
||||
int rd; // dest reg
|
||||
eMipsImmediateType ImmediateType;
|
||||
int Immediate;
|
||||
int OriginalImmediate;
|
||||
} tMipsOpcodeVariables;
|
||||
|
||||
class CMipsInstruction
|
||||
{
|
||||
public:
|
||||
CMipsInstruction(DebugInterface* cpu):cpu(cpu),Loaded(false) { };
|
||||
bool Load(char* Name, char* Params, int RamPos);
|
||||
bool Validate();
|
||||
void Encode();
|
||||
u32 getEncoding() { return encoding; };
|
||||
private:
|
||||
bool LoadEncoding(const tMipsOpcode& SourceOpcode, char* Line);
|
||||
tMipsOpcode Opcode;
|
||||
bool NoCheckError;
|
||||
bool Loaded;
|
||||
tMipsOpcodeVariables Vars;
|
||||
int RamPos;
|
||||
DebugInterface* cpu;
|
||||
u32 encoding;
|
||||
};
|
||||
|
||||
}
|
@ -76,30 +76,6 @@ const tMipsRegister MipsFloatRegister[] = {
|
||||
{ "f31", 31, 3}, { "$f31", 31, 4 }
|
||||
};
|
||||
|
||||
#define O_RS 0x00000001 // source reg
|
||||
#define O_RT 0x00000002 // target reg
|
||||
#define O_RD 0x00000004 // dest reg
|
||||
#define O_I16 0x00000008 // 16 bit immediate
|
||||
#define O_I20 0x00000010 // 16 bit immediate
|
||||
#define O_IPCA 0x00000020 // pc >> 2
|
||||
#define O_IPCR 0x00000080 // PC, -> difference >> 2
|
||||
#define O_I26 0x00000200 // 26 bit immediate
|
||||
#define O_I5 0x00000400 // 5 bit immediate
|
||||
#define O_RSD 0x00000800 // rs = rd
|
||||
#define O_RST 0x00001000 // rs = rt
|
||||
#define O_RDT 0x00002000 // rd = rt
|
||||
#define MO_DELAY 0x00004000 // delay slot follows
|
||||
#define MO_NODELAY 0x00008000 // can't be in a delay slot
|
||||
#define MO_DELAYRT 0x00010000 // rt won't be available for one instruction
|
||||
#define MO_IGNORERTD 0x00020000 // don't care for rt delay
|
||||
|
||||
#define MO_FRS 0x00040000 // float rs
|
||||
#define MO_FRD 0x00080000 // float rd
|
||||
#define MO_FRT 0x00100000 // float rt
|
||||
#define MO_FRSD 0x00200000 // float rs + rd
|
||||
#define MO_FRST 0x00400000 // float rs + rt
|
||||
#define MO_FRDT 0x00800000 // float rt + rd
|
||||
|
||||
/* Placeholders for encoding
|
||||
|
||||
s source register
|
||||
|
@ -16,6 +16,30 @@ typedef struct {
|
||||
short len;
|
||||
} tMipsRegister;
|
||||
|
||||
#define O_RS 0x00000001 // source reg
|
||||
#define O_RT 0x00000002 // target reg
|
||||
#define O_RD 0x00000004 // dest reg
|
||||
#define O_I16 0x00000008 // 16 bit immediate
|
||||
#define O_I20 0x00000010 // 16 bit immediate
|
||||
#define O_IPCA 0x00000020 // pc >> 2
|
||||
#define O_IPCR 0x00000080 // PC, -> difference >> 2
|
||||
#define O_I26 0x00000200 // 26 bit immediate
|
||||
#define O_I5 0x00000400 // 5 bit immediate
|
||||
#define O_RSD 0x00000800 // rs = rd
|
||||
#define O_RST 0x00001000 // rs = rt
|
||||
#define O_RDT 0x00002000 // rd = rt
|
||||
#define MO_DELAY 0x00004000 // delay slot follows
|
||||
#define MO_NODELAY 0x00008000 // can't be in a delay slot
|
||||
#define MO_DELAYRT 0x00010000 // rt won't be available for one instruction
|
||||
#define MO_IGNORERTD 0x00020000 // don't care for rt delay
|
||||
|
||||
#define MO_FRS 0x00040000 // float rs
|
||||
#define MO_FRD 0x00080000 // float rd
|
||||
#define MO_FRT 0x00100000 // float rt
|
||||
#define MO_FRSD 0x00200000 // float rs + rd
|
||||
#define MO_FRST 0x00400000 // float rs + rt
|
||||
#define MO_FRDT 0x00800000 // float rt + rd
|
||||
|
||||
extern const tMipsRegister MipsRegister[];
|
||||
extern const tMipsRegister MipsFloatRegister[];
|
||||
extern const tMipsOpcode MipsOpcodes[];
|
||||
|
Loading…
Reference in New Issue
Block a user