0
votes

Im trying to practice SystemVerilog and attempting to implement an ALU(Arithmetic Logic Unit) based on this diagram:

enter image description here

I simulating SystemVerilog code on EDA playground online(https://www.edaplayground.com/x/mYi):

ALU:

module alu(
  input  [31:0] a,
  input  [31:0] b,
  input  [2:0] f,
  output [31:0] result,

);

  /*000*/
  if (f[0]==0 && f[1]==0 && f[2]===0)
    begin
    assign result = a & b;
    end
  /*001*/
  else (f[0]==0 && f[1]==0 && f[2]==1)
    begin
    assign result = a | b;
    end
  /*010*/
  else (f[0]==0 && f[1]==1 && f[2]==0)
    begin
    assign result = a + b;
    end
  /*011 not used*/ 
  else (f[0]==0 && f[1]==1 && f[2]==1)
    begin
    assign result = -1;
    end
  /*100*/
  else (f[0]==1 && f[1]==0 && f[2]==0)
    begin
    assign result = a & ~b;
    end 
  /*101*/  
  else (f[0]==1 && f[1]==0 && f[2]==1)  
    begin
    assign result = a | ~b;
    end
  /*110*/
  else (f[0]==1 && f[1]==1 && f[2]==0) 
    begin
    assign result = a - b;
    end
  /*111 slt*/
  else
    begin
    assign result = -1; 
    end

endmodule

Partial Test Bench:

module testharness();
  reg  [31:0] a;
  reg  [31:0] b;
  reg  [2:0] f;
  reg  [31:0] result;


//DUT (Device Under Test)
alu alu_0 (
  .a   (a),
  .b   (b),
  .f    (f),
  .result (result)
);

// Test program
initial begin
     /*000*/
  f[0]=0; 
  f[1]=1;
  f[2]=0;
  /*0+0*/
  a[0]=0;
  b[0]=0;

  $display( "a (%d) + b (%d) = %d%d%d%d", a[0], b[0], result[0], result[1]);
   /*000*/
  f[0]=0;
  f[1]=1;
  f[2]=0;
  /*0+1*/
  a[0]=0;
  b[0]=1;

 $display( "a (%d) + b (%d) = %d%d", a[0], b[0], result[0], result[1]);

     /*000*/
  f[0]=0;
  f[1]=1;
  f[2]=0;
  /*1+1*/
  a[0]=1; 
  b[0]=1; 

  $display( "a (%d) + b (%d) = %d%d", a[0], b[0], result[0], result[1]);

  $finish;
end

endmodule

I keep getting this error:

ERROR VCP2000 "Syntax error. Unexpected token: (. Expected tokens: '???' , ';' , 'always' , 'and' , 'assign' ... ." "design.sv" 15 9

This is line:

else (f[0]==0 && f[1]==0 && f[2]==1)
    begin
    assign result = a | b;
    end

I dont see anything obvious.

Thanks

1
please start with reading a verilog tutorial. You either misused generate 'if` statements, or continuous assignments, or both. - Serge
You are missing the if keyword. Also instead of a long string of if..else if..else I would use 'case'. - Oldfart

1 Answers

0
votes

I think you are mixing up combinational logic using the alwaysstatement and continuous assignments. As mentioned earlier by other users, I also think it would be good if you would take a look at some basic Verilog tutorials. Asic-world.com has some great tutorials to get started with, for example, Verilog in One Day by Deepak Kumar Tala.

However, let me try to explain this to you. What you are using in your example is the continuous assignment statement. You can find more about this in section 10.3.2 in the IEEE Std 1800-2012. The manual says:

Assignments on nets or variables shall be continuous and automatic. In other words, whenever an operand in the right-hand expression changes value, the whole right-hand side shall be evaluated.

This is not the case here since the right-hand side operands of all your assignment statements are the same. It is not automatic, because it depends on your if statements. Take a look at this really simple example below. If you always want result to be a & b, you can use the code below. However, as you can imagine, for more complex logic this becomes rather lengthy.

module alu(
  input  [31:0] a,
  input  [31:0] b,
  output [31:0] result,

);

    assign result = (a & b);

endmodule

That's why SystemVerilog offers procedural blocks like always, always_comb, always_latch, and always_ff (section 9 in the IEEE Std 1800-2012). For your example, you should use always_comb. To quote section 9.2.2.2 of the manual:

SystemVerilog provides a special always_comb procedure for modeling combinational logic behavior.

With this, we could rewrite your code to

module alu(
  input  [31:0] a,
  input  [31:0] b,
  input  [2:0] f,
  output [31:0] result,

);

  reg [31:0] result_;   

  always_comb 
  begin
    /*000*/
    if (f[0]==0 && f[1]==0 && f[2]===0)
    begin
      result_ = a & b;
    end
    /*001*/
    else if (f[0]==0 && f[1]==0 && f[2]==1)
    begin
      result_ = a | b;
    end
    /*010*/
    else if (f[0]==0 && f[1]==1 && f[2]==0)
    begin
      result_ = a + b;
    end
    /*011 not used*/ 
    else if(f[0]==0 && f[1]==1 && f[2]==1)
    begin
      result_ = -1;
    end
    /*100*/
    else if (f[0]==1 && f[1]==0 && f[2]==0)
    begin
      assign result = a & ~b;
    end 
    /*101*/  
    else if (f[0]==1 && f[1]==0 && f[2]==1)  
    begin
      result_ = a | ~b;
    end
    /*110*/
    else if (f[0]==1 && f[1]==1 && f[2]==0) 
    begin
      result_ = a - b;
    end
    /*111 slt*/
    else
    begin
      result_ = -1; 
    end
  end // End of always_comb

  assign result = result_;

endmodule

Please mind that you can continously assign a wire, but you need to declare a variable as a reg to use it in an always block. That's the reason I am using result_, instead of directly assigning result. At the end of the code block, I continuously assign result_ to result. Asic-world.com also has a tutorial on the difference between regs and wires.

If you don't want to think about whether to use reg or wire, you could also use th new keyword logic.

Edit: As Oldfart pointed out, I orgininally forgot to fix your if...else statements. In your code, you always use else instead of else if. This is probably also the direct cause of the error the compiler is throwing at you.