Problem with VCS simulation for MAC operation - verilog

I intended to write and simulate a module performing MAC operation. My code is shown below
module PE # (
parameter DW = 8
)
(
input clk,
input rst_n,
input [DW-1 : 0] cin,
input [DW-1 : 0] w,
output [DW-1 : 0] cin_out,
output [DW-1 : 0] w_out,
output [2*DW : 0] pe_out
);
reg [DW-1 : 0] cin_reg;
reg [DW-1 : 0] w_reg;
reg [2*DW : 0] m_reg;
reg [2*DW : 0] pe_reg;
always #(posedge clk) begin
if(rst_n==1'b0) begin
pe_reg <= 0;
cin_reg <= 0;
w_reg <= 0;
end
else begin
cin_reg <= cin;
w_reg <= w;
m_reg <= cin_reg * w_reg;
pe_reg <= pe_reg + m_reg;
end
end
assign cin_out = cin_reg;
assign w_out = w_reg;
assign pe_out = pe_reg;
endmodule
I used VCS to simulate, however, pe_out kept xxxxxxxx as shown in fig below.
false wave
I have asked my friend to use verilator to simulate, it can work as expected. And if I delete pe_reg <= pe_reg + m_reg, it still works. Therefore, the issue is likely to be caused by the add operation? But I haven't solved it yet.
I'll be appreciate if anyone can give me some instructions. It have confused me for hours.
My tb is written as below.
module tb_PE;
reg clk;
reg rst_n;
reg [7:0] cin;
reg [7:0] w;
wire [7:0] cin_out;
wire [7:0] w_out;
wire [16:0] pe_out;
wire [16:0] pe_out_tmp;
initial begin
clk = 0;
forever begin
#10;
clk = ~clk;
end
end
initial begin
rst_n = 1'b1;
#5;
rst_n = 1'b0;
#10;
rst_n = 1'b1;
#5;
cin = 8'h01;
w = 8'h02;
#15;
cin = 8'h03;
w = 8'h04;
#20;
cin = 8'h05;
w = 8'h03;
#20;
cin = 8'h90;
w = 8'h88;
#20;
cin = 8'h65;
w = 8'h20;
#100;
$finish;
PE PE_U (
.clk(clk),
.rst_n(rst_n),
.cin(cin),
.w(w),
.cin_out(cin_out),
.w_out(w_out),
.pe_out(pe_out)
);
end

As #mkrieger1 mentioned, you have not initialized m_reg. So, the following is happening:
at the first posedge you initialized some of the variables, including pe_reg, while m_reg is still x.
at the second posedge m_reg is still x. Using nonblocking assignment you schedule it to change later, but in this expression pe_reg <= pe_reg + m_reg; it is still x.
as a result, pe_reg becomes x again because m_reg is still x and it will stays same because it is used recursively in the expression.
So, the easiest way to handle it is to initialize m_reg in the same bucket as pe_reg. If for some reason it is not acceptable, you need to delay evaluation of pe_reg for another cycle.

Related

Verilog Adder/Subtractor [duplicate]

This question already has answers here:
How do I use flip flop output as input for reset signal
(1 answer)
Why is my counter out value producing StX?
(2 answers)
Closed 2 months ago.
Trying to make a Binary adder and Subtractor in Verilog Output keeps coming out as X I don't think it is the testbench I believe is something wrong with the wires for the output F. The Flip Flops and the Multiplexer should be correct but I have no way of knowing for sure I do not get any error messages when I run this
module Subtractor(A, B, Bin, Bout , Sub); //Variables for subtractor
// 1-bit full binary subtractor.
input A;//Input variable
input B;//Input variable
input Bin;//Input variable
output Bout;
output Sub;
assign Bout=((~A)&(B))|((~A)&(Bin))|((B)&(Bin));
assign Sub=(A^B^Bin);
endmodule
module Adder(A, B, Cin, Cout, Sum);
// 1- bit full binary adder
input A, B, Cin;
output Cout, Sum;
assign Cout = ((A)&(Cin))|((B)&(Cin))|((A)&(B));
assign Sum = (A^B^Cin);
endmodule
module CarryFLIPFLOP(CLK,RESET,D,Q);
//Flip flop for carry value
input CLK,RESET,D;
output reg Q;
always #(posedge CLK)
begin
if(RESET)
Q<=0;
else
Q<=D;
end
endmodule
module BorrowFLIPFLOP(CLK,RESET,D,Q);
// 1- bit full binary adder
input CLK,RESET,D;
output reg Q;
//reg Q;
always #(posedge CLK)
begin
if(RESET)
Q<=0;
else
Q<=D;
end
endmodule
module Fplexer(Sum, Sub, S, F, clk);
input Sum, Sub, S, clk;
output reg F;
always#(posedge clk) begin
if(S==1) begin
F <= Sum;
end else begin
F <= Sub;
end
end
endmodule
module z_flag(clk,F,R,Z);
input clk,F,R;
output reg Z=1;
always#(posedge clk)begin
Z=R|(Z&~F);
end
endmodule
module top(A,B,S,R,clk,F,Z,N,V);
input A, B, S, R, clk;
output F, Z, N, V;
wire w0,w1,w2,w3,w4,w5,w6,w7,w8;
assign w7 = A;
assign w8 = B;
Subtractor S0(.A(w7), .B(w8), .Bin(w3), .Bout(w4), .Sub(w5));
BorrowFLIPFLOP Borrow(.CLK(clk), .RESET(R), .D(w2), .Q(w3));
Adder A0(.A(w7), .B(w8), .Cin(w0), .Cout(w1), .Sum(w2));
CarryFLIPFLOP Carry(.CLK(clk), .RESET(R), .D(w2), .Q(w0));
Fplexer multi(.Sum(w2), .Sub(w5), .S(S), .F(w6), .clk(clk));
assign V=(w0 & w1);
assign F = w6;
assign N = w6;
z_flag Zflag(.clk(clk), .F(w6), .R(R), .Z(Z));
endmodule
module testbench;
reg clk;
reg R;
reg A;
reg B;
reg S = 0;
wire F;
//intitialize clock/top
top UUT(A,B,S,R,clk,F,Z,N,V);
always
#5 clk = ~clk;
initial begin
$display("Testing +- Machine");
$monitor("%d - %d Is %d",A, B, F);
A = 0; B = 1; S = 0; R=0; #10;
clk = 1; #1;
clk = 0; #1;
clk = 1; #1;
A = 1; B = 1; #10;
clk = 1; #1;
clk = 0; #1;
clk = 1; #1;
A = 1; B = 0; #10;
clk = 1; #1;
clk = 0; #1;
clk = 1; #1;
end
endmodule
Your design has a reset signal and you never used it.
Your FLIPFLOP code does not have RESET in the sensitivity list.
You are making assignments to clk in an always block and in the initial block. Pick one place.
Learn how to save waveforms to see internal signals, not just the top level output.

I am building an ALU in Verilog and my self-checking testbench keeps receiving this continuous blue error?

I am tasked with building an ALU. However, I must not understand how the self-checking testbench with file.tv should run. I have run other simple testbenches just fine. I am sure there is a problem in the way that my testbench module is written,
code compiles (using quartus)
made a text file with binary and turned it into a "test.tv" file
opened modelsim and added file
when I run it, is has an issue where it just keeps running blue errors..
Here is my code:
module ALU(input [31:0] a,b,
input [2:0] f,
output reg [31:0] y ,
output reg zero);
always #(*) begin
case(f)
3'b000: y = a & b;
3'b001: y = a | b;
3'b010: y = a + b;
3'b011: y = 32'b0;
3'b100: y = a & ~b;
3'b101: y = a | ~b;
3'b110: y = a - b;
3'b111: y = a < b;
default: y = 32'b0;
endcase
if(y==0)
zero=1'b1;
else
zero=1'b0;
end
endmodule
//**********************
module ALUtest();
reg clk;
reg [31:0] a, b, yexpected;
wire [31:0] y;
reg [2:0] f;
reg zeroexpected;
wire zero;
reg [31:0] vectornum, errors;
reg [100:0] testvectors[10000:0];
ALU dut(a,b,f,y,zero);
always
begin
clk = 1; #5; clk = 0; #5;
end
initial
begin
$readmemb("test.tv", testvectors);
vectornum = 0; errors = 0;
end
always#(posedge clk)
begin
#1; {a,b,f, yexpected,zeroexpected} = testvectors[vectornum];
end
always #(negedge clk)
begin
if (y !== yexpected) begin
$display("Error: inputs = %b", {a,b,f});
$display(" outputs = %b (%b expected)", y, yexpected);
errors = errors + 1;
end
vectornum = vectornum + 1;
if (testvectors[vectornum] === 4'bx) begin
$display("%d tests completed with %d errors", vectornum, errors);
$stop;
end
end
endmodule
//*************************************
CONTINUOUS ERROR THAT KEEPS RUNNING UNTIL I STOP IT:
Error: inputs = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
outputs = 00000000000000000000000000000000(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx expected)
Error: inputs = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
outputs = 00000000000000000000000000000000(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx expected)
Error: inputs = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
outputs = 00000000000000000000000000000000(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx expected)
Error: inputs = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
outputs = 00000000000000000000000000000000(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx expected)
This is what my "test.tv" file looks like in binary
00000000000000000000000000000000_00000000000000000000000000000000_010_00000000000000000000000000000000_1
00000000000000000000000000000000_11111111111111111111111111111111_010_11111111111111111111111111111111_0
00000000000000000000000000000000_01010101010101010101010101010101_010_01010101010101010101010101010101_0
I know this might seem stupid and simple, but I am really trying to learn this and obviously do not understand something. Can someone please help? Thanks in advance!
testvectors is declared as:
reg [100:0] testvectors[10000:0];
100:0 means testvectors is 101 bits wide, but you are comparing it to a 4-bit value (4'bx is the same as 4'bxxxx).
Change:
if (testvectors[vectornum] === 4'bx) begin
to:
if (testvectors[vectornum] === {101{1'bx}}) begin
This stops for me using your 3-line test.tv file.
Note that the LHS (32*3+3+1) is 100 bits, but the RHS is 101 bits in the following expression:
{a,b,f, yexpected,zeroexpected} = testvectors[vectornum]
Also, you only specify 100 bits in the test.tv file. Perhaps you should declare testvectors as 100 bits wide:
reg [99:0] testvectors[10000:0];

Verilog accumulation code error

I am having a problem with accumulator code in Verilog. I simply generate pseudo random signals. Then, change the random signal level -1 to 1 from 0 to 1 so it is signed. Later, obtained 'acmin'. In this point, I need to accumulate 'acmin' signals. Debugger doesn't give me any error but I can't see any result. Can you help me to find problem?
module lfsr(clk, rst, seed, load, R, acc);
input [3:0] R;
input [26:0] seed;
input load;
input rst;
input clk;
reg [3:0]q;
wire [3:0] S;
wire overflow;
wire [3:0] acmin ;
wire [26:0] state_out;
wire [26:0] state_in;
output [7:0] acc;
reg [7:0] acc;
flipflop F[26:0] (state_out, clk, rst, state_in);
mux M1[26:0] (state_in, load, seed, {state_out[25],state_out[24],state_out[23],state_out[22],state_out[21],state_out[20],state_out[19],state_out[18],state_out[17],state_out[16],state_out[15],state_out[14],state_out[13],state_out[12],state_out[11],state_out[10],state_out[9],state_out[8],state_out[7],state_out[6],state_out[5],state_out[4],state_out[3],state_out[2], state_out[1], state_out[0], nextbit});
xor G1(nextbit, state_out[5], state_out[2], state_out[1], state_out[26]);
// Pseudorandom generator
always#(clk) begin
if (state_out[26]==0)
q=4'b1111; // 0 to -1
else
q=4'b0001; //1 to 1
end
assign acmin= R*q; // accumulator input
always#(clk) begin
if(rst)
acc = 8'b00000000;
else
acc = acc + acmin;
end
endmodule
Test bench;
module lfsrtst;
reg [3:0] R;
reg clk;
reg rst;
reg [26:0] seed;
reg load;
wire [7:0] acc;
lfsr lfsr(clk, rst, seed, load, R, acc);
initial
begin
clk = 0;
load = 0;
seed = 0;
rst = 0;
R=0;
#10 rst = 1;
#10 rst = 0;
#50 R = 4'b0111;
#50 R = 4'b0010;
#100 R = 4'b1111;
#50 R = 4'b1011;
#150 R = 4'b1101;
#50 R = 4'b1000;
end
// drive clock
always
#50 clk = !clk;
// program lfsr
initial begin
#100 seed = 27'b000000110000011000001000001;
load = 1;
#100 load = 0;
#1400 $stop;
end
endmodule
I have 'acmin' as I desired. I want to accumulate 'acmin' variable every time the edge of the clock rises and falls. However, 'acc' results nothing so what is the error?
Thanks.
The main problem that I see is that you have a synchronous reset:
always#(clk) begin
if(rst)
acc = 8'b00000000;
else
acc = acc + acmin;
end
But in your testbench you only strobe the reset for #20
#10 rst = 1;
#10 rst = 0;
This is too short, and the reset is never detected.
If you make these delays longer, then the problem should be fixed.
#100 rst = 1;
#100 rst = 0;
// then later
// program lfsr
initial begin
# also delay this so that it comes after the reset
#300 seed = 27'b000000110000011000001000001;
Alternatively you could make the reset asynchronous.
always#(clk or posedge rst) begin
I would try imply a flip-flop here by adding the posedge and converting to '<='
always#(posedge clk) begin
if(rst)
acc <= 8'b00000000;
else
acc <= acc + acmin;
end

How to execute task concurrently with other statements in an always block?

I am writing code for 8*4 RAM in Verilog. For each binary cell of memory, I am using an SR flip-flop. Initially, each cell is assigned 1'bx. The logic seems to be correct, but the output isn't. It is probably because statements are not getting executed concurrently. Can anyone suggest how can I get the task SRFlipFlop to get executed concurrently with other statements?
module memory(addr, read_data, rw, write_data, clk);
// read_data is the data read
// rw specifies read or write operation. 1 for read and 0 for write
// write data is the data to be written
// addr is the address to be written or read
task SRFlipFlop;
input d,r,s,clk; // d is the value initially stored
output q;
begin
case({s,r})
{1'b0,1'b0}: q<=d;
{1'b0,1'b1}: q<=1'b0;
{1'b1,1'b0}: q<=1'b1;
{1'b1,1'b1}: q<=1'bx;
endcase
end
endtask
task decoder; // a 3 to 8 line decoder
input [2:0] A;
input E;
output [7:0] D;
if (!E)
D <= 16'b0000000000000000;
else
begin
case (A)
3'b000 : D <= 8'b00000001;
3'b001 : D <= 8'b00000010;
3'b010 : D <= 8'b00000100;
3'b011 : D <= 8'b00001000;
3'b100 : D <= 8'b00010000;
3'b101 : D <= 8'b00100000;
3'b110 : D <= 8'b01000000;
3'b111 : D <= 8'b10000000;
endcase
end
endtask
output reg [3:0] read_data;
input [3:0] write_data;
input [2:0] addr;
input rw, clk;
reg [3:0] memory [7:0];
reg [3:0] r [7:0];
reg [3:0] s [7:0];
reg [3:0] intermediate;
reg [3:0] select [7:0];
reg [7:0] out;
reg [7:0] out1;
integer i,j,k,l;
initial
begin
for (i = 0; i <= 7; i=i+1)
begin
for (j = 0; j <= 3; j=j+1)
begin
memory[i][j] = 1'bx;
r[i][j] = 1'b0;
s[i][j] = 1'b0;
select[i][j] = 1'b0;
end
end
end
always #(posedge clk)
begin
decoder(addr, 1'b1, out);
for (i = 0; i <= 7; i=i+1)
begin
if (out[i] == 1'b1)
begin
for (j = 0; j <= 3; j=j+1)
begin
select[i][j] <= 1'b1;
s[i][j] <= write_data[j] & !rw & select[i][j];
r[i][j] <= !write_data[j] & !rw & select[i][j];
SRFlipFlop(memory[i][j],r[i][j],s[i][j],clk,intermediate);
memory[i][j] <= intermediate;
read_data[j] <= memory[i][j];
end
end
end
end
endmodule
Your code style is very software-oriented. Personally I like to know how my code will look as a circuit, so instead of using nested for loops and tasks I will use modules and generate-loops to create my circuits.
I have not been able to make your code work, but I suspect that the error is in the fact that s and r are not reset to zero on every iteration.
I have created a functioning design here:
http://www.edaplayground.com/x/Guc
Instead of using the initial block to initialize values I have added an asynchronous reset.
The SRFF-task has been converted to a module. A RAMblock module instantiates four SRFF-modules. 8 RAMblocks are instantiated in the memory module.
I have converted your packed(reg [] a []) arrays into unpacked arrays(reg [][] a) to be able to perform bitwise operations on several bits without for-loops.
If you have questions about the code, feel free to message me.
Edit: Perhaps the most important thing to note in this design is that I separate the sequential circuitry from the combinatorial. This way it is much easier to control what should be updated on the posedge of clk and what should just be a combinatorial reaction to the changes performed at the posedge.

wrong output value in 8 bit alu

I want to write an eight bit ALU. I have written this code but when I simulate it, the output has x value,why did it happen? and I have another problem that I do not know how can I show 8 bit parameter in Modelsim simulation while I have just two value 0 or 1?
module eightBitAlu(clk, a, b,si,ci, opcode,outp);
input clk;
input [7:0] a, b;
input [2:0] opcode;
input si;
input ci;
output reg [7:0] outp;
always #(posedge clk)
begin
case (opcode)
3'b000: outp <= a - b;
3'b000 : outp <= a + b;
3'b001 : outp =0;
3'b010 : outp <= a & b;
3'b011 : outp <= a | b;
3'b100 : outp <= ~a;
endcase
end
endmodule
and this is my test module
module test_8bitAlu();
reg clk=0,a=3,b=1,si=0,ci=0,opcode=1;
eightBitAlu alu(clk, a, b,si,ci, opcode,outp);
initial begin
#200 clk=1;
#200 opcode=0;
#200 opcode=2;
#200 opcode=3;
#200 opcode=4;
#200;
end
endmodule
a and b are only 1 bit wide leaving the top 7 bits of your input ports un-driven.
reg clk=0,a=3,b=1,si=0,ci=0,opcode=1;
is equivalent to :
reg clk = 0;
reg a = 3;
reg b = 1;
reg si = 0;
reg ci = 0;
reg opcode = 1;
What you need is:
reg clk = 0;
reg [7:0] a = 3;
reg [7:0] b = 1;
reg si = 0;
reg ci = 0;
reg [2:0] opcode = 1;
wire [7:0] outp;
Further improvemnets would be to include the width on the integer assignment ie:
reg clk = 1'd0;
reg [7:0] a = 8'd3;
b for binary, d for decimal, o for octal and h for hexadecimal in width'formatValue
Note
outp if not defined will be an implicit 1 bit wire.
Your clock in the testharness also only has 1 positive edge. You may prefer to define your clock as:
initial begin
clk = 1'b0;
forever begin
#100 clk = ~clk;
end
end
A complete version of the above is demonstrated at EDAplayground.

Resources