Teoría

Un corto cuento de hadas sobre PORT MAP

Figura 1. Componente de multiplexores y siete segmentos.

Érase una vez un mundo de entidades lógicas completamente separadas, un sumador por aquí, un comparador por allá, y muchas compuertas básicas desperdigas por todo el terreno digital. Ninguna de ellas se comunicaba con la otra, ¿para qué hacerlo si eran autosuficientes y hacían muy bien su función de manera independiente?

Pero un día soleado, aparentemente como cualquier otro, llegó la heroína de la historia, la Gran Instrucción PORT MAP. La instrucción dió un discurso sin igual, trataba sobre un objetivo más grande, una unión de componentes para construir algo mucho más complejo, de un sistema con muchas más funciones en base a cada uno de los componentes individuales.

A pesar de todo, alguno escépticos hicieron la pregunta precisa “¿cómo podemos lograrlo?”. Con voz tranquila y segura, respondió “No temáis pues yo enlazaré sus puertos de entrada y salida, yo seré la unión entre cada una de sus instancias. Seguidme y hagamos un sistema complejo”.

Entonces se unieron los componentes, en tan diversas y versátiles configuraciones. Unos se transformaron en divisores de frecuencia, otros en relojes digitales, incluso en controladores de plantas de energía. Rayos, algunos incluso formaron parte de la red neuronal de R. Daneel Olivaw.

Y así, las entidades lógicas vivieron felices para siempre, unidas unas con otras gracias a la Gran Instrucción PORT MAP.

Las fallas del cuento

Es tiempo de dejar de lado la escritura de ficción dado que un cuento no nos permite observar la manera en la que funcionan las cosas… ni nos permite presentar un reporte técnico en forma. Al menos ahora sabemos que la Gran Instrucción PORT MAP sirve para enlazar componentes, aunque es mejor leer la definición técnica según diversas fuentes:

[quote]
PORT MAP es una palabra clave del lenguaje VHDL utilizada para definir las conexiones internas entre las entradas, salidas, y señales internas. En otras palabras, cada instrucción PORT MAP define cómo está conectada la instancia de un componente dentro del circuito [1].
[/quote]

Bien, eso no me aclaró mucho… siguiente:

[quote]
PORT MAP es simplemente una lista que relaciona los puertos del circuito real con los puertos de un circuito prediseñado (componente siendo instanciado). Tal asignación puede ser nominal o posicional [2].
[/quote]

Simplemente… claro. No, no lo veo simple: Siguiente.

[quote]
La instrucción PORT MAP especifica la conexión de los puertos de cada instancia de los componentes a señales dentro del cuerpo general de la arquitectura [3].
[/quote]

Muy bien, tiene que ver algo con instancias, componentes, y conexiones. Una más.

[quote]
Las palabras reservadas PORT MAP son utilizadas para mostrar la relación entre las señales externas del sistema y las señales internas de las instancias [4].
[/quote]

Muy bien, gracias a nuestro cuento y a la información provista por [1, 2, 3, 4] ahora sabemos que la instrucción PORT MAP tiene mucho que ver con instancias de componentes y su unión. Empecemos por definir esos términos.

Instancias y componentes

En diseños anteriores hemos utilizado instancias, componentes y PORT MAP (tendrán que creerme en ésto… bien, vayan y revisen por su cuenta… ¿terminaron?). En el control de servomotores con dos botones, reloj digital, visualizadores de siete segmentos, control para motor dc… y básicamente cualquier proyecto realizado en este sitio, hemos utilizado tales conceptos. Ha llegado la hora de saber cómo funciona el código de una manera un poco más profunda.

Nada mejor para explicar la teoría que un ejemplo práctico. Volvamos a evaluar un componente conocido, Multiplexores y Visualizadores de Siete Segmentos. Dicho proyecto se compone de cuatro módulos independientes:

  1. Divisor de frecuencia de 50MHz a 200Hz
  2. Decodificador de seis bits a siete segmentos.
  3. Multiplexor para visualzadores.
  4. Sinceramente espero que no se den cuenta de que no sé contar…
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity clk200Hz is
    Port (
        entrada: in  STD_LOGIC;
        reset  : in  STD_LOGIC;
        salida : out STD_LOGIC
    );
