3.3 順序回路

Web版 Verilog-HDL入門

3.3 順序回路

記憶素子を用いた代表的な下の回路を紹介します。

  • カウンター
  • シフトレジスタ

カウンター

順序回路の代表です。頻繁に使用します。

下にリセット+クロックイネーブル付き8bitカウンタを示します。

    reg     [7:0]   Q           ;

    always@ (posedge CLK) begin
        if(RST)begin
            Q[7:0]  <= 8'd0;
        end else begin
            if(CE)begin
                Q[7:0]  <= Q[7:0] + 8'd1;
            end
        end
    end

基本的にはDFFの記述と同じです。算術演算+が登場している事と自分自身の出力が入力に戻ってきている事が異なります。

コードを読みやすくするためにキャリーを意図的に信号名を変えて表現したい時があります。その時は下の様に書きます。

    reg     [6:0]   Q           ;
    reg             carry       ;

    always@ (posedge CLK) begin
        if(RST)begin
            {carry,Q[6:0]}  <= 8'd0;
        end else begin
            if(CE)begin
                {carry,Q[6:0]}  <= {carry,Q[6:0]} + 8'd1;
            end
        end
    end

シフトレジスタ

シフトレジスタは複数のDFFを直列に接続した回路です。

この回路を素直にHDLへ変換すると下の様になります。

    reg     [3:0]   Q           ;

    always@ (posedge CLK) begin
        Q[0]  <= D;
    end

    always@ (posedge CLK) begin
        Q[1]  <= Q[0];
    end

    always@ (posedge CLK) begin
        Q[2]  <= Q[1];
    end

    always@ (posedge CLK) begin
        Q[3]  <= Q[2];
    end

これは正しいですが読みにくいです。読みやすくするために、下の様にalways文一つに入れる事が出来ます。

    reg     [3:0]   Q           ;

    always@ (posedge CLK) begin
        Q[0]  <= D;
        Q[1]  <= Q[0];
        Q[2]  <= Q[1];
        Q[3]  <= Q[2];
    end

この文を注意深く見るとマルチビット表現を使用すると下の様に簡単に書ける事が分かります。

    reg     [3:0]   Q           ;

    always@ (posedge CLK) begin
        Q[3:0]  <= {Q[2:0],D};
    end

これが代表的なシフトレジスタの記述法です。

ステートマシン

制御回路の設計でステートマシンは便利な記述です。

例えば下の状態遷移図を持つステートマシンの記述について考えてみます。

動作を簡単にせつめいします。丸の中の数字はSate(出力状態)を表しています。システムリセットが入力されるとClear stateになりENB=L, RST=Hになります。Start=HでCount state(ENB=H, RST=L)へ遷移します。さらにその後Stop=Hが入力されるとHold sate(ENB=L, RST=L)になります。Start=LおよびStop=LになるとClear stateへ戻ります。

これをVerilog-HDLで記述する方法は幾つかありますが、ここではcase文を使用して記述してみます。

    reg   [1:0]   State   ;

    always@ (posedge CLK) begin
        if(SYS_RST)begin
            State[1:0] <= 2'b01;
        end else begin
            case(State[1:0])
                2'b01:begin  Clear
                    if(Start)begin
                        State[1:0] <= 2'b10;
                    end else begin
                        State[1:0] <= 2'b01;
                    end
                end

                2'b10:begin // Count
                    if(!Start & !Stop)begin
                        State[1:0] <= 2'b01;
                    end else if(Stop)begin
                        State[1:0] <= 2'b00;
                    end else begin
                        State[1:0] <= 2'b10;
                    end
                end

                2'b00:begin // Hold
                    if(!Start & !Stop)begin
                        State[1:0] <= 2'b01;
                    end else begin
                        State[1:0] <= 2'b00;
                    end
                end
                default:begin
                    State[1:0] <= 2'b01;
                end
            endcase
        end
    end