【问题标题】:VHDL - Writing To RegistersVHDL - 写入寄存器
【发布时间】:2013-01-26 01:04:06
【问题描述】:

我想使用四个按钮作为输入,三个七段 LED 显示器作为输出。两个按钮应通过 16 个 RAM 位置上下移动;另外两个应该增加和减少当前显示的内存位置的内容。一个七段显示器应显示当前地址 (0–F),另外两个应以十六进制 (00–FF) 显示该位置的内容。这是我尝试执行此操作的代码(我还没有实现显示):

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity raminfr is
    port (
        clk : in std_logic;
        we : in std_logic;
        do : out unsigned(7 downto 0)
    );
end raminfr;

architecture rtl of raminfr is

type ram_type is array (0 to 15) of unsigned(7 downto 0);
signal RAM : ram_type;
signal read_a : unsigned(3 downto 0);
signal a : unsigned(3 downto 0);
signal di : unsigned(7 downto 0);
signal clock : std_logic;
signal key : std_logic_vector(3 downto 0);
begin
  U1: entity work.lab1 port map (
    clock =>clock,
    key => key,
    register_counter => a,
    value_counter => di
  );
process (clk)
begin
    if rising_edge(clk) then
        if we = '1' then
            RAM(to_integer(a)) <= di;
        end if;
        read_a <= a;
    end if;
end process;
do <= RAM(to_integer(read_a));
end rtl;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity lab1 is
    port(
        clock : in std_logic;
        key : in std_logic_vector(3 downto 0); 
        value_counter   : buffer unsigned(7 downto 0) ;
        register_counter : buffer unsigned(3 downto 0) 
        );
end lab1;

architecture up_and_down of lab1 is
    signal value_in_ram : unsigned(7 downto 0);
    signal clk : std_logic;
    signal we : std_logic;
        begin
        U1: entity work.raminfr port map (
            do=>value_in_ram,
            clk=>clk,
            we=>we
        );
    process(clock, value_counter, register_counter)
        begin
            if rising_edge(clock) then
                if (key(3)='0' and key(2)='0' and key(1)='1' and key(0)='0') then
                    value_counter <= value_counter + "1";   
                elsif (key(3)='0' and key(2)='0' and key(1)='0' and key(0)='1') then  
                    value_counter <= value_counter - "1";   
                elsif (key(3)='1' and key(2)='0' and key(1)='0' and key(0)='0') then
                    register_counter<= register_counter + "1";
                    value_counter <= value_in_ram;
                elsif (key(3)='0' and key(2)='1' and key(1)='0' and key(0)='0') then
                    register_counter<= register_counter - "1";
                    value_counter <= value_in_ram;
                end if;
            end if;
    end process;
end architecture up_and_down;

当我尝试编译它时,我会一遍又一遍地重复以下错误:

Error (12051): Project too complex: hierarchy path is too long
Error (12052): Entity "lab1" is instantiated by entity "raminfr"
Error (12052): Entity "raminfr" is instantiated by entity "lab1"

这显然是由于我已经将每个实体的端口映射到另一个,但我不知道任何其他方式来完成我想要完成的任务。有人可以提出替代方案吗?

【问题讨论】:

  • 试着描述一下你想要完成的事情怎么样?这段代码再次让我们猜测。

标签: vhdl


【解决方案1】:

这是一个猜测,因为不太清楚你想做什么。似乎问题在于设计:您很清楚最终结果应该做什么,但不清楚如何将其分解为以最简单的方式交互以实现目标的组件。

我的猜测是基于“raminfr”中的活动代码存储和加载数据独立于其他已经潜入的东西的事实。

所以我建议将“raminfr”作为一个内存组件进行清理,而不需要任何其他东西。然后它可以嵌入到处理键的“lab1”组件中,并存储和显示来自正确寄存器的值。它也可以在您需要记忆的任何地方重复使用。

让我们来看看 raminfr。

entity raminfr is
    port (
        clk : in std_logic;
        we : in std_logic;
        do : out unsigned(7 downto 0)
    );
end raminfr;

它有一个时钟、一个写使能输入和一个数据输出。但奇怪的是,没有地址或数据输入!现在,内存是一种标准的“设计模式”,偏离它可能是不明智的,所以让我们添加它们......

entity raminfr is
    port (
        clk  : in std_logic;
        we   : in std_logic;
        addr : in unsigned(3 downto 0);
        di   : in  unsigned(7 downto 0);
        do   : out unsigned(7 downto 0)
    );
end raminfr;

记忆模式的一些变体具有其他特征;读使能、输出使能、单独的读和写时钟等,但这个简单的在这里就可以了。

您还可以使用泛型来自定义其大小,修改其数据和地址总线宽度以匹配。这使得它更加有用,并节省了大量相似但不同的模块......

让我们清理架构以匹配。

architecture rtl of raminfr is
   type ram_type is array (0 to 15) of unsigned(7 downto 0);
   signal RAM    : ram_type;
   signal read_a : unsigned(3 downto 0);
begin
process (clk)
...
end process;
do <= RAM(to_integer(read_a));
end rtl;

现在我们可以在“lab1”模块中实例化它,连接它的新端口

    U1: entity work.raminfr port map (
        addr => register_counter,   -- was "a", typo
        di   => value_counter,
        do   => value_in_ram,
        clk  => clk,
        we   => we
    );

并对 lab1 的其余部分进行任何支持性更改。

这不是唯一合理的分解:您还可以使“lab1”成为一个没有自己存储的简单组件,并带出其他必要的信号作为端口。然后,您将需要第三个“顶级”实体,其架构将 lab1 和 raminfr 相互连接。

【讨论】:

  • 在您的示例中,我们将 a 映射到 register_counter 并将 di 映射到 value_counter。但是,在我看来,由于 a 和 di 是 RAM 的输入,我们应该做相反的事情,不是吗?我的印象是映射只能以一种方式工作,在这种情况下,如果我错了,请纠正我。
  • 抱歉打错了:我在端口列表中将地址称为“addr”,在端口映射中称为“a”-现已修复-这不会帮助您理解...端口映射有效无论端口是输入、输出、输入输出还是缓冲区,都以相同的方式循环(正式 => 实际)。我希望这可以澄清事情。
  • 所以如果我们将a映射到register_counter,我们本质上也是将register_counter映射到a?
  • 我们将它们连接在一起。
  • 这是让我感到困惑的部分 - 我认为这只是一种单向关系,这就是我将两个实体相互映射的原因。
猜你喜欢
  • 2013-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 2017-07-16
相关资源
最近更新 更多