/*
         *  This method extracts the subregister macros defined as follows
         *
         #define ADC_ISR_ADRDY_Pos         (0U)
         #define ADC_ISR_ADRDY_Msk         (0x1U << ADC_ISR_ADRDY_Pos)
         *
         */
        private NamedSubregister[] ExtractNewStyleSubregisters(ParsedHeaderFile parsedFile, PreprocessorMacro[] newStyleMacros)
        {
            List <NamedSubregister>  result          = new List <NamedSubregister>();
            Dictionary <string, int> positionsByName = new Dictionary <string, int>();
            Dictionary <string, int> bitCountsByName = new Dictionary <string, int>();
            var resolver = new BasicExpressionResolver(false);

            foreach (var macro in newStyleMacros)
            {
                var    expression = parsedFile.ResolveMacrosRecursively(macro.Value);
                var    value      = resolver.ResolveAddressExpression(expression);
                string key        = macro.Name.Substring(0, macro.Name.Length - 4);

                if (value == null)
                {
                    continue;
                }

                if (macro.Name.EndsWith("_Pos"))
                {
                    positionsByName[key] = (int)value.Value;
                }
                else if (macro.Name.EndsWith("_Msk"))
                {
                    if (!ExtractFirstBitAndSize(value.Value, out var size, out var firstBit))
                    {
                        _ReportWriter.HandleInvalidNewStyleBitMask(macro.Name, value.Value);
                    }
                    else
                    {
                        bitCountsByName[key] = size;
                    }
                }
            }
        public void AttachSubregisterDefinitions(ParsedHeaderFile parsedFile, PeripheralRegisterGenerator2.DiscoveredPeripheral[] peripherals)
        {
            var peripheralsByName = peripherals.ToDictionary(p => p.Name);

            foreach (var grp in parsedFile.PreprocessorMacroGroups)
            {
                if (!grp.CommentText.Contains(" definition"))
                {
                    continue;
                }

                var newStyleMacros = grp.Macros.Where(m => m.Name.EndsWith("_Pos") || m.Name.EndsWith("_Msk")).ToArray();
                NamedSubregister[] subregisters;
                if (newStyleMacros.Length > 0)
                {
                    subregisters = ExtractNewStyleSubregisters(parsedFile, newStyleMacros);
                }
                else
                {
                    subregisters = ExtractLegacySubregisters(parsedFile, grp.Macros);
                }

                foreach (var subreg in subregisters)
                {
                    MatchedStructureField[] foundFields = LocateMatchingFields(parsedFile, subreg.Name, peripheralsByName, out var specificInstanceName);

                    if (foundFields == null || foundFields.Length == 0)
                    {
                        _ReportWriter.HandleOrphanedSubregisterMacro(grp, subreg);
                    }
                    else
                    {
                        foreach (var f in foundFields)
                        {
                            f.Entry.AddSubregister(subreg, f.StrippedIndex, specificInstanceName, f.SubregisterName);
                        }
                    }
                }
            }
        }
        private MatchedStructureField[] LocateMatchingFields(ParsedHeaderFile parsedFile,
                                                             string subregisterName,
                                                             Dictionary <string, PeripheralRegisterGenerator2.DiscoveredPeripheral> peripheralsByName,
                                                             out string specificInstanceName)
        {
            ParsedStructure structureObj;

            MatchedStructureField[] foundFields = null;

            string[] components = subregisterName.Split('_');
            specificInstanceName = null;

            if (parsedFile.Structures.TryGetValue(components[0] + "_TypeDef", out structureObj) &&
                TryLocateFieldForSubregisterMacroName(structureObj, components, 1, out foundFields))
            {
                return(foundFields);
            }

            if (peripheralsByName.TryGetValue(components[0], out var periph) &&
                TryLocateFieldForSubregisterMacroName(periph.Structure, components, 1, out foundFields))
            {
                specificInstanceName = periph.Name;
                return(foundFields);
            }

            foreach (var s in parsedFile.Structures.Values)
            {
                if (s.Name.StartsWith(components[0]))
                {
                    int prefixLen = CountMatchingItems(s.Name.Split('_'), components);
                    if (TryLocateFieldForSubregisterMacroName(s, components, prefixLen, out foundFields))
                    {
                        return(foundFields);
                    }
                }
            }

            return(null);
        }
Beispiel #4
0
        private static DiscoveredPeripheral.Register[] TranslateStructureFieldsToRegisters(ParsedStructure obj, ParsedHeaderFile parsedFile)
        {
            ConstructedRegisterList    lst = new ConstructedRegisterList();
            RegisterTranslationContext ctx = new RegisterTranslationContext();

            lst.TranslateStructureFieldsToRegistersRecursively(obj, parsedFile, ref ctx, "");
            return(lst.Complete());
        }
Beispiel #5
0
            public void TranslateStructureFieldsToRegistersRecursively(ParsedStructure obj, ParsedHeaderFile parsedFile, ref RegisterTranslationContext ctx, string prefix)
            {
                foreach (var field in obj.Entries)
                {
                    var type = field.Type
                               .Where(t => t.Type == CppTokenizer.TokenType.Identifier)
                               .Select(t => t.Value)
                               .Where(t => t != "__IO" && t != "__I" && t != "__IM" && t != "__O" && t != "const")
                               .ToArray();

                    bool isReadOnly = field.Type.Count(t => t.Value == "__I" || t.Value == "const") > 0;

                    if (type.Length > 1)
                    {
                        throw new Exception("Could not reduce register type to a single token: " + string.Join("", type));
                    }

                    int size;

                    switch (type[0])
                    {
                    case "int32_t":
                    case "uint32_t":
                        size = 4;
                        break;

                    case "int16_t":
                    case "uint16_t":
                        size = 2;
                        break;

                    case "int8_t":
                    case "uint8_t":
                        size = 1;
                        break;

                    case "RSSLIB_S_CloseExitHDP_TypeDef":       //Actually a function pointer
                        size = 4;
                        break;

                    default:
                        for (int i = 0; i < field.ArraySize; i++)
                        {
                            string extraPrefix;
                            if (field.ArraySize == 1)
                            {
                                extraPrefix = $"{field.Name}.";
                            }
                            else
                            {
                                extraPrefix = $"{field.Name}[{i}].";
                            }

                            TranslateStructureFieldsToRegistersRecursively(parsedFile.Structures[type[0]], parsedFile, ref ctx, prefix + extraPrefix);
                        }
                        continue;
                    }

                    if ((ctx.CurrentOffset % size) != 0)
                    {
                        ctx.CurrentOffset += (size - (ctx.CurrentOffset % size));
                    }

                    for (int i = 0; i < field.ArraySize; i++)
                    {
                        string nameSuffix = "";
                        if (field.ArraySize > 1)
                        {
                            nameSuffix = $"[{i}]";
                        }

                        if (!field.Name.StartsWith("RESERVED", StringComparison.InvariantCultureIgnoreCase))
                        {
                            _Registers.Add(new DiscoveredPeripheral.Register
                            {
                                Offset         = (uint)ctx.CurrentOffset,
                                Name           = prefix + field.Name + nameSuffix,
                                SizeInBytes    = size,
                                IsReadOnly     = isReadOnly,
                                OriginalField  = field,
                                ZeroBasedIndex = i,
                            });
                        }

                        ctx.CurrentOffset += size;
                    }
                }
            }
Beispiel #6
0
        private static DiscoveredPeripheral[] LocateStructsReferencedInBaseExpressions(ParsedHeaderFile parsedFile)
        {
            List <DiscoveredPeripheral> structs = new List <DiscoveredPeripheral>();

            /*
             *  We are looking for preprocessor macros like the one below:
             *
             #define TIM3                ((TIM_TypeDef *) TIM3_BASE)
             *
             *  This is done by looping over ALL preprocessor macros defined in the source file and pick the ones that refer to typedef-ed structs.
             *  Then we recursively resolve the macro definition, getting something like ((TIM_TypeDef*)(((uint32_t)0x40000000U)+0x00000400)).
             *
             *  Finally, we use a very simple parser to compute that address defined in this macro and to verify that it's being cast to
             *  the correct type.
             *
             *  Once we have computed the address and confirmed its type, we can reliably conclude that a peripheral defined by that struct is
             *  present at the specified address.
             */

            var resolver = new BasicExpressionResolver(true);

            foreach (var macro in parsedFile.PreprocessorMacros.Values)
            {
                foreach (var token in macro.Value)
                {
                    if (token.Type == CppTokenizer.TokenType.Identifier && parsedFile.Structures.TryGetValue(token.Value, out var obj))
                    {
                        var addressExpression = parsedFile.ResolveMacrosRecursively(macro.Value);

                        if (addressExpression.Count(t => t.Value == "*") == 0)
                        {
                            continue;   //Not an address
                        }
                        BasicExpressionResolver.TypedInteger addr;

                        try
                        {
                            addr = resolver.ResolveAddressExpression(addressExpression);
                        }
                        catch (BasicExpressionResolver.UnexpectedNonNumberException ex)
                        {
                            if (ex.Token.Value == "SDMMC_BASE")
                            {
                                continue;   //Known bug in STM32H7. The value is used, but not defined anywhere
                            }
                            if (ex.Token.Value == "LCD_BASE" || ex.Token.Value == "JPGDEC_BASE")
                            {
                                continue;   //Known bug in STM32MP1. The value is used, but not defined anywhere
                            }
                            if (ex.Token.Value == "LTDC_Layer2_BASE")
                            {
                                continue;
                            }

                            throw;
                        }

                        if (addr.Type?.First().Value == obj.Name)
                        {
                            structs.Add(new DiscoveredPeripheral
                            {
                                ResolvedBaseAddress = addr.Value,
                                Structure           = obj,
                                Name      = macro.Name,
                                Registers = TranslateStructureFieldsToRegisters(obj, parsedFile)
                            });
                        }
                        else
                        {
                            //We have found a preprocessor macro referencing one of the typedefs, but not resolving to its type. This needs investigation.
                            Debugger.Break();
                        }

                        break;
                    }
                }
            }

            return(structs.ToArray());
        }