타이밍 차트를 그리고 싶다.

Doxygen처럼 HDL 모듈 문서를 쉽게 만들 수있는 도구를 원합니다. 뿐만 아니라, 자작하기로 했습니다.

어려움



(1) 인터페이스
모듈의 왼쪽에 입력 신호, 오른쪽에 출력 신호라고 하는 느낌으로 작도하는 것은 간단하게 할 수 있을 것 같다. 그렇지만, valid-ready와 같이 세트의 신호가 오른쪽과 왼쪽에 울고 헤어지는 것은 좋지 않네요.

(2) 타이밍 차트
당연하지만 모듈의 Gereric이나 Port를 잘라도 타이밍이나 프로토콜은 확실히 모른다. 타이밍 차트라든가 필기 밖에 없을까.

클럭과 로직이나 데이터를 걸면 좋지만, 곤란한 것이 클럭과의 위상 관계가 여러 가지 있는 것. 클럭과 동기하여 출력되는 레지스터, 클럭과 비동기 신호, 클럭보다 조금 늦게 출력이 나오는 메모리 읽기 데이터.

이것들을 제대로 쓸 수 없으면, 차트를 봐도 인과 관계를 깔끔하게 모른다.

그래서



타이밍 차트를 그려주는 페이지를 만들었습니다. 여기 해설은 요구가 있으면.
 // 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()とか呼ぶ

timechart.js
 // クロックと、偶数クロックの背景を描く
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();
}
...


추가



이 사이트가 좋을지도 h tps // 와ゔぇd m. 이 m

좋은 웹페이지 즐겨찾기