收藏并分享一篇文章,内容是使用VHDL语言来描述Block Ram,防止丢失,侵删。
原文链接:https://www.eefocus.com/guozhiyang/blog/14-03/302339_47a70.html?mobile=1
Block Ram作为一种固定资源存在于FPGA内,我们在设计中当然要好好加以利用,以便节省我们有限的LUT。使用Block Ram一般来讲有两种方法,一是用IP Core Generator,二是自己用硬件语言来描述。当然了,使用IP Core是最省事的一种做法,如今ISE的Core Generator的功能也很强大,可以帮助你定制一个符合你特殊设计要求的Block Ram。也正因为其界面很友好,大家使用起来应该也没什么难度,故这里不再赘述了,今天要说的是用HDL语言来描述Block Ram。这种方法虽然不像前者那么简便,但是好处就在于它的灵活性和可移植性。先来看看下面的VHDL代码:
–BRam.vhd
–Author:SCUT FPGA | Yili Chen
–This file describes a block ram
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity BRam is
generic
(
width: integer := 16; --Data width
depth: integer := 8 --Addr depth
);
port
(
clk : in std_logic;
addr : in std_logic_vector(depth - 1 downto 0);
cs : in std_logic;
we : in std_logic;
din : in std_logic_vector(width - 1 downto 0);
dout : out std_logic_vector(width - 1 downto 0)
);
end BRam;
architecture Behavioral of BRam is
type RamType is array(2 ** depth - 1 downto 0) of std_logic_vector(width - 1 downto 0);
signal Ram : RamType;
begin
process(clk)
begin
if clk’event and clk = ‘1’ then
if cs = ‘0’ then
if we = ‘1’ then
Ram(conv_integer(addr)) <= din;
else
dout <= Ram(conv_integer(addr));
end if;
end if;
end if;
end process;
end Behavioral;
好了,以上就是所有代码,它描述了一个简单的单口Ram。通过更改generic中的width和depth参数,我们便可以定制不同数据宽度和地址宽度的block ram,最主要的优点是,用HDL语言描述的Ram具有良好的可移植性。让我们再来看看这个文件的综合报告(使用ISE 10.1 WebPack):
-
HDL Synthesis *
=========================================================================
Performing bidirectional port resolution…
Synthesizing Unit .
Related source file is "H:/AESZigBee/BRam/HDL_Ram.vhd".
Found 256x16-bit single-port RAM <Mram_Ram> for signal <Ram>.
Found 16-bit register for signal <dout>.
Summary:
inferred 1 RAM(s).
inferred 16 D-type flip-flop(s).
Unit synthesized.
Synthesizing Unit .
Related source file is “H:/AESZigBee/BRam/RamTest.vhf”.
Unit synthesized.
=========================================================================
HDL Synthesis Report
Macro Statistics
RAMs : 1
256x16-bit single-port RAM : 1
Registers : 1
16-bit register : 1
=========================================================================
-
Advanced HDL Synthesis *
=========================================================================
Loading device for application Rf_Device from file ‘3s500e.nph’ in environment H:\ISE\ISE.
Synthesizing (advanced) Unit .
INFO:Xst - The RAM <Mram_Ram> will be implemented as a BLOCK RAM, absorbing the following register(s):
-----------------------------------------------------------------------
| ram_type | Block | |
-----------------------------------------------------------------------
| Port A |
| aspect ratio | 256-word x 16-bit | |
| mode | no-change | |
| clkA | connected to signal <clk> | rise |
| enA | connected to signal <cs> | low |
| weA | connected to signal <we> | high |
| addrA | connected to signal <addr> | |
| diA | connected to signal <din> | |
| doA | connected to signal <dout> | |
-----------------------------------------------------------------------
| optimization | speed | |
-----------------------------------------------------------------------
Unit synthesized (advanced).
Advanced HDL Synthesis Report
Macro Statistics
RAMs : 1
256x16-bit single-port block RAM : 1
可以看到该实体被综合成Block Ram了,并且加了16bit的输出寄存器。这实际上就相当于在IP Gen中选择了一个No read on write(即no-change,在写数据时输出不会改变)模式的单口Ram,并且选择加入输出寄存器。如果进行时序仿真我们可以看到,在we为低后的第二个时钟上升沿输出数据才会被更新,具体原因我猜测应该是由于综合器引入输出寄存器所致的,因为在IP Gen生成的Ram中如果使用了输出寄存器也将会是在第二个时钟触发沿才会更新数据。另外我们如果把
if we = ‘1’ then
Ram(conv_integer(addr)) <= din;
改成:
if we = ‘1’ then
dout <= Ram(conv_integer(addr));
Ram(conv_integer(addr)) <= din;
大家猜猜看综合结果会是什么样呢?没错,这时它会变成一个read-first模式的Block Ram,也就是在写数据之前它会先读出当前内存地址的数据来作为输出。
三种Ram的模式已经实现两种了,那write-first模式该怎么实现呢?呵呵,很简单,把刚刚加进去那个语句改成 dout <= din; 就行了。这时写入的数据会优先更新到输出,而不理会内存中原有的数据内容。
至于Distributed Ram的HDL描述呢,其实改动也只是很小,加个wr信号就行了