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 を使用。

pgen_reg.v : レジスタブロック
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// -----------------------------------------------------
//   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 と同様の記述を使用。

pgen_plsgen.v : パルス生成ブロック
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// -----------------------------------------------------
//   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

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

pgen.v : トップブロック
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
// -----------------------------------------------------
//   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

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

testbench.sv : テストベンチ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
// ----------------------------------------------------------
//   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 件のコメント:

コメントを投稿