帰らざるMOS回路(40) 2相ノンオーバラップクロックをVerilogで設計もどき

Joseph Halfmoon

別件記事で古の8080用の2相ノンオーバラップクロックもどきを制作。標準ロジックIC2個、合計7ゲートのロジックを組むのが老人には辛いっす。この際FPGAでやれば自分で配線せずとも出来るじゃん。ということでFPGAにしてみることにしましたが、そのためには回路をHDLで書かないとなりません。久しぶりにVerilog?

※かえらざるMOS回路 投稿順 INDEX

Icarus Verilog

とりあえず手元にあるFPGAは、超お求めやすい価格だったのだけれど使い方が良く分からない(マニュアルが簡体字中国語。。。)ものなんであります。米国製のFPGAであればツールチェーンにVerilogやVHDLのシミュレータやら何やらも含まれていたりするのですが、これはFPGAに書き込むビットファイルは生成できますがシミュレータは含まれません。そこで代表的なフリーのVerilogコンパイラ/シミュレータであるIcarus Verilogを使用することにいたしました。使うの相当久しぶりだな。

Icarus Verilogのドキュメントのページはこちら(数年前にあった「公式ページ」は無くなったみたいデス。でも上記のリンクの方が情報多くなってる気がしないでもない。)

今回作成予定の回路

今回FPGA上に実装しようとしている回路は以下のようなものです。

    1. ボード上に24MHzのオシレータが搭載されているのでそれをクロック源とする
    2. 24MHzを12分周すれば2MHzになる(オリジナル8080の速度?)
    3. 2MHzのクロック出力は2相ノンオーバラップとする
    4. ついでに2MHzを2,4、8、16分周して1MHz、500kHz、250kHz、125kHzの単相クロックも出力できるようにする

別件の2相ノンオーバラップクロック生成回路では、物理的な遅延を使ってノンオーバラップ期間を確保していたのですが、今回は12分周のところで各フェースのON期間を5、OFF期間を7として、確実に「1」の隙間(とりあえず40nsくらい。後で調整はなんとでもなる筈)を作るという目標です。

後はVerilog書くだけなので以下のようです。まず全体回路。このレベルの入出力をFPGAから外に接続の予定。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
module counter12
(
input wire CLK_IN,
input wire RST_N,
output wire [3:0]CLK_OUT,
output wire P1,
output wire P2
);
freqdiv12 FD12 ( CLK_IN, RST_N, P1, P2 );
freqdiv16 FD16 ( P1, RST_N, CLK_OUT );
endmodule
module counter12 ( input wire CLK_IN, input wire RST_N, output wire [3:0]CLK_OUT, output wire P1, output wire P2 ); freqdiv12 FD12 ( CLK_IN, RST_N, P1, P2 ); freqdiv16 FD16 ( P1, RST_N, CLK_OUT ); endmodule
module counter12
(
    input wire CLK_IN,
    input wire RST_N,
    output wire [3:0]CLK_OUT,
    output wire P1,
    output wire P2
);

freqdiv12 FD12 ( CLK_IN, RST_N, P1, P2 );
freqdiv16 FD16 ( P1, RST_N, CLK_OUT );

endmodule

