public static void AddVectorFeature(ref List <GDBFeatureDescriptor> features, uint registerWidth)
        {
            var vectorGroup = new GDBFeatureDescriptor("org.gnu.gdb.riscv.vector");

            var riscvVectorTypeFields = new List <GDBTypeField>();

            if (registerWidth / 128 > 0)
            {
                var vu128TypeID = $"vector_u128_{registerWidth / 128}";
                var vu128Type   = GDBCustomType.Vector(vu128TypeID, "uint128", registerWidth / 128);
                vectorGroup.Types.Add(vu128Type);
                riscvVectorTypeFields.Add(new GDBTypeField("q", vu128TypeID));
            }

            if (registerWidth / 64 > 0)
            {
                var vu64TypeID = $"vector_u64_{registerWidth / 64}";
                var vu64Type   = GDBCustomType.Vector(vu64TypeID, "uint64", registerWidth / 64);
                vectorGroup.Types.Add(vu64Type);
                riscvVectorTypeFields.Add(new GDBTypeField("l", vu64TypeID));
            }

            if (registerWidth / 32 > 0)
            {
                var vu32TypeID = $"vector_u32_{registerWidth / 32}";
                var vu32Type   = GDBCustomType.Vector(vu32TypeID, "uint32", registerWidth / 32);
                vectorGroup.Types.Add(vu32Type);
                riscvVectorTypeFields.Add(new GDBTypeField("w", vu32TypeID));
            }

            if (registerWidth / 16 > 0)
            {
                var vu16TypeID = $"vector_u16_{registerWidth / 16}";
                var vu16Type   = GDBCustomType.Vector(vu16TypeID, "uint16", registerWidth / 16);
                vectorGroup.Types.Add(vu16Type);
                riscvVectorTypeFields.Add(new GDBTypeField("s", vu16TypeID));
            }

            if (registerWidth / 8 > 0)
            {
                var vu8TypeID = $"vector_u8_{registerWidth / 8}";
                var vu8Type   = GDBCustomType.Vector(vu8TypeID, "uint8", registerWidth / 8);
                vectorGroup.Types.Add(vu8Type);
                riscvVectorTypeFields.Add(new GDBTypeField("b", vu8TypeID));
            }

            var riscvVectorType = GDBCustomType.Union("riscv_vector", riscvVectorTypeFields);

            vectorGroup.Types.Add(riscvVectorType);

            for (var index = 0u; index < NumberOfVRegisters; ++index)
            {
                vectorGroup.Registers.Add(new GDBRegisterDescriptor(StartOfVRegisters + index, registerWidth, $"v{index}", "riscv_vector", "vector"));
            }

            features.Add(vectorGroup);
        }
        public static void AddFpuFeature(ref List <GDBFeatureDescriptor> features, uint registerWidth, bool extensionH, bool extensionF, bool extensionD, bool extensionQ)
        {
            if (!(extensionH || extensionF || extensionD || extensionQ))
            {
                return;
            }

            var fpuGroup = new GDBFeatureDescriptor("org.gnu.gdb.riscv.fpu");
            var intType  = $"uint{registerWidth}";
            var fWidth   = 0u;
            var types    = new List <string>();

            if (extensionH)
            {
                fWidth = 16u;
                types.Add("half");

                var fields = new List <GDBTypeBitField>();
                fields.Add(new GDBTypeBitField("sign", 15, 15, "uint16"));
                fields.Add(new GDBTypeBitField("exponent", 10, 14, "uint16"));
                fields.Add(new GDBTypeBitField("fraction", 0, 9, "uint16"));
                var half = GDBCustomType.Struct("half", fWidth / 8, fields);
                fpuGroup.Types.Add(half);
            }
            if (extensionF)
            {
                fWidth = 32u;
                types.Add("single");
            }
            if (extensionD)
            {
                fWidth = 64u;
                types.Add("double");
            }
            if (extensionQ)
            {
                fWidth = 128u;
                types.Add("quad");

                var fields = new List <GDBTypeBitField>();
                fields.Add(new GDBTypeBitField("sign", 127, 127, "uint128"));
                fields.Add(new GDBTypeBitField("exponent", 112, 126, "uint128"));
                fields.Add(new GDBTypeBitField("fraction", 0, 111, "uint128"));
                var quad = GDBCustomType.Struct("quad", fWidth / 8, fields);
                fpuGroup.Types.Add(quad);
            }

            var floatType = $"ieee_{types[0]}";

            // If there's more than one float type then they're combined with union
            // narrower type is in the lowest part of the wider ones, specification calls it NaN-boxing model.
            if (types.Count > 1)
            {
                floatType = "nan_boxed_float";
                var fields = new List <GDBTypeField>();
                foreach (var type in types)
                {
                    fields.Add(new GDBTypeField(type, $"ieee_{type}"));
                }
                var nanBoxedFloat = GDBCustomType.Union(floatType, fields);
                fpuGroup.Types.Add(nanBoxedFloat);
            }

            for (var index = 0u; index < NumberOfFRegisters; ++index)
            {
                fpuGroup.Registers.Add(new GDBRegisterDescriptor((uint)RiscV32Registers.F0 + index, fWidth, $"f{index}", floatType, "float"));
            }

            // fflags, frm and fcsr are not implemented but are required for architecture description
            var fflagsIndex = (uint)RiscV32Registers.F0 + NumberOfFRegisters;

            fpuGroup.Registers.Add(new GDBRegisterDescriptor(fflagsIndex, registerWidth, "fflags", "", "float"));
            fpuGroup.Registers.Add(new GDBRegisterDescriptor(fflagsIndex + 1, registerWidth, "frm", "", "float"));
            fpuGroup.Registers.Add(new GDBRegisterDescriptor(fflagsIndex + 2, registerWidth, "fcsr", "", "float"));

            {
                var fields = new List <GDBTypeBitField>();
                fields.Add(new GDBTypeBitField("NX", 0, 0, "bool"));
                fields.Add(new GDBTypeBitField("UF", 1, 1, "bool"));
                fields.Add(new GDBTypeBitField("OF", 2, 2, "bool"));
                fields.Add(new GDBTypeBitField("DZ", 3, 3, "bool"));
                fields.Add(new GDBTypeBitField("NV", 4, 4, "bool"));
                var fflagsFlagsType = GDBCustomType.Flags("fflags_flags_type", 1, fields);
                fpuGroup.Types.Add(fflagsFlagsType);
            }
            {
                var fields = new List <GDBTypeEnumValue>();
                fields.Add(new GDBTypeEnumValue("RNE", 0b000));
                fields.Add(new GDBTypeEnumValue("RTZ", 0b001));
                fields.Add(new GDBTypeEnumValue("RDN", 0b010));
                fields.Add(new GDBTypeEnumValue("RUP", 0b011));
                fields.Add(new GDBTypeEnumValue("RMM", 0b100));
                fields.Add(new GDBTypeEnumValue("DYN", 0b111));
                var frmEnumType = GDBCustomType.Enum("frm_enum_type", 1, fields);
                fpuGroup.Types.Add(frmEnumType);
            }
            {
                var fields = new List <GDBTypeBitField>();
                fields.Add(new GDBTypeBitField("value", 0, 4, "fflags_flags_type"));
                var fflagsType = GDBCustomType.Struct("fflags_type", registerWidth / 8, fields);
                fpuGroup.Types.Add(fflagsType);
            }
            {
                var fields = new List <GDBTypeBitField>();
                fields.Add(new GDBTypeBitField("value", 0, 5, "frm_enum_type"));
                var frmType = GDBCustomType.Struct("frm_type", registerWidth / 8, fields);
                fpuGroup.Types.Add(frmType);
            }
            {
                var fields = new List <GDBTypeBitField>();
                fields.Add(new GDBTypeBitField("flags", 0, 4, "fflags_flags_type"));
                fields.Add(new GDBTypeBitField("rm", 5, 7, "frm_enum_type"));
                var fcsrType = GDBCustomType.Struct("fcsr_type", registerWidth / 8, fields);
                fpuGroup.Types.Add(fcsrType);
            }

            features.Add(fpuGroup);
        }