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
<code class="C">
ram {
name = "Memory 2";
prefix = "mem2K";
size = 1024;
width = 16;
access_bus = READ_WRITE;
access_dev = READ_ONLY;
};
</code>
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.
<code class="C">
ram {
name = "Memory 1";
prefix = "mem1k";
-- number of words of size 'width' in the RAM
size = 256;
-- width (bit count) of the memory's data bus
width = 32;
-- yes, we want the memory to be byte-addressable
byte_select = true;
-- core ports work in different clock domain
clock = "clk1_i";
-- here we define address wraparound. The memory address space is extended by 'wrap_bits'
-- number of bits, thus mirroring the memory 2^(wrap_bits) times. This allows for wrap-around
-- read/write operations passing from the end to the beginning of the memory with no extra math.
-- Useful for implementing circular buffers, etc.
wrap_bits = 1;
-- access. Defined the same way as for the registers.
access_bus = READ_WRITE;
access_dev = READ_WRITE;
};
</code>
Figure 3.* RAM block generated from the code shown above.