Johnson Counter Syntax error. Unexpected token: generate

Viewed 731

My college teacher asked for me to implement a Johnson Counter and it's test bench, with an width<=32 (he calls it an N parameter), and the implementation has to use generate/for structures. Although I had learned a little about Johnson Counter, I don't know how to use generate in this case, and I had some errors when I tried to run the test bench. Here is my implementation so far:

module johnsonCounter #(parameter N = 32)  
  ( 
    input clk,                
    input rstn,
    output reg [N-1:0] out
  );    

  always @ (posedge clk) begin
    if (!rstn)
      out <= 1;
    else begin
      out[N-1] <= ~out[0];
      generate
        for (int i = 0; i < N-1; i=i+1) begin
          out[i] <= out[i+1];
        end
      endgenerate

    end
  end
endmodule

Here is the test bench:

module tb;
  parameter N = 32;
  
  reg clk;
  reg rstn;
  wire [N-1:0] out;
  
  johnsonCounter    u0 (.clk (clk),
                .rstn (rstn),
                .out (out));
  
  always #10 clk = ~clk;
  
  initial begin
    {clk, rstn} <= 0;

    $monitor ("T=%0t out=%b", $time, out);
    repeat (2) @(posedge clk);
    rstn <= 1;
    repeat (15) @(posedge clk);
    $finish;
  end
  
  initial begin
    $dumpvars;
    $dumpfile("dump.vcd");
  end
endmodule

These are the errors:

ERROR VCP2000 "Syntax error. Unexpected token: generate[_GENERATE]. This is a Verilog keyword since IEEE Std 1364-2001 and cannot be used as an identifier. Use -v95 argument for compilation." "design.sv" 13  7
ERROR VCP2020 "begin...end pair(s) mismatch detected. 2 <end> tokens are missing." "design.sv" 17  7
ERROR VCP2020 "module/macromodule...endmodule pair(s) mismatch detected. 1 <endmodule> tokens are missing." "design.sv" 17  7
ERROR VCP2000 "Syntax error. Unexpected token: endgenerate[_ENDGENERATE]. This is a Verilog keyword since IEEE Std 1364-2001 and cannot be used as an identifier. Use -v95 argument for compilation." "design.sv" 17  7

Any help is welcome =)

2 Answers

It is illegal to use generate in that way.

For your code, just a for loop is needed (without generate):

  always @ (posedge clk) begin
    if (!rstn)
      out <= 1;
    else begin
      out[N-1] <= ~out[0];
      for (int i = 0; i < N-1; i=i+1) begin
          out[i] <= out[i+1];
      end
    end
  end

For generate syntax, refer to the IEEE Std 1800-2017, section 27. Generate constructs.

I tried implementing it using the generate construct. I am also new at this, so if anybody sees any problem or error, or could provide any suggestion to improve performance, I would appreciate it.

Regarding your question, I always use generate to instantiate several modules, I think it makes my code cleaner and easier to understand. So what I did is to define a simple D flip-flop module, which I will use to instantiate it. If you want to use generate, you have to define an iterative variable with genvar. Also, you should use generate outside an always block (I don't know if there is a situation where you could use it inside the always block). Below, you can see the code.

module ff 
  (
    input clk,
    input rstn,
    input d,
    output reg q,
    output reg qn
  );
  
  always @(posedge clk)
    begin
      if(!rstn)
        begin
          q <= 0;
          qn <= 1;
        end
      else
        begin
          q <= d;
          qn <= ~d;
        end
    end
endmodule

module johnsonCounter #(parameter N = 4)  
  ( 
    input clk,                
    input rstn,
    output [N-1:0] out,
    output [N-1:0] nout
  );    

  genvar i;
  generate
    for (i = 0; i < N-1; i=i+1) begin
      ff flip (.clk(clk), .rstn(rstn), .d(out[i+1]), .q(out[i]), .qn(nout[i]));
    end
  endgenerate
  
  ff lastFlip (.clk(clk), .rstn(clk), .d(nout[0]), .q(out[N-1]), .qn(nout[N-1]));
endmodule

Here you have the testbench, too. One thing I changed from your code is the dumpfile line. It should go before dumpvar.

module tb;
  parameter N = 4;
  
  reg clk;
  reg rstn;
  wire [N-1:0] out;
  
  johnsonCounter    u0 (.clk (clk),
                .rstn (rstn),
                .out (out));
  
  always #10 clk = ~clk;
  
  initial begin
    {clk, rstn} <= 0;

    $monitor ("T=%0t out=%b", $time, out);
    repeat (2) @(posedge clk);
    rstn <= 1;
    repeat (15) @(posedge clk);
    $finish;
  end
  
  initial begin
    $dumpfile("dump.vcd");
    $dumpvars;
  end
endmodule

This code was tested using EDA Playground and it worked fine but, as I said, I am not an expert, so if anybody finds any error or have any suggestion, it is welcome.

Related