In Intel Quartus, can I initialize RAM using a string parameter? - verilog

I need to initialize several instances of the same ram module with different data files which I would like to do as follows:
module ram #(
string HEXFILE = "split1.mem"
)
(
input logic clk,
input logic [31:0] a,
input logic [7:0] wd,
input logic we,
output logic [7:0] rd
);
logic [7:0] mem [3071:0];
integer fd;
initial $readmemh(HEXFILE, mem);
always_ff #(posedge clk) begin
if (we) mem[a] <= wd;
rd <= mem[a];
end
endmodule
And in my top level entity, initialize these as follows:
ram #(
.HEXFILE("split1.mem")
) M0 (
.clk(clk),
.a(a0),
.wd(wd0),
.we(we),
.rd(rd0)
);
ram #(
.HEXFILE("split2.mem")
) M1 (
.clk(clk),
.a(a1),
.wd(wd1),
.we(we),
.rd(rd1)
);
// And so on ...
But when I try to do this, I get the following error:
Error (10686): SystemVerilog error at ram.sv(18): HEXFILE has an aggregate value
It works fine if I use a string literal for the file name:
initial $readmemh("split1.mem", mem)
Any ideas on how I can achieve this without creating copies of the same file just to change the input file?
EDIT: I think Verilog treats parameters and string literals differently. It's treating string as an extension of logic which is why it's saying it needs to be extended.
I don't know how to define it as a string literal. The following seems to be working but it's a terrible terrible way in my opinion:
generate
if (HEXFILE == "split1.mem") initial $readmemh("split1.mem", mem);
else if (HEXFILE == "split2.mem") initial $readmemh("split2.mem", mem);
else if (HEXFILE == "split3.mem") initial $readmemh("split3.mem", mem);
else if (HEXFILE == "split4.mem") initial $readmemh("split4.mem", mem);
endgenerate

The reported error you see is for line 18 in the ram module, which is this line:
always_ff #(posedge clk) begin
When I run on different simulators, I don't see that exact error message, but with Synopsys VCS, I see:
Error-[ICPD] Illegal combination of drivers
ram.sv, 12
Illegal combination of procedural drivers
Variable "mem" is driven by an invalid combination of procedural drivers.
Variables written on left-hand of "always_ff" cannot be written to by any
other processes, including other "always_ff" processes.
This variable is declared at "ram.sv", 12: logic [7:0] mem[3071:0];
The first driver is at "ram.sv", 16: $readmemh(HEXFILE, mem);
The second driver is at "ram.sv", 18: always_ff #(posedge clk) begin
if (we) begin
...
Refer to IEEE Std 1800-2017, section 9.2.2.4 Sequential logic always_ff procedure:
Variables on the left-hand side of assignments within an always_ff
procedure, including variables from the contents of a called function,
shall not be written to by any other process.
The error goes away with:
always #(posedge clk) begin
Aside from that, I don't see any problem with using different values of HEXFILE passed to different instances. If you continue to see problems, you could try to use parameter instead of string:
module ram #(
parameter HEXFILE = "split1.mem"
)

Related

Quartus does not allow using a Generate block in Verilog

