よくわからないFPGAのこととか

よくわからないFPGAとか回路とか数学とかについて

遅延可変シフトレジスタ(Verilog)

概要

遅延サイクルと幅を設定可能なシフトレジスタです。
意外とネットに記述が見当たらないので作成しました。
FF生成は本モジュールをパラメーターを変えて使いまわすと楽そう。

f:id:manaka1122:20200719040441p:plain
Shift Register Module

ModelSimで動作確認し、Quartus13.1にて実装確認を行いました。

LUTでやることをRTLで記述しFFは必要なときに入れると、FPGA(LUT&FF)ライクなソースコードになるような気がします。(根拠あんまり無し)

ソースコード


shift_reg.v
// shift_reg.v
// author:manaka
// date:19/01/04
// Description:First

// History
// v0.1 create new
//

module shift_reg #(
   parameter SHIFT_CYCLE = 5
  ,parameter SHIFT_WIDTH = 12
  )
  (
   input                   rst             // reset
  ,input                   clk             // clock
  ,input [SHIFT_WIDTH-1:0] data_in         // data_input
  ,output[SHIFT_WIDTH-1:0] data_out        // data_output
  );

genvar reg_lp  ; // reg  loop variable
genvar wire_lp ; // wire loop variable
reg  [SHIFT_WIDTH-1:0] data_ff_r[SHIFT_CYCLE:1]  ; // shift_reg
wire [SHIFT_WIDTH-1:0] data_ff  [SHIFT_CYCLE:0]  ; // shift_wire

