1. RAM memory block

RAM block describes a dual-port RAM memory block with one port hooked to Wishbone bus, and the other port available for user application. Currently wbgen2 can produce:
  • RAM blocks of power-of-2 sizes,
  • variable data bus width (1 to 32/64 bits),
  • configurable byte select lines.

RAMs are implemented using FPGA embedded memory blocks (BRAM in Xilinx, DCRAM in Altera).

1.1. Block-specific attributes

Attribute Status Description
width = bits mandatory Width of RAM data bus in bits. Valid values are from 1 to 32 (64).
size = words mandatory Number of words of length width in the RAM array. Must be a power of 2.
byte_select = true/false optional When set to true, RAM will be byte-addressable using byte select lines (wb_sel_i from the WB bus and ram_bwsel_i from the peripheral). Default value is false (no byte addressing)
wrap_bits = num optional Number of extra bits allocated from the address bus. Used for mirroring the memory block multiple times (if wrap_bits > 0, the memory will be mirrored 2^wrap_bits times in the Wishbone address space. Useful for implementing circular buffers.
clock = clock signal optional Clock for the peripheral port of memory block. If it isn't specified, wbgen2 will assume the peripheral-side port works in WB bus clock domain)
access_bus, access_dev mandatory Specify how the memory block can be accessed from the bus and the peripheral. All combinations of READ_ONLY, READ_WRITE and WRITE_ONLY are supported (except for the nonsense ones: RO/RO or WO/WO).

1.2. Data organisation and byte addressing

Wbgen2 doesn't pack memory words - it places each memory word at different address, even if the memory width is smaller than the Wishbone bus width and several words could be packed into same address. In order to generate a memory which is seen by the WB master as a continuous block, declare it with the same width as the Wishbone data bus width and eventually enable byte_select for byte-wise access from the peripheral (see figure 1).

Figure 1. wbgen2 memory layout.

2. RAM examples

2.1. Simple RAM block

The following example shows a simple 2-kilobyte 16-bit RAM block. Readable/writable from the bus, readable from the slave. Generated RAM ports are shown on figure 1

1 ram {
2   name = "Memory 2";
3   prefix = "mem2K";
4   size = 1024;
5   width = 16;
6   access_bus = READ_WRITE;
7   access_dev = READ_ONLY;
8 };

Figure 2. RAM block generated from the code shown above.

2.2. Complex RAM block

This example demonstrates how to build a complex memory block - with byte addressing, asynchronous clock and mirrirong. Generated ports are shown on figure 3.

 1 ram {
 2   name = "Memory 1";
 3   prefix = "mem1k";
 5 -- number of words of size 'width' in the RAM
 6   size = 256;
 8 -- width (bit count) of the memory's data bus
 9   width = 32;
11 -- yes, we want the memory to be byte-addressable
12   byte_select = true;
14 -- core ports work in different clock domain
15   clock = "clk1_i";
17 -- here we define address wraparound. The memory address space is extended by 'wrap_bits' 
18 -- number of bits, thus mirroring the memory 2^(wrap_bits) times. This allows for wrap-around 
19 -- read/write operations passing from the end to the beginning of the memory with no extra math. 
20 -- Useful for implementing circular buffers, etc. 
21   wrap_bits = 1;
23 -- access. Defined the same way as for the registers.
24   access_bus = READ_WRITE;
25   access_dev = READ_WRITE;
26 };

Figure 3. RAM block generated from the code shown above.

ram_simple.png (3.1 kB) Tomasz Wlostowski, 2010-03-29 17:00

ram_complex.png (6.3 kB) Tomasz Wlostowski, 2010-03-29 17:00

memory_organisation.png (42.2 kB) Tomasz Wlostowski, 2010-03-29 17:27