DoxygenのようにHDLモジュールのドキュメントを簡単に作れるツールが欲しいです。しかたなく、自作することにしました。
困っていること
(1)インターフェース
モジュールの左に入力信号、右に出力信号という感じで作図するのは簡単にできそう。でも、valid-readyのようにセットの信号が右と左に泣き別れになるのはよくないですよね。
(2)タイミングチャート
当たり前ですが、モジュールのGerericやPortを切り出しても、タイミングやプロトコルはさっぱりわからない。タイミングチャートとか手書きするしかないかな。
クロックと、ロジックやデータをかけばよいのですが、困るのがクロックとの位相関係がいろいろあること。クロックと同期して出力されるレジスタ、クロックと非同期の信号、クロックより少し遅れて出力がでてくるメモリ読み出しデータ。
これらをちゃんと書きわけられないと、チャートをみても因果関係がさっぱりわからない。
というわけで
タイミングチャートを描いてくれるページをつくりました。 [ここです] (http://cgi1.plala.or.jp/~hbf/ppVhdl/ppTimeChart.cgi?sigdata=)解説はご要望があれば。
// 1行で1つの信号を記述
// 基本形
// <name>:<type>:<description>
//
// TYPE
// 0 : キャプション
// 1 : クロック
// 2 : ロジック <name>:2:<pos>[Pp]<dur>_annotation
// <pos>: 開始位置
// <dur>: 継続長
// P : レジスタ出力を想定したパルス(クロック同期)
// p :コンビネーション出力を想定したパルス
// 3 : バス <name>:2:<pos>[DdMm]<dur>_annotation
// D : レジスタ出力を想定したバス出力(クロック同期)
// d : コンビネーション出力を想定したバス出力
// M : メモリ出力を想定したバス出力(クロック同期だが少し遅れる)
// m : メモリ出力を想定したバス出力
:0:キャプション
CLK:1:
rd_en:2:3P
data:3:3m1_data

コード
せっかくなのでQiitaらしくコードも置いておきます。
perl書きらしく刹那的なコードですが
//こんな感じにジオメトリ情報をセットして
const WIDTH=400;
const HEIGHT=300;
//--
const ROW_HEIGHT=20;//行の高さ
const LOGIC_HEIGHT=15;//ハイレベルの高さ
const NAME_LEFT=5; //信号名開始位置
const SIG_LEFT=50; //信号描画領域左端
const SIG_RIGHT=380; //同 右端
const SIG_WIDTH=(SIG_RIGHT-SIG_LEFT);
//--
const TICK_START=0;
const CLK_OFSET=5; //クロックエッジまでの時間
var TICK_COUNT=10; //作画するクロック数
var TICK_WIDTH=SIG_WIDTH/TICK_COUNT;
//コンテキストと、Y方向の位置、パラメータを指定してdraw_CLK()とかdraw_logic()とか呼ぶ
// クロックと、偶数クロックの背景を描く
function draw_CLK(ctx,Y_BASE){
//---背景
ctx.fillStyle = "rgb(240,240,240)";ctx.lineWidth=1;
for(var i=0;i<TICK_COUNT;i+=2){
var x=i*TICK_WIDTH+SIG_LEFT+CLK_OFSET;
var yh=Y_BASE-LOGIC_HEIGHT;
ctx.fillRect(x,yh,TICK_WIDTH,HEIGHT-5-yh);
}
//
ctx.moveTo(SIG_LEFT,Y_BASE);
ctx.lineTo(SIG_LEFT+CLK_OFSET,Y_BASE);
for(var i=0;i<TICK_COUNT;i++){
var x=i*TICK_WIDTH+SIG_LEFT+CLK_OFSET;
ctx.lineTo(x,Y_BASE-LOGIC_HEIGHT);
ctx.lineTo(x+TICK_WIDTH/2,Y_BASE-LOGIC_HEIGHT);
ctx.lineTo(x+TICK_WIDTH/2,Y_BASE);
ctx.lineTo(x+TICK_WIDTH ,Y_BASE);
}
ctx.stroke();
}
function draw_logic(ctx,Y_BASE,sLogic){
var aLogic=sLogic.split(",");
var pos=0,clogic="L",logic=0,dur="-1";
var x=0*TICK_WIDTH+SIG_LEFT;
//
ctx.fillStyle = "blue";
ctx.moveTo(x,Y_BASE);
for(var i=0;i<aLogic.length;i++){
var code=aLogic[i];
var m=code.match(/^(\d*\.?\d*)([PpMm]?)(\d*\.?\d*)_?([A-z0-9]*)$/);
if(m == null) return;
var apos=0,dpos=1;
// 1 apos, 2 logic, 3 dpos
/*if(m[3] == null){//ロジック指定なし。反転
dpos=m[1]+0;apos=0;
}*/
apos=Number(m[1]); dpos=Number(m[3]);
if (dpos==0)dpos=1;
var offset=0;
if (m[2]==="p"){
offset = CLK_OFSET/2;
}
if ((m[2]==="M") || (m[2]==="m")){
offset = CLK_OFSET*2;
}
var newpos=apos;
if (newpos >= pos){
//あたらしいところまで線を引く
x=newpos*TICK_WIDTH+SIG_LEFT+offset;
ctx.lineTo(x,Y_BASE-logic*LOGIC_HEIGHT);
// P
logic=1;
ctx.lineTo(x,Y_BASE-logic*LOGIC_HEIGHT);
newpos += dpos;
if(m[4] != null){
ctx.fillText(m[4],NAME_LEFT+x,Y_BASE-LOGIC_HEIGHT/5);
}
x=newpos*TICK_WIDTH+SIG_LEFT+offset;
ctx.lineTo(x,Y_BASE-logic*LOGIC_HEIGHT);
logic=0;
ctx.lineTo(x,Y_BASE-logic*LOGIC_HEIGHT);
pos=newpos;
//
}
}
if(pos<TICK_COUNT){
pos = TICK_COUNT;
x=pos*TICK_WIDTH+SIG_LEFT;
ctx.lineTo(x,Y_BASE-logic*LOGIC_HEIGHT);
}
ctx.stroke();
}
...
追記
こちらのサイトがよいかも https://wavedrom.com