Compact Flash(というかPC104)風iocycleとマクロセルメタボリックシンドローム

 Compact Flash(以下CF)もobsolute化進行中のストレージだがSDcardコントローラを書く(ハード/ソフト含めて)能力も無く伝統のTrue IDE modeを想定する。

1.基本タイミング

 ネットで拾ったCFのデータシート(確か日立製作所)からTrue IDEのタイミングを以下に引用する。

・True IDE mode read timing

f:id:aki_iic:20211127161114p:plain

true ide mode read

・True IDE mode write timing

f:id:aki_iic:20211127161208p:plain

true ide mode write

 あまりの遅さに若い方は失神されるかもしれないが20世紀のデバイスはこんなもんだったんです。なのでそれに合わせる為に(主にtsuA(IORD/IOWR),tw(IORD/IOWR)を満たす為のタイミング生成(とdsack生成)がステートマシンのお仕事になる。

2.ステートダイヤグラム

 今回はiverilog-gtkwaveで試行錯誤した構成から逆生成したので正確さはあるが緊張感に欠けるかもしれない。

f:id:aki_iic:20211127161911p:plain

cf iosq (graphviz)

graphvizのコード( .dot )

// 2021/11/27 : verilogコードとgtkwaveから逆生成
// 2021/11/23 : CF用iosqを再整理、特にdsack
// ステートの割当て
//S0(000) : a == CF && as_b == 0 , wcnt <= w1
//S1(001) : wait w1 , wcnt <= w2
//S2(011) : wait w2
//S3(111) : wait ~cpuclk , wcnt <= w3
//S4(110) : wait w3 
//S5(100) : wait as_b

digraph {
    //rankdir=LR;
    graph [ layout = dot ];
    node [shape = doublecircle]; S0 S1 S2 S3 S4 S5 ;
    node [shape = parallelogram]; CF_iocycシーケンス;
    node [shape = ellipse]; iosq;
    node [shape = rarrow]; cf_ce_n cf_iord_n cf_iowr_n dsack_n;
    CF_iocycシーケンス -> S0 [ label = "CF iocyc制御" ];
    S0 -> S1 [ label = "a == CF && as_b == 0 , wcnt <= w1" ];
    S1 -> S2 [ label = "wait w1 , wcnt <= w2"];
    S2 -> S3 [ label = "wait w2" ];
    S3 -> S4 [ label = "wait ~cpuclk , wcnt <= w3" ];
    S4 -> S5 [ label = "wait w3"];
    S5 -> S0 [ label = "wait as_b == 1" ];
    S1 -> cf_ce_n [ label = "Assert cf_ce_n" ];
    S5 -> cf_ce_n [ label = "Negate cf_ce_n" ];
    S2 -> cf_iord_n [ label = "cpurw=read,Assert cf_iord_n" ];
    S5 -> cf_iord_n [ label = "Negate cf_iord_n" ];
    S2 -> cf_iowr_n [ label = "cpurw=write,Assert cf_iowr_n" ];
    S4 -> cf_iowr_n [ label = "Negate cf_iowr_n" ];
    S3 -> dsack_n [ label = "Assert dsack_n"];
    S5 -> dsack_n [ label = "Negate dsack_n"];
    S0 -> S0 [ label = "wait iocyc start"];
    S1 -> S1  [ label = "wait w1 sysclk"];
    S2 -> S2  [ label = "wait w2 sysclk"];
    S3 -> S3  [ label = "wait cpuclk=0"];
    S4 -> S4  [ label = "wait w3 sysclk"];
    S5 -> S5  [ label = "wait as_b"];
    S0 -> iosq ;
    S5 -> iosq ;
}

 graphvizマジック?で3bit johnsonカウンタのステートダイヤグラムが何かごちゃごちゃやってる様に見える不思議。graphvizは読む側は知れぬが書く側には優しい。

今回はw1,w2,w3なる待ち時間を生成してそれを元に各タイミングを生成するのがお仕事になる。

3.コードに落とす為の設計メモ

 タイミングチャートからステートダイヤグラムを設計しCPLDのコードに落とす前に各ステートの細目とベースカウンタ(例によってジョンソンカウンタ)から生成する各タイミングを整理しておく。

// 2021/11/23 : CF用iosqを再整理、特にdsack

S0(000) : a == CF && as_b == 0 , wcnt <= w1
S1(001) : wait w1 , wcnt <= w2
S2(011) : wait w2
S3(111) : wait ~cpuclk , wcnt <= w3
S4(110) : wait w3 
S5(100) : wait as_b

L0 : S0                 S3
L1 :      S1                   S4
L2 :            S2                      S5

w1 : □---□
w2 :      □----□
w3 :                     □-----□

ce : ○---------------------------------○
rd :      ○----------------------------○
wr :      ○--------------------○
ak :                     ○-------------○

ce = L0 | L2
rd = L1 | L2
wr = L1
ak = !L0 & L2

 我流メモで意味不明な点はご容赦。

4.1 verilogコード(抜粋)

// CF bus cycle sequence
    always @( cpuclk or iosq or a or as_b ) begin
        case ( iosq )
            S0 : if ( as_b == 0 && a == cf ) begin
                    nwcnt <= 0 ; //4'd4 ;
                    niosq <= S1 ;
                end
                else
                    niosq <= S0 ;
            S1 : if ( wcnt != w1 ) begin
                     nwcnt <= wcnt + 1 ;
                     niosq <= S1 ;
                end
                else begin
                    nwcnt <= 0 ; 
                    niosq <= S2 ;
                end
            S2 : if ( wcnt != w2 ) begin
                    nwcnt <= wcnt + 1 ;
                    niosq <= S2 ;
                end
                else
                    niosq <= S3 ;
            S3 : if ( ~cpuclk )
                    niosq <= S3 ;
                else begin
                    niosq <= S4 ;
                    nwcnt <= 0 ;
                end
            S4 : if ( wcnt != w3 ) begin
                    nwcnt <= wcnt + 1 ;
                    niosq <= S4 ;
                end
                else
                    niosq <= S5 ;
            S5 : if ( as_b )
                    niosq <= S0 ;
                else
                    niosq <= S5 ;
        endcase
    end

    assign cf_ce_n = ~( ( iosq[0] | iosq[2] ) & ~as_b ) ;
    assign cf_iord_n = ~( ( iosq[1] | iosq[2] ) & ~as_b & cpurw ) ;
    assign cf_iowr_n = ~( iosq[1] & ~as_b & ~cpurw) ;

    assign dsack_n = ~((~iosq[0] & iosq[2]) ) ;

4.2 テストベンチ(抜粋)

task cf_cyc ;
    input [7:0] adr ;
    input rw ;
begin
#(STEP);
    a = adr ;
    cpurw = rw ;
#(STEP);
    as_b = 0 ;
    if(cpurw)
        ds_b = 0 ;
#(STEP);
    if(~cpurw)
        ds_b = 0 ;
//    wait(~dsack_n);
#(STEP*2*7);
    as_b = 1 ; ds_b = 1 ;
#(STEP);
    cpurw = 1 ;
#(STEP*3);
end
endtask

4.3 シミュレーション結果(iverilog + gtkwave)

f:id:aki_iic:20211127164137p:plain

cf iosq simulation (iverilog + gtkwave)

・印刷形式

f:id:aki_iic:20211127180456p:plain

cf iosq simulation (BW)

 遅まきながら`timescale 1ns / 100psに設定したのでまともな時間軸になってる筈。

5.合成結果(或いは今回のオチ)

cpldfit:  version P.20131013                        Xilinx Inc.
                                  Fitter Report
Design Name: dramc                               Date: 11-24-2021, 11:30PM
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       
71 /108 ( 66%) 154 /540  ( 29%) 115/216 ( 53%)   33 /108 ( 31%) 46 /69  ( 67%)

 いつの間にやらマクロセル使用率が66%に増加している。前回の構成から25MC増加してるのは流石におかしいと色々調べてみたが原因判明せず。ベースカウンタを4ビットジョンソンにしてwcntカウンタを除去(FF数は減ってる筈)したら逆に75MCになってしまいこれがタイトルの所以である。もっとも今時の湯水の如くマクロセルなりロジックブロックを使えるデバイスからしたら108MCなぞ無いのと同じであろうが5V系のobsoluteなCPLD(且つIMTの世界)では今後の回路ブロック更新は慎重にならざるを得ない。。。