diff --git a/OneWare.sln b/OneWare.sln
index f74fba21..c5c74c16 100644
--- a/OneWare.sln
+++ b/OneWare.sln
@@ -176,6 +176,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneWare.Vhdl.UnitTests", "t
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneWare.WaveFormViewer.Tests", "tests\OneWare.WaveFormViewer.Tests\OneWare.WaveFormViewer.Tests.csproj", "{AAC4D6FA-4F94-4616-93B3-3BB47E4A0BB1}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneWare.UniversalFpgaProjectSystem.Tests", "tests\OneWare.UniversalFpgaProjectSystem.Tests\OneWare.UniversalFpgaProjectSystem.Tests.csproj", "{484F3E48-EF14-4801-B896-41BDB67A54E6}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -378,6 +380,10 @@ Global
{AAC4D6FA-4F94-4616-93B3-3BB47E4A0BB1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AAC4D6FA-4F94-4616-93B3-3BB47E4A0BB1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AAC4D6FA-4F94-4616-93B3-3BB47E4A0BB1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {484F3E48-EF14-4801-B896-41BDB67A54E6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {484F3E48-EF14-4801-B896-41BDB67A54E6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {484F3E48-EF14-4801-B896-41BDB67A54E6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {484F3E48-EF14-4801-B896-41BDB67A54E6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{F08B36E8-AB80-42CD-BD47-6B05E96DA390} = {0761690C-7DA0-4554-9F6B-211088412DCD}
@@ -437,5 +443,6 @@ Global
{3174F07C-F96E-4695-B05D-CE91845CF292} = {EB783E04-C3C8-45F8-B810-24798DAE2450}
{8EF6E36F-C63A-4F2A-99CF-8F3AE2A5C946} = {EB783E04-C3C8-45F8-B810-24798DAE2450}
{AAC4D6FA-4F94-4616-93B3-3BB47E4A0BB1} = {EB783E04-C3C8-45F8-B810-24798DAE2450}
+ {484F3E48-EF14-4801-B896-41BDB67A54E6} = {EB783E04-C3C8-45F8-B810-24798DAE2450}
EndGlobalSection
EndGlobal
diff --git a/src/OneWare.Cyc5000/Cyc5000Fpga.cs b/src/OneWare.Cyc5000/Cyc5000Fpga.cs
index 58c62119..fb6f76bf 100644
--- a/src/OneWare.Cyc5000/Cyc5000Fpga.cs
+++ b/src/OneWare.Cyc5000/Cyc5000Fpga.cs
@@ -6,6 +6,6 @@ public class Cyc5000Fpga : FpgaBase
{
public Cyc5000Fpga()
{
- LoadFromJson("avares://OneWare.Cyc5000/Assets/Cyc5000.json");
+ LoadFromJsonAsset("avares://OneWare.Cyc5000/Assets/Cyc5000.json");
}
}
\ No newline at end of file
diff --git a/src/OneWare.Essentials/Controls/SearchComboBox.axaml b/src/OneWare.Essentials/Controls/SearchComboBox.axaml
index 4ac1a9e0..88d3a1ee 100644
--- a/src/OneWare.Essentials/Controls/SearchComboBox.axaml
+++ b/src/OneWare.Essentials/Controls/SearchComboBox.axaml
@@ -86,4 +86,14 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/OneWare.Essentials/Controls/SearchComboBox.axaml.cs b/src/OneWare.Essentials/Controls/SearchComboBox.axaml.cs
index 8dfff4f8..a72690a5 100644
--- a/src/OneWare.Essentials/Controls/SearchComboBox.axaml.cs
+++ b/src/OneWare.Essentials/Controls/SearchComboBox.axaml.cs
@@ -10,6 +10,50 @@ public class SearchComboBox : ComboBox
{
private TextBox? _searchBox;
+ public static readonly StyledProperty IsInteractiveProperty =
+ AvaloniaProperty.Register(nameof(IsInteractive), true);
+
+ public bool IsInteractive
+ {
+ get => GetValue(IsInteractiveProperty);
+ set => SetValue(IsInteractiveProperty, value);
+ }
+
+ protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey)
+ {
+ return new SearchComboBoxItem();
+ }
+
+ private int _resultIndex = -1;
+
+ public int ResultIndex
+ {
+ get => _resultIndex;
+ set
+ {
+ _resultIndex = value;
+ ResultItem = ContainerFromIndex(value) as SearchComboBoxItem;
+ ScrollIntoView(value);
+ }
+ }
+
+ private SearchComboBoxItem? _resultItem;
+
+ public SearchComboBoxItem? ResultItem
+ {
+ get => _resultItem;
+ private set
+ {
+ if(_resultItem != null) _resultItem.IsSearchResult = false;
+ _resultItem = value;
+
+ if (_resultItem != null)
+ {
+ _resultItem.IsSearchResult = true;
+ }
+ }
+ }
+
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
@@ -18,39 +62,82 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
_searchBox!.TextChanged += (sender, args) =>
{
- SelectedItem = Items.FirstOrDefault(x =>
- x?.ToString()?.StartsWith(_searchBox.Text ?? string.Empty, StringComparison.OrdinalIgnoreCase) ?? false);
+ var item = Items.FirstOrDefault(x =>
+ x?.ToString()?.StartsWith(_searchBox.Text ?? string.Empty, StringComparison.OrdinalIgnoreCase)
+ ?? x?.ToString()?.Contains(_searchBox.Text ?? string.Empty, StringComparison.OrdinalIgnoreCase)
+ ?? false);
+
+ if (IsInteractive)
+ {
+ SelectedItem = item;
+ }
+ else
+ {
+ if (item != null)
+ {
+ ResultIndex = Items.IndexOf(item);
+ }
+ }
_searchBox.Focus();
};
this.DropDownOpened += (sender, args) =>
{
+ _searchBox.Text = string.Empty;
_searchBox.Focus();
};
}
-
+
protected override void OnKeyDown(KeyEventArgs e)
{
+ if(_searchBox == null) return;
+
if (e.Key == Key.Down)
{
- if (SelectedIndex < Items.Count - 1)
- SelectedIndex++;
+ if (IsInteractive)
+ {
+ if (SelectedIndex < Items.Count - 1)
+ SelectedIndex++;
+ }
+ else
+ {
+ if (ResultIndex < Items.Count - 1)
+ ResultIndex++;
+ }
+
e.Handled = true;
- _searchBox?.Focus();
+ _searchBox.Focus();
return;
}
if (e.Key == Key.Up)
{
- if (SelectedIndex > 0)
- SelectedIndex--;
+ if (IsInteractive)
+ {
+ if (SelectedIndex > 0)
+ SelectedIndex--;
+ }
+ else
+ {
+ if (ResultIndex > 0)
+ ResultIndex--;
+ }
+
e.Handled = true;
- _searchBox?.Focus();
+ _searchBox.Focus();
+ return;
+ }
+ if (e.Key == Key.Enter && !IsInteractive)
+ {
+ SelectedIndex = ResultIndex;
+ _searchBox.Text = string.Empty;
+ }
+ if (e.Key == Key.Space && _searchBox.IsFocused)
+ {
return;
}
-
base.OnKeyDown(e);
}
}
\ No newline at end of file
diff --git a/src/OneWare.Essentials/Controls/SearchComboBoxItem.cs b/src/OneWare.Essentials/Controls/SearchComboBoxItem.cs
new file mode 100644
index 00000000..87df3ed9
--- /dev/null
+++ b/src/OneWare.Essentials/Controls/SearchComboBoxItem.cs
@@ -0,0 +1,20 @@
+using Avalonia.Controls;
+
+namespace OneWare.Essentials.Controls;
+
+public class SearchComboBoxItem : ComboBoxItem
+{
+ protected override Type StyleKeyOverride => typeof(ComboBoxItem);
+
+ private bool _isSearchResult;
+
+ public bool IsSearchResult
+ {
+ get => _isSearchResult;
+ set
+ {
+ _isSearchResult = value;
+ ((IPseudoClasses)Classes).Set(":searchResult", value);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/OneWare.IceBreaker/IceBreakerFpga.cs b/src/OneWare.IceBreaker/IceBreakerFpga.cs
index ff7ab832..ba28768e 100644
--- a/src/OneWare.IceBreaker/IceBreakerFpga.cs
+++ b/src/OneWare.IceBreaker/IceBreakerFpga.cs
@@ -6,6 +6,6 @@ public class IceBreakerFpga : FpgaBase
{
public IceBreakerFpga()
{
- LoadFromJson("avares://OneWare.IceBreaker/Assets/IceBreakerV1.0e.json");
+ LoadFromJsonAsset("avares://OneWare.IceBreaker/Assets/IceBreakerV1.0e.json");
}
}
\ No newline at end of file
diff --git a/src/OneWare.Max10/Max10Fpga.cs b/src/OneWare.Max10/Max10Fpga.cs
index 9b3c58ee..cd4d38c6 100644
--- a/src/OneWare.Max10/Max10Fpga.cs
+++ b/src/OneWare.Max10/Max10Fpga.cs
@@ -6,6 +6,6 @@ public class Max10Fpga : FpgaBase
{
public Max10Fpga()
{
- LoadFromJson("avares://OneWare.Max10/Assets/Max10.json");
+ LoadFromJsonAsset("avares://OneWare.Max10/Assets/Max10.json");
}
}
\ No newline at end of file
diff --git a/src/OneWare.Max1000/Max1000Fpga.cs b/src/OneWare.Max1000/Max1000Fpga.cs
index 04370049..3ceca87d 100644
--- a/src/OneWare.Max1000/Max1000Fpga.cs
+++ b/src/OneWare.Max1000/Max1000Fpga.cs
@@ -6,6 +6,6 @@ public class Max1000Fpga : FpgaBase
{
public Max1000Fpga()
{
- LoadFromJson("avares://OneWare.Max1000/Assets/Max1000.json");
+ LoadFromJsonAsset("avares://OneWare.Max1000/Assets/Max1000.json");
}
}
\ No newline at end of file
diff --git a/src/OneWare.TangNano9K/TangNano9kFpga.cs b/src/OneWare.TangNano9K/TangNano9kFpga.cs
index 0a68785d..58844b47 100644
--- a/src/OneWare.TangNano9K/TangNano9kFpga.cs
+++ b/src/OneWare.TangNano9K/TangNano9kFpga.cs
@@ -6,6 +6,6 @@ public class TangNano9KFpga : FpgaBase
{
public TangNano9KFpga()
{
- LoadFromJson("avares://OneWare.TangNano9K/Assets/TangNano9K.json");
+ LoadFromJsonAsset("avares://OneWare.TangNano9K/Assets/TangNano9K.json");
}
}
\ No newline at end of file
diff --git a/src/OneWare.UniversalFpgaProjectSystem/Fpga/FpgaBase.cs b/src/OneWare.UniversalFpgaProjectSystem/Fpga/FpgaBase.cs
index 211e97de..f66428b8 100644
--- a/src/OneWare.UniversalFpgaProjectSystem/Fpga/FpgaBase.cs
+++ b/src/OneWare.UniversalFpgaProjectSystem/Fpga/FpgaBase.cs
@@ -22,11 +22,23 @@ protected FpgaBase(Dictionary? properties = null)
public IReadOnlyDictionary Properties { get; }
- protected void LoadFromJson(string path)
+ protected void LoadFromJsonAsset(string path)
{
- var stream = AssetLoader.Open(new Uri(path));
+ using var stream = AssetLoader.Open(new Uri(path));
+ using var reader = new StreamReader(stream);
+ LoadFromJson(reader.ReadToEnd());
+ }
+
+ protected void LoadFromJsonFile(string path)
+ {
+ using var stream = File.OpenRead(path);
+ using var reader = new StreamReader(stream);
+ LoadFromJson(reader.ReadToEnd());
+ }
- var properties = JsonNode.Parse(stream);
+ private void LoadFromJson(string json)
+ {
+ var properties = JsonNode.Parse(json);
if (properties == null) return;
diff --git a/src/OneWare.UniversalFpgaProjectSystem/Fpga/FpgaLoader.cs b/src/OneWare.UniversalFpgaProjectSystem/Fpga/FpgaLoader.cs
new file mode 100644
index 00000000..08efb8e3
--- /dev/null
+++ b/src/OneWare.UniversalFpgaProjectSystem/Fpga/FpgaLoader.cs
@@ -0,0 +1,9 @@
+namespace OneWare.UniversalFpgaProjectSystem.Fpga;
+
+public static class FpgaLoader
+{
+ public static IFpga LoadFromPath(string path)
+ {
+ return new GenericFpga(path);
+ }
+}
\ No newline at end of file
diff --git a/src/OneWare.UniversalFpgaProjectSystem/Fpga/GenericFpga.cs b/src/OneWare.UniversalFpgaProjectSystem/Fpga/GenericFpga.cs
new file mode 100644
index 00000000..9cfb91b0
--- /dev/null
+++ b/src/OneWare.UniversalFpgaProjectSystem/Fpga/GenericFpga.cs
@@ -0,0 +1,9 @@
+namespace OneWare.UniversalFpgaProjectSystem.Fpga;
+
+public class GenericFpga : FpgaBase
+{
+ public GenericFpga(string jsonPath)
+ {
+ LoadFromJsonFile(jsonPath);
+ }
+}
\ No newline at end of file
diff --git a/src/OneWare.UniversalFpgaProjectSystem/Models/FpgaModel.cs b/src/OneWare.UniversalFpgaProjectSystem/Models/FpgaModel.cs
index 681c120c..1a76e7d8 100644
--- a/src/OneWare.UniversalFpgaProjectSystem/Models/FpgaModel.cs
+++ b/src/OneWare.UniversalFpgaProjectSystem/Models/FpgaModel.cs
@@ -187,4 +187,9 @@ private void AddInterface(FpgaInterface fpgaInterface)
var model = new FpgaInterfaceModel(fpgaInterface, this);
InterfaceModels.Add(fpgaInterface.Name, model);
}
+
+ public override string ToString()
+ {
+ return Fpga.Name;
+ }
}
\ No newline at end of file
diff --git a/src/OneWare.UniversalFpgaProjectSystem/Services/FpgaService.cs b/src/OneWare.UniversalFpgaProjectSystem/Services/FpgaService.cs
index a22f3daa..30f2f1ee 100644
--- a/src/OneWare.UniversalFpgaProjectSystem/Services/FpgaService.cs
+++ b/src/OneWare.UniversalFpgaProjectSystem/Services/FpgaService.cs
@@ -1,5 +1,6 @@
using System.Collections.ObjectModel;
using OneWare.Essentials.Extensions;
+using OneWare.Essentials.Services;
using OneWare.UniversalFpgaProjectSystem.Fpga;
using OneWare.UniversalFpgaProjectSystem.Models;
using Prism.Ioc;
@@ -8,6 +9,17 @@ namespace OneWare.UniversalFpgaProjectSystem.Services;
public class FpgaService
{
+ private readonly ILogger _logger;
+ public FpgaService(IPaths paths, ILogger logger)
+ {
+ FpgaDirectory = Path.Combine(paths.DocumentsDirectory, "Hardware", "FPGA");
+ Directory.CreateDirectory(FpgaDirectory);
+
+ _logger = logger;
+ }
+
+ public string FpgaDirectory { get; }
+
public Dictionary CustomFpgaViewModels { get; } = new();
public Dictionary FpgaExtensionViewModels { get; } = new();
@@ -89,4 +101,33 @@ public void RegisterPreCompileStep() where T : IFpgaPreCompileStep
if (provider != null) return ContainerLocator.Container.Resolve(provider) as INodeProvider;
return null;
}
+
+ public void LoadGenericFpgas()
+ {
+ foreach (var fpga in Fpgas.ToArray())
+ {
+ if (fpga is GenericFpga)
+ {
+ Fpgas.Remove(fpga);
+ CustomFpgaViewModels.Remove(fpga);
+ }
+ }
+
+ try
+ {
+ foreach (var directory in Directory.GetDirectories(FpgaDirectory))
+ {
+ var fpgaFile = Path.Combine(directory, "fpga.json");
+ if (File.Exists(fpgaFile))
+ {
+ var fpga = FpgaLoader.LoadFromPath(fpgaFile);
+ RegisterFpga(fpga);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ _logger.Error(e.Message, e);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs b/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs
index af2a4ce4..5f5ff6f6 100644
--- a/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs
+++ b/src/OneWare.UniversalFpgaProjectSystem/ViewModels/UniversalFpgaProjectCompileViewModel.cs
@@ -1,9 +1,11 @@
using System.Collections.ObjectModel;
using System.Reactive.Disposables;
using System.Reactive.Linq;
+using Avalonia.Input;
using DynamicData.Binding;
using OneWare.Essentials.Controls;
using OneWare.Essentials.Enums;
+using OneWare.Essentials.Helpers;
using OneWare.Essentials.Models;
using OneWare.Essentials.Services;
using OneWare.Essentials.ViewModels;
@@ -37,6 +39,9 @@ public UniversalFpgaProjectCompileViewModel(IWindowService windowService,
{
Title = $"Connect and Compile - {Project.Header}{(x ? "*" : "")}";
});
+
+ //Load Fpgas from documents
+ fpgaService.LoadGenericFpgas();
//Construct FpgaModels
foreach (var fpga in fpgaService.Fpgas)
@@ -66,6 +71,8 @@ public UniversalFpgaProjectCompileViewModel(IWindowService windowService,
IsDirty = false;
}
+ public static KeyGesture SaveGesture => new(Key.S, PlatformHelper.ControlKey);
+
public ObservableCollection TopRightExtension { get; }
public UniversalFpgaProjectRoot Project { get; }
@@ -126,13 +133,7 @@ private async Task SafeQuitAsync(FlexibleWindow window)
}
}
- public void SaveAndCompile(FlexibleWindow window)
- {
- SaveAndClose(window);
- if (SelectedFpgaModel != null) _ = Project.RunToolchainAsync(SelectedFpgaModel);
- }
-
- public void SaveAndClose(FlexibleWindow window)
+ public void Save()
{
if (SelectedFpgaModel != null)
{
@@ -140,9 +141,20 @@ public void SaveAndClose(FlexibleWindow window)
Project.SetProjectProperty("Fpga", SelectedFpgaModel.Fpga.Name);
Project.Toolchain?.SaveConnections(Project, SelectedFpgaModel);
_ = _projectExplorerService.SaveProjectAsync(Project);
+
+ IsDirty = false;
}
-
- IsDirty = false;
+ }
+
+ public void SaveAndClose(FlexibleWindow window)
+ {
+ Save();
window.Close();
}
+
+ public void SaveAndCompile(FlexibleWindow window)
+ {
+ SaveAndClose(window);
+ if (SelectedFpgaModel != null) _ = Project.RunToolchainAsync(SelectedFpgaModel);
+ }
}
\ No newline at end of file
diff --git a/src/OneWare.UniversalFpgaProjectSystem/Views/UniversalFpgaProjectCompileView.axaml b/src/OneWare.UniversalFpgaProjectSystem/Views/UniversalFpgaProjectCompileView.axaml
index bbc4ebcb..4fd04c13 100644
--- a/src/OneWare.UniversalFpgaProjectSystem/Views/UniversalFpgaProjectCompileView.axaml
+++ b/src/OneWare.UniversalFpgaProjectSystem/Views/UniversalFpgaProjectCompileView.axaml
@@ -19,6 +19,11 @@
+
+
@@ -27,14 +32,14 @@
-
-
+
diff --git a/tests/OneWare.UniversalFpgaProjectSystem.Tests/Assets/Cyc5000/fpga.json b/tests/OneWare.UniversalFpgaProjectSystem.Tests/Assets/Cyc5000/fpga.json
new file mode 100644
index 00000000..4bc65f18
--- /dev/null
+++ b/tests/OneWare.UniversalFpgaProjectSystem.Tests/Assets/Cyc5000/fpga.json
@@ -0,0 +1,964 @@
+{
+ "Name": "CYC5000",
+ "Properties": {
+ "QuartusToolchain_Family": "Cyclone V",
+ "QuartusToolchain_Device": "5CEBA2U15C8",
+ "QuartusProgrammer_ShortTerm_Mode": "JTAG",
+ "QuartusProgrammer_ShortTerm_Operation": "P",
+ "QuartusProgrammer_LongTerm_Mode": "JTAG",
+ "QuartusProgrammer_LongTerm_Format": "JIC",
+ "QuartusProgrammer_LongTerm_CpfArguments": "-s 5CEBA2 --device EPCQ64A -m ASx4",
+ "QuartusProgrammer_LongTerm_Operation": "IPV"
+ },
+ "Pins": [
+ {
+ "Description": "CLK",
+ "Name": "F14"
+ },
+ {
+ "Description": "LED",
+ "Name": "P4"
+ },
+ {
+ "Description": "LED",
+ "Name": "M4"
+ },
+ {
+ "Description": "LED",
+ "Name": "M3"
+ },
+ {
+ "Description": "LED",
+ "Name": "N3"
+ },
+ {
+ "Description": "LED",
+ "Name": "V2"
+ },
+ {
+ "Description": "LED",
+ "Name": "T2"
+ },
+ {
+ "Description": "LED",
+ "Name": "L1"
+ },
+ {
+ "Description": "LED",
+ "Name": "K1"
+ },
+ {
+ "Description": "Button",
+ "Name": "L17"
+ },
+ {
+ "Description": "USB TX",
+ "Name": "E18"
+ },
+ {
+ "Description": "USB RX",
+ "Name": "F16"
+ },
+ {
+ "Description": "USB BD2",
+ "Name": "H17"
+ },
+ {
+ "Description": "USB BD3",
+ "Name": "H16"
+ },
+ {
+ "Description": "USB BD4",
+ "Name": "J16"
+ },
+ {
+ "Description": "USB BD5",
+ "Name": "G15"
+ },
+ {
+ "Description": "USB BD6",
+ "Name": "J14"
+ },
+ {
+ "Description": "USB BD7",
+ "Name": "L15"
+ },
+ {
+ "Description": "USB BC0",
+ "Name": "G13"
+ },
+ {
+ "Description": "USB BC1",
+ "Name": "H13"
+ },
+ {
+ "Description": "USB BC2",
+ "Name": "J15"
+ },
+ {
+ "Description": "USB BC3",
+ "Name": "J13"
+ },
+ {
+ "Description": "USB BC4",
+ "Name": "K16"
+ },
+ {
+ "Description": "USB BC5",
+ "Name": "K18"
+ },
+ {
+ "Description": "USB BC6",
+ "Name": "K17"
+ },
+ {
+ "Description": "USB BC7",
+ "Name": "L16"
+ },
+ {
+ "Description": "CRUVI HS SMB_ALERT",
+ "Name": "G17"
+ },
+ {
+ "Description": "CRUVI HS SMB_SDA",
+ "Name": "H18"
+ },
+ {
+ "Description": "CRUVI HS SMB_SCL",
+ "Name": "F17"
+ },
+ {
+ "Description": "CRUVI HS REFCLK",
+ "Name": "G14"
+ },
+ {
+ "Description": "CRUVI HS HSMIO",
+ "Name": "C16"
+ },
+ {
+ "Description": "CRUVI HS HSO",
+ "Name": "B14"
+ },
+ {
+ "Description": "CRUVI HS HSRST",
+ "Name": "B15"
+ },
+ {
+ "Description": "CRUVI HS HSI",
+ "Name": "D16"
+ },
+ {
+ "Description": "CRUVI HS Low Speed I/Os",
+ "Name": "F4"
+ },
+ {
+ "Description": "CRUVI HS Low Speed I/Os",
+ "Name": "J3"
+ },
+ {
+ "Description": "CRUVI HS Low Speed I/Os",
+ "Name": "E3"
+ },
+ {
+ "Description": "CRUVI HS Low Speed I/Os",
+ "Name": "J4"
+ },
+ {
+ "Description": "CRUVI HS Low Speed I/Os",
+ "Name": "E2"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "B17"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "B18"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A7"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A6"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "C13"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "C12"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "E8"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "F7"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "G6"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "F6"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "B4"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "B5"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A12"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "B12"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A11"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A10"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A14"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A15"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A16"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "A17"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "F9"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "F10"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "B7"
+ },
+ {
+ "Description": "CRUVI HS Differential I/Os",
+ "Name": "B8"
+ },
+ {
+ "Description": "VSEL",
+ "Name": "N10"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "V17"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "U17"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "T17"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "U18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "R17"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "R18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "P18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "N17"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "N18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "M18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "J18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "G18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "D18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "C18"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "T1"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "R2"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "R1"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "N2"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "L2"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "J1"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "F1"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "E1"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "D1"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "M2"
+ },
+ {
+ "Description": "Low Speed I/Os",
+ "Name": "P1"
+ },
+ {
+ "Description": "SPI Flash",
+ "Name": "P3"
+ },
+ {
+ "Description": "SPI Flash",
+ "Name": "K6"
+ },
+ {
+ "Description": "SPI Flash",
+ "Name": "V1"
+ },
+ {
+ "Description": "SPI Flash",
+ "Name": "U2"
+ },
+ {
+ "Description": "SPI Flash",
+ "Name": "U3"
+ },
+ {
+ "Description": "SPI Flash",
+ "Name": "M5"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "R13"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "U12"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "V12"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "V13"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "V15"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "V16"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "T16"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "U15"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "P14"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "T15"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "M13"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "P15"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "N16"
+ },
+ {
+ "Description": "SDRAM Address",
+ "Name": "R16,"
+ },
+ {
+ "Description": "SDRAM Bank Select",
+ "Name": "T12"
+ },
+ {
+ "Description": "SDRAM Bank Select",
+ "Name": "N13"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "U4"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "T4"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "V6"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "U5"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "V7"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "T5"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "V8"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "U8"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "P10"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "P9"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "T11"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "R9"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "R11"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "T9"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "V10"
+ },
+ {
+ "Description": "SDRAM Data",
+ "Name": "U9"
+ },
+ {
+ "Description": "SDRAM I/O Mask",
+ "Name": "U13"
+ },
+ {
+ "Description": "SDRAM I/O Mask",
+ "Name": "U14"
+ },
+ {
+ "Description": "SDRAM Row Address Strobe",
+ "Name": "P13"
+ },
+ {
+ "Description": "SDRAM Column Address Strobe",
+ "Name": "M14"
+ },
+ {
+ "Description": "SDRAM Write Enable",
+ "Name": "N12"
+ },
+ {
+ "Description": "SDRAM Clock",
+ "Name": "P16"
+ },
+ {
+ "Description": "SDRAM Clock Enable",
+ "Name": "T14"
+ },
+ {
+ "Description": "SDRAM Chip Select",
+ "Name": "L13"
+ }
+ ],
+ "Interfaces": [
+ {
+ "Name": "CRUVIHS_1",
+ "Connector": "CruviHS",
+ "Pins": [
+ {
+ "Name": "HS_Dif_1",
+ "Pin": "B17"
+ },
+ {
+ "Name": "HS_Dif_2",
+ "Pin": "B18"
+ },
+ {
+ "Name": "HS_Dif_3",
+ "Pin": "A7"
+ },
+ {
+ "Name": "HS_Dif_4",
+ "Pin": "A6"
+ },
+ {
+ "Name": "HS_Dif_5",
+ "Pin": "C13"
+ },
+ {
+ "Name": "HS_Dif_6",
+ "Pin": "C12"
+ },
+ {
+ "Name": "HS_Dif_7",
+ "Pin": "E8"
+ },
+ {
+ "Name": "HS_Dif_8",
+ "Pin": "F7"
+ },
+ {
+ "Name": "HS_Dif_9",
+ "Pin": "G6"
+ },
+ {
+ "Name": "HS_Dif_10",
+ "Pin": "F6"
+ },
+ {
+ "Name": "HS_Dif_11",
+ "Pin": "B4"
+ },
+ {
+ "Name": "HS_Dif_12",
+ "Pin": "B5"
+ },
+ {
+ "Name": "HS_Dif_13",
+ "Pin": "A12"
+ },
+ {
+ "Name": "HS_Dif_14",
+ "Pin": "B12"
+ },
+ {
+ "Name": "HS_Dif_15",
+ "Pin": "A11"
+ },
+ {
+ "Name": "HS_Dif_16",
+ "Pin": "A10"
+ },
+ {
+ "Name": "HS_Dif_17",
+ "Pin": "A14"
+ },
+ {
+ "Name": "HS_Dif_18",
+ "Pin": "A15"
+ },
+ {
+ "Name": "HS_Dif_19",
+ "Pin": "A16"
+ },
+ {
+ "Name": "HS_Dif_20",
+ "Pin": "A17"
+ },
+ {
+ "Name": "HS_Dif_21",
+ "Pin": "F9"
+ },
+ {
+ "Name": "HS_Dif_22",
+ "Pin": "F10"
+ },
+ {
+ "Name": "HS_Dif_23",
+ "Pin": "B7"
+ },
+ {
+ "Name": "HS_Dif_24",
+ "Pin": "B8"
+ },
+ {
+ "Name": "HS_Ale",
+ "Pin": "G17"
+ },
+ {
+ "Name": "HS_SDA",
+ "Pin": "H18"
+ },
+ {
+ "Name": "HS_SCL",
+ "Pin": "F17"
+ },
+ {
+ "Name": "HS_Ref",
+ "Pin": "G14"
+ },
+ {
+ "Name": "HS_HSM",
+ "Pin": "C16"
+ },
+ {
+ "Name": "HS_HSO",
+ "Pin": "B14"
+ },
+ {
+ "Name": "HS_HSR",
+ "Pin": "B15"
+ },
+ {
+ "Name": "HS_HSI",
+ "Pin": "D16"
+ },
+ {
+ "Name": "HS_LOW_,1",
+ "Pin": "F4"
+ },
+ {
+ "Name": "HS_LOW_2",
+ "Pin": "J3"
+ },
+ {
+ "Name": "HS_LOW_3",
+ "Pin": "E3"
+ },
+ {
+ "Name": "HS_LOW_4",
+ "Pin": "J4"
+ },
+ {
+ "Name": "HS_LOW_5",
+ "Pin": "E2"
+ }
+ ]
+ },
+ {
+ "Name": "UART",
+ "Pins": [
+ {
+ "Name": "TXD",
+ "Pin": "E18"
+ },
+ {
+ "Name": "RXD",
+ "Pin": "F16"
+ }
+ ]
+ },
+ {
+ "Name": "SDRAM",
+ "Pins": [
+ {
+ "Name": "ADD_1",
+ "Pin": "R13"
+ },
+ {
+ "Name": "ADD_2",
+ "Pin": "U12"
+ },
+ {
+ "Name": "ADD_3",
+ "Pin": "V12"
+ },
+ {
+ "Name": "ADD_4",
+ "Pin": "V13"
+ },
+ {
+ "Name": "ADD_5",
+ "Pin": "V15"
+ },
+ {
+ "Name": "ADD_6",
+ "Pin": "V16"
+ },
+ {
+ "Name": "ADD_7",
+ "Pin": "T16"
+ },
+ {
+ "Name": "ADD_8",
+ "Pin": "U15"
+ },
+ {
+ "Name": "ADD_9",
+ "Pin": "P14"
+ },
+ {
+ "Name": "ADD_10",
+ "Pin": "T15"
+ },
+ {
+ "Name": "ADD_11",
+ "Pin": "M13"
+ },
+ {
+ "Name": "ADD_12",
+ "Pin": "P15"
+ },
+ {
+ "Name": "ADD_13",
+ "Pin": "N16"
+ },
+ {
+ "Name": "ADD_14",
+ "Pin": "R16"
+ },
+ {
+ "Name": "BAN_1",
+ "Pin": "T12"
+ },
+ {
+ "Name": "BAN_2",
+ "Pin": "N13"
+ },
+ {
+ "Name": "DAT_1",
+ "Pin": "U4"
+ },
+ {
+ "Name": "DAT_2",
+ "Pin": "T4"
+ },
+ {
+ "Name": "DAT_3",
+ "Pin": "V6"
+ },
+ {
+ "Name": "DAT_4",
+ "Pin": "U5"
+ },
+ {
+ "Name": "DAT_5",
+ "Pin": "V7"
+ },
+ {
+ "Name": "DAT_6",
+ "Pin": "T5"
+ },
+ {
+ "Name": "DAT_7",
+ "Pin": "V8"
+ },
+ {
+ "Name": "DAT_8",
+ "Pin": "U8"
+ },
+ {
+ "Name": "DAT_9",
+ "Pin": "P10"
+ },
+ {
+ "Name": "DAT_10",
+ "Pin": "P9"
+ },
+ {
+ "Name": "DAT_11",
+ "Pin": "T11"
+ },
+ {
+ "Name": "DAT_12",
+ "Pin": "R9"
+ },
+ {
+ "Name": "DAT_13",
+ "Pin": "R11"
+ },
+ {
+ "Name": "DAT_14",
+ "Pin": "T9"
+ },
+ {
+ "Name": "DAT_15",
+ "Pin": "V10"
+ },
+ {
+ "Name": "DAT_16",
+ "Pin": "U9"
+ },
+ {
+ "Name": "DQM_1",
+ "Pin": "U13"
+ },
+ {
+ "Name": "DQM_2",
+ "Pin": "U14"
+ },
+ {
+ "Name": "RAS",
+ "Pin": "P13"
+ },
+ {
+ "Name": "CAS",
+ "Pin": "M14"
+ },
+ {
+ "Name": "WEN",
+ "Pin": "N12"
+ },
+ {
+ "Name": "ClK",
+ "Pin": "P16"
+ },
+ {
+ "Name": "CKE",
+ "Pin": "T14"
+ },
+ {
+ "Name": "CSE",
+ "Pin": "L13"
+ }
+ ]
+ },
+ {
+ "Name": "FLASH",
+ "Pins": [
+ {
+ "Name": "1",
+ "Pin": "K6"
+ },
+ {
+ "Name": "2",
+ "Pin": "U2"
+ },
+ {
+ "Name": "3",
+ "Pin": "V1"
+ },
+ {
+ "Name": "4",
+ "Pin": "P3"
+ },
+ {
+ "Name": "5",
+ "Pin": "U3"
+ },
+ {
+ "Name": "6",
+ "Pin": "M5"
+ }
+ ]
+ },
+ {
+ "Name": "LED",
+ "Pins": [
+ {
+ "Name": "1",
+ "Pin": "P4"
+ },
+ {
+ "Name": "2",
+ "Pin": "M4"
+ },
+ {
+ "Name": "3",
+ "Pin": "M3"
+ },
+ {
+ "Name": "4",
+ "Pin": "N3"
+ },
+ {
+ "Name": "5",
+ "Pin": "V2"
+ },
+ {
+ "Name": "6",
+ "Pin": "T2"
+ },
+ {
+ "Name": "7",
+ "Pin": "L1"
+ },
+ {
+ "Name": "8",
+ "Pin": "K1"
+ }
+ ]
+ },
+ {
+ "Name": "CLK",
+ "Pins": [
+ {
+ "Name": "1",
+ "Pin": "F14"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/OneWare.UniversalFpgaProjectSystem.Tests/LoadFpgaTests.cs b/tests/OneWare.UniversalFpgaProjectSystem.Tests/LoadFpgaTests.cs
new file mode 100644
index 00000000..b7b77efa
--- /dev/null
+++ b/tests/OneWare.UniversalFpgaProjectSystem.Tests/LoadFpgaTests.cs
@@ -0,0 +1,17 @@
+using System;
+using System.IO;
+using OneWare.UniversalFpgaProjectSystem.Fpga;
+using Xunit;
+
+namespace OneWare.UniversalFpgaProjectSystem.Tests;
+
+public class LoadFpgaTests
+{
+ [Fact]
+ public void LoadFpgaTest()
+ {
+ var fpga = FpgaLoader.LoadFromPath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Assets/Cyc5000/fpga.json"));
+
+ Assert.Equal("CYC5000", fpga.Name);
+ }
+}
\ No newline at end of file
diff --git a/tests/OneWare.UniversalFpgaProjectSystem.Tests/OneWare.UniversalFpgaProjectSystem.Tests.csproj b/tests/OneWare.UniversalFpgaProjectSystem.Tests/OneWare.UniversalFpgaProjectSystem.Tests.csproj
new file mode 100644
index 00000000..07a81e57
--- /dev/null
+++ b/tests/OneWare.UniversalFpgaProjectSystem.Tests/OneWare.UniversalFpgaProjectSystem.Tests.csproj
@@ -0,0 +1,26 @@
+
+
+
+
+
+ net8.0
+ Library
+ False
+ True
+ False
+ True
+ enable
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+