Verilog: Converted Integer Not Working for For loop - for-loop

I am writing a program in Verilog that accepts a binary value, converts it to Integer, and then prints "Hello, World!" that amount of times.
However, whenever I run the program, there is no display of Hello, World. Here is the code:
// Internal Variable
wire [0:4] two_times_rotate;
// Multiply the rotate_imm by two (left shift)
assign {two_times_rotate} = rotate_imm << 1;
integer i, times_rotated;
// Convert two_times_rotate into an integer
always #( two_times_rotate )
begin
times_rotated = two_times_rotate;
end
initial
begin
for (i = 0; i < times_rotated; i = i + 1)
begin
$display("Hello, World");
end
end
assign {out} = in;
endmodule
I tried using the following for loop instead:
for (i = 0; i < 7; i = i + 1)
And this one prints Hello, World seven times, like it should.
*UPDATE*
This is what I have in my code so far. I am trying to do a for that compares bits instead. It is still not working. How do I fully convert from binary to integer in a way that I can use it in the comparison in the for loop?
module immShifter(input[0:31] in, input[0:3] rotate_imm,
output[0:31] out);
// Internal Variable
wire [0:4] two_times_rotate;
reg [0:4] i;
// Multiply the rotate_imm by two (left shift)
assign {two_times_rotate} = rotate_imm << 1;
integer times_rotated, for_var;
// Convert two_times_rotate into an integer
always #( two_times_rotate )
begin
assign{times_rotated} = two_times_rotate;
end
initial
begin
assign{i} = 5'b00000;
assign{for_var} = times_rotated;
for (i = 5'b00000; i < times_rotated; i = i + 5'b00001)
begin
$display("Hello, World");
end
end
assign {out} = in;
endmodule

times_rotated is 32'bX at time 0 when the for-loop is being evaluated. The for-loop is checking i < 32'bX, which is false.
Based on your update, this may be what you are intending:
module immShifter( input [31:0] in, input [3:0] rotate_imm, output [31:0] out );
integer i, times_rotated;
always #*
begin
times_rotated = rotate_imm << 1;
for (i = 0; i < times_rotated; i++)
$display("Hello, World");
$display(""); // empty line as separate between changes to rotate_imm
end
assign out = in;
endmodule

Related

Why does this error in indexing BCD adder appear?

