Adding a new port to and entity is a common structural refactoring in preparation of adding new functionality.
Adding a port to an entity requires changes to the corresponding component declarations and instantiations in order to keep the design consistent. The Add Port refactoring does this automatically.
Suppose you have an entity like this:
entity calc is
port(... start: in boolean; ...)
end calc;
Within the design it may be declared and instantiated as follows:
component calc is
port(... start: in boolean; ...)
end calc;
...
calc_inst: calc
port map(... start => start, ...);
Now suppose you need to add an output port ready to the calc entity. You can do this by applying the Add Port refactoring to the entity. You will need to specify the name, type, and direction of the port. The refactored result will be as follows:
entity calc is
port(... start: in boolean; ready: out boolean; ...)
end calc;
...
component calc is
port(... start: in boolean; ready: out boolean; ...)
end calc;
...
calc_inst: calc
port map(... start => start, ready => open, ...);
Note that the ready port is stubbed to an open connection of the instance, presumably before it will be connected to other instances.
Adding new connections to instances is a common design requirement. This requires changes on various places in the design hierarchy. The Connect Instance refactoring does this automatically.
Suppose you have a design as follows:
entity calc is
port(... start: in boolean; ready: out boolean; ...)
end calc;
entity ctrl is
port(... start: out boolean; ...)
end ctrl;
...
signal start: boolean;
...
calc_inst: calc
port map(... start => start, ready => open, ...);
...
ctrl_inst: ctrl
port map(... start => start, ...);
Note
To keep this example short, component declarations are not shown, If they are present, they will be kept up to date by the refactoring.
Note that ready is an unconnected port of the calc_inst instance. Suppose you want to connect to the ctrl_inst instance. You can do by applying the Connect Instance refactoring on ctrl_inst. The refactoring tool will present a number of possible signals and ports you can connect to. Select the ready port, and the refactored design will look as follows:
entity calc is
port(... start: in boolean; ready: out boolean; ...)
end calc;
entity ctrl is
port(... start: out boolean; ready: in boolean; ...)
end ctrl;
...
signal start: boolean;
signal ready: boolean;
...
calc_inst: calc
port map(... start => start, ready => open ready, ...);
...
ctrl_inst: ctrl
port map(... start => start, ready => ready, ...);
The refactoring infers the type and direction of a new port of the ctrl entity. It updates the entity interface and its component declaration if applicable. It also declares a new ready signal, and updates the port maps of the instantiations.
At some point in the design process, it may be desirable to modify the design hierarchy. For example, adding a new level of hierarchy may make the design clearer and create a new module that can be reused.
Creating a new level of hierarchy manually implies typically a lot of cumbersome work. The Encapsulate Concurrent Statements refactoring does all the work automatically.
As an example, we use the architecture of clock generator module. It contains a process for a clock driver:
architecture BEH of clock_generator is
constant PERIOD: time := 50 ns;
begin
CLOCK_DRIVER: process is
begin
clock <= '0';
wait for PERIOD/2;
clock <= '1';
wait for PERIOD/2;
end process CLOCK_DRIVER;
end architecture BEH;
Suppose we need to add more output clocks to the clock generator module. Instead of duplicating the clock driver process, a better idea is to make it reusable. We can do that by encapsulating it in its own module. This can be accomplished automatically by applying the Encapsulate Concurrent Statements refactoring to the clock driver process.
After refactoring the clock generator architecture is modified as follows:
architecture BEH of clock_generator is
constant PERIOD: time := 50 ns;
begin
CLOCK_DRIVER: process is
begin
clock <= '0';
wait for PERIOD/2;
clock <= '1';
wait for PERIOD/2;
end process CLOCK_DRIVER;
clock_driver_inst: entity work.clock_driver(RTL)
generic map (
PERIOD => PERIOD
)
port map (
clock => clock
);
end architecture BEH;
Moreover, a new clock driver module has been created:
entity clock_driver is
generic (PERIOD: time);
port (clock: out std_logic);
end entity clock_driver;
architecture RTL of clock_driver is
begin
CLOCK_DRIVER: process is
begin
clock <= '0';
wait for PERIOD/2;
clock <= '1';
wait for PERIOD/2;
end process CLOCK_DRIVER;
end architecture RTL;
Note that the refactoring understands how to map signals to ports with the correct directions, and how to map constants to generics.
Quite a lot of code changes were made, even though this was a “simple” example, with only one concurrent statement being encapsulated. In general, the Encapsulate Concurrent Statements refactoring can encapsulate an arbitrary number of concurrent statements.