VHDL Code for Universal Shift Register with Example
A
universal shift register in VHDL is a register that can shift data left, right, load parallel data, or hold its value based on control signals. You define it using a process with a clock and control inputs to select the operation mode. The code uses a case statement inside a clocked process to implement these modes.Syntax
The universal shift register uses a clocked process with inputs for data, shift direction, load, and enable signals. Inside the process, a case statement controls the operation mode:
- clk: Clock signal triggering register updates.
- reset: Asynchronous reset to clear the register.
- shift_left: Control to shift bits left.
- shift_right: Control to shift bits right.
- load: Control to load parallel data.
- data_in: Parallel data input.
- serial_in_left and serial_in_right: Serial inputs for shifting.
- q: Register output.
vhdl
process(clk, reset) begin if reset = '1' then q <= (others => '0'); elsif rising_edge(clk) then case mode is when "00" => q <= q; -- Hold when "01" => q <= serial_in_right & q(q'left downto 1); -- Shift right when "10" => q <= q(q'right-1 downto 0) & serial_in_left; -- Shift left when "11" => q <= data_in; -- Load when others => q <= q; end case; end if; end process;
Example
This example shows a 4-bit universal shift register with synchronous reset and a 2-bit mode input to select the operation: hold, shift right, shift left, or load parallel data.
vhdl
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity UniversalShiftRegister is
Port (
clk : in std_logic;
reset : in std_logic;
mode : in std_logic_vector(1 downto 0); -- 00: Hold, 01: Shift Right, 10: Shift Left, 11: Load
data_in : in std_logic_vector(3 downto 0);
serial_in_left : in std_logic;
serial_in_right : in std_logic;
q : out std_logic_vector(3 downto 0)
);
end UniversalShiftRegister;
architecture Behavioral of UniversalShiftRegister is
signal reg_q : std_logic_vector(3 downto 0) := (others => '0');
begin
process(clk, reset)
begin
if reset = '1' then
reg_q <= (others => '0');
elsif rising_edge(clk) then
case mode is
when "00" =>
reg_q <= reg_q; -- Hold
when "01" =>
reg_q <= serial_in_right & reg_q(3 downto 1); -- Shift Right
when "10" =>
reg_q <= reg_q(2 downto 0) & serial_in_left; -- Shift Left
when "11" =>
reg_q <= data_in; -- Load
when others =>
reg_q <= reg_q;
end case;
end if;
end process;
q <= reg_q;
end Behavioral;Common Pitfalls
Common mistakes include:
- Not using a clock edge for updates, causing asynchronous behavior.
- Forgetting to reset the register, leading to unknown initial values.
- Incorrect bit slicing when shifting left or right.
- Not handling all
modecases, which can cause latches or unintended behavior.
Always use a synchronous process triggered by rising_edge(clk) and cover all cases in the case statement.
vhdl
process(clk) begin if rising_edge(clk) then if mode = "01" then -- Wrong: shifting bits incorrectly q <= q(2 downto 0) & serial_in_right; -- This shifts left instead of right end if; end if; end process; -- Correct shifting right: process(clk) begin if rising_edge(clk) then if mode = "01" then q <= serial_in_right & q(3 downto 1); -- Shift right correctly end if; end if; end process;
Quick Reference
Mode Control for Universal Shift Register:
| Mode | Operation |
|---|---|
| 00 | Hold (no change) |
| 01 | Shift Right (insert serial_in_right) |
| 10 | Shift Left (insert serial_in_left) |
| 11 | Load Parallel Data (data_in) |
| Mode | Operation |
|---|---|
| 00 | Hold (no change) |
| 01 | Shift Right (insert serial_in_right) |
| 10 | Shift Left (insert serial_in_left) |
| 11 | Load Parallel Data (data_in) |
Key Takeaways
Use a clocked process with rising_edge(clk) to update the register synchronously.
Control the operation mode with a 2-bit input to select hold, shift left, shift right, or load.
Always reset the register to a known state to avoid unknown outputs.
Be careful with bit slicing when shifting left or right to avoid data corruption.
Cover all mode cases in the case statement to prevent unintended latches.