Reputation: 28334
I'm learning VHDL and find something confusing. Suppose you have the following entity:
entity alu32 is
port(a, b : in STD_LOGIC_VECTOR(31 downto 0);
alucontrol : in STD_LOGIC_VECTOR(2 downto 0);
result : buffer STD_LOGIC_VECTOR(31 downto 0);
zero : out STD_LOGIC);
end alu32;
When using it as a component in another entity's architecture, it's defined like this:
component alu32
port(
a, b : in STD_LOGIC_VECTOR(31 downto 0);
alucontrol : in STD_LOGIC_VECTOR(2 downto 0);
result : buffer STD_LOGIC_VECTOR(31 downto 0);
zero : out STD_LOGIC
);
end component;
My question is, why do we redefine the port? It seems like a pointless exercise since it's exactly the same as in the entity declaration. Why wasn't VHDL design to allow you to simply use a component like this:
component alu32;
Upvotes: 1
Views: 573
Reputation: 3388
You can, since VHDL-93. You can instantiate using
Alu_0: entity work.alu32
port map (
...
);
In this snippet, you can replace work
for the VHDL library of the component you want to instantiate, work
is always the current library the VHDL source resides in.
Why use the component declaration? First, they are required if what you want to instantiate is not VHDL, such as Verilog, IP cores and netlist. Second, using configuration allow to change port/entity binding, but you need component declaration for that.
Upvotes: 7
Reputation:
Essentially the language designers were looking forward as carefully as they could, to a world that ... didn't quite happen that way.
The idea of a component
declaration was that it defines exactly what is expected when you instantiate it, thus an entity/architecture that uses these components is self-consistent and can be compiled and to some extent tested as an independent task from the components it uses - perhaps even before those components are written.
Bill Lynch's comment is relevant here, and easy to forget today : when compilation took a thousand times longer, this was a big productivity win
Later, when you build the overall design, that component is searched for in a library of components, and either an exactly matching entity is found (default configuration), or a specific component is selected by a configuration
statement. Or elaboration fails, reporting the mismatch as an error - no chance of creating a design with a part that doesn't quite fit. The library could contain a wide range of "alu32" components with different characteristics for different purposes (fast, small, with/without floating point, etc). This happens at "elaboration", roughly the same as the link stage in software, when (hopefully) the right entity/arch is found, and its ports checked against those of the component. This was a natural way to see design evolving for designers who grew up with "The TTL Data Book" - a library of physical building blocks in the form of TTL ICs.
However, in a typical use case today, we don't use libraries of components to such a great extent, so the "alu32" in your example is probably another file in the same project, compiled into your "work" library.
And in that case, the shorter, simpler "direct entity instantiation" (introduced in 1993) from Jonathan Drolet's answer is the correct approach. Downside? It does mean you have to write - and successfully compile - the "alu32" entity before you can syntax check the top level design (though you can write the architecture later, before elaboration).
Upvotes: 4
Reputation:
IEEE Std 1076-2008, 6.8 Component declarations
A component declaration declares an interface to a virtual design entity that may be used in a component instantiation statement. A component configuration or a configuration specification can be used to associate a component instance with a design entity that resides in a library.
3.4 Configuration declarations
In certain cases, however, it may be appropriate to leave unspecified the binding of component instances in a given block and to defer such specification until later.
A component declaration is like a Function prototype. A generic map or port map aspect is part of a binding indication.
From Annex I:
binding: The process of associating a design entity and, optionally, an architecture with an instance of a component. A binding can be specified in an explicit or a default binding indication. (3.4, 7.3.2, 7.3.3, 14.4.3.3, 14.5.4)
As an example of where you'd want to consider component declarations used with configuration declarations, a design where internal blocks have the same interface:
component sbox
port (
B: in std_logic_vector (1 to 6);
S: out std_logic_vector (1 to 4)
);
end component;
They are actually distinct and you use more than one:
S1: sbox
port map (
B => ExK(1 to 6),
S => PO(1 to 4)
);
S2: sbox
port map (
B => ExK(7 to 12),
S => PO(5 to 8)
);
The enclosing entities are otherwise identical (dslice).
You can specify which entity is used where during elaboration:
configuration behave_config of des is
for behave
for DSLICE0: dslice
use entity work.dslice(behave);
for behave
for S1: sbox
use entity work.sbox1(behave);
end for;
for S2: sbox
use entity work.sbox2(behave);
end for;
end for;
end for;
...
The DES encryption algorithm in this instance can be described as hardware in four sections differentiated by substitution box contents and external interconnections.
This design model demonstrates the hardware nature of the Digital Encryption Algorithm found in the Digital Encryption Standard (FIPS Pub 46, single DES). You can take a close look at this link - vhdl_des.tar.gz.
And for synthesis or simulation tools that don't support configuration the alternative is to uniquify the blocks containing the instantiated entities, in this case increasing the size of the design description by almost a factor of four along with the increased maintenance and hazards of needless replication.
Upvotes: 0