I want to count the number of ones in a packed array. I came up with the following code:
https://www.edaplayground.com/x/2Va6
I think it can be done easier. Any suggestion?
typedef bit bit6_t[5:0];
module test_rand;
bit [5:0] mask_packed;
bit mask_packed_bit[5:0];
int mask_unpacked[5:0];
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
mask_packed_bit = bit6_t'(mask_packed);
foreach (mask_packed_bit[i]) begin mask_unpacked[i] = int'(mask_packed_bit[i]); end
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("mask_unpacked = %p",mask_unpacked);
$display("mask_unpacked.sum = %p",mask_unpacked.sum());
$display("*********************************");
end
endmodule
1) For plain verilog code:
Your last implicit $cast to 'int is unnecessary. Since you only want the sum, you can:
typedef bit bit6_t[5:0];
module test_rand;
bit [5:0] mask_packed;
bit mask_packed_bit[5:0];
int sum = 0;
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
mask_packed_bit = bit6_t'(mask_packed);
foreach (mask_packed_bit[i]) begin sum += mask_packed_bit[i]; end
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("mask_packed_bit = %p",mask_packed_bit);
$display("sum = %p",sum);
$display("*********************************");
end
endmodule
Working example: https://www.edaplayground.com/x/5ZTW
2) If you are using systemverilog, you can use the simple $countones function.
module test_rand;
bit [5:0] mask_packed;
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("countones = %p", $countones(mask_packed));
$display("*********************************");
end
endmodule
Working example: https://www.edaplayground.com/x/2Nsd
You can try the following
typedef bit bit6_t[5:0];
module test_rand;
bit [5:0] mask_packed;
bit6_t mask_unpacked;
initial begin
mask_packed = $urandom_range(((2**6)-1),0);
mask_unpacked = bit6_t'(mask_packed);
$display("*********************************");
$display("mask_packed = %p",mask_packed);
$display("mask_unpacked = %p",mask_unpacked);
$display("mask_unpacked.sum = %p",mask_unpacked.sum() with (int'(item)));
$display("*********************************");
end
endmodule
Working example: https://www.edaplayground.com/x/5cXx
Related
I want to make an assignment to a variable with a variable lower index. This is what I want to do:
int i;
logic [63:0] data;
i = someCalculatedNumber;
data[63:(i*8)] = 'h0;
I know this won't compile. What is the best method to make this assignment?
If you are looking to zero-out the LSBs, then this should do it for you
data &= '1 << i*8;
or more readable
data = data & ('1 << i*8);
And if that's not exactly what you need, you can still use '1 << i*8 or its complement as a mask to select the portion of data you want to modify.
One way is to use a for loop:
module tb;
int i;
logic [63:0] data;
initial begin
data = '1;
$displayh(data);
i = 7;
for (int j=63; j>=(i*8); j--) data[j] = 0;
$displayh(data);
i = 2;
for (int j=63; j>=(i*8); j--) data[j] = 0;
$displayh(data);
end
endmodule
Output:
ffffffffffffffff
00ffffffffffffff
000000000000ffff
You can wrap the code in a function.
I'm having an issue with my SV code. I'm attempting to simulate a carry look ahead adder. However, when I look at my timing results
they show result has having an x propagated, as well as SUM.
Here is my SystemVerilog code
module fulladder (input logic i_bit1, i_bit2, i_carry,
output logic o_sum, o_carry);
assign o_sum = i_bit1 ^ i_bit2 ^ i_carry;
assign o_carry = (i_bit1 & i_bit2) | (i_carry & (i_bit1 ^ i_bit2));
endmodule
module carry_lookahead_adder
#(parameter WIDTH)
(input logic [WIDTH-1:0] i_add1,
input logic [WIDTH-1:0] i_add2,
output logic [WIDTH:0] o_result
);
logic [WIDTH:0] w_C;
logic [WIDTH-1:0] w_G, w_P, w_SUM;
//Generate full adders
genvar i;
generate for (i= 1; i<WIDTH; i++)
begin : f_loop
fulladder fi (
.i_bit1(i_add1[i]),
.i_bit2(i_add2[i]),
.i_carry(w_C[i]),
.o_sum(w_SUM[i]),
.o_carry()
);
end
endgenerate
genvar jj;
generate
for (jj=0; jj<WIDTH; jj++)
begin
assign w_G[jj] = i_add1[jj] & i_add2[jj];
assign w_P[jj] = i_add1[jj] | i_add2[jj];
assign w_C[jj+1] = w_G[jj] | (w_P[jj] & w_C[jj]);
end
endgenerate
assign w_C[0] = 1'b0; //No carry input
assign o_result = {w_C[WIDTH], w_SUM};
endmodule
and the testbench
module carry_lookahead_adder_tb (w_RESULT);
parameter WIDTH = 32;
logic [WIDTH-1:0] r_ADD_1 = 0;
logic [WIDTH-1:0] r_ADD_2 = 0;
output logic [WIDTH:0] w_RESULT;
carry_lookahead_adder #(.WIDTH(WIDTH)) carry_lookahead_inst
(
.i_add1(r_ADD_1),
.i_add2(r_ADD_2),
.o_result(w_RESULT)
);
initial
begin
$dumpfile("dump.vcd");
$dumpvars;
#10;
r_ADD_1 = 32'b00000000000000000000000000000000;
r_ADD_2 = 32'b00000000000000000000000000000001;
#10;
r_ADD_1 = 32'b00000000000000000000000000000010;
r_ADD_2 = 32'b00000000000000000000000000000010;
#10;
r_ADD_1 = 32'b00000000000000000000000000000101;
r_ADD_2 = 32'b00000000000000000000000000000110;
#10;
r_ADD_1 = 32'b00000000100000000000000000000101;
r_ADD_2 = 32'b00000000100000000000000000000110;
#10;
r_ADD_1 = 32'b11111111111111111111111111111111;
r_ADD_2 = 32'b11111111111111111111111111111111;
#10;
r_ADD_1 = 32'b00000000000000000000000000000000;
r_ADD_2 = 32'b00000000000000000000000000000001;
#10;
end
endmodule // carry_lookahead_adder_tb
Can anyone clue me into what may be causing this x? Sorry to post my full code; I'm just lost as to where the problem may be coming from.
Bit [0] of w_SUM is unknown because you are not driving it. Change the generate for loop so that the count starts from 0, not 1. Change:
generate for (i= 1; i<WIDTH; i++)
to:
generate for (i= 0; i<WIDTH; i++)
After this change, the x goes away.
The problem was that the for loop was not generating the right number of fulladder instances: you need 32, but you only got 31. There was no fulladder instance for you to connect w_SUM[0], i_add1[0], etc., to.
I'm designing a module that accepts multiple channels and outputs one channel.
Each channel consists of valid signal and data of some widths.
If a channel has valid data, the module should output that channel. If multiple channels have valid data, the module should output one of them (in my case, channel with highest index) and rests are dropped.
My simple implementation looks like this:
module test1 #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
input logic [DATA_WIDTH - 1 : 0] data_in [NUM_CHANNEL],
input logic valid_in [NUM_CHANNEL],
output logic [DATA_WIDTH - 1 : 0] data_out,
output logic valid_out
);
always_comb begin
valid_out = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (valid_in[i]) begin
valid_out = 1;
data_out = data_in[i];
end
end
end
endmodule
This works perfectly in both simulation and real circuit (FPGA).
However, channel can be complex type so I used interface like this:
interface channel #(
parameter DATA_WIDTH = 512
);
logic valid;
logic [DATA_WIDTH - 1 : 0] data;
modport in (
input valid,
input data
);
modport out (
output valid,
output data
);
endinterface // sub_csr_if
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (in[i].valid) begin
out.valid = 1;
out.data = in[i].data;
end
end
end
endmodule
Then, this code gets Nonconstant index into instance array 'sub_port'. error in ModelSim, and i is not a constant error in Quartus.
If I unroll the loop, it works but it becomes non-parametric code. (only works for fixed NUM_CHANNEL)
Why the latter one does not work, while the first one works flawlessly?
An array of instances (module or interface) is not a true array type. As your error message indicates, you cannot select a particular instance with a variable index. With a true array, every element is identical. Because of the way parameterization, defparam, and port connections work, each instance element could have differences. The elaboration process essentially flattens all hierarchy before simulation begins.
What you can do is use a generate construct to select your instance as follows
;
module test #(
parameter NUM_CHANNEL = 8,
parameter DATA_WIDTH = 512
) (
channel.in in[NUM_CHANNEL],
channel.out out
);
logic _valid[NUM_CHANNEL];
logic [DATA_WIDTH - 1 : 0] _data[NUM_CHANNEL];
for (genvar ii=0;ii<NUM_CHANNEL;ii++) begin
assign _valid[ii] = in[ii].valid;
assign _data[ii] = in[ii].data;
end
always_comb begin
out.valid = 0;
for (int i = 0; i < NUM_CHANNEL; ++i) begin
if (_valid[i]) begin
out.valid = 1;
out.data = _data[i];
end
end
end
endmodule
all,i need help.i encounter question about array data transaction.Please help me!
code is following.
packet is data class,and there is three queue,R,G,B,and in module "test",arith function 's return_data is no data. why?
question:though "into-arith" function,output tr_out is no data.
class packet # (int bit_depth =16);//packet class
bit [bit_depth-1:0] R[$];
bit [bit_depth-1:0] G[$];
bit [bit_depth-1:0] B[$];
endclass
//packet is data class
module test #(active_num=1920); //
packet in_tr [4];
initial begin
foreach(in_tr[i]) begin
in_tr[i] = new();
end
foreach(in_tr[j]) begin
for(int i=0;i<1920;i++) begin
in_tr[j].R.push_back(i);
end
end
process_in_tr;
end
task process_in_tr();
packet tr_out[4];
foreach(tr_out[i])begin
tr_out[i] = new();
end
tr_out[4] = into_arith(in_tr);
foreach(tr_out[j]) begin
foreach(tr_out[j].R[i]) begin
$display("%h",tr_out[j].R[i]);
end
end
endtask
function packet[4] into_arith(ref packet in_tr[4]);
packet tr_tmp[4];
foreach(tr_tmp[i]) begin
tr_tmp[i] = new();
end
for(int m=0;m<4;m++) begin
foreach(in_tr[m].R[i]) begin
tr_tmp[m].R.push_back(in_tr[m].R[i]);
tr_tmp[m].G.push_back(in_tr[m].G[i]);
tr_tmp[m].B.push_back(in_tr[m].B[i]);
end
end
return tr_tmp[4];
endfunction
endmodule
I couldn't event get this to compile in Questa, there are many syntax errors.
The three main problems are
The declaration of the function is an error. You must use a typedef when returning an aggregate type (in your case an unpacked array of packet#())
the assignment tr_out[4] = into_arith(in_tr); is illegal. You are trying to assign a unpacked array of 4 elements to the 5th element of an array, which doesn't even exist.
The return tr_tmp[4]; is also illegal. You are trying to return the non-existent 5th element of an array as the return value for a function that requires a 4-element array.
See all my corrections below:
class packet # (int bit_depth =16);//packet class
bit [bit_depth-1:0] R[$];
bit [bit_depth-1:0] G[$];
bit [bit_depth-1:0] B[$];
endclass
//packet is data class
module test #(active_num=1920); //
typedef packet#() packet4_t[4];
packet4_t in_tr;
initial begin
foreach(in_tr[j]) begin
in_tr[j] = new();
for(int i=0;i<1920;i++)
in_tr[j].R.push_back(i);
end
process_in_tr;
end
task process_in_tr();
packet4_t tr_out;
tr_out = into_arith(in_tr);
foreach(tr_out[j]) begin
foreach(tr_out[j].R[i]) begin
$display("%h",tr_out[j].R[i]);
end
end
endtask
function automatic packet4_t into_arith(ref packet4_t in_tr);
packet4_t tr_tmp;
foreach(tr_tmp[i]) begin
tr_tmp[i] = new();
tr_tmp[m].R = in_tr[m].R;
tr_tmp[m].G = in_tr[m].G;
tr_tmp[m].B = in_tr[m].B;
/* assigments above are the same as the foreach loop below
foreach(in_tr[m].R[i]) begin
tr_tmp[m].R.push_back(in_tr[m].R[i]);
tr_tmp[m].G.push_back(in_tr[m].G[i]);
tr_tmp[m].B.push_back(in_tr[m].B[i]);
end */
end
return tr_tmp;
endfunction
endmodule
I am trying to randomize an address which should be not fall in a previously allocated segment
suppose if I was allocated address 0, 10 ,40 , and the block length is 5,
when I randomized the address , it should not fall in the range of (0-4) ,( 10-14) , (40-44).
how can I constraint this in system verilog.
I tried a method but it is not working.
Here is my code:
constraint con {
foreach(keys[i]){
!(address inside {[keys[i]:keys[i]+BLOCK_SIZE]});
}
}
keys is array of address that were already alloted , generated address should not fall in the above ranges.
thanks
shiva
Your syntax seems correct to me. What issue do you see with it?
I tried the above and it works for me. See below code.
class t_constraints;
randc bit [2:0] addr; //using randc just to make all values appear.
int keys [2] = {0,4}; // Implies addr {0:1 and 4:5 should not assigned}
int BLOCK_SIZE = 1;
constraint con { foreach(keys[i])
{!(addr inside {[keys[i]:keys[i]+BLOCK_SIZE]});}
}
endclass: t_constraints
module tb_con;
t_constraints t_con;
initial begin
t_con = new();
repeat(8) begin
t_con.randomize();
$display("addr = %h",t_con.addr);
end
$finish;
end
endmodule: tb_con
Below is the log, It seems perfect.
addr = 3
addr = 6
addr = 7
addr = 2
addr = 2
addr = 3
addr = 7
addr = 6
$finish called from file "t_constraints.sv", line 26.
Sorry for not formatting properly. I am not able to answer after formatting. It gives me error saying code is not formatted properly.
EDIT:
If you want to consider the addr generated each time for the next randomization, use inline constraints in tb.
See below code
module tb_con;
t_constraints t_con;
int t_keys [$];
int T_BLOCK_SIZE;
initial begin
t_con = new();
repeat(3) begin // constraint solver cannot solve since after 3rd iteration there won't be any legal values.
t_keys = t_con.keys;
T_BLOCK_SIZE = t_con.BLOCK_SIZE;
t_con.randomize() with{
foreach(t_keys[i])
{ !(addr inside {[t_keys[i]:t_keys[i]+T_BLOCK_SIZE]});}
};
$display("addr = %h",t_con.addr);
t_con.keys.push_back(t_con.addr);
end
$finish;
end
endmodule: tb_con
NOTE: You must be careful not to iterate more than the possible values (here 3) else your simulation will exit with constraint inconsistency error.
It worked for me. Please show a complete testcase and the incorrect results you are getting.
class a;
rand bit [5:0] address;
bit [5:0] keys[] = {0,10,40};
int BLOCK_SIZE = 5;
constraint con {
foreach(keys[i]) {
!(address inside {[keys[i]:keys[i]+BLOCK_SIZE-1]}) ; }
}
endclass
module top;
a a_h;
initial begin
a_h = new;
repeat (200) begin
if (!a_h.randomize())
$error("randomize failed");
$display(a_h.address);
assert (!(a_h.address inside {[0:4],[10:14],[40:44]}));
end
end
endmodule // top