Usage of 'begin/end' in design modules

Viewed 402

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.

2 Answers

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.

You need begin end when you have multiple statements in a particular block. Example

//Single line statement hence no begin end needed
always@(posedge clk)
  a <= b &c;

 //Multiple lines hence begin end is needed
always@(posedge clk)
begin
 if(reset)
  a <= 'd0;
 else 
  a <= b & c;
end

Same applies for if else and case statements etc.

Related