问题描述
我试图在中实现双端口RAM出色的博客文章.但是,Modelsim在编译时会发出以下警告:
** Warning: fifo_ram.vhdl(24): (vcom-1236) Shared variables must be of a protected type.
我似乎也无法将其创建为波浪,向我表明,该变量没有使用下面的代码识别.
如何正确将此变量正确声明为"受保护"类型?另外,作为关于共享变量的更一般的问题 - 设计中所有实体之间的这个变量是否共享?
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; entity fifo_ram is generic (data : natural := 8; addr : natural := 16); port (w_clk : in std_logic; w_en : in std_logic; w_addr : in std_logic_vector (addr-1 downto 0); w_data : in std_logic_vector (data-1 downto 0); -- r_clk : in std_logic; r_rdy : in std_logic; r_addr : in std_logic_vector (addr-1 downto 0); r_data : out std_logic_vector (data-1 downto 0)); end fifo_ram; architecture rtl of fifo_ram is -- shared memory type mem_type is array ( (2**addr) - 1 downto 0 ) of std_logic_vector(data-1 downto 0); shared variable mem : mem_type; begin write: process (w_clk) begin if (rising_edge(w_clk)) then if (w_en = '1') then mem(conv_integer(w_addr)) := w_data; end if; end if; end process write; end architecture; ---------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; entity tb_fifo is generic (data : natural := 8; addr : natural := 16); end entity; architecture testbed of tb_fifo is signal tb_w_clk, tb_w_en : std_logic := '0'; signal tb_w_addr : std_logic_vector (addr-1 downto 0); signal tb_w_data : std_logic_vector (data-1 downto 0); signal tb_r_clk, tb_r_rdy : std_logic := '0'; signal tb_r_addr : std_logic_vector (addr-1 downto 0); signal tb_r_data : std_logic_vector (data-1 downto 0); begin dut : entity work.fifo_ram(rtl) port map(tb_w_clk, tb_w_en, tb_w_addr, tb_w_data, tb_r_clk, tb_r_rdy, tb_r_addr, tb_r_data); wclock : process is begin tb_w_clk <= '1'; wait for 10 ns; tb_w_clk <= '0'; wait for 10 ns; end process wclock; wdata : process is begin tb_w_addr <= x"FFFF"; tb_w_data <= x"AA"; wait for 100 ns; tb_w_en <= '1'; wait for 70 ns; tb_w_en <= '0'; wait; end process wdata; end architecture;
推荐答案
好的,浏览了博客文章,我现在明白了为什么他们使用共享变量而不是信号.它的原因是多个过程分配给了此变量,在Verilog或VHDL中的A Signal 中,这是不可能的.在这种情况下,合成器将对 mem 的多个驱动程序产生错误.但是,为了在这种情况下使用共享变量,您必须将其声明为保护.您需要做的是声明受保护的数据类型,然后在其中封装您的 mem 变量,就像面向对象的语言中的类一样.这是受保护数据类型的示例:
type mem_envelope is protected -- protected type declaration variable mem : mem_type; function GetVal( addr : integer ) return std_logic_vector(data - 1 downto 0); function SetVal( addr : integer; val : std_logic_vector(data - 1 downto 0) ) return boolean; --may be used to indicate whether write was successfull or not end protected mem_envelope;
然后声明类型mem_envelope的共享变量,并使用 getVal 和 setVal 函数以读取/写入进程中的内存.
其他推荐答案
实现真实dual-port(TDP)RAM的另一种方法是使用一个处理两个时钟.
signal ram : ram_t; signal a1_reg : unsigned(A_BITS-1 downto 0); signal a2_reg : unsigned(A_BITS-1 downto 0); .... process (clk1, clk2) begin -- process if rising_edge(clk1) then if ce1 = '1' then if we1 = '1' then ram(to_integer(a1)) <= d1; end if; a1_reg <= a1; end if; end if; if rising_edge(clk2) then if ce2 = '1' then if we2 = '1' then ram(to_integer(a2)) <= d2; end if; a2_reg <= a2; end if; end if; end process; q1 <= ram(to_integer(a1_reg)); -- returns new data q2 <= ram(to_integer(a2_reg)); -- returns new data
这甚至可以使用Xilinx工具进行合成. Altera工具需要Altsyncram宏才能获得适当的TDP-RAM识别.
问题描述
I was attempting to implement a dual port RAM as guided in this excellent blog post. However, ModelSim is giving the following warning when compiling:
** Warning: fifo_ram.vhdl(24): (vcom-1236) Shared variables must be of a protected type.
I also seem unable to create this as a wave, indicating to me that the variable is not being recognised using my code below.
How can I correctly declare this variable as a "protected" type? Also, as a more general question about shared variables - is this variable shared between all entities in a design?
library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; entity fifo_ram is generic (data : natural := 8; addr : natural := 16); port (w_clk : in std_logic; w_en : in std_logic; w_addr : in std_logic_vector (addr-1 downto 0); w_data : in std_logic_vector (data-1 downto 0); -- r_clk : in std_logic; r_rdy : in std_logic; r_addr : in std_logic_vector (addr-1 downto 0); r_data : out std_logic_vector (data-1 downto 0)); end fifo_ram; architecture rtl of fifo_ram is -- shared memory type mem_type is array ( (2**addr) - 1 downto 0 ) of std_logic_vector(data-1 downto 0); shared variable mem : mem_type; begin write: process (w_clk) begin if (rising_edge(w_clk)) then if (w_en = '1') then mem(conv_integer(w_addr)) := w_data; end if; end if; end process write; end architecture; ---------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; use ieee.numeric_std.all; entity tb_fifo is generic (data : natural := 8; addr : natural := 16); end entity; architecture testbed of tb_fifo is signal tb_w_clk, tb_w_en : std_logic := '0'; signal tb_w_addr : std_logic_vector (addr-1 downto 0); signal tb_w_data : std_logic_vector (data-1 downto 0); signal tb_r_clk, tb_r_rdy : std_logic := '0'; signal tb_r_addr : std_logic_vector (addr-1 downto 0); signal tb_r_data : std_logic_vector (data-1 downto 0); begin dut : entity work.fifo_ram(rtl) port map(tb_w_clk, tb_w_en, tb_w_addr, tb_w_data, tb_r_clk, tb_r_rdy, tb_r_addr, tb_r_data); wclock : process is begin tb_w_clk <= '1'; wait for 10 ns; tb_w_clk <= '0'; wait for 10 ns; end process wclock; wdata : process is begin tb_w_addr <= x"FFFF"; tb_w_data <= x"AA"; wait for 100 ns; tb_w_en <= '1'; wait for 70 ns; tb_w_en <= '0'; wait; end process wdata; end architecture;
推荐答案
OK, having gone through the blog post I now understand why they're using shared variable instead of signals. Its because multiple processes are assigning to this variable, which is not possible in the case of a reg in Verilog or a signal in VHDL. In that case the synthesizer will produce an error complaining of multiple drivers for mem. But in order to use shared variable in this case, you'll have to declare it as protected. What you need to do is declare a protected data type, and then encapsulate your mem variable inside it, much like classes in object oriented languages. Here's an example of the protected data type:
type mem_envelope is protected -- protected type declaration variable mem : mem_type; function GetVal( addr : integer ) return std_logic_vector(data - 1 downto 0); function SetVal( addr : integer; val : std_logic_vector(data - 1 downto 0) ) return boolean; --may be used to indicate whether write was successfull or not end protected mem_envelope;
Then declare a sharede variable of type mem_envelope and use GetVal and SetVal functions to read/write values to the memory inside your processes.
其他推荐答案
Another way of implementing a True-Dual-Port (TDP) RAM is to use one process with two clocks.
signal ram : ram_t; signal a1_reg : unsigned(A_BITS-1 downto 0); signal a2_reg : unsigned(A_BITS-1 downto 0); .... process (clk1, clk2) begin -- process if rising_edge(clk1) then if ce1 = '1' then if we1 = '1' then ram(to_integer(a1)) <= d1; end if; a1_reg <= a1; end if; end if; if rising_edge(clk2) then if ce2 = '1' then if we2 = '1' then ram(to_integer(a2)) <= d2; end if; a2_reg <= a2; end if; end if; end process; q1 <= ram(to_integer(a1_reg)); -- returns new data q2 <= ram(to_integer(a2_reg)); -- returns new data
This is even synthezisable with Xilinx tools. Altera tools need the altsyncram macro for a proper TDP-RAM recognition.
Source: PoC.mem.ocram.tdp