VHDL移位运营商

时间:2015-12-22 13:06:42

标签: vhdl

嗨我有下面的程序可以做我想做的事情,根据输入s_right或s_enable向左或向右移1位。 numeric.std库包含移位运算符,我想开始使用它们,这样我就能更好地掌握语言,但是找不到能够向我展示使用它们的正确方法的好例子

LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;


ENTITY  S_REG8 IS
port ( clk, s_enable, s_right, ser_in   :   in std_logic;
         ser_out                                :   out std_logic
        );
END ENTITY S_REG8;

ARCHITECTURE dflow OF S_REG8 IS
SIGNAL reg : std_logic_vector (7 DOWNTO 0); --7,6,5,4,3,2,1,0
SIGNAL selectors : std_logic_vector (1 DOWNTO 0);
BEGIN
SHIFT_REG:PROCESS (clk, s_enable, s_right)
    BEGIN
    selectors <= s_enable & s_right;
        IF clk'EVENT and clk ='1' THEN
            IF selectors <= "00" THEN
                reg (7 DOWNTO 0) <= reg (7 DOWNTO 0);
            ELSIF selectors <= "01" THEN
                reg (7 DOWNTO 0) <= reg (7 DOWNTO 0);
            ELSIF selectors <="10" THEN
                reg (0) <= ser_in;
                ser_out <= reg(7);
                --reg <= std_logic_vector(shift_left(unsigned(reg), 1);
                --SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL)
                reg (7 DOWNTO 1) <= reg (6 DOWNTO 0);

            ELSIF selectors <= "11" THEN
                reg (7) <= ser_in;
                ser_out <= reg(0);
                --reg <= shift_right(std_logic_vector(reg));
                reg (6 DOWNTO 0) <= reg (7 DOWNTO 1);                       
            END IF;
        END IF;
END PROCESS;
END ARCHITECTURE dflow; 

任何帮助都会非常感谢。

2 个答案:

答案 0 :(得分:2)

