Net 'VectorY[0]', or a directly connected net, is driven by more than one source, and at least one source is a constant net. (ELAB-368) - verilog

I am getting this error in VCS synthesizer. I have tried everything but it doesn't make sense to me.
it says VectorY[0], VectorY[1], VectorY[2], VectorY[3], or a directly connected net, is driven by more than one source, and at least one source is a constant net. (ELAB-368)
module control (clk, start, S1S2mux, newDist, CompStart, PEready, VectorX, VectorY, addressR, addressS1, addressS2,completed);
input clk;
input start;
output reg [15:0] S1S2mux;
output reg [15:0] newDist;
output CompStart;
output reg [15:0] PEready;
output reg [3:0] VectorX,VectorY;
output reg [7:0] AddressR;
output reg [9:0] AddressS1,AddressS2;
reg [12:0] count;
output reg completed;
integer i;
assign CompStart = start;
always #(posedge clk) begin
if(start==0) begin
count<= 12'b0;
completed<=0;
newDist<=0;
PEready<=0;
VectorX<=0;
VectorY<=0;
end
else if (completed==0)
count <= count+1'b1;
end
always #(count) begin
for (i = 0; i < 15; i = i+1)
begin
newDist [i] = (count [7:0] == i);
PEready [i] = (newDist [i] && !(count < 8'd256));
S1S2mux [i] = (count [3:0] > i);
end
addressR = count [7:0];
addressS1 = (count[11:8] + count[7:4] >> 4)*5'd32 + count [3:0];
addressS2 = (count[11:8] + count[7:4] >> 4)*4'd16 + count [3:0];
VectorX = count[3:0] - 4'd7;
VectorY = count[11:8] >> 4 - 4'd7;
completed = (count == 4'd16 * (8'd256 + 1));
end
endmodule

You can probably do like this...in systemverilog
create another logic variable
logic [3:0] VectorY_next;
and then in the sequential block, do ..
always_ff begin
if(start==0) begin
count<= 12'b0;
completed<=0;
newDist<=0;
PEready<=0;
VectorX<=0;
VectorY<=0;
end
else if (completed==0) begin
count <= count+1'b1;
VectorY <= VectorY_next;
end
end
And in the combinational block, you can write ...
always_comb begin
VectorY_next = VectorY;
for (i = 0; i < 15; i = i+1)
begin
.....
VectorY_next = count[11:8] >> 4 - 4'd7;
completed = (count == 4'd16 * (8'd256 + 1));
end
endmodule
And probably do the same for other ports too.To run using systemverilog, just use -sv option in the command line.

Related

Why is my register not updating in the testbench?

