How to test a VHDL file - vhdl

I've made a dual port register bank in VHDL, and I want to test it to make sure it works. How would I go about doing this? I know what I want to do (set register 2 to be a constant, read out of it in test program, write to register 3 and read it back out and see if I have the same results).
Only thing is, I'm new to VHDL, so I don't know if there's a console or how a test program is structured or how to instantiate the register file, or even what to compile it in (I've been using quartus so far).
Here's my register file:
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
-- Register File
entity RF is
port(
signal clk, we: in std_logic;
signal ImmediateValue : in std_logic_vector(15 downto 0);
signal RegisterSelectA, RegisterSelectB : in integer range 0 to 15;
signal AOut, BOut : out std_logic_vector(15 downto 0)
);
end RF
architecture behavior of RF is
array std_logic_vector_field is array(15 downto 0) of std_logic_vector(15 downto 0);
variable registers : std_logic_vector(15 downto 0);
process (clk, we, RegisterSelectA, RegisterSelectB, ImmediateValue)
wait until clk'event and clk = '1';
registers(RegisterSelectA) := ImmediateValue when we = '1';
AOut <= registers(RegisterSelectA);
BOut <= registers(RegisterSelectB);
end process;
end behavior;

First of all, if you are new to VHDL design, you might be best off starting with a tutorial on the web, or grabbing a book like "The Designer's Guide to VHDL".
Anyway, just like a software design, to test a VHDL design, you have to write some test code. In hardware design, usually these tests are unit-test like, but are often called "testbenches".
For the design you've given, you'll need to create something like this:
library ieee.std_logic_1164.all;
library ieee.numeric_std.all;
entity test_RF is
end entity;
architecture test of test_RF is
signal clk, we: std_logic;
signal ImmediateValue : std_logic_vector(15 downto 0);
signal RegisterSelectA, RegisterSelectB : integer range 0 to 15;
signal AOut, BOut : std_logic_vector(15 downto 0)
begin
-- Instantiate the design under test
u_RF : entity work.RF
port map (
clk => clk,
we => we,
ImmediateValue => ImmediateValue,
RegisterSelectA => RegisterSelectA,
RegisterSelectB => RegisterSelectB,
AOut => AOut,
BOut => BOut
);
-- create a clock
process is
begin
clk <= '0';
loop
wait for 10 ns;
clk <= not clk;
end loop;
end process;
-- create one or more processes to drive the inputs and read the outputs
process is
begin
wait until rising_edge(clk);
-- do stuff
-- use assert to check things
-- etc
end process;
end architecture;

Related

How to implement a test bench file for a 8x1 Multiplexer with 32-bit line width?

