how to nullify register in system verilog - verilog

How do I nullify a register in SystemVerilog if I do not know the size?
For example, if I have:
reg [DATA_WIDTH-1:0] data_stack;
with some parameter DATA_WIDTH given to the module. Is it possible to assign a zero to the register data_stack?
Note that it is sufficient to initialize a similar reg to zero as then I can simply perform a bitwise and between the two and nullify data_stack.

The IEEE Std 1800-2009 is the golden reference. The following sets all bits to 0:
data_stack = '0;
Refer to the section "Integer literal constants".
An unsized single-bit value can be specified by preceding the
single-bit value with an apostrophe ( ' ), but without the base
specifier. All bits of the unsized value shall be set to the value of
the specified bit. In a self-determined context, an unsized single-bit
value shall have a width of 1 bit, and the value shall be treated as
unsigned.

If I understand your question, you want to know how to generate a zero value with the same width as data_stack?
In that case, use the replication operator:
data_stack = {DATA_WIDTH{1'b0}};
This generates DATA_WIDTH number of zeros.

I think your searches would yield better results if you searched for initialising registers, instead of nullify.
If this is a testbench variable then just :
initial begin
data_stack = {DATA_WIDTH{1'b0}};
end
If it is to be used in a flip-flop you need to reset it:
always #(posedge clk or negedge reset_n) begin
if (~reset_n) begin
data_stack <= {DATA_WIDTH{1'b0}};
end
else begin
//<=nextvalue;
end
end

Related

Bit by bit comparison between two variables in Verilog

Currently, I am beginning to write the firmware by Verilog for one idea. It is comparing bit by bit between two variables and then using one binary counter to count the number of different bits.
For example:
I have two variables in verilog
A : 8'b00100001;
B : 8'b01000000;
Then I give the condition to compare bit by bit between two variables. If there is difference between 1 bit of A and 1 bit of B at same bit position, binary counter will count.
This is my verilog code:
module BERT_test(
input CLK,
input RST,
input [7:0] SIG_IN,
input [7:0] SIG_OUT,
output [7:0] NUM_ERR
);
integer i;
reg[7:0] sign_in;
reg[7:0] sign_out;
always #(posedge CLK) begin
sign_in[7:0] <= SIG_IN[7:0];
sign_out[7:0] <= SIG_OUT[7:0];
end
reg [15:0] bit_err;
// Combinational Logic
always #* begin
bit_err = 8'b0;
for (i=0;i<8;i=i+1) begin
if (sign_in[i] == sign_out[i]) begin
bit_err = bit_err + 8'b0;
end else begin
bit_err = bit_err + 8'b1;
end
end
assign NUM_ERR = bit_err;
end
endmodule
Then I had a mistake
Reference to vector wire 'NUM_ERR' is not a legal reg or variable lvalue
I do not know how to solve this problem. Are there any solutions for this problem or how I need to modify my firmware, please suggest me.
You are driving NUM_ERR (a net) from an always block. It is not permitted to drive nets from always blocks (or initial blocks). You need to move this line:
assign NUM_ERR = bit_err;
outside the always block.
You should not use an assign statement inside an always block. This is legal but is deprecated and means something weird. If you have included this line inside the always block by mistake, then indenting you code properly would have shown it up.
You have an assign WITHIN an always block. Move it outside.
Adding zero to bit error if the bits are the same is superfluous.
if (sign_in[i] != sign_out[i])
bit_err = bit_err + 8'b1;
Also bit error is 16 bits so it is not wrong to add 8'b1 but misleading.

How to use the input's values in "always" definiton in Verilog

I got the problem with using the input's value in Verilog.
I write:
module reg_vector (INPUT, ICLK, IENBL, NR, OUT);
parameter k = 6;
parameter n = 3;
input [(8*k)-1:0] INPUT;
input ICLK;
input IENBL;
input [n-1:0] NR;
reg [n-1:0] temp;
output reg [7:0] OUT;
always# (temp, posedge ICLK)
begin
if (IENBL)
begin
OUT = INPUT[temp*8 : temp*8+8];
end
end
endmodule
But got the error:
Error (10734): Verilog HDL error at reg_vector.v(25): temp is not a
constant
How should I fix it?
Thank you)
INPUT[temp*8 : temp*8+8] does not work because the : range syntax requires both sides to be a constant.
What you want is to use the +: array slicing: INPUT[temp*8 +: 8]
The left hand side of +: allows variables and represents the starting index. The right hand side is the width and must be a constant. For more on +: see Indexing vectors and arrays with +:
Other issues:
Remove temp from the sensitivity list.
temp needs to be assigned to something
OUT should be assigned with non-blocking (<=) not blocking (=) since it is sequential logic.
always #(posedge ICLK) // no temp in sensitivity list
begin
if (IENBL)
begin
OUT <= INPUT[temp*8 +: 8]; // non-blocking and +:
end
end
Even if your vector is always 1 byte wide, the tool understands it as a variable size and it does not know how to deal with it. (you also inverted the indexes temp*8 and temp*8+8 in the vector selection)
Another way to do it is to use the shift operator
OUT = INPUT >> (temp*8);
This should work as OUT will take the lower 8bits of the shifting by 8*temp of INPUT

How range overflow affects the simulation and synthesis?

module dut ( a,b_out,array,c);
input [2:0] a;
input [3:0] array;
input c;
output reg b_out;
always#( a or c or array) begin
if(c)
b_out = 1'b0;
else
b_out = array[a];
end
endmodule
There is a possible range overflow in the above RTL, how it exactly affects the simulation and synthesis?
When a > 3 and !c then b_out will be undef in simulation because an out-of bounds access to a vector returns undef (i.e. 1'bx). See 5.2.1 in IEEE Std 1364-2005:
A part-select of any type that addresses a range of bits that are
completely out of the address bounds of the net, reg, integer, time
variable, or parameter or a part-select that is x or z shall yield the
value x when read and shall have no effect on the data stored when
written. Part-selects that are partially out of range shall, when
read, return x for the bits that are out of range and shall, when
written, only affect the bits that are in range.
In synthesis this don't care will be transformed into whatever the synthesis tool deems the most efficient. Very likely that means that only the bottom two bits of a are used in array[a], i.e. it is identical to array[a[1:0]]. But there is no guarantee for that whatsoever and it would be equally correct to create a circuit that for example always returns 1 or 0 when a[2] is high.

Case statements in Verilog?

Say I have a 8 bit output reg called "myReg" and a 8 bit input called "checkReg". Can I check and assign their values in a case statement using hex values?
For instance (assume the code is in an always block)
case (checkReg)
2'hA0:myReg <= 2'h10;
2'hB0:myReg <= 2'hC0;
//Other cases
endcase
I want the above piece of code to do the following: If checkReg = 10100000, set myReg to 00010000. If checkReg = 10110000, set myReg to 11000000.
I wasn't sure if I could check and assign hex values to a vector and have it automatically converted to binary.
For straight base conversion (bin,oct,hex,dec) you do not need to do any special conversion in verilog. Things like BCD conversion does requires extra steps.
The number before the single-quote is the bit size, not the digit count. 2'hA0 should be 8'hA0, else the upper bit values will be masked.
reg [7:0] myReg;
always #* begin
case (checkReg)
8'hA0: myReg = 8'h10;
8'hB0: myReg = 8'hC0;
//Other cases
endcase
end

"<signal> is not a constant" error in if-statement

I am trying to write a simple module to output a 14-bit number based on the value of four input signals. My attempt is shown below.
module select_size(
input a,
input b,
input c,
input d,
output [13:0] size
);
if (a) begin
assign size = 14'h2222;
end
else begin
if (b) begin
assign size = 14'h1111;
end
else begin
if (c) begin
assign size = 14'h0777;
end
else begin
assign size = 14'h0333;
end
end
end
endmodule
Upon compilation, I receive the following error:
ERROR:HDLCompiler:44 - Line 67: c is not a constant
I don't understand why that particular if-statement isn't working if the other two preceding it are. I have tried changing the condition to
if (c == 1) begin
but to no avail.
Does anybody know how to solve this error? Thank you!
Two problems:
1) You need to put if statements inside an always block.
If you use verilog-2001, you can use
always #*
if ....
end
end
Otherwise specify all the inputs in the sensitivity list:
always #(a or b or c or d)
if ....
end
end
2) Constant assignments are not allowed inside if statements.
Remove the assign keyword from any statements inside the if block:
if (a) begin
size = 14'h2222;
end
You will also have to declare size as a reg type.
However my preference would be to rewrite the entire module with conditional operator, I find it much preferrable to read. This following module achieves the same result:
module select_size(
input a,
input b,
input c,
input d,
output [13:0] size
);
assign size = a ? 14'h2222 :
b ? 14'h1111 :
c ? 14'h0777 :
14'h0333 ;
endmodule
As #Tim has already answered, using reg types inside always blocks or wire with assign.
#Tim has also described the nested ternary assignments, while in the example are written very well, they are generally seen as bad practice. They imply a very long combinatorial path and can be hard to maintain. The combinatorial path may be optimised by synthesis which should imply a mux with optimised selection logic.
Easier to maintain code will have a lower cost of ownership, and as long as it does not lead to a larger synthesised design it is normally preferred.
My implementation would be to use a casez, (? are don't cares). I find the precedence of each value easier to see/debug.
module select_size(
input a,
input b,
input c,
input d,
output logic [13:0] size //logic (SystemVerilog) or reg type
);
always #* begin
casez ({a,b,c})
3'b1?? : size = 14'h2222 ;
3'b01? : size = 14'h1111 ;
3'b001 : size = 14'h0777 ;
3'b000 : size = 14'h0333 ;
default: size = 'bx ;
endcase
end
endmodule

Resources