演習C
★★★ 上級
所要:30–45分
8ビット ALU
算術演算と論理演算を1つのモジュールに統合した ALU(算術論理演算ユニット) を Verilog で設計しよう。
📚 概念説明:ALU とは
ALU(Arithmetic Logic Unit)は CPU の中心部品で、
算術演算(加算・減算)と論理演算(AND・OR・XOR・NOT)を1つのモジュールで担います。
opcode(操作コード)の値によって、どの演算を行うかを切り替えます。
| opcode(3ビット) | 演算 | 式 | 例(A=10, B=3) |
|---|---|---|---|
| 3'b000 | ADD | A + B | 13 |
| 3'b001 | SUB | A − B | 7 |
| 3'b010 | AND | A & B | 2 (0000_1010 & 0000_0011) |
| 3'b011 | OR | A | B | 11 (0000_1010 | 0000_0011) |
| 3'b100 | XOR | A ^ B | 9 (0000_1010 ^ 0000_0011) |
| 3'b101 | NOT A | ~A | 245 (1111_0101) |
| 3'b110〜111 | 未使用 | — | result = 0(default) |
ゼロフラグ(Zero Flag):
演算結果がちょうど 0 のとき、
zero = 1 になります。条件分岐命令などで使われる重要なフラグです。
📝 課題
モジュール名:alu8
入力:a [7:0]、b [7:0]、opcode [2:0]
出力:result [7:0](演算結果)、zero(結果が0のとき1)、cout(加減算時のキャリー/ボロー)
💻 Verilog テンプレート
Design(右パネル)
// ================================ // 8ビット ALU モジュール // opcode: 000=ADD 001=SUB 010=AND // 011=OR 100=XOR 101=NOT // ================================ module alu8 ( input [7:0] a, input [7:0] b, input [2:0] opcode, output reg [7:0] result, output reg cout, output zero ); wire [8:0] add_result = {1'b0,a} + {1'b0,b}; wire [8:0] sub_result = {1'b0,a} + {1'b0,~b} + 9'd1; assign zero = (result == 8'b0); always @(*) begin case (opcode) 3'b000: begin // ADD {cout, result} = add_result; end 3'b001: begin // SUB (borrow = ~cout) {cout, result} = sub_result; end 3'b010: begin result = a & b; cout = 0; end // AND 3'b011: begin result = a | b; cout = 0; end // OR 3'b100: begin result = a ^ b; cout = 0; end // XOR 3'b101: begin result = ~a; cout = 0; end // NOT default: begin result = 8'b0; cout = 0; end endcase end endmodule
Testbench(左パネル)
module tb_alu8; reg [7:0] a, b; reg [2:0] opcode; wire [7:0] result; wire cout, zero; alu8 uut (.a(a), .b(b), .opcode(opcode), .result(result), .cout(cout), .zero(zero)); initial begin $dumpfile("dump.vcd"); $dumpvars(0, tb_alu8); $monitor("op=%b a=%0d b=%0d | result=%0d cout=%0d zero=%0d", opcode, a, b, result, cout, zero); a=8'd10; b=8'd3; opcode=3'b000; #10; // ADD: 13 opcode=3'b001; #10; // SUB: 7 opcode=3'b010; #10; // AND: 2 opcode=3'b011; #10; // OR: 11 opcode=3'b100; #10; // XOR: 9 opcode=3'b101; #10; // NOT: 245 // ゼロフラグテスト a=8'd5; b=8'd5; opcode=3'b001; #10; // SUB: 0 → zero=1 $display("--- テスト完了 ---"); $finish; end endmodule
▶ EDA Playground で開く
各 opcode の演算を波形で確認しましょう。
🚀 EDA Playground を開く →※ ログインに Gmail が必要です。 使い方ガイドを見る
🤔 考えてみよう
- opcode=3'b001(SUB)でゼロフラグが 1 になるのはどんなとき?CPU の条件分岐命令(例:beq)に使う場合を考えよう。
- 今回の ALU に SHL(左シフト)と SHR(右シフト)演算を追加するとしたら、opcode と Verilog コードをどう変更しますか?
always @(*)の(*)は何を意味しますか?always @(a, b, opcode)と同じですか?- 現実の CPU(例:RISC-V)の ALU はどんな演算をサポートしていますか?調べてみよう。