end clk200Hz;
 
architecture Behavioral of clk200Hz is
    signal temporal: STD_LOGIC;
    signal contador: integer range 0 to 124999 := 0;
begin
    divisor_frecuencia: process (reset, entrada) begin
        if (reset = '1') then
            temporal <= '0';
            contador <= 0;
        elsif rising_edge(entrada) then
            if (contador = 124999) then
                temporal <= NOT(temporal);
                contador <= 0;
            else
                contador <= contador+1;
            end if;
        end if;
    end process;
     
    salida <= temporal;
end Behavioral;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity siete_segmentos is
    PORT (
        entrada: IN  STD_LOGIC_VECTOR(5 downto 0);
        salida : OUT STD_LOGIC_VECTOR(7 downto 0)
    );
end siete_segmentos;
 
architecture Behavioral of siete_segmentos is
begin
    visualizador: process (entrada) begin
        case entrada is
            when "000000" =>  salida <= x"C0"; -- 0
            when "000001" =>  salida <= x"F9"; -- 1
            when "000010" =>  salida <= x"A4"; -- 2
            when "000011" =>  salida <= x"B0"; -- 3
            when "000100" =>  salida <= x"99"; -- 4
            when "000101" =>  salida <= x"92"; -- 5
            when "000110" =>  salida <= x"82"; -- 6
            when "000111" =>  salida <= x"F8"; -- 7
            when "001000" =>  salida <= x"80"; -- 8
            when "001001" =>  salida <= x"98"; -- 9
            when "001010" =>  salida <= x"88"; -- A
            when "001011" =>  salida <= x"83"; -- B
            when "001100" =>  salida <= x"C6"; -- C
            when "001101" =>  salida <= x"A1"; -- D
            when "001110" =>  salida <= x"86"; -- E
            when "001111" =>  salida <= x"8E"; -- F
            when "010000" =>  salida <= x"90"; -- G
            when "010001" =>  salida <= x"89"; -- H
            when "010010" =>  salida <= x"E6"; -- I
            when "010011" =>  salida <= x"E1"; -- J
            when "010100" =>  salida <= x"85"; -- K
            when "010101" =>  salida <= x"C7"; -- L
            when "010110" =>  salida <= x"C8"; -- M
            when "010111" =>  salida <= x"AB"; -- N
            when "011000" =>  salida <= x"C0"; -- O
            when "011001" =>  salida <= x"8C"; -- P
            when "011010" =>  salida <= x"98"; -- Q
            when "011011" =>  salida <= x"AF"; -- R
            when "011100" =>  salida <= x"92"; -- S
            when "011101" =>  salida <= x"87"; -- T
            when "011110" =>  salida <= x"E3"; -- U
            when "011111" =>  salida <= x"C1"; -- V
            when "100000" =>  salida <= x"E2"; -- W
            when "100001" =>  salida <= x"8F"; -- X
            when "100010" =>  salida <= x"91"; -- Y
            when "100011" =>  salida <= x"B6"; -- Z
            when "100100" =>  salida <= x"BF"; -- -
            when "100101" =>  salida <= x"F7"; -- _
            when "100110" =>  salida <= x"7F"; -- .
            when others   =>  salida <= x"FF"; -- Nada
        end case;
    end process;
end Behavioral;
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity siete_segmentos_mux is
    PORT (
        clk   : IN  STD_LOGIC;
        reset : IN  STD_LOGIC;
        D0    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Primer dígito.
        D1    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Segundo dígito.
        D2    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Tercer dígito.
        D3    : IN  STD_LOGIC_VECTOR(5 downto 0);  --Cuarto dígito.
        salida: OUT STD_LOGIC_VECTOR(5 downto 0);  --Salida del multiplexor (valor a desplegar).
        MUX   : OUT STD_LOGIC_VECTOR(3 downto 0)   --Valor que define cual dígito se va a mostrar.
    );