I have a register that I increment by a different value base on the different inputs, When I run a test bench to check it, the value does not increment. Not sure why. Attached is my code and the TB, as well as a screen shot of the simulation:
`timescale 1ns / 1ps
module TEMP_P1(
input clk,
input reset,
input inquarter,
input indime,
input innickle,
input inbev1,
input inbev2,
input inbev3,
output reg [3:0] outquarter,
output reg [3:0] outdime,
output reg [3:0] outnickle,
output reg [1:0] outbev1,
output reg [1:0] outbev2,
output reg [1:0] outbev3
);
reg [31:0] total;
reg [3:0] quarter_count;
reg [3:0] dime_count;
reg [3:0] nickle_count;
always#(clk)begin
if(reset)begin
total = 0;
quarter_count = 0;
dime_count = 0;
nickle_count = 0;
end else begin
if (inquarter) begin
quarter_count = quarter_count + 1;
total = total + 25;
end
if (indime) begin
dime_count = dime_count + 1;
total = total + 10;
end
if (innickle) begin
nickle_count = nickle_count + 1;
total = total + 5;
end
if ((inbev1 === 1) && ( total >= 100)) begin
outbev1 = 1;
total = total - 100;
end
if ((inbev2 == 1) && ( total >= 120)) begin
outbev2 = 1;
total = total - 120;
end
if ((inbev3 == 1) && ( total >= 115)) begin
outbev3 = 1;
total = total - 115;
end
if (total >= 25) begin
outquarter = 1;
outdime = 0;
outnickle = 0;
total = total - 25;
end
if ((total >= 10) && (total < 25)) begin
outquarter = 0;
outdime = 1;
outnickle = 0;
total = total - 10;
end
if ((total >= 5) && (total < 10)) begin
outquarter = 0;
outdime = 0;
outnickle = 1;
total = total - 5;
end
end
end
endmodule
`timescale 1ns / 1ps
module TEMP_P1_TB(
);
reg clk;
reg reset;
reg inquarter;
reg indime;
reg innickle;
reg inbev1;
reg inbev2;
reg inbev3;
wire [3:0] outquarter;
wire [3:0] outdime;
wire [3:0] outnickle;
wire [1:0] outbev1;
wire [1:0] outbev2;
wire [1:0] outbev3;
TEMP_P1 UUT(.clk(clk), .reset(reset), .inquarter(inquarter), .indime(indime), .innickle(innickle), .inbev1(inbev1), .inbev2(inbev2), .inbev3(inbev3),
.outquarter(outquarter), .outdime(outdime), .outnickle(outnickle), .outbev1(outbev1), .outbev2(outbev2), .outbev3(outbev3));
initial begin
clk = 0;
reset = 0;
inquarter = 0;
indime = 0;
innickle = 0;
inbev1 = 0;
inbev2 = 0;
inbev3 = 0;
#10;
reset = 1;
#1
reset = 0;
#1
inquarter = 1;
#1;
inquarter = 0;
#1;
inquarter = 1;
#1;
inquarter = 0;
#1;
inquarter = 1;
#1;
inquarter = 0;
#1;
inquarter = 1;
#1;
inquarter = 0;
#1;
inquarter = 1;
#1;
inquarter = 0;
#1;
inbev1 = 1;
#1;
inbev1 = 0;
#1;
end
always begin
#1 clk = ~clk;
end
endmodule
I have tried changing blocking v. nonblocking assignments.
One major problem with your code is that you have Verilog simulation race conditions.
To model registers, you need to use these coding styles:
Signal changes triggered off only one edge of the clock (positive, for example):
#(posedge clk)
Nonblocking assignments: <=
This style must be used in both the design and testbench.
For the design, refer to these simple code examples.
In the testbench, you should replace all of the # delays, except for the clk signal, with #(posedge clk). This assures that the inputs will be synchronous to the clock. clk should use a blocking assignment; so there is no need to change your code there.
Also, the testbench code can be easier to understand if you use loops. I use repeat loops. Here are all the changes to both the design and testbench:
`timescale 1ns / 1ps
module TEMP_P1(
input clk,
input reset,
input inquarter,
input indime,
input innickle,
input inbev1,
input inbev2,
input inbev3,
output reg [3:0] outquarter,
output reg [3:0] outdime,
output reg [3:0] outnickle,
output reg [1:0] outbev1,
output reg [1:0] outbev2,
output reg [1:0] outbev3
);
reg [31:0] total;
reg [3:0] quarter_count;
reg [3:0] dime_count;
reg [3:0] nickle_count;
always #(posedge clk) begin
if (reset) begin
total <= 0;
quarter_count <= 0;
dime_count <= 0;
nickle_count <= 0;
end else begin
if (inquarter) begin
quarter_count <= quarter_count + 1;
total <= total + 25;
end
if (indime) begin
dime_count <= dime_count + 1;
total <= total + 10;
end
if (innickle) begin
nickle_count <= nickle_count + 1;
total <= total + 5;
end
if ((inbev1 === 1) && ( total >= 100)) begin
outbev1 <= 1;
total <= total - 100;
end
if ((inbev2 == 1) && ( total >= 120)) begin
outbev2 <= 1;
total <= total - 120;
end
if ((inbev3 == 1) && ( total >= 115)) begin
outbev3 <= 1;
total <= total - 115;
end
if (total >= 25) begin
outquarter <= 1;
outdime <= 0;
outnickle <= 0;
total <= total - 25;
end
if ((total >= 10) && (total < 25)) begin
outquarter <= 0;
outdime <= 1;
outnickle <= 0;
total <= total - 10;
end
if ((total >= 5) && (total < 10)) begin
outquarter <= 0;
outdime <= 0;
outnickle <= 1;
total <= total - 5;
end
end
end
endmodule
`timescale 1ns / 1ps
module TEMP_P1_TB;
reg clk;
reg reset;
reg inquarter;
reg indime;
reg innickle;
reg inbev1;
reg inbev2;
reg inbev3;
wire [3:0] outquarter;
wire [3:0] outdime;
wire [3:0] outnickle;
wire [1:0] outbev1;
wire [1:0] outbev2;
wire [1:0] outbev3;
TEMP_P1 UUT(.clk(clk), .reset(reset), .inquarter(inquarter), .indime(indime), .innickle(innickle), .inbev1(inbev1), .inbev2(inbev2), .inbev3(inbev3),
.outquarter(outquarter), .outdime(outdime), .outnickle(outnickle), .outbev1(outbev1), .outbev2(outbev2), .outbev3(outbev3));
initial begin
clk <= 0;
reset <= 0;
inquarter <= 0;
indime <= 0;
innickle <= 0;
inbev1 <= 0;
inbev2 <= 0;
inbev3 <= 0;
repeat (5) #(posedge clk);
reset <= 1;
repeat (1) #(posedge clk);
reset <= 0;
repeat (5) begin
repeat (1) #(posedge clk);
inquarter <= 1;
repeat (1) #(posedge clk);
inquarter <= 0;
end
repeat (1) #(posedge clk);
inbev1 <= 1;
repeat (1) #(posedge clk);
inbev1 <= 0;
repeat (10) #(posedge clk);
$finish;
end
always begin
#1 clk = ~clk;
end
endmodule
The above code fixes the timing problems (race conditions).
However, you also have problems with your logic since the total gets cleared after each quarter input, as you can see in the waves below:
If that is not your intended behavior, I recommend you spend more time looking at your internal waveforms. If you still have problems, you can ask a new question.
In the UUT, add the keyword posedge to # statement, like this:
always#(posedge clk)begin
In the testbench, assert reset at the beginning, release it a couple of clocks later, don't assert it again. It was asserted for 1/2 of a clock some time after the test was started. Best practice is to assert it at the unless there is a good reason not to do so.
initial begin
reset = 1;
#5 reset = 0;
Use non-blocking assignments everywhere in the UUT # statement for the clocked process like this (I did not fix them all, you should). Non-blocking assignments in a synchronous process is the correct way model registers:
always#(posedge clk)begin
if(reset)begin
total <= 0;
quarter_count <= 0;
dime_count <= 0;
nickle_count <= 0;
end else begin
if (inquarter) begin
quarter_count <= quarter_count + 1;
total <= total + 25;
In the testbench, hold the inputs (example inquarter) for at least 1 clock cycle so that they are able to be sampled at a logic 1, at the clock edge. inquarter is 1/2 a clock cycle wide. The clk period is #2, so if you change an input every #1, that is making a skinny pulse that would be easy for the DUT to miss. I did not fix these in the testbench you should. Register quarter_count is catching the input at 1 almost by accident in my simulation.
Make these changes and the registers start behaving as registers.
The waves looks like this for me on edaplayground:
Another issue is that you have an always block in the testbench
always begin
#1 clk = ~clk;
however there is no $finish or $stop anywhere in your code. The simulation will run forever until you click some sort of kill/stop in the simulation GUI, or kill the process from the command line. The solution to this is to add a
$finish;
at the end of the testbench main initial block. Now the simulation will compile, elaborate, run, and stop relatively quickly. My eda playground simulation run of your post takes about 15 seconds total.

