I writing in Verilog HDL for synthesis and I want to instantiate a DUAL PORT RAM with default values (zeros), how can do it?
Thanks, Netanel
As you mentioned Virtex-7 - look in the Xilinx Synthesis manual for examples of how to write Verilog that infers a memory block.
In Appendix C you can find this code:
// Dual-Port Block RAM with Two Write Ports
// File: HDL_Coding_Techniques/rams/rams_16.v
module v_rams_16 (clka,clkb,ena,enb,wea,web,addra,addrb,dia,dib,doa,dob);
input clka,clkb,ena,enb,wea,web;
input [9:0] addra,addrb;
input [15:0] dia,dib;
output [15:0] doa,dob;
reg [15:0] ram [1023:0];
reg [15:0] doa,dob;
always #(posedge clka) begin if (ena)
begin
if (wea)
ram[addra] <= dia;
doa <= ram[addra];
end
end
always #(posedge clkb) begin if (enb)
begin
if (web)
ram[addrb] <= dib;
dob <= ram[addrb];
end
end
endmodule
I'm not a Verilogger, but I'm sure you can tweak the ram declaration to make it initialise with all zeros.
Related
I am working with RAM in Verilog, and I need to implement a test bench where I will confirm the correct operation of the three memory processes (write data, read data and read commands). I have written a testbench where it seems to be writing and reading some integer numbers, but is there any way to fill the memory with words or strings to be more clear randomly?
This is my testbench:
module ramtest();
parameter WORD_SIZE=8;
parameter ADDR_WIDTH=8;
parameter RAM_SIZE=1<<ADDR_WIDTH;
reg we;
reg re;
reg [ADDR_WIDTH-1:0] addr;
reg [ADDR_WIDTH-1:0] instraddr;
reg [WORD_SIZE-1:0] datawr;
reg Clk;
reg [WORD_SIZE-1:0] mem[RAM_SIZE-1:0];
wire [WORD_SIZE-1:0] datard;
wire [WORD_SIZE-1:0] instrrd;
MCPU_RAMController raminst (.we(we),.datawr(datawr),.re(re),.addr(addr),.datard(datard),.instraddr(instraddr),.instrrd(instrrd));
integer i;
initial begin
we=0;
datawr=0;
instraddr=0;
addr=1;
#20;
for(i=0;i<RAM_SIZE;i=i+1) begin
datawr=i;
addr=i-1;
#10;
end
we=0;
addr=1;
instraddr=0;
for(i=0;i<RAM_SIZE;i=i+1) begin
addr=i-1;
#10;
end
end
endmodule
And here is the RAM controller code where I need to test:
module MCPU_RAMController(we, datawr, re, addr, datard, instraddr, instrrd);
parameter WORD_SIZE=8;
parameter ADDR_WIDTH=8;
parameter RAM_SIZE=1<<ADDR_WIDTH;
input we, re;
input [WORD_SIZE-1:0] datawr;
input [ADDR_WIDTH-1:0] addr;
input [ADDR_WIDTH-1:0] instraddr;
output [WORD_SIZE-1:0] datard;
output [WORD_SIZE-1:0] instrrd;
reg [WORD_SIZE-1:0] mem[RAM_SIZE-1:0];
reg [WORD_SIZE-1:0] datard;
reg [WORD_SIZE-1:0] instrrd;
always # (addr or we or re or datawr)
begin
if(we)begin
mem[addr]=datawr;
end
if(re) begin
datard=mem[addr];
end
end
always # (instraddr)
begin
instrrd=mem[instraddr];
end
endmodule
Currently, you are filling the memory with incrementing values (0, 1, 2, etc.) at incrementing addresses. One way to fill the memory with random data values is to use the $random system function.
In the testbench, change:
datawr=i;
to:
datawr=$random;
See also IEEE Std 1800-2017, section 18.13 Random number system functions and methods for more modern random functions ($urandom, etc.).
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.
I am implementing a 32bit RegFile(containing 32 registers). Now, for the combinational part, I am planning to use the switch case to out the read value of the 32registers based on the input register number. This is resulting in a switch case with 32cases and a default case. Is there any other way to optimize the code? Constraint is that my output needs to be a register and hence I am unable to use the following statement(containing assign):
assign rdDataA = rdAddrA == 0 ? reg0
Code:
module RegFile(input [4:0] src_rd_1,
input [4:0] src_rd_2,
input [4:0] des_wr_1,
input [31:0] data,
input clk,
input reset,
input wr_en,
output reg rd_val_1,
output reg rd_val_2
);
reg [31:0] register[31:0];
always_comb begin
case(src_rd_1)
5'd0:begin
rd_val_1=register[0];
end
5'd1:begin
rd_val_1=register[1];
end
5'd2:begin
rd_val_1=register[2];
end
5'd3:begin
rd_val_1=register[3];
end
5'd4:begin
rd_val_1=register[4];
//and so on...
end
Update:
I found out a way to optimize the code. I hope this would work...Any other suggestions are welcome
if(src_rd_1>=0)
begin
if(src_rd_1==0)
begin
rd_val_1=32'd0;
end
else
begin
rd_val_1=register[src_rd_1];
end
end
Any advise will helpful. TIA
The following is allowed by simulation tools:
always_comb begin
rd_val_1 = register[src_rd_1];
end
You'll have to try it out and see if your synthesis tool supports this.
Using reg doesn't mean it will synthesize to a register. To synthesize to a register a reg (or for SystemVerilogpreferablylogic`) should be assigned in a sequential always block.
always_ff #(posedge clk) begin
rd_val_1 <= register[src_rd_1];
end
Flopping the output makes it a clean, glitch-free output and doesn't add to the combinational propagation delay to any receiving modules.
I'm an FPGA noob trying to learn Verilog. How can I "assign" a value to a reg in an always block, either as an initial value, or as a constant. I'm trying to do something like this in the code below. I get an error because the 8 bit constant doesn't count as input. I also don't want to trigger the always off of a clock. I just want to assign a register to a specific value. As I want it to be synthesisable I can't use an initial block. Thanks a lot.
module top
(
input wire clk,
output wire [7:0] led
);
reg [7:0] data_reg ;
always #*
begin
data_reg = 8'b10101011;
end
assign led = data_reg;
endmodule
You can combine the register declaration with initialization.
reg [7:0] data_reg = 8'b10101011;
Or you can use an initial block
reg [7:0] data_reg;
initial data_reg = 8'b10101011;
You should use what your FPGA documentation recommends. There is no portable way to initialize register values other than using a reset net. This has a hardware cost associated with it on most synthesis targets.
The other answers are all good. For Xilinx FPGA designs, it is best not to use global reset lines, and use initial blocks for reset conditions for most logic. Here is the white paper from Ken Chapman (Xilinx FPGA guru)
http://japan.xilinx.com/support/documentation/white_papers/wp272.pdf
The always #* would never trigger as no Right hand arguments change. Why not use a wire with assign?
module top (
input wire clk,
output wire [7:0] led
);
wire [7:0] data_reg ;
assign data_reg = 8'b10101011;
assign led = data_reg;
endmodule
If you actually want a flop where you can change the value, the default would be in the reset clause.
module top
(
input clk,
input rst_n,
input [7:0] data,
output [7:0] led
);
reg [7:0] data_reg ;
always #(posedge clk or negedge rst_n) begin
if (!rst_n)
data_reg <= 8'b10101011;
else
data_reg <= data ;
end
assign led = data_reg;
endmodule
Hope this helps
When a chip gets power all of it's registers contain random values. It's not possible to have an an initial value. It will always be random.
This is why we have reset signals, to reset registers to a known value. The reset is controlled by something off chip, and we write our code to use it.
always #(posedge clk) begin
if (reset == 1) begin // For an active high reset
data_reg = 8'b10101011;
end else begin
data_reg = next_data_reg;
end
end
This is my synthesizable memory model in Verilog.
module memory(
output reg [31:0] data_out,
input [31:0] address,
input [31:0] data_in,
input write_enable,
input clk
);
reg [31:0] memory [0:255];
always #(posedge clk) begin
if (write_enable) begin
memory[address] <= data_in;
end
data_out <= memory[address];
end
endmodule
For example:
memory[32'h10] contains 0xAAAAAAAA
I just want to write one byte of data 0xFF in memory address 0x10 so that
memory[32'h10] contains 0xFFAAAAAA
Can you recommend a good way to change my code so that I can access only one bit, half-byte, byte, halfword, or word in my memory module?
You only declared 256 words of 32-bits, but your address bus is 32-bits wide, allowing up to 2^32 words of 32-bits. You might want to reduce your address bus width to 8-bits to match the number of words you declared.
For Xilinx FPGAs I use the CORE Generator tool to instantiate one or more BlockRAMs of the right width and depth. BlockRAMs have an option to support individual byte enables.
This code might work, but I haven't tried it
module memory (
output reg [31:0] data_out,
input [7:0] address,
input [31:0] data_in,
input [3:0] write_enable,
input clk
);
reg [31:0] memory [0:255];
reg [31:0] memory_in = 0; // wire reg
always #* begin : combinational_logic
memory_in = memory[address];
if (write_enable[3])
memory_in[31:24] = data_in[31:24];
if (write_enable[2])
memory_in[23:16] = data_in[23:16];
if (write_enable[1])
memory_in[15:8] = data_in[15:8];
if (write_enable[0])
memory_in[7:0] = data_in[7:0];
end
always #(posedge clk) begin : sequential_logic
if (|write_enable) begin
memory[address] <= memory_in;
end
data_out <= memory[address];
end
endmodule
What 'a good way' is depends on your synthesis target. If it's an FPGA you should consider that bit-wise write access for large memories is generally not a good idea. This will possibly prevent the memory from mapping to RAM resources, dramatically increasing routing costs.
Byte enables are generally directly supported. You can view the Xilinx coding guidelines here where it describes byte enables on page 159.