Skip to content

Commit

Permalink
Add ability to execute report_route_status on remote server (#16)
Browse files Browse the repository at this point in the history
* Add ability to execute report_route_status on remote server

Signed-off-by: Eddie Hung <[email protected]>

* No compression for zip

Signed-off-by: Eddie Hung <[email protected]>

* Add comment

Signed-off-by: Eddie Hung <[email protected]>

* Check for empty string

Signed-off-by: Eddie Hung <[email protected]>

---------

Signed-off-by: Eddie Hung <[email protected]>
  • Loading branch information
eddieh-xlnx authored Oct 16, 2023
1 parent 9000bdb commit a72a150
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 17 deletions.
24 changes: 21 additions & 3 deletions .github/workflows/make.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,31 @@ jobs:
with:
python-version: '3.11'
cache: 'pip'
- if: matrix.router == 'nxroute-poc'
- name: Download xcvu3p.device (nxroute-poc only)
if: matrix.router == 'nxroute-poc'
run:
wget -q https://github.com/eddieh-xlnx/fpga24_routing_contest/releases/download/xvu3p/xcvu3p.device
- run:
- env:
REPORT_ROUTE_STATUS_URL: ${{ secrets.REPORT_ROUTE_STATUS_URL }}
REPORT_ROUTE_STATUS_AUTH: ${{ secrets.REPORT_ROUTE_STATUS_AUTH }}
CHECK_PHYS_NETLIST_MOCK_PASS: ${{ matrix.router != 'nxroute-poc' && secrets.REPORT_ROUTE_STATUS_URL == '' }}
run: |
make ROUTER="${{ matrix.router }}" BENCHMARKS="${{ matrix.benchmark }}" VERBOSE=1
- run:
- name: Score summary
run:
make ROUTER="${{ matrix.router }}" BENCHMARKS="${{ matrix.benchmark }}" VERBOSE=1
- name: Verify pass (non nxroute-poc)
if: matrix.router != 'nxroute-poc'
run: |
grep -H PASS *.check
# Allow following grep to fail if no URL
grep -H -e "# of nets with routing errors[. :]\+0" *.check.log || ${{ secrets.REPORT_ROUTE_STATUS_URL == '' }}
- name: Verify fail (nxroute-poc)
if: matrix.router == 'nxroute-poc'
run: |
grep -H FAIL *.check
# Allow following grep to fail if no URL
grep -H -e "# of nets with routing errors[. :]\+[1-9]" -e "# of unrouted nets[. :]\+[1-9]" *.check.log || ${{ secrets.REPORT_ROUTE_STATUS_URL == '' }}
- uses: actions/upload-artifact@v3
if: always()
with:
Expand Down
9 changes: 5 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ export TIME=Wall-clock time (sec): %e

# Existence of the VERBOSE environment variable indicates whether router/
# checker outputs will be displayed on screen
ifdef VERBOSE
VERBOSE ?= 0
ifneq ($(VERBOSE), 0)
log_and_or_display = 2>&1 | tee $(1)
SHELL := /bin/bash -o pipefail
else
log_and_or_display = > $(1) 2>&1
endif
Expand Down Expand Up @@ -70,12 +72,11 @@ fpga-interchange-schema/interchange/capnp/java.capnp:
# Gradle is used to invoke the CheckPhysNetlist class' main method with arguments
# $^ (%.netlist and %_rwroute.phys), and display/redirect all output to [email protected] (%_rwroute.check.log).
# The exit code of Gradle determines if 'PASS' or 'FAIL' is written to $@ (%_rwroute.check)
# When inside GitHub Actions (which has no access to Vivado), and also when the routed netlist
# was successfully converted back into a DCP, then return a mock PASS result
%_$(ROUTER).check: %.netlist %_$(ROUTER).phys | compile-java
if ./gradlew -DjvmArgs="-Xms6g -Xmx6g" -Dmain=com.xilinx.fpga24_routing_contest.CheckPhysNetlist :run --args='$^' $(call log_and_or_display,$@.log); then \
echo "PASS" > $@; \
elif [[ ! -z "$(GITHUB_ACTION)" && -f "$(patsubst %.check,%.dcp,$@)" ]]; then \
elif [[ "$(CHECK_PHYS_NETLIST_MOCK_PASS)" == "true" && -f "$(patsubst %.check,%.dcp,$@)" ]]; then \
echo "::warning file=$@::CheckPhysNetlist returned FAIL but CHECK_PHYS_NETLIST_MOCK_PASS is set"; \
echo "PASS" > $@; \
else \
echo "FAIL" > $@; \
Expand Down
91 changes: 81 additions & 10 deletions src/com/xilinx/fpga24_routing_contest/CheckPhysNetlist.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,38 @@

import com.xilinx.rapidwright.design.Design;
import com.xilinx.rapidwright.edif.EDIFNetlist;
import com.xilinx.rapidwright.edif.EDIFTools;
import com.xilinx.rapidwright.interchange.LogNetlistReader;
import com.xilinx.rapidwright.interchange.PhysNetlistReader;
import com.xilinx.rapidwright.util.FileTools;
import com.xilinx.rapidwright.util.ReportRouteStatusResult;
import com.xilinx.rapidwright.util.VivadoTools;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.InterruptedException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpRequest.BodyPublishers;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.zip.Deflater;
import java.util.zip.ZipOutputStream;
import java.util.zip.ZipEntry;

public class CheckPhysNetlist {
public static void main(String[] args) throws IOException {
public static void main(String[] args) throws IOException, InterruptedException {
if (args.length != 2) {
System.err.println("USAGE: <input.netlist> <input.phys>");
return;
Expand Down Expand Up @@ -63,18 +79,73 @@ public static void main(String[] args) throws IOException {
Path outputDcp = Paths.get(FileTools.removeFileExtension(args[1]) + ".dcp");
design.writeCheckpoint(outputDcp);

if (!FileTools.isVivadoOnPath()) {
System.err.println("ERROR: `vivado` not detected on $PATH");
System.exit(1);
}

// Call Vivado's `report_route_status` command on this DCP
List<String> encryptedCells = netlist.getEncryptedCells();
boolean encrypted = encryptedCells != null && !encryptedCells.isEmpty();
ReportRouteStatusResult rrs = VivadoTools.reportRouteStatus(outputDcp, encrypted);
ReportRouteStatusResult rrs = null;
String reportRouteStatusUrl = System.getenv("REPORT_ROUTE_STATUS_URL");
if (reportRouteStatusUrl == null || reportRouteStatusUrl.isEmpty()) {
// Call local Vivado
if (!FileTools.isVivadoOnPath()) {
System.err.println("ERROR: `vivado` not detected on $PATH");
System.exit(1);
}

List<String> encryptedCells = netlist.getEncryptedCells();
boolean encrypted = encryptedCells != null && !encryptedCells.isEmpty();
rrs = VivadoTools.reportRouteStatus(outputDcp, encrypted);
} else {
// Upload DCP/ZIP-with-encrpyted-cells to a remote URL
Path uploadFile = outputDcp;
if (!netlist.getEncryptedCells().isEmpty()) {
// For designs with encrypted cells, create and upload a zip file
// containing those encrpyted cells and the *_load.tcl script along
// with the DCP
uploadFile = Paths.get(outputDcp.toString() + ".zip");
reportRouteStatusUrl += "-zip";
try (FileOutputStream fos = new FileOutputStream(uploadFile.toString());
ZipOutputStream zos = new ZipOutputStream(fos)) {
zos.setLevel(Deflater.NO_COMPRESSION);
zos.putNextEntry(new ZipEntry(outputDcp.toString()));
Files.copy(outputDcp, zos);
for (String fileName : netlist.getEncryptedCells()) {
zos.putNextEntry(new ZipEntry(fileName));
Files.copy(Paths.get(fileName), zos);
}
Path loadTclPath = FileTools.replaceExtension(outputDcp, EDIFTools.LOAD_TCL_SUFFIX);
zos.putNextEntry(new ZipEntry(loadTclPath.toString()));
Files.copy(loadTclPath, zos);
}
}

System.out.println("Uploading " + uploadFile + " ...");
HttpClient client = HttpClient.newHttpClient();

String reportRouteStatusAuth = System.getenv("REPORT_ROUTE_STATUS_AUTH");
String auth = "Basic " + Base64.getEncoder().encodeToString(reportRouteStatusAuth.getBytes());

HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(reportRouteStatusUrl))
.PUT(BodyPublishers.ofFile(uploadFile))
.setHeader("Authorization", auth)
.build();

HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
System.out.println("Status code: " + response.statusCode());
List<String> lines = new ArrayList<>();
System.out.println("Response:");
try (InputStream is = response.body();
BufferedReader br = new BufferedReader(new InputStreamReader(is))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
lines.add(line);
}
System.out.println("<EOF>");
}
rrs = new ReportRouteStatusResult(lines);
}

// Exit code 0 only if Vivado reported that it was fully routed
System.exit(rrs.isFullyRouted() ? 0 : 1);
System.exit(rrs.logicalNets > 0 && rrs.isFullyRouted() ? 0 : 1);
}
}

0 comments on commit a72a150

Please sign in to comment.