2021年10月25日月曜日

verilog : 多ビット信号の配列(二次元配列)と入出力ポート

目的:

入出力ポートには2次元配列を使用できない為、2次元配列を1次元配列にアサインする。

記述例:

内部信号
  reg  [P_BW-1:0]  r_rise_pos[0:6] ;
を 1次元の配列
  wire [P_BW*7-1:0] w_rise_pos ;
に アサイン する場合の記述例を以下に示す。

例1 :

assign  w_rise_pos = {r_rise_pos[6], r_rise_pos[5],r_rise_pos[4],r_rise_pos[3],
                      r_rise_pos[2], r_rise_pos[1],r_rise_pos[0] } ;

例2 :

generate
  for (i=0; i<7; i=i+1)
    begin : asin_1d
      assign w_rise_pos[(i+1)*P_BW-1:i*P_BW] = r_rise_pos[i] ;
    end
endgenerate

回路例:

この回路例は、レジスタブロック(pgen_reg)とパルス生成ブロック(pgen_plsgen)で構成。
7組の 立ち上げタイミング(r_rise_pos)と立ち下げタイミング(r_fall_pos)レジスタを持ち、スタートビット(r_cntstart) に '1' をライトする事で、設定したタイミングで ON/OFF する7つのパルスを出力する。
立ち上げ/たち下げタイミングを 2次元配列とし、ブロック間 を1次元配列として接続している。

RTL (Verilog)

レジスタブロック : 2次元配列→1次元配列 のアサインに 上述の 例1 と 例2 を使用。

// -----------------------------------------------------
//   2d-array Sample module 
//
//   Module Name : pgen_reg
//   Version     : 0.00
// -----------------------------------------------------
 
module pgen_reg #(                      // Module name : test
  parameter P_BW = 8                    // parameter list
) (                                     //
  clr,                                  // port list
  clk,
  adr,
  we,
  data,
  rd_data,
  cntstart,
  cntmax,
  rise_pos,
  fall_pos
) ;
 
// ====== port declaration ================
input                     clr      ;
input                     clk      ;
input            [3:0]    adr      ;
input                     we       ;
input       [P_BW-1:0]    data     ;
output      [P_BW-1:0]    rd_data  ;
output                    cntstart ;
output      [P_BW-1:0]    cntmax   ;
output reg  [7*P_BW-1:0]  rise_pos ;
output reg  [7*P_BW-1:0]  fall_pos ;
 
// ====== parameter declaration ===========
parameter   DLY = 1 ;
 
// ====== internal signal declaration =====
wire        [15:0]  sel        ;
wire        [15:0]  reg_wen    ;
wire  [7*P_BW-1:0]  w_rise_pos ;
wire  [7*P_BW-1:0]  w_fall_pos ;

reg              r_cntstart ;
reg  [P_BW-1:0]  r_cntmax     ; 
reg  [P_BW-1:0]  r_rise_pos[0:6] ;
reg  [P_BW-1:0]  r_fall_pos[0:6] ;

// variable for generate ----------
genvar i ;

// ====== logical description =============

// address decode -------------------------
assign sel = 16'd1 << adr ;

// write enable ---------------------------
assign reg_wen = sel & {16{we}} ;

// register -------------------------------

//   cntstart reg -----------------------
always @(posedge clk or posedge clr)
  if (clr) 
    r_cntstart  <= #DLY  1'b0 ;
  else if (reg_wen[0])
    r_cntstart  <= #DLY  data[0] ;

//   cntmax reg -------------------------
always @(posedge clk or posedge clr)
  if (clr) 
    r_cntmax    <= #DLY  {P_BW{1'b0}} ;
  else if (reg_wen[1])
    r_cntmax    <= #DLY  data ;

//   rise_pos, fall_pos reg -------------
generate
  for (i=0; i<7; i=i+1) 
    begin : pos_reg
      always @(posedge clk or posedge clr)
        if (clr)
          r_rise_pos[i]  <= #DLY  {P_BW{1'b0}} ;
        else if (reg_wen[i*2+2])
          r_rise_pos[i]  <= #DLY  data ;

      always @(posedge clk or posedge clr)
        if (clr) begin
          r_fall_pos[i]  <= #DLY  {P_BW{1'b0}} ;
          end
        else if (reg_wen[i*2+3])
          r_fall_pos[i]  <= #DLY  data ;
    end
