Verilog comparator - verilog

I'm newbie to a verilog.
I did a lot of research, and finally wrote this code, but it seems to not work.
Can anyone fix it for me?
module comparator();
reg[3:0] a, b;
wire[1:0] equal, lower, greater;
if (a<b) begin
equal = 0;
lower = 1;
greater = 0;
end
else if (a==b) begin
equal = 1;
lower = 0;
greater = 0;
end
else begin
equal = 0;
lower = 0;
greater = 1;
end;
initial begin
$monitor($time,
"a=%b, b=%b, greater=%b, equals=%b, lower=%b",
a, b, greater, equal, lower);
a=9; b=10;
#100 $display ("\n", $time, "\n");
end
endmodule

Behavioural procedures must be enclosed within an always block, like this:
Also, your module needs inputs and outputs. A more correct version would be like this:
module comparator (
input wire [3:0] a,
input wire [3:0] b,
output reg equal,
output reg lower,
output reg greater
);
always #* begin
if (a<b) begin
equal = 0;
lower = 1;
greater = 0;
end
else if (a==b) begin
equal = 1;
lower = 0;
greater = 0;
end
else begin
equal = 0;
lower = 0;
greater = 1;
end
end
endmodule
I suggest reading some tutorial about behavioral modelling with Verilog, because you missed a lot of points:
How to correctly define inputs and outputs in a module
What things can be wires and what things should be regs
The use of always #* to model combinational logic
And most important: how to write a test bench. Test benches are written as module with no inputs and outputs) that instantiates your UUT (unit under test), provides inputs, read outputs and check whether they are valid.
module testcomp;
reg [3:0] a, b;
wire eq, lw, gr;
comparator uut (
.a(a),
.b(b),
.equal(eq),
.lower(lw),
.greater(gr)
);
initial begin
a = 0;
repeat (16) begin
b = 0;
repeat (16) begin
#10;
$display ("TESTING %d and %d yields eq=%d lw=%d gr=%d", a, b, eq, lw, gr);
if (a==b && eq!=1'b1 && gr!=1'b0 && lw!=1'b0) begin
$display ("ERROR!");
$finish;
end
if (a>b && eq!=1'b0 && gr!=1'b1 && lw!=1'b0) begin
$display ("ERROR!");
$finish;
end
if (a<b && eq!=1'b1 && gr!=1'b0 && lw!=1'b1) begin
$display ("ERROR!");
$finish;
end
b = b + 1;
end
a = a + 1;
end
$display ("PASSED!");
$finish;
end
endmodule
You can play with this example at EDAPlayGround using this link:
http://www.edaplayground.com/x/CPq

Without always block:
module comparator (
input wire [3:0] a,
input wire [3:0] b,
output reg equal,
output reg lower,
output reg greater
);
assign equal = (a===b);
assign lower = (a<b)?1'b1:1'b0;
assign greater = (a>b)1'b1:1'b0;
end
Be careful, you need to consider 'X' and 'Z', use "===" instead of "=="

Related

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.

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)

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.

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

Verilog code adding two integers generated by a for loop

How about this? I'm looking for an output i+j=1+2, 2+3... 4+5.
module add(i,j,b);
input [31:0] i, j; //32 bit unsigned
output [31:0] y;
task ADD(i, j, y);
begin
for (i= 1; i <= 4; i++)
begin
for(j=2; j <= 5; j++)
assign y = i + j;
end
end
$display("y ", y);
endtask
endmodule
Is this intended for synthesis? If so you should probably avoid using tasks until you have learnt when they can be used. I never use them in synthesisable code.
functions on the other hand are often used for synthesis but can not contain timing information. Ie a function can only represent combinatorial logic, that all happens in an instant.
1) That is not how you use assign. The correct use would be:
wire [9:0] a;
assign a = 10'b0;
//or
//a,b both 10 bits driven from other logic
wire [9:0] sum;
assign sum = a + b;
Note how you assign to a wire, this is combinatorial.
2) Your display is outside of the for loop it will only display once at the end.
I would have done this some thing like:
module add(
input [31:0] a,
input [31:0] b,
output [31:0] sum
);
assign sum = a + b ;
endmodule
module testharness();
reg [31:0] a;
reg [31:0] b;
wire [31:0] sum;
reg clock;
// Make clock toggle every 10ns (20ns clock period)
initial begin
clock = 0;
forever begin
#10ns clock= ~clock;
end
end
//DUT (Device Under Test)
add add_0 (
.a ( a ),
.b ( b ),
.sum ( sum )
);
// Test program
initial begin
a=0;
b=0;
#(posedge clock);
$display( "a (%2d) + b (%2d) = sum (%2d)", a, b, sum );
a=1;
b=2;
#(posedge clock);
$display( "a (%2d) + b (%2d) = sum (%2d)", a, b, sum );
a=3;
b=4;
#(posedge clock);
$display( "a (%2d) + b (%2d) = sum (%2d)", a, b, sum );
$finish;
end
endmodule
Note how we have used time to separate the results, for more complicated designs you may use flip-flops which means you only get a new result per clock. Or per rising and falling edge if using DDR techniques.
You can now try to modify the test program section to stimulate the DUT as per your requirements.

Resources