VHDL - Writing To Registers

我是研究僧i 提交于 2019-12-12 03:44:49

问题


I want to use four push buttons as inputs and three seven-segment LED displays as outputs. Two push buttons should step up and down through the sixteen RAM locations; the other two should increment and decrement the contents of the currently-displayed memory location. One seven segment display should show the current address (0–F), and two others should display the contents of that location in hexadecimal (00–FF). This is my code to attempt to do this (I haven't implemented the display yet):

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;

When I try to compile this, I get the following errors repeating over and over:

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"

This is obviously due to the fact that I have port mapped each entity in the other, but I don't know any other way to accomplish what I want to accomplish. Can somebody suggest alternatives?


回答1:


This is a guess since it's not too clear what you want to do. It seems that the problem is one of design : you have a good idea what the end result should do, but it's not clear how to decompose that into components which interact in the simplest way to accomplish the goal.

I am basing this guess on the fact that the active code in "raminfr" stores and loads data independent of the other stuff that has crept in.

So I am going to suggest that "raminfr" be cleaned up as just a memory component WITHOUT any of the other stuff. It can then be embedded in the "lab1" component which handles keys, and stores and displays values from the correct registers. It can also be reused anywhere else you need a memory.

So let's look at raminfr.

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

It has a clock, a write enable input, and a data output. But curiously, no address or data inputs! Now, memory is such a standard "design pattern" that deviation from it is probably ill advised, so let's add them...

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;

Some variants of the memory pattern have other features; read enables, output enables, separate read and write clocks, etc but this simple one will do here.

You can also use generics to customise its size, modifying its data and address bus widths to match. This makes it much more useful and saves a proliferation of similar but different modules...

Let's clean up the architecture to match.

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;

Now we can instantiate it in the "lab1" module, connecting up its new ports

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

and making any supporting changes to the rest of lab1.

This is not the only reasonable decomposition : you could also make "lab1" a simple component without its own storage and bring out other necessary signals as ports. Then you would need a third "top level" entity whose architecture interconnected lab1 and raminfr.



来源:https://stackoverflow.com/questions/14532705/vhdl-writing-to-registers

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!