endgenerate

// read data select -----------------------
assign rd_data = (sel[0])  ?  {{(P_BW-1){1'b0}},r_cntstart} :
                 (sel[1])  ?  r_cntmax :
                 (sel[2])  ?  r_rise_pos[0] :
                 (sel[3])  ?  r_fall_pos[0] :
                 (sel[4])  ?  r_rise_pos[1] :
                 (sel[5])  ?  r_fall_pos[1] :
                 (sel[6])  ?  r_rise_pos[2] :
                 (sel[7])  ?  r_fall_pos[2] :
                 (sel[8])  ?  r_rise_pos[3] :
                 (sel[9])  ?  r_fall_pos[3] :
                 (sel[10]) ?  r_rise_pos[4] :
                 (sel[11]) ?  r_fall_pos[4] :
                 (sel[12]) ?  r_rise_pos[5] :
                 (sel[13]) ?  r_fall_pos[5] :
                 (sel[14]) ?  r_rise_pos[6] :
                 (sel[15]) ?  r_fall_pos[6] : {P_BW{1'b1}} ;

// 2d_array -> 1d_array --------------------
// EX.1 ------------
assign  w_rise_pos =   { r_rise_pos[6], 
                         r_rise_pos[5],
                         r_rise_pos[4],
                         r_rise_pos[3],
                         r_rise_pos[2],
                         r_rise_pos[1],
                         r_rise_pos[0] } ;
// EX.2 ------------
generate
  for (i=0; i<7; i=i+1)
    begin : asin_1d
      assign w_fall_pos[(i+1)*P_BW-1:i*P_BW] = r_fall_pos[i] ;
    end
endgenerate


// output signal ---------------------------
assign cntstart  = r_cntstart ; 
assign cntmax    = r_cntmax ;

always @(posedge clk or posedge clr)
  if (clr)
    rise_pos <= #DLY  {(7*P_BW){1'b0}} ;
  else
    rise_pos <= #DLY  w_rise_pos  ;

always @(posedge clk or posedge clr)
  if (clr)
    fall_pos <= #DLY {(7*P_BW){1'b0}} ;
  else
    fall_pos <= #DLY  w_fall_pos ;

endmodule

パルス生成ブロック : 1次元配列→2次元配列 のアサインに 上述の 例2 と同様の記述を使用。

// -----------------------------------------------------
//   2d-array Sample module 
//
//   Module Name : pgen_plsgen
//   Version     : 0.00
// -----------------------------------------------------
 
module pgen_plsgen #(              // Module name : test_plsgen
  parameter P_BW = 8               // parameter list
) (                                //
  clr,                             // port list
  clk,
  cntstart,
  cntmax,
  rise_pos,
  fall_pos,
  pls_0,
  pls_1,
  pls_2,
  pls_3,
  pls_4,
  pls_5,
  pls_6
) ;
 
// ====== port declaration ================
input                clr ;
input                clk ;
input                cntstart ;
input    [P_BW-1:0]  cntmax   ;
input  [7*P_BW-1:0]  rise_pos ;
input  [7*P_BW-1:0]  fall_pos ;
output               pls_0    ;
output               pls_1    ;
output               pls_2    ;
output               pls_3    ;
output               pls_4    ;
output               pls_5    ;
output               pls_6    ;
 
// ====== parameter declaration ===========
parameter   DLY = 1 ;
 
// ====== internal signal declaration =====
wire             w_start_pls  ;
wire  [P_BW-1:0] w_rise_pos[0:6] ;
wire  [P_BW-1:0] w_fall_pos[0:6] ;
wire             w_pls[0:6]  ;
wire             w_valid ;

reg              r_start_dl ;
reg  [P_BW-1:0]  r_count ;
reg              r_pls[0:6]  ;

// variable for generate ----------
genvar i ;

// ====== logical description =============

// input array -> 2d array assign ---------
generate
  for (i=0; i<7; i=i+1) 
    begin : asin_2d
      assign w_rise_pos[i] = rise_pos[(i+1)*P_BW-1:i*P_BW] ;
      assign w_fall_pos[i] = fall_pos[(i+1)*P_BW-1:i*P_BW] ;
    end
endgenerate

// generate start pulse -------------------
always @(posedge clk or posedge clr)
  if (clr)
    r_start_dl  <= #DLY  1'b0 ;
  else
    r_start_dl  <= #DLY  cntstart ;

assign w_start_pls = cntstart & ~r_start_dl ;

// pulse counter  -------------------------
always @(posedge clk or posedge clr)
  if (clr)
    r_count  <= #DLY  {P_BW{1'b0}};
  else if (w_start_pls)
    r_count  <= #DLY  {{(P_BW-1){1'b0}},1'b1} ;
  else if ((r_count > 0) && (r_count < cntmax) )
    r_count  <= #DLY  r_count + 1 ;
  else if (r_count == cntmax)
    r_count  <= #DLY  {P_BW{1'b0}} ;

assign r_valid = r_count != 0 ;

// pulse generate -------------------------
generate
  for (i=0; i<7; i=i+1) 
    begin : pos_reg
      assign w_pls[i] = (w_rise_pos[i] <= r_count) && (r_count < w_fall_pos[i]) && r_valid ;

      always @(posedge clk or posedge clr)
        if (clr)
          r_pls[i]  <= #DLY  {P_BW{1'b0}} ;
        else
          r_pls[i]  <= #DLY  w_pls[i] ;
    end
endgenerate

// output signal ---------------------------
assign pls_0 = r_pls[0]   ; 
assign pls_1 = r_pls[1]   ; 
assign pls_2 = r_pls[2]   ; 
assign pls_3 = r_pls[3]   ; 
assign pls_4 = r_pls[4]   ; 
assign pls_5 = r_pls[5]   ; 
assign pls_6 = r_pls[6]   ; 
 
endmodule

トップブロック : レジスタブロックとパルス生成ブロックの上位ブロック

// -----------------------------------------------------
//   2d-array Sample module 
//
//   Module Name : pgen
//   Version     : 0.00
// -----------------------------------------------------
 
module pgen(
  clr,                                  // port list
  clk,
  adr,
  we,
  data,
  rd_data,
  pls_0,
  pls_1,
  pls_2,
  pls_3,
  pls_4,
  pls_5,
  pls_6
) ;

// ====== port declaration ================
input                clr ;
input                clk ;
input         [3:0]  adr ;
input                we  ;
input    [     7:0]  data     ;
output   [     7:0]  rd_data  ;
output               pls_0    ;
output               pls_1    ;
output               pls_2    ;
output               pls_3    ;
output               pls_4    ;
output               pls_5    ;
output               pls_6    ;
 
// ====== internal signal declaration =====
wire               cntstart ;
wire   [     7:0]  cntmax   ;
wire [7*8   -1:0]  rise_pos ;
wire [7*8   -1:0]  fall_pos ;
 
// ====== logical description =============

pgen_reg #(            
  .P_BW  (8)  
)i_test_reg(                    
  .clr        ( clr          ),                 
  .clk        ( clk          ),
  .adr        ( adr          ),
  .we         ( we           ),
  .data       ( data         ),
  .rd_data    ( rd_data      ),
  .cntstart   ( cntstart     ),
  .cntmax     ( cntmax       ),
  .rise_pos   ( rise_pos     ),
  .fall_pos   ( fall_pos     )
) ;
 
pgen_plsgen #(
  .P_BW (8)
)i_test_plsgen(                  
  .clr          ( clr      ),               
  .clk          ( clk      ),
  .cntstart     ( cntstart ),
  .cntmax       ( cntmax   ),
  .rise_pos     ( rise_pos ),
  .fall_pos     ( fall_pos ),
  .pls_0        ( pls_0    ),
  .pls_1        ( pls_1    ),
  .pls_2        ( pls_2    ),
  .pls_3        ( pls_3    ),
  .pls_4        ( pls_4    ),
  .pls_5        ( pls_5    ),
  .pls_6        ( pls_6    )
) ;

endmodule

シミュレーション用のテストベンチ

// ----------------------------------------------------------
//   test bench
//
//     for pgen.v
// ----------------------------------------------------------

`timescale 1ns / 1ps

module testbench ;

// testbench logic -------------------
logic         clr;
logic         clk;
logic  [ 3:0] adr     ;
logic         we      ;
logic  [ 7:0] data    ;
logic  [ 7:0] rd_data ;
logic         pls_0   ;
logic         pls_1   ;
logic         pls_2   ;
logic         pls_3   ;
logic         pls_4   ;
logic         pls_5   ;
logic         pls_6   ;

// parameter -------------------------
parameter  MAX_SIM_TIME = 20000 ;

// target module ---------------------
pgen i_pgen (
  .clr           ( clr        ),
  .clk           ( clk        ),
  .adr           ( adr        ),
  .we            ( we         ),
  .data          ( data       ),
  .rd_data       ( rd_data    ),
  .pls_0         ( pls_0      ),
  .pls_1         ( pls_1      ),
  .pls_2         ( pls_2      ),
  .pls_3         ( pls_3      ),
  .pls_4         ( pls_4      ),
  .pls_5         ( pls_5      ),
  .pls_6         ( pls_6      )
) ;

// clock, reset generate -------------
initial begin
  clk = 0 ;
  clr = 1 ;
  #10 clr = 0 ;
  forever begin
    #10 clk = ~clk ;
  end
end

// scenario --------------------------
initial begin
  $dumpfile("wave.vcd");
  $dumpvars(0,testbench) ;

  adr         =  4'h0   ;
  we          =  1'b0   ;
  data        =  8'h0   ;

  #MAX_SIM_TIME
  $display(" SIM TIME OUT !!") ;
  $finish ;

  end

// include test patteern  ------------

initial begin

  $display (" ") ;
  #200

  @(posedge clk) #1
  adr    = 4'h2   ;     // rise_pos 0
  data   = 8'h10  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h3   ;     // fall_pos 0
  data   = 8'h14  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h4   ;     // rise_pos 1
  data   = 8'h20  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h5   ;     // fall_pos 1
  data   = 8'h28  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h6   ;     // rise_pos 2
  data   = 8'h30  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h7   ;     // fall_pos 2
  data   = 8'h3f  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h8   ;     // rise_pos 3
  data   = 8'h12  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h9   ;     // fall_pos 3
  data   = 8'h38  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'ha   ;     // rise_pos 4
  data   = 8'h3e  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'hb   ;     // fall_pos 4
  data   = 8'h3f  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'hc   ;     // rise_pos 5
  data   = 8'h0f  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'hd   ;     // fall_pos 5
  data   = 8'h10  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'he   ;     // rise_pos 6
  data   = 8'h20  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'hf   ;     // fall_pos 7
  data   = 8'h21  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  @(posedge clk) #1
  adr    = 4'h1   ;     // count max 
  data   = 8'h50  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h0   ;     // count start on
  data   = 8'h01  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;
  @(posedge clk) #1
  @(posedge clk) #1
  adr    = 4'h0   ;     // count start off
  data   = 8'h00  ;
  we     = 1'b1   ;
  @(posedge clk) #1
  we     = 1'b0   ;

  repeat(100) @(posedge clk)  ;

  $display ("test_END");

  $finish ;
end

// include assertion bind list -------
//`include "bind.list"
//`include "bind_sva.sv"
//`include "sva_1.sv"

endmodule

シミュレーション結果を以下に示す。
コマンドラインからの VCD出力では 2次元配列の信号が表示されなかった為、vivado GUI でのシミュレーション波形を表示。pls0 のみ レジスタブロックとパルス生成ブロックの2次元配列を表示。(他は パルス生成ブロックのみ)


 

0 件のコメント:

コメントを投稿