I am not sure, what exactly the error is. I think, my indexing in the for-loop is not Verilog-compatible, but I might be wrong.
Is it allowed to index like this (a[(4*i)+3:4*i]) in a for-loop just like in C/C++?
Here is a piece of my code, so the for-loop would make more sense
module testing(
input [399:0] a, b,
input cin,
output reg cout,
output reg [399:0] sum );
// bcd needs 4 bits + 1-bit carry --> 5 bits [4:0]
reg [4:0] temp_1;
always #(*) begin
for (int i = 0; i < 100; i++) begin
if (i == 0) begin // taking care of cin so the rest of the loop works smoothly
temp_1[4:0] = a[3:0] + b[3:0] + cin;
sum[3:0] = temp_1[3:0];
cout = temp_1[4];
end
else begin
temp_1[4:0] = a[(4*i)+3:4*i] + b[(4*i)+3:4*i] + cout;
sum[(4*i)+3:4*i] = temp_1[3:0];
cout = temp_1[4];
end
end
end
endmodule
This might seem obvious. I'm doing the exercises from:
HDLBits and got stuck on this one in particular for a long time (This solution isn't the one intended for the exercise).
Error messages Quartus:
Error (10734): Verilog HDL error at testing.v(46): i is not a constant File: ../testing.v Line: 46
Error (10734): Verilog HDL error at testing.v(47): i is not a constant File: ../testing.v Line: 47
But I tried the same way in indexing and got the same error
The error appears because Verilog does not allow variables at both indices of a part select (bus slice indexes).
The most dynamic thing that can be done involves the indexed part select.
Here is a related but not duplicate What is `+:` and `-:`? SO question.
Variations of this question are common on SO and other programmable logic design forums.
I took your example and used the -: operator rather than the : and changed the RHS of this to a constant. This version compiles.
module testing(
input [399:0] a, b,
input cin,
output reg cout,
output reg [399:0] sum );
// bcd needs 4 bits + 1-bit carry --> 5 bits [4:0]
reg [4:0] temp_1;
always #(*) begin
for (int i = 0; i < 100; i++) begin
if (i == 0) begin // taking care of cin so the rest of the loop works smoothly
temp_1[4:0] = a[3:0] + b[3:0] + cin;
sum[3:0] = temp_1[3:0];
cout = temp_1[4];
end
else begin
temp_1[4:0] = a[(4*i)+3-:4] + b[(4*i)+3-:4] + cout;
sum[(4*i)+3-:4] = temp_1[3:0];
cout = temp_1[4];
end
end
end
endmodule
The code will not behave as you wanted it to using the indexed part select.
You can use other operators that are more dynamic to create the behavior you need.
For example shifting, and masking.
Recommend you research what others have done, then ask again if it still is not clear.

Is it synthesizable, using integer variable for the for-loop within a generate block in a always block?

In the code below, the line: mem_reg[wr_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]][i*8 +: 8] <= wr_cmd_data[SEG_DATA_WIDTH*n+i*8 +: 8];
The index "i" is an integer type. It is being synthesized right??
I was under the impression that integer variables are only used for simulations in the initial procedural block
Also, the BRAM reg [SEG_DATA_WIDTH-1:0] mem_reg[2**INT_ADDR_WIDTH-1:0]; is being synthesized the number of times the genvar variable "n" loops in the for loop? The multiple generated BRAMs mem_reg will have the same names? And they cannot be accessed separately by name with something like: mem_reg[n] right?
`resetall
`timescale 1ns / 1ps
`default_nettype none
/*
* DMA parallel simple dual port RAM
*/
module dma_psdpram #
(
// RAM size
parameter SIZE = 4096,
// RAM segment count
parameter SEG_COUNT = 2,
// RAM segment data width
parameter SEG_DATA_WIDTH = 128,
// RAM segment byte enable width
parameter SEG_BE_WIDTH = SEG_DATA_WIDTH/8,
// RAM segment address width
parameter SEG_ADDR_WIDTH = $clog2(SIZE/(SEG_COUNT*SEG_BE_WIDTH)),
// Read data output pipeline stages
parameter PIPELINE = 2
)
(
input wire clk,
input wire rst,
/*
* Write port
*/
input wire [SEG_COUNT*SEG_BE_WIDTH-1:0] wr_cmd_be,
input wire [SEG_COUNT*SEG_ADDR_WIDTH-1:0] wr_cmd_addr,
input wire [SEG_COUNT*SEG_DATA_WIDTH-1:0] wr_cmd_data,
input wire [SEG_COUNT-1:0] wr_cmd_valid,
output wire [SEG_COUNT-1:0] wr_cmd_ready,
output wire [SEG_COUNT-1:0] wr_done,
/*
* Read port
*/
input wire [SEG_COUNT*SEG_ADDR_WIDTH-1:0] rd_cmd_addr,
input wire [SEG_COUNT-1:0] rd_cmd_valid,
output wire [SEG_COUNT-1:0] rd_cmd_ready,
output wire [SEG_COUNT*SEG_DATA_WIDTH-1:0] rd_resp_data,
output wire [SEG_COUNT-1:0] rd_resp_valid,
input wire [SEG_COUNT-1:0] rd_resp_ready
);
parameter INT_ADDR_WIDTH = $clog2(SIZE/(SEG_COUNT*SEG_BE_WIDTH));
// check configuration
initial begin
if (SEG_ADDR_WIDTH < INT_ADDR_WIDTH) begin
$error("Error: SEG_ADDR_WIDTH not sufficient for requested size (min %d for size %d) (instance %m)", INT_ADDR_WIDTH, SIZE);
$finish;
end
end
generate
genvar n;
for (n = 0; n < SEG_COUNT; n = n + 1) begin
(* ramstyle = "no_rw_check" *)
reg [SEG_DATA_WIDTH-1:0] mem_reg[2**INT_ADDR_WIDTH-1:0];
reg wr_done_reg = 1'b0;
reg [PIPELINE-1:0] rd_resp_valid_pipe_reg = 0;
reg [SEG_DATA_WIDTH-1:0] rd_resp_data_pipe_reg[PIPELINE-1:0];
integer i, j;
initial begin
// two nested loops for smaller number of iterations per loop
// workaround for synthesizer complaints about large loop counts
for (i = 0; i < 2**INT_ADDR_WIDTH; i = i + 2**(INT_ADDR_WIDTH/2)) begin
for (j = i; j < i + 2**(INT_ADDR_WIDTH/2); j = j + 1) begin
mem_reg[j] = 0;
end
end
for (i = 0; i < PIPELINE; i = i + 1) begin
rd_resp_data_pipe_reg[i] = 0;
end
end
always #(posedge clk) begin
wr_done_reg <= 1'b0;
for (i = 0; i < SEG_BE_WIDTH; i = i + 1) begin
if (wr_cmd_valid[n] && wr_cmd_be[n*SEG_BE_WIDTH+i]) begin
mem_reg[wr_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]][i*8 +: 8] <= wr_cmd_data[SEG_DATA_WIDTH*n+i*8 +: 8];
wr_done_reg <= 1'b1;
end
end
if (rst) begin
wr_done_reg <= 1'b0;
end
end
assign wr_cmd_ready[n] = 1'b1;
assign wr_done[n] = wr_done_reg;
always #(posedge clk) begin
if (rd_resp_ready[n]) begin
rd_resp_valid_pipe_reg[PIPELINE-1] <= 1'b0;
end
for (j = PIPELINE-1; j > 0; j = j - 1) begin
if (rd_resp_ready[n] || ((~rd_resp_valid_pipe_reg) >> j)) begin
rd_resp_valid_pipe_reg[j] <= rd_resp_valid_pipe_reg[j-1];
rd_resp_data_pipe_reg[j] <= rd_resp_data_pipe_reg[j-1];
rd_resp_valid_pipe_reg[j-1] <= 1'b0;
end
end
if (rd_cmd_valid[n] && rd_cmd_ready[n]) begin
rd_resp_valid_pipe_reg[0] <= 1'b1;
rd_resp_data_pipe_reg[0] <= mem_reg[rd_cmd_addr[SEG_ADDR_WIDTH*n +: INT_ADDR_WIDTH]];
end
if (rst) begin
rd_resp_valid_pipe_reg <= 0;
end
end
assign rd_cmd_ready[n] = rd_resp_ready[n] || ~rd_resp_valid_pipe_reg;
assign rd_resp_valid[n] = rd_resp_valid_pipe_reg[PIPELINE-1];
assign rd_resp_data[SEG_DATA_WIDTH*n +: SEG_DATA_WIDTH] = rd_resp_data_pipe_reg[PIPELINE-1];
end
endgenerate
endmodule
`resetall
try to use named blocks:
for (n = 0; n < SEG_COUNT; n = n + 1) begin : blkname
reg [SEG_DATA_WIDTH-1:0] mem_reg [2**INT_ADDR_WIDTH-1:0];
end
And access as:
assign x = blkname[i].mem_reg[j];

