Skip to content

Commit 84edbe5

Browse files
Merge pull request FPGA-Research#146 from IAmMarcelJung:bugfix/pathlib-file-path-handling
Use pathlib to extract the file name information
2 parents 50c9076 + 73ef1fe commit 84edbe5

File tree

1 file changed

+77
-95
lines changed

1 file changed

+77
-95
lines changed

FABulous.py

Lines changed: 77 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import readline
4242
import logging
4343
import tkinter as tk
44+
from pathlib import PurePosixPath, PureWindowsPath
45+
import platform
4446
readline.set_completer_delims(' \t\n')
4547
histfile = ""
4648
histfile_size = 1000
@@ -69,6 +71,16 @@ def create_project(project_dir, type: Literal["verilog", "vhdl"] = "verilog"):
6971
shutil.copytree(f"{fabulousRoot}/fabric_files/FABulous_project_template_{type}/",
7072
f"{project_dir}/", dirs_exist_ok=True)
7173

74+
def get_path(path):
75+
system = platform.system()
76+
# Darwin corresponds to MacOS, which also uses POSIX-style paths
77+
if system == "Linux" or system == "Darwin":
78+
return PurePosixPath(path)
79+
elif system == "Windows":
80+
return PureWindowsPath(path)
81+
else:
82+
raise NotImplementedError(f"Unsupported operating system: {system}")
83+
7284
class PlaceAndRouteError(Exception):
7385
"""An exception to be thrown when place and route fails."""
7486

@@ -625,7 +637,7 @@ def do_hls_create_project(self):
625637
with open(f"{self.projectDir}/HLS/config.tcl", "w") as f:
626638
f.write(f"source /root/legup-4.0/examples/legup.tcl\n")
627639

