From f962bbf091f6a5b9aea78227baa0ef1d3d2055cb Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Sat, 9 Jul 2022 11:46:29 +0100 Subject: [PATCH] Add --install command to compile third-party libraries --- .github/workflows/build-test.yml | 4 ++ Makefile.am | 3 + NEWS.md | 2 + README.md | 9 ++- configure.ac | 1 + contrib/Makemodule.am | 4 ++ contrib/README.md | 2 + contrib/functions.sh | 39 ++++++++++ contrib/install-osvvm.sh | 80 +++++++++++++++++++++ contrib/install-uvvm.sh | 120 +++++++++++++++++++++++++++++++ nvc.1 | 4 ++ src/cgen.c | 2 +- src/nvc.c | 90 ++++++++++++++++++++++- src/util.c | 27 +++++-- src/util.h | 3 +- 15 files changed, 380 insertions(+), 10 deletions(-) create mode 100644 contrib/Makemodule.am create mode 100644 contrib/README.md create mode 100644 contrib/functions.sh create mode 100755 contrib/install-osvvm.sh create mode 100755 contrib/install-uvvm.sh diff --git a/.github/workflows/build-test.yml b/.github/workflows/build-test.yml index 005ccb79..49b7c688 100644 --- a/.github/workflows/build-test.yml +++ b/.github/workflows/build-test.yml @@ -198,6 +198,10 @@ jobs: echo /opt/nvc-${{ steps.version.outputs.version }}/bin >> $GITHUB_PATH - name: Check --version output run: nvc --version + - name: Install OSVVM + run: nvc --install osvvm + - name: Install UVVM + run: nvc --install uvvm - name: Test FPHDL run: ./vhdl-projects/fphdl/test.sh - name: Test ZPU diff --git a/Makefile.am b/Makefile.am index 7fab103f..93383d70 100644 --- a/Makefile.am +++ b/Makefile.am @@ -21,6 +21,8 @@ check_PROGRAMS = check_LIBRARIES = noinst_PROGRAMS = pkgdata_DATA = +pkglibexec_PROGRAMS = +pkglibexec_SCRIPTS = EXTRA_PROGRAMS = CLEANFILES = DISTCLEANFILES = @@ -45,6 +47,7 @@ include lib/ieee.08/Makemodule.am include lib/vital/Makemodule.am include lib/synopsys/Makemodule.am include tools/Makemodule.am +include contrib/Makemodule.am compile-commands: $(MAKE) -C $(top_builddir) clean diff --git a/NEWS.md b/NEWS.md index 494388b0..e5d13c40 100644 --- a/NEWS.md +++ b/NEWS.md @@ -42,6 +42,8 @@ - The `--relax=` analysis option is deprecated and is now equivalent to passing `--relaxed`. The individual options are ignored. - Added support for generic subprograms in VHDL-2008. +- New command `--install` allows easy installation of common third-party + packages such as OSVVM and UVVM. ## Version 1.6.2 - 2022-04-03 - Fix `make -j` with GNU make (#440). diff --git a/README.md b/README.md index 13c695d3..733827ea 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,10 @@ could be used to program an FPGA or ASIC. It implements only the simulation behaviour of the language as described by the [IEEE 1076](https://standards.ieee.org/standard/1076-2019.html) standard. +NVC supports popular verification frameworks including +[OSVVM](https://osvvm.org/) and [UVVM](https://www.uvvm.org/). See +[below](#vendor-libraries) for installation instructions. + ### Usage Simulating a VHDL hardware design involves three steps: _analysing_ the @@ -183,8 +187,11 @@ information. ### Vendor Libraries -NVC provides scripts to compile the simulation libraries of common FPGA vendors. +NVC provides scripts to compile popular verification frameworks and the +simulation libraries of common FPGA vendors. +* For [OSVVM](https://osvvm.org/) use `nvc --install osvvm` +* For [UVVM](https://www.uvvm.org/) use `nvc --install uvvm` * For Xilinx ISE use `./tools/build-xilinx-ise.rb` * For Xilinx Vivado use `./tools/build-xilinx-vivado.rb` * For Altera Quartus use `./tools/build-altera.rb` diff --git a/configure.ac b/configure.ac index a9b529c8..397c193e 100644 --- a/configure.ac +++ b/configure.ac @@ -163,6 +163,7 @@ esac AX_DEFINE_DIR([DATADIR], [datadir/nvc], [Installation data directory]) AX_DEFINE_DIR([LIBDIR], [libdir/nvc], [Installation library directory]) +AX_DEFINE_DIR([LIBEXECDIR], [libexecdir/nvc], [Location of internal programs]) AX_DEFINE_DIR([TESTDIR], [srcdir/test], [Location of testcases]) # Prefer calling the linker directy to using CC diff --git a/contrib/Makemodule.am b/contrib/Makemodule.am new file mode 100644 index 00000000..3c72849f --- /dev/null +++ b/contrib/Makemodule.am @@ -0,0 +1,4 @@ +pkglibexec_SCRIPTS += \ + contrib/functions.sh \ + contrib/install-osvvm.sh \ + contrib/install-uvvm.sh diff --git a/contrib/README.md b/contrib/README.md new file mode 100644 index 00000000..3c8cf511 --- /dev/null +++ b/contrib/README.md @@ -0,0 +1,2 @@ +This directory contains scripts to install various third party packages. +Feel free to create a pull request to add new packages. diff --git a/contrib/functions.sh b/contrib/functions.sh new file mode 100644 index 00000000..53c720f0 --- /dev/null +++ b/contrib/functions.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +_safe () { + echo $* + $* + [ $? = 0 ] || exit 1 +} + +_nvc () { + local _work=${WORK:-work} + local _dest=${DEST:-$HOME/.nvc/lib} + local _opts="--std=${STD:-1993} --work=$_dest/$_work -L$_dest $GLOBAL_OPTS" + [ -d $_dest ] || _safe mkdir -p $_dest + _safe ${NVC:-nvc} $_opts $* +} + +analyse () { + local _files=$* + _nvc -a $A_OPTS $_files +} + +analyse_list () { + local _work=$1 + while read _src; do + WORK=$_work analyse $_src + done +} + +git_wrapper () { + local _repo=$1 + local _base=$(basename $_repo) + local _tag=$2 + local _cache=${CACHE:-$HOME/.cache/nvc}/$_base-$_tag + if [ ! -d $_cache/.git ]; then + _safe mkdir -p $_cache + _safe git clone --recursive $_repo -b $_tag $_cache --depth=1 + fi + _safe cd $_cache +} diff --git a/contrib/install-osvvm.sh b/contrib/install-osvvm.sh new file mode 100755 index 00000000..9efd125d --- /dev/null +++ b/contrib/install-osvvm.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# +# Called by "nvc --install osvvm". +# + +. $(dirname $BASH_SOURCE)/functions.sh + +git_wrapper https://github.com/osvvm/OsvvmLibraries 2022.04 + +STD=2008 + +analyse_list osvvm < #include #include +#include +#include +#include +#include const char *copy_string = "Copyright (C) 2011-2022 Nick Gasson\n" @@ -66,6 +70,7 @@ static int scan_cmd(int start, int argc, char **argv) { const char *commands[] = { "-a", "-e", "-r", "--dump", "--make", "--syntax", "--list", "--init", + "--install", }; for (int i = start; i < argc; i++) { @@ -627,6 +632,85 @@ static int init_cmd(int argc, char **argv) return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; } +static void list_packages(void) +{ + LOCAL_TEXT_BUF tb = tb_new(); + get_libexec_dir(tb); + + DIR *dir = opendir(tb_get(tb)); + tb_rewind(tb); + + if (dir != NULL) { + struct dirent *d; + while ((d = readdir(dir))) { + if (strncmp(d->d_name, "install-", 8)) + continue; + + const char *dot = strrchr(d->d_name, '.'); + if (dot == NULL) + continue; + + const int nchar = dot - d->d_name - 8; + tb_printf(tb, " %.*s", nchar, d->d_name + 8); + } + + closedir(dir); + } + + notef("the following packages can be installed:%s", tb_get(tb)); +} + +static int install_cmd(int argc, char **argv) +{ + static struct option long_options[] = { + { 0, 0, 0, 0 } + }; + + const int next_cmd = scan_cmd(2, argc, argv); + int c, index = 0; + const char *spec = ""; + while ((c = getopt_long(next_cmd, argv, spec, long_options, &index)) != -1) { + switch (c) { + case 0: + // Set a flag + break; + case '?': + bad_option("init", argv); + break; + } + } + + if (argc == optind) { + errorf("missing argument to $bold$--install$$ command"); + list_packages(); + return EXIT_FAILURE; + } + + for (int i = optind; i < next_cmd; i++) { + LOCAL_TEXT_BUF tb = tb_new(); + get_libexec_dir(tb); + tb_printf(tb, "/install-%s.sh", argv[i]); + + struct stat sb; + if (stat(tb_get(tb), &sb) != 0) { + errorf("%s is not an executable script", tb_get(tb)); + list_packages(); + return EXIT_FAILURE; + } + + const char *args[] = { + tb_get(tb), + NULL + }; + run_program(args); + } + + argc -= next_cmd - 1; + argv += next_cmd - 1; + + return argc > 1 ? process_command(argc, argv) : EXIT_SUCCESS; +} + static int syntax_cmd(int argc, char **argv) { static struct option long_options[] = { @@ -758,6 +842,7 @@ static void usage(void) " -r [OPTION]... UNIT\t\tExecute previously elaborated UNIT\n" " --dump [OPTION]... UNIT\tPrint out previously analysed UNIT\n" " --init\t\t\t\tInitialise work library directory\n" + " --install PKG\t\t\tInstall third-party packages\n" " --list\t\t\t\tPrint all units in the library\n" " --make [OPTION]... [UNIT]...\tGenerate makefile to rebuild UNITs\n" " --syntax FILE...\t\tCheck FILEs for syntax errors only\n" @@ -794,7 +879,7 @@ static void usage(void) " --exit-severity=S\tExit after assertion failure of severity S\n" " --format=FMT\tWaveform format is either fst or vcd\n" " --ieee-warnings=\tEnable ('on') or disable ('off') warnings\n" - " \t\t\tfrom IEEE packages\n" + " \t\t\t\t\tfrom IEEE packages\n" " --include=GLOB\tInclude signals matching GLOB in wave dump\n" " --load=PLUGIN\tLoad VHPI plugin at startup\n" " --profile\t\tDisplay detailed statistics at end of run\n" @@ -921,6 +1006,7 @@ static int process_command(int argc, char **argv) { "syntax", no_argument, 0, 's' }, { "list", no_argument, 0, 'l' }, { "init", no_argument, 0, 'i' }, + { "install", no_argument, 0, 'I' }, { 0, 0, 0, 0 } }; @@ -946,6 +1032,8 @@ static int process_command(int argc, char **argv) return list_cmd(argc, argv); case 'i': return init_cmd(argc, argv); + case 'I': + return install_cmd(argc, argv); default: fatal("missing command, try %s --help for usage", PACKAGE); return EXIT_FAILURE; diff --git a/src/util.c b/src/util.c index 37635174..72aed5ba 100644 --- a/src/util.c +++ b/src/util.c @@ -45,6 +45,7 @@ #include #include #include +#include #include #include @@ -1438,7 +1439,7 @@ void nvc_rusage(nvc_rusage_t *ru) #endif } -void run_program(const char *const *args, size_t n_args) +void run_program(const char *const *args) { #if defined __CYGWIN__ || defined __MINGW32__ int status = spawnv(_P_WAIT, args[0], (char *const *)args); @@ -1460,11 +1461,10 @@ void run_program(const char *const *args, size_t n_args) #endif // __CYGWIN__ if (status != 0) { - for (size_t i = 0; i < n_args && args[i]; i++) - fprintf(stderr, "%s%s", i > 0 ? " " : "", args[i]); - fprintf(stderr, "\n"); - fflush(stderr); - fatal("%s failed with status %d", args[0], status); + LOCAL_TEXT_BUF tb = tb_new(); + for (size_t i = 0; args[i] != NULL; i++) + tb_printf(tb, "%s%s", i > 0 ? " " : "", args[i]); + fatal("$bold$%s$$ failed with status %d", tb_get(tb), status); } } @@ -1709,6 +1709,21 @@ char *search_path(const char *name) return xstrdup(name); } +void get_libexec_dir(text_buf_t *tb) +{ +#if defined DEBUG && defined __linux__ && 0 + char buf[PATH_MAX]; + if (readlink("/proc/self/exe", buf, sizeof(buf)) > 0) { + tb_cat(tb, dirname(dirname(buf))); + tb_cat(tb, "/bin"); + } + else + tb_cat(tb, LIBEXECDIR); +#else + tb_cat(tb, LIBEXECDIR); +#endif +} + void progress(const char *fmt, ...) { if (opt_get_int(OPT_VERBOSE)) { diff --git a/src/util.h b/src/util.h index a65041b5..c385f719 100644 --- a/src/util.h +++ b/src/util.h @@ -178,7 +178,7 @@ void nvc_munmap(void *ptr, size_t length); void nvc_memprotect(void *ptr, size_t length, mem_access_t prot); void *mmap_guarded(size_t sz, guard_fault_fn_t fn, void *ctx); -void run_program(const char *const *args, size_t n_args); +void run_program(const char *const *args); text_buf_t *safe_symbol(ident_t id); text_buf_t *unsafe_symbol(const char *text); @@ -244,6 +244,7 @@ void *map_file(int fd, size_t size); void unmap_file(void *ptr, size_t size); void make_dir(const char *path); char *search_path(const char *name); +void get_libexec_dir(text_buf_t *tb); struct cpu_state; void capture_registers(struct cpu_state *cpu); -- 2.39.2