Verilog: Using reg As Counters For for-loops - verilog

In a module:
reg a, b;
integer i, j;
initial
begin
for (a = 0; a < 2; a = a + 1)
//some code
end
The textbook says it would be incorrect to get rid of integers i and j and use reg a and b directly as loop counters. Hint: reg variables have a fixed size and, hence, they wrap.
What does that mean? Doesn't integer have a fixed size as well? And what's wrapping?

A reg is either single bit, or multiple bit if you define it as an array. An integer, on the other hand is 32 bits. So if you have a loop, it is more convenient to use an integer variable that doesn't overflow as the loop advances.
In your example, you set a < 2, so with a single bit reg the loop never terminates.
Moreover integers are singed values.

Related

Is there a mandate for the variable to be of data type "integer" for arithmetic operations "+" and "-"?

Following is the code for finding factorial of a number. If I declare "i" as "register", the output (z) remains 1, irrespective of the input. If it is declared as "integer", I get the proper result. Why is it so? Please explain.
module Factorial_calc(n, z);
input [5:0] n;
output reg [64:0] z;
reg i;
// integer i;
always #(n)
begin
i=0;
z=1;
while(i<n)
begin
i=i+1;
z=i*z;
end
end
endmodule
Because your integer is 32 bits wide and your reg is only one bit wide. Your simulation should not finish for most values of n, let alone produce a result.
HDL is not like any other programming language. Beware that even if your code simulates it does not mean it will work in hardware. In your case it will not synthesize. You value of n is undefined at compile time.
Last be not least do NOT use x or z for variables, They are too easily confused with 'x or 'z.

Concatenation of RAM bits in Verilog

First of all, I had a lot of difficulty phrasing the title of this question. So if you understand the problem I'm facing, and there is a better way to word it and the question has been answered before, I apologise, and please do point out to me how I can resolve this. Anyways, here's the relevant code snippet that I've truncated for clarity:
parameter RAM_DEPTH = 256;
reg ram [0:RAM_DEPTH-1]; //256 deep memory, 1-bit size per location
parameter NUM_INST = 64;
parameter N = 4;
genvar x;
generate for (x = 0; x < NUM_INST; x = x + 1) begin: xs
//instantiate a module here
//connect N bits to input port
//which N bits depends module number x
mod inst (
.in(ram[x*N : x*N + N - 1]) //the error is here
);
end endgenerate
The error is:
error: Array cannot be indexed by a range.
I understand that this is because ram is declared as reg ram [0:RAM_DEPTH-1] instead of reg [0:RAM_DEPTH-1] ram. But is there a way to automate concatenation of RAM bits based on the N parameter, i.e. instead of having to write .in({ram[x*N],ram[x*N+1],ram[x*N+2],ram[x*N+3]}), there's an automated range selection logic that concatenates the bits based on N. You can imagine that if, say, N = 256, I would have to write a very long concatenation operator, and also makes my module less parametric.
In this case, should I just be using reg [0:RAM_DEPTH-1] ram declaration, and re-write my module to support bit updates on a single register array instead?
Thanks.
The easiest solution I found was to do as you suggested and turn reg ram [0:RAM_DEPTH-1] into reg [0:RAM_DEPTH-1] ram. An alternative would be the following:
parameter RAM_DEPTH = 256;
parameter NUM_INST = 64;
parameter N = 4;
reg [RAM_DEPTH-1:0] ram; //256 deep memory, 1-bit size per location
reg [N-1:0] ramwires [NUM_INST-1:0];
genvar x;
integer y, z;
generate for (x = 0; x < NUM_INST; x = x + 1) begin: xs
mod inst (
.in(ramwires[x])
);
end endgenerate
always#(*)
for (y = 0; y<NUM_INST; y = y + 1) begin
for (z=0; z<N; z = z + 1) begin
ramwires[y][z] = ram[y*N+z];
end
end
This converts the 1D array into a 2D array, which is easily passed into the module, while still being parameterizable.

Assigning an integer to a register

I am new to Verilog so I am having problems making conversions between different bases or types. More specifically I am trying to assign an integer to a 9 bit long register. The register will represent a signed integer in binary. I am trying to do something like this.
integer i = -10;
reg [8:0] r;
always #(posedge clk)
begin
r <= i;
end
P.S. I am using Verilog with Xilinx ISE v12.4
Integers can be assigned to registers - and the other way around, ref here. But care needs to be taken so that the value isn't truncated.

How to dynamically reverse the bit position in verilog?

