verilog~divider(分周器)~奇数分周もできるよ

こんにちは、Keymaleです。
今回は以前の記事でも紹介しましたDivider(分周器)です。以前の記事では偶数分周しかできない不完全なものでした。奇数分周もできるものは検索してもあまり出てこなかったので、紹介させていただきます。

Divider

早速ですが、以下にDividerのコードを紹介します。


module divider(
input  div_in,
output div_out
);

reg [7:0]div_number;
reg [7:0]cnt_p;
reg [7:0]cnt_n;
reg out_p;
reg out_n;
assign div_out = out_p ^ out_n;

initial begin
    div_number = 8'd3;
    cnt_p      = 8'd1;
    cnt_n      = 8'd1;
    out_p      = 0;
    out_n      = 0;
end

always@(posedge div_in)begin
    cnt_p <= cnt_n + 8'd1;
    if(cnt_n == div_number)begin
        cnt_p <= 8'd1;
        out_p <= ~out_p;
    end
end

always@(negedge div_in)begin
    cnt_n <= cnt_p + 8'd1;
    if(cnt_p == div_number)begin
        cnt_n <= 8'd1;
        out_n <= ~out_n;
   end
end

endmodule

上記コードについて説明していきます。変数については以下のようになっています。

div_in
入力する波形、分周する元

div_out
出力波形、分周後の波形

reg [7:0]div_number
分周数、今回は3分周、ビット数は8

reg [7:0]cnt_p
立ち上がりの回数をカウント

reg [7:0]cnt_n
立下りの回数をカウント

reg out_p
分周数×2の周波数(今回は6分周)の出力

reg out_n
分周数×2の周波数(今回は6分周)の出力の90度位相ずれ

今回はalways文を二つ用意してます。Quartusでのverilogではalwaysに2つ以上のクロックを用いることはできず、仮に2つ入れても片方はリセット信号と認識されてしまい、リセット動作以外をしようとするとエラーが出てしまいます。
そもそもなぜ二つalways文が必要かというと、入力信号の立ち上がりと立下りをカウントしたいからです。奇数で分周する際には立下りでも信号をカウントする必要があるからです。
今回は入力信号の立ち上がりと立下りでカウントして、それぞれ分周数に達したら出力を反転しています。その出力がreg out_p、reg out_nです。しかし出力は偶数分周のままなのですが、位相が90度ずれています。なので、この2つの出力をxorでとることで、奇数分周された波形を取り出すことができます。以下に上記コードでシミュレーションした波形を示します。

きちんと3分周できていることが確認できるかと思います。その他の変数の波形も載せておきました。div_numberを変更すれば、2,3,4,5,6….と様々な分周ができます。

以上がdividerのverilogでのコードでした。最後まで読んでいただきありがとうございます。ご意見、ご感想等あればコメントよろしくお願いします。