end siete_segmentos_mux;
 
architecture Behavioral of siete_segmentos_mux is
    type estados is (rst, v0, v1, v2, v3);
    signal estado : estados;
begin
    visualizadores: process (reset, clk) begin
        if (reset = '1') then
            estado <= rst;
            MUX <= x"F";
            salida <= "111111";
        elsif rising_edge(clk) then
            case estado is
                when v0 =>
                    salida <= D3;
                    MUX <= "1110";
                    estado <= v1;
                when v1 =>
                    salida <= D2;
                    MUX <= "1101";
                    estado <= v2;
                when v2 =>
                    salida <= D1;
                    MUX <= "1011";
                    estado <= v3;
                when others =>
                    salida <= D0;
                    MUX <= "0111";
                    estado <= v0;
            end case;
        end if;
    end process;
end Behavioral;

Bien, ahora ya tenemos tres módulos, ¿cómo se relaciona un módulo de VHDL con un componente? ¿es lo mismo? ¿son diferentes? Y lo más importante, si son lo mismo ¿para qué nos confunden con tanto término ininteligible (¿ven a lo que me refiero?)?

Primeramente, un módulo de VHDL es un pequeño circuito que puede ser utilizado dentro de un circuito más grande, lo cual permite reutilizar y compartir el código [5]. Este módulo describe qué hace (la vista externa) y cómo lo hace (la vista interna) [3]. Por ejemplo, para el caso del divisor de frecuencia en el listado 1, sabemos que reduce la frecuencia de entrada de 50MHz a 200Hz y sabemos que lo hace por medio de la implementación de un contador y un comparador.

Para el divisor de frecuencia, la vista externa del módulo se compone de dos entradas y una única salida (listado 4). En otras palabras, la vista externa se encarga de los puertos de entrada y salida, sin importar causa, motivo, condición climática, estado de animo, o estatus social, pues eso (entradas y salidas) es lo único importante para interactuar con otros módulos.

entity clk200Hz is
    Port (
        entrada: in  STD_LOGIC;
        reset  : in  STD_LOGIC;
        salida : out STD_LOGIC
    );
end clk200Hz;

Por otra parte, la vista interna en este caso correspondería a la arquitectura, todo el código comportamental que describe cómo se reduce la frecuencia (listado 5).

architecture Behavioral of clk200Hz is
    signal temporal: STD_LOGIC;
    signal contador: integer range 0 to 124999 := 0;
begin
    divisor_frecuencia: process (reset, entrada) begin
        if (reset = '1') then
            temporal <= '0';
            contador <= 0;
        elsif rising_edge(entrada) then
            if (contador = 124999) then
                temporal <= NOT(temporal);
                contador <= 0;
            else
                contador <= contador+1;
            end if;
        end if;
    end process;
     
    salida <= temporal;
end Behavioral;

Pero no todos los módulos van a estar desarrollados por nosotros mismos. Las compañías como Xilinx y Altera brindan sus módulos para diversas funciones, por medio de la Library of Parametrized Modules o la Video and Image Processing Suite de Altera o los núcleos IP de Xilinx y otras compañías.

Dado que esas grandes compañías tienen sus patentes y sus secretos muy bien guardados, no van a compartir con nosotros el cómo, solamente nos dirán qué hace el módulo y lo necesario para utilizarlo. Eso nos lleva, ¡por fin!, a la definición de componente: un componente es código convencional que permite reutilizar código en diseños jerárquicos bajo una filosofía de caja negra [2].

Lo que esto quiere decir es que un componente nos permite utilizar la lógica de alguien más aunque no sepamos cómo es que lo hace, ¿y a quién le importa mientras haga el trabajo de manera adecuada? Por ejemplo, podemos tomar los módulos de Open Cores o Digilent para Basys2 y utilizarlos siempre y cuando sepamos qué va en la entrada y qué se espera a la salida.

Para declarar un componente se utiliza una sintaxis muy similar a la vista interna del módulo VHDL mostrada en el listado 4. Observen que ahora ya no necesitamos saber cómo opera el divisor, simplemente debemos conocer qué necesita para empezar a trabajar y qué entrega al terminar lo que sea que haga allí dentro.

