Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ Compile shows, grouped into Synthesis, Place & Route and Bitstream.
| --- | --- |
| `yosysToolchainNextPnrTool` | The `nextpnr-*` binary, e.g. `nextpnr-ice40`, `nextpnr-ecp5`, `nextpnr-himbaechel`. Must match the synth tool's family. |
| `yosysToolchainNextPnrFlags` | Extra flags, typically the device and package selection. |
| `yosysToolchainConstraintFileType` | `pcf` or `ccf` — the constraint format the board uses. |
| `yosysToolchainOutputType` | `asc` or `txt` — the place & route output format the pack tool expects. |
| `yosysToolchainConstraintFileType` | `pcf`, `ccf` or `cst` — the constraint format the board uses. `ccf` and `cst` are converted from the project's PCF file. |
| `yosysToolchainOutputType` | `asc`, `txt` or `json` — the place & route output format the pack tool expects. |
| `yosysToolchainNextPnrVerbose` | `true` adds `--verbose` and shows the full nextpnr output in the Output panel. Turn this on when diagnosing timing or placement problems. |

### Bitstream (pack)
Expand All @@ -54,7 +54,7 @@ Compile shows, grouped into Synthesis, Place & Route and Bitstream.
| --- | --- |
| `yosysToolchainPackTool` | `icepack`, `ecppack`, `gowin_pack` or `gmpack`, matching the family. |
| `yosysToolchainPackFlags` | Extra flags for the pack tool. |
| `packToolOutputFormat` | `bin` or `bit`. |
| `packToolOutputFormat` | `bin`, `bit` or `fs`. |

The three tool selections must agree on the FPGA family: `synth_ice40` + `nextpnr-ice40` +
`icepack` is consistent, mixing families is not. The hardware package of a board ships correct
Expand Down
30 changes: 26 additions & 4 deletions src/OneWare.OssCadSuiteIntegration/Tools/ConstraintFileHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,24 @@ namespace OneWare.OssCadSuiteIntegration.Tools;

public class ConstraintFileHelper
{
[Obsolete(message: "Use ConvertPcfToCcf instead")]
public static void Convert(string pcfPath, string ccfPath)
{
ConvertPcfToCcf(pcfPath, ccfPath);
}

public static void ConvertPcfToCcf(string pcfPath, string ccfPath)
{
ConvertPcf(pcfPath, ccfPath, "#", (signal, pin) => $"NET \"{signal}\" Loc = \"{pin}\";");
}

public static void ConvertPcfToCst(string pcfPath, string cstPath)
{
ConvertPcf(pcfPath, cstPath, "//", (signal, pin) => $"IO_LOC \"{signal}\" {pin};");
}

private static void ConvertPcf(string pcfPath, string targetPath, string commentPrefix,
Func<string, string, string> formatConstraint)
{
if (!File.Exists(pcfPath))
throw new FileNotFoundException("PCF file not found", pcfPath);
Expand All @@ -23,7 +40,7 @@ public static void Convert(string pcfPath, string ccfPath)

if (line.StartsWith("#"))
{
result.Add(line);
result.Add(ReplaceCommentPrefix(line, commentPrefix));
continue;
}

Expand All @@ -45,15 +62,20 @@ public static void Convert(string pcfPath, string ccfPath)
var signal = parts[1];
var pin = parts[2];

var newLine = $"NET \"{signal}\" Loc = \"{pin}\";";
var newLine = formatConstraint(signal, pin);

if (!string.IsNullOrEmpty(comment))
newLine += $" {comment}";
newLine += $" {ReplaceCommentPrefix(comment, commentPrefix)}";

result.Add(newLine);
}

File.WriteAllLines(ccfPath, result);
File.WriteAllLines(targetPath, result);
}

private static string ReplaceCommentPrefix(string pcfComment, string commentPrefix)
{
return commentPrefix + pcfComment[1..];
}