628-
name = self.projectDir.split('/')[-1]
640+
name = get_path(self.projectDir).name
629641
with open(f"{self.projectDir}/HLS/Makefile", "w") as f:
630642
f.write(f"NAME = {name}\n")
631643
f.write(
@@ -644,7 +656,7 @@ def do_hls_create_project(self):
644656
os.chmod(f"./HLS/{name}.c", 0o666)
645657

646658
def do_hls_generate_verilog(self):
647-
name = self.projectDir.split('/')[-1]
659+
name = get_path(self.projectDir).name
648660
# create folder for the generated file
649661
if not os.path.exists(f"./HLS/generated_file"):
650662
os.mkdir(f"{name}/generated_file")
@@ -719,18 +731,11 @@ def do_synthesis_npnr(self, args):
719731
raise TypeError(f"do_place_and_route_npnr takes exactly one argument ({len(args)} given)")
720732
logger.info(
721733
f"Running synthesis that targeting Nextpnr with design {args[0]}")
722-
path, verilog_file = os.path.split(args[0])
723-
if len(verilog_file.split('.')) != 2:
724-
logger.error(
725-
"""
726-
No verilog file provided.
727-
Usage: synthesis_npnr <top_module_file>
728-
""")
729-
return
730-
731-
top_module_name, file_ending = verilog_file.split('.')
732-
733-
if file_ending != "v":
734+
path = get_path(args[0])
735+
parent = path.parent
736+
verilog_file = path.name
737+
top_module_name = path.stem
738+
if path.suffix != ".v":
734739
logger.error(
735740
"""
736741
No verilog file provided.
@@ -740,9 +745,9 @@ def do_synthesis_npnr(self, args):
740745

741746
json_file = top_module_name + ".json"
742747
runCmd = ["yosys",
743-
"-p", f"synth_fabulous -top top_wrapper -json {self.projectDir}/{path}/{json_file}",
744-
f"{self.projectDir}/{path}/{verilog_file}",
745-
f"{self.projectDir}/{path}/top_wrapper.v", ]
748+
"-p", f"synth_fabulous -top top_wrapper -json {self.projectDir}/{parent}/{json_file}",
749+
f"{self.projectDir}/{parent}/{verilog_file}",
750+
f"{self.projectDir}/{parent}/top_wrapper.v", ]
746751
try:
747752
sp.run(runCmd, check=True)
748753
logger.info("Synthesis completed")
@@ -761,18 +766,12 @@ def do_synthesis_blif(self, args):
761766
raise TypeError(f"do_place_and_route_npnr takes exactly one argument ({len(args)} given)")
762767
logger.info(
763768
f"Running synthesis that targeting BLIF with design {args[0]}")
764-
path, verilog_file = os.path.split(args[0])
765-
if len(verilog_file.split('.')) != 2:
766-
logger.error(
767-
"""
768-
No verilog file provided.
769-
Usage: synthesis_blif <top_module_file>
770-
""")
771-
return
772-
773-
top_module_name, file_ending = verilog_file.split('.')
774769

775-
if file_ending != "v":
770+
path = get_path(args[0])
771+
parent = path.parent
772+
verilog_file = path.name
773+
top_module_name = path.stem
774+
if path.suffix != ".v":
776775
logger.error(
777776
"""
778777
No verilog file provided.
@@ -782,9 +781,9 @@ def do_synthesis_blif(self, args):
782781

783782
blif_file = top_module_name + ".blif"
784783
runCmd = ["yosys",
785-
"-p", f"synth_fabulous -top top_wrapper -blif {self.projectDir}/{path}/{blif_file} -vpr",
786-
f"{self.projectDir}/{path}/{verilog_file}",
787-
f"{self.projectDir}/{path}/top_wrapper.v", ]
784+
"-p", f"synth_fabulous -top top_wrapper -blif {self.projectDir}/{parent}/{blif_file} -vpr",
785+
f"{self.projectDir}/{parent}/{verilog_file}",
786+
f"{self.projectDir}/{parent}/top_wrapper.v", ]
788787
try:
789788
sp.run(runCmd, check=True)
790789
logger.info("Synthesis completed.")
@@ -807,46 +806,41 @@ def do_place_and_route_npnr(self, args):
807806
raise TypeError(f"do_place_and_route_npnr takes exactly one argument ({len(args)} given)")
808807
logger.info(
809808
f"Running Placement and Routing with Nextpnr for design {args[0]}")
810-
path, json_file = os.path.split(args[0])
811-
if len(json_file.split('.')) != 2:
812-
logger.error(
813-
"""
814-
No json file provided.
815-
Usage: place_and_route_npnr <json_file> (<json_file> is generated by Yosys. Generate it by running synthesis_npnr.)
816-
""")
817-
return
809+
path = get_path(args[0])
810+
parent = path.parent
811+
json_file = path.name
812+
top_module_name = path.stem
818813

819-
top_module_name, file_ending = json_file.split('.')
820-
if file_ending != "json":
814+
if path.suffix != ".json":
821815
logger.error(
822816
"""
823817
No json file provided.
824818
Usage: place_and_route_npnr <json_file> (<json_file> is generated by Yosys. Generate it by running synthesis_npnr.)
825819
""")
826820
return
821+
827822
fasm_file = top_module_name + ".fasm"
828823
log_file = top_module_name + "_npnr_log.txt"
829824

830-
if path == "":
831-
path = "."
825+
if parent == "":
826+
parent = "."
832827

833828
if not os.path.exists(f"{self.projectDir}/.FABulous/pips.txt") or not os.path.exists(
834829
f"{self.projectDir}/.FABulous/bel.txt"):
835830
logger.error(
836831
"Pips and Bel files are not found, please run model_gen_npnr first")
837832
raise FileNotFoundError
838833

839-
print(self.projectDir)
840-
if os.path.exists(f"{self.projectDir}/{path}"):
834+
if os.path.exists(f"{self.projectDir}/{parent}"):
841835
# TODO rewriting the fab_arch script so no need to copy file for work around
842-
if f"{json_file}" in os.listdir(f"{self.projectDir}/{path}"):
836+
if f"{json_file}" in os.listdir(f"{self.projectDir}/{parent}"):
843837
runCmd = [f"FAB_ROOT={self.projectDir}",
844838
f"nextpnr-generic",
845839
"--uarch", "fabulous",
846-
"--json", f"{self.projectDir}/{path}/{json_file}",
847-
"-o", f"fasm={self.projectDir}/{path}/{fasm_file}",
840+
"--json", f"{self.projectDir}/{parent}/{json_file}",
841+
"-o", f"fasm={self.projectDir}/{parent}/{fasm_file}",
848842
"--verbose",
849-
"--log", f"{self.projectDir}/{path}/{log_file}"]
843+
"--log", f"{self.projectDir}/{parent}/{log_file}"]
850844
try:
851845
sp.run(" ".join(runCmd), stdout=sys.stdout,
852846
stderr=sp.STDOUT, check=True, shell=True)
@@ -857,13 +851,13 @@ def do_place_and_route_npnr(self, args):
857851