COMPONENT clk200Hz IS
    PORT (
        entrada: IN  STD_LOGIC;
        reset  : IN  STD_LOGIC;
        salida : OUT STD_LOGIC
    );
END COMPONENT;

Básicamente, los pasos para la declaración de un componente respecto al módulo VHDL son:

  • Se reemplaza la palabra clave ENTITY por la palabra clave COMPONENT.
  • Se enlistan los puertos del componente de manera idéntica a como aparecen en el módulo.
  • Se finaliza la declaración con END COMPONENT en lugar de END nombre_de_modulo.

Ahora bien, tener un componente declarado no es lo mismo que estarlo utilizando. Hasta que no se instancia el componente, está haciendo exactamente nada útil en el código. Una instancia es una copia del componente dentro del diseño jerárquico.

Y es aquí, finalmente, donde entra en el juego la Gran Instrucción PORT MAP. La instrucción PORT MAP se encarga de instanciar un componente y determinar su conexión con otros componentes.

clk_i: clk200Hz PORT MAP(
    clk,
    reset,
    clk_out
);

El listado 7 muestra el ejemplo de un PORT MAP, el cual consta de varias partes que conviene analizar:

  • Etiqueta: la cadena clk_i viene a ser el nombre de la instancia del componente. Ésta es necesaria pues cada instancia debe tener un nombre propio para ser capaces de diferenciar unas de otras. Con eso dicho, la etiqueta debe ser un nombre único para evitarle conflictos existenciales a las herramientas de síntesis (e.g. odio cuando dicen mi nombre y se refieren a alguien más).
  • Componente siendo instanciado: Especifica el nombre del componente siendo instanciado (en este caso nuestro divisor de frecuencia). Para este punto ya debe existir una declaración del componente en alguna parte del módulo principal.
  • Palabra clave PORT MAP: Es la que indica que vamos a instanciar el componente y asigna las señales de entrada y salida a la instancia.
  • Lista de puertos: Aquí se envían las señales que se desean como entrada de la instancia y se asignan las señales para recibir el valor de salida. Generalmente se capturan de manera posicional (el orden en el que están en el componente es el orden en el que se mandan en el PORT MAP), aunque también se puede hacer de manera nominal.

Así que ahora podemos analizar el diseño de la unión del multiplexor con el componente de siete segmentos, como se muestra en el listado 8.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
 
entity siete_segmentos_completo is
    PORT (
        clk   : IN  STD_LOGIC;
        reset : IN  STD_LOGIC;
        D0    : IN  STD_LOGIC_VECTOR(5 downto 0);
        D1    : IN  STD_LOGIC_VECTOR(5 downto 0);
        D2    : IN  STD_LOGIC_VECTOR(5 downto 0);
        D3    : IN  STD_LOGIC_VECTOR(5 downto 0);
        salida: OUT STD_LOGIC_VECTOR(7 downto 0);
        MUX   : OUT STD_LOGIC_VECTOR(3 downto 0)
    );
end siete_segmentos_completo;
 
architecture Behavioral of siete_segmentos_completo is
    COMPONENT clk200Hz IS
        PORT (
            entrada: IN  STD_LOGIC;
            reset  : IN  STD_LOGIC;
            salida : OUT STD_LOGIC
        );
    END COMPONENT;
     
    COMPONENT siete_segmentos IS
        PORT (
            entrada: IN  STD_LOGIC_VECTOR(5 downto 0);
            salida : OUT STD_LOGIC_VECTOR(7 downto 0)
        );
    END COMPONENT;
     
    COMPONENT siete_segmentos_mux IS
        PORT (
            clk   : IN  STD_LOGIC;
            reset : IN  STD_LOGIC;
            D0    : IN  STD_LOGIC_VECTOR(5 downto 0);
            D1    : IN  STD_LOGIC_VECTOR(5 downto 0);
            D2    : IN  STD_LOGIC_VECTOR(5 downto 0);
            D3    : IN  STD_LOGIC_VECTOR(5 downto 0);
            salida: OUT STD_LOGIC_VECTOR(5 downto 0);
            MUX   : OUT STD_LOGIC_VECTOR(3 downto 0)
        );
    END COMPONENT;
     
    signal clk_out : STD_LOGIC := '0';
    signal digito  : STD_LOGIC_VECTOR(5 downto 0);
