A simple TCL + python for PS7 cell definition extraction.

Signed-off-by: Maciej Kurc <mkurc@antmicro.com>
This commit is contained in:
Maciej Kurc 2019-12-09 17:15:39 +01:00
parent 3f0804a417
commit 5d140296d5
4 changed files with 229 additions and 0 deletions

View File

@ -0,0 +1,16 @@
.PHONY: all clean
all: ps7.v
clean:
rm -rf ps7.v
rm -rf ps7.csv
rm -rf *.xml
rm -rf *.log
rm -rf .Xil
ps7.csv: dump_ps7.tcl
$(XRAY_VIVADO) -mode batch -source dump_ps7.tcl -nojournal -log $(basename $@).log
ps7.v: ps7.csv make_cell.py
python3 make_cell.py $<

View File

@ -0,0 +1,3 @@
# PS7 verilog cell definition extractor
Extracts all pins of the PS7 bel from Vivado, groups them into buses, removes those that are not connected (TEST*, DEBUG*) and writes the PS7 verilog cell definition.

View File

@ -0,0 +1,18 @@
create_project -force -in_memory -name design -part xc7z020clg400-1
set_property design_mode PinPlanning [current_fileset]
open_io_design -name io_1
set fp [open ps7.csv w]
puts $fp "name,is_input,is_output"
set pins [get_bel_pins -of_objects [get_bels -of_objects [get_sites PS7* -of_objects [get_tiles PSS*]]]]
foreach pin $pins {
set pin_name [lindex [split $pin "/"] 2]
set is_input [get_property IS_INPUT $pin]
set is_output [get_property IS_OUTPUT $pin]
puts $fp "$pin_name,$is_input,$is_output"
}
close $fp

View File

@ -0,0 +1,192 @@
#!/usr/bin/env python3
import argparse
import csv
import re
from collections import defaultdict
# =============================================================================
def main():
BUS_REGEX = re.compile("(.*[A-Z_])([0-9]+)$")
# Parse arguments
parser = argparse.ArgumentParser()
parser.add_argument("csv", type=str, help="PS7 pin dump file")
args = parser.parse_args()
# Load pin dump
with open(args.csv, "r") as fp:
pin_dump = list(csv.DictReader(fp))
# Group pins into buses
buses = defaultdict(lambda :{
"direction": None,
"min": None,
"max": None,
"width": 0
})
for pin in list(pin_dump):
# Get bus name and signal index
match = BUS_REGEX.match(pin["name"])
if match:
name = match.group(1)
idx = int(match.group(2))
else:
name = pin["name"]
idx = 0
# Get direction
if int(pin["is_input"]):
direction = "input"
if int(pin["is_output"]):
direction = "output"
# Add to bus
bus = buses[name]
if bus["direction"] is None:
bus["direction"] = direction
else:
assert bus["direction"] == direction
if bus["min"] is None:
bus["min"] = idx
else:
bus["min"] = min(bus["min"], idx)
if bus["max"] is None:
bus["max"] = idx
else:
bus["max"] = max(bus["max"], idx)
bus["width"] = bus["max"] - bus["min"] + 1
# Sort buses by their purpose
for name, bus in buses.items():
# A test pin (unconnected)
if name.startswith("TEST"):
cls = "test"
# A debug pin (unconnected)
elif name.startswith("DEBUG"):
cls = "debug"
# A MIO/DDR pin.
elif name.startswith("MIO") or name.startswith("DDR") and \
name != "DDRARB":
cls = "mio"
# "Normal" pin
else:
cls = "normal"
bus["class"] = cls
# .....................................................
# Generate XML model
model_xml = """<models>
<model name="PS7">
"""
# Inputs
model_xml += """ <input_ports>
"""
for name in sorted(buses.keys()):
bus = buses[name]
# Skip not relevant pins
if bus["class"] not in ["normal", "mio"]:
continue
if bus["direction"] != "input":
continue
model_xml += " <port name=\"{}\"/>\n".format(name)
# Outputs
model_xml += """ </input_ports>
<output_ports>
"""
for name in sorted(buses.keys()):
bus = buses[name]
# Skip not relevant pins
if bus["class"] not in ["normal", "mio"]:
continue
if bus["direction"] != "output":
continue
model_xml += " <port name=\"{}\"/>\n".format(name)
model_xml += """ </output_ports>
"""
model_xml += """ </model>
</models>"""
with open("ps7.model.xml", "w") as fp:
fp.write(model_xml)
# .....................................................
# Generate XML pb_type
pb_name = "PS7"
blif_model = "PS7"
pb_xml = """<pb_type name="{}" blif_model=".subckt {}" num_pb="1">
""".format(pb_name, blif_model)
for name in sorted(buses.keys()):
bus = buses[name]
# Skip not relevant pins
if bus["class"] not in ["normal", "mio"]:
continue
pb_xml += " <{} name=\"{}\" num_pins=\"{}\"/>\n".format(
bus["direction"].ljust(6), name, bus["width"])
pb_xml += """</pb_type>
"""
with open("ps7.pb_type.xml", "w") as fp:
fp.write(pb_xml)
# .....................................................
# Prepare Verilog module definition for the PS7
pin_strs = []
for name in sorted(buses.keys()):
bus = buses[name]
# Skip not relevant pins
if bus["class"] not in ["normal", "mio"]:
continue
if bus["width"] > 1:
pin_str = " {} [{:>2d}:{:>2d}] {}".format(
bus["direction"].ljust(6), bus["max"], bus["min"], name)
else:
pin_str = " {} {}".format(bus["direction"].ljust(6), name)
pin_strs.append(pin_str)
verilog = """(* blackbox *)
module PS7 (
{}
);
endmodule
""".format(",\n".join(pin_strs))
with open("ps7.v", "w") as fp:
fp.write(verilog)
if __name__ == "__main__":
main()