帰らざるMOS回路(33) 1bit ALUを32個並べて32bit化。Verilog

Joseph Halfmoon

前回、1ビット分のALUをVerilog化してみたので、今回はそれを32個ならべて32ビット化してみます。まあね、芸のないリップルキャリーなので接続は超簡単、並べるだけ(遅いけれども。)論理演算でも算術演算(加算と減算だけれども)でもどんとこいっと。でもまだレジスタとか必要なものは何も繋がってないっす。

実験用なので、最初8ビットでやるかとも思ったのです。でも昨今の組み込みマイコンでもフツーなのは32ビット機です。Verilogで書く(とはいっても論理合成とかあてにしてないベタな回路を目指してマス)のだったら8ビットも32ビットも大差ないだろ~。といことでALUを32ビット化して動作確認いたしました。なお使用しているコードの中で呼び出されている1ビットALUは、以下の記事にソースを記載しているものです。

帰らざるMOS回路(32) MOSFET、MUXとリップルキャリーでALUをVerilog化

32ビット化

上記で作った1ビットALUの「セル」を32個並べれば基本的にはOKですが、一つだけ非対称なところがあります。キャリー(桁上げ)信号です。今回は「芸のないリップルキャリー」なので、以下のような接続となります。

    1. 最下位ビットに外部からキャリーイン
    2. 以降、一つ下のビットのキャリーアウト信号を一つ上のビットのキャリーインに接続
    3. 最上位ビットのキャリーアウト信号を外部へのキャリーアウトとする

32ビットのデータ入力 a,bおよび、データ出力 out はパラレル。制御信号 fnc と sel は全セル共通です。

ソースはこんな感じ。

/** @file
    32bit ALU
*/

`ifndef ALU32_V_
`define ALU32_V_

module alu32  (
    fnc, a, b, sel, cin, cout, out
);

input  	[3:0] fnc;
input   [31:0] a;
input   [31:0] b;
input   sel, cin;
output 	cout;
output  [31:0] out;
wire    [30:0] co;

alu aluB00(.FUNC(fnc), .A(a[0]), .B(b[0]), .SEL(sel), .CIN(cin),   .COUT(co[0]), .OUT(out[0]));
alu aluB01(.FUNC(fnc), .A(a[1]), .B(b[1]), .SEL(sel), .CIN(co[0]), .COUT(co[1]), .OUT(out[1]));
alu aluB02(.FUNC(fnc), .A(a[2]), .B(b[2]), .SEL(sel), .CIN(co[1]), .COUT(co[2]), .OUT(out[2]));
alu aluB03(.FUNC(fnc), .A(a[3]), .B(b[3]), .SEL(sel), .CIN(co[2]), .COUT(co[3]), .OUT(out[3]));
alu aluB04(.FUNC(fnc), .A(a[4]), .B(b[4]), .SEL(sel), .CIN(co[3]), .COUT(co[4]), .OUT(out[4]));
alu aluB05(.FUNC(fnc), .A(a[5]), .B(b[5]), .SEL(sel), .CIN(co[4]), .COUT(co[5]), .OUT(out[5]));
alu aluB06(.FUNC(fnc), .A(a[6]), .B(b[6]), .SEL(sel), .CIN(co[5]), .COUT(co[6]), .OUT(out[6]));
alu aluB07(.FUNC(fnc), .A(a[7]), .B(b[7]), .SEL(sel), .CIN(co[6]), .COUT(co[7]), .OUT(out[7]));

alu aluB08(.FUNC(fnc), .A(a[8]),  .B(b[8]),  .SEL(sel), .CIN(co[7]),  .COUT(co[8]),  .OUT(out[8]));
alu aluB09(.FUNC(fnc), .A(a[9]),  .B(b[9]),  .SEL(sel), .CIN(co[8]),  .COUT(co[9]),  .OUT(out[9]));
alu aluB10(.FUNC(fnc), .A(a[10]), .B(b[10]), .SEL(sel), .CIN(co[9]),  .COUT(co[10]), .OUT(out[10]));
alu aluB11(.FUNC(fnc), .A(a[11]), .B(b[11]), .SEL(sel), .CIN(co[10]), .COUT(co[11]), .OUT(out[11]));
alu aluB12(.FUNC(fnc), .A(a[12]), .B(b[12]), .SEL(sel), .CIN(co[11]), .COUT(co[12]), .OUT(out[12]));
alu aluB13(.FUNC(fnc), .A(a[13]), .B(b[13]), .SEL(sel), .CIN(co[12]), .COUT(co[13]), .OUT(out[13]));
alu aluB14(.FUNC(fnc), .A(a[14]), .B(b[14]), .SEL(sel), .CIN(co[13]), .COUT(co[14]), .OUT(out[14]));
alu aluB15(.FUNC(fnc), .A(a[15]), .B(b[15]), .SEL(sel), .CIN(co[14]), .COUT(co[15]), .OUT(out[15]));

