Hi I have the program below that does what I want to do, shift 1 bit left or right depending on inputs s_right or s_enable. The numeric.std library contains shift operators and I want to start using them so I get a better grasp on the language but can find no good examples that show me the right way at using them
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;
Any help would be great thanks.
From package numeric_std, the body:
-- 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;
These call:
-----------------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;
Where you find SHIFT_LEFT fills reg(0)
with '0' and SHIFT_RIGHT fills reg(7)
with '0'.
You had previously assigned ser_in
to reg(7)
and reg(0)
respectively, those assignments would be lost (the last assignment in a sequence of statements wins).
So reverse the order of the assignments:
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;
Notice this also gets rid of the ser_out
flip flop using a 2:1 mux instead, get's rid of the superfluous 'hold' assignments to reg(7 downto 0)
, uses the rising_edge function for immunity to events from a metastability value on clk
and moves the selectors
assignment to a concurrent signal assignment, allowing the process to be purely clock synchronous.
With a testbench (for shift right only):
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;
Notice at this point we haven't tested s_enable nor s_right = '0', but SHIFT_RIGHT works. Will SHIFT_LEFT work?
The secret was assigning the serial in to reg(0) or reg(7) after the shift function.