public static void ConvertCcfToPcf(string ccfPath, string pcfPath)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ public YosysCompileSettingsViewModel(UniversalFpgaProjectRoot fpgaProjectRoot, I
defaultProperties.GetValueOrDefault("yosysToolchainConstraintFileType") ?? "", [
"pcf",
"ccf",
"cst"
])
{
HoverDescription = "Set NextPnr tool"
Expand All @@ -119,7 +120,8 @@ public YosysCompileSettingsViewModel(UniversalFpgaProjectRoot fpgaProjectRoot, I
_nextPnrToolOutputTypeSetting = new ComboBoxSetting("NextPnr Output file type",
defaultProperties.GetValueOrDefault("yosysToolchainOutputType") ?? "", [
"asc",
"txt"
"txt",
"json"
])
{
HoverDescription = "Set NextPnr tool"
Expand Down Expand Up @@ -151,7 +153,8 @@ public YosysCompileSettingsViewModel(UniversalFpgaProjectRoot fpgaProjectRoot, I
_packOutputTypeSetting = new ComboBoxSetting("Pack output format",
defaultProperties.GetValueOrDefault("packToolOutputFormat") ?? "", [
"bin",
"bit"
"bit",
"fs"
])
{
HoverDescription = "Set Pack tool output format"
Expand Down
50 changes: 38 additions & 12 deletions src/OneWare.OssCadSuiteIntegration/Yosys/YosysService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -251,23 +251,21 @@ private async Task<bool> RunNextpnrAsync(UniversalFpgaProjectRoot project, FpgaM
builder.Add("--pcf").AddPath(pcfFile);
break;
case "ccf":
var absolutePcfPath = Path.Combine(project.RootFolderPath, pcfFile);
outputService.WriteLine($"Converting {absolutePcfPath} to CCF File");

if (File.Exists(absolutePcfPath))
{
ConstraintFileHelper.Convert(absolutePcfPath,
Path.Combine(project.RootFolderPath, "./build/constrains.ccf"));
}
else
{
outputService.WriteLine($"Could not generate CCF file from {pcfFile}");
if (!ConvertConstraintFile(project, pcfFile, "./build/constrains.ccf", "CCF",
ConstraintFileHelper.ConvertPcfToCcf))
return false;
}

builder.Add("-o");
builder.AddScript("ccf={path}", ("{path}", "./build/constrains.ccf"));
break;
case "cst":
if (!ConvertConstraintFile(project, pcfFile, "./build/constraints.cst", "CST",
ConstraintFileHelper.ConvertPcfToCst))
return false;

builder.Add("-o");
builder.AddScript("cst={path}", ("{path}", "./build/constraints.cst", true));
break;
default:
outputService.WriteLine($"Could not find Constraint file type: {cFileType}");
return false;
Expand All @@ -286,6 +284,10 @@ private async Task<bool> RunNextpnrAsync(UniversalFpgaProjectRoot project, FpgaM
builder.Add("-o");
builder.AddScript("out={path}", ("{path}", pnrOutput));
break;
case "json":
pnrOutput = "./build/pnr.json";
builder.Add("--write").AddPath(pnrOutput);
break;
default:
outputService.WriteLine($"Could not find output type: {cOutputType}");
return false;
Expand Down Expand Up @@ -354,6 +356,7 @@ public async Task<bool> AssembleAsync(UniversalFpgaProjectRoot project, FpgaMode
{
"asc" => "./build/nextpnr.asc",
"txt" => "./build/impl.txt",
"json" => "./build/pnr.json",
_ => throw new ArgumentException($"Unsupported input type: {cOutputType}")
};

Expand All @@ -371,12 +374,15 @@ public async Task<bool> AssembleAsync(UniversalFpgaProjectRoot project, FpgaMode
{
"bin" => "./build/pack.bin",
"bit" => "./build/pack.bit",
"fs" => "./build/pack.fs",
_ => throw new ArgumentException($"Unsupported output format: {pOutputFormat}")
};

// Remove a previous result so a failing run can never be followed by a stale bitstream
DeleteArtifact(project, outputPath);

// gowin_pack takes the output as an option, the other pack tools as the second argument
if (packTool == "gowin_pack") builder.Add("-o");
builder.AddPath(outputPath);

var flags = properties.GetValueOrDefault("yosysToolchainPackFlags")?.Split(' ',
Expand Down Expand Up @@ -440,6 +446,26 @@ public async Task<IEnumerable<FpgaNode>> ExtractNodesAsync(IProjectFile file)
return ReadJson(Path.Combine(buildpath, "yosys_nodes.json"));
}

/// <summary>
/// Converts the project's PCF file, which the constraint editor writes, into the format the nextpnr
/// architecture reads.
/// </summary>
private bool ConvertConstraintFile(UniversalFpgaProjectRoot project, string pcfFile, string targetFile,
string targetFormat, Action<string, string> convert)
{
var absolutePcfPath = Path.Combine(project.RootFolderPath, pcfFile);
outputService.WriteLine($"Converting {absolutePcfPath} to {targetFormat} File");

if (!File.Exists(absolutePcfPath))
{
outputService.WriteLine($"Could not generate {targetFormat} file from {pcfFile}");
return false;
}

convert(absolutePcfPath, Path.Combine(project.RootFolderPath, targetFile));
return true;
}

private static bool IsErrorLine(string line)
{
return line.TrimStart().StartsWith("Error:", StringComparison.OrdinalIgnoreCase);
Expand Down
Loading