AIに周波数カウンタを設計してもらう

電子工作

 ShrikeLiteで周波数カウンタを製作したいと思っています。過去にGPSDOを製作したことがありますが、10MHzで10ppbクラスの周波数確度を目指すとすれば、ゲートを10秒間開けて100Mカウントすることになるので、28ビット程度の桁数が必要です。GPSレシーバの1pps信号を利用してゲートを制御すれば、正確な周波数カウンタを自作することができます。私は、未だVerilogの学習途上なので、フルスクラッチで記述する自信がありません。そこで、GPSDOの一部としての周波数カウンタをAIに設計してもらいました。Geminiに次のように問いかけました。

28ビットの周波数カウンターをverilogで書いてください。
ただし、ゲート時間は、外部から入力されるgate_inにより制御され、カウント中はbusy信号を出力することとします。

 すると、次のようなVerilogのコードを提示されました。

module freq_counter_28bit (
    input  wire        clk,      // システムクロック
    input  wire        reset_n,  // 非同期リセット(負論理)
    input  wire        sig_in,   // 測定対象の入力信号
    input  wire        gate_in,  // 外部ゲート入力
    output reg  [27:0] freq_out, // 測定された周波数データ
    output reg         busy      // カウント中フラグ
);

    // 内部レジスタ
    reg [27:0] count_reg;
    reg        gate_sync_0, gate_sync_1; // gate_in同期化用
    reg        sig_sync_0, sig_sync_1;   // sig_inエッジ検出用

    // 信号の同期化とエッジ検出用バッファ
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            gate_sync_0 <= 1'b0;
            gate_sync_1 <= 1'b0;
            sig_sync_0  <= 1'b0;
            sig_sync_1  <= 1'b0;
        end else begin
            gate_sync_0 <= gate_in;
            gate_sync_1 <= gate_sync_0;
            sig_sync_0  <= sig_in;
            sig_sync_1  <= sig_sync_0;
        end
    end

    // エッジ検出フラグ
    wire gate_rising  = (gate_sync_0 && !gate_sync_1);
    wire gate_falling = (!gate_sync_0 && gate_sync_1);
    wire sig_rising   = (sig_sync_0  && !sig_sync_1);

    // メイン制御ロジック
    always @(posedge clk or negedge reset_n) begin
        if (!reset_n) begin
            count_reg <= 28'd0;
            freq_out  <= 28'd0;
            busy      <= 1'b0;
        end else begin
            if (gate_rising) begin
                // カウント開始
                count_reg <= 28'd0;
                busy      <= 1'b1;
            end 
            else if (busy) begin
                if (gate_falling) begin
                    // カウント終了、結果を保持
                    freq_out  <= count_reg;
                    busy      <= 1'b0;
                end else if (sig_rising) begin
                    // ゲート期間中の信号立ち上がりをカウント
                    count_reg <= count_reg + 1'b1;
                end
            end
        end
    end

endmodule

 日本語のコメント付きなので、初心者にとっては勉強になります。Geminiは、テストベンチの作成もお手伝いしましょうかとのオファーをくれたので、お願いしたところ、次のようなテストベンチのVerilogコードを提示してくれました。

`timescale 1ns / 1ps

module freq_counter_tb();

    // 信号定義
    reg         clk;
    reg         reset_n;
    reg         sig_in;
    reg         gate_in;
    wire [27:0] freq_out;
    wire        busy;

    // クロック周期の定義
    parameter CLK_PERIOD = 10; // 100MHz
    parameter SIG_PERIOD = 40; // 25MHz (テスト対象信号)

    // インスタンス化
    freq_counter_28bit uut (
        .clk(clk),
        .reset_n(reset_n),
        .sig_in(sig_in),
        .gate_in(gate_in),
        .freq_out(freq_out),
        .busy(busy)
    );

    // システムクロック生成
    initial clk = 0;
    always #(CLK_PERIOD/2) clk = ~clk;

    // テスト対象信号 (sig_in) 生成
    initial sig_in = 0;
    always #(SIG_PERIOD/2) sig_in = ~sig_in;

    // テストシナリオ
    initial begin
        // 初期状態
        reset_n = 0;
        gate_in = 0;
        
        // リセット解除
        #(CLK_PERIOD * 5);
        reset_n = 1;
        #(CLK_PERIOD * 5);

        // --- 測定サイクル 1 ---
        $display("Measurement 1 start...");
        gate_in = 1;
        #(SIG_PERIOD * 10.5); // sig_inを10回分カウントする程度の時間
        gate_in = 0;
        
        // busyが下がるのを待つ
        wait(busy == 0);
        $display("Result 1: %d pulses counted", freq_out);

        #(CLK_PERIOD * 10);

        // --- 測定サイクル 2 ---
        $display("Measurement 2 start...");
        gate_in = 1;
        #(SIG_PERIOD * 25.5); // sig_inを25回分カウントする程度の時間
        gate_in = 0;

        wait(busy == 0);
        $display("Result 2: %d pulses counted", freq_out);

        #(CLK_PERIOD * 20);
        $finish;
    end

    // 波形出力用 (GTKWave等で確認する場合)
    initial begin
        $dumpfile("freq_counter_tb.vcd");
        $dumpvars(0, freq_counter_tb);
    end

endmodule

 この2つのVerilogコードをicarus(iverilog)でコンパイルしてGTKWaveで確認してみました。Verilog初心者にとっては、回路設計だけでも大変なのに、シミュレータ用のコード(テストベンチ)まで作ってくれて大変助かります。しかもオールフリー(全部無料)です。私が現役だった20年前に比べると夢のような話です。

コメント