Pretty simple problem. Given the following code:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
generate
genvar k;
for(k=0; k<2; k=k+1) begin: m
always #(posedge clk) begin
if(wren[k])
ram[addr[k]] <= dIn[k];
dOut[k] <= ram[addr[k]];
end
end
endgenerate
endmodule
quarus 13.0sp1 gives this error (and its 20 other ill-begotten fraternally equivalent siblings):
Error (10028): Can't resolve multiple constant drivers for net "ram[63][14]" at main.v(42)
But if I manually un-roll the generate loop:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
always #(posedge clk) begin
if(wren[0])
ram[addr[0]] <= dIn[0];
dOut[0] <= ram[addr[0]];
end
always #(posedge clk) begin
if(wren[1])
ram[addr[1]] <= dIn[1];
dOut[1] <= ram[addr[1]];
end
endmodule
It all becomes okay with the analysis & synthesis step.
What's the cure to get the generate loop running?
I think the correct way is in the lines of what it's explained in this question: Using a generate with for loop in verilog
Which would be transferred to your code as this:
module main(
output reg [1:0][DATA_WIDTH-1:0] dOut,
input wire [1:0][DATA_WIDTH-1:0] dIn,
input wire [1:0][ADDR_WIDTH-1:0] addr,
input wire [1:0] wren,
input wire clk
);
parameter DATA_WIDTH = 16;
parameter ADDR_WIDTH = 6;
reg [DATA_WIDTH-1:0] ram [2**ADDR_WIDTH-1:0];
integer k;
always #(posedge clk) begin
for(k=0; k<2; k=k+1) begin:
if(wren[k])
ram[addr[k]] <= dIn[k];
dOut[k] <= ram[addr[k]];
end
end
endmodule
Keeping all accesses to your dual port RAM in one always block is convenient so the synthesizer can safely detect that you are efefctively using a dual port RAM at register ram.
Both the generate loop and unrolled versions should not have passed synthesis. In both cases the same address in ram can be assigned by both always blocks. Worse, if both bits of wren are high with both addresses being the same and data being different, then the result is indeterminable. The Verilog LRM states last assignment on a register wins and always blocks with the same trigger could be evaluated in any order.
Synthesis requires assignments to registers to be deterministic. Two (or more) always blocks having write access to the same bit is illegal because nondeterministic. If the unrolled is synthesizing correctly, then that means there are constants on wren and addr outside of the shown module that make it logically impossible for write conflict; for some reason the generate loop version is not getting the same optimization. Example of constraints that would allow optimization to prevent multi-always block write access:
One wren is hard coded to 0. Therefore only one block has exclusive access
Address have non overlapping sets of possible values. Ex addr[0] can only be even while addr[1] can only be odd, or addr[0] < 2**(ADDR_WIDTH/2) and addr[1] >= 2**(ADDR_WIDTH/2).
Synthesis is okay with dOut being assigned by two always blocks because each block has exclusive write access to its target bits (non overlapping sets of possible address values).
The single always block in mcleod_ideafix answer is the preferred solution. If both bits of wren are high with both addresses being the same, then wren[1] will always win. If wren[0] should have priority, then make the for-loop a count down.

Verilog : error Reference to scalar wire 'VALUE' is not a legal reg or variable lvalue

I'm stuck with this code. I don't understand why my VALUE cannot be inverted.
module PREDIV(
input wire QUARTZ,
output wire VALUE);
always # (posedge QUARTZ)
assign VALUE= ~VALUE;
endmodule
There are a few problems.
You should not use the assign keyword inside an always block.
When making a procedural assignment (those inside an always block), you should declare the signal as a reg type, not a wire. This is what your error message is referring to.
For sequential logic, you should use nonblocking assignments: <=.
Finally, a reg is initialized as unknown (X). You need a way to initialize VALUE, otherwise it will remain X. One way is to add a RESET signal.
module PREDIV(
input wire QUARTZ, input RESET,
output reg VALUE);
always # (posedge QUARTZ or posedge RESET)
if (RESET) begin
VALUE <= 0;
end else begin
VALUE <= ~VALUE;
end
endmodule
It looks like the code is using blocking assignment in the always block.
The always blocks should be using only non-blocking assignments.
The code should be something like:
always #(posedge QUARTS)
Value <= ~Value;

How to assign initial value to an input reg: Design compiler delete the assignment

I'm newbie in ASIC design. I have a design with for example two inputs a ,b. I'm using the following code for initialize these two signals. But the Design compiler generating a warning that the register "a" is a constant and will be removed. When I'm trying to do post-synthesis simulation these two signals are all 'z'. So how can I apply initial signal assignment to avoid such a problem?
always #(posedge(clk) or posedge (rst)) begin
if (rst) begin
a<=4d'5;
b <=4'd10;
end
end
While describing hardware system, you need to consider that input signals to your module comes from another module/system and their values are decided by that signals. Inputs to any module can only be wire type.
You can think of a module as a box that has inputs and outputs. The values of output signals are decided by input signal + logic inside the box. However, the module cannot decide what its inputs should be. It is only possible if there is feedback, and even in that case it would depend on other signals that are outside of the module's control.
As a result, output signals can be declared as output reg but the same is not true for inputs. However there is solution to your problem, I think what you want can be designed using the following method:
module your_module(
input clk,
input rst,
//other inputs and outputs that you might need
input [3:0] a,
input [3:0] b
);
//define registers
reg [3:0] a_register;
reg [3:0] b_register;
/*
These registers are defined to make it possible to
to give any value to that logics when posedge rst
is detected, otherwise you can use them as your
input logics
*/
//use initial block if you need
always#(posedge clk or posedge rst) begin
if(rst) begin
a_register <= 4'd5;
b_register <= 4'd10;
end
else
begin
a_register <= a;
b_register <= b;
// and use a_register and b_register as you want to use a and b
end
end
endmodule

Verilog - re-using register value on always posedge

