From 6e744dea9e227ecaffb714a14f3e5f9a556252bd Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 13:27:43 +0100 Subject: [PATCH 01/19] Added verisocks.utils module to Python API --- python/verisocks/utils.py | 116 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 python/verisocks/utils.py diff --git a/python/verisocks/utils.py b/python/verisocks/utils.py new file mode 100644 index 0000000..d902916 --- /dev/null +++ b/python/verisocks/utils.py @@ -0,0 +1,116 @@ +import subprocess +import os.path +import shutil +import socket +import logging + + +def find_free_port(): + """Find a free port on localhost + + The implementation for this function is not very elegant, but it does the + job... It uses the property of :py:meth:`socket.socket.bind` method to bind + the socket to a randomly-assigned free port when provided a :code:`('', 0)` + address argument. Using :py:meth:`socket.socket.getsockname` is then used + to retrieve the corresponding port number. Since the bound socket is closed + within the function, it is assumed that the same port number should also be + free again; this is where the weakness of this method lies, since race + conditions cannot be fully excluded. + """ + with socket.socket() as s: + s.bind(('', 0)) + retval = s.getsockname()[1] + return retval + + +def _format_path(cwd, path): + if os.path.isabs(path): + return path + return os.path.abspath(os.path.join(cwd, path)) + + +def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, + ivl_exec=None, ivl_args=[], vvp_exec=None, vvp_args=[], + capture_output=True): + """Set up Icarus simulation by elaborating the design with :code:`iverilog` + and launching the simulation with :code:`vvp`. + + Args: + cwd (str): Reference path to be used for all paths provided as relative + paths. Default = "." + vpi_libpath (str): Path to the compiled Verisocks VPI library (absolute + path). + src_files (str): Paths to all (verilog) source files to use for the + simulation. All files have to be added as separate arguments. + vvp_filepath (str): Path to the elaborated VVP file (iverilog output). + If None (default), the sim.vvp will be used. The path is relative + to the current directory. + ivl_exec (str): Path to :code:`iverilog` executable (absolute path). If + None (default), it is assumed to be defined in the system path. + ivl_args (list(str)): Arguments to :code:`iverilog` executable. + Default=[] (no extra arguments). + vvp_exec (str): Path to :code:`vvp` executable (absolute path). If None + (default), it is assumed to be defined in the system path. + vvp_args (list(str)): Arguments to :code:`vvp` executable. Default=[]. + capture_output (bool): Defines if stdout and stderr output are + "captured" (i.e. not visible). + + Returns: + subprocess.Popen + """ + + vpi_libpath = _format_path(cwd, vpi_libpath) + if not os.path.isfile(vpi_libpath): + raise FileNotFoundError(f"Could not find {vpi_libpath}") + + src_file_paths = [] + for src_file in src_files: + src_file_path = _format_path(cwd, src_file) + if not os.path.isfile(src_file_path): + raise FileNotFoundError(f"File {src_file_path} not found") + src_file_paths.append(src_file_path) + + if vvp_filepath: + vvp_outfile = _format_path(cwd, vvp_filepath) + else: + vvp_outfile = _format_path(cwd, "sim.vvp") + + # Elaboration with iverilog + if ivl_exec: + ivl_cmd = [_format_path(cwd, ivl_exec)] + else: + ivl_cmd = [shutil.which("iverilog")] + + ivl_cmd += [ + "-o", vvp_outfile, + "-Wall", + *ivl_args, + *src_file_paths + ] + subprocess.check_call(ivl_cmd) + + # Simulation with vvp + if vvp_exec: + vvp_cmd = [_format_path(cwd, vvp_exec)] + else: + vvp_cmd = [shutil.which("vvp")] + + vvp_cmd += [ + "-lvvp.log", + "-m", vpi_libpath, + *vvp_args, + vvp_outfile, + "-fst" + ] + + if capture_output: + pop = subprocess.Popen( + vvp_cmd, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL + ) + else: + pop = subprocess.Popen(vvp_cmd) + + logging.info(f"Launched Icarus with PID {pop.pid}") + return pop From 104aa5a10ecfa5a42c2ee167ceb7d208e92a1db9 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 13:28:19 +0100 Subject: [PATCH 02/19] Corrected SPI master example for standalone execution --- examples/spi_master/test_spi_master.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/spi_master/test_spi_master.py b/examples/spi_master/test_spi_master.py index 2e834db..a8fd2e0 100644 --- a/examples/spi_master/test_spi_master.py +++ b/examples/spi_master/test_spi_master.py @@ -175,9 +175,13 @@ def test_spi_master_simple(vs): if __name__ == "__main__": - str_port = input("Port number: ") - - with Verisocks(HOST, int(str_port)) as vs_cli: + setup_iverilog( + "spi_master_tb", + "spi_master.v", + "spi_slave.v", + "spi_master_tb.v" + ) + with Verisocks(HOST, PORT) as vs_cli: vs_cli.connect() test_spi_master_simple(vs_cli) vs_cli.finish() From 6a596c0ee1418ae420cc15e9c6362e5782fd3519 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 13:30:03 +0100 Subject: [PATCH 03/19] Added autodoc for verisocks.utils --- docs/src/python_client.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/src/python_client.rst b/docs/src/python_client.rst index 4cdc8df..188192b 100644 --- a/docs/src/python_client.rst +++ b/docs/src/python_client.rst @@ -42,3 +42,13 @@ Python client API documentation .. automodule:: verisocks.verisocks :members: + +Miscellaneous utilitaries +************************* + +The module :py:mod:`verisocks.utils` is a collection of miscellaneous +utilitaries and helper functions to ease setting up simulations using +Verisocks. + +.. automodule:: verisocks.utils + :members: From 37a4c9dd4755768f28726d73ebc7aef8b3c59d3f Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 13:30:11 +0100 Subject: [PATCH 04/19] Updated release notes --- docs/src/release_notes.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/src/release_notes.rst b/docs/src/release_notes.rst index 9fbbc3f..8ca47c3 100644 --- a/docs/src/release_notes.rst +++ b/docs/src/release_notes.rst @@ -9,6 +9,16 @@ version numbering system follows the `semantic versioning `_ principles. +1.1.0 - Ongoing +*************** + +* Added :py:mod:`verisocks.utils` Python utilitary functions, including + documentation. +* Corrected *SPI master* example for standalone execution. +* Added a minimalistic *Hello world* example, working both for standalone + execution or with pytest. + + 1.0.0 - 2024-01-04 ****************** From cce94a46cca04a667ada085cca29d845b4838040 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 13:30:48 +0100 Subject: [PATCH 05/19] Adjusted doc conf.py for pre-release 1.1.0 --- docs/conf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 5df6134..05ef179 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,8 +9,8 @@ project = 'Verisocks' copyright = '2023, Jérémie Chabloz' author = 'Jérémie Chabloz' -version = '1.0.0' -release = '1.0.0' +version = '1.1.0-pre' +release = '1.1.0' # -- General configuration --------------------------------------------------- # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration From 794eda0dee05b2fdc8df3a065a2e2f6bc2da4bd4 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 13:31:14 +0100 Subject: [PATCH 06/19] Added Hello World example --- examples/hello_world/hello_world_tb.v | 35 ++++++++++++++ examples/hello_world/pytest.ini | 5 ++ examples/hello_world/test_hello_world.py | 60 ++++++++++++++++++++++++ 3 files changed, 100 insertions(+) create mode 100644 examples/hello_world/hello_world_tb.v create mode 100644 examples/hello_world/pytest.ini create mode 100644 examples/hello_world/test_hello_world.py diff --git a/examples/hello_world/hello_world_tb.v b/examples/hello_world/hello_world_tb.v new file mode 100644 index 0000000..1c130f8 --- /dev/null +++ b/examples/hello_world/hello_world_tb.v @@ -0,0 +1,35 @@ +/****************************************************************************** +File: hello_world_tb.v +Description: Hello world example testbench for Verisocks +******************************************************************************/ + +/******************************************************************************* +Includes and misc definitions +*******************************************************************************/ +`timescale 1us/10ps //Time scale definitions + +`ifndef VS_NUM_PORT +`define VS_NUM_PORT 5100 +`endif + +`ifndef VS_TIMEOUT +`define VS_TIMEOUT 120 +`endif + +/******************************************************************************* +Testbench +*******************************************************************************/ +module hello_world_tb(); + + initial begin + + /* Launch Verisocks server after other initialization */ + $verisocks_init(`VS_NUM_PORT, `VS_TIMEOUT); + + /* Make sure that the simulation finishes after a while... */ + #1000 + $finish(0); + + end + +endmodule diff --git a/examples/hello_world/pytest.ini b/examples/hello_world/pytest.ini new file mode 100644 index 0000000..fce50b3 --- /dev/null +++ b/examples/hello_world/pytest.ini @@ -0,0 +1,5 @@ +[pytest] +log_file = pytest.log +log_file_level = DEBUG +log_file_format = [%(levelname)s][%(module)s] %(asctime)s - %(message)s +log_file_date_format = %Y-%m-%d %H:%M:%S diff --git a/examples/hello_world/test_hello_world.py b/examples/hello_world/test_hello_world.py new file mode 100644 index 0000000..9af8928 --- /dev/null +++ b/examples/hello_world/test_hello_world.py @@ -0,0 +1,60 @@ +from verisocks.verisocks import Verisocks +from verisocks.utils import setup_sim, find_free_port +import socket +import time +import pytest +import logging +import os.path + + +HOST = socket.gethostbyname("localhost") +PORT = find_free_port() +VS_TIMEOUT = 10 +LIBVPI = "../../build/verisocks.vpi" +CONNECT_DELAY = 0.1 + + +def setup_test(): + setup_sim( + LIBVPI, + "hello_world_tb.v", + cwd=os.path.dirname(__file__), + ivl_args=[ + f"-DVS_NUM_PORT={PORT}", + f"-DVS_TIMEOUT={VS_TIMEOUT}" + ] + ) + time.sleep(CONNECT_DELAY) + + +@pytest.fixture +def vs(): + setup_test() + _vs = Verisocks(HOST, PORT) + _vs.connect() + yield _vs + # Teardown + try: + _vs.finish() + except ConnectionError: + logging.warning("Connection error - Finish command not possible") + _vs.close() + + +def test_hello_world(vs): + + assert vs._connected + answer = vs.send_cmd("get", sel="sim_info") + assert answer['type'] == "result" + print(f"Simulator: {answer['product']}") + print(f"Version: {answer['version']}") + + answer = vs.send_cmd("info", value="Hello World!") + assert answer['type'] == "ack" + + +if __name__ == "__main__": + + setup_test() + with Verisocks(HOST, PORT) as vs_cli: + test_hello_world(vs_cli) From eef962c2986ca0b1dc64cfa3eafdbf17644474cc Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 13:32:59 +0100 Subject: [PATCH 07/19] Python API version set to 1.1.0 --- python/verisocks/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/verisocks/__init__.py b/python/verisocks/__init__.py index ef1a229..18199b9 100644 --- a/python/verisocks/__init__.py +++ b/python/verisocks/__init__.py @@ -1,4 +1,4 @@ """Verisocks Python client API """ -__version__ = "1.0.0" +__version__ = "1.1.0" From 4e2bd024ec214d81406589000a61a7a9479e472c Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 14:05:30 +0100 Subject: [PATCH 08/19] Updated setup_sim function to add configurable vvp log path --- python/verisocks/utils.py | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/python/verisocks/utils.py b/python/verisocks/utils.py index d902916..f92715a 100644 --- a/python/verisocks/utils.py +++ b/python/verisocks/utils.py @@ -30,21 +30,21 @@ def _format_path(cwd, path): def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, - ivl_exec=None, ivl_args=[], vvp_exec=None, vvp_args=[], - capture_output=True): + vvp_logpath="vvp.log", ivl_exec=None, ivl_args=[], vvp_exec=None, + vvp_args=[], vvp_postargs=[], capture_output=True): """Set up Icarus simulation by elaborating the design with :code:`iverilog` and launching the simulation with :code:`vvp`. Args: cwd (str): Reference path to be used for all paths provided as relative paths. Default = "." - vpi_libpath (str): Path to the compiled Verisocks VPI library (absolute - path). + vpi_libpath (str): Path to the compiled Verisocks VPI library. src_files (str): Paths to all (verilog) source files to use for the simulation. All files have to be added as separate arguments. vvp_filepath (str): Path to the elaborated VVP file (iverilog output). - If None (default), the sim.vvp will be used. The path is relative - to the current directory. + If None (default), "sim.vvp" will be used. + vvp_logpath (str): Path to a simulation logfile. Default="vvp.log". If + None, no logfile shall be created. ivl_exec (str): Path to :code:`iverilog` executable (absolute path). If None (default), it is assumed to be defined in the system path. ivl_args (list(str)): Arguments to :code:`iverilog` executable. @@ -52,8 +52,11 @@ def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, vvp_exec (str): Path to :code:`vvp` executable (absolute path). If None (default), it is assumed to be defined in the system path. vvp_args (list(str)): Arguments to :code:`vvp` executable. Default=[]. - capture_output (bool): Defines if stdout and stderr output are - "captured" (i.e. not visible). + vvp_postargs (list(str)): (Post-)arguments to :code:`vvp` executable. + Default=[]. In order to dump waveforms to an FST file, this should + be configured as ["-fst"]. + capture_output (bool): Defines if stdout and stderr output + are "captured" (i.e. not visible). Returns: subprocess.Popen @@ -95,13 +98,16 @@ def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, else: vvp_cmd = [shutil.which("vvp")] + if vvp_logpath: + vvp_cmd += ["-l" + _format_path(cwd, vvp_logpath)] + vvp_cmd += [ - "-lvvp.log", "-m", vpi_libpath, *vvp_args, vvp_outfile, - "-fst" + *vvp_postargs ] + print(vvp_cmd) if capture_output: pop = subprocess.Popen( From ea0b3a617501f914cd6ebee255b5cad4ee7599fb Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 15:24:55 +0100 Subject: [PATCH 09/19] Added README for Hello World example --- examples/hello_world/README.md | 50 ++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 examples/hello_world/README.md diff --git a/examples/hello_world/README.md b/examples/hello_world/README.md new file mode 100644 index 0000000..3e759a7 --- /dev/null +++ b/examples/hello_world/README.md @@ -0,0 +1,50 @@ +# Verisocks example - Hello World + +## Introduction + +This example shows how to use Verisocks with a minimalistic test case. The test +does nothing except asking Verisocks for the simulator name and version and +then send an "Hello World!" string to the simulator using the `info` command of +the TCP protocol. + +This example uses the helper function `setup_sim()` in order to easily set up +the simulation. + +## Files + +The example folder contains the following files: + +* [hello_world_tb.v](hello_world_tb.v): Top verilog testbench +* [test_hello_world.py](test_hello_world.py): Verisocks Python testbench file + +## Running the example + +This example can be run by directly executing the Python file or by using +[`pytest`](https://docs.pytest.org). + +### Standalone execution + +Simply run the test script: +```sh +python test_hello_world.py +``` + +The results of the test script execution can be checked from the content of the +`vvp.log` file, which should look like this: + +```log +INFO [Verisocks]: Server address: 127.0.0.1 +INFO [Verisocks]: Port: 44041 +INFO [Verisocks]: Connected to localhost +INFO [Verisocks]: Command "get(sel=sim_info)" received. +INFO [Verisocks]: Command "info" received. +INFO [Verisocks]: Hello World! +INFO [Verisocks]: Command "finish" received. Terminating simulation... +INFO [Verisocks]: Returning control to simulator +``` + +### Using pytest + +If you already have it installed, simply run `pytest` from within the SPI +master example directory or from a parent directory. +Otherwise, follow [installation instruction](https://docs.pytest.org/en/latest/getting-started.html#install-pytest). From 803ff19557ca253daed88bace956fcb91148102d Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 15:25:10 +0100 Subject: [PATCH 10/19] Update README for SPI master example --- examples/spi_master/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/examples/spi_master/README.md b/examples/spi_master/README.md index 23b5ca1..19f5388 100644 --- a/examples/spi_master/README.md +++ b/examples/spi_master/README.md @@ -66,3 +66,21 @@ def send_spi(vs, tx_buffer): rx_buffer = answer['value'] return rx_buffer, counter ``` + +## Running the example + +This example can be run by directly executing the Python file or by using +[`pytest`](https://docs.pytest.org). + +### Standalone execution + +Simply run the test script: +```sh +python test_spi_master.py +``` + +### Using pytest + +If you already have it installed, simply run `pytest` from within the SPI +master example directory or from a parent directory. +Otherwise, follow [installation instruction](https://docs.pytest.org/en/latest/getting-started.html#install-pytest). From f6729efc576d59ed06342d78aea72bb34741651c Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 15:26:00 +0100 Subject: [PATCH 11/19] Modified SPI master example - dump file configurable --- examples/spi_master/spi_master_tb.v | 4 +++- examples/spi_master/test_spi_master.py | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/spi_master/spi_master_tb.v b/examples/spi_master/spi_master_tb.v index 0f88be8..0d19aa7 100644 --- a/examples/spi_master/spi_master_tb.v +++ b/examples/spi_master/spi_master_tb.v @@ -41,8 +41,10 @@ module spi_master_tb(); /* Initial loop */ initial begin - $dumpfile("spi_master_tb.fst"); + `ifdef DUMP_FILE + $dumpfile(`DUMP_FILE); $dumpvars(0, spi_master_tb); + `endif /* Launch Verisocks server after other initialization */ $verisocks_init(`VS_NUM_PORT, `VS_TIMEOUT); diff --git a/examples/spi_master/test_spi_master.py b/examples/spi_master/test_spi_master.py index a8fd2e0..ab63ea6 100644 --- a/examples/spi_master/test_spi_master.py +++ b/examples/spi_master/test_spi_master.py @@ -58,6 +58,7 @@ def setup_iverilog(vvp_name, *src_files): "-Wall", f"-DVS_NUM_PORT={PORT}", f"-DVS_TIMEOUT={VS_TIMEOUT}", + "-DDUMP_FILE=\"spi_master_tb.fst\"", *src_file_paths, ] subprocess.check_call(cmd) From f6b02f5f674cea840df8baaa9d8e34940620f8ef Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 22:41:36 +0100 Subject: [PATCH 12/19] Added info() shortcut method --- docs/src/release_notes.rst | 3 +++ docs/src/tcp_protocol.rst | 3 +++ examples/hello_world/test_hello_world.py | 4 ++-- python/test/test_verisocks.py | 6 ++++++ 4 files changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/src/release_notes.rst b/docs/src/release_notes.rst index 8ca47c3..3a4345e 100644 --- a/docs/src/release_notes.rst +++ b/docs/src/release_notes.rst @@ -14,6 +14,9 @@ version numbering system follows the `semantic versioning * Added :py:mod:`verisocks.utils` Python utilitary functions, including documentation. +* Added :py:meth:`Verisocks.info() ` method + as a shortcut to implement the TCP protocol :keyword:`info + ` command. * Corrected *SPI master* example for standalone execution. * Added a minimalistic *Hello world* example, working both for standalone execution or with pytest. diff --git a/docs/src/tcp_protocol.rst b/docs/src/tcp_protocol.rst index 1f8c94e..57de1d2 100644 --- a/docs/src/tcp_protocol.rst +++ b/docs/src/tcp_protocol.rst @@ -149,6 +149,9 @@ arbitrary text is then printed out to the VPI standard output. * :json:`"type": "ack"` (acknowledgement) * :json:`"value": "command info received"` +With the provided Python client reference implementation, the method +:py:meth:`Verisocks.info() ` +corresponds to this command. .. _sec_tcp_cmd_finish: diff --git a/examples/hello_world/test_hello_world.py b/examples/hello_world/test_hello_world.py index 9af8928..e1c0a01 100644 --- a/examples/hello_world/test_hello_world.py +++ b/examples/hello_world/test_hello_world.py @@ -44,12 +44,12 @@ def vs(): def test_hello_world(vs): assert vs._connected - answer = vs.send_cmd("get", sel="sim_info") + answer = vs.get("sim_info") assert answer['type'] == "result" print(f"Simulator: {answer['product']}") print(f"Version: {answer['version']}") - answer = vs.send_cmd("info", value="Hello World!") + answer = vs.info("Hello World!") assert answer['type'] == "ack" diff --git a/python/test/test_verisocks.py b/python/test/test_verisocks.py index e06bc5c..f048d62 100644 --- a/python/test/test_verisocks.py +++ b/python/test/test_verisocks.py @@ -111,6 +111,12 @@ def test_connect_error(): vs.close() +def test_info(vs): + """Tests the info command""" + answer = vs.info("This is a test") + assert answer["type"] == "ack" + + def test_get_sim_info(vs): answer = vs.get("sim_info") assert answer["type"] == "result" From 45e33c6dafc1e3b517ff0f091014d3832d676d37 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Sun, 4 Feb 2024 22:42:03 +0100 Subject: [PATCH 13/19] Added cross'refs to TCP commands in Python API doc --- python/verisocks/verisocks.py | 46 ++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/python/verisocks/verisocks.py b/python/verisocks/verisocks.py index 3e54eb7..6c042d3 100644 --- a/python/verisocks/verisocks.py +++ b/python/verisocks/verisocks.py @@ -361,7 +361,8 @@ def send_cmd(self, command, **kwargs): return self.send(command=command, **kwargs) def run(self, cb, **kwargs): - """Sends a "run" command request to the Verisocks server. + """Sends a :keyword:`run ` command request to the + Verisocks server. Equivalent to :code:`send_cmd("run", cb=cb, ...)`. This command gives the focus back to the simulator and lets it run until the specified @@ -403,7 +404,8 @@ def run(self, cb, **kwargs): return self.send(command="run", cb=cb, **kwargs) def set(self, path, **kwargs): - """Sends a "set" command request to the Verisocks server. + """Sends a :keyword:`set ` command request to the + Verisocks server. Equivalent to :code:`send_cmd("set", path=path, **kwargs)`. This commands sets the value of a verilog object as defined by its path. @@ -422,8 +424,26 @@ def set(self, path, **kwargs): """ return self.send(command="set", path=path, **kwargs) + def info(self, value): + """Sends an :keyword:`info ` command to the Verisocks + server. + + This is a shortcut function, which is equivalent to + :code:`send_cmd("info", ...)`. This command is used to send any text to + the Verisocks server, which will then be streamed out to the VPI + standard output. + + Args: + value (str): Text to be sent to the VPI stdout + + Returns: + JSON object: Content of returned message + """ + return self.send(command="info", value=value) + def get(self, sel, path=""): - """Sends a :code:`"get"` command request to the Verisocks server. + """Sends a :keyword:`get ` command request to the + Verisocks server. Equivalent to :code:`send_cmd("get", ...)`. This commands can be used to obtain different pieces of information from the Verisocks @@ -452,16 +472,18 @@ def get(self, sel, path=""): return self.send(command="get", sel=sel, path=path) def finish(self, timeout=None): - """Sends a ``"finish"`` command to the Verisocks server that terminates - the simulation (and therefore also closes the Verisocks server itself). - The connection is closed as well by the function as a clean-up. + """Sends a :keyword:`finish ` command to the + Verisocks server that terminates the simulation (and therefore also + closes the Verisocks server itself). The connection is closed as well + by the function as a clean-up. """ retval = self.send(command="finish", timeout=timeout) self.close() return retval def stop(self, timeout=None): - """Sends a ``"stop"`` command to the Verisocks server. + """Sends a :keyword:`stop ` command to the Verisocks + server. The ``"stop"`` command stops the simulation. The Verisocks server socket is not closed, but the simulation has to be restarted for any @@ -474,11 +496,11 @@ def stop(self, timeout=None): return self.send(command="stop", timeout=timeout) def exit(self): - """Sends an ``"exit"`` command to the Verisocks server that gives back - control to the simulator and closes the Verisocks server socket. The - simulation runs to its end without having the possibility to take the - control back from the simulator anymore. The connection is closed - as well by the function.""" + """Sends an :keyword:`exit ` command to the Verisocks + server that gives back control to the simulator and closes the + Verisocks server socket. The simulation runs to its end without having + the possibility to take the control back from the simulator anymore. + The connection is closed as well by the function.""" retval = self.send(command="exit") self.close() return retval From b33bbc6fad176ddf96c361fd4a6bf589ce3272fd Mon Sep 17 00:00:00 2001 From: jchabloz Date: Wed, 7 Feb 2024 22:27:02 +0100 Subject: [PATCH 14/19] Improved utils function code (dumb mistakes + overall style) --- python/verisocks/utils.py | 31 ++++++++++++++++++++++--------- 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/python/verisocks/utils.py b/python/verisocks/utils.py index f92715a..8b39518 100644 --- a/python/verisocks/utils.py +++ b/python/verisocks/utils.py @@ -30,14 +30,15 @@ def _format_path(cwd, path): def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, - vvp_logpath="vvp.log", ivl_exec=None, ivl_args=[], vvp_exec=None, - vvp_args=[], vvp_postargs=[], capture_output=True): + vvp_logpath="vvp.log", ivl_exec=None, ivl_args=None, + vvp_exec=None, vvp_args=None, vvp_postargs=None, + capture_output=True): """Set up Icarus simulation by elaborating the design with :code:`iverilog` and launching the simulation with :code:`vvp`. Args: cwd (str): Reference path to be used for all paths provided as relative - paths. Default = "." + paths. vpi_libpath (str): Path to the compiled Verisocks VPI library. src_files (str): Paths to all (verilog) source files to use for the simulation. All files have to be added as separate arguments. @@ -47,14 +48,13 @@ def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, None, no logfile shall be created. ivl_exec (str): Path to :code:`iverilog` executable (absolute path). If None (default), it is assumed to be defined in the system path. - ivl_args (list(str)): Arguments to :code:`iverilog` executable. - Default=[] (no extra arguments). + ivl_args (str, list(str)): Arguments to :code:`iverilog` executable. vvp_exec (str): Path to :code:`vvp` executable (absolute path). If None (default), it is assumed to be defined in the system path. - vvp_args (list(str)): Arguments to :code:`vvp` executable. Default=[]. - vvp_postargs (list(str)): (Post-)arguments to :code:`vvp` executable. - Default=[]. In order to dump waveforms to an FST file, this should - be configured as ["-fst"]. + vvp_args (list(str)): Arguments to :code:`vvp` executable. + vvp_postargs (str, list(str)): (Post-)arguments to :code:`vvp` + executable. In order to dump waveforms to an FST file, this should + be configured as "-fst". capture_output (bool): Defines if stdout and stderr output are "captured" (i.e. not visible). @@ -84,6 +84,11 @@ def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, else: ivl_cmd = [shutil.which("iverilog")] + if ivl_args is None: + ivl_args = [] + elif isinstance(ivl_args, str): + ivl_args = [ivl_args] + ivl_cmd += [ "-o", vvp_outfile, "-Wall", @@ -100,6 +105,14 @@ def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, if vvp_logpath: vvp_cmd += ["-l" + _format_path(cwd, vvp_logpath)] + if vvp_args is None: + vvp_args = [] + elif isinstance(vvp_args, str): + vvp_args = [vvp_args] + if vvp_postargs is None: + vvp_postargs = [] + elif isinstance(vvp_postargs, str): + vvp_postargs = [vvp_postargs] vvp_cmd += [ "-m", vpi_libpath, From 4c2bcf1db673d78169a1f161e609ea12700bdd75 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Wed, 7 Feb 2024 23:04:45 +0100 Subject: [PATCH 15/19] Removed forgotten print statement --- python/verisocks/utils.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python/verisocks/utils.py b/python/verisocks/utils.py index 8b39518..8da9826 100644 --- a/python/verisocks/utils.py +++ b/python/verisocks/utils.py @@ -120,7 +120,6 @@ def setup_sim(vpi_libpath, *src_files, cwd=".", vvp_filepath=None, vvp_outfile, *vvp_postargs ] - print(vvp_cmd) if capture_output: pop = subprocess.Popen( From 5fc572e93c8d8a64b27362e1f55bb792f0f15df7 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Wed, 7 Feb 2024 23:05:04 +0100 Subject: [PATCH 16/19] Rewrote SPI master example using verisocks.utils functions --- examples/spi_master/test_spi_master.py | 92 +++++--------------------- 1 file changed, 17 insertions(+), 75 deletions(-) diff --git a/examples/spi_master/test_spi_master.py b/examples/spi_master/test_spi_master.py index ab63ea6..3bc5c5c 100644 --- a/examples/spi_master/test_spi_master.py +++ b/examples/spi_master/test_spi_master.py @@ -1,83 +1,36 @@ from verisocks.verisocks import Verisocks -import subprocess +from verisocks.utils import setup_sim, find_free_port import os.path import time -import shutil import logging import pytest import socket import random -def find_free_port(): - with socket.socket() as s: - s.bind(('', 0)) - return s.getsockname()[1] - - # Parameters HOST = socket.gethostbyname("localhost") PORT = find_free_port() LIBVPI = "../../build/verisocks.vpi" # Relative path to this file! CONNECT_DELAY = 0.01 VS_TIMEOUT = 10 - - -def get_abspath(relpath): - """Builds an absolute path from a path which is relative to the current - file - - Args: - * relpath (str): Relative path - - Returns: - * abspath (str): Absolute path - """ - return os.path.join(os.path.dirname(__file__), relpath) - - -def setup_iverilog(vvp_name, *src_files): - """Elaborate and run the verilog testbench file provided as an argument - - Args: - * src_file (str): Path to source file - - Returns: - * pop: Popen instance for spawned process - """ - src_file_paths = [] - for src_file in src_files: - src_file_path = get_abspath(src_file) - if not os.path.isfile(src_file_path): - raise FileNotFoundError - src_file_paths.append(src_file_path) - vvp_file_path = get_abspath(vvp_name) - cmd = [ - shutil.which("iverilog"), - "-o", vvp_file_path, - "-Wall", - f"-DVS_NUM_PORT={PORT}", - f"-DVS_TIMEOUT={VS_TIMEOUT}", - "-DDUMP_FILE=\"spi_master_tb.fst\"", - *src_file_paths, - ] - subprocess.check_call(cmd) - libvpi_path = get_abspath(LIBVPI) - cmd = [shutil.which("vvp"), "-lvvp.log", "-m", libvpi_path, - vvp_file_path, "-fst"] - pop = subprocess.Popen( - cmd, - stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL +SRC = ["spi_master.v", "spi_slave.v", "spi_master_tb.v"] + + +def setup_test(): + setup_sim( + LIBVPI, + *SRC, + cwd=os.path.dirname(__file__), + vvp_filepath="spi_master_tb", + ivl_args=[ + f"-DVS_NUM_PORT={PORT}", + f"-DVS_TIMEOUT={VS_TIMEOUT}", + "-DDUMP_FILE=\"spi_master_tb.fst\"" + ] ) - print(f"Launched Icarus with PID {pop.pid}") - - # Some delay is required for Icarus to launch the Verisocks server before - # being able to connect - Please adjust CONNECT_DELAY if required. time.sleep(CONNECT_DELAY) - return pop - def send_spi(vs, tx_buffer): """Triggers an SPI transaction @@ -129,10 +82,7 @@ def send_spi(vs, tx_buffer): @pytest.fixture def vs(): # Set up Icarus simulation and launch it as a separate process - pop = setup_iverilog("spi_master_tb", - "spi_master.v", - "spi_slave.v", - "spi_master_tb.v") + setup_test() _vs = Verisocks(HOST, PORT) _vs.connect() yield _vs @@ -142,7 +92,6 @@ def vs(): except ConnectionError: logging.warning("Connection error - Finish command not possible") _vs.close() - pop.communicate(timeout=10) def get_random_tx_buffer(): @@ -176,13 +125,6 @@ def test_spi_master_simple(vs): if __name__ == "__main__": - setup_iverilog( - "spi_master_tb", - "spi_master.v", - "spi_slave.v", - "spi_master_tb.v" - ) + setup_test() with Verisocks(HOST, PORT) as vs_cli: - vs_cli.connect() test_spi_master_simple(vs_cli) - vs_cli.finish() From 4ecfaee1891423ea4b84f23b5abea7b37fadf962 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Wed, 7 Feb 2024 23:26:25 +0100 Subject: [PATCH 17/19] Updated Actions config --- .github/workflows/builddocs.yml | 2 +- .github/workflows/testdocs.yml | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/testdocs.yml diff --git a/.github/workflows/builddocs.yml b/.github/workflows/builddocs.yml index 8d6c318..ab62dcc 100644 --- a/.github/workflows/builddocs.yml +++ b/.github/workflows/builddocs.yml @@ -1,4 +1,4 @@ -name: Build docs +name: Build and deploy docs on: workflow_dispatch: diff --git a/.github/workflows/testdocs.yml b/.github/workflows/testdocs.yml new file mode 100644 index 0000000..7b77f04 --- /dev/null +++ b/.github/workflows/testdocs.yml @@ -0,0 +1,32 @@ +name: Test building docs + +on: + push: + branches-ignore: + - 'main' + paths: + - 'docs/**' + +jobs: + build: + runs-on: ubuntu-latest + name: Build documentation + steps: + - name: Checkout repo + uses: actions/checkout@v3 + - name: Setup Python + uses: actions/setup-python@v4 + with: + python-version: "3" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -e ./python + pip install sphinx sphinx-rtd-theme myst-parser + - name: Render + run: | + sphinx-build -M html ./docs ./docs/_build + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: "./docs/_build/html" From acf549bd9301c9bb443131d9900fd356d7815021 Mon Sep 17 00:00:00 2001 From: jchabloz Date: Wed, 7 Feb 2024 23:34:24 +0100 Subject: [PATCH 18/19] Updated used actions versions --- .github/workflows/builddocs.yml | 4 ++-- .github/workflows/makefile.yml | 14 +++++++------- .github/workflows/testdocs.yml | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/builddocs.yml b/.github/workflows/builddocs.yml index ab62dcc..5b7e5e7 100644 --- a/.github/workflows/builddocs.yml +++ b/.github/workflows/builddocs.yml @@ -23,9 +23,9 @@ jobs: name: Build documentation steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3" - name: Install dependencies diff --git a/.github/workflows/makefile.yml b/.github/workflows/makefile.yml index d166489..ea7a52a 100644 --- a/.github/workflows/makefile.yml +++ b/.github/workflows/makefile.yml @@ -12,7 +12,7 @@ jobs: name: Builds VPI library steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: submodules: true - name: Install dependencies @@ -24,12 +24,12 @@ jobs: - name: Build and run cunit test run: cd test;make;cd .. - name: Upload build artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: libvpi path: build/verisocks.vpi - name: Archive cunit test artifacts - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: cunit-test-results path: | @@ -43,9 +43,9 @@ jobs: name: Run pytest steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3.7" - name: Install dependencies @@ -55,7 +55,7 @@ jobs: pip install -e ./python pip install pytest pytest-cov - name: Download build artifact - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: libvpi - name: Check verisocks.vpi @@ -67,7 +67,7 @@ jobs: run: pytest -x --log-cli-level=INFO --cov=verisocks - name: Archive test logs if: always() - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: test-logs path: | diff --git a/.github/workflows/testdocs.yml b/.github/workflows/testdocs.yml index 7b77f04..d06836a 100644 --- a/.github/workflows/testdocs.yml +++ b/.github/workflows/testdocs.yml @@ -13,9 +13,9 @@ jobs: name: Build documentation steps: - name: Checkout repo - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: "3" - name: Install dependencies From 09bbf1d591316c7d98453c63bbc4a02ee7238aca Mon Sep 17 00:00:00 2001 From: jchabloz Date: Wed, 7 Feb 2024 23:36:00 +0100 Subject: [PATCH 19/19] Doc version changed to 1.1.0 --- docs/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/conf.py b/docs/conf.py index 05ef179..cf2e362 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -9,7 +9,7 @@ project = 'Verisocks' copyright = '2023, Jérémie Chabloz' author = 'Jérémie Chabloz' -version = '1.1.0-pre' +version = '1.1.0' release = '1.1.0' # -- General configuration ---------------------------------------------------