PRBSをVerilogで作る

PRBSをVHDLとVerilogで設計します。CCITT 0.153やITU-T勧告 V.52などで使われているPRBS9を実際に設計してその手法を学びます。
PRBSの生成多項式は次のように記されています。
G(y) = X9+X5+1
したがって、回路図で示すと次のようになります。

この回路をそのまま作成しても面白くないので、PRBS3とPRBS15を切り替えられるように作ります。
PRBS3を規格として使う事はほとんどありませんし、例えば伝送路のBERを測る時に使うという事もありません。したがってPRBS3を解説している本もほとんど無いと思いますが、じつはPRBS3は自分で検証する際のデータとして非常に便利です。それは、PRBS3は7ビット周期になるので、データを見ただけで誤りを目視できるからです。たとえば、オシロスコープ等でデータを1ショットで捉えた時に、7ビット程度であれば、すぐに検証できます。これが128ビット等になると1ショットを取ったとしても巡回の始めを探すのに苦労します。なので、私はPRBSを使うときに、まずはPRBS3で大まかな動作を確認してから、PRBS9やPRBS15を使ってBER測定するようにしています。
// TITLE: "prbs.v" // MODULE NAME: // PROJECT CODE: // AUTHOR: (****@nakaharagiken.com) // CREATION DATE: 2020.8.7 // SOURCE: // LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. // DESCRIPTION: PRBSジェネレータ // NOTES TO USER: // SOURCE CONTROL: // REVISION HISTORY: v0.1 2020.8.7 First edition // // // 1->2->3->4->5->6->7->8->9->10->11->12->13->14->15 // ------------- // | | | // ->0->+->1->2-> PRBS3 = x^3+x^2+1 // // 1->2->3->4->5->6->7->8->9->10->11->12->13->14->15 // ==============------------ // | | | // ->0->1->2->3->4->5->6->7->8| PRBS9 = x^9+x^5+1 // // ============================================----- // | | | // ->0->1->2->3->4->5->6->7->8->9->10->11->12->13->14 PRBS15 = x^15+x^14+1 // `timescale 1ns/1ps module prbs( clock, nreset, // (i) 非同期リセット ~~reset~~|__normal__ enable, // (i) シリアルクロック同期イネーブル ~~enable~~|__disable__ mode, // (i) 00=off, 01=PRBS3, 10=PRBS9,11=PRBS15 prout // (0) 出力 ); input clock; input nreset; input enable; input [1:0] mode; // 00=off, 01=PRBS3, 10=PRBS9,11=PRBS15 output prout; //シフト・レジスタ reg [14:0] shift_r; reg rprbsout; reg [2:0] PRBS_S; wire wprbs3; wire wprbs9; wire wprbs15; // 各モード別タップ位置 assign wprbs3 = shift_r[2] ^ shift_r[1]; assign wprbs9 = shift_r[8] ^ shift_r[4]; assign wprbs15 = shift_r[14] ^ shift_r[13]; //モード選定 assign wprbs = (mode == 2'b00) ? 1'b0: // モード選択 (mode == 2'b01) ? wprbs3: (mode == 2'b10) ? wprbs9: wprbs15; /////////////////////////////////////////////////// // シフトレジスタの生成 /////////////////////////////////////////////////// always @ (posedge clock, negedge nreset) begin if (!nreset) begin shift_r <= 16'b1111_1111_1111_1111; // 初期値 end else begin if (mode == 2'b00) begin // OFFの時にはシフトレジスタを止める shift_r <= 16'b1111_1111_1111_1111; // 初期値 end else begin if (enable == 1'b1) begin shift_r[14] <= shift_r[13]; shift_r[13] <= shift_r[12]; shift_r[12] <= shift_r[11]; shift_r[11] <= shift_r[10]; shift_r[10] <= shift_r[9]; shift_r[9] <= shift_r[8]; shift_r[8] <= shift_r[7]; shift_r[7] <= shift_r[6]; shift_r[6] <= shift_r[5]; shift_r[5] <= shift_r[4]; shift_r[4] <= shift_r[3]; shift_r[3] <= shift_r[2]; shift_r[2] <= shift_r[1]; shift_r[1] <= shift_r[0]; shift_r[0] <= wprbs; end else begin shift_r <= shift_r; end end end end ///////////////////////////////////////////////// // データ取り出しタップの選択 ///////////////////////////////////////////////// always @ (posedge clock, negedge nreset) begin if (!nreset) begin rprbsout <= 0; // 初期値 end else begin if (enable == 1'b1) begin case (mode) 2'b00 : rprbsout <= 1'b0; // OFF 2'b01 : rprbsout <= shift_r[2]; // PRBS3 2'b10 : rprbsout <= shift_r[8]; // PRBS9 default : rprbsout <= shift_r[14]; // PRBS15 endcase end end end assign prout = rprbsout; endmodule
ソースコードは大きく2つに分かれています。PRBS用のシフトレジスタと出力信号の取り出しです。69行目からのブロックがPRBS用のシフトレジスタです。今回はPRBS15までを扱うので、15ビットのシフトレジスタになっています。shift_r[14:0] <= {shift_r[13:1],wprbs};のように書く事もできます。PRBSのモードを切り替えた時に、取り出すタップ位置を数えるのに、並べて書いた方が分かりやすいので、このように全ビットを記述しました。また、PRBSの初期値は71行目で電源投入時を設定していますが、モードを00にした時にも初期値で停止するようにしています。
PRBSは冒頭で示したようなブロック図でXORを使って巡回しますが、G(y)に相当するのがソースコードのwprbsです。56行目を見てください。ここでPRBS3、PRBS9、PRBS15の各々のG(y)を求めています。そして、61行目で各モードを切り替えています。切り替え信号を作る時に、Verilogでは61行目のようにassignを使って切り替えると便利です。
103行目からは出力信号の取り出し位置(タップ)を切り替えています。ここも61行目のようにassignを使って切り替えても良いのですが、下図のようにシフトレジスタの後に赤枠で示したように出力選択用にスイッチが入ります。

