2021年1月28日木曜日

verilog : 擬似乱数生成

 目的: 

疑似乱数の生成方法、RTLについて記す。

仕様:

本疑似乱数生成は、
  1. 9bit LFSR (線形帰還シフトレジスタ) をベースに生成する。
  2. 出力は 9bit 疑似乱数で 0x001~0x1ff を出力。
  3. 開始パルスで初期値を設定し、イネーブル信号で疑似乱数を更新する。

疑似乱数生成方法:

9bit LFSR

9bit LFSRのブロック図を以下に示す。
これは、多項式 X^9+X^5+1 の ガロアLFSR(線形帰還シフトレジスタ) で、
2^9=512 通り の内、0 を除いた 511通りの値を周期的に変化する。
512番目の値が最初の値と同じになる。
これを書き換えると以下の様に書ける。

出力 Q[9:1] は、初期値を 0x1FF とすると、
 0x1FF, 0x1EF, 0x1E7, 0x1E3, 0x1E1, 0x1E0, 0x0F0, 0x078, 0x03C, 0x01E, ……
 (511) (495) (487) (483) (481) (480) (240) (120) (60)  (30)  

の様に変化し、512番目で 0x1FF に戻る。
このままでも 疑似乱数ではあるが、隣り合う値の多くのビットは 1bit シフトした値の為、似た様なビットパターンとなる。

疑似乱数の生成

上述の為、下図の様に ビットシフトとEOR 部分(LSF) を 9段重ね、ビットシフトが1周したデータ(9個置きの値)を取得する様にする。

出力 Q[9:1] は、初期値を 0x1FF とすると、
 0x1FF, 0x01E, 0x1C3, 0x1B9, 0x090, 0x099, 0x1A2, 0x1FC, 0x07B, ……
 (511) ( 30) (451) (441) (144) (153) (418) (508) (123)
の様に変化し、512番目で 0x1FF に戻る。
尚、この疑似乱数には 0 は含まれない。FF の出力が 0 となると、以降、FF出力は 0のまま変化しなくなる。

0を含んだ疑似乱数が必要な場合、1bit 削ることで0を含む疑似乱数を得ることができる。
例えば、8bit の 疑似乱数を取得する場合、上の出力 Q の 下位 8bit (Q[8:1]) を取り出す。
但し、この場合、511  データ中に 0 が 1回、1~255 が 2回づつ発生となり、0の発生回数が他よりも少ない。
或いは、外部回路で 適用な位置に '0' を挿入する必要がある。


ブロック図:

疑似乱数生成回路のブロック図を以下に示す。
本回路は、上述の疑似乱数生成回路に以下を追加したものとなる。
  1. 初期値(SEED値) を設定できるようにする。
  2. イネーブルを追加し、イネーブルが 'H' の期間のみ出力を更新する。

RTL:

上述のブロック図 2 の RTL を以下に示す。
// ----------------------------------------------------------------------------
//  Pseudo-Random Number
//
//   Module Name : prn
//   Version     : 0.00
// ----------------------------------------------------------------------------
 
module prn (                            // Module name : prn
  CLR,                                  // port list
  CLK,
  seed,
  load,
  enable,
  prn
) ;
 
// port declaration ----------------
input              CLR      ;
input              CLK      ;
input       [ 8:0] seed     ;
input              load     ;
input              enable   ;
output      [ 8:0] prn      ;
 
// parameter declaration -----------
parameter P_DLY = 1 ;
 
// internal signal declaration -----
wire [9:1]  lsf0        ;
wire [9:1]  lsf1        ;
wire [9:1]  lsf2        ;
wire [9:1]  lsf3        ;
wire [9:1]  lsf4        ;
wire [9:1]  lsf5        ;
wire [9:1]  lsf6        ;
wire [9:1]  lsf7        ;
wire [9:1]  lsf8        ;

reg  [9:1]  Q           ;

// logical description -------------

assign lsf0 = {Q[1],Q[9:7],(Q[1]^Q[6]),Q[5:2]} ;
assign lsf1 = {lsf0[1],lsf0[9:7],(lsf0[1]^lsf0[6]),lsf0[5:2]} ;
assign lsf2 = {lsf1[1],lsf1[9:7],(lsf1[1]^lsf1[6]),lsf1[5:2]} ;
assign lsf3 = {lsf2[1],lsf2[9:7],(lsf2[1]^lsf2[6]),lsf2[5:2]} ;
assign lsf4 = {lsf3[1],lsf3[9:7],(lsf3[1]^lsf3[6]),lsf3[5:2]} ;
assign lsf5 = {lsf4[1],lsf4[9:7],(lsf4[1]^lsf4[6]),lsf4[5:2]} ;
assign lsf6 = {lsf5[1],lsf5[9:7],(lsf5[1]^lsf5[6]),lsf5[5:2]} ;
assign lsf7 = {lsf6[1],lsf6[9:7],(lsf6[1]^lsf6[6]),lsf6[5:2]} ;
assign lsf8 = {lsf7[1],lsf7[9:7],(lsf7[1]^lsf7[6]),lsf7[5:2]} ;

always @(posedge CLK or posedge CLR)
  if (CLR)
    Q <= #P_DLY 9'h1ff  ;
  else if (load)
    Q <= #P_DLY seed ;
  else if (enable)
    Q <= #P_DLY lsf8 ;

assign prn = Q[9:1] ;

endmodule

動作結果:

本回路のシミュレーション結果 を以下に示す。


0 件のコメント:

コメントを投稿