0
\$\begingroup\$

I am currently a CPE student taking up computer architecture, learning how to model major computer components using VHDL. Currently, I am working on a shift register as a sub component for a top-level design. I have a script written and somehow my outputs are not what I expected it to be and I can't seem to find the answer why. I'm also having a hard time looking for similar queries online so I hope someone could guide me on this one. The .vhdl and testbench scripts are shown below:

--- MAIN SCRIPT

> library IEEE; 
> use IEEE.STD_LOGIC_1164.ALL; 
> use IEEE.STD_LOGIC_UNSIGNED.ALL;
> 
> entity prodreg is
>     Port ( 
>            clk : in STD_LOGIC;
>            load : in STD_LOGIC;
>            shift : in STD_LOGIC;
>            a_in : in STD_LOGIC_VECTOR (7 downto 0);
>            q_in : in STD_LOGIC_VECTOR (7 downto 0);
>            q_out : out STD_LOGIC_VECTOR (7 downto 0);
>            a_out : out STD_LOGIC_VECTOR (7 downto 0);
>            q01 : out STD_LOGIC_VECTOR (1 downto 0)); end prodreg;
> 
> architecture Behavioral of prodreg is
> 
> begin
>     process(clk)
>     -- registers for q and q
>     variable p_q : STD_LOGIC_VECTOR (7 downto 0) := q_in; -- q (multiplier) being processed
>     variable p_a : STD_LOGIC_VECTOR (7 downto 0) := a_in; -- accumulator being processed
>     begin
>         if load <= '1' then
>             p_a := a_in;
>         end if;
>         if rising_edge(clk) then
>             if shift = '1' then -- conduct arithmetic shift right
>                 p_q(6 downto 0) := p_q(7 downto 1); -- do shift right for Q
>                 p_q(7) := p_a(0); -- save LSB of A in MSB of Q
>                 p_a(6 downto 0) := p_a(7 downto 1); -- do shift right for A
>             end if;            
>         end if;
>         q01(1) <= p_q(0); -- save LSB of Q in 'x.' of q01 (x is the position of bit)
>         q01(0) <= p_q(1); -- save LSB of Q in '.x' of q01 (x is the position of bit)
>         q_out <= p_q;
>         a_out <= p_a;            
>     end process; 
>     end Behavioral;

--- TEST BENCH

> library IEEE; 
> use IEEE.Std_logic_1164.all; 
> use IEEE.Numeric_Std.all;
> 
> entity prodreg_tb is end;
> 
> architecture bench of prodreg_tb is
> 
>   component prodreg
>       Port ( 
>              clk : in STD_LOGIC;
>              load : in STD_LOGIC;
>              shift : in STD_LOGIC;
>              a_in : in STD_LOGIC_VECTOR (7 downto 0);
>              q_in: in STD_LOGIC_VECTOR (7 downto 0);
>              q_out : out STD_LOGIC_VECTOR (7 downto 0);
>              a_out : out STD_LOGIC_VECTOR (7 downto 0);
>              q01 : out STD_LOGIC_VECTOR (1 downto 0));   end component;
> 
>   signal clk: STD_LOGIC;   signal load: STD_LOGIC;   signal shift:
> STD_LOGIC;   signal a_in: STD_LOGIC_VECTOR (7 downto 0);   signal
> q_in: STD_LOGIC_VECTOR (7 downto 0);   signal q_out: STD_LOGIC_VECTOR
> (7 downto 0);   signal a_out: STD_LOGIC_VECTOR (7 downto 0);   signal
> q01: STD_LOGIC_VECTOR (1 downto 0);
> 
>   constant clock_period: time := 10 ns;   signal stop_the_clock:
> boolean;
> 
> begin
> 
>   uut: prodreg port map ( clk   => clk,
>                           load  => load,
>                           shift => shift,
>                           a_in  => a_in,
>                           q_in     => q_in,
>                           q_out => q_out,
>                           a_out => a_out,
>                           q01   => q01 );
> 
>   stimulus: process   begin
>   
>     load <= '0';
>     shift <= '0';
>     a_in <= "10001111";
>     q_in <= "00000101";
>     wait for 5ns;
>     
>     load <= '1';
>     shift <= '0';
>     wait for 5ns;
>     
>     load <= '0';
>     shift <= '1';
>     wait for 15ns;
>     
>     load <= '0';
>     shift <= '0';
>     wait for 5ns;
>     
>     load <= '0';
>     shift <= '1';
>     wait for 10ns;    
>     
>     load <= '0';
>     shift <= '1';
>     wait for 10ns;
>     --stop_the_clock <= true;
>     wait;   end process;
> 
>   clocking: process   begin
>     while not stop_the_clock loop
>       clk <= '0', '1' after clock_period / 2;
>       wait for clock_period;
>     end loop;
>     wait;   end process;
> 
> end;

