From 1cd2901d854b969a8cb1afc66e3f3388766776a0 Mon Sep 17 00:00:00 2001 From: Tomasz Michalak Date: Wed, 9 Jun 2021 23:01:27 +0200 Subject: fpga_interchange: Add initial site router test framework Signed-off-by: Tomasz Michalak --- fpga_interchange/site_router_tests/CMakeLists.txt | 2 + .../site_router_tests/common/run_script.py | 29 +++++ .../site_router_tests/common/synth.tcl | 14 +++ .../site_router_tests/lut/CMakeLists.txt | 6 + fpga_interchange/site_router_tests/lut/lut.v | 24 ++++ fpga_interchange/site_router_tests/lut/lut.xdc | 32 +++++ fpga_interchange/site_router_tests/lut/test.yaml | 28 +++++ .../site_router_tests/site_router_test.cmake | 133 +++++++++++++++++++++ 8 files changed, 268 insertions(+) create mode 100644 fpga_interchange/site_router_tests/CMakeLists.txt create mode 100644 fpga_interchange/site_router_tests/common/run_script.py create mode 100644 fpga_interchange/site_router_tests/common/synth.tcl create mode 100644 fpga_interchange/site_router_tests/lut/CMakeLists.txt create mode 100644 fpga_interchange/site_router_tests/lut/lut.v create mode 100644 fpga_interchange/site_router_tests/lut/lut.xdc create mode 100644 fpga_interchange/site_router_tests/lut/test.yaml create mode 100644 fpga_interchange/site_router_tests/site_router_test.cmake diff --git a/fpga_interchange/site_router_tests/CMakeLists.txt b/fpga_interchange/site_router_tests/CMakeLists.txt new file mode 100644 index 0000000..e67b5ff --- /dev/null +++ b/fpga_interchange/site_router_tests/CMakeLists.txt @@ -0,0 +1,2 @@ +include(site_router_test.cmake) +add_subdirectory(lut) diff --git a/fpga_interchange/site_router_tests/common/run_script.py b/fpga_interchange/site_router_tests/common/run_script.py new file mode 100644 index 0000000..07faf89 --- /dev/null +++ b/fpga_interchange/site_router_tests/common/run_script.py @@ -0,0 +1,29 @@ +import sys +import yaml +import os + +def test_case(ctx): + with open(os.environ['TEST_YAML'], 'r') as f: + test_data = yaml.safe_load(f.read()) + if 'test_case' in test_data: + ctx.pack() + for test_step in test_data['test_case']: + print(test_step) + if "place" in test_step: + for cell, bel in test_step["place"].items(): + print("Binding Bel {} to Cell {}".format(bel, cell)) + assert cell in ctx.cells, "Cell {} does not exist".format(cell) + ctx.bindBel(bel, ctx.cells[cell], STRENGTH_WEAK) + if "test" in test_step: + print(test_step["test"]) + for bel, check in test_step["test"].items(): + print("Checking if location of bel {} is {}".format(bel, check)) + print("Test result: {}, isBelLocationValid: {}, expected: {}".format(ctx.isBelLocationValid(bel) == check, ctx.isBelLocationValid(bel), check)) + if "unplace" in test_step: + print(test_step["unplace"]) + cell = test_step["unplace"] + print("Unbinding Bel {}".format(cell)) + ctx.explain_bel_status(cell) + ctx.unbindBel(cell) + +test_case(ctx) diff --git a/fpga_interchange/site_router_tests/common/synth.tcl b/fpga_interchange/site_router_tests/common/synth.tcl new file mode 100644 index 0000000..cba4503 --- /dev/null +++ b/fpga_interchange/site_router_tests/common/synth.tcl @@ -0,0 +1,14 @@ +yosys -import + +read_verilog $::env(SOURCES) + +synth_xilinx -flatten -abc9 -nosrl -nocarry -nodsp + +# opt_expr -undriven makes sure all nets are driven, if only by the $undef +# net. +opt_expr -undriven +opt_clean + +setundef -zero -params + +write_json $::env(OUT_JSON) diff --git a/fpga_interchange/site_router_tests/lut/CMakeLists.txt b/fpga_interchange/site_router_tests/lut/CMakeLists.txt new file mode 100644 index 0000000..1441b38 --- /dev/null +++ b/fpga_interchange/site_router_tests/lut/CMakeLists.txt @@ -0,0 +1,6 @@ +add_site_router_test( + name lut + board arty35t + test_script test.yaml + sources lut.v +) diff --git a/fpga_interchange/site_router_tests/lut/lut.v b/fpga_interchange/site_router_tests/lut/lut.v new file mode 100644 index 0000000..141d7b1 --- /dev/null +++ b/fpga_interchange/site_router_tests/lut/lut.v @@ -0,0 +1,24 @@ +module top(input [5:0] lut_1_in, input [4:0] lut_2_in, output lut_1_out, output lut_2_out); + +(* keep *) +LUT6 #(.INIT(64'hFFFFFFFFFFFFFFFF)) lut_1 ( + .I0(lut_1_in[0]), + .I1(lut_1_in[1]), + .I2(lut_1_in[2]), + .I3(lut_1_in[3]), + .I4(lut_1_in[4]), + .I5(lut_1_in[5]), + .O(lut_1_out) +); + +(* keep *) +LUT5 #(.INIT(32'h0)) lut_2 ( + .I0(lut_1_in[0]), + .I1(lut_2_in[1]), + .I2(lut_2_in[2]), + .I3(lut_2_in[3]), + .I4(lut_2_in[4]), + .O(lut_2_out) +); + +endmodule diff --git a/fpga_interchange/site_router_tests/lut/lut.xdc b/fpga_interchange/site_router_tests/lut/lut.xdc new file mode 100644 index 0000000..426b3a9 --- /dev/null +++ b/fpga_interchange/site_router_tests/lut/lut.xdc @@ -0,0 +1,32 @@ +## arty-35t board +set_property PACKAGE_PIN G13 [get_ports lut_1_in[0]] +set_property PACKAGE_PIN B11 [get_ports lut_1_in[1]] +set_property PACKAGE_PIN A11 [get_ports lut_1_in[2]] +set_property PACKAGE_PIN D12 [get_ports lut_1_in[3]] +set_property PACKAGE_PIN D13 [get_ports lut_1_in[4]] +set_property PACKAGE_PIN B18 [get_ports lut_1_in[5]] + +set_property PACKAGE_PIN E15 [get_ports lut_2_in[0]] +set_property PACKAGE_PIN E16 [get_ports lut_2_in[1]] +set_property PACKAGE_PIN D15 [get_ports lut_2_in[2]] +set_property PACKAGE_PIN C15 [get_ports lut_2_in[3]] +set_property PACKAGE_PIN J17 [get_ports lut_2_in[4]] + +set_property PACKAGE_PIN H5 [get_ports lut_1_out] +set_property PACKAGE_PIN J5 [get_ports lut_2_out] + +set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[0]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[1]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[2]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[3]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[4]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[5]] + +set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[0]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[1]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[2]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[3]] +set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[4]] + +set_property IOSTANDARD LVCMOS33 [get_ports lut_1_out] +set_property IOSTANDARD LVCMOS33 [get_ports lut_2_out] diff --git a/fpga_interchange/site_router_tests/lut/test.yaml b/fpga_interchange/site_router_tests/lut/test.yaml new file mode 100644 index 0000000..e299d81 --- /dev/null +++ b/fpga_interchange/site_router_tests/lut/test.yaml @@ -0,0 +1,28 @@ +test_case: + - place: + # Place cell `lut_2` at BEL `SLICE_X1Y8.SLICEL/A6LUT` + lut_1: SLICE_X1Y8.SLICEL/A6LUT + - test: + # Make sure this placement is accept + SLICE_X1Y8.SLICEL/A6LUT: true + - unplace: + SLICE_X1Y8.SLICEL/A6LUT + # - place: + # lut_1: SLICE_X1Y8.SLICEL/B6LUT + # - test: + # # Make sure this placement is accept + # SLICE_X1Y8.SLICEL/A6LUT: true + # SLICE_X1Y8.SLICEL/B6LUT: true + # - place: + # lut_1: SLICE_X1Y8.SLICEL/A6LUT + # lut_2: SLICE_X1Y8.SLICEL/A5LUT + # - test: + # # The site is now invalid because too many signals into the A6/A5LUT + # SLICE_X1Y8.SLICEL/A6LUT: false + # SLICE_X1Y8.SLICEL/A5LUT: false + # - unplace: + # - lut_2 + # - test: + # # By removing lut_2, the site is valid again + # SLICE_X1Y8.SLICEL/A6LUT: true + # SLICE_X1Y8.SLICEL/A5LUT: true diff --git a/fpga_interchange/site_router_tests/site_router_test.cmake b/fpga_interchange/site_router_tests/site_router_test.cmake new file mode 100644 index 0000000..26403bd --- /dev/null +++ b/fpga_interchange/site_router_tests/site_router_test.cmake @@ -0,0 +1,133 @@ +function(add_site_router_test) + # ~~~ + # add_site_router_test( + # name + # board + # test_script + # sources + # [top ] + # ) + # + # Generates targets to run desired site router tests. + # + # Arguments: + # - name: base test name. The real test name will be _ + # - board: name of the board to be used in the test, e.g. arty35t + # - test_script: YAML description of the test case + # - sources: list of HDL sources + # - top (optional): name of the top level module. + # If not provided, "top" is assigned as top level module + + set(options) + set(oneValueArgs name test_script board top) + set(multiValueArgs sources) + + cmake_parse_arguments( + add_site_router_test + "${options}" + "${oneValueArgs}" + "${multiValueArgs}" + ${ARGN} + ) + + set(name ${add_site_router_test_name}) + set(test_script ${add_site_router_test_test_script}) + set(board ${add_site_router_test_board}) + set(top ${add_site_router_test_top}) + set(sources) + get_property(device TARGET board-${board} PROPERTY DEVICE) + get_property(package TARGET board-${board} PROPERTY PACKAGE) + foreach(source ${add_site_router_test_sources}) + list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/${source}) + endforeach() + + if (NOT DEFINED top) + # Setting default top value + set(top "top") + endif() + + set(common_dir ${CMAKE_CURRENT_SOURCE_DIR}/../common) + + # Synthesis + set(synth_json ${CMAKE_CURRENT_BINARY_DIR}/${name}.json) + add_custom_command( + OUTPUT ${synth_json} + COMMAND ${CMAKE_COMMAND} -E env + SOURCES="${sources}" + OUT_JSON=${synth_json} + yosys -c ${common_dir}/synth.tcl + DEPENDS ${sources} + ) + + add_custom_target(site_router_tests-${name}-json DEPENDS ${synth_json}) + + # Logical Netlist + get_property(device_target TARGET device-${device} PROPERTY DEVICE_TARGET) + get_property(device_loc TARGET device-${device} PROPERTY DEVICE_LOC) + + set(netlist ${CMAKE_CURRENT_BINARY_DIR}/${name}.netlist) + add_custom_command( + OUTPUT ${netlist} + COMMAND + ${PYTHON_EXECUTABLE} -mfpga_interchange.yosys_json + --schema_dir ${INTERCHANGE_SCHEMA_PATH} + --device ${device_loc} + --top ${top} + ${synth_json} + ${netlist} + DEPENDS + ${synth_json} + ${device_target} + ${device_loc} + ) + + add_custom_target(site_router_tests-${name}-netlist DEPENDS ${netlist}) + + # Logical Netlist YAML + set(netlist_yaml ${CMAKE_CURRENT_BINARY_DIR}/${name}.netlist.yaml) + add_custom_command( + OUTPUT ${netlist_yaml} + COMMAND + ${PYTHON_EXECUTABLE} -mfpga_interchange.convert + --schema_dir ${INTERCHANGE_SCHEMA_PATH} + --schema logical + --input_format capnp + --output_format yaml + ${netlist} + ${netlist_yaml} + DEPENDS + ${netlist} + ) + + add_custom_target(site_router_tests-${name}-netlist-yaml DEPENDS ${netlist_yaml}) + + # Physical Netlist + get_target_property(chipdb_bin_target device-${device} CHIPDB_BIN_TARGET) + get_target_property(chipdb_bin_loc device-${device} CHIPDB_BIN_LOC) + get_target_property(nextpnr_path nextpnr-fpga_interchange BINARY_DIR) + set(xdc ${CMAKE_CURRENT_SOURCE_DIR}/${name}.xdc) + set(run_script ${common_dir}/run_script.py) + set(test_result ${CMAKE_CURRENT_BINARY_DIR}/${name}.test_result) + + add_custom_command( + OUTPUT ${test_result} + COMMAND + ${CMAKE_COMMAND} -E env TEST_YAML=${CMAKE_CURRENT_SOURCE_DIR}/${test_script} + ${nextpnr_path}/nextpnr-fpga_interchange + --run ${run_script} + --no-route + --chipdb ${chipdb_bin_loc} + --xdc ${xdc} + --netlist ${netlist} + --package ${package} > ${test_result} + DEPENDS + nextpnr-fpga_interchange + ${netlist} + ${xdc} + ${chipdb_bin_target} + ${chipdb_bin_loc} + ${run_script} + ) + + add_custom_target(site_router_tests-${name}-test DEPENDS ${test_result}) +endfunction() -- cgit v1.2.3