diff --git a/.github/Dockerfile b/.github/Dockerfile new file mode 100644 index 00000000..083335a6 --- /dev/null +++ b/.github/Dockerfile @@ -0,0 +1,5 @@ +FROM ghdl/vunit:llvm + +RUN apt update -qq \ + && apt install -y imagemagick \ + && python3 -m pip install pytest --progress-bar off diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c67f4eaf..ca686f5a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -11,88 +11,72 @@ env: jobs: - lin: - strategy: - fail-fast: false - max-parallel: 3 - matrix: - task: [ - vhpidirect/quickstart/random, - vhpidirect/quickstart/math, - vhpidirect/quickstart/customc, - vhpidirect/quickstart/wrapping/basic, - vhpidirect/quickstart/wrapping/time, - vhpidirect/quickstart/linking/bind, - vhpidirect/quickstart/package, - vhpidirect/quickstart/sharedvar, - vhpidirect/shared/shlib, - vhpidirect/shared/dlopen, - vhpidirect/shared/shghdl, - vhpidirect/arrays/intvector, - vhpidirect/arrays/logicvector, - vhpidirect/arrays/matrices, - vhpidirect/arrays/matrices/framebuffer, - vpi/quickstart, - ] + lin-docker: runs-on: ubuntu-latest env: DOCKER_BUILDKIT: 1 - DOCKER_IMAGE: ghdl/ghdl:buster-llvm-7 steps: - uses: actions/checkout@v2 - - run: docker pull $DOCKER_IMAGE - - run: docker run --rm -tv $(pwd):/src -e CI $DOCKER_IMAGE /src/${{ matrix.task}}/run.sh + - run: docker build -t cosim/test - < .github/Dockerfile + - run: docker run --rm -v $(pwd):/src -w /src -e CI cosim/test python3 -m pytest -v -s -ra test.py --color=yes - vunit: - strategy: - fail-fast: false - max-parallel: 3 - matrix: - task: [ - vhpidirect/arrays/matrices/vunit_axis_vcs, - ] + win-stable: + runs-on: windows-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-python@v2 + with: + python-version: 3.8 + - env: + WINDOWS_RELEASE: 0.37-mingw64-llvm + shell: bash + run: | + curl -fsSL -o ghdl.zip https://github.com/ghdl/ghdl/releases/download/v0.37/ghdl-${WINDOWS_RELEASE}.zip + 7z x ghdl.zip "-o../ghdl-tmp" -y + mv ../ghdl-tmp/GHDL/${WINDOWS_RELEASE}/ ../ghdl + rm -rf ../ghdl-tmp ghdl.zip + export PATH=$PATH:$(pwd)/../ghdl/bin + python -m pip install pytest vunit_hdl --progress-bar off + python -m pytest -v -s -ra test.py --color=yes + + lin-setup: runs-on: ubuntu-latest env: DOCKER_BUILDKIT: 1 DOCKER_IMAGE: ghdl/vunit:llvm steps: - uses: actions/checkout@v2 - - run: docker pull $DOCKER_IMAGE - - run: docker run --rm -tv $(pwd):/src -w /src/${{ matrix.task}} -e CI $DOCKER_IMAGE python3 run.py -v + - uses: umarcor/setup-ghdl@master + with: + backend: llvm + - uses: actions/setup-python@v2 + with: + python-version: 3.8 + - name: Install dependencies + run: | + ghdl --version + sudo apt update -qq + sudo apt install -y imagemagick + python -m pip install --progress-bar off pytest vunit_hdl + - run: python -m pytest -v -s -ra test.py --color=yes - win: - strategy: - fail-fast: false - max-parallel: 3 - matrix: - task: [ - vhpidirect/quickstart/random, - vhpidirect/quickstart/math, - vhpidirect/quickstart/customc, - vhpidirect/quickstart/wrapping/basic, - vhpidirect/quickstart/wrapping/time, - #vhpidirect/quickstart/linking/bind, ! needs investigation, output of list-link seems to have wrong path format - vhpidirect/quickstart/package, - vhpidirect/quickstart/sharedvar, - vhpidirect/shared/shlib, - #vhpidirect/shared/dlopen, ! dlfcn.h is not available on win - #vhpidirect/shared/shghdl, ! dlfcn.h is not available on win - vhpidirect/arrays/intvector, - vhpidirect/arrays/logicvector, - vhpidirect/arrays/matrices, - #vhpidirect/arrays/matrices/framebuffer, ! needs ImageMagick's 'convert' - vpi/quickstart, - ] + win-setup: runs-on: windows-latest - env: - WINDOWS_RELEASE: 0.37-mingw64-llvm steps: - uses: actions/checkout@v2 - - shell: bash + - uses: eine/setup-msys2@v0 + with: + msystem: MINGW64 + update: true + install: mingw-w64-x86_64-python-pip make + - uses: umarcor/setup-ghdl@master + with: + backend: llvm + - name: Install dependencies + shell: msys2 {0} run: | - curl -fsSL -o ghdl.zip https://github.com/ghdl/ghdl/releases/download/v0.37/ghdl-${WINDOWS_RELEASE}.zip - 7z x ghdl.zip "-o../ghdl-tmp" -y - mv ../ghdl-tmp/GHDL/${WINDOWS_RELEASE}/ ../ghdl - rm -rf ../ghdl-tmp ghdl.zip - export PATH=$PATH:$(pwd)/../ghdl/bin - ./${{ matrix.task}}/run.sh + ghdl --version + python -m pip install --progress-bar off pytest vunit_hdl + - shell: msys2 {0} + run: | + python -m pytest -v -s -ra test.py --color=yes diff --git a/.gitignore b/.gitignore index ec86efdd..8b3b8c3a 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,6 @@ ent* tb* !*.vhd !*.vhdl +doc/_build +.vunit_hash +**/vunit_out/ diff --git a/README.md b/README.md index faaa28c1..32a95fe4 100644 --- a/README.md +++ b/README.md @@ -20,3 +20,23 @@ Subdirs in [vhpidirect](./vhpidirect) and [vpi](./vpi) contain groups of example additional examples. Explanations are available in the [docs](https://ghdl.github.io/ghdl-cosim). *This repository was created recently and multiple existing examples are not published yet. Find on-going work in issue [#1](https://github.com/ghdl/ghdl-cosim/issues/1) and in [open Pull Requests](https://github.com/ghdl/ghdl-cosim/pulls)*. + +## Makefiles + +### Brief refresher + +The first rule in each makefile is the default rule executed, `afresh` will clean and then run. This is triggered by calling `make`. + +All makefile rules can be called by specifying the target (argument left of the rule's ':') after make: e.g. `make run` + +Make echoes each command before executing it, unless the line starts with `@`. All lines are echoed to the terminal, excepting `echo` calls. +This provides transparency on the commands being executed. + +### Symbols used + +The symbols below are used in order to make it easy to create a consistent change in the make operation. + +- `CC?=gcc`, `CFLAGS+=-fPIC` + - These determine which C compiler is used and the flags that are issued with it. +- `GHDL?=ghdl`, `STD?=93` + - These determine the GHDL executable called and the VHDL standard used. diff --git a/doc/index.rst b/doc/index.rst index 231d06dc..2c34f0ef 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -45,7 +45,7 @@ supported. However, a *vhdlator*/*ghdlator* might be available in the future. because, as the name suggests, it is a direct interface. However, on the one hand VHPIDIRECT requires modification of VHDL sources, which might not be possible or desirable in certain contexts. On the other hand, VPI/VHPI allow use cases which are not yet possible with VHPIDIRECT, such as controlling execution time steps. It is suggested to read the quick -start examples of both interfacing mechanisms, in order to get a feel of the differences. +start examples of both interfacing mechanisms, in order to get a feel for the differences. .. toctree:: diff --git a/doc/vhpi/index.rst b/doc/vhpi/index.rst index 7dadeffa..7f85ede2 100644 --- a/doc/vhpi/index.rst +++ b/doc/vhpi/index.rst @@ -6,12 +6,15 @@ Introduction ============ .. ATTENTION:: - Since VPI and VHPI provide very similar features, and because VPI is already supported in GHDL, VHPI is not available (yet). - Hence, the information in this section is provided for completeness only. + Since VPI and VHPI provide very similar features, and because VPI is already supported in GHDL, VHPI is not available + (yet). Hence, the information in this section is provided for completeness only. VHDL Programming Interface (VHPI) was introduced in 2007, as an ammendment to IEEE Std 1076-2002: `1076c-2007 - IEEE Standard VHDL Language Reference Manual - Procedural Language Application Interface `_. In the 2009, the programming interface was published as part of `1076-2008 - IEEE Standard VHDL Language Reference Manual `_. The latest version was published in 2019: `1076-2019 - IEEE Standard for VHDL Language Reference Manual `_. -Some vendors support C programming interfaces similar to VHPI. For example, Mentor Graphics' ModelSim/QuestaSim supports a -Foreign Language Interface (FLI) that provides functions to have procedural access to information within the simulator, ``vsim``. These allow to traverse the hierarchy, get/set values and control a simulation run. See `Using ModelSim Foreign Language Interface for c – VHDL CoSimulation and for Simulator Control on Linux x86 Platform `_ and `github.com/andrepool/fli `_. +Some vendors support C programming interfaces similar to VHPI. For example, Mentor Graphics' ModelSim/QuestaSim supports +a Foreign Language Interface (FLI) that provides functions to have procedural access to information within the simulator, +``vsim``. These functions allow traversing the hierarchy, getting/setting values and controlling a simulation run. See +`Using ModelSim Foreign Language Interface for c – VHDL CoSimulation and for Simulator Control on Linux x86 Platform `_ +and `github.com/andrepool/fli `_. diff --git a/doc/vhpidirect/examples/quickstart.rst b/doc/vhpidirect/examples/quickstart.rst index 216de3f9..82b48c04 100644 --- a/doc/vhpidirect/examples/quickstart.rst +++ b/doc/vhpidirect/examples/quickstart.rst @@ -64,12 +64,12 @@ Wrapping ghdl_main :cosimtree:`basic ` --------------------------------------------------------- -Instead of using GHDL's own entrypoint to the execution, it is possible to wrap it by providing a custom ``main`` -function. Upon existence of ``main``, execution of the simulation is triggered by calling ``ghdl_main``. +Instead of using GHDL's own entrypoint to the execution, it is possible to wrap it by providing a custom program +entrypoint (``main`` function), wherein the execution of the simulation is triggered by calling ``ghdl_main``. -This is the most basic example of such usage. ``ghdl_main`` is declared as ``extern`` in C, and arguments ``argc`` and -``argv`` are passed without modification. However, this sets the ground for custom prepocessing and postprocessing in a -foreign language. +This example shows the most basic of such usage. ``ghdl_main`` is declared as ``extern`` in C, and arguments ``argc`` +and ``argv`` are passed without modification. However, this sets the ground for custom prepocessing and postprocessing +in a foreign language. Other options are to just pass empty arguments (``ghdl_main(0, NULL)``) or to customize them: @@ -84,11 +84,11 @@ See :ref:`COSIM:VHPIDIRECT:Wrapping` for further details about the constraints o ------------------------------------------------------- Although most of the provided examples are written in C, VHPIDIRECT can be used with any language that supports a -C-alike compile and link model. +C-like compile and link model. This example shows how to time the execution of a simulation from either C or Ada. In both cases, function ``clock`` is used to get the time before and after calling ``ghdl_main``. Regarding the build procedure, it is to be noted that C -sources are elaborated with :option:`-e`, because GHDL allows to pass parameters (in this case, additional C sources) +sources are elaborated with :option:`-e`, because GHDL allows passing parameters (in this case, additional C sources) to the compiler and/or linker. However, since it is not possible to do so with Ada, ``gnatmake``, :option:`--bind` and :option:`--list-link` are used instead. See :ref:`COSIM:VHPIDIRECT:Linking` for further info about custom linking setups. @@ -137,7 +137,7 @@ numbers. Subprogram declaration requirements are detailed under the :ref:`COSIM: While sharing variables through packages in VHDL 1993 is flexible, in VHDL 2008 protected types need to be used. However, GHDL allows to relax some rules of the LRM through :option:`-frelaxed`. -This example shows multiple alternatives to share variables through packages, depending on the target version of the +This example showcases multiple ways of sharing variables through packages, depending on the target version of the standard. Three different binaries are built from the same entity, using: * A VHDL 1993 package with ``--std=93``. diff --git a/doc/vpi/examples/index.rst b/doc/vpi/examples/index.rst index c4b4abbd..d211f8d4 100644 --- a/doc/vpi/examples/index.rst +++ b/doc/vpi/examples/index.rst @@ -5,7 +5,7 @@ Examples ######## A very brief description of how to use VPI is that ``vpi_user.h`` provides dozens of functions to scan/navigate the hierarchy -of the elaborated hardware design, and it allows to set callbacks for specific events/signals. +of the elaborated hardware design, and it allows setting callbacks for specific events/signals. .. NOTE:: Since VHDL sources are agnostic to the usage of VPI modules, most of the examples in this section reuse the same VHDL diff --git a/doc/vpi/examples/quickstart.rst b/doc/vpi/examples/quickstart.rst index d65ee146..bce914eb 100644 --- a/doc/vpi/examples/quickstart.rst +++ b/doc/vpi/examples/quickstart.rst @@ -12,6 +12,6 @@ Quick Start This is the most minimal example, where a single callback is registered at the beginning of the simulation. The callback just prints ``Hello!``. Then, the simulation is executed as usual. -VPI allows to register callbacks at multiple events and to optionally delay their execution after the event is triggered. +VPI allows registering callbacks at multiple events and to optionally delay their execution after the event is triggered. The list of available callback reasons is defined in :ghdlsrc:`vpi_user.h `. The structure type that is used and required to register a callback, ``s_cb_data``, is also defined in the same header file. diff --git a/test.py b/test.py new file mode 100644 index 00000000..96751893 --- /dev/null +++ b/test.py @@ -0,0 +1,92 @@ +""" +Verify that all example run scripts work correctly +""" + +from sys import executable, platform +from os import environ +from pathlib import Path +from subprocess import check_call +import unittest +import pytest + + +class TestExamples(unittest.TestCase): + """ + Verify that example run scripts work correctly + """ + + def setUp(self): + self.shell = ['bash'] if platform == 'win32' else [] + self.root = Path(__file__).parent + self.vhpidirect = self.root / 'vhpidirect' + self.vpi = self.root / 'vpi' + + def test_vhpidirect_quickstart_random(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'random' / 'run.sh')], shell=True) + + def test_vhpidirect_quickstart_math(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'math' / 'run.sh')], shell=True) + + def test_vhpidirect_quickstart_customc(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'customc' / 'run.sh')], shell=True) + + def test_vhpidirect_quickstart_wrapping_basic(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'wrapping' / 'basic' / 'run.sh')], shell=True) + + def test_vhpidirect_quickstart_wrapping_time(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'wrapping' / 'time' / 'run.sh')], shell=True) + + @unittest.skipUnless( + platform != 'win32', + "win: needs investigation, output of list-link seems to have wrong path format", + ) + def test_vhpidirect_quickstart_linking_bind(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'linking' / 'bind' / 'run.sh')], shell=True) + + def test_vhpidirect_quickstart_package(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'package' / 'run.sh')], shell=True) + + def test_vhpidirect_quickstart_sharedvar(self): + check_call(self.shell + [str(self.vhpidirect / 'quickstart' / 'sharedvar' / 'run.sh')], shell=True) + + def test_vhpidirect_shared_shlib(self): + check_call(self.shell + [str(self.vhpidirect / 'shared' / 'shlib' / 'run.sh')], shell=True) + + @unittest.skipUnless( + platform != 'win32', + "win: dlfcn.h is not available on win", + ) + def test_vhpidirect_shared_dlopen(self): + check_call(self.shell + [str(self.vhpidirect / 'shared' / 'dlopen' / 'run.sh')], shell=True) + + @unittest.skipUnless( + platform != 'win32', + "win: dlfcn.h is not available on win", + ) + def test_vhpidirect_shared_shghdl(self): + check_call(self.shell + [str(self.vhpidirect / 'shared' / 'shghdl' / 'run.sh')], shell=True) + + def test_vhpidirect_arrays_intvector(self): + # check_call(self.shell + [str(self.vhpidirect / 'arrays' / 'intvector' / 'run.sh')], shell=True) + # check_call(self.shell + ['make', 'run'], shell=True, cwd=str(self.vhpidirect / 'arrays' / 'intvector')) + check_call(['make', 'run'], shell=True, cwd=str(self.vhpidirect / 'arrays' / 'intvector')) + + + def test_vhpidirect_arrays_logicvector(self): + check_call(self.shell + [str(self.vhpidirect / 'arrays' / 'logicvector' / 'run.sh')], shell=True) + + def test_vhpidirect_arrays_matrices(self): + check_call(self.shell + [str(self.vhpidirect / 'arrays' / 'matrices' / 'run.sh')], shell=True) + + def test_vhpidirect_arrays_matrices_vunit_axis_vcs(self): + check_call([executable, str(self.vhpidirect / 'arrays' / 'matrices' / 'vunit_axis_vcs' / 'run.py')], shell=True) + + @unittest.skipUnless( + platform != 'win32', + "win: needs ImageMagick's 'convert'", + ) + def test_vhpidirect_arrays_matrices_framebuffer(self): + check_call(self.shell + [str(self.vhpidirect / 'arrays' / 'matrices' / 'framebuffer' / 'run.sh')], shell=True) + + def test_vpi_quickstart(self): + check_call(self.shell + [str(self.vpi / 'quickstart' / 'run.sh')], shell=True) diff --git a/vhpidirect/arrays/intvector/csized/makefile b/vhpidirect/arrays/intvector/csized/makefile new file mode 100644 index 00000000..fc261856 --- /dev/null +++ b/vhpidirect/arrays/intvector/csized/makefile @@ -0,0 +1,55 @@ +CC ?= gcc +GHDL ?= ghdl +CFLAGS += -fPIC +STD ?= 93 + +WORK_DIR ?= . + +VHDL_DEPS ?= tb.vhd +VHDL_O_DEPS ?= $(patsubst %.vhd,%.o,$(VHDL_DEPS)) + +# Default +refresh : clean run + +# Executable commands +run : tb tb_main + +tb : c_tb + @echo "Execute tb" + ./tb + @echo + +tb_main : main_tb + @echo "Execute main_tb" + ./main_tb + @echo + +# Compile executable + +main_% : %.o mkdir_$(WORK_DIR) + $(GHDL) -e --workdir=$(WORK_DIR)/ --std=$(STD) -Wl,main.c -o $@ $(subst main_,,$@) + +c_% : %.o mkdir_$(WORK_DIR) + $(GHDL) -e --workdir=$(WORK_DIR)/ --std=$(STD) -Wl,caux.c $(subst c_,,$@) + +%.o : %.vhd mkdir_$(WORK_DIR) + @echo "Analyze $<" + $(GHDL) -a --std=$(STD) --workdir=$(WORK_DIR) $< + +mkdir_% : + mkdir -p $(subst mkdir_,,$@) + +# Clean + +.PHONY: clean + +clean: clean_work clean_tb clean_tb_main + +clean_tb: + rm -f ./tb + +clean_tb_main: + rm -f ./tb_main + +clean_work: + rm -f $(WORK_DIR)/*.o $(WORK_DIR)/work-obj*.cf diff --git a/vhpidirect/arrays/intvector/csized/run.sh b/vhpidirect/arrays/intvector/csized/old_run.sh similarity index 100% rename from vhpidirect/arrays/intvector/csized/run.sh rename to vhpidirect/arrays/intvector/csized/old_run.sh diff --git a/vhpidirect/arrays/intvector/makefile b/vhpidirect/arrays/intvector/makefile new file mode 100644 index 00000000..fa828354 --- /dev/null +++ b/vhpidirect/arrays/intvector/makefile @@ -0,0 +1,12 @@ +EXAMPLE_DIRS = ./csized ./vhdlsized + +# Default +afresh : clean run + +run : + $(foreach dir,$(EXAMPLE_DIRS),$(MAKE) -C $(dir)/ run;) + +# Clean + +clean: + $(foreach dir,$(EXAMPLE_DIRS),$(MAKE) -C $(dir)/ clean;) \ No newline at end of file diff --git a/vhpidirect/arrays/intvector/run.sh b/vhpidirect/arrays/intvector/old_run.sh similarity index 100% rename from vhpidirect/arrays/intvector/run.sh rename to vhpidirect/arrays/intvector/old_run.sh diff --git a/vhpidirect/arrays/intvector/vhdlsized/caux.c b/vhpidirect/arrays/intvector/vhdlsized/caux.c index a33648d9..59d06b88 100755 --- a/vhpidirect/arrays/intvector/vhdlsized/caux.c +++ b/vhpidirect/arrays/intvector/vhdlsized/caux.c @@ -1,5 +1,6 @@ #include #include +#include #include int* allocIntArr(int arrSize){ diff --git a/vhpidirect/arrays/intvector/vhdlsized/makefile b/vhpidirect/arrays/intvector/vhdlsized/makefile new file mode 100644 index 00000000..9d7f73fe --- /dev/null +++ b/vhpidirect/arrays/intvector/vhdlsized/makefile @@ -0,0 +1,55 @@ +CC ?= gcc +GHDL ?= ghdl +CFLAGS += -fPIC +STD ?= 93 + +WORK_DIR ?= . + +VHDL_DEPS ?= pkg.vhd tb.vhd +VHDL_O_DEPS ?= $(patsubst %.vhd,%.o,$(VHDL_DEPS)) + +# Default +refresh : clean run + +# Executable commands +run : calloc_tb vhdlalloc_tb + +calloc_tb : pkg.o tb_calloc + @echo "Execute tb_calloc" + ./tb_calloc + @echo + +vhdlalloc_tb : pkg.o tb_vhdlalloc + @echo "Execute tb_vhdlalloc" + ./tb_vhdlalloc + @echo + +# Compile executable + +tb_% : tb.o mkdir_$(WORK_DIR) + $(GHDL) -e --workdir=$(WORK_DIR)/ --std=$(STD) -Wl,caux.c -o $@ tb $(subst tb_,,$@) + +c_% : %.o mkdir_$(WORK_DIR) + $(GHDL) -e --workdir=$(WORK_DIR)/ --std=$(STD) -Wl,caux.c $(subst c_,,$@) + +%.o : %.vhd mkdir_$(WORK_DIR) + @echo "Analyze $<" + $(GHDL) -a --std=$(STD) --workdir=$(WORK_DIR) $< + +mkdir_% : + mkdir -p $(subst mkdir_,,$@) + +# Clean + +.PHONY: clean + +clean: clean_work clean_tb clean_tb_main + +clean_tb: + rm -f ./tb + +clean_tb_main: + rm -f ./tb_main + +clean_work: + rm -f $(WORK_DIR)/*.o $(WORK_DIR)/work-obj*.cf diff --git a/vhpidirect/arrays/intvector/vhdlsized/run.sh b/vhpidirect/arrays/intvector/vhdlsized/old_run.sh similarity index 100% rename from vhpidirect/arrays/intvector/vhdlsized/run.sh rename to vhpidirect/arrays/intvector/vhdlsized/old_run.sh