static void Main(string[] args) { bool ShowWarnings = true; bool ShowInfo = true; bool ShowFile = false; int desiredSize = 0; List <FileParserException> exceptionList = new List <FileParserException>(); Console.WriteLine("--MiniSRC Assembler by Mitchell Waite--\n"); Console.WriteLine("-- Updated for 2021 by Alex McKinnon --\n"); if (args.Length == 0) { Console.Write("Usage: minisrc_asm.exe [file] [output] [length] [options]\n\n[file] is a relative or absolute path to a MiniSRC asm file\n[output] is the desired location for the generated MIF\n\n[length] is the desired MIF size length, in (32 bit) words of memory.\n\nOptions:\n-showfile : show the MIF output in the console window.\n-noinfo : supress informational messages\n-nowarn : supress warning messages\n\nUse an & symbol to specify a line with data items, separated by spaces or commas -> &0x5,0x6\nUse an @ symbol to specify a subroutine, on its own line.\n\n"); } else if (!File.Exists(args[0])) { Console.Write("The file specified below does not exist.\n\n" + args[0]); } else if (!Int32.TryParse(args[2], out desiredSize)) { Console.Write("The following integer is not valid for desired MIF size: " + args[2] + "\n\n"); } else { Console.WriteLine("Input: " + args[0]); Console.WriteLine("Output: " + args[1]); Console.WriteLine(""); if (args.Contains("-noinfo")) { ShowInfo = false; } if (args.Contains("-nowarn")) { ShowWarnings = false; } if (args.Contains("-showfile")) { ShowFile = true; } try { List <String> outList = FileParser.ParseFile(args[0], ref exceptionList, desiredSize); File.WriteAllLines(args[1], outList); if (ShowFile) { foreach (string s in outList) { Console.WriteLine(s); } Console.WriteLine(); } if (exceptionList.Count > 0) { foreach (FileParserException ex in exceptionList) { StringBuilder s = new StringBuilder(); if (ex.ErrorType == 1 && ShowWarnings) { s.Append("Warning"); } else if (ex.ErrorType == 2 && ShowInfo) { s.Append("Information"); } else { s.Append("Error"); } s.AppendFormat(" in file: {0}\nLine: {1}\nMessage: {2}\n\n", args[0], ex.LineNumber, ex.Message); Console.Error.Write(s); } } } catch (Exception ex) { StringBuilder s = new StringBuilder(); s.AppendFormat("There was an error processing the assembly file.\n\nError: {0}\nMessage: {1}\nStack: {2}\n", ex.GetType().ToString(), ex.Message, ex.StackTrace); Console.Error.Write(s); } } Console.WriteLine("Assembler Finished. Press any key to continue."); Console.ReadKey(); }
public SRCInstruction ParseInstruction(string inst) { SRCInstruction tmpInst = new SRCInstruction(); tmpInst.originalInstructionString = inst; tmpInst.outputInstructionString = ""; tmpInst.replaceImmediateWithAddress = false; string instruction = inst.ToLower(); if (instruction == "nop") { tmpInst.outputInstructionString = "C8000000"; return(tmpInst); //opcode for NOP } else if (instruction == "halt") { tmpInst.outputInstructionString = "D0000000"; //opcode for HALT! return(tmpInst); } else //not a single word no operand instruction { string[] wsplit = inst.ToLower().Split(' '); StringBuilder s = new StringBuilder(); s.Append(opcodeDictionary[wsplit[0]]); try { switch (wsplit[0]) { case "ld": case "ldi": { string regString; if (wsplit.Length > 2) { regString = (wsplit[1] + wsplit[2]); if (wsplit.Length > 3) { //dump warning } } else { regString = wsplit[1]; } Regex idx = new Regex(@"(([rR][0-9]*),\s*[$|0x|0X|-]*[0-9]+\(([rR][0-9]+)\))\s*"); Regex reg = new Regex(@"([rR][0-9]*),\s*[$|0x|0X|-]*[0-9]+\s*"); Regex sub = new Regex(@"([rR][0-9]*),\s*[\@][a-zA-Z0-9]+\s*"); //will match an @ declaration.... this should be good if (idx.IsMatch(regString)) { string[] dirString = regString.Split(','); string[] addString = dirString[1].Split('('); s.AppendFormat("{0}", RxToBin(FileParser.TrimWhiteSpace(dirString[0]))); s.AppendFormat("{0}", RxToBin(FileParser.TrimWhiteSpace(addString[1].TrimEnd(')')))); string immString = FileParser.TrimWhiteSpace(addString[0]); int c_sx = 0; string c_sx_string = ""; if (immString.StartsWith("$")) { immString = immString.Remove(0, 1); c_sx = Convert.ToInt32(immString, 16); } else if (immString.ToLower().StartsWith("0x")) { c_sx = Convert.ToInt32(immString, 16); } else { c_sx = Convert.ToInt32(immString); } if (c_sx < -524288 || c_sx > 524287) { throw new ArgumentOutOfRangeException("Immediate Value out of range."); } else { c_sx_string = String.Format(Convert.ToString(c_sx, 2)).PadLeft(19, '0'); if (c_sx_string.Length > 19) //remove erroneous 1s { c_sx_string = c_sx_string.Substring(c_sx_string.Length - 19, 19); } } s.AppendFormat("{0}", c_sx_string); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString(), 2).ToString("X"); return(tmpInst); } else if (reg.IsMatch(regString)) { string[] dirString = regString.Split(','); s.AppendFormat("{0}0000", RxToBin(FileParser.TrimWhiteSpace(dirString[0]))); string immString = FileParser.TrimWhiteSpace(dirString[1]); int c_sx = 0; string c_sx_string = ""; if (immString.StartsWith("$")) { immString = immString.Remove(0, 1); c_sx = Convert.ToInt32(immString, 16); } else if (immString.ToLower().StartsWith("0x")) { c_sx = Convert.ToInt32(immString, 16); } else { c_sx = Convert.ToInt32(immString); } if (c_sx < -524288 || c_sx > 524287) { throw new ArgumentOutOfRangeException("Immediate Value out of range."); } else { c_sx_string = String.Format(Convert.ToString(c_sx, 2)).PadLeft(19, '0'); if (c_sx_string.Length > 19) //remove erroneous 1s { c_sx_string = c_sx_string.Substring(c_sx_string.Length - 19, 19); } } s.AppendFormat("{0}", c_sx_string); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString(), 2).ToString("X"); return(tmpInst); } else if (sub.IsMatch(regString)) { //we're matching a subroutine. save this for later. string[] dirString = regString.Split(','); tmpInst.immediateToReplace = dirString[1]; tmpInst.replaceImmediateWithAddress = true; return(tmpInst); } else { throw new ArgumentException("Syntax Error in '" + inst + "' : invalid instruction format."); } } case "st": { string regString; if (wsplit.Length > 2) { regString = (wsplit[1] + wsplit[2]); if (wsplit.Length > 3) { //dump warning } } else { regString = wsplit[1]; } Regex idx = new Regex(@"[$|0x|0X|-]([0-9]*[a-f|A-F]*)*\([rR][0-9]+\)\s*,\s*[rR][0-9]+"); Regex reg = new Regex(@"[$|0x|0X|-]*[0-9]+\s*,\s*[rR][0-9]+\s*"); if (idx.IsMatch(regString)) { string[] dirString = regString.Split(','); string[] addString = dirString[0].Split('('); s.AppendFormat("{0}", RxToBin(FileParser.TrimWhiteSpace(dirString[1]))); s.AppendFormat("{0}", RxToBin(FileParser.TrimWhiteSpace(addString[1].TrimEnd(')')))); string immString = FileParser.TrimWhiteSpace(addString[0]); int c_sx = 0; string c_sx_string = ""; if (immString.StartsWith("$")) { immString = immString.Remove(0, 1); c_sx = Convert.ToInt32(immString, 16); } else if (immString.ToLower().StartsWith("0x")) { c_sx = Convert.ToInt32(immString, 16); } else { c_sx = Convert.ToInt32(immString); } if (c_sx < -524288 || c_sx > 524287) { throw new ArgumentOutOfRangeException("Immediate Value out of range."); } else { c_sx_string = String.Format(Convert.ToString(c_sx, 2)).PadLeft(19, '0'); if (c_sx_string.Length > 19) //remove erroneous 1s { c_sx_string = c_sx_string.Substring(c_sx_string.Length - 19, 19); } } s.AppendFormat("{0}", c_sx_string); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString(), 2).ToString("X"); return(tmpInst); } else if (reg.IsMatch(regString)) { string[] dirString = regString.Split(','); s.AppendFormat("{0}0000", RxToBin(FileParser.TrimWhiteSpace(dirString[1]))); string immString = FileParser.TrimWhiteSpace(dirString[0]); int c_sx = 0; string c_sx_string = ""; if (immString.StartsWith("$")) { immString = immString.Remove(0, 1); c_sx = Convert.ToInt32(immString, 16); } else if (immString.ToLower().StartsWith("0x")) { c_sx = Convert.ToInt32(immString, 16); } else { c_sx = Convert.ToInt32(immString); } if (c_sx < -524288 || c_sx > 524287) { throw new ArgumentOutOfRangeException("Immediate Value out of range."); } else { c_sx_string = String.Format(Convert.ToString(c_sx, 2)).PadLeft(19, '0'); if (c_sx_string.Length > 19) //remove erroneous 1s { c_sx_string = c_sx_string.Substring(c_sx_string.Length - 19, 19); } } s.AppendFormat("{0}", c_sx_string); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString(), 2).ToString("X"); return(tmpInst); } else { throw new ArgumentException("Syntax Error in '" + inst + "' : invalid instruction format."); } } //operation,register instructions case "jal": case "jr": case "mflo": case "mfhi": case "in": case "out": { if (wsplit.Length > 2) { //dump warning here } s.Append(RxToBin(wsplit[1])); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString().PadRight(32, '0'), 2).ToString("X"); return(tmpInst); } //operation, three registers, no immediate value case "add": case "sub": case "and": case "or": case "shr": case "shl": case "ror": case "rol": { string[] regString; if (wsplit.Length > 3) { regString = (wsplit[1] + wsplit[2] + wsplit[3]).Split(','); if (wsplit.Length > 4) { //dump warning } } else if (wsplit.Length > 2) { regString = (wsplit[1] + wsplit[2]).Split(','); } else { regString = wsplit[1].Split(','); } s.AppendFormat("{0}{1}{2}", RxToBin(FileParser.TrimWhiteSpace(regString[0])), RxToBin(FileParser.TrimWhiteSpace(regString[1])), RxToBin(FileParser.TrimWhiteSpace(regString[2]))); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString().PadRight(32, '0'), 2).ToString("X"); return(tmpInst); } //operation, two registers, immediate value case "addi": case "andi": case "ori": { string[] regString; if (wsplit.Length > 3) { regString = (wsplit[1] + wsplit[2] + wsplit[3]).Split(','); if (wsplit.Length > 4) { //dump warning } } else if (wsplit.Length > 2) { regString = (wsplit[1] + wsplit[2]).Split(','); } else { regString = wsplit[1].Split(','); } s.AppendFormat("{0}{1}", RxToBin(FileParser.TrimWhiteSpace(regString[0])), RxToBin(FileParser.TrimWhiteSpace(regString[1]))); string immString = FileParser.TrimWhiteSpace(regString[2]); int c_sx = 0; string c_sx_string = ""; if (immString.StartsWith("$")) { immString = immString.Remove(0, 1); c_sx = Convert.ToInt32(immString, 16); } else if (immString.ToLower().StartsWith("0x")) { c_sx = Convert.ToInt32(immString, 16); } else { c_sx = Convert.ToInt32(immString); } if (c_sx < -524288 || c_sx > 524287) { throw new ArgumentOutOfRangeException("Immediate Value out of range."); } else { c_sx_string = String.Format(Convert.ToString(c_sx, 2)).PadLeft(19, '0'); if (c_sx_string.Length > 19) //remove erroneous 1s { c_sx_string = c_sx_string.Substring(c_sx_string.Length - 19, 19); } } s.AppendFormat("{0}", c_sx_string); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString(), 2).ToString("X"); return(tmpInst); } //operation, two registers, nothing else case "not": case "neg": case "div": case "mul": { string[] regString; if (wsplit.Length > 2) { regString = (wsplit[1] + wsplit[2]).Split(','); if (wsplit.Length > 3) { //dump warning } } else { regString = wsplit[1].Split(','); } s.AppendFormat("{0}{1}", RxToBin(FileParser.TrimWhiteSpace(regString[0])), RxToBin(FileParser.TrimWhiteSpace(regString[1]))); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString().PadRight(32, '0'), 2).ToString("X"); return(tmpInst); } //branches case "brzr": case "brnz": case "brpl": case "brmi": { string[] regString; if (wsplit.Length > 2) { regString = (wsplit[1] + wsplit[2]).Split(','); if (wsplit.Length > 3) { //dump warning } } else { regString = wsplit[1].Split(','); } s.AppendFormat("{0}{1}", RxToBin(FileParser.TrimWhiteSpace(regString[0])), "00"); s.Append(branchSuffix[wsplit[0]]); // Constant added to end string immString = FileParser.TrimWhiteSpace(regString[1]); int c_sx = 0; string c_sx_string = ""; if (immString.StartsWith("$")) { immString = immString.Remove(0, 1); c_sx = Convert.ToInt32(immString, 16); } else if (immString.ToLower().StartsWith("0x")) { c_sx = Convert.ToInt32(immString, 16); } else { c_sx = Convert.ToInt32(immString); } if (c_sx < -524288 || c_sx > 524287) { throw new ArgumentOutOfRangeException("Immediate Value out of range."); } else { c_sx_string = String.Format(Convert.ToString(c_sx, 2)).PadLeft(19, '0'); if (c_sx_string.Length > 19) //remove erroneous 1s { c_sx_string = c_sx_string.Substring(c_sx_string.Length - 19, 19); } } s.AppendFormat("{0}", c_sx_string); tmpInst.outputInstructionString = Convert.ToUInt32(s.ToString(), 2).ToString("X"); return(tmpInst); } default: { throw new ArgumentException("Unknown instruction: " + wsplit[0]); } } } catch (IndexOutOfRangeException) { throw new ArgumentException("Syntax Error, argument(s) are missing from '" + inst + "'"); } } }