system verilog: for loop index variable issue - system-verilog

`timescale 1ns / 1ps
module param_right_shifter
# (parameter N = 3)
(
input logic [$clog2(N)-1:0] a, // input
input logic [N-1:0] amt, // shift bits
output logic [$clog2(N)-1:0] y // output
);
logic [$clog2(N)-1:0][N:0] s;
logic [$clog2(N)-1:0] placeholder = a;
localparam bit_num = $clog2(N)-1;
always_comb
begin
for(int i = 0; i < N; i++)
begin
if (i == 0)
begin
s[i] = amt[i] ? {placeholder[i], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
else
begin
s[i] = amt[i] ? {placeholder[$clog2(N)-1:0], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
end
end
endmodule
I am having an issue with referencing the 'i' variable. It says that 'range must be bounded by constant expressions'. I am unsure of how to resolve.

Try below. I am assuming N is will have a constant value throughout the simulation.
Please note that placeholder is driven by all bits of s so here placeholder will settle to s[N-1].
genvar i;
generate
for(i = 0; i < N; i++)
begin
if (i == 0)
begin
always_comb
begin
s[i] = amt[i] ? {placeholder[i], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
end
else
begin
always_comb
begin
s[i] = amt[i] ? {placeholder[$clog2(N)-1:0], placeholder[bit_num:2**i]} : placeholder;
placeholder = s[i];
end
end
end
endgenerate

Related

VVP can't compile

I do have a problem with compiling my code :
module alu(i_a, i_b , i_oper, o_y, o_status, i_rsn, i_clk);
parameter BITS = 4;
parameter OPER = 3;
input logic signed [BITS - 1:0] i_a, i_b;
input logic [OPER-2:0] i_oper;
input logic i_clk;
input logic i_rsn;
output logic signed [BITS - 1:0] o_y;
output logic [3:0] o_status;
logic [BITS - 1:0] o_y_mux;
logic [BITS - 1:0] o_y_1;
logic [BITS - 1:0] o_y_2;
logic [BITS - 1:0] o_y_3;
logic [BITS - 1:0] o_y_4;
logic [3:0] o_status_mux;
logic [3:0] o_status_1;
logic [3:0] o_status_2;
logic [3:0] o_status_3;
logic [3:0] o_status_4;
ashift_example1 #(.BITS(BITS)) case1 (.i_a(i_a), .i_b(i_b), .o_arith_left(o_y_1), .o_error(o_status_1));
U2_to_ZM #(.BITS(BITS)) case2 (.i_a(i_a), .o_zm(o_y_2), .o_status(o_status_2));
porownanie #(.BITS(BITS)) case3 (.i_a(i_a), .i_b(i_b), .o_smaller(o_y_3), .o_error(o_status_3));
replace #(.BITS(BITS)) case4 (.i_a(i_a), .i_b(i_b), .o_replaced(o_y_4), .o_error(o_status_4));
always_comb
begin
{o_y_mux, o_status_mux} = '0;
case (i_oper)
2'b00 : o_y_mux = o_y_1;
2'b01 : o_y_mux = o_y_2;
2'b10 : o_y_mux = o_y_3;
2'b11 : o_y_mux = o_y_4;
default : o_y_mux = '0;
endcase
case (i_oper)
2'b00 : o_status_mux = o_status_1;
2'b01 : o_status_mux = o_status_2;
2'b10 : o_status_mux = o_status_3;
2'b11 : o_status_mux = o_status_4;
default : o_status_mux = '0;
endcase
end
always_ff #(posedge i_clk)
begin
if(i_rsn == 1)
begin
o_y <= o_y_mux;
o_status <= o_status_mux;
end
else
begin
o_y <= '0;
o_status <= '0;
end
end
endmodule
This is the code for the module (the module is a multiplexer).Below is testbench :
`timescale 1ns/1ps
module test_alu;
parameter BITS = 4;
parameter OPER = 3;
logic signed [BITS - 1:0] i_a, i_b;
logic [OPER-2:0] i_oper;
logic i_rsn;
logic i_clk;
logic signed [BITS - 1:0] o_y;
logic signed [BITS - 1:0] o_y_rtl;
logic [3:0] o_status;
logic [3:0] o_status_rtl;
alu #(.BITS(BITS), .OPER(OPER)) alu (.i_a(i_a), .i_b(i_b), .i_oper(i_oper), .o_y(o_y), .o_status(o_status), .i_rsn(i_rsn), .i_clk(i_clk));
//exe_unit_38_rtl alu_rtl (.i_a(i_a), .i_b(i_b), .i_oper(i_oper), .o_y(o_y_rtl), .o_status(o_status_rtl), .i_rsn(i_rsn), .i_clk(i_clk));
initial
begin
$dumpfile("alu.vcd");
$dumpvars(0,test_alu);
i_rsn = 1;
i_clk = 0;
i_oper = 2;
i_a = '0;
i_b = '0;
#1
i_clk = 1;
i_oper = 1;
i_a[3] = 1;
#1
i_clk = 0;
i_oper = 3;
i_b[3] = 0;
i_a[3] = 0;
i_a[2] = 1;
i_a[0] = 0;
#1
i_clk = 1;
i_oper = 0;
i_a[0] = 0;
i_b[1] = 1;
i_a[3] = 1;
#1
$finish;
end
endmodule
Here are also the modules that the multiplexer needs :
module ashift_example1(i_a, i_b, o_arith_left, o_error);
parameter BITS = 4;
input logic signed [BITS-1:0] i_a, i_b;
output logic signed [BITS-1:0] o_arith_left;
output logic [3:0] o_error;
integer x;
always_comb
begin
x = 0;
o_arith_left = '0;
o_error = '0;
if(i_b >= 0)
begin
o_arith_left = i_a <<< i_b;
if(i_a < 0)
begin
o_arith_left[BITS-1] = 'd1;
end
else
begin
o_arith_left[BITS-1] = 'd0;
end
end
else
begin
o_error[0] = 1;
o_arith_left = 'x;
end
for (int i = 0; i<BITS;i++)
begin
if(o_arith_left == 1)
begin
x = x+1;
end
end
if (x % 2 == 0 && o_arith_left != '0)
begin
o_error[1] = 1;
end
if(o_arith_left == '1)
begin
o_error[2] = 1;
end
end
endmodule
module U2_to_ZM (i_a , o_zm, o_status);
parameter BITS = 4;
input logic signed [BITS-1:0] i_a;
output logic signed [BITS-1:0] o_zm;
output logic [3:0] o_status;
logic signed [BITS-1:0] one;
integer x;
always_comb
begin
x = 0;
one = i_a;
o_status = '0;
if(i_a < 0)
begin
for (int i = 0; i<BITS-1; i++)
begin
one = ~i_a;
end
if(one == '1)
begin
o_status[3] = 1;
o_status[0] = 1;
o_zm = 'x;
end
else
begin
o_zm = one + 1;
end
end
else
begin
o_zm = one;
end
for (int i = 0; i<BITS;i++)
begin
if(o_zm == 1)
begin
x = x + 1;
end
end
if (x % 2 == 0 && o_zm != '0)
begin
o_status[1] = 1;
end
if (o_zm == '1)
begin
o_status[2] = 1;
end
end
endmodule
module porownanie(i_a, i_b, o_smaller, o_error);
parameter BITS = 4;
input logic signed [BITS-1:0] i_a, i_b;
output logic signed [BITS-1:0] o_smaller;
output logic [3:0] o_error;
always_comb
begin
o_error = '0;
o_smaller = '0;
if(i_a<=i_b)
begin
o_smaller = 'd1;
end
else
begin
o_smaller = '0;
end
if(o_smaller == '1)
begin
o_error[2] = 1;
end
end
endmodule
module replace(i_a, i_b, o_replaced, o_error);
parameter BITS = 4;
input logic signed [BITS-1:0] i_a, i_b;
output logic signed [BITS-1:0] o_replaced;
output logic [3:0] o_error;
integer x;
integer i;
always_comb
begin
x = 0;
i = 0;
o_replaced = '0;
o_error = '0;
if(i_b < 0 || i_b > BITS)
begin
o_error[0] = 1;
o_replaced = 'x;
end
else
begin
i = i_b;
o_replaced = i_a;
o_replaced = 1;
end
for (int i = 0; i<BITS;i++)
begin
if(o_replaced == 1)
begin
x = x+1;
end
end
if (x % 2 == 0 && o_replaced != '0)
begin
o_error[1] = 1;
end
if (o_replaced == '1)
begin
o_error[2] = 1;
end
end
endmodule
The problem is that the Multiplexer works in Windows but doesn't work in Linux I don't know why ...
Whenever I use vvp it says that it made the VCD code but the terminal doesn't respond to anything and the VCD code that I open on gthwave doesn't want to open like it is not a vcd file

Implementation of wait statement inside a fork join block

what modification is needed to display i value =5,2,7? I am not getting output. Any suggestion will be helpful.
module tb#(int T=8);
bit [8:0] abc;
initial
begin
for(int i=0; i<T; i++)
begin
fork
begin
wait(abc[i] == 1'b1);
$display(i,$time);
end
join_none
end
end
initial
begin
abc[5] = 1'b1;
#10 abc[2] = 1'b1;
abc[7] = 1'b1;
end
endmodule
https://www.edaplayground.com/x/JUZR
There is only one instance of the variable i and it's value is 8 by the point in time that the process begins. You need to declare a variable k that has a different value for each iteration of the loop.
module tb#(int T=8);
bit [8:0] abc;
initial
begin
for(int i=0; i<T; i++)
begin
automatic int k = i;
fork
begin
wait(abc[k] == 1'b1);
$display(i,k,,,$time);
end
join_none
end
end
initial
begin
abc[5] = 1'b1;
#10 abc[2] = 1'b1;
abc[7] = 1'b1;
end
endmodule
See https://verificationacademy.com/forums/systemverilog/fork-joinnone-inside-loop

Bit slicing with variable width in SystemVerilog

I am trying to access certain sections of an array using the +: operator however getting the infamous [variable] is not a constant error. The only problem is, the width I would like the get from the array is changing as well.
This is the loop I have:
logic [N-1:0] a;
logic [2**N-2:0] b;
for (i = 0; i < N; i++)
a[i] = b[(2**i)-1 +: 2**i] == {(2**i){1'b1}};
In other words, if N = 4, I want this loop to do this:
a[0] = b[0:0] == 1'b1;
a[1] = b[2:1] == 2'b11;
a[2] = b[6:3] == 4'b1111;
a[3] = b[14:7] == 8'b11111111;
Logically, I'm pretty certain that the loop I provided works however SystemVerilog doesn't allow non-constants to be used for setting the width (after the a:).
How can I utilize the +: operator when my starting index and width are both dependent on a non-constant variable? or is there another way of doing this considering that N can be a large number.
Thanks!
EDIT:
This can be done with shifts, here is a working code:
for (i = 0; i < N; i++)
a[i] <= ((b >> (2**i)-1) << ((2**N) - (2**i) - 1)) ==
{(2**N-1){1'b1}} << ((2**N) - (2**i) - 1);
You cannot use +: with variable widths. It is actually just a short-hand for shifts and masks. For example, something like the following should work in your case:
logic [N-1:0] a;
logic [2**N-2:0] b;
always_comb begin
for (int i = 0; i < N; i++) begin
logic [2**N-2:0] tmpb, tmp1;
tmpb = b >> ((2**i)+1);
tmp1 = ((2**N)'(1) << (2**i)) - 1;
a[i] = (tmpb & tmp1) == 0;
end
end
you just need to figure out exact numbers of shifts and widths.
You can use a combination of '+:` operator with a mask
parameter N = 8; localparam N2 = 2**(N-1);
logic [N-1:0] a;
logic [2**N-1:0] b;
initial begin
b ={8'b000001,4'b1111,2'b01,1'b1};
for (int i = 0; i < N; i++)
a[i] = (b[(2**i)-1 +: N2] | ~N2'((1 << 2**i)- 1)) == '1;
$displayb(a,,b);
end
You can use +: provided that the right hand side is a constant or genvar.
logic [N-1:0] a;
logic [2**N-2:0] b;
for (genvar i = 0; i < N; i++) begin : gen_a
assign a[i] = b[(2**i)-1 +: 2**i] == {(2**i){1'b1}};
end
Note that this for-loop is a generate-for-loop which is not within a procedural block (ie begin-end)

SystemVerilog: $urandom_range gives values outside of range

I am getting an odd issue in ModelSim where I set an input variable to a random value in a range, but for some reason, I get a value outside of the range. All my code is included below but the essential line is:
write_addrs[i] = $urandom_range(1,NUM_ARCH_REGS);
In ModelSim, it is being assigned to 0 when it shouldn't (as shown in the waveform; the highlighted signal)...
The thing that is confounding me is that I don't ever set the write_adresses to zero except for when I set the initial signals in the INITIAL_VECTOR_VALUES block. I only modify the variable by using the $urandom_range function with the range explicitly excluding the number zero.
The main blocks of code in which I write to this variable are here:
initial begin : INITIAL_VECTOR_VALUES
advance = 0;
checkpoint = 0;
recover = 0;
write_before_checkpoint = 0;
for (int i = 0; i < NUM_READ_PORTS; i++)
read_addrs[i] = 0;
for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
write_addrs[i] = 0; //<--------------------- HERE!!!
wr_en[i] = 0;
write_data[i] = 0;
commit_en[i] = 0;
commit_data[i] = 0;
commit_addrs[i]= 0;
end
end
... and here:
task random_operations(int repeat_num);
//local vars
int operation_select, num_write, num_commit;
int current_checkpoints;
int loop_idx;
##5;
current_checkpoints = 0; //initialize
$display("Begin Random Operations # %0t", $time());
while (loop_idx < repeat_num) begin
... other stuff ...
//operand select (sets the stimulus inputs)
for (int k = 0; k < num_write; k++) begin
write_addrs[k] = $urandom_range(1,NUM_ARCH_REGS); //<--------------------- HERE!!!
$display("%0t: num_write = %0d",$time(), num_write);
$display("%0t: write_addrs[%0d] = %0d", $time(), k, write_addrs[k]);
write_data[k] = $urandom_range(1,128);
wr_en[k] = 1;
end
...
loop_idx++;
##1;
//reset signals (reset stimulus inputs)
...
end : end_while
endtask : random_operations
Does anyone know why this would be happening?
REFERENCE CODE
`timescale 1ns/1ns
module testbench;
localparam int NUM_CHECKPOINTS = 8;
localparam int NUM_ARCH_REGS = 32;
localparam int NUM_READ_PORTS = 4;
localparam int NUM_WRITE_PORTS = 2;
logic clk;
logic rst;
initial begin : CLOCK_INIT
clk = 1'b0;
forever #5 clk = ~clk;
end
default clocking tb_clk #(posedge clk); endclocking
logic [$clog2(32)-1:0] read_addrs [4];
logic [$clog2(32)-1:0] write_addrs [2];
logic wr_en [2];
logic advance; //moves tail pointer forward
logic checkpoint; //moves head pointer forward
logic recover; //moves head pointer backward (to tail)
logic write_before_checkpoint;
logic [$clog2(32)-1:0] commit_addrs [2];
logic [$clog2(128)-1:0] commit_data [2];
logic commit_en [2];
logic [$clog2(128)-1:0] write_data [2];
logic [$clog2(128)-1:0] read_data [4];
logic [$clog2(128)-1:0] write_evict_data [2];
logic enable_assertions;
cfc_rat dut(.*);
shadow_rat rat_monitor(.*);
initial begin : INITIAL_VECTOR_VALUES
advance = 0;
checkpoint = 0;
recover = 0;
write_before_checkpoint = 0;
for (int i = 0; i < NUM_READ_PORTS; i++)
read_addrs[i] = 0;
for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
write_addrs[i] = 0;
wr_en[i] = 0;
write_data[i] = 0;
commit_en[i] = 0;
commit_data[i] = 0;
commit_addrs[i]= 0;
end
end
task reset();
rst = 1;
##2;
rst = 0;
##1;
endtask : reset
task random_operations(int repeat_num);
//local vars
int operation_select, num_write, num_commit;
int current_checkpoints;
int loop_idx;
##5;
current_checkpoints = 0; //initialize
$display("Begin Random Operations # %0t", $time());
while (loop_idx < repeat_num) begin
operation_select = (loop_idx < 5) ? 1 : ((dut.dfa.chkpt_empty) ? $urandom_range(0,1) : ((dut.dfa.chkpt_full) ? 1 : $urandom_range(0,2)));
num_write = $urandom_range(0,NUM_WRITE_PORTS);
num_commit = $urandom_range(0,NUM_WRITE_PORTS);
case (operation_select)
0: begin //checkpoint
if (current_checkpoints+1 < NUM_CHECKPOINTS) begin
$display("Checkpoint # %0t", $time());
write_before_checkpoint = $urandom_range(0,1);
checkpoint = 1;
current_checkpoints++;
end
else begin
loop_idx--;
continue;
end
end
1: $display("Normal RW # %0t",$time()); //no operation, only read and write
2: begin //advance
if (current_checkpoints > 0) begin
advance = 1;
$display("Advance # %0t", $time());
current_checkpoints--;
end
else begin
loop_idx--;
continue;
end
end
3: begin //recover
$display("Recover # %0t", $time());
recover = 1;
current_checkpoints = 0;
end
default:;
endcase // operation_select
//operand select (sets the stimulus inputs)
for (int k = 0; k < NUM_READ_PORTS; k++)
read_addrs[k] = $urandom_range(0,NUM_ARCH_REGS);
for (int k = 0; k < num_write; k++) begin
write_addrs[k] = $urandom_range(1,NUM_ARCH_REGS);
$display("%0t: num_write = %0d",$time(), num_write);
$display("%0t: write_addrs[%0d] = %0d", $time(), k, write_addrs[k]);
write_data[k] = $urandom_range(1,128);
wr_en[k] = 1;
end
for (int k = 0; k < num_commit; k++) begin
commit_addrs[k] = $urandom_range(1,NUM_ARCH_REGS);
commit_data[k] = $urandom_range(1,128);
commit_en[k] = 1;
end
loop_idx++;
##1;
//reset signals (reset stimulus inputs)
checkpoint = 0;
recover = 0;
advance = 0;
write_before_checkpoint = 0;
for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
write_data[i] = 0;
wr_en[i] = 0;
end
for (int i = 0; i < NUM_READ_PORTS; i++)
read_addrs[i] = 0;
for (int i = 0; i < NUM_WRITE_PORTS; i++) begin
commit_en[i] = 0;
commit_data[i] = 0;
end
end : end_repeat
endtask : random_operations
initial begin : TEST_VECTORS
enable_assertions = 1; //for testing the monitor
reset();
random_operations(5000);
##10;
$display("Finished Successfuly! # %0t",$time());
$finish;
end
endmodule
The problem is that $urandom_range(1, NUM_ARCH_REGS) returns values from 1 to 32. But, write_addrs is declared as logic [4:0], which means it can only take on values from 0 to 31. When $urandom_range returns 32 (which is the same as 6'b10_000), the assignment in your code truncates it to 5 bits, dropping the MSB, and 5'b0_0000 is stored in write_addrs.
To fix this, only allow random values up to 31.
Change:
write_addrs[k] = $urandom_range(1, NUM_ARCH_REGS);
to:
write_addrs[k] = $urandom_range(1, NUM_ARCH_REGS-1);
Here is a complete example to demonstrate the problem:
module tb;
localparam int NUM_ARCH_REGS = 32;
logic [$clog2(32)-1:0] write_addrs [2];
initial begin
repeat (100) begin
for (int k=0; k<2; k++) begin
write_addrs[k] = $urandom_range(1, NUM_ARCH_REGS);
$write("write_addrs[%0d]=%02d ", k, write_addrs[k]);
end
$display;
end
end
endmodule
The problem you see is not specific to ModelSim; I am able to see it on 2 other simulators.

"Illegal reference to net " error in systemverilog - trying to design simple arbitrer

Here is the code I have for simple arbitrer
module arbiter(clk,rst,req,grnt,req_val);
input clk;
input rst;
input [3:0] req;
input [3:0] req_val;
output [3:0] grnt;
int j;
int i;
parameter A = 2'd0;
parameter B = 2'd1;
parameter C = 2'd2;
parameter D = 2'd3;
logic [1:0] current_state;
logic [1:0] next_state;
always_comb
begin
case (current_state)
D:
begin
grnt = 4'b1000;
j = 0;
for (i = 0; i<4;i++) begin
if (req[(j+i) % 4 ] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
A:
begin
j = 1;
grnt = 4'b001;
for (i = 0; i<4;i++) begin
if (req[(i+j) % 4] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
B:
begin
j = 2;
grnt = 4'b0010;
for (i = 0; i<4;i++ ) begin
if (req[(i+j) % 4] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
C:
begin
j = 3;
grnt = 4'b0100;
for (i = 0; i<4;i++ ) begin
if (req[(i+j)% 4] == 1)
break;
end
case (i)
0: next_state = A;
1: next_state = B;
2: next_state = C;
3: next_state = D;
endcase
end
endcase
end
endmodule
always_ff#(posedge clk)
begin
current_state <= next_state;
end
endmodule
and I get the following error:
arbitrer.sv(21): (vlog-2110) Illegal reference to net "grnt".
and
arbitrer.sv(87): near "always_ff": syntax error, unexpected always_ff, expecting class.
So whats wrong with grnt ? I cant assign directly to a module output ?
There are two problems with your code.
You have used endmodule statement twice in your code. Just comment out one at line number 86.
You haven't define a data type for grnt variable, so by default it's a wire and wire can't be used in always block, so declare it as a reg/logic.