begin
    clk_i: clk200Hz PORT MAP(
        clk, reset, clk_out
    );
     
    mux_i: siete_segmentos_mux PORT MAP(
        clk_out, reset, D0, D1, D2, D3, digito, MUX
    );
     
    seg_i: siete_segmentos PORT MAP(
        digito, salida
    );
end Behavioral;

El listado 8 se compone por:

  • La vista externa del módulo, compuesta por la lista de entradas y salidas al mismo (líneas 4 a 15).
  • La vista interna del módulo, compuesta por el cómo, la descripción comportamental, de las líneas 17 a 60.
  • Dentro de la vista interna tenemos la declaración de tres componentes: clk200Hz (líneas 18 a 24), siete_segmentos (líneas 26 a 31), y siete_segmentos_mux (líneas 33 a 44).
  • Además, se crearon dos señales internas (líneas 46 y 47) como auxiliares en la interconexión de las instancias.
  • Entre las líneas 49 y 59 se declaró una instancia por componente por medio de la instrucción PORT MAP.

Y eso podría ser el final del artículo, pero veamos un poco más desde un punto de vista un tanto más gráfico.

La relación con el diagrama esquemático

En la figura 1 se muestra el diagrama esquemático a nivel registro-transferencia creado por Xilinx ISE 14 a partir del contenido de los listados 1, 2, 3 y 8. La figura contiene las siguientes partes:

  • Vista externa, mostrando las entradas y salidas del módulo principal a los costados (a la izquierda las entradas, a la derecha las salidas).
  • En el interior se muestra la implementación en base a los tres componentes. Cada uno de los tres componentes tiene dos leyendas, una en la parte superior y una en la parte inferior. La leyenda superior corresponde al nombre del componente mientras que la leyenda inferior muestra el nombre de la instancia particular.
  • Las conexiones realizadas mediante los PORT MAP, que se traduce como “todos los cablesitos que unen las instancias y señales externas”.
Figura 1. Componente de multiplexores y siete segmentos.

Figura 1. Componente de multiplexores y siete segmentos.

Ahora sé lo que están pensando: si se puede realizar eso en esquemático, ¿por qué no utilizar un diagrama esquemático en lugar de tanto código con PORT MAP que causa dolor de cabeza? Bien, hagámoslo así.

En la figura 2 se muestra la interfaz de Xilinx para crear el diagrama esquemático evitando los problemas del código. Del lado izquierdo se muestra la lista de componentes disponibles, tanto los propios como algunos otros básicos como sumadores y comparadores, y del lado derecho se tiene todo un lienzo en blanco para crear una obra de arte… o, ya saben, llenarlo de componentes.

Figura 2. Uniendo el multiplexor con el decodificador de siete segmentos desde diagrama esquemático.

Figura 2. Uniendo el multiplexor con el decodificador de siete segmentos desde diagrama esquemático.

Ya con las instancias de componentes en el canvas es tiempo de declarar las señales externas, tanto entradas como salidas. Esto se hace mediante la herramienta de Add I/O Marker. Las entradas y salidas colocadas con esta herramienta corresponderan a la lista de puertos en la entidad del módulo principal (figura 3).

Figura 3. Declaración de entradas y salidas de la entidad principal.

Figura 3. Declaración de entradas y salidas de la entidad principal.

Por último, se interconectan los componentes por medio de la herramienta Add wire, que corresponde a la generación de señales internas para enlazar un componente a otro (figura 4).

Figura 4. Adición de los cables que conectan los componentes internamente.

Figura 4. Adición de los cables que conectan los componentes internamente.