I'm writing a VHDL code to model an 8x1 multiplexer where each input has 32-bit width. So I created an array to model the MUX but now I'm stuck with the Test Bench, it's gotten so complicated. Here is my original file (I'm sure it has so many redundancies) How can I actually make the test bench to recognize my array (R_in) from the component's file and then how will I stimulate it?
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
ENTITY mux8_1 IS
PORT(Rs :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
in0,in1,in2,in3,in4,in5,in6,in7 :IN STD_LOGIC_VECTOR(31 DOWNTO 0);
R_out :OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
);
END mux8_1;
ARCHITECTURE behaviour OF mux8_1 IS
type t_array_mux is array (0 to 7) of STD_LOGIC_VECTOR(31 DOWNTO 0);
signal R_in:t_array_mux;
BEGIN
R_in(0) <= in0;
R_in(1) <= in1;
R_in(2) <= in2;
R_in(3) <= in3;
R_in(4) <= in4;
R_in(5) <= in5;
R_in(6) <= in6;
R_in(7) <= in7;
process(R_in, Rs)
BEGIN
CASE Rs IS
WHEN "000"=>R_out<=R_in(0);
WHEN "001"=>R_out<=R_in(1);
WHEN "010"=>R_out<=R_in(2);
WHEN "011"=>R_out<=R_in(3);
WHEN "100"=>R_out<=R_in(4);
WHEN "101"=>R_out<=R_in(5);
WHEN "110"=>R_out<=R_in(6);
WHEN "111"=>R_out<=R_in(7);
WHEN OTHERS=>R_out<= (others => '0');
END CASE;
END process;
END behaviour;
And here is my "in progress" test bench file. Just ignore the "stimulus process" part I know it's wrong I just couldn't figure out how to write it for a 32-bit signal.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use ieee.numeric_std.all;
ENTITY mux8_1_TB IS
END mux8_1_TB;
ARCHITECTURE behaviour OF mux8_1_TB IS
COMPONENT mux8_1
PORT(Rs :IN STD_LOGIC_VECTOR(2 DOWNTO 0);
in0,in1,in2,in3,in4,in5,in6,in7 :IN STD_LOGIC_VECTOR(31 DOWNTO 0);
R_out :OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
);
END COMPONENT;
type t_array_mux is array (0 to 7) of STD_LOGIC_VECTOR(31 DOWNTO 0);
--Inputs
signal R_in:t_array_mux:=(others=>'0');
signal in0,in1,in2,in3,in4,in5,in6,in7 :STD_LOGIC_VECTOR(31 DOWNTO 0):=(others=>'0');
signal Rs :STD_LOGIC_VECTOR(2 DOWNTO 0):=(others=>'0');
--Outputs
signal R_out:STD_LOGIC_VECTOR(31 DOWNTO 0);
-- Instantiate the Unit Under Test + connect the ports to my signal
BEGIN
R_in(0) <= in0;
R_in(1) <= in1;
R_in(2) <= in2;
R_in(3) <= in3;
R_in(4) <= in4;
R_in(5) <= in5;
R_in(6) <= in6;
R_in(7) <= in7;
uut: mux8_1 PORT MAP(
Rs=>Rs,
R_in=>R_in,
R_out=>R_out
);
-- Stimulus process (where the values -> inputs are set)
PROCESS
begin
R_in<="01010101";
wait for 10 ns;
Rs<="001";
wait for 10 ns;
Rs<="010";
wait for 20 ns;
Rs<="011";
wait for 30 ns;
Rs<="100";
wait for 40 ns;
Rs<="101";
wait for 50 ns;
Rs<="110";
wait for 60 ns;
Rs<="111";
wait for 70 ns;
END PROCESS;
END;
You need to change your uut port map so instead of R_in, it has individual in0 - in7 ports to match your mux8_1 component definition. Then, map in0 - in7 testbench signals directly to these ports:
uut: mux8_1 port map(
...
in0 => in0,
in1 => in1,
...
);
Or if you want to keep the R_in signal, port map like this:
uut: mux8_1 port map(
...
in0 => R_in(0),
in1 => R_in(1),
...
);
This assignment to R_in in your testbench is incorrect:
R_in<="01010101";
R_in is defined as a t_array_mux type, so it can't be assigned a bit vector value. It has to be assigned to an array of 32-bit std_logic_vector. That line should really be removed altogether, as you're already making assignments to R_in in another location outside of the process. Multiple assignments will cause signal contention.
You're initializing R_in in your testbench like this:
signal R_in:t_array_mux:=(others=>'0');
The others keyword as you've used it will only work on an individual std_logic_vector. You need to nest others for your array of std_logic_vector:
signal R_in:t_array_mux:=(others=>(others=>'0'));
You'll want to assign values to your 32-bit in0 - in7 signals so you can see the output of your mux change in the sim. They can be assigned outside the stimulus process. You can assign them using hex-notation (x preceding "") or just binary:
in0 <= x"12345678"; --hex
or
in0 <= "00010010001101000101011001111000"; --binary
Your stimulus process looks fine. As you change Rs, you would expect to see the different input values on R_out. You could add a single wait; at the end of the process, or the process will keep repeating until the end of sim.
Component ports with user-defined types
Alternatively, you could port map your R_in testbench signal directly to a R_in port on your component as you've done, but it would take a bit more work. Your mux8_1 component definition does not have an R_in port. You can add a t_array_mux type port named R_in, if you define the t_array_mux type in a package which you then include in your component and testbench files
library work;
use work.your_package_name.all;
in addition to library IEEE, etc. Then you can use the t_array_mux type in your component port definition:
ENTITY mux8_1 IS
PORT(Rs : IN STD_LOGIC_VECTOR(2 DOWNTO 0);
R_in : IN T_ARRAY_MUX; --User-defined port type
R_out : OUT STD_LOGIC_VECTOR(31 DOWNTO 0)
);
END mux8_1;
This will allow you to do the port mapping of your uut the way you currently have it. You'll have to add the package to the project or compile list in whatever tool you're using.
Using a testbench, you can test the correctness/output behavior of your module by giving a sequence of input signals and then comparing the output signals with the expected output.
Firstly, R_in is unknown to your testbench file, as it was an internal signal of your module. So, providing values to that signal doesn't make sense.
Secondly, you need to supply input to your in0, in1, ..., in7 signals, as they seem to drive your output signal R_out, along with the other input signal Rs

