FONT SIZE : AAA
FPGA tools don’t understand any instantiated RAMs used in the SoC design. In addition, there are limits imposed by the memory architectures available in the FPGA device itself, so there is no guarantee that all types of SoC RAMs can be directly mapped into BlockRAMs or distributed RAMs that are supported in the FPGA device. Before exploring that further, here is a quick recap on FPGA RAMs (more details are in chapter 3).
In FPGAs, there are two different groups of RAMS; Block RAMs and distributed RAMs.
• BlockRAM: The Virtex®-6 block RAM stores up to 36K bits of data and can be configured as either two independent 18-Kbit RAMs, or one 36- Kbit RAM. Each 36-Kbit BlockRAM can be configured in a number of ways e.g., 32K x 1, 16K x 2 etc. they can also be cascaded to create a 64Kx1 RAM. Each 18Kb BlockRAM can be configured as a 16K x 1, 8K x2, 4K x 4, 2K x 9, or 1K x 18 memory.
• Write and read are synchronous operations. The two ports are symmetrical and totally independent, sharing only the stored data. Each port can be configured in one of the available widths, independent of the other port. The memory content can be initialized or cleared by the configuration bitstream so that contents are already present when the device comes out of reset. During a write operation the memory can be set to have the data output either remain unchanged, reflect the new data being written or the previous data now being overwritten.
• The BlockRAMs may be configured as single-port, simple dual-port and true dual-port. Furthermore, embedded dual-port or single-port RAM modules, ROM modules, synchronous FIFOs, and data width converters are easily implemented from BlockRAMs using the Xilinx® CORE Generator™ module generator tool.
• Distributed RAM: The look-up tables in the FPGA can also be configured as RAM and because these are spread throughout the device, we call them distributed RAMs. With the use of surrounding logic, there is great flexibility in how distributed RAM can be used.
• In cases where the SoC RAM topology is not compatible with BlockRAM (e.g., quad-port or bit-addressable RAM) then distributed RAMs can be used. In any case, if the size of the RAM is small (e.g., 16x8, 36x2) then distributed RAMs are generally a better choice than BlockRAM.
• Interfaces to external RAM: FPGAs have a growing amount of internal RAM but it is inefficient to use up whole FPGAs just to map a few Megabytes of RAM from an ASIC. Furthermore, most SoC designs contain much larger RAMs than a few Megabytes, so for these reasons it will probably be necessary to map some of the SoC memory to external RAM components on the boards. FPGAs have the ability to interface through fast IO to external memories and even built-in support for interfacing to standard external RAMs, such as DDR2 and DDR3.
When mapping SoC RAMs it is necessary to adapt the RTL so that the FPGA tool flow can map it into the appropriate resource. We can do this without changing the existing RTL, but instead we add extra RTL files to act as an adaptor between the black-box RAM instantiations in the SoC RTL and the necessary FPGA or external equivalent. We call these adapters “wrappers” and we shall spend some time exploring their use next.
A wrapper is a small piece of RTL that contains an item to be implemented in the FPGA, but which has a top-level boundary that maps to the component/module instantiation in the SoC RTL. Experienced prototypers will be very familiar with wrappers and may indeed have built up their own libraries of wrappers for use in various situations.
The diagram in Figure 88 shows the basic arrangement, in this case two wrappers used in the same level of hierarchy. Good practice in RTL would suggest that this would be at the lowest level of hierarchy of the SoC design but in the prototype, a wrapper adds levels below the logic already in place in the SoC. Strictly speaking this may break the style guide for the SoC project as a whole but may be preferable to editing the RTL in situ to add the new RAMs.
The simplest way to start creating a wrapper is to copy the component/module declaration from the SoC RTL and paste into a new RTL file. We shall later see what other items we might put in the wrapper body.
The first aim of a wrapper is to link the ports on the SoC RTL instantiation to the relevant ports on a module/component which the FPGA synthesis will understand as FPGA or external elements. This module/component may be a different black-box instantiation, for example a Xilinx® RAM macro or an external memory black box, or it may be another layer of hierarchy in which some new RTL infers an FPGA RAM.
Figure 89 shows a schematic generated as an “RTL view” by Synopsys FPGA synthesis.
Note that the port names of the top level, shown as page connectors in the schematic, are the same as the ports on the wrapper. This is not strictly necessary but careful choice of port names will make it easier for others to understand the intent and also some tools will be able to make additional associations by name. For example, during partitioning, the Certify® tool can associate the port names of an instantiated black box within the wrapper, with the pin names of the external memory as described on the board description (see chapter 8)
However, a wrapper can be more sophisticated and can be used to manipulate the SoC top-level ports into something that connects with rather different FPGA or external resources. For example, a wrapper might be written to merge input and output buses on an SoC RAM instantiation, into a common tri-state bus for connection to an external SRAM, as shown in Figure 90.
Here a 1Mx32 SoC RAM cell is being modeled with a small external memory device, using the RTL shown in Figure 91. Again, the top-level ports correspond with the RAM instantiation in the SoC RTL, the lower pin on “extram” correspond with the pin names on the RAM device as they appear in the board description.
In this case both the RAM in the SoC and in the external device are named explicitly. We shall see later how we can make generic wrappers which allow parameterization and allow wider reuse for our wrappers.
Figure 91: VHDL code for wrapper shown in Figure 90 above
-- entity matches ram cell instantiation in ASIC design
entity UMC1048576x32S is -- 1Mx32 RAM
port (
ADR : in std_logic_vector(19 downto 0);
DI : in std_logic_vector(31 downto 0);
DOUT : out std_logic_vector(31 downto 0);
CK : in std_logic;
WEN : in std_logic;-- active low
CEN : in std_logic;-- active low
OEN : in std_logic -- active low
);
end UMC1048576x32S;
architecture wrap of UMC1048576x32S is
component extram is
port (
A : in std_logic_vector(19 downto 0) ;
IO : inout std_logic_vector(31 downto 0) ;
CEn : in std_logic ;
CE2 : in std_logic ;
CE2n: in std_logic ;
GWn : in std_logic ;
Gn : in std_logic ;
CLK : in std_logic );
end component;
signal extrambus : std_logic_vector (31 downto 0);
signal regdi : std_logic_vector (31 downto 0);
begin
process (CK)
begin
if rising_edge (CK) then
regdi <= DI;
end if;
end process;
-- wrapper logic to combine/split input and output data onto bidir on external ram
extrambus <= regdi when WEN ='1' else (others=>'Z');
DOUT <= extrambus;
-- ram declaration matches ram chip on prototype board
UPD44322321: extram -- instance of external 1Meg x 32 Sync SRAM
port map (
A => ADR,
IO=> extrambus,
CEn=> CEN,
CE2=> '1',
CE2n=> '0',
GWn=> WEN,
Gn=> OEN,
CLK=> CK
);
end wrap;
There are a number of tools which help to generate RAM and other memories for use in FPGA and we can use these for creating part of the contents for our wrapper. These tools are extensively used by FPGA designers for everyday production designs but can be equally useful for those using FPGAs only for prototyping. We will mention in particular two tools; CORE Generator tool from Xilinx and SYNCore from Synopsys.
CORE Generator tool creates memory models for implementation only in Xilinx® FPGA, the flow is typically to use the black box instantiation of the memory as created by CORE Generator tool and then the implementation is added-in automatically during place and route. The implementation of the memory (i.e., to fill the black box) is in a Xilinx-specific object format, called ngc, and might even be encrypted. The contents may be used by the synthesis tool if they can understand the ngc format. The FPGA elements can then be inspected for timing or physical information, which are both useful during FPGA synthesis.
As an alternative to CORE Generator tool, Synplify Pro from Synopsys includes a sub-tool called the SYNCore IP Wizard. SYNCore generates portable parameterized RTL for IP elements including RAMs in different configurations such as single-port RAM, dual-port RAM and byte-enabled RAMs. Figure 92 shows a screenshot of SYNCore showing a dual-port RAM being created to target a Virtex-6 FPGA. In this case, the output is human readable Verilog RTL and so fully useable during all stages of FPGA synthesis and place and route.
Tools such as SYNCore and CORE Generator tool allow us to quickly generate the necessary internal FPGA RAMs and other memories for modeling the SoC instantiated memories, via the use of suitable wrappers.
So far we have used wrappers to instantiate equivalent memories in place of the SoC instantiated memory. The memories generated by SYNCore, however, are actually in RTL from which FPGA synthesis can infer the required FPGA memory. This approach can be expanded to allow the creation of a small library of RTL descriptions which can be parameterized by the wrapper to create a large variety of different memories, for example, corresponding with the different types that we listed earlier in Table 16 (see page 195).
An RTL example for a paramaterized RAM is shown in Figure 93 on the next page.
Figure 93: Example of paramaterized generic RAM
module gen_ram #
(
parameter
D_WIDTH = 8,
A_WIDTH = 10,
NUM_RDPORTS = 2 )
(
input wrclk,
input wren,
input [A_WIDTH-1:0] wraddr,
input [D_WIDTH-1:0] wrdata,
input rdclk,
input [(NUM_RDPORTS*A_WIDTH) -1:0] rdaddr,
output reg [(NUM_RDPORTS*D_WIDTH)-1:0] rddata );
reg [D_WIDTH-1:0] mem [(1<<A_WIDTH)-1:0];
integer i;
always @ (posedge wrclk)
begin
if(wren)
mem[wraddr] <= wrdata;
end
always @ (posedge rdclk)
begin
for(i=0;i<NUM_RDPORTS;i=i+1)
rddata[i*D_WIDTH +: D_WIDTH] <= mem[rdaddr[i*A_WIDTH +:
A_WIDTH]];
end
endmodule
This example is a single-write and multiple-read RAM but the number of read ports can be changed by the NUM_RDPORTS parameter. Notice that the defaults in this example are used to set the number of read ports to two, but this would be overridden by a new parameter passed into the RTL from the hierarchy layer above. Synplify Pro would synthesize the above RTL into the RAM structure shown in Figure 94.
When mapped into BlockRAM in a Virtex-6 device, the rddata register bank would also be packed into the BlockRAM.
We have so far considered two different kinds of wrappers. We have seen that some SoC designs do not use wrappers and instead instantiate the SoC memory directly into the surrounding RTL. In those cases, we need to use the SoC memory instantiation itself to define the top of the wrapper and place the FPGA or external equivalent in that.
The second (and best) way to use memory in an SoC design is to put a wrapper around each instantiation, as shown in Figure 96. This requires that some foresight has been given to the needs of the prototypers and falls under the heading of Design-for-Prototyping, as we shall see in chapter 9.
In normal prototype usage, we would replace the wrapper contents that instantiate the SoC memory with wrapper contents that instantiate or infer an FPGA equivalent, or an external chip, as shown in Figure 95.
Let’s now consider a special case where we have a wrapper which instantiates both the SoC memory and the FPGA memory at the same time.
An overview of this arrangement is shown in Figure 97 where we can see that both wrappers are present throughout the verification process and we only choose one during synthesis using the branching macro again. During verification runs, both the FPGA memory model and the SoC memory model are evaluated and assertions are used to compare the output of each, which should be functionally identical. Only the SoC memory’s result is passed to the rest of the logic. Within reasonable limits this should not drastically increase the simulation runtime but we do get the benefit that the FPGA memory is thoroughly tested in all SoC verification runs before being used in the prototype.
Using this approach, any discrepancies involved with assumptions on the RAM models between the SoC and FPGA versions can be found early in the design cycle, in fact even before synthesizing the design.
This methodology will require flow changes in the setup, and would definitely require that the SoC team embrace Design-for-Prototyping methods. Even if this requires some additional effort, we gain the advantage that memory modeling defects are found early in the design cycle.
We could also envisage a generic memory library in which for each memory used in SoC designs company-wide, we have a single file which encapsulates the RAM from ASIC Library, the equivalent RAM using FPGA resources and the equivalency check. If we maintain such a generic memory library then we would not need to make any RTL changes for most memories when it comes to prototyping.
Manufacturer:Xilinx
Product Categories: CPLDs
Lifecycle:Active Active
RoHS:
Manufacturer:Xilinx
Product Categories: CPLDs
Lifecycle:Active Active
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories: CPLDs
Lifecycle:Active Active
RoHS:
Manufacturer:Xilinx
Product Categories: Embedded - CPLDs (Complex Programmable Logic Devices)
Lifecycle:Active Active
RoHS: No RoHS
Manufacturer:Xilinx
Product Categories: FPGAs
Lifecycle:Obsolete -
RoHS: No RoHS
Support