Skip to content

fpga_interchange: Add initial site router test framework #10

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 11, 2021
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
2 changes: 2 additions & 0 deletions fpga_interchange/site_router_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
include(site_router_test.cmake)
add_subdirectory(lut)
29 changes: 29 additions & 0 deletions fpga_interchange/site_router_tests/common/run_script.py
Original file line number Diff line number Diff line change
@@ -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)
14 changes: 14 additions & 0 deletions fpga_interchange/site_router_tests/common/synth.tcl
Original file line number Diff line number Diff line change
@@ -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)
6 changes: 6 additions & 0 deletions fpga_interchange/site_router_tests/lut/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
add_site_router_test(
name lut
board arty35t
test_script test.yaml
sources lut.v
)
24 changes: 24 additions & 0 deletions fpga_interchange/site_router_tests/lut/lut.v
Original file line number Diff line number Diff line change
@@ -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
32 changes: 32 additions & 0 deletions fpga_interchange/site_router_tests/lut/lut.xdc
Original file line number Diff line number Diff line change
@@ -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]
28 changes: 28 additions & 0 deletions fpga_interchange/site_router_tests/lut/test.yaml
Original file line number Diff line number Diff line change
@@ -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
133 changes: 133 additions & 0 deletions fpga_interchange/site_router_tests/site_router_test.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
function(add_site_router_test)
# ~~~
# add_site_router_test(
# name <name>
# board <board>
# test_script <yaml>
# sources <sources list>
# [top <top name>]
# )
#
# Generates targets to run desired site router tests.
#
# Arguments:
# - name: base test name. The real test name will be <name>_<board>
# - 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()