Reputation: 334
I am coding a pattern generator in VHDL. I finished it recently but now I have a problem with the test-bench.
My Code:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_unsigned.all;
entity pattern_gen is
Port (
clk_i : in STD_LOGIC;-- 100Mhz clock on Basys 3 FPGA board
x : in INTEGER;
y: in INTEGER;
modus : in STD_LOGIC;
enable : in STD_LOGIC;
red : out STD_LOGIC_VECTOR(3 downto 0);
green : out STD_LOGIC_VECTOR(3 downto 0);
blue : out STD_LOGIC_VECTOR(3 downto 0)
);
end pattern_gen;
architecture Behavioral of pattern_gen is
signal segment_x : integer := 0;
signal segment_y : integer := 0;
begin
stripes : PROCESS(modus, segment_x, x, clk_i)
BEGIN
IF( clk_i'EVENT and clk_i = '1') then
IF(modus = '0' AND enable = '1' ) THEN --Mod 0 -> Stripes enabled
IF(x < (40+ (160*(segment_x-1)))) THEN
red <= (OTHERS => '1');
green <= (OTHERS => '0');
blue <= (OTHERS => '0');
ELSE IF(x < (80+ (160*(segment_x-1)))) THEN
red <= (OTHERS => '0');
green <= (OTHERS => '1');
blue <= (OTHERS => '0');
ELSE IF(x < (120+ (160*(segment_x-1)))) THEN
red <= (OTHERS => '0');
green <= (OTHERS => '0');
blue <= (OTHERS => '1');
ELSE IF(x < (160+ (160*(segment_x-1)))) THEN
red <= (OTHERS => '0');
green <= (OTHERS => '0');
blue <= (OTHERS => '0');
END IF;
END IF;
END IF;
END IF;
END IF;
end if;
END PROCESS;
panels: PROCESS(modus, segment_x, segment_y, clk_i)
variable i: integer range -10 to 100;
BEGIN
IF(clk_i'EVENT and clk_i = '1') then
IF(modus = '1' AND enable = '1' ) THEN --Mod 1 -> Panels enabled
i := segment_x*segment_y;
while (i>0) loop
IF (i = 1) then
red <= (OTHERS => '1');
green <= (OTHERS => '0');
blue <= (OTHERS => '0');
else if(i = 2) then
red <= (OTHERS => '0');
green <= (OTHERS => '1');
blue <= (OTHERS => '0');
else if(i=3) then
red <= (OTHERS => '0');
green <= (OTHERS => '0');
blue <= (OTHERS => '1');
end if;
end if;
end if;
i := i - 3;
end loop;
END IF;
END IF;
END PROCESS;
segment: PROCESS(x, y, modus, clk_i)
variable i: integer range 0 to 10;
BEGIN
if(clk_i'EVENT and clk_i = '1') then
IF(modus = '0' AND enable = '1') THEN
i := 1;
while i<=4 loop
IF(x < (i * 160))then
segment_x <= i;
exit;
END IF;
i := i +1;
END loop;
ELSIF (modus = '1' AND enable = '1') THEN --Mod 1 -> Panels enabled
i:=1; --reset i for horizintal segment
while i<=10 loop
IF(x < (i * 64))then
segment_x <= i;
exit;
END IF;
i := i +1;
end loop;
i:=1; --reset i for vertical segment
while i<=10 loop
IF(y < (i * 48)) then
segment_y <= i;
exit;
end if;
i := i +1;
end loop;
END IF;
end if;
END PROCESS;
end Behavioral;
The testbench is very short, I just want to test a few cases.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.std_logic_unsigned.all;
entity pattern_gen_tb is
end entity;
architecture sim of pattern_gen_tb is
component pattern_gen
Port (
clk_i : in STD_LOGIC;
x : in INTEGER;
y: in INTEGER;
modus : in STD_LOGIC;
enable : in STD_LOGIC;
red : out STD_LOGIC_VECTOR(3 downto 0);
green : out STD_LOGIC_VECTOR(3 downto 0);
blue : out STD_LOGIC_VECTOR(3 downto 0)
);
end component;
signal clk_s : STD_LOGIC := '0';
signal x_s : INTEGER;
signal y_s : INTEGER;
signal modus_s : std_logic;
signal enable_s : std_logic;
signal red_s : STD_LOGIC_VECTOR(3 downto 0);
signal green_s :STD_LOGIC_VECTOR(3 downto 0);
signal blue_s : STD_LOGIC_VECTOR(3 downto 0);
begin
uut : pattern_gen
port map(
clk_i => clk_s,
x => x_s,
y => y_s,
modus => modus_s,
enable => enable_s,
red => red_s,
green => green_s,
blue => blue_s
);
clk_s <= not clk_s after 10 ns;
p_test : process
begin
x_s <= 44;
y_s<= 300;
modus_s <= '0';
enable_s <= '1'; -- result should be green(1,1,1,1)
wait;
end process;
end sim;
The Result of the Simulation is undefined even though Segment is calculated correctly and the second If Statement should trigger because 44 < (80 + 160 * (1-1)) therefore the Output should be
Segment 1 and Stripe 2 -> green (1,1,1,1) red and blue(0,0,0,0)
What am I missing? I've been trying to get it working for hours now.
Upvotes: 0
Views: 306
Reputation:
You drive red, green, and blue from multiple processes.
Having searched the to date 152 posts on multiple drivers there's not a single posted question with an upvoted answer that adequately explains why or how you return 'U's (or in some cases 'X's).
IEEE Std 1076-2008
14.7 Execution of a model
14.7.2 Drivers
Every signal assignment statement in a process statement defines a set of drivers for certain scalar signals. There is a single driver for a given scalar signal S in a process statement, provided that there is at least one signal assignment statement in that process statement and that the longest static prefix of the target signal of that signal assignment statement denotes S or denotes a composite signal of which S is a subelement. Each such signal assignment statement is said to be associated with that driver. Execution of a signal assignment statement affects only the associated driver(s).
14.7.3.2 Driving values
> The driving value of any signal S is determined by the following steps:
...
e) If S is a basic signal:...
— If S is a resolved signal and has one or more sources, then the driving values of the sources of S are examined. ... the driving value of S is obtained by executing the resolution function associated with S, where that function is called with an input parameter consisting of the concatenation of the driving values of the sources of S, with the exception of the value of any source of S whose current value is determined by the null transaction.
How that resolution function is operated is described in 14.7.3.2 Driving values.
The type or subtype std_logic_vector (-2008) is resolved composite type or sutype with a resolved element type (-2008) that uses a resolution function for it's elements provided in IEEE package std_logic_1164, the package body:
-------------------------------------------------------------------
-- resolution function
-------------------------------------------------------------------
constant resolution_table : stdlogic_table := (
-- ---------------------------------------------------------
-- | U X 0 1 Z W L H - | |
-- ---------------------------------------------------------
('U', 'U', 'U', 'U', 'U', 'U', 'U', 'U', 'U'), -- | U |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X'), -- | X |
('U', 'X', '0', 'X', '0', '0', '0', '0', 'X'), -- | 0 |
('U', 'X', 'X', '1', '1', '1', '1', '1', 'X'), -- | 1 |
('U', 'X', '0', '1', 'Z', 'W', 'L', 'H', 'X'), -- | Z |
('U', 'X', '0', '1', 'W', 'W', 'W', 'W', 'X'), -- | W |
('U', 'X', '0', '1', 'L', 'W', 'L', 'W', 'X'), -- | L |
('U', 'X', '0', '1', 'H', 'W', 'W', 'H', 'X'), -- | H |
('U', 'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X') -- | - |
);
function resolved (s : STD_ULOGIC_VECTOR) return STD_ULOGIC is
variable result : STD_ULOGIC := 'Z'; -- weakest state default
begin
-- the test for a single driver is essential otherwise the
-- loop would return 'X' for a single driver of '-' and that
-- would conflict with the value of a single driver unresolved
-- signal.
if (s'length = 1) then return s(s'low);
else
for i in s'range loop
result := resolution_table(result, s(i));
end loop;
end if;
return result;
end function resolved;
One by one each driver value is compared against a resolved value of previous drivers to determine the resolved value including each new driver.
Signal update is done by element due to a characteristic known as longest static prefix (8. Names), where using indexed names (8.4) or slice names (8.5) force the granularity of drivers for array composites to elements (which also meets the definition of subelements). (Assignments to elements of records have drivers for all the elements of a record composite and any subelements. See 8.3 selected names. Records don't have subsets of elements.)
The resolution of multiple drivers emulates what happens when two outputs are tied together. Tying multiple outputs together can be a violation of design constraints in FPGA synthesis tools for internal nets for example.
In your design you have assignments to drivers in multiple processes (and concurrent statements also provide process statements).
Two of the processes don't effect any assignment to red, green or blue contingent on the value of modus which is not updated. Resolution of a 'U' with any other value of std_ulogic results in a 'U'.
If your testbench had caused assignment to red or green or blue in more than one process a '0' for one scalar element driver in one process would be resolved with a '1' from the other driver to an 'X'.
A lot of target device families don't allow internal signals to have multiple sources (drivers). This is quite common in FPGAs for instance (while Xilinx supports automatic conversion of mutually exclusively driven multiple sources to be converted to multiplexer selected sources through a software patented process for some device families).
One solution to the synthesis limitation on multiple drivers might be to combine the first two processes into one, assignments separated by conditional choice of modus values.
Another solution might be to assign unique signals in each process and assign red, green and blue to these values in another process steered by the value of modus (emulating the software patent manually, which should also provide cause to question it's validity).
While loops are not historically synthesis eligible, while for loops with fixed range loop parameters have always been supported. Today some synthesis tools support while loops where the exit condition can be determined by a relatively few loop iterations. (Loops are unrolled in synthesis.) At least one of your while loops will likely require the algorithm being implemented be rewritten.
Upvotes: 1