Add project configuration and build tools
- Introduced new scripts for project generation and synthesis (dodo.py, generate_prj.py, generate_scr.py, run_xst.py). - Implemented configuration parsing for VHDL sources and project settings (config.py). - Added default configuration values (defaults.py). - Updated .gitignore to include additional file types. - Created test cases for project generation and configuration parsing (test_generate_prj.py, test_generate_scr.py, test_project_cfg.py).
This commit is contained in:
0
tests/__init__.py
Normal file
0
tests/__init__.py
Normal file
72
tests/test_config.py
Normal file
72
tests/test_config.py
Normal file
@@ -0,0 +1,72 @@
|
||||
from tools.config import parse_vhdl_ls_toml
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import textwrap
|
||||
import pytest
|
||||
|
||||
|
||||
def test_parsing_skips_third_party_libs():
|
||||
content = textwrap.dedent("""
|
||||
[libraries.lib]
|
||||
files = ["src/main.vhd"]
|
||||
|
||||
[libraries.XILINX]
|
||||
files = ["/opt/Xilinx/abc.vhd"]
|
||||
is_third_party = true
|
||||
""")
|
||||
with tempfile.NamedTemporaryFile("w+", suffix=".toml", delete=False) as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
result = parse_vhdl_ls_toml(Path(f.name))
|
||||
|
||||
assert "work" in result
|
||||
assert "XILINX" not in result
|
||||
assert result["work"] == [Path("src/main.vhd")]
|
||||
|
||||
|
||||
def test_parsing_multiple_libraries():
|
||||
content = textwrap.dedent("""
|
||||
[libraries.lib]
|
||||
files = ["src/foo.vhd", "src/bar.vhd"]
|
||||
|
||||
[libraries.myip]
|
||||
files = ["ipcore/top.vhd"]
|
||||
""")
|
||||
with tempfile.NamedTemporaryFile("w+", suffix=".toml", delete=False) as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
result = parse_vhdl_ls_toml(Path(f.name))
|
||||
|
||||
assert "work" in result
|
||||
assert "myip" in result
|
||||
assert result["work"] == [Path("src/foo.vhd"), Path("src/bar.vhd")]
|
||||
assert result["myip"] == [Path("ipcore/top.vhd")]
|
||||
|
||||
|
||||
def test_empty_toml_file():
|
||||
with tempfile.NamedTemporaryFile("w+", suffix=".toml", delete=False) as f:
|
||||
f.write("") # Empty file
|
||||
f.flush()
|
||||
result = parse_vhdl_ls_toml(Path(f.name))
|
||||
|
||||
assert result == {}
|
||||
|
||||
|
||||
def test_missing_file_raises_error():
|
||||
with pytest.raises(FileNotFoundError):
|
||||
parse_vhdl_ls_toml(Path("nonexistent.toml"))
|
||||
|
||||
|
||||
def test_libname_translation_to_work():
|
||||
content = textwrap.dedent("""
|
||||
[libraries.lib]
|
||||
files = ["src/xyz.vhd"]
|
||||
""")
|
||||
with tempfile.NamedTemporaryFile("w+", suffix=".toml", delete=False) as f:
|
||||
f.write(content)
|
||||
f.flush()
|
||||
result = parse_vhdl_ls_toml(Path(f.name))
|
||||
|
||||
assert "work" in result
|
||||
assert "lib" not in result
|
||||
assert result["work"] == [Path("src/xyz.vhd")]
|
47
tests/test_generate_prj.py
Normal file
47
tests/test_generate_prj.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
from tasks.generate_prj import generate_prj
|
||||
|
||||
|
||||
def write_file(path: Path, content: str):
|
||||
path.write_text(content.strip(), encoding="utf-8")
|
||||
|
||||
|
||||
def test_generate_prj_single_lib(tmp_path):
|
||||
cfg_path = tmp_path / "project.cfg"
|
||||
toml_path = tmp_path / "vhdl_ls.toml"
|
||||
prj_path = tmp_path / "working" / "MyProject.prj"
|
||||
|
||||
write_file(cfg_path, "PROJECT = MyProject\nTARGET_PART = dummy\nXILINX = /some/path")
|
||||
write_file(toml_path, """
|
||||
[libraries.lib]
|
||||
files = ["src/main.vhd"]
|
||||
""")
|
||||
|
||||
generate_prj(prj_path, cfg_path, toml_path)
|
||||
|
||||
assert prj_path.exists()
|
||||
content = prj_path.read_text()
|
||||
assert "vhdl work ../src/main.vhd" in content
|
||||
|
||||
|
||||
def test_generate_prj_multiple_libs(tmp_path):
|
||||
cfg_path = tmp_path / "project.cfg"
|
||||
toml_path = tmp_path / "vhdl_ls.toml"
|
||||
prj_path = tmp_path / "working" / "MyProject.prj"
|
||||
|
||||
write_file(cfg_path, "PROJECT = MyProject\nTARGET_PART = dummy\nXILINX = /some/path")
|
||||
write_file(toml_path, """
|
||||
[libraries.lib]
|
||||
files = ["src/A.vhd", "src/B.vhd"]
|
||||
|
||||
[libraries.otherlib]
|
||||
files = ["src/C.vhd"]
|
||||
""")
|
||||
|
||||
generate_prj(prj_path, cfg_path, toml_path)
|
||||
|
||||
content = prj_path.read_text()
|
||||
assert "vhdl work ../src/A.vhd" in content
|
||||
assert "vhdl work ../src/B.vhd" in content
|
||||
assert "vhdl otherlib ../src/C.vhd" in content
|
44
tests/test_generate_scr.py
Normal file
44
tests/test_generate_scr.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from pathlib import Path
|
||||
from tasks.generate_scr import generate_scr
|
||||
|
||||
|
||||
def write_file(path: Path, content: str):
|
||||
path.write_text(content.strip(), encoding="utf-8")
|
||||
|
||||
|
||||
def test_generate_scr_basic(tmp_path):
|
||||
cfg_path = tmp_path / "project.cfg"
|
||||
scr_path = tmp_path / "working" / "MyProject.scr"
|
||||
|
||||
write_file(cfg_path, """
|
||||
PROJECT = MyProject
|
||||
TARGET_PART = xc3s50-4-pq208
|
||||
XILINX = /some/path
|
||||
""")
|
||||
|
||||
generate_scr(scr_path, cfg_path)
|
||||
|
||||
content = scr_path.read_text()
|
||||
assert "-ifn MyProject.prj" in content
|
||||
assert "-ofn MyProject.ngc" in content
|
||||
assert "-top MyProject" in content
|
||||
assert "-p xc3s50-4-pq208" in content
|
||||
|
||||
|
||||
def test_generate_scr_with_top_and_opts(tmp_path):
|
||||
cfg_path = tmp_path / "project.cfg"
|
||||
scr_path = tmp_path / "working" / "MyProject.scr"
|
||||
|
||||
write_file(cfg_path, """
|
||||
PROJECT = MyProject
|
||||
TARGET_PART = xc3s200-5-ft256
|
||||
TOPLEVEL = TopModule
|
||||
XST_OPTS = -opt_mode Speed -opt_level 2
|
||||
XILINX = /some/path
|
||||
""")
|
||||
|
||||
generate_scr(scr_path, cfg_path)
|
||||
|
||||
content = scr_path.read_text()
|
||||
assert "-top TopModule" in content
|
||||
assert "-opt_mode Speed -opt_level 2" in content
|
51
tests/test_project_cfg.py
Normal file
51
tests/test_project_cfg.py
Normal file
@@ -0,0 +1,51 @@
|
||||
from build.tools.config import parse_project_cfg
|
||||
from pathlib import Path
|
||||
import tempfile
|
||||
import textwrap
|
||||
|
||||
|
||||
def test_parse_complex_project_cfg_correctly():
|
||||
cfg = textwrap.dedent("""
|
||||
## Main settings.. ##
|
||||
PROJECT = SpriteChannel
|
||||
TARGET_PART = xc3s1200e-4-fg320
|
||||
XILINX = /opt/Xilinx/14.7/ISE_DS/ISE
|
||||
TOPLEVEL = SpriteChannel
|
||||
CONSTRAINTS = src/SpriteChannel.ucf
|
||||
|
||||
# Sources (should be ignored)
|
||||
VHDSOURCE += src/GenericCounter.vhd
|
||||
VSOURCE += src/something.v
|
||||
VHDTEST += test/SpriteChannel_tb.vhd
|
||||
|
||||
# Options
|
||||
XST_OPTS += -opt_mode Speed
|
||||
XST_OPTS += -opt_level 2
|
||||
MAP_OPTS = -detail -timing -ol high
|
||||
PAR_OPTS = -ol high
|
||||
BITGEN_OPTS = -g StartupClk:JtagClk
|
||||
|
||||
# Programmer
|
||||
PROGRAMMER = digilent
|
||||
""")
|
||||
|
||||
with tempfile.NamedTemporaryFile("w+", suffix=".cfg", delete=False) as f:
|
||||
f.write(cfg)
|
||||
f.flush()
|
||||
result = parse_project_cfg(Path(f.name))
|
||||
|
||||
assert result["PROJECT"] == "SpriteChannel"
|
||||
assert result["TARGET_PART"] == "xc3s1200e-4-fg320"
|
||||
assert result["XILINX"] == "/opt/Xilinx/14.7/ISE_DS/ISE"
|
||||
assert result["TOPLEVEL"] == "SpriteChannel"
|
||||
assert result["CONSTRAINTS"] == "src/SpriteChannel.ucf"
|
||||
assert result["XST_OPTS"] == "-opt_mode Speed -opt_level 2"
|
||||
assert result["MAP_OPTS"] == "-detail -timing -ol high"
|
||||
assert result["PAR_OPTS"] == "-ol high"
|
||||
assert result["BITGEN_OPTS"] == "-g StartupClk:JtagClk"
|
||||
assert result["PROGRAMMER"] == "digilent"
|
||||
|
||||
# Sicherstellen, dass SOURCE-Felder ignoriert wurden
|
||||
assert "VHDSOURCE" not in result
|
||||
assert "VSOURCE" not in result
|
||||
assert "VHDTEST" not in result
|
Reference in New Issue
Block a user