diff --git a/.github/workflows/gold.yml b/.github/workflows/gold.yml index eb46156..4afcbcf 100644 --- a/.github/workflows/gold.yml +++ b/.github/workflows/gold.yml @@ -34,6 +34,15 @@ jobs: - name: Run the test run: cd test/param_override; ./test.sh -debug 15 + gvp2_test_5s: + # Smoke test for bin/gvp2.pl via demo/gvp2/Makefile's pattern-match target. + runs-on: ubuntu-latest + steps: + - name: Check out repository code + uses: actions/checkout@v2 + - name: Run the test + run: cd test/gvp2test; ./test.sh + func_fail_1m: runs-on: ubuntu-latest steps: diff --git a/demo/gvp2/Makefile b/demo/gvp2/Makefile index df80492..5e072a3 100644 --- a/demo/gvp2/Makefile +++ b/demo/gvp2/Makefile @@ -1,13 +1,13 @@ -# Standalone Makefile for the gvp2 demo / smoke test. -# Resolves both tools relative to this directory; no env vars required. +# Standalone Makefile for the gvp2 demo. +# Resolves the tool relative to this directory; no env vars required. +# Regression test lives in test/gvp2test/. HERE := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) GVP2 ?= $(abspath $(HERE)/../../bin/gvp2.pl) -GVP ?= $(abspath $(HERE)/../../gvpy/gvp.pl) ARGS := --incdirs . --defparam WIDTH=16 example.vp -.PHONY: all run rawperl test clean +.PHONY: all run rawperl clean all: run @@ -21,35 +21,6 @@ rawperl: example.rawperl.pl example.rawperl.pl: example.vp example_inc.vph example_lib.pl $(GVP2) $(GVP2) --rawperl $(ARGS) > $@ -# Smoke test: run gvp2.pl on example.vp and verify the output contains every -# feature the template exercises. Strict diff against gvp.pl is not used -# because gvp2.pl inherits Genesis2's parser, which has known cosmetic -# differences (Start/End Include markers, `timescale spacing, no pinclude -# markers) — see the gvp2 design notes. -test: example.v - @ok=1; \ - for pat in \ - 'parameter WIDTH => 16 (command line)' \ - 'module example_demo' \ - 'wire \[15:0\] inc_signal' \ - 'wire \[15:0\] tap_00' \ - 'wire \[15:0\] tap_03' \ - 'Sub /\*PARAMS: WIDTH=>16' \ - 'doubled WIDTH = 32' \ - 'endmodule'; \ - do \ - if grep -q -- "$$pat" example.v; then \ - echo " OK : $$pat"; \ - else \ - echo " MISS : $$pat"; ok=0; \ - fi; \ - done; \ - if [ $$ok -eq 1 ]; then \ - echo "PASS: gvp2.pl smoke test"; \ - else \ - echo "FAIL: gvp2.pl smoke test"; exit 1; \ - fi - clean: rm -f example.v example.rawperl.pl rm -f /tmp/example.vp.*.pl diff --git a/demo/gvp2/example.vp b/demo/gvp2/example.vp index 162e2b6..f01da67 100644 --- a/demo/gvp2/example.vp +++ b/demo/gvp2/example.vp @@ -1,7 +1,7 @@ // gvp2 demo + smoke test: exercises every gvp.pl built-in plus include/pinclude `timescale 1ns/1ps -//;my $WIDTH = parameter(name => 'WIDTH', val => 8); -//;pinclude("example_lib.pl") +//; my $WIDTH = parameter(name => 'WIDTH', val => 8); +//; pinclude("example_lib.pl") module `mname`_demo ( input wire clk, diff --git a/extras/emacs/README.md b/extras/emacs/README.md new file mode 100644 index 0000000..a112735 --- /dev/null +++ b/extras/emacs/README.md @@ -0,0 +1,24 @@ +# Emacs support for `.vp` / `.svp` / `.vph` + +`genesis2-mode` — a major mode for Genesis2 Perl-templated +Verilog/SystemVerilog files. Derives from `verilog-mode`; uses +`mmm-mode` to layer real `perl-mode` on the embedded-Perl regions. + +## Install + +```sh +mkdir -p ~/.emacs.d/lisp/mmm +curl -sSL https://melpa.org/packages/mmm-mode-20240222.428.tar \ + | tar -x --strip-components=1 -C ~/.emacs.d/lisp/mmm +cp genesis2-mode.el ~/.emacs.d/ +``` + +Add to `~/.emacs.d/init.el`: + +```elisp +(add-to-list 'load-path "~/.emacs.d/lisp/mmm") +(require 'mmm-mode) +(load "~/.emacs.d/genesis2-mode") +(setq mmm-submode-decoration-level 0) +(setq mmm-global-mode 'maybe) +``` diff --git a/extras/emacs/genesis2-mode.el b/extras/emacs/genesis2-mode.el new file mode 100644 index 0000000..0dbe852 --- /dev/null +++ b/extras/emacs/genesis2-mode.el @@ -0,0 +1,94 @@ +;;; genesis2-mode.el --- Major mode for Genesis2 .vp/.svp/.vph templates -*- lexical-binding: t; -*- + +;; Author: Genesis2 contributors +;; Keywords: languages, verilog, perl +;; Package-Requires: ((emacs "26.1") (mmm-mode "0.5.9")) +;; +;; This file mirrors `extras/vim/syntax/genesis2.vim'. + + +(require 'verilog-mode) +(require 'mmm-mode) +(require 'mmm-auto) + +(defgroup genesis2 nil + "Major mode for Genesis2 Perl-templated Verilog files." + :group 'languages + :prefix "genesis2-") + +(defface genesis2-delim-face + '((t :inherit font-lock-preprocessor-face)) + "Face for the Genesis2 region delimiters: `//;' and the bracketing backticks." + :group 'genesis2) + +(defface genesis2-sentinel-face + '((t :inherit font-lock-comment-face :weight bold)) + "Face for comment-only Perl lines (`//; # ...')." + :group 'genesis2) + +(defconst genesis2--verilog-backtick-directives + '("timescale" "default_nettype" "include" + "ifdef" "if" "ifndef" "else" "endif") + "Verilog `directive keywords excluded from inline-Perl region matching.") + +(defconst genesis2--font-lock-keywords + `(("^[ \t]*//;[ \t]*#.*$" . 'genesis2-sentinel-face) + ("//;\\(?:[^#]\\|$\\)" 0 'genesis2-delim-face t) + ("`" . 'genesis2-delim-face)) + "Additional font-lock keywords for `genesis2-mode'.") + +;;;###autoload +(define-derived-mode genesis2-mode verilog-mode "Genesis2" + "Major mode for Genesis2 Perl-templated Verilog/SystemVerilog files." + (font-lock-add-keywords nil genesis2--font-lock-keywords)) + +;;;###autoload +(progn + (add-to-list 'auto-mode-alist '("\\.vp\\'" . genesis2-mode)) + (add-to-list 'auto-mode-alist '("\\.svp\\'" . genesis2-mode)) + (add-to-list 'auto-mode-alist '("\\.vph\\'" . genesis2-mode))) + +;; Emacs regex has no lookahead; exclusions are done via :front-verify. + +(defun genesis2--perl-line-verify () + "Return non-nil unless the matched `//;' is a `//; # ...' comment line." + (save-excursion + (goto-char (match-end 0)) + (not (looking-at-p "[ \t]*#")))) + +(defun genesis2--perl-inline-verify () + "Return non-nil unless the matched backtick opens a Verilog directive." + (save-excursion + (goto-char (match-end 0)) + (not (looking-at-p + (concat "\\(?:" + (mapconcat #'regexp-quote + genesis2--verilog-backtick-directives "\\|") + "\\)\\>"))))) + +(mmm-add-classes + '((genesis2-perl-line + :submode perl-mode + :face mmm-code-submode-face + :front "//;" + :front-verify genesis2--perl-line-verify + :back "$" + :include-front nil + :include-back nil) + (genesis2-perl-inline + :submode perl-mode + :face mmm-code-submode-face + :front "\\(?:^\\|[^\\\\]\\)\\(`\\)" + :front-match 1 + :front-verify genesis2--perl-inline-verify + :back "\\(?:^\\|[^\\\\]\\)\\(`\\)" + :back-match 1 + :include-front nil + :include-back nil))) + +(mmm-add-mode-ext-class 'genesis2-mode nil 'genesis2-perl-line) +(mmm-add-mode-ext-class 'genesis2-mode nil 'genesis2-perl-inline) + +(provide 'genesis2-mode) + +;;; genesis2-mode.el ends here diff --git a/extras/vim/README.md b/extras/vim/README.md index 09f11c3..bb801c6 100644 --- a/extras/vim/README.md +++ b/extras/vim/README.md @@ -8,8 +8,8 @@ Highlights: - `//;`-prefixed Perl lines highlighted via embedded `@perlTop`. - Backtick-delimited inline Perl expressions, escape-aware (`` \` ``) and excluding Verilog backtick directives (`` `timescale ``, `` `ifdef ``, ...). -- Sentinel comments (`//; # endforeach`, `//; # endif`, ...) highlighted bold - so block-closers stand out. +- Comment-only Perl lines (`//; # ...`) highlighted bold so they stand out + from regular Perl statements. ## Install @@ -19,11 +19,11 @@ Copy (or symlink) the two directories into your vim runtime: ```sh mkdir -p ~/.vim/after/ftdetect ~/.vim/syntax -cp after/ftdetect/vp.vim ~/.vim/after/ftdetect/vp.vim -cp syntax/vp.vim ~/.vim/syntax/vp.vim +cp after/ftdetect/genesis2.vim ~/.vim/after/ftdetect/genesis2.vim +cp syntax/genesis2.vim ~/.vim/syntax/genesis2.vim ``` -The ftdetect lives under `after/` and uses `set filetype=vp` (force) so it +The ftdetect lives under `after/` and uses `set filetype=genesis2` (force) so it wins against the `verilog_systemverilog` plugin (and any other plugin) whose ftdetect maps `*.vp` to a different filetype and uses `au!` to clear earlier autocmds. @@ -41,6 +41,6 @@ Plug 'Genesis2', { 'rtp': 'vim.vp' } (Adjust the source spec for your fork/clone location.) ## Files -- `after/ftdetect/vp.vim` — maps `*.vp`, `*.svp`, `*.vph` to filetype `vp`, +- `after/ftdetect/genesis2.vim` — maps `*.vp`, `*.svp`, `*.vph` to filetype `genesis2`, forcing the filetype so it overrides plugins that also claim `*.vp`. -- `syntax/vp.vim` — syntax rules layered on top of Verilog/SystemVerilog. +- `syntax/genesis2.vim` — syntax rules layered on top of Verilog/SystemVerilog. diff --git a/extras/vim/after/ftdetect/vp.vim b/extras/vim/after/ftdetect/genesis2.vim similarity index 55% rename from extras/vim/after/ftdetect/vp.vim rename to extras/vim/after/ftdetect/genesis2.vim index 65947ad..25284e3 100644 --- a/extras/vim/after/ftdetect/vp.vim +++ b/extras/vim/after/ftdetect/genesis2.vim @@ -1,6 +1,6 @@ " Use `set filetype=` (force) and run from after/ftdetect so we win against " plugins like verilog_systemverilog whose ftdetect maps *.vp to verilog and " uses `au!` to clear earlier autocmds. -au! BufRead,BufNewFile *.vp set filetype=vp -au! BufRead,BufNewFile *.svp set filetype=vp -au! BufRead,BufNewFile *.vph set filetype=vp +au! BufRead,BufNewFile *.vp set filetype=genesis2 +au! BufRead,BufNewFile *.svp set filetype=genesis2 +au! BufRead,BufNewFile *.vph set filetype=genesis2 diff --git a/extras/vim/syntax/genesis2.vim b/extras/vim/syntax/genesis2.vim new file mode 100644 index 0000000..2220623 --- /dev/null +++ b/extras/vim/syntax/genesis2.vim @@ -0,0 +1,113 @@ +" Vim syntax file +" Language: Genesis2 Perl template (.vp / .svp / .vph) +" Verilog/SystemVerilog base with embedded Perl on `//;` lines and inside +" backtick-delimited inline expressions. + +if version < 600 + syntax clear +elseif exists("b:current_syntax") + finish +endif + +" Base: SystemVerilog if available, else plain Verilog. +if !empty(globpath(&runtimepath, 'syntax/verilog_systemverilog.vim')) + ru! syntax/verilog_systemverilog.vim + set ft=verilog_systemverilog +else + ru! syntax/verilog.vim + set ft=verilog +endif +unlet! b:current_syntax + +" Embedded Perl. Some perl.vim builds bail early if b:current_syntax is set; +" make sure it isn't before we include. +unlet! b:current_syntax +syn include @perlTop syntax/perl.vim +unlet! b:current_syntax + +" //; # ... -- comment-only Perl lines. Highlighted as comments but bold so +" they stand out from regular Perl statements. +syn match genesis2Sentinel +//;\s*#.*$+ containedin=ALL + +" //; -- the rest of the line is Perl (excluding the sentinel form +" above, which is matched separately). +syn region genesis2Line matchgroup=genesis2Delim + \ start=+//;\(\s*#\)\@!+ end=+$+ + \ keepend containedin=ALL contains=@perlTop + +" `expr` -- inline Perl expression. +" * \\\@ -- the rest of the line is Perl (excluding the sentinel form -" above, which is matched separately). -syn region vpLine matchgroup=vpDelim - \ start=+//;\(\s*#\)\@!+ end=+$+ - \ keepend containedin=ALL contains=@perlTop - -" `expr` -- inline Perl expression. -" * \\\@ 16 (command line) + +module example_demo ( + input wire clk, + input wire [15:0] din, + output reg [15:0] dout +); + +// ----- Start Include Of GENESIS_HOME/demo/gvp2/example_inc.vph ----- +// included via //;include("example_inc.vph") - exercises Genesis2 include path +// inline backtick: WIDTH parameter is 16 +wire [15:0] inc_signal; +// ----- End Include Of GENESIS_HOME/demo/gvp2/example_inc.vph ----- + + wire [15:0] tap_00; + wire [15:0] tap_01; + wire [15:0] tap_02; + wire [15:0] tap_03; + + Sub /*PARAMS: WIDTH=>16 */ u_sub1 (.clk(clk), .d(din), .q(dout)); + +// note: doubled WIDTH = 32 +endmodule diff --git a/test/gvp2test/test.sh b/test/gvp2test/test.sh new file mode 100755 index 0000000..963894e --- /dev/null +++ b/test/gvp2test/test.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +USAGE=" + DESCRIPTION: + Smoke test for bin/gvp2.pl: regenerates demo/gvp2/example.v from the + fixtures and diffs against expected_output.v in this directory. + + USAGE: $0 +" +if [ "$1" == "--help" ]; then echo "$USAGE"; exit; fi + +# We should be here: Genesis2/test/gvp2test/ +export GENESIS_HOME=$(cd ../..; pwd) +export PATH=$GENESIS_HOME/bin:$PATH +export PERL5LIB=$GENESIS_HOME/PerlLibs:$GENESIS_HOME/PerlLibs/ExtrasForOldPerlDistributions:$PERL5LIB + +printf '\n\nBUILD\n' +make -C "$GENESIS_HOME/demo/gvp2" clean example.v || exit 13 + +# Strip the absolute GENESIS_HOME prefix so the diff is portable. +actual=$(mktemp) +sed "s|$GENESIS_HOME|GENESIS_HOME|g" "$GENESIS_HOME/demo/gvp2/example.v" > "$actual" + +printf '\n\nCOMPARE diff -u expected_output.v actual\n' +if diff -u expected_output.v "$actual"; then + result=PASS +else + result=FAIL +fi +rm -f "$actual" + +echo '' +echo '------------------------------------------------------------------------' +echo Test result: $result +echo '------------------------------------------------------------------------' +echo '' + +[ "$result" == "PASS" ] || exit 13 +exit 0