前回はゲートレベルシミュレータ上で1bit分のALU(Arithmetic Logic Unit)を試作。全ての論理演算と加算(減算は2の補数)を行えるような「セル」です。算術演算時にはリップルキャリーなので実際に作ったら「遅い」ですが、とりあえず速度は考えないっと。今回は前回の回路をVerilogで書き直してみます。
※かえらざるMOS回路 投稿順 INDEX
※使用させていただいとりますフリーの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ビット出力。
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をテストするためのテストベンチ
以下のシーケンスでテストしています。
-
- 論理演算モード、AND演算、AとBの値の組み合わせ4通り
- 論理演算モード、OR演算、AとBの値の組み合わせ4通り
- 論理演算モード、NOT演算、AのNOTを取る。Bは無視。確認のためAとBの値の組み合わせ4通り
- 算術演算モード、キャリーイン無。AとBの値の組み合わせ4通り
- 算術演算モード、キャリーイン有。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
実行結果
実行結果が以下に。予定どおりですな。
論理合成の時代のコードじゃない気がしないでもないですが、こんなもんでも計算はできると。ますますトラディショナル(古色蒼然)なMOS回路へ向かって邁進(退化)か?