Skip to content

Commit 04098fc

Browse files
committed
fpga_interchange: Add initial site router test framework
Signed-off-by: Tomasz Michalak <tmichalak@antmicro.com>
1 parent caf7261 commit 04098fc

File tree

8 files changed

+280
-0
lines changed

8 files changed

+280
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
include(site_router_test.cmake)
2+
add_subdirectory(lut)
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import sys
2+
print(
3+
"""
4+
import yaml
5+
6+
def test_case(ctx):
7+
with open(""" + "\"" + sys.argv[1] + "\"" + """, 'r') as f:
8+
test_data = yaml.safe_load(f.read())
9+
if 'test_case' in test_data:
10+
ctx.pack()
11+
for test_step in test_data['test_case']:
12+
print(test_step)
13+
if "place" in test_step:
14+
for cell, bel in test_step["place"].items():
15+
print("Binding Bel {} to Cell {}".format(bel, cell))
16+
assert cell in ctx.cells, "Cell {} does not exist".format(cell)
17+
ctx.bindBel(bel, ctx.cells[cell], STRENGTH_WEAK)
18+
if "test" in test_step:
19+
print(test_step["test"])
20+
for bel, check in test_step["test"].items():
21+
print("Checking if location of bel {} is {}".format(bel, check))
22+
print("Test result: {}, isBelLocationValid: {}, expected: {}".format(ctx.isBelLocationValid(bel) == check, ctx.isBelLocationValid(bel), check))
23+
if "unplace" in test_step:
24+
print(test_step["unplace"])
25+
cell = test_step["unplace"]
26+
print("Unbinding Bel {}".format(cell))
27+
ctx.explain_bel_status(cell)
28+
ctx.unbindBel(cell)
29+
30+
test_case(ctx)
31+
""")
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
yosys -import
2+
3+
read_verilog $::env(SOURCES)
4+
5+
synth_xilinx -flatten -abc9 -nosrl -nocarry -nodsp
6+
7+
# opt_expr -undriven makes sure all nets are driven, if only by the $undef
8+
# net.
9+
opt_expr -undriven
10+
opt_clean
11+
12+
setundef -zero -params
13+
14+
write_json $::env(OUT_JSON)
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
add_site_router_test(
2+
name lut
3+
board arty35t
4+
test_script test.yaml
5+
sources lut.v
6+
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module top(input [5:0] lut_1_in, input [4:0] lut_2_in, output lut_1_out, output lut_2_out);
2+
3+
(* keep *)
4+
LUT6 #(.INIT(64'hFFFFFFFFFFFFFFFF)) lut_1 (
5+
.I0(lut_1_in[0]),
6+
.I1(lut_1_in[1]),
7+
.I2(lut_1_in[2]),
8+
.I3(lut_1_in[3]),
9+
.I4(lut_1_in[4]),
10+
.I5(lut_1_in[5]),
11+
.O(lut_1_out)
12+
);
13+
14+
(* keep *)
15+
LUT5 #(.INIT(32'h0)) lut_2 (
16+
.I0(lut_1_in[0]),
17+
.I1(lut_2_in[1]),
18+
.I2(lut_2_in[2]),
19+
.I3(lut_2_in[3]),
20+
.I4(lut_2_in[4]),
21+
.O(lut_2_out)
22+
);
23+
24+
endmodule
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
## arty-35t board
2+
set_property PACKAGE_PIN G13 [get_ports lut_1_in[0]]
3+
set_property PACKAGE_PIN B11 [get_ports lut_1_in[1]]
4+
set_property PACKAGE_PIN A11 [get_ports lut_1_in[2]]
5+
set_property PACKAGE_PIN D12 [get_ports lut_1_in[3]]
6+
set_property PACKAGE_PIN D13 [get_ports lut_1_in[4]]
7+
set_property PACKAGE_PIN B18 [get_ports lut_1_in[5]]
8+
9+
set_property PACKAGE_PIN E15 [get_ports lut_2_in[0]]
10+
set_property PACKAGE_PIN E16 [get_ports lut_2_in[1]]
11+
set_property PACKAGE_PIN D15 [get_ports lut_2_in[2]]
12+
set_property PACKAGE_PIN C15 [get_ports lut_2_in[3]]
13+
set_property PACKAGE_PIN J17 [get_ports lut_2_in[4]]
14+
15+
set_property PACKAGE_PIN H5 [get_ports lut_1_out]
16+
set_property PACKAGE_PIN J5 [get_ports lut_2_out]
17+
18+
set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[0]]
19+
set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[1]]
20+
set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[2]]
21+
set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[3]]
22+
set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[4]]
23+
set_property IOSTANDARD LVCMOS33 [get_ports lut_1_in[5]]
24+
25+
set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[0]]
26+
set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[1]]
27+
set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[2]]
28+
set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[3]]
29+
set_property IOSTANDARD LVCMOS33 [get_ports lut_2_in[4]]
30+
31+
set_property IOSTANDARD LVCMOS33 [get_ports lut_1_out]
32+
set_property IOSTANDARD LVCMOS33 [get_ports lut_2_out]
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
test_case:
2+
- place:
3+
# Place cell `lut_2` at BEL `SLICE_X1Y8.SLICEL/A6LUT`
4+
lut_1: SLICE_X1Y8.SLICEL/A6LUT
5+
- test:
6+
# Make sure this placement is accept
7+
SLICE_X1Y8.SLICEL/A6LUT: true
8+
- unplace:
9+
SLICE_X1Y8.SLICEL/A6LUT
10+
# - place:
11+
# lut_1: SLICE_X1Y8.SLICEL/B6LUT
12+
# - test:
13+
# # Make sure this placement is accept
14+
# SLICE_X1Y8.SLICEL/A6LUT: true
15+
# SLICE_X1Y8.SLICEL/B6LUT: true
16+
# - place:
17+
# lut_1: SLICE_X1Y8.SLICEL/A6LUT
18+
# lut_2: SLICE_X1Y8.SLICEL/A5LUT
19+
# - test:
20+
# # The site is now invalid because too many signals into the A6/A5LUT
21+
# SLICE_X1Y8.SLICEL/A6LUT: false
22+
# SLICE_X1Y8.SLICEL/A5LUT: false
23+
# - unplace:
24+
# - lut_2
25+
# - test:
26+
# # By removing lut_2, the site is valid again
27+
# SLICE_X1Y8.SLICEL/A6LUT: true
28+
# SLICE_X1Y8.SLICEL/A5LUT: true
Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
function(add_site_router_test)
2+
# ~~~
3+
# add_site_router_test(
4+
# name <name>
5+
# board <board>
6+
# test_script <yaml>
7+
# sources <sources list>
8+
# [top <top name>]
9+
# )
10+
#
11+
# Generates targets to run desired site router tests.
12+
#
13+
# Arguments:
14+
# - name: base test name. The real test name will be <name>_<board>
15+
# - board: name of the board to be used in the test, e.g. arty35t
16+
# - test_script: YAML description of the test case
17+
# - sources: list of HDL sources
18+
# - top (optional): name of the top level module.
19+
# If not provided, "top" is assigned as top level module
20+
21+
set(options)
22+
set(oneValueArgs name test_script board top)
23+
set(multiValueArgs sources)
24+
25+
cmake_parse_arguments(
26+
add_site_router_test
27+
"${options}"
28+
"${oneValueArgs}"
29+
"${multiValueArgs}"
30+
${ARGN}
31+
)
32+
33+
set(name ${add_site_router_test_name})
34+
set(test_script ${add_site_router_test_test_script})
35+
set(board ${add_site_router_test_board})
36+
set(top ${add_site_router_test_top})
37+
set(sources)
38+
get_property(device TARGET board-${board} PROPERTY DEVICE)
39+
get_property(package TARGET board-${board} PROPERTY PACKAGE)
40+
foreach(source ${add_site_router_test_sources})
41+
list(APPEND sources ${CMAKE_CURRENT_SOURCE_DIR}/${source})
42+
endforeach()
43+
44+
if (NOT DEFINED top)
45+
# Setting default top value
46+
set(top "top")
47+
endif()
48+
49+
set(common_dir ${CMAKE_CURRENT_SOURCE_DIR}/../common)
50+
51+
# Synthesis
52+
set(synth_json ${CMAKE_CURRENT_BINARY_DIR}/${name}.json)
53+
add_custom_command(
54+
OUTPUT ${synth_json}
55+
COMMAND ${CMAKE_COMMAND} -E env
56+
SOURCES="${sources}"
57+
OUT_JSON=${synth_json}
58+
yosys -c ${common_dir}/synth.tcl
59+
DEPENDS ${sources}
60+
)
61+
62+
add_custom_target(site_router_tests-${name}-json DEPENDS ${synth_json})
63+
64+
# Logical Netlist
65+
get_property(device_target TARGET device-${device} PROPERTY DEVICE_TARGET)
66+
get_property(device_loc TARGET device-${device} PROPERTY DEVICE_LOC)
67+
68+
set(netlist ${CMAKE_CURRENT_BINARY_DIR}/${name}.netlist)
69+
add_custom_command(
70+
OUTPUT ${netlist}
71+
COMMAND
72+
${PYTHON_EXECUTABLE} -mfpga_interchange.yosys_json
73+
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
74+
--device ${device_loc}
75+
--top ${top}
76+
${synth_json}
77+
${netlist}
78+
DEPENDS
79+
${synth_json}
80+
${device_target}
81+
${device_loc}
82+
)
83+
84+
add_custom_target(site_router_tests-${name}-netlist DEPENDS ${netlist})
85+
86+
# Logical Netlist YAML
87+
set(netlist_yaml ${CMAKE_CURRENT_BINARY_DIR}/${name}.netlist.yaml)
88+
add_custom_command(
89+
OUTPUT ${netlist_yaml}
90+
COMMAND
91+
${PYTHON_EXECUTABLE} -mfpga_interchange.convert
92+
--schema_dir ${INTERCHANGE_SCHEMA_PATH}
93+
--schema logical
94+
--input_format capnp
95+
--output_format yaml
96+
${netlist}
97+
${netlist_yaml}
98+
DEPENDS
99+
${netlist}
100+
)
101+
102+
add_custom_target(site_router_tests-${name}-netlist-yaml DEPENDS ${netlist_yaml})
103+
# Run script
104+
set(run_script ${CMAKE_CURRENT_BINARY_DIR}/${name}.py)
105+
106+
add_custom_command(
107+
OUTPUT ${run_script}
108+
COMMAND
109+
${PYTHON_EXECUTABLE}
110+
${common_dir}/run_script.tpl.py
111+
${CMAKE_CURRENT_SOURCE_DIR}/${test_script} > ${run_script}
112+
DEPENDS
113+
${test_script}
114+
)
115+
add_custom_target(site_router_tests-${name}-run_script DEPENDS ${run_script})
116+
117+
# Physical Netlist
118+
get_property(chipdb_bin_target TARGET device-${device} PROPERTY CHIPDB_BIN_TARGET)
119+
get_property(chipdb_bin_loc TARGET device-${device} PROPERTY CHIPDB_BIN_LOC)
120+
set(test_result ${CMAKE_CURRENT_BINARY_DIR}/${name}.test_result)
121+
set(xdc ${CMAKE_CURRENT_SOURCE_DIR}/${name}.xdc)
122+
123+
add_custom_command(
124+
OUTPUT ${test_result}
125+
COMMAND
126+
nextpnr-fpga_interchange
127+
--run ${run_script}
128+
--no-route
129+
--chipdb ${chipdb_bin_loc}
130+
--xdc ${xdc}
131+
--netlist ${netlist}
132+
--package ${package} > ${test_result}
133+
DEPENDS
134+
nextpnr-fpga_interchange
135+
${netlist}
136+
${xdc}
137+
${chipdb_bin_target}
138+
${chipdb_bin_loc}
139+
${run_script}
140+
)
141+
142+
add_custom_target(site_router_tests-${name}-test DEPENDS ${test_result})
143+
endfunction()

0 commit comments

Comments
 (0)