(System)Verilog bit cut out from arbitrary position

I'd like to make an output bus 1 bit shorter than the input, by cutting a bit from arbitrary position, like this:
module jdoodle;
integer i;
reg [8:0] in;
reg [7:0] out;
reg [3:0] idx;
always #*
begin
case(idx)
0: out = in[8:1];
1: out = {in[8:2], in[0]};
2: out = {in[8:3], in[1:0]};
3: out = {in[8:4], in[2:0]};
4: out = {in[8:5], in[3:0]};
5: out = {in[8:6], in[4:0]};
6: out = {in[8:7], in[5:0]};
7: out = {in[8], in[6:0]};
default: out = in[7:0];
endcase
end
initial begin
in = 9'b010101010;
for (i = 0; i < 9; i++)
begin
idx = i; #10;
$display ("%x - %08b", idx, out);
end
$finish;
end
endmodule
I found a way to write it in one line:
module jdoodle;
integer i;
reg [8:0] in;
reg [3:0] idx;
wire [7:0] out;
assign out = ((in >> 1) & (16'h00ff << idx)) | (in & (16'hff00 >> (16-idx)));
initial begin
in = 9'b010101010;
for (i = 0; i < 9; i++)
begin
idx = i; #10;
$display ("%x - %08b", idx, out);
end
$finish;
end
endmodule
But its less readable than the first, but the first is quite bad for larger buses. Is there a more elegant way to do it? Also is there standard library for verilog like std for c++, containing common modules like arbitrary rotate?
Thanks
Edit: here's the expected output:
0 - 01010101
1 - 01010100
2 - 01010110
3 - 01010010
4 - 01011010
5 - 01001010
6 - 01101010
7 - 00101010
8 - 10101010
You can use a loop to work on each bit:
module jdoodle #(parameter INW = 'd9)
(
input [INW-1:0] in,
output[INW-2:0] out,
input [$clog2(INW)-1:0] idx
);
always_comb begin
for(int i = 0; i<INW; i++) begin
if (i < idx) out[i] = in[i];
else if (i > idx) out[i-1] = in[i];
// do nothing if i == idx
end
end
endmodule

Unable to use enum in systemverilog

