Reduction or with stride - verilog

I'd like to make an or of some bits, but they are not on a contiguous array. See |ack[i-1:0][j] in the following example, where | is the bitwise reduction or.
module cb #(
parameter PORTS = 4
)(
input dest[PORTS][PORTS],
output ack[PORTS][PORTS]
);
generate
genvar i, j, used[PORTS];
for ( i = 0; i < PORTS; i++ )
begin
for ( j = 0; j < PORTS; j++)
begin
assign ack[i][j] = dest[i][j] && ! (|ack[i-1:0][j]);
end
end
endgenerate
endmodule
In this concrete case, what I really want is for the ack[i][j] bit to be 1 for the first dest[i][j] that is 1 in each "column".
Obviously, this gives a "range not allowed in a prefix" error. How could I implement this behaviour?

You can use an auxiliary signal, I guess this is what you tried to do with the genvar used[PORTS], genvars are processed during compilation time so they can't hold values that depends on the inputs, this is why we must use a signal.
used[i][j] is will iteratively compute ack[0][j] | ... | ack[i-1][j]
module cb #(
parameter PORTS = 4
)(
input dest[PORTS][PORTS],
output ack[PORTS][PORTS]
);
logic used[PORTS][PORTS];
generate
genvar i, j;
for ( i = 0; i < PORTS; i++ )
begin
for ( j = 0; j < PORTS; j++)
begin
assign used[i][j] = i == 0 ? 1'b0: ack[i][j] | used[i-1][j];
assign ack[i][j] = dest[i][j] && ! used[i-1][j];
end
end
endgenerate
endmodule

Generate block just cause creation of 16 separate assignments in your case. they do not make much sense here. There is a simpler solution with a single procedural block.
module cb #(
parameter PORTS = 4
)(
input dest[PORTS][PORTS],
output logic ack[PORTS][PORTS]
);
always #* begin
logic flag;
flag = 0;
for ( int i = 0; i < PORTS; i++ ) begin
for ( int j = 0; j < PORTS; j++) begin
if (dest[i][j] == 1'b1)
flag = 1;
ack[i][j] = flag;
end
end
end
endmodule
You set flag when dest condition is right. It is persistent till the end of the block, setting value of ack. It works according to your description.

I ended up combining both answers to get the following code:
module cb #(
parameter PORTS = 4
)(
input dest[PORTS][PORTS],
output ack[PORTS][PORTS]
);
logic used[PORTS][PORTS];
always_comb begin
logic used[PORTS];
// First resetting to 0
for ( int j = 0; j < PORTS; j++ )
used[j] = 0;
for ( int i = 0; i < PORTS; i++ )
begin
for ( int j = 0; j < PORTS; j++)
begin
ack[i][j] = dest[i][j] && !used[j];
used[j] = used[j] | ack[i][j];
end
end
end
endmodule
This code takes into account that at most one port can be used “per column” (and not just one at all).

Related

How to access Verilog genvar generated instances and their signals

I need to initialize arrays in generated instances via generate block in Verilog. I'm trying to use the syntax below, however, I get an error as
External reference foo[0].bar.array[0] remains unresolved.
in Xilinx ISE.
integer i, j;
initial begin
// initialization of arrays
for(i=0; i<(2**7); i=i+1) begin
valid_array[i] = 0;
for(j=0; j<N; j=j+1) begin
foo[j].bar.array[i] = 0;
end
end
end
This is my generate block:
genvar jj;
generate
for(jj = 0; jj < N; jj = jj + 1) begin : foo
Memory_v3
#(
.ADDRESS_WIDTH(INDEX),
.DATA_WIDTH(TAG)
) bar
(
.clock(clock),
.we(we),
.addr_a(addra),
.addr_b(addrb),
.din(din),
.dout(dout)
);
end
endgenerate
What is the correct way to do this?
the problem is that foo block gets resolved at compile time. So, the names like foo[0], foo[1] are pre-generated and are compile-time names, they not work with dynamic index resolution at run-time. Therefore foo[j] will not work.
the solution in this case is to use another generate block to initialize them. Something like the following.
generate
for(jj = 0; jj < N; jj = jj + 1) begin : foo_init
initial begin
// initialization of arrays
for(i=0; i<(2**7); i=i+1) begin
foo[jj].bar.array[i] = 0;
end
end
end
endgenerate
Same story is with array of instances.
FOO bar[3:0](); // array of instances
int i,j;
generate
for(jj = 0; jj < 4; jj = jj + 1) begin : foo_init
initial begin
for(i=0; i<(2**7); i=i+1) begin
bar[jj].array[i] = 0;
end
end
end
endgenerate
BTW, in system verilog you can avoid using generate/endgenerate pairs:

