第2週目の課題ページにある図をそのまま Verilog で記述すれば図1, 2, 3のようになる。
module HALF_ADDER(A, B, S, CO);
input A;
input B;
output S;
output CO;
assign CO = A & B;
assign S = (A | B) & ~CO;
endmodule
|
module FULL_ADDER(A, B, CI, S, CO);
input A;
input B;
input CI;
output S;
output CO;
wire U1_S;
wire U1_CO;
wire U2_CO;
HALF_ADDER U1 (.A(A), .B(B), .S(U1_S), .CO(U1_CO));
HALF_ADDER U2 (.A(U1_S), .B(CI), .S(S), .CO(U2_CO));
assign CO = U1_CO | U2_CO;
endmodule
|
module ADDER4(A, B, S, CO);
input [3:0] A;
input [3:0] B;
output [3:0] S;
output CO;
wire U0_CO;
wire U1_CO;
wire U2_CO;
HALF_ADDER U0 (.A(A[0]), .B(B[0]), .S(S[0]), .CO(U0_CO));
FULL_ADDER U1 (.A(A[1]), .B(B[1]), .CI(U0_CO), .S(S[1]), .CO(U1_CO));
FULL_ADDER U2 (.A(A[2]), .B(B[2]), .CI(U1_CO), .S(S[2]), .CO(U2_CO));
FULL_ADDER U3 (.A(A[3]), .B(B[3]), .CI(U2_CO), .S(S[3]), .CO(CO));
endmodule
|
2進数表記した2値に対する筆算による乗算例を図5に示す。
図4. 乗算例
例の場合は、乗数の第3, 2, 0 ビットが 1、第1ビットが 0 であり、被乗数1011 を 3, 2, 0 ビット左シフトして得られる3値の和を取ることにより積を得ることができる。一般に、乗数の各ビットの値を調べ、1となるすべてのビット(第iビットとする)について、被乗数をiビット左シフトして得られる値を求め、それぞれの和を取ることにより、積を得ることができる。ここで、図5 に示すようにバスAの各値と乗数の iビット目の値 B[i] の論理積(AND)演算により、B[i] が 1 であるとき被乗数 A、0であるとき全零になるバス ABi を得ることができる。
図5. ABi (i=0〜3) を求める回路
積YはABi (i=0〜3) をiビット左シフトして得られる値の総和をとることにより得られる。左シフト操作には特殊な回路を用いる必要はなく、配線を左にずらすことで実現できる。積Yは8ビット値で得られる。一般に積の桁数は、高々、被乗数と乗数の桁数の和である。この場合は被乗数と乗数の桁数は共に高々4桁であり、積の桁数も高々4+4=8桁となる。図6 に4ビット乗算器の構成を示す。なお、図6には含めていないが4ビット乗算器には ABi を求めるための図5に示す回路が4個必要である。
図6. 4ビット乗算器
図6に基づいて作成した4ビット乗算器 Verilog 記述例を以下に示す。モジュール ADDER4 は課題1で作成した4ビット加算器である。また、モジュール MULTIPLIER4X1 は図5に示す ABi を求める回路である。モジュール MULTIPLIER4X1 の記述例を図7に示す。
module MULTIPLIER4(A, B, Y);
input [3:0] A;
input [3:0] B;
output [7:0] Y;
wire [3:0] AB3;
wire [3:0] AB2;
wire [3:0] AB1;
wire [3:0] AB0;
wire [3:0] U4_S;
wire [3:0] U5_S;
wire U4_CO;
wire U5_CO;
MULTIPLIER4X1 U0 (.A(A), .B(B[0]), .Y(AB0));
MULTIPLIER4X1 U1 (.A(A), .B(B[1]), .Y(AB1));
MULTIPLIER4X1 U2 (.A(A), .B(B[2]), .Y(AB2));
MULTIPLIER4X1 U3 (.A(A), .B(B[3]), .Y(AB3));
assign Y[0] = AB0[0];
ADDER4 U4 (.A({1'b0, AB0[3:1]}), .B(AB1), .S(U4_S), .CO(U4_CO));
assign Y[1] = U4_S[0];
ADDER4 U5 (.A({U4_CO, U4_S[3:1]}), .B(AB2), .S(U5_S), .CO(U5_CO));
assign Y[2] = U5_S[0];
ADDER4 U6 (.A({U5_CO, U5_S[3:1]}), .B(AB3), .S(Y[6:3]), .CO(Y[7]));
endmodule
|
module MULTIPLIER4X1(A, B, Y);
input [3:0] A;
input B;
output [3:0] Y;
assign Y = A & {4{B}};
endmodule
|
この乗算器は加算器を3個持つ。一般に乗算器は加算器と比べ回路量がとても大きい。
課題のページで示したセレクタの例のようにcase 文を用いることにより、真理値表をほぼそのままプログラムに書くことができる。先週分の解説に示した真理値表より、7セグメントデコーダは図8のように書ける。図8 では default 文において A〜G に 1'bx を代入している。x は不定値を意味する。0 になっても 1 になってもよい場合には不定値の代入を明記することが強く求められる。
module DECODER7(I, A, B, C, D, E, F, G);
input [3:0] I;
output A;
output B;
output C;
output D;
output E;
output F;
output G;
reg A;
reg B;
reg C;
reg D;
reg E;
reg F;
reg G;
always @(*) begin
case(I)
0: begin
A <= 0;
B <= 0;
C <= 0;
D <= 0;
E <= 0;
F <= 0;
G <= 1;
end
1: begin
A <= 1;
B <= 0;
C <= 0;
D <= 1;
E <= 1;
F <= 1;
G <= 1;
end
2: begin
A <= 0;
B <= 0;
C <= 1;
D <= 0;
E <= 0;
F <= 1;
G <= 0;
end
3: begin
A <= 0;
B <= 0;
C <= 0;
D <= 0;
E <= 1;
F <= 1;
G <= 0;
end
4: begin
A <= 1;
B <= 0;
C <= 0;
D <= 1;
E <= 1;
F <= 0;
G <= 0;
end
5: begin
A <= 0;
B <= 1;
C <= 0;
D <= 0;
E <= 1;
F <= 0;
G <= 0;
end
6: begin
A <= 0;
B <= 1;
C <= 0;
D <= 0;
E <= 0;
F <= 0;
G <= 0;
end
7: begin
A <= 0;
B <= 0;
C <= 0;
D <= 1;
E <= 1;
F <= 1;
G <= 1;
end
8: begin
A <= 0;
B <= 0;
C <= 0;
D <= 0;
E <= 0;
F <= 0;
G <= 0;
end
9: begin
A <= 0;
B <= 0;
C <= 0;
D <= 0;
E <= 1;
F <= 0;
G <= 0;
end
default: begin
A <= 1'bx;
B <= 1'bx;
C <= 1'bx;
D <= 1'bx;
E <= 1'bx;
F <= 1'bx;
G <= 1'bx;
end
endcase
end
endmodule
|
例えば、(0001)2=1 と (1111)2=15 または -1 を例に考える。このとき、積は表1の通りになる。
表1. (0001)2 と (1111)2 の乗算結果
| 被乗数 | 乗数 | signed あり | signed なし |
|---|---|---|---|
| 0001 | 0001 | 00000001(=1) | 00000001(=1) |
| 0001 | 1111 | 11111111(=-1) | 00001111(=15) |
| 1111 | 1111 | 00000001(=1) | 11100001(=225) |
signed ありとなしのときでは2進数表記でも結果が異なることに注意されたい。2の補数表現を用いれば、正負の符号を気にせず加減算器を構成することができると習ったであろう。これは情報数学の妙の一つである。しかし、この妙も加減算器に限定した話である。乗算など他の演算を考えるときはやはり符号を気にする必要がある。
複素数 A=AR+jAI と B=BR+jBI の積 Y は (ARBR-AIBI)+j(ARBI+AIBR)となる。これをプログラムに書けばよい。
図9は回路記述例である。32ビットバス A について、例えば、実数部は A[31:16] に対応する。しかし、A[31:16] は signed なしのバスと見なされる。そこで、signed で宣言されたバス AR に一旦代入し、AR を演算式に用いている。
module COMPLEX_MULTIPLIER(A, B, Y);
input [31:0] A;
input [31:0] B;
output [31:0] Y;
wire signed [15:0] AR;
wire signed [15:0] AI;
wire signed [15:0] BR;
wire signed [15:0] BI;
wire signed [31:0] YR;
wire signed [31:0] YI;
assign {AR, AI} = A;
assign {BR, BI} = B;
assign YR = AR * BR - AI * BI;
assign YI = AR * BI + AI * BR;
assign Y = {YR[15:0], YI[15:0]};
endmodule
|
難波 一輝 (助教・伊藤・北神・難波研究室)
工学部1号棟4階409号室、内線3255、043-290-3255、namba@ieee.org