How to implement a test bench for 4x1 mux - vhdl

I'm struggling to write a test bench for this:
---------------------------------------
LIBRARY ieee;
USE ieee.std_logic_1164.all;
---------------------------------------
ENTITY mux IS
PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
y: OUT STD_LOGIC);
END mux;
---------------------------------------
ARCHITECTURE pure_logic OF mux IS
BEGIN
y <= (a AND NOT s1 AND NOT s0) OR
(b AND NOT s1 AND s0) OR
(c AND s1 AND NOT s0) OR
(d AND s1 AND s0);
END pure_logic;
---------------------------------------
This is my progress so far.
I am not quite sure how to write the stimulus part.
I tried running it through a behavioral simulation, but I am getting Undefined Errors in the results.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity mux_tb is
-- Port ( );
end mux_tb;
architecture Behavioral of mux_tb is
component mux
PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
y: OUT STD_LOGIC);
end component;
signal a : std_logic;
signal b : std_logic;
signal c : std_logic;
signal d : std_logic;
signal s0 : std_logic;
signal s1 : std_logic;
signal y : std_logic;
begin
uut: mux port map (
a => a,
b => b,
c => c,
d => d,
s0 => s0,
s1 => s1,
y => y
);
process
begin
s0 <= '0'; s1 <= '0';
wait for 100 ns;
s1 <= '0'; s0 <= '1';
wait for 100ns;
s1 <= '1'; s0 <= '0';
wait for 100ns;
s1 <= '1'; s0 <= '1';
end process;
end Behavioral;
Could anyone explain what I am doing wrong?

