FlipFlopのRTL記述
次にフリップフロップ(FlipFlop)をHDLでどう記述するかを説明する。
FlipFlop(FF)とは値を記憶する素子であり、クロック(clk)というグローバルな信号の立ち上がりタイミングでのみ入力値 (in)を取り込み記憶する。また記憶している値は常に出力(d0_reg)している。
FFの動作をタイミングチャートで書くと下図のようになる。
たぶん初心者にとってわかりにくいのはFFを2つ直列接続したときの動作で、d1_regに入る値はd0_regの更新後の値でなく更新前の値になる。
もしソフトウェア言語で
d0_reg = in; d1_reg = d0_reg; |
と書くと、d1_regにはd0_regの更新後の値が代入されるが、デジタル回路ではクロックの立ち上がりタイミングで全レジスタが同時に代入されるので、HDLで書くと次のようになる。
クロック立ち上がり時に代入: d0_reg =前のin; クロック立ち上がり時に代入: d1_reg =前のd0_reg; |
このとき代入文を書く順序は任意でよいことに注意。
◇
Verilog言語ではFFの記憶値(=出力値)をreg変数で表し、reg変数への代入はalways文というもので書く。また代入の記号も(=)でなくノンブロッキング代入(<=)で書くが、とりあえずそういうものだと思えばよい。
reg d0_reg, d1_reg; always @(posedge clk) d0_reg <= in; always @(posedge clk) d1_reg <= d0_reg; |
reg変数への代入文の右辺はこの例では単なるreg変数になっているが、論理式やfunction文を書いてもよく、
always @(posedge clk) d0_reg <= a_reg & b_wire; always @(posedge clk) d1_reg <= func(a_reg,b_wire); |
さらに代入文自体をif文やcase文の中に入れてもよい。この場合はFFと組合せ回路をまとめて書いたことになる。
always @(posedge clk) begin if(s_wire) d0_reg <= a_reg & b_wire; else d0_reg <= c_wire; end |
◇◇
最後にreg変数とwire変数について整理しておく。これさえ理解しておけば、あとはソフトウェア言語のアナロジでVerilogも読めると思う。
【reg変数】 ・reg変数はnビットのFFを表すのに使う。 ・reg変数への代入はalways文内でノンブロッキング代入(<=)を使う。 ・代入文の右辺は、reg変数、wire変数の論理式またはfunction文を使う。 |
【wire変数】 ・wire変数は素子間の信号線を表すのに使う。 ・wire変数への代入はassign文でブロッキング代入(=)を使う。 ・代入文の右辺は、reg変数、wire変数の論理式またはfunction文を使う。 |