4

私はHDL言語に非常に慣れていません。シフトレジスタのプログラム方法について質問があります。(私は私が他の方向にシフトすることを知っています)。なぜ本は使うのwire[N-1:0] r_nextですか?私の実装の欠点は何ですか?ありがとう

私の最初の試みは次のとおりです

module lesson04#(parameter N=8)(
    input wire clk, reset,
    input wire data,
    output wire out
);

reg [N-1: 0] r_reg;


always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg =0;
    else 
        r_reg[0]=data;
        r_reg = r_reg<<1;
end

assign out =r_reg[N-1];
endmodule 

しかし、本は次のように述べています。

module lesson04#(parameter N=8)(
    input wire clk, reset,
    input wire data,
    output wire out
);

reg [N-1: 0] r_reg;
wire[N-1:0] r_next;

always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg =0;
    else 
        r_reg <= r_next;
end

assign r_next= {data, r_reg[N-1:1]};
assign out =r_reg[N-1];
endmodule
4

2 に答える 2

6

まず第一に、コードのセクションの周りの-sをbegin忘れないでください:end

else begin
     r_reg[0]=data;
     r_reg = r_reg<<1;
end

r_reg[0]=dataこれがないと、ステートメントのelse句にのみ含まれます。ifこれは機能しますが、シーケンシャルロジック記述のブロッキングステートメントのために悪いスタイルと見なされます...

次に、シーケンシャルブロックのモデリングには、ノンブロッキング割り当て(<=)を使用します。そうしないと、計算が「失敗」する可能性があります(詳細については、グーグルノンブロッキングとブロッキング)。あなたの例は非常にうまくいくかもしれませんが(シミュレーターで試してみましたか?)、物事がより複雑になり、より多くの変数が追加されると、物事が壊れる可能性があります。

always @(posedge clk or negedge reset)
begin
    if(!reset)
         r_reg <= 0;
    else begin // This is horrible! Don't write code like this!
        r_reg[0] = data;     // blocking
        r_reg <= r_reg<<1;   // non-blocking
    end
end

上記の理由から、コンボロジックをシーケンシャルロジックから分離して、シーケンシャルブロックのレジスタにノンブロッキング割り当てを書き込み、コンボブロックにブロッキングを記述して、スケジューリングについて心配する必要がないようにすることをお勧めします。

このようにコーディングするには、現在の状態を使用して次の出力がどうあるべきかを計算する必要があります。したがって、r_nextバスが答えになります。このようにすべてのフリップフロップを周囲のコンボロジックから分離すると、合成ツールも役立つと思います。

また、リセットがアクティブロー(つまりリセット)の場合は、またはLOWなどの名前を付ける必要があります。resetbreset_n

于 2010-08-19T13:17:39.533 に答える
3

あなたの実装は、本のそれとはかなり異なる出力を生成します。入力を駆動してシミュレーションを実行するための単純なテストベンチを構築することにより、これを自分自身に証明する必要があります。本の出力は入力データを1クロックサイクルだけシフトするのに対し、出力は入力データを8クロックサイクルだけシフトすることがわかります。

ちなみに、あなたはあなたのalwaysブロックをインデントしました、私はそれがあなたが望んでいたものではないと信じるように導かれます。これがあなたのブロックが実際にどのように振る舞うかです:

always @(posedge clk or negedge reset)
begin
    if(!reset) begin
         r_reg =0;
    end else begin
        r_reg[0]=data;
    end
    r_reg = r_reg<<1;
end

この混乱を避けるために、私は常にステートメントでbegin/endキーワードを明示的に使用します。if/else

r_reg1番目の割り当て(r_reg[0]=data;)を2番目の割り当て()で覆い隠すため、シミュレートする方法は常に0ですr_reg = r_reg<<1;。もう1つの違いは、本dataがシフトレジスタのMSBに割り当てているのに、LSBに割り当てていることです。

適切なリンティングおよび合成ツールを使用している場合は、コードに対して大量の警告が表示される可能性があります。これにより、いくつかの変更を行うように警告されます。

于 2010-08-19T13:19:57.657 に答える