This website uses cookies. By using this site, you consent to the use of cookies. For more information, please take a look at our Privacy Policy.
Home > FPGA Technical Tutorials > FPGA-Based Prototyping Methodology > Getting the design ready for the prototype > Handling instantiated SoC RAM in FPGA

TABLE OF CONTENTS

Xilinx FPGA FPGA Forum

Handling instantiated SoC RAM in FPGA

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).

Note: RAMs in Virtex®-6 FPGAs

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.

Using memory wrappers

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.

Basic concept of a wrapper for memory.png

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.

Wrappers to instantiate equivalent FPGA RAMs

Figure 89 shows a schematic generated as an “RTL view” by Synopsys FPGA  synthesis.

Typical wrapper for instantiate FPGA RAM as seen in Synplify® RTL.png

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.

Wrapper merging SoC RAM data ports onto bidir port on external.png

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;

Tools for generating replacement memories

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.  

Synopsys SYNCore memory compiler.png

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.

Wrappers to infer equivalent RAMs

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.

RAM structure inferred by RTL in Figure 93.png

When mapped into BlockRAM in a Virtex-6 device, the rddata register bank would  also be packed into the BlockRAM.

Advanced self-checking wrappers

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.

Preferred wrapper in SoC design using Design-for-Prototyping.png

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.

Switching between wrappers using `define fpga macro.png

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.

Self-checking RAM model.png

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.



  • XC2C384-10TQG144I

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 9K Gates 384 Macro Cells 125MHz 0.18um Technology 1.8V 144-Pin TQFP
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS:

  • XC2C384-7PQ208C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 9K Gates 384 Macro Cells 217MHz 0.18um Technology 1.8V 208-Pin PQFP
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS: No RoHS

  • XC2C512-10FG324C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 12K Gates 512 Macro Cells 128MHz 0.18um Technology 1.8V 324-Pin FBGA
  • Product Categories: CPLDs

    Lifecycle:Active Active

    RoHS:

  • XC2C512-10FT256C

    Manufacturer:Xilinx

  • CPLD CoolRunner -II Family 12K Gates 512 Macro Cells 128MHz 0.18um Technology 1.8V 256-Pin FTBGA
  • Product Categories: Embedded - CPLDs (Complex Programmable Logic Devices)

    Lifecycle:Active Active

    RoHS: No RoHS

  • XC5215-5HQ208C

    Manufacturer:Xilinx

  • FPGA XC5200 Family 23K Gates 1936 Cells 83MHz 0.5um Technology 5V 208-Pin HSPQFP EP
  • Product Categories: FPGAs

    Lifecycle:Obsolete -

    RoHS: No RoHS

Need Help?

Support

If you have any questions about the product and related issues, Please contact us.