public static List <String> ParseFile(string file, ref List <FileParserException> fpx, int desiredMifSize) { InstructionParser iParse = new InstructionParser(); Dictionary <string, int> SubroutineTable = new Dictionary <string, int>(); List <SRCInstruction> instructionsToReparse = new List <SRCInstruction>(); List <String> outList = new List <string>(); int memoryLocation = 0; string[] inputFile = File.ReadAllLines(file); for (int i = 0; i < inputFile.Length; i++) { string trimmed = TrimWhiteSpace(inputFile[i].Split(';')[0].Trim()); string result = ""; if (trimmed.ToLower().StartsWith("org")) { try { //memory origin designation string memLoc = trimmed.ToLower().Split(' ')[1]; int actualLoc = 0; if (memLoc.StartsWith("$")) { memLoc = memLoc.TrimStart('$'); actualLoc = Convert.ToInt32(memLoc, 16); } else if (memLoc.StartsWith("0x")) { actualLoc = Convert.ToInt32(memLoc, 16); } else { actualLoc = Convert.ToInt32(memLoc); } if (actualLoc == memoryLocation) { fpx.Add(new FileParserException("Ignoring org directive '" + trimmed + "' : Erroneous.", i, 1)); } else if (actualLoc < memoryLocation) { fpx.Add(new FileParserException("Ignoring org directive '" + trimmed + "' : Can't go backwards in memory.", i, 1)); } else if (actualLoc - 1 == memoryLocation) { StringBuilder s = new StringBuilder(); s.AppendFormat("{0} : 00000000;", String.Format("{0:X}", actualLoc - 1)); result = s.ToString(); outList.Add(result); memoryLocation = actualLoc; } else { StringBuilder s = new StringBuilder(); s.AppendFormat("[{0}..{1}] : 00000000;", String.Format("{0:X}", memoryLocation), String.Format("{0:X}", actualLoc - 1)); result = s.ToString(); outList.Add(result); memoryLocation = actualLoc; } } catch (Exception ex) { fpx.Add(new FileParserException("Error parsing org directive '" + trimmed + "' : " + ex.Message, i, 0)); } } else if (trimmed.StartsWith("@"))//subroutine { SubroutineTable.Add(trimmed, memoryLocation); fpx.Add(new FileParserException("Subroutine Found at location " + String.Format("{0:X}", memoryLocation) + " '" + trimmed + "'", i, 2)); } else if (trimmed.StartsWith("&"))//data spec { string[] dataItems = trimmed.Remove(0, 1).Replace(' ', ',').Split(','); for (int j = 0; j < dataItems.Length; j++) { string dataItem; try { if (dataItems[j].StartsWith("$")) { dataItem = dataItems[j].TrimStart('$'); dataItem = Convert.ToInt32(dataItem, 16).ToString("X"); } else if (dataItems[j].ToLower().StartsWith("0x")) { dataItem = Convert.ToInt32(dataItems[j], 16).ToString("X"); } else { dataItem = Convert.ToInt32(dataItems[j]).ToString("X"); } StringBuilder s = new StringBuilder(); s.AppendFormat("{0} : {1};", String.Format("{0:X}", memoryLocation++), dataItem); result = s.ToString(); outList.Add(result); } catch (Exception ex) { fpx.Add(new FileParserException("Error parsing data item '" + dataItems[j] + "' : " + ex.Message, i, 0)); throw; } } } else if (String.IsNullOrWhiteSpace(trimmed)) { //do nothing- this is a comment or other such line } else { //intsruction! Yay! try { SRCInstruction outputInst = iParse.ParseInstruction(trimmed); StringBuilder s = new StringBuilder(); if (outputInst.replaceImmediateWithAddress) { //... do this instructionsToReparse.Add(outputInst); int instructionIdx = instructionsToReparse.Count - 1; s.AppendFormat("{0} : REPARSEINSTRUCTION_{1};", String.Format("{0:X}", memoryLocation++), instructionIdx); } else { string tmpResult = outputInst.outputInstructionString.PadLeft(8, '0'); s.AppendFormat("{0} : {1};", String.Format("{0:X}", memoryLocation++), tmpResult); } result = s.ToString(); outList.Add(result); } catch (Exception ex) { fpx.Add(new FileParserException("Error parsing instruction '" + trimmed + "' : " + ex.Message, i, 0)); } } } //return outList; //loop thru outList and find the memory locations to replace.... for (int i = 0; i < outList.Count; i++) { if (outList[i].Contains("REPARSEINSTRUCTION")) { //we gotta reparse this shit! string reparseMarker = outList[i].Split(':')[1].Trim(' ').Trim(';'); int reparseIdx = Convert.ToInt32(reparseMarker.Split('_')[1]); SRCInstruction reparseInst = instructionsToReparse[reparseIdx]; try { string replacementMemoryLocation = "0x" + SubroutineTable[reparseInst.immediateToReplace].ToString("X"); string replacementInstruction = reparseInst.originalInstructionString.Replace(reparseInst.immediateToReplace, replacementMemoryLocation); SRCInstruction newInstruction = iParse.ParseInstruction(replacementInstruction); string tmpResult = newInstruction.outputInstructionString.PadLeft(8, '0'); outList[i] = outList[i].Replace(reparseMarker, tmpResult); } catch (Exception ex) { fpx.Add(new FileParserException("Error parsing instruction (2nd pass)'" + outList[i] + "' : " + ex.Message, i, 0)); } } } int pow = 0; while (desiredMifSize > (int)Math.Pow(2, pow)) { pow = pow + 1; } if (desiredMifSize < (int)Math.Pow(2, pow)) { desiredMifSize = (int)Math.Pow(2, pow); fpx.Add(new FileParserException("MIF extended to a power of two length.", 0, 2)); } if (memoryLocation < desiredMifSize - 1) { StringBuilder s = new StringBuilder(); s.AppendFormat("[{0}..{1}] : 00000000;", String.Format("{0:X}", memoryLocation), String.Format("{0:X}", desiredMifSize - 1)); outList.Add(s.ToString()); memoryLocation = desiredMifSize; } else if (memoryLocation > desiredMifSize - 1) { while (desiredMifSize - 1 < memoryLocation) { pow = pow + 1; desiredMifSize = (int)Math.Pow(2, pow); } if (memoryLocation == desiredMifSize - 1) { StringBuilder s = new StringBuilder(); s.AppendFormat("{0} : 00000000;", String.Format(String.Format("{0:X}", desiredMifSize - 1))); outList.Add(s.ToString()); memoryLocation = desiredMifSize; } else { StringBuilder s = new StringBuilder(); s.AppendFormat("[{0}..{1}] : 00000000;", String.Format("{0:X}", memoryLocation), String.Format("{0:X}", desiredMifSize - 1)); outList.Add(s.ToString()); memoryLocation = desiredMifSize; } fpx.Add(new FileParserException("MIF extended to accommodate code length", 0, 2)); } List <string> FileOutList = new List <string>(); FileOutList.Add("WIDTH=32;"); FileOutList.Add("DEPTH=" + Convert.ToString((int)Math.Pow(2, pow)) + ";"); FileOutList.Add("ADDRESS_RADIX=HEX;"); FileOutList.Add("DATA_RADIX=HEX;"); FileOutList.Add(""); FileOutList.Add("CONTENT BEGIN"); FileOutList.AddRange(outList); FileOutList.Add("END;"); return(FileOutList); }
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 + "'"); } } }