diff --git a/src/OneWare.Quartus/OneWare.Quartus.csproj b/src/OneWare.Quartus/OneWare.Quartus.csproj index f3eb449..fe2e3f2 100644 --- a/src/OneWare.Quartus/OneWare.Quartus.csproj +++ b/src/OneWare.Quartus/OneWare.Quartus.csproj @@ -16,8 +16,8 @@ - - + + diff --git a/src/OneWare.Quartus/QuartusLoader.cs b/src/OneWare.Quartus/QuartusLoader.cs index e221f31..cdaf43e 100644 --- a/src/OneWare.Quartus/QuartusLoader.cs +++ b/src/OneWare.Quartus/QuartusLoader.cs @@ -54,13 +54,13 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) return; } - var shortTermMode = properties.GetValueOrDefault("QuartusProgrammer_ShortTermMode") ?? "JTAG"; - var shortTermOperation = properties.GetValueOrDefault("QuartusProgrammer_ShortTermOperation") ?? "P"; + var shortTermMode = properties.GetValueOrDefault("QuartusProgrammer_ShortTerm_Mode") ?? "JTAG"; + var shortTermOperation = properties.GetValueOrDefault("QuartusProgrammer_ShortTerm_Operation") ?? "P"; var shortTermArgs = properties.GetValueOrDefault("QuartusProgrammer_ShortTerm_Arguments")?.Split(' ') ?? []; List pgmArgs = ["-c", cableName, "-m", shortTermMode]; pgmArgs.AddRange(shortTermArgs); - pgmArgs.AddRange(["-o", $"p;{sofFile}"]); + pgmArgs.AddRange(["-o", $"{shortTermOperation};{sofFile}"]); await childProcessService.ExecuteShellAsync("quartus_pgm", pgmArgs, project.FullPath, "Running Quartus programmer (Short-Term)...", AppState.Loading, true); @@ -115,8 +115,8 @@ await childProcessService.ExecuteShellAsync("quartus_pgm", pgmArgs, programFile = convertedFilePath; } - var longTermMode = properties.GetValueOrDefault("QuartusProgrammer_LongTermMode") ?? "JTAG"; - var longTermOperation = properties.GetValueOrDefault("QuartusProgrammer_LongTermOperation") ?? "P"; + var longTermMode = properties.GetValueOrDefault("QuartusProgrammer_LongTerm_Mode") ?? "JTAG"; + var longTermOperation = properties.GetValueOrDefault("QuartusProgrammer_LongTerm_Operation") ?? "P"; var longTermArgs = properties.GetValueOrDefault("QuartusProgrammer_LongTerm_Arguments")?.Split(' ') ?? []; List pgmArgs = ["-c", cableName, "-m", longTermMode]; diff --git a/src/OneWare.Quartus/QuartusModule.cs b/src/OneWare.Quartus/QuartusModule.cs index 8078651..83937e1 100644 --- a/src/OneWare.Quartus/QuartusModule.cs +++ b/src/OneWare.Quartus/QuartusModule.cs @@ -32,6 +32,14 @@ public void OnInitialized(IContainerProvider containerProvider) { DataContext = containerProvider.Resolve() })); + containerProvider.Resolve().RegisterUiExtension("UniversalFpgaToolBar_DownloaderConfigurationExtension", new UiExtension(x => + { + if (x is not UniversalFpgaProjectRoot cm) return null; + return new QuartusLoaderWindowExtensionView() + { + DataContext = containerProvider.Resolve((typeof(UniversalFpgaProjectRoot), cm)) + }; + })); containerProvider.Resolve().RegisterToolchain(); containerProvider.Resolve().RegisterLoader(); diff --git a/src/OneWare.Quartus/QuartusToolchain.cs b/src/OneWare.Quartus/QuartusToolchain.cs index 94c0c80..c530462 100644 --- a/src/OneWare.Quartus/QuartusToolchain.cs +++ b/src/OneWare.Quartus/QuartusToolchain.cs @@ -2,6 +2,7 @@ using OneWare.Quartus.Helper; using OneWare.Quartus.Services; using OneWare.UniversalFpgaProjectSystem.Models; +using OneWare.UniversalFpgaProjectSystem.Parser; using OneWare.UniversalFpgaProjectSystem.Services; namespace OneWare.Quartus; @@ -66,15 +67,20 @@ public Task CompileAsync(UniversalFpgaProjectRoot project, FpgaModel fpga) { var topEntity = project.TopEntity?.Header ?? throw new Exception("No TopEntity set!"); topEntity = Path.GetFileNameWithoutExtension(topEntity); + + var properties = FpgaSettingsParser.LoadSettings(project, fpga.Fpga.Name); var qsfPath = QsfHelper.GetQsfPath(project); var qsf = QsfHelper.ReadQsf(qsfPath); + + var family = properties.GetValueOrDefault("QuartusToolchain_Family") ?? throw new Exception("No Family set!"); + var device = properties.GetValueOrDefault("QuartusToolchain_Device") ?? throw new Exception("No Device set!"); //Add Family - qsf.SetGlobalAssignment("FAMILY", fpga.Fpga.Family); + qsf.SetGlobalAssignment("FAMILY", family); //Add Device - qsf.SetGlobalAssignment("DEVICE", fpga.Fpga.Model); + qsf.SetGlobalAssignment("DEVICE", device); //Add toplevel qsf.SetGlobalAssignment("TOP_LEVEL_ENTITY", topEntity); diff --git a/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs b/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs index 85538d2..1a80db6 100644 --- a/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs +++ b/src/OneWare.Quartus/ViewModels/QuartusCompileSettingsViewModel.cs @@ -1,27 +1,22 @@ -using DynamicData; -using ImTools; -using OneWare.Essentials.Controls; +using OneWare.Essentials.Controls; using OneWare.Essentials.ViewModels; -using OneWare.ProjectSystem.Models; using OneWare.Quartus.Helper; -using OneWare.Settings; using OneWare.Settings.ViewModels; -using OneWare.Settings.ViewModels.SettingTypes; using OneWare.UniversalFpgaProjectSystem.Models; namespace OneWare.Quartus.ViewModels; public class QuartusCompileSettingsViewModel : FlexibleWindowViewModelBase { - private string _qsfPath; - private QsfFile _qsfFile; + private readonly string _qsfPath; + private readonly QsfFile _qsfFile; public SettingsCollectionViewModel SettingsCollection { get; } = new("Quartus Settings") { ShowTitle = false }; - private List _settings = []; + private readonly List _settings = []; public QuartusCompileSettingsViewModel(UniversalFpgaProjectRoot fpgaProjectRoot) { diff --git a/src/OneWare.Quartus/ViewModels/QuartusLoaderSettingsViewModel.cs b/src/OneWare.Quartus/ViewModels/QuartusLoaderSettingsViewModel.cs new file mode 100644 index 0000000..9e08184 --- /dev/null +++ b/src/OneWare.Quartus/ViewModels/QuartusLoaderSettingsViewModel.cs @@ -0,0 +1,124 @@ +using DynamicData; +using OneWare.Essentials.Controls; +using OneWare.Essentials.ViewModels; +using OneWare.Settings; +using OneWare.Settings.ViewModels; +using OneWare.Settings.ViewModels.SettingTypes; +using OneWare.UniversalFpgaProjectSystem.Fpga; +using OneWare.UniversalFpgaProjectSystem.Models; +using OneWare.UniversalFpgaProjectSystem.Parser; + +namespace OneWare.Quartus.ViewModels; + +public class QuartusLoaderSettingsViewModel : FlexibleWindowViewModelBase +{ + private readonly UniversalFpgaProjectRoot _projectRoot; + private readonly Dictionary _settings; + private readonly IFpga _fpga; + private readonly ComboBoxSetting _shortTermModeSetting; + private readonly TitledSetting _shortTermOperationSetting; + private readonly TitledSetting _shortTermArgumentsSetting; + private readonly ComboBoxSetting _longTermModeSetting; + private readonly TitledSetting _longTermOperationSetting; + private readonly ComboBoxSetting _longTermFormatSetting; + private readonly TitledSetting _longTermCpfArgumentsSetting; + private readonly TitledSetting _longTermArgumentsSetting; + + public SettingsCollectionViewModel SettingsCollection { get; } = new("Quartus Loader Settings") + { + ShowTitle = false + }; + + public QuartusLoaderSettingsViewModel(UniversalFpgaProjectRoot projectRoot, IFpga fpga) + { + _projectRoot = projectRoot; + _fpga = fpga; + + Title = "Quartus Loader Settings"; + Id = "Quartus Loader Settings"; + + var defaultProperties = fpga.Properties; + _settings = FpgaSettingsParser.LoadSettings(projectRoot, fpga.Name); + + _shortTermModeSetting = new ComboBoxSetting("Short Term Mode", "Mode to use for Short Term Programming", + defaultProperties.GetValueOrDefault("QuartusProgrammer_ShortTerm_Mode") ?? "", ["JTAG", "CJTAG", "AS", "PS"]); + + _shortTermOperationSetting = new TitledSetting("Short Term Operation", "Operation to use for Short Term Programming", + defaultProperties.GetValueOrDefault("QuartusProgrammer_ShortTerm_Operation") ?? ""); + + _shortTermArgumentsSetting = new TitledSetting("Short Term Additional Arguments", "Additional Arguments to use for Short Term Programming", + defaultProperties.GetValueOrDefault("QuartusProgrammer_ShortTerm_Arguments") ?? ""); + + _longTermModeSetting = new ComboBoxSetting("Long Term Mode", "Mode to use for Long Term Programming", + defaultProperties.GetValueOrDefault("QuartusProgrammer_LongTerm_Mode") ?? "", ["JTAG", "CJTAG", "AS", "PS"]); + + _longTermOperationSetting = new TitledSetting("Long Term Operation", "Operation to use for Long Term Programming", + defaultProperties.GetValueOrDefault("QuartusProgrammer_LongTerm_Operation") ?? ""); + + _longTermFormatSetting = new ComboBoxSetting("Long Term Format", "Programming Format to use", + defaultProperties.GetValueOrDefault("QuartusProgrammer_LongTerm_Format") ?? "", ["POF", "JIC"]); + + _longTermCpfArgumentsSetting = new TitledSetting("Long Term Cpf Arguments", "If format is different from POF, these arguments will be used to convert .sof to given format", + defaultProperties.GetValueOrDefault("QuartusProgrammer_LongTerm_CpfArguments") ?? ""); + + _longTermArgumentsSetting = new TitledSetting("Long Term Additional Arguments", "Additional Arguments to use for Long Term Programming", + defaultProperties.GetValueOrDefault("QuartusProgrammer_LongTerm_Arguments") ?? ""); + + if (_settings.TryGetValue("QuartusProgrammer_ShortTerm_Mode", out var qPstMode)) + _shortTermModeSetting.Value = qPstMode; + + if (_settings.TryGetValue("QuartusProgrammer_ShortTerm_Operation", out var qPstOperation)) + _shortTermOperationSetting.Value = qPstOperation; + + if (_settings.TryGetValue("QuartusProgrammer_ShortTerm_Arguments", out var qPstArguments)) + _shortTermArgumentsSetting.Value = qPstArguments; + + if (_settings.TryGetValue("QuartusProgrammer_LongTerm_Mode", out var qPltMode)) + _longTermModeSetting.Value = qPltMode; + + if (_settings.TryGetValue("QuartusProgrammer_LongTerm_Operation", out var qPltOperation)) + _longTermOperationSetting.Value = qPltOperation; + + if (_settings.TryGetValue("QuartusProgrammer_LongTerm_Format", out var qPltFormat)) + _longTermFormatSetting.Value = qPltFormat; + + if (_settings.TryGetValue("QuartusProgrammer_LongTerm_CpfArguments", out var qPltCpfArguments)) + _longTermCpfArgumentsSetting.Value = qPltCpfArguments; + + if (_settings.TryGetValue("QuartusProgrammer_LongTerm_Arguments", out var qPltArguments)) + _longTermArgumentsSetting.Value = qPltArguments; + + SettingsCollection.SettingModels.Add(new ComboBoxSettingViewModel(_shortTermModeSetting)); + SettingsCollection.SettingModels.Add(new TextBoxSettingViewModel(_shortTermOperationSetting)); + SettingsCollection.SettingModels.Add(new TextBoxSettingViewModel(_shortTermArgumentsSetting)); + SettingsCollection.SettingModels.Add(new ComboBoxSettingViewModel(_longTermModeSetting)); + SettingsCollection.SettingModels.Add(new TextBoxSettingViewModel(_longTermOperationSetting)); + SettingsCollection.SettingModels.Add(new ComboBoxSettingViewModel(_longTermFormatSetting)); + SettingsCollection.SettingModels.Add(new TextBoxSettingViewModel(_longTermCpfArgumentsSetting)); + SettingsCollection.SettingModels.Add(new TextBoxSettingViewModel(_longTermArgumentsSetting)); + } + + public void Save(FlexibleWindow flexibleWindow) + { + _settings["QuartusProgrammer_ShortTerm_Mode"] = _shortTermModeSetting.Value.ToString()!; + _settings["QuartusProgrammer_ShortTerm_Operation"] = _shortTermOperationSetting.Value.ToString()!; + _settings["QuartusProgrammer_ShortTerm_Arguments"] = _shortTermArgumentsSetting.Value.ToString()!; + _settings["QuartusProgrammer_LongTerm_Mode"] = _longTermModeSetting.Value.ToString()!; + _settings["QuartusProgrammer_LongTerm_Operation"] = _longTermOperationSetting.Value.ToString()!; + _settings["QuartusProgrammer_LongTerm_Format"] = _longTermFormatSetting.Value.ToString()!; + _settings["QuartusProgrammer_LongTerm_CpfArguments"] = _longTermCpfArgumentsSetting.Value.ToString()!; + _settings["QuartusProgrammer_LongTerm_Arguments"] = _longTermArgumentsSetting.Value.ToString()!; + + FpgaSettingsParser.SaveSettings(_projectRoot, _fpga.Name, _settings); + + Close(flexibleWindow); + } + + public void Reset() + { + foreach (var setting in SettingsCollection.SettingModels) + { + setting.Setting.Value = setting.Setting.DefaultValue; + } + } +} \ No newline at end of file diff --git a/src/OneWare.Quartus/ViewModels/QuartusLoaderWindowExtensionViewModel.cs b/src/OneWare.Quartus/ViewModels/QuartusLoaderWindowExtensionViewModel.cs new file mode 100644 index 0000000..569513c --- /dev/null +++ b/src/OneWare.Quartus/ViewModels/QuartusLoaderWindowExtensionViewModel.cs @@ -0,0 +1,52 @@ +using Avalonia.Controls; +using Avalonia.Threading; +using CommunityToolkit.Mvvm.ComponentModel; +using OneWare.Essentials.Services; +using OneWare.Quartus.Views; +using OneWare.UniversalFpgaProjectSystem.Fpga; +using OneWare.UniversalFpgaProjectSystem.Models; +using OneWare.UniversalFpgaProjectSystem.Services; +using Prism.Ioc; + +namespace OneWare.Quartus.ViewModels; + +public class QuartusLoaderWindowExtensionViewModel : ObservableObject +{ + private readonly IWindowService _windowService; + private readonly UniversalFpgaProjectRoot _projectRoot; + private readonly IFpga? _fpga; + + public bool IsVisible { get; } + + public bool IsEnabled { get; } + + public QuartusLoaderWindowExtensionViewModel(UniversalFpgaProjectRoot projectRoot, IWindowService windowService, FpgaService fpgaService) + { + _windowService = windowService; + _projectRoot = projectRoot; + + _fpga = fpgaService.Fpgas.FirstOrDefault(x => x.Name == projectRoot.GetProjectProperty("Fpga")); + + IsVisible = projectRoot.Loader is QuartusLoader; + IsEnabled = _fpga != null; + } + + public async Task OpenSettingsAsync(Control control) + { + if (_fpga == null) return; + + var ownerWindow = TopLevel.GetTopLevel(control) as Window; + await Dispatcher.UIThread.InvokeAsync(async () => + { + try + { + await _windowService.ShowDialogAsync(new QuartusLoaderSettingsView() + { DataContext = new QuartusLoaderSettingsViewModel(_projectRoot, _fpga) }, ownerWindow); + } + catch (Exception e) + { + ContainerLocator.Container.Resolve().Error(e.Message, e); + } + }); + } +} \ No newline at end of file diff --git a/src/OneWare.Quartus/Views/QuartusLoaderSettingsView.axaml b/src/OneWare.Quartus/Views/QuartusLoaderSettingsView.axaml new file mode 100644 index 0000000..8bacb20 --- /dev/null +++ b/src/OneWare.Quartus/Views/QuartusLoaderSettingsView.axaml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/src/OneWare.Quartus/Views/QuartusLoaderSettingsView.axaml.cs b/src/OneWare.Quartus/Views/QuartusLoaderSettingsView.axaml.cs new file mode 100644 index 0000000..4d336c4 --- /dev/null +++ b/src/OneWare.Quartus/Views/QuartusLoaderSettingsView.axaml.cs @@ -0,0 +1,11 @@ +using OneWare.Essentials.Controls; + +namespace OneWare.Quartus.Views; + +public partial class QuartusLoaderSettingsView : FlexibleWindow +{ + public QuartusLoaderSettingsView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/OneWare.Quartus/Views/QuartusLoaderWindowExtensionView.axaml b/src/OneWare.Quartus/Views/QuartusLoaderWindowExtensionView.axaml new file mode 100644 index 0000000..112daab --- /dev/null +++ b/src/OneWare.Quartus/Views/QuartusLoaderWindowExtensionView.axaml @@ -0,0 +1,15 @@ + + + + + + + diff --git a/src/OneWare.Quartus/Views/QuartusLoaderWindowExtensionView.axaml.cs b/src/OneWare.Quartus/Views/QuartusLoaderWindowExtensionView.axaml.cs new file mode 100644 index 0000000..9e151b8 --- /dev/null +++ b/src/OneWare.Quartus/Views/QuartusLoaderWindowExtensionView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; + +namespace OneWare.Quartus.Views; + +public partial class QuartusLoaderWindowExtensionView : UserControl +{ + public QuartusLoaderWindowExtensionView() + { + InitializeComponent(); + } +} \ No newline at end of file diff --git a/src/OneWare.Quartus/oneware.json b/src/OneWare.Quartus/oneware.json index c26be7f..6f848b4 100644 --- a/src/OneWare.Quartus/oneware.json +++ b/src/OneWare.Quartus/oneware.json @@ -2,13 +2,13 @@ "Dependencies": [ { "Name": "OneWare.Essentials", - "MinVersion": "0.4.6.0", - "MaxVersion": "0.4.6.0" + "MinVersion": "0.4.7.0", + "MaxVersion": "0.4.7.0" }, { "Name": "OneWare.UniversalFpgaProjectSystem", - "MinVersion": "0.16.8.0", - "MaxVersion": "0.16.8.0" + "MinVersion": "0.17.0.0", + "MaxVersion": "0.17.0.0" } ] } \ No newline at end of file