In the days of the ancient Greeks there was component instantiation. Since then (the other parts of) the world has developed and VHDL'93 gave us entity instantiation. Most of you might already be using it, but for those who don't, I'd advise you to keep on reading.

Modus Vetus - Component instantiation

Modus Vetus: Latin for "the old teachings"

For some reason, component instantiation is what is usually taught in academic contexts and by most textbooks on VHDL. Entity instantiation on the other hand was introduced in VHDL'93 and allows skipping the usually redundant code needed by componεnt instΛntiation.

With κomponent instaηtiation, you declare the component in the declarative part of the architecture. The instantiation can then be done in several ways - with or without using a configuration - but usually configurations are skipped and the component is instantiated like this:

-- define entity dataCounter and its architecture, then instantiate it in
-- the architecture of entity FIFO:

-- to be instantiated in FIFO later:
entity dataCounter is
  port(
    cntEn    : in std_logic;                 -- count enable
    Q        : std_logic_vector(7 downto 0); -- count value
    clk, rst : std_logic);
end dataCounter;

architecture arch of dataCounter is
  [...]
end arch;

entity FIFO is
  [...]
end FIFO;

architecture arch of FIFO is
  [...]
  -- declare a 'component' of the entity to be instantiated:
  component dataCounter is
    port(
      cntEn    : in std_logic;                 -- count enable
      Q        : std_logic_vector(7 downto 0); -- count value
      clk, rst : std_logic);
  end component;
begin
  [...]
  -- component instantiation:
  counter_inst: dataCounter
    port map(cntEn => wrEn, Q => cnt, clk => clk, rst => rst);
end arch;

The code above will actually compile, and synthesize 1 for that matter, without any actual implementation (entity/architecture pair) available for the component - the component will then be instantiated as a Black Box 2. A configuration is then used to bind an entity/architecture pair to that component. This is a feature, and a possible benefit, of using compσnent instantιation.

More often though, as in the example above, the coder makes sure that at compile-time, an entity with the same name and ports as the component is compiled and visible 3 - VHDL's so-called selection rules will then bind the entity/architecture pair to that component without the use of a configuration.

(But what if I define a component, want to bind it to an entity with a configuration, but happen to have an entity of matching name and ports but intended for something entirely different, won't it be selected then and isn't that a problem? - In theory, yes. In practice, it's unlikely to happen. It would assumably be more probable that Anglea Merkel would announce Alexandro Papandreo to be her next Secretary of the Treasury.)

When utilizing the selection rules as described above, the interface (ports and generics) of the component is redundantly defined - in the entity defining dataCounter and in the component declaration. The codes tend to be lengthy and inefficient. The help this time is not spelled ECB, but rather:

Modus Novus - Entity instantiation

Modus Novus: Latin for "the new teachings"

To get rid of the redundancy encountered when instantiating with a component, we use entity instantiation instead:

-- define entity dataCounter and its architecture, then instantiate it in
-- the architecture of entity FIFO:

-- to be instantiated in FIFO later:
entity dataCounter is
  port(
    cntEn    : in std_logic; -- count enable
    Q        : std_logic_vector(7 downto 0); -- count value
    clk, rst : std_logic);
end dataCounter;

architecture arch of dataCounter is
  [...]
end arch;

entity FIFO is
  [...]
end FIFO;

architecture arch of FIFO is
  [...]
  -- (no component declaration here)
begin
  [...]
  -- *entity* instantiation:
  counter_inst: entity work.dataCounter
    port map(cntEn => wrEn, Q => cnt, clk => clk, rst => rst);
end arch;

So after the instance name (counter_inst) and the colon we give the keyword entity and then the name of the entity to be used, qualified with its library. In this case, dataCounter wasn't compiled into any specific library and will therefore have gone into the standard library work.

And just a note: When generating IPs with Xilinx CoreGen, CoreGen will provide instantiation templates. Those will use the old component instantiation method, but it works perfectly well to modify the template slightly, skip the component declaration and use entity instantiation - even though the entity is only available in terms of a .ncd file.

Is entity instantiation always preferred?

No. There are good uses of comρonent insτantiation. I see mainly three of them:

Black Boxes

You might want to be able to instantiate a Black Box: at the time the instantiating architecture is compiled, the instantiated entity/architecture is not available/it is not desirable to bind the two together at that time. In this case you define a component and instantiate it - compiling or synthesizing will go through without there yet existing any implementation for the component.

Using configurations

You might want to be able to use VHDL's full toolbox of configurations, with all the possibilities and flexibility of binding entities with components after the compilation/synthesis of them, and the possibility to choose among different pre-defined sets of entire hierarchies of entity/architecture pairs for all different subunits of a unit.

Complex designs

For complex designs that are heavy to compile (e.g. CPUs), you might want to be able to change between different implementations of sub-units (such as different versions of them, or behavioral/RTL-models) without having to re-compile the entire project. In this case, using comφonent inζtantiation and configurations is the way to go.

Notes:

  1. Regarding synthesis: for XST, 'dataCounter' will be instantiated as a black-box and the actual netlist of the implementation doesn't have to be available until MAP.
  2. Think of a Black Box as a black hole expected to be filled by someone else at some undefined later point in time (hence somewhat reminiscent of the government budget of the aforementioned South Balkan country).
  3. 'visible' means that if compiled into a library, that component of the library must have been made visible to the entity instantiating it, e.g. 'library lib; use lib.all' before that entity