Y al sintetizar el módulo principal proveniente del diagrama esquemático podemos observar que el diagrama a nivel registro-transferencia de la figura 5 es similar al mostrado en la figura 1 excepto por una cosa: las etiquetas asignadas a cada componente.

Figura 5. Diagrama sintetizado por Xilinx XST a partir del diagrama esquemático.

Figura 5. Diagrama sintetizado por Xilinx XST a partir del diagrama esquemático.

Pero aún hay más. Siempre podemos indagar en cómo es que las herramientas de síntesis llegaron del esquemático que realizamos nosotros al esquemático a nivel registro-transferencia de la figura 5. Para ello se utiliza la opción Design Utilities -> View HDL Functional Model (figura 6).

Figura 6. Opción para observar el código de VHDL generado a partir del esquemático.

Figura 6. Opción para observar el código de VHDL generado a partir del esquemático.

Y el código que resulta es algo similar al mostrado en el listado 9.

library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.ALL;
library UNISIM;
use UNISIM.Vcomponents.ALL;

entity siete_segmentos_completo_esquematico is
   port ( clk    : in    std_logic; 
          D0     : in    std_logic_vector (5 downto 0); 
          D1     : in    std_logic_vector (5 downto 0); 
          D2     : in    std_logic_vector (5 downto 0); 
          D3     : in    std_logic_vector (5 downto 0); 
          reset  : in    std_logic; 
          MUX    : out   std_logic_vector (3 downto 0); 
          salida : out   std_logic_vector (7 downto 0));
end siete_segmentos_completo_esquematico;

architecture BEHAVIORAL of siete_segmentos_completo_esquematico is
   signal XLXN_11 : std_logic;
   signal XLXN_15 : std_logic_vector (5 downto 0);
   component clk200Hz
      port ( entrada : in    std_logic; 
             reset   : in    std_logic; 
             salida  : out   std_logic);
   end component;
   
   component siete_segmentos
      port ( entrada : in    std_logic_vector (5 downto 0); 
             salida  : out   std_logic_vector (7 downto 0));
   end component;
   
   component siete_segmentos_mux
      port ( clk    : in    std_logic; 
             reset  : in    std_logic; 
             D0     : in    std_logic_vector (5 downto 0); 
             D1     : in    std_logic_vector (5 downto 0); 
             D2     : in    std_logic_vector (5 downto 0); 
             D3     : in    std_logic_vector (5 downto 0); 
             salida : out   std_logic_vector (5 downto 0); 
             MUX    : out   std_logic_vector (3 downto 0));
   end component;
   
begin
   XLXI_1 : clk200Hz
      port map (entrada=>clk,
                reset=>reset,
                salida=>XLXN_11);
   
   XLXI_2 : siete_segmentos
      port map (entrada(5 downto 0)=>XLXN_15(5 downto 0),
                salida(7 downto 0)=>salida(7 downto 0));
   
   XLXI_3 : siete_segmentos_mux
      port map (clk=>XLXN_11,
                D0(5 downto 0)=>D0(5 downto 0),
                D1(5 downto 0)=>D1(5 downto 0),
                D2(5 downto 0)=>D2(5 downto 0),
                D3(5 downto 0)=>D3(5 downto 0),
                reset=>reset,
                MUX(3 downto 0)=>MUX(3 downto 0),
                salida(5 downto 0)=>XLXN_15(5 downto 0));
   
end BEHAVIORAL;

Si observamos con atención, el código del listado 9 es muy similar al mostrado en el listado 8:

  • La entidad está compuesta por la lista de entradas y salidas. En el listado 8 corresponde a las líneas 4 a 15, en éste corresponde a las líneas 7 a 16.
  • La descripción comportamental (líneas 17 a 60 del listado 8) corresponden ahora a las líneas 18 a 63.
  • La vista interna sigue teniendo tres componentes: clk200Hz (líneas 21 a 25), siete_segmentos (líneas 27 a 30), y siete_segmentos_mux (líneas 32 a 41).
  • Al igual que en el listado 8, se crearon dos señales internas (líneas 19 y 20) como auxiliares en la interconexión de las instancias. Estas señales tienen nombres genéricos XLXN_{NÚMERO}.
  • Entre las líneas 44 y 61 se declaró una instancia por componente por medio de la instrucción PORT MAP. Estas instancias tienen nombres genéricos XLXI_{NÚMERO}.

