Ya vimos anteriormente como introducir el código VHDL usado en el software de XILINX (más concretamene Vivado) en un modelo de SIMULINK, que luego nos servía para simular el comportamiento de las salidas del diseño previamente hecho.
A ese diseño descrito en VHDL lo llamamos LEDA_blog, y lo hemos usado profusamente hasta ahora.
Dejo los enlaces de las entradas de este blog dónde se hizo (así no tienes que navegar en él y te facilito las cosas):
Sintetizando lo que hicimos fue:
XILINX (VHDL) => SIMULINK
Esta vez vamos a realizar el proceso contrario,
SIMULINK => XILINX (VHDL)
Sólo que esta vez partiremos de un diseño más sencillo, un simple multiplexor 2 a 1 (2 entradas una salida), lo que en electrónica digital usamos muchas veces como un "Hola Mundo" (y sin embargo eso no quita que los multplexores son circuitos combinacionales muy importantes en electrónica digital).
Las razones por las que vamos a partir de un diseño sencillo son tres:
- La primera es que siempre es más pedagógico ir de lo sencillo a lo complejo.
- La segunda es algo bastante más prosaico, y es que esta entrada la voy a hacer con los trials de las últimas versiones de Vivado y Matlab -en la versión más completa de los dos programas- y los 30 días que los tengo gratis están a punto de vencer. Si me pongo con algo más complejo es posible que me quede a medias.
- La tercera es que no quiero que acabemos odiando el dichoso diseño LEDA_blog (estoy intentando parecer divertido, no el tipo serio y aburrido que soy :P).
Si no sabes lo que es un multiplexor (ya dije que pretendo escribir para todos los públicos como las antiguas películas de Walt Disney), no te preocupes, cuando acabe el tutorial tendrás unas nociones muy claras, te lo garantizo.
Esto es uno de los motivos por los que me gustan tanto los tutoriales tipo "receta de cocina" (pantallazos y más pantallazos), aprendes mucho casi sin darte cuenta, es casi un método socrático de aprender.
Bueno, basta de pedantería mía y vamos "al meollo" (algunos tipos serios y aburridos además somos pedantes hasta decir basta).
Tutorial:
Paso 1: Enlazar Vivado con Matlab.
Tal y como lo he planteado la idea que te puedes hacer es que se empieza por abrir el Matlab y luego el Simulink, si lo haces así lo más probable es que no se carguen las librerías de XILINX en Matlab y SIMULINK.
Se empieza por el nexo de unión entre estos dos softwares (el paquete de aplicaciones de XILINX y Matlab-SIMULINK), el System Generator.
Para que todo te funcione correctamente antes deberías haber configurado ese nexo de unión mediante el System Generator Matlab Configurator.
Si leíste los tutoriales que dejé para pasar de Vivado a Simulink, y lo pusiste en práctica en tu ordenador (computador o computadora), puedes saltarte directamente esta parte.
En caso contrario es aconsejable que sigas leyendo porque sino no te va a funcionar.
El proceso para enlazar Vivado con Matlab lo explico en el "1er Paso" de la entrada:
Con el primer apartado "1er Paso" es suficiente, no hace falta que lo leas todo si no quieres.
Paso 2: Abrir Matlab y luego SIMULINK mediante el System Generator.
Dónde tengas tu XILINX, encontrarás el System Generator - entre otras aplicaciones del paquete de software-.
Según tu sistema operativo tendrás que navegar hasta su ubicación. Por ejemplo, si tienes un Widows 7 (XP o Vista), una forma puede ser clic en inicio, programas, xilinx....
Yo lo tengo en el escritorio como un enlace directo.
Haces doble clic en él y se abre el Matlab. Una vez abierto Matlab abrimos Simulink para lo cual clic con el ratón en el icono que señalo a continuación:
Después de un rato más o menos grande (según la potencia de tu ordenador, las condiciones en que lo tengas etc), se abre la interfaz de Simulink, que en las últimas versiones de Matlab es así (antes se abría primero las librerías, y luego creabas el modelo):
En ese cuadro de diálogo o ventana emergente que se nos abre, hacemos clic en Blank Model para crear nuestro modelo desde cero.
Aparece nuestro modelo aún "virgen":
Paso 3: Creación del modelo de Simulink.
Para crear nuestro modelo tenemos que abrir las librerías de Simulink (Library Browser), para ello clic dónde señalo:
Tenemos:
Fijemosnos en el "Simulink Library Browser", porqué si todo ha ido bien se deben de haber cargado las nuevas librerías de Xilinx, si es la primera vez que usas el "System Generator" seguramente -si la memoria no me falla- que a la vez que se abre el "Simulink Library Browser, se estará procesando la carga de las librerías en él.
Como son las últimas en incorporarse deslizamos el scrollbar (o barra de deslizamiento en este caso vertical) hacia abajo.
Desplegando la lista de esas librerías tenemos dentro de ellas otras:
Dentro de la librería Xilinx Blockset vamos a hacer uso de la Basic Elements.
Haciendo doble clic en Basic Elements tenemos:
Vemos que dentro de la sub-librería Basic Elements tenemos a su vez un conjunto de bloques de diseño que se pueden incorporar a nuestro modelo aún vacío de Simulink.
El primero (y muy importante en este caso), es el System Generator que se destaca de otros por ser el primero de color rojo y con una forma característica de 'E' mayúscula.
Hay dos formas de incorporar un bloque de diseño a el modelo, ambas muy sencillas e intuitivas.
Una es "pinchando" (o haciendo clic en él) y arrastrando con el ratón a la ventana del modelo.
Forma 1:
Forma 2:
Otra es hacer clic derecho en el bloque seleccionado y en la lista desplegable que aparece clic en Add block to model 'nombre del modelo', en este caso no le hemos puesto aún nombre y por defecto se denomina untitled, así que sería Add block to model untitled.
Una vez está el bloque en el modelo, lo mantenemos seleccionado - y sino lo está lo seleccionamos- para desplazarlo arrastrando con el ratón. Yo lo suelo ver en el extremo superior izquierda en los tutoriales de Internet, y a mi me parece un buen lugar para colocar el System Generator, así que "pincho" (un sólo clic del botón izquierdo del ratón) en él y lo arrastro (desplazamos con el ratón) a ese lugar.
Aún nos queda configurar el bloque System Generator dentro del modelo, para lo cual hacemos doble clic en el icono que nos ha quedado en el modelo de Simulink.
Tal y como está configurado en la anterior figura nos valdría (es como me viene a mi por defecto), sobre todo por el hecho de que no vamos a implementar el sistema digital que estamos diseñando en ningún hardware. Si pudiera lo implementaría en la Spartan-3E, pero en las nuevas versiones de Vivado ya no se encuentra la Spartan-3E y menos la placa de desarrollo Core3S250E.
Pero vamos a suponer que quisiéramos implementar lo para una versión muy concreta de FPGA, por ejemplo la Kintex7 en lugar de una Zynq que es la que viene por defecto, En el drop-down list del campo Part, vamos a hacer:
Y nos queda:
En esta ocasión tampoco nos preocupa demasiado las pestañas Clocking y General, lo que venga por defecto estará bien.
Ahora sólo falta pulsar Apply y luego OK, tras lo cual conviene salvar el modelo y darle nombre. Más adelante haremos uso del botón Generate justo a la izquierda de OK.
Por tanto hacemos clic en File, Save As, y navegamos hasta dónde deseemos guardar el modelo de Simulink.
Yo le damos el nombre que queramos (yo le he dado el nombre de mux2a1_blog) y pulsamos en guardar.
Continuamos construyendo el modelo, el próximo bloque que vamos a añadir también está en Basic Elements de la librería de BlockSet Xilinx, y es obviamente el bloque que corresponde al multiplexor denominado Mux, en realidad todos los bloques que vamos a usar en este tutorial están es Basic Elements.
Ahora hacemos doble clic sobre el bloque Mux seleccionado en el modelo de Simulink (que yo he llamado mux2a1_blog) para configurarlo.
Tenemos la ventana emergente:
Al igual que antes por defecto tendremos lo que se muestra en la figura anterior (sino es así ponlo de esta forma please).
Ahora Apply y Ok.
Antes de seguir, voy a comentar (estoy partiendo de la base de que algún lector no tiene mucha experiencia con Simulink) que los bloques de diseño que vamos incorporando a nuestro modelo se pueden cambiar de tamaño, tanto en horizontal como en vertical.
En este caso nos interesa cambiar de tamaño el bloque Mux. Para ello basta con tener seleccionado el bloque e ir arrastrando con el ratón en los extremos cuando el puntero del ratón lo señala.
Seguimos construyendo del modelo, como dijimos antes nos basta con los bloques de Basic Elements.
Ahora realizamos las conexiones, es fácil e intuitivo, pero ya que me estoy metiendo a tanto nivel de detalle voy a dejar algunas figuras que dan una idea de como se hace.
Hacemos lo mismo con el resto de conexiones y nos queda:
Dentro de la librería Xilinx Blockset vamos a hacer uso de la Basic Elements.
Haciendo doble clic en Basic Elements tenemos:
Vemos que dentro de la sub-librería Basic Elements tenemos a su vez un conjunto de bloques de diseño que se pueden incorporar a nuestro modelo aún vacío de Simulink.
El primero (y muy importante en este caso), es el System Generator que se destaca de otros por ser el primero de color rojo y con una forma característica de 'E' mayúscula.
Hay dos formas de incorporar un bloque de diseño a el modelo, ambas muy sencillas e intuitivas.
Una es "pinchando" (o haciendo clic en él) y arrastrando con el ratón a la ventana del modelo.
Forma 1:
Forma 2:
Otra es hacer clic derecho en el bloque seleccionado y en la lista desplegable que aparece clic en Add block to model 'nombre del modelo', en este caso no le hemos puesto aún nombre y por defecto se denomina untitled, así que sería Add block to model untitled.
Una vez está el bloque en el modelo, lo mantenemos seleccionado - y sino lo está lo seleccionamos- para desplazarlo arrastrando con el ratón. Yo lo suelo ver en el extremo superior izquierda en los tutoriales de Internet, y a mi me parece un buen lugar para colocar el System Generator, así que "pincho" (un sólo clic del botón izquierdo del ratón) en él y lo arrastro (desplazamos con el ratón) a ese lugar.
Aún nos queda configurar el bloque System Generator dentro del modelo, para lo cual hacemos doble clic en el icono que nos ha quedado en el modelo de Simulink.
Tal y como está configurado en la anterior figura nos valdría (es como me viene a mi por defecto), sobre todo por el hecho de que no vamos a implementar el sistema digital que estamos diseñando en ningún hardware. Si pudiera lo implementaría en la Spartan-3E, pero en las nuevas versiones de Vivado ya no se encuentra la Spartan-3E y menos la placa de desarrollo Core3S250E.
Pero vamos a suponer que quisiéramos implementar lo para una versión muy concreta de FPGA, por ejemplo la Kintex7 en lugar de una Zynq que es la que viene por defecto, En el drop-down list del campo Part, vamos a hacer:
Y nos queda:
En esta ocasión tampoco nos preocupa demasiado las pestañas Clocking y General, lo que venga por defecto estará bien.
Ahora sólo falta pulsar Apply y luego OK, tras lo cual conviene salvar el modelo y darle nombre. Más adelante haremos uso del botón Generate justo a la izquierda de OK.
Por tanto hacemos clic en File, Save As, y navegamos hasta dónde deseemos guardar el modelo de Simulink.
Yo le damos el nombre que queramos (yo le he dado el nombre de mux2a1_blog) y pulsamos en guardar.
Continuamos construyendo el modelo, el próximo bloque que vamos a añadir también está en Basic Elements de la librería de BlockSet Xilinx, y es obviamente el bloque que corresponde al multiplexor denominado Mux, en realidad todos los bloques que vamos a usar en este tutorial están es Basic Elements.
Ahora hacemos doble clic sobre el bloque Mux seleccionado en el modelo de Simulink (que yo he llamado mux2a1_blog) para configurarlo.
Tenemos la ventana emergente:
La pestaña Basic la dejamos tal cual está en la figura que es como viene por defecto.
Clic en la pestaña Output:
Ahora Apply y Ok.
Antes de seguir, voy a comentar (estoy partiendo de la base de que algún lector no tiene mucha experiencia con Simulink) que los bloques de diseño que vamos incorporando a nuestro modelo se pueden cambiar de tamaño, tanto en horizontal como en vertical.
En este caso nos interesa cambiar de tamaño el bloque Mux. Para ello basta con tener seleccionado el bloque e ir arrastrando con el ratón en los extremos cuando el puntero del ratón lo señala.
Seguimos construyendo del modelo, como dijimos antes nos basta con los bloques de Basic Elements.
Ahora realizamos las conexiones, es fácil e intuitivo, pero ya que me estoy metiendo a tanto nivel de detalle voy a dejar algunas figuras que dan una idea de como se hace.
Hacemos lo mismo con el resto de conexiones y nos queda:
Ahora tenemos que configurar los nuevos bloques introducidos, los del tipo "Gateway In" y "Gateway Out".
Aparece una ventana emergente o cuadro de diálogo.
Por defecto yo lo tengo de esta manera:
Lo modificamos para que quede como sigue:
Ahora seleccionamos la pestaña Implementation:
La dejamos tal y como está. Apply y Ok.
Hacemos exactamente igual con Gate Way In1 y Gate Way In2.
Con Gate Way Out no hay que hacer cambios, no obstante le vamos a echar un vistazo.
No changes!, keep the same! (spanglish).
El resto de bloques ya no son de las librerías de Xilinx, son de la principal de Simulink (la primera, más concretamente de Sinks, Sources y Signal Routing).
Finalmente quedaría:
No obstante, para no perder mucho tiempo buscando en las librerías, puedes hacer una cosa que es usar el buscador de las librerías (Libraries Search).
Enter (o Intro) y se obtienen los resultados de la búsqueda:
Para dar valores a los bloques Constant, doble clic en cada uno de ellos:
Y modificamos:
Ahora ya lo tenemos completado, ahora guardamos los cambios (clic en save):
Paso 4: Generar, compilar y simular.
Para generar el código (que luego se podrá abrir con Vivado), compilarlo y simularlo en Simulink, volvemos a hacer doble clic en el bloque de diseño System Generator.
Una vez hecho doble clic, tarde más o menos, se abrirá la ventana que ya abrimos.
En ella pulsamos el botón generate, y se abre una pequeña ventana con el logo rojo en forma de 'E' cambiando a distintas formas e indicando que se está procesando la generación y compilación.
Finalmente el proceso de generación de código y compilación termina, y tan sólo tenemos que dar en OK en esa pequeña ventana en la que el logo iba tomando distintas formas y ahora permanece de nuevo con su forma característica fija y con el mensaje "Generation Compiled".
Una vez hecho clic en OK cerramos la ventana de informes y pulsamos en el botón de OK en la ventana de System Generator.
Antes de abrir el código VHDL en Vivado, estamos ya en disposición de simular con el Simulink.
Para mostrar como la simulación, si todo ha ido bien resulta, dejo un clip.
-------------------------------------------------------
Nota:
Si lo ves muy pequeño haz clic en fullscreen en el extremo inferior izquierda, y luego pulsa Esc del teclado.
-------------------------------------------------------
Paso 5: Obtener el código VHDL en Vivado.
Para ello ejecutamos Vivado, yo lo tengo como acceso directo en el escritorio.
En mi caso tarda un poco en abrirse un poco (es un programa potente), si es tu caso también un poco de paciencia.
Una vez abierto el interfaz de Vivado clic en OpenProject y navegamos hasta el lugar dónde hemos guardado el modelo de Simulink.
En dicha carpeta ya se ha creado otra llamada netlist, entramos en ella.
Dentro de ella encontramos una llamada hdl_netlist nos introducimos en ella.
Dentro de la carpeta en hdl_netlist hacemos clic en el archivo con el icono característico de Vivado y con extensión '.xpr'. En mi caso es el archivo mux2a1_blog.xpr.
Clic en Ok.
Tenemos lo siguiente:
Si nos fijamos en la ventana dentro del interfaz llamada Sources, tenemos ahí varios archivos con extensión '.vhd', es ahí dónde se ha creado no uno, sino varios códigos VHDL del multiplexor 2 a 1.
El principal es el mux2a1_blog-estructural (mux2a1_blog.vhd), si hacemos doble clic en él,
Justo a la derecha de esta ventana se nos despliega los códigos que son:
-- Generated from Simulink block mux2a1_blog_struct
-- Generated from Simulink block
-- Generated from Simulink block
Estos sólo dentro de la raíz de mux2a1_blog-estructural (mux2a1_blog.vhd).
Si encuentro tiempo los explicaré con más detalle en el futuro, no obstante por si desea el lector o lectora echarles un ojo, los dejo en el siguiente cuadro para copiar y pegar.
-- Generated from Simulink block mux2a1_blog_struct library IEEE; use IEEE.std_logic_1164.all; library xil_defaultlib; use xil_defaultlib.conv_pkg.all; entity mux2a1_blog_struct is port ( gateway_in : in std_logic_vector( 1-1 downto 0 ); gateway_in1 : in std_logic_vector( 1-1 downto 0 ); gateway_in2 : in std_logic_vector( 1-1 downto 0 ); clk_1 : in std_logic; ce_1 : in std_logic; gateway_out : out std_logic_vector( 1-1 downto 0 ) ); end mux2a1_blog_struct; architecture structural of mux2a1_blog_struct is signal gateway_in_net : std_logic_vector( 1-1 downto 0 ); signal gateway_in1_net : std_logic_vector( 1-1 downto 0 ); signal gateway_in2_net : std_logic_vector( 1-1 downto 0 ); signal mux_y_net : std_logic_vector( 1-1 downto 0 ); signal clk_net : std_logic; signal ce_net : std_logic; begin gateway_in_net <= gateway_in; gateway_in1_net <= gateway_in1; gateway_in2_net <= gateway_in2; gateway_out <= mux_y_net; clk_net <= clk_1; ce_net <= ce_1; mux : entity xil_defaultlib.sysgen_mux_36237b0251 port map ( clr => '0', sel => gateway_in_net, d0 => gateway_in1_net, d1 => gateway_in2_net, clk => clk_net, ce => ce_net, y => mux_y_net ); end structural; -- Generated from Simulink block library IEEE; use IEEE.std_logic_1164.all; library xil_defaultlib; use xil_defaultlib.conv_pkg.all; entity mux2a1_blog_default_clock_driver is port ( mux2a1_blog_sysclk : in std_logic; mux2a1_blog_sysce : in std_logic; mux2a1_blog_sysclr : in std_logic; mux2a1_blog_clk1 : out std_logic; mux2a1_blog_ce1 : out std_logic ); end mux2a1_blog_default_clock_driver; architecture structural of mux2a1_blog_default_clock_driver is begin clockdriver : entity xil_defaultlib.xlclockdriver generic map ( period => 1, log_2_period => 1 ) port map ( sysclk => mux2a1_blog_sysclk, sysce => mux2a1_blog_sysce, sysclr => mux2a1_blog_sysclr, clk => mux2a1_blog_clk1, ce => mux2a1_blog_ce1 ); end structural; -- Generated from Simulink block library IEEE; use IEEE.std_logic_1164.all; library xil_defaultlib; use xil_defaultlib.conv_pkg.all; entity mux2a1_blog is port ( gateway_in : in std_logic; gateway_in1 : in std_logic; gateway_in2 : in std_logic; clk : in std_logic; gateway_out : out std_logic ); end mux2a1_blog; architecture structural of mux2a1_blog is attribute core_generation_info : string; attribute core_generation_info of structural : architecture is "mux2a1_blog,sysgen_core_2016_2,{,compilation=HDL Netlist,block_icon_display=Default,family=kintex7,part=xc7k325t,speed=-2,package=ffg900,synthesis_language=vhdl,hdl_library=xil_defaultlib,synthesis_strategy=Vivado Synthesis Defaults,implementation_strategy=Vivado Implementation Defaults,testbench=0,interface_doc=0,ce_clr=0,clock_period=10,system_simulink_period=1,waveform_viewer=0,axilite_interface=0,ip_catalog_plugin=0,hwcosim_burst_mode=0,simulation_time=10,mux=1,}"; signal clk_1_net : std_logic; signal ce_1_net : std_logic; begin mux2a1_blog_default_clock_driver : entity xil_defaultlib.mux2a1_blog_default_clock_driver port map ( mux2a1_blog_sysclk => clk, mux2a1_blog_sysce => '1', mux2a1_blog_sysclr => '0', mux2a1_blog_clk1 => clk_1_net, mux2a1_blog_ce1 => ce_1_net ); mux2a1_blog_struct : entity xil_defaultlib.mux2a1_blog_struct port map ( gateway_in(0) => gateway_in, gateway_in1(0) => gateway_in1, gateway_in2(0) => gateway_in2, clk_1 => clk_1_net, ce_1 => ce_1_net, gateway_out(0) => gateway_out );
Por el momento lo dejamos aquí, espero que este tutorial resulte útil :).
-Fin-