/* shift register */
generate
  for(reg_lp = 0; reg_lp < SHIFT_CYCLE; reg_lp = reg_lp + 1) begin : gen_reg_lp
    always @(posedge clk or posedge rst)
      begin
      if(rst)begin
        data_ff_r[reg_lp+1] <= {SHIFT_WIDTH{1'b0}};
      end
      else begin
        data_ff_r[reg_lp+1] <= data_ff[reg_lp];
      end
    end
  end
endgenerate

generate
  for( wire_lp = 0; wire_lp < SHIFT_CYCLE; wire_lp = wire_lp + 1) begin : gen_wire_lp
    assign data_ff[wire_lp+1] = data_ff_r[wire_lp+1]; 
  end
endgenerate

/* external port */
assign data_ff[0] = data_in              ;
assign data_out   = data_ff[SHIFT_CYCLE] ;

endmodule

検証環境

  • shift_reg_tb.v
    • shift_reg_top.v TOPからパラメーターでデータ幅とサイクル数を定義
      • S1.shift_reg.v width:12 cycle数: 5
      • S2.shift_reg.v width:32 cycle数:11
      • S3.shift_reg.v width: 1 cycle数:22

shift_reg_top.v
// shift_reg_tb.v
// author:manaka
// date:19/01/04
// Description:First

// History
// v0.1 create new
//

module shift_reg_top
  (
   input                   RST             // reset
  ,input                   CLK             // clock
  ,input [11:0]            DATA_1_IN       // data_input
  ,output[11:0]            DATA_1_OUT      // data_output
  ,input [31:0]            DATA_2_IN       // data_input
  ,output[31:0]            DATA_2_OUT      // data_output
  ,input  [0:0]            DATA_3_IN       // data_input
  ,output [0:0]            DATA_3_OUT      // data_output
  );

//------------------------------------
//  shift_reg module
//------------------------------------
defparam S1.SHIFT_CYCLE =  5 ;
defparam S1.SHIFT_WIDTH = 12 ;

shift_reg S1(
         .rst      (RST) 
        ,.clk      (CLK)
        ,.data_in  (DATA_1_IN)        
        ,.data_out (DATA_1_OUT)
    );

defparam S2.SHIFT_CYCLE = 11 ;
defparam S2.SHIFT_WIDTH = 32 ;

shift_reg S2(
         .rst      (RST) 
        ,.clk      (CLK)
        ,.data_in  (DATA_2_IN)        
        ,.data_out (DATA_2_OUT)
    );

defparam S3.SHIFT_CYCLE = 22;
defparam S3.SHIFT_WIDTH =  1;

shift_reg S3(
         .rst      (RST) 
        ,.clk      (CLK)
        ,.data_in  (DATA_3_IN)        
        ,.data_out (DATA_3_OUT)
    );

endmodule

shift_reg_tb.v
// shift_reg_tb.v
// author:manaka
// date:19/01/04
// Description:First

// History
// v0.1 create new
//

`timescale 1ps/1ps

module shift_reg_tb();


    reg             CLK             ;
    reg             RST             ;
    reg     [11:0]  DATA_1_IN       ;
    wire    [11:0]  DATA_1_OUT      ;
    reg     [31:0]  DATA_2_IN       ;
    wire    [31:0]  DATA_2_OUT      ;
    reg      [0:0]  DATA_3_IN       ;
    wire     [0:0]  DATA_3_OUT      ;

//------------------------------------
//  shift_reg module
//------------------------------------

shift_reg_top top_inst(
         .RST        (RST        )     
        ,.CLK        (CLK        )     
        ,.DATA_1_IN  (DATA_1_IN  )     
        ,.DATA_1_OUT (DATA_1_OUT )     
        ,.DATA_2_IN  (DATA_2_IN  )     
        ,.DATA_2_OUT (DATA_2_OUT )     
        ,.DATA_3_IN  (DATA_3_IN  )     
        ,.DATA_3_OUT (DATA_3_OUT )     
    );
    
//------------------------------------
//  Clock generator
//------------------------------------
parameter   CLK_PERIOD   = 20000;    // ps 20ns

  initial begin
      CLK      = 1'b0;
  end
  
  always #(CLK_PERIOD/2) begin
      CLK  <= ~CLK;
  end 
//------------------------------------
//  Reset generator
//------------------------------------
    initial begin
        RST = 1 ;
        repeat(20) @(negedge CLK);
        RST = 0 ;
    end
//------------------------------------
//  Test
//------------------------------------
initial begin
        DATA_1_IN= {12{1'b0}};
        DATA_2_IN= {32{1'b0}};
        DATA_3_IN=  {1{1'b0}};
        @(negedge CLK);
        while(RST==0) @(negedge CLK);
        repeat(50) @(negedge CLK);
        
        DATA_1_IN= {12{1'b1}};
        DATA_2_IN= {32{1'b1}};
        DATA_3_IN=  {1{1'b1}};
        repeat(100) @(negedge CLK);  
        DATA_1_IN= {12{1'b0}};
        DATA_2_IN= {32{1'b0}};
        DATA_3_IN=  {1{1'b0}};
        repeat(100) @(negedge CLK);  
        $stop;
end

endmodule

検証結果

シミュレーション検証

TOPで宣言したモジュールがパラメーターにより遅延されることを確認。
- 12bit 5サイクル
- 32bit 11サイクル
- 1bit 22サイクル

f:id:manaka1122:20200712134417j:plain
sim波形

ツール合成(Quartus13.1)

RTL viewer

Quartusで合成し、RTLViewerを確認。FFが125サイクルと3211サイクルと1*22サイクル生成されている。

f:id:manaka1122:20200712134444j:plain
RTL Viewer

テクノロジーマップ viewer

ロジックのFFが使用されると思っていたが、テクノロジーマップではRAMが使われている。 たくさんのシフトレジスタに各CellのFFを使うとLUTや配線リソースを効率的に使いづらくなる。そのため、RAMを使うようにツール側でつくられている。 FPGAリソースを効率的に使うために、ツール側が対応しているようだ。
(※この辺の特許はXilinxがLUTメモリはFFに使う方法をおさえているため、もしかしてRAM方法がとられているのか?VHDL編参照。)

f:id:manaka1122:20200712134513j:plain
TechnologyMap01
f:id:manaka1122:20200712134649j:plain
TechnologyMap02