Generate Conditional Assignment Statements in Verilog - 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

Related

Reduction or with stride

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).

Interconnect modules in for loop with different connectivity on some ports between different instances

Is it possible to instantiate a module in a for loop and change some port connectivity between different instances using an if statement?
Something like:
genvar g_i;
generate
for (g_i = 0; g_i < PWLINK_NUM; g_i++) begin : pwrlink
pdndlvrlnlpwrlinkvert_cbb pdndlvrlnlpwrlink_cbb(
if (g_i == 0) begin
.dftmeasen(pwr_dftmeasen),
end
else begin
.dftmeasen(1'b0),
end
.bldr_en(bldr_en[g_i]),
.bldr_mode(bldr_mode[g_i]),
.bldr_strength(bldr_strength[g_i]),
.hven(hvenout[g_i]),
.legacy_mode_en(legacy_mode_en[g_i]),
.force_on(force_on[g_i]),
.pwrup(pwrup[g_i]),
end
endgenerate
I get a compile error when I try to use if-else inside a generate for loop that way.
One way to do this is to declare a new signal and connect it to the instance port just like all the other ports:
wire [PWLINK_NUM-1:0] dftmeasen = { {(PWLINK_NUM-1){1'b0}}, pwr_dftmeasen};
genvar g_i;
generate
for (g_i = 0; g_i < PWLINK_NUM; g_i++) begin : pwrlink
pdndlvrlnlpwrlinkvert_cbb pdndlvrlnlpwrlink_cbb (
.dftmeasen (dftmeasen[g_i]),
.bldr_en (bldr_en [g_i]),
One possibilty is to define a temp signal for dftmeasen differently for differnt iterations, like int the following. tmp is defined as a wire for iteration 0 and as a parameter for the rest. The only secret is to have named blocks in the if statement with the same name in both paths. I used i for the name.
for (genvar g_i = 0; g_i < PWLINK_NUM; g_i++) begin : pwrlink
if (g_i == 0) begin: i // <<
wire tmp = pwr_dftmeasen;
end: i
else begin: i // <<
parameter bit tmp = 0;
end: i
pdndlvrlnlpwrlinkvert_cbb pdndlvrlnlpwrlink_cbb(
.dftmeasen(i.tmp), // i.tmp
.bldr_en(bldr_en[g_i])
);
end

How to simplify code using a temporal int variable

I want CODE 1 and CODE 2 to do the same
module testModule #( parameter LEN = 4,
parameter logic [0:0] OPTION = 1'b0 )
(
input Clk,
input [ 7:0][LEN-1:0] DataIn,
input [ 7:0][LEN-1:0] Factor,
output [15:0][LEN-1:0] DataOut_1,
output [15:0][LEN-1:0] DataOut_2
);
// CODE 1
always_ff #(posedge Clk) begin
for (int i = 0; i < LEN; i++) begin
if (OPTION == 1'b0) begin
DataOut_1[i] <= DataIn[i] * Factor[0];
end else begin
DataOut_1[i] <= DataIn[i] * Factor[i];
end
end
end
// CODE 2
always_ff #(posedge Clk) begin
for (int i = 0; i < LEN; i++) begin
int select = (OPTION == 1'b0) ? 0 : i;
DataOut_2[i] <= DataIn[i] * Factor[select];
end
end
endmodule
OPTION can be either 0 of 1.
But I get the following errors in CODE 2 in line
int select = (OPTION == 1'b0) ? 0 : i;
Local static variable with initializer requires 'static' keyword
automatic variable illegal in static variable initializer
I don't want to simplify the for loop because the in my original code I need it
This question is a variant on this other but I didn't want to change the original code question
You have a couple of issues there:
you cannot assign to a net inside an always block. DataOut_1/2 are declared as nets. So, you should declare them as regs at minimum:
output reg [15:0][LEN-1:0] DataOut_1,
output reg [15:0][LEN-1:0] DataOut_2
All variables defined in the module are static by nature. Except in some cases. The i defined in the 'for' loop is automatic. Therefore you cannot use it as an initializer to a static variable. You need to declare 'select' as automatic:
automatic int select = (OPTION == 1'b0) ? 0 : i;

System Verilog Loops

Im currently working on the Shift-Add Algorithm (32x32 bit Multiplication) in System Verilog. System Verilog cant find any error and my code is working correctly according to GTKwave. When I synthesize my circuit with yosys, Latches will be added. And that is the Problem. I dont want Latches in my Circuit. Heres my Code:
module multiplier(
input logic clk_i,
input logic rst_i,
input logic start_i,
input logic [31:0] a_i,
input logic [31:0] b_i,
output logic finished_o,
output logic [63:0] result_o
);
typedef enum logic [1:0] { STATE_A, STATE_B} state_t;
state_t state_p, state_n;
logic [63:0] fin_res;
logic [63:0] tmp;
logic rst_flag;
integer i;
always #(posedge clk_i or posedge rst_i) begin
if (rst_i == 1'b1) begin
state_p <= STATE_B;
end
else begin
state_p <= state_n;
end
end
always #(*)begin
state_n = state_p;
case (state_p)
STATE_A: if (start_i == 0) state_n = STATE_B;
STATE_B: if (start_i == 1) state_n = STATE_A;
default: state_n = state_p;
endcase
end
always #(*) begin
case (state_p)
STATE_A: begin
rst_flag = 1;
fin_res = 0;
finished_o = 0;
tmp = 0;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
default: begin
finished_o = 0;
result_o = 0;
end
endcase
end
endmodule
After spending 2 days only with debugging and not finding any mistake I would like to ask if u could help me. I am assigning every output (at least I think so). So where is my mistake? Is it the for loop? But what would be wrong with it? Thanks in advance for your help :)
Some useful Information for the Code-Snippet: start_i is the starting signal. If this is set to 1 the multiplication should be started. finished_o is the finish flag. If this is set to 1 the CPU will know that the computation is completed. a_i and b_i are the inputs which should be multiplied. result_o is the result of the multiplication which can be read when finished_o is set to 1.
According to yosys i get the following latches:
64 DLATCH_N
64 DLATCH_P
I think something may be wrong with fin_res in the for loop cause that logic variable is exactly 64 bits long as are the Latches
From the comment you have a bunch of variables which are not assigned in the second case statement causing synthesis to generate latches. To avoid it you need to assign all the vars in all branches of the case statement and conditional statements recursively.
However, if there is a default value you can assign to all of them, you can use a pattern similar to the one from the second always block, just assigning default values before the 'case' statement. This way you do not even need the default clause and you can get rid of it in the second always block as well.
always #(*) begin
// set default values
rst_flag = 0;
fin_res = 0;
finished_o = 0;
tmp = 0;
result_o = 0;
case (state_p)
STATE_A: begin
rst_flag = 1;
for (i = 0; i < 32; i = i + 1) begin
if (a_i[i] == 1'b1) begin
tmp = b_i;
tmp = tmp << i;
fin_res = fin_res + tmp;
end
end
end
STATE_B: begin
result_o = fin_res;
// are you sure that you do not need a latch here?
if (rst_flag == 1) finished_o = 1;
if (start_i == 1) finished_o = 0;
end
// you do not need 'default' here.
endcase
end
My fixes will cause combinational behavior and should get rid of latches in synthesis, but it does not look like they will behave as you expected. It looks like you really need a latches here.
rst_flag must be a latch. You set it in STATE_A and use it in STATE_B. It has to keep the value between states. This is a latch behavior.
In STATE_B you change finished_o only if some of conditions met. What happens if the rst_flag and start_i are both 0. do you want finished_o to be 0 or the previous value? In the latter case you need a latch.
How about fin_res ? What do you want to do with it in other states? keep previous value (latch) or have a default value (no latch).
...

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.

Resources