Why is this shift register not loading properly in VHDL?

I have a custom shift register that has an input DL (left-most input), DR (right-most), a CLR that clears and loads DR, an S that shifts to the right, and a W that loads left. After testing it, the right-most one is loaded, but not on the left. I have re-read the code several times, but I cannot figure out what is wrong. Here's the code:

    library IEEE;
use IEEE.std_logic_1164.all;

entity shiftregister is
    port (
        CLK, CLR: in STD_LOGIC;
        S: in STD_LOGIC; --Shift right
 W: in STD_LOGIC; --Write
 Cin: in STD_LOGIC; --possible carry in from the addition
        DL: in STD_LOGIC_VECTOR (7 downto 0); --left load for addition result
 DR: in STD_LOGIC_VECTOR (7 downto 0); --right load for initial multiplier
        Q: out STD_LOGIC_VECTOR (15 downto 0)
     );
end shiftregister ;

architecture shiftregister of shiftregister is
signal IQ: std_logic_vector(15 downto 0):= (others => '0');
begin
   process (CLK)
   begin
 if(CLK'event and CLK='1') then 
          if CLR = '1' then 
   IQ(7 downto 0)  <= DR;  --CLR clears and initializes the multiplier
   IQ(15 downto 8) <= (others => '0');
   else 
  if (S='1') then
    IQ <= Cin & IQ(15 downto 1);
  elsif (W='1') then
    IQ(15 downto 8) <= DL;
  end if;
          end if;

 end if;  
    end process;
Q<=IQ;
end shiftregister;

      

Waveform

waveform

enter image description here

TestBench

library IEEE;
use IEEE.std_logic_1164.all;

entity register_tb is
end register_tb;

architecture register_tb of register_tb is
    component shiftregister is port (
        CLK, CLR: in STD_LOGIC;
        S: in STD_LOGIC; --Shift right
        W: in STD_LOGIC; --Write
        Cin: in STD_LOGIC; --possible carry in from the addition
        DL: in STD_LOGIC_VECTOR (7 downto 0); --left load for addition result
        DR: in STD_LOGIC_VECTOR (7 downto 0); --right load for initial multiplier
        Q: out STD_LOGIC_VECTOR (15 downto 0)
    );
    end component;

    signal CLK: std_logic:='0';
    signal CLR: std_logic:='1';
    signal Cin: std_logic:='0';
    signal S: std_logic:='1';
    signal W: std_logic:='0';
    signal DL, DR: std_logic_vector(7 downto 0):="00000000";
    signal Q: std_logic_vector(15 downto 0):="0000000000000000";
begin 
    U0: shiftregister port map (CLK, CLR, S, W, Cin, DL,DR,Q);

    CLR <= not CLR    after 20 ns;
    CLK <= not CLK    after 5 ns;
    W   <= not W      after 10 ns;
    DL  <= "10101010" after 10 ns;
    DR  <= "00110011" after 10 ns;

end register_tb;

      

+3


source to share


2 answers


Your simulation shows that your input is S

always high. The way you set up the conditions means that the last elsif statement will not be executed as it S

takes precedence over W

. If you want your entry to take precedence over your switch operation, you must switch your conditions.

if (W='1') then
  IQ(15 downto 8) <= DL;
elsif (S='1') then
  IQ <= Cin & IQ(15 downto 1);
end if;

      



Based on your comment about the desired behavior, you can do something like this:

if (S='1' and W='1') then
  IQ  <= Cin & DL & IQ(7 downto 1);
elsif (W='1') then -- S=0
  IQ(15 downto 8) <= DL;
elsif (S='1') then -- W=0
  IQ <= Cin & IQ(15 downto 1);
end if; -- W=0 & S=0

      

+3


source


Some improvements:

(1) Remove all signal but CLK from the sensitivity list. Your process has no asynchronous signals, so only a clock is required in the sensitivity list.

process(CLK)

      

(2) Assign zero to required bits only -> a matter of taste;)



IQ(7 downto 0)  <= DR;              --CLR clears and initializes the multiplier
IQ(15 downto 8) <= (others => '0');

      

(3) The elsif operator can specify the priority of an assignment:

if (S='1') then
  IQ <= Cin & IQ(15 downto 1);
elsif (W='1') then
  IQ(15 downto 8) <= DL;
end if;

      

(4) The string Q <= IQ;

creates a second 16-bit register. I think this is not intended. Move this line out of process.

+2


source







All Articles