用C#实现一个简易的Mips汇编器

  • Mips31个寄存器
  • Mips指令入门
  • Mips内存安排
  • C#实现
    • 项目结构
    • Token.cs,定义Mips汇编语言的Token
    • ConvertHelper.cs,作为进制转换类,帮助我们处理进制转换
    • Scanner.cs,扫描器实现
    • InsturctionTranslator.cs,指令翻译
    • Program.cs
    • source_code.txt 测试

用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 Instrcutionpublic enum Instrcution{//RTypeadd,addu,sub,subu,and,or,xor,nor,slt,sltu,sll,srl,sra,sllv,srlv,srav,jr,//ITypeaddi,addiu,andi,ori,xori,sltiu,lui,lw,sw,beq,bne,bgtz,//JTypej,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 7else 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进制,输入为一个Charpublic 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 <= 0000EFFFif ((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, 0x00001001sw.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.upperopType = "lui";opNums = new string[] { "$1", "0x" + immHex.Substring(0, 4) };hexCode = TranslateSentence(opType, opNums);sw.WriteLine(hexCode);//ori $1, $1, immHex.lowopType = "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;}elseimmBinary = 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;}elseimmBinary = 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;}elseactualAddrBinary = 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 - immBinaryimmBinary = 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;}elseactualAddrBinary = 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 - immBinaryimmBinary = 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;}elseactualAddrBinary.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 翻译Regprivate string TranslateReg(string reg){string regCode = "";//$xnstring register = reg.Substring(1);//xnregCode = 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寄存器,为了方便,就不在函数中调用函数了
.datamode:.word 0x00000000#点灯模式,21~23位开关作为模式选择开关count:.word 0x00000834 #每个模式运行2100次,2100次过后可以切换为当前选定模式timer:.word 0x00000001 #实际赫兹为500hz,半秒对应于运行250次;事实上,并不准确,运行速度较慢,可以进一步改小timer;经实验,当timer=1时,效果最佳mode1:.word 0x00000020mode2:.word 0x00000040mode3:.word 0x00000080mode1_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 0x00000000t1:.word 0x00000000t2:.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 addressmain_loop:    lw   $1,0xC72($28)          #8 读高8位开关数据 t1=xxxx_xxxx_xxxx_xxxx_xxxx_xxxx_sw23,sw22,sw21,x_xxxxandi  $t1, $1, 0x000000E0     #c  屏蔽其他位  t1=0000_0000_0000_0000_0000_0000_sw23,sw22,sw21,0_0000sw $t1, mode         #14 保存选项            mode = t1lw $t2, mode1         #1clw $t3, mode2            #24lw $t4, mode3            #2cbeq $t1,$t2,mode_mode1   #30 if mode == mode1, go mode_mode1beq $t1,$t3,mode_mode2 #34 if mode == mode2, go mode_mode2beq $t1,$t4,mode_mode3 #38 if mode == mode3, go mode_mode3j main_loop                #3c else keep loop#=================================mode1=============================
mode_mode1:
mode1_init:lw $s3, count    #40 初始化s3 为counter,2100次后结束mode1lw $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_endbeq $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  -1j mode1_start_lightmode1_start_dark:beq $s3,$0,mode1_end #2100次结束,if counter == 0, go mode1_endaddi $t6, $0, 0x00000FFFbeq $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  -1j mode1_start_darkmode1_end:j main_loop#mode1处理函数
model1_processor:and $t1,$s4, $s6 # t1=s4 & s6         00XXX000and $t2,$s5, $s7 # t2 = s5 & s7       000XXX00srl $t1,$t1, 12  #t1 = t1<<12 00000XXXsll $t2, $t2, 4 #t2 = t2>>4  00XXX000sw $t1, t1sw $t2, t2add $t3,$t1,$t2 #t3 = 00XXXXXX,为当前左右灯泡状态sw $t3, tempandi $t1, $t3,  0x0000FFFF #t1为右LED状态sw $t1,0xC60($28)     #亮右灯andi $t1, $t3,  0x00FF0000  #t1为左LED状态srl $t1,$t1,16                #t1 = 000000XXsw $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次后结束mode2addi $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 endbeq $s1, $s4, mode2_dark # 如果全亮,则说明该熄灯了,go mode2_darksra $s1,$s1,1    #0xFFXXXXXXandi $t1, $s1, 0x00FFFFFF #t1 = s1 &  0x00FFFFFF    0x00XXXXXXjal mode2_processor   #call mode2_processor,调用模式2处理函数jal start_timer #call timer,调用计时函数addi $s3,$s3,-1 #counter = counter  -1j mode2_lightmode2_dark:lw $s1, mode2_init_light_state #重置灯亮状态beq $s3, $0, mode2_end #if counter = 0, go endbeq $s2, $s5, mode2_light # 如果全灭,则说明该亮灯了,go mode2_lightsrl $s2,$s2,1 #0x00XXXXXXandi $t1, $s2, 0x00FFFFFF #t1 = s1 &  0x00FFFFFF    0x00XXXXXXjal mode2_processor   #call ,调用模式2处理函数jal start_timer #call timer,调用计时函数addi $s3,$s3,-1    #counter = counter  -1j mode2_darkmode2_end:j main_loopmode2_processor:andi $t2, $t1, 0x0000FFFFsw $t2,0xC60($28)  #亮右灯andi $t3, $t1,0x00FF0000    # t3 = 0x00XX0000srl $t3,$t3,16    # t3 = 0x000000XXsw $t3,0xC62($28)     # 亮左灯jr $ra
#=================================mode3=============================
mode_mode3:
mode3_init:lw  $t1,0xC70($28)          # 读低16位开关数据, t1 = 0x0000XXXX  sw $t1, mode3_input_X #初始化X = $0000XXXXlw $s3, count #初始化s3 为counter,2100次后结束mode3lw $s1, mode3_input_X # s1 = Xmode3_start:beq $s3, $0, mode3_end #if counter = 0, go endandi $t1, $s1, 0x0000FFFFsw $t1,0xC60($28)   #亮右灯andi $t2, $s1,0x00FF0000    # t3 = 0x00XX0000srl $t2,$t2,16    # t3 = 0x000000XXsw $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_0000srl $s1, $s1, 1 #s1 = b 0000_0000_0xxx_xxxx_xxxx_xxxx_xxxx_xxxxadd $s1, $s1, $t1# s1 = b 0000_0000_s1[0]xxx_xxxx_xxxx_xxxx_xxxx_xxxxsw $s1, tempjal start_timer #call timer,调用计时函数addi $s3,$s3,-1 #counter = counter - 1 j mode3_startmode3_end:j main_loop#计时器函数
start_timer:
timer_init:lw $t8, timer
timer_start:beq $t8, $0, timer_endaddi $t8, $t8,-1j timer_start
timer_end:jr $ra

用C#实现一个简易的Mips汇编器相关推荐

  1. 计算机组成实验六MIPS汇编器,杭电计组实验6-MIPS汇编器与模拟器实验.doc

    <杭电计组实验6-MIPS汇编器与模拟器实验.doc>由会员分享,提供在线免费全文阅读可下载,此文档格式为doc,更多相关<杭电计组实验6-MIPS汇编器与模拟器实验.doc> ...

  2. 在windows程序中嵌入Lua脚本引擎--建立一个简易的“云命令”执行的系统

    在<在windows程序中嵌入Lua脚本引擎--使用VS IDE编译Luajit脚本引擎>开始处,我提到某公司被指责使用"云命令"暗杀一些软件.本文将讲述如何去模拟一个 ...

  3. 用java实现一个简易自动提款机

    用java实现一个简易自动提款机,且有以下要求 如何实现呢?首先,我们定义一个用户类User,同时根据要求设计好属性(本人部分命名没有使用驼峰命名法,不够规范).因为一个人可能有多个卡,卡号又不能重复 ...

  4. python写一个文件下载器_Python3使用TCP编写一个简易的文件下载器

    原标题:Python3使用TCP编写一个简易的文件下载器 利用Python3来实现TCP协议,和UDP类似.UDP应用于及时通信,而TCP协议用来传送文件.命令等操作,因为这些数据不允许丢失,否则会造 ...

  5. 连夜撸了一个简易聊天室

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 分不清轮询.长轮询?不知道什么时候该用websocket还 ...

  6. python 正则的使用 —— 编写一个简易的计算器

    python 正则的使用 -- 编写一个简易的计算器 在 Alex 的博客上看到的对正则这一章节作业是编写一个计算器,要求能计算出下面的算式. 1 - 2 * ( (60-30 +(-40/5) * ...

  7. 从零开始实现一个简易的Java MVC框架(六)--加强AOP功能

    前言 在前面从零开始实现一个简易的Java MVC框架(四)--实现AOP和从零开始实现一个简易的Java MVC框架(五)--引入aspectj实现AOP切点这两节文章中已经实现了AOP功能并且引用 ...

  8. 一个简易实用的web权限管理模块的应用与实现

    本文介绍一个简易实用的web权限管理模块的应用与实现. 先介绍数据模型和应用界面,后继对实现细节做选择性阐述. 数据表关系如下: 该图标明了登陆用户.角色.部门(机构).用户组.角色和模块功能之间的关 ...

  9. 怎么用线程刷新 tkinter 进度条_tkinter做一个简易提词板(2)

    书接上文 花果山美男子:tkinter做一个简易提词板​zhuanlan.zhihu.com 上回说到,文字的动态效果还可以用after方法和StringVar来实现,今天我们就用它们来重新制作提词板 ...

最新文章

  1. 【CentOS Linux 7】实验1【Linux文件目录管理】
  2. PX4/Pixhawk---uORB深入理解和应用
  3. Redis高可用sentinel
  4. 获取Authorize.Net Transaction Key ( Getting Your Authorize.Net Transaction Key )
  5. Aptana 开发环境执行时默认的工作路径
  6. Poisson泊松分布
  7. 功夫小子实践开发-菜单场景之游戏秘籍场景的分析和实现
  8. IDEA修改主题及字体大小
  9. R语言的帮助文档以及相关函数
  10. ConceptDraw MINDMAP 12 Mac版思维导图软件有哪些有点?
  11. 使用CAGradientLayer绘制渐变色
  12. 解决Vivado implementation拥塞的策略方法(一)
  13. 常用到的宏定义!!!!!
  14. C语言源文件名为什么无效,scanf函数,想说输入不容易!----小话c语言(3)
  15. android重力传感器横竖反,Android重力感应实现方式
  16. Android 11 强制分区存储
  17. 腾讯云WebIM和阿里百川即时通讯使用总结
  18. 【Java SE】第二话·第一个Java程序
  19. 【WordPress】修改固定链接,文章链接
  20. 通过java agent监控程序执行

热门文章

  1. 你知道如何修改单选框、复选框、下拉框的默认样式吗
  2. 【增加苏宁】2020双十一淘宝领喵币+京东全名营业+支付宝+苏宁の自动化任务
  3. 计算机水冷散热器上市公司,十大计算机散热器品牌,水冷散热器-CPU散热器-笔记本散热器品牌,更适合计算机散热器...
  4. 使用cmd查看端口号
  5. 使用阿里云服务器三分钟搭建网站教程(详细图文详解)
  6. Matlab中创建和使用表
  7. 步进电机S(SigMoid)曲线加减速【查表法】
  8. c语言设计实验报告答案,武汉理工大学《C语言程序设计》实验报告答案
  9. depot_tools window 安装流程
  10. python将图片转为字符画_Python将图片转换为字符画的方法