wire [9:0] data_reg;
reg [3:0] Reverse_Count = 8; //This register is derived in logic and I need to use it in following logic in order to reverse the bit position.
assign data_reg[9:0] = 10'h88; // Data Register
genvar i;
for (i=0; i< Reverse_Count; i=i+1)
assign IReg_swiz[i] = IReg[Reverse_Count - 1 -i];
This is generating syntax error. May I know how to do this in verilog
If you'd have Reverse_Count as constant, your task boils down to just wire mix-up, which is essentially free in HDL.
In your case, the task can be nicely reduced to first mirroring wide data and then shifting by Reverse_Count to get LBS bit on its position, which itself is done just by a row of N-to-1 multiplexers.
integer i;
reg [9:0] reversed;
wire [9:0] result;
// mirror bits in wide 10-bit value
always #*
for(i=0;i<10;i=i+1)
reversed[i] = data_reg[9-i];
// settle LSB on its place
assign result = reversed>>(10-Reverse_Count);
Reverse_Count is not a constant, ie it is not a parameter or localparam.
This means that the generate statement you would be creating and destroying hardware as required, this is not allowed in verilog as it would not be possible in hardware.
The Bus that your reversing should have a fixed width at compile time, it should be possible to declare Reverse_Count as a parameter.
Since the value of Reverse_Count dunamic, you cannot use a generate statement. You can use an always block with for-loop. To be synthesizable, the for-loop needs able to static unroll. To decide which bits reverse, use an if condition to compare the indexing value and Reverse_Count
Example:
parameter MAX = 10;
reg [MAX-1:0] IReg_swiz;
integer i;
always #* begin
for (i=0; i < MAX ; i=i+1) begin
if (i < Reverse_Count) begin
IReg_swiz[i] = IReg[Reverse_Count - 1 -i];
end
else begin
// All bits need to be assigned or complex latching logic will be inferred.
IReg_swiz[i] = IReg[i]; // Other values okay depending on your requirements.
end
end
end

Calculating a parameter in a loop generate block

I have an array of parameters WIDTHS, and I need to calculate another parameter RIGHT based on some values in WIDTHS in a generate block. Is this possible? If not, is there an alternative way?
Here is an example of what I am trying to do. Suppose we have a predefined register module REG which has inputs d, q, we (write enable), CLK and _RESET. I would like to create a new module called GroupReg, which instantiates N instances of REG. Each instance has a different width (hence the WIDTH parameter array). The d, q, and we of each group are aggregated in arrays with the same name in GroupReg and need to be specified for each instance. Specifying we is easy (we[i]) since it is only one bit. However, specifying d and q with the correct LEFT and RIGHT values is where I have problem with since each group has a different width.
Looks like the only way to assign a value to a parameter is upon its definition, which prevents assigning a value to it in a generate loop.
module GroupReg(d, q, we, CLK, _RESET);
parameter N = 4; //Number of groups
//INDICES has to have N+1 members. Last member should be 0
parameter integer WIDTHS [N:0] = {40, 30, 20, 10, 0};
parameter integer DW_TOTAL = 128;
input logic [DW_TOTAL-1:0] d; // Data Input
input logic [N-1:0] we; // write enable
input logic CLK; // Clock Input
input logic _RESET; // Reset input (active low)
output logic [DW_TOTAL-1:0] q; // Q output
genvar i, j;
for (i=N-1 ; i>=0 ; i--) begin:REGISTERS
localparam WIDTH = WIDTHS[i];
localparam LEFT = RIGHT + WIDTHS[i];;
localparam RIGHT = 0;
for (j = 0 ; j<i ; j++) // <<----- Does not work
RIGHT = RIGHT + WIDTH[j];
REG #(
.DW (WIDTH),
)
reg_i
(
.d(d[LEFT:RIGHT]),
.q(q[LEFT:RIGHT]),
.we(we[i]),
.CLK(CLK),
._RESET(_RESET)
);
end : REGISTERS
endmodule
I tried using the sum() array reduction method on WIDTHS and it worked in Aldec Riviera PRO:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
parameter integer DW_TOTAL = WIDTHS.sum();
initial begin
$display("DW_TOTAL", DW_TOTAL);
end
endmodule
If you're lucky it's going to work in your simulator too.
I anyway don't really get what you're trying to do making N a parameter, seeing as how you're anyway hardcoding a fixed number of values for the widths.
This works in Modelsim:
module some_module;
parameter N = 4; //Number of groups
parameter integer WIDTHS [N:0] = '{40, 30, 20, 10, 0};
genvar i;
for (i=N-1 ; i>=0 ; i--) begin
localparam integer FOO[i:0] = WIDTHS[i:0];
//localparam RIGHT = FOO.sum();
initial begin
foreach (FOO[i])
$display("FOO[%0d] = %h", i, FOO[i]);
end
end
endmodule
The FOO parameter would only store the relevant entries from WIDTH for a specific loop iteration. If sum() would work, you'd be home free. The slicing syntax doesn't work in Riviera, however.
This is a typical example of vendors interpreting the standard differently, basically because it's not specific enough. Still, if you use a simulator from a different EDA company, try combining the two answers; maybe you're lucky and it works.

Resources