key word :
AND , OR , Ex-OR , NOT , Half-Adder , Full-Adder
下位モジュールとの接続方法(順番・名前) 7セグメントデコーダー
001の方では大まかな構成を書いたので、今回は論理回路の記述を。
・AND
Verilog 記述 | 真理値表 | 記号 | |||||||||||||||
module name(a,b,z); input a,b; output z; assign z = a & b; end module |
|
![]() |
あと、ここで説明することとしたら [X:0] の記述。
これは信号のビット長を定めるもので、8bitの信号を扱いたい場合は[7:0]って記述するのが一般的です。(7 downto 0)
一応[0:7]とか[8:1]って書いても大丈夫なんですけど、最下位bitが0bit目ってのが一番慣れ親しんでると思うんで、[7:0] で進めていきます。
7bit | 6bit | 5bit | 4bit | 3bit | 2bit | 1bit | 0bit |
・OR
Verilog 記述 | 真理値表 | 記号 | |||||||||||||||
module name(a,b,z); input a,b; output z; assign z = a | b; end module |
|
![]() |
OR。それ以上でもそれ以下でもない。
・Ex-OR
Verilog 記述 | 真理値表 | 記号 | |||||||||||||||
module name(a,b,z); input a,b; output z; assign z = a ^ b; end module |
|
![]() |
あんまり使わないから、久しぶりに使うときどっちが1だったか忘れてしまったり。
・Not
Verilog 記述 | 真理値表 | 記号 | ||||||
module name(a,b,z); input a; output z; assign z = ~a; end module |
|
![]() |
否定。
とりあえず最低限の記述はこんなもんです。
・半加算器 Half-Adder
Verilog 記述 | 真理値表 | 記号 | ||||||||||||||||||||
input x,y; output z,c; assign z = x ^ y; assign c = x & y; |
|
![]() |
半加算。
入力した2つの値を加算し、その出力と桁上がり分を出力
真理値表を見ての通り、桁上がり無しの出力zはEx-ORの値。
桁上がりの分はANDの値。
・全加算器 Full-Adder
Verilog 記述 | 内容 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
module HA(x,y,z,c); input x,y; output z,c; assign z = x ^ y; assign c = x & y; endmodule input x,y,Cin; output Zout,Cout; wire z1,c1,c2 HA HA_1(x,y,z1,c1); HA HA_2(.x(z1),.y(Cin),.z(Zout),.c(c2)); assign Cout = c2 ^ c1; |
全加算。 半加算器の入力に、桁上がり分を追加 Haを組み合わせて記述。 Verilog記述の上部に記述してあるのHAがモジュール名で、作った各.vファイルの最初に定めたmodule名と同じ。 別のファイルで作ってある。 一応、同一のファイル内に記述して後で呼び出してもRTLシミュでは動くが、 ゲートシミュで使うツールでは駄目な場合があるのでモジュール毎に分けるのが吉 下部でのHA_1,HA_2は、インスタンス名で、このモジュール内で使用する際の個別の名前 functionが回路内部に記述するのに対し、外部にある回路といったイメージである。 HA_1では、ポートリスト順による接続をしており、モジュールHAに記述されている順に値が代入される。 使用する値が少なく、構造も簡単な場合は手間がかからず楽であるが、 信号数が増え、接続が複雑になるとHA_2の様な名前による接続を行ったほうが 見ただけで判るので良い。 他人に判り易く、後から記述を見ても判り易いという事を考えると、後者の方が優れている。 |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
真理値表 | 記号 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
![]() |
・下位モジュールとの接続に関して
module HA(x,y,z,c);
input a,b;
output z,c;
assign z = x ^ y;
assign c = x & y;
endmodule
↑呼び出し対象
・順番による接続
HA HA_1(x,y,z1,c1);
名前の通り、呼び出し側モジュールで値が宣言されている順にならって値を代入。
xにはxを yにはyを zにはz1を cにはc1を入れる。
HA HA_1(z1,c1,x,y);
逆に↑の様に記述すれば
xにはz1を yにはc1を zにはxを cにはyが代入される。
・名前による接続
HA HA_2(.x(z1),.y(Cin),.z(Zout),.c(c2));
同じく名前の通り、呼び出し対象のどの部分にどんな値を入れるかを記述。
.x( )ってのが、呼び出し対象側のxに相当。
最初はちょっと面倒に感じるかもしれないけれど、視覚的に判り易いのでこちらで慣れるのをお勧めします。
・7セグメントデコーダ
動作 | 真理値表 | 記号 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
a-gの信号がLの時に点灯。 |
|
![]() |
時間の入力信号qに対してそれをデコードし、入力信号に応じたデコード信号a-gを出力する。
真理値表より、 a が点灯する条件としては入力値A-Dが"0001"と"0100"の時であり、これを回路で表すと以下のようになる。
そして、Verilog記述は
assign a = (~A & ~B & ~C & D) | (~A & B & ~C & ~D); |
![]() |
assign e = (~A & D) | (~A & ~B & ~C) | (~B & ~C & D); 更に冗長項を利用すると assign e = D | (~B & ~C); となる。 今更カルノー図の説明は要らんよね? |
module segment(q,a,b,c,d,e,f,g); input [3:0] q; output a,b,c,d,e,f,g; assign a = (~q[3] & ~q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & ~q[1] & ~q[0]); assign b = (~q[3] & q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & q[1] & ~q[0]); assign c = (~q[3] & ~q[2] & q[1] & ~q[0]); assign d = (~q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & ~q[1] & ~q[0]) | (~q[3] & q[2] & q[1] & q[0]); assign e = (~q[3] & q[0]) | (q[3] & ~q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & ~q[1] & ~q[0]); assign f = (~q[3] & ~q[2] & q[1]) | (~q[3] & ~q[2] & q[0]); assign g = (~q[3] & ~q[2] & ~q[1]) | (~q[3] & q[2] & q[1] & q[0]); endmodule module segment(q,seg); input [3:0] q; output [6:0] seg; assign seg[6] = (~q[3] & ~q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & ~q[1] & ~q[0]); assign seg[5] = (~q[3] & q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & q[1] & ~q[0]); assign seg[4] = (~q[3] & ~q[2] & q[1] & ~q[0]); assign seg[3] = (~q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & ~q[1] & ~q[0]) | (~q[3] & q[2] & q[1] & q[0]); assign seg[2] = (~q[3] & q[0]) | (q[3] & ~q[2] & ~q[1] & q[0]) | (~q[3] & q[2] & ~q[1] & ~q[0]); assign seg[1] = (~q[3] & ~q[2] & q[1]) | (~q[3] & ~q[2] & q[0]); assign seg[0] = (~q[3] & ~q[2] & ~q[1]) | (~q[3] & q[2] & q[1] & q[0]); endmodule |
そんな訳でカルノー図を使い記述を楽にするのだけれど、それでも結構面倒だし、
第一式を見ただけじゃ何をやっているのか分からんです。 一応動きますけど。。 また、下の例のように配列に値を収めても構わないです。 |
module segment(q,segment); input [3:0] q; output [6:0] segment; reg [6:0]segment; always @(q)begin case({q}) 4'b0000 : segment = 7'b0000001; 4'b0001 : segment = 7'b1001111; 4'b0010 : segment = 7'b0010010; 4'b0011 : segment = 7'b0000110; 4'b0100 : segment = 7'b1001100; 4'b0101 : segment = 7'b0100100; 4'b0110 : segment = 7'b0100000; 4'b0111 : segment = 7'b0001101; 4'b1000 : segment = 7'b0000000; 4'b1001 : segment = 7'b0001100; default : segment = 7'b0000000; endcase end endmodule |
そこで登場するのが case文 qの値が 4'b000 だった場合 segment = 7'0000001;を行う って感じです。 予期しない値が入力された場合に備えてdefaultを定めるのはデフォ。 この場合のalwaysは、qが変化した際に動作するって意味。 |
ん〜、まだまだ書くことがあるけれど何だか長くなったので次回へー。