ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

gvim快捷键声明wire和reg

gvim快捷键声明wire和reg

摘要

在verilog的编写中,可能存在很多的wire和reg需要去声明。gvim中的verilog-mode插件对于写的组合或者时序逻辑这部分的支持貌似并不好。可以使用gvim的快捷键做辅助,对这部分进行快捷声明。

  1. 步骤1
    在.vimrc中复制如下代码并source
" ================= Verilog declare: append + aligned + jump ================= "Assumption: one signal per line(wire/reg/input/output xxx;)" "Keys:" <leader>dw : declare wire under /*AUTOWIRE*/ "<leader>dr : declare reg under/*AUTOREG*/" <leader>di : declare input under /*autoinput*/ "<leader>do: declare output under/*autooutput*/if!exists('g:verilog_decl_name_col')let g:verilog_decl_name_col = 13" Signal name start column (1-based) endif if !exists('g:verilog_decl_indent') let g:verilog_decl_indent = ' ' "indent string:' 'or"\t"endiffunction!s:FindMarker(marker)abortreturnsearch('\c\/\*\s*'.a:marker.'\s*\*\/','nw')endfunctionfunction!s:AlreadyDeclared(name)abort" 全局上下搜索,支持 wire/reg/input/output let pat = '^\s*\%(wire\|reg\|input\|output\)\>\s*\%(\[[^]]\+\]\s*\)\?\<' . escape(a:name, '\') . '\>\s*;' return search(pat, 'n') > 0 || search(pat, 'bn') > 0 endfunction function! s:PadToNameCol(keyword) abort let name_col = get(g:, 'verilog_decl_name_col', 13) let prefix = g:verilog_decl_indent . a:keyword . ' ' let spaces = name_col - strlen(prefix) return repeat(' ', spaces < 1 ? 1 : spaces) endfunction function! s:IsOnePerLineDecl(kind, line) abort return a:line =~# '^\s*' . a:kind . '\>\s*\%(\[[^]]\+\]\s*\)\?\h\w*\s*;\s*$' endfunction function! s:FindInsertAfterDeclBlock(anchor, kind) abort let lnum = a:anchor + 1 let last = a:anchor while lnum <= line('$') let txt = getline(lnum) if <SID>IsOnePerLineDecl(a:kind, txt) let last = lnum let lnum += 1 continue endif break endwhile return last endfunction function! s:Declare(marker, kind) abort let name = expand('<cword>') if empty(name) echoerr "No identifier under cursor" return endif if <SID>AlreadyDeclared(name) echom "Already declared:" . name return endif let anchor = <SID>FindMarker(a:marker) if anchor <= 0 echoerr "Marker not found:/*" . a:marker . "*/(case-insensitive)" return endif let prefix = g:verilog_decl_indent . a:kind let newline = prefix . <SID>PadToNameCol(a:kind) . name . ';' let insert_after = <SID>FindInsertAfterDeclBlock(anchor, a:kind) call append(insert_after, newline) "光标跳到新行,定位到信号名 let target_lnum = insert_after+1 call cursor(target_lnum,1)let name_start = strlen(prefix.<SID>PadToNameCol(a:kind))+1 call cursor(target_lnum,name_start)endfunction nnoremap <leader>dw :call <SID>Declare('autowire','wire')<CR> nnoremap <leader>dr :call <SID>Declare('autoreg','reg')<CR> nnoremap <leader>di :call <SID>Declare('autoinput','input')<CR> nnoremap <leader>do:call <SID>Declare('autooutput','output')<CR> " 可选:一键插入标记映射 nnoremap <leader>mw :call append(line('.')+1,'/*AUTOWIRE*/')<CR> nnoremap <leader>mr :call append(line('.')+1,'/*AUTOREG*/')<CR> nnoremap <leader>mi:call append(line('.')+1,'/*autoinput*/')<CR> nnoremap <leader>mo :call append(line('.')+1,'/*autooutput*/')<CR>
  1. 需要在verilog的.v文件中存在/*autowire*/和/*autoreg*/。
module top ( input clk, input rst_n, input a, input b ); /*autowire*/ /*autoreg*/ always @(*) begin comb_sum = a ^ b; end always @(posedge clk or negedge rst_n) begin if (!rst_n) q <= 1'b0; else q <= comb_sum; end endmodule
  1. 在要声明的wire信号光标出按下\dw,在要声明的reg信号光标处按下\dr。
/*autowire*/ wire comb_sum; /*autoreg*/ reg q;

效果如上。

  1. 缺点
    在产生的声明中,不会有位宽的识别,每次产生声明后,光标会自动跳转到声明行,可以手动补齐位宽。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进