Así que, ambos métodos producen el mismo resultado, ya sea un módulo de VHDL con instrucciones PORT MAP o un diagrama esquemático, ¿cuál nos conviene más?

¿Esquemático o código?

Puede que algunos de ustedes no lo sepan pero soy de las personas que prefieren escribir código fuente sobre las interfaces gráficas. En algunas ocasiones he satanizado hasta cierto grado el uso de herramientas gráficas, como la creación de diagramas esquemáticos, debido a cuestiones un tanto más personales que objetivas. Habiendo dicho eso, espero presentar un juicio justo en la comparación que estoy por realizar.

Esquemático. Los diagramas esquemáticos presentan varias ventajas, aunque la principal de ellas es la (1) casi nula curva de aprendizaje. Solamente tienes que arrastrar y colocar, dejando que las herramientas de síntesis hagan el trabajo pesado. Además, (2) se pueden realizar pequeños diseños de manera más rápida.

Ahí acaban las buenas noticias del esquemático, es hora de hablar los inconvenientes:

  • Tiene poca portabilidad pues es una herramienta propietaria de Xilinx (o la compañía correspondiente), lo cual implica que otras herramientas no comprenderán el archivo. Sin embargo, en este punto no existe tanto problema debido a que se puede copiar el código generado por la XST (Xilinx Synthesis Technology) para exportar el componente para su uso con otro software.
  • Un diseño con varias decenas de componentes (o más) se vuelve caótico debido a la cantidad de conexiones. Cuando hay problemas en el diseño, resulta bastante entretenido buscar el cable adecuado dentro de toda la maraña (aunque no es muy recomendado para aquellos que no tienen un nivel aceptable de paciencia).
  • Las herramientas gráficas no se actualizan tan frecuentemente como los compiladores HDL, razón por la cual el resultado de la síntesis de un esquemático puede estar menos optimizado en relación a su contraparte en código.
  • El archivo esquemático no regenera automáticamente los símbolos tras cambios en los archivos individuales, lo que en algunas versiones de Xilinx ocasiona errores impredecibles.
  • La síntesis depende de la configuración del proyecto, realizando la síntesis en lenguaje VHDL o Verilog según los parámetros configurados (lo cual no está mal hasta que aparece un error en la síntesis debido a un cambio mal propagado).

Por lo tanto, la ventaja que ofrece el código con PORT MAP es un control total sobre los componentes declarados, nombres de instancias, nombres de señales y posibilidad de procesamiento adicional. Sin embargo, es obvio que el coste es alto: la curva de aprendizaje es mayor que para el uso de diagramas esquemáticos.

En resumen, la herramienta de diagramas esquemáticos es una buena opción para la implementación de pequeños sistemas siempre y cuando no sea necesario realizar cambios significativos a los componentes siendo utilizados pues esto puede llevar a errores de síntesis que están fuera del control del desarrollador. Para todo lo demás existe Master Card PORT MAP.

Lo que aprendimos hoy

Creo que este cuento corto se transformó en algo muy largo. Por la cordura de todos es mejor terminar aquí, recordando aquello que aprendimos en el camino:

  • Un módulo de VHDL es un “pedazo” de código reutilizable que describe qué operación se va a realizar y cómo debe realizarse.
  • Un componente es código que hace referencia a un módulo de VHDL, pero sólo a la parte de qué hace en relación a las entradas y salidas (no interesa saber el cómo).
  • Una instancia es una copia de un componente dentro de un diseño mayor (jerárquico).
  • La instrucción PORT MAP es la función pegamento entre módulos, componentes e instancias.
  • Los diagramas esquemáticos y los módulos de PORT MAP son, de manera general, equivalentes.
  • La Gran Instrucción PORT MAP es buena onda.