858852
else:
859853
logger.error(
860-
f"Cannot find file \"{json_file}\" in path \"./{path}/\", which is generated by running Yosys with Nextpnr backend (e.g. synthesis_npnr).")
854+
f"Cannot find file \"{json_file}\" in path \"./{parent}/\", which is generated by running Yosys with Nextpnr backend (e.g. synthesis_npnr).")
861855
raise FileNotFoundError
862856

863857
logger.info("Placement and Routing completed")
864858
else:
865859
logger.error(
866-
f"Directory {self.projectDir}/{path} does not exist.")
860+
f"Directory {self.projectDir}/{parent} does not exist.")
867861
raise FileNotFoundError
868862

869863
def complete_place_and_route_npnr(self, text, *ignored):
@@ -877,7 +871,8 @@ def do_place_and_route_vpr(self, args):
877871
raise TypeError(f"do_place_and_route_npnr takes exactly one argument ({len(args)} given)")
878872
logger.info(
879873
f"Running Placement and Routing with vpr for design {args[0]}")
880-
path, blif_file = os.path.split(args[0])
874+
path = get_path(args[0])
875+
blif_file = path.name
881876

882877
if os.path.exists(f"{self.projectDir}/user_design/{blif_file}"):
883878
if not os.getenv('VTR_ROOT'):
@@ -914,18 +909,12 @@ def do_gen_bitStream_binary(self, args):
914909
if len(args) != 1:
915910
logger.error("Usage: gen_bitStream_binary <fasm_file>")
916911
return
917-
path, fasm_file = os.path.split(args[0])
918-
if len(fasm_file.split('.')) != 2:
919-
logger.error(
920-
"""
921-
No fasm file provided.
922-
Usage: gen_bitStream_binary <fasm_file>
923-
""")
924-
return
925-
926-
top_module_name, file_ending = fasm_file.split('.')
912+
path = get_path(args[0])
913+
parent = path.parent
914+
fasm_file = path.name
915+
top_module_name = path.stem
927916

