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

Joseph Halfmoon

前回はゲートレベルシミュレータ上で1bit分のALU(Arithmetic Logic Unit)を試作。全ての論理演算と加算(減算は2の補数)を行えるような「セル」です。算術演算時にはリップルキャリーなので実際に作ったら「遅い」ですが、とりあえず速度は考えないっと。今回は前回の回路をVerilogで書き直してみます。

※使用させていただいとりますフリーのVerilog処理系へのリンクが以下に。

Icarus Verilog

前回作成のALU(1ビット分)

前回作成の1ビット分のALUセルが以下に。全て正論理で書いてます。また、論理合成に頼る気などなく、本当はMOSFETを並べて作るつもりなのですが、とりあえずゲートレベルのMUXなどで代用しています。

    • 入力各1ビット、AとB
    • 機能指定FUNC、4ビット。論理演算時には、ANDなら1000のように真理値表どおりの値を与える。算術演算時にはXOR相当で0110。
    • CIN、COUT各1ビット、キャリーイン(下のビットからの桁あがり)、キャリーアウト(上のビットへの桁あがり)
    • SEL 論理演算(0)か算術演算(1)かセレクト
    • OUT AとBとCINを演算した結果のその桁の1ビット出力。

MOS_ALU_CELL

Verilogで書き直し

上記回路を「ほぼほぼ」そのままVerilog化してみたものが以下に。論理合成など考えてないので、ベタなassign文で = してます。ま、こんなもんで論理演算、算術演算できる筈。

`ifndef ALU_V_
`define ALU_V_

module alu  (
    FUNC, A, B, SEL, CIN, COUT, OUT
);

input  	[3:0] FUNC;
input   A, B, SEL, CIN;
output 	COUT, OUT;
wire    [1:0] fin;
wire    fout, aout, xout;
wire    [1:0] cmuxin;
wire    [1:0] omuxin;

assign fin = {B, A};
assign fout = FUNC[fin];
assign aout = B & A;
assign xout = fout ^ CIN;
assign cmuxin = {CIN, aout};
assign omuxin = {xout, fout};
assign COUT = cmuxin[fout];
assign OUT = omuxin[SEL];

endmodule
`endif // ALU_V_
上記の1bit ALUをテストするためのテストベンチ

以下のシーケンスでテストしています。

    1. 論理演算モード、AND演算、AとBの値の組み合わせ4通り
    2. 論理演算モード、OR演算、AとBの値の組み合わせ4通り
    3. 論理演算モード、NOT演算、AのNOTを取る。Bは無視。確認のためAとBの値の組み合わせ4通り
    4. 算術演算モード、キャリーイン無。AとBの値の組み合わせ4通り
    5. 算術演算モード、キャリーイン有。AとBの値の組み合わせ4通り

Verilogソースが以下に。

`timescale 1 ns / 100 ps

module alu_tb;

parameter CYCLE = 100;
parameter DELAY1 = 10;

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

/* 1 bit ALU */
alu dut(
    .FUNC(fnc), .A(a), .B(b),
    .SEL(sel), .CIN(cin),
    .COUT(cout), .OUT(out)
);

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

initial begin
    sel = 1'b0; cin = 1'b0; 
    #DELAY1	fnc = 4'b1000; a = 1'b0; b= 1'b0;
    #CYCLE  a = 1'b0; b= 1'b1;
    #CYCLE  a = 1'b1; b= 1'b0;
    #CYCLE  a = 1'b1; b= 1'b1;
    #CYCLE  fnc = 4'b1110; a = 1'b0; b= 1'b0;
    #CYCLE  a = 1'b0; b= 1'b1;
    #CYCLE  a = 1'b1; b= 1'b0;
    #CYCLE  a = 1'b1; b= 1'b1;
    #CYCLE  fnc = 4'b1010; a = 1'b0; b= 1'b0;
    #CYCLE  a = 1'b0; b= 1'b1;
    #CYCLE  a = 1'b1; b= 1'b0;
    #CYCLE  a = 1'b1; b= 1'b1;
    #CYCLE  fnc = 4'b0110; a = 1'b0; b= 1'b0; sel = 1'b1;
    #CYCLE  a = 1'b0; b= 1'b1;
    #CYCLE  a = 1'b1; b= 1'b0;
    #CYCLE  a = 1'b1; b= 1'b1;
    #CYCLE  fnc = 4'b0110; a = 1'b0; b= 1'b0; cin = 1'b1;
    #CYCLE  a = 1'b0; b= 1'b1;
    #CYCLE  a = 1'b1; b= 1'b0;
    #CYCLE  a = 1'b1; b= 1'b1;
    #CYCLE
    $finish;
end

endmodule //encoder_tb
実行結果

実行結果が以下に。予定どおりですな。

ALU_Result

論理合成の時代のコードじゃない気がしないでもないですが、こんなもんでも計算はできると。ますますトラディショナル(古色蒼然)なMOS回路へ向かって邁進(退化)か?

帰らざるMOS回路(31) MOSFET、古式ゆかしい?MUXとリップルキャリーでALU へ戻る

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