public Instruction[] AssembleInstructions(ref uint pc, string line, List <AssemblerPatch> patches) { line = line.Trim(); if (line.Length == 0) { return new Instruction[] { } } ; int vfpuSize = 0; var lineTokens = line.Split(new[] { ' ', '\t' }, 2); var instructionName = lineTokens[0].ToLower(); InstructionInfo instructionInfo; if (instructionName.EndsWith(".s")) { vfpuSize = 1; } if (instructionName.EndsWith(".p")) { vfpuSize = 2; } if (instructionName.EndsWith(".t")) { vfpuSize = 3; } if (instructionName.EndsWith(".q")) { vfpuSize = 4; } if (!Instructions.ContainsKey(instructionName)) { // Vfpu instruction with suffix. if (vfpuSize > 0) { instructionName.Substr(-2); instructionName = instructionName.Substr(0, -2); } } if (Instructions.TryGetValue(instructionName, out instructionInfo)) { var instruction = new Instruction() { Value = instructionInfo.Value & instructionInfo.Mask, }; if (vfpuSize > 0) { instruction.OneTwo = vfpuSize; } var matches = Matcher(instructionInfo.AsmEncoding, lineTokens.Length > 1 ? lineTokens[1] : ""); foreach (var match in matches) { var key = match.Key; var value = match.Value; switch (key) { // VFPU // Vector registers case "%zs": case "%zp": case "%zt": case "%zq": case "%zm": instruction.Vd = ParseVfprName(vfpuSize, value); break; case "%ys": case "%yp": case "%yt": case "%yq": case "%ym": case "%yn": case "%tym": if (key == "%tym") { value = (value[0] == 'M' ? 'E' : 'M') + value.Substring(1); } instruction.Vs = ParseVfprName(vfpuSize, value); break; case "%xs": case "%xp": case "%xt": case "%xq": case "%xm": instruction.Vt = ParseVfprName(vfpuSize, value); break; case "%vk": instruction.Imm5 = ParseVfprConstantName(value); break; case "%vr": instruction.Imm5 = ParseVfprRotate(value); break; //case "%zm": throw(new NotImplementedException("zm")); // sv.q %Xq, %Y case "%Xq": instruction.Vt51 = ParseVfprName(vfpuSize, value); break; case "%Y": { var info = ParseVfprOffset(vfpuSize, value); if (info.Offset % 4 != 0) { throw new Exception("Offset must be multiple of 4"); } instruction.Imm14 = info.Offset / 4; instruction.Rs = info.Rs; } break; // VFPU: prefixes (source/target) case "%vp0": case "%vp1": case "%vp2": case "%vp3": { var index = int.Parse(key.Substr(-1)); VfpuPrefix vfpuPrefix = instruction.Value; ParseAndUpdateVfprSourceTargetPrefix(index, value, ref vfpuPrefix); instruction.Value = vfpuPrefix; } break; // VFPU: prefixes (destination) case "%vp4": case "%vp5": case "%vp6": case "%vp7": { var index = int.Parse(key.Substr(-1)) - 4; VfpuDestinationPrefix vfpuPrefix = instruction.Value; ParseAndUpdateVfprDestinationPrefix(index, value, ref vfpuPrefix); instruction.Value = vfpuPrefix; } break; //case "%xs": Instruction.VD = ParseVfprName(VfpuSize, Value); break; // FPU case "%S": instruction.Fs = ParseFprName(value); break; case "%D": instruction.Fd = ParseFprName(value); break; case "%T": instruction.Ft = ParseFprName(value); break; // CPU case "%J": case "%s": instruction.Rs = ParseGprName(value); break; case "%d": instruction.Rd = ParseGprName(value); break; case "%t": instruction.Rt = ParseGprName(value); break; case "%a": instruction.Pos = (uint)ParseIntegerConstant(value); break; case "%ne": instruction.SizeE = (uint)ParseIntegerConstant(value); break; case "%ni": instruction.SizeI = (uint)ParseIntegerConstant(value); break; case "%p": instruction.Rd = ParseIntegerConstant(value); break; case "%c": case "%C": instruction.Code = (uint)ParseIntegerConstant(value); break; case "%vi": case "%i": instruction.Imm = ParseIntegerConstant(value); break; case "%I": instruction.Immu = (uint)ParseIntegerConstant(value); break; case "%j": patches.Add(new AssemblerPatch() { Address = pc, LabelName = value, Type = AssemblerPatchType.Abs26 }); break; case "%O": patches.Add(new AssemblerPatch() { Address = pc, LabelName = value, Type = AssemblerPatchType.Rel16 }); break; default: throw new InvalidDataException( $"Unknown format \'{key}\' <-- ({instructionInfo.AsmEncoding})" ); } } /* * if ((InstructionInfo.InstructionType & InstructionType.B) != 0) * { * //Patches.Add(new Patch() { Address = PC, LabelName = }); * } * else if ((InstructionInfo.InstructionType & InstructionType.Jump) != 0) * { * } */ pc += 4; return(new[] { instruction }); } else { switch (instructionName) { case "nop": { //return AssembleInstructions(ref PC, "sll r0, r0, r0"); return(AssembleInstructions(ref pc, "and r0, r0, r0", patches)); } case "b": { var info = Matcher("%O", lineTokens[1]); return(AssembleInstructions(ref pc, $"beq r0, r0, {info["%O"]}", patches)); } case "li": { var info = Matcher("%d, %i", lineTokens[1]); var destReg = info["%d"]; var value = ParseIntegerConstant(info["%i"]); // Needs LUI if ((short)value != value) { var list = new List <Instruction>(); list.AddRange(AssembleInstructions(ref pc, "lui " + destReg + ", " + ((value >> 16) & 0xFFFF), patches)); list.AddRange(AssembleInstructions(ref pc, "ori " + destReg + ", " + destReg + ", " + (value & 0xFFFF), patches)); //Console.WriteLine(List.ToJson()); return(list.ToArray()); } else { return(AssembleInstructions(ref pc, "addi " + destReg + ", r0, " + value, patches)); } } default: throw new InvalidOperationException("Unknown instruction type '" + instructionName + "'"); } } }
public static void ParseAndUpdateVfprSourceTargetPrefix(int index, string registerName, ref VfpuPrefix vfpuPrefix) { int setIndex; bool isConstant; registerName = registerName.Replace(" ", ""); if (registerName.StartsWith("-")) { registerName = registerName.Substr(1); vfpuPrefix.SourceNegate(index, true); } if (registerName.StartsWith("|") && registerName.EndsWith("|")) { registerName = registerName.Substr(1, -1); vfpuPrefix.SourceAbsolute(index, true); } switch (registerName) { case "x": isConstant = false; setIndex = 0; break; case "y": isConstant = false; setIndex = 1; break; case "z": isConstant = false; setIndex = 2; break; case "w": isConstant = false; setIndex = 3; break; case "3": isConstant = true; setIndex = 0; vfpuPrefix.SourceAbsolute(index, true); break; case "0": isConstant = true; setIndex = 0; vfpuPrefix.SourceAbsolute(index, false); break; case "1/3": isConstant = true; setIndex = 1; vfpuPrefix.SourceAbsolute(index, true); break; case "1": isConstant = true; setIndex = 1; vfpuPrefix.SourceAbsolute(index, false); break; case "1/4": isConstant = true; setIndex = 2; vfpuPrefix.SourceAbsolute(index, true); break; case "2": isConstant = true; setIndex = 2; vfpuPrefix.SourceAbsolute(index, false); break; case "1/6": isConstant = true; setIndex = 3; vfpuPrefix.SourceAbsolute(index, true); break; case "1/2": isConstant = true; setIndex = 3; vfpuPrefix.SourceAbsolute(index, false); break; default: throw new NotImplementedException($"Invalid RegisterName {registerName}"); } vfpuPrefix.SourceConstant(index, isConstant); vfpuPrefix.SourceIndex(index, (uint)setIndex); }