From c9dcc0e56e0e8962d00bfb0120aa0c27006e8475 Mon Sep 17 00:00:00 2001 From: Sebastian Wittlich Date: Wed, 18 Mar 2026 19:00:31 +0100 Subject: [PATCH 1/2] fix openFPGALoader + add gen_verilog --- .../Loaders/OpenFpgaLoader.cs | 36 ++++++++++++++++--- .../OssCadSuiteIntegrationModule.cs | 20 +++++++++++ .../Yosys/YosysService.cs | 10 +++++- 3 files changed, 61 insertions(+), 5 deletions(-) diff --git a/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs b/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs index 5161f847e..ea8ba4f53 100644 --- a/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs +++ b/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs @@ -29,7 +29,7 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) var board = properties.GetValueOrDefault("openFpgaLoaderBoard"); var cable = properties.GetValueOrDefault("OpenFpgaLoader_Cable"); - List openFpgaLoaderArguments = []; + List openFpgaLoaderArguments = []; if (!string.IsNullOrEmpty(board)) { openFpgaLoaderArguments.AddRange(["-b", board]); @@ -44,9 +44,19 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) return; } - if (longTerm) openFpgaLoaderArguments.Add("-f"); + if (longTerm) + { + if (properties.GetValueOrDefault("openFpgaLoaderLongTermFlags") is { } longFlags) + openFpgaLoaderArguments.Add(longFlags); + + openFpgaLoaderArguments.Add("-f"); + } + else if (properties.GetValueOrDefault("openFpgaLoaderShortTermFlags") is { } shortFlags) + { + openFpgaLoaderArguments.Add(shortFlags); + } - openFpgaLoaderArguments.AddRange(properties.GetValueOrDefault("OpenFpgaLoader_Flags")?.Split(' ', + openFpgaLoaderArguments.AddRange(properties.GetValueOrDefault("OpenFpgaLoaderFlags")?.Split(' ', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) ?? []); var bitstreamFormat = properties @@ -66,6 +76,7 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) } var path = settingsService.GetSettingValue(OssCadSuiteIntegrationModule.OpenFpgaLoaderPathSetting); + outputService.WriteLine("Starting OpenFpgaLoader ..."); var command = ToolCommand.FromShellParams(path, openFpgaLoaderArguments, project.FullPath, $"Running {path}...", AppState.Loading, true, null, s => { @@ -73,7 +84,24 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) return true; }); - await toolExecutionDispatcherService.ExecuteAsync(command); + // await toolExecutionDispatcherService.ExecuteAsync(command); + + try + { + await toolExecutionDispatcherService.ExecuteAsync(command); + } + catch (Exception ex) + { + // Schreibt den Fehler direkt in deine Konsole/Output-Service + Dispatcher.UIThread.Post(() => + { + outputService.WriteLine($"Error in ExecuteAsync: {ex.Message}"); + if (ex.InnerException != null) + { + outputService.WriteLine($"Details: {ex.InnerException.Message}"); + } + }); + } //await childProcess.ExecuteShellAsync(path, openFpgaLoaderArguments, // project.FullPath, "Running OpenFPGALoader...", AppState.Loading, true); diff --git a/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs b/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs index 3e4bb5433..fa6248d7d 100644 --- a/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs +++ b/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs @@ -367,6 +367,7 @@ public override void Initialize(IServiceProvider serviceProvider) var windowService = serviceProvider.Resolve(); var projectExplorerService = serviceProvider.Resolve(); var fpgaService = serviceProvider.Resolve(); + var outputService = serviceProvider.Resolve(); fpgaService.RegisterNodeProvider(); @@ -598,6 +599,25 @@ await serviceProvider.Resolve().OpenInGtkWaveAsync(wave.FullPath } } } + if (x is [IProjectFile { Extension: ".ccf" } ccf]) + { + if (ccf.Root is UniversalFpgaProjectRoot universalFpgaProjectRoot) + { + l.Add(new MenuItemModel("ccf") + { + Header = "Convert to pcf", + Command = new AsyncRelayCommand(() => + { + var absoluteCcfPath = Path.Combine(universalFpgaProjectRoot.RootFolderPath, ccf.FullPath); + var absolutePcfPath = Path.ChangeExtension(absoluteCcfPath, ".pcf"); + outputService.WriteLine($"Converting {absoluteCcfPath} to CCF File"); + if (Path.Exists(absolutePcfPath)) + ConstraintFileHelper.Convert(absoluteCcfPath, absolutePcfPath); + return Task.CompletedTask; + }), + }); + } + } }); serviceProvider.Resolve().RegisterFileOpenOverwrite(x => diff --git a/src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs b/src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs index d971aa658..0b5146f0f 100644 --- a/src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs +++ b/src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs @@ -74,6 +74,14 @@ public async Task SynthAsync(UniversalFpgaProjectRoot project, FpgaModel f var includedFiles = project.GetFiles("*.v").Concat(project.GetFiles("*.sv")) .Where(x => !project.IsCompileExcluded(x)) .Where(x => !project.IsTestBench(x)); + + var genVerilogPath = Path.Combine(project.RootFolderPath, "build", "gen_verilog"); + if (Directory.Exists(genVerilogPath)) + { + var generatedFiles = Directory.EnumerateFiles(genVerilogPath, "*.v", + SearchOption.AllDirectories); + includedFiles = includedFiles.Concat(generatedFiles); + } var yosysSynthTool = properties.GetValueOrDefault("yosysToolchainYosysSynthTool") ?? throw new Exception("Yosys Tool not set!"); @@ -91,7 +99,7 @@ public async Task SynthAsync(UniversalFpgaProjectRoot project, FpgaModel f } else { - yosysCommand = yosysCommand.Replace("$TOP", top.Split(".")[0]); + yosysCommand = yosysCommand.Replace("$TOP", Path.GetFileNameWithoutExtension(top)); yosysCommand = yosysCommand.Replace("$SYNTH_TOOL", yosysSynthTool); yosysCommand = yosysCommand.Replace("$OUTPUT", "build/synth.json"); From ad7af6db515b6987fac9782132be0b62d4bfdd63 Mon Sep 17 00:00:00 2001 From: Sebastian Wittlich Date: Thu, 19 Mar 2026 11:43:04 +0100 Subject: [PATCH 2/2] Add File/Exit, CleanUp Code, Fix GHDL Path, Add CleanBuildFolder --- src/OneWare.Core/App.axaml.cs | 13 ++++++++ .../Loaders/OpenFpgaLoader.cs | 13 ++------ .../OssCadSuiteIntegrationModule.cs | 9 ++++-- .../UniversalFpgaProjectManager.cs | 31 ++++++++++++++----- 4 files changed, 47 insertions(+), 19 deletions(-) diff --git a/src/OneWare.Core/App.axaml.cs b/src/OneWare.Core/App.axaml.cs index 5380aa124..de1920caf 100644 --- a/src/OneWare.Core/App.axaml.cs +++ b/src/OneWare.Core/App.axaml.cs @@ -401,6 +401,19 @@ Select the target OpenVINO device. InputGesture = new KeyGesture(Key.S, PlatformHelper.ControlKey | KeyModifiers.Shift), Icon = new IconModel("VsImageLib.SaveAll16X") }); + windowService.RegisterMenuItem("MainWindow_MainMenu/File", new MenuItemModel("exit") + { + Command = new RelayCommand(() => + { + if (Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + { + desktop.MainWindow?.Close(); + } + }), + Header = "Exit", + InputGesture = new KeyGesture(Key.X, PlatformHelper.ControlKey | KeyModifiers.Shift), + Icon = new IconModel("VsImageLib.Exit") + }); var applicationCommandService = Services.Resolve(); diff --git a/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs b/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs index ea8ba4f53..771bdde49 100644 --- a/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs +++ b/src/OneWare.OssCadSuiteIntegration/Loaders/OpenFpgaLoader.cs @@ -9,8 +9,7 @@ namespace OneWare.OssCadSuiteIntegration.Loaders; -public class OpenFpgaLoader(IChildProcessService childProcess, - ISettingsService settingsService, ILogger logger, IOutputService outputService, +public class OpenFpgaLoader(ISettingsService settingsService, ILogger logger, IOutputService outputService, IToolExecutionDispatcherService toolExecutionDispatcherService) : IFpgaLoader { @@ -29,7 +28,7 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) var board = properties.GetValueOrDefault("openFpgaLoaderBoard"); var cable = properties.GetValueOrDefault("OpenFpgaLoader_Cable"); - List openFpgaLoaderArguments = []; + List openFpgaLoaderArguments = []; if (!string.IsNullOrEmpty(board)) { openFpgaLoaderArguments.AddRange(["-b", board]); @@ -77,22 +76,19 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) var path = settingsService.GetSettingValue(OssCadSuiteIntegrationModule.OpenFpgaLoaderPathSetting); outputService.WriteLine("Starting OpenFpgaLoader ..."); - var command = ToolCommand.FromShellParams(path, openFpgaLoaderArguments, + var command = ToolCommand.FromShellParams(path, openFpgaLoaderArguments!, project.FullPath, $"Running {path}...", AppState.Loading, true, null, s => { Dispatcher.UIThread.Post(() => { outputService.WriteLine(s); }); return true; }); - // await toolExecutionDispatcherService.ExecuteAsync(command); - try { await toolExecutionDispatcherService.ExecuteAsync(command); } catch (Exception ex) { - // Schreibt den Fehler direkt in deine Konsole/Output-Service Dispatcher.UIThread.Post(() => { outputService.WriteLine($"Error in ExecuteAsync: {ex.Message}"); @@ -102,8 +98,5 @@ public async Task DownloadAsync(UniversalFpgaProjectRoot project) } }); } - - //await childProcess.ExecuteShellAsync(path, openFpgaLoaderArguments, - // project.FullPath, "Running OpenFPGALoader...", AppState.Loading, true); } } \ No newline at end of file diff --git a/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs b/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs index fa6248d7d..f0a38f13f 100644 --- a/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs +++ b/src/OneWare.OssCadSuiteIntegration/OssCadSuiteIntegrationModule.cs @@ -546,8 +546,13 @@ await windowService.ShowDialogAsync( Path.Combine(x, "lib", $"python3{PlatformHelper.ExecutableExtension}")); //environmentService.SetEnvironmentVariable("VERILATOR_ROOT", // Path.Combine(x, "share", $"verilator")); - environmentService.SetEnvironmentVariable("GHDL_PREFIX", - Path.Combine(x, "lib", $"ghdl")); + // GHDL is not provided in the Windows version + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + environmentService.SetEnvironmentVariable("GHDL_PREFIX", + Path.Combine(x, "lib", $"ghdl")); + } + environmentService.SetEnvironmentVariable("GTK_EXE_PREFIX", x); environmentService.SetEnvironmentVariable("GTK_DATA_PREFIX", x); environmentService.SetEnvironmentVariable("GDK_PIXBUF_MODULEDIR", diff --git a/src/OneWare.UniversalFpgaProjectSystem/UniversalFpgaProjectManager.cs b/src/OneWare.UniversalFpgaProjectSystem/UniversalFpgaProjectManager.cs index b8be0159a..96cf68bf4 100644 --- a/src/OneWare.UniversalFpgaProjectSystem/UniversalFpgaProjectManager.cs +++ b/src/OneWare.UniversalFpgaProjectSystem/UniversalFpgaProjectManager.cs @@ -1,11 +1,6 @@ -using Avalonia; -using Avalonia.Controls; -using CommunityToolkit.Mvvm.Input; -using OneWare.Essentials.Extensions; -using OneWare.Essentials.Helpers; +using CommunityToolkit.Mvvm.Input; using OneWare.Essentials.Models; using OneWare.Essentials.Services; -using OneWare.Essentials.ViewModels; using OneWare.UniversalFpgaProjectSystem.Models; using OneWare.UniversalFpgaProjectSystem.Services; using OneWare.UniversalFpgaProjectSystem.ViewModels; @@ -19,14 +14,16 @@ public class UniversalFpgaProjectManager : IProjectManager private readonly IMainDockService _mainDockService; private readonly IProjectExplorerService _projectExplorerService; private readonly IWindowService _windowService; + private readonly IOutputService _outputService; public UniversalFpgaProjectManager(IProjectExplorerService projectExplorerService, IMainDockService mainDockService, - IWindowService windowService, FpgaService fpgaService) + IWindowService windowService, FpgaService fpgaService, IOutputService outputService) { _projectExplorerService = projectExplorerService; _mainDockService = mainDockService; _windowService = windowService; _fpgaService = fpgaService; + _outputService = outputService; _projectExplorerService.RegisterConstructContextMenu(ConstructContextMenu); } @@ -112,6 +109,12 @@ private void ConstructContextMenu(IReadOnlyList selected, Command = new AsyncRelayCommand(() => _projectExplorerService.ReloadProjectAsync(root)), Icon = new IconModel("VsImageLib.RefreshGrey16X") }); + menuItems.Add(new MenuItemModel("Clean") + { + Header = "Clean", + Command = new AsyncRelayCommand(() => + CleanBuildFoldersAsync(root)) + }); menuItems.Add(new MenuItemModel("ProjectSettings") { Header = "Project Settings", @@ -211,4 +214,18 @@ await _windowService.ShowDialogAsync(new UniversalFpgaProjectSettingsEditorView typeof(UniversalFpgaProjectRoot), root)) }); } + + private async Task CleanBuildFoldersAsync(UniversalFpgaProjectRoot root) + { + var buildFolderPath = Path.Combine(root.RootFolderPath, "build"); + _outputService.WriteLine($"Cleaning build folders: {buildFolderPath}"); + if (Directory.Exists(buildFolderPath)) + { + await Task.Run(() => + { + Directory.Delete(buildFolderPath, true); + Directory.CreateDirectory(buildFolderPath); + }); + } + } }