alu aluB16(.FUNC(fnc), .A(a[16]), .B(b[16]), .SEL(sel), .CIN(co[15]), .COUT(co[16]), .OUT(out[16]));
alu aluB17(.FUNC(fnc), .A(a[17]), .B(b[17]), .SEL(sel), .CIN(co[16]), .COUT(co[17]), .OUT(out[17]));
alu aluB18(.FUNC(fnc), .A(a[18]), .B(b[18]), .SEL(sel), .CIN(co[17]), .COUT(co[18]), .OUT(out[18]));
alu aluB19(.FUNC(fnc), .A(a[19]), .B(b[19]), .SEL(sel), .CIN(co[18]), .COUT(co[19]), .OUT(out[19]));
alu aluB20(.FUNC(fnc), .A(a[20]), .B(b[20]), .SEL(sel), .CIN(co[19]), .COUT(co[20]), .OUT(out[20]));
alu aluB21(.FUNC(fnc), .A(a[21]), .B(b[21]), .SEL(sel), .CIN(co[20]), .COUT(co[21]), .OUT(out[21]));
alu aluB22(.FUNC(fnc), .A(a[22]), .B(b[22]), .SEL(sel), .CIN(co[21]), .COUT(co[22]), .OUT(out[22]));
alu aluB23(.FUNC(fnc), .A(a[23]), .B(b[23]), .SEL(sel), .CIN(co[22]), .COUT(co[23]), .OUT(out[23]));

alu aluB24(.FUNC(fnc), .A(a[24]), .B(b[24]), .SEL(sel), .CIN(co[23]), .COUT(co[24]), .OUT(out[24]));
alu aluB25(.FUNC(fnc), .A(a[25]), .B(b[25]), .SEL(sel), .CIN(co[24]), .COUT(co[25]), .OUT(out[25]));
alu aluB26(.FUNC(fnc), .A(a[26]), .B(b[26]), .SEL(sel), .CIN(co[25]), .COUT(co[26]), .OUT(out[26]));
alu aluB27(.FUNC(fnc), .A(a[27]), .B(b[27]), .SEL(sel), .CIN(co[26]), .COUT(co[27]), .OUT(out[27]));
alu aluB28(.FUNC(fnc), .A(a[28]), .B(b[28]), .SEL(sel), .CIN(co[27]), .COUT(co[28]), .OUT(out[28]));
alu aluB29(.FUNC(fnc), .A(a[29]), .B(b[29]), .SEL(sel), .CIN(co[28]), .COUT(co[29]), .OUT(out[29]));
alu aluB30(.FUNC(fnc), .A(a[30]), .B(b[30]), .SEL(sel), .CIN(co[29]), .COUT(co[30]), .OUT(out[30]));
alu aluB31(.FUNC(fnc), .A(a[31]), .B(b[31]), .SEL(sel), .CIN(co[30]), .COUT(cout),   .OUT(out[31]));

endmodule
`endif // ALU32_V_
32ビットALUを「軽く」テストするテストベンチ

がっつりテストするのはまた後でということで、要所だけ軽く抑えるつもりのテストベンチが以下に。ぶっちゃけ前回1ビットALUのテストの流用です。とりあえず繋いで動けばOKっと。

    1. aとbの論理AND、最初はa, b ともにオール0
    2. aとbの論理AND、a and b をOUTへ
    3. aとbの論理OR、a or b をOUTへ
    4. aをスルー、bを無視、a をそのままOUTへ
    5. a+bの符号無算術演算、キャリーインなし、結果OUTへ、キャリーアウト無
    6. a+bの符号無算術演算、キャリーインあり、結果OUTへ、キャリーアウト無
    7. a+bの符号無算術演算、キャリーインあり、結果OUTへ、キャリーアウト有

こんなもんです。

/** @file
    ALU32 Test bench
*/

`timescale 1 ns / 1 ps

module alu32_tb;

parameter CYCLE = 100;
parameter DELAY1 = 10;

wire [31:0] out;
wire cout;
reg [3:0] fnc;
reg [31:0] a;
reg [31:0] b;
reg cin, sel; 

alu32 dut(.fnc(fnc), .a(a), .b(b), .sel(sel), .cin(cin), .cout(cout), .out(out));

initial begin
    $dumpfile("alu32_tb.vcd");
    $dumpvars(-1, dut);
    $monitor("%d fnc=%b sel=%b : a=%h b=%h cin=%b : cout=%b OUT=%h", $stime, fnc, sel, a, b, cin, cout, out);
end

initial begin
    sel = 1'b0; cin = 1'b0; 
    #DELAY1	fnc = 4'b1000; a = 32'h00000000; b= 32'h00000000;
    #CYCLE  a = 32'h5a5a1234; b= 32'h5aa500ff;
    #CYCLE  fnc = 4'b1110;
    #CYCLE  fnc = 4'b1010;
    #CYCLE  fnc = 4'b0110; sel = 1'b1; a = 32'h7FFFFFFF; b= 32'h00000001;
    #CYCLE  cin = 1'b1; a = 32'h00000000; b= 32'h00000001;
    #CYCLE  cin = 1'b1; a = 32'h7FFFFFFF; b= 32'h80000000;
    #CYCLE
    $finish;
end

endmodule //alu32_tb
実行結果

まず標準出力でみえる $monitorの結果。これだけ見て動作はOK。ALU32_SIM_Results

折角 VCD ファイルも生成しているので、GTKwave(波形ビューワー)で動作波形を観察してみました。こんな感じ。ALU32_SIM_WAVE

よろしいんじゃないでしょうか。まあ、動いて当然だな、自分。並べただけだし。

帰らざるMOS回路(32) MOSFET、MUXとリップルキャリーでALUをVerilog化 へ戻る

帰らざるMOS回路(34) 2R1Wのレジスタファイル(仮)でっち上げ、Verilog へ進む