从包numeric_std,正文:

  -- Id: S.1
  function SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED is
  begin
    if (ARG'LENGTH < 1) then return NAU;
    end if;
    return UNSIGNED(XSLL(STD_LOGIC_VECTOR(ARG), COUNT));
  end SHIFT_LEFT;

  -- Id: S.2
  function SHIFT_RIGHT (ARG: UNSIGNED; COUNT: NATURAL) return UNSIGNED is
  begin
    if (ARG'LENGTH < 1) then return NAU;
    end if;
    return UNSIGNED(XSRL(STD_LOGIC_VECTOR(ARG), COUNT));
  end SHIFT_RIGHT;

这些电话:

  -----------------Local Subprograms - shift/rotate ops-------------------------

  function XSLL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
      is
    constant ARG_L: INTEGER := ARG'LENGTH-1;
    alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
    variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0');   begin
    if COUNT <= ARG_L then
      RESULT(ARG_L downto COUNT) := XARG(ARG_L-COUNT downto 0);
    end if;


    return RESULT;   end XSLL;

  function XSRL (ARG: STD_LOGIC_VECTOR; COUNT: NATURAL) return STD_LOGIC_VECTOR
      is
    constant ARG_L: INTEGER := ARG'LENGTH-1;
    alias XARG: STD_LOGIC_VECTOR(ARG_L downto 0) is ARG;
    variable RESULT: STD_LOGIC_VECTOR(ARG_L downto 0) := (others => '0');   begin
    if COUNT <= ARG_L then
      RESULT(ARG_L-COUNT downto 0) := XARG(ARG_L downto COUNT);
    end if;
    return RESULT;   end XSRL;

如果您发现SHIFT_LEFT使用&#39; 0&#39;填充reg(0)。和SHIFT_RIGHT使用&#39; 0&#39;填充reg(7)

您之前已经分别ser_in分配给reg(7)reg(0),这些分配将会丢失(一系列陈述中的最后一项分配获胜)。

所以颠倒作业的顺序:

architecture fie of s_reg8 is
    signal reg:         std_logic_vector (7 downto 0);
    signal selectors:   std_logic_vector (1 downto 0);
begin

    -- make process purely clock synchrnous
    selectors <= s_enable & s_right;
    -- ser_out multiplexer instead of flip flop:
    ser_out <=  reg(7) when s_right =  '0' else
                reg(0); --  when s_right = '1' else
                -- 'X';
shift_reg:
    process (clk)
    begin
        if rising_edge (clk) then -- immunity to metastability transitions
        -- if clk'event and clk ='1' then
            -- if selectors <= "00" then  -- redundant
            --     reg (7 downto 0) <= reg (7 downto 0);
            -- if selectors <= "01" then  -- redundant 
            --    reg (7 downto 0) <= reg (7 downto 0);
            -- elsif selectors <= "10" then
            if selectors = "10" then -- was elsif equality not 
                reg <= std_logic_vector(shift_left(unsigned(reg), 1));
                -- also added missing right paren
                reg (0) <= ser_in;  -- change the order so this occurs
                -- ser_out <= reg(7); -- no flip flop
                -- reg <= std_logic_vector(shift_left(unsigned(reg), 1); 
                -- SHIFT_LEFT (ARG: UNSIGNED; COUNT: NATURAL)
                -- reg (7 downto 1) <= reg (6 downto 0);

            -- elsif selectors <= "11" then
            elsif selectors = "11" then
                reg <= std_logic_vector(shift_right(unsigned(reg),1)); 
                -- missing distance, proper type conversion
                reg (7) <= ser_in;  -- change order so this assignment happens
                -- ser_out <= reg(0); -- no flip flop
                -- reg <= shift_right(std_logic_vector(reg));
                -- reg (6 downto 0) <= reg (7 downto 1);                       
            end if;
        end if;
end process;
end architecture; 

请注意,这也是使用2:1多路复用器摆脱ser_out触发器,取而代之的是摆脱多余的“保持&#39;对reg(7 downto 0)的赋值,使用rising_edge函数来抵消来自clk上的亚稳态值的事件,并将selectors赋值移动到并发信号分配,从而允许该过程纯粹是时钟同步。

使用测试平台(仅适用于右移):

library ieee;
use ieee.std_logic_1164.all;

entity s_reg8_tb is
end entity;

architecture foo of s_reg8_tb is
    signal clk:             std_logic := '0';
    signal s_enable:        std_logic;
    signal s_right:         std_logic;
    signal ser_in:          std_logic;
    signal ser_out:         std_logic;
    constant ser_in_val0:   std_logic_vector (1 to 8) := x"B9";
    constant ser_in_val1:   std_logic_vector (1 to 8) := x"AC";
begin
    CLOCK: -- clock period 20 ns
    process
    begin
        wait for 10 ns;
        clk <= not clk;
        if now > 800 ns then -- automagically stop the clock
            wait;
        end if;
    end process;
DUT:
    entity work.s_reg8
        port map (
            clk => clk, 
            s_enable => s_enable, 
            s_right => s_right, 
            ser_in => ser_in,
            ser_out => ser_out
        );
STIMULUS:
    process
    begin
        s_enable <= '1';
        s_right <= '1';
        for i in 1 to 8 loop
            ser_in  <= ser_in_val0(i);
            wait for 20 ns; -- one clock period
        end loop;
        for i in 1 to 8 loop
            ser_in  <= ser_in_val1(i);
            wait for 20 ns; -- one clock period
        end loop;   
        for i in 1 to 8 loop  -- so we get all val0 out
            ser_in  <= ser_in_val0(i);
            wait for 20 ns; -- one clock period
        end loop;   
        s_enable <= '0';
        wait for 20 ns;  -- one clock
        wait;      
    end process;
end architecture;

我们得到: s_reg8_tb.png

请注意,此时我们还没有测试过s_enable或s_right =&#39; 0&#39;,但SHIFT_RIGHT可以正常工作。 SHIFT_LEFT会工作吗?

秘密是在移位功能之后将序列输入到reg(0)或reg(7)。

答案 1 :(得分:0)

感谢您详细回复user1155120。我已经使用下面的描述来模拟寄存器中一位的左右移位。

LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.numeric_std.all;
ENTITY  S_REG8 IS
port ( clk, s_enable, s_right, ser_in   :   in std_logic;
         ser_out                                :   out std_logic
        );
END ENTITY S_REG8;
ARCHITECTURE dflow OF S_REG8 IS
SIGNAL reg:         std_logic_vector (7 downto 0);
SIGNAL selectors:   std_logic_vector (1 downto 0);
BEGIN
selectors <=  s_right & s_enable;
ser_out <=  reg(7) when selectors = "01" else
            reg(0); 
shift_reg:
PROCESS (clk)
BEGIN
    IF rising_edge (clk) THEN
        IF selectors = "01" THEN
            reg <= std_logic_vector(shift_left(unsigned(reg), 1));
            reg (0) <= ser_in;
            --  ser_out <= reg (7); 
        ELSIF selectors = "11" THEN
            reg <= std_logic_vector(shift_right(unsigned(reg),1)); 
            reg (7) <= ser_in; 
            --  ser_out <= reg (0);
        END IF;
    END IF;
END PROCESS;
END ARCHITECTURE;       

对于模拟,我一直在使用Quartus II ModSim,我得到以下结果:

ModSim Results

结果看起来很棒。将单个1位状态添加到寄存器中我可以看到它移动到寄存器的左侧或右侧,具体取决于输入s_right或s_enable的切换。 与我添加到原始描述中的加法锁存器相比,在set_out和reg(0)和(7)上使用多路复用器更有意义。 很多,谢谢