Inferring block ram in Spartan II with non standard bus size

G

Guy_Sweden

Guest
Hello.
Im relatively new to VHDL and im doing a small project in which i've to
store the co-efficients of the FIR filter into the block ram at system
startup which are supposed to be used later by the filter block for
implementing the MAC operation needed for the filter.
I am using spartan II by xilinx. First of all, what i'd like to know is
that, what does the phrase 'infer from the code' imply in the context
of memory instantiation in vhdl or any HD.
I used to think that there are dedicated hardware memory blocks on the
FPGA and we need to address the port pins as in done in microcontroller
programming environments and the like. After reading for a while and
coming accross many codes for that, I now understand it as the
synthesis tool 'realises' such a block in the FPGA. The only
restriction we have is that we should write code keeping in mind the
actual hardware capabilities of the board and/or the target device.
Like incase of the XC2S50 device we can instantiate 8 blocks of 4K bits
each and so on.
Is my thinking correct in this regard or is there something which i am
overlooking and/on misinterpreting?

Now heres the second question: The block ram in the spartan II FPGA is
arranged as 4K blocks and the blocks can have variable address and data
bus widths depending on the width of the data bus.
My data is 10 bits wide and I actually need 9 (actually 8.6) bits to
address that data. So when I write the code for that, can I declare an
input port which is 10 bits wide (std_logic_vector(9 downto 0) ) or do
I have to specify it using a signal which is 16 bits wide. The xilinx
user manual says that the block ram can have data widths of 1,2,4,8,
and 16. So if I declare my signal as 10 bits wide does the tool infer
the code and create a 4K block with a data bus which is 16 bits wide.

Heres a sample code which I've adapted from my synthesis tool vendor's
reference guide:

LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
USE ieee.std_logic_unsigned.all;

ENTITY syncram_sndsmple IS
generic (
data_width : natural := 10;
addr_width : natural := 4);

port (
clk : in std_logic;
we : in std_logic;
addr : in std_logic_vector(addr_width - 1 downto 0);
data_in : in std_logic_vector(data_width - 1 downto 0);
data_out : out std_logic_vector(data_width - 1 downto 0));

END ENTITY syncram_sndsmple ;

--
ARCHITECTURE rtl OF syncram_sndsmple IS

type mem_type is array (2**addr_width downto 0) of
std_logic_vector(data_width - 1 downto 0);
signal mem : mem_type;
signal addr_reg : std_logic_vector(addr_width - 1 downto 0);
attribute block_ram : boolean;
attribute block_ram of mem : signal is true;
begin
singleport_sndsmple : process(clk)
begin
if clk'event and clk = '1' then
if we = '1' then
mem(conv_integer(addr)) <= data_in;
end if;
addr_reg <= addr;
end if;
end process singleport_sndsmple;
data_out <= mem(conv_integer(addr_reg));

END ARCHITECTURE rtl;

Is this enough for it to be up and running. If I instantiate a
component which uses the above entity will it create a 'RAM - like'
structure on the FPGA die while programming?
How does the tool know that it has to create a RAM when it synthesizes
the above code? in the example above, does the 'block_ram' attribute
tells the synthesis tool that we are asking for a dedicated Block RAM
and we do not want it to be implemented using the CLB of the FPGA? So
is using such vendor specific attributes the way by which the synthesis
tool infers what it is meant to synthesize?

A last question: If I want to have more than 16 bit wide data bus, say
a 20 bit bus, do I just have to change it in the generic map for the
data_width and the synthesis tool will infer and create two 4K block
RAMs (in case of spartan II devices) and then cascade them to obtain
the given data width?

Help would be sincerely appreciated.

With best Regards,
Aijaz Baig.
 
A couple of answers:

"Infer from the code". If the synthesizer is smart, it can spot a RAM
in your code, and automatically utilize a block RAM (or distributed
RAM) primitive.

Last time I checked, Xilinx's XST was _not_ that smart. Other's are,
but if you're using XST you'll probably need to use CoreGen.

I agree about accomidating the hardware with your coding. One thing I
do is put wrappers around any vendor-specific primitives. That way if
I wind up porting the code, I know where to find the "problems".

Your 10-bit wide RAM can be made from an 8-bit & a 2-bit in parallel.

If you have a sparse addressing space, you can do "interesting" things
with the address bits to realize them.

I once built a 192x12 memory using tactics similar to the above.

GH
 
ghelbig@lycos.com wrote:
A couple of answers:

"Infer from the code". If the synthesizer is smart, it can spot a RAM
in your code, and automatically utilize a block RAM (or distributed
RAM) primitive.

Last time I checked, Xilinx's XST was _not_ that smart. Other's are,
but if you're using XST you'll probably need to use CoreGen.

I agree about accomidating the hardware with your coding. One thing I
do is put wrappers around any vendor-specific primitives. That way if
I wind up porting the code, I know where to find the "problems".

Your 10-bit wide RAM can be made from an 8-bit & a 2-bit in parallel.

If you have a sparse addressing space, you can do "interesting" things
with the address bits to realize them.

I once built a 192x12 memory using tactics similar to the above.


The "horse's mouth" on inferring logic in Xilinx parts is the Libraries
Guide (versions exist for the different FPGA families).
It gives generic VHDL (& Verilog) templates, which will infer each of
the major primitives.
I haven't tried using those templates with a non-standard bus width, but
if it fails, it's pretty trivial to pad the unused bits to the next
larger size.
 

Welcome to EDABoard.com

Sponsor

Back
Top