Your testbench does not supply stimuli for a, b, c and d. You need to assign them as well as s0 and s1.
architecture full_behavior of mux_tb is
component mux
PORT ( a, b, c, d, s0, s1: IN STD_LOGIC;
y: OUT STD_LOGIC);
end component;
signal a : std_logic;
signal b : std_logic;
signal c : std_logic;
signal d : std_logic;
signal s0 : std_logic;
signal s1 : std_logic;
signal y : std_logic;
use ieee.numeric_std.all; -- CHANGED Added use clause
begin
uut:
mux port map (
a => a,
b => b,
c => c,
d => d,
s0 => s0,
s1 => s1,
y => y
);
STIMULI_ASSERT:
process
variable inputs: std_logic_vector (3 downto 0); -- data inputs
variable s1s0: integer range 0 to 3; -- selects as integer
begin
for i in 0 to 63 loop
(d, c, b, a, s1, s0) <= to_unsigned(i, 6);
wait for 100 ns;
inputs := (d, c, b, a);
s1s0 := to_integer(unsigned'(s1 & s0));
assert y = inputs(s1s0)
report "Expected " & std_ulogic'image(inputs(s1s0)) &
" got " & std_ulogic'image(y)
severity error;
end loop;
wait;
end process;
end architecture;
You can do this with a for loop which assigned values to all the mux inputs. Additionally if all the inputs are ordered you can use s0 and s1 to select which of the data inputs should appear on y.
Here the for loop range is determined by the power of two raised to the number of inputs.
This
(d, c, b, a, s1, s0) <= to_unsigned(i, 6);
is an aggregate assignment that takes it's type from context (the entire statement). 6 is the number of inputs and specifies the length of integer value i converted to unsigned. The assignment is to individual elements of the target aggregate.
this
inputs := (d, c, b, a);
has the type of the aggregate specified by the assignment target (std_logic_vector).
and this
s1s0 := to_integer(unsigned'(s1 & s0));
saves the integer value of the concatenation of s1 & s0 specified as type unsigned to s1s0.
The assertion checks the expected output as an indexed value of the data inputs against y and when not equal reports an error along with the expected and y values.
We use type unsigned declared in IEEE package numeric_std along with it's operations when we want to treat a composite value as an unsigned number.

You might want separate loops for the ABCD inputs and the select inputs. This makes it easier to see that the output reacts to B but not A,C,D inputs when the select is set to B, and so on. Clearer than trying to interpret a 6 bit number.
In addition to the stimulus part covered in other answers, a good TB will compute (or read from an array or file or something) the expected outputs, and compare these with the actual outputs, reporting any differences ... you can use Assert/Report for this.
If you then log Pass/Fail and number of errors (possibly to a file) at end of test, you can use this in regression tests and never have to stare at waveforms again. That's when it gets to be a time saver.
See also osvvm.org and Vunit (on github) for tools to help.

I am not quite sure how to write the stimulus part
You appear to be asking for a design technique that can be used to stimulate the inputs.
A simple method for testing a purely combinatorial circuit like your component is to drive the inputs from a test counter. In this case, it can be a 7-bit std_logic_vector counter.
Then write a loop with 128 passes. On each pass, it will perform the component's logic function on the counter value to produce an expected result. The pass will wait for the component outputs to settle then use an assert to compare the actual result with the expected result and display an error if they don't match. Then increment counter and do the next pass.

Related

Not understanding vhdl online compiler error

i am using an inline compiler (https://www.edaplayground.com/) and im not understanding the online compilers error message. I am trying to build the boolean expression (a * !b) + (b * !c) + (!b * c).
My code is:
library IEEE;
use IEEE.std_logic_1164.all;
ENTITY (MySimp) IS
PORT (A: in STD_LOGIC;
B: in STD_LOGIC;
C: in STD_LOGIC;
Z: out STD_LOGIC;
);
End MySimp;
ARCHITECTURE (details) OF (MySimp) IS
BEGIN
PROCESS
VARIABLE D, E, F: STD_LOGIC;
BEGIN
IF A AND (NOT B)= '1' THEN D:= '1';
ELSE D:= '0';
END IF:
IF B AND (NOT C)= '1' THEN E:= '1';
ELSE E:= '0';
END IF:
IF C AND (NOT B)= '1' THEN F:= '1';
ELSE F:= '0';
END IF:
Z <= D OR E OR F;
END PROCESS;
END details;
As the error shows, you are compiling a VHDL file (.vhd) as a (System) Verilog file (.sv). Those are two different hardware description languages.
In the Languages and Libraries tab on the left, you need to set the Testbench + Design to VHDL.
But there's a problem in your code. The process statement doesn't have a sensitivity list. HDLs are usually parallel languages, which means you need to indicate when a process needs to be triggered: else it will try to loop indefinitely in an infinitesimal time. You either need to add a wait-statement, to stop the loop, or implicitly do that by adding the trigger signals to the process sensitivity list. e.g.
process (a,b,c)
There are more semantical issues with your code. I added them in comments
library ieee;
use ieee.std_logic_1164.all;
entity MySimp is -- no braces around the name
port (
a: in std_logic;
b: in std_logic;
c: in std_logic;
z: out std_logic -- no semicolon
);
end entity;
architecture arch of MySimp is
begin
process(a, b, c)
variable d, e, f: std_logic;
begin
if (a and (not b))= '1' then -- add braces around the logic expression
d:= '1';
else
d:= '0';
end if; -- semicolon instead of colon
-- alternative method 1
if b='1' and c='0' then
e:= '1';
else
e:= '0';
end if;
-- alternative method 2
f := c and (not b);
z <= d or e or f;
end process;
-- or replace the whole process by:
--z <= (a and (not b)) or (b xor c);
-- as (b and (not c)) or (c and (not b)) is an exclusive-or operation
end architecture;

Q: VHDL Implementation of 2 simple funcitons

I'm looking to implement the functions y = a and b; y = (a or b) and (c or d).
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity task1_tb is
-- Port ( ); end task1_tb;
architecture Behavioral of task1_tb is
--declaring the component component task1
Port ( a : in STD_LOGIC;
b : in STD_LOGIC;
y : out STD_LOGIC); end component;
signal y,a,b: std_logic;
signal counter: unsigned(1 downto 0):="00";
begin
uut: task1 port map(a => a, b => b, y => y );
end Behavioral;
How can I assign a (bit 1) and b (bit 2) so it will test ever possible value and make a 20ns delay between each combination? I've been trying to learn VHDL these past two days for a school project and not even sure if what I have is right.
You're looking to use a wait for <duration> in your stimulus process.
process
begin
for i in 0 to 2**2-1 loop --2**(number of input bits)-1
(a, b) <= to_unsigned(i,2);
wait for 20 ns;
end loop;
wait;
end process;
Credit to user1155120 for refinements.

I am unable to find error in my simulation file of VHDL

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity test_adder_vhdl is
end test_adder_vhdl;
architecture Behavioral of test_adder_vhdl is
constant clock_period : time := 1000 ns ;
component adder is
PORT (A: in STD_LOGIC;
B: in STD_LOGIC;
SUM: out STD_LOGIC;
CARRY: out STD_LOGIC);
end component adder;
SIGNAL A: STD_LOGIC : ='0';
SIGNAL B: STD_LOGIC : ='0';
SIGNAL SUM: STD_LOGIC : ='0';
SIGNAL CARRY: STD_LOGIC : ='0';
begin
uut: adder port map(
A=> A;
B=> B;
SUM => SUM;
CARRY => CARRY;
);
clk gena: process
begin
wait for 100 ns;
A <= not A;
end process;
clk genb: process
begin
wait for 50 ns;
B <= not B;
end process;
end Behavioral;
The error in the above code is
[HDL 9-806] Syntax error near ":". ["F:/practiceWorkspace/practice1/practice1.srcs/sim_1/new/test_adder_vhdl.vhd":38]
You are not showing line number correspondence with your design. The error appears to correspond with the signal declaration for A. There are more syntax errors.
Statements are delimited by a semicolon. Interface declarations are separated by semicolons. Other object declarations are delimited by semicolons. Multiple elements (in the association list here) are separated by commas.
There are four signal declarations (A, B, SUM, CARRY) with extraneous spaces between the ':' and '=' in the compound delimiter ":=" used to providing a default value of '0'.
These should be:
SIGNAL A: STD_LOGIC := '0';
SIGNAL B: STD_LOGIC := '0';
SIGNAL SUM: STD_LOGIC := '0';
SIGNAL CARRY: STD_LOGIC := '0';
:= is a used to signify variable assignment, values for constants and default expressions (values) for objects.
In the port map ',' should be used as a separator in the association list instead of ';'.
uut: adder port map (
A=> A,
B=> B,
SUM => SUM,
CARRY => CARRY -- NO TRAILING SEPARATOR
);
The last association does not require a following comma (a delimiter used as a separator).
There's a space instead of an underscore in the labels clk_gena and clk_genb.
clk_gena: process
begin
wait for 100 ns;
A <= not A;
end process;
clk_genb: process
begin
wait for 50 ns;
B <= not B;
end process;
A label is a single identifier consisting of a letter followed by one or more letters or numbers separated by zero or one underscore characters. The processes are labelled (named) clk_gena and clk_genb.
After fixing these your code analyzes (compiles). Without the entity and architecture pair for component adder your code can't be elaborated (linked) or simulated.
Note that the two processes suspend for 50 ns, and a process without an implicit last wait statement waiting on elements of a sensitivity list will merrily start executing the first sequential statement of the process after executing the last.
The expectation would be that you'd either add a trailing wait statement or control simulation by an implementation dependent method (e.g. run for some simulation time interval).
Your constant clock_period is not used (as yet) in your testbench.

VHDL: Signal defined in the architecture not taking the assigned value

I'm trying to write VHDL code for a 3 input simple adder. When I type the following code, S gets the correct output value but S1 gets zero, and hence add_out also gets the wrong value.
library ieee;
use ieee.std_logic_1164.all;
entity adder is
port( A,B : in std_logic_vector(3 downto 0);
C : in std_logic;
carry_out : out std_logic;
S : out std_logic_vector(3 downto 0);
addOut : out std_logic_vector(4 downto 0));
end adder;
architecture behavioral of adder is
signal S1 : std_logic_vector(3 downto 0);
begin
proc : process(A,B,C) is
variable carry : std_logic;
begin
carry := C;
for i in 0 to 3 loop
S(i) <= A(i) xor B(i) xor carry;
S1(i) <= A(i) xor B(i) xor carry;
carry := (A(i) and B(i)) or (B(i) and carry) or (A(i) and carry);
end loop;
carry_out <= carry;
addOut <= carry & S1;
end process proc;
end behavioral;
Why is the signal S1 not getting the same value as S?
S1 probably (almost certainly) DOES get the same value as S.
However you wouldn't expect to see that value of S1 on addOut, thanks to the mistake in the process sensitivity list. Study the semantics of signal assignment, (aka "postponed assignment") and delta cycles, and all will become clear. (My usual explanation on this topic, if you'll excuse some self publicity)
Specifically, you have a new value on S1, but no means to wake up the process again to propagate it to any other signal.
The best fix is probably to move the addOut and carryOut assignments outside the process, where they will immediately reflect any changes on their own inputs, and reduce the likelihood of sim/synth mismatches.

port map in structural VHDL code

I have the following code for a structural modeling in VHDL. When I try to compile it (ghdl -a filename.vhdl), I get this error in the 4 lines commented below: "<=" or ":=" expected instead of port
BTW, I had already defined the components used before the code block below.
What's wrong with my code? Am I not allowed to use port map inside a process/if-statement?
What can I do to fix this? Thanks!
-- Entity Definition
entity jk is
port(
CP: in std_logic; -- clock signal
J : in std_logic; -- J signal
K : in std_logic; -- K signal
Q : inout std_logic; -- Q signal
QN : inout std_logic; -- Q' signal
reset : in std_logic -- reset signal
);
end entity jk;
architecture dev1 of jk is
-- declare the singals that outputs the results of some gates
signal a, b, internal_q, internal_qn : std_logic;
-- get each component needed
component and3 is
port(o0 : out std_logic; i0, i1, i2: in std_logic);
end component and3;
component nor2 is
port(o0 : out std_logic; i0, i1: in std_logic);
end component nor2;
begin
internal_q <= Q; -- used to show internal Q value
QN <= not Q; -- inverse of Q
internal_qn <= QN; -- used to show internal QN value
process is
begin
if (reset = '0') then -- asynchronous reset
Q <= '0';
internal_qn <= '0';
elsif rising_edge(CP) then -- on positive clock edge
-- AND gate outputs
g0: and3 port map(a, internal_q, K, CP); -- error
g1: and3 port map(b, internal_qn, J, CP); - error
-- NOR gate outputs
g2: nor2 port map(Q, a, internal_qn); -error
g3: nor2 port map(QN, b, internal_q); -error
end if;
end process;
end architecture dev2;
No, you are not allowed to instantiate components (use port maps) inside of a process.
You should be instantiating your components below the begin statement of your architecture. Wire them up there appropriately. Your process should drive all of the registered logic. I actually don't see any need for a process statement at all in this code. Since all of your inputs are coming from your entity (I assume) then you really don't need to do any registered logic in this file.
Can you post your entity as well? I cannot see where signals J and K and CP and Q and QN are being defined.

Resources