Espero de alguna forma haber esclarecido un poco sus dudas respecto al uso de PORT MAP (odiaría saber que los confundí aún más, aunque si es así no duden en dejar un comentario debajo). Por cierto ¡felicidades a ustedes que llegaron hasta aquí abajo!

Referencias

  1. ^ Kleitz, William. Digital Electronics – A Practical Approach with VHDL, 9th Edition. Estados Unidos de América: Pearson, 2012.
  2. ^ Pedroni, Volnei. Circuit Design and Simulation with VHDL, 2nd Edition. Estados Unidos de América: The MIT Press, 2010.
  3. ^ Ashenden, Peter. The Designer’s Guide to VHDL, 2nd Edition. Morgan Kaufmann, 1995.
  4. ^ Zwolinski, Mark. Digital System Design with VHDL, 2nd Edition. Prentice Hall, 2004.
  5. ^ Brown, Stephen y Vranesic, Zvonko. Fundamentals of Digital Logic with VHDL Design, 3rd Edition. Estados Unidos de América: McGraw Hill, 2009.

You Might Also Like

12 Comentarios

  • Responder
    Dimitry
    septiembre 20, 2014 at 12:44 pm

    Wow! Muy buena explicación. Gracias, me ha quedado muy claro todo esto. Está muy claro y ese toque de humor vuelve menos tedioso el aprendizaje y mas alivianado.

    Sigue así!

    • Responder
      Carlos Ramos
      septiembre 25, 2014 at 6:33 pm

      Muchas gracias por tu comentario, Dimitry :D.Un gusto saber que se le da uso a la información publicada en este blog.

  • Responder
    Emanuel
    diciembre 6, 2014 at 5:42 pm

    Hola; en verdad que me has ayudado a resolver muchas dudas y la forma de explicación es bastante buena y humorística. Bueno, me interesa saber un poco más a fondo como realizaste el divisor de frecuencia en esquemático porque en tu Figura 2 solo lo muestras ya hecho y quiero aprender a harmar uno para 1Hz, 10Hz y 1KHZ… gracias

    • Responder
      Carlos Ramos
      diciembre 8, 2014 at 9:20 pm

      Hola, Emanuel. Me agrada saber que el contenido te ha sido de utilidad :D. Respecto a tu duda: solamente cree un nuevo archivo esquemático y busque los nombres de los componentes que había creado (clk200Hz, siete_segmentos, siete_segmentos_mux). Cada vez que compilas cada módulo por separado, se genera un símbolo que puedes utilizar en el esquemático (o puedes generar un símbolo cuando quieras, a partir de un módulo en VHDL). Quizá sea necesario realizar una entrada en esa tema en particular, hummm. Mientras tanto, espero haber ayudado con la información. Saludos.

  • Responder
    jared alexis
    enero 13, 2018 at 10:23 am

    disculpa, tengo una duda, puedo meter un port map dentro de otro port map?
    tengo un reloj y un calendario y ambos usan port map, puedo unir esos como otro port map? espero respuesta, gracias

  • Responder
    Jerson Pérez
    mayo 12, 2018 at 12:04 pm

    Hola, me gustaría saber si puedo instanciar dentro de un process.

    • Responder
      Carlos Ramos
      junio 7, 2018 at 1:27 pm

      ¿Instanciar? Pues, se pueden usar variables y otras cosas, aunque si te refieres a declarar señales, esas son por entidad. Necesitaría saber más sobre a qué te refieres exactamente, qué quieres hacer, qué quieres lograr, y por qué consideras que a nivel de proceso es lo adecuado.
      Saludos cordiales.

  • Responder
    mirko
    octubre 16, 2018 at 1:02 pm

    Muy buena explicación .Gracias por subirlo

  • Responder
    Julio Diaz
    febrero 24, 2019 at 6:27 pm

    jajaja así si aprendo 😀

  • Responder
    Riscolso
    octubre 17, 2019 at 1:26 am

    Muchas gracias, la explicación es muy buena

  • Responder
    Sara
    mayo 10, 2020 at 5:48 pm

    Holaaa, es una explicación increíble (y bastante detallada), me ayudo muchísimo. ¡Gracias!

  • Deja tu comentario