Mercurial > emacs
diff lisp/progmodes/verilog-mode.el @ 79545:176f1495425c
New file.
author | Dan Nicolaescu <dann@ics.uci.edu> |
---|---|
date | Sat, 08 Dec 2007 17:58:56 +0000 |
parents | |
children | 0413a70bb454 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lisp/progmodes/verilog-mode.el Sat Dec 08 17:58:56 2007 +0000 @@ -0,0 +1,10335 @@ +;; verilog-mode.el --- major mode for editing verilog source in Emacs +;; +;; $Id: verilog-mode.el 377 2007-12-07 17:21:25Z wsnyder $ + +;; Copyright (C) 1996-2007 Free Software Foundation, Inc. + +;; Author: Michael McNamara (mac@verilog.com) +;; http://www.verilog.com +;; +;; AUTO features, signal, modsig; by: Wilson Snyder +;; (wsnyder@wsnyder.org) +;; http://www.veripool.com +;; Keywords: languages + +;; This program is free software; you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation; either version 2 of the License, or +;; (at your option) any later version. + +;; This program is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with this program; if not, write to the Free Software +;; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +;;; Commentary: + +;; This mode borrows heavily from the Pascal-mode and the cc-mode of emacs + +;; USAGE +;; ===== + +;; A major mode for editing Verilog HDL source code. When you have +;; entered Verilog mode, you may get more info by pressing C-h m. You +;; may also get online help describing various functions by: C-h f +;; <Name of function you want described> + +;; KNOWN BUGS / BUG REPORTS +;; ======================= + +;; Verilog is a rapidly evolving language, and hence this mode is +;; under continuous development. Hence this is beta code, and likely +;; has bugs. Please report any and all bugs to me at mac@verilog.com. +;; Please use verilog-submit-bug-report to submit a report; type C-c +;; C-b to invoke this and as a result I will have a much easier time +;; of reproducing the bug you find, and hence fixing it. + +;; INSTALLING THE MODE +;; =================== + +;; An older version of this mode may be already installed as a part of +;; your environment, and one method of updating would be to update +;; your emacs environment. Sometimes this is difficult for local +;; political/control reasons, and hence you can always install a +;; private copy (or even a shared copy) which overrides the system +;; default. + +;; You can get step by step help in installing this file by going to +;; <http://www.verilog.com/emacs_install.html> + +;; The short list of installation instructions are: To set up +;; automatic verilog mode, put this file in your load path, and put +;; the following in code (please un comment it first!) in your +;; .emacs, or in your site's site-load.el + +; (autoload 'verilog-mode "verilog-mode" "Verilog mode" t ) +; (setq auto-mode-alist (cons '("\\.v\\'" . verilog-mode) auto-mode-alist)) +; (setq auto-mode-alist (cons '("\\.dv\\'" . verilog-mode) auto-mode-alist)) + +;; If you want to customize Verilog mode to fit your needs better, +;; you may add these lines (the values of the variables presented +;; here are the defaults). Note also that if you use an emacs that +;; supports custom, it's probably better to use the custom menu to +;; edit these. +;; +;; Be sure to examine at the help for verilog-auto, and the other +;; verilog-auto-* functions for some major coding time savers. +;; +; ;; User customization for Verilog mode +; (setq verilog-indent-level 3 +; verilog-indent-level-module 3 +; verilog-indent-level-declaration 3 +; verilog-indent-level-behavioral 3 +; verilog-indent-level-directive 1 +; verilog-case-indent 2 +; verilog-auto-newline t +; verilog-auto-indent-on-newline t +; verilog-tab-always-indent t +; verilog-auto-endcomments t +; verilog-minimum-comment-distance 40 +; verilog-indent-begin-after-if t +; verilog-auto-lineup '(all) +; verilog-highlight-p1800-keywords nil +; verilog-linter "my_lint_shell_command" +; ) + +;; + +;;; History: +;; +;; +;;; Code: + +(provide 'verilog-mode) + +;; This variable will always hold the version number of the mode +(defconst verilog-mode-version (substring "$$Revision: 377 $$" 12 -3) + "Version of this verilog mode.") +(defconst verilog-mode-release-date (substring "$$Date: 2007-12-07 12:21:25 -0500 (Fri, 07 Dec 2007) $$" 8 -3) + "Version of this verilog mode.") + +(defun verilog-version () + "Inform caller of the version of this file." + (interactive) + (message (concat "Using verilog-mode version " verilog-mode-version) )) + +;; Insure we have certain packages, and deal with it if we don't +(if (fboundp 'eval-when-compile) + (eval-when-compile + (require 'verilog-mode) + (condition-case nil + (require 'imenu) + (error nil)) + (condition-case nil + (require 'reporter) + (error nil)) + (condition-case nil + (require 'easymenu) + (error nil)) + (condition-case nil + (require 'regexp-opt) + (error nil)) + (condition-case nil + (load "skeleton") ;; bug in 19.28 through 19.30 skeleton.el, not provided. + (error nil)) + (condition-case nil + (require 'vc) + (error nil)) + (condition-case nil + (if (fboundp 'when) + nil ;; fab + (defmacro when (var &rest body) + (` (cond ( (, var) (,@ body)))))) + (error nil)) + (condition-case nil + (if (fboundp 'unless) + nil ;; fab + (defmacro unless (var &rest body) + (` (if (, var) nil (,@ body))))) + (error nil)) + (condition-case nil + (if (fboundp 'store-match-data) + nil ;; fab + (defmacro store-match-data (&rest args) nil)) + (error nil)) + (condition-case nil + (if (boundp 'current-menubar) + nil ;; great + (progn + (defmacro set-buffer-menubar (&rest args) nil) + (defmacro add-submenu (&rest args) nil)) + ) + (error nil)) + (condition-case nil + (if (fboundp 'zmacs-activate-region) + nil ;; great + (defmacro zmacs-activate-region (&rest args) nil)) + (error nil)) + (condition-case nil + (if (fboundp 'char-before) + nil ;; great + (defmacro char-before (&rest body) + (` (char-after (1- (point)))))) + (error nil)) + ;; Requires to define variables that would be "free" warnings + (condition-case nil + (require 'font-lock) + (error nil)) + (condition-case nil + (require 'compile) + (error nil)) + (condition-case nil + (require 'custom) + (error nil)) + (condition-case nil + (require 'dinotrace) + (error nil)) + (condition-case nil + (if (fboundp 'dinotrace-unannotate-all) + nil ;; great + (defun dinotrace-unannotate-all (&rest args) nil)) + (error nil)) + (condition-case nil + (if (fboundp 'customize-apropos) + nil ;; great + (defun customize-apropos (&rest args) nil)) + (error nil)) + (condition-case nil + (if (fboundp 'match-string-no-properties) + nil ;; great + (defsubst match-string-no-properties (num &optional string) + "Return string of text matched by last search, without text properties. +NUM specifies which parenthesized expression in the last regexp. + Value is nil if NUMth pair didn't match, or there were less than NUM pairs. +Zero means the entire text matched by the whole regexp or whole string. +STRING should be given if the last search was by `string-match' on STRING." + (if (match-beginning num) + (if string + (let ((result + (substring string (match-beginning num) (match-end num)))) + (set-text-properties 0 (length result) nil result) + result) + (buffer-substring-no-properties (match-beginning num) + (match-end num) + (current-buffer) + ))))) + (error nil)) + (if (and (featurep 'custom) (fboundp 'custom-declare-variable)) + nil ;; We've got what we needed + ;; We have the old custom-library, hack around it! + (defmacro defgroup (&rest args) nil) + (defmacro customize (&rest args) + (message "Sorry, Customize is not available with this version of emacs")) + (defmacro defcustom (var value doc &rest args) + (` (defvar (, var) (, value) (, doc)))) + ) + (if (fboundp 'defface) + nil ; great! + (defmacro defface (var value doc &rest args) + (` (make-face (, var)))) + ) + + (if (and (featurep 'custom) (fboundp 'customize-group)) + nil ;; We've got what we needed + ;; We have an intermediate custom-library, hack around it! + (defmacro customize-group (var &rest args) + (`(customize (, var) ))) + ) + + )) +;; Provide a regular expression optimization routine, using regexp-opt +;; if provided by the user's elisp libraries +(eval-and-compile + (if (fboundp 'regexp-opt) + ;; regexp-opt is defined, does it take 3 or 2 arguments? + (if (fboundp 'function-max-args) + (case (function-max-args `regexp-opt) + ( 3 ;; It takes 3 + (condition-case nil ; Hide this defun from emacses + ;with just a two input regexp + (defun verilog-regexp-opt (a b) + "Deal with differing number of required arguments for `regexp-opt'. + Call 'regexp-opt' on A and B." + (regexp-opt a b 't) + ) + (error nil)) + ) + ( 2 ;; It takes 2 + (defun verilog-regexp-opt (a b) + "Call 'regexp-opt' on A and B." + (regexp-opt a b)) + ) + ( t nil)) + ;; We can't tell; assume it takes 2 + (defun verilog-regexp-opt (a b) + "Call 'regexp-opt' on A and B." + (regexp-opt a b)) + ) + ;; There is no regexp-opt, provide our own + (defun verilog-regexp-opt (strings &optional paren shy) + (let ((open (if paren "\\(" "")) (close (if paren "\\)" ""))) + (concat open (mapconcat 'regexp-quote strings "\\|") close))) + )) + +(eval-when-compile + (defun verilog-regexp-words (a) + "Call 'regexp-opt' with word delimiters." + (concat "\\<" (verilog-regexp-opt a t) "\\>"))) + +(defun verilog-regexp-words (a) + "Call 'regexp-opt' with word delimiters for the words A." + (concat "\\<" (verilog-regexp-opt a t) "\\>")) + +(defun verilog-customize () + "Link to customize screen for Verilog." + (interactive) + (customize-group 'verilog-mode)) + +(defun verilog-font-customize () + "Link to customize fonts used for Verilog." + (interactive) + (customize-apropos "font-lock-*" 'faces)) + +(defgroup verilog-mode nil + "Facilitates easy editing of Verilog source text" + :group 'languages) + +; (defgroup verilog-mode-fonts nil +; "Facilitates easy customization fonts used in Verilog source text" +; :link '(customize-apropos "font-lock-*" 'faces) +; :group 'verilog-mode) + +(defgroup verilog-mode-indent nil + "Customize indentation and highlighting of verilog source text" + :group 'verilog-mode) + +(defgroup verilog-mode-actions nil + "Customize actions on verilog source text" + :group 'verilog-mode) + +(defgroup verilog-mode-auto nil + "Customize AUTO actions when expanding verilog source text" + :group 'verilog-mode) + +(defcustom verilog-linter + "echo 'No verilog-linter set, see \"M-x describe-variable verilog-linter\"'" + "*Unix program and arguments to call to run a lint checker on verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defcustom verilog-coverage + "echo 'No verilog-coverage set, see \"M-x describe-variable verilog-coverage\"'" + "*Program and arguments to use to annotate for coverage verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defcustom verilog-simulator + "echo 'No verilog-simulator set, see \"M-x describe-variable verilog-simulator\"'" + "*Program and arguments to use to interpret verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defcustom verilog-compiler + "echo 'No verilog-compiler set, see \"M-x describe-variable verilog-compiler\"'" + "*Program and arguments to use to compile verilog source. +Depending on the `verilog-set-compile-command', this may be invoked when +you type \\[compile]. When the compile completes, \\[next-error] will take +you to the next lint error." + :type 'string + :group 'verilog-mode-actions) + +(defvar verilog-tool 'verilog-linter + "Which tool to use for building compiler-command. +Either nil, `verilog-linter, `verilog-coverage, `verilog-simulator, or +`verilog-compiler. Alternatively use the \"Choose Compilation Action\" +menu. See `verilog-set-compile-command' for more information.") + +(defcustom verilog-highlight-translate-off nil + "*Non-nil means background-highlight code excluded from translation. +That is, all code between \"// synopsys translate_off\" and +\"// synopsys translate_on\" is highlighted using a different background color +\(face `verilog-font-lock-translate-off-face'). + +Note: This will slow down on-the-fly fontification (and thus editing). + +Note: Activate the new setting in a Verilog buffer by re-fontifying it (menu +entry \"Fontify Buffer\"). XEmacs: turn off and on font locking." + :type 'boolean + :group 'verilog-mode-indent) + +(defcustom verilog-indent-level 3 + "*Indentation of Verilog statements with respect to containing block." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-level-module 3 + "*Indentation of Module level Verilog statements. (eg always, initial) +Set to 0 to get initial and always statements lined up on the left side of +your screen." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-level-declaration 3 + "*Indentation of declarations with respect to containing block. +Set to 0 to get them list right under containing block." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-declaration-macros nil + "*How to treat macro expansions in a declaration. +If nil, indent as: + input [31:0] a; + input `CP; + output c; +If non nil, treat as: + input [31:0] a; + input `CP ; + output c;" + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-indent-lists t + "*How to treat indenting items in a list. +If t (the default), indent as: + always @( posedge a or + reset ) begin + +If nil, treat as: + always @( posedge a or + reset ) begin" + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-indent-level-behavioral 3 + "*Absolute indentation of first begin in a task or function block. +Set to 0 to get such code to start at the left side of the screen." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-indent-level-directive 1 + "*Indentation to add to each level of `ifdef declarations. +Set to 0 to have all directives start at the left side of the screen." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-cexp-indent 2 + "*Indentation of Verilog statements split across lines." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-case-indent 2 + "*Indentation for case statements." + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-auto-newline t + "*True means automatically newline after semicolons." + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-auto-indent-on-newline t + "*True means automatically indent line after newline." + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-tab-always-indent t + "*True means TAB should always re-indent the current line. +Nil means TAB will only reindent when at the beginning of the line." + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-tab-to-comment nil + "*True means TAB moves to the right hand column in preparation for a comment." + :group 'verilog-mode-actions + :type 'boolean) + +(defcustom verilog-indent-begin-after-if t + "*If true, indent begin statements following if, else, while, for and repeat. +Otherwise, line them up." + :group 'verilog-mode-indent + :type 'boolean ) + + +(defcustom verilog-align-ifelse nil + "*If true, align `else' under matching `if'. +Otherwise else is lined up with first character on line holding matching if." + :group 'verilog-mode-indent + :type 'boolean ) + +(defcustom verilog-minimum-comment-distance 10 + "*Minimum distance (in lines) between begin and end required before a comment. +Setting this variable to zero results in every end acquiring a comment; the +default avoids too many redundant comments in tight quarters" + :group 'verilog-mode-indent + :type 'integer) + +(defcustom verilog-auto-lineup '(declaration) + "*Algorithm for lining up statements on multiple lines. + +If this list contains the symbol 'all', then all line ups described below +are done. + +If this list contains the symbol 'declaration', then declarations are lined up +with any preceding declarations, taking into account widths and the like, so +for example the code: + reg [31:0] a; + reg b; +would become + reg [31:0] a; + reg b; + +If this list contains the symbol 'assignment', then assignments are lined up +with any preceding assignments, so for example the code + a_long_variable = b + c; + d = e + f; +would become + a_long_variable = b + c; + d = e + f;" + +;; The following is not implemented: +;If this list contains the symbol 'case', then case items are lined up +;with any preceding case items, so for example the code +; case (a) begin +; a_long_state : a = 3; +; b: a = 4; +; endcase +;would become +; case (a) begin +; a_long_state : a = 3; +; b : a = 4; +; endcase +; + + :group 'verilog-mode-indent + :type 'list ) + +(defcustom verilog-highlight-p1800-keywords nil + "*If true highlight words newly reserved by IEEE-1800 in +verilog-font-lock-p1800-face in order to gently suggest changing where +these words are used as variables to something else. Nil means highlight +these words as appropriate for the SystemVerilog IEEE-1800 standard. Note +that changing this will require restarting emacs to see the effect as font +color choices are cached by emacs" + :group 'verilog-mode-indent + :type 'boolean) + +(defcustom verilog-auto-endcomments t + "*True means insert a comment /* ... */ after 'end's. +The name of the function or case will be set between the braces." + :group 'verilog-mode-actions + :type 'boolean ) + +(defcustom verilog-auto-read-includes nil + "*True means to automatically read includes before AUTOs. +This will do a `verilog-read-defines' and `verilog-read-includes' before +each AUTO expansion. This makes it easier to embed defines and includes, +but can result in very slow reading times if there are many or large +include files." + :group 'verilog-mode-actions + :type 'boolean ) + +(defcustom verilog-auto-save-policy nil + "*Non-nil indicates action to take when saving a Verilog buffer with AUTOs. +A value of `force' will always do a \\[verilog-auto] automatically if +needed on every save. A value of `detect' will do \\[verilog-auto] +automatically when it thinks necessary. A value of `ask' will query the +user when it thinks updating is needed. + +You should not rely on the 'ask or 'detect policies, they are safeguards +only. They do not detect when AUTOINSTs need to be updated because a +sub-module's port list has changed." + :group 'verilog-mode-actions + :type '(choice (const nil) (const ask) (const detect) (const force))) + +(defcustom verilog-auto-star-expand t + "*Non-nil indicates to expand a SystemVerilog .* instance ports. +They will be expanded in the same way as if there was a AUTOINST in the +instantiation. See also `verilog-auto-star' and `verilog-auto-star-save'." + :group 'verilog-mode-actions + :type 'boolean) + +(defcustom verilog-auto-star-save nil + "*Non-nil indicates to save to disk SystemVerilog .* instance expansions. +Nil indicates direct connections will be removed before saving. Only +meaningful to those created due to `verilog-auto-star-expand' being set. + +Instead of setting this, you may want to use /*AUTOINST*/, which will +always be saved." + :group 'verilog-mode-actions + :type 'boolean) + +(defvar verilog-auto-update-tick nil + "Modification tick at which autos were last performed.") + +(defvar verilog-auto-last-file-locals nil + "Text from file-local-variables during last evaluation.") + +(defvar verilog-error-regexp-add-didit nil) +(defvar verilog-error-regexp nil) +(setq verilog-error-regexp-add-didit nil + verilog-error-regexp + '( + ; SureLint +;; ("[^\n]*\\[\\([^:]+\\):\\([0-9]+\\)\\]" 1 2) + ; Most SureFire tools + ("\\(WARNING\\|ERROR\\|INFO\\)[^:]*: \\([^,]+\\), \\(line \\|\\)\\([0-9]+\\):" 2 4 ) + ("\ +\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)\\([) \t]\\|\ +:\\([^0-9\n]\\|\\([0-9]+:\\)\\)\\)" 1 2 5) + ; xsim + ; Error! in file /homes/mac/Axis/Xsim/test.v at line 13 [OBJ_NOT_DECLARED] + ("\\(Error\\|Warning\\).*in file (\\([^ \t]+\\) at line *\\([0-9]+\\))" 2 3) + ; vcs + ("\\(Error\\|Warning\\):[^(]*(\\([^ \t]+\\) line *\\([0-9]+\\))" 2 3) + ("Warning:.*(port.*(\\([^ \t]+\\) line \\([0-9]+\\))" 1 2) + ("\\(Error\\|Warning\\):[\n.]*\\([^ \t]+\\) *\\([0-9]+\\):" 2 3) + ("syntax error:.*\n\\([^ \t]+\\) *\\([0-9]+\\):" 1 2) + ; Verilator + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 3 4) + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 3 4) + ; vxl + ("\\(Error\\|Warning\\)!.*\n?.*\"\\([^\"]+\\)\", \\([0-9]+\\)" 2 3) + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+\\([0-9]+\\):.*$" 1 2) ; vxl + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+line[ \t]+\\([0-9]+\\):.*$" 1 2) + ; nc-verilog + (".*\\*[WE],[0-9A-Z]+ (\\([^ \t,]+\\),\\([0-9]+\\)|" 1 2) + ; Leda + ("In file \\([^ \t]+\\)[ \t]+line[ \t]+\\([0-9]+\\):\n[^\n]*\n[^\n]*\n\\[\\(Warning\\|Error\\|Failure\\)\\][^\n]*" 1 2) + ) +; "*List of regexps for verilog compilers, like verilint. See compilation-error-regexp-alist for the formatting." +) + +(defvar verilog-error-font-lock-keywords + '( + ("[^\n]*\\[\\([^:]+\\):\\([0-9]+\\)\\]" 1 bold t) + ("[^\n]*\\[\\([^:]+\\):\\([0-9]+\\)\\]" 2 bold t) + + ("\\(WARNING\\|ERROR\\|INFO\\): \\([^,]+\\), line \\([0-9]+\\):" 2 bold t) + ("\\(WARNING\\|ERROR\\|INFO\\): \\([^,]+\\), line \\([0-9]+\\):" 3 bold t) + + ("\ +\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)\\([) \t]\\|\ +:\\([^0-9\n]\\|\\([0-9]+:\\)\\)\\)" 1 bold t) + ("\ +\\([a-zA-Z]?:?[^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)\\([) \t]\\|\ +:\\([^0-9\n]\\|\\([0-9]+:\\)\\)\\)" 1 bold t) + + ("\\(Error\\|Warning\\):[^(]*(\\([^ \t]+\\) line *\\([0-9]+\\))" 2 bold t) + ("\\(Error\\|Warning\\):[^(]*(\\([^ \t]+\\) line *\\([0-9]+\\))" 3 bold t) + + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 3 bold t) + ("%?\\(Error\\|Warning\\)\\(-[^:]+\\|\\):[\n ]*\\([^ \t:]+\\):\\([0-9]+\\):" 4 bold t) + + ("Warning:.*(port.*(\\([^ \t]+\\) line \\([0-9]+\\))" 1 bold t) + ("Warning:.*(port.*(\\([^ \t]+\\) line \\([0-9]+\\))" 1 bold t) + + ("\\(Error\\|Warning\\):[\n.]*\\([^ \t]+\\) *\\([0-9]+\\):" 2 bold t) + ("\\(Error\\|Warning\\):[\n.]*\\([^ \t]+\\) *\\([0-9]+\\):" 3 bold t) + + ("syntax error:.*\n\\([^ \t]+\\) *\\([0-9]+\\):" 1 bold t) + ("syntax error:.*\n\\([^ \t]+\\) *\\([0-9]+\\):" 2 bold t) + ; vxl + ("\\(Error\\|Warning\\)!.*\n?.*\"\\([^\"]+\\)\", \\([0-9]+\\)" 2 bold t) + ("\\(Error\\|Warning\\)!.*\n?.*\"\\([^\"]+\\)\", \\([0-9]+\\)" 2 bold t) + + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+\\([0-9]+\\):.*$" 1 bold t) + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+\\([0-9]+\\):.*$" 2 bold t) + + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+line[ \t]+\\([0-9]+\\):.*$" 1 bold t) + ("([WE][0-9A-Z]+)[ \t]+\\([^ \t\n,]+\\)[, \t]+line[ \t]+\\([0-9]+\\):.*$" 2 bold t) + ; nc-verilog + (".*[WE],[0-9A-Z]+ (\\([^ \t,]+\\),\\([0-9]+\\)|" 1 bold t) + (".*[WE],[0-9A-Z]+ (\\([^ \t,]+\\),\\([0-9]+\\)|" 2 bold t) + ; Leda + ("In file \\([^ \t]+\\)[ \t]+line[ \t]+\\([0-9]+\\):\n[^\n]*\n[^\n]*\n\\[\\(Warning\\|Error\\|Failure\\)\\][^\n]*" 1 bold t) + ("In file \\([^ \t]+\\)[ \t]+line[ \t]+\\([0-9]+\\):\n[^\n]*\n[^\n]*\n\\[\\(Warning\\|Error\\|Failure\\)\\][^\n]*" 2 bold t) + ) + "*Keywords to also highlight in Verilog *compilation* buffers." + ) + +(defcustom verilog-library-flags '("") + "*List of standard Verilog arguments to use for /*AUTOINST*/. +These arguments are used to find files for `verilog-auto', and match +the flags accepted by a standard Verilog-XL simulator. + + -f filename Reads more `verilog-library-flags' from the filename. + +incdir+dir Adds the directory to `verilog-library-directories'. + -Idir Adds the directory to `verilog-library-directories'. + -y dir Adds the directory to `verilog-library-directories'. + +libext+.v Adds the extensions to `verilog-library-extensions'. + -v filename Adds the filename to `verilog-library-files'. + + filename Adds the filename to `verilog-library-files'. + This is not recommended, -v is a better choice. + +You might want these defined in each file; put at the *END* of your file +something like: + + // Local Variables: + // verilog-library-flags:(\"-y dir -y otherdir\") + // End: + +Verilog-mode attempts to detect changes to this local variable, but they +are only insured to be correct when the file is first visited. Thus if you +have problems, use \\[find-alternate-file] RET to have these take effect. + +See also the variables mentioned above." + :group 'verilog-mode-auto + :type '(repeat string)) + +(defcustom verilog-library-directories '(".") + "*List of directories when looking for files for /*AUTOINST*/. +The directory may be relative to the current file, or absolute. +Environment variables are also expanded in the directory names. +Having at least the current directory is a good idea. + +You might want these defined in each file; put at the *END* of your file +something like: + + // Local Variables: + // verilog-library-directories:(\".\" \"subdir\" \"subdir2\") + // End: + +Verilog-mode attempts to detect changes to this local variable, but they +are only insured to be correct when the file is first visited. Thus if you +have problems, use \\[find-alternate-file] RET to have these take effect. + +See also `verilog-library-flags', `verilog-library-files' +and `verilog-library-extensions'." + :group 'verilog-mode-auto + :type '(repeat file)) + +(defcustom verilog-library-files '() + "*List of files to search for modules when looking for AUTOINST files. +This is a complete path, usually to a technology file with many standard +cells defined in it. + +You might want these defined in each file; put at the *END* of your file +something like: + + // Local Variables: + // verilog-library-files:(\"/some/path/technology.v\" \"/some/path/tech2.v\") + // End: + +Verilog-mode attempts to detect changes to this local variable, but they +are only insured to be correct when the file is first visited. Thus if you +have problems, use \\[find-alternate-file] RET to have these take effect. + +See also `verilog-library-flags', `verilog-library-directories'." + :group 'verilog-mode-auto + :type '(repeat directory)) + +(defcustom verilog-library-extensions '(".v") + "*List of extensions to use when looking for files for /*AUTOINST*/. +See also `verilog-library-flags', `verilog-library-directories'." + :type '(repeat string) + :group 'verilog-mode-auto) + +(defcustom verilog-active-low-regexp nil + "*If set, treat signals matching this regexp as active low. +This is used for AUTORESET and AUTOTIEOFF. For proper behavior, +you will probably also need `verilog-auto-reset-widths' set." + :group 'verilog-mode-auto + :type 'string) + +(defcustom verilog-auto-sense-include-inputs nil + "*If true, AUTOSENSE should include all inputs. +If nil, only inputs that are NOT output signals in the same block are +included." + :type 'boolean + :group 'verilog-mode-auto) + +(defcustom verilog-auto-sense-defines-constant nil + "*If true, AUTOSENSE should assume all defines represent constants. +When true, the defines will not be included in sensitivity lists. To +maintain compatibility with other sites, this should be set at the bottom +of each verilog file that requires it, rather than being set globally." + :type 'boolean + :group 'verilog-mode-auto) + +(defcustom verilog-auto-reset-widths t + "*If true, AUTORESET should determine the width of signals. +This is then used to set the width of the zero (32'h0 for example). This +is required by some lint tools that aren't smart enough to ignore widths of +the constant zero. This may result in ugly code when parameters determine +the MSB or LSB of a signal inside a AUTORESET." + :type 'boolean + :group 'verilog-mode-auto) + +(defcustom verilog-assignment-delay "" + "*Text used for delays in delayed assignments. Add a trailing space if set." + :type 'string + :group 'verilog-mode-auto) + +(defcustom verilog-auto-inst-vector t + "*If true, when creating default ports with AUTOINST, use bus subscripts. +If nil, skip the subscript when it matches the entire bus as declared in +the module (AUTOWIRE signals always are subscripted, you must manually +declare the wire to have the subscripts removed.) Nil may speed up some +simulators, but is less general and harder to read, so avoid." + :group 'verilog-mode-auto + :type 'boolean ) + +(defcustom verilog-auto-inst-template-numbers nil + "*If true, when creating templated ports with AUTOINST, add a comment. +The comment will add the line number of the template that was used for that +port declaration. Setting this aids in debugging, but nil is suggested for +regular use to prevent large numbers of merge conflicts." + :group 'verilog-mode-auto + :type 'boolean ) + +(defvar verilog-auto-inst-column 40 + "Column number for first part of auto-inst.") + +(defcustom verilog-auto-input-ignore-regexp nil + "*If set, when creating AUTOINPUT list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-auto-inout-ignore-regexp nil + "*If set, when creating AUTOINOUT list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-auto-output-ignore-regexp nil + "*If set, when creating AUTOOUTPUT list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-auto-unused-ignore-regexp nil + "*If set, when creating AUTOUNUSED list, ignore signals matching this regexp. +See the \\[verilog-faq] for examples on using this." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-typedef-regexp nil + "*If non-nil, regular expression that matches Verilog-2001 typedef names. +For example, \"_t$\" matches typedefs named with _t, as in the C language." + :group 'verilog-mode-auto + :type 'string ) + +(defcustom verilog-mode-hook 'verilog-set-compile-command + "*Hook (List of functions) run after verilog mode is loaded." + :type 'hook + :group 'verilog-mode) + +(defcustom verilog-auto-hook nil + "*Hook run after `verilog-mode' updates AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-before-auto-hook nil + "*Hook run before `verilog-mode' updates AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-delete-auto-hook nil + "*Hook run after `verilog-mode' deletes AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-before-delete-auto-hook nil + "*Hook run before `verilog-mode' deletes AUTOs." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-getopt-flags-hook nil + "*Hook run after `verilog-getopt-flags' determines the Verilog option lists." + :type 'hook + :group 'verilog-mode-auto) + +(defcustom verilog-before-getopt-flags-hook nil + "*Hook run before `verilog-getopt-flags' determines the Verilog option lists." + :type 'hook + :group 'verilog-mode-auto) + +(defvar verilog-imenu-generic-expression + '((nil "^\\s-*\\(\\(m\\(odule\\|acromodule\\)\\)\\|primitive\\)\\s-+\\([a-zA-Z0-9_.:]+\\)" 4) + ("*Vars*" "^\\s-*\\(reg\\|wire\\)\\s-+\\(\\|\\[[^]]+\\]\\s-+\\)\\([A-Za-z0-9_]+\\)" 3)) + "Imenu expression for Verilog-mode. See `imenu-generic-expression'.") + +;; +;; provide a verilog-header function. +;; Customization variables: +;; +(defvar verilog-date-scientific-format nil + "*If non-nil, dates are written in scientific format (e.g. 1997/09/17). +If nil, in European format (e.g. 17.09.1997). The brain-dead American +format (e.g. 09/17/1997) is not supported.") + +(defvar verilog-company nil + "*Default name of Company for verilog header. +If set will become buffer local.") + +(defvar verilog-project nil + "*Default name of Project for verilog header. +If set will become buffer local.") + +(define-abbrev-table 'verilog-mode-abbrev-table ()) + +(defvar verilog-mode-map () + "Keymap used in Verilog mode.") +(if verilog-mode-map + () + (setq verilog-mode-map (make-sparse-keymap)) + (define-key verilog-mode-map ";" 'electric-verilog-semi) + (define-key verilog-mode-map [(control 59)] 'electric-verilog-semi-with-comment) + (define-key verilog-mode-map ":" 'electric-verilog-colon) + ;;(define-key verilog-mode-map "=" 'electric-verilog-equal) + (define-key verilog-mode-map "\`" 'electric-verilog-tick) + (define-key verilog-mode-map "\t" 'electric-verilog-tab) + (define-key verilog-mode-map "\r" 'electric-verilog-terminate-line) + ;; backspace/delete key bindings + (define-key verilog-mode-map [backspace] 'backward-delete-char-untabify) + (unless (boundp 'delete-key-deletes-forward) ; XEmacs variable + (define-key verilog-mode-map [delete] 'delete-char) + (define-key verilog-mode-map [(meta delete)] 'kill-word)) + (define-key verilog-mode-map "\M-\C-b" 'electric-verilog-backward-sexp) + (define-key verilog-mode-map "\M-\C-f" 'electric-verilog-forward-sexp) + (define-key verilog-mode-map "\M-\r" `electric-verilog-terminate-and-indent) + (define-key verilog-mode-map "\M-\t" 'verilog-complete-word) + (define-key verilog-mode-map "\M-?" 'verilog-show-completions) + (define-key verilog-mode-map [(meta control h)] 'verilog-mark-defun) + (define-key verilog-mode-map "\C-c\`" 'verilog-lint-off) + (define-key verilog-mode-map "\C-c\*" 'verilog-delete-auto-star-implicit) + (define-key verilog-mode-map "\C-c\C-r" 'verilog-label-be) + (define-key verilog-mode-map "\C-c\C-i" 'verilog-pretty-declarations) + (define-key verilog-mode-map "\C-c=" 'verilog-pretty-expr) + (define-key verilog-mode-map "\C-c\C-b" 'verilog-submit-bug-report) + (define-key verilog-mode-map "\M-*" 'verilog-star-comment) + (define-key verilog-mode-map "\C-c\C-c" 'verilog-comment-region) + (define-key verilog-mode-map "\C-c\C-u" 'verilog-uncomment-region) + (define-key verilog-mode-map "\M-\C-a" 'verilog-beg-of-defun) + (define-key verilog-mode-map "\M-\C-e" 'verilog-end-of-defun) + (define-key verilog-mode-map "\C-c\C-d" 'verilog-goto-defun) + (define-key verilog-mode-map "\C-c\C-k" 'verilog-delete-auto) + (define-key verilog-mode-map "\C-c\C-a" 'verilog-auto) + (define-key verilog-mode-map "\C-c\C-s" 'verilog-auto-save-compile) + (define-key verilog-mode-map "\C-c\C-z" 'verilog-inject-auto) + (define-key verilog-mode-map "\C-c\C-e" 'verilog-expand-vector) + (define-key verilog-mode-map "\C-c\C-h" 'verilog-header) + ) + +;; menus +(defvar verilog-xemacs-menu + '("Verilog" + ("Choose Compilation Action" + ["None" + (progn + (setq verilog-tool nil) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool nil)] + ["Lint" + (progn + (setq verilog-tool 'verilog-linter) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-linter)] + ["Coverage" + (progn + (setq verilog-tool 'verilog-coverage) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-coverage)] + ["Simulator" + (progn + (setq verilog-tool 'verilog-simulator) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-simulator)] + ["Compiler" + (progn + (setq verilog-tool 'verilog-compiler) + (verilog-set-compile-command)) + :style radio + :selected (equal verilog-tool `verilog-compiler)] + ) + ("Move" + ["Beginning of function" verilog-beg-of-defun t] + ["End of function" verilog-end-of-defun t] + ["Mark function" verilog-mark-defun t] + ["Goto function/module" verilog-goto-defun t] + ["Move to beginning of block" electric-verilog-backward-sexp t] + ["Move to end of block" electric-verilog-forward-sexp t] + ) + ("Comments" + ["Comment Region" verilog-comment-region t] + ["UnComment Region" verilog-uncomment-region t] + ["Multi-line comment insert" verilog-star-comment t] + ["Lint error to comment" verilog-lint-off t] + ) + "----" + ["Compile" compile t] + ["AUTO, Save, Compile" verilog-auto-save-compile t] + ["Next Compile Error" next-error t] + ["Ignore Lint Warning at point" verilog-lint-off t] + "----" + ["Line up declarations around point" verilog-pretty-declarations t] + ["Line up equations around point" verilog-pretty-expr t] + ["Redo/insert comments on every end" verilog-label-be t] + ["Expand [x:y] vector line" verilog-expand-vector t] + ["Insert begin-end block" verilog-insert-block t] + ["Complete word" verilog-complete-word t] + "----" + ["Recompute AUTOs" verilog-auto t] + ["Kill AUTOs" verilog-delete-auto t] + ["Inject AUTOs" verilog-inject-auto t] + ("AUTO Help..." + ["AUTO General" (describe-function 'verilog-auto) t] + ["AUTO Library Flags" (describe-variable 'verilog-library-flags) t] + ["AUTO Library Path" (describe-variable 'verilog-library-directories) t] + ["AUTO Library Files" (describe-variable 'verilog-library-files) t] + ["AUTO Library Extensions" (describe-variable 'verilog-library-extensions) t] + ["AUTO `define Reading" (describe-function 'verilog-read-defines) t] + ["AUTO `include Reading" (describe-function 'verilog-read-includes) t] + ["AUTOARG" (describe-function 'verilog-auto-arg) t] + ["AUTOASCIIENUM" (describe-function 'verilog-auto-ascii-enum) t] + ["AUTOINOUTMODULE" (describe-function 'verilog-auto-inout-module) t] + ["AUTOINOUT" (describe-function 'verilog-auto-inout) t] + ["AUTOINPUT" (describe-function 'verilog-auto-input) t] + ["AUTOINST" (describe-function 'verilog-auto-inst) t] + ["AUTOINST (.*)" (describe-function 'verilog-auto-star) t] + ["AUTOINSTPARAM" (describe-function 'verilog-auto-inst-param) t] + ["AUTOOUTPUT" (describe-function 'verilog-auto-output) t] + ["AUTOOUTPUTEVERY" (describe-function 'verilog-auto-output-every) t] + ["AUTOREG" (describe-function 'verilog-auto-reg) t] + ["AUTOREGINPUT" (describe-function 'verilog-auto-reg-input) t] + ["AUTORESET" (describe-function 'verilog-auto-reset) t] + ["AUTOSENSE" (describe-function 'verilog-auto-sense) t] + ["AUTOTIEOFF" (describe-function 'verilog-auto-tieoff) t] + ["AUTOUNUSED" (describe-function 'verilog-auto-unused) t] + ["AUTOWIRE" (describe-function 'verilog-auto-wire) t] + ) + "----" + ["Submit bug report" verilog-submit-bug-report t] + ["Version and FAQ" verilog-faq t] + ["Customize Verilog Mode..." verilog-customize t] + ["Customize Verilog Fonts & Colors" verilog-font-customize t] + ) + "Emacs menu for VERILOG mode." + ) +(defvar verilog-statement-menu + '("Statements" + ["Header" verilog-sk-header t] + ["Comment" verilog-sk-comment t] + "----" + ["Module" verilog-sk-module t] + ["Primitive" verilog-sk-primitive t] + "----" + ["Input" verilog-sk-input t] + ["Output" verilog-sk-output t] + ["Inout" verilog-sk-inout t] + ["Wire" verilog-sk-wire t] + ["Reg" verilog-sk-reg t] + ["Define thing under point as a register" verilog-sk-define-signal t] + "----" + ["Initial" verilog-sk-initial t] + ["Always" verilog-sk-always t] + ["Function" verilog-sk-function t] + ["Task" verilog-sk-task t] + ["Specify" verilog-sk-specify t] + ["Generate" verilog-sk-generate t] + "----" + ["Begin" verilog-sk-begin t] + ["If" verilog-sk-if t] + ["(if) else" verilog-sk-else-if t] + ["For" verilog-sk-for t] + ["While" verilog-sk-while t] + ["Fork" verilog-sk-fork t] + ["Repeat" verilog-sk-repeat t] + ["Case" verilog-sk-case t] + ["Casex" verilog-sk-casex t] + ["Casez" verilog-sk-casez t] + ) + "Menu for statement templates in Verilog." + ) + +(easy-menu-define verilog-menu verilog-mode-map "Menu for Verilog mode" + verilog-xemacs-menu) +(easy-menu-define verilog-stmt-menu verilog-mode-map "Menu for statement templates in Verilog." + verilog-statement-menu) + +(defvar verilog-mode-abbrev-table nil + "Abbrev table in use in Verilog-mode buffers.") + +(define-abbrev-table 'verilog-mode-abbrev-table ()) + +;; compilation program +(defun verilog-set-compile-command () + "Function to compute shell command to compile verilog. + +This reads `verilog-tool' and sets `compile-command'. This specifies the +program that executes when you type \\[compile] or +\\[verilog-auto-save-compile]. + +By default `verilog-tool' uses a Makefile if one exists in the current +directory. If not, it is set to the `verilog-linter', `verilog-coverage', +`verilog-simulator', or `verilog-compiler' variables, as selected with the +Verilog -> \"Choose Compilation Action\" menu. + +You should set `verilog-tool' or the other variables to the path and +arguments for your Verilog simulator. For example: + \"vcs -p123 -O\" +or a string like: + \"(cd /tmp; surecov %s)\". + +In the former case, the path to the current buffer is concat'ed to the +value of `verilog-tool'; in the later, the path to the current buffer is +substituted for the %s. + +Where __FILE__ appears in the string, the buffer-file-name of the current +buffer, without the directory portion, will be substituted." + (interactive) + (cond + ((or (file-exists-p "makefile") ;If there is a makefile, use it + (file-exists-p "Makefile")) + (make-local-variable 'compile-command) + (setq compile-command "make ")) + (t + (make-local-variable 'compile-command) + (setq compile-command + (if verilog-tool + (if (string-match "%s" (eval verilog-tool)) + (format (eval verilog-tool) (or buffer-file-name "")) + (concat (eval verilog-tool) " " (or buffer-file-name ""))) + "")))) + (verilog-modify-compile-command)) + +(defun verilog-modify-compile-command () + "Replace meta-information in `compile-command'. +Where __FILE__ appears in the string, the current buffer's file-name, +without the directory portion, will be substituted." + (when (and + (stringp compile-command) + (string-match "\\b__FILE__\\b" compile-command)) + (make-local-variable 'compile-command) + (setq compile-command + (verilog-string-replace-matches + "\\b__FILE__\\b" (file-name-nondirectory (buffer-file-name)) + t t compile-command)))) + +(defun verilog-error-regexp-add () + "Add the messages to the `compilation-error-regexp-alist'. +Called by `compilation-mode-hook'. This allows \\[next-error] to find the errors." + (if (not verilog-error-regexp-add-didit) + (progn + (setq verilog-error-regexp-add-didit t) + (setq-default compilation-error-regexp-alist + (append verilog-error-regexp + (default-value 'compilation-error-regexp-alist))) + ;; Could be buffer local at this point; maybe also in let; change all three + (setq compilation-error-regexp-alist (default-value 'compilation-error-regexp-alist)) + (set (make-local-variable 'compilation-error-regexp-alist) + (default-value 'compilation-error-regexp-alist)) + ))) + +(add-hook 'compilation-mode-hook 'verilog-error-regexp-add) + +(defconst verilog-directive-re + ;; "`case" "`default" "`define" "`define" "`else" "`endfor" "`endif" + ;; "`endprotect" "`endswitch" "`endwhile" "`for" "`format" "`if" "`ifdef" + ;; "`ifndef" "`include" "`let" "`protect" "`switch" "`timescale" + ;; "`time_scale" "`undef" "`while" + "\\<`\\(case\\|def\\(ault\\|ine\\(\\)?\\)\\|e\\(lse\\|nd\\(for\\|if\\|protect\\|switch\\|while\\)\\)\\|for\\(mat\\)?\\|i\\(f\\(def\\|ndef\\)?\\|nclude\\)\\|let\\|protect\\|switch\\|time\\(_scale\\|scale\\)\\|undef\\|while\\)\\>") + +(defconst verilog-directive-begin + "\\<`\\(for\\|i\\(f\\|fdef\\|fndef\\)\\|switch\\|while\\)\\>") + +(defconst verilog-directive-middle + "\\<`\\(else\\|default\\|case\\)\\>") + +(defconst verilog-directive-end + "`\\(endfor\\|endif\\|endswitch\\|endwhile\\)\\>") + +(defconst verilog-directive-re-1 + (concat "[ \t]*" verilog-directive-re)) + +;; +;; Regular expressions used to calculate indent, etc. +;; +(defconst verilog-symbol-re "\\<[a-zA-Z_][a-zA-Z_0-9.]*\\>") +(defconst verilog-case-re "\\(\\<case[xz]?\\>\\|\\<randcase\\>\\)") +;; Want to match +;; aa : +;; aa,bb : +;; a[34:32] : +;; a, +;; b : + +(defconst verilog-no-indent-begin-re + "\\<\\(if\\|else\\|while\\|for\\|repeat\\|always\\|always_comb\\|always_ff\\|always_latch\\)\\>") + +(defconst verilog-ends-re + ;; Parenthesis indicate type of keyword found + (concat + "\\(\\<else\\>\\)\\|" ; 1 + "\\(\\<if\\>\\)\\|" ; 2 + "\\(\\<end\\>\\)\\|" ; 3 + "\\(\\<endcase\\>\\)\\|" ; 4 + "\\(\\<endfunction\\>\\)\\|" ; 5 + "\\(\\<endtask\\>\\)\\|" ; 6 + "\\(\\<endspecify\\>\\)\\|" ; 7 + "\\(\\<endtable\\>\\)\\|" ; 8 + "\\(\\<endgenerate\\>\\)\\|" ; 9 + "\\(\\<join\\(_any\\|_none\\)?\\>\\)\\|" ; 10 + "\\(\\<endclass\\>\\)\\|" ; 11 + "\\(\\<endgroup\\>\\)" ; 12 + )) + +(defconst verilog-auto-end-comment-lines-re + ;; Matches to names in this list cause auto-end-commentation + (concat "\\(" + verilog-directive-re "\\)\\|\\(" + (eval-when-compile + (verilog-regexp-words + `( "begin" + "else" + "end" + "endcase" + "endclass" + "endclocking" + "endgroup" + "endfunction" + "endmodule" + "endprogram" + "endprimitive" + "endinterface" + "endpackage" + "endsequence" + "endspecify" + "endtable" + "endtask" + "join" + "join_any" + "join_none" + "module" + "macromodule" + "primitive" + "interface" + "package"))) + "\\)")) + +;;; NOTE: verilog-leap-to-head expects that verilog-end-block-re and +;;; verilog-end-block-ordered-re matches exactly the same strings. +(defconst verilog-end-block-ordered-re + ;; Parenthesis indicate type of keyword found + (concat "\\(\\<endcase\\>\\)\\|" ; 1 + "\\(\\<end\\>\\)\\|" ; 2 + "\\(\\<end" ; 3, but not used + "\\(" ; 4, but not used + "\\(function\\)\\|" ; 5 + "\\(task\\)\\|" ; 6 + "\\(module\\)\\|" ; 7 + "\\(primitive\\)\\|" ; 8 + "\\(interface\\)\\|" ; 9 + "\\(package\\)\\|" ; 10 + "\\(class\\)\\|" ; 11 + "\\(group\\)\\|" ; 12 + "\\(program\\)\\|" ; 13 + "\\(sequence\\)\\|" ; 14 + "\\(clocking\\)\\|" ; 15 + "\\)\\>\\)")) +(defconst verilog-end-block-re + (eval-when-compile + (verilog-regexp-words + + `("end" ;; closes begin + "endcase" ;; closes any of case, casex casez or randcase + "join" "join_any" "join_none" ;; closes fork + "endclass" + "endtable" + "endspecify" + "endfunction" + "endgenerate" + "endtask" + "endgroup" + "endproperty" + "endinterface" + "endpackage" + "endprogram" + "endsequence" + "endclocking" + ) + ))) + + +(defconst verilog-endcomment-reason-re + ;; Parenthesis indicate type of keyword found + (concat + "\\(\\<fork\\>\\)\\|" + "\\(\\<begin\\>\\)\\|" + "\\(\\<if\\>\\)\\|" + "\\(\\<clocking\\>\\)\\|" + "\\(\\<else\\>\\)\\|" + "\\(\\<end\\>.*\\<else\\>\\)\\|" + "\\(\\<task\\>\\)\\|" + "\\(\\<function\\>\\)\\|" + "\\(\\<initial\\>\\)\\|" + "\\(\\<interface\\>\\)\\|" + "\\(\\<package\\>\\)\\|" + "\\(\\<final\\>\\)\\|" + "\\(\\<always\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(\\<always_comb\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(\\<always_ff\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(\\<always_latch\\>\\(\[ \t\]*@\\)?\\)\\|" + "\\(@\\)\\|" + "\\(\\<while\\>\\)\\|" + "\\(\\<for\\(ever\\|each\\)?\\>\\)\\|" + "\\(\\<repeat\\>\\)\\|\\(\\<wait\\>\\)\\|" + "#")) + +(defconst verilog-named-block-re "begin[ \t]*:") + +;; These words begin a block which can occur inside a module which should be indented, +;; and closed with the respective word from the end-block list + +(defconst verilog-beg-block-re + (eval-when-compile + (verilog-regexp-words + `("begin" + "case" "casex" "casez" "randcase" + "clocking" + "generate" + "fork" + "function" + "property" + "specify" + "table" + "task" + )))) +;; These are the same words, in a specific order in the regular +;; expression so that matching will work nicely for +;; verilog-forward-sexp and verilog-calc-indent + +(defconst verilog-beg-block-re-ordered + ( concat "\\<" + "\\(begin\\)" ;1 + "\\|\\(randcase\\|\\(unique\\s-+\\|priority\\s-+\\)?case[xz]?\\)" ; 2 +;; "\\|\\(randcase\\|case[xz]?\\)" ; 2 + "\\|\\(fork\\)" ;3 + "\\|\\(class\\)" ;4 + "\\|\\(table\\)" ;5 + "\\|\\(specify\\)" ;6 + "\\|\\(function\\)" ;7 + "\\|\\(task\\)" ;8 + "\\|\\(generate\\)" ;9 + "\\|\\(covergroup\\)" ;10 + "\\|\\(property\\)" ;11 + "\\|\\(\\(rand\\)?sequence\\)" ;12 + "\\|\\(clocking\\)" ;13 + "\\>")) + +(defconst verilog-end-block-ordered-rry + [ "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<endcase\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" + "\\(\\<randcase\\>\\|\\<case[xz]?\\>\\)\\|\\(\\<endcase\\>\\)" + "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" + "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" + "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" + "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" + "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" + "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" + "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" + "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" + "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" + "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" + "\\(\\<clocking\\>\\)\\|\\(\\<endclocking\\>\\)" + ] ) + +(defconst verilog-nameable-item-re + (eval-when-compile + (verilog-regexp-words + `("begin" + "fork" + "join" "join_any" "join_none" + "end" + "endcase" + "endconfig" + "endclass" + "endclocking" + "endfunction" + "endgenerate" + "endmodule" + "endprimative" + "endinterface" + "endpackage" + "endspecify" + "endtable" + "endtask" ) + ))) + +(defconst verilog-declaration-opener + (eval-when-compile + (verilog-regexp-words + `("module" "begin" "task" "function")))) + +(defconst verilog-declaration-prefix-re + (eval-when-compile + (verilog-regexp-words + `( + ;; port direction + "inout" "input" "output" "ref" + ;; changeableness + "const" "static" "protected" "local" + ;; parameters + "localparam" "parameter" "var" + ;; type creation + "typedef" + )))) +(defconst verilog-declaration-core-re + (eval-when-compile + (verilog-regexp-words + `( + ;; integer_atom_type + "byte" "shortint" "int" "longint" "integer" "time" + ;; integer_vector_type + "bit" "logic" "reg" + ;; non_integer_type + "shortreal" "real" "realtime" + ;; net_type + "supply0" "supply1" "tri" "triand" "trior" "trireg" "tri0" "tri1" "uwire" "wire" "wand" "wor" + ;; misc + "string" "event" "chandle" "virtual" "enum" "genvar" + "struct" "union" + ;; builtin classes + "mailbox" "semaphore" + )))) +(defconst verilog-declaration-re + (concat "\\(" verilog-declaration-prefix-re "\\s-*\\)?" verilog-declaration-core-re)) +(defconst verilog-range-re "\\(\\[[^]]*\\]\\s-*\\)+") +(defconst verilog-optional-signed-re "\\s-*\\(signed\\)?") +(defconst verilog-optional-signed-range-re + (concat + "\\s-*\\(\\<\\(reg\\|wire\\)\\>\\s-*\\)?\\(\\<signed\\>\\s-*\\)?\\(" verilog-range-re "\\)?")) +(defconst verilog-macroexp-re "`\\sw+") + +(defconst verilog-delay-re "#\\s-*\\(\\([0-9_]+\\('s?[hdxbo][0-9a-fA-F_xz]+\\)?\\)\\|\\(([^()]*)\\)\\|\\(\\sw+\\)\\)") +(defconst verilog-declaration-re-2-no-macro + (concat "\\s-*" verilog-declaration-re + "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)" + "\\)?")) +(defconst verilog-declaration-re-2-macro + (concat "\\s-*" verilog-declaration-re + "\\s-*\\(\\(" verilog-optional-signed-range-re "\\)\\|\\(" verilog-delay-re "\\)" + "\\|\\(" verilog-macroexp-re "\\)" + "\\)?")) +(defconst verilog-declaration-re-1-macro + (concat "^" verilog-declaration-re-2-macro)) + +(defconst verilog-declaration-re-1-no-macro (concat "^" verilog-declaration-re-2-no-macro)) + +(defconst verilog-defun-re + (eval-when-compile (verilog-regexp-words `("macromodule" "module" "class" "program" "interface" "package" "primitive" "config")))) +(defconst verilog-end-defun-re + (eval-when-compile (verilog-regexp-words `("endmodule" "endclass" "endprogram" "endinterface" "endpackage" "endprimitive" "endconfig")))) +(defconst verilog-zero-indent-re + (concat verilog-defun-re "\\|" verilog-end-defun-re)) + +(defconst verilog-behavioral-block-beg-re + (concat "\\(\\<initial\\>\\|\\<final\\>\\|\\<always\\>\\|\\<always_comb\\>\\|\\<always_ff\\>\\|" + "\\<always_latch\\>\\|\\<function\\>\\|\\<task\\>\\)")) + +(defconst verilog-indent-re + (eval-when-compile + (verilog-regexp-words + `( + "{" + "always" "always_latch" "always_ff" "always_comb" + "begin" "end" +; "unique" "priority" + "case" "casex" "casez" "randcase" "endcase" + "class" "endclass" + "clocking" "endclocking" + "config" "endconfig" + "covergroup" "endgroup" + "fork" "join" "join_any" "join_none" + "function" "endfunction" + "final" + "generate" "endgenerate" + "initial" + "interface" "endinterface" + "module" "macromodule" "endmodule" + "package" "endpackage" + "primitive" "endprimative" + "program" "endprogram" + "property" "endproperty" + "sequence" "randsequence" "endsequence" + "specify" "endspecify" + "table" "endtable" + "task" "endtask" + "`case" + "`default" + "`define" "`undef" + "`if" "`ifdef" "`ifndef" "`else" "`endif" + "`while" "`endwhile" + "`for" "`endfor" + "`format" + "`include" + "`let" + "`protect" "`endprotect" + "`switch" "`endswitch" + "`timescale" + "`time_scale" + )))) + +(defconst verilog-defun-level-re + (eval-when-compile + (verilog-regexp-words + `( + "module" "macromodule" "primitive" "class" "program" "initial" "final" "always" "always_comb" + "always_ff" "always_latch" "endtask" "endfunction" "interface" "package" + "config")))) + +(defconst verilog-defun-level-not-generate-re + (eval-when-compile + (verilog-regexp-words + `( + "module" "macromodule" "primitive" "class" "program" "interface" "package" "config")))) + +(defconst verilog-cpp-level-re + (eval-when-compile + (verilog-regexp-words + `( + "endmodule" "endprimitive" "endinterface" "endpackage" "endprogram" "endclass" + )))) +(defconst verilog-extended-case-re "\\(unique\\s-+\\|priority\\s-+\\)?case[xz]?") +(defconst verilog-extended-complete-re + (concat "\\(\\<extern\\s-+\\|\\<virtual\\s-+\\|\\<protected\\s-+\\)*\\(\\<function\\>\\|\\<task\\>\\)" + "\\|\\(\\<typedef\\>\\s-+\\)*\\(\\<struct\\>\\|\\<union\\>\\|\\<class\\>\\)" + "\\|" verilog-extended-case-re )) +(defconst verilog-basic-complete-re + (eval-when-compile + (verilog-regexp-words + `( + "always" "assign" "always_latch" "always_ff" "always_comb" "constraint" + "import" "initial" "final" "module" "macromodule" "repeat" "randcase" "while" + "if" "for" "forever" "foreach" "else" "parameter" "do" + )))) +(defconst verilog-complete-reg + (concat + verilog-extended-complete-re + "\\|" + verilog-basic-complete-re)) + +(defconst verilog-end-statement-re + (concat "\\(" verilog-beg-block-re "\\)\\|\\(" + verilog-end-block-re "\\)")) + +(defconst verilog-endcase-re + (concat verilog-case-re "\\|" + "\\(endcase\\)\\|" + verilog-defun-re + )) + +(defconst verilog-exclude-str-start "/* -----\\/----- EXCLUDED -----\\/-----" + "String used to mark beginning of excluded text.") +(defconst verilog-exclude-str-end " -----/\\----- EXCLUDED -----/\\----- */" + "String used to mark end of excluded text.") +(defconst verilog-preprocessor-re + (eval-when-compile + (verilog-regexp-words + `( + "`define" "`include" "`ifdef" "`ifndef" "`if" "`endif" "`else" + )))) + +(defconst verilog-keywords + '( "`case" "`default" "`define" "`else" "`endfor" "`endif" + "`endprotect" "`endswitch" "`endwhile" "`for" "`format" "`if" "`ifdef" + "`ifndef" "`include" "`let" "`protect" "`switch" "`timescale" + "`time_scale" "`undef" "`while" + + "after" "alias" "always" "always_comb" "always_ff" "always_latch" "and" + "assert" "assign" "assume" "automatic" "before" "begin" "bind" + "bins" "binsof" "bit" "break" "buf" "bufif0" "bufif1" "byte" + "case" "casex" "casez" "cell" "chandle" "class" "clocking" "cmos" + "config" "const" "constraint" "context" "continue" "cover" + "covergroup" "coverpoint" "cross" "deassign" "default" "defparam" + "design" "disable" "dist" "do" "edge" "else" "end" "endcase" + "endclass" "endclocking" "endconfig" "endfunction" "endgenerate" + "endgroup" "endinterface" "endmodule" "endpackage" "endprimitive" + "endprogram" "endproperty" "endspecify" "endsequence" "endtable" + "endtask" "enum" "event" "expect" "export" "extends" "extern" + "final" "first_match" "for" "force" "foreach" "forever" "fork" + "forkjoin" "function" "generate" "genvar" "highz0" "highz1" "if" + "iff" "ifnone" "ignore_bins" "illegal_bins" "import" "incdir" + "include" "initial" "inout" "input" "inside" "instance" "int" + "integer" "interface" "intersect" "join" "join_any" "join_none" + "large" "liblist" "library" "local" "localparam" "logic" + "longint" "macromodule" "mailbox" "matches" "medium" "modport" "module" + "nand" "negedge" "new" "nmos" "nor" "noshowcancelled" "not" + "notif0" "notif1" "null" "or" "output" "package" "packed" + "parameter" "pmos" "posedge" "primitive" "priority" "program" + "property" "protected" "pull0" "pull1" "pulldown" "pullup" + "pulsestyle_onevent" "pulsestyle_ondetect" "pure" "rand" "randc" + "randcase" "randsequence" "rcmos" "real" "realtime" "ref" "reg" + "release" "repeat" "return" "rnmos" "rpmos" "rtran" "rtranif0" + "rtranif1" "scalared" "semaphore" "sequence" "shortint" "shortreal" + "showcancelled" "signed" "small" "solve" "specify" "specparam" + "static" "string" "strong0" "strong1" "struct" "super" "supply0" + "supply1" "table" "tagged" "task" "this" "throughout" "time" + "timeprecision" "timeunit" "tran" "tranif0" "tranif1" "tri" + "tri0" "tri1" "triand" "trior" "trireg" "type" "typedef" "union" + "unique" "unsigned" "use" "uwire" "var" "vectored" "virtual" "void" + "wait" "wait_order" "wand" "weak0" "weak1" "while" "wildcard" + "wire" "with" "within" "wor" "xnor" "xor" + ) + "List of Verilog keywords.") + + +(defconst verilog-emacs-features + ;; Documentation at the bottom + (let ((major (and (boundp 'emacs-major-version) + emacs-major-version)) + (minor (and (boundp 'emacs-minor-version) + emacs-minor-version)) + flavor comments flock-syntax) + ;; figure out version numbers if not already discovered + (and (or (not major) (not minor)) + (string-match "\\([0-9]+\\).\\([0-9]+\\)" emacs-version) + (setq major (string-to-int (substring emacs-version + (match-beginning 1) + (match-end 1))) + minor (string-to-int (substring emacs-version + (match-beginning 2) + (match-end 2))))) + (if (not (and major minor)) + (error "Cannot figure out the major and minor version numbers")) + ;; calculate the major version + (cond + ((= major 4) (setq major 'v18)) ;Epoch 4 + ((= major 18) (setq major 'v18)) ;Emacs 18 + ((= major 19) (setq major 'v19 ;Emacs 19 + flavor (if (or (string-match "Lucid" emacs-version) + (string-match "XEmacs" emacs-version)) + 'XEmacs 'FSF))) + ((> major 19) (setq major 'v20 + flavor (if (or (string-match "Lucid" emacs-version) + (string-match "XEmacs" emacs-version)) + 'XEmacs 'FSF))) + ;; I don't know + (t (error "Cannot recognize major version number: %s" major))) + ;; XEmacs 19 uses 8-bit modify-syntax-entry flags, as do all + ;; patched Emacs 19, Emacs 18, Epoch 4's. Only Emacs 19 uses a + ;; 1-bit flag. Let's be as smart as we can about figuring this + ;; out. + (if (or (eq major 'v20) (eq major 'v19)) + (let ((table (copy-syntax-table))) + (modify-syntax-entry ?a ". 12345678" table) + (cond + ;; XEmacs pre 20 and Emacs pre 19.30 use vectors for syntax tables. + ((vectorp table) + (if (= (logand (lsh (aref table ?a) -16) 255) 255) + (setq comments '8-bit) + (setq comments '1-bit))) + ;; XEmacs 20 is known to be 8-bit + ((eq flavor 'XEmacs) (setq comments '8-bit)) + ;; Emacs 19.30 and beyond are known to be 1-bit + ((eq flavor 'FSF) (setq comments '1-bit)) + ;; Don't know what this is + (t (error "Couldn't figure out syntax table format")) + )) + ;; Emacs 18 has no support for dual comments + (setq comments 'no-dual-comments)) + ;; determine whether to use old or new font lock syntax + ;; We can assume 8-bit syntax table emacsen support new syntax, otherwise + ;; look for version > 19.30 + (setq flock-syntax + (if (or (equal comments '8-bit) + (equal major 'v20) + (and (equal major 'v19) (> minor 30))) + 'flock-syntax-after-1930 + 'flock-syntax-before-1930)) + ;; lets do some minimal sanity checking. + (if (or + ;; Emacs before 19.6 had bugs + (and (eq major 'v19) (eq flavor 'XEmacs) (< minor 6)) + ;; Emacs 19 before 19.21 has known bugs + (and (eq major 'v19) (eq flavor 'FSF) (< minor 21)) + ) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "The version of Emacs that you are running, %s, +has known bugs in its syntax parsing routines which will affect the +performance of verilog-mode. You should strongly consider upgrading to the +latest available version. verilog-mode may continue to work, after a +fashion, but strange indentation errors could be encountered." + emacs-version)))) + ;; Emacs 18, with no patch is not too good + (if (and (eq major 'v18) (eq comments 'no-dual-comments)) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "The version of Emacs 18 you are running, %s, +has known deficiencies in its ability to handle the dual verilog +(and C++) comments, (e.g. the // and /* */ comments). This will +not be much of a problem for you if you only use the /* */ comments, +but you really should strongly consider upgrading to one of the latest +Emacs 19's. In Emacs 18, you may also experience performance degradations. +Emacs 19 has some new built-in routines which will speed things up for you. +Because of these inherent problems, verilog-mode is not supported +on emacs-18." + emacs-version)))) + ;; Emacs 18 with the syntax patches are no longer supported + (if (and (eq major 'v18) (not (eq comments 'no-dual-comments))) + (with-output-to-temp-buffer "*verilog-mode warnings*" + (print (format + "You are running a syntax patched Emacs 18 variant. While this should +work for you, you may want to consider upgrading to Emacs 19. +The syntax patches are no longer supported either for verilog-mode.")))) + (list major comments flock-syntax)) + "A list of features extant in the Emacs you are using. +There are many flavors of Emacs out there, each with different +features supporting those needed by `verilog-mode'. Here's the current +supported list, along with the values for this variable: + + Vanilla Emacs 18/Epoch 4: (v18 no-dual-comments flock-syntax-before-1930) + Emacs 18/Epoch 4 (patch2): (v18 8-bit flock-syntax-after-1930) + XEmacs (formerly Lucid) 19: (v19 8-bit flock-syntax-after-1930) + XEmacs 20: (v20 8-bit flock-syntax-after-1930) + Emacs 19.1-19.30: (v19 8-bit flock-syntax-before-1930) + Emacs 19.31-19.xx: (v19 8-bit flock-syntax-after-1930) + Emacs20 : (v20 1-bit flock-syntax-after-1930).") + +(defconst verilog-comment-start-regexp "//\\|/\\*" + "Dual comment value for `comment-start-regexp'.") + +(defun verilog-populate-syntax-table (table) + "Populate the syntax TABLE." + (modify-syntax-entry ?\\ "\\" table) + (modify-syntax-entry ?+ "." table) + (modify-syntax-entry ?- "." table) + (modify-syntax-entry ?= "." table) + (modify-syntax-entry ?% "." table) + (modify-syntax-entry ?< "." table) + (modify-syntax-entry ?> "." table) + (modify-syntax-entry ?& "." table) + (modify-syntax-entry ?| "." table) + (modify-syntax-entry ?` "w" table) + (modify-syntax-entry ?_ "w" table) + (modify-syntax-entry ?\' "." table) +) + +(defun verilog-setup-dual-comments (table) + "Set up TABLE to handle block and line style comments." + (cond + ((memq '8-bit verilog-emacs-features) + ;; XEmacs (formerly Lucid) has the best implementation + (modify-syntax-entry ?/ ". 1456" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + ) + ((memq '1-bit verilog-emacs-features) + ;; Emacs 19 does things differently, but we can work with it + (modify-syntax-entry ?/ ". 124b" table) + (modify-syntax-entry ?* ". 23" table) + (modify-syntax-entry ?\n "> b" table) + ) + )) + +(defvar verilog-mode-syntax-table nil + "Syntax table used in `verilog-mode' buffers.") + +(defconst verilog-font-lock-keywords nil + "Default highlighting for Verilog mode.") + +(defconst verilog-font-lock-keywords-1 nil + "Subdued level highlighting for Verilog mode.") + +(defconst verilog-font-lock-keywords-2 nil + "Medium level highlighting for Verilog mode. +See also `verilog-font-lock-extra-types'.") + +(defconst verilog-font-lock-keywords-3 nil + "Gaudy level highlighting for Verilog mode. +See also `verilog-font-lock-extra-types'.") +(defvar verilog-font-lock-translate-off-face + 'verilog-font-lock-translate-off-face + "Font to use for translated off regions.") +(defface verilog-font-lock-translate-off-face + '((((class color) + (background light)) + (:background "gray90" :italic t )) + (((class color) + (background dark)) + (:background "gray10" :italic t )) + (((class grayscale) (background light)) + (:foreground "DimGray" :italic t)) + (((class grayscale) (background dark)) + (:foreground "LightGray" :italic t)) + (t (:italis t))) + "Font lock mode face used to background highlight translate-off regions." + :group 'font-lock-highlighting-faces) + +(defvar verilog-font-lock-p1800-face + 'verilog-font-lock-p1800-face + "Font to use for p1800 keywords.") +(defface verilog-font-lock-p1800-face + '((((class color) + (background light)) + (:foreground "DarkOrange3" :bold t )) + (((class color) + (background dark)) + (:foreground "orange1" :bold t )) + (t (:italic t))) + "Font lock mode face used to highlight P1800 keywords." + :group 'font-lock-highlighting-faces) + +(defvar verilog-font-lock-ams-face + 'verilog-font-lock-ams-face + "Font to use for Analog/Mixed Signal keywords.") +(defface verilog-font-lock-ams-face + '((((class color) + (background light)) + (:foreground "Purple" :bold t )) + (((class color) + (background dark)) + (:foreground "orange1" :bold t )) + (t (:italic t))) + "Font lock mode face used to highlight AMS keywords." + :group 'font-lock-highlighting-faces) + +(let* ((verilog-type-font-keywords + (eval-when-compile + (verilog-regexp-opt + '( + "and" "bit" "buf" "bufif0" "bufif1" "cmos" "defparam" + "event" "genvar" "inout" "input" "integer" "localparam" + "logic" "mailbox" "nand" "nmos" "not" "notif0" "notif1" "or" + "output" "parameter" "pmos" "pull0" "pull1" "pullup" + "rcmos" "real" "realtime" "reg" "rnmos" "rpmos" "rtran" + "rtranif0" "rtranif1" "semaphore" "signed" "struct" "supply" + "supply0" "supply1" "time" "tran" "tranif0" "tranif1" + "tri" "tri0" "tri1" "triand" "trior" "trireg" "typedef" + "uwire" "vectored" "wand" "wire" "wor" "xnor" "xor" + ) nil ))) + + (verilog-pragma-keywords + (eval-when-compile + (verilog-regexp-opt + '("surefire" "synopsys" "rtl_synthesis" "verilint" ) nil + ))) + + (verilog-p1800-keywords + (eval-when-compile + (verilog-regexp-opt + '("alias" "assert" "assume" "automatic" "before" "bind" + "bins" "binsof" "break" "byte" "cell" "chandle" "class" + "clocking" "config" "const" "constraint" "context" "continue" + "cover" "covergroup" "coverpoint" "cross" "deassign" "design" + "dist" "do" "edge" "endclass" "endclocking" "endconfig" + "endgroup" "endprogram" "endproperty" "endsequence" "enum" + "expect" "export" "extends" "extern" "first_match" "foreach" + "forkjoin" "genvar" "highz0" "highz1" "ifnone" "ignore_bins" + "illegal_bins" "import" "incdir" "include" "inside" "instance" + "int" "intersect" "large" "liblist" "library" "local" "longint" + "matches" "medium" "modport" "new" "noshowcancelled" "null" + "packed" "program" "property" "protected" "pull0" "pull1" + "pulsestyle_onevent" "pulsestyle_ondetect" "pure" "rand" "randc" + "randcase" "randsequence" "ref" "release" "return" "scalared" + "sequence" "shortint" "shortreal" "showcancelled" "small" "solve" + "specparam" "static" "string" "strong0" "strong1" "struct" + "super" "tagged" "this" "throughout" "timeprecision" "timeunit" + "type" "union" "unsigned" "use" "var" "virtual" "void" + "wait_order" "weak0" "weak1" "wildcard" "with" "within" + ) nil ))) + + (verilog-ams-keywords + (eval-when-compile + (verilog-regexp-opt + '("above" "abs" "absdelay" "acos" "acosh" "ac_stim" + "aliasparam" "analog" "analysis" "asin" "asinh" "atan" "atan2" "atanh" + "branch" "ceil" "connectmodule" "connectrules" "cos" "cosh" "ddt" + "ddx" "discipline" "driver_update" "enddiscipline" "endconnectrules" + "endnature" "endparamset" "exclude" "exp" "final_step" "flicker_noise" + "floor" "flow" "from" "ground" "hypot" "idt" "idtmod" "inf" + "initial_step" "laplace_nd" "laplace_np" "laplace_zd" "laplace_zp" + "last_crossing" "limexp" "ln" "log" "max" "min" "nature" + "net_resolution" "noise_table" "paramset" "potential" "pow" "sin" + "sinh" "slew" "sqrt" "tan" "tanh" "timer" "transition" "white_noise" + "wreal" "zi_nd" "zi_np" "zi_zd" ) nil ))) + + (verilog-font-keywords + (eval-when-compile + (verilog-regexp-opt + '( + "assign" "begin" "case" "casex" "casez" "randcase" "deassign" + "default" "disable" "else" "end" "endcase" "endfunction" + "endgenerate" "endinterface" "endmodule" "endprimitive" + "endspecify" "endtable" "endtask" "final" "for" "force" "return" "break" + "continue" "forever" "fork" "function" "generate" "if" "iff" "initial" + "interface" "join" "join_any" "join_none" "macromodule" "module" "negedge" + "package" "endpackage" "always" "always_comb" "always_ff" + "always_latch" "posedge" "primitive" "priority" "release" + "repeat" "specify" "table" "task" "unique" "wait" "while" + "class" "program" "endclass" "endprogram" + ) nil )))) + + (setq verilog-font-lock-keywords + (list + ;; Fontify all builtin keywords + (concat "\\<\\(" verilog-font-keywords "\\|" + ;; And user/system tasks and functions + "\\$[a-zA-Z][a-zA-Z0-9_\\$]*" + "\\)\\>") + ;; Fontify all types + (cons (concat "\\<\\(" verilog-type-font-keywords "\\)\\>") + 'font-lock-type-face) + ;; Fontify IEEE-P1800 keywords appropriately + (if verilog-highlight-p1800-keywords + (cons (concat "\\<\\(" verilog-p1800-keywords "\\)\\>") + 'verilog-font-lock-p1800-face) + (cons (concat "\\<\\(" verilog-p1800-keywords "\\)\\>") + 'font-lock-type-face)) + ;; Fontify Verilog-AMS keywords + (cons (concat "\\<\\(" verilog-ams-keywords "\\)\\>") + 'verilog-font-lock-ams-face) + )) + + (setq verilog-font-lock-keywords-1 + (append verilog-font-lock-keywords + (list + ;; Fontify module definitions + (list + "\\<\\(\\(macro\\)?module\\|primitive\\|class\\|program\\|interface\\|package\\|task\\)\\>\\s-*\\(\\sw+\\)" + '(1 font-lock-keyword-face) + '(3 font-lock-function-name-face 'prepend)) + ;; Fontify function definitions + (list + (concat "\\<function\\>\\s-+\\(integer\\|real\\(time\\)?\\|time\\)\\s-+\\(\\sw+\\)" ) + '(1 font-lock-keyword-face) + '(3 font-lock-reference-face prepend) + ) + '("\\<function\\>\\s-+\\(\\[[^]]+\\]\\)\\s-+\\(\\sw+\\)" + (1 font-lock-keyword-face) + (2 font-lock-reference-face append) + ) + '("\\<function\\>\\s-+\\(\\sw+\\)" + 1 'font-lock-reference-face append) + ))) + + (setq verilog-font-lock-keywords-2 + (append verilog-font-lock-keywords-1 + (list + ;; Fontify pragmas + (concat "\\(//\\s-*" verilog-pragma-keywords "\\s-.*\\)") + ;; Fontify escaped names + '("\\(\\\\\\S-*\\s-\\)" 0 font-lock-function-name-face) + ;; Fontify macro definitions/ uses + '("`\\s-*[A-Za-z][A-Za-z0-9_]*" 0 (if (boundp 'font-lock-preprocessor-face) + 'font-lock-preprocessor-face + 'font-lock-type-face)) + ;; Fontify delays/numbers + '("\\(@\\)\\|\\(#\\s-*\\(\\(\[0-9_.\]+\\('s?[hdxbo][0-9a-fA-F_xz]*\\)?\\)\\|\\(([^()]+)\\|\\sw+\\)\\)\\)" + 0 font-lock-type-face append) + ;; Fontify instantiation names + '("\\([A-Za-z][A-Za-z0-9_]+\\)\\s-*(" 1 font-lock-function-name-face) + + ))) + + (setq verilog-font-lock-keywords-3 + (append verilog-font-lock-keywords-2 + (when verilog-highlight-translate-off + (list + ;; Fontify things in translate off regions + '(verilog-match-translate-off (0 'verilog-font-lock-translate-off-face prepend)) + ))) + ) + ) + + + +(defun verilog-inside-comment-p () + "Check if point inside a nested comment." + (save-excursion + (let ((st-point (point)) hitbeg) + (or (search-backward "//" (verilog-get-beg-of-line) t) + (if (progn + ;; This is for tricky case //*, we keep searching if /* is proceeded by // on same line + (while (and (setq hitbeg (search-backward "/*" nil t)) + (progn (forward-char 1) (search-backward "//" (verilog-get-beg-of-line) t)))) + hitbeg) + (not (search-forward "*/" st-point t))))))) + +(defun verilog-declaration-end () + (search-forward ";")) + +(defun verilog-point-text (&optional pointnum) + "Return text describing where POINTNUM or current point is (for errors). +Use filename, if current buffer being edited shorten to just buffer name." + (concat (or (and (equal (window-buffer (selected-window)) (current-buffer)) + (buffer-name)) + buffer-file-name + (buffer-name)) + ":" (int-to-string (count-lines (point-min) (or pointnum (point)))))) + +(defun electric-verilog-backward-sexp () + "Move backward over a sexp." + (interactive) + ;; before that see if we are in a comment + (verilog-backward-sexp) +) +(defun electric-verilog-forward-sexp () + "Move backward over a sexp." + (interactive) + ;; before that see if we are in a comment + (verilog-forward-sexp) +) +;;;used by hs-minor-mode +(defun verilog-forward-sexp-function (arg) + (if (< arg 0) + (verilog-backward-sexp) + (verilog-forward-sexp))) + + +(defun verilog-backward-sexp () + (let ((reg) + (elsec 1) + (found nil) + (st (point)) + ) + (if (not (looking-at "\\<")) + (forward-word -1)) + (cond + ((verilog-skip-backward-comment-or-string) + ) + ((looking-at "\\<else\\>") + (setq reg (concat + verilog-end-block-re + "\\|\\(\\<else\\>\\)" + "\\|\\(\\<if\\>\\)" + )) + (while (and (not found) + (verilog-re-search-backward reg nil 'move)) + (cond + ((match-end 1) ; matched verilog-end-block-re + ; try to leap back to matching outward block by striding across + ; indent level changing tokens then immediately + ; previous line governs indentation. + (verilog-leap-to-head)) + ((match-end 2) ; else, we're in deep + (setq elsec (1+ elsec))) + ((match-end 3) ; found it + (setq elsec (1- elsec)) + (if (= 0 elsec) + ;; Now previous line describes syntax + (setq found 't) + )) + ) + ) + ) + ((looking-at verilog-end-block-re) + (verilog-leap-to-head)) + ((looking-at "\\(endmodule\\>\\)\\|\\(\\<endprimitive\\>\\)\\|\\(\\<endclass\\>\\)\\|\\(\\<endprogram\\>\\)\\|\\(\\<endinterface\\>\\)\\|\\(\\<endpackage\\>\\)") + (cond + ((match-end 1) + (verilog-re-search-backward "\\<\\(macro\\)?module\\>" nil 'move)) + ((match-end 2) + (verilog-re-search-backward "\\<primitive\\>" nil 'move)) + ((match-end 3) + (verilog-re-search-backward "\\<class\\>" nil 'move)) + ((match-end 4) + (verilog-re-search-backward "\\<program\\>" nil 'move)) + ((match-end 5) + (verilog-re-search-backward "\\<interface\\>" nil 'move)) + ((match-end 6) + (verilog-re-search-backward "\\<package\\>" nil 'move)) + (t + (goto-char st) + (backward-sexp 1)))) + (t + (goto-char st) + (backward-sexp)) + ) ;; cond + )) + +(defun verilog-forward-sexp () + (let ((reg) + (md 2) + (st (point))) + (if (not (looking-at "\\<")) + (forward-word -1)) + (cond + ((verilog-skip-forward-comment-or-string) + (verilog-forward-syntactic-ws) + ) + ((looking-at verilog-beg-block-re-ordered);; begin|case|fork|class|table|specify|function|task|generate|covergroup|property|sequence|clocking + (cond + ((match-end 1) ; end + ;; Search forward for matching begin + (setq reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)" )) + ((match-end 2) ; endcase + ;; Search forward for matching case + (setq reg "\\(\\<randcase\\>\\|\\(\\<unique\\>\\s-+\\|\\<priority\\>\\s-+\\)?\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" ) + ) + ((match-end 3) ; join + ;; Search forward for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" )) + ((match-end 4) ; endclass + ;; Search forward for matching class + (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" )) + ((match-end 5) ; endtable + ;; Search forward for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )) + ((match-end 6) ; endspecify + ;; Search forward for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )) + ((match-end 7) ; endfunction + ;; Search forward for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )) + ((match-end 8) ; endtask + ;; Search forward for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )) + ((match-end 9) ; endgenerate + ;; Search forward for matching generate + (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" )) + ((match-end 10) ; endgroup + ;; Search forward for matching covergroup + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" )) + ((match-end 11) ; endproperty + ;; Search forward for matching property + (setq reg "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" )) + ((match-end 12) ; endsequence + ;; Search forward for matching sequence + (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" ) + (setq md 3) ; 3 to get to endsequence in the reg above + ) + ((match-end 13) ; endclocking + ;; Search forward for matching clocking + (setq reg "\\(\\<clocking\\>\\)\\|\\(\\<endclocking\\>\\)" )) + ) + (if (forward-word 1) + (catch 'skip + (let ((nest 1)) + (while (verilog-re-search-forward reg nil 'move) + (cond + ((match-end md) ; the closer in reg, so we are climbing out + (setq nest (1- nest)) + (if (= 0 nest) ; we are out! + (throw 'skip 1))) + ((match-end 1) ; the opener in reg, so we are deeper now + (setq nest (1+ nest))))) + ))) + ) + ((looking-at (concat + "\\(\\<\\(macro\\)?module\\>\\)\\|" + "\\(\\<primitive\\>\\)\\|" + "\\(\\<class\\>\\)\\|" + "\\(\\<program\\>\\)\\|" + "\\(\\<interface\\>\\)\\|" + "\\(\\<package\\>\\)")) + (cond + ((match-end 1) + (verilog-re-search-forward "\\<endmodule\\>" nil 'move)) + ((match-end 2) + (verilog-re-search-forward "\\<endprimitive\\>" nil 'move)) + ((match-end 3) + (verilog-re-search-forward "\\<endclass\\>" nil 'move)) + ((match-end 4) + (verilog-re-search-forward "\\<endprogram\\>" nil 'move)) + ((match-end 5) + (verilog-re-search-forward "\\<endinterface\\>" nil 'move)) + ((match-end 6) + (verilog-re-search-forward "\\<endpackage\\>" nil 'move)) + (t + (goto-char st) + (if (= (following-char) ?\) ) + (forward-char 1) + (forward-sexp 1))))) + (t + (goto-char st) + (if (= (following-char) ?\) ) + (forward-char 1) + (forward-sexp 1))) + ) ;; cond + )) + +(defun verilog-declaration-beg () + (verilog-re-search-backward verilog-declaration-re (bobp) t)) + +;; +;; Macros +;; + +(defsubst verilog-string-replace-matches (from-string to-string fixedcase literal string) + "Replace occurrences of FROM-STRING with TO-STRING. +FIXEDCASE and LITERAL as in `replace-match`. STRING is what to replace. +The case (verilog-string-replace-matches \"o\" \"oo\" nil nil \"foobar\") +will break, as the o's continuously replace. xa -> x works ok though." + ;; Hopefully soon to a emacs built-in + (let ((start 0)) + (while (string-match from-string string start) + (setq string (replace-match to-string fixedcase literal string) + start (min (length string) (match-end 0)))) + string)) + +(defsubst verilog-string-remove-spaces (string) + "Remove spaces surrounding STRING." + (save-match-data + (setq string (verilog-string-replace-matches "^\\s-+" "" nil nil string)) + (setq string (verilog-string-replace-matches "\\s-+$" "" nil nil string)) + string)) + +(defsubst verilog-re-search-forward (REGEXP BOUND NOERROR) + ; checkdoc-params: (REGEXP BOUND NOERROR) + "Like `re-search-forward', but skips over match in comments or strings." + (store-match-data '(nil nil)) + (while (and + (re-search-forward REGEXP BOUND NOERROR) + (and (verilog-skip-forward-comment-or-string) + (progn + (store-match-data '(nil nil)) + (if BOUND + (< (point) BOUND) + t) + )))) + (match-end 0)) + +(defsubst verilog-re-search-backward (REGEXP BOUND NOERROR) + ; checkdoc-params: (REGEXP BOUND NOERROR) + "Like `re-search-backward', but skips over match in comments or strings." + (store-match-data '(nil nil)) + (while (and + (re-search-backward REGEXP BOUND NOERROR) + (and (verilog-skip-backward-comment-or-string) + (progn + (store-match-data '(nil nil)) + (if BOUND + (> (point) BOUND) + t) + )))) + (match-end 0)) + +(defsubst verilog-re-search-forward-quick (regexp bound noerror) + "Like `verilog-re-search-forward', including use of REGEXP BOUND and NOERROR, +but trashes match data and is faster for REGEXP that doesn't match often. +This may at some point use text properties to ignore comments, +so there may be a large up front penalty for the first search." + (let (pt) + (while (and (not pt) + (re-search-forward regexp bound noerror)) + (if (not (verilog-inside-comment-p)) + (setq pt (match-end 0)))) + pt)) + +(defsubst verilog-re-search-backward-quick (regexp bound noerror) + ; checkdoc-params: (REGEXP BOUND NOERROR) + "Like `verilog-re-search-backward', including use of REGEXP BOUND and NOERROR, +but trashes match data and is faster for REGEXP that doesn't match often. +This may at some point use text properties to ignore comments, +so there may be a large up front penalty for the first search." + (let (pt) + (while (and (not pt) + (re-search-backward regexp bound noerror)) + (if (not (verilog-inside-comment-p)) + (setq pt (match-end 0)))) + pt)) + +(defsubst verilog-get-beg-of-line (&optional arg) + (save-excursion + (beginning-of-line arg) + (point))) + +(defsubst verilog-get-end-of-line (&optional arg) + (save-excursion + (end-of-line arg) + (point))) + +(defsubst verilog-within-string () + (save-excursion + (nth 3 (parse-partial-sexp (verilog-get-beg-of-line) (point))))) + +(require 'font-lock) +(defvar verilog-need-fld 1) +(defvar font-lock-defaults-alist nil) ;In case we are XEmacs + +(defun verilog-font-lock-init () + "Initialize fontification." + ;; highlight keywords and standardized types, attributes, enumeration + ;; values, and subprograms + (setq verilog-font-lock-keywords-3 + (append verilog-font-lock-keywords-2 + (when verilog-highlight-translate-off + (list + ;; Fontify things in translate off regions + '(verilog-match-translate-off (0 'verilog-font-lock-translate-off-face prepend)) + )) + ) + ) + (put 'verilog-mode 'font-lock-defaults + '((verilog-font-lock-keywords + verilog-font-lock-keywords-1 + verilog-font-lock-keywords-2 + verilog-font-lock-keywords-3 + ) + nil ;; nil means highlight strings & comments as well as keywords + nil ;; nil means keywords must match case + nil ;; syntax table handled elsewhere + verilog-beg-of-defun ;; function to move to beginning of reasonable region to highlight + )) + (if verilog-need-fld + (let ((verilog-mode-defaults + '((verilog-font-lock-keywords + verilog-font-lock-keywords-1 + verilog-font-lock-keywords-2 + verilog-font-lock-keywords-3 + ) + nil ;; nil means highlight strings & comments as well as keywords + nil ;; nil means keywords must match case + nil ;; syntax table handled elsewhere + verilog-beg-of-defun ;; function to move to beginning of reasonable region to highlight + ))) + (setq font-lock-defaults-alist + (append + font-lock-defaults-alist + (list (cons 'verilog-mode verilog-mode-defaults)))) + (setq verilog-need-fld 0)))) + +;; initialize fontification for Verilog Mode +(verilog-font-lock-init) +;; start up message +(defconst verilog-startup-message-lines + '("Please use \\[verilog-submit-bug-report] to report bugs." + "Visit http://www.verilog.com to check for updates" + )) +(defconst verilog-startup-message-displayed t) +(defun verilog-display-startup-message () + (if (not verilog-startup-message-displayed) + (if (sit-for 5) + (let ((lines verilog-startup-message-lines)) + (message "verilog-mode version %s, released %s; type \\[describe-mode] for help" + verilog-mode-version verilog-mode-release-date) + (setq verilog-startup-message-displayed t) + (while (and (sit-for 4) lines) + (message (substitute-command-keys (car lines))) + (setq lines (cdr lines))))) + (message ""))) +;; +;; +;; Mode +;; +(defvar verilog-which-tool 1) +;;###autoload +(defun verilog-mode () + "Major mode for editing Verilog code. +\\<verilog-mode-map> +See \\[describe-function] verilog-auto (\\[verilog-auto]) for details on how +AUTOs can improve coding efficiency. + +Use \\[verilog-faq] for a pointer to frequently asked questions. + +NEWLINE, TAB indents for Verilog code. +Delete converts tabs to spaces as it moves back. + +Supports highlighting. + +Turning on Verilog mode calls the value of the variable `verilog-mode-hook' +with no args, if that value is non-nil. + +Variables controlling indentation/edit style: + + variable `verilog-indent-level' (default 3) + Indentation of Verilog statements with respect to containing block. + `verilog-indent-level-module' (default 3) + Absolute indentation of Module level Verilog statements. + Set to 0 to get initial and always statements lined up + on the left side of your screen. + `verilog-indent-level-declaration' (default 3) + Indentation of declarations with respect to containing block. + Set to 0 to get them list right under containing block. + `verilog-indent-level-behavioral' (default 3) + Indentation of first begin in a task or function block + Set to 0 to get such code to lined up underneath the task or function keyword + `verilog-indent-level-directive' (default 1) + Indentation of `ifdef/`endif blocks + `verilog-cexp-indent' (default 1) + Indentation of Verilog statements broken across lines i.e.: + if (a) + begin + `verilog-case-indent' (default 2) + Indentation for case statements. + `verilog-auto-newline' (default nil) + Non-nil means automatically newline after semicolons and the punctuation + mark after an end. + `verilog-auto-indent-on-newline' (default t) + Non-nil means automatically indent line after newline + `verilog-tab-always-indent' (default t) + Non-nil means TAB in Verilog mode should always reindent the current line, + regardless of where in the line point is when the TAB command is used. + `verilog-indent-begin-after-if' (default t) + Non-nil means to indent begin statements following a preceding + if, else, while, for and repeat statements, if any. otherwise, + the begin is lined up with the preceding token. If t, you get: + if (a) + begin // amount of indent based on `verilog-cexp-indent' + otherwise you get: + if (a) + begin + `verilog-auto-endcomments' (default t) + Non-nil means a comment /* ... */ is set after the ends which ends + cases, tasks, functions and modules. + The type and name of the object will be set between the braces. + `verilog-minimum-comment-distance' (default 10) + Minimum distance (in lines) between begin and end required before a comment + will be inserted. Setting this variable to zero results in every + end acquiring a comment; the default avoids too many redundant + comments in tight quarters. + `verilog-auto-lineup' (default `(all)) + List of contexts where auto lineup of code should be done. + +Variables controlling other actions: + + `verilog-linter' (default surelint) + Unix program to call to run the lint checker. This is the default + command for \\[compile-command] and \\[verilog-auto-save-compile]. + +See \\[customize] for the complete list of variables. + +AUTO expansion functions are, in part: + + \\[verilog-auto] Expand AUTO statements. + \\[verilog-delete-auto] Remove the AUTOs. + \\[verilog-inject-auto] Insert AUTOs for the first time. + +Some other functions are: + + \\[verilog-complete-word] Complete word with appropriate possibilities. + \\[verilog-mark-defun] Mark function. + \\[verilog-beg-of-defun] Move to beginning of current function. + \\[verilog-end-of-defun] Move to end of current function. + \\[verilog-label-be] Label matching begin ... end, fork ... join, etc statements. + + \\[verilog-comment-region] Put marked area in a comment. + \\[verilog-uncomment-region] Uncomment an area commented with \\[verilog-comment-region]. + \\[verilog-insert-block] Insert begin ... end;. + \\[verilog-star-comment] Insert /* ... */. + + \\[verilog-sk-always] Insert a always @(AS) begin .. end block. + \\[verilog-sk-begin] Insert a begin .. end block. + \\[verilog-sk-case] Insert a case block, prompting for details. + \\[verilog-sk-for] Insert a for (...) begin .. end block, prompting for details. + \\[verilog-sk-generate] Insert a generate .. endgenerate block. + \\[verilog-sk-header] Insert a nice header block at the top of file. + \\[verilog-sk-initial] Insert an initial begin .. end block. + \\[verilog-sk-fork] Insert a fork begin .. end .. join block. + \\[verilog-sk-module] Insert a module .. (/*AUTOARG*/);.. endmodule block. + \\[verilog-sk-primitive] Insert a primitive .. (.. );.. endprimitive block. + \\[verilog-sk-repeat] Insert a repeat (..) begin .. end block. + \\[verilog-sk-specify] Insert a specify .. endspecify block. + \\[verilog-sk-task] Insert a task .. begin .. end endtask block. + \\[verilog-sk-while] Insert a while (...) begin .. end block, prompting for details. + \\[verilog-sk-casex] Insert a casex (...) item: begin.. end endcase block, prompting for details. + \\[verilog-sk-casez] Insert a casez (...) item: begin.. end endcase block, prompting for details. + \\[verilog-sk-if] Insert an if (..) begin .. end block. + \\[verilog-sk-else-if] Insert an else if (..) begin .. end block. + \\[verilog-sk-comment] Insert a comment block. + \\[verilog-sk-assign] Insert an assign .. = ..; statement. + \\[verilog-sk-function] Insert a function .. begin .. end endfunction block. + \\[verilog-sk-input] Insert an input declaration, prompting for details. + \\[verilog-sk-output] Insert an output declaration, prompting for details. + \\[verilog-sk-state-machine] Insert a state machine definition, prompting for details. + \\[verilog-sk-inout] Insert an inout declaration, prompting for details. + \\[verilog-sk-wire] Insert a wire declaration, prompting for details. + \\[verilog-sk-reg] Insert a register declaration, prompting for details. + \\[verilog-sk-define-signal] Define signal under point as a register at the top of the module. + +All key bindings can be seen in a Verilog-buffer with \\[describe-bindings]. +Key bindings specific to `verilog-mode-map' are: + +\\{verilog-mode-map}" + (interactive) + (kill-all-local-variables) + (use-local-map verilog-mode-map) + (setq major-mode 'verilog-mode) + (setq mode-name "Verilog") + (setq local-abbrev-table verilog-mode-abbrev-table) + (setq verilog-mode-syntax-table (make-syntax-table)) + (verilog-populate-syntax-table verilog-mode-syntax-table) + ;; add extra comment syntax + (verilog-setup-dual-comments verilog-mode-syntax-table) + (set-syntax-table verilog-mode-syntax-table) + (make-local-variable 'indent-line-function) + (setq indent-line-function 'verilog-indent-line-relative) + (setq comment-indent-function 'verilog-comment-indent) + (make-local-variable 'parse-sexp-ignore-comments) + (setq parse-sexp-ignore-comments nil) + (make-local-variable 'comment-start) + (make-local-variable 'comment-end) + (make-local-variable 'comment-multi-line) + (make-local-variable 'comment-start-skip) + (setq comment-start "// " + comment-end "" + comment-start-skip "/\\*+ *\\|// *" + comment-multi-line nil) + ;; Set up for compilation + (setq verilog-which-tool 1) + (setq verilog-tool 'verilog-linter) + (verilog-set-compile-command) + (when (boundp 'hack-local-variables-hook) ;; Also modify any file-local-variables + (add-hook 'hack-local-variables-hook 'verilog-modify-compile-command t)) + + ;; Setting up menus + (if (featurep 'xemacs) + (progn + (if (and current-menubar + (not (assoc "Verilog" current-menubar))) + (progn + ;; (set-buffer-menubar (copy-sequence current-menubar)) + (add-submenu nil verilog-xemacs-menu) + (add-submenu nil verilog-stmt-menu) + ) + ) + )) + ;; Stuff for GNU emacs + (make-local-variable 'font-lock-defaults) + ;;------------------------------------------------------------ + ;; now hook in 'verilog-colorize-include-files (eldo-mode.el&spice-mode.el) + ;; all buffer local: + (make-local-hook 'font-lock-mode-hook) + (make-local-hook 'font-lock-after-fontify-buffer-hook); doesn't exist in emacs 20 + (add-hook 'font-lock-mode-hook 'verilog-colorize-include-files-buffer t t) + (add-hook 'font-lock-after-fontify-buffer-hook 'verilog-colorize-include-files-buffer t t) ; not in emacs 20 + (make-local-hook 'after-change-functions) + (add-hook 'after-change-functions 'verilog-colorize-include-files t t) + + ;; Tell imenu how to handle verilog. + (make-local-variable 'imenu-generic-expression) + (setq imenu-generic-expression verilog-imenu-generic-expression) + ;; hideshow support + (unless (assq 'verilog-mode hs-special-modes-alist) + (setq hs-special-modes-alist + (cons '(verilog-mode-mode "\\<begin\\>" "\\<end\\>" nil + verilog-forward-sexp-function) + hs-special-modes-alist))) + ;; Display version splash information. + (verilog-display-startup-message) + + ;; Stuff for autos + (add-hook 'write-contents-hooks 'verilog-auto-save-check) ; already local +;; (verilog-auto-reeval-locals t) ; Save locals in case user changes them +;; (verilog-getopt-flags) + (run-hooks 'verilog-mode-hook)) + + +;; +;; Electric functions +;; +(defun electric-verilog-terminate-line (&optional arg) + "Terminate line and indent next line. +With optional ARG, remove existing end of line comments." + (interactive) + ;; before that see if we are in a comment + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ; Inside // comment + (if (eolp) + (progn + (delete-horizontal-space) + (newline)) + (progn + (newline) + (insert-string "// ") + (beginning-of-line))) + (verilog-indent-line)) + ((nth 4 state) ; Inside any comment (hence /**/) + (newline) + (verilog-more-comment)) + ((eolp) + ;; First, check if current line should be indented + (if (save-excursion + (delete-horizontal-space) + (beginning-of-line) + (skip-chars-forward " \t") + (if (looking-at verilog-auto-end-comment-lines-re) + (let ((indent-str (verilog-indent-line))) + ;; Maybe we should set some endcomments + (if verilog-auto-endcomments + (verilog-set-auto-endcomments indent-str arg)) + (end-of-line) + (delete-horizontal-space) + (if arg + () + (newline)) + nil) + (progn + (end-of-line) + (delete-horizontal-space) + 't + ) + ) + ) + ;; see if we should line up assignments + (progn + (if (or (memq 'all verilog-auto-lineup) + (memq 'assignments verilog-auto-lineup)) + (verilog-pretty-expr) + ) + (newline) + ) + (forward-line 1) + ) + ;; Indent next line + (if verilog-auto-indent-on-newline + (verilog-indent-line)) + ) + (t + (newline)) + ))) + +(defun electric-verilog-terminate-and-indent () + "Insert a newline and indent for the next statement." + (interactive) + (electric-verilog-terminate-line 1)) + +(defun electric-verilog-semi () + "Insert `;' character and reindent the line." + (interactive) + (insert last-command-char) + + (if (or (verilog-in-comment-or-string-p) + (verilog-in-escaped-name-p)) + () + (save-excursion + (beginning-of-line) + (verilog-forward-ws&directives) + (verilog-indent-line) + ) + (if (and verilog-auto-newline + (not (verilog-parenthesis-depth))) + (electric-verilog-terminate-line)))) + +(defun electric-verilog-semi-with-comment () + "Insert `;' character, reindent the line and indent for comment." + (interactive) + (insert "\;") + (save-excursion + (beginning-of-line) + (verilog-indent-line)) + (indent-for-comment)) + +(defun electric-verilog-colon () + "Insert `:' and do all indentations except line indent on this line." + (interactive) + (insert last-command-char) + ;; Do nothing if within string. + (if (or + (verilog-within-string) + (not (verilog-in-case-region-p))) + () + (save-excursion + (let ((p (point)) + (lim (progn (verilog-beg-of-statement) (point)))) + (goto-char p) + (verilog-backward-case-item lim) + (verilog-indent-line))) +;; (let ((verilog-tab-always-indent nil)) +;; (verilog-indent-line)) + )) + +;;(defun electric-verilog-equal () +;; "Insert `=', and do indentation if within block." +;; (interactive) +;; (insert last-command-char) +;; Could auto line up expressions, but not yet +;; (if (eq (car (verilog-calculate-indent)) 'block) +;; (let ((verilog-tab-always-indent nil)) +;; (verilog-indent-command))) +;; ) + +(defun electric-verilog-tick () + "Insert back-tick, and indent to column 0 if this is a CPP directive." + (interactive) + (insert last-command-char) + (save-excursion + (if (progn + (beginning-of-line) + (looking-at verilog-directive-re-1)) + (verilog-indent-line)))) + +(defun electric-verilog-tab () + "Function called when TAB is pressed in Verilog mode." + (interactive) + ;; If verilog-tab-always-indent, indent the beginning of the line. + (if (or verilog-tab-always-indent + (save-excursion + (skip-chars-backward " \t") + (bolp))) + (let* ((oldpnt (point)) + (boi-point + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (verilog-indent-line) + (back-to-indentation) + (point)))) + (if (< (point) boi-point) + (back-to-indentation) + (cond ((not verilog-tab-to-comment)) + ((not (eolp)) + (end-of-line)) + (t + (indent-for-comment) + (when (and (eolp) (= oldpnt (point))) + ; kill existing comment + (beginning-of-line) + (re-search-forward comment-start-skip oldpnt 'move) + (goto-char (match-beginning 0)) + (skip-chars-backward " \t") + (kill-region (point) oldpnt) + )))) + ) + (progn (insert "\t")))) + + + +;; +;; Interactive functions +;; + +(defun verilog-indent-buffer () + "Indent-region the entire buffer as Verilog code. +To call this from the command line, see \\[verilog-batch-indent]." + (interactive) + (verilog-mode) + (indent-region (point-min) (point-max) nil)) + +(defun verilog-insert-block () + "Insert Verilog begin ... end; block in the code with right indentation." + (interactive) + (verilog-indent-line) + (insert "begin") + (electric-verilog-terminate-line) + (save-excursion + (electric-verilog-terminate-line) + (insert "end") + (beginning-of-line) + (verilog-indent-line))) + +(defun verilog-star-comment () + "Insert Verilog star comment at point." + (interactive) + (verilog-indent-line) + (insert "/*") + (save-excursion + (newline) + (insert " */")) + (newline) + (insert " * ")) + +(defun verilog-insert-indices (MAX) + "Insert a set of indices at into the rectangle. +The upper left corner is defined by the current point. Indices always +begin with 0 and extend to the MAX - 1. If no prefix arg is given, the +user is prompted for a value. The indices are surrounded by square brackets +[]. For example, the following code with the point located after the first +'a' gives: + + a = b a[ 0] = b + a = b a[ 1] = b + a = b a[ 2] = b + a = b a[ 3] = b + a = b ==> insert-indices ==> a[ 4] = b + a = b a[ 5] = b + a = b a[ 6] = b + a = b a[ 7] = b + a = b a[ 8] = b" + + (interactive "NMAX?") + (save-excursion + (let ((n 0)) + (while (< n MAX) + (save-excursion + (insert (format "[%3d]" n))) + (next-line 1) + (setq n (1+ n)))))) + + +(defun verilog-generate-numbers (MAX) + "Insert a set of generated numbers into a rectangle. +The upper left corner is defined by point. The numbers are padded to three +digits, starting with 000 and extending to (MAX - 1). If no prefix argument +is supplied, then the user is prompted for the MAX number. consider the +following code fragment: + + buf buf buf buf000 + buf buf buf buf001 + buf buf buf buf002 + buf buf buf buf003 + buf buf ==> insert-indices ==> buf buf004 + buf buf buf buf005 + buf buf buf buf006 + buf buf buf buf007 + buf buf buf buf008" + + (interactive "NMAX?") + (save-excursion + (let ((n 0)) + (while (< n MAX) + (save-excursion + (insert (format "%3.3d" n))) + (next-line 1) + (setq n (1+ n)))))) + +(defun verilog-mark-defun () + "Mark the current verilog function (or procedure). +This puts the mark at the end, and point at the beginning." + (interactive) + (push-mark (point)) + (verilog-end-of-defun) + (push-mark (point)) + (verilog-beg-of-defun) + (zmacs-activate-region)) + +(defun verilog-comment-region (start end) + ; checkdoc-params: (start end) + "Put the region into a Verilog comment. +The comments that are in this area are \"deformed\": +`*)' becomes `!(*' and `}' becomes `!{'. +These deformed comments are returned to normal if you use +\\[verilog-uncomment-region] to undo the commenting. + +The commented area starts with `verilog-exclude-str-start', and ends with +`verilog-exclude-str-end'. But if you change these variables, +\\[verilog-uncomment-region] won't recognize the comments." + (interactive "r") + (save-excursion + ;; Insert start and endcomments + (goto-char end) + (if (and (save-excursion (skip-chars-forward " \t") (eolp)) + (not (save-excursion (skip-chars-backward " \t") (bolp)))) + (forward-line 1) + (beginning-of-line)) + (insert verilog-exclude-str-end) + (setq end (point)) + (newline) + (goto-char start) + (beginning-of-line) + (insert verilog-exclude-str-start) + (newline) + ;; Replace end-comments within commented area + (goto-char end) + (save-excursion + (while (re-search-backward "\\*/" start t) + (replace-match "*-/" t t))) + (save-excursion + (let ((s+1 (1+ start))) + (while (re-search-backward "/\\*" s+1 t) + (replace-match "/-*" t t)))) + )) + +(defun verilog-uncomment-region () + "Uncomment a commented area; change deformed comments back to normal. +This command does nothing if the pointer is not in a commented +area. See also `verilog-comment-region'." + (interactive) + (save-excursion + (let ((start (point)) + (end (point))) + ;; Find the boundaries of the comment + (save-excursion + (setq start (progn (search-backward verilog-exclude-str-start nil t) + (point))) + (setq end (progn (search-forward verilog-exclude-str-end nil t) + (point)))) + ;; Check if we're really inside a comment + (if (or (equal start (point)) (<= end (point))) + (message "Not standing within commented area.") + (progn + ;; Remove endcomment + (goto-char end) + (beginning-of-line) + (let ((pos (point))) + (end-of-line) + (delete-region pos (1+ (point)))) + ;; Change comments back to normal + (save-excursion + (while (re-search-backward "\\*-/" start t) + (replace-match "*/" t t))) + (save-excursion + (while (re-search-backward "/-\\*" start t) + (replace-match "/*" t t))) + ;; Remove start comment + (goto-char start) + (beginning-of-line) + (let ((pos (point))) + (end-of-line) + (delete-region pos (1+ (point))))))))) + +(defun verilog-beg-of-defun () + "Move backward to the beginning of the current function or procedure." + (interactive) + (verilog-re-search-backward verilog-defun-re nil 'move)) + +(defun verilog-end-of-defun () + "Move forward to the end of the current function or procedure." + (interactive) + (verilog-re-search-forward verilog-end-defun-re nil 'move)) + +(defun verilog-get-beg-of-defun (&optional warn) + (save-excursion + (cond ((verilog-re-search-forward-quick verilog-defun-re nil t) + (point)) + (t + (error "%s: Can't find module beginning" (verilog-point-text)) + (point-max))))) +(defun verilog-get-end-of-defun (&optional warn) + (save-excursion + (cond ((verilog-re-search-forward-quick verilog-end-defun-re nil t) + (point)) + (t + (error "%s: Can't find endmodule" (verilog-point-text)) + (point-max))))) + +(defun verilog-label-be (&optional arg) + "Label matching begin ... end, fork ... join and case ... endcase statements. +With ARG, first kill any existing labels." + (interactive) + (let ((cnt 0) + (oldpos (point)) + (b (progn + (verilog-beg-of-defun) + (point-marker))) + (e (progn + (verilog-end-of-defun) + (point-marker))) + ) + (goto-char (marker-position b)) + (if (> (- e b) 200) + (message "Relabeling module...")) + (while (and + (> (marker-position e) (point)) + (verilog-re-search-forward + (concat + "\\<end\\(\\(function\\)\\|\\(task\\)\\|\\(module\\)\\|\\(primitive\\)\\|\\(interface\\)\\|\\(package\\)\\|\\(case\\)\\)?\\>" + "\\|\\(`endif\\)\\|\\(`else\\)") + nil 'move)) + (goto-char (match-beginning 0)) + (let ((indent-str (verilog-indent-line))) + (verilog-set-auto-endcomments indent-str 't) + (end-of-line) + (delete-horizontal-space) + ) + (setq cnt (1+ cnt)) + (if (= 9 (% cnt 10)) + (message "%d..." cnt)) + ) + (goto-char oldpos) + (if (or + (> (- e b) 200) + (> cnt 20)) + (message "%d lines auto commented" cnt)) + )) + +(defun verilog-beg-of-statement () + "Move backward to beginning of statement." + (interactive) + ;; Move back token by token until we see the end + ;; of some ealier line. + (while + ;; If the current point does not begin a new + ;; statement, as in the character ahead of us is a ';', or SOF + ;; or the string after us unambiguosly starts a statement, + ;; or the token before us unambiguously ends a statement, + ;; then move back a token and test again. + (not (or + (bolp) + (= (preceding-char) ?\;) + (not (or + (looking-at "\\<") + (forward-word -1))) + (and + (looking-at verilog-extended-complete-re) + (not (save-excursion + (verilog-backward-token) + (looking-at verilog-extended-complete-re))) + ) + (looking-at verilog-basic-complete-re) + (save-excursion + (verilog-backward-token) + (or + (looking-at verilog-end-block-re) + (looking-at verilog-preprocessor-re))) + )) + (verilog-backward-syntactic-ws) + (verilog-backward-token)) + ;; Now point is where the previous line ended. + (verilog-forward-syntactic-ws)) + +(defun verilog-beg-of-statement-1 () + "Move backward to beginning of statement." + (interactive) + (let ((pt (point))) + + (while (and (not (looking-at verilog-complete-reg)) + (setq pt (point)) + (verilog-backward-token) + (not (looking-at verilog-complete-reg)) + (verilog-backward-syntactic-ws) + (setq pt (point)) + (not (bolp)) + (not (= (preceding-char) ?\;)))) + (goto-char pt) + (verilog-forward-ws&directives))) + +(defun verilog-end-of-statement () + "Move forward to end of current statement." + (interactive) + (let ((nest 0) pos) + (or (looking-at verilog-beg-block-re) + ;; Skip to end of statement + (setq pos (catch 'found + (while t + (forward-sexp 1) + (verilog-skip-forward-comment-or-string) + (cond ((looking-at "[ \t]*;") + (skip-chars-forward "^;") + (forward-char 1) + (throw 'found (point))) + ((save-excursion + (forward-sexp -1) + (looking-at verilog-beg-block-re)) + (goto-char (match-beginning 0)) + (throw 'found nil)) + ((looking-at "[ \t]*)") + (throw 'found (point))) + ((eobp) + (throw 'found (point)))))))) + (if (not pos) + ;; Skip a whole block + (catch 'found + (while t + (verilog-re-search-forward verilog-end-statement-re nil 'move) + (setq nest (if (match-end 1) + (1+ nest) + (1- nest))) + (cond ((eobp) + (throw 'found (point))) + ((= 0 nest) + (throw 'found (verilog-end-of-statement)))))) + pos))) + +(defun verilog-in-case-region-p () + "Return TRUE if in a case region; +more specifically, point @ in the line foo : @ begin" + (interactive) + (save-excursion + (if (and + (progn (verilog-forward-syntactic-ws) + (looking-at "\\<begin\\>")) + (progn (verilog-backward-syntactic-ws) + (= (preceding-char) ?\:))) + (catch 'found + (let ((nest 1)) + (while t + (verilog-re-search-backward + (concat "\\(\\<module\\>\\)\\|\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|" + "\\(\\<endcase\\>\\)\\>") + nil 'move) + (cond + ((match-end 3) + (setq nest (1+ nest))) + ((match-end 2) + (if (= nest 1) + (throw 'found 1)) + (setq nest (1- nest))) + (t + (throw 'found (= nest 0))) + )))) + nil))) +(defun verilog-in-struct-region-p () + "Return TRUE if in a struct region; +more specifically, in a list after a struct|union keyword" + (interactive) + (save-excursion + (let* ((state (parse-partial-sexp (point-min) (point))) + (depth (nth 0 state))) + (if depth + (progn (backward-up-list depth) + (verilog-beg-of-statement) + (looking-at "\\<typedef\\>?\\s-*\\<struct\\|union\\>") + ) + ) + ) + ) + ) + +(defun verilog-in-generate-region-p () + "Return TRUE if in a generate region; +more specifically, after a generate and before an endgenerate" + (interactive) + (let ((lim (save-excursion (verilog-beg-of-defun) (point))) + (nest 1) + ) + (save-excursion + (while (and + (/= nest 0) + (verilog-re-search-backward "\\<\\(generate\\)\\|\\(endgenerate\\)\\>" lim 'move) + (cond + ((match-end 1) ; generate + (setq nest (1- nest))) + ((match-end 2) ; endgenerate + (setq nest (1+ nest))) + )) + )) + (= nest 0) )) ; return nest + +(defun verilog-in-fork-region-p () + "Return true if between a fork and join." + (interactive) + (let ((lim (save-excursion (verilog-beg-of-defun) (point))) + (nest 1) + ) + (save-excursion + (while (and + (/= nest 0) + (verilog-re-search-backward "\\<\\(fork\\)\\|\\(join\\(_any\\|_none\\)?\\)\\>" lim 'move) + (cond + ((match-end 1) ; fork + (setq nest (1- nest))) + ((match-end 2) ; join + (setq nest (1+ nest))) + )) + )) + (= nest 0) )) ; return nest + +(defun verilog-backward-case-item (lim) + "Skip backward to nearest enclosing case item. +Limit search to point LIM." + (interactive) + (let ((str 'nil) + (lim1 + (progn + (save-excursion + (verilog-re-search-backward verilog-endcomment-reason-re + lim 'move) + (point))))) + ;; Try to find the real : + (if (save-excursion (search-backward ":" lim1 t)) + (let ((colon 0) + b e ) + (while + (and + (< colon 1) + (verilog-re-search-backward "\\(\\[\\)\\|\\(\\]\\)\\|\\(:\\)" + lim1 'move)) + (cond + ((match-end 1) ;; [ + (setq colon (1+ colon)) + (if (>= colon 0) + (error "%s: unbalanced [" (verilog-point-text)))) + ((match-end 2) ;; ] + (setq colon (1- colon))) + + ((match-end 3) ;; : + (setq colon (1+ colon))) + )) + ;; Skip back to beginning of case item + (skip-chars-backward "\t ") + (verilog-skip-backward-comment-or-string) + (setq e (point)) + (setq b + (progn + (if + (verilog-re-search-backward + "\\<\\(case[zx]?\\)\\>\\|;\\|\\<end\\>" nil 'move) + (progn + (cond + ((match-end 1) + (goto-char (match-end 1)) + (verilog-forward-ws&directives) + (if (looking-at "(") + (progn + (forward-sexp) + (verilog-forward-ws&directives))) + (point)) + (t + (goto-char (match-end 0)) + (verilog-forward-ws&directives) + (point)) + )) + (error "Malformed case item") + ))) + (setq str (buffer-substring b e)) + (if + (setq e + (string-match + "[ \t]*\\(\\(\n\\)\\|\\(//\\)\\|\\(/\\*\\)\\)" str)) + (setq str (concat (substring str 0 e) "..."))) + str) + 'nil))) + + +;; +;; Other functions +;; + +(defun kill-existing-comment () + "Kill auto comment on this line." + (save-excursion + (let* ( + (e (progn + (end-of-line) + (point))) + (b (progn + (beginning-of-line) + (search-forward "//" e t)))) + (if b + (delete-region (- b 2) e))))) + +(defconst verilog-directive-nest-re + (concat "\\(`else\\>\\)\\|" + "\\(`endif\\>\\)\\|" + "\\(`if\\>\\)\\|" + "\\(`ifdef\\>\\)\\|" + "\\(`ifndef\\>\\)")) +(defun verilog-set-auto-endcomments (indent-str kill-existing-comment) + "Add ending comment with given INDENT-STR. +With KILL-EXISTING-COMMENT, remove what was there before. +Insert `// case: 7 ' or `// NAME ' on this line if appropriate. +Insert `// case expr ' if this line ends a case block. +Insert `// ifdef FOO ' if this line ends code conditional on FOO. +Insert `// NAME ' if this line ends a function, task, module, primitive or interface named NAME." + (save-excursion + (cond + (; Comment close preprocessor directives + (and + (looking-at "\\(`endif\\)\\|\\(`else\\)") + (or kill-existing-comment + (not (save-excursion + (end-of-line) + (search-backward "//" (verilog-get-beg-of-line) t))))) + (let ((nest 1) b e + m + (else (if (match-end 2) "!" " ")) + ) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (save-excursion + (backward-sexp 1) + (while (and (/= nest 0) + (verilog-re-search-backward verilog-directive-nest-re nil 'move)) + (cond + ((match-end 1) ; `else + (if (= nest 1) + (setq else "!"))) + ((match-end 2) ; `endif + (setq nest (1+ nest))) + ((match-end 3) ; `if + (setq nest (1- nest))) + ((match-end 4) ; `ifdef + (setq nest (1- nest))) + ((match-end 5) ; `ifndef + (setq nest (1- nest))) + )) + (if (match-end 0) + (setq + m (buffer-substring + (match-beginning 0) + (match-end 0)) + b (progn + (skip-chars-forward "^ \t") + (verilog-forward-syntactic-ws) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point) + )))) + (if b + (if (> (count-lines (point) b) verilog-minimum-comment-distance) + (insert (concat " // " else m " " (buffer-substring b e)))) + (progn + (insert " // unmatched `else or `endif") + (ding 't)) + ))) + + (; Comment close case/class/function/task/module and named block + (and (looking-at "\\<end") + (or kill-existing-comment + (not (save-excursion + (end-of-line) + (search-backward "//" (verilog-get-beg-of-line) t))))) + (let ((type (car indent-str))) + (unless (eq type 'declaration) + (unless (looking-at (concat "\\(" verilog-end-block-ordered-re "\\)[ \t]*:")) ;; ignore named ends + (if (looking-at verilog-end-block-ordered-re) + (cond + (;- This is a case block; search back for the start of this case + (match-end 1) ;; of verilog-end-block-ordered-re + + (let ((err 't) + (str "UNMATCHED!!")) + (save-excursion + (verilog-leap-to-head) + (cond + ((looking-at "\\<randcase\\>") + (setq str "randcase") + (setq err nil) + ) + ((match-end 0) + (goto-char (match-end 1)) + (if nil + (let (s f) + (setq s (match-beginning 1)) + (setq f (progn (end-of-line) + (point))) + (setq str (buffer-substring s f))) + (setq err nil)) + (setq str (concat (buffer-substring (match-beginning 1) (match-end 1)) + " " + (verilog-get-expr)))))) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (insert (concat " // " str )) + (if err (ding 't)) + )) + + (;- This is a begin..end block + (match-end 2) ;; of verilog-end-block-ordered-re + (let ((str " // UNMATCHED !!") + (err 't) + (here (point)) + there + cntx + ) + (save-excursion + (verilog-leap-to-head) + (setq there (point)) + (if (not (match-end 0)) + (progn + (goto-char here) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (insert str) + (ding 't) + ) + (let ((lim + (save-excursion (verilog-beg-of-defun) (point))) + (here (point)) + ) + (cond + (;-- handle named block differently + (looking-at verilog-named-block-re) + (search-forward ":") + (setq there (point)) + (setq str (verilog-get-expr)) + (setq err nil) + (setq str (concat " // block: " str ))) + + ((verilog-in-case-region-p) ;-- handle case item differently + (goto-char here) + (setq str (verilog-backward-case-item lim)) + (setq there (point)) + (setq err nil) + (setq str (concat " // case: " str ))) + + (;- try to find "reason" for this begin + (cond + (; + (eq here (progn + (verilog-backward-token) + (verilog-beg-of-statement-1) + (point))) + (setq err nil) + (setq str "")) + ((looking-at verilog-endcomment-reason-re) + (setq there (match-end 0)) + (setq cntx (concat + (buffer-substring (match-beginning 0) (match-end 0)) " ")) + (cond + (;- begin + (match-end 2) + (setq err nil) + (save-excursion + (if (and (verilog-continued-line) + (looking-at "\\<repeat\\>\\|\\<wait\\>\\|\\<always\\>")) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq str + (concat " // " + (buffer-substring (match-beginning 0) (match-end 0)) " " + (verilog-get-expr)))) + (setq str "")))) + + (;- else + (match-end 4) + (let ((nest 0) + ( reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<if\\>\\)") + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest))) + ((match-end 2) ; end + (setq nest (1+ nest))) + ((match-end 3) + (if (= 0 nest) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // else: !if" str )) + (throw 'skip 1)) + ))) + )))) + + (;- end else + (match-end 5) + (goto-char there) + (let ((nest 0) + ( reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|\\(\\<if\\>\\)") + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest))) + ((match-end 2) ; end + (setq nest (1+ nest))) + ((match-end 3) + (if (= 0 nest) + (progn + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // else: !if" str )) + (throw 'skip 1)) + ))) + )))) + + (;- task/function/initial et cetera + t + (match-end 0) + (goto-char (match-end 0)) + (setq there (point)) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // " cntx str ))) + + (;-- otherwise... + (setq str " // auto-endcomment confused ")) + )) + + ((and + (verilog-in-case-region-p) ;-- handle case item differently + (progn + (setq there (point)) + (goto-char here) + (setq str (verilog-backward-case-item lim)))) + (setq err nil) + (setq str (concat " // case: " str ))) + + ((verilog-in-fork-region-p) + (setq err nil) + (setq str " // fork branch" )) + + ((looking-at "\\<end\\>") + ;; HERE + (forward-word 1) + (verilog-forward-syntactic-ws) + (setq err nil) + (setq str (verilog-get-expr)) + (setq str (concat " // " cntx str ))) + + )))) + (goto-char here) + (end-of-line) + (if kill-existing-comment + (kill-existing-comment)) + (delete-horizontal-space) + (if (or err + (> (count-lines here there) verilog-minimum-comment-distance)) + (insert str)) + (if err (ding 't)) + )))) + (;- this is endclass, which can be nested + (match-end 11) ;; of verilog-end-block-ordered-re + ;;(goto-char there) + (let ((nest 0) + ( reg "\\<\\(class\\)\\|\\(endclass\\)\\|\\(package\\|primitive\\|\\(macro\\)?module\\)\\>") + string + ) + (save-excursion + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 3) ; endclass + (ding 't) + (setq string "unmatched endclass") + (throw 'skip 1)) + + ((match-end 2) ; endclass + (setq nest (1+ nest))) + + ((match-end 1) ; class + (setq nest (1- nest)) + (if (< nest 0) + (progn + (goto-char (match-end 0)) + (let (b e) + (setq b (progn + (skip-chars-forward "^ \t") + (verilog-forward-ws&directives) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))) + (setq string (buffer-substring b e))) + (throw 'skip 1)))) + )))) + (end-of-line) + (insert (concat " // " string ))) + ) + + (;- this is end{function,generate,task,module,primitive,table,generate} + ;- which can not be nested. + t + (let (string reg (width nil)) + (end-of-line) + (if kill-existing-comment + (save-match-data + (kill-existing-comment))) + (delete-horizontal-space) + (backward-sexp) + (cond + ((match-end 5) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<function\\>\\)\\|\\(\\<\\(endfunction\\|task\\|\\(macro\\)?module\\|primitive\\)\\>\\)") + (setq width "\\(\\s-*\\(\\[[^]]*\\]\\)\\|\\(real\\(time\\)?\\)\\|\\(integer\\)\\|\\(time\\)\\)?") + ) + ((match-end 6) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<task\\>\\)\\|\\(\\<\\(endtask\\|function\\|\\(macro\\)?module\\|primitive\\)\\>\\)")) + ((match-end 7) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<\\(macro\\)?module\\>\\)\\|\\<endmodule\\>")) + ((match-end 8) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<primitive\\>\\)\\|\\(\\<\\(endprimitive\\|package\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 9) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<interface\\>\\)\\|\\(\\<\\(endinterface\\|package\\|primitive\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 10) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<package\\>\\)\\|\\(\\<\\(endpackage\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 11) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<class\\>\\)\\|\\(\\<\\(endclass\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 12) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<\\(endcovergroup\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 13) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<program\\>\\)\\|\\(\\<\\(endprogram\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 14) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<\\(endsequence\\|primitive\\|interface\\|\\(macro\\)?module\\)\\>\\)")) + ((match-end 15) ;; of verilog-end-block-ordered-re + (setq reg "\\(\\<clocking\\>\\)\\|\\<endclocking\\>")) + + (t (error "Problem in verilog-set-auto-endcomments")) + ) + (let (b e) + (save-excursion + (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) + (setq b (progn + (skip-chars-forward "^ \t") + (verilog-forward-ws&directives) + (if (and width (looking-at width)) + (progn + (goto-char (match-end 0)) + (verilog-forward-ws&directives) + )) + (point)) + e (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))) + (setq string (buffer-substring b e))) + (t + (ding 't) + (setq string "unmatched end(function|task|module|primitive|interface|package|class|clocking)"))))) + (end-of-line) + (insert (concat " // " string ))) + )))))))))) + +(defun verilog-get-expr() + "Grab expression at point, e.g, case ( a | b & (c ^d))" + (let* ((b (progn + (verilog-forward-syntactic-ws) + (skip-chars-forward " \t") + (point))) + (e (let ((par 1)) + (cond + ((looking-at "@") + (forward-char 1) + (verilog-forward-syntactic-ws) + (if (looking-at "(") + (progn + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\((\\)\\|\\()\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))))) + (point)) + ((looking-at "(") + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\((\\)\\|\\()\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))) + (point)) + ((looking-at "\\[") + (forward-char 1) + (while (and (/= par 0) + (verilog-re-search-forward "\\(\\[\\)\\|\\(\\]\\)" nil 'move)) + (cond + ((match-end 1) + (setq par (1+ par))) + ((match-end 2) + (setq par (1- par))))) + (verilog-forward-syntactic-ws) + (skip-chars-forward "^ \t\n\f") + (point)) + ((looking-at "/[/\\*]") + b) + ('t + (skip-chars-forward "^: \t\n\f") + (point) + )))) + (str (buffer-substring b e))) + (if (setq e (string-match "[ \t]*\\(\\(\n\\)\\|\\(//\\)\\|\\(/\\*\\)\\)" str)) + (setq str (concat (substring str 0 e) "..."))) + str)) + +(defun verilog-expand-vector () + "Take a signal vector on the current line and expand it to multiple lines. +Useful for creating tri's and other expanded fields." + (interactive) + (verilog-expand-vector-internal "[" "]")) + +(defun verilog-expand-vector-internal (bra ket) + "Given BRA, the start brace and KET, the end brace, expand one line into many lines." + (save-excursion + (forward-line 0) + (let ((signal-string (buffer-substring (point) + (progn + (end-of-line) (point))))) + (if (string-match (concat "\\(.*\\)" + (regexp-quote bra) + "\\([0-9]*\\)\\(:[0-9]*\\|\\)\\(::[0-9---]*\\|\\)" + (regexp-quote ket) + "\\(.*\\)$") signal-string) + (let* ((sig-head (match-string 1 signal-string)) + (vec-start (string-to-int (match-string 2 signal-string))) + (vec-end (if (= (match-beginning 3) (match-end 3)) + vec-start + (string-to-int (substring signal-string (1+ (match-beginning 3)) (match-end 3))))) + (vec-range (if (= (match-beginning 4) (match-end 4)) + 1 + (string-to-int (substring signal-string (+ 2 (match-beginning 4)) (match-end 4))))) + (sig-tail (match-string 5 signal-string)) + vec) + ;; Decode vectors + (setq vec nil) + (if (< vec-range 0) + (let ((tmp vec-start)) + (setq vec-start vec-end + vec-end tmp + vec-range (- vec-range)))) + (if (< vec-end vec-start) + (while (<= vec-end vec-start) + (setq vec (append vec (list vec-start))) + (setq vec-start (- vec-start vec-range))) + (while (<= vec-start vec-end) + (setq vec (append vec (list vec-start))) + (setq vec-start (+ vec-start vec-range)))) + ;; + ;; Delete current line + (delete-region (point) (progn (forward-line 0) (point))) + ;; + ;; Expand vector + (while vec + (insert (concat sig-head bra (int-to-string (car vec)) ket sig-tail "\n")) + (setq vec (cdr vec))) + (delete-char -1) + ;; + ))))) + +(defun verilog-strip-comments () + "Strip all comments from the verilog code." + (interactive) + (goto-char (point-min)) + (while (re-search-forward "//" nil t) + (if (verilog-within-string) + (re-search-forward "\"" nil t) + (if (verilog-in-star-comment-p) + (re-search-forward "\*/" nil t) + (let ((bpt (- (point) 2))) + (end-of-line) + (delete-region bpt (point)))))) + ;; + (goto-char (point-min)) + (while (re-search-forward "/\\*" nil t) + (if (verilog-within-string) + (re-search-forward "\"" nil t) + (let ((bpt (- (point) 2))) + (re-search-forward "\\*/") + (delete-region bpt (point)))))) + +(defun verilog-one-line () + "Convert structural verilog instances to occupy one line." + (interactive) + (goto-char (point-min)) + (while (re-search-forward "\\([^;]\\)[ \t]*\n[ \t]*" nil t) + (replace-match "\\1 " nil nil))) + +(defun verilog-linter-name () + "Return name of linter, either surelint or verilint." + (let ((compile-word1 (verilog-string-replace-matches "\\s .*$" "" nil nil + compile-command)) + (lint-word1 (verilog-string-replace-matches "\\s .*$" "" nil nil + verilog-linter))) + (cond ((equal compile-word1 "surelint") `surelint) + ((equal compile-word1 "verilint") `verilint) + ((equal lint-word1 "surelint") `surelint) + ((equal lint-word1 "verilint") `verilint) + (t `surelint)))) ;; back compatibility + +(defun verilog-lint-off () + "Convert a Verilog linter warning line into a disable statement. +For example: + pci_bfm_null.v, line 46: Unused input: pci_rst_ +becomes a comment for the appropriate tool. + +The first word of the `compile-command' or `verilog-linter' +variables are used to determine which product is being used. + +See \\[verilog-surelint-off] and \\[verilog-verilint-off]." + (interactive) + (let ((linter (verilog-linter-name))) + (cond ((equal linter `surelint) + (verilog-surelint-off)) + ((equal linter `verilint) + (verilog-verilint-off)) + (t (error "Linter name not set"))))) + +(defun verilog-surelint-off () + "Convert a SureLint warning line into a disable statement. +Run from Verilog source window; assumes there is a *compile* buffer +with point set appropriately. + +For example: + WARNING [STD-UDDONX]: xx.v, line 8: output out is never assigned. +becomes: + // surefire lint_line_off UDDONX" + (interactive) + (save-excursion + (switch-to-buffer compilation-last-buffer) + (beginning-of-line) + (when + (looking-at "\\(INFO\\|WARNING\\|ERROR\\) \\[[^-]+-\\([^]]+\\)\\]: \\([^,]+\\), line \\([0-9]+\\): \\(.*\\)$") + (let* ((code (match-string 2)) + (file (match-string 3)) + (line (match-string 4)) + (buffer (get-file-buffer file)) + dir filename) + (unless buffer + (progn + (setq buffer + (and (file-exists-p file) + (find-file-noselect file))) + (or buffer + (let* ((pop-up-windows t)) + (let ((name (expand-file-name + (read-file-name + (format "Find this error in: (default %s) " + file) + dir file t)))) + (if (file-directory-p name) + (setq name (expand-file-name filename name))) + (setq buffer + (and (file-exists-p name) + (find-file-noselect name)))))))) + (switch-to-buffer buffer) + (goto-line (string-to-number line)) + (end-of-line) + (catch 'already + (cond + ((verilog-in-slash-comment-p) + (re-search-backward "//") + (cond + ((looking-at "// surefire lint_off_line ") + (goto-char (match-end 0)) + (let ((lim (save-excursion (end-of-line) (point)))) + (if (re-search-forward code lim 'move) + (throw 'already t) + (insert-string (concat " " code))))) + (t + ))) + ((verilog-in-star-comment-p) + (re-search-backward "/\*") + (insert-string (format " // surefire lint_off_line %6s" code )) + ) + (t + (insert-string (format " // surefire lint_off_line %6s" code )) + ))))))) + +(defun verilog-verilint-off () + "Convert a Verilint warning line into a disable statement. + +For example: + (W240) pci_bfm_null.v, line 46: Unused input: pci_rst_ +becomes: + //Verilint 240 off // WARNING: Unused input" + (interactive) + (save-excursion + (beginning-of-line) + (when (looking-at "\\(.*\\)([WE]\\([0-9A-Z]+\\)).*,\\s +line\\s +[0-9]+:\\s +\\([^:\n]+\\):?.*$") + (replace-match (format + ;; %3s makes numbers 1-999 line up nicely + "\\1//Verilint %3s off // WARNING: \\3" + (match-string 2))) + (beginning-of-line) + (verilog-indent-line)))) + +(defun verilog-auto-save-compile () + "Update automatics with \\[verilog-auto], save the buffer, and compile." + (interactive) + (verilog-auto) ; Always do it for safety + (save-buffer) + (compile compile-command)) + + + +;; +;; Batch +;; + +(defmacro verilog-batch-error-wrapper (&rest body) + "Execute BODY and add error prefix to any errors found. +This lets programs calling batch mode to easily extract error messages." + (` (condition-case err + (progn (,@ body)) + (error + (error "%%Error: %s%s" (error-message-string err) + (if (featurep 'xemacs) "\n" "")))))) ;; xemacs forgets to add a newline + +(defun verilog-batch-execute-func (funref) + "Internal processing of a batch command, running FUNREF on all command arguments." + (verilog-batch-error-wrapper + ;; General globals needed + (setq make-backup-files nil) + (setq-default make-backup-files nil) + (setq enable-local-variables t) + (setq enable-local-eval t) + ;; Make sure any sub-files we read get proper mode + (setq default-major-mode `verilog-mode) + ;; Ditto files already read in + (mapcar '(lambda (buf) + (when (buffer-file-name buf) + (save-excursion + (set-buffer buf) + (verilog-mode)))) + (buffer-list)) + ;; Process the files + (mapcar '(lambda (buf) + (when (buffer-file-name buf) + (save-excursion + (if (not (file-exists-p (buffer-file-name buf))) + (error (concat "File not found: " (buffer-file-name buf)))) + (message (concat "Processing " (buffer-file-name buf))) + (set-buffer buf) + (funcall funref) + (save-buffer)))) + (buffer-list)))) + +(defun verilog-batch-auto () + "For use with --batch, perform automatic expansions as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, updates automatics +with \\[verilog-auto] on all command-line files, and saves the buffers. +For proper results, multiple filenames need to be passed on the command +line in bottom-up order." + (unless noninteractive + (error "Use verilog-batch-auto only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-auto)) + +(defun verilog-batch-delete-auto () + "For use with --batch, perform automatic deletion as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, deletes automatics +with \\[verilog-delete-auto] on all command-line files, and saves the buffers." + (unless noninteractive + (error "Use verilog-batch-delete-auto only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-delete-auto)) + +(defun verilog-batch-inject-auto () + "For use with --batch, perform automatic injection as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, injects new automatics +with \\[verilog-inject-auto] on all command-line files, and saves the buffers. +For proper results, multiple filenames need to be passed on the command +line in bottom-up order." + (unless noninteractive + (error "Use verilog-batch-inject-auto only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-inject-auto)) + +(defun verilog-batch-indent () + "For use with --batch, reindent an a entire file as a stand-alone tool. +This sets up the appropriate Verilog-Mode environment, calls +\\[verilog-indent-buffer] on all command-line files, and saves the buffers." + (unless noninteractive + (error "Use verilog-batch-indent only with --batch")) ;; Otherwise we'd mess up buffer modes + (verilog-batch-execute-func `verilog-indent-buffer)) + + +;; +;; Indentation +;; +(defconst verilog-indent-alist + '((block . (+ ind verilog-indent-level)) + (case . (+ ind verilog-case-indent)) + (cparenexp . (+ ind verilog-indent-level)) + (cexp . (+ ind verilog-cexp-indent)) + (defun . verilog-indent-level-module) + (declaration . verilog-indent-level-declaration) + (directive . (verilog-calculate-indent-directive)) + (tf . verilog-indent-level) + (behavioral . (+ verilog-indent-level-behavioral verilog-indent-level-module)) + (statement . ind) + (cpp . 0) + (comment . (verilog-comment-indent)) + (unknown . 3) + (string . 0))) + +(defun verilog-continued-line-1 (lim) + "Return true if this is a continued line. +Set point to where line starts. Limit search to point LIM." + (let ((continued 't)) + (if (eq 0 (forward-line -1)) + (progn + (end-of-line) + (verilog-backward-ws&directives lim) + (if (bobp) + (setq continued nil) + (setq continued (verilog-backward-token)))) + (setq continued nil)) + continued)) + +(defun verilog-calculate-indent () + "Calculate the indent of the current Verilog line. +Examine previous lines. Once a line is found that is definitive as to the +type of the current line, return that lines' indent level and its +type. Return a list of two elements: (INDENT-TYPE INDENT-LEVEL)." + (save-excursion + (let* ((starting_position (point)) + (par 0) + (begin (looking-at "[ \t]*begin\\>")) + (lim (save-excursion (verilog-re-search-backward "\\(\\<begin\\>\\)\\|\\(\\<module\\>\\)" nil t))) + (type (catch 'nesting + ;; Keep working backwards until we can figure out + ;; what type of statement this is. + ;; Basically we need to figure out + ;; 1) if this is a continuation of the previous line; + ;; 2) are we in a block scope (begin..end) + + ;; if we are in a comment, done. + (if (verilog-in-star-comment-p) + (throw 'nesting 'comment)) + + ;; if we have a directive, done. + (if (save-excursion (beginning-of-line) (looking-at verilog-directive-re-1)) + (throw 'nesting 'directive)) + + ;; unless we are in the newfangled coverpoint or constraint blocks + ;; if we are in a parenthesized list, and the user likes to indent these, return. + (if (and + verilog-indent-lists + (not (verilog-in-coverage)) + (verilog-in-paren)) + (progn (setq par 1) + (throw 'nesting 'block)) + ) + + ;; See if we are continuing a previous line + (while t + ;; trap out if we crawl off the top of the buffer + (if (bobp) (throw 'nesting 'cpp)) + + (if (verilog-continued-line-1 lim) + (let ((sp (point))) + (if (and + (not (looking-at verilog-complete-reg)) + (verilog-continued-line-1 lim)) + (progn (goto-char sp) + (throw 'nesting 'cexp)) + + (goto-char sp)) + + (if (and begin + (not verilog-indent-begin-after-if) + (looking-at verilog-no-indent-begin-re)) + (progn + (beginning-of-line) + (skip-chars-forward " \t") + (throw 'nesting 'statement)) + (progn + (throw 'nesting 'cexp)))) + ;; not a continued line + (goto-char starting_position)) + + (if (looking-at "\\<else\\>") + ;; search back for governing if, striding across begin..end pairs + ;; appropriately + (let ((elsec 1)) + (while (verilog-re-search-backward verilog-ends-re nil 'move) + (cond + ((match-end 1) ; else, we're in deep + (setq elsec (1+ elsec))) + ((match-end 2) ; if + (setq elsec (1- elsec)) + (if (= 0 elsec) + (if verilog-align-ifelse + (throw 'nesting 'statement) + (progn ;; back up to first word on this line + (beginning-of-line) + (verilog-forward-syntactic-ws) + (throw 'nesting 'statement))))) + (t ; endblock + ; try to leap back to matching outward block by striding across + ; indent level changing tokens then immediately + ; previous line governs indentation. + (let (( reg) (nest 1)) +;; verilog-ends => else|if|end|join(_any|_none|)|endcase|endclass|endtable|endspecify|endfunction|endtask|endgenerate|endgroup + (cond + ((match-end 3) ; end + ;; Search back for matching begin + (setq reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)" )) + ((match-end 4) ; endcase + ;; Search back for matching case + (setq reg "\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" )) + ((match-end 5) ; endfunction + ;; Search back for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )) + ((match-end 6) ; endtask + ;; Search back for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )) + ((match-end 7) ; endspecify + ;; Search back for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )) + ((match-end 8) ; endtable + ;; Search back for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )) + ((match-end 9) ; endgenerate + ;; Search back for matching generate + (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" )) + ((match-end 10) ; joins + ;; Search back for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|none\\)?\\>\\)" )) + ((match-end 11) ; class + ;; Search back for matching class + (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" )) + ((match-end 12) ; covergroup + ;; Search back for matching covergroup + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" )) + ) + (catch 'skip + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest)) + (if (= 0 nest) + (throw 'skip 1))) + ((match-end 2) ; end + (setq nest (1+ nest))))) + ) + )) + )))) + (throw 'nesting (verilog-calc-1)) + ) + );; catch nesting + );; type + ) + ;; Return type of block and indent level. + (if (not type) + (setq type 'cpp)) + (if (> par 0) ; Unclosed Parenthesis + (list 'cparenexp par) + (cond + ((eq type 'case) + (list type (verilog-case-indent-level))) + ((eq type 'statement) + (list type (current-column))) + ((eq type 'defun) + (list type 0)) + (t + (list type (verilog-current-indent-level))))) + ))) +(defun verilog-wai () + "Show matching nesting block for debugging." + (interactive) + (save-excursion + (let ((nesting (verilog-calc-1))) + (message "You are at nesting %s" nesting)))) + +(defun verilog-calc-1 () + (catch 'nesting + (while (verilog-re-search-backward (concat "\\({\\|}\\|" verilog-indent-re "\\)") nil 'move) + (cond + ((equal (char-after) ?\{) + (if (verilog-at-constraint-p) + (throw 'nesting 'block) + )) + ((equal (char-after) ?\}) + + (let ((there (verilog-at-close-constraint-p))) + (if there (goto-char there)))) + + ((looking-at verilog-beg-block-re-ordered) + (cond + ((match-end 2) ; *sigh* could be "unique case" or "priority casex" + (let ((here (point))) + (verilog-beg-of-statement) + (if (looking-at verilog-extended-case-re) + (throw 'nesting 'case) + (goto-char here))) + (throw 'nesting 'case)) + + ;; need to consider typedef struct here... + ((looking-at "\\<class\\|struct\\|function\\|task\\|property\\>") + ; *sigh* These words have an optional prefix: + ; extern {virtual|protected}? function a(); + ; assert property (p_1); + ; typedef class foo; + ; and we don't want to confuse this with + ; function a(); + ; property + ; ... + ; endfunction + (let ((here (point))) + (save-excursion + (verilog-beg-of-statement) + (if (= (point) here) + (throw 'nesting 'block)) + ))) + (t (throw 'nesting 'block)))) + + ((looking-at verilog-end-block-re) + (verilog-leap-to-head) + (if (verilog-in-case-region-p) + (progn + (verilog-leap-to-case-head) + (if (looking-at verilog-case-re) + (throw 'nesting 'case))))) + + ((looking-at (if (verilog-in-generate-region-p) + verilog-defun-level-not-generate-re + verilog-defun-level-re)) + (throw 'nesting 'defun)) + + ((looking-at verilog-cpp-level-re) + (throw 'nesting 'cpp)) + + ((bobp) + (throw 'nesting 'cpp)) + )) + (throw 'nesting 'cpp) + ) + ) + +(defun verilog-calculate-indent-directive () + "Return indentation level for directive. +For speed, the searcher looks at the last directive, not the indent +of the appropriate enclosing block." + (let ((base -1) ;; Indent of the line that determines our indentation + (ind 0) ;; Relative offset caused by other directives (like `endif on same line as `else) + ) + ;; Start at current location, scan back for another directive + + (save-excursion + (beginning-of-line) + (while (and (< base 0) + (verilog-re-search-backward verilog-directive-re nil t)) + (cond ((save-excursion (skip-chars-backward " \t") (bolp)) + (setq base (current-indentation)) + )) + (cond ((and (looking-at verilog-directive-end) (< base 0)) ;; Only matters when not at BOL + (setq ind (- ind verilog-indent-level-directive))) + ((and (looking-at verilog-directive-middle) (>= base 0)) ;; Only matters when at BOL + (setq ind (+ ind verilog-indent-level-directive))) + ((looking-at verilog-directive-begin) + (setq ind (+ ind verilog-indent-level-directive))))) + ;; Adjust indent to starting indent of critical line + (setq ind (max 0 (+ ind base)))) + + (save-excursion + (beginning-of-line) + (skip-chars-forward " \t") + (cond ((or (looking-at verilog-directive-middle) + (looking-at verilog-directive-end)) + (setq ind (max 0 (- ind verilog-indent-level-directive)))))) + ind)) + +(defun verilog-leap-to-case-head () + (let ((nest 1)) + (while (/= 0 nest) + (verilog-re-search-backward "\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" nil 'move) + (cond + ((match-end 1) + (setq nest (1- nest))) + ((match-end 2) + (setq nest (1+ nest))) + ((bobp) + (ding 't) + (setq nest 0)))))) + +(defun verilog-leap-to-head () + "Move point to the head of this block; jump from end to matching begin, +from endcase to matching case, and so on." + (let ((reg nil) + snest + (nest 1)) + (cond + ((looking-at "\\<end\\>") + ;; 1: Search back for matching begin + (setq reg (concat "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|" + "\\(\\<endcase\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" ))) + ((looking-at "\\<endcase\\>") + ;; 2: Search back for matching case + (setq reg "\\(\\<randcase\\>\\|\\<case[xz]?\\>\\)\\|\\(\\<endcase\\>\\)" )) + ((looking-at "\\<join\\(_any\\|_none\\)?\\>") + ;; 3: Search back for matching fork + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" )) + ((looking-at "\\<endclass\\>") + ;; 4: Search back for matching class + (setq reg "\\(\\<class\\>\\)\\|\\(\\<endclass\\>\\)" )) + ((looking-at "\\<endtable\\>") + ;; 5: Search back for matching table + (setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )) + ((looking-at "\\<endspecify\\>") + ;; 6: Search back for matching specify + (setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )) + ((looking-at "\\<endfunction\\>") + ;; 7: Search back for matching function + (setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )) + ((looking-at "\\<endgenerate\\>") + ;; 8: Search back for matching generate + (setq reg "\\(\\<generate\\>\\)\\|\\(\\<endgenerate\\>\\)" )) + ((looking-at "\\<endtask\\>") + ;; 9: Search back for matching task + (setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )) + ((looking-at "\\<endgroup\\>") + ;; 10: Search back for matching covergroup + (setq reg "\\(\\<covergroup\\>\\)\\|\\(\\<endgroup\\>\\)" )) + ((looking-at "\\<endproperty\\>") + ;; 11: Search back for matching property + (setq reg "\\(\\<property\\>\\)\\|\\(\\<endproperty\\>\\)" )) + ((looking-at "\\<endinterface\\>") + ;; 12: Search back for matching interface + (setq reg "\\(\\<interface\\>\\)\\|\\(\\<endinterface\\>\\)" )) + ((looking-at "\\<endsequence\\>") + ;; 12: Search back for matching sequence + (setq reg "\\(\\<\\(rand\\)?sequence\\>\\)\\|\\(\\<endsequence\\>\\)" )) + ((looking-at "\\<endclocking\\>") + ;; 12: Search back for matching clocking + (setq reg "\\(\\<clocking\\)\\|\\(\\<endclocking\\>\\)" )) + ) + (if reg + (catch 'skip + (let (sreg) + (while (verilog-re-search-backward reg nil 'move) + (cond + ((match-end 1) ; begin + (setq nest (1- nest)) + (if (= 0 nest) + ;; Now previous line describes syntax + (throw 'skip 1)) + (if (and snest + (= snest nest)) + (setq reg sreg))) + ((match-end 2) ; end + (setq nest (1+ nest))) + ((match-end 3) + ;; endcase, jump to case + (setq snest nest) + (setq nest (1+ nest)) + (setq sreg reg) + (setq reg "\\(\\<randcase\\>\\|\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" )) + ((match-end 4) + ;; join, jump to fork + (setq snest nest) + (setq nest (1+ nest)) + (setq sreg reg) + (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\(_any\\|_none\\)?\\>\\)" )) + ))))))) + +(defun verilog-continued-line () + "Return true if this is a continued line. +Set point to where line starts" + (let ((continued 't)) + (if (eq 0 (forward-line -1)) + (progn + (end-of-line) + (verilog-backward-ws&directives) + (if (bobp) + (setq continued nil) + (while (and continued + (save-excursion + (skip-chars-backward " \t") + (not (bolp)))) + (setq continued (verilog-backward-token)) + ) ;; while + )) + (setq continued nil)) + continued)) + +(defun verilog-backward-token () + "Step backward token, returning true if we are now at an end of line token." + (interactive) + (verilog-backward-syntactic-ws) + (cond + ((bolp) + nil) + (;-- Anything ending in a ; is complete + (= (preceding-char) ?\;) + nil) + (; If a "}" is prefixed by a ";", then this is a complete statement + ; i.e.: constraint foo { a = b; } + (= (preceding-char) ?\}) + (progn + (backward-char) + (verilog-at-close-constraint-p)) + ) + (;-- constraint foo { a = b } + ; is a complete statement. *sigh* + (= (preceding-char) ?\{) + (progn + (backward-char) + (not (verilog-at-constraint-p))) + ) + (;-- Could be 'case (foo)' or 'always @(bar)' which is complete + ; also could be simply '@(foo)' + ; or foo u1 #(a=8) + ; (b, ... which ISN'T complete + ;;;; Do we need this??? + (= (preceding-char) ?\)) + (progn + (backward-char) + (backward-up-list 1) + (verilog-backward-syntactic-ws) + (let ((back (point))) + (forward-word -1) + (cond + ((looking-at "\\<\\(always\\(_latch\\|_ff\\|_comb\\)?\\|case\\(\\|[xz]\\)\\|for\\(\\|each\\|ever\\)\\|i\\(f\\|nitial\\)\\|repeat\\|while\\)\\>") + (not (looking-at "\\<randcase\\>\\|\\<case[xz]?\\>[^:]"))) + (t + (goto-char back) + (cond + ((= (preceding-char) ?\@) + (backward-char) + (save-excursion + (verilog-backward-token) + (not (looking-at "\\<\\(always\\(_latch\\|_ff\\|_comb\\)?\\|initial\\|while\\)\\>")))) + ((= (preceding-char) ?\#) + (backward-char) + ) + (t t)) + ))))) + + (;-- any of begin|initial|while are complete statements; 'begin : foo' is also complete + t + (forward-word -1) + (cond + ((looking-at "\\<else\\>") + t) + ((looking-at verilog-indent-re) + nil) + (t + (let + ((back (point))) + (verilog-backward-syntactic-ws) + (cond + ((= (preceding-char) ?\:) + (backward-char) + (verilog-backward-syntactic-ws) + (backward-sexp) + (if (looking-at verilog-nameable-item-re ) + nil + t) + ) + ((= (preceding-char) ?\#) + (backward-char) + t) + ((= (preceding-char) ?\`) + (backward-char) + t) + + (t + (goto-char back) + t) + ))))))) + +(defun verilog-backward-syntactic-ws (&optional bound) + "Backward skip over syntactic whitespace for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-min))) (here bound) ) + (if (< bound (point)) + (progn + (narrow-to-region bound (point)) + (while (/= here (point)) + (setq here (point)) + (verilog-skip-backward-comments) + ))) + )) + t) + +(defun verilog-forward-syntactic-ws (&optional bound) + "Forward skip over syntactic whitespace for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-max))) + (here bound) + ) + (if (> bound (point)) + (progn + (narrow-to-region (point) bound) + (while (/= here (point)) + (setq here (point)) + (forward-comment (buffer-size)) + ))) + ))) + +(defun verilog-backward-ws&directives (&optional bound) + "Backward skip over syntactic whitespace and compiler directives for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-min))) + (here bound) + (p nil) ) + (if (< bound (point)) + (progn + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ;; in // comment + (verilog-re-search-backward "//" nil 'move) + (skip-chars-backward "/")) + ((nth 4 state) ;; in /* */ comment + (verilog-re-search-backward "/\*" nil 'move)))) + (narrow-to-region bound (point)) + (while (/= here (point)) + (setq here (point)) + (verilog-skip-backward-comments) + (setq p + (save-excursion + (beginning-of-line) + (cond + ((verilog-within-translate-off) + (verilog-back-to-start-translate-off (point-min))) + ((looking-at verilog-directive-re-1) + (point)) + (t + nil)))) + (if p (goto-char p)) + ))) + ))) + +(defun verilog-forward-ws&directives (&optional bound) + "Forward skip over syntactic whitespace and compiler directives for Emacs 19. +Optional BOUND limits search." + (save-restriction + (let* ((bound (or bound (point-max))) + (here bound) + jump + ) + (if (> bound (point)) + (progn + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ;; in // comment + (verilog-re-search-forward "//" nil 'move)) + ((nth 4 state) ;; in /* */ comment + (verilog-re-search-forward "/\*" nil 'move)))) + (narrow-to-region (point) bound) + (while (/= here (point)) + (setq here (point) + jump nil) + (forward-comment (buffer-size)) + (save-excursion + (beginning-of-line) + (if (looking-at verilog-directive-re-1) + (setq jump t))) + (if jump + (beginning-of-line 2)) + ))) + ))) + +(defun verilog-in-comment-p () + "Return true if in a star or // comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (or (nth 4 state) (nth 7 state)))) + +(defun verilog-in-star-comment-p () + "Return true if in a star comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (and + (nth 4 state) ; t if in a comment of style a // or b /**/ + (not + (nth 7 state) ; t if in a comment of style b /**/ + )))) + +(defun verilog-in-slash-comment-p () + "Return true if in a slash comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (nth 7 state))) + +(defun verilog-in-comment-or-string-p () + "Return true if in a string or comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (or (nth 3 state) (nth 4 state) (nth 7 state)))) ; Inside string or comment) + +(defun verilog-in-escaped-name-p () + "Return true if in an escaped name." + (save-excursion + (backward-char) + (skip-chars-backward "^ \t\n\f") + (if (equal (char-after (point) ) ?\\ ) + t + nil))) + +(defun verilog-in-paren () + "Return true if in a parenthetical expression." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (> (nth 0 state) 0 ))) + +(defun verilog-in-coverage () + "Return true if in a constraint or coverpoint expression." + (interactive) + (save-excursion + (if (verilog-in-paren) + (progn + (backward-up-list 1) + (verilog-at-constraint-p) + ) + nil))) +(defun verilog-at-close-constraint-p () + "If at the } that closes a constraint or covergroup, return true." + (if (and + (equal (char-after) ?\}) + (verilog-in-paren)) + + (save-excursion + (verilog-backward-ws&directives) + (if (equal (char-before) ?\;) + (point) + nil)))) + +(defun verilog-at-constraint-p () + "If at the { of a constraint or coverpoint definition, return true, moving point to constraint." + (if (save-excursion + (and + (equal (char-after) ?\{) + (forward-list) + (progn (backward-char 1) + (verilog-backward-ws&directives) + (equal (char-before) ?\;)) + )) + ;; maybe + (verilog-re-search-backward "\\<constraint\\|coverpoint\\|cross\\>" nil 'move) + ;; not + nil + ) + ) + +(defun verilog-parenthesis-depth () + "Return non zero if in parenthetical-expression." + (save-excursion + (nth 1 (parse-partial-sexp (point-min) (point))))) + + +(defun verilog-skip-forward-comment-or-string () + "Return true if in a string or comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 3 state) ;Inside string + (goto-char (nth 3 state)) + t) + ((nth 7 state) ;Inside // comment + (forward-line 1) + t) + ((nth 4 state) ;Inside any comment (hence /**/) + (search-forward "*/")) + (t + nil)))) + +(defun verilog-skip-backward-comment-or-string () + "Return true if in a string or comment." + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 3 state) ;Inside string + (search-backward "\"") + t) + ((nth 7 state) ;Inside // comment + (search-backward "//") + (skip-chars-backward "/") + t) + ((nth 4 state) ;Inside /* */ comment + (search-backward "/*") + t) + (t + nil)))) + +(defun verilog-skip-backward-comments () + "Return true if a comment was skipped." + (let ((more t)) + (while more + (setq more + (let ((state + (save-excursion + (parse-partial-sexp (point-min) (point))))) + (cond + ((nth 7 state) ;Inside // comment + (search-backward "//") + (skip-chars-backward "/") + (skip-chars-backward " \t\n\f") + t) + ((nth 4 state) ;Inside /* */ comment + (search-backward "/*") + (skip-chars-backward " \t\n\f") + t) + ((and (not (bobp)) + (= (char-before) ?\/) + (= (char-before (1- (point))) ?\*) + ) + (goto-char (- (point) 2)) + t) + (t + (skip-chars-backward " \t\n\f") + nil))))))) + +(defun verilog-skip-forward-comment-p () + "If in comment, move to end and return true." + (let (state) + (progn + (setq state + (save-excursion + (parse-partial-sexp (point-min) (point)))) + (cond + ((nth 3 state) + t) + ((nth 7 state) ;Inside // comment + (end-of-line) + (forward-char 1) + t) + ((nth 4 state) ;Inside any comment + t) + (t + nil))))) + +(defun verilog-indent-line-relative () + "Cheap version of indent line. +Only look at a few lines to determine indent level." + (interactive) + (let ((indent-str) + (sp (point))) + (if (looking-at "^[ \t]*$") + (cond ;- A blank line; No need to be too smart. + ((bobp) + (setq indent-str (list 'cpp 0))) + ((verilog-continued-line) + (let ((sp1 (point))) + (if (verilog-continued-line) + (progn (goto-char sp) + (setq indent-str (list 'statement (verilog-current-indent-level)))) + (goto-char sp1) + (setq indent-str (list 'block (verilog-current-indent-level))))) + (goto-char sp)) + ((goto-char sp) + (setq indent-str (verilog-calculate-indent)))) + (progn (skip-chars-forward " \t") + (setq indent-str (verilog-calculate-indent)))) + (verilog-do-indent indent-str))) + +(defun verilog-indent-line () + "Indent for special part of code." + (verilog-do-indent (verilog-calculate-indent))) + +(defun verilog-do-indent (indent-str) + (let ((type (car indent-str)) + (ind (car (cdr indent-str)))) + (cond + (; handle continued exp + (eq type 'cexp) + (let ((here (point))) + (verilog-backward-syntactic-ws) + (cond + ((or + (= (preceding-char) ?\,) + (= (preceding-char) ?\]) + (save-excursion + (verilog-beg-of-statement-1) + (looking-at verilog-declaration-re))) + (let* ( fst + (val + (save-excursion + (backward-char 1) + (verilog-beg-of-statement-1) + (setq fst (point)) + (if (looking-at verilog-declaration-re) + (progn ;; we have multiple words + (goto-char (match-end 0)) + (skip-chars-forward " \t") + (cond + ((and verilog-indent-declaration-macros + (= (following-char) ?\`)) + (progn + (forward-char 1) + (forward-word 1) + (skip-chars-forward " \t"))) + ((= (following-char) ?\[) + (progn + (forward-char 1) + (backward-up-list -1) + (skip-chars-forward " \t"))) + ) + (current-column)) + (progn + (goto-char fst) + (+ (current-column) verilog-cexp-indent)) + )))) + (goto-char here) + (indent-line-to val)) + ) + ((= (preceding-char) ?\) ) + (goto-char here) + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + (indent-line-to val))) + (t + (goto-char here) + (let ((val)) + (verilog-beg-of-statement-1) + (if (and (< (point) here) + (verilog-re-search-forward "=[ \\t]*" here 'move)) + (setq val (current-column)) + (setq val (eval (cdr (assoc type verilog-indent-alist))))) + (goto-char here) + (indent-line-to val))) + ))) + + (; handle inside parenthetical expressions + (eq type 'cparenexp) + (let ((val (save-excursion + (backward-up-list 1) + (forward-char 1) + (skip-chars-forward " \t") + (current-column)))) + (indent-line-to val) + (if (and (not (verilog-in-struct-region-p)) + (looking-at verilog-declaration-re)) + (verilog-indent-declaration ind)) + )) + + (;-- Handle the ends + (or + (looking-at verilog-end-block-re ) + (verilog-at-close-constraint-p)) + (let ((val (if (eq type 'statement) + (- ind verilog-indent-level) + ind))) + (indent-line-to val))) + + (;-- Case -- maybe line 'em up + (and (eq type 'case) (not (looking-at "^[ \t]*$"))) + (progn + (cond + ((looking-at "\\<endcase\\>") + (indent-line-to ind)) + (t + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + (indent-line-to val)))))) + + (;-- defun + (and (eq type 'defun) + (looking-at verilog-zero-indent-re)) + (indent-line-to 0)) + + (;-- declaration + (and (or + (eq type 'defun) + (eq type 'block)) + (looking-at verilog-declaration-re)) + (verilog-indent-declaration ind)) + + (;-- Everything else + t + (let ((val (eval (cdr (assoc type verilog-indent-alist))))) + (indent-line-to val))) + ) + (if (looking-at "[ \t]+$") + (skip-chars-forward " \t")) + indent-str ; Return indent data + )) + +(defun verilog-current-indent-level () + "Return the indent-level the current statement has." + (save-excursion + (let (par-pos) + (beginning-of-line) + (setq par-pos (verilog-parenthesis-depth)) + (while par-pos + (goto-char par-pos) + (beginning-of-line) + (setq par-pos (verilog-parenthesis-depth))) + (skip-chars-forward " \t") + (current-column)))) + +(defun verilog-case-indent-level () + "Return the indent-level the current statement has. +Do not count named blocks or case-statements." + (save-excursion + (skip-chars-forward " \t") + (cond + ((looking-at verilog-named-block-re) + (current-column)) + ((and (not (looking-at verilog-case-re)) + (looking-at "^[^:;]+[ \t]*:")) + (verilog-re-search-forward ":" nil t) + (skip-chars-forward " \t") + (current-column)) + (t + (current-column))))) + +(defun verilog-indent-comment () + "Indent current line as comment." + (let* ((stcol + (cond + ((verilog-in-star-comment-p) + (save-excursion + (re-search-backward "/\\*" nil t) + (1+(current-column)))) + (comment-column + comment-column ) + (t + (save-excursion + (re-search-backward "//" nil t) + (current-column))) + ))) + (indent-line-to stcol) + stcol)) + +(defun verilog-more-comment () + "Make more comment lines like the previous." + (let* ((star 0) + (stcol + (cond + ((verilog-in-star-comment-p) + (save-excursion + (setq star 1) + (re-search-backward "/\\*" nil t) + (1+(current-column)))) + (comment-column + comment-column ) + (t + (save-excursion + (re-search-backward "//" nil t) + (current-column))) + ))) + (progn + (indent-to stcol) + (if (and star + (save-excursion + (forward-line -1) + (skip-chars-forward " \t") + (looking-at "\*"))) + (insert "* "))))) + +(defun verilog-comment-indent (&optional arg) + "Return the column number the line should be indented to. +ARG is ignored, for `comment-indent-function' compatibility." + (cond + ((verilog-in-star-comment-p) + (save-excursion + (re-search-backward "/\\*" nil t) + (1+(current-column)))) + ( comment-column + comment-column ) + (t + (save-excursion + (re-search-backward "//" nil t) + (current-column))))) + +;; + +(defun verilog-pretty-declarations () + "Line up declarations around point." + (interactive) + (save-excursion + (if (progn + (verilog-beg-of-statement-1) + (looking-at verilog-declaration-re)) + (let* ((m1 (make-marker)) + (e) (r) + (here (point)) + ;; Start of declaration range + (start + (progn + (verilog-beg-of-statement-1) + (while (looking-at verilog-declaration-re) + (beginning-of-line) + (setq e (point)) + (verilog-backward-syntactic-ws) + (backward-char) + (verilog-beg-of-statement-1)) ;Ack, need to grok `define + e)) + ;; End of declaration range + (end + (progn + (goto-char here) + (verilog-end-of-statement) + (setq e (point)) ;Might be on last line + (verilog-forward-syntactic-ws) + (while (looking-at verilog-declaration-re) + (beginning-of-line) + (verilog-end-of-statement) + (setq e (point)) + (verilog-forward-syntactic-ws)) + e)) + (edpos (set-marker (make-marker) end)) + (ind) + (base-ind + (progn + (goto-char start) + (verilog-do-indent (verilog-calculate-indent)) + (verilog-forward-ws&directives) + (current-column))) + ) + (goto-char end) + (goto-char start) + (if (> (- end start) 100) + (message "Lining up declarations..(please stand by)")) + ;; Get the beginning of line indent first + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (cond + ( (save-excursion (skip-chars-backward " \t") + (bolp)) + (verilog-forward-ws&directives) + (indent-line-to base-ind) + (verilog-forward-ws&directives) + (verilog-re-search-forward "[ \t\n\f]" e 'move) + ) + (t + (just-one-space) + (verilog-re-search-forward "[ \t\n\f]" e 'move) + ) + ) + ) + ;;(forward-line)) + ;; Now find biggest prefix + (setq ind (verilog-get-lineup-indent start edpos)) + ;; Now indent each line. + (goto-char start) + (while (progn (setq e (marker-position edpos)) + (setq r (- e (point))) + (> r 0)) + (setq e (point)) + (message "%d" r) + (cond + ((or (and verilog-indent-declaration-macros + (looking-at verilog-declaration-re-1-macro)) + (looking-at verilog-declaration-re-1-no-macro)) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[#`]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (just-one-space) + (indent-to ind)) + (progn + (just-one-space) + (indent-to ind)) + ))) + ((verilog-continued-line-1 start) + (goto-char e) + (indent-line-to ind)) + (t ; Must be comment or white space + (goto-char e) + (verilog-forward-ws&directives) + (forward-line -1)) + ) + (forward-line 1)) + (message ""))))) + +(defun verilog-pretty-expr (&optional myre) + "Line up expressions around point." + (interactive "sRegular Expression: ((<|:)?=) ") + (save-excursion + (if (or (eq myre nil) + (string-equal myre "")) + (setq myre "\\(<\\|:\\)?=")) +; (setq myre (concat "\\(^[^;" myre "]*\\)\\([" myre "]\\)")) + (setq myre (concat "\\(^[^;#:?=]*\\)\\([" myre "]\\)")) + (beginning-of-line) + (if (and (not (looking-at (concat "^\\s-*" verilog-complete-reg))) + (looking-at myre)) + (let* ((here (point)) + (e) (r) + (start + (progn + (beginning-of-line) + (setq e (point)) + (verilog-backward-syntactic-ws) + (beginning-of-line) + (while (and (not (looking-at (concat "^\\s-*" verilog-complete-reg))) + (looking-at myre) + (not (bobp)) + ) + (setq e (point)) + (verilog-backward-syntactic-ws) + (beginning-of-line) + ) ;Ack, need to grok `define + e)) + (end + (progn + (goto-char here) + (end-of-line) + (setq e (point)) ;Might be on last line + (verilog-forward-syntactic-ws) + (beginning-of-line) + (while (and (not(looking-at (concat "^\\s-*" verilog-complete-reg))) + (looking-at myre)) + (end-of-line) + (setq e (point)) + (verilog-forward-syntactic-ws) + (beginning-of-line) + ) + e)) + (edpos (set-marker (make-marker) end)) + (ind) + ) + (goto-char start) + (verilog-do-indent (verilog-calculate-indent)) + (if (> (- end start) 100) + (message "Lining up expressions..(please stand by)")) + + ;; Set indent to minimum throughout region + (while (< (point) (marker-position edpos)) + (beginning-of-line) + (verilog-just-one-space myre) + (end-of-line) + (verilog-forward-syntactic-ws) + ) + + ;; Now find biggest prefix + (setq ind (verilog-get-lineup-indent-2 myre start edpos)) + + ;; Now indent each line. + (goto-char start) + (while (progn (setq e (marker-position edpos)) + (setq r (- e (point))) + (> r 0)) + (setq e (point)) + (message "%d" r) + (cond + ((looking-at myre) + (goto-char (match-end 1)) + (if (eq (char-after) ?=) + (indent-to (1+ ind)) ; line up the = of the <= with surrounding = + (indent-to ind) + ) + ) + ((verilog-continued-line-1 start) + (goto-char e) + (indent-line-to ind)) + (t ; Must be comment or white space + (goto-char e) + (verilog-forward-ws&directives) + (forward-line -1)) + ) + (forward-line 1)) + (message "") + )))) + +(defun verilog-just-one-space (myre) + "Remove extra spaces around regular expression MYRE." + (interactive) + (if (and (not(looking-at verilog-complete-reg)) + (looking-at myre)) + (let ((p1 (match-end 1)) + (p2 (match-end 2))) + (progn + (goto-char p2) + (if (looking-at "\\s-") (just-one-space) ) + (goto-char p1) + (forward-char -1) + (if (looking-at "\\s-") (just-one-space)) + ) + )) + (message "")) + +(defun verilog-indent-declaration (baseind) + "Indent current lines as declaration. +Line up the variable names based on previous declaration's indentation. +BASEIND is the base indent to offset everything." + (interactive) + (let ((pos (point-marker)) + (lim (save-excursion + ;; (verilog-re-search-backward verilog-declaration-opener nil 'move) + (verilog-re-search-backward "\\(\\<begin\\>\\)\\|\\(\\<module\\>\\)\\|\\(\\<task\\>\\)" nil 'move) + (point))) + (ind) + (val) + (m1 (make-marker)) + ) + (setq val (+ baseind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (indent-line-to val) + + ;; Use previous declaration (in this module) as template. + (if (or (memq 'all verilog-auto-lineup) + (memq 'declaration verilog-auto-lineup)) + (if (verilog-re-search-backward + (or (and verilog-indent-declaration-macros + verilog-declaration-re-1-macro) + verilog-declaration-re-1-no-macro) lim t) + (progn + (goto-char (match-end 0)) + (skip-chars-forward " \t") + (setq ind (current-column)) + (goto-char pos) + (setq val (+ baseind (eval (cdr (assoc 'declaration verilog-indent-alist))))) + (indent-line-to val) + (if (and verilog-indent-declaration-macros + (looking-at verilog-declaration-re-2-macro)) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[#`]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (just-one-space) + (indent-to ind) + ) + (if (/= (current-column) ind) + (progn + (just-one-space) + (indent-to ind)) + ))) + (if (looking-at verilog-declaration-re-2-no-macro) + (let ((p (match-end 0))) + (set-marker m1 p) + (if (verilog-re-search-forward "[[`#]" p 'move) + (progn + (forward-char -1) + (just-one-space) + (goto-char (marker-position m1)) + (just-one-space) + (indent-to ind)) + (if (/= (current-column) ind) + (progn + (just-one-space) + (indent-to ind)) + ))) + ))) + ) + ) + (goto-char pos) + ) + ) + +(defun verilog-get-lineup-indent (b edpos) + "Return the indent level that will line up several lines within the region. +Region is defined by B and EDPOS." + (save-excursion + (let ((ind 0) e) + (goto-char b) + ;; Get rightmost position + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (if (verilog-re-search-forward + (or (and verilog-indent-declaration-macros + verilog-declaration-re-1-macro) + verilog-declaration-re-1-no-macro) e 'move) + (progn + (goto-char (match-end 0)) + (verilog-backward-syntactic-ws) + (if (> (current-column) ind) + (setq ind (current-column))) + (goto-char (match-end 0))))) + (if (> ind 0) + (1+ ind) + ;; No lineup-string found + (goto-char b) + (end-of-line) + (skip-chars-backward " \t") + (1+ (current-column)))))) + +(defun verilog-get-lineup-indent-2 (myre b edpos) + "Return the indent level that will line up several lines within the region." + (save-excursion + (let ((ind 0) e) + (goto-char b) + ;; Get rightmost position + (while (progn (setq e (marker-position edpos)) + (< (point) e)) + (if (verilog-re-search-forward myre e 'move) + (progn + (goto-char (match-end 0)) + (verilog-backward-syntactic-ws) + (if (> (current-column) ind) + (setq ind (current-column))) + (goto-char (match-end 0))))) + (if (> ind 0) + (1+ ind) + ;; No lineup-string found + (goto-char b) + (end-of-line) + (skip-chars-backward " \t") + (1+ (current-column)))))) + +(defun verilog-comment-depth (type val) + "A useful mode debugging aide. TYPE and VAL are comments for insertion." + (save-excursion + (let + ((b (prog2 + (beginning-of-line) + (point-marker) + (end-of-line))) + (e (point-marker))) + (if (re-search-backward " /\\* \[#-\]# \[a-zA-Z\]+ \[0-9\]+ ## \\*/" b t) + (progn + (replace-match " /* -# ## */") + (end-of-line)) + (progn + (end-of-line) + (insert " /* ## ## */")))) + (backward-char 6) + (insert + (format "%s %d" type val)))) + +;; +;; +;; Completion +;; +(defvar verilog-str nil) +(defvar verilog-all nil) +(defvar verilog-pred nil) +(defvar verilog-buffer-to-use nil) +(defvar verilog-flag nil) +(defvar verilog-toggle-completions nil + "*True means \\<verilog-mode-map>\\[verilog-complete-word] should try all possible completions one by one. +Repeated use of \\[verilog-complete-word] will show you all of them. +Normally, when there is more than one possible completion, +it displays a list of all possible completions.") + + +(defvar verilog-type-keywords + '( + "and" "buf" "bufif0" "bufif1" "cmos" "defparam" "inout" "input" + "integer" "localparam" "logic" "mailbox" "nand" "nmos" "nor" "not" "notif0" + "notif1" "or" "output" "parameter" "pmos" "pull0" "pull1" "pullup" + "rcmos" "real" "realtime" "reg" "rnmos" "rpmos" "rtran" "rtranif0" + "rtranif1" "semaphore" "time" "tran" "tranif0" "tranif1" "tri" "tri0" "tri1" + "triand" "trior" "trireg" "wand" "wire" "wor" "xnor" "xor" + ) + "*Keywords for types used when completing a word in a declaration or parmlist. +\(eg. integer, real, reg...)") + +(defvar verilog-cpp-keywords + '("module" "macromodule" "primitive" "timescale" "define" "ifdef" "ifndef" "else" + "endif") + "*Keywords to complete when at first word of a line in declarative scope. +\(eg. initial, always, begin, assign.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-defun-keywords + (append + '( + "always" "always_comb" "always_ff" "always_latch" "assign" + "begin" "end" "generate" "endgenerate" "module" "endmodule" + "specify" "endspecify" "function" "endfunction" "initial" "final" + "task" "endtask" "primitive" "endprimitive" + ) + verilog-type-keywords) + "*Keywords to complete when at first word of a line in declarative scope. +\(eg. initial, always, begin, assign.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-block-keywords + '( + "begin" "break" "case" "continue" "else" "end" "endfunction" + "endgenerate" "endinterface" "endpackage" "endspecify" "endtask" + "for" "fork" "if" "join" "join_any" "join_none" "repeat" "return" + "while") + "*Keywords to complete when at first word of a line in behavioral scope. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-tf-keywords + '("begin" "break" "fork" "join" "join_any" "join_none" "case" "end" "endtask" "endfunction" "if" "else" "for" "while" "repeat") + "*Keywords to complete when at first word of a line in a task or function. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-case-keywords + '("begin" "fork" "join" "join_any" "join_none" "case" "end" "endcase" "if" "else" "for" "repeat") + "*Keywords to complete when at first word of a line in case scope. +\(eg. begin, if, then, else, for, fork.) +The procedures and variables defined within the Verilog program +will be completed runtime and should not be added to this list.") + +(defvar verilog-separator-keywords + '("else" "then" "begin") + "*Keywords to complete when NOT standing at the first word of a statement. +\(eg. else, then.) +Variables and function names defined within the +Verilog program are completed runtime and should not be added to this list.") + +(defun verilog-string-diff (str1 str2) + "Return index of first letter where STR1 and STR2 differs." + (catch 'done + (let ((diff 0)) + (while t + (if (or (> (1+ diff) (length str1)) + (> (1+ diff) (length str2))) + (throw 'done diff)) + (or (equal (aref str1 diff) (aref str2 diff)) + (throw 'done diff)) + (setq diff (1+ diff)))))) + +;; Calculate all possible completions for functions if argument is `function', +;; completions for procedures if argument is `procedure' or both functions and +;; procedures otherwise. + +(defun verilog-func-completion (type) + "Build regular expression for module/task/function names. +TYPE is 'module, 'tf for task or function, or t if unknown." + (if (string= verilog-str "") + (setq verilog-str "[a-zA-Z_]")) + (let ((verilog-str (concat (cond + ((eq type 'module) "\\<\\(module\\)\\s +") + ((eq type 'tf) "\\<\\(task\\|function\\)\\s +") + (t "\\<\\(task\\|function\\|module\\)\\s +")) + "\\<\\(" verilog-str "[a-zA-Z0-9_.]*\\)\\>")) + match) + + (if (not (looking-at verilog-defun-re)) + (verilog-re-search-backward verilog-defun-re nil t)) + (forward-char 1) + + ;; Search through all reachable functions + (goto-char (point-min)) + (while (verilog-re-search-forward verilog-str (point-max) t) + (progn (setq match (buffer-substring (match-beginning 2) + (match-end 2))) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + (if (match-beginning 0) + (goto-char (match-beginning 0))))) + +(defun verilog-get-completion-decl (end) + "Macro for searching through current declaration (var, type or const) +for matches of `str' and adding the occurrence tp `all' through point END." + (let ((re (or (and verilog-indent-declaration-macros + verilog-declaration-re-2-macro) + verilog-declaration-re-2-no-macro)) + decl-end match) + ;; Traverse lines + (while (and (< (point) end) + (verilog-re-search-forward re end t)) + ;; Traverse current line + (setq decl-end (save-excursion (verilog-declaration-end))) + (while (and (verilog-re-search-forward verilog-symbol-re decl-end t) + (not (match-end 1))) + (setq match (buffer-substring (match-beginning 0) (match-end 0))) + (if (string-match (concat "\\<" verilog-str) match) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + (forward-line 1) + ) + ) + verilog-all + ) + +(defun verilog-type-completion () + "Calculate all possible completions for types." + (let ((start (point)) + goon) + ;; Search for all reachable type declarations + (while (or (verilog-beg-of-defun) + (setq goon (not goon))) + (save-excursion + (if (and (< start (prog1 (save-excursion (verilog-end-of-defun) + (point)) + (forward-char 1))) + (verilog-re-search-forward + "\\<type\\>\\|\\<\\(begin\\|function\\|procedure\\)\\>" + start t) + (not (match-end 1))) + ;; Check current type declaration + (verilog-get-completion-decl start)))))) + +(defun verilog-var-completion () + "Calculate all possible completions for variables (or constants)." + (let ((start (point))) + ;; Search for all reachable var declarations + (verilog-beg-of-defun) + (save-excursion + ;; Check var declarations + (verilog-get-completion-decl start)))) + +(defun verilog-keyword-completion (keyword-list) + "Give list of all possible completions of keywords in KEYWORD-LIST." + (mapcar '(lambda (s) + (if (string-match (concat "\\<" verilog-str) s) + (if (or (null verilog-pred) + (funcall verilog-pred s)) + (setq verilog-all (cons s verilog-all))))) + keyword-list)) + + +(defun verilog-completion (verilog-str verilog-pred verilog-flag) + "Function passed to `completing-read', `try-completion' or `all-completions'. +Called to get completion on VERILOG-STR. If VERILOG-PRED is non-nil, it +must be a function to be called for every match to check if this should +really be a match. If VERILOG-FLAG is t, the function returns a list of all +possible completions. If VERILOG-FLAG is nil it returns a string, the +longest possible completion, or t if STR is an exact match. If VERILOG-FLAG +is 'lambda, the function returns t if STR is an exact match, nil +otherwise." + (save-excursion + (let ((verilog-all nil)) + ;; Set buffer to use for searching labels. This should be set + ;; within functions which use verilog-completions + (set-buffer verilog-buffer-to-use) + + ;; Determine what should be completed + (let ((state (car (verilog-calculate-indent)))) + (cond ((eq state 'defun) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'module) + (verilog-keyword-completion verilog-defun-keywords)) + + ((eq state 'behavioral) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'module) + (verilog-keyword-completion verilog-defun-keywords)) + + ((eq state 'block) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-block-keywords)) + + ((eq state 'case) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-case-keywords)) + + ((eq state 'tf) + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'tf) + (verilog-keyword-completion verilog-tf-keywords)) + + ((eq state 'cpp) + (save-excursion (verilog-var-completion)) + (verilog-keyword-completion verilog-cpp-keywords)) + + ((eq state 'cparenexp) + (save-excursion (verilog-var-completion))) + + (t;--Anywhere else + (save-excursion (verilog-var-completion)) + (verilog-func-completion 'both) + (verilog-keyword-completion verilog-separator-keywords)))) + + ;; Now we have built a list of all matches. Give response to caller + (verilog-completion-response)))) + +(defun verilog-completion-response () + (cond ((or (equal verilog-flag 'lambda) (null verilog-flag)) + ;; This was not called by all-completions + (if (null verilog-all) + ;; Return nil if there was no matching label + nil + ;; Get longest string common in the labels + (let* ((elm (cdr verilog-all)) + (match (car verilog-all)) + (min (length match)) + tmp) + (if (string= match verilog-str) + ;; Return t if first match was an exact match + (setq match t) + (while (not (null elm)) + ;; Find longest common string + (if (< (setq tmp (verilog-string-diff match (car elm))) min) + (progn + (setq min tmp) + (setq match (substring match 0 min)))) + ;; Terminate with match=t if this is an exact match + (if (string= (car elm) verilog-str) + (progn + (setq match t) + (setq elm nil)) + (setq elm (cdr elm))))) + ;; If this is a test just for exact match, return nil ot t + (if (and (equal verilog-flag 'lambda) (not (equal match 't))) + nil + match)))) + ;; If flag is t, this was called by all-completions. Return + ;; list of all possible completions + (verilog-flag + verilog-all))) + +(defvar verilog-last-word-numb 0) +(defvar verilog-last-word-shown nil) +(defvar verilog-last-completions nil) + +(defun verilog-complete-word () + "Complete word at current point. +\(See also `verilog-toggle-completions', `verilog-type-keywords', +and `verilog-separator-keywords'.)" + (interactive) + (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) + (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) + (verilog-str (buffer-substring b e)) + ;; The following variable is used in verilog-completion + (verilog-buffer-to-use (current-buffer)) + (allcomp (if (and verilog-toggle-completions + (string= verilog-last-word-shown verilog-str)) + verilog-last-completions + (all-completions verilog-str 'verilog-completion))) + (match (if verilog-toggle-completions + "" (try-completion + verilog-str (mapcar '(lambda (elm) + (cons elm 0)) allcomp))))) + ;; Delete old string + (delete-region b e) + + ;; Toggle-completions inserts whole labels + (if verilog-toggle-completions + (progn + ;; Update entry number in list + (setq verilog-last-completions allcomp + verilog-last-word-numb + (if (>= verilog-last-word-numb (1- (length allcomp))) + 0 + (1+ verilog-last-word-numb))) + (setq verilog-last-word-shown (elt allcomp verilog-last-word-numb)) + ;; Display next match or same string if no match was found + (if (not (null allcomp)) + (insert "" verilog-last-word-shown) + (insert "" verilog-str) + (message "(No match)"))) + ;; The other form of completion does not necessarily do that. + + ;; Insert match if found, or the original string if no match + (if (or (null match) (equal match 't)) + (progn (insert "" verilog-str) + (message "(No match)")) + (insert "" match)) + ;; Give message about current status of completion + (cond ((equal match 't) + (if (not (null (cdr allcomp))) + (message "(Complete but not unique)") + (message "(Sole completion)"))) + ;; Display buffer if the current completion didn't help + ;; on completing the label. + ((and (not (null (cdr allcomp))) (= (length verilog-str) + (length match))) + (with-output-to-temp-buffer "*Completions*" + (display-completion-list allcomp)) + ;; Wait for a key press. Then delete *Completion* window + (momentary-string-display "" (point)) + (delete-window (get-buffer-window (get-buffer "*Completions*"))) + ))))) + +(defun verilog-show-completions () + "Show all possible completions at current point." + (interactive) + (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point))) + (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point))) + (verilog-str (buffer-substring b e)) + ;; The following variable is used in verilog-completion + (verilog-buffer-to-use (current-buffer)) + (allcomp (if (and verilog-toggle-completions + (string= verilog-last-word-shown verilog-str)) + verilog-last-completions + (all-completions verilog-str 'verilog-completion)))) + ;; Show possible completions in a temporary buffer. + (with-output-to-temp-buffer "*Completions*" + (display-completion-list allcomp)) + ;; Wait for a key press. Then delete *Completion* window + (momentary-string-display "" (point)) + (delete-window (get-buffer-window (get-buffer "*Completions*"))))) + + +(defun verilog-get-default-symbol () + "Return symbol around current point as a string." + (save-excursion + (buffer-substring (progn + (skip-chars-backward " \t") + (skip-chars-backward "a-zA-Z0-9_") + (point)) + (progn + (skip-chars-forward "a-zA-Z0-9_") + (point))))) + +(defun verilog-build-defun-re (str &optional arg) + "Return function/task/module starting with STR as regular expression. +With optional second ARG non-nil, STR is the complete name of the instruction." + (if arg + (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "\\)\\>") + (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "[a-zA-Z0-9_]*\\)\\>"))) + +(defun verilog-comp-defun (verilog-str verilog-pred verilog-flag) + "Function passed to `completing-read', `try-completion' or `all-completions'. +Returns a completion on any function name based on VERILOG-STR prefix. If +VERILOG-PRED is non-nil, it must be a function to be called for every match +to check if this should really be a match. If VERILOG-FLAG is t, the +function returns a list of all possible completions. If it is nil it +returns a string, the longest possible completion, or t if VERILOG-STR is +an exact match. If VERILOG-FLAG is 'lambda, the function returns t if +VERILOG-STR is an exact match, nil otherwise." + (save-excursion + (let ((verilog-all nil) + match) + + ;; Set buffer to use for searching labels. This should be set + ;; within functions which use verilog-completions + (set-buffer verilog-buffer-to-use) + + (let ((verilog-str verilog-str)) + ;; Build regular expression for functions + (if (string= verilog-str "") + (setq verilog-str (verilog-build-defun-re "[a-zA-Z_]")) + (setq verilog-str (verilog-build-defun-re verilog-str))) + (goto-char (point-min)) + + ;; Build a list of all possible completions + (while (verilog-re-search-forward verilog-str nil t) + (setq match (buffer-substring (match-beginning 2) (match-end 2))) + (if (or (null verilog-pred) + (funcall verilog-pred match)) + (setq verilog-all (cons match verilog-all))))) + + ;; Now we have built a list of all matches. Give response to caller + (verilog-completion-response)))) + +(defun verilog-goto-defun () + "Move to specified Verilog module/task/function. +The default is a name found in the buffer around point. +If search fails, other files are checked based on +`verilog-library-flags'." + (interactive) + (let* ((default (verilog-get-default-symbol)) + ;; The following variable is used in verilog-comp-function + (verilog-buffer-to-use (current-buffer)) + (label (if (not (string= default "")) + ;; Do completion with default + (completing-read (concat "Label: (default " default ") ") + 'verilog-comp-defun nil nil "") + ;; There is no default value. Complete without it + (completing-read "Label: " + 'verilog-comp-defun nil nil ""))) + pt) + ;; If there was no response on prompt, use default value + (if (string= label "") + (setq label default)) + ;; Goto right place in buffer if label is not an empty string + (or (string= label "") + (progn + (save-excursion + (goto-char (point-min)) + (setq pt (re-search-forward (verilog-build-defun-re label t) nil t))) + (when pt + (goto-char pt) + (beginning-of-line)) + pt) + (verilog-goto-defun-file label) + ))) + +;; Eliminate compile warning +(eval-when-compile + (if (not (boundp 'occur-pos-list)) + (defvar occur-pos-list nil "Backward compatibility occur positions."))) + +(defun verilog-showscopes () + "List all scopes in this module." + (interactive) + (let ((buffer (current-buffer)) + (linenum 1) + (nlines 0) + (first 1) + (prevpos (point-min)) + (final-context-start (make-marker)) + (regexp "\\(module\\s-+\\w+\\s-*(\\)\\|\\(\\w+\\s-+\\w+\\s-*(\\)") + ) + (with-output-to-temp-buffer "*Occur*" + (save-excursion + (message (format "Searching for %s ..." regexp)) + ;; Find next match, but give up if prev match was at end of buffer. + (while (and (not (= prevpos (point-max))) + (verilog-re-search-forward regexp nil t)) + (goto-char (match-beginning 0)) + (beginning-of-line) + (save-match-data + (setq linenum (+ linenum (count-lines prevpos (point))))) + (setq prevpos (point)) + (goto-char (match-end 0)) + (let* ((start (save-excursion + (goto-char (match-beginning 0)) + (forward-line (if (< nlines 0) nlines (- nlines))) + (point))) + (end (save-excursion + (goto-char (match-end 0)) + (if (> nlines 0) + (forward-line (1+ nlines)) + (forward-line 1)) + (point))) + (tag (format "%3d" linenum)) + (empty (make-string (length tag) ?\ )) + tem) + (save-excursion + (setq tem (make-marker)) + (set-marker tem (point)) + (set-buffer standard-output) + (setq occur-pos-list (cons tem occur-pos-list)) + (or first (zerop nlines) + (insert "--------\n")) + (setq first nil) + (insert-buffer-substring buffer start end) + (backward-char (- end start)) + (setq tem (if (< nlines 0) (- nlines) nlines)) + (while (> tem 0) + (insert empty ?:) + (forward-line 1) + (setq tem (1- tem))) + (let ((this-linenum linenum)) + (set-marker final-context-start + (+ (point) (- (match-end 0) (match-beginning 0)))) + (while (< (point) final-context-start) + (if (null tag) + (setq tag (format "%3d" this-linenum))) + (insert tag ?:))))))) + (set-buffer-modified-p nil)))) + + +;; Highlight helper functions +(defconst verilog-directive-regexp "\\(translate\\|coverage\\|lint\\)_") +(defun verilog-within-translate-off () + "Return point if within translate-off region, else nil." + (and (save-excursion + (re-search-backward + (concat "//\\s-*.*\\s-*" verilog-directive-regexp "\\(on\\|off\\)\\>") + nil t)) + (equal "off" (match-string 2)) + (point))) + +(defun verilog-start-translate-off (limit) + "Return point before translate-off directive if before LIMIT, else nil." + (when (re-search-forward + (concat "//\\s-*.*\\s-*" verilog-directive-regexp "off\\>") + limit t) + (match-beginning 0))) + +(defun verilog-back-to-start-translate-off (limit) + "Return point before translate-off directive if before LIMIT, else nil." + (when (re-search-backward + (concat "//\\s-*.*\\s-*" verilog-directive-regexp "off\\>") + limit t) + (match-beginning 0))) + +(defun verilog-end-translate-off (limit) + "Return point after translate-on directive if before LIMIT, else nil." + + (re-search-forward (concat + "//\\s-*.*\\s-*" verilog-directive-regexp "on\\>") limit t)) + +(defun verilog-match-translate-off (limit) + "Match a translate-off block, setting `match-data' and returning t, else nil. +Bound search by LIMIT." + (when (< (point) limit) + (let ((start (or (verilog-within-translate-off) + (verilog-start-translate-off limit))) + (case-fold-search t)) + (when start + (let ((end (or (verilog-end-translate-off limit) limit))) + (set-match-data (list start end)) + (goto-char end)))))) + +(defun verilog-font-lock-match-item (limit) + "Match, and move over, any declaration item after point. +Bound search by LIMIT. Adapted from +`font-lock-match-c-style-declaration-item-and-skip-to-next'." + (condition-case nil + (save-restriction + (narrow-to-region (point-min) limit) + ;; match item + (when (looking-at "\\s-*\\([a-zA-Z]\\w*\\)") + (save-match-data + (goto-char (match-end 1)) + ;; move to next item + (if (looking-at "\\(\\s-*,\\)") + (goto-char (match-end 1)) + (end-of-line) t)))) + (error nil))) + + +;; Added by Subbu Meiyappan for Header + +(defun verilog-header () + "Insert a standard Verilog file header." + (interactive) + (let ((start (point))) + (insert "\ +//----------------------------------------------------------------------------- +// Title : <title> +// Project : <project> +//----------------------------------------------------------------------------- +// File : <filename> +// Author : <author> +// Created : <credate> +// Last modified : <moddate> +//----------------------------------------------------------------------------- +// Description : +// <description> +//----------------------------------------------------------------------------- +// Copyright (c) <copydate> by <company> This model is the confidential and +// proprietary property of <company> and the possession or use of this +// file requires a written license from <company>. +//------------------------------------------------------------------------------ +// Modification history : +// <modhist> +//----------------------------------------------------------------------------- + +") + (goto-char start) + (search-forward "<filename>") + (replace-match (buffer-name) t t) + (search-forward "<author>") (replace-match "" t t) + (insert (user-full-name)) + (insert " <" (user-login-name) "@" (system-name) ">") + (search-forward "<credate>") (replace-match "" t t) + (insert-date) + (search-forward "<moddate>") (replace-match "" t t) + (insert-date) + (search-forward "<copydate>") (replace-match "" t t) + (insert-year) + (search-forward "<modhist>") (replace-match "" t t) + (insert-date) + (insert " : created") + (goto-char start) + (let (string) + (setq string (read-string "title: ")) + (search-forward "<title>") + (replace-match string t t) + (setq string (read-string "project: " verilog-project)) + (make-variable-buffer-local 'verilog-project) + (setq verilog-project string) + (search-forward "<project>") + (replace-match string t t) + (setq string (read-string "Company: " verilog-company)) + (make-variable-buffer-local 'verilog-company) + (setq verilog-company string) + (search-forward "<company>") + (replace-match string t t) + (search-forward "<company>") + (replace-match string t t) + (search-forward "<company>") + (replace-match string t t) + (search-backward "<description>") + (replace-match "" t t) + ))) + +;; verilog-header Uses the insert-date function + +(defun insert-date () + "Insert date from the system." + (interactive) + (let ((timpos)) + (setq timpos (point)) + (if verilog-date-scientific-format + (shell-command "date \"+@%Y/%m/%d\"" t) + (shell-command "date \"+@%d.%m.%Y\"" t)) + (search-forward "@") + (delete-region timpos (point)) + (end-of-line)) + (delete-char 1)) + +(defun insert-year () + "Insert year from the system." + (interactive) + (let ((timpos)) + (setq timpos (point)) + (shell-command "date \"+@%Y\"" t) + (search-forward "@") + (delete-region timpos (point)) + (end-of-line)) + (delete-char 1)) + + +;; +;; Signal list parsing +;; + +;; Elements of a signal list +(defsubst verilog-sig-name (sig) + (car sig)) +(defsubst verilog-sig-bits (sig) + (nth 1 sig)) +(defsubst verilog-sig-comment (sig) + (nth 2 sig)) +(defsubst verilog-sig-memory (sig) + (nth 3 sig)) +(defsubst verilog-sig-enum (sig) + (nth 4 sig)) +(defsubst verilog-sig-signed (sig) + (nth 5 sig)) +(defsubst verilog-sig-type (sig) + (nth 6 sig)) +(defsubst verilog-sig-multidim (sig) + (nth 7 sig)) +(defsubst verilog-sig-multidim-string (sig) + (if (verilog-sig-multidim sig) + (let ((str "") (args (verilog-sig-multidim sig))) + (while args + (setq str (concat str (car args))) + (setq args (cdr args))) + str))) +(defsubst verilog-sig-width (sig) + (verilog-make-width-expression (verilog-sig-bits sig))) + +(defsubst verilog-alw-get-inputs (sigs) + (nth 2 sigs)) +(defsubst verilog-alw-get-outputs (sigs) + (nth 0 sigs)) +(defsubst verilog-alw-get-uses-delayed (sigs) + (nth 3 sigs)) + +(defun verilog-signals-not-in (in-list not-list) + "Return list of signals in IN-LIST that aren't also in NOT-LIST, +and also remove any duplicates in IN-LIST. +Signals must be in standard (base vector) form." + (let (out-list) + (while in-list + (if (not (or (assoc (car (car in-list)) not-list) + (assoc (car (car in-list)) out-list))) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list))) +;;(verilog-signals-not-in '(("A" "") ("B" "") ("DEL" "[2:3]")) '(("DEL" "") ("EXT" ""))) + +(defun verilog-signals-in (in-list other-list) + "Return list of signals in IN-LIST that are also in OTHER-LIST. +Signals must be in standard (base vector) form." + (let (out-list) + (while in-list + (if (assoc (car (car in-list)) other-list) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list))) +;;(verilog-signals-in '(("A" "") ("B" "") ("DEL" "[2:3]")) '(("DEL" "") ("EXT" ""))) + +(defun verilog-signals-memory (in-list) + "Return list of signals in IN-LIST that are memoried (multidimensional)." + (let (out-list) + (while in-list + (if (nth 3 (car in-list)) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + out-list)) +;;(verilog-signals-memory '(("A" nil nil "[3:0]")) '(("B" nil nil nil))) + +(defun verilog-signals-sort-compare (a b) + "Compare signal A and B for sorting." + (string< (car a) (car b))) + +(defun verilog-signals-not-params (in-list) + "Return list of signals in IN-LIST that aren't parameters or numeric constants." + (let (out-list) + (while in-list + (unless (boundp (intern (concat "vh-" (car (car in-list))))) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list))) + +(defun verilog-signals-combine-bus (in-list) + "Return a list of signals in IN-LIST, with busses combined. +Duplicate signals are also removed. For example A[2] and A[1] become A[2:1]." + (let (combo buswarn + out-list + sig highbit lowbit ; Temp information about current signal + sv-name sv-highbit sv-lowbit ; Details about signal we are forming + sv-comment sv-memory sv-enum sv-signed sv-type sv-multidim sv-busstring + bus) + ;; Shove signals so duplicated signals will be adjacent + (setq in-list (sort in-list `verilog-signals-sort-compare)) + (while in-list + (setq sig (car in-list)) + ;; No current signal; form from existing details + (unless sv-name + (setq sv-name (verilog-sig-name sig) + sv-highbit nil + sv-busstring nil + sv-comment (verilog-sig-comment sig) + sv-memory (verilog-sig-memory sig) + sv-enum (verilog-sig-enum sig) + sv-signed (verilog-sig-signed sig) + sv-type (verilog-sig-type sig) + sv-multidim (verilog-sig-multidim sig) + combo "" + buswarn "" + )) + ;; Extract bus details + (setq bus (verilog-sig-bits sig)) + (cond ((and bus + (or (and (string-match "\\[\\([0-9]+\\):\\([0-9]+\\)\\]" bus) + (setq highbit (string-to-int (match-string 1 bus)) + lowbit (string-to-int (match-string 2 bus)))) + (and (string-match "\\[\\([0-9]+\\)\\]" bus) + (setq highbit (string-to-int (match-string 1 bus)) + lowbit highbit)))) + ;; Combine bits in bus + (if sv-highbit + (setq sv-highbit (max highbit sv-highbit) + sv-lowbit (min lowbit sv-lowbit)) + (setq sv-highbit highbit + sv-lowbit lowbit))) + (bus + ;; String, probably something like `preproc:0 + (setq sv-busstring bus))) + ;; Peek ahead to next signal + (setq in-list (cdr in-list)) + (setq sig (car in-list)) + (cond ((and sig (equal sv-name (verilog-sig-name sig))) + ;; Combine with this signal + (when (and sv-busstring (not (equal sv-busstring (verilog-sig-bits sig)))) + (when nil ;; Debugging + (message (concat "Warning, can't merge into single bus " + sv-name bus + ", the AUTOs may be wrong"))) + (setq buswarn ", Couldn't Merge")) + (if (verilog-sig-comment sig) (setq combo ", ...")) + (setq sv-memory (or sv-memory (verilog-sig-memory sig)) + sv-enum (or sv-enum (verilog-sig-enum sig)) + sv-signed (or sv-signed (verilog-sig-signed sig)) + sv-type (or sv-type (verilog-sig-type sig)) + sv-multidim (or sv-multidim (verilog-sig-multidim sig)))) + ;; Doesn't match next signal, add to queue, zero in prep for next + ;; Note sig may also be nil for the last signal in the list + (t + (setq out-list + (cons (list sv-name + (or sv-busstring + (if sv-highbit + (concat "[" (int-to-string sv-highbit) ":" (int-to-string sv-lowbit) "]"))) + (concat sv-comment combo buswarn) + sv-memory sv-enum sv-signed sv-type sv-multidim) + out-list) + sv-name nil))) + ) + ;; + out-list)) + +(defun verilog-sig-tieoff (sig &optional no-width) + "Return tieoff expression for given SIGNAL, with appropriate width. +Ignore width if optional NO-WIDTH is set." + (let* ((width (if no-width nil (verilog-sig-width sig)))) + (concat + (if (and verilog-active-low-regexp + (string-match verilog-active-low-regexp (verilog-sig-name sig))) + "~" "") + (cond ((not width) + "0") + ((string-match "^[0-9]+$" width) + (concat width (if (verilog-sig-signed sig) "'sh0" "'h0"))) + (t + (concat "{" width "{1'b0}}")))))) + +;; +;; Port/Wire/Etc Reading +;; + +(defun verilog-read-inst-backward-name () + "Internal. Move point back to beginning of inst-name." + (verilog-backward-open-paren) + (let (done) + (while (not done) + (verilog-re-search-backward-quick "\\()\\|\\b[a-zA-Z0-9`_\$]\\|\\]\\)" nil nil) ; ] isn't word boundary + (cond ((looking-at ")") + (verilog-backward-open-paren)) + (t (setq done t))))) + (while (looking-at "\\]") + (verilog-backward-open-bracket) + (verilog-re-search-backward-quick "\\(\\b[a-zA-Z0-9`_\$]\\|\\]\\)" nil nil)) + (skip-chars-backward "a-zA-Z0-9`_$")) + +(defun verilog-read-inst-module () + "Return module_name when point is inside instantiation." + (save-excursion + (verilog-read-inst-backward-name) + ;; Skip over instantiation name + (verilog-re-search-backward-quick "\\(\\b[a-zA-Z0-9`_\$]\\|)\\)" nil nil) ; ) isn't word boundary + ;; Check for parameterized instantiations + (when (looking-at ")") + (verilog-backward-open-paren) + (verilog-re-search-backward-quick "\\b[a-zA-Z0-9`_\$]" nil nil)) + (skip-chars-backward "a-zA-Z0-9'_$") + (looking-at "[a-zA-Z0-9`_\$]+") + ;; Important: don't use match string, this must work with emacs 19 font-lock on + (buffer-substring-no-properties (match-beginning 0) (match-end 0)))) + +(defun verilog-read-inst-name () + "Return instance_name when point is inside instantiation." + (save-excursion + (verilog-read-inst-backward-name) + (looking-at "[a-zA-Z0-9`_\$]+") + ;; Important: don't use match string, this must work with emacs 19 font-lock on + (buffer-substring-no-properties (match-beginning 0) (match-end 0)))) + +(defun verilog-read-module-name () + "Return module name when after its ( or ;." + (save-excursion + (re-search-backward "[(;]") + (verilog-re-search-backward-quick "\\b[a-zA-Z0-9`_\$]" nil nil) + (skip-chars-backward "a-zA-Z0-9`_$") + (looking-at "[a-zA-Z0-9`_\$]+") + ;; Important: don't use match string, this must work with emacs 19 font-lock on + (buffer-substring-no-properties (match-beginning 0) (match-end 0)))) + +(defun verilog-read-auto-params (num-param &optional max-param) + "Return parameter list inside auto. +Optional NUM-PARAM and MAX-PARAM check for a specific number of parameters." + (let ((olist)) + (save-excursion + ;; /*AUTOPUNT("parameter", "parameter")*/ + (search-backward "(") + (while (looking-at "(?\\s *\"\\([^\"]*\\)\"\\s *,?") + (setq olist (cons (match-string 1) olist)) + (goto-char (match-end 0)))) + (or (eq nil num-param) + (<= num-param (length olist)) + (error "%s: Expected %d parameters" (verilog-point-text) num-param)) + (if (eq max-param nil) (setq max-param num-param)) + (or (eq nil max-param) + (>= max-param (length olist)) + (error "%s: Expected <= %d parameters" (verilog-point-text) max-param)) + (nreverse olist))) + +(defun verilog-read-decls () + "Compute signal declaration information for the current module at point. +Return a array of [outputs inouts inputs wire reg assign const]." + (let ((end-mod-point (or (verilog-get-end-of-defun t) (point-max))) + (functask 0) (paren 0) (sig-paren 0) + sigs-in sigs-out sigs-inout sigs-wire sigs-reg sigs-assign sigs-const sigs-gparam + vec expect-signal keywd newsig rvalue enum io signed typedefed multidim) + (save-excursion + (verilog-beg-of-defun) + (setq sigs-const (verilog-read-auto-constants (point) end-mod-point)) + (while (< (point) end-mod-point) + ;;(if dbg (setq dbg (cons (format "Pt %s Vec %s Kwd'%s'\n" (point) vec keywd) dbg))) + (cond + ((looking-at "//") + (if (looking-at "[^\n]*synopsys\\s +enum\\s +\\([a-zA-Z0-9_]+\\)") + (setq enum (match-string 1))) + (search-forward "\n")) + ((looking-at "/\\*") + (forward-char 2) + (if (looking-at "[^*]*synopsys\\s +enum\\s +\\([a-zA-Z0-9_]+\\)") + (setq enum (match-string 1))) + (or (search-forward "*/") + (error "%s: Unmatched /* */, at char %d" (verilog-point-text) (point)))) + ((looking-at "(\\*") + (forward-char 2) + (or (looking-at "\\s-*)") ; It's a "always @ (*)" + (search-forward "*)") + (error "%s: Unmatched (* *), at char %d" (verilog-point-text) (point)))) + ((eq ?\" (following-char)) + (or (re-search-forward "[^\\]\"" nil t) ;; don't forward-char first, since we look for a non backslash first + (error "%s: Unmatched quotes, at char %d" (verilog-point-text) (point)))) + ((eq ?\; (following-char)) + (setq vec nil io nil expect-signal nil newsig nil paren 0 rvalue nil) + (forward-char 1)) + ((eq ?= (following-char)) + (setq rvalue t newsig nil) + (forward-char 1)) + ((and (or rvalue sig-paren) + (cond ((and (eq ?, (following-char)) + (eq paren sig-paren)) + (setq rvalue nil) + (forward-char 1) + t) + ;; ,'s can occur inside {} & funcs + ((looking-at "[{(]") + (setq paren (1+ paren)) + (forward-char 1) + t) + ((looking-at "[})]") + (setq paren (1- paren)) + (forward-char 1) + (when (< paren sig-paren) + (setq expect-signal nil)) ; ) that ends variables inside v2k arg list + t) + ))) + ((looking-at "\\s-*\\(\\[[^]]+\\]\\)") + (goto-char (match-end 0)) + (cond (newsig ; Memory, not just width. Patch last signal added's memory (nth 3) + (setcar (cdr (cdr (cdr newsig))) (match-string 1))) + (vec ;; Multidimensional + (setq multidim (cons vec multidim)) + (setq vec (verilog-string-replace-matches + "\\s-+" "" nil nil (match-string 1)))) + (t ;; Bit width + (setq vec (verilog-string-replace-matches + "\\s-+" "" nil nil (match-string 1)))))) + ;; Normal or escaped identifier -- note we remember the \ if escaped + ((looking-at "\\s-*\\([a-zA-Z0-9`_$]+\\|\\\\[^ \t\n\f]+\\)") + (goto-char (match-end 0)) + (setq keywd (match-string 1)) + (when (string-match "^\\\\" keywd) + (setq keywd (concat keywd " "))) ;; Escaped ID needs space at end + (cond ((equal keywd "input") + (setq vec nil enum nil rvalue nil newsig nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-in io t)) + ((equal keywd "output") + (setq vec nil enum nil rvalue nil newsig nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-out io t)) + ((equal keywd "inout") + (setq vec nil enum nil rvalue nil newsig nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-inout io t)) + ((or (equal keywd "wire") + (equal keywd "tri") + (equal keywd "tri0") + (equal keywd "tri1")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-wire))) + ((or (equal keywd "reg") + (equal keywd "trireg")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-reg))) + ((equal keywd "assign") + (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-assign)) + ((or (equal keywd "supply0") + (equal keywd "supply1") + (equal keywd "supply") + (equal keywd "localparam")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-const))) + ((or (equal keywd "parameter")) + (unless io (setq vec nil enum nil rvalue nil signed nil typedefed nil multidim nil sig-paren paren + expect-signal 'sigs-gparam))) + ((equal keywd "signed") + (setq signed "signed")) + ((or (equal keywd "function") + (equal keywd "task")) + (setq functask (1+ functask))) + ((or (equal keywd "endfunction") + (equal keywd "endtask")) + (setq functask (1- functask))) + ((or (equal keywd "`ifdef") + (equal keywd "`ifndef")) + (setq rvalue t)) + ((verilog-typedef-name-p keywd) + (setq typedefed keywd)) + ((and expect-signal + (eq functask 0) + (not rvalue) + (eq paren sig-paren) + (not (member keywd verilog-keywords))) + ;; Add new signal to expect-signal's variable + (setq newsig (list keywd vec nil nil enum signed typedefed multidim)) + (set expect-signal (cons newsig + (symbol-value expect-signal)))))) + (t + (forward-char 1))) + (skip-syntax-forward " ")) + ;; Return arguments + (vector (nreverse sigs-out) + (nreverse sigs-inout) + (nreverse sigs-in) + (nreverse sigs-wire) + (nreverse sigs-reg) + (nreverse sigs-assign) + (nreverse sigs-const) + (nreverse sigs-gparam) + )))) + +(defvar sigs-in nil) ; Prevent compile warning +(defvar sigs-inout nil) ; Prevent compile warning +(defvar sigs-out nil) ; Prevent compile warning + +(defun verilog-read-sub-decls-sig (submodi comment port sig vec multidim) + "For verilog-read-sub-decls-line, add a signal." + (let (portdata) + (when sig + (setq port (verilog-symbol-detick-denumber port)) + (setq sig (verilog-symbol-detick-denumber sig)) + (if sig (setq sig (verilog-string-replace-matches "^[---+~!|&]+" "" nil nil sig))) + (if vec (setq vec (verilog-symbol-detick-denumber vec))) + (if multidim (setq multidim (mapcar `verilog-symbol-detick-denumber multidim))) + (unless (or (not sig) + (equal sig "")) ;; Ignore .foo(1'b1) assignments + (cond ((setq portdata (assoc port (verilog-modi-get-inouts submodi))) + (setq sigs-inout (cons (list sig vec (concat "To/From " comment) nil nil + (verilog-sig-signed portdata) + (verilog-sig-type portdata) + multidim) + sigs-inout))) + ((setq portdata (assoc port (verilog-modi-get-outputs submodi))) + (setq sigs-out (cons (list sig vec (concat "From " comment) nil nil + (verilog-sig-signed portdata) + (verilog-sig-type portdata) + multidim) + sigs-out))) + ((setq portdata (assoc port (verilog-modi-get-inputs submodi))) + (setq sigs-in (cons (list sig vec (concat "To " comment) nil nil + (verilog-sig-signed portdata) + (verilog-sig-type portdata) + multidim) + sigs-in))) + ;; (t -- warning pin isn't defined.) ; Leave for lint tool + ))))) + +(defun verilog-read-sub-decls-line (submodi comment) + "For read-sub-decls, read lines of port defs until none match anymore. +Return the list of signals found, using submodi to look up each port." + (let (done port sig vec multidim) + (save-excursion + (forward-line 1) + (while (not done) + ;; Get port name + (cond ((looking-at "\\s-*\\.\\s-*\\([a-zA-Z0-9`_$]*\\)\\s-*(\\s-*") + (setq port (match-string 1)) + (goto-char (match-end 0))) + ((looking-at "\\s-*\\.\\s-*\\(\\\\[^ \t\n\f]*\\)\\s-*(\\s-*") + (setq port (concat (match-string 1) " ")) ;; escaped id's need trailing space + (goto-char (match-end 0))) + ((looking-at "\\s-*\\.[^(]*(") + (setq port nil) ;; skip this line + (goto-char (match-end 0))) + (t + (setq port nil done t))) ;; Unknown, ignore rest of line + ;; Get signal name + (when port + (setq multidim nil) + (cond ((looking-at "\\(\\\\[^ \t\n\f]*\\)\\s-*)") + (setq sig (concat (match-string 1) " ") ;; escaped id's need trailing space + vec nil)) + ; We intentionally ignore (non-escaped) signals with .s in them + ; this prevents AUTOWIRE etc from noticing hierarchical sigs. + ((looking-at "\\([^[({).]*\\)\\s-*)") + (setq sig (verilog-string-remove-spaces (match-string 1)) + vec nil)) + ((looking-at "\\([^[({).]*\\)\\s-*\\(\\[[^]]+\\]\\)\\s-*)") + (setq sig (verilog-string-remove-spaces (match-string 1)) + vec (match-string 2))) + ((looking-at "\\([^[({).]*\\)\\s-*/\\*\\(\\[[^*]+\\]\\)\\*/\\s-*)") + (setq sig (verilog-string-remove-spaces (match-string 1)) + vec nil) + (let ((parse (match-string 2))) + (while (string-match "^\\(\\[[^]]+\\]\\)\\(.*\\)$" parse) + (when vec (setq multidim (cons vec multidim))) + (setq vec (match-string 1 parse)) + (setq parse (match-string 2 parse))))) + ((looking-at "{\\(.*\\)}.*\\s-*)") + (let ((mlst (split-string (match-string 1) ",")) + mstr) + (while (setq mstr (pop mlst)) + ;;(unless noninteractive (message "sig: %s " mstr)) + (cond + ((string-match "\\(['`a-zA-Z0-9_$]+\\)\\s-*$" mstr) + (setq sig (verilog-string-remove-spaces (match-string 1 mstr)) + vec nil) + ;;(unless noninteractive (message "concat sig1: %s %s" mstr (match-string 1 mstr))) + ) + ((string-match "\\([^[({).]+\\)\\s-*\\(\\[[^]]+\\]\\)\\s-*" mstr) + (setq sig (verilog-string-remove-spaces (match-string 1 mstr)) + vec (match-string 2 mstr)) + ;;(unless noninteractive (message "concat sig2: '%s' '%s' '%s'" mstr (match-string 1 mstr) (match-string 2 mstr))) + ) + (t + (setq sig nil))) + ;; Process signals + (verilog-read-sub-decls-sig submodi comment port sig vec multidim)))) + (t + (setq sig nil))) + ;; Process signals + (verilog-read-sub-decls-sig submodi comment port sig vec multidim)) + ;; + (forward-line 1))))) + +(defun verilog-read-sub-decls () + "Internally parse signals going to modules under this module. +Return a array of [ outputs inouts inputs ] signals for modules that are +instantiated in this module. For example if declare A A (.B(SIG)) and SIG +is a output, then SIG will be included in the list. + +This only works on instantiations created with /*AUTOINST*/ converted by +\\[verilog-auto-inst]. Otherwise, it would have to read in the whole +component library to determine connectivity of the design. + +One work around for this problem is to manually create // Inputs and // +Outputs comments above subcell signals, for example: + + module1 instance1x ( + // Outputs + .out (out), + // Inputs + .in (in));" + (save-excursion + (let ((end-mod-point (verilog-get-end-of-defun t)) + st-point end-inst-point + ;; below 3 modified by verilog-read-sub-decls-line + sigs-out sigs-inout sigs-in) + (verilog-beg-of-defun) + (while (re-search-forward "\\(/\\*AUTOINST\\*/\\|\\.\\*\\)" end-mod-point t) + (save-excursion + (goto-char (match-beginning 0)) + (unless (verilog-inside-comment-p) + ;; Attempt to snarf a comment + (let* ((submod (verilog-read-inst-module)) + (inst (verilog-read-inst-name)) + (comment (concat inst " of " submod ".v")) submodi) + (when (setq submodi (verilog-modi-lookup submod t)) + ;; This could have used a list created by verilog-auto-inst + ;; However I want it to be runnable even on user's manually added signals + (verilog-backward-open-paren) + (setq end-inst-point (save-excursion (forward-sexp 1) (point)) + st-point (point)) + (while (re-search-forward "\\s *(?\\s *// Outputs" end-inst-point t) + (verilog-read-sub-decls-line submodi comment)) ;; Modifies sigs-out + (goto-char st-point) + (while (re-search-forward "\\s *// Inouts" end-inst-point t) + (verilog-read-sub-decls-line submodi comment)) ;; Modifies sigs-inout + (goto-char st-point) + (while (re-search-forward "\\s *// Inputs" end-inst-point t) + (verilog-read-sub-decls-line submodi comment)) ;; Modifies sigs-in + ))))) + ;; Combine duplicate bits + ;;(setq rr (vector sigs-out sigs-inout sigs-in)) + (vector (verilog-signals-combine-bus (nreverse sigs-out)) + (verilog-signals-combine-bus (nreverse sigs-inout)) + (verilog-signals-combine-bus (nreverse sigs-in)))))) + +(defun verilog-read-inst-pins () + "Return a array of [ pins ] for the current instantiation at point. +For example if declare A A (.B(SIG)) then B will be included in the list." + (save-excursion + (let ((end-mod-point (point)) ;; presume at /*AUTOINST*/ point + pins pin) + (verilog-backward-open-paren) + (while (re-search-forward "\\.\\([^(,) \t\n\f]*\\)\\s-*" end-mod-point t) + (setq pin (match-string 1)) + (unless (verilog-inside-comment-p) + (setq pins (cons (list pin) pins)) + (when (looking-at "(") + (forward-sexp 1)))) + (vector pins)))) + +(defun verilog-read-arg-pins () + "Return a array of [ pins ] for the current argument declaration at point." + (save-excursion + (let ((end-mod-point (point)) ;; presume at /*AUTOARG*/ point + pins pin) + (verilog-backward-open-paren) + (while (re-search-forward "\\([a-zA-Z0-9$_.%`]+\\)" end-mod-point t) + (setq pin (match-string 1)) + (unless (verilog-inside-comment-p) + (setq pins (cons (list pin) pins)))) + (vector pins)))) + +(defun verilog-read-auto-constants (beg end-mod-point) + "Return a list of AUTO_CONSTANTs used in the region from BEG to END-MOD-POINT." + ;; Insert new + (save-excursion + (let (sig-list tpl-end-pt) + (goto-char beg) + (while (re-search-forward "\\<AUTO_CONSTANT" end-mod-point t) + (if (not (looking-at "\\s *(")) + (error "%s: Missing () after AUTO_CONSTANT" (verilog-point-text))) + (search-forward "(" end-mod-point) + (setq tpl-end-pt (save-excursion + (backward-char 1) + (forward-sexp 1) ;; Moves to paren that closes argdecl's + (backward-char 1) + (point))) + (while (re-search-forward "\\s-*\\([\"a-zA-Z0-9$_.%`]+\\)\\s-*,*" tpl-end-pt t) + (setq sig-list (cons (list (match-string 1) nil nil) sig-list)))) + sig-list))) + +(defun verilog-read-auto-lisp (start end) + "Look for and evaluate a AUTO_LISP between START and END." + (save-excursion + (goto-char start) + (while (re-search-forward "\\<AUTO_LISP(" end t) + (backward-char) + (let* ((beg-pt (prog1 (point) + (forward-sexp 1))) ;; Closing paren + (end-pt (point))) + (eval-region beg-pt end-pt nil))))) + +(eval-when-compile + ;; These are passed in a let, not global + (if (not (boundp 'sigs-in)) + (defvar sigs-in nil) (defvar sigs-out nil) + (defvar got-sig nil) (defvar got-rvalue nil) (defvar uses-delayed nil))) + +(defun verilog-read-always-signals-recurse + (exit-keywd rvalue ignore-next) + "Recursive routine for parentheses/bracket matching. +EXIT-KEYWD is expression to stop at, nil if top level. +RVALUE is true if at right hand side of equal. +IGNORE-NEXT is true to ignore next token, fake from inside case statement." + (let* ((semi-rvalue (equal "endcase" exit-keywd)) ;; true if after a ; we are looking for rvalue + keywd last-keywd sig-tolk sig-last-tolk gotend got-sig got-rvalue end-else-check) + ;;(if dbg (setq dbg (concat dbg (format "Recursion %S %S %S\n" exit-keywd rvalue ignore-next)))) + (while (not (or (eobp) gotend)) + (cond + ((looking-at "//") + (search-forward "\n")) + ((looking-at "/\\*") + (or (search-forward "*/") + (error "%s: Unmatched /* */, at char %d" (verilog-point-text) (point)))) + ((looking-at "(\\*") + (or (looking-at "(\\*\\s-*)") ; It's a "always @ (*)" + (search-forward "*)") + (error "%s: Unmatched (* *), at char %d" (verilog-point-text) (point)))) + (t (setq keywd (buffer-substring-no-properties + (point) + (save-excursion (when (eq 0 (skip-chars-forward "a-zA-Z0-9$_.%`")) + (forward-char 1)) + (point))) + sig-last-tolk sig-tolk + sig-tolk nil) + ;;(if dbg (setq dbg (concat dbg (format "\tPt=%S %S\trv=%S in=%S ee=%S\n" (point) keywd rvalue ignore-next end-else-check)))) + (cond + ((equal keywd "\"") + (or (re-search-forward "[^\\]\"" nil t) + (error "%s: Unmatched quotes, at char %d" (verilog-point-text) (point)))) + ;; else at top level loop, keep parsing + ((and end-else-check (equal keywd "else")) + ;;(if dbg (setq dbg (concat dbg (format "\tif-check-else %s\n" keywd)))) + ;; no forward movement, want to see else in lower loop + (setq end-else-check nil)) + ;; End at top level loop + ((and end-else-check (looking-at "[^ \t\n\f]")) + ;;(if dbg (setq dbg (concat dbg (format "\tif-check-else-other %s\n" keywd)))) + (setq gotend t)) + ;; Final statement? + ((and exit-keywd (equal keywd exit-keywd)) + (setq gotend t) + (forward-char (length keywd))) + ;; Standard tokens... + ((equal keywd ";") + (setq ignore-next nil rvalue semi-rvalue) + ;; Final statement at top level loop? + (when (not exit-keywd) + ;;(if dbg (setq dbg (concat dbg (format "\ttop-end-check %s\n" keywd)))) + (setq end-else-check t)) + (forward-char 1)) + ((equal keywd "'") + (if (looking-at "'s?[hdxbo][0-9a-fA-F_xz? \t]*") + (goto-char (match-end 0)) + (forward-char 1))) + ((equal keywd ":") ;; Case statement, begin/end label, x?y:z + (cond ((equal "endcase" exit-keywd) ;; case x: y=z; statement next + (setq ignore-next nil rvalue nil)) + ((equal "?" exit-keywd) ;; x?y:z rvalue + ) ;; NOP + (got-sig ;; label: statement + (setq ignore-next nil rvalue semi-rvalue got-sig nil)) + ((not rvalue) ;; begin label + (setq ignore-next t rvalue nil))) + (forward-char 1)) + ((equal keywd "=") + (if (eq (char-before) ?< ) + (setq uses-delayed 1)) + (setq ignore-next nil rvalue t) + (forward-char 1)) + ((equal keywd "?") + (forward-char 1) + (verilog-read-always-signals-recurse ":" rvalue nil)) + ((equal keywd "[") + (forward-char 1) + (verilog-read-always-signals-recurse "]" t nil)) + ((equal keywd "(") + (forward-char 1) + (cond (sig-last-tolk ;; Function call; zap last signal + (setq got-sig nil))) + (cond ((equal last-keywd "for") + (verilog-read-always-signals-recurse ";" nil nil) + (verilog-read-always-signals-recurse ";" t nil) + (verilog-read-always-signals-recurse ")" nil nil)) + (t (verilog-read-always-signals-recurse ")" t nil)))) + ((equal keywd "begin") + (skip-syntax-forward "w_") + (verilog-read-always-signals-recurse "end" nil nil) + ;;(if dbg (setq dbg (concat dbg (format "\tgot-end %s\n" exit-keywd)))) + (setq ignore-next nil rvalue semi-rvalue) + (if (not exit-keywd) (setq end-else-check t))) + ((or (equal keywd "case") + (equal keywd "casex") + (equal keywd "casez")) + (skip-syntax-forward "w_") + (verilog-read-always-signals-recurse "endcase" t nil) + (setq ignore-next nil rvalue semi-rvalue) + (if (not exit-keywd) (setq gotend t))) ;; top level begin/end + ((string-match "^[$`a-zA-Z_]" keywd) ;; not exactly word constituent + (cond ((or (equal keywd "`ifdef") + (equal keywd "`ifndef")) + (setq ignore-next t)) + ((or ignore-next + (member keywd verilog-keywords) + (string-match "^\\$" keywd)) ;; PLI task + (setq ignore-next nil)) + (t + (setq keywd (verilog-symbol-detick-denumber keywd)) + (when got-sig + (if got-rvalue (setq sigs-in (cons got-sig sigs-in)) + (setq sigs-out (cons got-sig sigs-out))) + ;;(if dbg (setq dbg (concat dbg (format "\t\tgot-sig=%S rv=%S\n" got-sig got-rvalue)))) + ) + (setq got-rvalue rvalue + got-sig (if (or (not keywd) + (assoc keywd (if got-rvalue sigs-in sigs-out))) + nil (list keywd nil nil)) + sig-tolk t))) + (skip-chars-forward "a-zA-Z0-9$_.%`")) + (t + (forward-char 1))) + ;; End of non-comment token + (setq last-keywd keywd) + )) + (skip-syntax-forward " ")) + ;; Append the final pending signal + (when got-sig + (if got-rvalue (setq sigs-in (cons got-sig sigs-in)) + (setq sigs-out (cons got-sig sigs-out))) + ;;(if dbg (setq dbg (concat dbg (format "\t\tgot-sig=%S rv=%S\n" got-sig got-rvalue)))) + (setq got-sig nil)) + ;;(if dbg (setq dbg (concat dbg (format "ENDRecursion %s\n" exit-keywd)))) + )) + +(defun verilog-read-always-signals () + "Parse always block at point and return list of (outputs inout inputs)." + ;; Insert new + (save-excursion + (let* (;;(dbg "") + sigs-in sigs-out + uses-delayed) ;; Found signal/rvalue; push if not function + (search-forward ")") + (verilog-read-always-signals-recurse nil nil nil) + ;;(if dbg (save-excursion (set-buffer (get-buffer-create "*vl-dbg*")) (delete-region (point-min) (point-max)) (insert dbg) (setq dbg ""))) + ;; Return what was found + (list sigs-out nil sigs-in uses-delayed)))) + +(defun verilog-read-instants () + "Parse module at point and return list of ( ( file instance ) ... )." + (verilog-beg-of-defun) + (let* ((end-mod-point (verilog-get-end-of-defun t)) + (state nil) + (instants-list nil)) + (save-excursion + (while (< (point) end-mod-point) + ;; Stay at level 0, no comments + (while (progn + (setq state (parse-partial-sexp (point) end-mod-point 0 t nil)) + (or (> (car state) 0) ; in parens + (nth 5 state) ; comment + )) + (forward-line 1)) + (beginning-of-line) + (if (looking-at "^\\s-*\\([a-zA-Z0-9`_$]+\\)\\s-+\\([a-zA-Z0-9`_$]+\\)\\s-*(") + ;;(if (looking-at "^\\(.+\\)$") + (let ((module (match-string 1)) + (instant (match-string 2))) + (if (not (member module verilog-keywords)) + (setq instants-list (cons (list module instant) instants-list))))) + (forward-line 1) + )) + instants-list)) + + +(defun verilog-read-auto-template (module) + "Look for a auto_template for the instantiation of the given MODULE. +If found returns the signal name connections. Return REGEXP and +list of ( (signal_name connection_name)... )" + (save-excursion + ;; Find beginning + (let ((tpl-regexp "\\([0-9]+\\)") + (lineno 0) + (templateno 0) + tpl-sig-list tpl-wild-list tpl-end-pt rep) + (cond ((or + (re-search-backward (concat "^\\s-*/?\\*?\\s-*" module "\\s-+AUTO_TEMPLATE") nil t) + (progn + (goto-char (point-min)) + (re-search-forward (concat "^\\s-*/?\\*?\\s-*" module "\\s-+AUTO_TEMPLATE") nil t))) + (goto-char (match-end 0)) + ;; Parse "REGEXP" + ;; We reserve @"..." for future lisp expressions that evaluate once-per-AUTOINST + (when (looking-at "\\s-*\"\\([^\"]*)\\)\"") + (setq tpl-regexp (match-string 1)) + (goto-char (match-end 0))) + (search-forward "(") + ;; Parse lines in the template + (when verilog-auto-inst-template-numbers + (save-excursion + (goto-char (point-min)) + (while (search-forward "AUTO_TEMPLATE" nil t) + (setq templateno (1+ templateno))))) + (setq tpl-end-pt (save-excursion + (backward-char 1) + (forward-sexp 1) ;; Moves to paren that closes argdecl's + (backward-char 1) + (point))) + ;; + (while (< (point) tpl-end-pt) + (cond ((looking-at "\\s-*\\.\\([a-zA-Z0-9`_$]+\\)\\s-*(\\(.*\\))\\s-*\\(,\\|)\\s-*;\\)") + (setq tpl-sig-list (cons (list + (match-string-no-properties 1) + (match-string-no-properties 2) + templateno lineno) + tpl-sig-list)) + (goto-char (match-end 0))) + ;; Regexp form?? + ((looking-at + ;; Regexp bug in xemacs disallows ][ inside [], and wants + last + "\\s-*\\.\\(\\([a-zA-Z0-9`_$+@^.*?|---]+\\|[][]\\|\\\\[()|]\\)+\\)\\s-*(\\(.*\\))\\s-*\\(,\\|)\\s-*;\\)") + (setq rep (match-string-no-properties 3)) + (goto-char (match-end 0)) + (setq tpl-wild-list + (cons (list + (concat "^" + (verilog-string-replace-matches "@" "\\\\([0-9]+\\\\)" nil nil + (match-string 1)) + "$") + rep + templateno lineno) + tpl-wild-list))) + ((looking-at "[ \t\f]+") + (goto-char (match-end 0))) + ((looking-at "\n") + (setq lineno (1+ lineno)) + (goto-char (match-end 0))) + ((looking-at "//") + (search-forward "\n")) + ((looking-at "/\\*") + (forward-char 2) + (or (search-forward "*/") + (error "%s: Unmatched /* */, at char %d" (verilog-point-text) (point)))) + (t + (error "%s: AUTO_TEMPLATE parsing error: %s" + (verilog-point-text) + (progn (looking-at ".*$") (match-string 0)))) + )) + ;; Return + (vector tpl-regexp + (list tpl-sig-list tpl-wild-list))) + ;; If no template found + (t (vector tpl-regexp nil)))))) +;;(progn (find-file "auto-template.v") (verilog-read-auto-template "ptl_entry")) + +(defun verilog-set-define (defname defvalue &optional buffer enumname) + "Set the definition DEFNAME to the DEFVALUE in the given BUFFER. +Optionally associate it with the specified enumeration ENUMNAME." + (save-excursion + (set-buffer (or buffer (current-buffer))) + (let ((mac (intern (concat "vh-" defname)))) + ;;(message "Define %s=%s" defname defvalue) (sleep-for 1) + ;; Need to define to a constant if no value given + (set (make-variable-buffer-local mac) + (if (equal defvalue "") "1" defvalue))) + (if enumname + (let ((enumvar (intern (concat "venum-" enumname)))) + ;;(message "Define %s=%s" defname defvalue) (sleep-for 1) + (make-variable-buffer-local enumvar) + (add-to-list enumvar defname))) + )) + +(defun verilog-read-defines (&optional filename recurse subcall) + "Read `defines and parameters for the current file, or optional FILENAME. +If the filename is provided, `verilog-library-flags' will be used to +resolve it. If optional RECURSE is non-nil, recurse through `includes. + +Parameters must be simple assignments to constants, or have their own +\"parameter\" label rather than a list of parameters. Thus: + + parameter X = 5, Y = 10; // Ok + parameter X = {1'b1, 2'h2}; // Ok + parameter X = {1'b1, 2'h2}, Y = 10; // Bad, make into 2 parameter lines + +Defines must be simple text substitutions, one on a line, starting +at the beginning of the line. Any ifdefs or multiline comments around the +define are ignored. + +Defines are stored inside Emacs variables using the name vh-{definename}. + +This function is useful for setting vh-* variables. The file variables +feature can be used to set defines that `verilog-mode' can see; put at the +*END* of your file something like: + + // Local Variables: + // vh-macro:\"macro_definition\" + // End: + +If macros are defined earlier in the same file and you want their values, +you can read them automatically (provided `enable-local-eval' is on): + + // Local Variables: + // eval:(verilog-read-defines) + // eval:(verilog-read-defines \"group_standard_includes.v\") + // End: + +Note these are only read when the file is first visited, you must use +\\[find-alternate-file] RET to have these take effect after editing them! + +If you want to disable the \"Process `eval' or hook local variables\" +warning message, you need to add to your .emacs file: + + (setq enable-local-eval t)" + (let ((origbuf (current-buffer))) + (save-excursion + (unless subcall (verilog-getopt-flags)) + (when filename + (let ((fns (verilog-library-filenames filename (buffer-file-name)))) + (if fns + (set-buffer (find-file-noselect (car fns))) + (error (concat (verilog-point-text) + ": Can't find verilog-read-defines file: " filename))))) + (when recurse + (goto-char (point-min)) + (while (re-search-forward "^\\s-*`include\\s-+\\([^ \t\n\f]+\\)" nil t) + (let ((inc (verilog-string-replace-matches "\"" "" nil nil (match-string-no-properties 1)))) + (unless (verilog-inside-comment-p) + (verilog-read-defines inc recurse t))))) + ;; Read `defines + ;; note we don't use verilog-re... it's faster this way, and that + ;; function has problems when comments are at the end of the define + (goto-char (point-min)) + (while (re-search-forward "^\\s-*`define\\s-+\\([a-zA-Z0-9_$]+\\)\\s-+\\(.*\\)$" nil t) + (let ((defname (match-string-no-properties 1)) + (defvalue (match-string-no-properties 2))) + (setq defvalue (verilog-string-replace-matches "\\s-*/[/*].*$" "" nil nil defvalue)) + (verilog-set-define defname defvalue origbuf))) + ;; Hack: Read parameters + (goto-char (point-min)) + (while (re-search-forward + "^\\s-*\\(parameter\\|localparam\\)\\(\\(\\s-*\\[[^]]*\\]\\|\\)\\s-+\\([a-zA-Z0-9_$]+\\)\\s-*=\\s-*\\([^;,]*\\),?\\|\\)\\s-*" nil t) + (let ((var (match-string-no-properties 4)) + (val (match-string-no-properties 5)) + enumname) + ;; The primary way of getting defines is verilog-read-decls + ;; However, that isn't called yet for included files, so we'll add another scheme + (if (looking-at "[^\n]*synopsys\\s +enum\\s +\\([a-zA-Z0-9_]+\\)") + (setq enumname (match-string-no-properties 1))) + (if var + (verilog-set-define var val origbuf enumname)) + (forward-comment 999) + (while (looking-at "\\s-*,?\\s-*\\([a-zA-Z0-9_$]+\\)\\s-*=\\s-*\\([^;,]*\\),?\\s-*") + (verilog-set-define (match-string-no-properties 1) (match-string-no-properties 2) origbuf enumname) + (goto-char (match-end 0)) + (forward-comment 999)))) + ))) + +(defun verilog-read-includes () + "Read `includes for the current file. +This will find all of the `includes which are at the beginning of lines, +ignoring any ifdefs or multiline comments around them. +`verilog-read-defines' is then performed on the current and each included +file. + +It is often useful put at the *END* of your file something like: + + // Local Variables: + // eval:(verilog-read-defines) + // eval:(verilog-read-includes) + // End: + +Note includes are only read when the file is first visited, you must use +\\[find-alternate-file] RET to have these take effect after editing them! + +It is good to get in the habit of including all needed files in each .v +file that needs it, rather than waiting for compile time. This will aid +this process, Verilint, and readability. To prevent defining the same +variable over and over when many modules are compiled together, put a test +around the inside each include file: + +foo.v (a include): + `ifdef _FOO_V // include if not already included + `else + `define _FOO_V + ... contents of file + `endif // _FOO_V" +;;slow: (verilog-read-defines nil t)) + (save-excursion + (verilog-getopt-flags) + (goto-char (point-min)) + (while (re-search-forward "^\\s-*`include\\s-+\\([^ \t\n\f]+\\)" nil t) + (let ((inc (verilog-string-replace-matches "\"" "" nil nil (match-string 1)))) + (verilog-read-defines inc nil t))))) + +(defun verilog-read-signals (&optional start end) + "Return a simple list of all possible signals in the file. +Bounded by optional region from START to END. Overly aggressive but fast. +Some macros and such are also found and included. For dinotrace.el" + (let (sigs-all keywd) + (progn;save-excursion + (goto-char (or start (point-min))) + (setq end (or end (point-max))) + (while (re-search-forward "[\"/a-zA-Z_.%`]" end t) + (forward-char -1) + (cond + ((looking-at "//") + (search-forward "\n")) + ((looking-at "/\\*") + (search-forward "*/")) + ((looking-at "(\\*") + (or (looking-at "(\\*\\s-*)") ; It's a "always @ (*)" + (search-forward "*)"))) + ((eq ?\" (following-char)) + (re-search-forward "[^\\]\"")) ;; don't forward-char first, since we look for a non backslash first + ((looking-at "\\s-*\\([a-zA-Z0-9$_.%`]+\\)") + (goto-char (match-end 0)) + (setq keywd (match-string-no-properties 1)) + (or (member keywd verilog-keywords) + (member keywd sigs-all) + (setq sigs-all (cons keywd sigs-all)))) + (t (forward-char 1))) + ) + ;; Return list + sigs-all))) + +;; +;; Argument file parsing +;; + +(defun verilog-getopt (arglist) + "Parse -f, -v etc arguments in ARGLIST list or string." + (unless (listp arglist) (setq arglist (list arglist))) + (let ((space-args '()) + arg next-param) + ;; Split on spaces, so users can pass whole command lines + (while arglist + (setq arg (car arglist) + arglist (cdr arglist)) + (while (string-match "^\\([^ \t\n\f]+\\)[ \t\n\f]*\\(.*$\\)" arg) + (setq space-args (append space-args + (list (match-string-no-properties 1 arg)))) + (setq arg (match-string 2 arg)))) + ;; Parse arguments + (while space-args + (setq arg (car space-args) + space-args (cdr space-args)) + (cond + ;; Need another arg + ((equal arg "-f") + (setq next-param arg)) + ((equal arg "-v") + (setq next-param arg)) + ((equal arg "-y") + (setq next-param arg)) + ;; +libext+(ext1)+(ext2)... + ((string-match "^\\+libext\\+\\(.*\\)" arg) + (setq arg (match-string 1 arg)) + (while (string-match "\\([^+]+\\)\\+?\\(.*\\)" arg) + (verilog-add-list-unique `verilog-library-extensions + (match-string 1 arg)) + (setq arg (match-string 2 arg)))) + ;; + ((or (string-match "^-D\\([^+=]*\\)[+=]\\(.*\\)" arg) ;; -Ddefine=val + (string-match "^-D\\([^+=]*\\)\\(\\)" arg) ;; -Ddefine + (string-match "^\\+define\\([^+=]*\\)[+=]\\(.*\\)" arg) ;; +define+val + (string-match "^\\+define\\([^+=]*\\)\\(\\)" arg)) ;; +define+define + (verilog-set-define (match-string 1 arg) (match-string 2 arg))) + ;; + ((or (string-match "^\\+incdir\\+\\(.*\\)" arg) ;; +incdir+dir + (string-match "^-I\\(.*\\)" arg)) ;; -Idir + (verilog-add-list-unique `verilog-library-directories + (match-string 1 arg))) + ;; Ignore + ((equal "+librescan" arg)) + ((string-match "^-U\\(.*\\)" arg)) ;; -Udefine + ;; Second parameters + ((equal next-param "-f") + (setq next-param nil) + (verilog-getopt-file arg)) + ((equal next-param "-v") + (setq next-param nil) + (verilog-add-list-unique `verilog-library-files arg)) + ((equal next-param "-y") + (setq next-param nil) + (verilog-add-list-unique `verilog-library-directories arg)) + ;; Filename + ((string-match "^[^-+]" arg) + (verilog-add-list-unique `verilog-library-files arg)) + ;; Default - ignore; no warning + ) + ) + ) + ) +;;(verilog-getopt (list "+libext+.a+.b" "+incdir+foodir" "+define+a+aval" "-f" "otherf" "-v" "library" "-y" "dir")) + +(defun verilog-getopt-file (filename) + "Read verilog options from the specified FILENAME." + (save-excursion + (let ((fns (verilog-library-filenames filename (buffer-file-name))) + (orig-buffer (current-buffer)) + line) + (if fns + (set-buffer (find-file-noselect (car fns))) + (error (concat (verilog-point-text) + "Can't find verilog-getopt-file -f file: " filename))) + (goto-char (point-min)) + (while (not (eobp)) + (setq line (buffer-substring (point) + (save-excursion (end-of-line) (point)))) + (forward-line 1) + (when (string-match "//" line) + (setq line (substring line 0 (match-beginning 0)))) + (save-excursion + (set-buffer orig-buffer) ; Variables are buffer-local, so need right context. + (verilog-getopt line)))))) + +(defun verilog-getopt-flags () + "Convert `verilog-library-flags' into standard library variables." + ;; If the flags are local, then all the outputs should be local also + (when (local-variable-p `verilog-library-flags (current-buffer)) + (make-variable-buffer-local 'verilog-library-extensions) + (make-variable-buffer-local 'verilog-library-directories) + (make-variable-buffer-local 'verilog-library-files) + (make-variable-buffer-local 'verilog-library-flags)) + ;; Allow user to customize + (run-hooks 'verilog-before-getopt-flags-hook) + ;; Process arguments + (verilog-getopt verilog-library-flags) + ;; Allow user to customize + (run-hooks 'verilog-getopt-flags-hook)) + +(defun verilog-add-list-unique (varref object) + "Append to VARREF list the given OBJECT, +unless it is already a member of the variable's list" + (unless (member object (symbol-value varref)) + (set varref (append (symbol-value varref) (list object)))) + varref) +;;(progn (setq l '()) (verilog-add-list-unique `l "a") (verilog-add-list-unique `l "a") l) + + +;; +;; Module name lookup +;; + +(defun verilog-module-inside-filename-p (module filename) + "Return point if MODULE is specified inside FILENAME, else nil. +Allows version control to check out the file if need be." + (and (or (file-exists-p filename) + (and + (condition-case nil + (fboundp 'vc-backend) + (error nil)) + (vc-backend filename))) + (let (pt) + (save-excursion + (set-buffer (find-file-noselect filename)) + (goto-char (point-min)) + (while (and + ;; It may be tempting to look for verilog-defun-re, don't, it slows things down a lot! + (verilog-re-search-forward-quick "\\<module\\>" nil t) + (verilog-re-search-forward-quick "[(;]" nil t)) + (if (equal module (verilog-read-module-name)) + (setq pt (point)))) + pt)))) + +(defun verilog-is-number (symbol) + "Return true if SYMBOL is number-like." + (or (string-match "^[0-9 \t:]+$" symbol) + (string-match "^[---]*[0-9]+$" symbol) + (string-match "^[0-9 \t]+'s?[hdxbo][0-9a-fA-F_xz? \t]*$" symbol) + )) + +(defun verilog-symbol-detick (symbol wing-it) + "Return a expanded SYMBOL name without any defines. +If the variable vh-{symbol} is defined, return that value. +If undefined, and WING-IT, return just SYMBOL without the tick, else nil." + (while (and symbol (string-match "^`" symbol)) + (setq symbol (substring symbol 1)) + (setq symbol + (if (boundp (intern (concat "vh-" symbol))) + ;; Emacs has a bug where boundp on a buffer-local + ;; variable in only one buffer returns t in another. + ;; This can confuse, so check for nil. + (let ((val (eval (intern (concat "vh-" symbol))))) + (if (eq val nil) + (if wing-it symbol nil) + val)) + (if wing-it symbol nil)))) + symbol) +;;(verilog-symbol-detick "`mod" nil) + +(defun verilog-symbol-detick-denumber (symbol) + "Return SYMBOL with defines converted and any numbers dropped to nil." + (when (string-match "^`" symbol) + ;; This only will work if the define is a simple signal, not + ;; something like a[b]. Sorry, it should be substituted into the parser + (setq symbol + (verilog-string-replace-matches + "\[[^0-9: \t]+\]" "" nil nil + (or (verilog-symbol-detick symbol nil) + (if verilog-auto-sense-defines-constant + "0" + symbol))))) + (if (verilog-is-number symbol) + nil + symbol)) + +(defun verilog-symbol-detick-text (text) + "Return TEXT with any without any known defines. +If the variable vh-{symbol} is defined, substitute that value." + (let ((ok t) symbol val) + (while (and ok (string-match "`\\([a-zA-Z0-9_]+\\)" text)) + (setq symbol (match-string 1 text)) + (message symbol) + (cond ((and + (boundp (intern (concat "vh-" symbol))) + ;; Emacs has a bug where boundp on a buffer-local + ;; variable in only one buffer returns t in another. + ;; This can confuse, so check for nil. + (setq val (eval (intern (concat "vh-" symbol))))) + (setq text (replace-match val nil nil text))) + (t (setq ok nil))))) + text) +;;(progn (setq vh-mod "`foo" vh-foo "bar") (verilog-symbol-detick-text "bar `mod `undefed")) + +(defun verilog-expand-dirnames (&optional dirnames) + "Return a list of existing directories given a list of wildcarded DIRNAMES. +Or, just the existing dirnames themselves if there are no wildcards." + (interactive) + (unless dirnames (error "`verilog-library-directories' should include at least '.'")) + (setq dirnames (reverse dirnames)) ; not nreverse + (let ((dirlist nil) + pattern dirfile dirfiles dirname root filename rest) + (while dirnames + (setq dirname (substitute-in-file-name (car dirnames)) + dirnames (cdr dirnames)) + (cond ((string-match (concat "^\\(\\|[/\\]*[^*?]*[/\\]\\)" ;; root + "\\([^/\\]*[*?][^/\\]*\\)" ;; filename with *? + "\\(.*\\)") ;; rest + dirname) + (setq root (match-string 1 dirname) + filename (match-string 2 dirname) + rest (match-string 3 dirname) + pattern filename) + ;; now replace those * and ? with .+ and . + ;; use ^ and /> to get only whole file names + ;;verilog-string-replace-matches + (setq pattern (verilog-string-replace-matches "[*]" ".+" nil nil pattern) + pattern (verilog-string-replace-matches "[?]" "." nil nil pattern) + + ;; Unfortunately allows abc/*/rtl to match abc/rtl + ;; because abc/.. shows up in dirfiles. Solutions welcome. + dirfiles (if (file-directory-p root) ; Ignore version control external + (directory-files root t pattern nil))) + (while dirfiles + (setq dirfile (expand-file-name (concat (car dirfiles) rest)) + dirfiles (cdr dirfiles)) + (if (file-directory-p dirfile) + (setq dirlist (cons dirfile dirlist)))) + ) + ;; Defaults + (t + (if (file-directory-p dirname) + (setq dirlist (cons dirname dirlist)))) + )) + dirlist)) +;;(verilog-expand-dirnames (list "." ".." "nonexist" "../*" "/home/wsnyder/*/v")) + +(defun verilog-library-filenames (filename current &optional check-ext) + "Return a search path to find the given FILENAME name. +Uses the CURRENT filename, `verilog-library-directories' and +`verilog-library-extensions' variables to build the path. +With optional CHECK-EXT also check `verilog-library-extensions'." + (let ((ckdir (verilog-expand-dirnames verilog-library-directories)) + fn outlist) + (while ckdir + (let ((ckext (if check-ext verilog-library-extensions `("")))) + (while ckext + (setq fn (expand-file-name + (concat filename (car ckext)) + (expand-file-name (car ckdir) (file-name-directory current)))) + (if (file-exists-p fn) + (setq outlist (cons fn outlist))) + (setq ckext (cdr ckext)))) + (setq ckdir (cdr ckdir))) + (nreverse outlist))) + +(defun verilog-module-filenames (module current) + "Return a search path to find the given MODULE name. +Uses the CURRENT filename, `verilog-library-extensions', +`verilog-library-directories' and `verilog-library-files' +variables to build the path." + ;; Return search locations for it + (append (list current) ; first, current buffer + (verilog-library-filenames module current t) + verilog-library-files)) ; finally, any libraries + +;; +;; Module Information +;; +;; Many of these functions work on "modi" a module information structure +;; A modi is: [module-name-string file-name begin-point] + +(defvar verilog-cache-enabled t + "If true, enable caching of signals, etc. Set to nil for debugging to make things SLOW!") + +(defvar verilog-modi-cache-list nil + "Cache of ((Module Function) Buf-Tick Buf-Modtime Func-Returns)... +For speeding up verilog-modi-get-* commands. +Buffer-local.") + +(defvar verilog-modi-cache-preserve-tick nil + "Modification tick after which the cache is still considered valid. +Use verilog-preserve-cache's to set") +(defvar verilog-modi-cache-preserve-buffer nil + "Modification tick after which the cache is still considered valid. +Use verilog-preserve-cache's to set") + +(defun verilog-modi-current () + "Return the modi structure for the module currently at point." + (let* (name pt) + ;; read current module's name + (save-excursion + (verilog-re-search-backward-quick verilog-defun-re nil nil) + (verilog-re-search-forward-quick "(" nil nil) + (setq name (verilog-read-module-name)) + (setq pt (point))) + ;; return + (vector name (or (buffer-file-name) (current-buffer)) pt))) + +(defvar verilog-modi-lookup-last-mod nil "Cache of last module looked up.") +(defvar verilog-modi-lookup-last-modi nil "Cache of last modi returned.") +(defvar verilog-modi-lookup-last-current nil "Cache of last `current-buffer' looked up.") +(defvar verilog-modi-lookup-last-tick nil "Cache of last `buffer-modified-tick' looked up.") + +(defun verilog-modi-lookup (module allow-cache &optional ignore-error) + "Find the file and point at which MODULE is defined. +If ALLOW-CACHE is set, check and remember cache of previous lookups. +Return modi if successful, else print message unless IGNORE-ERROR is true." + (let* ((current (or (buffer-file-name) (current-buffer)))) + (cond ((and verilog-modi-lookup-last-modi + verilog-cache-enabled + allow-cache + (equal verilog-modi-lookup-last-mod module) + (equal verilog-modi-lookup-last-current current) + (equal verilog-modi-lookup-last-tick (buffer-modified-tick))) + ;; ok as is + ) + (t (let* ((realmod (verilog-symbol-detick module t)) + (orig-filenames (verilog-module-filenames realmod current)) + (filenames orig-filenames) + pt) + (while (and filenames (not pt)) + (if (not (setq pt (verilog-module-inside-filename-p realmod (car filenames)))) + (setq filenames (cdr filenames)))) + (cond (pt (setq verilog-modi-lookup-last-modi + (vector realmod (car filenames) pt))) + (t (setq verilog-modi-lookup-last-modi nil) + (or ignore-error + (error (concat (verilog-point-text) + ": Can't locate " module " module definition" + (if (not (equal module realmod)) + (concat " (Expanded macro to " realmod ")") + "") + "\n Check the verilog-library-directories variable." + "\n I looked in (if not listed, doesn't exist):\n\t" + (mapconcat 'concat orig-filenames "\n\t"))))) + ) + (setq verilog-modi-lookup-last-mod module + verilog-modi-lookup-last-current current + verilog-modi-lookup-last-tick (buffer-modified-tick))))) + verilog-modi-lookup-last-modi + )) + +(defsubst verilog-modi-name (modi) + (aref modi 0)) +(defsubst verilog-modi-file-or-buffer (modi) + (aref modi 1)) +(defsubst verilog-modi-point (modi) + (aref modi 2)) + +(defun verilog-modi-filename (modi) + "Filename of MODI, or name of buffer if its never been saved." + (if (bufferp (verilog-modi-file-or-buffer modi)) + (or (buffer-file-name (verilog-modi-file-or-buffer modi)) + (buffer-name (verilog-modi-file-or-buffer modi))) + (verilog-modi-file-or-buffer modi))) + +(defun verilog-modi-goto (modi) + "Move point/buffer to specified MODI." + (or modi (error "Passed unfound modi to goto, check earlier")) + (set-buffer (if (bufferp (verilog-modi-file-or-buffer modi)) + (verilog-modi-file-or-buffer modi) + (find-file-noselect (verilog-modi-file-or-buffer modi)))) + (or (equal major-mode `verilog-mode) ;; Put into verilog mode to get syntax + (verilog-mode)) + (goto-char (verilog-modi-point modi))) + +(defun verilog-goto-defun-file (module) + "Move point to the file at which a given MODULE is defined." + (interactive "sGoto File for Module: ") + (let* ((modi (verilog-modi-lookup module nil))) + (when modi + (verilog-modi-goto modi) + (switch-to-buffer (current-buffer))))) + +(defun verilog-modi-cache-results (modi function) + "Run on MODI the given FUNCTION. Locate the module in a file. +Cache the output of function so next call may have faster access." + (let (func-returns fass) + (save-excursion + (verilog-modi-goto modi) + (if (and (setq fass (assoc (list (verilog-modi-name modi) function) + verilog-modi-cache-list)) + ;; Destroy caching when incorrect; Modified or file changed + (not (and verilog-cache-enabled + (or (equal (buffer-modified-tick) (nth 1 fass)) + (and verilog-modi-cache-preserve-tick + (<= verilog-modi-cache-preserve-tick (nth 1 fass)) + (equal verilog-modi-cache-preserve-buffer (current-buffer)))) + (equal (visited-file-modtime) (nth 2 fass))))) + (setq verilog-modi-cache-list nil + fass nil)) + (cond (fass + ;; Found + (setq func-returns (nth 3 fass))) + (t + ;; Read from file + ;; Clear then restore any hilighting to make emacs19 happy + (let ((fontlocked (when (and (boundp 'font-lock-mode) + font-lock-mode) + (font-lock-mode nil) + t))) + (setq func-returns (funcall function)) + (when fontlocked (font-lock-mode t))) + ;; Cache for next time + (make-variable-buffer-local 'verilog-modi-cache-list) + (setq verilog-modi-cache-list + (cons (list (list (verilog-modi-name modi) function) + (buffer-modified-tick) + (visited-file-modtime) + func-returns) + verilog-modi-cache-list))) + )) + ;; + func-returns)) + +(defun verilog-modi-cache-add (modi function element sig-list) + "Add function return results to the module cache. +Update MODI's cache for given FUNCTION so that the return ELEMENT of that +function now contains the additional SIG-LIST parameters." + (let (fass) + (save-excursion + (verilog-modi-goto modi) + (if (setq fass (assoc (list (verilog-modi-name modi) function) + verilog-modi-cache-list)) + (let ((func-returns (nth 3 fass))) + (aset func-returns element + (append sig-list (aref func-returns element)))))))) + +(defmacro verilog-preserve-cache (&rest body) + "Execute the BODY forms, allowing cache preservation within BODY. +This means that changes to the buffer will not result in the cache being +flushed. If the changes affect the modsig state, they must call the +modsig-cache-add-* function, else the results of later calls may be +incorrect. Without this, changes are assumed to be adding/removing signals +and invalidating the cache." + `(let ((verilog-modi-cache-preserve-tick (buffer-modified-tick)) + (verilog-modi-cache-preserve-buffer (current-buffer))) + (progn ,@body))) + +(defsubst verilog-modi-get-decls (modi) + (verilog-modi-cache-results modi 'verilog-read-decls)) + +(defsubst verilog-modi-get-sub-decls (modi) + (verilog-modi-cache-results modi 'verilog-read-sub-decls)) + +;; Signal reading for given module +;; Note these all take modi's - as returned from the verilog-modi-current function +(defsubst verilog-modi-get-outputs (modi) + (aref (verilog-modi-get-decls modi) 0)) +(defsubst verilog-modi-get-inouts (modi) + (aref (verilog-modi-get-decls modi) 1)) +(defsubst verilog-modi-get-inputs (modi) + (aref (verilog-modi-get-decls modi) 2)) +(defsubst verilog-modi-get-wires (modi) + (aref (verilog-modi-get-decls modi) 3)) +(defsubst verilog-modi-get-regs (modi) + (aref (verilog-modi-get-decls modi) 4)) +(defsubst verilog-modi-get-assigns (modi) + (aref (verilog-modi-get-decls modi) 5)) +(defsubst verilog-modi-get-consts (modi) + (aref (verilog-modi-get-decls modi) 6)) +(defsubst verilog-modi-get-gparams (modi) + (aref (verilog-modi-get-decls modi) 7)) +(defsubst verilog-modi-get-sub-outputs (modi) + (aref (verilog-modi-get-sub-decls modi) 0)) +(defsubst verilog-modi-get-sub-inouts (modi) + (aref (verilog-modi-get-sub-decls modi) 1)) +(defsubst verilog-modi-get-sub-inputs (modi) + (aref (verilog-modi-get-sub-decls modi) 2)) + + +(defun verilog-signals-matching-enum (in-list enum) + "Return all signals in IN-LIST matching the given ENUM." + (let (out-list) + (while in-list + (if (equal (verilog-sig-enum (car in-list)) enum) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + ;; New scheme + (let* ((enumvar (intern (concat "venum-" enum))) + (enumlist (and (boundp enumvar) (eval enumvar)))) + (while enumlist + (add-to-list 'out-list (list (car enumlist))) + (setq enumlist (cdr enumlist)))) + (nreverse out-list))) + +(defun verilog-signals-not-matching-regexp (in-list regexp) + "Return all signals in IN-LIST not matching the given REGEXP, if non-nil." + (if (not regexp) + in-list + (let (out-list) + (while in-list + (if (not (string-match regexp (verilog-sig-name (car in-list)))) + (setq out-list (cons (car in-list) out-list))) + (setq in-list (cdr in-list))) + (nreverse out-list)))) + +;; Combined +(defun verilog-modi-get-signals (modi) + (append + (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi) + (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-assigns modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi))) + +(defun verilog-modi-get-ports (modi) + (append + (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi))) + +(defsubst verilog-modi-cache-add-outputs (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 0 sig-list)) +(defsubst verilog-modi-cache-add-inouts (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 1 sig-list)) +(defsubst verilog-modi-cache-add-inputs (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 2 sig-list)) +(defsubst verilog-modi-cache-add-wires (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 3 sig-list)) +(defsubst verilog-modi-cache-add-regs (modi sig-list) + (verilog-modi-cache-add modi 'verilog-read-decls 4 sig-list)) + +(defun verilog-signals-from-signame (signame-list) + "Return signals in standard form from SIGNAME-LIST, a simple list of signal names." + (mapcar (function (lambda (name) (list name nil nil))) + signame-list)) + +;; +;; Auto creation utilities +;; + +(defun verilog-auto-search-do (search-for func) + "Search for the given auto text SEARCH-FOR, and perform FUNC where it occurs." + (goto-char (point-min)) + (while (search-forward search-for nil t) + (if (not (save-excursion + (goto-char (match-beginning 0)) + (verilog-inside-comment-p))) + (funcall func)))) + +(defun verilog-auto-re-search-do (search-for func) + "Search for the given auto text SEARCH-FOR, and perform FUNC where it occurs." + (goto-char (point-min)) + (while (re-search-forward search-for nil t) + (if (not (save-excursion + (goto-char (match-beginning 0)) + (verilog-inside-comment-p))) + (funcall func)))) + +(defun verilog-insert-one-definition (sig type indent-pt) + "Print out a definition for SIGNAL of the given TYPE, +with appropriate INDENT-PT indentation." + (indent-to indent-pt) + (insert type) + (when (verilog-sig-signed sig) + (insert " " (verilog-sig-signed sig))) + (when (verilog-sig-multidim sig) + (insert " " (verilog-sig-multidim-string sig))) + (when (verilog-sig-bits sig) + (insert " " (verilog-sig-bits sig))) + (indent-to (max 24 (+ indent-pt 16))) + (unless (= (char-syntax (preceding-char)) ?\ ) + (insert " ")) ; Need space between "]name" if indent-to did nothing + (insert (verilog-sig-name sig))) + +(defun verilog-insert-definition (sigs direction indent-pt v2k &optional dont-sort) + "Print out a definition for a list of SIGS of the given DIRECTION, +with appropriate INDENT-PT indentation. If V2K, use Verilog 2001 I/O +format. Sort unless DONT-SORT. DIRECTION is normally wire/reg/output." + (or dont-sort + (setq sigs (sort (copy-alist sigs) `verilog-signals-sort-compare))) + (while sigs + (let ((sig (car sigs))) + (verilog-insert-one-definition + sig + ;; Want "type x" or "output type x", not "wire type x" + (cond ((verilog-sig-type sig) + (concat + (if (not (equal direction "wire")) + (concat direction " ")) + (verilog-sig-type sig))) + (t direction)) + indent-pt) + (insert (if v2k "," ";")) + (if (or (not (verilog-sig-comment sig)) + (equal "" (verilog-sig-comment sig))) + (insert "\n") + (indent-to (max 48 (+ indent-pt 40))) + (insert (concat "// " (verilog-sig-comment sig) "\n"))) + (setq sigs (cdr sigs))))) + +(eval-when-compile + (if (not (boundp 'indent-pt)) + (defvar indent-pt nil "Local used by insert-indent"))) + +(defun verilog-insert-indent (&rest stuff) + "Indent to position stored in local `indent-pt' variable, then insert STUFF. +Presumes that any newlines end a list element." + (let ((need-indent t)) + (while stuff + (if need-indent (indent-to indent-pt)) + (setq need-indent nil) + (insert (car stuff)) + (setq need-indent (string-match "\n$" (car stuff)) + stuff (cdr stuff))))) +;;(let ((indent-pt 10)) (verilog-insert-indent "hello\n" "addon" "there\n")) + +(defun verilog-repair-open-comma () + "If backwards-from-point is other than a open parenthesis insert comma." + (save-excursion + (verilog-backward-syntactic-ws) + (when (save-excursion + (backward-char 1) + (and (not (looking-at "[(,]")) + (progn + (verilog-re-search-backward "[(`]" nil t) + (looking-at "(")))) + (insert ",")))) + +(defun verilog-repair-close-comma () + "If point is at a comma followed by a close parenthesis, fix it. +This repairs those mis-inserted by a AUTOARG." + ;; It would be much nicer if Verilog allowed extra commas like Perl does! + (save-excursion + (verilog-forward-close-paren) + (backward-char 1) + (verilog-backward-syntactic-ws) + (backward-char 1) + (when (looking-at ",") + (delete-char 1)))) + +(defun verilog-get-list (start end) + "Return the elements of a comma separated list between START and END." + (interactive) + (let ((my-list (list)) + my-string) + (save-excursion + (while (< (point) end) + (when (re-search-forward "\\([^,{]+\\)" end t) + (setq my-string (verilog-string-remove-spaces (match-string 1))) + (setq my-list (nconc my-list (list my-string) )) + (goto-char (match-end 0)))) + my-list))) + +(defun verilog-make-width-expression (range-exp) + "Return an expression calculating the length of a range [x:y] in RANGE-EXP." + ;; strip off the [] + (cond ((not range-exp) + "1") + (t + (if (string-match "^\\[\\(.*\\)\\]$" range-exp) + (setq range-exp (match-string 1 range-exp))) + (cond ((not range-exp) + "1") + ((string-match "^\\s *\\([0-9]+\\)\\s *:\\s *\\([0-9]+\\)\\s *$" range-exp) + (int-to-string (1+ (abs (- (string-to-int (match-string 1 range-exp)) + (string-to-int (match-string 2 range-exp))))))) + ((string-match "^\\(.*\\)\\s *:\\s *\\(.*\\)\\s *$" range-exp) + (concat "(1+(" (match-string 1 range-exp) + ")" + (if (equal "0" (match-string 2 range-exp)) ;; Don't bother with -(0) + "" + (concat "-(" (match-string 2 range-exp) ")")) + ")")) + (t nil))))) +;;(verilog-make-width-expression "`A:`B") + +(defun verilog-typedef-name-p (variable-name) + "Return true if the VARIABLE-NAME is a type definition." + (when verilog-typedef-regexp + (string-match verilog-typedef-regexp variable-name))) + +;; +;; Auto deletion +;; + +(defun verilog-delete-autos-lined () + "Delete autos that occupy multiple lines, between begin and end comments." + (let ((pt (point))) + (forward-line 1) + (when (and + (looking-at "\\s-*// Beginning") + (search-forward "// End of automatic" nil t)) + ;; End exists + (end-of-line) + (delete-region pt (point)) + (forward-line 1)) + )) + +(defun verilog-forward-close-paren () + "Find the close parenthesis that match the current point, +ignore other close parenthesis with matching open parens" + (let ((parens 1)) + (while (> parens 0) + (unless (verilog-re-search-forward-quick "[()]" nil t) + (error "%s: Mismatching ()" (verilog-point-text))) + (cond ((= (preceding-char) ?\( ) + (setq parens (1+ parens))) + ((= (preceding-char) ?\) ) + (setq parens (1- parens))))))) + +(defun verilog-backward-open-paren () + "Find the open parenthesis that match the current point, +ignore other open parenthesis with matching close parens" + (let ((parens 1)) + (while (> parens 0) + (unless (verilog-re-search-backward-quick "[()]" nil t) + (error "%s: Mismatching ()" (verilog-point-text))) + (cond ((= (following-char) ?\) ) + (setq parens (1+ parens))) + ((= (following-char) ?\( ) + (setq parens (1- parens))))))) + +(defun verilog-backward-open-bracket () + "Find the open bracket that match the current point, +ignore other open bracket with matching close bracket" + (let ((parens 1)) + (while (> parens 0) + (unless (verilog-re-search-backward-quick "[][]" nil t) + (error "%s: Mismatching []" (verilog-point-text))) + (cond ((= (following-char) ?\] ) + (setq parens (1+ parens))) + ((= (following-char) ?\[ ) + (setq parens (1- parens))))))) + +(defun verilog-delete-to-paren () + "Delete the automatic inst/sense/arg created by autos. +Deletion stops at the matching end parenthesis." + (delete-region (point) + (save-excursion + (verilog-backward-open-paren) + (forward-sexp 1) ;; Moves to paren that closes argdecl's + (backward-char 1) + (point)))) + +(defun verilog-auto-star-safe () + "Return if a .* AUTOINST is safe to delete or expand. +It was created by the AUTOS themselves, or by the user." + (and verilog-auto-star-expand + (looking-at "[ \t\n\f,]*\\([)]\\|// \\(Outputs\\|Inouts\\|Inputs\\)\\)"))) + +(defun verilog-delete-auto-star-all () + "Delete a .* AUTOINST, if it is safe." + (when (verilog-auto-star-safe) + (verilog-delete-to-paren))) + +(defun verilog-delete-auto-star-implicit () + "Delete all .* implicit connections created by `verilog-auto-star'. +This function will be called automatically at save unless +`verilog-auto-star-save' is set, any non-templated expanded pins will be +removed." + (interactive) + (let (paren-pt indent have-close-paren) + (save-excursion + (goto-char (point-min)) + ;; We need to match these even outside of comments. + ;; For reasonable performance, we don't check if inside comments, sorry. + (while (re-search-forward "// Implicit \\.\\*" nil t) + (setq paren-pt (point)) + (beginning-of-line) + (setq have-close-paren + (save-excursion + (when (search-forward ");" paren-pt t) + (setq indent (current-indentation)) + t))) + (delete-region (point) (+ 1 paren-pt)) ; Nuke line incl CR + (when have-close-paren + ;; Delete extra commentary + (save-excursion + (while (progn + (forward-line -1) + (looking-at "\\s *//\\s *\\(Outputs\\|Inouts\\|Inputs\\)\n")) + (delete-region (match-beginning 0) (match-end 0)))) + ;; If it is simple, we can put the ); on the same line as the last text + (let ((rtn-pt (point))) + (save-excursion + (while (progn (backward-char 1) + (looking-at "[ \t\n\f]"))) + (when (looking-at ",") + (delete-region (+ 1 (point)) rtn-pt)))) + (when (bolp) + (indent-to indent)) + (insert ");\n") + ;; Still need to kill final comma - always is one as we put one after the .* + (re-search-backward ",") + (delete-char 1)))))) + +(defun verilog-delete-auto () + "Delete the automatic outputs, regs, and wires created by \\[verilog-auto]. +Use \\[verilog-auto] to re-insert the updated AUTOs. + +The hooks `verilog-before-delete-auto-hook' and `verilog-delete-auto-hook' are +called before and after this function, respectively." + (interactive) + (save-excursion + (if (buffer-file-name) + (find-file-noselect (buffer-file-name))) ;; To check we have latest version + ;; Allow user to customize + (run-hooks 'verilog-before-delete-auto-hook) + + ;; Remove those that have multi-line insertions + (verilog-auto-re-search-do "/\\*AUTO\\(OUTPUTEVERY\\|CONCATCOMMENT\\|WIRE\\|REG\\|DEFINEVALUE\\|REGINPUT\\|INPUT\\|OUTPUT\\|INOUT\\|RESET\\|TIEOFF\\|UNUSED\\)\\*/" + 'verilog-delete-autos-lined) + ;; Remove those that have multi-line insertions with parameters + (verilog-auto-re-search-do "/\\*AUTO\\(INOUTMODULE\\|ASCIIENUM\\)([^)]*)\\*/" + 'verilog-delete-autos-lined) + ;; Remove those that are in parenthesis + (verilog-auto-re-search-do "/\\*\\(AS\\|AUTO\\(ARG\\|CONCATWIDTH\\|INST\\|INSTPARAM\\|SENSE\\)\\)\\*/" + 'verilog-delete-to-paren) + ;; Do .* instantiations, but avoid removing any user pins by looking for our magic comments + (verilog-auto-re-search-do "\\.\\*" + 'verilog-delete-auto-star-all) + ;; Remove template comments ... anywhere in case was pasted after AUTOINST removed + (goto-char (point-min)) + (while (re-search-forward "\\s-*// \\(Templated\\|Implicit \\.\\*\\)[ \tLT0-9]*$" nil t) + (replace-match "")) + + ;; Final customize + (run-hooks 'verilog-delete-auto-hook))) + +;; +;; Auto inject +;; + +(defun verilog-inject-auto () + "Examine legacy non-AUTO code and insert AUTOs in appropriate places. + +Any always @ blocks with sensitivity lists that match computed lists will +be replaced with /*AS*/ comments. + +Any cells will get /*AUTOINST*/ added to the end of the pin list. Pins with +have identical names will be deleted. + +Argument lists will not be deleted, /*AUTOARG*/ will only be inserted to +support adding new ports. You may wish to delete older ports yourself. + +For example: + + module ex_inject (i, o); + input i; + input j; + output o; + always @ (i or j) + o = i | j; + cell cell (.foobar(baz), + .j(j)); + endmodule + +Typing \\[verilog-inject-auto] will make this into: + + module ex_inject (i, o/*AUTOARG*/ + // Inputs + j); + input i; + output o; + always @ (/*AS*/i or j) + o = i | j; + cell cell (.foobar(baz), + /*AUTOINST*/ + // Outputs + .j(j)); + endmodule" + (interactive) + (verilog-auto t)) + +(defun verilog-inject-arg () + "Inject AUTOARG into new code. See `verilog-inject-auto'." + ;; Presume one module per file. + (save-excursion + (goto-char (point-min)) + (while (verilog-re-search-forward-quick "\\<module\\>" nil t) + (let ((endmodp (save-excursion + (verilog-re-search-forward-quick "\\<endmodule\\>" nil t) + (point)))) + ;; See if there's already a comment .. inside a comment so not verilog-re-search + (when (not (re-search-forward "/\\*AUTOARG\\*/" endmodp t)) + (verilog-re-search-forward-quick ";" nil t) + (backward-char 1) + (verilog-backward-syntactic-ws) + (backward-char 1) ; Moves to paren that closes argdecl's + (when (looking-at ")") + (insert "/*AUTOARG*/"))))))) + +(defun verilog-inject-sense () + "Inject AUTOSENSE into new code. See `verilog-inject-auto'." + (save-excursion + (goto-char (point-min)) + (while (verilog-re-search-forward-quick "\\<always\\s *@\\s *(" nil t) + (let ((start-pt (point)) + (modi (verilog-modi-current)) + pre-sigs + got-sigs) + (backward-char 1) + (forward-sexp 1) + (backward-char 1) ;; End ) + (when (not (verilog-re-search-backward "/\\*\\(AUTOSENSE\\|AS\\)\\*/" start-pt t)) + (setq pre-sigs (verilog-signals-from-signame + (verilog-read-signals start-pt (point))) + got-sigs (verilog-auto-sense-sigs modi nil)) + (when (not (or (verilog-signals-not-in pre-sigs got-sigs) ; Both are equal? + (verilog-signals-not-in got-sigs pre-sigs))) + (delete-region start-pt (point)) + (insert "/*AS*/"))))))) + +(defun verilog-inject-inst () + "Inject AUTOINST into new code. See `verilog-inject-auto'." + (save-excursion + (goto-char (point-min)) + ;; It's hard to distinguish modules; we'll instead search for pins. + (while (verilog-re-search-forward-quick "\\.\\s *[a-zA-Z0-9`_\$]+\\s *(\\s *[a-zA-Z0-9`_\$]+\\s *)" nil t) + (verilog-backward-open-paren) ;; Inst start + (cond + ((= (preceding-char) ?\#) ;; #(...) parameter section, not pin. Skip. + (forward-char 1) + (verilog-forward-close-paren)) ;; Parameters done + (t + (forward-char 1) + (let ((indent-pt (+ (current-column))) + (end-pt (save-excursion (verilog-forward-close-paren) (point)))) + (cond ((verilog-re-search-forward "\\(/\\*AUTOINST\\*/\\|\\.\\*\\)" end-pt t) + (goto-char end-pt)) ;; Already there, continue search with next instance + (t + ;; Delete identical interconnect + (let ((case-fold-search nil)) ;; So we don't convert upper-to-lower, etc + (while (verilog-re-search-forward "\\.\\s *\\([a-zA-Z0-9`_\$]+\\)*\\s *(\\s *\\1\\s *)\\s *" end-pt t) + (delete-region (match-beginning 0) (match-end 0)) + (setq end-pt (- end-pt (- (match-end 0) (match-beginning 0)))) ;; Keep it correct + (while (or (looking-at "[ \t\n\f,]+") + (looking-at "//[^\n]*")) + (delete-region (match-beginning 0) (match-end 0)) + (setq end-pt (- end-pt (- (match-end 0) (match-beginning 0))))))) + (verilog-forward-close-paren) + (backward-char 1) + ;; Not verilog-re-search, as we don't want to strip comments + (while (re-search-backward "[ \t\n\f]+" (- (point) 1) t) + (delete-region (match-beginning 0) (match-end 0))) + (insert "\n") + (indent-to indent-pt) + (insert "/*AUTOINST*/"))))))))) + +;; +;; Auto save +;; + +(defun verilog-auto-save-check () + "On saving see if we need auto update." + (cond ((not verilog-auto-save-policy)) ; disabled + ((not (save-excursion + (save-match-data + (let ((case-fold-search nil)) + (goto-char (point-min)) + (re-search-forward "AUTO" nil t)))))) + ((eq verilog-auto-save-policy 'force) + (verilog-auto)) + ((not (buffer-modified-p))) + ((eq verilog-auto-update-tick (buffer-modified-tick))) ; up-to-date + ((eq verilog-auto-save-policy 'detect) + (verilog-auto)) + (t + (when (yes-or-no-p "AUTO statements not recomputed, do it now? ") + (verilog-auto)) + ;; Don't ask again if didn't update + (set (make-local-variable 'verilog-auto-update-tick) (buffer-modified-tick)) + )) + (when (not verilog-auto-star-save) + (verilog-delete-auto-star-implicit)) + nil) ;; Always return nil -- we don't write the file ourselves + +(defun verilog-auto-read-locals () + "Return file local variable segment at bottom of file." + (save-excursion + (goto-char (point-max)) + (if (re-search-backward "Local Variables:" nil t) + (buffer-substring-no-properties (point) (point-max)) + ""))) + +(defun verilog-auto-reeval-locals (&optional force) + "Read file local variable segment at bottom of file if it has changed. +If FORCE, always reread it." + (make-variable-buffer-local 'verilog-auto-last-file-locals) + (let ((curlocal (verilog-auto-read-locals))) + (when (or force (not (equal verilog-auto-last-file-locals curlocal))) + (setq verilog-auto-last-file-locals curlocal) + ;; Note this may cause this function to be recursively invoked. + ;; The above when statement will prevent it from recursing forever. + (hack-local-variables) + t))) + +;; +;; Auto creation +;; + +(defun verilog-auto-arg-ports (sigs message indent-pt) + "Print a list of ports for a AUTOINST. +Takes SIGS list, adds MESSAGE to front and inserts each at INDENT-PT." + (when sigs + (insert "\n") + (indent-to indent-pt) + (insert message) + (insert "\n") + (let ((space "")) + (indent-to indent-pt) + (while sigs + (cond ((> (+ 2 (current-column) (length (verilog-sig-name (car sigs)))) fill-column) + (insert "\n") + (indent-to indent-pt)) + (t (insert space))) + (insert (verilog-sig-name (car sigs)) ",") + (setq sigs (cdr sigs) + space " "))))) + +(defun verilog-auto-arg () + "Expand AUTOARG statements. +Replace the argument declarations at the beginning of the +module with ones automatically derived from input and output +statements. This can be dangerous if the module is instantiated +using position-based connections, so use only name-based when +instantiating the resulting module. Long lines are split based +on the `fill-column', see \\[set-fill-column]. + +Limitations: + Concatenation and outputting partial busses is not supported. + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + +For example: + + module ex_arg (/*AUTOARG*/); + input i; + output o; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_arg (/*AUTOARG*/ + // Outputs + o, + // Inputs + i + ); + input i; + output o; + endmodule + +Any ports declared between the ( and /*AUTOARG*/ are presumed to be +predeclared and are not redeclared by AUTOARG. AUTOARG will make a +conservative guess on adding a comma for the first signal, if you have any +ifdefs or complicated expressions before the AUTOARG you will need to +choose the comma yourself. + +Avoid declaring ports manually, as it makes code harder to maintain." + (save-excursion + (let ((modi (verilog-modi-current)) + (skip-pins (aref (verilog-read-arg-pins) 0))) + (verilog-repair-open-comma) + (verilog-auto-arg-ports (verilog-signals-not-in + (verilog-modi-get-outputs modi) + skip-pins) + "// Outputs" + verilog-indent-level-declaration) + (verilog-auto-arg-ports (verilog-signals-not-in + (verilog-modi-get-inouts modi) + skip-pins) + "// Inouts" + verilog-indent-level-declaration) + (verilog-auto-arg-ports (verilog-signals-not-in + (verilog-modi-get-inputs modi) + skip-pins) + "// Inputs" + verilog-indent-level-declaration) + (verilog-repair-close-comma) + (unless (eq (char-before) ?/ ) + (insert "\n")) + (indent-to verilog-indent-level-declaration) + ))) + +(defun verilog-auto-inst-port-map (port-st) + nil) + +(defvar vector-skip-list nil) ; Prevent compile warning +(defvar vl-cell-type nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-cell-name nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-name nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-width nil "See `verilog-auto-inst'.") ; Prevent compile warning +(defvar vl-dir nil "See `verilog-auto-inst'.") ; Prevent compile warning + +(defun verilog-auto-inst-port (port-st indent-pt tpl-list tpl-num for-star) + "Print out a instantiation connection for this PORT-ST. +Insert to INDENT-PT, use template TPL-LIST. +@ are instantiation numbers, replaced with TPL-NUM. +@\"(expression @)\" are evaluated, with @ as a variable." + (let* ((port (verilog-sig-name port-st)) + (tpl-ass (or (assoc port (car tpl-list)) + (verilog-auto-inst-port-map port-st))) + ;; vl-* are documented for user use + (vl-name (verilog-sig-name port-st)) + (vl-width (verilog-sig-width port-st)) + (vl-bits (if (or verilog-auto-inst-vector + (not (assoc port vector-skip-list)) + (not (equal (verilog-sig-bits port-st) + (verilog-sig-bits (assoc port vector-skip-list))))) + (or (verilog-sig-bits port-st) "") + "")) + ;; Default if not found + (tpl-net (if (verilog-sig-multidim port-st) + (concat port "/*" (verilog-sig-multidim-string port-st) + vl-bits "*/") + (concat port vl-bits))) + (case-fold-search nil)) + ;; Find template + (cond (tpl-ass ; Template of exact port name + (setq tpl-net (nth 1 tpl-ass))) + ((nth 1 tpl-list) ; Wildcards in template, search them + (let ((wildcards (nth 1 tpl-list))) + (while wildcards + (when (string-match (nth 0 (car wildcards)) port) + (setq tpl-ass (car wildcards) ; so allow @ parsing + tpl-net (replace-match (nth 1 (car wildcards)) + t nil port))) + (setq wildcards (cdr wildcards)))))) + ;; Parse Templated variable + (when tpl-ass + ;; Evaluate @"(lispcode)" + (when (string-match "@\".*[^\\]\"" tpl-net) + (while (string-match "@\"\\(\\([^\\\"]*\\(\\\\.\\)*\\)*\\)\"" tpl-net) + (setq tpl-net + (concat + (substring tpl-net 0 (match-beginning 0)) + (save-match-data + (let* ((expr (match-string 1 tpl-net)) + (value + (progn + (setq expr (verilog-string-replace-matches "\\\\\"" "\"" nil nil expr)) + (setq expr (verilog-string-replace-matches "@" tpl-num nil nil expr)) + (prin1 (eval (car (read-from-string expr))) + (lambda (ch) ()))))) + (if (numberp value) (setq value (number-to-string value))) + value + )) + (substring tpl-net (match-end 0)))))) + ;; Replace @ and [] magic variables in final output + (setq tpl-net (verilog-string-replace-matches "@" tpl-num nil nil tpl-net)) + (setq tpl-net (verilog-string-replace-matches "\\[\\]" vl-bits nil nil tpl-net)) + ) + (indent-to indent-pt) + (insert "." port) + (indent-to verilog-auto-inst-column) + (insert "(" tpl-net "),") + (cond (tpl-ass + (indent-to (+ (if (< verilog-auto-inst-column 48) 24 16) + verilog-auto-inst-column)) + (insert " // Templated") + (when verilog-auto-inst-template-numbers + (insert " T" (int-to-string (nth 2 tpl-ass)) + " L" (int-to-string (nth 3 tpl-ass))))) + (for-star + (indent-to (+ (if (< verilog-auto-inst-column 48) 24 16) + verilog-auto-inst-column)) + (insert " // Implicit .\*"))) ;For some reason the . or * must be escaped... + (insert "\n"))) +;;(verilog-auto-inst-port (list "foo" "[5:0]") 10 (list (list "foo" "a@\"(% (+ @ 1) 4)\"a")) "3") +;;(x "incom[@\"(+ (* 8 @) 7)\":@\"(* 8 @)\"]") +;;(x ".out (outgo[@\"(concat (+ (* 8 @) 7) \\\":\\\" ( * 8 @))\"]));") + +(defun verilog-auto-inst-first () + "Insert , etc before first ever port in this instant, as part of \\[verilog-auto-inst]." + ;; Do we need a trailing comma? + ;; There maybe a ifdef or something similar before us. What a mess. Thus + ;; to avoid trouble we only insert on preceeding ) or *. + ;; Insert first port on new line + (insert "\n") ;; Must insert before search, so point will move forward if insert comma + (save-excursion + (verilog-re-search-backward "[^ \t\n\f]" nil nil) + (when (looking-at ")\\|\\*") ;; Generally don't insert, unless we are fairly sure + (forward-char 1) + (insert ",")))) + +(defun verilog-auto-star () + "Expand SystemVerilog .* pins, as part of \\[verilog-auto]. + +If `verilog-auto-star-expand' is set, .* pins are treated if they were +AUTOINST statements, otherwise they are ignored. For safety, Verilog-Mode +will also ignore any .* that are not last in your pin list (this prevents +it from deleting pins following the .* when it expands the AUTOINST.) + +On writing your file, unless `verilog-auto-star-save' is set, any +non-templated expanded pins will be removed. You may do this at any time +with \\[verilog-delete-auto-star-implicit]. + +If you are converting a module to use .* for the first time, you may wish +to use \\[verilog-inject-auto] and then replace the created AUTOINST with .*. + +See `verilog-auto-inst' for examples, templates, and more information." + (when (verilog-auto-star-safe) + (verilog-auto-inst))) + +(defun verilog-auto-inst () + "Expand AUTOINST statements, as part of \\[verilog-auto]. +Replace the pin connections to an instantiation with ones +automatically derived from the module header of the instantiated netlist. + +If `verilog-auto-star-expand' is set, also expand SystemVerilog .* ports, +and delete them before saving unless `verilog-auto-star-save' is set. +See `verilog-auto-star' for more information. + +Limitations: + Module names must be resolvable to filenames by adding a + `verilog-library-extensions', and being found in the same directory, or + by changing the variable `verilog-library-flags' or + `verilog-library-directories'. Macros `modname are translated through the + vh-{name} Emacs variable, if that is not found, it just ignores the `. + + In templates you must have one signal per line, ending in a ), or ));, + and have proper () nesting, including a final ); to end the template. + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + SystemVerilog multidimmensional input/output has only experimental support. + +For example, first take the submodule inst.v: + + module inst (o,i) + output [31:0] o; + input i; + wire [31:0] o = {32{i}}; + endmodule + +This is then used in a upper level module: + + module ex_inst (o,i) + output o; + input i; + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_inst (o,i) + output o; + input i; + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule + +Where the list of inputs and outputs came from the inst module. + +Exceptions: + + Unless you are instantiating a module multiple times, or the module is + something trivial like a adder, DO NOT CHANGE SIGNAL NAMES ACROSS HIERARCHY. + It just makes for unmaintainable code. To sanitize signal names, try + vrename from http://www.veripool.com + + When you need to violate this suggestion there are two ways to list + exceptions, placing them before the AUTOINST, or using templates. + + Any ports defined before the /*AUTOINST*/ are not included in the list of + automatics. This is similar to making a template as described below, but + is restricted to simple connections just like you normally make. Also note + that any signals before the AUTOINST will only be picked up by AUTOWIRE if + you have the appropriate // Input or // Output comment, and exactly the + same line formatting as AUTOINST itself uses. + + inst inst (// Inputs + .i (my_i_dont_mess_with_it), + /*AUTOINST*/ + // Outputs + .ov (ov[31:0])); + + +Templates: + + For multiple instantiations based upon a single template, create a + commented out template: + + /* instantiating_module_name AUTO_TEMPLATE ( + .sig3 (sigz[]), + ); + */ + + Templates go ABOVE the instantiation(s). When a instantiation is + expanded `verilog-mode' simply searches up for the closest template. + Thus you can have multiple templates for the same module, just alternate + between the template for a instantiation and the instantiation itself. + + The module name must be the same as the name of the module in the + instantiation name, and the code \"AUTO_TEMPLATE\" must be in these exact + words and capitalized. Only signals that must be different for each + instantiation need to be listed. + + Inside a template, a [] in a connection name (with nothing else inside + the brackets) will be replaced by the same bus subscript as it is being + connected to, or the [] will be removed if it is a single bit signal. + Generally it is a good idea to do this for all connections in a template, + as then they will work for any width signal, and with AUTOWIRE. See + PTL_BUS becoming PTL_BUSNEW below. + + If you have a complicated template, set `verilog-auto-inst-template-numbers' + to see which regexps are matching. Don't leave that mode set after + debugging is completed though, it will result in lots of extra differences + and merge conflicts. + + For example: + + /* psm_mas AUTO_TEMPLATE ( + .ptl_bus (ptl_busnew[]), + ); + */ + psm_mas ms2m (/*AUTOINST*/); + + Typing \\[verilog-auto] will make this into: + + psm_mas ms2m (/*AUTOINST*/ + // Outputs + .NotInTemplate (NotInTemplate), + .ptl_bus (ptl_busnew[3:0]), // Templated + .... + +@ Templates: + + It is common to instantiate a cell multiple times, so templates make it + trivial to substitute part of the cell name into the connection name. + + /* cell_type AUTO_TEMPLATE <optional \"REGEXP\"> ( + .sig1 (sigx[@]), + .sig2 (sigy[@\"(% (+ 1 @) 4)\"]), + ); + */ + + If no regular expression is provided immediately after the AUTO_TEMPLATE + keyword, then the @ character in any connection names will be replaced + with the instantiation number; the first digits found in the cell's + instantiation name. + + If a regular expression is provided, the @ character will be replaced + with the first \(\) grouping that matches against the cell name. Using a + regexp of \"\\([0-9]+\\)\" provides identical values for @ as when no + regexp is provided. If you use multiple layers of parenthesis, + \"test\\([^0-9]+\\)_\\([0-9]+\\)\" would replace @ with non-number + characters after test and before _, whereas + \"\\(test\\([a-z]+\\)_\\([0-9]+\\)\\)\" would replace @ with the entire + match. + + For example: + + /* psm_mas AUTO_TEMPLATE ( + .ptl_mapvalidx (ptl_mapvalid[@]), + .ptl_mapvalidp1x (ptl_mapvalid[@\"(% (+ 1 @) 4)\"]), + ); + */ + psm_mas ms2m (/*AUTOINST*/); + + Typing \\[verilog-auto] will make this into: + + psm_mas ms2m (/*AUTOINST*/ + // Outputs + .ptl_mapvalidx (ptl_mapvalid[2]), + .ptl_mapvalidp1x (ptl_mapvalid[3])); + + Note the @ character was replaced with the 2 from \"ms2m\". + + Alternatively, using a regular expression for @: + + /* psm_mas AUTO_TEMPLATE \"_\\([a-z]+\\)\" ( + .ptl_mapvalidx (@_ptl_mapvalid), + .ptl_mapvalidp1x (ptl_mapvalid_@), + ); + */ + psm_mas ms2_FOO (/*AUTOINST*/); + psm_mas ms2_BAR (/*AUTOINST*/); + + Typing \\[verilog-auto] will make this into: + + psm_mas ms2_FOO (/*AUTOINST*/ + // Outputs + .ptl_mapvalidx (FOO_ptl_mapvalid), + .ptl_mapvalidp1x (ptl_mapvalid_FOO)); + psm_mas ms2_BAR (/*AUTOINST*/ + // Outputs + .ptl_mapvalidx (BAR_ptl_mapvalid), + .ptl_mapvalidp1x (ptl_mapvalid_BAR)); + + +Regexp Templates: + + A template entry of the form + + .pci_req\\([0-9]+\\)_l (pci_req_jtag_[\\1]), + + will apply a Emacs style regular expression search for any port beginning + in pci_req followed by numbers and ending in _l and connecting that to + the pci_req_jtag_[] net, with the bus subscript coming from what matches + inside the first set of \\( \\). Thus pci_req2_l becomes pci_req_jtag_[2]. + + Since \\([0-9]+\\) is so common and ugly to read, a @ in the port name + does the same thing. (Note a @ in the connection/replacement text is + completely different -- still use \\1 there!) Thus this is the same as + the above template: + + .pci_req@_l (pci_req_jtag_[\\1]), + + Here's another example to remove the _l, useful when naming conventions + specify _ alone to mean active low. Note the use of [] to keep the bus + subscript: + + .\\(.*\\)_l (\\1_[]), + +Lisp Templates: + + First any regular expression template is expanded. + + If the syntax @\"( ... )\" is found in a connection, the expression in + quotes will be evaluated as a Lisp expression, with @ replaced by the + instantiation number. The MAPVALIDP1X example above would put @+1 modulo + 4 into the brackets. Quote all double-quotes inside the expression with + a leading backslash (\\\"). There are special variables defined that are + useful in these Lisp functions: + + vl-name Name portion of the input/output port + vl-bits Bus bits portion of the input/output port ('[2:0]') + vl-width Width of the input/output port ('3' for [2:0]) + May be a (...) expression if bits isn't a constant. + vl-dir Direction of the pin input/output/inout. + vl-cell-type Module name/type of the cell ('psm_mas') + vl-cell-name Instance name of the cell ('ms2m') + + Normal Lisp variables may be used in expressions. See + `verilog-read-defines' which can set vh-{definename} variables for use + here. Also, any comments of the form: + + /*AUTO_LISP(setq foo 1)*/ + + will evaluate any Lisp expression inside the parenthesis between the + beginning of the buffer and the point of the AUTOINST. This allows + functions to be defined or variables to be changed between instantiations. + + Note that when using lisp expressions errors may occur when @ is not a + number, you may need to use the standard Emacs Lisp functions + `number-to-string' and `string-to-number'. + + After the evaluation is completed, @ substitution and [] substitution + occur." + (save-excursion + ;; Find beginning + (let* ((pt (point)) + (for-star (save-excursion (backward-char 2) (looking-at "\\.\\*"))) + (indent-pt (save-excursion (verilog-backward-open-paren) + (1+ (current-column)))) + (verilog-auto-inst-column (max verilog-auto-inst-column + (+ 16 (* 8 (/ (+ indent-pt 7) 8))))) + (modi (verilog-modi-current)) + (vector-skip-list (unless verilog-auto-inst-vector + (verilog-modi-get-signals modi))) + submod submodi inst skip-pins tpl-list tpl-num did-first) + ;; Find module name that is instantiated + (setq submod (verilog-read-inst-module) + inst (verilog-read-inst-name) + vl-cell-type submod + vl-cell-name inst + skip-pins (aref (verilog-read-inst-pins) 0)) + + ;; Parse any AUTO_LISP() before here + (verilog-read-auto-lisp (point-min) pt) + + ;; Lookup position, etc of submodule + ;; Note this may raise an error + (when (setq submodi (verilog-modi-lookup submod t)) + ;; If there's a number in the instantiation, it may be a argument to the + ;; automatic variable instantiation program. + (let* ((tpl-info (verilog-read-auto-template submod)) + (tpl-regexp (aref tpl-info 0))) + (setq tpl-num (if (string-match tpl-regexp inst) + (match-string 1 inst) + "") + tpl-list (aref tpl-info 1))) + ;; Find submodule's signals and dump + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-outputs submodi) + skip-pins)) + (vl-dir "output")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Outputs\n") ;; Note these are searched for in verilog-read-sub-decls + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num for-star))) + sig-list))) + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-inouts submodi) + skip-pins)) + (vl-dir "inout")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Inouts\n") + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num for-star))) + sig-list))) + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-inputs submodi) + skip-pins)) + (vl-dir "input")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Inputs\n") + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num for-star))) + sig-list))) + ;; Kill extra semi + (save-excursion + (cond (did-first + (re-search-backward "," pt t) + (delete-char 1) + (insert ");") + (search-forward "\n") ;; Added by inst-port + (delete-backward-char 1) + (if (search-forward ")" nil t) ;; From user, moved up a line + (delete-backward-char 1)) + (if (search-forward ";" nil t) ;; Don't error if user had syntax error and forgot it + (delete-backward-char 1)) + ))) + )))) + +(defun verilog-auto-inst-param () + "Expand AUTOINSTPARAM statements, as part of \\[verilog-auto]. +Replace the parameter connections to an instantiation with ones +automatically derived from the module header of the instantiated netlist. + +See \\[verilog-auto-inst] for limitations, and templates to customize the +output. + +For example, first take the submodule inst.v: + + module inst (o,i) + parameter PAR; + endmodule + +This is then used in a upper level module: + + module ex_inst (o,i) + parameter PAR; + inst #(/*AUTOINSTPARAM*/) + inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_inst (o,i) + output o; + input i; + inst (/*AUTOINSTPARAM*/ + // Parameters + .PAR (PAR)); + inst (/*AUTOINST*/); + endmodule + +Where the list of parameter connections come from the inst module. + +Templates: + + You can customize the parameter connections using AUTO_TEMPLATEs, + just as you would with \\[verilog-auto-inst]." + (save-excursion + ;; Find beginning + (let* ((pt (point)) + (indent-pt (save-excursion (verilog-backward-open-paren) + (1+ (current-column)))) + (verilog-auto-inst-column (max verilog-auto-inst-column + (+ 16 (* 8 (/ (+ indent-pt 7) 8))))) + (modi (verilog-modi-current)) + (vector-skip-list (unless verilog-auto-inst-vector + (verilog-modi-get-signals modi))) + submod submodi inst skip-pins tpl-list tpl-num did-first) + ;; Find module name that is instantiated + (setq submod (save-excursion + ;; Get to the point where AUTOINST normally is to read the module + (verilog-re-search-forward-quick "[(;]" nil nil) + (verilog-read-inst-module)) + inst (save-excursion + ;; Get to the point where AUTOINST normally is to read the module + (verilog-re-search-forward-quick "[(;]" nil nil) + (verilog-read-inst-name)) + vl-cell-type submod + vl-cell-name inst + skip-pins (aref (verilog-read-inst-pins) 0)) + + ;; Parse any AUTO_LISP() before here + (verilog-read-auto-lisp (point-min) pt) + + ;; Lookup position, etc of submodule + ;; Note this may raise an error + (when (setq submodi (verilog-modi-lookup submod t)) + ;; If there's a number in the instantiation, it may be a argument to the + ;; automatic variable instantiation program. + (let* ((tpl-info (verilog-read-auto-template submod)) + (tpl-regexp (aref tpl-info 0))) + (setq tpl-num (if (string-match tpl-regexp inst) + (match-string 1 inst) + "") + tpl-list (aref tpl-info 1))) + ;; Find submodule's signals and dump + (let ((sig-list (verilog-signals-not-in + (verilog-modi-get-gparams submodi) + skip-pins)) + (vl-dir "parameter")) + (when sig-list + (when (not did-first) (verilog-auto-inst-first) (setq did-first t)) + (indent-to indent-pt) + (insert "// Parameters\n") ;; Note these are searched for in verilog-read-sub-decls + (mapcar (function (lambda (port) + (verilog-auto-inst-port port indent-pt tpl-list tpl-num nil))) + sig-list))) + ;; Kill extra semi + (save-excursion + (cond (did-first + (re-search-backward "," pt t) + (delete-char 1) + (insert ")") + (search-forward "\n") ;; Added by inst-port + (delete-backward-char 1) + (if (search-forward ")" nil t) ;; From user, moved up a line + (delete-backward-char 1)) + ))) + )))) + +(defun verilog-auto-reg () + "Expand AUTOREG statements, as part of \\[verilog-auto]. +Make reg statements for any output that isn't already declared, +and isn't a wire output from a block. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + This does NOT work on memories, declare those yourself. + +An example: + + module ex_reg (o,i) + output o; + input i; + /*AUTOREG*/ + always o = i; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_reg (o,i) + output o; + input i; + /*AUTOREG*/ + // Beginning of automatic regs (for this module's undeclared outputs) + reg o; + // End of automatics + always o = i; + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-outputs modi) + (append (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-assigns modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (forward-line 1) + (when sig-list + (verilog-insert-indent "// Beginning of automatic regs (for this module's undeclared outputs)\n") + (verilog-insert-definition sig-list "reg" indent-pt nil) + (verilog-modi-cache-add-regs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + ))) + +(defun verilog-auto-reg-input () + "Expand AUTOREGINPUT statements, as part of \\[verilog-auto]. +Make reg statements instantiation inputs that aren't already declared. +This is useful for making a top level shell for testing the module that is +to be instantiated. + +Limitations: + This ONLY detects inputs of AUTOINSTants (see `verilog-read-sub-decls'). + + This does NOT work on memories, declare those yourself. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_reg_input (o,i) + output o; + input i; + /*AUTOREGINPUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_reg_input (o,i) + output o; + input i; + /*AUTOREGINPUT*/ + // Beginning of automatic reg inputs (for undeclared ... + reg [31:0] iv; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .o (o[31:0]), + // Inputs + .iv (iv)); + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-combine-bus + (verilog-signals-not-in + (append (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-inouts modi)) + (verilog-modi-get-signals modi) + )))) + (forward-line 1) + (when sig-list + (verilog-insert-indent "// Beginning of automatic reg inputs (for undeclared instantiated-module inputs)\n") + (verilog-insert-definition sig-list "reg" indent-pt nil) + (verilog-modi-cache-add-regs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + ))) + +(defun verilog-auto-wire () + "Expand AUTOWIRE statements, as part of \\[verilog-auto]. +Make wire statements for instantiations outputs that aren't +already declared. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'), + and all busses must have widths, such as those from AUTOINST, or using [] + in AUTO_TEMPLATEs. + + This does NOT work on memories or SystemVerilog .name connections, + declare those yourself. + + Verilog-mode will add \"Couldn't Merge\" comments to signals it cannot + determine how to bus together. This occurs when you have ports with + non-numeric or non-sequential bus subscripts. If Verilog-Mode + mis-guessed, you'll have to declare them yourself. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_wire (o,i) + output o; + input i; + /*AUTOWIRE*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_wire (o,i) + output o; + input i; + /*AUTOWIRE*/ + // Beginning of automatic wires + wire [31:0] ov; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + wire o = | ov; + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-combine-bus + (verilog-signals-not-in + (append (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi)) + (verilog-modi-get-signals modi) + )))) + (forward-line 1) + (when sig-list + (verilog-insert-indent "// Beginning of automatic wires (for undeclared instantiated-module outputs)\n") + (verilog-insert-definition sig-list "wire" indent-pt nil) + (verilog-modi-cache-add-wires modi sig-list) + (verilog-insert-indent "// End of automatics\n") + (when nil ;; Too slow on huge modules, plus makes everyone's module change + (beginning-of-line) + (setq pnt (point)) + (verilog-pretty-declarations) + (goto-char pnt) + (verilog-pretty-expr "//"))) + ))) + +(defun verilog-auto-output () + "Expand AUTOOUTPUT statements, as part of \\[verilog-auto]. +Make output statements for any output signal from an /*AUTOINST*/ that +isn't a input to another AUTOINST. This is useful for modules which +only instantiate other modules. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + If any concatenation, or bit-subscripts are missing in the AUTOINSTant's + instantiation, all bets are off. (For example due to a AUTO_TEMPLATE). + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + Signals matching `verilog-auto-output-ignore-regexp' are not included. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_output (ov,i) + input i; + /*AUTOOUTPUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_output (ov,i) + input i; + /*AUTOOUTPUT*/ + // Beginning of automatic outputs (from unused autoinst outputs) + output [31:0] ov; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-sub-outputs modi) + (append (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-output-ignore-regexp)) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic outputs (from unused autoinst outputs)\n") + (verilog-insert-definition sig-list "output" indent-pt v2k) + (verilog-modi-cache-add-outputs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-output-every () + "Expand AUTOOUTPUTEVERY statements, as part of \\[verilog-auto]. +Make output statements for any signals that aren't primary inputs or +outputs already. This makes every signal in the design a output. This is +useful to get Synopsys to preserve every signal in the design, since it +won't optimize away the outputs. + +An example: + + module ex_output_every (o,i,tempa,tempb) + output o; + input i; + /*AUTOOUTPUTEVERY*/ + wire tempa = i; + wire tempb = tempa; + wire o = tempb; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_output_every (o,i,tempa,tempb) + output o; + input i; + /*AUTOOUTPUTEVERY*/ + // Beginning of automatic outputs (every signal) + output tempb; + output tempa; + // End of automatics + wire tempa = i; + wire tempb = tempa; + wire o = tempb; + endmodule" + (save-excursion + ;;Point must be at insertion point + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-combine-bus + (verilog-signals-not-in + (verilog-modi-get-signals modi) + (verilog-modi-get-ports modi) + )))) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic outputs (every signal)\n") + (verilog-insert-definition sig-list "output" indent-pt v2k) + (verilog-modi-cache-add-outputs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-input () + "Expand AUTOINPUT statements, as part of \\[verilog-auto]. +Make input statements for any input signal into an /*AUTOINST*/ that +isn't declared elsewhere inside the module. This is useful for modules which +only instantiate other modules. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + If any concatenation, or bit-subscripts are missing in the AUTOINSTant's + instantiation, all bets are off. (For example due to a AUTO_TEMPLATE). + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + Signals matching `verilog-auto-input-ignore-regexp' are not included. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_input (ov,i) + output [31:0] ov; + /*AUTOINPUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_input (ov,i) + output [31:0] ov; + /*AUTOINPUT*/ + // Beginning of automatic inputs (from unused autoinst inputs) + input i; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Outputs + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule" + (save-excursion + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-sub-inputs modi) + (append (verilog-modi-get-inputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-input-ignore-regexp)) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic inputs (from unused autoinst inputs)\n") + (verilog-insert-definition sig-list "input" indent-pt v2k) + (verilog-modi-cache-add-inputs modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-inout () + "Expand AUTOINOUT statements, as part of \\[verilog-auto]. +Make inout statements for any inout signal in an /*AUTOINST*/ that +isn't declared elsewhere inside the module. + +Limitations: + This ONLY detects outputs of AUTOINSTants (see `verilog-read-sub-decls'). + + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + If any concatenation, or bit-subscripts are missing in the AUTOINSTant's + instantiation, all bets are off. (For example due to a AUTO_TEMPLATE). + + Typedefs must match `verilog-typedef-regexp', which is disabled by default. + + Signals matching `verilog-auto-inout-ignore-regexp' are not included. + +An example (see `verilog-auto-inst' for what else is going on here): + + module ex_inout (ov,i) + input i; + /*AUTOINOUT*/ + inst inst (/*AUTOINST*/); + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_inout (ov,i) + input i; + /*AUTOINOUT*/ + // Beginning of automatic inouts (from unused autoinst inouts) + inout [31:0] ov; // From inst of inst.v + // End of automatics + inst inst (/*AUTOINST*/ + // Inouts + .ov (ov[31:0]), + // Inputs + .i (i)); + endmodule" + (save-excursion + ;; Point must be at insertion point. + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-sub-inouts modi) + (append (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi) + (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-outputs modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-inout-ignore-regexp)) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when sig-list + (verilog-insert-indent "// Beginning of automatic inouts (from unused autoinst inouts)\n") + (verilog-insert-definition sig-list "inout" indent-pt v2k) + (verilog-modi-cache-add-inouts modi sig-list) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))) + +(defun verilog-auto-inout-module () + "Expand AUTOINOUTMODULE statements, as part of \\[verilog-auto]. +Take input/output/inout statements from the specified module and insert +into the current module. This is useful for making null templates and +shell modules which need to have identical I/O with another module. Any +I/O which are already defined in this module will not be redefined. + +Limitations: + If placed inside the parenthesis of a module declaration, it creates + Verilog 2001 style, else uses Verilog 1995 style. + + Concatenation and outputting partial busses is not supported. + + Module names must be resolvable to filenames. See `verilog-auto-inst'. + + Signals are not inserted in the same order as in the original module, + though they will appear to be in the same order to a AUTOINST + instantiating either module. + +An example: + + module ex_shell (/*AUTOARG*/) + /*AUTOINOUTMODULE(\"ex_main\")*/ + endmodule + + module ex_main (i,o,io) + input i; + output o; + inout io; + endmodule + +Typing \\[verilog-auto] will make this into: + + module ex_shell (/*AUTOARG*/i,o,io) + /*AUTOINOUTMODULE(\"ex_main\")*/ + // Beginning of automatic in/out/inouts (from specific module) + input i; + output o; + inout io; + // End of automatics + endmodule" + (save-excursion + (let* ((submod (car (verilog-read-auto-params 1))) submodi) + ;; Lookup position, etc of co-module + ;; Note this may raise an error + (when (setq submodi (verilog-modi-lookup submod t)) + (let* ((indent-pt (current-indentation)) + (v2k (verilog-in-paren)) + (modi (verilog-modi-current)) + (sig-list-i (verilog-signals-not-in + (verilog-modi-get-inputs submodi) + (append (verilog-modi-get-inputs modi)))) + (sig-list-o (verilog-signals-not-in + (verilog-modi-get-outputs submodi) + (append (verilog-modi-get-outputs modi)))) + (sig-list-io (verilog-signals-not-in + (verilog-modi-get-inouts submodi) + (append (verilog-modi-get-inouts modi))))) + (forward-line 1) + (when v2k (verilog-repair-open-comma)) + (when (or sig-list-i sig-list-o sig-list-io) + (verilog-insert-indent "// Beginning of automatic in/out/inouts (from specific module)\n") + ;; Don't sort them so a upper AUTOINST will match the main module + (verilog-insert-definition sig-list-o "output" indent-pt v2k t) + (verilog-insert-definition sig-list-io "inout" indent-pt v2k t) + (verilog-insert-definition sig-list-i "input" indent-pt v2k t) + (verilog-modi-cache-add-inputs modi sig-list-i) + (verilog-modi-cache-add-outputs modi sig-list-o) + (verilog-modi-cache-add-inouts modi sig-list-io) + (verilog-insert-indent "// End of automatics\n")) + (when v2k (verilog-repair-close-comma)) + ))))) + +(defun verilog-auto-sense-sigs (modi presense-sigs) + "Return list of signals for current AUTOSENSE block." + (let* ((sigss (verilog-read-always-signals)) + (sig-list (verilog-signals-not-params + (verilog-signals-not-in (verilog-alw-get-inputs sigss) + (append (and (not verilog-auto-sense-include-inputs) + (verilog-alw-get-outputs sigss)) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + presense-sigs))))) + sig-list)) + +(defun verilog-auto-sense () + "Expand AUTOSENSE statements, as part of \\[verilog-auto]. +Replace the always (/*AUTOSENSE*/) sensitivity list (/*AS*/ for short) +with one automatically derived from all inputs declared in the always +statement. Signals that are generated within the same always block are NOT +placed into the sensitivity list (see `verilog-auto-sense-include-inputs'). +Long lines are split based on the `fill-column', see \\[set-fill-column]. + +Limitations: + Verilog does not allow memories (multidimensional arrays) in sensitivity + lists. AUTOSENSE will thus exclude them, and add a /*memory or*/ comment. + +Constant signals: + AUTOSENSE cannot always determine if a `define is a constant or a signal + (it could be in a include file for example). If a `define or other signal + is put into the AUTOSENSE list and is not desired, use the AUTO_CONSTANT + declaration anywhere in the module (parenthesis are required): + + /* AUTO_CONSTANT ( `this_is_really_constant_dont_autosense_it ) */ + + Better yet, use a parameter, which will be understood to be constant + automatically. + +OOps! + If AUTOSENSE makes a mistake, please report it. (First try putting + a begin/end after your always!) As a workaround, if a signal that + shouldn't be in the sensitivity list was, use the AUTO_CONSTANT above. + If a signal should be in the sensitivity list wasn't, placing it before + the /*AUTOSENSE*/ comment will prevent it from being deleted when the + autos are updated (or added if it occurs there already). + +An example: + + always @ (/*AUTOSENSE*/) begin + /* AUTO_CONSTANT (`constant) */ + outin = ina | inb | `constant; + out = outin; + end + +Typing \\[verilog-auto] will make this into: + + always @ (/*AUTOSENSE*/ina or inb) begin + /* AUTO_CONSTANT (`constant) */ + outin = ina | inb | `constant; + out = outin; + end" + (save-excursion + ;; Find beginning + (let* ((start-pt (save-excursion + (verilog-re-search-backward "(" nil t) + (point))) + (indent-pt (save-excursion + (or (and (goto-char start-pt) (1+ (current-column))) + (current-indentation)))) + (modi (verilog-modi-current)) + (sig-memories (verilog-signals-memory + (append + (verilog-modi-get-regs modi) + (verilog-modi-get-wires modi)))) + sig-list not-first presense-sigs) + ;; Read signals in always, eliminate outputs from sense list + (setq presense-sigs (verilog-signals-from-signame + (save-excursion + (verilog-read-signals start-pt (point))))) + (setq sig-list (verilog-auto-sense-sigs modi presense-sigs)) + (when sig-memories + (let ((tlen (length sig-list))) + (setq sig-list (verilog-signals-not-in sig-list sig-memories)) + (if (not (eq tlen (length sig-list))) (insert " /*memory or*/ ")))) + (if (and presense-sigs ;; Add a "or" if not "(.... or /*AUTOSENSE*/" + (save-excursion (goto-char (point)) + (verilog-re-search-backward "[a-zA-Z0-9$_.%`]+" start-pt t) + (verilog-re-search-backward "\\s-" start-pt t) + (while (looking-at "\\s-`endif") + (verilog-re-search-backward "[a-zA-Z0-9$_.%`]+" start-pt t) + (verilog-re-search-backward "\\s-" start-pt t)) + (not (looking-at "\\s-or\\b")))) + (setq not-first t)) + (setq sig-list (sort sig-list `verilog-signals-sort-compare)) + (while sig-list + (cond ((> (+ 4 (current-column) (length (verilog-sig-name (car sig-list)))) fill-column) ;+4 for width of or + (insert "\n") + (indent-to indent-pt) + (if not-first (insert "or "))) + (not-first (insert " or "))) + (insert (verilog-sig-name (car sig-list))) + (setq sig-list (cdr sig-list) + not-first t)) + ))) + +(defun verilog-auto-reset () + "Expand AUTORESET statements, as part of \\[verilog-auto]. +Replace the /*AUTORESET*/ comment with code to initialize all +registers set elsewhere in the always block. + +Limitations: + AUTORESET will not clear memories. + + AUTORESET uses <= if there are any <= in the block, else it uses =. + +/*AUTORESET*/ presumes that any signals mentioned between the previous +begin/case/if statement and the AUTORESET comment are being reset manually +and should not be automatically reset. This includes omitting any signals +used on the right hand side of assignments. + +By default, AUTORESET will include the width of the signal in the autos, +this is a recent change. To control this behavior, see +`verilog-auto-reset-widths'. + +AUTORESET ties signals to deasserted, which is presumed to be zero. +Signals that match `verilog-active-low-regexp' will be deasserted by tieing +them to a one. + +An example: + + always @(posedge clk or negedge reset_l) begin + if (!reset_l) begin + c <= 1; + /*AUTORESET*/ + end + else begin + a <= in_a; + b <= in_b; + c <= in_c; + end + end + +Typing \\[verilog-auto] will make this into: + + always @(posedge core_clk or negedge reset_l) begin + if (!reset_l) begin + c <= 1; + /*AUTORESET*/ + // Beginning of autoreset for uninitialized flops + a <= 0; + b <= 0; + // End of automatics + end + else begin + a <= in_a; + b <= in_b; + c <= in_c; + end + end" + + (interactive) + (save-excursion + ;; Find beginning + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (all-list (verilog-modi-get-signals modi)) + sigss sig-list prereset-sigs assignment-str) + ;; Read signals in always, eliminate outputs from reset list + (setq prereset-sigs (verilog-signals-from-signame + (save-excursion + (verilog-read-signals + (save-excursion + (verilog-re-search-backward "\\(@\\|\\<begin\\>\\|\\<if\\>\\|\\<case\\>\\)" nil t) + (point)) + (point))))) + (save-excursion + (verilog-re-search-backward "@" nil t) + (setq sigss (verilog-read-always-signals))) + (setq assignment-str (if (verilog-alw-get-uses-delayed sigss) + (concat " <= " verilog-assignment-delay) + " = ")) + (setq sig-list (verilog-signals-not-in (verilog-alw-get-outputs sigss) + prereset-sigs)) + (setq sig-list (sort sig-list `verilog-signals-sort-compare)) + (when sig-list + (insert "\n"); + (indent-to indent-pt) + (insert "// Beginning of autoreset for uninitialized flops\n"); + (indent-to indent-pt) + (while sig-list + (let ((sig (or (assoc (verilog-sig-name (car sig-list)) all-list) ;; As sig-list has no widths + (car sig-list)))) + (insert (verilog-sig-name sig) + assignment-str + (verilog-sig-tieoff sig (not verilog-auto-reset-widths)) + ";\n") + (indent-to indent-pt) + (setq sig-list (cdr sig-list)))) + (insert "// End of automatics")) + ))) + +(defun verilog-auto-tieoff () + "Expand AUTOTIEOFF statements, as part of \\[verilog-auto]. +Replace the /*AUTOTIEOFF*/ comment with code to wire-tie all unused output +signals to deasserted. + +/*AUTOTIEOFF*/ is used to make stub modules; modules that have the same +input/output list as another module, but no internals. Specifically, it +finds all outputs in the module, and if that input is not otherwise declared +as a register or wire, creates a tieoff. + +AUTORESET ties signals to deasserted, which is presumed to be zero. +Signals that match `verilog-active-low-regexp' will be deasserted by tieing +them to a one. + +An example of making a stub for another module: + + module FooStub (/*AUTOINST*/); + /*AUTOINOUTMODULE(\"Foo\")*/ + /*AUTOTIEOFF*/ + // verilator lint_off UNUSED + wire _unused_ok = &{1'b0, + /*AUTOUNUSED*/ + 1'b0}; + // verilator lint_on UNUSED + endmodule + +Typing \\[verilog-auto] will make this into: + + module FooStub (/*AUTOINST*/...); + /*AUTOINOUTMODULE(\"Foo\")*/ + // Beginning of autotieoff + output [2:0] foo; + // End of automatics + + /*AUTOTIEOFF*/ + // Beginning of autotieoff + wire [2:0] foo = 3'b0; + // End of automatics + ... + endmodule" + (interactive) + (save-excursion + ;; Find beginning + (let* ((indent-pt (current-indentation)) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (verilog-modi-get-outputs modi) + (append (verilog-modi-get-wires modi) + (verilog-modi-get-regs modi) + (verilog-modi-get-assigns modi) + (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi) + (verilog-modi-get-sub-outputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (when sig-list + (forward-line 1) + (verilog-insert-indent "// Beginning of automatic tieoffs (for this module's unterminated outputs)\n") + (setq sig-list (sort (copy-alist sig-list) `verilog-signals-sort-compare)) + (verilog-modi-cache-add-wires modi sig-list) ; Before we trash list + (while sig-list + (let ((sig (car sig-list))) + (verilog-insert-one-definition sig "wire" indent-pt) + (indent-to (max 48 (+ indent-pt 40))) + (insert "= " (verilog-sig-tieoff sig) + ";\n") + (setq sig-list (cdr sig-list)))) + (verilog-insert-indent "// End of automatics\n") + )))) + +(defun verilog-auto-unused () + "Expand AUTOUNUSED statements, as part of \\[verilog-auto]. +Replace the /*AUTOUNUSED*/ comment with a comma separated list of all unused +input and inout signals. + +/*AUTOUNUSED*/ is used to make stub modules; modules that have the same +input/output list as another module, but no internals. Specifically, it +finds all inputs and inouts in the module, and if that input is not otherwise +used, adds it to a comma separated list. + +The comma separated list is intended to be used to create a _unused_ok +signal. Using the exact name \"_unused_ok\" for name of the temporary +signal is recommended as it will insure maximum forward compatibility, it +also makes lint warnings easy to understand; ignore any unused warnings +with \"unused\" in the signal name. + +To reduce simulation time, the _unused_ok signal should be forced to a +constant to prevent wiggling. The easiest thing to do is use a +reduction-and with 1'b0 as shown. + +This way all unused signals are in one place, making it convenient to add +your tool's specific pragmas around the assignment to disable any unused +warnings. + +You can add signals you do not want included in AUTOUNUSED with +`verilog-auto-unused-ignore-regexp'. + +An example of making a stub for another module: + + module FooStub (/*AUTOINST*/); + /*AUTOINOUTMODULE(\"Foo\")*/ + /*AUTOTIEOFF*/ + // verilator lint_off UNUSED + wire _unused_ok = &{1'b0, + /*AUTOUNUSED*/ + 1'b0}; + // verilator lint_on UNUSED + endmodule + +Typing \\[verilog-auto] will make this into: + + ... + // verilator lint_off UNUSED + wire _unused_ok = &{1'b0, + /*AUTOUNUSED*/ + // Beginning of automatics + unused_input_a, + unused_input_b, + unused_input_c, + // End of automatics + 1'b0}; + // verilator lint_on UNUSED + endmodule" + (interactive) + (save-excursion + ;; Find beginning + (let* ((indent-pt (progn (search-backward "/*") (current-column))) + (modi (verilog-modi-current)) + (sig-list (verilog-signals-not-in + (append (verilog-modi-get-inputs modi) + (verilog-modi-get-inouts modi)) + (append (verilog-modi-get-sub-inputs modi) + (verilog-modi-get-sub-inouts modi) + )))) + (setq sig-list (verilog-signals-not-matching-regexp + sig-list verilog-auto-unused-ignore-regexp)) + (when sig-list + (forward-line 1) + (verilog-insert-indent "// Beginning of automatic unused inputs\n") + (setq sig-list (sort (copy-alist sig-list) `verilog-signals-sort-compare)) + (while sig-list + (let ((sig (car sig-list))) + (indent-to indent-pt) + (insert (verilog-sig-name sig) ",\n") + (setq sig-list (cdr sig-list)))) + (verilog-insert-indent "// End of automatics\n") + )))) + +(defun verilog-enum-ascii (signm elim-regexp) + "Convert a enum name SIGNM to a ascii string for insertion. +Remove user provided prefix ELIM-REGEXP." + (or elim-regexp (setq elim-regexp "_ DONT MATCH IT_")) + (let ((case-fold-search t)) + ;; All upper becomes all lower for readability + (downcase (verilog-string-replace-matches elim-regexp "" nil nil signm)))) + +(defun verilog-auto-ascii-enum () + "Expand AUTOASCIIENUM statements, as part of \\[verilog-auto]. +Create a register to contain the ASCII decode of a enumerated signal type. +This will allow trace viewers to show the ASCII name of states. + +First, parameters are built into a enumeration using the synopsys enum +comment. The comment must be between the keyword and the symbol. +(Annoying, but that's what Synopsys's dc_shell FSM reader requires.) + +Next, registers which that enum applies to are also tagged with the same +enum. Synopsys also suggests labeling state vectors, but `verilog-mode' +doesn't care. + +Finally, a AUTOASCIIENUM command is used. + + The first parameter is the name of the signal to be decoded. + + The second parameter is the name to store the ASCII code into. For the + signal foo, I suggest the name _foo__ascii, where the leading _ indicates + a signal that is just for simulation, and the magic characters _ascii + tell viewers like Dinotrace to display in ASCII format. + + The final optional parameter is a string which will be removed from the + state names. + +An example: + + //== State enumeration + parameter [2:0] // synopsys enum state_info + SM_IDLE = 3'b000, + SM_SEND = 3'b001, + SM_WAIT1 = 3'b010; + //== State variables + reg [2:0] /* synopsys enum state_info */ + state_r; /* synopsys state_vector state_r */ + reg [2:0] /* synopsys enum state_info */ + state_e1; + + //== ASCII state decoding + + /*AUTOASCIIENUM(\"state_r\", \"state_ascii_r\", \"SM_\")*/ + +Typing \\[verilog-auto] will make this into: + + ... same front matter ... + + /*AUTOASCIIENUM(\"state_r\", \"state_ascii_r\", \"SM_\")*/ + // Beginning of automatic ASCII enum decoding + reg [39:0] state_ascii_r; // Decode of state_r + always @(state_r) begin + case ({state_r}) + SM_IDLE: state_ascii_r = \"idle \"; + SM_SEND: state_ascii_r = \"send \"; + SM_WAIT1: state_ascii_r = \"wait1\"; + default: state_ascii_r = \"%Erro\"; + endcase + end + // End of automatics" + (save-excursion + (let* ((params (verilog-read-auto-params 2 3)) + (undecode-name (nth 0 params)) + (ascii-name (nth 1 params)) + (elim-regexp (nth 2 params)) + ;; + (indent-pt (current-indentation)) + (modi (verilog-modi-current)) + ;; + (sig-list-consts (append (verilog-modi-get-consts modi) + (verilog-modi-get-gparams modi))) + (sig-list-all (append (verilog-modi-get-regs modi) + (verilog-modi-get-outputs modi) + (verilog-modi-get-inouts modi) + (verilog-modi-get-inputs modi) + (verilog-modi-get-wires modi))) + ;; + (undecode-sig (or (assoc undecode-name sig-list-all) + (error "%s: Signal %s not found in design" (verilog-point-text) undecode-name))) + (undecode-enum (or (verilog-sig-enum undecode-sig) + (error "%s: Signal %s does not have a enum tag" (verilog-point-text) undecode-name))) + ;; + (enum-sigs (or (verilog-signals-matching-enum sig-list-consts undecode-enum) + (error "%s: No state definitions for %s" (verilog-point-text) undecode-enum))) + ;; + (enum-chars 0) + (ascii-chars 0)) + ;; + ;; Find number of ascii chars needed + (let ((tmp-sigs enum-sigs)) + (while tmp-sigs + (setq enum-chars (max enum-chars (length (verilog-sig-name (car tmp-sigs)))) + ascii-chars (max ascii-chars (length (verilog-enum-ascii + (verilog-sig-name (car tmp-sigs)) + elim-regexp))) + tmp-sigs (cdr tmp-sigs)))) + ;; + (forward-line 1) + (verilog-insert-indent "// Beginning of automatic ASCII enum decoding\n") + (let ((decode-sig-list (list (list ascii-name (format "[%d:0]" (- (* ascii-chars 8) 1)) + (concat "Decode of " undecode-name) nil nil)))) + (verilog-insert-definition decode-sig-list "reg" indent-pt nil) + (verilog-modi-cache-add-regs modi decode-sig-list)) + ;; + (verilog-insert-indent "always @(" undecode-name ") begin\n") + (setq indent-pt (+ indent-pt verilog-indent-level)) + (indent-to indent-pt) + (insert "case ({" undecode-name "})\n") + (setq indent-pt (+ indent-pt verilog-case-indent)) + ;; + (let ((tmp-sigs enum-sigs) + (chrfmt (format "%%-%ds %s = \"%%-%ds\";\n" (1+ (max 8 enum-chars)) + ascii-name ascii-chars)) + (errname (substring "%Error" 0 (min 6 ascii-chars)))) + (while tmp-sigs + (verilog-insert-indent + (format chrfmt (concat (verilog-sig-name (car tmp-sigs)) ":") + (verilog-enum-ascii (verilog-sig-name (car tmp-sigs)) + elim-regexp))) + (setq tmp-sigs (cdr tmp-sigs))) + (verilog-insert-indent (format chrfmt "default:" errname))) + ;; + (setq indent-pt (- indent-pt verilog-case-indent)) + (verilog-insert-indent "endcase\n") + (setq indent-pt (- indent-pt verilog-indent-level)) + (verilog-insert-indent "end\n" + "// End of automatics\n") + ))) + +(defun verilog-auto-templated-rel () + "Replace Templated relative line numbers with absolute line numbers. +Internal use only. This hacks around the line numbers in AUTOINST Templates +being different from the final output's line numbering." + (let ((templateno 0) (template-line (list 0))) + ;; Find line number each template is on + (goto-char (point-min)) + (while (search-forward "AUTO_TEMPLATE" nil t) + (setq templateno (1+ templateno)) + (setq template-line (cons (count-lines (point-min) (point)) template-line))) + (setq template-line (nreverse template-line)) + ;; Replace T# L# with absolute line number + (goto-char (point-min)) + (while (re-search-forward " Templated T\\([0-9]+\\) L\\([0-9]+\\)" nil t) + (replace-match (concat " Templated " + (int-to-string (+ (nth (string-to-int (match-string 1)) + template-line) + (string-to-int (match-string 2))))) + t t)))) + + +;; +;; Auto top level +;; + +(defun verilog-auto (&optional inject) ; Use verilog-inject-auto instead of passing a arg + "Expand AUTO statements. +Look for any /*AUTO...*/ commands in the code, as used in +instantiations or argument headers. Update the list of signals +following the /*AUTO...*/ command. + +Use \\[verilog-delete-auto] to remove the AUTOs. + +Use \\[verilog-inject-auto] to insert AUTOs for the first time. + +Use \\[verilog-faq] for a pointer to frequently asked questions. + +The hooks `verilog-before-auto-hook' and `verilog-auto-hook' are +called before and after this function, respectively. + +For example: + module (/*AUTOARG*/) + /*AUTOINPUT*/ + /*AUTOOUTPUT*/ + /*AUTOWIRE*/ + /*AUTOREG*/ + somesub sub #(/*AUTOINSTPARAM*/) (/*AUTOINST*/); + +You can also update the AUTOs from the shell using: + emacs --batch <filenames.v> -f verilog-batch-auto +Or fix indentation with: + emacs --batch <filenames.v> -f verilog-batch-indent +Likewise, you can delete or inject AUTOs with: + emacs --batch <filenames.v> -f verilog-batch-delete-auto + emacs --batch <filenames.v> -f verilog-batch-inject-auto + +Using \\[describe-function], see also: + `verilog-auto-arg' for AUTOARG module instantiations + `verilog-auto-ascii-enum' for AUTOASCIIENUM enumeration decoding + `verilog-auto-inout-module' for AUTOINOUTMODULE copying i/o from elsewhere + `verilog-auto-inout' for AUTOINOUT making hierarchy inouts + `verilog-auto-input' for AUTOINPUT making hierarchy inputs + `verilog-auto-inst' for AUTOINST instantiation pins + `verilog-auto-star' for AUTOINST .* SystemVerilog pins + `verilog-auto-inst-param' for AUTOINSTPARAM instantiation params + `verilog-auto-output' for AUTOOUTPUT making hierarchy outputs + `verilog-auto-output-every' for AUTOOUTPUTEVERY making all outputs + `verilog-auto-reg' for AUTOREG registers + `verilog-auto-reg-input' for AUTOREGINPUT instantiation registers + `verilog-auto-reset' for AUTORESET flop resets + `verilog-auto-sense' for AUTOSENSE always sensitivity lists + `verilog-auto-tieoff' for AUTOTIEOFF output tieoffs + `verilog-auto-unused' for AUTOUNUSED unused inputs/inouts + `verilog-auto-wire' for AUTOWIRE instantiation wires + + `verilog-read-defines' for reading `define values + `verilog-read-includes' for reading `includes + +If you have bugs with these autos, try contacting the AUTOAUTHOR +Wilson Snyder (wsnyder@wsnyder.org), and/or see http://www.veripool.com." + (interactive) + (unless noninteractive (message "Updating AUTOs...")) + (if (featurep 'dinotrace) + (dinotrace-unannotate-all)) + (let ((oldbuf (if (not (buffer-modified-p)) + (buffer-string))) + ;; Before version 20, match-string with font-lock returns a + ;; vector that is not equal to the string. IE if on "input" + ;; nil==(equal "input" (progn (looking-at "input") (match-string 0))) + (fontlocked (when (and (boundp 'font-lock-mode) + font-lock-mode) + (font-lock-mode nil) + t))) + (unwind-protect + (save-excursion + ;; If we're not in verilog-mode, change syntax table so parsing works right + (unless (eq major-mode `verilog-mode) (verilog-mode)) + ;; Allow user to customize + (run-hooks 'verilog-before-auto-hook) + ;; Try to save the user from needing to revert-file to reread file local-variables + (verilog-auto-reeval-locals) + (verilog-read-auto-lisp (point-min) (point-max)) + (verilog-getopt-flags) + ;; These two may seem obvious to do always, but on large includes it can be way too slow + (when verilog-auto-read-includes + (verilog-read-includes) + (verilog-read-defines nil nil t)) + ;; This particular ordering is important + ;; INST: Lower modules correct, no internal dependencies, FIRST + (verilog-preserve-cache + ;; Clear existing autos else we'll be screwed by existing ones + (verilog-delete-auto) + ;; Injection if appropriate + (when inject + (verilog-inject-inst) + (verilog-inject-sense) + (verilog-inject-arg)) + ;; + (verilog-auto-search-do "/*AUTOINSTPARAM*/" 'verilog-auto-inst-param) + (verilog-auto-search-do "/*AUTOINST*/" 'verilog-auto-inst) + (verilog-auto-search-do ".*" 'verilog-auto-star) + ;; Doesn't matter when done, but combine it with a common changer + (verilog-auto-re-search-do "/\\*\\(AUTOSENSE\\|AS\\)\\*/" 'verilog-auto-sense) + (verilog-auto-re-search-do "/\\*AUTORESET\\*/" 'verilog-auto-reset) + ;; Must be done before autoin/out as creates a reg + (verilog-auto-re-search-do "/\\*AUTOASCIIENUM([^)]*)\\*/" 'verilog-auto-ascii-enum) + ;; + ;; first in/outs from other files + (verilog-auto-re-search-do "/\\*AUTOINOUTMODULE([^)]*)\\*/" 'verilog-auto-inout-module) + ;; next in/outs which need previous sucked inputs first + (verilog-auto-search-do "/*AUTOOUTPUT*/" 'verilog-auto-output) + (verilog-auto-search-do "/*AUTOINPUT*/" 'verilog-auto-input) + (verilog-auto-search-do "/*AUTOINOUT*/" 'verilog-auto-inout) + ;; Then tie off those in/outs + (verilog-auto-search-do "/*AUTOTIEOFF*/" 'verilog-auto-tieoff) + ;; Wires/regs must be after inputs/outputs + (verilog-auto-search-do "/*AUTOWIRE*/" 'verilog-auto-wire) + (verilog-auto-search-do "/*AUTOREG*/" 'verilog-auto-reg) + (verilog-auto-search-do "/*AUTOREGINPUT*/" 'verilog-auto-reg-input) + ;; outputevery needs AUTOOUTPUTs done first + (verilog-auto-search-do "/*AUTOOUTPUTEVERY*/" 'verilog-auto-output-every) + ;; After we've created all new variables + (verilog-auto-search-do "/*AUTOUNUSED*/" 'verilog-auto-unused) + ;; Must be after all inputs outputs are generated + (verilog-auto-search-do "/*AUTOARG*/" 'verilog-auto-arg) + ;; Fix line numbers (comments only) + (verilog-auto-templated-rel) + ) + ;; + (run-hooks 'verilog-auto-hook) + ;; + (set (make-local-variable 'verilog-auto-update-tick) (buffer-modified-tick)) + ;; + ;; If end result is same as when started, clear modified flag + (cond ((and oldbuf (equal oldbuf (buffer-string))) + (set-buffer-modified-p nil) + (unless noninteractive (message "Updating AUTOs...done (no changes)"))) + (t (unless noninteractive (message "Updating AUTOs...done"))))) + ;; Unwind forms + (progn + ;; Restore font-lock + (when fontlocked (font-lock-mode t))) + ))) + + +;; +;; Skeleton based code insertion +;; +(defvar verilog-template-map nil + "Keymap used in Verilog mode for smart template operations.") + +(let ((verilog-mp (make-sparse-keymap))) + (define-key verilog-mp "a" 'verilog-sk-always) + (define-key verilog-mp "b" 'verilog-sk-begin) + (define-key verilog-mp "c" 'verilog-sk-case) + (define-key verilog-mp "f" 'verilog-sk-for) + (define-key verilog-mp "g" 'verilog-sk-generate) + (define-key verilog-mp "h" 'verilog-sk-header) + (define-key verilog-mp "i" 'verilog-sk-initial) + (define-key verilog-mp "j" 'verilog-sk-fork) + (define-key verilog-mp "m" 'verilog-sk-module) + (define-key verilog-mp "p" 'verilog-sk-primitive) + (define-key verilog-mp "r" 'verilog-sk-repeat) + (define-key verilog-mp "s" 'verilog-sk-specify) + (define-key verilog-mp "t" 'verilog-sk-task) + (define-key verilog-mp "w" 'verilog-sk-while) + (define-key verilog-mp "x" 'verilog-sk-casex) + (define-key verilog-mp "z" 'verilog-sk-casez) + (define-key verilog-mp "?" 'verilog-sk-if) + (define-key verilog-mp ":" 'verilog-sk-else-if) + (define-key verilog-mp "/" 'verilog-sk-comment) + (define-key verilog-mp "A" 'verilog-sk-assign) + (define-key verilog-mp "F" 'verilog-sk-function) + (define-key verilog-mp "I" 'verilog-sk-input) + (define-key verilog-mp "O" 'verilog-sk-output) + (define-key verilog-mp "S" 'verilog-sk-state-machine) + (define-key verilog-mp "=" 'verilog-sk-inout) + (define-key verilog-mp "W" 'verilog-sk-wire) + (define-key verilog-mp "R" 'verilog-sk-reg) + (define-key verilog-mp "D" 'verilog-sk-define-signal) + (setq verilog-template-map verilog-mp)) + +;; +;; Place the templates into Verilog Mode. They may be inserted under any key. +;; C-c C-t will be the default. If you use templates a lot, you +;; may want to consider moving the binding to another key in your .emacs +;; file. +;; +;(define-key verilog-mode-map "\C-ct" verilog-template-map) +(define-key verilog-mode-map "\C-c\C-t" verilog-template-map) + +;;; ---- statement skeletons ------------------------------------------ + +(define-skeleton verilog-sk-prompt-condition + "Prompt for the loop condition." + "[condition]: " str ) + +(define-skeleton verilog-sk-prompt-init + "Prompt for the loop init statement." + "[initial statement]: " str ) + +(define-skeleton verilog-sk-prompt-inc + "Prompt for the loop increment statement." + "[increment statement]: " str ) + +(define-skeleton verilog-sk-prompt-name + "Prompt for the name of something." + "[name]: " str) + +(define-skeleton verilog-sk-prompt-clock + "Prompt for the name of something." + "name and edge of clock(s): " str) + +(defvar verilog-sk-reset nil) +(defun verilog-sk-prompt-reset () + "Prompt for the name of a state machine reset." + (setq verilog-sk-reset (read-input "name of reset: " "rst"))) + + +(define-skeleton verilog-sk-prompt-state-selector + "Prompt for the name of a state machine selector." + "name of selector (eg {a,b,c,d}): " str ) + +(define-skeleton verilog-sk-prompt-output + "Prompt for the name of something." + "output: " str) + +(define-skeleton verilog-sk-prompt-msb + "Prompt for least significant bit specification." + "msb:" str & ?: & (verilog-sk-prompt-lsb) | -1 ) + +(define-skeleton verilog-sk-prompt-lsb + "Prompt for least significant bit specification." + "lsb:" str ) + +(defvar verilog-sk-p nil) +(define-skeleton verilog-sk-prompt-width + "Prompt for a width specification." + () + (progn + (setq verilog-sk-p (point)) + (verilog-sk-prompt-msb) + (if (> (point) verilog-sk-p) "] " " "))) + +(defun verilog-sk-header () + "Insert a descriptive header at the top of the file." + (interactive "*") + (save-excursion + (goto-char (point-min)) + (verilog-sk-header-tmpl))) + +(define-skeleton verilog-sk-header-tmpl + "Insert a comment block containing the module title, author, etc." + "[Description]: " + "// -*- Mode: Verilog -*-" + "\n// Filename : " (buffer-name) + "\n// Description : " str + "\n// Author : " (user-full-name) + "\n// Created On : " (current-time-string) + "\n// Last Modified By: ." + "\n// Last Modified On: ." + "\n// Update Count : 0" + "\n// Status : Unknown, Use with caution!" + "\n") + +(define-skeleton verilog-sk-module + "Insert a module definition." + () + > "module " (verilog-sk-prompt-name) " (/*AUTOARG*/ ) ;" \n + > _ \n + > (- verilog-indent-level-behavioral) "endmodule" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-primitive + "Insert a task definition." + () + > "primitive " (verilog-sk-prompt-name) " ( " (verilog-sk-prompt-output) ("input:" ", " str ) " );"\n + > _ \n + > (- verilog-indent-level-behavioral) "endprimitive" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-task + "Insert a task definition." + () + > "task " (verilog-sk-prompt-name) & ?; \n + > _ \n + > "begin" \n + > \n + > (- verilog-indent-level-behavioral) "end" \n + > (- verilog-indent-level-behavioral) "endtask" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-function + "Insert a function definition." + () + > "function [" (verilog-sk-prompt-width) | -1 (verilog-sk-prompt-name) ?; \n + > _ \n + > "begin" \n + > \n + > (- verilog-indent-level-behavioral) "end" \n + > (- verilog-indent-level-behavioral) "endfunction" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-always + "Insert always block. Uses the minibuffer to prompt +for sensitivity list." + () + > "always @ ( /*AUTOSENSE*/ ) begin\n" + > _ \n + > (- verilog-indent-level-behavioral) "end" \n > + ) + +(define-skeleton verilog-sk-initial + "Insert an initial block." + () + > "initial begin\n" + > _ \n + > (- verilog-indent-level-behavioral) "end" \n > ) + +(define-skeleton verilog-sk-specify + "Insert specify block. " + () + > "specify\n" + > _ \n + > (- verilog-indent-level-behavioral) "endspecify" \n > ) + +(define-skeleton verilog-sk-generate + "Insert generate block. " + () + > "generate\n" + > _ \n + > (- verilog-indent-level-behavioral) "endgenerate" \n > ) + +(define-skeleton verilog-sk-begin + "Insert begin end block. Uses the minibuffer to prompt for name" + () + > "begin" (verilog-sk-prompt-name) \n + > _ \n + > (- verilog-indent-level-behavioral) "end" +) + +(define-skeleton verilog-sk-fork + "Insert an fork join block." + () + > "fork\n" + > "begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end" \n + > "begin" \n + > \n + > (- verilog-indent-level-behavioral) "end" \n + > (- verilog-indent-level-behavioral) "join" \n + > ) + + +(define-skeleton verilog-sk-case + "Build skeleton case statement, prompting for the selector expression, +and the case items." + "[selector expression]: " + > "case (" str ") " \n + > ("case selector: " str ": begin" \n > _ \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-casex + "Build skeleton casex statement, prompting for the selector expression, +and the case items." + "[selector expression]: " + > "casex (" str ") " \n + > ("case selector: " str ": begin" \n > _ \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-casez + "Build skeleton casez statement, prompting for the selector expression, +and the case items." + "[selector expression]: " + > "casez (" str ") " \n + > ("case selector: " str ": begin" \n > _ \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-if + "Insert a skeleton if statement." + > "if (" (verilog-sk-prompt-condition) & ")" " begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " \n ) + +(define-skeleton verilog-sk-else-if + "Insert a skeleton else if statement." + > (verilog-indent-line) "else if (" + (progn (setq verilog-sk-p (point)) nil) (verilog-sk-prompt-condition) (if (> (point) verilog-sk-p) ") " -1 ) & " begin" \n + > _ \n + > "end" (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-datadef + "Common routine to get data definition" + () + (verilog-sk-prompt-width) | -1 ("name (RET to end):" str ", ") -2 ";" \n) + +(define-skeleton verilog-sk-input + "Insert an input definition." + () + > "input [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-output + "Insert an output definition." + () + > "output [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-inout + "Insert an inout definition." + () + > "inout [" (verilog-sk-datadef)) + +(defvar verilog-sk-signal nil) +(define-skeleton verilog-sk-def-reg + "Insert a reg definition." + () + > "reg [" (verilog-sk-prompt-width) | -1 verilog-sk-signal ";" \n (verilog-pretty-declarations) ) + +(defun verilog-sk-define-signal () + "Insert a definition of signal under point at top of module." + (interactive "*") + (let* ( + (sig-re "[a-zA-Z0-9_]*") + (v1 (buffer-substring + (save-excursion + (skip-chars-backward sig-re) + (point)) + (save-excursion + (skip-chars-forward sig-re) + (point)))) + ) + (if (not (member v1 verilog-keywords)) + (save-excursion + (setq verilog-sk-signal v1) + (verilog-beg-of-defun) + (verilog-end-of-statement) + (verilog-forward-syntactic-ws) + (verilog-sk-def-reg) + (message "signal at point is %s" v1)) + (message "object at point (%s) is a keyword" v1)) + ) + ) + + +(define-skeleton verilog-sk-wire + "Insert a wire definition." + () + > "wire [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-reg + "Insert a reg definition." + () + > "reg [" (verilog-sk-datadef)) + +(define-skeleton verilog-sk-assign + "Insert a skeleton assign statement." + () + > "assign " (verilog-sk-prompt-name) " = " _ ";" \n) + +(define-skeleton verilog-sk-while + "Insert a skeleton while loop statement." + () + > "while (" (verilog-sk-prompt-condition) ") begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-repeat + "Insert a skeleton repeat loop statement." + () + > "repeat (" (verilog-sk-prompt-condition) ") begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-for + "Insert a skeleton while loop statement." + () + > "for (" + (verilog-sk-prompt-init) "; " + (verilog-sk-prompt-condition) "; " + (verilog-sk-prompt-inc) + ") begin" \n + > _ \n + > (- verilog-indent-level-behavioral) "end " (progn (electric-verilog-terminate-line) nil)) + +(define-skeleton verilog-sk-comment + "Inserts three comment lines, making a display comment." + () + > "/*\n" + > "* " _ \n + > "*/") + +(define-skeleton verilog-sk-state-machine + "Insert a state machine definition." + "Name of state variable: " + '(setq input "state") + > "// State registers for " str | -23 \n + '(setq verilog-sk-state str) + > "reg [" (verilog-sk-prompt-width) | -1 verilog-sk-state ", next_" verilog-sk-state ?; \n + '(setq input nil) + > \n + > "// State FF for " verilog-sk-state \n + > "always @ ( " (read-string "clock:" "posedge clk") " or " (verilog-sk-prompt-reset) " ) begin" \n + > "if ( " verilog-sk-reset " ) " verilog-sk-state " = 0; else" \n + > verilog-sk-state " = next_" verilog-sk-state ?; \n + > (- verilog-indent-level-behavioral) "end" (progn (electric-verilog-terminate-line) nil) + > \n + > "// Next State Logic for " verilog-sk-state \n + > "always @ ( /*AUTOSENSE*/ ) begin\n" + > "case (" (verilog-sk-prompt-state-selector) ") " \n + > ("case selector: " str ": begin" \n > "next_" verilog-sk-state " = " _ ";" \n > (- verilog-indent-level-behavioral) "end" \n ) + resume: > (- verilog-case-indent) "endcase" (progn (electric-verilog-terminate-line) nil) + > (- verilog-indent-level-behavioral) "end" (progn (electric-verilog-terminate-line) nil)) + +;; Eliminate compile warning +(eval-when-compile + (if (not (boundp 'mode-popup-menu)) + (defvar mode-popup-menu nil "Compatibility with XEmacs."))) + +;; ---- add menu 'Statements' in Verilog mode (MH) +(defun verilog-add-statement-menu () + "Add the menu 'Statements' to the menu bar in Verilog mode." + (if (featurep 'xemacs) + (progn + (easy-menu-add verilog-stmt-menu) + (easy-menu-add verilog-menu) + (setq mode-popup-menu (cons "Verilog Mode" verilog-stmt-menu))))) + +(add-hook 'verilog-mode-hook 'verilog-add-statement-menu) + + + +;; +;; Include file loading with mouse/return event +;; +;; idea & first impl.: M. Rouat (eldo-mode.el) +;; second (emacs/xemacs) impl.: G. Van der Plas (spice-mode.el) + +(if (featurep 'xemacs) + (require 'overlay) + (require 'lucid)) ;; what else can we do ?? + +(defconst verilog-include-file-regexp + "^`include\\s-+\"\\([^\n\"]*\\)\"" + "Regexp that matches the include file.") + +(defvar verilog-mode-mouse-map nil + "Map containing mouse bindings for `verilog-mode'.") + +(if verilog-mode-mouse-map + () + (let ((map (make-sparse-keymap))) ; as described in info pages, make a map + (set-keymap-parent map verilog-mode-map) + ;; mouse button bindings + (define-key map "\r" 'verilog-load-file-at-point) + (if (featurep 'xemacs) + (define-key map 'button2 'verilog-load-file-at-mouse);ffap-at-mouse ? + (define-key map [mouse-2] 'verilog-load-file-at-mouse)) + (if (featurep 'xemacs) + (define-key map 'Sh-button2 'mouse-yank) ; you wanna paste don't you ? + (define-key map [S-mouse-2] 'mouse-yank-at-click)) + (setq verilog-mode-mouse-map map))) ;; copy complete map now + +;; create set-extent-keymap procedure when it does not exist +(eval-and-compile + (unless (fboundp 'set-extent-keymap) + (defun set-extent-keymap (extent keymap) + "fallback version of set-extent-keymap (for emacs 2[01])" + (set-extent-property extent 'local-map keymap)))) + +(defun verilog-colorize-include-files (beg end old-len) + "This function colorizes included files when the mouse passes over them. +Clicking on the middle-mouse button loads them in a buffer (as in dired)." + (save-excursion + (save-match-data + (let (end-point) + (goto-char end) + (setq end-point (verilog-get-end-of-line)) + (goto-char beg) + (beginning-of-line) ; scan entire line ! + ;; delete overlays existing on this line + (let ((overlays (overlays-in (point) end-point))) + (while overlays + (if (and + (overlay-get (car overlays) 'detachable) + (overlay-get (car overlays) 'verilog-include-file)) + (delete-overlay (car overlays))) + (setq overlays (cdr overlays)))) ; let + ;; make new ones, could reuse deleted one ? + (while (search-forward-regexp verilog-include-file-regexp end-point t) + (let (extent) + (goto-char (match-beginning 1)) + (or (extent-at (point) (buffer-name) 'mouse-face) ;; not yet extended + (progn + (setq extent (make-extent (match-beginning 1) (match-end 1))) + (set-extent-property extent 'start-closed 't) + (set-extent-property extent 'end-closed 't) + (set-extent-property extent 'detachable 't) + (set-extent-property extent 'verilog-include-file 't) + (set-extent-property extent 'mouse-face 'highlight) + (set-extent-keymap extent verilog-mode-mouse-map))))))))) + + +(defun verilog-colorize-include-files-buffer () + "Colorize a include file." + (interactive) + ;; delete overlays + (let ((overlays (overlays-in (point-min) (point-max)))) + (while overlays + (if (and + (overlay-get (car overlays) 'detachable) + (overlay-get (car overlays) 'verilog-include-file)) + (delete-overlay (car overlays))) + (setq overlays (cdr overlays)))) ; let + ;; remake overlays + (verilog-colorize-include-files (point-min) (point-max) nil)) + +;; ffap-at-mouse isn't useful for verilog mode. It uses library paths. +;; so define this function to do more or less the same as ffap-at-mouse +;; but first resolve filename... +(defun verilog-load-file-at-mouse (event) + "Load file under button 2 click's EVENT. +Files are checked based on `verilog-library-directories'." + (interactive "@e") + (save-excursion ;; implement a verilog specific ffap-at-mouse + (mouse-set-point event) + (beginning-of-line) + (if (looking-at verilog-include-file-regexp) + (if (and (car (verilog-library-filenames + (match-string 1) (buffer-file-name))) + (file-readable-p (car (verilog-library-filenames + (match-string 1) (buffer-file-name))))) + (find-file (car (verilog-library-filenames + (match-string 1) (buffer-file-name)))) + (progn + (message + "File '%s' isn't readable, use shift-mouse2 to paste in this field" + (match-string 1)))) + ))) + +;; ffap isn't useable for verilog mode. It uses library paths. +;; so define this function to do more or less the same as ffap +;; but first resolve filename... +(defun verilog-load-file-at-point () + "Load file under point. +Files are checked based on `verilog-library-directories'." + (interactive) + (save-excursion ;; implement a verilog specific ffap + (beginning-of-line) + (if (looking-at verilog-include-file-regexp) + (if (and + (car (verilog-library-filenames + (match-string 1) (buffer-file-name))) + (file-readable-p (car (verilog-library-filenames + (match-string 1) (buffer-file-name))))) + (find-file (car (verilog-library-filenames + (match-string 1) (buffer-file-name)))))) + )) + + +;; +;; Bug reporting +;; + +(defun verilog-faq () + "Tell the user their current version, and where to get the FAQ etc." + (interactive) + (with-output-to-temp-buffer "*verilog-mode help*" + (princ (format "You are using verilog-mode %s\n" verilog-mode-version)) + (princ "\n") + (princ "For new releases, see http://www.verilog.com\n") + (princ "\n") + (princ "For frequently asked questions, see http://www.veripool.com/verilog-mode-faq.html\n") + (princ "\n") + (princ "To submit a bug, use M-x verilog-submit-bug-report\n") + (princ "\n"))) + +(defun verilog-submit-bug-report () + "Submit via mail a bug report on verilog-mode.el." + (interactive) + (let ((reporter-prompt-for-summary-p t)) + (reporter-submit-bug-report + "mac@verilog.com" + (concat "verilog-mode v" verilog-mode-version) + '( + verilog-align-ifelse + verilog-auto-endcomments + verilog-auto-hook + verilog-auto-indent-on-newline + verilog-auto-inst-vector + verilog-auto-inst-template-numbers + verilog-auto-lineup + verilog-auto-newline + verilog-auto-save-policy + verilog-auto-sense-defines-constant + verilog-auto-sense-include-inputs + verilog-before-auto-hook + verilog-case-indent + verilog-cexp-indent + verilog-compiler + verilog-coverage + verilog-highlight-translate-off + verilog-indent-begin-after-if + verilog-indent-declaration-macros + verilog-indent-level + verilog-indent-level-behavioral + verilog-indent-level-declaration + verilog-indent-level-directive + verilog-indent-level-module + verilog-indent-lists + verilog-library-flags + verilog-library-directories + verilog-library-extensions + verilog-library-files + verilog-linter + verilog-minimum-comment-distance + verilog-mode-hook + verilog-simulator + verilog-tab-always-indent + verilog-tab-to-comment + ) + nil nil + (concat "Hi Mac, + +I want to report a bug. I've read the `Bugs' section of `Info' on +Emacs, so I know how to make a clear and unambiguous report. To get +to that Info section, I typed + +M-x info RET m " invocation-name " RET m bugs RET + +Before I go further, I want to say that Verilog mode has changed my life. +I save so much time, my files are colored nicely, my co workers respect +my coding ability... until now. I'd really appreciate anything you +could do to help me out with this minor deficiency in the product. + +If you have bugs with the AUTO functions, please CC the AUTOAUTHOR Wilson +Snyder (wsnyder@wsnyder.org) and/or see http://www.veripool.com. +You may also want to look at the Verilog-Mode FAQ, see +http://www.veripool.com/verilog-mode-faq.html. + +To reproduce the bug, start a fresh Emacs via " invocation-name " +-no-init-file -no-site-file'. In a new buffer, in verilog mode, type +the code included below. + +Given those lines, I expected [[Fill in here]] to happen; +but instead, [[Fill in here]] happens!. + +== The code: ==")))) + +;; Local Variables: +;; checkdoc-permit-comma-termination-flag:t +;; checkdoc-force-docstrings-flag:nil +;; End: + +;;; verilog-mode.el ends here