小ネタということで、以前 verilog を書くために作った emacs lisp を紹介。
この lisp は、/*auto-script 〜 */で囲まれた部分を任意のコマンドに流して、
その結果を挿入する。
例えば、C 言語で sin table (例えば1.31の固定小数点) を埋め込みたいとする。
(PC じゃないかもしれないけど、組み込みとかなら有り得る)
そんなとき auto-script があれば、ちょろっとコードを書いて、
M-x auto-script してあげれば、以下のように即席でテーブルが埋め込まれる。
int sin_table[256] = {
/*auto-script (ruby)
for i in 0..255
printf "0x%08x,", Math.sin(i * Math::PI / 256) * (1 << 23)
if i % 8 == 7
print "\n"
end
end
*/
0x00000000,0x0001921d,0x0003242a,...
(中略)
0x000c8bd3,0x000afb68,0x00096a90,...
// End of auto-script
};
コードを修正したければ、コメント内の ruby のコードを書き換えて M-x auto-script。
auto-script の直後の (ruby) で言語を指定。(〜)表記を省略すると ruby が選択される。
同じコード内に auto-script が沢山できると、
共通の初期化コードが必要になることがある。
その場合は、
/*auto-script-init
初期化コード
*/
とすれば、その初期化コードがブロック毎の先頭に挿入されたものとして扱われる。
普通 C とかなら、こんなことは要らないのですが、
verilog って言語仕様がいわゆるソフトウェア記述言語と比べると、
あまりに貧弱で冗長なので、こういったプリプロセスが
必要になるときがあるんです。
といっても、verilog-mode で大部分の内部配線は完全自動化 (auto-template系)、
さらに Verilog-2001 が使えるなら generate 文でかなり冗長さは無くせますが。
やっぱり、それでも冗長なのが verilog なんですな。
(正確には verilog に限らず RTL 全般。verilog は VHDL と比べればまだましかも)
ほんと、効率悪すぎ。
今日は 16KBも コード書いたー!って思ったら、殆どが verilog-mode の
自動配線とかあるしな。これらのツールが無かったらマジ終わってる言語ですよ。
というわけで、以下コード。
.emacs に貼り付ければ多分動く。
lisp はよく分かってないので、直情的な書き方していて、不味い部分もあるかもしれない。
変なところがあったら教えてくださると助かります。
; --------------------------------
; auto script (by mnishibe)
(defun auto-script ()
"auto-script"
(interactive)
(let (st end run-string run-init-string ret-string point-kill-end
(cmdname "ruby")
(tmp-buffer (get-buffer-create "*auto-script-tmp*"))
)
(save-excursion
(setq run-init-string "")
(goto-char (point-min))
(if (search-forward "/*auto-script-init" nil t)
(progn
(setq st (point))
(search-forward "*/")
(setq end (match-end 0))
(setq run-init-string (buffer-substring (+ st 1) (- end 2)))
(goto-char end)
)
)
(while (search-forward "/*auto-script" nil t)
(goto-char (match-end 0))
(if (looking-at "[\s\t]*(\\([a-zA-Z0-9_.]+\\))")
(progn
(setq cmdname (buffer-substring (match-beginning 1) (match-end 1)))
(goto-char (match-end 0))
)
)
(setq st (point))
(search-forward "*/")
(setq end (match-end 0))
(if (search-forward "// End of auto-script" nil t)
(progn
(setq point-kill-end (point))
(unless (search-backward "/*auto-script" end t)
(kill-region end point-kill-end)
)
)
)
(setq run-string (buffer-substring (+ st 1) (- end 2)))
(save-current-buffer
(message "run auto-script...")
(set-buffer tmp-buffer)
(insert run-init-string)
(insert run-string)
(call-process-region (point-min) (point-max) cmdname t t)
(setq ret-string (buffer-substring (point-min) (point-max)))
(erase-buffer)
)
(goto-char (+ end 1))
(insert ret-string "// End of auto-script\n")
(indent-region (+ end 1) (point) nil)
(message "finish auto-script...")
)
)
)
)