VHDL Filter not getting output for first values

I tried implementing a fir filter in VHDL but during the first three clocks I get no output and the error at 0 ps, Instance /filter_tb/uut/ : Warning: There is an 'U'|'X'|'W'|'Z'|'-' in an arithmetic operand, the result will be 'X'(es)..
Source file (I also have 2 other files for D Flip-Flops):
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.std_logic_unsigned.all;
entity filter is
port ( x: in STD_LOGIC_VECTOR(3 downto 0);
clk: in STD_LOGIC;
y: out STD_LOGIC_VECTOR(9 downto 0));
end filter;
architecture struct of filter is
type array1 is array (0 to 3) of STD_LOGIC_VECTOR(3 downto 0);
signal coef : array1 :=( "0001", "0011", "0010", "0001");
signal c0, c1, c2, c3: STD_LOGIC_VECTOR(7 downto 0):="00000000";
signal s0, s1, s2, s3: STD_LOGIC_VECTOR(3 downto 0) :="0000";
signal sum: STD_LOGIC_VECTOR(9 downto 0):="0000000000";
component DFF is
Port ( d : in STD_LOGIC_VECTOR(3 downto 0);
clk : in STD_LOGIC;
q : out STD_LOGIC_VECTOR(3 downto 0));
end component;
component lDFF is
Port ( d : in STD_LOGIC_VECTOR(9 downto 0);
clk : in STD_LOGIC;
q : out STD_LOGIC_VECTOR(9 downto 0));
end component;
begin
s0<=x;
c0<=x*coef(0);
DFF1: DFF port map(s0,clk,s1);
c1<=s1*coef(1);
DFF2: DFF port map(s1,clk,s2);
c2<=s2*coef(2);
DFF3: DFF port map(s2,clk,s3);
c3<=s3*coef(3);
sum<=("00" & c0+c1+c2+c3);
lDFF1: lDFF port map(sum,clk,y);
end struct;
Testbench:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use ieee.std_logic_unsigned.all;
ENTITY filter_tb IS
END filter_tb;
ARCHITECTURE behavior OF filter_tb IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT filter
PORT(
x : IN STD_LOGIC_VECTOR(3 downto 0);
clk : IN std_logic;
y : OUT STD_LOGIC_VECTOR(9 downto 0)
);
END COMPONENT;
--Inputs
signal x : STD_LOGIC_VECTOR(3 downto 0) := (others => '0');
signal clk : std_logic := '0';
--Outputs
signal y : STD_LOGIC_VECTOR(9 downto 0);
-- Clock period definitions
constant clk_period : time := 10 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: filter PORT MAP (
x => x,
clk => clk,
y => y
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc1: process
begin
x<="0001";
wait for 10ns;
x<="0011";
wait for 10ns;
x<="0010";
wait for 10ns;
--x<="0011";
end process;
END;
Output:
If anyonce could help, I'd appreciate it. I think it has something to do with the inital values of the signals c_i and s_i but I'm not too sure.
Your FIR filter contains flip-flops. These flip-flops have no reset input and so power up in an unknown state. You simulator models this by initialising the flip-flops' outputs to "UUUU" (as the are four bits wide). A 'U' std_logic value represents and uninitialised value.
So, your code behaves as you ought to expect. If you're not happy with that behaviour, you need to add a reset input and connect it to your flip-flops.
You have build a series of three register making up a cascade of registers.
You have not provided a reset so the register contents will be Unknown. You use the registers for calculations without any condition. Thus you arithmetic calculations will see the Unknown values and fail as you have seen.
The first (simplest) solution would be to add a reset. But that is not the best solution. You will no longer get warnings but the first three cycles of your output will be based on the register reset value not of your input signal.
If you have a big stream and don't care about some incorrect values in the first clock cycle you can live with that.
The really correct way would be to have a 'valid' signal transported along side your data. You only present the output data when there is a 'valid'. This is the standard method to process data through any pipeline hardware structure.
By the way: you normally do not build D-ffs yourself. The synthesizer will do that for you. You just use a clocked process and process the data vectors in it.
I have some questions. If I add a reset pin, when will I toggle it from 1 to 0? How can I create this circuit without explicitly using D-ffs?
You make a reset signal in the same way as you make your clock.
As to D-registers: they come out if you use the standard register VHDL code:
reg : process (clk,reset_n)
begin
// a-synchronous active low reset
if (reset_n='0') then
s0 <= "0000";
s1 <= "0000";
s2 <= "0000";
elsif (rising_edge(clk)) then
s0 <= x;
s1 <= s0;
s2 <= s1;
....
(Code entered as-is, not checked for syntax or typing errors)

Signal value won't be initialized during simulation

We've a project for college where we have to simulate a MAC unit for DSP.
For the simulation, I'm using Aldec Riviera Pro 2014.06 through EDA playground.
The problem is that even though I initialized a 32-bit signed signal named add_res, at the simulation its value will be shown as XXXX_XXXX the whole time.
Here's the simulation's result.
Here's the code of the design.vhd
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;
-----------------------------
ENTITY mac IS
PORT (B, C : IN SIGNED (15 DOWNTO 0);
clk : IN STD_LOGIC;
A : OUT SIGNED (31 DOWNTO 0));
END mac;
-----------------------------
ARCHITECTURE mac_rtl OF mac IS
SIGNAL mul_res: SIGNED (31 DOWNTO 0);
SIGNAL add_res: SIGNED (31 DOWNTO 0) := (others => '0');
BEGIN
mul_res <= B * C;
PROCESS (clk)
BEGIN
A <= mul_res + add_res;
add_res <= A;
END PROCESS;
END mac_rtl;
And here's the code of the testbench.vhd
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
entity testbench is
end entity testbench;
architecture BENCH of testbench is
component mac is
port (B, C : in SIGNED (15 DOWNTO 0);
clk : in STD_LOGIC;
A : out SIGNED (31 DOWNTO 0));
end component;
signal StopClock : BOOLEAN;
signal clk : STD_LOGIC;
signal B, C : SIGNED (15 DOWNTO 0);
signal A : SIGNED (31 DOWNTO 0);
begin
ClockGenerator: process
begin
clk <= '0';
wait for 2 ns;
while not StopClock loop
clk <= '0';
wait for 1 ns;
clk <= '1';
wait for 1 ns;
end loop;
wait;
end process ClockGenerator;
Stimulus: process
begin
B <= "0000000000000010";
C <= "0000000000001000";
wait;
end process Stimulus;
DUT : entity work.mac
port map (B, C, clk, A);
end architecture BENCH;
I've searched here and in Google in general for others having the same problem, but the solutions given didn't help.
I've tried and with a Reset variable from testbench, but nothing. It's like it won't be initialized at all, while everything else work normally.
The issue is that the value of add_res and mul_res have to be known at the time add_res is loaded into a register.
Note that the process is sensitive to clk but doesn't use an edge nor qualify with a value of clk.
I modified your architecture to qualify add_res update to the rising edge of clk. There's a built in assumption you have non-metavalue values on mult_res at that time. That can be dealt with in part by defining a default initial value.
Also the new value of A is not available until signals are update, which doesn't occur while there are any processes pending to be resumed in the current simulation cycle. This means you need to assign to add_res (which holds the accumulated value anyway) and assign to A outside the process:
ARCHITECTURE mac_rtl OF mac IS
SIGNAL mul_res: SIGNED (31 DOWNTO 0) := (others => '0'); -- added init val
SIGNAL add_res: SIGNED (31 DOWNTO 0) := (others => '0');
BEGIN
mul_res <= B * C;
PROCESS (clk)
BEGIN
if rising_edge(clk) then -- ADDED
-- A <= mul_res + add_res; CHANGED
add_res <= mul_res + add_res;
-- add_res <= A; CHANGED
end if; -- ADDED
END PROCESS;
A <= add_res;
END mac_rtl;
And this gives:
You could note there is no need to try to collapse A and add_res. For simulation purposes delta cycles caused by signal assignments that take effect after 0 simulation time has passed do not take simulation time.
Scheduled signal updates and delta cycles are used to emulate concurrency in signals that are inherently assigned sequentially. (And yes in the modified architecture the assignment to A will occur one delta cycle later than add_res).
(And yes I put a StopClock transaction at the tail end of the stimuli in process Stimulus in the testbench).

Realizing Top Level Entity in Testbench using VHDL

I'm a newbie in VHDL and hardware world.
I'm trying to make a Count&Compare example using Top Level Hierarchy and test it with testbench and see the results on ISIM.
Here is my block diagram sketch:
So I end up these 3 vhd source files:
Counter.vhd
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Count_src is
Port ( CLK : in STD_LOGIC;
Reset : in STD_LOGIC;
S : out STD_LOGIC_VECTOR (3 downto 0));
end Count_src;
architecture Behavioral of Count_src is
signal count : STD_LOGIC_VECTOR (3 downto 0);
begin
process (Reset, CLK)
begin
if Reset = '1' then -- Active high reset
count <= "0000"; -- Clear count to 0
elsif (rising_edge(CLK)) then -- Positive edge
count <= count + "0001"; -- increment count
end if;
end process;
S <= count; -- Export count
end Behavioral;
Compare
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Compare_src is
Port ( A : in STD_LOGIC_VECTOR (3 downto 0);
B : in STD_LOGIC_VECTOR (3 downto 0);
S : out STD_LOGIC);
end Compare_src;
architecture Behavioral of Compare_src is
begin
S <= '1' when (A = B) else -- Test if A and B are same
'0'; -- Set when S is different
end Behavioral;
CountCompare (Top Level)
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
--use IEEE.NUMERIC_STD.ALL;
-- Uncomment the following library declaration if instantiating
-- any Xilinx primitives in this code.
--library UNISIM;
--use UNISIM.VComponents.all;
entity CountCompare_src is
Port ( Clock : in STD_LOGIC;
Reset : in STD_LOGIC;
Value : in STD_LOGIC_VECTOR (3 downto 0);
Flag : out STD_LOGIC);
end CountCompare_src;
architecture Behavioral of CountCompare_src is
-- COMPONENT DECLERATIONS
component counter is
port ( CLK : in std_logic;
Reset : in std_logic;
S : out std_logic_vector(3 downto 0)
);
end component;
component compare is
port (A : in std_logic_vector(3 downto 0);
B : in std_logic_vector(3 downto 0);
S : out std_logic
);
end component;
-- Component Spesification and Binding
for all : counter use entity work.Count_src(behavioral);
for all : compare use entity work.Compare_src(behavioral);
-- Internal Wires
signal count_out : std_logic_vector(3 downto 0);
begin
-- Component instantiation
C1: counter PORT MAP ( Reset => Reset,
CLK => Clock,
S => count_out
);
C2: compare PORT MAP ( A => count_out,
B => Value,
S => Flag
);
end Behavioral;
To test the design I wrote a testbench as follows:
TestBench
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
ENTITY TopLevelTester_tb IS
END TopLevelTester_tb;
ARCHITECTURE behavior OF TopLevelTester_tb IS
--Input and Output definitions.
signal Clock : std_logic := '0';
signal Reset : std_logic := '0';
signal Value : std_logic_vector(3 downto 0) := "1000";
signal Flag : std_logic;
-- Clock period definitions
constant clk_period : time := 1 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: entity work.CountCompare_src PORT MAP
(
Clock => Clock,
Reset => Reset,
Value => Value
);
proc: process
begin
Clock <= '0';
wait for clk_period/2;
Clock <= '1';
wait for clk_period/2;
end process;
END;
When I simulate behavioral model, the ISIM pops up, but I see no changes on the Compare Flag. Here is the ss of the ISIM:
What am I missing here? Why does'nt the Flag change?
My best regards.
You have two problems, both in your testbench.
The first is that you never reset count in the counter, it will always be 'U's or 'X's (after you increment it).
The second is that the directly entity instantiation in the testbench is missing an association for the formal flag output to the actual flag signal:
begin
uut:
entity work.countcompare_src
port map (
clock => clock,
reset => reset,
value => value,
flag => flag
);
proc:
process
begin
clock <= '0';
wait for clk_period/2;
clock <= '1';
wait for clk_period/2;
if now > 20 ns then
wait;
end if;
end process;
stimulus:
process
begin
wait for 1 ns;
reset <= '1';
wait for 1 ns;
reset <= '0';
wait;
end process;
Fix those two things and you get:

VHDL - Writing To Registers

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?
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.

Resources