1
votes

Below is the always block code.

I need to have same code 11 times, with same functionality but on different variables. So how can I reuse the code?

  always @(posedge tconClk or negedge tconRst_n)
  begin
    if(~tconRst_n)
    begin
      pulse_cnt <= 0;
      pulse_start = 0;
      start_written = 0;
      pulse_width <= 'h271;
    end
    else if(~pulse_rst)
    begin
      pulse_cnt <= 0;
      pulse_start = 0;
    end
    else
    begin
      if(start_signal)
      begin
//        start_written = 0;
        pulse_width <= (pulse_start) ? pulse_width : START_PW;
        pulse_start = 1;
      end
      pulse_cnt <= (pulse_start) ? (pulse_cnt + 1) : pulse_cnt;
    end
  end

Naming Pattern -

  • tconClk, tconRst_n is common,
  • pulse_cnt0, pulse_cnt1 upto 10,
  • pulse_width0, pulse_width1 upto 10,
  • pulse_start[0:10] (Array),
  • start_written[0:10] (Array),
  • pulse_rst[0:10] (Array),
  • start_signal[0:10] (Array),
  • START_PW (No pattern, different name for each 11 always blocks)

Note -

  1. Defining macro won't work, as this code contains many verilog tokens.

  2. I can't make module of the code, because the signals used in the always block, are also used in other part of the code. So if I make module, then I won't be able to ensure proper reg or wire connections to the module. (Like a module output port must be a wire, but that same signal has been used as a reg in other part of code)

3
Im not sure why you cant use macros for this. You can define multiline macros that contain many tokens, so Im not sure why you believe you cannot.Unn
@Unn : I have tried, through multiline macro with arguments, but I got compile error. So, if it is possible, then I request you to post it as an answer.Karan Shah
I don't see why this can't be a module. Have you tried? Driving a reg with a module output is fine.nguthrie
Macros, a module, or a combination of both can all work. Can you give some examples of what the other variable names will be? Is there a naming pattern? For example all groups have the same suffix signals (eg:_cnt,_start,_width) and only the prefix (pulse) changes.Greg
Emacs verilog mode AUTO_TEMPLATE to the rescue. I don't have time right now to write up the proper template for your case, but here is a link to the documentation: veripool.org/projects/verilog-mode/wiki/Faqnguthrie

3 Answers

1
votes

You can use the emacs script verilog-mode using encapulate the RTL in a module and utilize AUTO_TEMPLATE. Something like the following (not tested) then execute verilog-batch-auto within (or batch of) emacs:

/* PulseModule AUTO_TEMPLATE "\([0-9]+\)$" (
     .pulse_cnt(pulse_cnt@),
     .pulse_width(pulse_width@),
     .pulse_start(pulse_start[@]),
     .start_written(start_written[@]),
     .pulse_rst(pulse_rst[@]),
     .start_signal(start_signal[@]),
     .tconClk(tconClk),
     .tconRst_n(tconRst_n)
    );
*/
PulseModule pm_0 (/*AUTOINST*/ .start_pulse_width(START_PW) );
PulseModule pm_1 (/*AUTOINST*/ .start_pulse_width(OTHER_START_PW) );
...
PulseModule pm_10 (/*AUTOINST*/ .start_pulse_width(SOME_OTHER_START_PW) );

There are also various embedded code (such as Perl's EP3, Ruby's eRuby/ruby_it, Python's prepro, etc.) that can generate the desired code.

SystemVerilog enhanced the functionality of macros. For you the `` feature will make your task easier. See IEEE Std 1800-2012 § 22.5.1 `define.

Multi-line macros are a pain to debug. Although it is possible to put your RTL as one macro, I strongly recommend putting it in a module and have the macro instantiate the macro. Something lake the following (not tested):

`define PULSEMACRO(id,val) \
   PulseModule pm_``id( \
     .pulse_cnt(pulse_cnt``id), .pulse_width(pulse_width``id), \
     .pulse_start(pulse_start[id]), .start_written(start_written[id]), \
     .pulse_rst(pulse_rst[id]), .start_signal(start_signal[id]), \
     .start_pulse_width(val) \
     .tconClk(tconClk), .tconRst_n(tconRst_n) )

This instantiate as like follows. Note that a generate for-loop will not work. Macros are evaluated before generate blocks.

`PULSEMACRO(0,START_PW);
`PULSEMACRO(1,OTHER_START_PW);
...
`PULSEMACRO(10,SOME_OTHER_START_PW);

SystemVerilog can also pass multi-dimensional arrays through module ports. Therefore you can rename reg [PULSE_CNT_WIDTH-1:0] pulse_cnt0,...,pulse_cnt10 to logic [PULSE_CNT_WIDTH-1:0] pulse_cnt [11]. With this conversion you can use generate loops.


Alternatively, you can collapse the pulse_cnt into a big bus reg [PULSE_CNT_WIDTH*11-1:0] pulse_cnt, then use bit slicing for indexing pulse_cnt[PULSE_CNT_WIDTH*index +: PULSE_CNT_WIDTH]. Bit slicing is also compatable with Verilog. See What is `+:` and `-:`? and Indexing vectors and arrays with +:

0
votes

Put the always inside a generate statement. You should find lots of examples on SO: here, for instance. You still need to modify your code, which may be no easier than modifying it for module instantiation.

Your code is broken at the moment, because pulse_rst is tested before the clock edge, and it's not in the sensitivity list. You should put it in the list, or recode the block. Note that there are issues in Verilog with having two async controls and a clock; look up "verilog flops with async set and reset", or ask again with a different question.

0
votes

I think you still can use macro. Change those non-common variables into a macro, for example pulse_cnt into `pulse_cnt. Put them into a file and use it as include file.

For example your code,

always @(...) 
begin
  `pulse_cnt <= 0;
  // ...
end

Put this template into a file called for example, my_always.v

Then reuse the code in your other file/module as follows:

`define pulse_cnt pulse_cnt0
`include "my_always.v"
`undef pulse_cnt

`define pulse_cnt pulse_cnt1
`include "my_always.v"
`undef pulse_cnt

//... and so on