Block RAM
Block RAM
Block RAM (BRAM) is a type of random access memory embedded throughout an FPGA for data
storage. You can use BRAM to transfer data between multiple clock domains by using local FIFO,
transfer data between an FPGA target and a host processor by using a DMA FIFO, transfer data
between FPGA targets by using a peer-to-peer FIFO and store large data sets on an FPGA target more
efficiently than RAM built from look-up tables.
Block RAM is a discrete part of FPGA, meaning there are only so many of them available of them on
the chip. Usually the bigger and more expensive the FPGA, the more Block RAM it will have on it.
Block RAMs come in a finite size, 4/8/16/32 kb (kilobits) are common. They have a customizable
width and depth.
Features
Synchronous Operation
Each memory access, read, and write is controlled by the clock. All inputs, data, address, clock
enable, and write enable are registered. The data output is always latched, retaining data until the
next operation. An optional output data pipeline register allows higher clock rates at the cost of an
extra cycle of latency. During a write operation, the data output can be made to reflect the
previously stored data, the newly written data, or remain unchanged. There is independent reset
control of output latches and registers.
Asynchronous Operation
The data outputs can also be set or reset asynchronously. Sleep input (places array in low power
state) can be optionally asynchronous.
The block RAM has two completely independent ports that share nothing but the stored
One port is dedicated as a write port and the other as a read port. Consequently, the data width can
be extended to 72 bits for the 36 Kb full block RAM or 36 bits for the "split" 18 Kb block RAM.
Suppose you want to write some data into the Block RAM buffer, then read it out at a later time. This
would involve driving wen high for one clock cycle and dout would have your write data. For the
single port configuration, you can either read or write data on Port A, you can’t do both at the same
time.
Verilog Code:
`timescale 1 ps / 1 ps
module blockram_wrapper
(BRAM_PORTA_0_addr,
BRAM_PORTA_0_clk,
BRAM_PORTA_0_din,
BRAM_PORTA_0_dout,
BRAM_PORTA_0_en,
BRAM_PORTA_0_rst,
BRAM_PORTA_0_we);
input [31:0]BRAM_PORTA_0_addr;
input BRAM_PORTA_0_clk;
input [31:0]BRAM_PORTA_0_din;
output [31:0]BRAM_PORTA_0_dout;
input BRAM_PORTA_0_en;
input BRAM_PORTA_0_rst;
input [3:0]BRAM_PORTA_0_we;
wire [31:0]BRAM_PORTA_0_addr;
wire BRAM_PORTA_0_clk;
wire [31:0]BRAM_PORTA_0_din;
wire [31:0]BRAM_PORTA_0_dout;
wire BRAM_PORTA_0_en;
wire BRAM_PORTA_0_rst;
wire [3:0]BRAM_PORTA_0_we;
blockram_vaes2 blockram_vaes2_i
(.BRAM_PORTA_0_addr(BRAM_PORTA_0_addr),
.BRAM_PORTA_0_clk(BRAM_PORTA_0_clk),
.BRAM_PORTA_0_din(BRAM_PORTA_0_din),
.BRAM_PORTA_0_dout(BRAM_PORTA_0_dout),
.BRAM_PORTA_0_en(BRAM_PORTA_0_en),
.BRAM_PORTA_0_rst(BRAM_PORTA_0_rst),
.BRAM_PORTA_0_we(BRAM_PORTA_0_we));
endmodule
TESTBENCH:
module tb_blockram;
reg [31:0] addr;
reg clk;
reg en;
reg rst;
blockram_wrapper uut (
.BRAM_PORTA_0_addr(addr),
.BRAM_PORTA_0_clk(clk),
.BRAM_PORTA_0_din(din),
.BRAM_PORTA_0_dout(dout),
.BRAM_PORTA_0_en(en),
.BRAM_PORTA_0_rst(rst),
.BRAM_PORTA_0_we(we) );
initial begin
addr = 0;
clk = 0;
din = 0;
en = 0;
rst = 0;
we = 0;
rst = 1;
#10;
rst = 0;
#100;
#100;
en = 1;
// Disable read/write
#100;
en = 0;
#20;
en = 1; // Enable read
#10;
#10;
$finish;
end
units endmodule
VHDL Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
library UNISIM;
use UNISIM.VCOMPONENTS.ALL;
entity bram_1_wrapper is
port (
BRAM_PORTA_0_clk : in STD_LOGIC;
BRAM_PORTA_0_en : in STD_LOGIC;
BRAM_PORTA_0_rst : in STD_LOGIC;
);
end bram_1_wrapper;
component bram_1 is
port (
BRAM_PORTA_0_clk : in STD_LOGIC;
BRAM_PORTA_0_en : in STD_LOGIC;
BRAM_PORTA_0_rst : in STD_LOGIC;
);
end
component bram_1;
begin
port map (
);
end STRUCTURE;
Results:
Schematic:
Method 2: From IP Catalog -
- Project Manager > IP Catalog OR Window > IP Catalog
- In IP Catalog window, search for Block Memory Generator and double click on Block Memory
Generator.
- A window will open with lots of options here. Using this window, we can create RAM and ROM.
- Select Interface Type to Native and Memory Type Single Port RAM.
- Click on Port A Options and type 8 in Write Width and Read Width.
- Type 16 in Write Depth and Read Depth
- Select Enable Port Type to Always Enable. Click OK.
- This will create a Block RAM of width 8-bit and depth 16 (Total 16 numbers of locations). For
locating 16 locations, 4-bit address lines is required.
Verilog Code:
module bram_singleport(clk,address,data_in,data_out,write_en);
input clk;
input write_en;
input [3:0]address;
input [7:0]data_in;
output [7:0]data_out;
blk_mem_gen_0
bram(.clka(clk),.addra(address),.dina(data_in),.douta(data_out),.wea(write_en)); endmodule
Testbench:
module tb_bram_singleport;
reg clk;
reg [3:0]address;
reg [7:0]data_in;
wire [7:0]data_out;
reg write_en;
bram_singleport uut(clk,address,data_in,data_out,write_en);
initial begin
clk = 0;
data_in = 8'h42;
address = 4'h5;
#20
#20
#20
$finish();
end
endmodule
Schematic –
Results:
Verilog Code:
module bram_singleport(clk,address,data_in,data_out,write_en);
input clk;
input write_en;
input [3:0]address;
input [7:0]data_in;
output [7:0]data_out;
blk_mem_gen_0
bram(.clka(clk),.addra(address),.dina(data_in),.douta(data_out),.wea(write_en)); endmodule
Testbench:
module tb_design_1_wrapper;
reg [12:0] BRAM_PORTA_0_addr;
reg BRAM_PORTA_0_clk;
reg [5:0] BRAM_PORTA_0_din;
reg BRAM_PORTA_0_en;
reg BRAM_PORTA_0_rst;
reg [0:0] BRAM_PORTA_0_we;
wire [5:0] BRAM_PORTA_0_dout;
design_1_wrapper dut
(.BRAM_PORTA_0_addr(BRAM_PORTA_0_addr),
.BRAM_PORTA_0_clk(BRAM_PORTA_0_clk),
.BRAM_PORTA_0_din(BRAM_PORTA_0_din),
.BRAM_PORTA_0_dout(BRAM_PORTA_0_dout),
.BRAM_PORTA_0_en(BRAM_PORTA_0_en),
.BRAM_PORTA_0_rst(BRAM_PORTA_0_rst),
.BRAM_PORTA_0_we(BRAM_PORTA_0_we));
initial begin
BRAM_PORTA_0_clk = 0;
BRAM_PORTA_0_addr = 0;
BRAM_PORTA_0_en = 0;
BRAM_PORTA_0_rst = 0;
BRAM_PORTA_0_we = 0;
#200;
end
endmodule
Schematic
Results:
input wr_en,
input port_en_a,
input port_en_b,
begin
end
assign data_out_a = port_en_a ? ram[addr_in_a] :
: 'dZ;
endmodule
Testbench:
module tb_dualport_bram;
reg CLK;
reg wr_en;
reg [7:0] data_in;
reg [3:0] addr_in_a;
reg [3:0] addr_in_b;
reg port_en_a;
reg port_en_b;
integer i;
initial begin
CLK = 1;
addr_in_a = 0;
addr_in_b = 0;
port_en_a = 0;
port_en_b = 0;
wr_en = 0;
data_in = 0;
#20;
port_en_a = 1;
wr_en = 1;
for(i=1; i <= 16; i = i + 1)
begin
data_in = i;
addr_in_a = i-1;
#10;
end
wr_en = 0;
port_en_a = 0;
port_en_b = 1;
for(i=1; i <= 16; i = i + 1)
begin
addr_in_b = i-1;
#10;
end
port_en_b = 0;
end
endmodule
Results: