I have created a simple module that I replicate several times using the Verilog generate statement. However, it seems that the generate statement somehow effects variable assignment in the module. Here's the code:
module test();
timeunit 10ns;
timeprecision 1ns;
wire[3:0] out;
reg[3:0] values[0:4] = {5, 6, 7, 8, 9};
logic clk;
generate
genvar i;
for (i=0; i < 5; i++) begin: M1
MUT mut(
.out,
.in(values[i]),
.clk
);
end
endgenerate
initial begin
#1 clk = 0;
$monitor("%b %b %b %b %b\n", M1[0].mut.out, M1[1].mut.out, M1[2].mut.out, M1[3].mut.out, M1[4].mut.out);
#10 $stop;
end
always #1 clk++;
endmodule
module MUT(output [3:0] out, input [3:0] in, input clk);
reg[3:0] my_reg[0:7];
assign out = my_reg[7];
always #(posedge clk) begin
my_reg[7] <= in; //5
end
endmodule
The expected output of this test program would be 0101 0110 0111 1000 1001, however the output I get is xxxx xxxx xxxx xxxx. It seems that the values in the values variable in the test module are not getting assigned to the out variable in the MUT module. However, when I replace my_reg[7] <= in; with say, my_reg[7] <= 5;, the code works as expected. The code also works when I assign directly to out (after declaring it as register) i.e. out <= in;. There's no problem if I replicate the MUT modules 'manually' without using any generate statements.
You are not connecting the outputs to separate wires. So they are implicitly tied together(like how it did for clock) resulting multiple drivers for a bit.
Just add
wire[3:0] out[0:4];
generate
genvar i;
for (i=0; i < 5; i++) begin: M1
MUT mut(
.out(out[i]), // Connect to different wires
.in(values[i]),
.clk
);
end
endgenerate
Try to initialize clk variable with 0.
Related
I have implemented an 8 bit serial-in parallel-out register in SystemVerilog and I'm trying to test it. I'm using Icarus Verilog as simulator.
In the test bench, I send 8 bits and wait for the rising edge of a signal, then check the obtained parallel buffer. The problem is that, after waiting for the rising edge, the parallel buffer has not the expected value. However, if I add a #0 delay to the assert it does work.
The signal on which I'm waiting the rising edge, and the buffer that should contain the expected value are assigned as:
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
I know buff contains the right value, then, how is that on the rising edge of rdy, rdy is effectively 1 but out_data is still 0?
Wave dump
Note: See how when rdy goes high out_data is 0xaa.
Code
Serial-in parallel-out register
module sipo_reg(
input wire in_data,
output wire [7:0] out_data,
output wire rdy,
input wire en,
input wire rst,
input wire clk
);
reg [7:0] buff;
reg [2:0] i;
reg was_enabled;
wire _clk;
always #(posedge _clk, posedge rst) begin
if (rst) begin
buff <= 0;
i <= 7;
was_enabled <= 0;
end else begin
was_enabled <= 1;
buff[i] <= in_data;
i <= i == 0 ? 7 : (i - 1);
end
end
assign _clk = en | clk; // I know this is a very bad practice, I'm on it...
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
endmodule
Test bench:
module utils_sipo_reg_tb;
reg clk = 1'b1;
wire _clk;
always #2 clk = ~clk;
assign _clk = clk | en;
reg in_data = 1'b0, rst = 1'b0, en = 1'b0;
wire [7:0] out_data;
wire rdy;
sipo_reg dut(in_data, out_data, rdy, en, rst, clk);
integer i = 0;
initial begin
$dumpfile(`VCD);
$dumpvars(1, utils_sipo_reg_tb);
en = 1;
#4 rst = 1;
#4 rst = 0;
assert(out_data === 8'b0);
assert(rdy === 1'b0);
//
// read 8 bits works
//
#4 en = 0;
for (i = 0; i < 8; i = i + 1) begin
#(negedge _clk) in_data = ~in_data;
end
en = 1;
#(posedge rdy);
assert(rdy === 1'b1);
assert(out_data === 8'haa); // <-- This fails, but works if I add a '#0' delay.
#20;
$finish;
end
endmodule
I have tried to replace these lines
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{rdy}} & buff;
by these
assign rdy = (i == 7) & was_enabled;
assign out_data = {8{((i == 7) & was_enabled)}} & buff;
because I suspected the simulator was 'calculating' out_data after rdy because the former depends on the latter. However, they are still continuous assignments with 0 delay, I would expect them to get their value at the exact same time (unless a delay is added).
Would it be a good design practice to add a few picoseconds of delay after each #(posedge signal) to make sure everything is settled by the simulator?
You have a race condition in your testbench because you are trying to sample a signal at a time where it is changing. All digital systems have inherent race conditions, and the way to deal with them is to only sample your signals when you know they are stable.
In your case, you could use a small numeric delay as you have suggested. However, since you have a clock signal, if you know that changes to signals only occur on the posedge of the clock, you could sample signals at the negedge:
#(posedge rdy);
#(negedge clk);
assert(rdy === 1'b1);
assert(out_data === 8'haa);
This is a more robust approach than using a numeric delay since it scales better (no need to worry about picking the best numeric delay value).
This is a synchronous design and your assertion should synchronous as well. That means only using one edge, the (positive) clock edge. Once you start using other signal edges, you run into race conditions between statements waiting for the signal to change, which includes both the #(posedge rdy) procedural delay and the assign out_data = {8{rdy}} & buff; continuous assignment.
There are two approaches to fixing this in your testbench:
Do not use #(posedge rdy) in your prodedural code. Use
#(posedge clk iff (rdy === 1'b1));
assert(out_data === 8'haa);
Since i and was_enabled are both updated with nonblocking assignments, rdy gets sampled with its old value, as well as out_data in the assertion that follows.
Another option is using a concurrent assertion which is outside of any procedural code
assert property (#(posedge clk) $rose(rdy) |-> out_data === 8'haa);
This reads "When rdy has risen, this implies on the same cycle that out_data must be 8'haa"
I am new one in Verilog and I need to write a simple test bench, but I get an error and I cannot understand why it is
Here is my code
`timescale 1 ns / 1 ns
module test_bench_lb2;
reg [12:0] in_lines_tb;
wire [4:0] out_lines_tb;
wire error_tb;
localparam PERIOD = 10;
initial
begin
genvar i;
for(i = 0; i <= 8000; i = i + 1)
begin
in_lines_tb = i;
#PERIOD;
end
#(PERIOD*20) $stop;
end
initial
begin
$monitor("time = %time in_lines = %b out_lines = %b error = %b",
$time, in_lines_tb, out_lines_tb, error_tb);
end
DESHIFRATOR inst1(.in_lines(in_lines_tb), .out_lines(out_lines_tb), .error(error_tb));
endmodule
This
genvar i;
should be this
integer i;
A genvar is a special kind of variable used in a construct called a generate loop. You code uses an ordinary for loop.
module accumulator (
input [7:0] A ,
input reset,
input clk,
output reg carryout,
output reg overflow,
output reg [8:0] S,
output reg HEX0,
output reg HEX1,
output reg HEX2,
output reg HEX3
);
reg signA;
reg signS;
reg [7:0] magA;
reg [7:0] magS;
reg Alarger;
initial begin
S = 9'b000000000;
end
always_ff # (posedge clk, posedge reset) begin
if (reset) begin
S = 9'b000000000;
end
else begin
begin
signA <= A[7]; //Is A negative or positive
signS <= S[7];
S <= A + S;
end
if (signA == 1) begin //A is negative so magnitude is of 2s compliment
magA <= (~A[7:0] + 1'b1);
end
else begin
magA <= A;
end
if (signS == 1) begin //sum is negative so magnitude is of 2s compliment
magS <= (~S[7:0] + 1'b1);
end
else begin
magS <= S;
end
if (magA > magS) begin
Alarger <= 1'b1; //Magnitude of A is larger than magnitude of sum
end
else begin
Alarger <= 1'b0;
end
if ((signA == 1) & (Alarger == 1) & (S[7] == 0)) begin
overflow <= 1'b1;
end
else begin
overflow <= 1'b0;
end
if ((signS == 1) & (Alarger == 0) & (S[7] == 0)) begin
overflow <= 1'b1;
end
else begin
overflow <= 1'b0;
end
if ((signS == 1) & (signA == 1) & (S[7] == 0)) begin
overflow <= 1'b1;
end
else begin
overflow <= 1'b0;
end
if ((signS == 0) & (signA == 0) & (S[7] == 1)) begin
overflow <= 1'b1;
end
else begin
overflow <= 1'b0;
end
if (S[8] == 1) begin //carryout occurred
carryout <= 1'b1;
overflow <= 1'b0;
S <= 9'b000000000; //sum no longer valid
end
else begin
carryout <= 1'b0;
end
display_hex h1 //display of A
(
.bin (magA),
.hexl (HEX2),
.hexh (HEX3)
);
display_hex h2 //display of sum
(
.bin (S[7:0]),
.hexl (HEX0),
.hexh (HEX1)
);
end
end
endmodule
I am trying to make an accumulator that adds A (8 digit binary value that can be signed or unsigned) repeatedly to the sum. Once the sum is computed, then sum and A should display the value on 4 hex display LEDs (2 LEDs for A and 2 LEDs for sum). However, I am having a hard time getting it to compile. I have searched the error code and it seems like a general error for a syntax error and can have several meanings.
The error is the result of these two lines:
display_hex h1 //display of A
(
.bin (magA),
.hexl (HEX2),
.hexh (HEX3)
);
display_hex h2 //display of sum
(
.bin (S[7:0]),
.hexl (HEX0),
.hexh (HEX1)
);
Here, it appears you have a module named display_hex which converts an 8-bit value into the needed digits for a seven segment display. You are trying to use the module as if it were a function and modules are very much NOT functions. Modules in Verilog (or SystemVerilog as you are using, but the difference is really token at this point) can be though of as a group of hardware that takes in some inputs and spits out some outputs; and its important to note that they are static things. They either exist in the design or they do not; just like using ICs on a breadboard. The top module is the breadboard and the modules you declare under that module are components you are plugging into the board. The inputs and outputs are the various connections (pins) you must wire up to make everything work.
That said, always blocks (like the always_ff you are using) form a way of describing the logic and registers inside modules. Thus, you do thinks like assign logic/reg variables inside them to describe how the hardware behaves. If you look at your logic, you'll notice that the module declarations are dependent on reset; ie if reset is asserted, these modules wont exist, which doesnt make any sense. Electrical signals don't make entire ICs in a circuit disappear! Thus, you need to pull your module declaration out of your logical description of your acculumator, like so:
module accumulator (
...
);
...
display_hex h1 //display of A
(
.bin (magA),
.hexl (HEX2),
.hexh (HEX3)
);
display_hex h2 //display of sum
(
.bin (S[7:0]),
.hexl (HEX0),
.hexh (HEX1)
);
...
always_ff #(posedge clk, posedge reset) begin
// Your accumulator logic here
...
end
endmodule
Notice that the module declarations for the display_hex modules are stand alone, as I am declaring these modules exist, not dependence on anything!
However, there are a number of issues with your design besides that:
As you are using SystemVerilog constructs (always_ff), you should declare all of your variables type logic, not reg or left blank (ie, input clk should be input logic clk, reg signA should be logic signA). The logic type just makes everything easier, so use it :)
In your always_ff block, you do reset correctly except that the assignment should really be NBA (use S <= 9'b0;, not S = 9'b0; in the if (reset))
You use NBA inside your always_ff, which is correct, however, it appears you need to use these values right away in the following logic. This will not work as you expect, or at least it will not act within the same clock cycle. To fix this, youll need to decide what should be a register and what should just be values resulting from intermediate logic, then create a separate always_comb for the intermediate values.
I am making the assumption that the HEX variables are meant for seven segment displays, so they should probably declared at least [6:0] HEXn
I was not able to reproduce the exact error, but moving the instantiations of display_hex outside always_ff resolves the main issue:
module accumulator
(
/* ... */
);
// ...
always_ff # (posedge clk, posedge reset) begin
/* ... */
end
display_hex h1 (
/* ... */
);
display_hex h2 (
/* ... */
);
endmodule
Another thing: The code drives variable S from initial as well as always. This creates multiple drivers and the code will not compile. To fix this, remove the initial completely, you don't need it since S will be set to 0 when reset is asserted.
OR
You can move all the logic into the initial block; it'd look something like this (but this, most probably, won't synthesize):
initial begin
S = 0;
forever begin
wait #(posedge clock);
// Do stuff here ..
end
end
I am trying to pass a array structure as reg [0:31]instructionmem[0:31] between two modules.
I coded it as follows :
Module No 1:
module module1(instructionmem);
output reg [0:31]instructionmem[0:31];
------------------
----lines of code---
---------------
endmodule
Module No 2:
module module2(instructionmem);
input [0:31]instructionmem[0:31];
--------------------------------
-----line of code---------------
-------------------------------
endmodule
Testbench:
module test_bench();
wire [0:31]instructionmem[0:31];
module1 m1(instructionmem);
module2 m2(instructionmem);
endmodule
I am getting errors for this implementation. So how can we send such array structures ?
This is not possible in Verilog. (See sec. 12.3.3, Syntax 12-4 of the Verilog 2005 standard document, IEEE Std. 1364-2005.)
Instead you should "flatten" the array and pass it as a simple vector, e.g.:
module module1(instructionmem);
output [32*32-1:0] instructionmem;
reg [31:0] instructionmem_array [31:0];
genvar i;
generate for (i = 0; i < 32; i = i+1) begin:instmem
assign instructionmem[32*i +: 32] = instructionmem_array[i];
end endgenerate
endmodule
module module2(instructionmem);
input [32*32-1:0] instructionmem;
reg [31:0] instructionmem_array [31:0];
integer i;
always #*
for (i = 0; i < 32; i = i+1)
instructionmem_array[i] = instructionmem[32*i +: 32];
endmodule
module test_bench(instructionmem);
output [32*32-1:0] instructionmem;
module1 m1(instructionmem);
module2 m2(instructionmem);
endmodule
I am trying to design a simple 8-bit 2's complementor. Here is my code:
twos_complement_of_8bits.v
//`include "complementor.v"
module twos_complement_of_8bits(output [7:0] out, input [7:0] in);
integer i;
initial
begin
for(i = 0; i <= 7; i = i + 1)
complementor C(out[i], in[i]);
end
assign out = out + 1;
endmodule
I got an error at this line:
complementor C(out[i], in[i]);
Syntax error near 'C' found.
How can I fix it?
I think you can eliminate your complementor module, then change your twos_complement_of_8bits as follows:
module twos_complement_of_8bits (output [7:0] out, input [7:0] in);
assign out = ~in + 1;
endmodule
If that doesn't give you the output you want, please show some expected output values.
In more complicated situations, you can place arrays of instances of modules or use a generate block.
Here is an example of how to use a generate block:
module twos_complement_of_8bits (output [7:0] out, input [7:0] in);
wire [7:0] out_ones;
genvar i;
generate
for (i=0; i<=7; i=i+1) begin
complementor C[i] (out_ones[i], in[i]);
end
endgenerate
assign out = out_ones + 1;
endmodule