uvmls 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uvmls/__init__.py +3 -0
- uvmls/__main__.py +10 -0
- uvmls/cli.py +201 -0
- uvmls/documents.py +28 -0
- uvmls/elab.py +457 -0
- uvmls/fixes.py +981 -0
- uvmls/formatting.py +225 -0
- uvmls/indexer.py +2060 -0
- uvmls/lints.py +528 -0
- uvmls/mcp.py +1247 -0
- uvmls/model.py +363 -0
- uvmls/naturaldocs.py +123 -0
- uvmls/navigation.py +1025 -0
- uvmls/project.py +528 -0
- uvmls/sarif.py +111 -0
- uvmls/server.py +1533 -0
- uvmls/shim/uvm_macros.svh +396 -0
- uvmls/signatures.py +130 -0
- uvmls/third_party/.rules.verible_lint +67 -0
- uvmls/third_party/uvm-1.2/LICENSE.txt +201 -0
- uvmls/third_party/uvm-1.2/NOTICE.txt +48 -0
- uvmls/third_party/uvm-1.2/README.md +20 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_barrier.svh +209 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_base.svh +111 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_bottomup_phase.svh +112 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_callback.svh +1198 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_cmdline_processor.svh +461 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_common_phases.svh +451 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_comparer.svh +422 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_component.svh +3638 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_config_db.svh +410 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_coreservice.svh +223 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_domain.svh +218 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_event.svh +394 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_event_callback.svh +90 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_factory.svh +1789 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_globals.svh +564 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_heartbeat.svh +341 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_links.svh +370 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_misc.svh +753 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_object.svh +1330 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_object_globals.svh +657 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_objection.svh +1453 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_packer.svh +1037 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_phase.svh +2253 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_pool.svh +347 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_port_base.svh +792 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_printer.svh +1231 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_queue.svh +203 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_recorder.svh +1140 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_registry.svh +380 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_report_catcher.svh +711 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_report_handler.svh +799 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_report_message.svh +939 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_report_object.svh +658 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_report_server.svh +921 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_resource.svh +1694 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_resource_db.svh +399 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_resource_specializations.svh +170 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_root.svh +1072 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_runtime_phases.svh +555 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_spell_chkr.svh +203 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_task_phase.svh +161 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_topdown_phase.svh +114 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_tr_database.svh +432 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_tr_stream.svh +591 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_transaction.svh +780 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_traversal.svh +288 -0
- uvmls/third_party/uvm-1.2/src/base/uvm_version.svh +37 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_agent.svh +135 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_algorithmic_comparator.svh +134 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_comps.svh +36 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_driver.svh +88 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_env.svh +53 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_in_order_comparator.svh +259 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_monitor.svh +53 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_pair.svh +170 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_policies.svh +141 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_push_driver.svh +96 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_random_stimulus.svh +131 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_scoreboard.svh +55 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_subscriber.svh +67 -0
- uvmls/third_party/uvm-1.2/src/comps/uvm_test.svh +81 -0
- uvmls/third_party/uvm-1.2/src/dap/uvm_dap.svh +34 -0
- uvmls/third_party/uvm-1.2/src/dap/uvm_get_to_lock_dap.svh +154 -0
- uvmls/third_party/uvm-1.2/src/dap/uvm_set_before_get_dap.svh +184 -0
- uvmls/third_party/uvm-1.2/src/dap/uvm_set_get_dap_base.svh +83 -0
- uvmls/third_party/uvm-1.2/src/dap/uvm_simple_lock_dap.svh +178 -0
- uvmls/third_party/uvm-1.2/src/deprecated/readme.important +35 -0
- uvmls/third_party/uvm-1.2/src/deprecated/uvm_resource_converter.svh +199 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_common.c +50 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_dpi.cc +43 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_dpi.h +65 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_dpi.svh +42 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_hdl.c +36 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_hdl.svh +163 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_hdl_inca.c +677 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_hdl_questa.c +406 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_hdl_vcs.c +426 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_regex.cc +256 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_regex.svh +88 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_svcmd_dpi.c +134 -0
- uvmls/third_party/uvm-1.2/src/dpi/uvm_svcmd_dpi.svh +65 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_callback_defines.svh +300 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_deprecated_defines.svh +250 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_global_defines.svh +59 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_message_defines.svh +537 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_object_defines.svh +3814 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_phase_defines.svh +129 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_printer_defines.svh +422 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_reg_defines.svh +68 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_sequence_defines.svh +455 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_tlm_defines.svh +616 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_undefineall.svh +85 -0
- uvmls/third_party/uvm-1.2/src/macros/uvm_version_defines.svh +149 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_mem_access_seq.svh +307 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_mem_walk_seq.svh +299 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_reg_access_seq.svh +365 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_reg_bit_bash_seq.svh +302 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_reg_hw_reset_seq.svh +171 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_reg_mem_built_in_seq.svh +138 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_reg_mem_hdl_paths_seq.svh +174 -0
- uvmls/third_party/uvm-1.2/src/reg/sequences/uvm_reg_mem_shared_access_seq.svh +485 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_mem.svh +2409 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_mem_mam.svh +1017 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg.svh +3101 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_adapter.svh +253 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_backdoor.svh +347 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_block.svh +2271 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_cbs.svh +529 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_field.svh +2012 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_fifo.svh +310 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_file.svh +500 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_indirect.svh +329 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_item.svh +315 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_map.svh +2224 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_model.svh +442 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_predictor.svh +264 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_reg_sequence.svh +547 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_vreg.svh +1553 -0
- uvmls/third_party/uvm-1.2/src/reg/uvm_vreg_field.svh +1004 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_push_sequencer.svh +84 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_seq.svh +39 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequence.svh +147 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequence_base.svh +1404 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequence_builtin.svh +299 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequence_item.svh +497 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequence_library.svh +812 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequencer.svh +346 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequencer_analysis_fifo.svh +38 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequencer_base.svh +1774 -0
- uvmls/third_party/uvm-1.2/src/seq/uvm_sequencer_param_base.svh +459 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_analysis_port.svh +155 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_exports.svh +259 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_imps.svh +316 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_ports.svh +262 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_sqr_connections.svh +83 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_sqr_ifs.svh +252 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_tlm.svh +39 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_tlm_fifo_base.svh +252 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_tlm_fifos.svh +238 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_tlm_ifs.svh +218 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_tlm_imps.svh +228 -0
- uvmls/third_party/uvm-1.2/src/tlm1/uvm_tlm_req_rsp.svh +348 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2.svh +29 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_defines.svh +44 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_exports.svh +64 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_generic_payload.svh +1052 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_ifs.svh +177 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_imps.svh +202 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_ports.svh +74 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_sockets.svh +433 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_sockets_base.svh +194 -0
- uvmls/third_party/uvm-1.2/src/tlm2/uvm_tlm2_time.svh +332 -0
- uvmls/third_party/uvm-1.2/src/uvm.sv +24 -0
- uvmls/third_party/uvm-1.2/src/uvm_macros.svh +81 -0
- uvmls/third_party/uvm-1.2/src/uvm_pkg.sv +42 -0
- uvmls/uvm.py +168 -0
- uvmls/views.py +737 -0
- uvmls/workspace.py +1132 -0
- uvmls-0.1.0.dist-info/METADATA +63 -0
- uvmls-0.1.0.dist-info/RECORD +187 -0
- uvmls-0.1.0.dist-info/WHEEL +5 -0
- uvmls-0.1.0.dist-info/entry_points.txt +2 -0
- uvmls-0.1.0.dist-info/licenses/LICENSE +201 -0
- uvmls-0.1.0.dist-info/licenses/NOTICE +46 -0
- uvmls-0.1.0.dist-info/top_level.txt +1 -0
uvmls/__init__.py
ADDED
uvmls/__main__.py
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
|
|
3
|
+
if len(sys.argv) > 1 and sys.argv[1] == "elab-worker":
|
|
4
|
+
from .elab import worker as main
|
|
5
|
+
elif len(sys.argv) > 1 and sys.argv[1] in ("graph", "topology", "configdb", "lint", "stats", "elab", "mcp"):
|
|
6
|
+
from .cli import main
|
|
7
|
+
else:
|
|
8
|
+
from .server import main
|
|
9
|
+
|
|
10
|
+
main()
|
uvmls/cli.py
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""Command line access to the index, for scripts and CI.
|
|
2
|
+
|
|
3
|
+
python -m uvmls lint -f tb.f # exit 1 if any warning/error
|
|
4
|
+
python -m uvmls elab -f tb.f [--top T] # full slang elaboration; exit 1 if any error
|
|
5
|
+
python -m uvmls graph -f tb.f -o graph.json
|
|
6
|
+
python -m uvmls topology -f tb.f --test my_test
|
|
7
|
+
python -m uvmls configdb -f tb.f
|
|
8
|
+
python -m uvmls stats [DIR]
|
|
9
|
+
python -m uvmls mcp [DIR] -f tb.f # MCP server over stdio (see mcp.py)
|
|
10
|
+
|
|
11
|
+
The UVM library is --uvm-home or $UVM_HOME, else a uvm_pkg.sv the project already
|
|
12
|
+
compiles, else the bundled Accellera UVM 1.2 (--no-bundled-uvm: the built-in model).
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
import argparse
|
|
18
|
+
import json
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
from . import __version__
|
|
23
|
+
from .elab import displayed, elaborate, request_for, skip_reason, uvm_label
|
|
24
|
+
from .lints import lint
|
|
25
|
+
from .model import Diag, Range
|
|
26
|
+
from .project import ProjectConfig, build_source_set
|
|
27
|
+
from .sarif import write_log
|
|
28
|
+
from .views import class_graph, config_db_report, topology
|
|
29
|
+
from .workspace import Workspace
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _workspace(args, index: bool = True, config: ProjectConfig | None = None) -> Workspace:
|
|
33
|
+
"""index=False only works out the sources (all `elab` needs with a filelist); `config` replaces
|
|
34
|
+
the one the flags describe."""
|
|
35
|
+
root = os.path.abspath(args.dir)
|
|
36
|
+
cfg = config or ProjectConfig(workspace_roots=[root],
|
|
37
|
+
filelists=[os.path.abspath(f) for f in args.filelist],
|
|
38
|
+
include_dirs=[os.path.abspath(d) for d in args.incdir],
|
|
39
|
+
defines=dict(d.partition("=")[::2] for d in args.define),
|
|
40
|
+
uvm_home=args.uvm_home, env_uvm_home=os.environ.get("UVM_HOME"),
|
|
41
|
+
bundled_uvm=not args.no_bundled_uvm, exclude=list(args.exclude))
|
|
42
|
+
ws = Workspace()
|
|
43
|
+
if index:
|
|
44
|
+
ws.configure(cfg)
|
|
45
|
+
else:
|
|
46
|
+
ws.config, ws.sources = cfg, build_source_set(cfg)
|
|
47
|
+
for w in ws.sources.warnings:
|
|
48
|
+
print(f"warning: {w}", file=sys.stderr)
|
|
49
|
+
return ws
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def _print_tree(node, depth=0, out=sys.stdout):
|
|
53
|
+
extra = []
|
|
54
|
+
if node.get("overriddenFrom"):
|
|
55
|
+
extra.append(f"override of {node['overriddenFrom']}")
|
|
56
|
+
if node.get("conditional"):
|
|
57
|
+
extra.append(f"if {node['condition']}")
|
|
58
|
+
tail = f" ({'; '.join(extra)})" if extra else ""
|
|
59
|
+
out.write(f"{' ' * depth}{node['name']} : {node['type']} [{node['role']}]{tail}\n")
|
|
60
|
+
for c in node["children"]:
|
|
61
|
+
_print_tree(c, depth + 1, out)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _elab(ws: Workspace, args) -> int:
|
|
65
|
+
"""Exit status: 0 clean, 1 errors, 2 not elaborated (skipped or failed)."""
|
|
66
|
+
reason = skip_reason(ws)
|
|
67
|
+
if reason:
|
|
68
|
+
if args.sarif:
|
|
69
|
+
write_log(args.sarif, args.dir, [])
|
|
70
|
+
print(f"elaboration skipped: {reason}", file=sys.stderr)
|
|
71
|
+
return 2
|
|
72
|
+
request = request_for(ws, tops=args.top)
|
|
73
|
+
request["listAll"] = bool(args.sarif) # a code-scanning report must not drop findings past the display limits
|
|
74
|
+
result = elaborate(request)
|
|
75
|
+
if args.sarif:
|
|
76
|
+
write_log(args.sarif, args.dir, [Diag(
|
|
77
|
+
Range(d["file"] or "", d["line"], d["col"], d["endLine"], d["endCol"]),
|
|
78
|
+
d["message"], d["severity"], d["code"], "slang-elab") for d in result["diagnostics"]],
|
|
79
|
+
fallback=args.filelist[0] if args.filelist else None)
|
|
80
|
+
listed, more = displayed(result["diagnostics"]) # the console and --json keep their limits
|
|
81
|
+
result = {**result, "diagnostics": listed, "counts": {**result["counts"], "omitted": result["counts"]["omitted"] + more}}
|
|
82
|
+
out = sys.stderr if args.sarif == "-" else sys.stdout
|
|
83
|
+
if args.json and args.sarif != "-":
|
|
84
|
+
print(json.dumps(result, indent=1))
|
|
85
|
+
elif not args.json:
|
|
86
|
+
for d in result["diagnostics"]:
|
|
87
|
+
where = f"{os.path.relpath(d['file'])}:{d['line'] + 1}:{d['col'] + 1}: " if d["file"] else ""
|
|
88
|
+
print(f"{where}{d['severity']}: {d['message']} [{d['code']}]", file=out)
|
|
89
|
+
c = result["counts"]
|
|
90
|
+
notes = [f"top: {', '.join(result['tops']) or 'none'}", uvm_label(ws.sources)]
|
|
91
|
+
if c.get("omitted"):
|
|
92
|
+
notes.append(f"{c['omitted']} more not listed")
|
|
93
|
+
if c.get("libraryErrors"):
|
|
94
|
+
notes.append(f"{c['libraryErrors']} error(s) the UVM library reports on its own not shown")
|
|
95
|
+
print(f"{c['errors']} error(s), {c['warnings']} warning(s) in {result['seconds']}s "
|
|
96
|
+
f"({'; '.join(notes)})", file=sys.stderr)
|
|
97
|
+
if result["error"]:
|
|
98
|
+
print(f"elaboration failed: {result['error']}", file=sys.stderr)
|
|
99
|
+
return 2
|
|
100
|
+
return 1 if result["counts"]["errors"] else 0
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def findings(ws: Workspace) -> list[Diag]:
|
|
104
|
+
"""Lint findings and parse errors or warnings of the user files, each once, in file order."""
|
|
105
|
+
diags = [d for d in ws.user_diagnostics() if d.severity in ("error", "warning")]
|
|
106
|
+
for ds in lint(ws).values():
|
|
107
|
+
diags += ds
|
|
108
|
+
seen = set()
|
|
109
|
+
uniq = []
|
|
110
|
+
for d in sorted(diags, key=lambda d: (d.range.path, d.range.line, d.range.col)):
|
|
111
|
+
key = (d.range.path, d.range.line, d.range.col, d.message)
|
|
112
|
+
if key not in seen:
|
|
113
|
+
seen.add(key)
|
|
114
|
+
uniq.append(d)
|
|
115
|
+
return uniq
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def pyslang_version() -> str:
|
|
119
|
+
try:
|
|
120
|
+
from importlib.metadata import version
|
|
121
|
+
return version("pyslang")
|
|
122
|
+
except Exception: # not installed as a distribution
|
|
123
|
+
return "unknown"
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def main(argv=None):
|
|
127
|
+
ap = argparse.ArgumentParser(prog="python -m uvmls", description=__doc__,
|
|
128
|
+
formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
129
|
+
ap.add_argument("--version", action="version", version=f"uvmls {__version__} (pyslang {pyslang_version()})")
|
|
130
|
+
ap.add_argument("command", choices=["graph", "topology", "configdb", "lint", "stats", "elab", "mcp"])
|
|
131
|
+
ap.add_argument("dir", nargs="?", default=".", help="workspace directory (default: .)")
|
|
132
|
+
ap.add_argument("-f", dest="filelist", action="append", default=[], help="filelist (.f)")
|
|
133
|
+
ap.add_argument("-I", "--incdir", action="append", default=[], help="include directory")
|
|
134
|
+
ap.add_argument("-D", "--define", action="append", default=[], help="macro define NAME[=VALUE]")
|
|
135
|
+
ap.add_argument("--uvm-home", help="UVM installation (falls back to $UVM_HOME)")
|
|
136
|
+
ap.add_argument("--no-bundled-uvm", action="store_true",
|
|
137
|
+
help="use the built-in UVM model instead of the bundled UVM 1.2")
|
|
138
|
+
ap.add_argument("--exclude", action="append", default=[], metavar="GLOB",
|
|
139
|
+
help="leave out files matching this glob in discovery mode (as uvm.exclude)")
|
|
140
|
+
ap.add_argument("--test", help="test class for topology")
|
|
141
|
+
ap.add_argument("--top", action="append", default=[], help="top module for elab (default: slang picks)")
|
|
142
|
+
ap.add_argument("--json", action="store_true", help="print JSON instead of text")
|
|
143
|
+
ap.add_argument("--sarif", metavar="FILE", help="write lint or elab diagnostics as SARIF (use - for stdout)")
|
|
144
|
+
ap.add_argument("-o", "--output", help="write JSON to this file")
|
|
145
|
+
# Intermixed: `lint --test t DIR -f x.f` has the positional after an option, which argparse before
|
|
146
|
+
# Python 3.12 would otherwise take as absent and reject DIR as unrecognized.
|
|
147
|
+
args = ap.parse_intermixed_args(argv)
|
|
148
|
+
if args.sarif and args.command not in ("lint", "elab"):
|
|
149
|
+
ap.error("--sarif is only available for lint and elab")
|
|
150
|
+
if args.command == "mcp":
|
|
151
|
+
from .mcp import serve
|
|
152
|
+
sys.exit(serve(args))
|
|
153
|
+
# Without a filelist, elab needs the index to spot several testbenches in one tree.
|
|
154
|
+
ws = _workspace(args, index=not (args.command == "elab" and args.filelist))
|
|
155
|
+
|
|
156
|
+
if args.command == "elab":
|
|
157
|
+
sys.exit(_elab(ws, args))
|
|
158
|
+
if args.command == "stats":
|
|
159
|
+
data = ws.stats()
|
|
160
|
+
elif args.command == "graph":
|
|
161
|
+
data = class_graph(ws)
|
|
162
|
+
elif args.command == "topology":
|
|
163
|
+
data = topology(ws, args.test)
|
|
164
|
+
elif args.command == "configdb":
|
|
165
|
+
data = config_db_report(ws)
|
|
166
|
+
else:
|
|
167
|
+
uniq = findings(ws)
|
|
168
|
+
if args.sarif:
|
|
169
|
+
write_log(args.sarif, args.dir, uniq)
|
|
170
|
+
out = sys.stderr if args.sarif == "-" else sys.stdout
|
|
171
|
+
if args.json and args.sarif != "-":
|
|
172
|
+
print(json.dumps([{"file": d.range.path, "line": d.range.line + 1, "col": d.range.col + 1,
|
|
173
|
+
"severity": d.severity, "code": d.code, "message": d.message}
|
|
174
|
+
for d in uniq], indent=2))
|
|
175
|
+
elif not args.json:
|
|
176
|
+
for d in uniq:
|
|
177
|
+
rel = os.path.relpath(d.range.path)
|
|
178
|
+
print(f"{rel}:{d.range.line + 1}:{d.range.col + 1}: {d.severity}: {d.message} [{d.code}]", file=out)
|
|
179
|
+
print(f"{len(uniq)} problem(s)", file=sys.stderr)
|
|
180
|
+
sys.exit(1 if any(d.severity in ("error", "warning") for d in uniq) else 0)
|
|
181
|
+
|
|
182
|
+
if args.output:
|
|
183
|
+
with open(args.output, "w") as f:
|
|
184
|
+
json.dump(data, f, indent=1)
|
|
185
|
+
elif args.json or args.command in ("graph", "stats"):
|
|
186
|
+
print(json.dumps(data, indent=1))
|
|
187
|
+
elif args.command == "topology":
|
|
188
|
+
print(f"test: {data['test']} (tests: {', '.join(data['tests'])})")
|
|
189
|
+
if data["root"]:
|
|
190
|
+
_print_tree(data["root"])
|
|
191
|
+
for c in data["connections"]:
|
|
192
|
+
print(f" {c['source']}.{c['sourcePort']} -> {c['target']}.{c['targetPort']}"
|
|
193
|
+
+ (" (alias)" if c["kind"] == "alias" else ""))
|
|
194
|
+
elif args.command == "configdb":
|
|
195
|
+
for row in data["fields"]:
|
|
196
|
+
print(f"{row['field']:24} {row['status']:14} types={', '.join(row['types'])} "
|
|
197
|
+
f"sets={len(row['sets'])} gets={len(row['gets'])}")
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
if __name__ == "__main__":
|
|
201
|
+
main()
|
uvmls/documents.py
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""LSP documents use CR/LF line endings, including when applying incremental changes."""
|
|
2
|
+
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
from pygls.workspace import Workspace as PyglsWorkspace
|
|
6
|
+
from pygls.workspace.text_document import TextDocument as PyglsTextDocument
|
|
7
|
+
|
|
8
|
+
LINE_RE = re.compile(r"[^\r\n]*(?:\r\n|\r|\n)|[^\r\n]+$")
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class TextDocument(PyglsTextDocument):
|
|
12
|
+
@property
|
|
13
|
+
def source(self) -> str:
|
|
14
|
+
if self._source is None and self.path is not None:
|
|
15
|
+
with open(self.path, encoding="utf-8", newline="") as f:
|
|
16
|
+
return f.read()
|
|
17
|
+
return self._source or ""
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def lines(self) -> tuple[str, ...]:
|
|
21
|
+
# str.splitlines also splits page breaks and Unicode separators, unlike LSP and slang.
|
|
22
|
+
return tuple(LINE_RE.findall(self.source))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Workspace(PyglsWorkspace):
|
|
26
|
+
def _create_text_document(self, doc_uri, source=None, version=None, language_id=None):
|
|
27
|
+
return TextDocument(doc_uri, source=source, version=version, language_id=language_id,
|
|
28
|
+
sync_kind=self._sync_kind, position_codec=self._position_codec)
|