週刊 TD4をFPGAで創る 第4号 「ALUを創る」
第8章からです。
頑張って記事を書くぞ!
1.74HC283
というわけで4bit Full-Adder。
P信号,G信号を使ってCarry-LookaheadなAdderにするって奴はテストによく出るよ!
module LOGIC_74HC283(CIN, A1, A2, A3, A4, B1, B2, B3, B4, S1, S2, S3, S4, COUT);
input CIN, A1, A2, A3, A4, B1, B2, B3, B4;
output S1, S2, S3, S4, COUT;
wire [3:0] G;
wire [3:0] P;
wire [3:0] C;
assign G[0] = ~(A1 & B1);
assign G[1] = ~(A2 & B2);
assign G[2] = ~(A3 & B3);
assign G[3] = ~(A4 & B4);
assign P[0] = ~(A1 | B1);
assign P[1] = ~(A2 | B2);
assign P[2] = ~(A3 | B3);
assign P[3] = ~(A4 | B4);
assign C[0] = CIN;
assign C[1] = ~((~CIN & G[0]) | P[0]);
assign C[2] = ~((~CIN & G[0] & G[1]) | (G[1] & P[0]) | P[1]);
assign C[3] = ~((~CIN & G[0] & G[1] & G[2]) | (G[1] & G[2] & P[0]) | (G[2] & P[1]) | P[2]);
assign COUT = ~((~CIN & G[0] & G[1] & G[2] & G[3]) | (G[1] & G[2] & G[3] & P[0]) | (G[2] & G[3] & P[1]) | (G[3] & P[2]) | P[3]);
assign S1 = (C[0] ^ (~P[0] & G[0]));
assign S2 = (C[1] ^ (~P[1] & G[1]));
assign S3 = (C[2] ^ (~P[2] & G[2]));
assign S4 = (C[3] ^ (~P[3] & G[3]));
endmodule
テストベンチはこんな感じ?
module logic_74hc283_test;
reg CIN;
reg [3:0] A;
reg [3:0] B;
wire [3:0] S;
wire COUT;
LOGIC_74HC283 logic_74hc283(CIN,
A[0], A[1], A[2], A[3],
B[0], B[1], B[2], B[3],
S[0], S[1], S[2], S[3],
COUT);
initial begin
$dumpfile("logic_74hc283_test.vcd");
$dumpvars(0, logic_74hc283_test);
$monitor ("%t: A = %d, B = %d, CIN = %b, S = %d, COUT = %b",
$time, A, B, CIN, S, COUT);
CIN = 0;
A = 0; B = 0;
#10 A = 1; B = 1;
#10 A = 1; B = 2;
#10 A = 2; B = 3;
#10 A = 4; B = 2;
#10 A = 4; B = 3;
#10 A = 4; B = 5;
#10 A = 8; B = 10;
#10 A = 6; B = 7;
#10 A = 12; B = 9;
#10 $finish;
end
endmodule
番外編
2.74HC181
物理的になくても,Verilogで書くことならできちゃうんです。簡単にね!
回路図はこんな感じです。
まったく,わけがわからないよ。
でも,なんとなーく,左右にわかれてますよね?よね?
色をつけるとわかりやすい!
それじゃあ元気よく実装しましょう!(半泣)
module LOGIC_74HC181(CIN, S0, S1, S2, S3, M, A0, A1, A2, A3, B0, B1, B2, B3, F0, F1, F2, F3, COUT, COMP, G, P);
input CIN, S0, S1, S2, S3, M, A0, A1, A2, A3, B0, B1, B2, B3;
output F0, F1, F2, F3, COUT, COMP, G, P;
wire [3:0] D;
wire [3:0] E;
wire [3:0] F;
assign D[0] = ~((~B0 & S1) | (B0 & S0) | A0);
assign D[1] = ~((~B1 & S1) | (B1 & S0) | A1);
assign D[2] = ~((~B2 & S1) | (B2 & S0) | A2);
assign D[3] = ~((~B3 & S1) | (B3 & S0) | A3);
assign E[0] = ~((B0 & S3 & A0) | (A0 & S2 & ~B0));
assign E[1] = ~((B1 & S3 & A1) | (A1 & S2 & ~B1));
assign E[2] = ~((B2 & S3 & A2) | (A2 & S2 & ~B2));
assign E[3] = ~((B3 & S3 & A3) | (A3 & S2 & ~B3));
assign F0 = ((D[0] ^ E[0]) ^ ~(CIN & ~M));
assign F1 = ((D[1] ^ E[1]) ^ ~((CIN & E[0] & ~M) | (D[0] & ~M)));
assign F2 = ((D[2] ^ E[2]) ^ ~((CIN & E[0] & E[1] & ~M) | (E[1] & D[0] & ~M) | (D[1] & ~M)));
assign F3 = ((D[3] ^ E[3]) ^ ~((CIN & E[0] & E[1] & E[2] & ~M) | (E[1] & E[2] & D[0] & ~M) | (E[2] & D[1] & ~M) | (D[2] & ~M)));
assign P = ~(E[0] & E[1] & E[2] & E[3]);
assign G = ~(D[3] | (E[3] & D[2]) | (E[3] & E[2] & D[1]) | (E[3] & E[2] & E[1] & D[0]));
assign COMP = F0 & F1 & F2 & F3;
assign COUT = ~G | (E[3] & E[2] & E[1] & E[0] & CIN);
endmodule
網羅テストを実行するのはさすがに無理だと思うので,適当にテストベンチ書いてテストしてみるといいよ!
あと,このICはActive-LowとActive-Highで挙動が違うから注意してね!
詳しいことはデータシート読め!
番外編終わり
3.74HC74
フラグレジスタ用のフリップフロップ回路です。
奥さん!二個入りニコニコ大特価だよ!
module LOGIC_74HC74(CLR1, D1, CK1, PR1, Q1, Qb1, CLR2, D2, CK2, PR2, Q2, Qb2);
input CLR1, D1, CK1, PR1, CLR2, D2, CK2, PR2;
output Q1, Qb1, Q2, Qb2;
reg Q1, Q2;
assign Qb1 = ~Q1;
assign Qb2 = ~Q2;
initial begin
Q1 <= 1'b0;
Q2 <= 1'b0;
end
always @(CLR1, CK1, PR1, CLR2, CK2, PR2) begin
if(~CLR1) begin
Q1 <= 1'b0;
end else if(~PR1) begin
Q1 <= 1'b1;
end else if(CK1) begin
Q1 <= D1;
end
if(~CLR2) begin
Q2 <= 1'b0;
end else if(~PR2) begin
Q2 <= 1'b1;
end else if(CK2) begin
Q2 <= D2;
end
end
endmodule
テストベンチはこんな感じ?
module logic_74hc74_test;
reg CLR1, D1, CK1, PR1, CLR2, D2, CK2, PR2;
wire Q1, Qb1, Q2, Qb2;
LOGIC_74HC74 logic_74hc74(CLR1, D1, CK1, PR1, Q1, Qb1, CLR2, D2, CK2, PR2, Q2, Qb2);
initial begin
$dumpfile("logic_74hc74_test.vcd");
$dumpvars(0, logic_74hc74_test);
$monitor ("%t: CK1 = %b, (CLR1, PR1) = (%b, %b), D1 = %b, Q1 = %b | CK2 = %b, (CLR2, PR2) = (%b, %b), D2 = %b, Q2 = %b",
$time, CK1, CLR1, PR1, D1, Q1, CK2, CLR2, PR2, D2, Q2);
CK1 = 0; CK2 = 0;
CLR1 = 1; CLR2 = 1;
PR1 = 1; PR2 = 1;
D1 = 0; D2 = 0;
#3 D1 = 1; D2 = 1;
#1 D1 = 0; D2 = 0;
#30 $finish;
end
always #3 CK1 = ~CK1;
always #5 CK2 = ~CK2;
endmodule
4.8.2節までの回路
というわけで,8.2節までの回路(つまり,I/Oポートなし)を書いてみます。
module CHAPTER_8_2(CLOCK, RESET, SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3, ROM_DATA, ROM_ADDRESS);
input CLOCK, RESET;
input SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3;
input [7:0] ROM_DATA;
output [3:0] ROM_ADDRESS;
reg Vcc = 1'b1;
reg GND = 1'b0;
wire [6:0] NOT_IN_USE;
wire [3:0] REGISTER_IN;
wire [3:0] REGISTER_A_OUT;
wire [3:0] REGISTER_B_OUT;
wire [3:0] REGISTER_C_OUT;
wire [3:0] REGISTER_D_OUT;
wire [3:0] ALU_IN_A;
wire [3:0] ALU_IN_B;
wire CARRY_OUT, C_FLAG;
wire [3:0] OPERATION_CODE;
wire [3:0] IMEEDIATE_DATA;
assign ROM_ADDRESS = REGISTER_D_OUT;
assign OPERATION_CODE = ROM_DATA[7:4];
assign IMEEDIATE_DATA = ROM_DATA[3:0];
assign ALU_IN_B = IMEEDIATE_DATA;
LOGIC_74HC161 Register_A (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
GND, LOAD_0, GND,
REGISTER_A_OUT[0], REGISTER_A_OUT[1], REGISTER_A_OUT[2], REGISTER_A_OUT[3],
NOT_IN_USE[0]);
LOGIC_74HC161 Register_B (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
GND, LOAD_1, GND,
REGISTER_B_OUT[0], REGISTER_B_OUT[1], REGISTER_B_OUT[2], REGISTER_B_OUT[3],
NOT_IN_USE[1]);
LOGIC_74HC161 Register_C (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
GND, LOAD_2, GND,
REGISTER_C_OUT[0], REGISTER_C_OUT[1], REGISTER_C_OUT[2], REGISTER_C_OUT[3],
NOT_IN_USE[2]);
LOGIC_74HC161 Register_D (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
Vcc, LOAD_3, Vcc,
REGISTER_D_OUT[0], REGISTER_D_OUT[1], REGISTER_D_OUT[2], REGISTER_D_OUT[3],
NOT_IN_USE[3]);
LOGIC_74HC153 Register_Selector_0 (SELECT_A, SELECT_B, GND, GND,
REGISTER_A_OUT[0], REGISTER_B_OUT[0], REGISTER_C_OUT[0], GND,
REGISTER_A_OUT[1], REGISTER_B_OUT[1], REGISTER_C_OUT[1], GND,
ALU_IN_A[0], ALU_IN_A[1]);
LOGIC_74HC153 Register_Selector_1 (SELECT_A, SELECT_B, GND, GND,
REGISTER_A_OUT[2], REGISTER_B_OUT[2], REGISTER_C_OUT[2], GND,
REGISTER_A_OUT[3], REGISTER_B_OUT[3], REGISTER_C_OUT[3], GND,
ALU_IN_A[2], ALU_IN_A[3]);
LOGIC_74HC283 ALU (GND,
ALU_IN_A[0], ALU_IN_A[1], ALU_IN_A[2], ALU_IN_A[3],
ALU_IN_B[0], ALU_IN_B[1], ALU_IN_B[2], ALU_IN_B[3],
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
CARRY_OUT);
LOGIC_74HC74 C_Flag (RESET, CARRY_OUT, CLOCK, Vcc, C_FLAG, NOT_IN_USE[4],
GND, GND, GND, GND, NOT_IN_USE[5], NOT_IN_USE[6]);
endmodule
だいぶCPUっぽくなってきましたね!
4.8.3節までの回路
どんどんいってみましょう!
8.3節までの回路(つまり,I/Oポートつき)を書いてみます。
module CHAPTER_8_3(CLOCK, RESET, SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3, ROM_DATA, ROM_ADDRESS);
input CLOCK, RESET;
input SELECT_A, SELECT_B, LOAD_0, LOAD_1, LOAD_2, LOAD_3;
input [7:0] ROM_DATA;
output [3:0] ROM_ADDRESS;
reg Vcc = 1'b1;
reg GND = 1'b0;
wire [6:0] NOT_IN_USE;
wire [3:0] REGISTER_IN;
wire [3:0] REGISTER_A_OUT;
wire [3:0] REGISTER_B_OUT;
wire [3:0] REGISTER_C_OUT;
wire [3:0] REGISTER_D_OUT;
wire [3:0] ALU_IN_A;
wire [3:0] ALU_IN_B;
wire CARRY_OUT, C_FLAG;
wire [3:0] OPERATION_CODE;
wire [3:0] IMEEDIATE_DATA;
assign ROM_ADDRESS = REGISTER_D_OUT;
assign OPERATION_CODE = ROM_DATA[7:4];
assign IMEEDIATE_DATA = ROM_DATA[3:0];
assign ALU_IN_B = IMEEDIATE_DATA;
assign OUTPUT = REGISTER_C_OUT;
LOGIC_74HC161 Register_A (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
GND, LOAD_0, GND,
REGISTER_A_OUT[0], REGISTER_A_OUT[1], REGISTER_A_OUT[2], REGISTER_A_OUT[3],
NOT_IN_USE[0]);
LOGIC_74HC161 Register_B (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
GND, LOAD_1, GND,
REGISTER_B_OUT[0], REGISTER_B_OUT[1], REGISTER_B_OUT[2], REGISTER_B_OUT[3],
NOT_IN_USE[1]);
LOGIC_74HC161 Register_C (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
GND, LOAD_2, GND,
REGISTER_C_OUT[0], REGISTER_C_OUT[1], REGISTER_C_OUT[2], REGISTER_C_OUT[3],
NOT_IN_USE[2]);
LOGIC_74HC161 Register_D (RESET, CLOCK,
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
Vcc, LOAD_3, Vcc,
REGISTER_D_OUT[0], REGISTER_D_OUT[1], REGISTER_D_OUT[2], REGISTER_D_OUT[3],
NOT_IN_USE[3]);
LOGIC_74HC153 Register_Selector_0 (SELECT_A, SELECT_B, GND, GND,
REGISTER_A_OUT[0], REGISTER_B_OUT[0], REGISTER_C_OUT[0], GND,
REGISTER_A_OUT[1], REGISTER_B_OUT[1], REGISTER_C_OUT[1], GND,
ALU_IN_A[0], ALU_IN_A[1]);
LOGIC_74HC153 Register_Selector_1 (SELECT_A, SELECT_B, GND, GND,
REGISTER_A_OUT[2], REGISTER_B_OUT[2], REGISTER_C_OUT[2], GND,
REGISTER_A_OUT[3], REGISTER_B_OUT[3], REGISTER_C_OUT[3], GND,
ALU_IN_A[2], ALU_IN_A[3]);
LOGIC_74HC283 ALU (GND,
ALU_IN_A[0], ALU_IN_A[1], ALU_IN_A[2], ALU_IN_A[3],
ALU_IN_B[0], ALU_IN_B[1], ALU_IN_B[2], ALU_IN_B[3],
REGISTER_IN[0], REGISTER_IN[1], REGISTER_IN[2], REGISTER_IN[3],
CARRY_OUT);
LOGIC_74HC74 C_Flag (RESET, CARRY_OUT, CLOCK, Vcc, C_FLAG, NOT_IN_USE[4],
GND, GND, GND, GND, NOT_IN_USE[5], NOT_IN_USE[6]);
endmodule
次回予告
ついにシミュレーション編最終回!
命令デコーダを完成させます!
そして,全てを結合させCPU全体の完成です!
乞うご期待!!!
Amazon.co.jp - 渡波 郁 「CPUの創りかた」 毎日コミュニケーションズ (2003)