I want to read a register (std_logic_vector) and modify it, e.g. shift it to left or right. If I define
port (a: in std_logic_vector(3 downto 0));
then I am not able to modify it since it can not be written.
You can't modify the input itself because it is coming from outside the entity. What you can do is:-
1. feed it through some combinational logic to produce an output which is related to it, eg. shifted left or right.
2. Load it into a register and then shift it left or right.
Which approach you would use depends on the nature of the 'modification'. If you want the output to always be a shifted version of the current input then use combinatorial logic. If you want to progressively shift the data on each clock then use a register.
signal tmp:std_logic_vector(3 downto 0) := a;
then, is that a valid statement for synthesis? Is there any better option?
You can't do that. The ':=' operator is only for giving the signal a default initial value (which is ignored in synthesis).
A signal is the equivalent of a wire. There is no point copying an input directly into a signal because the input is already a signal, so all you have done is joined a wire onto another wire. But if you put some logic between them then you can do something useful. For example:-
entity shifter is
Port (
a: in std_logic_vector(3 downto 0);
b: out std_logic_vector(3 downto 0)
);
end shifter;
architecture Behavioural of shifter is
begin
b <= a(2 downto 0) & '0';
end Behavioral
This takes the lower 3 bits of a, adds a '0' at the right-hand end, then sends the resulting 4 bit vector to output b, effectively shifting the input left. This technique can be used to shift or rotate by any number of places. You could also add a vector to control how many places to shift, and then you have a programmable barrel shifter.
If you want to store the data in a register for subsequent manipulation then you need to clock it. The code below adds inputs 'clk' and 'load' to clock the register and select between loading and shifting. When load is 1, port input a is clocked into the register. When load is 0, the register's output is shifted and clocked back into itself. Finally, the register's output is routed to port output b.
entity shiftreg is
Port (
clk: in std_logic;
load: in std_logic;
a: in std_logic_vector(3 downto 0);
b: out std_logic_vector(3 downto 0)
);
end shiftreg;
architecture Behavioural of shiftreg is
signal reg: std_logic_vector(3 downto 0);
begin
process (clk, reg)
begin
if rising_edge(clk) then
if (load='1') then
reg <= a;
else
reg <= reg(2 downto 0) & '0';
end if;
end if;
end process;
b <= reg;
end Behavioral;
You might wonder why we have to create a signal for the register, rather than just clocking b. The reason is that b is
output only, so we cannot read it. However if we make it inout then we can:-
port ( b: inout std_logic_vector(3 downto 0)
...
process (clk)
begin
if rising_edge(clk) then
if (load='1') then
b <= a;
else
b <= b(2 downto 0) & '0';
end if;
end if;
end process;
In practice both versions may produce identical logic, so (apart from extra typing) there is no penalty for using the intermediate signal - and it makes the intention clearer.