内部に配置したfreqdiv12が元クロックの12分周回路、freqdiv16が2分周4段で16分周回路です。最初は12分周回路。この中で2フェーズノンオーバラップを作製。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
module freqdiv12
(
input wire CLK_IN,
input wire RST_N,
output wire P1,
output wire P2
);
reg [3:0] count;
reg phase1;
reg phase2;
initial
begin
count=4'b0000;
phase1=0;
phase2=0;
end
always @(posedge CLK_IN)
begin
if (RST_N==1)
count <= 4'b0000;
else if (count == 4'b1011)
count <= 4'b0000;
else
count <= count + 1;
end
always @(posedge CLK_IN)
begin
if (count == 4'b0000)
phase1 <= 1;
else if (count == 4'b0101)
phase1 <= 0;
end
always @(posedge CLK_IN)
begin
if (count == 4'b0110)
phase2 <= 1;
else if (count == 4'b1011)
phase2 <= 0;
end
assign P1 = phase1;
assign P2 = phase2;
endmodule
module freqdiv12 ( input wire CLK_IN, input wire RST_N, output wire P1, output wire P2 ); reg [3:0] count; reg phase1; reg phase2; initial begin count=4'b0000; phase1=0; phase2=0; end always @(posedge CLK_IN) begin if (RST_N==1) count <= 4'b0000; else if (count == 4'b1011) count <= 4'b0000; else count <= count + 1; end always @(posedge CLK_IN) begin if (count == 4'b0000) phase1 <= 1; else if (count == 4'b0101) phase1 <= 0; end always @(posedge CLK_IN) begin if (count == 4'b0110) phase2 <= 1; else if (count == 4'b1011) phase2 <= 0; end assign P1 = phase1; assign P2 = phase2; endmodule
module freqdiv12
(
    input wire CLK_IN,
    input wire RST_N,
    output wire P1,
    output wire P2
);

reg [3:0] count;
reg phase1;
reg phase2;
    
initial
begin
    count=4'b0000;
    phase1=0;
    phase2=0;
end

always @(posedge CLK_IN)
begin
    if (RST_N==1)
        count <= 4'b0000;
    else if (count == 4'b1011)
        count <= 4'b0000;
    else
        count <= count + 1;
end

always @(posedge CLK_IN)
begin
    if (count == 4'b0000)
        phase1 <= 1;
    else if (count == 4'b0101)
        phase1 <= 0;
end

always @(posedge CLK_IN)
begin
    if (count == 4'b0110)
        phase2 <= 1;
    else if (count == 4'b1011)
        phase2 <= 0;
end

assign P1 = phase1;
assign P2 = phase2;
endmodule

つづいて16分周回路。こんなもんで良いか?

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
module freqdiv16
(
input wire CLK_IN,
input wire RST_N,
output wire [3:0]CLK_OUT
);
reg [3:0] count;
initial
begin
count=4'b0000;
end
always @(posedge CLK_IN)
begin
if (RST_N==1)
count <= 4'b0000;
else if (count == 4'b1111)
count <= 4'b0000;
else
count <= count + 1;
end
assign CLK_OUT = count;
endmodule
module freqdiv16 ( input wire CLK_IN, input wire RST_N, output wire [3:0]CLK_OUT ); reg [3:0] count; initial begin count=4'b0000; end always @(posedge CLK_IN) begin if (RST_N==1) count <= 4'b0000; else if (count == 4'b1111) count <= 4'b0000; else count <= count + 1; end assign CLK_OUT = count; endmodule
module freqdiv16
(
    input wire CLK_IN,
    input wire RST_N,
    output wire [3:0]CLK_OUT
);

reg [3:0] count;
    
initial
begin
    count=4'b0000;
end

always @(posedge CLK_IN)
begin
    if (RST_N==1)
        count <= 4'b0000;
    else if (count == 4'b1111)
        count <= 4'b0000;
    else
        count <= count + 1;
end

assign CLK_OUT = count;
endmodule

ここまでが後で論理合成にかける予定の部分。

テストベンチ

通例手抜きのテストベンチが以下に。ボード上のクロック源は24MHzなんだけれども、計算メンドイという理由で25MHzクロックにしてるぞ。まあ遅延とか全然なシミュレーションなので雰囲気だけね~。いい加減な。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
`timescale 1 ns / 100 ps
module counter8_tb;
reg CLK, RST;
wire [3:0] OUT;
wire P1;
wire P2;
parameter STEP = 40;
counter12 dut(CLK, RST, OUT, P1, P2);
initial begin
$dumpfile("counter12.vcd");
$dumpvars(-1, dut);
$monitor("%d CLK=%d RST=%d OUT=%d P1=%d P2=%d", $stime, CLK, RST, OUT, P1, P2);
end
always begin
CLK=0; #(STEP/2);
CLK=1; #(STEP/2);
end
initial begin
#0 RST = 1'b1;
#STEP RST = 1'b0;
#(STEP*600) $finish;
end
endmodule
`timescale 1 ns / 100 ps module counter8_tb; reg CLK, RST; wire [3:0] OUT; wire P1; wire P2; parameter STEP = 40; counter12 dut(CLK, RST, OUT, P1, P2); initial begin $dumpfile("counter12.vcd"); $dumpvars(-1, dut); $monitor("%d CLK=%d RST=%d OUT=%d P1=%d P2=%d", $stime, CLK, RST, OUT, P1, P2); end always begin CLK=0; #(STEP/2); CLK=1; #(STEP/2); end initial begin #0 RST = 1'b1; #STEP RST = 1'b0; #(STEP*600) $finish; end endmodule
`timescale 1 ns / 100 ps

module counter8_tb;

reg CLK, RST;
wire [3:0] OUT;
wire P1;
wire P2;

parameter STEP = 40;

counter12 dut(CLK, RST, OUT, P1, P2);

initial begin
    $dumpfile("counter12.vcd");
    $dumpvars(-1, dut);
    $monitor("%d CLK=%d RST=%d OUT=%d P1=%d P2=%d", $stime, CLK, RST, OUT, P1, P2);
end

always begin
    CLK=0; #(STEP/2);
    CLK=1; #(STEP/2);
end

initial begin
    #0			RST = 1'b1;
    #STEP		RST = 1'b0;
    #(STEP*600) $finish;
end

endmodule
エラボレーション(ビルド)してシミュレーション

上記で作成のファイル4つをエラボレーション(ビルド。)

$ iverilog -o counter12.out counter12_tb.v counter12.v freqdiv12.v freqdiv16.v

生成されたオブジェクト counter12.outのシミュレーション実行

$ vvp counter12.out >counter12_out.txt

上記でテキスト出力されたシミュレーション結果の頭のところが以下に。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
VCD info: dumpfile counter12.vcd opened for output.
0 CLK=0 RST=1 OUT= 0 P1=0 P2=0
20 CLK=1 RST=1 OUT= 0 P1=1 P2=0
40 CLK=0 RST=0 OUT= 0 P1=1 P2=0
60 CLK=1 RST=0 OUT= 0 P1=1 P2=0
80 CLK=0 RST=0 OUT= 0 P1=1 P2=0
100 CLK=1 RST=0 OUT= 0 P1=1 P2=0
120 CLK=0 RST=0 OUT= 0 P1=1 P2=0
140 CLK=1 RST=0 OUT= 0 P1=1 P2=0
160 CLK=0 RST=0 OUT= 0 P1=1 P2=0
180 CLK=1 RST=0 OUT= 0 P1=1 P2=0
200 CLK=0 RST=0 OUT= 0 P1=1 P2=0
220 CLK=1 RST=0 OUT= 0 P1=1 P2=0
240 CLK=0 RST=0 OUT= 0 P1=1 P2=0
260 CLK=1 RST=0 OUT= 0 P1=0 P2=0
280 CLK=0 RST=0 OUT= 0 P1=0 P2=0
300 CLK=1 RST=0 OUT= 0 P1=0 P2=1
VCD info: dumpfile counter12.vcd opened for output. 0 CLK=0 RST=1 OUT= 0 P1=0 P2=0 20 CLK=1 RST=1 OUT= 0 P1=1 P2=0 40 CLK=0 RST=0 OUT= 0 P1=1 P2=0 60 CLK=1 RST=0 OUT= 0 P1=1 P2=0 80 CLK=0 RST=0 OUT= 0 P1=1 P2=0 100 CLK=1 RST=0 OUT= 0 P1=1 P2=0 120 CLK=0 RST=0 OUT= 0 P1=1 P2=0 140 CLK=1 RST=0 OUT= 0 P1=1 P2=0 160 CLK=0 RST=0 OUT= 0 P1=1 P2=0 180 CLK=1 RST=0 OUT= 0 P1=1 P2=0 200 CLK=0 RST=0 OUT= 0 P1=1 P2=0 220 CLK=1 RST=0 OUT= 0 P1=1 P2=0 240 CLK=0 RST=0 OUT= 0 P1=1 P2=0 260 CLK=1 RST=0 OUT= 0 P1=0 P2=0 280 CLK=0 RST=0 OUT= 0 P1=0 P2=0 300 CLK=1 RST=0 OUT= 0 P1=0 P2=1
VCD info: dumpfile counter12.vcd opened for output.
         0 CLK=0 RST=1 OUT= 0 P1=0 P2=0
        20 CLK=1 RST=1 OUT= 0 P1=1 P2=0
        40 CLK=0 RST=0 OUT= 0 P1=1 P2=0
        60 CLK=1 RST=0 OUT= 0 P1=1 P2=0
        80 CLK=0 RST=0 OUT= 0 P1=1 P2=0
       100 CLK=1 RST=0 OUT= 0 P1=1 P2=0
       120 CLK=0 RST=0 OUT= 0 P1=1 P2=0
       140 CLK=1 RST=0 OUT= 0 P1=1 P2=0
       160 CLK=0 RST=0 OUT= 0 P1=1 P2=0
       180 CLK=1 RST=0 OUT= 0 P1=1 P2=0
       200 CLK=0 RST=0 OUT= 0 P1=1 P2=0
       220 CLK=1 RST=0 OUT= 0 P1=1 P2=0
       240 CLK=0 RST=0 OUT= 0 P1=1 P2=0
       260 CLK=1 RST=0 OUT= 0 P1=0 P2=0
       280 CLK=0 RST=0 OUT= 0 P1=0 P2=0
       300 CLK=1 RST=0 OUT= 0 P1=0 P2=1

また結果を波形ビューワー gtkwave で観察したところが以下に。counter12SIMwave

2相クロックの間に「隙間」は空いておる、と。

帰らざるMOS回路(39) セントロニクスI/Fのタイミングチャートを描く へ戻る

帰らざるMOS回路(41) 2相ノンオーバラップクロック生成回路をFPGA実装 へ進む