読者です 読者をやめる 読者になる 読者になる

case自動入力

verilogでcase文を書いてるときにめんどくさいところがあります.

function [3:0] func;
  input [1:0] in;
  case(in)
    2'h0:    func = 4'h0; // <- この部分を書くのが面倒
    2'h1:    func = 4'h2;
    2'h2:    func = 4'h4;
    2'h3:    func = 4'h8;
    default: func = 4'hx;
  endcase
endfunction

セレクタなどで書く頻度が多い割に,毎回ヤンクするのも面倒でしたので自動的に挿入してくれるコマンドを作ってみました.
上記の例では":VerilogInsertCaseList 2 4 func"と打ち込むと

    2'h0:    func = 4'h
    2'h1:    func = 4'h
    2'h2:    func = 4'h
    2'h3:    func = 4'h
    default: func = 4'hx;

と挿入されます.第一引数はラベルのbit数,第二引数は右辺のbit数,第三引数は左辺の変数名を指定します.
default:以外の右辺が途中で止まってる(;すらない)のは仕様で,ここは手入力するようにしてます.
;までタイプしたらjですぐ下の部分を書き込めるようにしたかったので.

ソース

autocmd FiletypeAutoCmd FileType verilog call <SID>FileType_verilog()
function! s:FileType_verilog()
  command! -buffer -nargs=+ VerilogInsertCaseList call <SID>VerilogInsertCaseList(<f-args>)
endfunction

function! s:VerilogInsertCaseList(l_num, r_num, name)
  let l:pat = '^\(\d\+\)$'
  if(a:l_num =~? l:pat && a:r_num =~? l:pat)
    let l:l_bit = float2nr(ceil(str2nr(a:l_num)/4.0))
    let l:r_bit = float2nr(ceil(str2nr(a:r_num)/4.0))

    let l:lab_len = strlen(a:l_num) + 2 + l:l_bit
    let l:def_len = strlen('default')
    let l:lab_rep = (l:def_len > l:lab_len) ? l:def_len - l:lab_len : 0
    let l:def_rep = (l:def_len > l:lab_len) ? 0 : l:lab_len - l:def_len

    if(&l:expandtab)
      let l:indent = repeat(' ', indent('.')) " expandtab
    else
      let l:indent = repeat("\t", indent('.') / &l:tabstop) " noexpandtab
    endif

    let l:format = a:l_num . "'h%0" . l:l_bit . 'x:'

    let l:size = float2nr(pow(2, str2nr(a:l_num)))
    let l:i    = 0
    let l:list = []

    while(l:i < l:size)
      let l:str = l:indent . printf(l:format, l:i) .
            \ repeat(' ', l:lab_rep) . ' ' . a:name . ' = ' . a:r_num . "'h"
      call add(l:list, l:str)
      let l:i += 1
    endwhile

    let l:str = l:indent . 'default:' . repeat(' ', l:def_rep) .
          \ ' ' . a:name . ' = ' . a:r_num . "'h" . repeat('x', l:r_bit) . ';'
    call add(l:list, l:str)

    call append(line('.'), l:list)
  endif
endfunction

インデントを作ってる部分(l:indent)はこんなので良いのでしょうか?もうちょっとうまいやり方があるのかもしれません.
ほんとは":VerilogInsertCaseList 2b 4h func"のようにbinaryやhexでも指定できるようにしたかったのですが,vimのprintf()が変換指示子として%bを持っていないのであきらめました.