Verilog : Muliplication of Integer and parameter and for loop - verilog

When i am trying to compile following verilog RTL cadence simulator is throwing a error as illegal operand for constant expression.
RTL is:
module selection_logic( data_out, data_in , valid_info);
input [(number_of_channel * per_channel_data) - 1 : 0] data_in;
input [number_of_channel - 1: 0] valid_info;
output reg [number_of_channel - 1 : 0] data_in;
integer i;
always #(*)
begin
for (i = 0; i < number_of_channel; i = i + 1)
begin
if (valid_info[i])
data_out[(per_channel_data*(i+1)) - 1: per_channel_data*i] = data_in[[(per_channel_data*(i+1)) - 1: per_channel_data*i]
else
data_out[(per_channel_data*(i+1)) - 1: per_channel_data*i] = {per_channel_data{1'b0};
end
end
endmodule

Array slicing using the arrayName[MSB:LSB] require MSB and LSB to be constants. Instead, use the arrayName[start_bit +: WIDTH], where WIDTH is a constant and start_bit can be a variable. Refer to
"Indexing vectors and arrays with +:" and "What is `+:` and `-:`?"
data_out[per_channel_data*i +: per_channel_data] = data_in[per_channel_data*i +: per_channel_data];
If stuck with with Verilog-1995, then add a second for-loop and assign each bit individually:
for(i=0; i<per_channel_data; i=i+1) begin
for(j=0; j<per_channel_data; j=j+1) begin
if (valid_info[i])
data_out[per_channel_data*i+j] = data_in[per_channel_data*i+j];
else
data_out[per_channel_data*i+j] = 1'b0;
end
end

Related

Output port continuous assignment problem

I have the code below, which is an array of shift registers connected to each other.
i.e., Sin->sr1->sr2->...sr14->sr15->sr16->Sout.
module Array #(
parameter NCOL = 4,
parameter NROW = 4
)
(
input clk,
input reset,
input Sin,
output Sout
);
// NCOL * NROW shift registers
wire [NCOL - 1: 0] shift_reg [NROW - 1: 0];
genvar i, j;
/* Connected array of SRs */
generate
for (j = 0; j < NCOL; j=j+1) begin: sr_y
for (i = 0; i < NROW; i=i+1) begin: sr_x
sr sr_inst (
.clk(clk),
.reset(reset),
.Sin(shift_reg[i][j]),
.Sout(shift_reg[i+1][j])
);
end
end
// connect 4th SR in each column to the 1st SR in the next column
for (j = 0; j < NCOL - 1; j=j+1) begin: shift_y
assign shift_reg[0][j+1] = shift_reg[NROW-1][j];
end
endgenerate
/* Connect the shift register endpoints to the input and output of the module */
assign shift_reg[0][0] = Sin;
assign Sout = shift_reg[NROW-1][NCOL-1];
endmodule
module sr #(parameter WIDTH = 16)(
input clk,
input reset,
input Sin,
output Sout
);
reg [WIDTH-1:0] sr_data;
reg sout; /* Latched shift register output */
always #(posedge clk) begin
if (reset) begin
sr_data <= 16'd0;
end else begin
sr_data[0] <= Sin;
sr_data[WIDTH-1:1] <= sr_data[WIDTH-2:0];
end
end
always #(negedge clk) begin
if (reset == 1'b1) begin
sout <= 1'b0;
end else begin
sout <= sr_data[WIDTH-1];
end
end
assign Sout = sout;
endmodule
I got some errors (below) when trying to compile. I have declared the ports as wires, but I still have the same problem. Could you help solve the errors as I can't seem to see the issue?
warning: ignoring out of bounds l-value array access shift_reg[4].
error: Output port expression must support continuous assignment.
: Port 6 (Sout) of sr is connected to shift_reg[(i)+('sd1)][j]
You declared the signal as:
wire [NCOL - 1: 0] shift_reg [NROW - 1: 0];
When you plug in the parameter values, this resolves to:
wire [3:0] shift_reg [3:0];
This is an array of 4 elements (0 to 3), each of which is 4 bits wide.
The problem is this line inside the for loops:
.Sout(shift_reg[i+1][j])
When i is set to its maximum value of 3 in the loop, i+1 is 4, which resolves to:
.Sout(shift_reg[4][j])
But, there is no shift_reg[4] element of the array. That explains the warning message. You are selecting an element which is not in the array ("out of bounds").
I don't understand the error message, but I suspect it will go away if you fix the code that produces the warning.

How to assign variable pins to a port in verilog?

I have a 32-bit input port pins and a 32-bit input enable pin_en, and want to generate a 16-bit output selected by the enables. I wrote verilog like this, but seems there are some errors.
How can I fix it or any other way to achive? Thanks!
ps: No more than 16 pins selected by en, but maybe less.
input [31:0] pins;
input [31:0] pin_en;
output [15:0] actual_pins;
generate
genvar i;
localparam cnt = 0;
for(i = 0; (i < 'd32) & (cnt < 'd16); i = i + 'd1) begin : b1
if(pin_en[i]) begin
assign actual_pins[i] = pins[cnt];
cnt = cnt + 'd1;
end
end
if(cnt < 16)
assign actual_pins[16 : cnt] = 'b0;
endgenerate
I think that there are several errors in you code:
in generate blocks you cannot do any generation, based on the actual values of variables. The blocks are for the constant expressions only which could be resolved at compilation time, not at the run time. Also, you cannot modify anything in the generated blocks besides genvars. Paremeters (localparams) cannot be modified, so the cnt = cnt + 1 is just illegal there.
you messed up actual_pins and pins. by logic there should be actual_pins[cnt];
you use binary & operator, but you should have used logical && instead.
So, all your code should have been implemented in a run-time constructs, i.e., always blocks. You also need a trigger which will cause the always block to be evaluated. I created a small example where the always block is to be triggered by a clock.
module top (
input clk,
input [31:0] pins,
input [31:0] pin_en,
output reg [15:0] actual_pins
);
always #(posedge clk) begin
int cnt = 0;
int i;
for(i = 0; (i < 'd32) && (cnt < 'd16); i = i + 'd1) begin
if(pin_en[i]) begin
actual_pins[cnt] = pins[i];
cnt = cnt + 'd1;
end
end
for(; cnt < 16; cnt = cnt + 1)
actual_pins[j] = 1'b0;
end
endmodule

Bit slicing in verilog

How can I write wdata[((8*j)+7) : (8*i)] = $random; in verilog programming language? , where i and j are reg type variable. Modelsim gives error for constant range variable. How could I write it in proper manner.
You should think from Hardware prospective for the solution.
Here is one solution. Hope that it will help you.
module temp(clk);
input clk;
reg i, j;
reg [23:0] register, select;
wire [23:0] temp;
initial
begin
i = 'd1;
j = 'd1;
end
generate
for(genvar i = 0; i<24; i++)
begin
assign temp[i] = select[i] ? $random : register[i];
end
endgenerate
always # (posedge clk)
begin
register <= temp;
end
always # *
begin
select = (32'hffff_ffff << ((j<<3)+8)) ^ (32'hffff_ffff << (i<<3));
end
endmodule
Use the array slicing construction. You can find more detailed explanation at Array slicing Q&A
bit [7:0] PA, PB;
int loc;
initial begin
loc = 3;
PA = PB; // Read/Write
PA[7:4] = 'hA; // Read/Write of a slice
PA[loc -:4] = PA[loc+1 +:4]; // Read/Write of a variable slice equivalent to PA[3:0] = PA[7:4];
end
Verilog 2001 Syntax
[M -: N] // negative offset from bit index M, N bit result
[M +: N] // positive offset from bit index M, N bit result

Parameterizing a casex statement in verilog

Consider the following function which I would like to parameterize. I have created some parameters to set a width of the input and a corresponding width parameter for the output.
parameter SELECT_WIDTH = 6;
parameter PRIENC_WIDTH = $clog2(SELECT_WIDTH+1);
function [PRIENC_WIDTH-1:0] prienc6;
input [SELECT_WIDTH-1:0] select;
reg [PRIENC_WIDTH-1:0] out;
begin
casex(select)
6'b000001: out = 3'b101; // Is it possible to parameterize the case statement with generate
6'b00001x: out = 3'b100;
6'b0001xx: out = 3'b011;
6'b001xxx: out = 3'b010;
6'b01xxxx: out = 3'b001;
6'b1xxxxx: out = 3'b000;
endcase
prienc6 = out ;
end
end function
Obviously, the casex statement cases will not expand as written.
So I tried the following, which didn't compile correctly indicating unexpected generate found.
function [PRIENC_WIDTH-1:0] prienc_n;
input [SELECT_WIDTH-1:0] select;
reg [PRIENC_WIDTH-1:0] out;
begin
genvar gv_j;
casex(select)
for (gv_j = 0; gv_j < SELECT_WIDTH; gv_j = gv_j + 1)
begin
{{(SELECT_WIDTH-1)-gv_j{1'b0}},1'b1,{gv_j{1'bx}}} : out = (SELECT_WIDTH-1)-gv_j;
end
endcase
prienc_n = out ;
end
end function
I have been able to get the correct behavior using parameterized if's, but it seems like I should be able to parameterize that casex statement. Any thoughts on how to do this? I guess what I will try next is to wrap the casex in the generate loop and create 6 casex statements, each with only one state.
Since you tagged this question with SystemVerilog, I'll show you how to do this without a case statement or generate
function logic [PRIENC_WIDTH-1:0] prienc_n(
input [SELECT_WIDTH-1:0] select);
for (int j = 0; j < SELECT_WIDTH; j++) begin
if (select[SELECT_WIDTH-1]) return j;
select <<=1;
end
// if no 1 found
return ('x); // you did not specify this case
endfunction
If you need to stay in Verilog, it will need an intermediate variable
function reg [PRIENC_WIDTH-1:0] prienc_n(
input [SELECT_WIDTH-1:0] select);
reg [PRIENC_WIDTH-1:0] out;
integer j;
begin
out = {PRIENC_WIDTH{1'bx}}; // what should be returned if no 1 found
for (j = 0; j < SELECT_WIDTH; j = j + 1) begin
if (select[SELECT_WIDTH-1]) begin
out = j;
select = 0;
end
select = select << 1;
end
prienc_n = out;
end
endfunction

Fifo buffer in Verilog. generate always

I'm tring to write universal fifo buffer.
To make it universal i used code like this.
genvar i;
generate
for(i=0;i<BusWidthIn;i=i+1) begin: i_buffin
always # (negedge clkin) begin
if (!full)
Buffer[wr_ptr+i] <= datain[i*BitPerWord+BitPerWord-1:i*BitPerWord];
end
end
endgenerate
In simulation it works properly, but in Quartus it gives
Error (10028): Can't resolve multiple constant drivers for net "Buffer[30][6]" at fifo.v(33) and so on.
All Code
module fifo_m(clkin,datain,clkout,dataout,full,empty);
parameter BusWidthIn = 3, //in 10*bits
BusWidthOut = 1, //in 10*bits
BufferLen = 4, // in power of 2 , e.g. 4 will be 2^4=16 bytes
BitPerWord = 10;
input clkin;
input [BusWidthIn*BitPerWord-1:0] datain;
input clkout;
output [BusWidthOut*BitPerWord-1:0] dataout;
output full;
output empty;
reg [BusWidthOut*BitPerWord-1:0] dataout;
reg [BitPerWord-1:0] Buffer [(1 << BufferLen)-1 : 0];
wire [BusWidthIn*BitPerWord-1:0] tbuff;
reg [BufferLen - 1 : 0] rd_ptr, wr_ptr;
wire [BufferLen - 1 : 0] cnt_buff;
wire full;
wire empty;
assign cnt_buff = wr_ptr > rd_ptr ? wr_ptr - rd_ptr : (1 << BufferLen) - rd_ptr + wr_ptr;
assign full = cnt_buff > (1 << BufferLen) - BusWidthIn;
assign empty = cnt_buff < BusWidthOut;
initial begin
rd_ptr = 0;
wr_ptr = 0;
end
genvar i;
generate
for(i=0;i<BusWidthIn;i=i+1) begin: i_buffin
always # (negedge clkin) begin
if (!full)
Buffer[wr_ptr+i] <= datain[i*BitPerWord+BitPerWord-1:i*BitPerWord];
end
end
endgenerate
always # (negedge clkin)
begin
if (!full)
wr_ptr = wr_ptr + BusWidthIn;
end
genvar j;
generate
for(j=0;j<BusWidthOut;j=j+1) begin : i_buffout
always # (posedge clkout) begin
dataout[j*BitPerWord+BitPerWord-1:j*BitPerWord] <= Buffer[rd_ptr+j];
end
end
endgenerate
always # (posedge clkout)
begin
if (!empty)
rd_ptr = rd_ptr + BusWidthOut;
end
endmodule
To solve this problem I must put for inside always, but how I can do it?
I think the issue is that synthesis doesn't know that wr_ptr is always a multiple of 3, hence from the synthesis point of view 3 different always blocks can assign to each Buffer entry. I think you can recode your logic to assign just a single Buffer entry per always block.
genvar i, j;
generate
for(i=0;i < (1<<(BufferLen)); i=i+1) begin: i_buffin
for(j = (i%BusWidthIn);j == (i%BusWidthIn); j++) begin // a long way to write 'j = (i%BusWidthIn);'
always # (negedge clkin) begin
if (!full) begin
if (wr_ptr*BusWidthIn + j == i) begin
Buffer[i] <= datain[j*BitPerWord+BitPerWord-1:j*BitPerWord];
end
end
end
end
end
endgenerate
Also at http://www.edaplayground.com/x/23L (based off of Morgan's copy).
And, don't you need to add a valid signal into the fifo, or is the data actually always available to be pushed in ?
Other then the *_ptr in your code should be assigned with non-blocking assignment (<=), there really isn't anything wrong with your code.
If you want to assign Buffer with a for-loop inside of an always block, you can use the following:
integer i;
always #(negedge clkin) begin
if (!full) begin
for (i=0;i<BusWidthIn;i=i+1) begin: i_buffin
Buffer[wr_ptr+i] <= datain[i*BitPerWord +: BitPerWord];
end
wr_ptr <= wr_ptr + BusWidthIn;
end
end
datain[i*BitPerWord+BitPerWord-1:i*BitPerWord] will not compile in Verilog because the MSB and LSB select bits are variables. Verilog requires a known range. +: is for part-select (also known as a slice) allows a variable select index and a constant range value. It was introduced in IEEE Std 1364-2001 § 4.2.1. You can also read more about it in IEEE Std 1800-2012 § 11.5.1, or refer to previously asked questions: What is `+:` and `-:`? and Indexing vectors and arrays with +:.

Resources