/* * 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); }
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()); }
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; } } }
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()); }