Consider the following code:
Module Test (B, A, CLK)
Input A, CLK;
Output B;
Reg RA;
Always #(Posedge CLK)
Begin
RA=A;
B=RA;
End
EndModule
Would that work properly to move the input to the register and then to the output on every positive edge? Can it be created with circuits?
It depends what you are trying to do...
If you just want a single flip-flop, the simplest way is to declare reg B; then you can write always #(posedge CLK) B <= A;. There is no need for another signal.
If (for some style reason) you want to separate the flip-flop from the output, you can wire them together with a continuous assignment assign B = RA;. The circuit would be the same.
If you want two flip-flops (2-stage pipeline), your code is almost correct but remember to declare reg B; and use <= for both updates (they can be written in either order).
If RA is some sort of temporary variable for describing your intentions to the tools, then Yes; you can write to it with = and use its value in the same process (do not try to access it from any other process). This is occasionally useful for e.g. accumulating things in loops, but here it would just be confusing and error-prone!
To synthesize real hardware you would typically also have a reset signal and would need to use it in the proper way for each flip-flop.
To answer your question, yes, what you've written (conceptually) will work. In terms of syntax, here's something that will compile and do what you're thinking. Note that I've declared your output B a register and used nonblocking assignments for the registers.
module Test (
input wire CLK,
input wire A,
output reg B
);
reg RA;
always #(posedge CLK) begin
RA <= A;
B <= RA;
end
endmodule

how to initialize ram of multiple instance with different contents in quartus

I designed a RAM module, and I need multiple instances of this module each with a different memory initialization file.
The Quartus manual says that Quartus supports the $readmemh() function to initialize RAM. So I added two parameters to this module and pass different parameters to each instance, in order to specify which files each instance will read.
My code below works in Modelsim, but when fails when synthesizing. Quartus crashes, and after I remove it, Quartus synthesizes successfully.
module cell_module
#(
parameter X_ID = "1",
parameter Y_ID = "1",
parameter DIR_ID = {X_ID, "_", Y_ID}
)
...
reg [15:0] Mem_1 [0:31];
reg [15:0] Mem_2 [0:31];
`ifdef SIM_MEM_INIT
initial begin
$readmemh ({"../data", DIR_ID, "/file1.txt"},Mem_1);
$readmemh ({"../data", DIR_ID, "/file2.txt"},Mem_2);
end
`endif
The above module is instantiated in the top level like this:
cell_module #(.X_ID("1"), .Y_ID("1")) cell_module1 (...)
cell_module #(.X_ID("1"), .Y_ID("2")) cell_module2 (...)
cell_module #(.X_ID("2"), .Y_ID("1")) cell_module3 (...)
cell_module #(.X_ID("2"), .Y_ID("2")) cell_module4 (...)
The parameters specify which folder contains the initial memory for that cell.
This code works in Modelsim, and Quartus analysis and elaborate successfully completes.
But it causes quartus_map to crash when synthesizing. I can't find any information about this error message.
If this isn't possible, are there any good methods to initialize multiple instance's RAM with different contents?
Thanks
EDIT:
I built a small Quartus project to test whether this could be done. I followed the Quartus manual and wrote a standard RAM module with two extra parameters to define the folder of the initialization memory file.
This is code of ram,
module mem_init
#(parameter DATA_WIDTH=8, parameter ADDR_WIDTH=6, parameter X_ID = "1", Y_ID = "1", DIR_ID = {X_ID,"_", Y_ID})
(input [(DATA_WIDTH-1):0] data,
input [(ADDR_WIDTH-1):0] addr,
input we, clk,
output [(DATA_WIDTH-1):0] q);
reg [DATA_WIDTH-1:0] ram[2**ADDR_WIDTH-1:0];
reg [ADDR_WIDTH-1:0] addr_reg;
initial
begin : INIT
$readmemh ("../data", DIR_ID, "/file.txt", ram);
end
always # (posedge clk)
begin
if (we)
ram[addr] <= data;
addr_reg <= addr;
end
assign q = ram[addr_reg];
endmodule
And its initialization:
mem_init #(.DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .X_ID("1"), .Y_ID("1"))
mem1 (.data(data1), .addr(add1), .we(we), .clk(clk), .q(q1));
mem_init #(.DATA_WIDTH(DATA_WIDTH), .ADDR_WIDTH(ADDR_WIDTH), .X_ID("1"), .Y_ID("2"))
mem2 ( .data(data2),.addr(add2),.we(we), .clk(clk), .q(q2));
This works in simulation and Quartus successfully synthesizes this design.
"initial block" is not supported by the IEEE-1800 standard for synthesis.
If Altera/Intel lets you get away with that, then there is this issue, in terms of hierarchical references, that may help you too:
https://github.com/YosysHQ/yosys/issues/344
you can implement a reset signal.
always (posedge clock or posedge reset)
begin
if(reset==0)
begin
$readmemh ("../data", DIR_ID, "/file.txt", ram);
end
end
it will help you; I think.
once again check what will be synthesizable in Verilog.

Resources