用C#实现一个简易的Mips汇编器
用C#实现一个简易的Mips汇编器,咳咳,该汇编器不支持外部文件引入,目前只支持数据段(.data)、代码段(.text),话不多说,我们直接看怎么实现。
另外,本汇编器为本人大二下的MipsCpu实验一部分,实为不易,转载还望标明出处。
Mips31个寄存器
本图为Mars汇编软件截图。
Mips指令入门
图为哈尔滨工业大学(深圳)MipsCpu实现指令截图。
Mips内存安排
代码段首地址从0x00400000开始;
数据段首地址从0x10010000开始;
C#实现
项目结构
Token.cs,定义Mips汇编语言的Token
using System;
using System.Collections.Generic;
using System.Text;
namespace AssembleHelper
{
//变量
public class Var
{
public string Name { get; set; }
public string InitVal { get; set; }
public BaseType Type { get; set; }
public string Addr { get; set; }
}
//标号
public class Label
{
public string Name { get; set; }
public string Address { get; set; }
}
//数据类型
public enum BaseType
{
WORD,
BYTE
}
//Mips Instrcution
public enum Instrcution
{
//RType
add,
addu,
sub,
subu,
and,
or,
xor,
nor,
slt,
sltu,
sll,
srl,
sra,
sllv,
srlv,
srav,
jr,
//IType
addi,
addiu,
andi,
ori,
xori,
sltiu,
lui,
lw,
sw,
beq,
bne,
bgtz,
//JType
j,
jal
}
//寄存器
public enum Register
{
zero,
at,
v0,
v1,
a0,
a1,
a2,
a3,
t0,
t1,
t2,
t3,
t4,
t5,
t6,
t7,
s0,
s1,
s2,
s3,
s4,
s5,
s6,
s7,
t8,
t9,
k0,
k1,
gp,
sp,
fp,
ra
}
}
ConvertHelper.cs,作为进制转换类,帮助我们处理进制转换
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace AssembleHelper
{
public static class ConvertHelper
{
/// <summary>
/// 把十进制、八进制、十六进制数转化为length位的16进制数
/// </summary>
/// <param name="integer">字符型整数</param>
/// <param name="length">Hex位数</param>
/// <returns></returns>
public static string ConvertIntegerToHex(string integer, int length = 8)
{
//补码表示
string hexCode = "";
bool isSigned = integer[0] == '-';
if (isSigned)
{
integer = integer.Substring(1);
}
//16进制
if ((integer.ToLower()).StartsWith("0x"))
{
string binaryCode = "";
string negBinaryCode = "";
string hex = integer.Substring(2);
for (int i = hex.Length - 1; i >= 0; i--)
{
binaryCode = binaryCode.Insert(0, HexToBinary(hex[i]));
}
while (binaryCode.Length <= length * 4 - 1)
{
binaryCode = binaryCode.Insert(0, "0");
}
if (isSigned)
{
negBinaryCode = ReverseBinary(binaryCode);
hex = BinaryToHex(negBinaryCode);
}
else
{
hex = BinaryToHex(binaryCode);
}
hexCode = hex;
}
//8进制 0 1 2 3 4 5 6 7
else if ((integer.ToLower()).Length > 1 && (integer.ToLower()).StartsWith("0"))
{
string binaryCode = "";
string negBinaryCode = "";
string oct = integer.Substring(1);
string hex = "";
for (int i = oct.Length - 1; i >= 0; i--)
{
binaryCode = binaryCode.Insert(0, OctToBinary(oct[i]));
}
while (binaryCode.Length <= length * 4 - 1)
{
binaryCode = binaryCode.Insert(0, "0");
}
if (isSigned)
{
negBinaryCode = ReverseBinary(binaryCode);
hex = BinaryToHex(negBinaryCode);
}
else
{
hex = BinaryToHex(binaryCode);
}
hexCode = hex;
}
//10进制
else
{
string binaryCode = "";
string negBinaryCode = "";
string dec = integer;
string hex = "";
long d = Convert.ToInt64(dec);
//binaryCode = DecToBinary(dec);
binaryCode = Convert.ToString(d, 2);
while (binaryCode.Length <= length * 4 - 1)
{
binaryCode = binaryCode.Insert(0, "0");
}
if (isSigned)
{
negBinaryCode = ReverseBinary(binaryCode);
hex = BinaryToHex(negBinaryCode);
}
else
{
hex = BinaryToHex(binaryCode);
}
hexCode = hex;
}
return hexCode;
}
//补码
public static string ReverseBinary(string binaryCode)
{
List<char> negBinaryCode = binaryCode.ToList();
int index = -1;
string hex = "";
for (int i = negBinaryCode.Count - 1; i >= 0; i--)
{
if (negBinaryCode[i] == '1')
{
index = i;
break;
}
}
for (int i = index - 1; i >= 0; i--)
{
if (binaryCode[i] == '1')
{
negBinaryCode[i] = '0';
}
else
{
negBinaryCode[i] = '1';
}
}
for (int i = negBinaryCode.Count - 1; i >= 0; i--)
{
hex = hex.Insert(0, negBinaryCode[i].ToString());
}
return hex;
}
//16进制Char字符转化为二进制
public static string HexToBinary(char hex)
{
string binary = "";
switch (hex)
{
case '0':
binary = "0000";
break;
case '1':
binary = "0001";
break;
case '2':
binary = "0010";
break;
case '3':
binary = "0011";
break;
case '4':
binary = "0100";
break;
case '5':
binary = "0101";
break;
case '6':
binary = "0110";
break;
case '7':
binary = "0111";
break;
case '8':
binary = "1000";
break;
case '9':
binary = "1001";
break;
case 'a':
binary = "1010";
break;
case 'b':
binary = "1011";
break;
case 'c':
binary = "1100";
break;
case 'd':
binary = "1101";
break;
case 'e':
binary = "1110";
break;
case 'f':
binary = "1111";
break;
case 'A':
binary = "1010";
break;
case 'B':
binary = "1011";
break;
case 'C':
binary = "1100";
break;
case 'D':
binary = "1101";
break;
case 'E':
binary = "1110";
break;
case 'F':
binary = "1111";
break;
default:
break;
}
return binary;
}
//8进制转化为2进制,输入为一个Char
public static string OctToBinary(char oct)
{
string binary = "";
switch (oct)
{
case '0':
binary = "000";
break;
case '1':
binary = "001";
break;
case '2':
binary = "010";
break;
case '3':
binary = "011";
break;
case '4':
binary = "100";
break;
case '5':
binary = "101";
break;
case '6':
binary = "110";
break;
case '7':
binary = "111";
break;
default:
break;
}
return binary;
}
/// <summary>
/// 32位binary2Hex
/// </summary>
/// <param name="binary"></param>
/// <returns></returns>
public static string BinaryToHex(string binary)
{
string hex = "";
int i = binary.Length - 4;
while (i >= 0)
{
switch (binary.Substring(i, 4))
{
case "0000":
hex = hex.Insert(0, "0");
break;
case "0001":
hex = hex.Insert(0, "1");
break;
case "0010":
hex = hex.Insert(0, "2");
break;
case "0011":
hex = hex.Insert(0, "3");
break;
case "0100":
hex = hex.Insert(0, "4");
break;
case "0101":
hex = hex.Insert(0, "5");
break;
case "0110":
hex = hex.Insert(0, "6");
break;
case "0111":
hex = hex.Insert(0, "7");
break;
case "1000":
hex = hex.Insert(0, "8");
break;
case "1001":
hex = hex.Insert(0, "9");
break;
case "1010":
hex = hex.Insert(0, "a");
break;
case "1011":
hex = hex.Insert(0, "b");
break;
case "1100":
hex = hex.Insert(0, "c");
break;
case "1101":
hex = hex.Insert(0, "d");
break;
case "1110":
hex = hex.Insert(0, "e");
break;
case "1111":
hex = hex.Insert(0, "f");
break;
default:
break;
}
i -= 4;
}
return hex;
}
}
}
Scanner.cs,扫描器实现
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
namespace AssembleHelper
{
public class Scanner
{
StreamReader StreamReader;
public string CurrentString;
public string[] OpNums = new string[]{};
public string OpType = "";
public int innerLine = 0; //忽略空格
public int Line = 0; //不忽略空格
public bool IsData = true;
public Scanner(string code, bool isData = true)
{
StreamReader = File.OpenText(code);
IsData = isData;
}
public void ResetLine()
{
innerLine = 0;
Line = 0;
}
public void ScanLine()
{
CurrentString = StreamReader.ReadLine();
if (CurrentString == null)
{
return;
}
//删除空行
CurrentString = CurrentString.Trim();
while (CurrentString.Length == 0)
{
Line++;
CurrentString = StreamReader.ReadLine();
if (CurrentString == null)
{
return;
}
CurrentString = CurrentString.Trim();
}
//删除整行注释
while (CurrentString.Trim().StartsWith('#'))
{
CurrentString = StreamReader.ReadLine();
}
//删除空行
CurrentString = CurrentString.Trim();
while (CurrentString.Length == 0)
{
Line++;
CurrentString = StreamReader.ReadLine();
if (CurrentString == null)
{
return;
}
CurrentString = CurrentString.Trim();
}
//扫描文本
if (!IsData)
{
if (!CurrentString.Contains(":"))
innerLine++; //是标号行数不变
}
//扫描数据
Line++;
//删除一行里面的注释
List<char> currentStringList = CurrentString.ToList();
int firstAnnotation = currentStringList.FindIndex(s => { return s == '#'; });
if (firstAnnotation != -1)
{
CurrentString = CurrentString.Substring(0, firstAnnotation); //删除注释
}
Console.WriteLine(CurrentString + ": " + ConvertHelper.ConvertIntegerToHex((innerLine * 4 | 0x0040000).ToString()));
try
{
int firstSpace = currentStringList.FindIndex(s =>
{
return s == ' ';
});
string opType = CurrentString.Substring(0, firstSpace);
string opNum = CurrentString.Substring(firstSpace).Trim();
//切割
string[] opNums = opNum.Split(",");
for (int i = 0; i < opNums.Length; i++)
{
opNums[i] = opNums[i].Trim();
}
OpNums = opNums;
OpType = opType;
if (!OpNums[1].Contains("$") && ((CurrentString.Contains("sw") || CurrentString.Contains("lw"))))
{
innerLine++; //拆成两行
}
if ((opType.ToLower() == (Instrcution.andi).ToString() || (opType.ToLower() == (Instrcution.addi).ToString()
|| (opType.ToLower() == (Instrcution.addiu).ToString() || (opType.ToLower() == (Instrcution.ori).ToString() ||
(opType.ToLower() == (Instrcution.sltiu).ToString()))))))
{
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[2]);
//immHex > 0xFFFF;
// FFFF0000 <= immHex <= FFFFFFFF
// 00000000 <= immHex <= 0000EFFF
if ((immHex.CompareTo("FFFF0000") >= 0 && (immHex.CompareTo("FFFFFFFF") <= 0) ||
(immHex.CompareTo("00000000") >= 0 && (immHex.CompareTo("0000FFFF") <= 0))))
{
//合法
}
else
{
innerLine += 2; //拆成三行
}
}
}
catch(Exception ex)
{
}
//Console.WriteLine(innerLine);
}
}
}
InsturctionTranslator.cs,指令翻译
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
namespace AssembleHelper
{
public class InstructionTranslator
{
Scanner Scanner;
FileStream DataFileStream; //数据段16进制码
FileStream TextFileStream; //代码段16进制码
FileStream TextSegCodeStream; //代码段代码
Dictionary<string, Var> SymbolTable = new Dictionary<string, Var>();
Dictionary<string, Label> LabelTable = new Dictionary<string, Label>();
const string DataTxt = "G:\\ComputerHardWare\\AssembleHelper\\AssembleHelper\\data.txt";
const string TextTxt = "G:\\ComputerHardWare\\AssembleHelper\\AssembleHelper\\text.txt";
const string TextSegCode = "G:\\ComputerHardWare\\AssembleHelper\\AssembleHelper\\textSeg.txt";
string Buffer = "";
public InstructionTranslator(string code)
{
Scanner = new Scanner(code, true);
DataFileStream = new FileStream(DataTxt, FileMode.Create, FileAccess.Write);//创建写入文件
TextFileStream = new FileStream(TextTxt, FileMode.Create, FileAccess.Write);//创建写入文件
TextSegCodeStream = new FileStream(TextSegCode, FileMode.Create, FileAccess.Write);//创建写入文件
}
public void Translate()
{
Scanner.ScanLine();
Console.WriteLine("---data---");
if (Scanner.CurrentString.Contains(".data"))
{
BuildSymbolTable();
}
Console.WriteLine("---label---");
BuildLabelTable();
Console.WriteLine("---Transdata---");
TranslateData();
Console.WriteLine("---Transtext---");
TranslateText();
}
bool isByte = false;
private void TranslateData()
{
using (StreamWriter sw = new StreamWriter(DataFileStream))
{
int currentAddr = 0;
foreach (KeyValuePair<string, Var> var in SymbolTable)
{
if (isByte == false)
{
if (var.Value.Type == BaseType.BYTE)
{
var.Value.Addr = "0x" + Convert.ToString(currentAddr | 0x10010000, 16);
currentAddr += 1;
if (var.Value.InitVal != null)
Buffer = Buffer.Insert(0, var.Value.InitVal.Substring(var.Value.InitVal.Length - 2, 2));
isByte = true;
}
else
{
var.Value.Addr = "0x" + Convert.ToString(currentAddr | 0x10010000, 16);
currentAddr += 4;
sw.WriteLine(var.Value.InitVal);
}
}
else
{
if (var.Value.Type == BaseType.BYTE)
{
var.Value.Addr = "0x" + Convert.ToString(currentAddr | 0x10010000, 16);
currentAddr += 1;
if (var.Value.InitVal != null)
Buffer = Buffer.Insert(0, var.Value.InitVal.Substring(var.Value.InitVal.Length - 2, 2));
}
else
{
isByte = false;
//在这里先写Buffer的值
if (Buffer != "")
{
string data = "";
while (Buffer.Length % 8 != 0)
{
Buffer = Buffer.Insert(0, "0");
}
int i = Buffer.Length - 8;
while (i >= 0)
{
data = Buffer.Substring(i, 8);
sw.WriteLine(data);
i -= 8;
}
}
var.Value.Addr = "0x" + Convert.ToString(currentAddr | 0x10010000, 16);
currentAddr += 4;
sw.WriteLine(var.Value.InitVal);
Buffer = "";
}
}
}
}
}
private void TranslateText()
{
using (StreamWriter sw = new StreamWriter(TextFileStream))
{
Scanner = new Scanner(TextSegCode, false);
Scanner.ScanLine();
while (true)
{
//string[] instruction = Scanner.CurrentString.Split(",");
/*List<char> currentStringList = Scanner.CurrentString.ToList();
int firstSpace = currentStringList.FindIndex(s =>
{
return s == ' ';
});
string opType = Scanner.CurrentString.Substring(0, firstSpace);
string opNum = Scanner.CurrentString.Substring(firstSpace).Trim();
//切割
string[] opNums = opNum.Split(",");
for (int i = 0; i < opNums.Length; i++)
{
opNums[i] = opNums[i].Trim();
}*/
string opType = Scanner.OpType;
string[] opNums = Scanner.OpNums;
string hexCode = "";
//如果是sw,lw,而且尾巴是Ident的形式
if((opType.ToLower() == (Instrcution.sw).ToString() || opType.ToLower() == (Instrcution.lw).ToString())&&
SymbolTable.ContainsKey(opNums[1]))
{
//lui $1, 0x00001001
sw.WriteLine("3c011001");
opNums[1] = SymbolTable[opNums[1]].Addr + "($1)";
}
else if((opType.ToLower() == (Instrcution.andi).ToString()|| (opType.ToLower() == (Instrcution.addi).ToString()
|| (opType.ToLower() == (Instrcution.addiu).ToString() || (opType.ToLower() == (Instrcution.ori).ToString() ||
(opType.ToLower() == (Instrcution.sltiu).ToString()))))))
{
string originalOpType = opType;
string[] originalOpNums = opNums;
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[2]);
if ((immHex.CompareTo("FFFF0000") >= 0 && (immHex.CompareTo("FFFFFFFF") <= 0) ||
(immHex.CompareTo("00000000") >= 0 && (immHex.CompareTo("0000FFFF") <= 0))))
{
//合法
}
else
{ //lui $1, immHex.upper
opType = "lui";
opNums = new string[] { "$1", "0x" + immHex.Substring(0, 4) };
hexCode = TranslateSentence(opType, opNums);
sw.WriteLine(hexCode);
//ori $1, $1, immHex.low
opType = "ori";
opNums = new string[] { "$1", "$1", "0x" + immHex.Substring(4, 4) };
hexCode = TranslateSentence(opType, opNums);
sw.WriteLine(hexCode);
if (originalOpType.ToLower() == (Instrcution.andi).ToString())
{
opType = "and";
}
else if (originalOpType.ToLower() == (Instrcution.addi).ToString())
{
opType = "add";
}
else if (originalOpType.ToLower() == (Instrcution.addiu).ToString())
{
opType = "add";
}
else if (originalOpType.ToLower() == (Instrcution.ori).ToString())
{
opType = "or";
}
else if (originalOpType.ToLower() == (Instrcution.sltiu).ToString())
{
opType = "slt";
}
opNums = originalOpNums;
opNums[2] = "$1";
}
}
hexCode = TranslateSentence(opType, opNums);
sw.WriteLine(hexCode);
Scanner.ScanLine();
if (Scanner.CurrentString == null)
{
break;
}
}
}
}
private void BuildLabelTable()
{
using(StreamWriter sw = new StreamWriter(TextSegCodeStream))
{
//Scanner.ScanLine();
if (Scanner.CurrentString.StartsWith(".text"))
{
Scanner.ScanLine();
}
Scanner.IsData = false;
while (true)
{
if (Scanner.CurrentString.Contains(":"))
{
InsertLabel(Scanner.CurrentString);
}
else
{
sw.WriteLine(Scanner.CurrentString);
}
Scanner.ScanLine();
if (Scanner.CurrentString == null)
{
break;
}
}
}
}
private void InsertLabel(string currentString)
{
string[] cutSentence = currentString.Split(":");
string labelName = cutSentence[0];
int decAddr = (Scanner.innerLine + 1) * 4;
decAddr |= 0x00400000;
string labelAddr = ConvertHelper.ConvertIntegerToHex(decAddr.ToString());
labelAddr = labelAddr.Insert(0, "0x");
Label label = new Label
{
Name = labelName,
Address = labelAddr
};
LabelTable.Add(labelName, label);
}
private void BuildSymbolTable()
{
Scanner.ScanLine();
while(true)
{
//Console.WriteLine(Scanner.CurrentString + " 去除了空格后行数:" + Scanner.innerLine + " 原本的行数:" + Scanner.Line);
InsertVar(Scanner.CurrentString);
Scanner.ScanLine();
if (Scanner.CurrentString == null || Scanner.CurrentString.StartsWith(".text"))
{
break;
}
}
}
private void InsertVar(string currentString)
{
//awd:.word 12312
//awd:.word
string[] varDecl = currentString.Split(":");
string varName = varDecl[0];
string[] initSentence = varDecl[1].Split(" ");
bool isInit = initSentence.Length == 1 ? false : true;
if (isInit)
{
Var var = new Var
{
Name = varName,
InitVal = ConvertHelper.ConvertIntegerToHex(initSentence[1]),
Type = ConvertStringToType(initSentence[0]),
};
SymbolTable.Add(varName, var);
}
else
{
Var var = new Var
{
Name = varName,
Type = ConvertStringToType(initSentence[0]),
};
SymbolTable.Add(varName, var);
}
}
public void GetTable()
{
foreach (KeyValuePair<string, Var> var in SymbolTable)
{
Console.WriteLine("变量:{0} .{1},初始值:{2},地址:{3}", var.Key, var.Value.Type.ToString(), var.Value.InitVal == "" ? "" : var.Value.InitVal, var.Value.Addr);
}
Console.WriteLine("---------------------------");
foreach (KeyValuePair<string, Label> label in LabelTable)
{
Console.WriteLine("标号:{0} ,地址:{1}", label.Key, label.Value.Address);
}
}
private BaseType ConvertStringToType(string s)
{
if ((s.ToLower()).Contains(".word"))
{
return BaseType.WORD;
}
else if((s.ToLower()).Contains(".byte"))
{
return BaseType.BYTE;
}
return BaseType.BYTE;
}
private string TranslateSentence(string opType, string[] opNums)
{
string hex = "";
if (opType.ToLower() == (Instrcution.add).ToString())
{
string func = "100000";
hex = BaseRTypeCodeTranslation(opNums,func);
}
else if(opType.ToLower() == (Instrcution.addu).ToString())
{
string func = "100001";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.sub).ToString())
{
string func = "100010";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.subu).ToString())
{
string func = "100011";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.and).ToString())
{
string func = "100100";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.or).ToString())
{
string func = "100101";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.xor).ToString())
{
string func = "100110";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.nor).ToString())
{
string func = "100111";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.slt).ToString())
{
string func = "101010";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.sltu).ToString())
{
string func = "101011";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.sll).ToString())
{
string rs = "00000";
string op = "000000";
string rt = TranslateRegisterToRegCode(opNums[1]);
string rd = TranslateRegisterToRegCode(opNums[0]);
string shamtHex = ConvertHelper.ConvertIntegerToHex( opNums[2]);
string shamtBinary = "";
string func = "000000";
for(int i = shamtHex.Length - 1; i >= 0; i--)
{
shamtBinary = shamtBinary.Insert(0, ConvertHelper.HexToBinary(shamtHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + rd + shamtBinary.Substring(27) + func);
}
else if (opType.ToLower() == (Instrcution.srl).ToString())
{
string rs = "00000";
string op = "000000";
string rt = TranslateRegisterToRegCode(opNums[1]);
string rd = TranslateRegisterToRegCode(opNums[0]);
string shamtHex = ConvertHelper.ConvertIntegerToHex(opNums[2]);
string shamtBinary = "";
string func = "000010";
for (int i = shamtHex.Length - 1; i >= 0; i--)
{
shamtBinary = shamtBinary.Insert(0, ConvertHelper.HexToBinary(shamtHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + rd + shamtBinary.Substring(27) + func);
}
else if (opType.ToLower() == (Instrcution.sra).ToString())
{
string rs = "00000";
string op = "000000";
string rt = TranslateRegisterToRegCode(opNums[1]);
string rd = TranslateRegisterToRegCode(opNums[0]);
string shamtHex = ConvertHelper.ConvertIntegerToHex(opNums[2]);
string shamtBinary = "";
string func = "000011";
for (int i = shamtHex.Length - 1; i >= 0; i--)
{
shamtBinary = shamtBinary.Insert(0, ConvertHelper.HexToBinary(shamtHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + rd + shamtBinary.Substring(27) + func);
}
else if (opType.ToLower() == (Instrcution.sllv).ToString())
{
string func = "000100";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.srlv).ToString())
{
string func = "000110";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.srav).ToString())
{
string func = "000111";
hex = BaseRTypeCodeTranslation(opNums, func);
}
else if (opType.ToLower() == (Instrcution.jr).ToString())
{
string func = "001000";
string op = "000000";
string rt = "00000";
string rd = rt;
string shamt = rt;
string rs = TranslateReg(opNums[0]);
hex = ConvertHelper.BinaryToHex(op + rs + rt + rd + shamt + func);
}
else if (opType.ToLower() == (Instrcution.addi).ToString())
{
string op = "001000";
hex = BaseITypeCodeTranslation(opNums, op);
}
else if (opType.ToLower() == (Instrcution.addiu).ToString())
{
string op = "001001";
hex = BaseITypeCodeTranslation(opNums, op);
}
else if (opType.ToLower() == (Instrcution.andi).ToString())
{
string op = "001100";
hex = BaseITypeCodeTranslation(opNums, op);
}
else if (opType.ToLower() == (Instrcution.ori).ToString())
{
string op = "001101";
hex = BaseITypeCodeTranslation(opNums, op);
}
else if (opType.ToLower() == (Instrcution.xori).ToString())
{
string op = "001101";
hex = BaseITypeCodeTranslation(opNums, op);
}
else if (opType.ToLower() == (Instrcution.sltiu).ToString())
{
string op = "001110";
hex = BaseITypeCodeTranslation(opNums, op);
}
else if (opType.ToLower() == (Instrcution.lui).ToString())
{
string op = "001111";
string rs = "00000";
string rt = TranslateReg(opNums[0]);
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[1]);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
if (immBinary.Length == 16)
{
break;
}
else
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + immBinary);
}
else if (opType.ToLower() == (Instrcution.lw).ToString())
{
string op = "100011";
string rt = TranslateReg(opNums[0]);
string[] offsets = opNums[1].Split("(");
for(int i = 0; i < offsets.Length; i++)
{
offsets[i] = offsets[i].Trim();
}
string immHex = ConvertHelper.ConvertIntegerToHex(offsets[0]);
string immBinary = "";
for(int i = immHex.Length - 1; i >= 0; i--)
{
if(immBinary.Length == 16)
{
break;
}
else
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
string[] reg2 = offsets[1].Split(")");
string rs = TranslateReg(reg2[0]);
hex = ConvertHelper.BinaryToHex(op + rs + rt + immBinary);
}
else if (opType.ToLower() == (Instrcution.sw).ToString())
{
string op = "101011";
string rt = TranslateReg(opNums[0]);
string[] offsets = opNums[1].Split("(");
for (int i = 0; i < offsets.Length; i++)
{
offsets[i] = offsets[i].Trim();
}
string immHex = ConvertHelper.ConvertIntegerToHex(offsets[0]);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
if (immBinary.Length == 16)
{
break;
}
else
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
string[] reg2 = offsets[1].Split(")");
string rs = TranslateReg(reg2[0]);
hex = ConvertHelper.BinaryToHex(op + rs + rt + immBinary);
}
else if (opType.ToLower() == (Instrcution.beq).ToString())
{
string op = "000100";
string rs = TranslateReg(opNums[0]);
string rt = TranslateReg(opNums[1]);
if(!LabelTable.ContainsKey(opNums[2]))
{
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[2]);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
if (immBinary.Length == 16)
{
break;
}
else
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + immBinary);
}
else
{
string immHex = ConvertHelper.ConvertIntegerToHex(LabelTable[opNums[2]].Address);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
//下一条指令
string nextAddrHex = ConvertHelper.ConvertIntegerToHex(((Scanner.innerLine) * 4 | 0x00400000 ).ToString());
string nextAddrBinary = "";
for(int i = nextAddrHex.Length - 1; i >= 0; i--)
{
nextAddrBinary = nextAddrBinary.Insert(0, ConvertHelper.HexToBinary(nextAddrHex[i]));
}
//immBinary - currentAddrBinary
nextAddrBinary = ConvertHelper.ReverseBinary(nextAddrBinary);
long immByte = Convert.ToInt64(immBinary, 2);
long currentByte = Convert.ToInt64(nextAddrBinary, 2);
long actualAddr = (immByte + currentByte) / 4;
string actualAddrHex= ConvertHelper.ConvertIntegerToHex(actualAddr.ToString());
string actualAddrBinary = "";
for (int i = actualAddrHex.Length - 1; i >= 0; i--)
{
if(actualAddrBinary.Length == 16)
{
break;
}
else
actualAddrBinary = actualAddrBinary.Insert(0, ConvertHelper.HexToBinary(actualAddrHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + actualAddrBinary);
}
}
else if (opType.ToLower() == (Instrcution.bne).ToString())
{
string op = "000101";
string rs = TranslateReg(opNums[0]);
string rt = TranslateReg(opNums[1]);
if (!LabelTable.ContainsKey(opNums[2]))
{
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[2]);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
if (immBinary.Length == 16)
{
break;
}
else
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + immBinary);
}
else
{
string immHex = ConvertHelper.ConvertIntegerToHex(LabelTable[opNums[2]].Address);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
string currentAddrHex = ConvertHelper.ConvertIntegerToHex((((Scanner.innerLine - 1) * 4) | 0x00400000).ToString());
string currentAddrBinary = "";
for (int i = currentAddrHex.Length - 1; i >= 0; i--)
{
currentAddrBinary = currentAddrBinary.Insert(0, ConvertHelper.HexToBinary(currentAddrHex[i]));
}
//currentAddrBinary - immBinary
immBinary = ConvertHelper.ReverseBinary(immBinary);
byte immByte = Convert.ToByte(immBinary, 2);
byte currentByte = Convert.ToByte(currentAddrBinary, 2);
int actualAddr = immByte + currentByte;
string actualAddrHex = ConvertHelper.ConvertIntegerToHex(actualAddr.ToString());
string actualAddrBinary = "";
for (int i = actualAddrHex.Length - 1; i >= 0; i--)
{
if (actualAddrBinary.Length == 16)
{
break;
}
else
actualAddrBinary = actualAddrBinary.Insert(0, ConvertHelper.HexToBinary(actualAddrHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + actualAddrBinary);
}
}
else if (opType.ToLower() == (Instrcution.bgtz).ToString())
{
string op = "000111";
string rs = TranslateReg(opNums[0]);
string rt = "00000";
if(!LabelTable.ContainsKey(opNums[1]))
{
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[1]);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
if (immBinary.Length == 16)
{
break;
}
else
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + immBinary);
}
else
{
string immHex = ConvertHelper.ConvertIntegerToHex(LabelTable[opNums[1]].Address);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
string currentAddrHex = ConvertHelper.ConvertIntegerToHex((((Scanner.innerLine - 1) * 4) | 0x00400000).ToString());
string currentAddrBinary = "";
for (int i = currentAddrHex.Length - 1; i >= 0; i--)
{
currentAddrBinary = currentAddrBinary.Insert(0, ConvertHelper.HexToBinary(currentAddrHex[i]));
}
//currentAddrBinary - immBinary
immBinary = ConvertHelper.ReverseBinary(immBinary);
byte immByte = Convert.ToByte(immBinary, 2);
byte currentByte = Convert.ToByte(currentAddrBinary, 2);
int actualAddr = immByte + currentByte;
string actualAddrHex = ConvertHelper.ConvertIntegerToHex(actualAddr.ToString());
string actualAddrBinary = "";
for (int i = actualAddrHex.Length - 1; i >= 0; i--)
{
if (actualAddrBinary.Length == 16)
{
break;
}
else
actualAddrBinary.Insert(0, ConvertHelper.HexToBinary(actualAddrHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + actualAddrBinary);
}
}
else if (opType.ToLower() == (Instrcution.j).ToString())
{
string op = "000010";
if (!LabelTable.ContainsKey(opNums[0]))
{
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[0]);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
if (immBinary.Length == 26)
{
break;
}
else
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
}
hex = ConvertHelper.BinaryToHex(op + immBinary);
}
else
{
string immHex = ConvertHelper.ConvertIntegerToHex(LabelTable[opNums[0]].Address);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + immBinary.Substring(4,26));
}
}
else if (opType.ToLower() == (Instrcution.jal).ToString())
{
string op = "000011";
if (!LabelTable.ContainsKey(opNums[0]))
{
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[0]);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
if (immBinary.Length == 26)
{
break;
}
else
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
}
hex = ConvertHelper.BinaryToHex(op + immBinary);
}
else
{
string immHex = ConvertHelper.ConvertIntegerToHex(LabelTable[opNums[0]].Address);
string immBinary = "";
for (int i = immHex.Length - 1; i >= 0; i--)
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
hex = ConvertHelper.BinaryToHex(op + immBinary.Substring(4, 26));
}
}
return hex;
}
private string BaseITypeCodeTranslation(string[] opNums, string op)
{
string hex = "";
string rs = TranslateReg(opNums[1]);
string rt = TranslateReg(opNums[0]);
string immHex = ConvertHelper.ConvertIntegerToHex(opNums[2]);
string immBinary = "";
for(int i = immHex.Length - 1; i >= 0; i--)
{
if(immBinary.Length == 16)
{
break;
}
else
{
immBinary = immBinary.Insert(0, ConvertHelper.HexToBinary(immHex[i]));
}
}
hex = ConvertHelper.BinaryToHex(op + rs + rt + immBinary);
return hex;
}
private string BaseRTypeCodeTranslation(string[] opNums, string func)
{
string hex = "";
string rs = TranslateReg(opNums[1]);
string rt = TranslateReg(opNums[2]);
string rd = TranslateReg(opNums[0]);
string op = "000000";
string shamt = "00000";
hex = ConvertHelper.BinaryToHex(op + rs + rt + rd + shamt + func);
return hex;
}
#region 翻译Reg
private string TranslateReg(string reg)
{
string regCode = "";
//$xn
string register = reg.Substring(1);
//xn
regCode = TranslateRegisterToRegCode(register);
return regCode;
}
private string TranslateRegisterToRegCode(string register)
{
string regCode = "";
if (register.Contains(Register.zero.ToString()) || register == "0")
{
regCode = "00000";
}
else if (register.Contains(Register.at.ToString()) || register == "1")
{
regCode = "00001";
}
else if (register.Contains(Register.v0.ToString()) || register == "2")
{
regCode = "00010";
}
else if (register.Contains(Register.v1.ToString()) || register == "3")
{
regCode = "00011";
}
else if (register.Contains(Register.a0.ToString()) || register == "4")
{
regCode = "00100";
}
else if (register.Contains(Register.a1.ToString()) || register == "5")
{
regCode = "00101";
}
else if (register.Contains(Register.a2.ToString()) || register == "6")
{
regCode = "00110";
}
else if (register.Contains(Register.a3.ToString()) || register == "7")
{
regCode = "00111";
}
else if (register.Contains(Register.t0.ToString())|| register == "8")
{
regCode = "01000";
}
else if (register.Contains(Register.t1.ToString()) || register == "9")
{
regCode = "01001";
}
else if (register.Contains(Register.t2.ToString()) || register == "10")
{
regCode = "01010";
}
else if (register.Contains(Register.t3.ToString()) || register == "11")
{
regCode = "01011";
}
else if (register.Contains(Register.t4.ToString()) || register == "12")
{
regCode = "01100";
}
else if (register.Contains(Register.t5.ToString()) || register == "13")
{
regCode = "01101";
}
else if (register.Contains(Register.t6.ToString()) || register == "14")
{
regCode = "01110";
}
else if (register.Contains(Register.t7.ToString()) || register == "15")
{
regCode = "01111";
}
else if (register.Contains(Register.s0.ToString()) || register == "16")
{
regCode = "10000";
}
else if (register.Contains(Register.s1.ToString()) || register == "17")
{
regCode = "10001";
}
else if (register.Contains(Register.s2.ToString()) || register == "18")
{
regCode = "10010";
}
else if (register.Contains(Register.s3.ToString()) || register == "19")
{
regCode = "10011";
}
else if (register.Contains(Register.s4.ToString()) || register == "20")
{
regCode = "10100";
}
else if (register.Contains(Register.s5.ToString()) || register == "21")
{
regCode = "10101";
}
else if (register.Contains(Register.s6.ToString()) || register == "22")
{
regCode = "10110";
}
else if (register.Contains(Register.s7.ToString()) || register == "23")
{
regCode = "10111";
}
else if (register.Contains(Register.t8.ToString()) || register == "24")
{
regCode = "11000";
}
else if (register.Contains(Register.t9.ToString()) || register == "25")
{
regCode = "11001";
}
else if (register.Contains(Register.k0.ToString()) || register == "26")
{
regCode = "11010";
}
else if (register.Contains(Register.k1.ToString()) || register == "27")
{
regCode = "11011";
}
else if (register.Contains(Register.gp.ToString()) || register == "28")
{
regCode = "11100";
}
else if (register.Contains(Register.sp.ToString()) || register == "29")
{
regCode = "11101";
}
else if (register.Contains(Register.fp.ToString()) || register == "30")
{
regCode = "11110";
}
else if (register.Contains(Register.ra.ToString()) || register == "31")
{
regCode = "11111";
}
return regCode;
}
#endregion
}
}
Program.cs
using System;
namespace AssembleHelper
{
class Program
{
static void Main(string[] args)
{
InstructionTranslator instructionTranslator = new InstructionTranslator("G:\\ComputerHardWare\\AssembleHelper\\AssembleHelper\\source_code.txt");
instructionTranslator.Translate();
instructionTranslator.GetTable();
}
}
}
source_code.txt 测试
#版本2:新增时控函数,由变量timer决定每个灯泡亮的间隔
#版本3:增加处理函数,函数中调用其他函数需要保存$ra寄存器,为了方便,就不在函数中调用函数了
.data
mode:.word 0x00000000#点灯模式,21~23位开关作为模式选择开关
count:.word 0x00000834 #每个模式运行2100次,2100次过后可以切换为当前选定模式
timer:.word 0x00000001 #实际赫兹为500hz,半秒对应于运行250次;事实上,并不准确,运行速度较慢,可以进一步改小timer;经实验,当timer=1时,效果最佳
mode1:.word 0x00000020
mode2:.word 0x00000040
mode3:.word 0x00000080
mode1_init_rstate:.word 0x00000FFF #模式1,初始右灯状态
mode1_init_lstate:.word 0xFFF00000 #模式1, 初始左灯状态
mode2_init_light_state:.word 0xFF000000 #模式2,初始亮灯状态
mode2_init_dark_state:.word 0x00FFFFFF # 模式2,初始暗灯状态
mode3_input_X:.word 0x00000000 #模式3,低16位输入的X,
temp:.word 0x00000000
t1:.word 0x00000000
t2:.word 0x00000000
.text
lui $1,0xFFFF #0 let $28 = 0xFFFF0000 as the upper 16 bits of the port address
ori $28,$1,0xF000 #4 $28 port is the upper 20 bits of the system's I/O address
main_loop:
lw $1,0xC72($28) #8 读高8位开关数据 t1=xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_sw23,sw22,sw21,x_xxxx
andi $t1, $1, 0x000000E0 #c 屏蔽其他位 t1=0000_0000_0000_0000_0000_0000_sw23,sw22,sw21,0_0000
sw $t1, mode #14 保存选项 mode = t1
lw $t2, mode1 #1c
lw $t3, mode2 #24
lw $t4, mode3 #2c
beq $t1,$t2,mode_mode1 #30 if mode == mode1, go mode_mode1
beq $t1,$t3,mode_mode2 #34 if mode == mode2, go mode_mode2
beq $t1,$t4,mode_mode3 #38 if mode == mode3, go mode_mode3
j main_loop #3c else keep loop
#=================================mode1=============================
mode_mode1:
mode1_init:
lw $s3, count #40 初始化s3 为counter,2100次后结束mode1
lw $s4, mode1_init_rstate #初始化s4右灯泡状态
lw $s5, mode1_init_lstate #初始化s5左灯泡状态
addi $s6, $0, 0x00FFF000 # 初始化s6为右全亮状态
addi $s7, $0, 0x000FFF00 # 初始化s7为左全亮状态
mode1_start_light:
beq $s3,$0,mode1_end #2100次结束,if counter == 0, go mode1_end
beq $s4, $s6, mode1_start_dark #说明灯已全亮,该熄灭了
mode1_light:
sll $s4,$s4,1 #右灯泡向左移,亮一个
srl $s5,$s5,1 #左灯泡向右移,亮一个
jal model1_processor #call model1_processor,调用模式1处理函数
jal start_timer #call timer,调用计时函数
addi $s3,$s3,-1 #counter = counter -1
j mode1_start_light
mode1_start_dark:
beq $s3,$0,mode1_end #2100次结束,if counter == 0, go mode1_end
addi $t6, $0, 0x00000FFF
beq $s4, $t6, mode1_start_light # t4 = t6 = 0x00000FFF说明灯已全暗,该亮了
mode1_dark:
srl $s4,$s4,1 #右灯泡向右移,灭一个
sll $s5,$s5,1 #左灯泡向左移,灭一个
jal model1_processor #call model1_processor,调用模式1处理函数
jal start_timer #call timer,调用计时函数
addi $s3,$s3,-1 #counter = counter -1
j mode1_start_dark
mode1_end:
j main_loop
#mode1处理函数
model1_processor:
and $t1,$s4, $s6 # t1=s4 & s6 00XXX000
and $t2,$s5, $s7 # t2 = s5 & s7 000XXX00
srl $t1,$t1, 12 #t1 = t1<<12 00000XXX
sll $t2, $t2, 4 #t2 = t2>>4 00XXX000
sw $t1, t1
sw $t2, t2
add $t3,$t1,$t2 #t3 = 00XXXXXX,为当前左右灯泡状态
sw $t3, temp
andi $t1, $t3, 0x0000FFFF #t1为右LED状态
sw $t1,0xC60($28) #亮右灯
andi $t1, $t3, 0x00FF0000 #t1为左LED状态
srl $t1,$t1,16 #t1 = 000000XX
sw $t1, 0xC62($28) #亮左灯
jr $ra
#=================================mode2=============================
mode_mode2:
mode2_init:
lw $s1, mode2_init_light_state #s1 = 0xFF000000,初始亮灯状态
lw $s2, mode2_init_dark_state # s2 = 0x00FFFFFF,初始熄灯状态
lw $s3, count #初始化s3 为counter,2100次后结束mode2
addi $s4,$0, 0xFFFFFFFF #s4 = 0xFFFFFFFF,灯全亮状态
addi $s5,$0, 0x00000000 #s5 = 0x00000000,灯全灭状态
mode2_light:
lw $s2, mode2_init_dark_state #重置熄灯状态
beq $s3, $0, mode2_end #if counter = 0, go end
beq $s1, $s4, mode2_dark # 如果全亮,则说明该熄灯了,go mode2_dark
sra $s1,$s1,1 #0xFFXXXXXX
andi $t1, $s1, 0x00FFFFFF #t1 = s1 & 0x00FFFFFF 0x00XXXXXX
jal mode2_processor #call mode2_processor,调用模式2处理函数
jal start_timer #call timer,调用计时函数
addi $s3,$s3,-1 #counter = counter -1
j mode2_light
mode2_dark:
lw $s1, mode2_init_light_state #重置灯亮状态
beq $s3, $0, mode2_end #if counter = 0, go end
beq $s2, $s5, mode2_light # 如果全灭,则说明该亮灯了,go mode2_light
srl $s2,$s2,1 #0x00XXXXXX
andi $t1, $s2, 0x00FFFFFF #t1 = s1 & 0x00FFFFFF 0x00XXXXXX
jal mode2_processor #call ,调用模式2处理函数
jal start_timer #call timer,调用计时函数
addi $s3,$s3,-1 #counter = counter -1
j mode2_dark
mode2_end:
j main_loop
mode2_processor:
andi $t2, $t1, 0x0000FFFF
sw $t2,0xC60($28) #亮右灯
andi $t3, $t1,0x00FF0000 # t3 = 0x00XX0000
srl $t3,$t3,16 # t3 = 0x000000XX
sw $t3,0xC62($28) # 亮左灯
jr $ra
#=================================mode3=============================
mode_mode3:
mode3_init:
lw $t1,0xC70($28) # 读低16位开关数据, t1 = 0x0000XXXX
sw $t1, mode3_input_X #初始化X = $0000XXXX
lw $s3, count #初始化s3 为counter,2100次后结束mode3
lw $s1, mode3_input_X # s1 = X
mode3_start:
beq $s3, $0, mode3_end #if counter = 0, go end
andi $t1, $s1, 0x0000FFFF
sw $t1,0xC60($28) #亮右灯
andi $t2, $s1,0x00FF0000 # t3 = 0x00XX0000
srl $t2,$t2,16 # t3 = 0x000000XX
sw $t2,0xC62($28) # 亮左灯
andi $t1, $s1, 0x00000001 #t1 = s1[0]
sll $t1, $t1, 23 #t1 = b 0000_0000_s1[0]000_0000_0000_0000_0000_0000
srl $s1, $s1, 1 #s1 = b 0000_0000_0xxx_xxxx_xxxx_xxxx_xxxx_xxxx
add $s1, $s1, $t1# s1 = b 0000_0000_s1[0]xxx_xxxx_xxxx_xxxx_xxxx_xxxx
sw $s1, temp
jal start_timer #call timer,调用计时函数
addi $s3,$s3,-1 #counter = counter - 1
j mode3_start
mode3_end:
j main_loop
#计时器函数
start_timer:
timer_init:
lw $t8, timer
timer_start:
beq $t8, $0, timer_end
addi $t8, $t8,-1
j timer_start
timer_end:
jr $ra