;;;
;;; Port/Wire/Etc Reading
;;;
(defun verilog-read-inst-module ()
"Return module_name when point is inside instantiation"
(save-excursion
(search-backward "(")
;; Skip over instantiation name
(verilog-re-search-backward-quick "\\b[a-zA-Z0-9`_\$]" nil nil)
(skip-chars-backward "a-zA-Z0-9`_$")
(verilog-re-search-backward-quick "\\b[a-zA-Z0-9`_)\$]" nil nil)
;; Check for parameterized instantiations
(when (looking-at ")")
(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-inst-name ()
"Return instance_name when point is inside instantiation.
Or, 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-param ()
"Return parameter inside auto"
(save-excursion
;; /*AUTOPUNT("parameter")*/
(search-backward "(")
(if (looking-at "(\\s *\"\\([^\"]*\\)\"")
(match-string 1)
nil)))
(defun verilog-read-decls ()
"Return a array of [outputs inouts inputs wire reg assign const] used in the
current
module that the point is over."
(let ((end-mod-point (or (verilog-get-end-of-defun t) (point-max)))
(functask 0) (paren 0)
sigs-in sigs-out sigs-inout sigs-wire sigs-reg sigs-assign sigs-const
vec expect-signal keywd newsig rvalue)
(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 "//")
(search-forward "\n"))
((looking-at "/\\*")
(or (search-forward "*/")
(error "Unmatched /* */, at char %d in %s" (point) (buffer-name))))
((eq ?\" (following-char))
(or (re-search-forward "[^\\]\"" nil t) ;; don't forward-char first,
since we look for a non backslash first
(error "Unmatched quotes, at char %d in %s" (point) (buffer-name))))
((eq ?\; (following-char))
(setq vec 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 rvalue
(cond ((and (eq ?, (following-char))
(eq paren 0))
(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)
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)))
(t ;; Bit width
(setq vec (verilog-string-replace-matches
"\\s-+" "" nil nil (match-string 1))))))
((looking-at "\\s-*\\([a-zA-Z0-9`_$]+\\)")
(goto-char (match-end 0))
(setq keywd (match-string 1))
(cond ((equal keywd "input")
(setq vec nil expect-signal 'sigs-in))
((equal keywd "output")
(setq vec nil expect-signal 'sigs-out))
((equal keywd "inout")
(setq vec nil expect-signal 'sigs-inout))
((equal keywd "wire")
(setq vec nil expect-signal 'sigs-wire))
((equal keywd "reg")
(setq vec nil expect-signal 'sigs-reg))
((equal keywd "assign")
(setq vec nil expect-signal 'sigs-assign))
((or (equal keywd "supply0")
(equal keywd "supply1")
(equal keywd "supply")
(equal keywd "parameter"))
(setq vec nil expect-signal 'sigs-const))
((or (equal keywd "function")
(equal keywd "task"))
(setq functask (1+ functask)))
((or (equal keywd "endfunction")
(equal keywd "endtask"))
(setq functask (1- functask)))
((and expect-signal
(eq functask 0)
(not rvalue))
;; Add new signal to expect-signal's variable
(setq newsig (list keywd vec nil nil))
(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)
))))
(defun verilog-read-sub-decls-line (comment)
;; For read-sub-decl, read lines of port defs until none match anymore
(let (sigs)
(while (or
(if (looking-at "\\s-*\\.[^(]*(\\s-*\\([^[({)]*\\)\\s-*)")
(let ((sig (verilog-string-remove-spaces (match-string 1)))
vec)
(or (equal sig "")
(setq sigs (cons (list sig vec comment)
sigs)))))
(if (looking-at
"\\s-*\\.[^(]*(\\s-*\\([^[({)]*\\)\\s-*\\(\\[[^]]+\\]\\)\\s-*)")
(let ((sig (verilog-string-remove-spaces (match-string 1)))
(vec (match-string 2)))
(or (equal sig "")
(setq sigs (cons (list sig vec comment)
sigs)))))
(looking-at "\\s-*\\.[^(]*("))
(forward-line 1))
sigs))
(defun verilog-read-sub-decls ()
"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 it will be included in the list.
This only works on instantiations created with /*AUTOINST*/ converted by
\\[verilog-auto-instant]. Otherwise, it would have to read in the whole
component library to determine connectivity of the design."
(save-excursion
(let ((end-mod-point (verilog-get-end-of-defun t))
sigs-out sigs-inout sigs-in comment)
(verilog-beg-of-defun)
(while (search-forward "/*AUTOINST*/" end-mod-point t)
(forward-line 1)
(save-excursion
;; Attempt to snarf a comment
(setq comment (concat (verilog-read-inst-name)
" of " (verilog-read-inst-module) ".v")))
;; This could have used a list created by verilog-auto-instant
;; However I want it to be runable even if that function wasn't called before.
(when (looking-at "\\s *// Outputs")
(forward-line 1)
(setq sigs-out (append (verilog-read-sub-decls-line
(concat "From " comment)) sigs-out)))
(when (looking-at "\\s *// Inouts")
(forward-line 1)
(setq sigs-inout (append (verilog-read-sub-decls-line
(concat "To/From " comment)) sigs-inout)))
(when (looking-at "\\s *// Inputs")
(forward-line 1)
(setq sigs-in (append (verilog-read-sub-decls-line
(concat "To " comment)) sigs-in)))
)
;; Combine duplicate bits
(vector (verilog-signals-combine-bus sigs-out)
(verilog-signals-combine-bus sigs-inout)
(verilog-signals-combine-bus sigs-in)))))
(defun verilog-read-auto-constants (beg end-mod-point)
"Return a list of (constants) used in the region"
;; Insert new
(save-excursion
(let (sig-list tpl-end-pt)
(goto-char beg)
(while (re-search-forward "\\<AUTO_CONSTANT" end-mod-point t)
(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)))
(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)))
(defun verilog-read-always-signals-recurse
(exit-keywd ;; Expression to stop at, nil if top level
rvalue ;; right hand side of equal
ignore-next ;; Ignore next token, it's fake
)
"Recursive routine for parentheses/bracket matching."
(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)
;;(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 "Unmatched /* */, at char %d in %s" (point) (buffer-name))))
(t (setq keywd (buffer-substring-no-properties
(point)
(save-excursion (when (eq 0 (skip-syntax-forward "w_"))
(forward-char 1))
(point)))
sig-last-tolk sig-tolk
sig-tolk nil)
;;(if dbg (setq dbg (concat dbg (format "\tPt %S %S\t%S %S\n" (point) keywd
rvalue ignore-next))))
(cond
((equal keywd "\"")
(or (re-search-forward "[^\\]\"" nil t)
(error "Unmatched quotes, at char %d in %s" (point) (buffer-name))))
;; Final statement?
((equal keywd (or exit-keywd ";"))
(setq gotend t)
(forward-char (length keywd)))
((equal keywd ";")
(setq ignore-next nil rvalue semi-rvalue)
(forward-char 1))
((equal keywd "'")
(setq ignore-next t)
(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))
((not rvalue) ;; begin label
(setq ignore-next t rvalue nil)))
(forward-char 1))
((equal keywd "=")
(setq ignore-next nil rvalue t)
(forward-char 1))
((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)
(setq ignore-next nil rvalue semi-rvalue)
(if (not exit-keywd) (setq gotend t))) ;; top level begin/end
((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 constituant
(cond ((or ignore-next
(member keywd verilog-keywords)
(string-match "^\\$" keywd)) ;; PLI task
(setq ignore-next nil))
(t
(when (string-match "^`" keywd)
;; 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 keywd
(verilog-string-replace-matches
"\[[^0-9: \t]+\]" "" nil nil
(or (verilog-symbol-detick keywd nil) keywd)))
(if (string-match "^[0-9 \t]+$" keywd)
(setq keywd nil))
)
(if got-sig (if got-rvalue
(setq sigs-in (cons got-sig sigs-in))
(setq sigs-out (cons got-sig sigs-out))))
(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-syntax-forward "w_"))
(t
(forward-char 1)))
;; End of non-comment tolken
(setq last-keywd keywd)
))
(skip-syntax-forward " "))
;;(if dbg (setq dbg (concat dbg (format "ENDRecursion %s\n" exit-keywd))))
))
(defun verilog-read-always-signals ()
"Return a list of (inputs outputs) used in the current
always block that the point is over."
;; Insert new
(save-excursion
(let* (;;(dbg "")
sigs-in sigs-out
got-sig got-rvalue) ;; Found signal/rvalue; push if not function
(search-forward ")")
(verilog-read-always-signals-recurse nil nil nil)
;; Return what was found
(if got-sig (if got-rvalue
(setq sigs-in (cons got-sig sigs-in))
(setq sigs-out (cons got-sig sigs-out))))
;;(if dbg (message dbg))
(list sigs-in sigs-out))))
(defun verilog-read-instants ()
"Return a list of ( ( file instance ) ... ) for the
module that the point is over."
(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)
"Looks for a auto_template for the instantiation of the given module. If
found returns the signal name connections. Return nil or list of
( (signal_name connection_name)... )
"
(save-excursion
;; Find beginning
(let (tpl-list tpl-end-pt)
(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)))
(search-forward "(")
(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)
(when (looking-at
"\\s-*\\.\\([a-zA-Z0-9`_$]+\\)\\s-*(\\(.*\\))\\s-*\\(,\\|)\\s-*;\\)")
(setq tpl-list (cons
(list
(match-string 1)
(match-string 2))
tpl-list)))
(forward-line 1))
;;
tpl-list
)))))
;;;(progn (find-file "auto-template.v") (verilog-read-auto-template
"ptl_entry"))
(defun verilog-read-defines ()
"Read `defines for the given file. They must be simple text substitutions,
one on a line.
Defines are stored inside emacs variables using the name vh-{definename}.
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)
// 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!
"
(save-excursion
(goto-char (point-min))
(while (re-search-forward
"^\\s-*`define\\s-+\\([a-zA-Z0-9_$]+\\)\\s-+\\(.*\\)$" nil t)
(let ((mac (intern (concat "vh-" (match-string 1))))
(value (match-string 2)))
(setq value (verilog-string-replace-matches "\\s-*/[/*].*$" "" nil
nil value))
(make-variable-buffer-local mac)
(set mac value)))))
(defun verilog-read-signals ()
"Return a simple list of all possible signals in the file, 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 (point-min))
(while (re-search-forward "[\"/a-zA-Z_]" nil t)
(forward-char -1)
(cond
((looking-at "//")
(search-forward "\n"))
((looking-at "/\\*")
(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 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)))
;;;
;;; Module name lookup
;;;
(defun verilog-module-inside-filename-p (mod filename)
"Return point if the given file has the module specified, else nil.
Allows version control to check out the file if need be."
(and (or (file-exists-p filename)
(and (fboundp 'vc-backend) (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 mod (verilog-read-inst-name))
(setq pt (point))))
pt))))
(defun verilog-symbol-detick (mod 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."
(when (string-match "^`" mod)
(setq mod (substring mod 1))
(if (boundp (intern (concat "vh-" mod)))
(setq mod (eval (intern (concat "vh-" mod))))
(if (not wing-it) (setq mod nil))))
mod)
;;(verilog-symbol-detick "mod" nil)
(defun verilog-module-filenames (mod current)
"Return a search path to find the given module name. Uses the
verilog-library-directories variable to build the path"
;; Return search locations for it
(append (list current) ; first, current buffer
(mapcar (function (lambda (dir)
(expand-file-name
(concat mod ".v")
(expand-file-name dir (file-name-directory current)))))
verilog-library-directories)))
;;;
;;; 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-inst-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-current nil "Cache of last current looked up")
(defvar verilog-modi-lookup-last-modi nil "Cache of last modi returned")
(defun verilog-modi-lookup (mod allow-cache)
"Find the file and point at which a given module is defined.
Return modi if successful, else print message."
(let* ((current (or (buffer-file-name) (current-buffer))))
(cond ((and (equal verilog-modi-lookup-last-mod mod)
(equal verilog-modi-lookup-last-current current)
verilog-modi-lookup-last-modi
verilog-cache-enabled
allow-cache)
;; ok as is
)
(t (let* ((realmod (verilog-symbol-detick mod 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)
(error (concat "Can't locate " mod " module definition"
(if (not (equal mod realmod))
(concat " (Expanded macro to " realmod ")")
"")
"\n Check the verilog-library-directories variable."
"\n I looked in:\n\t" (mapconcat 'concat orig-filenames
"\n\t"))))
)
(setq verilog-modi-lookup-last-mod mod
verilog-modi-lookup-last-current current))))
verilog-modi-lookup-last-modi
))
(defsubst verilog-modi-name (modi)
(aref modi 0))
(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 (aref modi 1))
(aref modi 1)
(find-file-noselect (aref modi 1))))
(or (equal major-mode `verilog-mode) ;; Put into verilog mode to get syntax
(verilog-mode))
(goto-char (aref modi 2)))
(defun verilog-goto-defun-file (mod)
"Move point to the file at which a given module is defined."
(interactive "sGoto File for Module: ")
(let* ((modi (verilog-modi-lookup mod nil)))
(when modi
(verilog-modi-goto modi)
(switch-to-buffer (current-buffer)))))
(defun verilog-modi-cache-results (modi function)
"Run FUNCTION for given MODI. 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 (memq 'v19 verilog-emacs-features)
(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 idx sig-list)
"Update the modi's cache for given function so that the elt'th
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 idx
(append sig-list (aref func-returns idx))))))))
(defmacro verilog-preserve-cache (&rest body)
"Execute the BODY forms, allowing cache preservation cache within calls
inside the 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 modi-lookupFIX 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-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))
;;; 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)))
(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))
;;;
;;; Auto creation utilities
;;;
(defun verilog-auto-search-do (search-for func)
"Search for the given auto text, and perform function 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, and perform function 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-definition (sigs type indent-pt &optional dont-sort)
"Print out a definition for a list of SIGNALS of the given TYPE,
with appropriate INPUT. TYPE is normally wire/reg/output."
(or dont-sort
(setq sigs (sort (copy-alist sigs) (function (lambda (a b) (string< (car a) (car
b)))))))
(while sigs
(let ((sig (car sigs)))
(indent-to indent-pt)
(insert type)
(when (nth 1 sig)
(insert " " (nth 1 sig)))
(indent-to (max 24 (+ indent-pt 16)))
(insert (concat (car sig) ";"))
(if (not (nth 2 sig))
(insert "\n")
(indent-to (max 48 (+ indent-pt 40)))
(insert (concat "// " (nth 2 sig) "\n")))
(setq sigs (cdr sigs)))))
;;;
;;; Auto deletion
;;;
(defun verilog-delete-autos-lined ()
(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-delete-to-paren ()
"Delete the automatic inst/sense/arg created by verilog-mode.
Deletion stops at the matching end parenthesis."
(delete-region (point)
(save-excursion
(verilog-re-search-backward-quick "(" nil nil)
(forward-sexp 1) ;; Moves to paren that closes argdecl's
(backward-char 1)
(point))))
(defun verilog-delete-auto ()
"Delete the automatic outputs, regs, and wires created by verilog-mode.
Use \\[verilog-auto] to re-insert the updated AUTOs."
(interactive)
(save-excursion
(if (buffer-file-name)
(find-file-noselect (buffer-file-name))) ;; To check we have latest version
;; Remove those that have multi-line insertions
(verilog-auto-re-search-do
"/\\*AUTO\\(OUTPUTEVERY\\|WIRE\\|REG\\|INPUT\\|OUTPUT\\)\\*/"
'verilog-delete-autos-lined)
;; Remove those that have multi-line insertions with parameters
(verilog-auto-re-search-do "/\\*AUTO\\(INOUTMODULE\\)([^)]*)\\*/"
'verilog-delete-autos-lined)
;; Remove those that are in parenthesis
(verilog-auto-re-search-do "/\\*AUTO\\(ARG\\|INST\\|SENSE\\)\\*/"
'verilog-delete-to-paren)
;; Remove template comments ... anywhere in case was pasted after AUTOINST removed
(goto-char (point-min))
(while (re-search-forward "\\s-*// Templated$" nil t)
(replace-match ""))))
;;;
;;; Auto creation
;;;
(defun verilog-auto-arg-ports (sigs message indent-pt)
"Print a argument list"
(when sigs
(insert "\n")
(indent-to indent-pt)
(insert message)
(insert "\n")
(indent-to indent-pt)
(while sigs
(cond ((> (+ 2 (current-column) (length (nth 0 (car sigs)))) fill-column)
(insert "\n")
(indent-to indent-pt)))
(insert (nth 0 (car sigs)) ", ")
(setq sigs (cdr sigs)))))
(defun verilog-auto-arg ()
"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:
Concatencation and outputting partial busses is not supported.
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
"
(save-excursion
(let ((modi (verilog-modi-current))
(pt (point)))
(verilog-auto-arg-ports (verilog-modi-get-outputs modi)
"// Outputs"
verilog-indent-level-declaration)
(verilog-auto-arg-ports (verilog-modi-get-inouts modi)
"// Inouts"
verilog-indent-level-declaration)
(verilog-auto-arg-ports (verilog-modi-get-inputs modi)
"// Inputs"
verilog-indent-level-declaration)
(save-excursion
(if (re-search-backward "," pt t)
(delete-char 2)))
(insert "\n")
(indent-to verilog-indent-level-declaration)
)))
(defun verilog-auto-inst-port (port-st indent-pt tpl-list tpl-num)
"Print out a instantiation connection for this port. @ are instantiation numbers.
@\"(expression @)\" are evaluated, with @ as a variable."
(let* ((port (car port-st))
(tpl-ass (assoc port tpl-list))
(tpl-net (concat port (nth 1 port-st))))
(cond (tpl-ass
(setq tpl-net (nth 1 tpl-ass))
(cond ((string-match "(a)\"\\(.*[^\\]\\)\"" tpl-net)
(setq tpl-net
(concat
(substring tpl-net 0 (match-beginning 0))
(save-match-data
(let ((expr (match-string 1 tpl-net)))
(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) ()))))
(substring tpl-net (match-end 0)))))
(t
(setq tpl-net (verilog-string-replace-matches "@" tpl-num nil nil tpl-net))
))))
(indent-to indent-pt)
(insert "." port)
(indent-to 40)
(insert "(" tpl-net "),")
(when tpl-ass
(indent-to 64)
(insert " // Templated"))
(insert "\n")))
;;;(verilog-auto-inst-port (list "foo" "[5:0]") 10 (list (list
"foo" "a@\"(% (+ @ 1) 4)\"a")) "3")
(defun verilog-auto-inst ()
"Replace the argument calls inside an instantiation with ones
automatically derived from the module header of the instantiated netlist.
Limitations:
This presumes a one-to-one port name to signal name mapping.
Module names must be resolvable to filenames, either by being in the same
directory, or by changing the variable verilog-library-directories.
Macros `modname are translated through the vh-{name} emacs variable,
if that is not found, it just ignores the `.
A simple example:
module ex_inst (o,i)
output o;
input i;
inst inst (/*AUTOINST*/);
endmodule
Where somewhere the instantiated module is declared:
module inst (o,i)
output [31:0] o;
input i;
wire [31:0] o = {32{i}};
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.
For multiple instantiations based upon a single template,
Create a commented out template:
/*
psm_mas AUTO_TEMPLATE (
.PTL_MAPVALIDX (PTL_MAPVALID[@]),
.PTL_MAPVALIDP1X (PTL_MAPVALID[@\"(% (+ 1 @) 4)\"]),
);
*/
where the @ character should be replaced by the instantiation number. 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.
If the syntax @\"( ... )\" is found, the expression in quotes will be
evaluated as a lisp expression, with @ replaced by the instantation number.
The example above would put @+1 modulo 4 into the brackets. Quote all
double-quotes inside the expression with a leading backslash (\").