/// <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> /// Generates a list of instructions for the ADDI instruction, given that the immediate argument /// is larger than 11 bits (neglecting the sign bit). /// </summary> /// <param name="address">The next address in the .text segment.</param> /// <param name="immediate"></param> /// <param name="args"></param> /// <returns></returns> private List <int> GenerateExpandedInstruction(int address, int immediate, string[] args) { // load the upper 20 bits of the immediate into the destination register int shiftedImm = immediate >> 12; IEnumerable <int> backingLuiInstructions = new LuiProcessor().GenerateCodeForInstruction(address, new[] { args[0], shiftedImm.ToString() }); // or that with the lower 12 bits of that immediate. IEnumerable <int> backingOriInstructions = new OriProcessor().GenerateCodeForInstruction(address, new[] { args[0], args[0], (immediate & 0xFFF).ToString() }); // add the value of what we have in our register with the rs1 register. IEnumerable <int> backingAddInstructions = new AddProcessor().GenerateCodeForInstruction(address, new[] { args[0], args[0], args[1] }); var instructionList = new List <int>(); instructionList.AddRange(backingLuiInstructions); instructionList.AddRange(backingOriInstructions); instructionList.AddRange(backingAddInstructions); return(instructionList); }