2
votes

I have a problem with this SystemVerilog code. Here is the code:

module mult ( multiplicand, multiplier, Product, clk, clear, Startm, endm );

input [31:0] multiplicand;
input [31:0] multiplier  ;
input clk;
input clear; 
input Startm;

output logic [63:0] Product;
output logic endm;


enum logic [1:0] { inicio, multiplicar, nao_multiplicar, fim } estados;
logic [1:0] state;

logic [31:0] mplier;
logic [31:0] mplier_aux;
logic [31:0] mcand ;
logic [31:0] mcand_aux;
logic [63:0] Prod  ;
logic [63:0] Prod_aux;
logic [5:0] cont;
logic [5:0] cont_aux;

initial begin
    mplier     = multiplier;
    mplier_aux = multiplier;
    mcand     = multiplicand;
    mcand_aux = multiplicand;
    Prod      = 0;
    Prod_aux  = 0;
    state     = inicio;
    cont      = 0;
    cont_aux  = 0; 
end

always_ff @( posedge clk )
begin
    if( clear ) 
    begin
        state <= inicio;
    end
    else if ( Startm )
    begin
        case( state )
        inicio :
        begin
                    if( mplier[0] == 0 )
                    begin
                        state <= nao_multiplicar;
                    end
                    else if( mplier[0] == 1 )
                    begin
                        state <= multiplicar;
                    end
        end
        multiplicar :
        begin
                    if( cont == 32 )
                        state <= fim;
                    else if( mplier[0] == 0 )
                    begin
                        state <= nao_multiplicar;
                    end
                    else if( mplier[0] == 1 )
                    begin
                        state <= multiplicar;
                    end
        end
        nao_multiplicar:
        begin
                    if( cont == 32 )
                        state <= fim;
                    else if( mplier[0] == 0 )
                    begin
                        state <= nao_multiplicar;
                    end
                    else if( mplier[0] == 1 )
                    begin
                        state <= multiplicar;
                    end
        end
        fim:
        begin
                    state <= inicio;
        end
        endcase
    end
end
    always_comb
    begin
        case(state)
        inicio:
        begin
                    mplier = multiplier;
                    mcand  = multiplicand;
                    Prod   = 0;
                    cont_aux = cont + 1;
                    cont = cont_aux;
        end
        multiplicar:
        begin   
                    mcand_aux  = mcand  << 1;
                    mcand      = mcand_aux  ;
                    mplier_aux = mplier >> 1;
                    mplier     = mplier_aux ;
                    Prod_aux   = Prod + mcand;
                    Prod       = Prod_aux;
                    cont_aux   = cont + 1;
                    cont       = cont_aux;
        end
        nao_multiplicar:
        begin
                    cont_aux = cont + 1;
                    cont     = cont_aux;
        end
        fim:
        begin
                    Product = Prod;
                    endm    = 1;
        end
        endcase
    end     
endmodule

I'm trying write a multiplicator with inputs of 32 bits and a product of 64 bits using the Booth's algorithm. This error occur:

always_comb construct does not infer purely combinational logic

Why does this happens?

4
A minimal example that shows your problem would hlep. - Brian Carlton

4 Answers

6
votes

When describing combinational logic in always blocks, you have to make sure that all your variables are assigned to a value in all paths in your code. Otherwise a latch will be inferred. It's easy to miss something like this in traditional always blocks, so the always_comb block was introduced in SystemVerilog to explicitly check for this.

In your case, you've a few buses which are not assigned values in each branch of the case statement, for example mcand hasn't a value assigned to it in branches nao_multiplicar and fim.

There are 2 solutions. First is to, well, assign to all your variables in all your code branches.

Another solution is to write 'default' values for all of the variables in the always_comb before the case statement. In this way, each variable will always be assigned to a value each time the always_comb block triggers, and there'll be no warnings. YOur case statement then only needs to deal with the variables that need to change:

always_comb
begin
    // Defaults (I think I got them all)
    mplier     = multiplier;
    mcand      = multiplicand;
    Prod_aux   = 0;
    Prod       = 0;
    cont_aux   = 0;
    cont       = 0;
    Product    = 0;
    endm       = 0;

    // Now override the defaults when appropriate
    case(state)
    inicio:
    begin
                mplier = multiplier;
                mcand  = multiplicand;
                Prod   = 0;
                cont_aux = cont + 1;
                cont = cont_aux;
    end
    multiplicar:
    begin   
                mcand_aux  = mcand  << 1;
                mcand      = mcand_aux  ;
                mplier_aux = mplier >> 1;
                mplier     = mplier_aux ;
                Prod_aux   = Prod + mcand;
                Prod       = Prod_aux;
                cont_aux   = cont + 1;
                cont       = cont_aux;
    end
    nao_multiplicar:
    begin
                cont_aux = cont + 1;
                cont     = cont_aux;
    end
    fim:
    begin
                Product = Prod;
                endm    = 1;
    end
    endcase
end     
3
votes

All the compile errors are eliminated when I get rid of the initial block. I'm using simulators from Cadence and Synopsys.

Here is a quote from the IEEE Std, 1800-2009, section 9.2.2.4 "Sequential logic always_ff procedure":

The always_ff procedure imposes the restriction that it contains one and only one event control and no blocking timing controls. Variables on the left-hand side of assignments within an always_ff procedure, including variables from the contents of a called function, shall not be written to by any other process.

There is a similar quote for always_comb.

The documentation is readily available from the IEEE. Your simulator should also have documentation.

The error message you receive from your tool seems not to be very helpful in this case.

1
votes

always_comb will infer combinational logic, however, in your always_comb block you are doing assignments like C code, e.g:

always_comb
begin
  ...
  cont_aux   = cont + 1;
  cont       = cont_aux;
  ...
end

Here you are asking to make a combinational logic with feedback.

If you want to store values in time, you have to put your assignments in an always_ff block, which will infer sequential logic.

always_ff @(posedge clk)
begin
  ...
  cont <= cont + 1;
  ...
end
0
votes

The LRM is the most useful documentation I use for system verilog

http://www.vhdl.org/sv/SystemVerilog_3.1a.pdf