このスイッチの遅延が生じますので、DFFを一つ追加してから出力するようにしています。最後に、テストベンチを記載しておきます。
// TITLE: "TB_prbs.v" // MODULE NAME: TB_prbs // PROJECT CODE: // AUTHOR: (****@nakaharagiken.com) // CREATION DATE: 2020.8.8 // SOURCE: // LICENSE: Copyright (c) 2020 nakaharagiken All rights reserved. // DESCRIPTION: prbs.vのテストベンチ // NOTES TO USER: // SOURCE CONTROL: // REVISION HISTORY: v0.1 2020.8.8 First edition // // `timescale 1ns/1ps module TB_prbs; parameter SYSCLK_PERIOD = 100; // 10MHz reg i_clock; reg i_nreset; // (i) 非同期リセット ~~reset~~|__normal__ reg i_enable; // (i) シリアルクロック同期イネーブル ~~enable~~|__disable__ reg [1:0] i_mode; // (i) 00=off, 01=PRBS3, 10=PRBS9,11=PRBS15 wire o_prout; // (0) 出力 ////////////////////////////////////////////////////////////////////// // Clock Driver ////////////////////////////////////////////////////////////////////// always @(i_clock) #(SYSCLK_PERIOD / 2.0) i_clock <= !i_clock; ////////////////////////////////////////////////////////////////////// // Main ////////////////////////////////////////////////////////////////////// initial begin i_clock <= 0; i_nreset <= 0; // 初期値 i_enable <= 0; i_mode <= 2'b00; repeat(50) @(posedge i_clock); i_nreset <= 1; repeat(100) @(posedge i_clock); i_enable <= 1'b1; i_mode <= 2'b00; repeat(100) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(5) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(100) @(posedge i_clock); i_enable <= 1'b0; i_mode <= 2'b00; repeat(5) @(posedge i_clock); i_mode <= 2'b01; i_enable <= 1'b1; repeat(100) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(5) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(100) @(posedge i_clock); i_enable <= 1'b0; i_mode <= 2'b00; repeat(5) @(posedge i_clock); i_mode <= 2'b10; i_enable <= 1'b1; repeat(100) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(5) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(100) @(posedge i_clock); i_mode <= 2'b11; i_enable <= 1'b1; repeat(100) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(5) @(posedge i_clock); i_enable <= 1'b0; repeat(5) @(posedge i_clock); i_enable <= 1'b1; repeat(100) @(posedge i_clock); end prbs inst_prbs( .clock (i_clock), .nreset (i_nreset), // (i) 非同期リセット ~~reset~~|__normal__ .enable (i_enable), // (i) シリアルクロック同期イネーブル ~~enable~~|__disable__ .mode (i_mode), // (i) 00=off, 01=PRBS3, 10=PRBS9,11=PRBS15 .prout (o_prout) // (0) 出力 ); endmodule
-
前の記事
PRBSの設計方法と概念 2020.08.06
-
次の記事
デジタル信号処理の固定小数点設計方法 2020.08.13

コメントを書く