private static void GenerateBSP(List <DeviceInfo> devList, string outputDir) { BoardSupportPackage bsp = new BoardSupportPackage { GNUTargetID = "avr", PackageID = "com.sysprogs.avr.core", PackageDescription = "AVR MCUs", GeneratedMakFileName = "avr.mak", Examples = new string[] { "Samples/LEDBlink" } }; bsp.SupportedMCUs = devList.Select(d => d.ToBSPMCU()).ToArray(); bsp.MCUFamilies = new MCUFamily[] { new MCUFamily { ID = "avr" } }; bsp.DebugMethodPackages = new string[] { "debuggers\\core", "debuggers\\avarice" }; string defDir = Path.Combine(outputDir, "DeviceDefinitions"); Directory.CreateDirectory(defDir); foreach (var dev in devList) { MCUDefinition d = dev.ToDeviceDefinition(); if (d == null) { Console.WriteLine("Warning: no register information found for " + dev.Name); continue; } using (var fs = File.Create(Path.Combine(defDir, dev.Name + ".xml.gz"))) using (var gs = new GZipStream(fs, CompressionMode.Compress)) XmlTools.SaveObjectToStream(d, gs); } XmlTools.SaveObject(bsp, Path.Combine(outputDir, "bsp.xml")); }
public static MCU GenerateMCUDefinition(string bspDir, string linkerScript, string generatorResourceDir, string target, string debugComponentDir) { string mcuName = Path.GetFileNameWithoutExtension(linkerScript).TrimStart('D'); string copiedFilesDir = Path.Combine(bspDir, "DeviceFiles", mcuName); Directory.CreateDirectory(copiedFilesDir); File.Copy(linkerScript, Path.Combine(bspDir, "LinkerScripts", Path.GetFileName(linkerScript)), true); Dictionary <string, int> memorySizes = new Dictionary <string, int>(); Regex rgMemory = new Regex("^[ \t]+([^ ]+)[ \t]+:[ \t]+ORIGIN[ \t]*=[ \t]*0x([0-9a-fA-F]+),[ \t]*LENGTH[ \t]*=[ \t]*([0-9]+)"); foreach (var line in File.ReadAllLines(linkerScript)) { var m = rgMemory.Match(line); if (m.Success) { memorySizes[m.Groups[1].Value] = int.Parse(m.Groups[3].Value); } } List <string> headers = new List <string>(); foreach (var rf in RenamedFiles) { string file = Path.Combine(generatorResourceDir, string.Format(rf.SourceFileFormat, mcuName)); if (!File.Exists(file)) { Directory.Delete(copiedFilesDir, true); return(null); } var lines = File.ReadAllLines(file); if (rf.MakeWeakFunctions) { Regex rgFunc = new Regex("void[ \t]+(INT_[a-zA-Z0-9_]+)[ \t]*\\(void\\)"); for (int i = 0; i < lines.Length; i++) { var m = rgFunc.Match(lines[i]); if (m.Success) { lines[i] = lines[i].Substring(0, m.Groups[1].Index) + "__attribute__((weak)) " + lines[i].Substring(m.Groups[1].Index); } } } File.WriteAllLines(Path.Combine(copiedFilesDir, rf.TargetFileName), lines); if (rf.TargetFileName.EndsWith(".h")) { headers.Add($"$$SYS:BSP_ROOT$$/DeviceFiles/{mcuName}/rf.TargetFileName"); } } var mcu = new MCU { ID = mcuName, FamilyID = target, CompilationFlags = new ToolFlags { IncludeDirectories = new[] { $"$$SYS:BSP_ROOT$$/DeviceFiles/{mcuName}" }, LinkerScript = "$$SYS:BSP_ROOT$$/LinkerScripts/" + Path.GetFileName(linkerScript), LDFLAGS = "-nostartfiles -Wl,-e_PowerON_Reset", COMMONFLAGS = "$$com.sysprogs.renesas.doubles$$ $$com.sysprogs.renesas.core$$", }, AdditionalSourcesRequiredForTesting = true, AdditionalHeaderFiles = headers.ToArray() }; string peripheralFile = Path.Combine(debugComponentDir, "IoFiles", mcuName + ".sfrx"); if (File.Exists(peripheralFile)) { var doc = new XmlDocument(); doc.Load(peripheralFile); MCUDefinition definition = new MCUDefinition { MCUName = mcuName, RegisterSets = doc.DocumentElement.SelectNodes("moduletable/module").OfType <XmlElement>().Select(TransformRegisterSet).Where(s => s != null).ToArray() }; using (var fs = new FileStream(Path.Combine(bspDir, "DeviceDefinitions", mcuName + ".xml.gz"), FileMode.Create, FileAccess.Write)) using (var gs = new GZipStream(fs, CompressionMode.Compress)) XmlTools.SaveObjectToStream(definition, gs); mcu.MCUDefinitionFile = $"DeviceDefinitions/{mcuName}.xml"; } memorySizes.TryGetValue("ROM", out mcu.FLASHSize); memorySizes.TryGetValue("RAM", out mcu.RAMSize); return(mcu); }
static void InsertRegisterValidationCode(string sourceFile, MCUDefinition mcuDefinition, LoadedRenamingRule[] renameRules, string[] pNonValidatedRegisters) { if (!File.Exists(sourceFile)) throw new Exception("File does not exist: " + sourceFile); if (mcuDefinition != null) { using (var sw = new StreamWriter(sourceFile, true)) { sw.WriteLine(); sw.WriteLine("#define STATIC_ASSERT(COND) typedef char static_assertion[(COND)?1:-1]"); sw.WriteLine("void ValidateOffsets()"); sw.WriteLine("{"); foreach (var regset in mcuDefinition.RegisterSets) foreach (var reg in regset.Registers) { string regName = reg.Name; if (IsNoValid(regset.UserFriendlyName, pNonValidatedRegisters)) continue; if (renameRules != null) foreach (var rule in renameRules) { if (rule.RegisterSetRegex?.IsMatch(regset.UserFriendlyName) != false) { var match = rule.RegisterRegex.Match(regName); if (match.Success) { switch (rule.Mode) { case RegisterRenamingMode.Normal: regName = string.Format("{0}[{1}]", match.Groups[1], int.Parse(match.Groups[2].ToString()) + rule.Offset); break; case RegisterRenamingMode.HighLow: regName = string.Format("{0}[{1}]", match.Groups[1], match.Groups[2].ToString() == "H" ? 1 : 0); break; case RegisterRenamingMode.WithSuffix: regName = string.Format("{0}[{1}].{2}", match.Groups[1], int.Parse(match.Groups[2].ToString()) + rule.Offset, match.Groups[3]); break; } break; } } } if (mcuDefinition.MCUName.StartsWith("MSP432")) { if (regName.Contains("RESERVED")) continue; sw.WriteLine("STATIC_ASSERT((unsigned)&({0}->r{1}) == {2});", regset.UserFriendlyName, regName, reg.Address); } else sw.WriteLine("STATIC_ASSERT((unsigned)&({0}->{1}) == {2});", regset.UserFriendlyName, regName, reg.Address); } sw.WriteLine("}"); } } }
static void InsertRegisterValidationCode(string sourceFile, MCUDefinition mcuDefinition, LoadedRenamingRule[] renameRules, string[] pNonValidatedRegisters, string[] pUndefinedMacros) { if (!File.Exists(sourceFile)) { throw new Exception("File does not exist: " + sourceFile); } if (mcuDefinition != null) { using (var sw = new StreamWriter(sourceFile, true)) { sw.WriteLine(); sw.WriteLine("#define STATIC_ASSERT(COND) typedef char static_assertion[(COND)?1:-1]"); sw.WriteLine("void ValidateOffsets()"); sw.WriteLine("{"); foreach (var regset in mcuDefinition.RegisterSets) { foreach (var reg in regset.Registers) { string regName = reg.Name; if (IsNoValid(regset.UserFriendlyName, pNonValidatedRegisters)) { continue; } if (IsNoValid(regName, pNonValidatedRegisters)) { continue; } if (IsNoValid(regName, pUndefinedMacros)) { sw.WriteLine($"#undef {regName}"); } if (renameRules != null) { foreach (var rule in renameRules) { if (rule.RegisterSetRegex?.IsMatch(regset.UserFriendlyName) != false) { var match = rule.RegisterRegex.Match(regName); if (match.Success) { switch (rule.Mode) { case RegisterRenamingMode.Normal: regName = string.Format("{0}[{1}]", match.Groups[1], int.Parse(match.Groups[2].ToString()) + rule.Offset); break; case RegisterRenamingMode.HighLow: regName = string.Format("{0}[{1}]", match.Groups[1], match.Groups[2].ToString() == "H" ? 1 : 0); break; case RegisterRenamingMode.WithSuffix: regName = string.Format("{0}[{1}].{2}", match.Groups[1], int.Parse(match.Groups[2].ToString()) + rule.Offset, match.Groups[3]); break; } break; } } } } if (regset.UserFriendlyName.StartsWith("ARM Cortex M")) { continue; } if (mcuDefinition.MCUName.StartsWith("MSP432")) { if (regName.Contains("RESERVED")) { continue; } sw.WriteLine("STATIC_ASSERT((unsigned)&({0}->r{1}) == {2});", regset.UserFriendlyName, regName, reg.Address); } else { sw.WriteLine("STATIC_ASSERT((unsigned)&({0}->{1}) == {2});", regset.UserFriendlyName, regName, reg.Address); } } } sw.WriteLine("}"); } } }
static void GenerateBSP(string toolchainDir, string ccsDir) { string[] keys = null; string bspDir = toolchainDir + @"\msp430-bsp"; Dictionary <string, Dictionary <string, string> > tiMCUs = new Dictionary <string, Dictionary <string, string> >(StringComparer.CurrentCultureIgnoreCase); foreach (var line in File.ReadAllLines(@"..\..\msp430.csv")) { string[] cells = line.Split(';'); if (keys == null) { keys = cells; continue; } Dictionary <string, string> entry = new Dictionary <string, string>(); for (int i = 0; i < cells.Length; i++) { entry[keys[i]] = cells[i]; } tiMCUs[cells[0]] = entry; int idx = cells[0].IndexOf('-'); if (idx != -1) { tiMCUs[cells[0].Substring(0, idx)] = entry; } } Regex rgLen = new Regex(".*LENGTH = 0x([0-9a-fA-F]{4}).*"); Regex rgOrigin = new Regex(".*ORIGIN = 0x([0-9a-fA-F]{4}).*"); Regex rgPeriph = new Regex("__([^ ]+) = (0x[a-fA-F0-9]+);"); List <string> families = new List <string>(); List <MCU> MCUs = new List <MCU>(); List <MCUFamily> famList = new List <MCUFamily>(); Directory.CreateDirectory(bspDir); Directory.CreateDirectory(bspDir + "\\devices"); XmlSerializer regSer = new XmlSerializer(typeof(MCUDefinition)); string[] files = Directory.GetFiles(Path.Combine(toolchainDir, "include"), "*.h"); for (int i = 0; i < files.Length; i++) { string file = files[i]; var proc = new Process(); string mcuName = Path.GetFileNameWithoutExtension(file).ToLower(); proc.StartInfo.FileName = toolchainDir + @"\bin\msp430-elf-gcc.exe"; proc.StartInfo.Arguments = $"-I. -E {mcuName}.h -o - -mmcu={mcuName}"; proc.StartInfo.WorkingDirectory = Path.Combine(toolchainDir, "include"); proc.StartInfo.UseShellExecute = false; proc.StartInfo.RedirectStandardOutput = true; proc.Start(); List <string> lines = new List <string>(); for (; ;) { var line = proc.StandardOutput.ReadLine(); if (line == null) { break; } lines.Add(line); } proc.WaitForExit(); if (proc.ExitCode != 0) { continue; } List <HardwareRegister> regs = new List <HardwareRegister>(); MCU mcu = new MCU(); mcu.ID = mcuName; mcu.CompilationFlags.COMMONFLAGS = "-mmcu=" + mcuName; string ld = Path.ChangeExtension(file, ".ld"); if (!File.Exists(ld)) { continue; } foreach (var line in File.ReadAllLines(ld)) { if (line.StartsWith(" RAM")) { var m = rgLen.Match(line); mcu.RAMSize = int.Parse(m.Groups[1].ToString(), System.Globalization.NumberStyles.HexNumber); m = rgOrigin.Match(line); mcu.RAMBase = uint.Parse(m.Groups[1].ToString(), System.Globalization.NumberStyles.HexNumber); } if (line.StartsWith(" ROM")) { var m = rgLen.Match(line); mcu.FLASHSize = int.Parse(m.Groups[1].ToString(), System.Globalization.NumberStyles.HexNumber); m = rgOrigin.Match(line); mcu.FLASHBase = uint.Parse(m.Groups[1].ToString(), System.Globalization.NumberStyles.HexNumber); } } if (mcu.RAMSize == 0) { throw new Exception("RAM size cannot be 0"); } foreach (var line in lines) { Regex rgRegister = new Regex("extern volatile (.*) ([^ ]+) __asm__\\(\"([^\"]+)\"\\)"); var m = rgRegister.Match(line); if (!m.Success) { if (line.Contains("extern") && line.Contains("__asm__")) { throw new Exception("Suspicious line"); } continue; } string type = m.Groups[1].Value; string name = m.Groups[2].Value; if (name.EndsWith("_H") || name.EndsWith("_L")) { continue; } if (!m.Groups[3].Value.StartsWith("0x")) { throw new Exception("Invalid addr for " + name); } ulong addr = ulong.Parse(m.Groups[3].Value.Substring(2), System.Globalization.NumberStyles.HexNumber); HardwareRegister reg = new HardwareRegister(); // TODO: the registers are not all 8 bits // According to some datasheets (not all were checked): // 01FFh to 0100h -> 16 bits // 0FFh to 010h -> 8bits // 0Fh to 00h -> 8-bit SFR (special function register) if (type == "unsigned char") { reg.SizeInBits = 8; } else if (type == "unsigned int") { reg.SizeInBits = 16; } else if (type == "unsigned long int") { reg.SizeInBits = 32; } else { throw new Exception("Unknown type"); } reg.Name = name; reg.Address = m.Groups[3].Value; regs.Add(reg); } string family = "Other"; Dictionary <string, string> info; if (tiMCUs.TryGetValue(mcu.ID, out info)) { family = info["Description"]; } int idx = families.IndexOf(family); if (idx == -1) { idx = families.Count; families.Add(family); famList.Add(new MCUFamily { ID = "fam_" + idx, UserFriendlyName = family, CompilationFlags = null }); } mcu.FamilyID = "fam_" + idx.ToString(); mcu.MCUDefinitionFile = "devices\\" + mcu.ID + ".xml"; mcu.HierarchicalPath = family; MCUs.Add(mcu); MCUDefinition desc = new MCUDefinition { MCUName = mcu.ID, RegisterSets = new HardwareRegisterSet[] { new HardwareRegisterSet { Registers = regs.ToArray() } } }; //, Specs = specs }; AdjustHardwareRegisters(ccsDir, mcu.ID, ref desc.RegisterSets); using (var fs = File.Create(bspDir + "\\" + mcu.MCUDefinitionFile + ".gz")) using (var gs = new GZipStream(fs, CompressionMode.Compress)) regSer.Serialize(gs, desc); Console.WriteLine($"Processed {mcuName} ({i}/{files.Length}) [{i * 100 / files.Length}%]"); } //Build the XML file BoardSupportPackage bsp = new BoardSupportPackage { GNUTargetID = "msp430", PackageID = "com.sysprogs.msp430.core", PackageDescription = "MSP430 MCUs" }; bsp.SupportedMCUs = MCUs.ToArray(); bsp.MCUFamilies = famList.ToArray(); bsp.DebugMethodPackages = new string[] { "debuggers\\core", "debuggers\\mspdebug" }; bsp.Examples = new string[] { "Samples\\LEDBlink" }; #if BSP_ADDITIONAL_GCC_FLAGS bsp.AdditionalGCCFlags = new PropertyList { PropertyGroups = new PropertyGroup[] { new PropertyGroup { Name = "MSP430 Options", Properties = new PropertyEntry[] { new PropertyEntry.Boolean { Name = "Disable watchdog on startup", Description = "Link the crt0 modules that disable the watchdog on startup", UniqueID = "com.sysprogs.msp430.mdisable-watchdog", ValueForTrue = "-mdisable-watchdog", ValueForFalse = "", }, new PropertyEntry.Boolean { Name = "Enable libcalls for shifts", Description = "Use library routines for non-constant shifts", UniqueID = "com.sysprogs.msp430.menable-libcall-shift", ValueForTrue = "-menable-libcall-shift", ValueForFalse = "", }, new PropertyEntry.Boolean { Name = "Inline hardware multiplication", Description = "Issue inline multiplication code for 32-bit integers", UniqueID = "com.sysprogs.msp430.minline-hwmul", ValueForTrue = "-minline-hwmul", ValueForFalse = "", }, new PropertyEntry.Enumerated { Name = "Interrupt vector count", Description = "Specify number of interrupt vectors on chip:", UniqueID = "com.sysprogs.msp430.mivcnt", GNUPrefix = "-mivcnt=", SuggestionList = new PropertyEntry.Enumerated.Suggestion[] { new PropertyEntry.Enumerated.Suggestion { InternalValue = "", UserFriendlyName = "(default)" }, new PropertyEntry.Enumerated.Suggestion { InternalValue = "16" }, new PropertyEntry.Enumerated.Suggestion { InternalValue = "32" }, new PropertyEntry.Enumerated.Suggestion { InternalValue = "64" }, }, AllowFreeEntry = true, }, new PropertyEntry.Enumerated { Name = "Hardware multiplier", Description = "Define available hardware multiplier", UniqueID = "com.sysprogs.msp430.mmpy", GNUPrefix = "-mmpy=", SuggestionList = new PropertyEntry.Enumerated.Suggestion[] { new PropertyEntry.Enumerated.Suggestion { InternalValue = "", UserFriendlyName = "(default)" }, new PropertyEntry.Enumerated.Suggestion { InternalValue = "16" }, new PropertyEntry.Enumerated.Suggestion { InternalValue = "16se" }, new PropertyEntry.Enumerated.Suggestion { InternalValue = "32" }, new PropertyEntry.Enumerated.Suggestion { InternalValue = "32dw" }, } }, new PropertyEntry.Boolean { Name = "No hardware multiplication in ISRs", Description = "Assume interrupt routine does not do hardware multiplication", UniqueID = "com.sysprogs.msp430.noint-hwmul", ValueForTrue = "-noint-hwmul", ValueForFalse = "", }, new PropertyEntry.Boolean { Name = "Prologue space optimization", Description = "Use subroutine call for function prologue/epilogue when possible", UniqueID = "com.sysprogs.msp430.msave-prologue", ValueForTrue = "-msave-prologue", ValueForFalse = "", }, } } } }; #endif XmlSerializer ser = new XmlSerializer(typeof(BoardSupportPackage), PropertyEntry.EntryTypes); using (var fs = File.Create(bspDir + "\\BSP.xml")) ser.Serialize(fs, bsp); //mcuSelector1.Reset(); var lBsp = LoadedBSP.Load(new BSPSummary(bspDir), null); //mcuSelector1.AddBSP(lBsp); //embeddedDebugSettingsControl1.Reset(); //embeddedDebugSettingsControl1.AddDebugMethods(lBsp.KnownDebugMethods); }