aki_iic’s blog

己の欲せざる処人に施す事無かれ、狂人の真似するは即ち狂人なり

bus error例外と下手の考え休むに似たり

 迂遠を重ねてbus error例外検出・生成用ステートマシン(3ビットジョンソンだけど)をこしらえたので記す。

1.基本的な考え方

 バスエラーは/ASがnegateされず(=dsack_nが所定時間以内にアサートされず)busがlockされるのを防ぐCPU側の仕掛けで具体的には/ASがアサートされてから所定時間内にネゲートされなければ/BERRをアサートする時間監視回路を構成すれば良い。この所定時間は適時適当で良く9〜12μS程度にする場合が多い(と思われる)。根拠はと言えばDRAMのリフレッシュサイクル(2ms/128cyc=15.6us)より短めの値でそのくらいなのでは?と勝手に考えているが極端に長い(数百usとか)で無ければ良い。Normal not ready系のバスアーキテクチャではbus errorの概念は有る(PCIとか)ので一般的と思われる。x86系は伝統的にNormal ready系が多いと思っているのでこの回路は実装されない(のでは?)。

2.実装方針

 バスロック防止の為の安全回路故上記所定時間含めて実装方法は色々あるが例によってマクロセル消費を少なく楽に実装するつもりが色々迂遠する羽目になってしもうた。これは構成を真面目に考えてなかった(所謂詰めが甘い)のが原因で結局の処

2.1 バスエラー監視時間はリフレッシュクロック(16usを想定)を非同期データとしてそれの0.5〜1.5cycleを検出する。平たく言えばリフレッシュクロックのL->H->Lをステートマシンで検出して各ステートにas_bがネゲートされたら最初のステートに戻る(タイムアウトしないで正常にバスサイクル終了)をネチネチ組み込む羽目になった。

3.verilogコード(抜粋)

 200行近くになってポイントが分からなくなってきたので該当するコードだけ抜き出す↓

    reg [2:0] besq,nbesq ; // bus error sequencer

// state register
    always @( posedge sysclk or negedge reset_b ) begin
        if ( ~reset_b )
            begin
                drsq <= S0 ;
                rfsq <= R0 ;
                besq <= S0 ;
            end
        else
            begin
                drsq <= ndrsq ;
                rfsq <= nrfsq ;
                besq <= nbesq ;
            end
    end

// bus error sequence
    always @( besq or refclk or as_b ) begin
        case ( besq )
            S0 : if ( as_b && ~refclk )
                    nbesq <= S0 ;
                else
                    nbesq <= S1 ;
            S1 : if ( ~as_b && refclk )
                    nbesq <= S2 ;
                else
                    if( as_b )
                        nbesq <= S0 ;
            S2 : if ( ~as_b && ~refclk )
                    nbesq <= S3 ;
                else
                    if ( as_b )
                        nbesq <= S0 ;
            S3 : if ( ~as_b && refclk )
                    nbesq <= S4 ;
                else
                    if ( as_b )
                        nbesq <= S0 ;
            S4 : nbesq <= S5 ;
            S5 : if ( ~as_b )
                    nbesq <= S5 ;
                else
                    nbesq <= S0 ;
        endcase
    end

    assign berr_n = ~( ~besq[1] & besq[2] ) ;            

 ジョンソンの一つ覚えで毎度同様のパタンだが私にとってジョンソンカウンタやグレイコードカウンタは楽して安定したステートマシンを構成できる「定跡」故この程度の回路規模ではこの手が私には最適解と考えている。今時このような低レベルなコーディングはしないのかもしれないが所詮道楽故。

4.テストベンチ(抜粋)

parameter REF = 16*1000*1000; // 16us

always begin
    refclk = 1 ; #(REF/2) ;
    refclk = 0 ; #(REF/2) ;
end
task berr_cyc ;
    input [7:0] adr ;
begin
#(STEP);
    a = adr ;
#(STEP);
    as_b = 0 ;
#(STEP);
    wait(~berr_n) ;
#(STEP*2*4);
    as_b = 1 ;
#(STEP*2*10);
end
endtask

initial begin
    $display("シミュレーション開始");
    $dumpfile("dramc_tp.vcd");
    $dumpvars(0,dramc);
//    $monitor("cpuclk = %b reset_b = %b as_b = %b dsack_n = %b refclk %b a = 8'h%x",cpuclk,reset_b,as_b,dsack_n,refclk,a);
    sim_init ;
    dram_cyc(8'h80);
    dram_cyc(8'h81);
//    dram_cyc(8'h12);
//    io_cyc(8'h00,1);io_cyc(8'h00,0); // psd area
//    io_cyc(8'hf0,1);io_cyc(8'hf0,0); // rtc area
//    io_cyc(8'hf1,1);io_cyc(8'hf1,0); // 16550 area
//    io_cyc(8'hf2,1);io_cyc(8'hf2,0); // ft245 area
//    irq_cyc(7'b1000000);irq_cyc(7'b0100000);irq_cyc(7'b0010000);irq_cyc(7'b0001000);
//    irq_cyc(7'b0000100);irq_cyc(7'b0000010);irq_cyc(7'b0000001);
    berr_cyc(8'h12);
    io_cyc(8'hf0,1);io_cyc(8'h0,1);
    $display("シミュレーション終了");
    $finish ;
end

 berr_cyc(a31:24の上位8bit)が今回追加したtaskでwait文でberr_nがassertされる迄待つのでバグってると無限待ちになります(マズイ)。

4.iverilog+GTKwaveでのシミュレーション波形

f:id:aki_iic:20211120074345p:plain

bus error

 berr_nのアサートタイミングがrefclkのエッジ(非同期)に依存するがそれは別途カウンタを設けても同じなので気にしない。。。

 (ジジイには)みづらいのでprintイメージの白黒画面も付けておく。

f:id:aki_iic:20211120075131p:plain

bus error timing (BW)

5.合成結果(ise14.7 20131013版)

cpldfit:  version P.20131013                        Xilinx Inc.
                                  Fitter Report
Design Name: dramc                               Date: 11-20-2021,  2:05AM
Device Used: XC95108-20-PC84
Fitting Status: Successful

*************************  Mapped Resource Summary  **************************

Macrocells     Product Terms    Function Block   Registers      Pins           
Used/Tot       Used/Tot         Inps Used/Tot    Used/Tot       Used/Tot       
46 /108 ( 43%) 91  /540  ( 17%) 87 /216 ( 40%)   21 /108 ( 19%) 42 /69  ( 61%)

 マクロセル使用率 46/108(43%),Pin使用率 42/69(61%)とマクロセル緊縮財政効果が現れてる?かもしれない。まだPC104系バスインタフェースが未実装故(他の忘れてる・抜けてる機能含めて)インプリ不可能状況に陥る可能性は回避出来そうな気がしてきた。。。

6.その他

 タイトルはこの構成に辿り着く迄にrefclk/4をカウントしたり/asで非同期クリアのカウンタ構成にしてみたり(大昔作ったLSIではこの部分だけ非同期回路であった。)sysclk/cpuclkから愚直にカウントしてみようと考えたり(マクロセル節約方針に反するので脳内却下したが)期待通りにシミュレーション出来なくてその原因を思いつかない場合に実態を確認せず思い込みで行動すると無為に時間と労力と気力を浪費してしまう教訓で最近の座右の銘ランク上昇中の言葉でもある。誰しも下手に埋没するのを潔しとせぬ故それに纏わる行為を努力と呼ぶのかもしれない(しみじみ)。