verilogsystem-verilog

Usage of 'begin/end' in design modules


I tried making a BCD counter on EDA Playground using icarus verilog for simulation. In my first try, I coded the always block without using the begin and end keywords:

module bcdcounter(out, clock, reset);
  output [3:0] out;
  input clock, reset;
  
  reg [3:0] outstate= 4'd0;
  reg [1:0] state= 2'd0;
  
  always@(posedge reset)
    case(state)
      2'd0: state <=2'd1;
      2'd1: state <=2'd2;
      2'd2: state <=2'd0;
    endcase
  
  always@(posedge clock or state)
    if(!state) 
      outstate <= 4'd0;
  if(state == 2'd1) 
    if(outstate != 4'd9)
      outstate <= outstate +4'd1;
  else 
    outstate <= 4'd0;
  if(state == 2'd2) 
    outstate <= outstate;
  
  assign out = outstate;
    
endmodule

and the following output was generated while I checked:

design.sv:21: syntax error
design.sv:21: error: Invalid module instantiation
design.sv:23: syntax error
design.sv:23: error: Invalid module instantiation
design.sv:25: syntax error
design.sv:25: error: Invalid module instantiation
Exit code expected: 0, received: 1

But, once I added a few begin and end keywords, it did work without errors:

module bcdcounter(out, clock, reset);
  output [3:0] out;
  input clock, reset;
  
  reg [3:0] outstate= 4'd0;
  reg [1:0] state= 2'd0;
  
  always@(posedge reset)
    case(state)
      2'd0: state <=2'd1;
      2'd1: state <=2'd2;
      2'd2: state <=2'd0;
    endcase
  
  always@(posedge clock or state)
    begin
      if(!state)
        outstate <=4'd0;
      if(state==2'd1)
        begin
          if(outstate!=4'd9)
            outstate<= outstate+4'd1;
          else outstate<= 4'd0;
        end
      if(state==2'd2)
        outstate<=outstate;
    end
  
  assign out = outstate;
    
endmodule

When do we need to use the begin and end keywords in the design modules? Any help would be appreciated.


Solution

  • begin/end keywords are mandatory when you have multiple statements within an always block.

    In your 1st always block, you don't need begin/end since the case statement is considered a single statement.

    However, in your 2nd always block, you have 3 top-level if statements, which means you need to group them together inside begin/end. Here is the code with different whitespace to clearly show the separate statements:

    always@(posedge clock or state) begin
    
        // Statement 1
        if(!state) outstate <= 4'd0;
    
        // Statement 2
        if(state == 2'd1) 
            if(outstate != 4'd9)
                outstate <= outstate +4'd1;
            else 
                outstate <= 4'd0;
    
        // Statement 3
        if(state == 2'd2) outstate <= outstate;
    
    end  
    

    Since this code compiles without syntax errors, it demonstrates a couple things:

    1. The begin/end keywords shown are mandatory
    2. No other begin/end keywords are needed

    However, other begin/end keywords are optional. You may decide to use them in every if statement. Here is another way to write the code:

    always@(posedge clock or state) begin
    
        if (!state) begin 
            outstate <= 4'd0;
        end
    
        if (state == 2'd1) begin
            if (outstate != 4'd9) begin
                outstate <= outstate +4'd1;
            end else begin
                outstate <= 4'd0;
            end
        end
    
        if (state == 2'd2) begin
            outstate <= outstate;
        end
    
    end  
    

    The same rules apply for initial and final procedural blocks, just like they do for always blocks.