/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } IEnumerable <int> returnVal = null; int instruction = 0; int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(args[1]); int rs2Reg = 0; try { rs2Reg = RegisterMap.GetNumericRegisterValue(args[2]); List <int> instructionList = new List <int>(); instruction |= 0x2000000; instruction |= (rs2Reg << 20); instruction |= (rs1Reg << 15); instruction |= (0x6 << 12); instruction |= (rdReg << 7); instruction |= 0x33; instructionList.Add(instruction); returnVal = instructionList; } catch (ArgumentException) { throw; } return(returnVal); }
/// <summary> /// Takes an argument (e.g. 4(x9)) and parameterizes it into the offset component /// and its numeric register ID. /// </summary> /// <param name="trimmedArgToken">The token to parameterize, with whitespace trimmed on both left/right sides.</param> /// <returns>A parameterized register/offset structure.</returns> public static ParameterizedInstructionArg ParameterizeArgument(string trimmedArgToken) { string[] parameterizedArgs = trimmedArgToken.Split(new[] { '(', ')' }, StringSplitOptions.RemoveEmptyEntries).Apply((str) => str.Trim()).ToArray(); // we should expect one or two arguments. if (parameterizedArgs.Length != 1 && parameterizedArgs.Length != 2) { throw new ArgumentException(trimmedArgToken + " was not in a valid format."); } ParameterizedInstructionArg retVal = default(ParameterizedInstructionArg); // if we have one argument, assume its the register name, and that the offset is 0. if (parameterizedArgs.Length == 1) { int registerId = RegisterMap.GetNumericRegisterValue(parameterizedArgs[0]); retVal = new ParameterizedInstructionArg(0, registerId); } else { bool isValidOffset = IntExtensions.TryParseEx(parameterizedArgs[0], out short offsetVal) && ((offsetVal & 0xF000) == 0); if (!isValidOffset) { throw new ArgumentException(parameterizedArgs[0] + " is not a valid 12-bit offset."); } int registerId = RegisterMap.GetNumericRegisterValue(parameterizedArgs[1]); retVal = new ParameterizedInstructionArg(offsetVal, registerId); } return(retVal); }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int nextTextAddress, string[] args) { if (args.Length != 2) { throw new ArgumentException("Invalid number of arguments provided. Expected 2, received " + args.Length + '.'); } int rs2 = RegisterMap.GetNumericRegisterValue(args[0]); var retList = new List <int>(); ParameterizedInstructionArg arg = ParameterizedInstructionArg.ParameterizeArgument(args[1]); int instruction = 0; int upperOffset = (arg.Offset & 0xFE0); int lowerOffset = (arg.Offset & 0x1F); instruction |= (upperOffset << 25); instruction |= (rs2 << 20); instruction |= (arg.Register << 15); byte funcCode = GetFunctionCode(); instruction |= (funcCode << 12); instruction |= (lowerOffset << 7); instruction |= 0x23; retList.Add(instruction); return(retList); }
public void Execute(string[] args) { try { int regIdx = -1; string regName = args[0]; if (RegisterMap.IsNamedIntegerRegister(regName)) { regIdx = RegisterMap.GetNumericRegisterValue(regName); m_Terminal.PrintString("\t" + regName + " = " + m_Registers.UserIntRegisters[regIdx].Value + '\n'); } else if (RegisterMap.IsNamedFloatingPointRegister(regName)) { regIdx = RegisterMap.GetNumericFloatingPointRegisterValue(regName); m_Terminal.PrintString("\t" + regName + " = " + m_Registers.UserFloatingPointRegisters[regIdx].Value + '\n'); } else { throw new ParseException(regName + " is not a valid integer register name."); } } catch (Exception ex) { m_Terminal.PrintString(ex.Message + '\n'); } }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect two arguments. if not, throw an ArgumentException if (args.Length != 2) { throw new ArgumentException("Invalid number of arguments provided. Expected 2, received " + args.Length + '.'); } string rs1 = args[0].Trim(); string immediateStr = args[1].Trim(); int immediate = 0; if (!IntExtensions.TryParseEx(immediateStr, out immediate)) { throw new ArgumentException("auipc - argument 2 was non-integer immediate value."); } int rs1Reg = RegisterMap.GetNumericRegisterValue(rs1); // shift this such that int bitShiftedImm = immediate << 12; int instruction = 0; instruction |= bitShiftedImm; instruction |= (rs1Reg << 7); instruction |= 0x17; var inList = new List <int>(); inList.Add(instruction); return(inList); }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } string rd = args[0].Trim(); string rs1 = args[1].Trim(); string rs2 = args[2].Trim(); IEnumerable <int> returnVal = null; int instruction = 0; int rdReg = RegisterMap.GetNumericRegisterValue(rd); int rs1Reg = RegisterMap.GetNumericRegisterValue(rs1); int rs2Reg = 0; try { rs2Reg = RegisterMap.GetNumericRegisterValue(rs2); List <int> instructionList = new List <int>(); instruction |= (rs2Reg << 20); instruction |= (rs1Reg << 15); instruction |= (0x7 << 12); instruction |= (rdReg << 7); instruction |= 0x33; instructionList.Add(instruction); returnVal = instructionList; } catch (ArgumentException) { // try to parse the string as a number; maybe the user meant andi? short immediate = 0; bool isShort = IntExtensions.TryParseEx(rs2, out immediate); if (isShort) { var immediateParser = new AndiProcessor(); returnVal = immediateParser.GenerateCodeForInstruction(address, args); } else { // otherwise, this is garbage; rethrow the value. throw; } } return(returnVal); }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } IEnumerable <int> returnVal = null; int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(args[1]); int shiftAmt = 0; bool isValidImmediate = IntExtensions.TryParseEx(args[2], out shiftAmt); // ensure our shift amount is 5 bits or less. isValidImmediate = isValidImmediate && ((shiftAmt & 0xFFFFFFE0) == 0); var instructionList = new List <int>(); if (isValidImmediate) { int instruction = 0; instruction |= (0x1 << 30); instruction |= (shiftAmt << 20); instruction |= (rs1Reg << 15); instruction |= (0x5 << 12); instruction |= (rdReg << 7); instruction |= 0x13; instructionList.Add(instruction); returnVal = instructionList; } else { // otherwise, emit three instructions. load the upper 20 bits of the immediate into the destination register, // bitwise-or it with the remaining 12 bits, and then shift the target register by the destination register. var luiProc = new LuiProcessor(); instructionList.AddRange(luiProc.GenerateCodeForInstruction(address, new string[] { args[0], (shiftAmt >> 12).ToString() })); int orImmVal = shiftAmt & 0xFFF; var oriProc = new OriProcessor(); instructionList.AddRange(oriProc.GenerateCodeForInstruction(address, new string[] { args[0], orImmVal.ToString() })); var sraProc = new SraProcessor(); instructionList.AddRange(sraProc.GenerateCodeForInstruction(address, new string[] { args[0], args[1], args[0] })); } return(returnVal); }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } IEnumerable <int> returnVal = null; int instruction = 0; int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(args[1]); int rs2Reg = 0; try { rs2Reg = RegisterMap.GetNumericRegisterValue(args[2]); List <int> instructionList = new List <int>(); instruction |= (rs2Reg << 20); instruction |= (rs1Reg << 15); // or opcode/funt3/funct7 = 0x33/0x6/0x0 instruction |= (0x6 << 12); instruction |= (rdReg << 7); instruction |= 0x33; instructionList.Add(instruction); returnVal = instructionList; } catch (ArgumentException) { // try parsing as ori instruction int immediate = 0; bool isShort = IntExtensions.TryParseEx(args[2], out immediate); if (isShort) { var immediateParser = new OriProcessor(); returnVal = immediateParser.GenerateCodeForInstruction(address, args); } else { throw; } } return(returnVal); }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(args[1]); uint immVal = 0; bool isValidImmediate = IntExtensions.TryParseEx(args[2], out immVal); // this is okay, as we expect an unsigned value. isValidImmediate = isValidImmediate && ((immVal & 0xFFFFF000) == 0); var instructionList = new List <int>(); if (isValidImmediate) { int instruction = GenerateUnexpandedInstruction(immVal, rs1Reg, rdReg); instructionList.Add(instruction); } else { // otherwise, emit three instructions. load the upper 20 bits of the immediate into the destination register, // bitwise-or it with the remaining 12 bits, and then use sltu (the s-type). var luiProc = new LuiProcessor(); instructionList.AddRange(luiProc.GenerateCodeForInstruction(address, new string[] { args[0], (immVal >> 12).ToString() })); uint orImmVal = immVal & 0xFFF; var oriProc = new OriProcessor(); instructionList.AddRange(oriProc.GenerateCodeForInstruction(address, new string[] { args[0], orImmVal.ToString() })); var sltuProc = new SltuProcessor(); instructionList.AddRange(sltuProc.GenerateCodeForInstruction(address, new string[] { args[0], args[1], args[0] })); } return(instructionList); }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(args[1]); int immVal = 0; bool isValidImmediate = IntExtensions.TryParseEx(args[2], out immVal); if (isValidImmediate) { var instructionList = new List <int>(); // if the immediate is greater than 12 bits, use // an auipc instruction. if (!IsValidTwelveBitSignedImmediate(immVal)) { var auipcHelper = new AuipcProcessor(); IEnumerable <int> auipcInstructions = auipcHelper.GenerateCodeForInstruction(address, new string[] { args[1], (immVal >> 12).ToString() }); instructionList.AddRange(auipcInstructions); } int instruction = 0; instruction |= (immVal << 20); instruction |= (rs1Reg << 15); instruction |= (rdReg << 7); instruction |= 0x67; instructionList.Add(instruction); return(instructionList); } else { throw new ArgumentException("Immediate was not a valid 32-bit integer."); } }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { if (args.Length != 2) { throw new ArgumentException("Invalid number of arguments provided. Expected 2, received " + args.Length + '.'); } int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); var retList = new List <int>(); byte funcCode = GetFunctionCode(); if (IsParameterizedToken(args[1])) { ParameterizedInstructionArg arg = ParameterizedInstructionArg.ParameterizeArgument(args[1]); int instruction = 0; instruction |= ((arg.Offset & 0xFFF) << 20); instruction |= (arg.Register << 15); instruction |= (funcCode << 12); instruction |= (rdReg << 7); instruction |= 0x3; retList.Add(instruction); } else { Symbol sym = SymbolTable.GetSymbol(args[1]); int shiftedAddress = sym.Address >> 12; retList.AddRange(new LuiProcessor().GenerateCodeForInstruction(address, new[] { args[0], shiftedAddress.ToString() })); int numericOffset = sym.Address & 0xFFF; int instruction = 0; instruction |= (numericOffset << 20); instruction |= (rdReg << 15); instruction |= (funcCode << 12); instruction |= (rdReg << 7); instruction |= 0x3; retList.Add(instruction); } return(retList); }
public void Execute(string[] args) { try { string regName = args[0]; if (IntExtensions.TryParseEx(args[1], out int iValue)) { if (RegisterMap.IsNamedIntegerRegister(regName)) { int regIdx = RegisterMap.GetNumericRegisterValue(regName); m_Registers.UserIntRegisters[regIdx].Value = iValue; m_Terminal.PrintString("\t" + regName + " = " + iValue + '\n'); } else { throw new ParseException(regName + " was not a valid register name."); } } else if (FloatExtensions.TryParseEx(args[1], out float fValue)) { if (RegisterMap.IsNamedFloatingPointRegister(regName)) { int regIdx = RegisterMap.GetNumericFloatingPointRegisterValue(regName); m_Registers.UserFloatingPointRegisters[regIdx].Value = fValue; m_Terminal.PrintString("\t" + regName + " = " + fValue + '\n'); } else { throw new ParseException(regName + " was not a valid register name."); } } else { throw new ParseException(args[1] + " was not a valid 32-bit value"); } } catch (Exception ex) { m_Terminal.PrintString(ex.Message + '\n'); } }
public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] instructionArgs) { // we expect three arguments. if not, throw an ArgumentException if (instructionArgs.Length != 2) { throw new ArgumentException("Invalid number of arguments provided. Expected 2, received " + instructionArgs.Length + '.'); } const int BASE_OPCODE = 0x53; int rdReg = RegisterMap.GetNumericFloatingPointRegisterValue(instructionArgs[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(instructionArgs[1]); int outputInst = (0x1A << 27) | (rs1Reg << 15) | (rdReg << 7) | BASE_OPCODE; var instList = new List <int> { outputInst }; return(instList); }
public void Execute(string[] args) { try { string fmtString = args[1]; if (fmtString.Contains("\"")) { fmtString = fmtString.Replace("\"", string.Empty); } fmtString = fmtString.Trim(); int regIdx = -1; string regName = string.Empty; if (RegisterMap.IsNamedIntegerRegister(args[0])) { regIdx = RegisterMap.GetNumericRegisterValue(args[0]); regName = args[0]; m_Terminal.PrintString("\t" + regName + " = " + m_Registers.UserIntRegisters[regIdx].Value.ToString(fmtString) + '\n'); } else if (RegisterMap.IsNamedFloatingPointRegister(args[0])) { regIdx = RegisterMap.GetNumericFloatingPointRegisterValue(args[0]); regName = args[0]; m_Terminal.PrintString("\t" + regName + " = " + m_Registers.UserFloatingPointRegisters[regIdx].Value.ToString(fmtString) + '\n'); } else { throw new ParseException(regIdx + " was not a valid register name."); } } catch (Exception ex) { m_Terminal.PrintString(ex.Message + '\n'); } }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(args[1]); int immVal = 0; bool isValidImmediate = IntExtensions.TryParseEx(args[2], out immVal); if (isValidImmediate) { var instructionList = default(List <int>); // see if this is a valid 12 bit immediate. // if it is greater, treat this as a pseudo instruction and generate // underlying code to support it. otherwise, use the real andi instruction. if (!IsValidTwelveBitSignedImmediate(immVal)) { instructionList = GenerateExpandedInstruction(address, immVal, args); } else { instructionList = new List <int>(); int instruction = GenerateUnexpandedInstruction(immVal, rs1Reg, rdReg); instructionList.Add(instruction); } return(instructionList); } else { throw new ArgumentException(args[2] + " is not a valid immediate value."); } }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); int rs1Reg = RegisterMap.GetNumericRegisterValue(args[1]); int immVal = 0; bool isValidImmediate = IntExtensions.TryParseEx(args[2], out immVal); if (isValidImmediate) { var instructionList = default(List <int>); // if the mask is greater not zero, this would indicate that there are bits beyond the 11th bit offset. // help the user by generating equivalent s-type instructions if (!IsValidTwelveBitSignedImmediate(immVal)) { instructionList = GenerateExpandedInstruction(address, immVal, args); } else { instructionList = new List <int>(); int instruction = GenerateUnexpandedInstruction(immVal, rs1Reg, rdReg); instructionList.Add(instruction); } return(instructionList); } else { throw new ArgumentException(args[2] + " is not a valid immediate value."); } }
/// <summary> /// Parses an instruction and generates the binary code for it. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect two arguments. if not, throw an ArgumentException if (args.Length != 2) { throw new ArgumentException("Invalid number of arguments provided. Expected 2, received " + args.Length + '.'); } int rdReg = RegisterMap.GetNumericRegisterValue(args[0]); #if DEBUG int targetAddress = 0; if (SymbolTable.ContainsSymbol(args[1])) { Symbol symbolLabel = SymbolTable.GetSymbol(args[1]); targetAddress = symbolLabel.Address; } else if (!IntExtensions.TryParseEx(args[1], out targetAddress)) { throw new ArgumentException(args[1] + " was not a symbol name or valid 32-bit address."); } var instructionList = new List <int>(); // the offset is doubled implicitly by the processor, so halve it here. int offset = (targetAddress - address); // this should rarely happen, but if the halved immediate exceeds the 21 bit boundary, // error out and notify the user. if ((Math.Abs(offset / 2) & 0xFFE00000) != 0) { throw new ArgumentException("jal - the offset between the address of \"0x" + targetAddress.ToString("X") + "\"" + " and this instruction address (0x" + address.ToString("X") + ") exceeds the 21 bit immediate limit. Use jalr instead."); } #else Symbol symbolLabel = SymbolTable.GetSymbol(args[1]); var instructionList = new List <int>(); // the offset is doubled implicitly by the processor, so halve it here. int offset = (symbolLabel.Address - address); // this should rarely happen, but if the halved immediate exceeds the 21 bit boundary, // error out and notify the user. if ((Math.Abs(offset / 2) & 0xFFE00000) != 0) { throw new ArgumentException("jal - the offset between the address of \"" + symbolLabel.LabelName + "\"" + " (0x" + symbolLabel.Address.ToString("X") + " and this instruction address (0x" + address.ToString("X") + ") exceeds the 21 bit immediate limit. Use jalr instead."); } #endif int instruction = 0; // get the twentieth bit offset (21st bit) of the offset value // and shift it to the 31st bit offset. instruction |= ((offset & 0x100000) << 11); // get the 10-1 bit offsets and shift that range to the 30-20 offset. instruction |= ((offset & 0x7FE) << 20); // get the 11th bit offset and shift it to offset 20. instruction |= ((offset & 0x800) << 9); // get the 19-12 bit offsets and shift them to position 18-11 instruction |= ((offset & 0xFF000)); // shift the rd register value up to offset 11-7 instruction |= (rdReg << 7); instruction |= 0x6F; instructionList.Add(instruction); return(instructionList); }
/// <summary> /// Generates the basic code for a branch instruction by delegating to implementing classes /// to provide a function code. /// </summary> /// <param name="address">The address of the instruction being parsed in the .text segment.</param> /// <param name="args">An array containing the arguments of the instruction.</param> /// <returns>One or more 32-bit integers representing this instruction. If this interface is implemented /// for a pseudo-instruction, this may return more than one instruction value.</returns> public override IEnumerable <int> GenerateCodeForInstruction(int address, string[] args) { // we expect three arguments. if not, throw an ArgumentException if (args.Length != 3) { throw new ArgumentException("Invalid number of arguments provided. Expected 3, received " + args.Length + '.'); } int rs1Reg = RegisterMap.GetNumericRegisterValue(args[0]); int rs2Reg = RegisterMap.GetNumericRegisterValue(args[1]); Symbol symbolLabel = SymbolTable.GetSymbol(args[2]); // the instruction should always have a last two bits of 0, since they're word aligned. System.Diagnostics.Debug.Assert((symbolLabel.Address & 0x3) == 0); // find the difference between the jump-to address and the theoretical next address. // note that the processor internally doubles this value, so we halve it here. int offset = (symbolLabel.Address - address); // if the offset is greater than the 12 bit immediate, // throw an error so that bad code isn't silently generated. if (!IsValidTwelveBitSignedImmediate(Math.Abs(offset))) { throw new ArgumentException("The offset between the address of \"" + symbolLabel.LabelName + "\"" + " (0x" + symbolLabel.Address.ToString("X") + " and this instruction address (0x" + address.ToString("X") + ") exceeds the 12 bit immediate limit."); } // this is a B-type instruction, so bits go all over the place. // last bit is ignored, since it would be zero anyway. // get the thirteenth (offset 12) bit of the immediate (counting from zero), and shift it to the end. int offset0 = offset & 0x1000; int instruction = 0; instruction |= (offset0 << 19); // get the 11-6 (offsets 10-5) bits of the immediate. int offset1 = offset & 0x7E0; instruction |= (offset1 << 20); instruction |= (rs2Reg << 20); instruction |= (rs1Reg << 15); // Get the implementation function code, and move it into position byte funcCode = GetFunctionCode(); instruction |= (funcCode << 12); // get the 5-2 (offsets 4-1) bits of the immediate // they belong in the 11-8th offset of the code, so left shift by 7 bits. int offset2 = offset & 0x1E; instruction |= (offset2 << 7); // get the 12th (offset 11) bit of the immediate. // this belongs in the 7th offset, so we need to bit shift it right by 4. int offset3 = offset & 0x800; instruction |= (offset3 >> 4); instruction |= 0x63; var instructionList = new List <int>(); instructionList.Add(instruction); return(instructionList); }