8 bit sequential multiplier using add and shift

I'm designing an 8-bit signed sequential multiplier using Verilog. The inputs are clk (clock), rst (reset), a (8 bit multiplier), b (8 bit multiplicand), and the outputs are p (product) and rdy (ready signal, indicating multiplication is over). For negative inputs, I do a sign extension and save it in the 15 bit register variables multiplier and multiplicand. Here's my code:
module seq_mult (p, rdy, clk, reset, a, b);
input clk, reset;
input [7:0] a, b;
output [15:0] p;
output rdy;
reg [15:0] p;
reg [15:0] multiplier;
reg [15:0] multiplicand;
reg rdy;
reg [4:0] ctr;
always #(posedge clk or posedge reset) begin
if (reset)
begin
rdy <= 0;
p <= 0;
ctr <= 0;
multiplier <= {{8{a[7]}}, a};
multiplicand <= {{8{b[7]}}, b};
end
else
begin
if(ctr < 16)
begin
if(multiplier[ctr]==1)
begin
multiplicand = multiplicand<<ctr;
p <= p + multiplicand;
end
ctr <= ctr+1;
end
else
begin
rdy <= 1;
end
end
end //End of always block
endmodule
And here's my testbench:
`timescale 1ns/1ns
`define width 8
`define TESTFILE "test_in.dat"
module seq_mult_tb () ;
reg signed [`width-1:0] a, b;
reg clk, reset;
wire signed [2*`width-1:0] p;
wire rdy;
integer total, err;
integer i, s, fp, numtests;
// Golden reference - can be automatically generated in this case
// otherwise store and read from a file
wire signed [2*`width-1:0] ans = a*b;
// Device under test - always use named mapping of signals to ports
seq_mult dut( .clk(clk),
.reset(reset),
.a(a),
.b(b),
.p(p),
.rdy(rdy));
// Set up 10ns clock
always #5 clk = !clk;
// A task to automatically run till the rdy signal comes back from DUT
task apply_and_check;
input [`width-1:0] ain;
input [`width-1:0] bin;
begin
// Set the inputs
a = ain;
b = bin;
// Reset the DUT for one clock cycle
reset = 1;
#(posedge clk);
// Remove reset
#1 reset = 0;
// Loop until the DUT indicates 'rdy'
while (rdy == 0) begin
#(posedge clk); // Wait for one clock cycle
end
if (p == ans) begin
$display($time, " Passed %d * %d = %d", a, b, p);
end else begin
$display($time, " Fail %d * %d: %d instead of %d", a, b, p, ans);
err = err + 1;
end
total = total + 1;
end
endtask // apply_and_check
initial begin
// Initialize the clock
clk = 1;
// Counters to track progress
total = 0;
err = 0;
// Get all inputs from file: 1st line has number of inputs
fp = $fopen(`TESTFILE, "r");
s = $fscanf(fp, "%d\n", numtests);
// Sequences of values pumped through DUT
for (i=0; i<numtests; i=i+1) begin
s = $fscanf(fp, "%d %d\n", a, b);
apply_and_check(a, b);
end
if (err > 0) begin
$display("FAIL %d out of %d", err, total);
end else begin
$display("PASS %d tests", total);
end
$finish;
end
endmodule // seq_mult_tb
I also created a file called test_in.dat in which the test cases are stored (first line indicates number of test cases):
10
5 5
2 3
10 1
10 2
20 20
-128 2
10 -128
-1 -1
10 0
0 2
Now the problem is: the code works for only the first two inputs and for the last two inputs. For the remaining inputs, I get a different number than is expected. Can someone point out any logical error in my code that is causing this? Or if there's a much simpler strategy for doing the same, please let me know of that as well.
multiplicand is shifted to the left by ctr in each iteration if multiplier[ctr] is 1.
But ctr already includes the previous shift amounts, so you are shifting too far.
You should just shift multiplicand by 1 in every iteration unconditionally:
multiplicand <= multiplicand << 1;
if (multiplier[ctr] == 1)
begin
p <= p + multiplicand;
end
ctr <= ctr + 1;
You should also use nonblocking assignment for multiplicand. You might need to move the shifting to after adding it to p.

Error count for two different patterns in verilog

I have made 2 forms of data patterns and wants to compare them in the form of error count.....when the 2 patterns are not equal, the error count should be high....i made the code including test bench, but when i ran behavioral sumilation, the error count is only high at value 0 and not at value 1.....I expect it to be high at both 0 and 1....please help me out in this, since I am new with verilog
here is the code
`timescale 1ns / 1ps
module pattern(
clk,
start,
rst,enter code here
clear,
data_in1,
data_in2,
error
);
input [1:0] data_in1;
input [1:0] data_in2;
input clk;
input start;
input rst;
input clear;
output [1:0] error;
reg [1:0] comp_out;
reg [1:0] i = 0;
assign error = comp_out;
always#(posedge clk)
begin
comp_out = 0;
if(rst)
comp_out = 0;
else
begin
for(i = 0; i < 2; i = i + 1)
begin
if(data_in1[i] != data_in2[i])
comp_out <= comp_out + 1;
end
end
end
endmodule
here is the test bench for the above code
`timescale 1ns / 1ps
module tb_pattern();
// inputs
reg clk;
reg rst;
reg [1:0] data_in1;
reg [1:0] data_in2;
wire [1:0] error;
//outputs
//wire [15:0] count;
//instantiate the unit under test (UUT)
pattern uut (
// .count(count),
.clk(clk),
.start(start),
.rst(rst),
.clear(clear),
.data_in1(data_in1),
.data_in2(data_in2),
.error(error)
);
initial begin
clk = 1'b0;
rst = 1'b1;
repeat(4) #10 clk = ~clk;
rst = 1'b0;
forever #10 clk = ~clk; // generate a clock
end
initial begin
//initialize inputs
clk = 0;
//rst = 1;
data_in1 = 2'b00;
data_in2 = 2'b01;
#100
data_in1 = 2'b11;
data_in2 = 2'b00;
#100
$finish;
end
//force rest after delay
//#20 rst = 0;
//#25 rst = 1;
endmodule
When incrementing in a for loop you need to use blocking assignment (=), however when assigning flops you should use non-blocking assignment (<=). When you need to use a for loop to assign a flop, it is best to split the combinational and synchronous functionality into separate always blocks.
...
reg [1:0] comp_out, next_comb_out;
always #* begin : comb
next_comp_out = 0;
for (i = 0; i < 2; i = i + 1) begin
if (data_in1[i] != data_in2[i]) begin
next_comp_out = next_comp_out + 1;
end
end
end
always #(posedge clk) begin : dff
if (rst) begin
comb_out <= 1'b0;
end
else begin
comb_out <= next_comp_out;
end
end
...
begin
for(i = 0; i < 2; i = i + 1)
begin
if(data_in1[i] != data_in2[i])
comp_out <= comp_out + 1;
end
end
This for loop doesn't work the way you think it does. Because this is a non-blocking assignment, only the last iteration of the loop actually applies. So only the last bit is actually being compared here.
If both bits of your data mismatch, then the loop unrolls to something which looks like this:
comp_out <= comp_out + 1;
comp_out <= comp_out + 1;
Because this is non-blocking, the RHS of the equation are both evaluated at the same time, leaving you with:
comp_out <= 0 + 1;
comp_out <= 0 + 1;
So even though you tried to use this as a counter, only the last line takes effect, and you get a mismatch count of '1', no matter how many bits mismatch.
Try using a blocking statement (=) for comp_out assignment instead.

Reduce array to sum of elements

I am trying to reduce a vector to a sum of all it elements. Is there an easy way to do this in verilog?
Similar to the systemverilog .sum method.
Thanks
My combinational solution for this problem:
//example array
parameter cells = 8;
reg [7:0]array[cells-1:0] = {1,2,3,4,5,1,1,1};
//###############################################
genvar i;
wire [7:0] summation_steps [cells-2 : 0];//container for all sumation steps
generate
assign summation_steps[0] = array[0] + array[1];//for less cost starts witch first sum (not array[0])
for(i=0; i<cells-2; i=i+1) begin
assign summation_steps[i+1] = summation_steps[i] + array[i+2];
end
endgenerate
wire [7:0] result;
assign result = summation_steps[cells-2];
Verilog doesn't have any built-in array methods like SV. Therefore, a for-loop can be used to perform the desired functionality. Example:
parameter N = 64;
integer i;
reg [7:0] array [0:N-1]
reg [N+6:0] sum; // enough bits to handle overflow
always #*
begin
sum = {(N+7){1'b0}}; // all zero
for(i = 0; i < N; i=i+1)
sum = sum + array[i];
end
In critiquing the other answers delivered here, there are some comments to make.
The first important thing is to provide space for the sum to be accumulated. statements such as the following, in RTL, won't do that:
sum = sum + array[i]
because each of the unique nets created on the Right Hand Side (RHS) of the expression are all being assigned back to the same signal called "sum", leading to ambiguity in which of the unique nets is actually the driver (called a multiple driver hazard). To compound the problem, this statement also creates a combinational loop issue because sum is used combinationally to drive itself - not good. What would be good would be if something different could be used as the load and as the driver on each successive iteration of the loop....
Back to the argument though, in the above situation, the signal will be driven to an unknown value by most simulator tools (because: which driver should it pick? so assume none of them are right, or all of them are right - unknown!!). That is if it manages to get through the compiler at all (which is unlikely, and it doesn't at least in Cadence IEV).
The right way to do it would be to set up the following. Say you were summing bytes:
parameter NUM_BYTES = 4;
reg [7:0] array_of_bytes [NUM_BYTES-1:0];
reg [8+$clog2(NUM_BYTES):0] sum [NUM_BYTES-1:1];
always #* begin
for (int i=1; i<NUM_BYTES; i+=1) begin
if (i == 1) begin
sum[i] = array_of_bytes[i] + array_of_bytes[i-1];
end
else begin
sum[i] = sum[i-1] + array_of_bytes[i];
end
end
end
// The accumulated value is indexed at sum[NUM_BYTES-1]
Here is a module that works for arbitrarily sized arrays and does not require extra storage:
module arrsum(input clk,
input rst,
input go,
output reg [7:0] cnt,
input wire [7:0] buf_,
input wire [7:0] n,
output reg [7:0] sum);
always #(posedge clk, posedge rst) begin
if (rst) begin
cnt <= 0;
sum <= 0;
end else begin
if (cnt == 0) begin
if (go == 1) begin
cnt <= n;
sum <= 0;
end
end else begin
cnt <= cnt - 1;
sum <= sum + buf_;
end
end
end
endmodule
module arrsum_tb();
localparam N = 6;
reg clk = 0, rst = 0, go = 0;
wire [7:0] cnt;
reg [7:0] buf_, n;
wire [7:0] sum;
reg [7:0] arr[9:0];
integer i;
arrsum dut(clk, rst, go, cnt, buf_, n, sum);
initial begin
$display("time clk rst sum cnt");
$monitor("%4g %b %b %d %d",
$time, clk, rst, sum, cnt);
arr[0] = 5;
arr[1] = 6;
arr[2] = 7;
arr[3] = 10;
arr[4] = 2;
arr[5] = 2;
#5 clk = !clk;
#5 rst = 1;
#5 rst = 0;
#5 clk = !clk;
go = 1;
n = N;
#5 clk = !clk;
#5 clk = !clk;
for (i = 0; i < N; i++) begin
buf_ = arr[i];
#5 clk = !clk;
#5 clk = !clk;
go = 0;
end
#5 clk = !clk;
$finish;
end
endmodule
I designed it for 8-bit numbers but it can easily be adapted for other kinds of numbers too.

Instantiating a value in or out of an always block

I have written a piece of code that will return a quotient and a reminder, based on numbers that i provide and some other data that i used to shift the numbers in place.
The problem I have now is that i cannot keep a good track of my quotient if I test more values one after another.
I need a way to initialize my cat register, so that I no longer get residual values from previous computations.
Here is the code I was talking about:
module divide(
input [7:0] a, b,
input [3:0] counter, msb,
output reg [7:0] q,
output reg [7:0] r
);
always #(*) begin
for(i = 0; i < counter + 1 ; i = i+1) begin
sum = s_a + s_b; //previously calculated values
if(sum[8-msb] == 1) begin
assign s_a = s_a;
assign s_b = s_b >>> 1;
cat[counter - i] = 1'b0;
end
else begin
assign s_a = sum;
assign s_b = s_b >>> 1;
cat[counter - i] = 1'b1;
end
assign r = s_a;
assign q = cat;
end
end
endmodule
Note: I have declared all the registers that are in this code, but for some purpose I cannot declare them here.
You do not use assign inside always or initial blocks.
The assignments to cat are combinatorial therefore it is not a flip-flop, ie has no reset. The fact that it is a reg type has nothing to do with the hardware but a simulator optimisation.
I would have written it as (no functional alterations made):
module divide#(
parameter DATA_W = 8
)(
input [7:0] a, b,
input [3:0] counter, msb,
output reg [7:0] q,
output reg [7:0] r
);
//Definitions
reg [DATA_W-1:0] sum;
reg [DATA_W-1:0] s_a;
reg [DATA_W-1:0] s_b;
integer i;
always #* begin
for(i = 0; i < (counter + 1); i = i+1) begin
sum = s_a + s_b; //previously calculated values
if(sum[8-msb] == 1'b1) begin
s_a = s_a;
s_b = s_b >>> 1;
cat[counter - i] = 1'b0;
end
else begin
s_a = sum;
s_b = s_b >>> 1;
cat[counter - i] = 1'b1;
end
r = s_a;
q = cat;
end
end
endmodule
You have the following line:
sum = s_a + s_b; //previously calculated values
You have not included any flip-flops here, unless you have implied latches which are really to be avoided, there is no memory or state involved. i.e. there are no previously calculated values.
Instead of a combinatorial block you likely want to add a flip-flop and take multiple clock cycles to calculate the result.
instead of an always #* try:
always #(posedge clk or negedge rst_n) begin
if (~rst_n) begin
s_a <= 'b0; //Reset Value
end
else begin
s_a <= next value; //Normal logic
end
end

Resources