diff --git a/src/OneWare.Quartus/Helper/IQsfSetting.cs b/src/OneWare.Quartus/Helper/IQsfSetting.cs new file mode 100644 index 0000000..3520487 --- /dev/null +++ b/src/OneWare.Quartus/Helper/IQsfSetting.cs @@ -0,0 +1,9 @@ +using OneWare.Settings.ViewModels.SettingTypes; + +namespace OneWare.Quartus.Helper; + +public interface IQsfSetting +{ + public SettingViewModel GetViewModel(); + public void Save(); +} \ No newline at end of file diff --git a/src/OneWare.Quartus/Helper/QsfFile.cs b/src/OneWare.Quartus/Helper/QsfFile.cs index 770be71..becfe28 100644 --- a/src/OneWare.Quartus/Helper/QsfFile.cs +++ b/src/OneWare.Quartus/Helper/QsfFile.cs @@ -12,6 +12,9 @@ public partial class QsfFile(string[] lines) [GeneratedRegex(@"set_location_assignment\s")] private static partial Regex RemoveLocationAssignmentRegex(); + [GeneratedRegex(@"set_global_assignment\s-name\s\w+_FILE\s(.+)")] + private static partial Regex RemoveFileAssignmentRegex(); + public List Lines { get; private set; } = lines.ToList(); public string? GetGlobalAssignment(string propertyName) @@ -71,6 +74,12 @@ public void AddLocationAssignment(string pin, string node) Lines.Add($"set_location_assignment PIN_{pin} -to {node}"); } + public void RemoveFileAssignments() + { + var regex = RemoveFileAssignmentRegex(); + Lines = Lines.Where(x => !regex.IsMatch(x)).ToList(); + } + public void RemoveLocationAssignments() { var regex = RemoveLocationAssignmentRegex(); diff --git a/src/OneWare.Quartus/Helper/QsfSettingComboBox.cs b/src/OneWare.Quartus/Helper/QsfSettingComboBox.cs new file mode 100644 index 0000000..bebda11 --- /dev/null +++ b/src/OneWare.Quartus/Helper/QsfSettingComboBox.cs @@ -0,0 +1,42 @@ +using OneWare.Settings; +using OneWare.Settings.ViewModels.SettingTypes; + +namespace OneWare.Quartus.Helper; + +public class QsfSettingComboBox : IQsfSetting +{ + private readonly string _name; + private readonly QsfFile _qsfFile; + private readonly Dictionary _options; + private readonly ComboBoxSetting _setting; + + public QsfSettingComboBox(QsfFile file, string name, string title, string description, Dictionary options, string defaultValue) + { + _qsfFile = file; + _name = name; + _options = options; + + _setting = new ComboBoxSetting(title, description, defaultValue, options.Values); + + var setting = file.GetGlobalAssignment(name); + + if (!string.IsNullOrWhiteSpace(setting)) + { + options.TryAdd(setting, setting); + _setting.Value = options[setting]; + } + } + + public SettingViewModel GetViewModel() + { + return new ComboBoxSettingViewModel(_setting); + } + + public void Save() + { + if(_setting.Value.ToString() != "Default") + _qsfFile.SetGlobalAssignment(_name, _options.FirstOrDefault(x => x.Value == (string)_setting.Value).Key); + else + _qsfFile.RemoveGlobalAssignment(_name); + } +} \ No newline at end of file diff --git a/src/OneWare.Quartus/QuartusToolchain.cs b/src/OneWare.Quartus/QuartusToolchain.cs index 73ab4b3..69fca07 100644 --- a/src/OneWare.Quartus/QuartusToolchain.cs +++ b/src/OneWare.Quartus/QuartusToolchain.cs @@ -52,17 +52,17 @@ public void SaveConnections(UniversalFpgaProjectRoot project, FpgaModel fpga) qsf.SetGlobalAssignment("TOP_LEVEL_ENTITY", topEntity); //Add Files + qsf.RemoveFileAssignments(); foreach (var file in project.Files) { qsf.AddFile(file); } + //Add Connections qsf.RemoveLocationAssignments(); - foreach (var (_, pinModel) in fpga.PinModels) + foreach (var (_, pinModel) in fpga.PinModels.Where(x => x.Value.Connection != null)) { - if(pinModel.Connection == null) continue; - - qsf.AddLocationAssignment(pinModel.Pin.Name, pinModel.Connection.Node.Name); + qsf.AddLocationAssignment(pinModel.Pin.Name, pinModel.Connection!.Node.Name); } QsfHelper.WriteQsf(qsfPath, qsf); diff --git a/src/OneWare.Quartus/Services/QuartusService.cs b/src/OneWare.Quartus/Services/QuartusService.cs index 045940f..3020e09 100644 --- a/src/OneWare.Quartus/Services/QuartusService.cs +++ b/src/OneWare.Quartus/Services/QuartusService.cs @@ -20,7 +20,7 @@ public async Task CompileAsync(UniversalFpgaProjectRoot project, FpgaModel fpga) var start = DateTime.Now; outputService.WriteLine("Compiling...\n==================", Brushes.CornflowerBlue); - await childProcessService.ExecuteShellAsync("quartus_sh", + var (success, _) =await childProcessService.ExecuteShellAsync("quartus_sh", $"--flow compile {Path.GetFileNameWithoutExtension(project.TopEntity.Header)}", project.FullPath, "Running Quartus Prime Shell...", AppState.Loading, true, (x) => { @@ -35,6 +35,9 @@ await childProcessService.ExecuteShellAsync("quartus_sh", var compileTime = DateTime.Now - start; - outputService.WriteLine($"==================\n\nCompilation finished after {(int)compileTime.TotalMinutes:D2}:{compileTime.Seconds:D2}\n"); + if(success) + outputService.WriteLine($"==================\n\nCompilation finished after {(int)compileTime.TotalMinutes:D2}:{compileTime.Seconds:D2}\n"); + else + outputService.WriteLine($"==================\n\nCompilation failed after {(int)compileTime.TotalMinutes:D2}:{compileTime.Seconds:D2}\n", Brushes.Red); } } \ No newline at end of file diff --git a/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs b/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs index c5d8a2a..145af29 100644 --- a/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs +++ b/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs @@ -1,4 +1,6 @@ -using OneWare.Essentials.Controls; +using DynamicData; +using ImTools; +using OneWare.Essentials.Controls; using OneWare.Essentials.ViewModels; using OneWare.ProjectSystem.Models; using OneWare.Quartus.Helper; @@ -19,30 +21,7 @@ public class QuartusCompileSettingsViewModel : FlexibleWindowViewModelBase ShowTitle = false }; - private ComboBoxSetting _processorCountSetting; - private ComboBoxSetting _configurationModeSetting; - private ComboBoxSetting _optimizationModeSetting; - - private Dictionary AvailableConfigurationModes { get; } = new() - { - { "DEFAULT", "Default" }, - { "DUAL IMAGES", "Dual Compressed Images (256Kbits UFM)" }, - { "SINGLE COMP IMAGE", "Single Compressed Image (1376Kbits UFM)" }, - { "SINGLE COMP IMAGE WITH ERAM", "Single Compressed Image with Memory Initialization (256Kbits UFM)" }, - { "SINGLE IMAGE", "Single Uncompressed Image (912Kbits UFM)" }, - { "SINGLE IMAGE WITH ERAM", "Single Uncompressed Image with Memory Initialization (256Kbits UFM)" } - }; - - private Dictionary AvailableOptimizationModes { get; } = new() - { - { "BALANCED", "Balanced" }, - { "HIGH PERFORMANCE EFFORT", "Performance (High effort - increases runtime)" }, - { "AGGRESSIVE PERFORMANCE", "Performance (Aggressive - increases runtime and area)" }, - { "HIGH POWER EFFORT", "Power (High effort - increases runtime)" }, - { "AGGRESSIVE POWER", "Power (Aggressive - increases runtime, reduces performance)" }, - { "AGGRESSIVE AREA", "Area (Aggressive - reduces performance)" } - }; - + private List _settings = []; public QuartusCompileSettingsViewModel(UniversalFpgaProjectRoot fpgaProjectRoot) { @@ -51,36 +30,44 @@ public QuartusCompileSettingsViewModel(UniversalFpgaProjectRoot fpgaProjectRoot) _qsfPath = QsfHelper.GetQsfPath(fpgaProjectRoot); _qsfFile = QsfHelper.ReadQsf(_qsfPath); - - _processorCountSetting = new ComboBoxSetting("Parallel Compilation Processors", - "Max processors Quartus will use to compile", - Environment.ProcessorCount, Enumerable.Range(1, Environment.ProcessorCount).Cast()); - - _configurationModeSetting = new ComboBoxSetting("Configuration Mode", "Quartus Configuration Mode", - AvailableConfigurationModes["DEFAULT"], AvailableConfigurationModes.Values); - - _optimizationModeSetting = new ComboBoxSetting("Optimization Mode", "Quartus Optimization Mode", - AvailableOptimizationModes["BALANCED"], AvailableOptimizationModes.Values); - SettingsCollection.SettingModels.Add(new ComboBoxSettingViewModel(_processorCountSetting)); - SettingsCollection.SettingModels.Add(new ComboBoxSettingViewModel(_configurationModeSetting)); - SettingsCollection.SettingModels.Add(new ComboBoxSettingViewModel(_optimizationModeSetting)); + _settings.Add(new QsfSettingComboBox(_qsfFile, "NUM_PARALLEL_PROCESSORS", "Parallel CPU Count", "Max processors Quartus will use to compile", + Enumerable.Range(1, Environment.ProcessorCount).Select(x => x.ToString()).ToDictionary(x => x.ToString()), Environment.ProcessorCount.ToString())); - var processorCount = _qsfFile.GetGlobalAssignment("NUM_PARALLEL_PROCESSORS"); - if(!string.IsNullOrWhiteSpace(processorCount) && int.TryParse(processorCount, out var processorCountInt)) _processorCountSetting.Value = processorCountInt; - - var configurationMode = _qsfFile.GetGlobalAssignment("INTERNAL_FLASH_UPDATE_MODE"); - if(!string.IsNullOrWhiteSpace(configurationMode)) _configurationModeSetting.Value = configurationMode; + _settings.Add(new QsfSettingComboBox(_qsfFile, "INTERNAL_FLASH_UPDATE_MODE", "Configuration Mode", "Quartus Configuration Mode", + new Dictionary() + { + { "DEFAULT", "Default" }, + { "DUAL IMAGES", "Dual Compressed Images (256Kbits UFM)" }, + { "SINGLE COMP IMAGE", "Single Compressed Image (1376Kbits UFM)" }, + { "SINGLE COMP IMAGE WITH ERAM", "Single Compressed Image with Memory Initialization (256Kbits UFM)" }, + { "SINGLE IMAGE", "Single Uncompressed Image (912Kbits UFM)" }, + { "SINGLE IMAGE WITH ERAM", "Single Uncompressed Image with Memory Initialization (256Kbits UFM)" } + }, "Default")); - var optimizationMode = _qsfFile.GetGlobalAssignment("OPTIMIZATION_MODE"); - if(!string.IsNullOrWhiteSpace(optimizationMode)) _optimizationModeSetting.Value = optimizationMode; + _settings.Add(new QsfSettingComboBox(_qsfFile, "OPTIMIZATION_MODE", "Optimization Mode", "Quartus Optimization Mode", + new Dictionary() + { + { "BALANCED", "Balanced" }, + { "HIGH PERFORMANCE EFFORT", "Performance (High effort - increases runtime)" }, + { "AGGRESSIVE PERFORMANCE", "Performance (Aggressive - increases runtime and area)" }, + { "HIGH POWER EFFORT", "Power (High effort - increases runtime)" }, + { "AGGRESSIVE POWER", "Power (Aggressive - increases runtime, reduces performance)" }, + { "AGGRESSIVE AREA", "Area (Aggressive - reduces performance)" } + }, "Balanced")); + + foreach (var setting in _settings) + { + SettingsCollection.SettingModels.Add(setting.GetViewModel()); + } } public void Save(FlexibleWindow flexibleWindow) { - _qsfFile.SetGlobalAssignment("NUM_PARALLEL_PROCESSORS", _processorCountSetting.Value.ToString()!); - _qsfFile.SetGlobalAssignment("INTERNAL_FLASH_UPDATE_MODE", _configurationModeSetting.Value.ToString()!); - _qsfFile.SetGlobalAssignment("OPTIMIZATION_MODE", _optimizationModeSetting.Value.ToString()!); + foreach (var setting in _settings) + { + setting.Save(); + } QsfHelper.WriteQsf(_qsfPath, _qsfFile); Close(flexibleWindow);