// Expand a JAL Label instruction into LUI, ORI and JAL instructions private String[] jumpAndLink(String assembly) { String[] instruction = Regex.Split(assembly, @"\s+"); String[] binaryLines = { "", "", "" }; String binary1 = "1111"; // LUI Rdest Imm(from label) String binary2 = "0010"; // ORI Rdest Imm String binary3 = "010011111000"; // JAL R15 OpExt Rtarget if (labels.Contains(instruction[2])) { String reg = convertReg(instruction[1]); binary1 += reg; LabelPair labelLocation = (LabelPair)labelList[labels.IndexOf(instruction[2])]; binary1 += convertUpper8(labelLocation.LineNum); // Imm for LUI binary2 += reg; binary2 += convertLower8(labelLocation.LineNum); // Imm for ORI binary3 += convertReg(instruction[1]); binaryLines[0] = binary1; binaryLines[1] = binary2; binaryLines[2] = binary3; } else { binaryLines[0] = "label error"; binaryLines[1] = "label error"; binaryLines[2] = "label error"; } return(binaryLines); }
// Expand a JCond Label instruction into LUI, ORI and JCond instructions private String[] jump(String assembly) { String[] instruction = Regex.Split(assembly, @"\s+"); String[] binaryLines = { "", "", "" }; String binary1 = "1111"; // LUI Rdest Imm(from label) String binary2 = "0010"; // ORI Rdest Imm String binary3 = "0100"; // start of JCond if (labels.Contains(instruction[2])) { String reg = convertReg(instruction[1]); binary1 += reg; LabelPair labelLocation = (LabelPair)labelList[labels.IndexOf(instruction[2])]; binary1 += convertUpper8(labelLocation.LineNum); // Imm for LUI binary2 += reg; binary2 += convertLower8(labelLocation.LineNum); // Imm for ORI binary3 += convertCondition(instruction[0].TrimStart('J')); binary3 += "1100"; binary3 += convertReg(instruction[1]); binaryLines[0] = binary1; binaryLines[1] = binary2; binaryLines[2] = binary3; } else // Generate an error { binaryLines[0] = "label error"; binaryLines[1] = "label error"; binaryLines[2] = "label error"; } return(binaryLines); }
// Converts an assembly file line by line private void quickConvButton_Click(object sender, EventArgs e) { sourceLineCount = 0; // Keep track of source line numbers for error reporting destLineCount = 0; // Use to keep track of output addresses for branch label offset and jump label calculations sourceFileTextBox.Text = ""; // Location of input assembly file destFileTextBox.Text = ""; // Location of output binary file destHexTextBox.Text = ""; // Use this to display binary instructions in HEX for debugging labelsTextBox.Text = ""; // Use this to display all labels with their addresses for help debugging code lineList = new ArrayList(); // Keep track of lines labelList = new ArrayList(); // Keep track of lables with their binary addresses (Use LabelPair helper class) labels = new ArrayList(); // Keep track of label names errorList = new ArrayList(); // List to keep track of errors // No source file selected if (!File.Exists(sourceTextBox.Text)) { MessageBox.Show("Please enter a valid source file", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } // No destination file selected if (destinationTextBox.Text == "") { MessageBox.Show("Please Enter a Destination File", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } else { // Check to see if destination file exists, // Create it if it doesn't, ask to overwrite if it does if (File.Exists(destinationTextBox.Text)) { if (destinationTextBox.Text == sourceFileTextBox.Text) { MessageBox.Show("Destination file cannot be the same as the source file!", "File Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); return; } DialogResult result = MessageBox.Show(destinationTextBox.Text + " already exists. Do you want to overwrite it?", "Overwrite File?", MessageBoxButtons.YesNo, MessageBoxIcon.Warning); if (result == DialogResult.Yes) { File.Delete(destinationTextBox.Text); } else { return; } } StreamReader sourceFile = new StreamReader(sourceTextBox.Text, true); // Open source file { ArrayList destLineList = new ArrayList(); // List of output instructions String line; // Current working line // First time through file is to create a label list to use for // branch offset and jump address calculations while ((line = sourceFile.ReadLine()) != null) { // Remove whitespaces from beginning and end of line char[] trimWhite = {}; line = line.TrimStart(trimWhite); line = line.TrimEnd(trimWhite); line = line.ToUpper(); // Allos comments with : without creating a label String[] splitLine = Regex.Split(line, "//"); line = splitLine[0].TrimEnd(); if (!line.StartsWith("//") && (line != "")) { if (line.Contains(':')) { LabelPair pair; // Remove whitespaces and get label by itself char[] trimChars = { ':', ' ', '\t' }; String trimmed = line.TrimEnd(trimChars); String[] split = Regex.Split(trimmed, @"\s+"); String lbl = split[0]; pair = new LabelPair(lbl, destLineCount); // Make sure label is not a duplicate if (!labels.Contains(split[0])) { labels.Add(lbl); labelList.Add(pair); } else { // Generate an error if it is a duplicate errorList.Add(new LabelPair(split[0], sourceLineCount)); } } // Get rid of leading tabs else if (line.StartsWith("\t")) { char[] trimChars = { '\t' }; line.TrimStart(trimChars); } // Compensate for jump instructions being expanded into three instructions else if (line.StartsWith("J")) { destLineCount++; destLineCount++; destLineCount++; } // All other instructions need only one line else { destLineCount++; } } } destLineCount = 0; sourceFile.Close(); // Re-open file for second time through sourceFile = new StreamReader(sourceTextBox.Text, true); using (StreamWriter destFile = File.CreateText(destinationTextBox.Text)) { // Second time through file is for actual instruction conversion while ((line = sourceFile.ReadLine()) != null) { // Remove leading and trailing whitespaces char[] trimWhite = { }; line = line.TrimStart(trimWhite); line = line.TrimEnd(trimWhite); line = line.ToUpper(); if (!line.StartsWith("//") && (line != "")) // Ignore comment lines and empty lines { String[] splitLine = Regex.Split(line, "//"); // Ignore comments after instructions line = splitLine[0].TrimEnd(); if (!line.Contains(':')) // Make sure the line is not a label, then parse it as an instruction { sourceFileTextBox.Text += line; sourceFileTextBox.Text += Environment.NewLine; if (line.StartsWith("JAL")) { try { String[] binaryLines = jumpAndLink(line); if (binaryLines[0].Contains("error") || binaryLines[1].Contains("error") || binaryLines[2].Contains("error")) { errorList.Add(new LabelPair(line, sourceLineCount)); } destLineList.Add(binaryLines[0]); destLineList.Add(binaryLines[1]); destLineList.Add(binaryLines[2]); destLineCount++; destLineCount++; destLineCount++; sourceLineCount++; } catch { destLineList.Add("JAL error"); errorList.Add(new LabelPair(line, sourceLineCount)); } } else if (line.StartsWith("J")) // Jump instructions all expand into 3 binary instructions { try { sourceFileTextBox.Text += line; sourceFileTextBox.Text += Environment.NewLine; String[] binaryLines = jump(line); destLineList.Add(binaryLines[0]); destLineList.Add(binaryLines[1]); destLineList.Add(binaryLines[2]); destLineCount++; destLineCount++; destLineCount++; sourceLineCount++; } catch { destLineList.Add("JCond error"); errorList.Add(new LabelPair(line, sourceLineCount)); } } else { String destLine = convertToBinary(line); destLineList.Add(destLine); if (destLine.Contains("error")) { errorList.Add(new LabelPair(line, sourceLineCount)); } destLineCount++; sourceLineCount++; } } else // it is a label { sourceFileTextBox.Text += line; sourceFileTextBox.Text += Environment.NewLine; sourceLineCount++; } } else // It is a comment { sourceLineCount++; } } // Output binary instructions to file and textbox and output Hex to textbox for (int i = 0; i < destLineList.Count; i++) { destFile.WriteLine(destLineList[i]); destFileTextBox.Text += destLineList[i]; destFileTextBox.Text += Environment.NewLine; destHexTextBox.Text += convertBinToHex((String)destLineList[i]); destHexTextBox.Text += Environment.NewLine; } for (int i = 0; i < labelList.Count; i++) { LabelPair currentLabel = (LabelPair)labelList[i]; labelsTextBox.Text += currentLabel.Label + "\t" + currentLabel.LineNum + "\t" + convertUImm8(currentLabel.LineNum.ToString()) + Environment.NewLine; } //pad file to fill 2^14 lines and the map located from 13396 to 14263 int ii; int iii; for (ii = destLineList.Count; ii < 13395; ii++) { destFile.WriteLine("0000000000000000"); } String mapstring = Properties.Resources.PacmanMap1; destFile.Write(mapstring); destFile.Write(Environment.NewLine); for (iii = 14264; iii < 16384; iii++) { destFile.WriteLine("0000000000000000"); } destFile.Write("0000000000000000"); destFile.Close(); } sourceFile.Close(); } // If there were errors, generate the message with a list of the errors and their source file line numbers if (errorList.Count != 0) { ErrorForm errorForm = new ErrorForm(); errorForm.errorTextBox.Text = ""; foreach (LabelPair error in errorList) { errorForm.errorTextBox.Text += error.LineNum + "\t" + error.Label + Environment.NewLine; } errorForm.Show(); } } }
// Converts an assembly instruction into a binary machine code instruction private String convertToBinary(String assembly) { String[] instruction = Regex.Split(assembly, @"\s+"); // split on white spaces String OpCode = ""; String OpExt = ""; String Rsrc = ""; String Rdest = ""; String Raddr = ""; String Ramount = ""; String Imm = ""; String Cond = ""; String Disp = ""; String binary = ""; // NOP Assembly format = INST if (instruction[0] == "NOP") { binary = "0000000000000000"; } // ADD Assembly format = INST Rsrc Rdest else if (instruction[0] == "ADD") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "0101"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // ADDI Assembly format = INST Imm Rdest else if (instruction[0] == "ADDI") { short Immediate = Convert.ToInt16(instruction[1]); if ((-128 <= Immediate) && (Immediate <= 127)) // Make sure it is within 8 bit signed range { OpCode = "0101"; Imm = convertImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // ADDU Assembly format = INST Rsrc Rdest else if (instruction[0] == "ADDU") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "0110"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // ADDUI Assembly format = INST Imm Rdest else if (instruction[0] == "ADDUI") { short Immediate = Convert.ToInt16(instruction[1]); if ((0 <= Immediate) && (Immediate <= 255)) // Make sure it is within 8 bit unsigned range { OpCode = "0110"; Imm = convertUImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // ADDC Assembly format = INST Rsrc Rdest else if (instruction[0] == "ADDC") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "0111"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // ADDCI Assembly format = INST Imm Rdest else if (instruction[0] == "ADDCI") { short Immediate = Convert.ToInt16(instruction[1]); if ((-128 <= Immediate) && (Immediate <= 127)) // Make sure it is within 8 bit signed range { OpCode = "0111"; Imm = convertImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // MUL Assembly format = INST Rsrc Rdest else if (instruction[0] == "MUL") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "1110"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // MULI Assembly format = INST Imm Rdest else if (instruction[0] == "MULI") { short Immediate = Convert.ToInt16(instruction[1]); if ((-128 <= Immediate) && (Immediate <= 127)) // Make sure it is within 8 bit signed range { OpCode = "1110"; Imm = convertImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // SUB Assembly format = INST Rsrc Rdest else if (instruction[0] == "SUB") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "1001"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // SUBI Assembly format = INST Imm Rdest else if (instruction[0] == "SUBI") { short Immediate = Convert.ToInt16(instruction[1]); if ((-128 <= Immediate) && (Immediate <= 127)) // Make sure it is within 8 bit signed range { OpCode = "1001"; Imm = convertImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // SUBC Assembly format = INST Rsrc Rdest else if (instruction[0] == "SUBC") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "1010"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // SUBCI Assembly format = INST Imm Rdest else if (instruction[0] == "SUBCI") { short Immediate = Convert.ToInt16(instruction[1]); if ((-128 <= Immediate) && (Immediate <= 127)) // Make sure it is within 8 bit signed range { OpCode = "1010"; Imm = convertImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // CMP Assembly format = INST Rsrc Rdest else if (instruction[0] == "CMP") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "1011"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // CMPI Assembly format = INST Imm Rdest else if (instruction[0] == "CMPI") { short Immediate = Convert.ToInt16(instruction[1]); if ((0 <= Immediate) && (Immediate <= 255)) // Make sure it is within 8 bit unsigned range { OpCode = "1011"; Imm = convertImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } OpCode = "1011"; Imm = convertImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } // AND Assembly format = INST Rsrc Rdest else if (instruction[0] == "AND") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "0001"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // ANDI Assembly format = INST Imm Rdest else if (instruction[0] == "ANDI") { short Immediate = Convert.ToInt16(instruction[1]); if ((0 <= Immediate) && (Immediate <= 255)) // Make sure it is within 8 bit unsigned range { OpCode = "0001"; Imm = convertUImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // OR Assembly format = INST Rsrc Rdest else if (instruction[0] == "OR") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "0010"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // ORI Assembly format = INST Imm Rdest else if (instruction[0] == "ORI") { short Immediate = Convert.ToInt16(instruction[1]); if ((0 <= Immediate) && (Immediate <= 255)) // Make sure it is within 8 bit unsigned range { OpCode = "0010"; Imm = convertUImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // XOR Assembly format = INST Rsrc Rdest else if (instruction[0] == "XOR") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "0011"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // XORI Assembly format = INST Imm Rdest else if (instruction[0] == "XORI") { short Immediate = Convert.ToInt16(instruction[1]); if ((0 <= Immediate) && (Immediate <= 255)) // Make sure it is within 8 bit unsigned range { OpCode = "0011"; Imm = convertUImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // MOV Assembly format = INST Rsrc Rdest else if (instruction[0] == "MOV") { OpCode = "0000"; Rsrc = convertReg(instruction[1]); OpExt = "1101"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // MOVI Assembly format = INST Imm Rdest else if (instruction[0] == "MOVI") { short Immediate = Convert.ToInt16(instruction[1]); if ((0 <= Immediate) && (Immediate <= 255)) // Make sure it is within 8 bit unsigned range { OpCode = "1101"; Imm = convertUImm8(instruction[1]); Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // LSH Assembly format = INST Ramount Rdest else if (instruction[0] == "LSH") { OpCode = "1000"; Ramount = convertReg(instruction[1]); OpExt = "0100"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Ramount; } // LSHI Assembly format = INST Imm Rdest else if (instruction[0] == "LSHI") { short Immediate = Convert.ToInt16(instruction[1]); if ((0 <= Immediate) && (Immediate <= 255)) // Make sure it is within 8 bit unsigned range { OpCode = "1000"; Imm = "000" + convertImm5(instruction[1]); // 5 bit 2's compliment padded to 8 bits Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + Imm; } else { binary = "Imm range error"; } } // ASHU Assembly format = INST Ramount Rdest else if (instruction[0] == "ASHU") { OpCode = "1000"; Rdest = convertReg(instruction[2]); Ramount = convertReg(instruction[1]); // 2's comp (-15 to 15) OpExt = "0110"; binary = OpCode + Rdest + OpExt + Ramount; } // ASHUI Assembly format = INST Imm Rdest else if (instruction[0] == "ASHUI") { OpCode = "1000"; Rdest = convertReg(instruction[2]); Imm = "001" + convertImm5(instruction[1]); binary = OpCode + Rdest + Imm; } // LUI Assembly format = INST Imm Rdest else if (instruction[0] == "LUI") { OpCode = "1111"; Rdest = convertReg(instruction[2]); Imm = convertUImm8(instruction[1]); binary = OpCode + Rdest + Imm; } // LOAD Assembly format = INST Rdest Raddr else if (instruction[0] == "LOAD") { OpCode = "0100"; Rdest = convertReg(instruction[1]); OpExt = "0000"; Raddr = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Raddr; } // STOR Assembly format = INST Rsrc Raddr else if (instruction[0] == "STOR") { OpCode = "0100"; Rsrc = convertReg(instruction[1]); OpExt = "0100"; Raddr = convertReg(instruction[2]); binary = OpCode + Rsrc + OpExt + Raddr; } // SNXB Assembly format = INST Rsrc Rdest else if (instruction[0] == "SNXB") { OpCode = "0100"; Rsrc = convertReg(instruction[1]); OpExt = "0000"; Rdest = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Rsrc; } // ZRXB Assembly format = INST Rsrc Rdest else if (instruction[0] == "ZRXB") { OpCode = "0100"; Rdest = convertReg(instruction[1]); OpExt = "0010"; Raddr = convertReg(instruction[2]); binary = OpCode + Rdest + OpExt + Raddr; } // SCOND Assembly format = INST Rdest else if ((instruction[0] == "SEQ") || (instruction[0] == "SNE") || (instruction[0] == "SGE") || (instruction[0] == "SCS") || (instruction[0] == "SCC") || (instruction[0] == "SHI") || (instruction[0] == "SLS") || (instruction[0] == "SLO") || (instruction[0] == "SHS") || (instruction[0] == "SGT") || (instruction[0] == "SLE") || (instruction[0] == "SFS") || (instruction[0] == "SFC") || (instruction[0] == "SLT") || (instruction[0] == "SUC") || (instruction[0] == "S")) { String condition = instruction[0].TrimStart('S'); OpCode = "0100"; Rdest = convertReg(instruction[1]); OpExt = "1101"; Cond = convertCondition(condition); binary = OpCode + Rdest + OpExt + Cond; } // BCOND Assembly format = INST Label - Automatically calculate branch offsets for a given label else if ((instruction[0] == "BEQ") || (instruction[0] == "BNE") || (instruction[0] == "BGE") || (instruction[0] == "BCS") || (instruction[0] == "BCC") || (instruction[0] == "BHI") || (instruction[0] == "BLS") || (instruction[0] == "BLO") || (instruction[0] == "BHS") || (instruction[0] == "BGT") || (instruction[0] == "BLE") || (instruction[0] == "BFS") || (instruction[0] == "BFC") || (instruction[0] == "BLT") || (instruction[0] == "BUC") || (instruction[0] == "B")) { String condition = instruction[0].TrimStart('B'); OpCode = "1100"; if (labels.Contains(instruction[1])) // Make sure it is a valid label { LabelPair labelLocation = (LabelPair)labelList[labels.IndexOf(instruction[1])]; Disp = convertDisp8(labelLocation.LineNum, destLineCount); } else // Treat it as a number displacement { int Num; bool isNum = int.TryParse(instruction[1], out Num); if (isNum) { Disp = convertImm8(Num.ToString()); } else { Disp = convertImm8(instruction[1]); } } Cond = convertCondition(condition); binary = OpCode + Cond + Disp; } // DI Assembly format = INST else if (instruction[0] == "DI") { binary = "0100000000110000"; } // EI Assembly format = INST else if (instruction[0] == "EI") { binary = "0100000001110000"; } // RETX Assembly format = INST else if (instruction[0] == "RETX") { binary = "0100000010011111"; // Always returns to address in R15 (1111) } // WAIT Assembly format = INST else if (instruction[0] == "WAIT") { binary = "0000000010010000"; } else { binary = "error"; } return(binary); }