VVP can't compile - system-verilog

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

Related

How to pass a reference array of variables to task?

I am trying to pass a reference array of variables. It works fine with a reference to variable, but not with an array of variables. The goal with the task is to be able to take an array of variables, and read them on every clock edge.
So this code does not work
module tb;
logic clock = 0;
logic a = 0;
logic b = 0;
task automatic read_vars(ref logic clock, input int clock_edges = 10,
const ref logic signal_array[]);
repeat (clock_edges) begin
#(posedge clock) $display("#TIME: %t Clock edge", $time);
for (int i = 0; i < signal_array.size(); i++) begin
$display("Variable %0d: %0b", i, signal_array[i]);
end
end
endtask
always begin
#1 clock = 1;
#1 clock = 0;
end
always begin
#3 b = 1;
#3 b = 0;
end
always begin
#7 a = 1;
#7 a = 0;
end
initial begin
fork
read_vars(.clock(clock), .signal_array({a, b}));
join_none
#1000;
$finish();
end
endmodule
I get the following error
read_vars(.clock(clock), .signal_array({a, b}));
|
xmvlog: *E,BADRFA (tb.sv,25|45): invalid ref argument usage because actual argument is not a variable. [SystemVerilog].
module worklib.tb:sv
But this code works.
module tb;
logic clock = 0;
logic a = 0;
logic b = 0;
task automatic read_vars(ref logic clock, ref logic a, ref logic b, input int clock_edges = 10);
repeat (clock_edges) begin
#(posedge clock) begin
$display("#TIME: %t Clock edge", $time);
$display("a = %b ", a);
$display("b = %b ", b);
end
end
endtask
always begin
#1 clock = 1;
#1 clock = 0;
end
always begin
#3 b = 1;
#3 b = 0;
end
always begin
#7 a = 1;
#7 a = 0;
end
initial begin
fork
read_vars(.clock(clock), .a(a), .b(b));
join_none
#1000;
$finish();
end
endmodule
What you are trying to do is impossible in verilog.
First of all, having a reference to an array will not help in solving the issue. Arrays contain values of something. So creation of an array with {a,b} will just copy values of the variables into the array and updating variables will not be reflected in any case.
What you are after is an array of references to variables, which is impossible in a verilog.
However, class variables are always reference. So, you can wrap your vars in a class in test bench. Here is a modified example of yours:
class V;
logic val;
endclass:V
module tb;
V a = new;
V b = new;
V arr[] = '{a, b};
logic clock = 0;
//logic a = 0;
//logic b = 0;
task automatic read_vars(ref logic clock, input int clock_edges = 10,
V signal_array[]);
repeat (clock_edges) begin
#(posedge clock) $display("#TIME: %t Clock edge", $time);
for (int i = 0; i < signal_array.size(); i++) begin
$display("Variable %0d: %0b", i, signal_array[i].val);
end
end
endtask
always begin
#1 clock = 1;
#1 clock = 0;
end
always begin
#3 b.val = 1;
#3 b.val = 0;
end
always begin
#7 a.val = 1;
#7 a.val = 0;
end
initial begin
fork
read_vars(.clock(clock), .signal_array(arr));
join_none
#1000;
$finish();
end
endmodule

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

system verilog: for loop index variable issue

`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

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.