(;- this is end{function,task,module}
t
(let (string reg (width nil))
(end-of-line)
(if kill-existing-comment
(kill-existing-comment))
(delete-horizontal-space)
(backward-sexp)
(cond
((match-end 5)
(setq reg "\\(\\<function\\>\\)\\|\\(\\<\\(endfunction\\|task\\|\\(macro\\)?module\\|primitive\\)\\>\\)")
(setq width "\\(\\s-*\\(\\[[^]]*\\]\\)\\|\\(real\\(time\\)?\\)\\|\\(integer\\)\\|\\(time\\)\\)?")
)
((match-end 6)
(setq reg "\\(\\<task\\>\\)\\|\\(\\<\\(endtask\\|function\\|\\(macro\\)?module\\|primitive\\)\\>\\)"))
((match-end 7)
(setq reg "\\(\\<\\(macro\\)?module\\>\\)\\|\\<endmodule\\>"))
((match-end 8)
(setq reg "\\(\\<primitive\\>\\)\\|\\(\\<\\(endprimitive\\|function\\|task\\|\\(macro\\)?module\\)\\>\\)"))
)
(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 "unmactched end(function|task|module|primitive)")))))
(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)
(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")
(point))
((looking-at "/[/\\*]")
b)
('t
(skip-chars-forward "^: \t\n")
(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 a start brace and end brace, expand one line into many lines."
(interactive)
(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)
(let ((bpt (- (point) 2)))
(end-of-line)
(delete-region bpt (point))))
;;
(goto-char (point-min))
(while (re-search-forward "/\\*" nil t)
(let ((bpt (- (point) 2)))
(re-search-forward "\\*/")
(delete-region bpt (point))))
)
(defun verilog-one-line ()
"Converts 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-verilint-off ()
"Convert a verilint warning line into a disable statement.
(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)))
(verilog-indent-line))))
(defun verilog-auto-save-compile ()
"Update automatics with \\[verilog-auto],
save the buffer, and compile to check syntax."
(interactive)
(verilog-auto)
(save-buffer)
(compile compile-command))
;;;
;;; 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)
(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"
(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, through examination
of previous lines. Once a line is found that is definitive as to the
type of the current line, return that lines' indent level and it's
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 are in a parenthesized list, done.
(if (verilog-in-paren) (progn (setq par 1) (throw 'nesting 'block)))
; (if (/= 0 (verilog-parenthesis-depth)) (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))
(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) ; found it
(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|endcase|endtable|endspecify|endfunction|endtask
(cond
((match-end 3) ; end
;; Search back for matching begin
(setq reg "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)" )
)
((match-end 5) ; endcase
;; Search back for matching case
(setq reg "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" )
)
((match-end 7) ; endspecify
;; Search back for matching specify
(setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )
)
((match-end 8) ; endfunction
;; Search back for matching function
(setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )
)
((match-end 9) ; endtask
;; Search back for matching task
(setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )
)
((match-end 4) ; join
;; Search back for matching fork
(setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" )
)
((match-end 6) ; endtable
;; Search back for matching table
(setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )
)
)
(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))
)
)
)
)
;; 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-indent-level)))))
)
)
)
(defun verilog-calc-1 ()
""
(catch 'nesting
(while (verilog-re-search-backward verilog-indent-re nil 'move)
(cond
((looking-at verilog-behavioral-level-re)
(throw 'nesting 'behavioral))
((looking-at verilog-beg-block-re-1)
(cond
((match-end 2) (throw 'nesting 'case))
(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 verilog-defun-level-re)
(throw 'nesting 'defun))
((looking-at verilog-cpp-level-re)
(throw 'nesting 'cpp))
((bobp)
(throw 'nesting 'cpp))
)
)
)
)
(defun verilog-leap-to-case-head () ""
(let ((nest 1))
(while (/= 0 nest)
(verilog-re-search-backward "\\(\\<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
snest
(nest 1))
(cond
((looking-at "\\<end\\>")
;; Search back for matching begin
(setq reg (concat "\\(\\<begin\\>\\)\\|\\(\\<end\\>\\)\\|"
"\\(\\<endcase\\>\\)\\|\\(\\<join\\>\\)" )))
((looking-at "\\<endcase\\>")
;; Search back for matching case
(setq reg "\\(\\<case[xz]?\\>\\)\\|\\(\\<endcase\\>\\)" )
)
((looking-at "\\<join\\>")
;; Search back for matching fork
(setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" )
)
((looking-at "\\<endtable\\>")
;; Search back for matching table
(setq reg "\\(\\<table\\>\\)\\|\\(\\<endtable\\>\\)" )
)
((looking-at "\\<endspecify\\>")
;; Search back for matching specify
(setq reg "\\(\\<specify\\>\\)\\|\\(\\<endspecify\\>\\)" )
)
((looking-at "\\<endfunction\\>")
;; Search back for matching function
(setq reg "\\(\\<function\\>\\)\\|\\(\\<endfunction\\>\\)" )
)
((looking-at "\\<endtask\\>")
;; Search back for matching task
(setq reg "\\(\\<task\\>\\)\\|\\(\\<endtask\\>\\)" )
)
)
(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 "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" )
)
((match-end 4)
;; join, jump to fork
(setq snest nest)
(setq nest (1+ nest))
(setq sreg reg)
(setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" )
)
)
)
)
)
)
)
(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"
(verilog-backward-syntactic-ws)
(cond
((bolp)
nil)
(;-- Anything ending in a ; is complete
(= (preceding-char) ?\;)
nil)
(;-- Could be 'case (foo)' or 'always @(bar)' which is complete
(= (preceding-char) ?\))
(progn
(backward-char)
(backward-up-list 1)
(verilog-backward-syntactic-ws)
(forward-word -1)
(not (looking-at "\\<case[xz]?\\>[^:]"))))
(;-- any of begin|initial|while are complete statements; 'begin : foo' is also complete
t
(forward-word -1)
(cond
(
(looking-at "\\(else\\)\\|\\(initial\\>\\)\\|\\(always\\>\\)")
t)
(
(looking-at verilog-indent-reg)
nil)
(t
(let
((back (point)))
(verilog-backward-syntactic-ws)
(cond
((= (preceding-char) ?\:)
(backward-char)
(verilog-backward-syntactic-ws)
(backward-sexp)
(if (looking-at "begin")
nil
t)
)
((= (preceding-char) ?\#)
(backward-char)
t)
((= (preceding-char) ?\`)
(backward-char)
t)
(t
(goto-char back)
t)
)
)
)
)
)
)
)
(defun verilog-backward-syntactic-ws (&optional lim)
;; Backward skip over syntactic whitespace for Emacs 19.
(save-restriction
(let* ((lim (or lim (point-min))) (here lim) )
(if (< lim (point))
(progn
(narrow-to-region lim (point))
(while (/= here (point))
(setq here (point))
(forward-comment (-(buffer-size)))
)))
))
t)
(defun verilog-forward-syntactic-ws (&optional lim)
;; forward skip over syntactic whitespace for Emacs 19.
(save-restriction
(let* ((lim (or lim (point-max)))
(here lim)
)
(if (> lim (point))
(progn
(narrow-to-region (point) lim)
(while (/= here (point))
(setq here (point))
(forward-comment (buffer-size))
)))
)))
(defun verilog-backward-ws&directives (&optional lim)
;; Backward skip over syntactic whitespace and compiler directives for Emacs 19.
(save-restriction
(let* ((lim (or lim (point-min)))
(here lim)
jump
)
(if (< lim (point))
(progn
(let ((state
(save-excursion
(parse-partial-sexp (point-min) (point)))))
(cond
((nth 4 state) ;; in /* */ comment
(verilog-re-search-backward "/\*" nil 'move)
)
((nth 7 state) ;; in // comment
(verilog-re-search-backward "//" nil 'move)
)))
(narrow-to-region lim (point))
(while (/= here (point))
(setq here (point))
(forward-comment (-(buffer-size)))
(save-excursion
(beginning-of-line)
(if (looking-at verilog-directive-re-1)
(setq jump t)
(setq jump nil)))
(if jump
(beginning-of-line))
)))
)))
(defun verilog-forward-ws&directives (&optional lim)
;; forward skip over syntactic whitespace and compiler directives for Emacs 19.
(save-restriction
(let* ((lim (or lim (point-max)))
(here lim)
jump
)
(if (> lim (point))
(progn
(let ((state
(save-excursion
(parse-partial-sexp (point-min) (point)))))
(cond
((nth 4 state) ;; in /* */ comment
(verilog-re-search-forward "/\*" nil 'move)
)
((nth 7 state) ;; in // comment
(verilog-re-search-forward "//" nil 'move)
)))
(narrow-to-region (point) lim)
(while (/= here (point))
(setq here (point))
(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)))))
(nth 4 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")
(if (= (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)))))
(/= 0 (nth 0 state)))
)
(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 "//")
t)
((nth 4 state) ;Inside /* */ comment
(search-backward "/*")
t)
(t
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 that only looks 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-indent-level))))
(goto-char sp1)
(setq indent-str (list 'block (verilog-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."
(if (looking-at verilog-directive-re)
;; We could nicely nest `ifdef's, but...
(progn
(delete-horizontal-space)
(indent-to 0)
(list 'cpp 0)) ; Return verilog-calculate-indent data
(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")
(if (= (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)
(if (/= (current-column) val)
(progn
(delete-horizontal-space)
(indent-to val)))
)
)
((= (preceding-char) ?\) )
(goto-char here)
(let ((val (eval (cdr (assoc type verilog-indent-alist)))))
(if (/= (current-column) val)
(progn
(delete-horizontal-space)
(indent-to val)))
)