928-
if file_ending != "fasm":
917+
if path.suffix != ".fasm":
929918
logger.error(
930919
"""
931920
No fasm file provided.
@@ -940,19 +929,19 @@ def do_gen_bitStream_binary(self, args):
940929
"Cannot find bitStreamSpec.bin file, which is generated by running gen_bitStream_spec")
941930
return
942931

943-
if not os.path.exists(f"{self.projectDir}/{path}/{fasm_file}"):
932+
if not os.path.exists(f"{self.projectDir}/{parent}/{fasm_file}"):
944933
logger.error(
945-
f"Cannot find {self.projectDir}/{path}/{fasm_file} file which is generated by running place_and_route_npnr or place_and_route_vpr. Potentially Place and Route Failed.")
934+
f"Cannot find {self.projectDir}/{parent}/{fasm_file} file which is generated by running place_and_route_npnr or place_and_route_vpr. Potentially Place and Route Failed.")
946935
return
947936

948937
logger.info(
949-
f"Generating Bitstream for design {self.projectDir}/{args[0]}")
950-
logger.info(f"Outputting to {self.projectDir}/{path}/{bitstream_file}")
938+
f"Generating Bitstream for design {self.projectDir}/{path}")
939+
logger.info(f"Outputting to {self.projectDir}/{parent}/{bitstream_file}")
951940
runCmd = ["python3", f"{fabulousRoot}/fabric_cad/bit_gen.py",
952941
"-genBitstream",
953-
f"{self.projectDir}/{path}/{fasm_file}",
942+
f"{self.projectDir}/{parent}/{fasm_file}",
954943
f"{self.projectDir}/.FABulous/bitStreamSpec.bin",
955-
f"{self.projectDir}/{path}/{bitstream_file}"]
944+
f"{self.projectDir}/{parent}/{bitstream_file}"]
956945

957946
try:
958947
sp.run(runCmd, check=True)
@@ -979,37 +968,29 @@ def do_run_FABulous_bitstream(self, *args):
979968
"Usage: run_FABulous_bitstream <npnr|vpr> <top_module_file>")
980969
return
981970

982-
verilog_file_path = args[1]
983-
if len(verilog_file_path.split('.')) != 2:
984-
logger.error(
985-
"""
986-
No verilog file provided.
987-
Usage: run_FABulous_bitstream <npnr|vpr> <top_module_file>
988-
""")
989-
return
990-
991-
file_ending = verilog_file_path.split('.')[1]
971+
verilog_file_path = get_path(args[1])
972+
file_path_no_suffix = verilog_file_path.parent / verilog_file_path.stem
992973

993-
if file_ending != "v":
974+
if verilog_file_path.suffix != ".v":
994975
logger.error(
995976
"""
996977
No verilog file provided.
997978
Usage: run_FABulous_bitstream <npnr|vpr> <top_module_file>
998979
""")
999980
return
1000981

1001-
json_file_path = verilog_file_path.split('.')[0] + ".json"
1002-
blif_file_path = verilog_file_path.split('.')[0] + ".blif"
1003-
fasm_file_path = verilog_file_path.split('.')[0] + ".fasm"
982+
json_file_path = file_path_no_suffix.with_suffix(".json")
983+
blif_file_path = file_path_no_suffix.with_suffix(".blif")
984+
fasm_file_path = file_path_no_suffix.with_suffix(".fasm")
1004985

1005986
if args[0] == "vpr":
1006-
self.do_synthesis_blif(verilog_file_path)
1007-
self.do_place_and_route_vpr(blif_file_path)
1008-
self.do_gen_bitStream_binary(fasm_file_path)
987+
self.do_synthesis_blif(str(verilog_file_path))
988+
self.do_place_and_route_vpr(str(blif_file_path))
989+
self.do_gen_bitStream_binary(str(fasm_file_path))
1009990
elif args[0] == "npnr":
1010-
self.do_synthesis_npnr(verilog_file_path)
1011-
self.do_place_and_route_npnr(json_file_path)
1012-
self.do_gen_bitStream_binary(fasm_file_path)
991+
self.do_synthesis_npnr(str(verilog_file_path))
992+
self.do_place_and_route_npnr(str(json_file_path))
993+
self.do_gen_bitStream_binary(str(fasm_file_path))
1013994
else:
1014995
logger.error(
1015996
"Usage: run_FABulous_bitstream <npnr|vpr> <top_module_file>")
@@ -1029,21 +1010,22 @@ def do_tcl(self, args):
10291010
if len(args) != 1:
10301011
logger.error("Usage: tcl <tcl_script>")
10311012
return
1032-
path, name = os.path.split(args[0])
1033-
name = name.split('.')[0]
1034-
if not os.path.exists(args[0]):
1013+
path_str = args[0]
1014+
path = get_path(path_str)
1015+
name = path.stem
1016+
if not os.path.exists(path_str):
10351017
logger.error(
1036-
f"Cannot find {args[0]}")
1018+
f"Cannot find {path_str}")
10371019
return
10381020

1039-
logger.info(f"Execute TCL script {args[0]}")
1021+
logger.info(f"Execute TCL script {path_str}")
10401022
tcl = tk.Tcl()
10411023
for fun in dir(self.__class__):
10421024
if fun.startswith("do_"):
10431025
name = fun.strip("do_")
10441026
tcl.createcommand(name, getattr(self, fun))
10451027

1046-
tcl.evalfile(args[0])
1028+
tcl.evalfile(path_str)
10471029
logger.info("TCL script executed")
10481030

10491031
def complete_tcl(self, text, *ignored):

0 commit comments

Comments
 (0)