enter image description here

The model is designed to act as an arithmetic shift register where it takes two 8-bit numbers, 'a' and 'q', and execute the mentioned shift as a 16-bit respectively. The output should be the mentioned 8-bit numbers and the last two bits of q (q0 and q1, hence, q01). I used variables because I learned that it's suppose to act as a register so that I could save and use data from the previous process. As 'a' and 'q' always shift per cycle, only a changes upon 'load'. Additionally, the model is also suppose to represent an accumulator (hence the loading of 'a', and the need of retaining 'q' and 'a' within the component).

But as shown in the test bench, the 'q' throws U values I can't seem to understand why, and as for the q, I expected it to shift normally assuming its taking on the retained q value from the variable declaration. I've modeled another sub-component which was a decrement counter and scripted it the same as this one where the variable declared is 'variable counter : STD_LOGIC_VECTOR (3 downto 0) := "1000"' instead. On that simulation, the results were correct as it was decrementing from 8 to 0.

Can anyone tell me advice or my mistake on this one? Help will be very much appreciated, thanks!

\$\endgroup\$
2
  • 1
    \$\begingroup\$ Stay well away from variables until you completely understand VHDL. The name 'variable' may sound attractive because variables are primary items in maths and software programming. In VHDL, the standard item is the signal. Variables have specific purposes where signals cannot be used: in testbenches, in design processes to denote nodes in combinatorial logic paths and avoid registers being generated. They are not 'local signals' for processes, though some think they are. Do yourself a big favour: if you're confused between variables and signals, avoid variables completely until much later. \$\endgroup\$ – TonyM May 5 at 16:13
  • 1
    \$\begingroup\$ What you have should be written with signals only, which would read much simpler and clearer. If I had time, I'd post an answer but that's not possible right now. \$\endgroup\$ – TonyM May 5 at 16:15
3
\$\begingroup\$

The initial value declaration on p_q loads the port state at initialization time, when it is still undefined, and the load = '1' code does not reload p_q.

I'd also omit the initial value declarations or explicitly write (others => 'U') so simulation and synthesis behave the same.

Also, these variables can be signals.

\$\endgroup\$
0
\$\begingroup\$

I've played around with the output lines and initialized variables to find a solution and learn important concepts.

First, I initialized 'q' within the sub-component instead of providing it from the top-level. A is also initialized was '0' and its input depends on the load and stored variable.

Second, I just utilized the variables solely for register purposes. Signal should be used to properly process the signal, processing with the variable somehow didn't give me correct output in the end.

Third, the outputs are set outside the process statement. Previous scripts had different results depending on where the output was placed, I am not sure why, something I will look onto.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity prodreg is
    Port ( 
           clk : in STD_LOGIC;
           load : in STD_LOGIC;
           shift : in STD_LOGIC;
           a_in : in STD_LOGIC_VECTOR (7 downto 0);
           q_in : in STD_LOGIC_VECTOR (7 downto 0);
           q_out : out STD_LOGIC_VECTOR (7 downto 0);
           a_out : out STD_LOGIC_VECTOR (7 downto 0);
           q01 : out STD_LOGIC_VECTOR (1 downto 0));
end prodreg;

architecture Behavioral of prodreg is

    signal s_q : STD_LOGIC_VECTOR (7 downto 0); -- q (multiplier) being processed
    signal s_a : STD_LOGIC_VECTOR (7 downto 0); -- accumulator being processed


begin
    process(clk)
    -- registers for q and a
    variable p_q : STD_LOGIC_VECTOR (7 downto 0) := "00000101"; -- q (multiplier) being processed
    variable p_a : STD_LOGIC_VECTOR (7 downto 0); -- accumulator being processed
    
    begin
        if rising_edge(clk) then
            if load <= '1' then
                s_a <= a_in;            
            else
                s_a <= p_a;                
            end if;        
                s_q <= p_q;
            if shift = '1' then -- conduct arithmetic shift right
                s_q(6 downto 0) <= s_q(7 downto 1); -- do shift right for Q
                s_q(7) <= s_a(0); -- save LSB of A in MSB of Q
                s_a(6 downto 0) <= s_a(7 downto 1); -- do shift right for A
                                              
                p_a := s_a; 
                p_q := s_q;                                 
            end if;                                                             
        end if;                
    end process;
                q01(1) <= s_q(0); -- save LSB of Q in 'x.' of q01 (x is the position of bit)
                q01(0) <= s_q(1); -- save LSB of Q in '.x' of q01 (x is the position of bit)   
                q_out <= s_q;
                a_out <= s_a;    
end Behavioral;

enter image description here

With that, the q and a outputs are shifting right as desired. I hope this information helps beginner VHDL scripters in the future.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.