private static IEnumerable <MCUDefinitionWithPredicate> ParsePeripheralRegisters(string dir, MCUFamilyBuilder fam, string specificDevice, ParseReportWriter writer) { var mainClassifier = fam.Definition.Subfamilies.First(f => f.IsPrimary); List <MCUDefinitionWithPredicate> result = new List <MCUDefinitionWithPredicate>(); Console.Write("Parsing {0} registers using the new parsing logic...", fam.Definition.Name); foreach (var fn in Directory.GetFiles(dir, "*.h")) { string subfamily = Path.GetFileNameWithoutExtension(fn); string subfamilyForMatching = subfamily; if (subfamily.Length != 11 && subfamily.Length != 12) { if (subfamily.EndsWith("_cm4", StringComparison.InvariantCultureIgnoreCase)) { //This is a header file for the Cortex-M4 core of an STM32MP1 device subfamilyForMatching = subfamily.Substring(0, subfamily.Length - 4); } else { continue; } } if (specificDevice != null && subfamily != specificDevice) { continue; } var r = new MCUDefinitionWithPredicate { MCUName = subfamily, RegisterSets = PeripheralRegisterGenerator2.GeneratePeripheralRegisterDefinitionsFromHeaderFile(fn, fam.MCUs[0].Core, writer), MatchPredicate = m => StringComparer.InvariantCultureIgnoreCase.Compare(mainClassifier.TryMatchMCUName(m.Name), subfamilyForMatching) == 0, }; result.Add(r); } Console.WriteLine("done"); return(result); }
static void Main(string[] args) { var regKey = Registry.CurrentUser.CreateSubKey(@"SOFTWARE\Sysprogs\BSPGenerators\STM32"); var sdkRoot = regKey.GetValue("SDKRoot") as string ?? throw new Exception("Please specify STM32 SDK root via registry"); var cubeRoot = regKey.GetValue("CubeMXRoot") as string ?? throw new Exception("Please specify STM32CubeMX location via registry"); if (args.Contains("/fetch")) { //This will load the latest SDK list from the STM32CubeMX directory and will fetch/unpack them to our SDKRoot directory. //Before running this, ensure the STM32CubeMX has the up-to-date SDK definitions (using the 'check for update' function), as //otherwise the BSP generator will fetch the old versions. SDKFetcher.FetchLatestSDKs(sdkRoot, cubeRoot); } string rulesetName = args.FirstOrDefault(a => a.StartsWith("/rules:"))?.Substring(7) ?? STM32Ruleset.Classic.ToString(); STM32Ruleset ruleset = Enum.GetValues(typeof(STM32Ruleset)) .OfType <STM32Ruleset>() .First(v => StringComparer.InvariantCultureIgnoreCase.Compare(v.ToString(), rulesetName) == 0); ///If the MCU list format changes again, create a new implementation of the IDeviceListProvider interface, switch to using it, but keep the old one for reference & easy comparison. IDeviceListProvider provider = new DeviceListProviders.CubeProvider(); var bspBuilder = new STM32BSPBuilder(new BSPDirectories(sdkRoot, @"..\..\Output\" + rulesetName, @"..\..\rules\" + rulesetName), cubeRoot); Directory.CreateDirectory(@"..\..\Logs"); using (var wr = new ParseReportWriter(@"..\..\Logs\registers.log")) { var devices = provider.LoadDeviceList(bspBuilder); if (devices.Where(d => d.FlashSize == 0 && !d.Name.StartsWith("STM32MP1")).Count() > 0) { throw new Exception($"Some deviceshave FLASH Size({devices.Where(d => d.FlashSize == 0).Count()}) = 0 "); } List <MCUFamilyBuilder> allFamilies = new List <MCUFamilyBuilder>(); string extraFrameworksFile = Path.Combine(bspBuilder.Directories.RulesDir, "FrameworkTemplates.xml"); if (!File.Exists(extraFrameworksFile) && File.Exists(Path.ChangeExtension(extraFrameworksFile, ".txt"))) { extraFrameworksFile = Path.Combine(bspBuilder.Directories.RulesDir, File.ReadAllText(Path.ChangeExtension(extraFrameworksFile, ".txt"))); } Dictionary <string, STM32SDKCollection.SDK> sdksByVariable = bspBuilder.SDKList.SDKs.ToDictionary(s => $"$$STM32:{s.Family}_DIR$$"); List <STM32SDKCollection.SDK> referencedSDKs = new List <STM32SDKCollection.SDK>(); foreach (var fn in Directory.GetFiles(bspBuilder.Directories.RulesDir + @"\families", "*.xml")) { var fam = XmlTools.LoadObject <FamilyDefinition>(fn); if (File.Exists(extraFrameworksFile)) { int idx = fam.PrimaryHeaderDir.IndexOf('\\'); string baseDir = fam.PrimaryHeaderDir.Substring(0, idx); if (!baseDir.StartsWith("$$STM32:")) { throw new Exception("Invalid base directory. Please recheck the family definition."); } string baseFamName = fam.Name; if (baseFamName.EndsWith("_M4")) { baseFamName = baseFamName.Substring(0, baseFamName.Length - 3); } referencedSDKs.Add(sdksByVariable[baseDir]); var dict = new Dictionary <string, string> { { "STM32:FAMILY_EX", fam.Name }, { "STM32:FAMILY", baseFamName }, { "STM32:FAMILY_DIR", baseDir }, }; var extraFrameworkFamily = XmlTools.LoadObject <FamilyDefinition>(extraFrameworksFile); //USB host/device libraries are not always compatible between different device families. Hence we need to ship separate per-family copies of those. var expandedExtraFrameworks = extraFrameworkFamily.AdditionalFrameworks.Select(fw => { fw.ID = VariableHelper.ExpandVariables(fw.ID, dict); fw.Name = VariableHelper.ExpandVariables(fw.Name, dict); fw.RequiredFrameworks = ExpandVariables(fw.RequiredFrameworks, dict); fw.IncompatibleFrameworks = ExpandVariables(fw.IncompatibleFrameworks, dict); foreach (var job in fw.CopyJobs) { job.SourceFolder = VariableHelper.ExpandVariables(job.SourceFolder, dict); job.TargetFolder = VariableHelper.ExpandVariables(job.TargetFolder, dict); job.AdditionalIncludeDirs = VariableHelper.ExpandVariables(job.AdditionalIncludeDirs, dict); } return(fw); }); //Furthermore, some families do not include a USB host peripheral and hence do not contain a USB Host library. We need to skip it automatically. var extraFrameworksWithoutMissingFolders = expandedExtraFrameworks.Where(fw => fw.CopyJobs.Count(j => { string expandedJobSourceDir = j.SourceFolder; bspBuilder.ExpandVariables(ref expandedJobSourceDir); return(!Directory.Exists(expandedJobSourceDir)); }) == 0); fam.AdditionalFrameworks = fam.AdditionalFrameworks.Concat(extraFrameworksWithoutMissingFolders).ToArray(); } bspBuilder.InsertLegacyHALRulesIfNecessary(fam, bspBuilder.ReverseFileConditions); switch (ruleset) { case STM32Ruleset.STM32WB: allFamilies.Add(new STM32WBFamilyBuilder(bspBuilder, fam)); break; case STM32Ruleset.STM32MP1: allFamilies.Add(new STM32MP1FamilyBuilder(bspBuilder, fam)); break; case STM32Ruleset.Classic: default: allFamilies.Add(new STM32ClassicFamilyBuilder(bspBuilder, fam)); break; } } var rejects = BSPGeneratorTools.AssignMCUsToFamilies(devices, allFamilies); if (rejects.Count > 0 && ruleset == STM32Ruleset.Classic) { Console.WriteLine("Globally unsupported MCUs:"); foreach (var r in rejects) { Console.WriteLine("\t{0}", r.Name); } } List <MCUFamily> familyDefinitions = new List <MCUFamily>(); List <MCU> mcuDefinitions = new List <MCU>(); List <EmbeddedFramework> frameworks = new List <EmbeddedFramework>(); List <MCUFamilyBuilder.CopiedSample> exampleDirs = new List <MCUFamilyBuilder.CopiedSample>(); bool noPeripheralRegisters = args.Contains("/noperiph"); string specificDeviceForDebuggingPeripheralRegisterGenerator = args.FirstOrDefault(a => a.StartsWith("/periph:"))?.Substring(8); var commonPseudofamily = new MCUFamilyBuilder(bspBuilder, XmlTools.LoadObject <FamilyDefinition>(bspBuilder.Directories.RulesDir + @"\CommonFiles.xml")); foreach (var fw in commonPseudofamily.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } List <ConditionalToolFlags> allConditionalToolFlags = new List <ConditionalToolFlags>(); foreach (var fam in allFamilies) { bspBuilder.GetMemoryMcu(fam); var rejectedMCUs = fam.RemoveUnsupportedMCUs(true); if (rejectedMCUs.Length != 0) { Console.WriteLine("Unsupported {0} MCUs:", fam.Definition.Name); foreach (var mcu in rejectedMCUs) { Console.WriteLine("\t{0}", mcu.Name); } } fam.AttachStartupFiles(ParseStartupFiles(fam.Definition.StartupFileDir, fam)); if (!noPeripheralRegisters) { fam.AttachPeripheralRegisters(ParsePeripheralRegisters(fam.Definition.PrimaryHeaderDir, fam, specificDeviceForDebuggingPeripheralRegisterGenerator, wr), throwIfNotFound: specificDeviceForDebuggingPeripheralRegisterGenerator == null); } familyDefinitions.Add(fam.GenerateFamilyObject(MCUFamilyBuilder.CoreSpecificFlags.All, true)); fam.GenerateLinkerScripts(false); foreach (var mcu in fam.MCUs) { mcuDefinitions.Add(mcu.GenerateDefinition(fam, bspBuilder, !noPeripheralRegisters && specificDeviceForDebuggingPeripheralRegisterGenerator == null)); } foreach (var fw in fam.GenerateFrameworkDefinitions()) { frameworks.Add(fw); } foreach (var sample in fam.CopySamples()) { exampleDirs.Add(sample); } if (fam.Definition.ConditionalFlags != null) { allConditionalToolFlags.AddRange(fam.Definition.ConditionalFlags); } } foreach (var sample in commonPseudofamily.CopySamples(null, allFamilies.Where(f => f.Definition.AdditionalSystemVars != null).SelectMany(f => f.Definition.AdditionalSystemVars))) { exampleDirs.Add(sample); } var prioritizer = new SamplePrioritizer(Path.Combine(bspBuilder.Directories.RulesDir, "SamplePriorities.txt")); exampleDirs.Sort((a, b) => prioritizer.Prioritize(a.RelativePath, b.RelativePath)); var bsp = XmlTools.LoadObject <BoardSupportPackage>(Path.Combine(bspBuilder.Directories.RulesDir, "BSPTemplate.xml")); bsp.MCUFamilies = familyDefinitions.ToArray(); bsp.SupportedMCUs = mcuDefinitions.ToArray(); bsp.Frameworks = frameworks.ToArray(); bsp.Examples = exampleDirs.Where(s => !s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(); bsp.TestExamples = exampleDirs.Where(s => s.IsTestProjectSample).Select(s => s.RelativePath).ToArray(); bsp.PackageVersion = bspBuilder.SDKList.BSPVersion; bsp.FileConditions = bspBuilder.MatchedFileConditions.ToArray(); bsp.InitializationCodeInsertionPoints = commonPseudofamily.Definition.InitializationCodeInsertionPoints; bsp.ConditionalFlags = allConditionalToolFlags.ToArray(); bspBuilder.SDKList.SDKs = referencedSDKs.Distinct().ToArray(); XmlTools.SaveObject(bspBuilder.SDKList, Path.Combine(bspBuilder.BSPRoot, "SDKVersions.xml")); bspBuilder.ValidateBSP(bsp); bspBuilder.ReverseFileConditions.SaveIfConsistent(bspBuilder.Directories.OutputDir, bspBuilder.ExportRenamedFileTable(), ruleset == STM32Ruleset.STM32WB); File.Copy(@"..\..\stm32_compat.h", Path.Combine(bspBuilder.BSPRoot, "stm32_compat.h"), true); Console.WriteLine("Saving BSP..."); bspBuilder.Save(bsp, true); } }
public static HardwareRegisterSet[] GeneratePeripheralRegisterDefinitionsFromHeaderFile(string peripheralHeaderFile, CortexCore core, ParseReportWriter reportWriter) { using (var handle = reportWriter.BeginParsingFile(peripheralHeaderFile)) { var parser = new HeaderFileParser(peripheralHeaderFile, handle); var parsedFile = parser.ParseHeaderFile(); if (core == CortexCore.M4 && parsedFile.PreprocessorMacros.TryGetValue("HSEM_COMMON", out var hsem)) { /* * This is the only relevant use of #ifdef in the STM32 headers: * #if defined(CORE_CM4) #define HSEM_COMMON ((HSEM_Common_TypeDef *) (HSEM_BASE + 0x110UL)) #else #define HSEM_COMMON ((HSEM_Common_TypeDef *) (HSEM_BASE + 0x100UL)) #endif * * Currently, instead of fully parsing it, we just patch it manually for the M4 core. */ for (int i = 0; i < hsem.Value.Length; i++) { if (hsem.Value[i].Value == "0x100UL") { hsem.Value[i].Value = "0x110UL"; } } } var peripherals = LocateStructsReferencedInBaseExpressions(parsedFile); var subregisterParser = new PeripheralSubregisterParser(handle); subregisterParser.AttachSubregisterDefinitions(parsedFile, peripherals); List <HardwareRegisterSet> sets = new List <HardwareRegisterSet>(); string coreFile = $@"../../../CoreReg/OutCorexx/core_{core}.xml"; if (core != CortexCore.Invalid) { if (!File.Exists(coreFile)) { throw new Exception("Unknown ARM core: " + core); } sets.Add(XmlTools.LoadObject <HardwareRegisterSet>(coreFile)); } foreach (var peripheral in peripherals) { sets.Add(new HardwareRegisterSet { Registers = peripheral.Registers.Select(r => r.ToHardwareRegister(peripheral)).ToArray(), UserFriendlyName = peripheral.Name, ExpressionPrefix = peripheral.Name + "->", }); } return(sets.ToArray()); } }