When FPGA synthesis is performed, memory is also created as block memory in vivado, similar to clock wiz (DCM), and bits are generated.
How to create block memory
First, select IP Catalog from the Project manager on the far left of the Vivado window.
When you select IP Catalog, a window like the following will appear. Search for memory and select Block Memory Generator.
This will bring up a window like this, where you can set memory options.
So, how do we modify which values? To figure that out, we first need to understand how memory instances are structured in typical ASIC architecture designs.
input wire clk ;
input wire data0_cs ;
input wire [10:0] data0_addr ;
input wire [ 3:0] data0_we ;
input wire [31:0] data0_wdata;
output wire [31:0] data0_rdata;
spsram_2048x32 u_mem0 (
.CLK (clk )
,.CEN (~data0_cs )
,.WEN (~(|data0_we))
,.BWEN (~data0_we )
,.A ( data0_addr )
,.D ( data0_wdata)
,.Q ( data0_rdata)
);- CLK: memory input clock
- CEN: chip enable signal (active low)
- WEN: write enable signal (active low)
- BWEN: byte write enable signal (active low)
- A: address signal
- D: memory write(input) data
- Q: memory read(output) data
What we need to pay close attention to here are the memory type, we, and width/depth. Let's take a look at them one by one.
Memory type
Most memory instance names are listed here. Here, it's called spsram, which stands for single-port RAM. So, what other types are there?
- single port ram (sp ram)
- simple dual port ram (tp ram)
- true dual port ram (dp ram)
Let's understand the characteristics of each memory by looking at the block diagram.
Single port ram(sp ram)
SP RAM is literally a memory with only one memory port (A).
Simple dual port ram (tp ram)
TP RAM has two memory ports (A, B), but the chip enable signal (ena) and the write enable signal (wea) are shared between the two ports. So, one port is used for writing, and the other port is used for reading.
True dual port ram (dp ram)
DP RAM is a memory in which both memory ports (A, B) have their own ena signals (ena, enb) and wen signals (wea, web), so all memory ports can be read and written. Therefore, unlike TP RAM, it has dina, dinb, douta, and doutb signals.
Write enable(we)
To understand we, let's check the memory port.
Memory u_mem0 (
.clka ()
,.ena ()
,.wea ()
,.addra ()
,.dina ()
,.douta ()
);- addra: address signal
- dina: memory write(input) data
- douta: memory read(output) data
Of course, there is clk, and then there is en, we, addr, data_in, and data_out. en is enable and we is write enable. en is a 1-bit signal, but we may or may not be 1-bit. This is because we can decide whether to write a byte or write the data width at once. If data_width is 32 bits, when byte write enable is enabled, we will be a 4-bit signal, and when byte write enable is not enabled, we will be a 1-bit signal.
1-byte can be set to 8-bit or 9-bit (but most people would probably set it to 8-bit, right?) and if byte write enable is set, the data width that follows can only be entered as 8(or 9) x n. (ex. if set to 8-bit, data_width can only be set to 8, 16, 24, 32…)
Shall we set it up to here?
Width / Depth
The width and depth are also specified in the instance name. It is spsram_2048x32, where 2048 is the depth and 32 is the width. When you set the depth and width, the memory's addra, dina, and douta are automatically changed.
Then, you can modify it as follows.
input wire clk ;
input wire data0_cs ;
input wire [10:0] data0_addr ;
input wire [ 3:0] data0_we ;
input wire [31:0] data0_wdata;
output wire [31:0] data0_rdata;
`ifdef FPGA
spsram_2048x32_FPGA u_mem0_FPGA (
.clka (clk )
,.ena (data0_cs )
,.wea (data0_we )
,.addra (data0_addr )
,.dina (data0_wdata)
,.douta (data0_rdata)
);
`else
spsram_2048x32 u_mem0 (
.CLK (clk )
,.CEN (~data0_cs )
,.WEN (~(|data0_we))
,.BWEN (~data0_we )
,.A ( data0_addr )
,.D ( data0_wdata)
,.Q ( data0_rdata)
);
`endifI don't remember exactly the polarity of ena and wea;;;;
ROM code(boot loader) setting
Computers and SoCs have ROM (Read-Only Memory), so when booting, they need to load and execute a boot loader embedded in the ROM. So, how do we embed this boot loader into a memory block when synthesizing a bit file for board testing?
You can do this in the Memory Generator settings. You can specify the boot loader to run in the "Other options" section, as shown below. Load the corresponding bootloader file from the block to be used as ROM and synthesize the bits. Once the bits are downloaded to the board, the specified program will be executed.