Rewrite long xor statement - system-verilog

Look at the following statement. c_r gets assigned an xor versioned of all c[k].
always_ff # (posedge clk_i)
begin
for(k = 0; k < 16; k++)
c_r[k*8 +: 8] <= c[k][0] ^ c[k][1] ^ c[k][2] ^ c[k][3] ^ c[k][4] ^ c[k][5] ^ c[k][6] ^ c[k][7] ^ c[k][8] ^ c[k][9] ^ c[k][10] ^ c[k][11] ^ c[k][12] ^ c[k][13] ^ c[k][14] ^ c[k][15];
end
The design works, however is there a possibility to refactor the statement for easier maintenance and readability?
Note: c is defined as logic [7:0] c[16][16];

I would propose the following:
logic [16*8-1:0] c_r, next_c_r;
logic [7:0] c[16][16];
always_comb begin
next_c_r = '0;
foreach(c[idx0,idx1]) begin
next_c_r[idx0*8 +: 8] ^= c[idx0][idx1];
end
end
always_ff # (posedge clk_i)
begin
c_r <= next_c_r;
end
The foreach will iterate through all selected indexes. See IEEE Std 1800-2012 § 12.7.3 The foreach-loop for full syntax usage and functionality. ^= is a binary bitwise assignment operators, refer to IEEE Std 1800-2012 § 11.4 Operator descriptions. There are various code examples for foreach and ^= throughout the LRM.

You could try using a for loop inside to compute the XOR result and assign that to the c_r slice:
always_ff # (posedge clk_i)
begin
for(int k = 0; k < 16; k++) begin
logic [7:0] xor_result;
for (int i = 0; i < 16; i++)
xor_result ^= c[k][i];
c_r[k*8 +: 8] <= xor_result;
end
end
I'm not sure how well this will synthesize with your tool, but I've seen my colleagues use these kind of tricks (in VHDL) all the time.

Reduction operators are useful for this, a short example:
wire result;
wire [3:0] bus;
//assign result = bus[0] ^ bus[1] ^ bus[2] ^ bus[3];
assign result = ^bus;
So the unary ^ collapses the bus to a single bit, this also works for & and |.
In your case I believe that this should work:
always_ff # (posedge clk_i)
begin
for(k = 0; k < 16; k++)
c_r[k*8 +: 8] <= ^c[k];
end
If this is not possible embedding a second loop (which is extracted to a combinatorial section):
logic [15:0] parity_bus;
always_comb begin
for(k = 0; k < 16; k++) begin
parity_bus[k] = 1'b0;
for(int i = 0; i < 16; i++) begin
parity_bus[k] = parity_bus[k] ^c[k][i];
end
end
end
always_ff # (posedge clk_i) begin
for(k = 0; k < 16; k++) begin
c_r[k*8 +: 8] <= parity_bus[k];
end
end
You are effectively describing 16 sets of XOR logic in parallel.

Related

How do I vary the lower index of a variable assignment?

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.

SystemVerilog X propagation issue

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.

NBA assignment of $urandom

Can $urandom be NBA assigned in a for loop to an unpacked array of variables?
module tb();
logic clk [2];
initial clk[0] = 0;
always clk[0] = #1ns !clk[0];
for (genvar i = 1; i < 2; i++)
assign #(1ns/2) clk[i] = clk[i-1];
int tmp [2] [8];
always # (posedge clk[0]) begin
foreach (tmp[0][i]) begin
/*int m;
m = $urandom(); // SECTION 1 - using this code works (commenting out SECTION 2)
tmp[0][i] <= m;*/
tmp[0][i] <= $urandom(); // SECTION 2
end
#1ns;
foreach (tmp[0][i]) begin
$display("%1d", tmp[0][i]);
end
$finish();
end
for (genvar i = 1; i < 2; i++) begin
always_ff # (posedge clk[i]) begin
tmp[i] <= tmp[i-1]; // SECTION 3 (just removing this works too)
end
end
endmodule
Using Cadence tools (xrun 17.09-v002), I get all 8 of tmp[0] ints assigned the same value.
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
-2147414528
Can someone confirm whether this code is legal?
I have spoken to Cadence and been told this:
R&D’s response.
This use model of having $urandom call inside a non-blocking assignment is wrong.
The scheduling semantics of System Verilog dictates that the RHS is calculated and sampled once in the "inactive region" and then in the "NBA region" it's assigned the ALL of the elements of the foreach at the same time!
There is no difference in calling $urandom in a procedural loop versus serially calling $urandom multiple times. Your code gives the desired results in several tools, including Cadence's on EDAPlayground.com. Perhaps you are not showing is part of your problem. It always helps to show an MCVE, like
module top;
int tmp [2] [8];
bit clk;
initial begin
#1 clk=1;
#1 $display("%p",
tmp[0]);
end
always # (posedge clk) begin
foreach (tmp[,i]) begin
tmp[0][i] <= $urandom();
end
end
endmodule

Assigning value to a specific bit in 2D unpacked array[system-verilog]