Two genvar in single genarte for loop?

Is below sort of generate loop is valid in system verilog.
genvar i,j;
for (i=0,j=5; i<5 && j<10; i++,j++) begin:M1
integer t;
initial begin
t = i*j;
end
endgenerate
Nope. I'm not even sure what the behavior of this code should be, or in what order they execute.
genvar i,j;
for (i = 0; i <5; i++) begin
for (j = 5; j < 10; j++) begin
$display("%d", i*j);
end
end
you don't need 'endgenerate' in the end.
You cannot do much with genvars in your example.
The following code mimics what you asked for, but it might not work with all simulators. It works with synopsys vcs but does not work with icarus.
module g;
genvar i;
for (i=0; i<5; i++) begin:M
if (i == 0) begin:B
parameter j = 5;
end
else begin:B
parameter j = g.M[i-1].B.j + 1;
end
integer t;
initial begin
t = i*B.j;
$display(i, B.j, t);
end
end // block: M
endmodule // g
the idea is to declare the parameter j inside the generate loop so that its value is an increment of the value declared in the previous iteration. You need to add a named block 'B' to declare conditionally.

Generate Conditional Assignment Statements in Verilog

I'm trying to create a simple crossbar style interconnect between N masters and M slaves.
Say if I have 2 Masters and 2 Slaves, the crossbar connects them as follows:
// Master - to - Slave
assign s[0].addr = (gnt[0] == 1) ? m[0].addr : ( (gnt[1] == 1) ? m[1].addr : 'b0; )
assign s[0].data = (gnt[0] == 1) ? m[0].data : ( (gnt[1] == 1) ? m[1].data : 'b0; )
// Slave - to - Master
assign m[0].resp = (sel[0] == 1) ? s[0].resp : ( (sel[1] == 1) ? s[1].resp : 'b0; )
Is there a way to generate the above assign statements if number of master and slaves are parameters? Or is there any other way to accomplish what I'm trying to do? Any help would be appreciated.
You can use generate blocks in this case:
typedef struct {
integer addr;
integer data;
integer resp;
} sigs;
module crossbar;
parameter int num_masters = 3;
parameter int num_slaves = 3;
sigs s[num_slaves];
sigs m[num_masters];
bit gnt[num_masters];
genvar i, j;
// master to slave loop
for (i = 0; i < num_slaves; i++) begin
wire[31:0] addr;
for (j = 0; j < num_masters; j++) begin
assign addr = gnt[j] == 1'b1 ? m[j].addr : 'z;
end
assign addr = gnt == '0 ? '0 : 'z;
assign s[i].addr = addr;
end
endmodule
What I illustrated here are only the assigns for addr. You'd had to have data and any other master to slave signals to this loop and create another loop where you loop over masters first and then slaves to assign resp and any other slave to master signals.
I've used an intermediate wire for addr to be able to have an assign statement per master. This way, when a master is granted it will drive the wire, otherwise it will drive high impedance. It's therefore vital to not grant two or more masters at the same time.
It isn't exactly what you have, but you can replace the multiple assigns with a priority encoding scheme if you want to allow multiple masters at the same time.
The muxing logic can be scaled withing a combinational block. The example below defaults in assignments to zero then updates the assignments with LSB priority.
parameter NUM_MASTERS=5, NUM_SLAVES=3;
/*
* ...
*/
for ( genvar s_idx = 0; s_idx < NUM_SLAVES; s_idx++ ) begin
alwasy_comb begin
// default value
s[s_idx].addr = '0;
s[s_idx].data = '0;
// update with lsb priority
for ( int idx = NUM_MASTERS-1; idx >= 0; idx-- ) begin
if (gnt[idx]) begin
s[s_idx].addr = m[idx].addr;
s[s_idx].data = m[idx].data;
end
end
end
end
for ( genvar m_idx = 0; m_idx < NUM_MASTERS; m_idx++ ) begin
alwasy_comb begin
// default value
m[m_idx].resp = '0;
// update with lsb priority
for ( int idx = NUM_SLAVES-1; idx >= 0; idx-- ) begin
if (sel[idx]) begin
m[m_idx].resp = s[idx].resp;
end
end
end
end

How to test primality in Verilog?

I have the Verilog code shown below, and if I try to compile it I get an error message. The point is that I'm trying to manipulate an input, which as long as I know cannot be done in Verilog. The point is that I need check the following condition in Verilog:
static int prime(unsigned long long n)
{
unsigned long long val = 1;
unsigned long long divisor = 5;
if (n == 2 || n == 3)
return 1;
if (n < 2 || n%2 == 0 || n%3 == 0)
return 0;
for ( ; divisor<=n/divisor; val++, divisor=6*val-1)
{
if (n%divisor == 0 || n%(divisor+2) == 0)
return 0;
}
return 1;
}
At the moment I have the following code:
module prime(clk, rst, start, A, ready, P);
input clk, rst, start;
input [7:0] A;
output ready, P;
reg ready, P;
wire [7:0] divisor;
assign divisor = 5;
wire [7:0] val;
assign val = 1;
always # (posedge clk or posedge rst) begin
if (!rst) begin
P <= 0;
end
else if (start) begin
case (A)
0 : P <= 1;
1 : P <= 1;
2 : P <= 1;
3 : P <= 1;
endcase
if (A%2 == 0 && A != 2) begin
P <= 0;
end
else begin
for( ; divisor <= A/divisor; val=val+1, divisor=6*val-1) begin
if (A%divisor == 0 || A%(divisor+2) == 0) begin
P <= 0;
end
end
// need to set P to 1
end
end
end
endmodule
Please also note I need to test primes in the form of 6n+1 or 6n-1, and I also need to assume in my code that 0 and 1 are also primes.
If I try the above code I get an error message saying:
Enhanced FOR loop is not enabled for verilog
If anyone can help me solve the error and finish my logic in Verilog, I would be glad.
The Verilog BNF does not allow empty or compound statements in for(;;). Change the file to *.sv to compile it under SystemVerilog rules. Otherwise change your for loop statement to have simple statements
for( divisor =5; divisor <= A/divisor; divisor=6*val-1) begin
if (A%divisor == 0 || A%(divisor+2) == 0) begin
P <= 0;
end
val++;
end
Also, you can't make procedural assignments to wires. make them variables.

How to write a Verilog function that determines if all elements in an array are equal?

Let's say I have N registers and I want a function that checks if all register contents are equal. How do I write that without having to spell out every single element?
function equal (input [0:N-1][width-1:0] in);
equal = (???) ? 1'b1 : 1'b0;
endfunction
A simple for loop is one way:
module tb;
parameter N = 8;
parameter width = 4;
reg [0:N-1][width-1:0] arr;
initial begin
for (int i=0; i<N; i++) arr[i] = 5;
$display(equal(arr));
for (int i=0; i<N; i++) arr[i] = 2*i;
$display(equal(arr));
end
function equal (input [0:N-1][width-1:0] in);
for (int i=1; i<N; i++) begin
if (in[i] !== in[0]) return 0;
end
return 1;
endfunction
endmodule
Output:
1
0
module tb;
parameter W = 8;
parameter N= 4;
logic [N-1:0][W-1:0] in0, in1;
logic res;
initial begin
in0 = {8'd6,8'd6,8'd6,8'd6};
in1 = {8'd6,8'd6,8'd55,8'd6};
res = equal(in0);
$display(res);
res = equal(in1);
$display(res);
end
function logic equal(input logic [N-1:0][W-1:0] in);
equal = (in === {N{in[0]}}) ? 1 : 0;
endfunction
endmodule
Modelsim results:
# 1
# 0

Resources