Example #1
0
        public static void ParseAndUpdateVfprDestinationPrefix(int index, string registerName,
                                                               ref VfpuDestinationPrefix vfpuPrefix)
        {
            switch (registerName)
            {
            case "m":
            case "M":
                vfpuPrefix.DestinationMask(index, true);
                break;

            case "0:1":
                vfpuPrefix.DestinationMask(index, false);
                vfpuPrefix.DestinationSaturation(index, 1);
                break;

            case "-1:1":
                vfpuPrefix.DestinationMask(index, false);
                vfpuPrefix.DestinationSaturation(index, 3);
                break;

            default: throw new NotImplementedException($"Invalid RegisterName {registerName}");
            }
        }
Example #2
0
        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 + "'");
                }
            }
        }