I am trying to assign value on a specific bit of a 2D array(code[i][k]). This is a net type. But the value not being assigned.reg [3:0] code[0:3] gets unknown logic value 'X'.
Here is the code snippet
for(k=0;k<len;k++) begin
if (tc[k] == 1'b0) begin
code[i][k]= 1'b0;//----> value is not assigning as expected
end else begin
code[i][k]= 1'b1;// ---> value is not assigning as expected
end
end
codeLen[i] = len;
This for loop belongs to always block.Here, code and codeLen is output type.
output [3:0] code[0:3];
output [3:0] codeLen[0:3];
reg [3:0] code[0:3];
reg [3:0] codeLen[0:3];
codeLen[i] is assigned correctly but not the code[i][k]. I was trying to assign k-th bit of i-th byte.
Details
I have created a module which takes 6 inputs and returns two 2-dimensional arrays as output.
Here is the module:
`timescale 1ns / 1ps
module generate_code(CLK,nRST,nodes,nodeCount,characters,charCount,code,codeLen);
input CLK;
input nRST;
input integer nodeCount;//Total nodes in huffman tree
input integer charCount;//Total unique characters
input [6:0] characters[0:3];
input [23:0] nodes[0:6]; // total characters
output [3:0] code[0:3]; //[2:0] max code length <= total characters
output [3:0] codeLen[0:3];
reg [3:0] code[0:3];
reg [3:0] codeLen[0:3];
reg[3:0] tc;//temprary code reg. Holds a single bit in each byte
integer len=0;//code length
reg [23:0] tNode;
function void FindRoot;
reg [23:0] aNode;//local
integer i;
begin
for (i=0; i<nodeCount;i++) begin // For all nodes
aNode= nodes[i]; // aNode is current node
if (tNode[23:16] == aNode[14:7]) begin
tc[len]= tNode[15];//15th bit of nodes is codebit
len++;
//aNode is parent of tNode. Is it root?
if(aNode[23:16]==8'b0000_0000) begin//or frequency==nodeCount or node_id = 8'b1111_1111
return;
end else begin
tNode=aNode;
FindRoot();
end
end
end
end
endfunction
always#(posedge CLK or negedge nRST)
begin
if(!nRST) begin
// init
end
else begin
// Do code generation
integer i,j,k;
for(i= 0;i < charCount;i++) begin // For all character we are going to find codeword
for(j=0; j<nodeCount; j++) begin
tNode= nodes[j];//current node
if (characters[i] == tNode[6:0]) begin
// Got the character. tNode is a leaf nodes. Lets back track to root.
break;
end
end
len=0;
FindRoot();
for(k=0;k<len;k++) begin
if (tc[k] == 1'b0) begin
code[i][k]= 1'b0;
end else begin
code[i][k]= 1'b1;
end
end
//code[i]=2;
codeLen[i]= len;
end
end
end
endmodule
When I am assigning values to code[][], it is expected that following loop is executed. Though not all the bits of code[][] will be set. During debugging, when I come to assignment, I found that value is not being assigned (code[i][k] =1 or 0). Its getting unknown logic value X.
for(k=0;k<len;k++) begin
if (tc[k] == 1'b0) begin
code[i][k]= 1'b0;
end else begin
code[i][k]= 1'b1;
end
end
Testbench:
`timescale 1ns / 1ps
module generate_code_test;
// Inputs
reg CLK;
reg nRST;
integer nodeCount=7;//Total nodes in huffman tree
integer charCount=4;//Total unique characters
reg [6:0] characters[0:3];
reg [23:0] nodes[0:6]; // total characters
// Outputs
wire [3:0] code[0:3]; //[2:0] max code length <= total characters
wire [3:0] codeLen[0:3];
generate_code uut (
.CLK(CLK),
.nRST(nRST),
.nodes(nodes),
.nodeCount(nodeCount),
.characters(characters),
.charCount(charCount),
.code(code),
.codeLen(codeLen)
);
initial begin
// Initialize Inputs
CLK = 0;
nRST = 0;
nodeCount= 7;
charCount= 4;
characters[0]= 7'b110_0001;
characters[1]= 7'b110_0010;
characters[2]= 7'b110_0011;
characters[3]= 7'b110_0100;
nodes[0] = 24'b0000_0011_0_0000_0001_110_0001;
nodes[1] = 24'b0000_0011_1_0000_0010_110_0011;
nodes[2] = 24'b0000_0101_1_0000_0011_111_1111;
nodes[3] = 24'b0000_0101_0_0000_0100_110_0010;
nodes[4] = 24'b1111_1111_1_0000_0101_111_1111;
nodes[5] = 24'b1111_1111_0_0000_0110_110_0100;
nodes[6] = 24'b0000_0000_0_1111_1111_111_1111;
// Wait 10 ns for global reset to finish
#10;
nRST = 1;
end
parameter DELAY = 1;
always
#DELAY CLK = ~CLK;
endmodule
The code has been compiled in ModelSim 2016
I just started learning verilog. So I would really appreciate your help to show my mistakes.
Regards.
I got a fix for my problem. Not all the bits of code[][] has been set. This leads to unknown logic value in code[][] even after setting the bit. It gets solved after initializing all the bits of code[][] in always block.

Is the ++ operator in System Verilog blocking or non-blocking?

Good coding convention says that we should use blocking assignments in a combinational block, and non-blocking assignments in a sequential block. I want to use the ++ operator in a combinatorial block, but I don't know if it is blocking. So is this code:
input [3:0] some_bus;
logic [2:0] count_ones;
always_comb begin
count_ones = '0;
for(int i=0; i<4; i++) begin
if(some_bus[i])
count_ones++;
end
end
equivalent to this:
input [3:0] some_bus;
logic [2:0] count_ones;
always_comb begin
count_ones = '0;
for(int i=0; i<4; i++) begin
if(some_bus[i])
count_ones = count_ones + 1;
end
end
or this:
input [3:0] some_bus;
logic [2:0] count_ones;
always_comb begin
count_ones = '0;
for(int i=0; i<4; i++) begin
if(some_bus[i])
count_ones <= count_ones + 1;
end
end
I did look in the 1800-2012 standard but could not figure it out. An answer that points me to the appropriate section in the standard would be appreciated.
According to section 11.4.2 of IEEE Std 1800-2012, it is blocking.
SystemVerilog includes the C increment and decrement assignment operators ++i , --i , i++ , and i-- . These do not need parentheses when used in expressions. These increment and decrement assignment operators behave as blocking assignments.