Added MIPS assembler

This commit is contained in:
Kingcom 2013-07-28 14:50:25 +02:00
parent 1f9991dbec
commit 0a78a2d160
7 changed files with 484 additions and 24 deletions

View File

@ -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

View File

@ -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" />

View File

@ -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
View 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
View 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;
};
}

View File

@ -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

View File

@ -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[];