Author Topic: Modifying an input port  (Read 1146 times)

0 Members and 1 Guest are viewing this topic.

Offline mnTopic starter

  • Contributor
  • Posts: 16
  • Country: ca
Modifying an input port
« on: September 11, 2017, 01:19:39 pm »
Hi
The question may look so simple, but I appreciate if someone explain that. I want to read a register (std_logic_vector) and modify it, e.g. shift it to left or right. If I define

Code: [Select]
port (a: in std_logic_vector(3 downto 0));
then I am not able to modify it since it can not be written. So, what should i do? If I define a signal to hold a copy of that like this

Code: [Select]
    signal tmp:std_logic_vector(3 downto 0) := a;
then, is that a valid statement for synthesis? Is there any better option?
 

Offline Bruce Abbott

  • Frequent Contributor
  • **
  • Posts: 627
  • Country: nz
    • Bruce Abbott's R/C Models and Electronics
Re: Modifying an input port
« Reply #1 on: September 14, 2017, 11:50:33 am »
I want to read a register (std_logic_vector) and modify it, e.g. shift it to left or right. If I define

Code: [Select]
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.
 
Quote
Code: [Select]
    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:-

Code: [Select]
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.

Code: [Select]
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:-

Code: [Select]
  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.
 
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf