Way to initialize synthesizable 2D array with constant values in Verilog - arrays

in VHDL, I can easily do this:
constant cmdbytes : bytearray(0 to Total) := (x"05", x"00", x...};
I want synthesizable constants so that when the FPGA starts, this array has the data I supplied. These registers are wired to VCC or ground to represent 1 or 0. I can then use them to generate a waveform. Also I would like to have 2D byte array which is 3D in verilog world.

If you're just using the array to pull out one value at a time, how about using a case statement? Granted, it's a long-winded way of doing it, but you could always write a script to write the RTL for you.
reg [7:0] value;
reg [7:0] i;
always #(posedge clk or negedge rst_n) begin
if(!rst_n)
i <= 8'd0;
else
i <= i + 1;
end
always #(*) begin
case(i)
8'h00: value = 8'd0;
8'h01: value = 8'd34;
...
endcase
endcase
Another way is to use an initial statement. As far as I'm aware, FPGA synthesis tools will allow you to set initial values for arrays in the following manner. Again, a script to write this may be the way to go.
reg [0:35][7:0] my_array;
initial begin
my_array[0] = 8'd45;
my_array[1] = 8'd26;
...
end
And if your FGPA synthesis tools support some SystemVerilog, you'll be able to initialise the array like so:
reg [0:34][7:0] my_array = '{ 8'd90, 8'd34, ... }; // note the '{

module test (
input [7:0] p1_sa, // i
input [7:0] p1_sb, // i
output [7:0] p3, // o
output [7:0] p3b // o
);
logic [7:0] array2d [7:0] = {99,124,119,123,242,107,111,197};
assign p3 = array2d[p1_sa];
assign p3b = array2d[p1_sb];
endmodule
I tried the above system verilog code and it is working fine in modelsim and Vivado.

An alternative to the case statement approach is to use a function to access values.
Example for an "array" of size 4 containing 8 bit constants:
function [7:0] cmdbytes;
input [1:0] index;
reg [7:0] t[0:3];
begin
{
t[0],t[1],t[2],t[3]
} = {
8'h05, 8'h00, 8'h5b, 8'h45
};
cmdbytes = t[index];
end
endfunction
One can access the constants like so:
wire [7:0] value0;
wire [7:0] value1;
wire [7:0] value2;
wire [7:0] value3;
assign value0 = cmdbytes(2'd0);
assign value1 = cmdbytes(2'd1);
assign value2 = cmdbytes(2'd2);
assign value3 = cmdbytes(2'd3);

Verilog 2005 doesn't allow array initialization. Though your FPGA vendor should have a means to generate a ROM.

Related

syntax error in accessing 2d register array in verilog code to synthesize in leonardo tool

I made a simple cache with verilog code in ISE tool, and used a 2d array of registers as my cache memory, simulating testbench on it in Modelsim done well and no syntax errors and no mistake in desires output signals, but in Leonardo tool when I tell Leonardo read it in library ams600nm it return syntax error near first line that I accessed my 2d array (cache), do you have any idea?
code:
module Cache(clk , wr
,din,adr,dout
);
input clk;
input wr;
input [3:0] din;
input [3:0] adr;
output [3:0] dout;
output hit;
reg [8:0] cache [3:0];
reg h;
reg [3:0] out;
initial
begin
***cache[0][8] = 1'b0; -----here-----
cache[1][8] = 1'b0; -----also here for sure-----
cache[2][8] = 1'b0;
cache[3][8] = 1'b0;***
end
You don't have output hit in module port list.
You don't have endmodule keyword.
Some software allow to access only all bits in array's row. I don't have access to your software, so I can't test it, but you should try something like that:
temp = cache[0];
cache[0] = {1'b 0, temp[7:0]};
This is equivalent to:
cache[0][8] = 1'b0;
temp should be declared as reg [8:0] temp; (same width as cache).

reading multiple block ram indexes in one write clock cycle

I have an application where I'm continuously writing to a block ram at a slow clock speed (clk_a) and within this slow clock cycle need to read three indexes from the block ram at a fast clock speed (clk_b) to use these values as operands in a math module, the result being written back to the block ram on the next slow clock. These three indexes are the current address written to at posedge of the slow clock, plus the two immediate neighbouring addresses (addr_a -1 and addr_a +1).
What is an efficient way to synthesize this? My best attempt to date uses a small counter (triplet) running at fast clock rate that increments the addresses but I end up running out of logic as it looks like Yosys does not infer the ram properly. What is a good strategy for this?
here is what I have:
module myRam2 (
input clk_a,
input clk_b,
input we_a,
input re_a,
input [10:0] addr_a,
input [10:0] addr_b,
input [11:0] din_a,
output [11:0] leftNeighbor,
output [11:0] currentX,
output [11:0] rightNeighbor
);
parameter MEM_INIT_FILE2 = "";
initial
if (MEM_INIT_FILE2 != "")
$readmemh(MEM_INIT_FILE2, ram2);
reg [11:0] ram2 [0:2047];
reg [1:0] triplet = 3;
reg [10:0] old_addr_a;
reg [11:0] temp;
always #(posedge clk_a) begin
ram2[addr_a] <= din_a;
end
always#(posedge clk_b)
if (old_addr_a != addr_a) begin
triplet <= 0;
old_addr_a <= addr_a;
end
else
if(triplet < 3) begin
triplet <= triplet +1;
end
always #(posedge clk_b) begin
temp <= ram2[addr_a + (triplet - 1)];
end
always #(posedge clk_b) begin
case(triplet)
0: leftN <= temp;
1: X <= temp;
2: rightN <= temp;
endcase
end
reg signed [11:0] leftN;
reg signed [11:0] X;
reg signed [11:0] rightN;
assign leftNeighbor = leftN;
assign currentX = X;
assign rightNeighbor = rightN;
endmodule
Regarding the efficiency the following approach should work and removes the need for a faster clock:
module myRam2 (
input wire clk,
input wire we,
input wire re,
input wire [10:0] addr_a,
input wire [10:0] addr_b,
input wire [11:0] din_a,
output reg [11:0] leftNeighbor,
output reg [11:0] currentX,
output reg [11:0] rightNeighbor
);
reg [11:0] ram2 [2047:0];/* synthesis syn_ramstyle = "no_rw_check" */;
always #(posedge clk) begin
if(we) ram2[addr_a] <= din_a;
if(re) {leftNeighbor,currentX,rightNeighbor} <= {ram2[addr_b-1],ram2[addr_b],ram2[addr_b+1]};
end
endmodule
The synthesis keyword helped me in the past to increase the likelyhood of correctly inferred ram.
EDIT: removed second example suggesting a 1D mapping. It turned out that at least Lattice LSE cannot deal with that approach. However the first code snipped should work according to Active-HDL and Lattice LSE.

Arrays of interface instances in SystemVerilog with parametrized number of elements

I'm using SystemVerilog for synthesis. I fought with the fact that arrays of interfaces are not really arrays in SystemVerilog and the index has to be a constant value, but got over it using at lot of boilerplate generate for and assign statements to overcome what is really a language limitation (if I can emulate the effect using more code, the language could just do The Right Thing(tm) itself).
For the following pseudo-code, I leave out much of what's there in the real code (modports, tasks, etc) for clarity.
I have an interface:
interface i_triplex();
logic a; // input wire
logic b; // output wire
logic [127:0] data; // output wires
endinterface
And I am passing an array of these interfaces to a module which looks like
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
i_triplex t[NUNITS]
);
always_ff #(posedge clk) begin
if (rst) begin
// insert code to initialize the "data" member
// in all interface instances in the array.
end
else begin
// ...
end
end
endmodule
What would your preferred way to use all interface instance in the array uniformly -- regardless of the value of NUNITS? I have some suggestions, but I am eager to learn what other engineers can come up with.
Suggestion 1:
Use VHDL.
Suggestion 2:
Scrap the interface and do it oldschool Verilog-style, as in
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
// This was once a proud i_triplex array
input wire i_triplex_a[NUNITS],
input wire i_triplex_b[NUNITS],
input wire [127:0] i_triplex_data[NUNITS],
);
always_ff #(posedge clk) begin
if (rst) begin
for (int i = 0; i < NUNITS; i++)
i_triplex_data[i] <= '1;
end
else begin
// ...
end
end
endmodule
Suggestion 3:
Use a struct for input wires and a struct for output wires instead of the interface.
Suggestion 4:
Use a preprocessor-like system that unrolls generate for loops inside processes (what the language should do anyway!), so the resulting code looks like (preprocessed with NUNITS=4):
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
i_triplex t[NUNITS]
);
always_ff #(posedge clk) begin
if (rst) begin
i_triplex.data[0] <= '1;
i_triplex.data[1] <= '1;
i_triplex.data[2] <= '1;
i_triplex.data[3] <= '1;
end
else begin
// ...
end
end
endmodule
Suggestion 5:
Use the generate for / assign solution:
module roundrobin_triplex#(
parameter int NUNITS = 8
)
(
input wire clk,
input wire rst,
i_triplex t[NUNITS]
);
wire i_triplex_a[NUNITS];
wire i_triplex_b[NUNITS];
wire [127:0] i_triplex_data[NUNITS];
generate
genvar i;
// The wires of the interface which are to be driven
// from this module are assigned here.
for (i = 0; i < NUNITS; i++) begin
assign t[i].b = i_triplex_b[i];
assign t[i].data = i_triplex_data[i];
end
endgenerate
always_ff #(posedge clk) begin
if (rst) begin
for (int i = 0; i < NUNITS; i++)
i_triplex_data[i] <= '1;
end
else begin
// ...
end
end
endmodule
Arrays of module or interface instances cannot be treated as regular arrays because parameterization, generate blocks, and defparam statements can make elements of the array instance non-unique. That cannot happen with arrays of variables/wires.
My suggestion would be a modification of your suggestion 2; put arrays of variables/wires inside a single interface instance.
how about suggestion #6, use parameterized interface:
interface I #(NPORTS = 8);
logic clk;
logic a[NPORTS];
logic b[NPORTS];
logic [127:0] data [NPORTS];
endinterface //
module roundrobin#(NUMPORTS = 8) (I t);
logic [127:0] data[NUMPORTS];
always_ff #(posedge t.clk) begin
data <= t.data;
end
endmodule // roundrobin
Note, that you do not need the loop in system verilog. you can use array assignments:
data <= t.data;
and for the sake of convenience you can add functions or statements to the interface itself, i.e.
interface I #(NPORTS = 8);
logic clk;
logic a[NPORTS];
logic b[NPORTS];
logic [127:0] data [NPORTS];
function logic [127:0] getData(int n);
return data[n];
endfunction // getData
endinterface // I
and use
data[i] <= t.getData(i);
Sorry, the above example is probably not very useful, but it might give you an idea.
Suggestion 1: VHDL may be a practical. However, it seems to become marginal in industry.
Suggestion 2: In my opinion, Interfaces are relevant if you intent to reuse it widely and implement verification/protocols into it. If you can unpack your interface like this, while keeping your sanity, then I do not see a justification for an interface in the first place.
Suggestion 3: I never tried to synthesise struct, it may be a good idea.
Suggestion 4: Simple solution,although quite verbose .
Suggestion 5: I used something similar for one of my project. However, I wrote a sort of adapter module to hide the assigns.
Actually, when I need something like that, I try to write an atomic module which operates on a fixed number of interfaces. Then, I use for generate structures to generalize it on an interface array.
Maybe I'm missing something by why not putting all yours code from roundrobin_triplex into generate (you do not need extra assigns)
interface i_triplex();
logic a; // input wire
logic b; // output wire
logic [127:0] data; // output wires
initial $fmonitor(1,data);
endinterface
module roundrobin_triplex#(parameter int NUNITS = 8)
(
input wire clk,
input wire rst,
i_triplex t[NUNITS]
);
genvar i;
for( i=0; i<NUNITS; i++)begin
always_ff #(posedge clk) begin
if (rst) begin
t[i].data <=0;
end
else begin
t[i].data <=t[i].data+1;
end
end
end
endmodule
module top;
parameter P=4;
bit clk,rst;
i_triplex ii[P]();
roundrobin_triplex #(P)uut(clk,rst,ii);
initial begin
rst=1;
repeat(2) #(posedge clk);
rst=0;
repeat(10) #(posedge clk);
$finish;
end
always #5 clk =~clk;
endmodule

In verilog Part-select of vector reg array is illegal

reg [data_width-1:0]coeff[0:order-1];
wire[3:0]lsbcoeff;
wire [7:4]msbcoeff;
lsbcoeff = coeff[3:0];
msbcoeff = coeff[7:4];
In the above line of code, im getting error
Part-select of vector reg array 'coeff' is illegal
Illegal right hand side of blocking assignment
Please guide me , how to overcome this ?
Xilinx v14.2
Verilog coding
You have coeff defined as a vector of coefficients, I am not sure what you expect coeff[3:0] to return? a vector of the LSBS? I think what you intended was something like coeff[0][3:0] Selecting the LSBs of the first vector. Code below shows a possible way of doing this:
module tb;
localparam data_width = 8;
localparam order = 2;
reg [data_width-1:0]coeff[0:order-1];
reg [3:0] lsbcoeff;
reg [7:4] msbcoeff;
reg [7:0] this_coeff;
always #* begin
lsbcoeff = coeff[0][3:0];
msbcoeff = coeff[0][7:4];
end
endmodule
and now I have read the comments I see this is what #Greg has already suggested.
In addition to #Morgan code, the wire should be assigned value using assign statement in verilog.
always #(*) begin
assign lsbcoeff = coeff[0][3:0];
assign msbcoeff = coeff[0][7:4];
end

how to declare output array in verilog?

I am trying to ADD two array and want output in array in verilog code. But error is occured. which is ERROR:HDLCompiler:1335: Port sum must not be declared to be an array in verilog code . can anyone tell me how to declare output array in verilog code. Thanks.
module array(clk,sum,reset);
input clk,reset;
//input [7:0] din;
//input [7:0] A[3:0];
//input [7:0] B[3:0];
output sum[3:0];
wire [7:0] sum[3:0];
reg [7:0] A[3:0];
reg [7:0] B[3:0];
integer i;
always#(posedge clk)
begin
if(reset==1'b1)
begin
A[0]<=1;
A[1]<=2;
A[2]<=3;
A[3]<=4;
B[0]<=5;
B[1]<=5;
B[2]<=5;
B[3]<=5;
sum[0]<=0;
sum[1]<=0;
sum[2]<=0;
sum[3]<=0;
end
else
begin
for(i=0;i<4;i=i+1)
begin
sum[i]=(A[i] + B[i]);
end
end
end
endmodule
Array style ports are only supported in SystemVerilog, if you can use that you should probably stop using the Verilog-95 style port declaration.
Verilog 2001 and above port declaration, with SystemVerilog multi dimension ports
module array(
input clk,
input reset,
input [7:0] A [3:0],
input [7:0] B [3:0],
output reg [7:0] sum[3:0]
);
Verilog vs SystemVerilog files are often identified by file extension so saving as a .sv file will normally switch the compiler over to SystemVerilog.
A combinatorial version on EDA Playground using the free modelsim 10.1d simulator.
Also note that if you are assigning a value to sum in an always block it needs to be a reg not a wire. Since your using SystemVerilog now everything can be declared as logic instead, for more info Checkout this answer.

Resources