I have a design file ALU and another testbench. Here is my code:
parameter WIDHT = 4;
typedef enum logic[1:0] {
ADD =2'b00,
AND =2'b01,
OR = 2'b10,
XOR = 2'b11
} operation;
module ALU
(
input logic [WIDHT-1:0] A,B,
input operation op,
output logic [WIDHT-1:0] R,
output logic N,Z,V
);
always_comb
begin
unique case(op)
ADD: R = A+B;
AND: R = A&B;
OR: R = A|B;
XOR: R = A^B;
default : R=0;
endcase
if(R=='b0)
Z = 1;
else if (R[WIDHT-1] == 1'b1)
begin
if( A[WIDHT-1] == 1'b0 && B[WIDHT-1] == 1'b0)
V = 1;
else
N = 1;
end
else if (R[WIDHT-1] == 1'b0)
begin
if( A[WIDHT-1] == 1'b1 && B[WIDHT-1] == 1'b1)
V = 1;
else
begin
R=0;
Z=0;
V=0;
end
end
end
endmodule: ALU
Here is my testbench:
parameter W = 4;
module ALU_tb;
logic [W-1:0] A,B;
logic [1:0] op1;
logic [W-1:0] R;
logic N,Z,V;
ALU alu(A,B,op1,R,N,Z,V);
initial
begin
$monitor($time," A = %b, B = %b, ope = %b, R = %b, N = %b, Z = %b, V = %b",A,B,op1,R,N,Z,V);
A =0;
B=0;
#10;
for(A=0; A<2**W ; A++)
begin
for(B=0; B<'d2**W ; B++)
begin
/*for(op = op.first; op<=op.last; op.next)
#10; */
for(op1 = 2'b00; op1<=2'b11; op1++)
#10;
end
end
end
endmodule: ALU_tb
Now, the code compiles successfully but doesn't simulate. It gives me an error saying that I need to assign an enum to the same enum type or one of its value. What is that I am doing wrong? Any suggestions? One thing I found was to use packages and put the typedef enum in it and then import the package in both my design and testbench files. But I am trying to avoid using enum in my testbench. Can someone suggest something?
An enum is a stronger type than most integral types. You need use the package method to make the types assignment compatible.
Another option is making your port a bit-vector, and then casting it to operation type inside your design.

109 bit tree comparator with generate and for loop

I am trying to write a Verilog code for the 109-bit tree comparator, but I am still new to the generate loop.
I have written some code so far, but I am getting some errors. Also, I am not sure if I can use 2-d arrays for g and l signals?
parameter NUM_OF_BITS = 109;
parameter NUM_OF_LEVELS = 7;
genvar i;
for (x=0; x<NUM_OF_LEVELS; x=x+1) begin:
generate for (i=0; i<NUM_OF_BITS/((2*x)+1); i=i+1) begin: MCs
mag_comp2_1 mc (in0[2*i+1:2*i],in1[2*i+1:2*i],g[x][i],l[x][i]);
end
endgenerate
NUM_OF_BITS = NUM_OF_BITS/2;
end
Why not define the interconnections in for blocks? This way it will be more convenent for you.
An incomplete example:
parameter NUM_OF_BITS = 220;
parameter NUM_OF_LEVELS = 7;
genvar i,x;
generate for (x=1; x<NUM_OF_LEVELS; x=x+1)
begin: Ls
wire [NUM_OF_BITS/(2**x)-1:0] output1;
wire [NUM_OF_BITS/(2**x)-1:0] output2;
for (i=0; i<NUM_OF_BITS/(2**x); i=i+1)
begin: MCs
if (x == 1)
begin
// for the first level connect inputs to the module
mag_comp2_1 mc (input1[2*i+1:2*i],input2[2*i+1:2*i],output1[i],output2[i]);
end
else
begin
// for other levels connect ouputs of the previous level
mag_comp2_1 mc (Ls[x-1].output1[2*i+1:2*i],Ls[x-1].output2]2[2*i+1:2*i],output1[i],output2[i]);
end
end
end
endgenerate
you need something like the following. generate .. endgenerate tell the compiler to unroll all the loops and conditional statements between the keywords. So, you end up with a lot of instances of the module mag_comp2_1
parameter NUM_OF_BITS = 109;
parameter NUM_OF_LEVELS = 7;
genvar i, x;
generate
for (x=0; x<NUM_OF_LEVELS; x=x+1) begin: externloop
for (i=0; i<NUM_OF_BITS/((2*x)+1); i=i+1) begin: MCs
mag_comp2_1 mc (in0[2*i+1:2*i],in1[2*i+1:2*i],g[x][i],l[x][i]);
end
//NUM_OF_BITS = NUM_OF_BITS/2;
end
endgenerate
parameter NUM_OF_BITS = 220;
parameter NUM_OF_LEVELS = 7;
genvar x,i;
wire [NUM_OF_LEVELS:0][NUM_OF_BITS:0] g, l;
assign g[0] = in0;
assign l[0] = in1;
generate for (x=1; x<NUM_OF_LEVELS; x=x+1) begin: Ls
for (i=0; i<NUM_OF_BITS/(2**x); i=i+1) begin: MCs
mag_comp2_1 mc (g[x-1][2*i+1:2*i],l[x-1][2*i+1:2*i],g[x][i],l[x][i]);
end
end
endgenerate
assign gt = g[NUM_OF_LEVELS][0];
assign lt = l[NUM_OF_LEVELS][0];

Resources