Modelado del comportamiento de un proyecto Quartus en Verilog en el entorno ModelSim

En el último artículo, hicimos un módulo bastante complejo. Por supuesto, inserté el resultado ya depurado en el cuerpo del artículo. Pero me pareció que es bastante extraño cuando el autor dice “haz lo que hago”, pero no muestra un proceso muy importante. Permítame mostrarle cómo generalmente se depura un sistema mediante la simulación. Además, el próximo artículo contendrá información que ni siquiera yo conocía hace una semana. Pero para llegar a ellos, debe comprender los principios básicos. Entonces. Echemos un vistazo a cómo preparar rápidamente e iniciar con la misma rapidez el proceso de modelado en el entorno ModelSim.









¿Cómo funciona un programa de computadora común? Existe un cierto entorno externo (el monitor y el teclado con "mouse" son los representantes más típicos de este mismo entorno). El programa interactúa con ellos. Al depurar, puede crear influencias reales del entorno externo o puede emularlas. Nuestros evaluadores suelen escribir todo tipo de scripts que simplemente emulan influencias externas. Después de eso, se lanzan los analizadores de registros, que verifican que las respuestas sean correctas el miércoles.



¿Qué pasa si todo tiene errores en este programa de computadora? Puede establecer puntos de interrupción y examinar una instantánea del sistema en el momento en que llegan. Una porción del sistema son los valores de las variables. Quizás los estados de varios mutex y otros objetos de sincronización. En general, una instantánea de los parámetros internos del sistema depurado.



Al depurar para FPGA, puede hacer lo mismo. Es cierto que si el entorno es real, detenerse y estudiar una sección del sistema es problemático, aunque posible. Como parte de la historia de Redd, sigo promoviendo la idea de que todo debe ser simple y rápido. No diseñamos sistemas complejos. Estamos haciendo una especie de módulos, como se hizo en el artículo anterior . Es sofisticado, pero muy, muy sencillo. En general, haremos su modelado de comportamiento.



Y aquí surge la pregunta sobre el entorno externo. ¿Cómo simularlo? Los modelos vienen en nuestra ayuda. Verilog (así como VHDL y otros similares) es bastante posible para describir el comportamiento de cualquier cosa. Estamos haciendo un sistema que funciona con el microcircuito ULPI ... Entonces, para probar su funcionamiento, debe haber algo en el otro extremo que se comporte exactamente como el ULPI. Es decir, el modelo ULPI. Pero esto no es suficiente. Nuestro bloque reacciona a los comandos del bus ALAVON_MM. Es este autobús el que da vida al bloque. Por lo tanto, también necesitamos agregar el modelo de bus AVALON_MM, y este modelo debe estar activo. Es ella quien someterá las influencias de prueba.







En última instancia, tenemos que crear ese sistema. Y luego podremos registrar diagramas de tiempos de señales en todos sus buses e incluso dentro de cualquiera de sus módulos. Si ocurre un error, podemos establecer puntos de interrupción y examinar instantáneas del sistema para encontrar al enemigo. Aunque, personalmente, normalmente no establezco estos puntos de corte, la mayoría de las veces el análisis de gráficos de tiempo es suficiente. El hecho es que las señales pueden verse no solo en la interfaz, sino también en las internas. Al extraer una docena o dos de señales internas en el gráfico, normalmente puede adivinar qué está mal implementado en la lógica.



El propósito del artículo de hoy no es hablar sobre qué es el modelado en general (esta es una larga historia), sino mostrar cómo llevar a cabo este modelado más rápidamente. Y consideraremos esto no en una misión de combate, sino en un ejemplo simple. Haremos un sistema de prueba muy sencillo para que en el próximo artículo ya entendamos de dónde crecen las piernas de una versión más compleja del mismo, porque al leer es más conveniente no sentarse y preguntarse: “¿Por qué hace esto?”, Sino conocer todos los principios básicos, de los que ya se desprenden complicaciones. ... Por cierto, recientemente resultó que uno de mis conocidos, aunque posee la habilidad de modelar, no sabía que el entorno Quartus tiene mecanismos incorporados que le permiten hacer esto de manera fácil y natural. Dedicó mucho más esfuerzo de lo necesario. Entonces, tal vez alguien también aprenda ahora algo nuevo por sí mismo sobre las posibilidades inherentes a Quartus. Entonces,empecemos.



Verilog



Las personas se dividen en dos categorías. A los que les gusta crear todo desde cero con las manos y a los que les gusta hacerlo con el ratón. Crear todo con tus manos es más correcto. Puedes controlar cada acción y hacer todo lo que sabes perfectamente. Pero la memoria no es confiable. Si está haciendo lo mismo todo el tiempo, tiene en cuenta los detalles y si tiene que cambiar de idioma todo el tiempo, después de uno o dos meses debe recordar lo que debe hacerse allí. Por lo tanto, trabajar a través de la opción "jugar con el mouse" tiene derecho a existir al menos debido a esto. Nuevamente, si el módulo que se está depurando tiene una docena de señales de interfaz, siempre me aburro de hacer el trabajo de rutina de volver a declararlas y reenviarlas. Por lo tanto, ahora consideraremos cómo hacer un modelo usando el "mouse". Y luego, todos decidirán por sí mismos si esto es suficiente para él o si debe cambiar al trabajo manual.



Entonces, queremos simular el módulo. Lo que es "simular" está más allá del alcance de nuestro ciclo, puede escribir un ciclo grande separado sobre este tema. Es decir, en el marco de esta sección, asumimos que está familiarizado con la metodología para desarrollar un modelo. Pero entonces hay que incluirlo todo en el proyecto ... ¿O no? Por extraño que parezca, ni siquiera necesita crear su propio proyecto para modelar un módulo. Podemos adherirnos como parásito a cualquier proyecto, sin incluir nada nuevo en él, pero solo creando una suite de pruebas que no participará en el ensamblaje principal de ninguna manera.



En aras del interés, adjuntemos a nuestro proyecto ULPI un módulo tan divertido en SystemVerilog, escrito por mí específicamente para ilustrar y no tiene nada que ver con el analizador desarrollado. Hace solo un tiempo tuve un montón de problemas con el cálculo de sumas de comprobación, así que me vino a la cabeza.

module sum(
input         clk,
input [7:0]   data,
input         we,
input         sof,
output [15:0] sum
);

logic [15:0] temp;

always @ (posedge clk)
begin
     if (we) 
     begin
         if (sof)
             temp <= data;
         else
             temp <= temp + data;
     end
end

//   - 
//assign sum = (~temp)+1;
//    :
assign sum = temp;
endmodule


Se puede ver que los datos llegan a través de un bus, que recuerda de forma muy remota a AVALON_MM, y simplemente se emite en código paralelo.



Pongamos el archivo resultante en el directorio con nuestro proyecto, pero no lo incluiremos en el proyecto en Quartus. En su lugar, crearemos un conjunto de pruebas específicamente para ello. Para ello, seleccione el elemento de menú Asignaciones—> Configuración:







y en el árbol que aparece, busque el elemento Configuración de herramientas EDA—> Simulación:







Por cierto, sobre el tipo de simulación resaltado por el marco verde. ¿Quizás alguien recuerde que en los primeros artículos dije que a la hora de crear un proyecto, por pura costumbre, elijo ModelSim Altera? Era la misma pistola en el escenario que tarde o temprano tenía que disparar. Sin embargo, si no seleccionó un tipo de modelado al crear el proyecto, puede seleccionarlo o cambiarlo aquí.



Seguimos creando una suite de pruebas. Cambie el botón de opción a Compilar banco de pruebas (por cierto, ¿cómo se traduce este término a la perfección al ruso? No me atrevo a escribir "banco de pruebas", ya que no veo ningún banco) y presione el botón Bancos de prueba :







en el cuadro de diálogo que se abre, presione Nuevo :







si es necesario caso de prueba manualmente, puede completar los campos en una sola pasada. Pero como hacemos todo con el "mouse", ahora llenamos solo una parte de los campos, y luego completaremos el resto. En el campo Nombre del banco de pruebasEscribí la palabra Parazit (¿de qué otra manera llamar a una prueba que simplemente parasita el proyecto?). La palabra Parazit debajo se completó automáticamente. No lo cambiaremos ahora, pero en el futuro todavía tenemos que hacerlo. Además, usando el botón "...", seleccioné el archivo sum.sv con el código del sumador a depurar, y luego, usando el botón Agregar , lo empujé a la lista de archivos de prueba. Por ahora, eso es todo. Cerrando el diálogo ...







A continuación, continuaremos formando la prueba en el entorno ModelSim. Para hacer esto, seleccione el elemento de menú Herramientas—> Ejecutar herramientas de simulación—> Simulación RTL:







Se abre la ventana ModelSim. Quizás se encuentren errores en el código de Verilog, luego debe cerrar ModelSim, corregir los errores y volver a abrir. Pero tarde o temprano, la lista de errores se volverá puramente organizativa. Me parece así:







No se encontró ningún módulo de nivel superior. Esto es normal. Todavía no lo hemos creado simplemente. Por tanto, vamos a trabajar en la lista de bibliotecas y la abrimos. Aquí está, nuestro sumador.







Pase el mouse sobre él, presione el botón derecho del mouse y seleccione el elemento de menú Crear ola. Todo esto es tan aburrido en el texto, si estuviera grabando un video, todo el proceso tomaría decenas de segundos, así que no se alarme, pero observe sus manos más. Entonces, Create Wave ...







Las señales de la interfaz del módulo se movieron automáticamente al gráfico:







Es necesario asignar un valor a uno de ellos. No importa cuál, es importante nombrar. El antiguo entorno de modelado de Quartus era bueno para generar señales de reloj. Lamentablemente, se retiró de la entrega hace mucho tiempo, desde que comenzaron a adjuntar ModelSim, y aquí no todo es tan bonito con algo así. No vi el sentido de generar un generador aquí, así que ni siquiera lo mostraré. Entonces ... Bueno, establezcamos la línea we en cero. Apuntamos a la señal, presionamos el botón derecho, seleccionamos el elemento de menú Editar—> Editor de ondas—> Crear / Modificar WaveForm.







En el cuadro de diálogo que aparece, seleccione Constante . Y al mismo tiempo cambiaremos el tiempo, digamos, en 100 microsegundos:







A continuación, indicamos el valor 0:







Hemos creado el conjunto de datos mínimo requerido y el resto será más fácil de hacer con bolígrafos. Exportamos el archivo. Para hacer esto, seleccione el elemento de menú Archivo—> Exportar—> Forma de onda:







Seleccione el tipo de archivo Verilog Testbench (por cierto, es una pena que no sea SystemVerilog, pero en el futuro será posible corregirlo con bolígrafos). También configuramos el nombre del archivo. Lo llamé parazit_tb , siguiendo el "¿por qué no?"







Eso es todo, ModelSim se puede cerrar, mientras que la casa temporal no necesita guardarse.



Qué hacer con el modelo a continuación



Aquí hay un archivo Verilog tan torcido, pero aún así, listo para usar, el sistema creado para nosotros:

`timescale 1ns / 1ns
module parazit_tb  ; 
 
  reg    sof   ; 
  reg    we   ; 
  wire  [15:0]  sum   ; 
  reg  [7:0]  data   ; 
  reg    clk   ; 
  sum  
   DUT  ( 
       .sof (sof ) ,
      .we (we ) ,
      .sum (sum ) ,
      .data (data ) ,
      .clk (clk ) ); 



// "Constant Pattern"
// Start Time = 0 ns, End Time = 100 us, Period = 0 ns
  initial
  begin
  end

  initial
	#0 $stop;
endmodule


La automatización nos salvó de escribir bloques de construcción. Además, si hubiera más señales de interfaz, la automatización registraría y conectaría obedientemente todos los circuitos. Personalmente, al crear conjuntos de pruebas manualmente, lo que me deprime es el proceso de descripción de señales y su reenvío. Ahora, en este archivo, crearemos un modelo de entorno que afectará al módulo de suma depurado .



Como puede ver, no tiene sentido establecer las constantes hechas por el oscilador. Pero aún así, se han creado todos los circuitos, se ha conectado el módulo a probar, incluso se ha creado la sección inicial . Refinemos el código. Primero, eliminaremos el punto de interrupción eliminando las líneas:

  initial
	#0 $stop;


A continuación, agreguemos un modelo de un generador de reloj (¡cómo extraño un generador maravilloso, que fue hecho por los antiguos Quartuses! Allí se podía establecer la frecuencia en megahercios y no pensar en recalcularla en un período, y más aún, medio período).

  always 
  begin
      clk = 0;
      #5;
      clk = 1;
      #5;
  end


Ahora necesitamos enviar algunos bytes de datos. La forma más sencilla de hacer esto es en la sección inicial , pero si escribo allí cada fase de acceso al bus, el código de esta sección se volverá confuso. Por tanto, haré la siguiente tarea (es ella quien actúa como modelo de neumático):

task SendByte (input reg[7:0] D);
    begin
        data = D;
        we = 1;
        @(posedge clk);
        #1
        we = 0;
   end
endtask


Bueno, escribiré el propósito de las constantes y la llamada de ciclos para trabajar con el bus en el bloque inicial . Permítame recordarle que el tipo de registro # 123 significa "esperar 123 unidades de tiempo". Lo tenemos en nanosegundos. También les recuerdo que dado que las asignaciones son secuenciales, usamos la operación "igual", no la "flecha". Entonces, tenemos el siguiente código de prueba principal:

Mira aquí
  initial
  begin
     sof = 0;
     we = 0;
     data = 0;
     #13;
     //   
     sof = 1;
     SendByte (1);
     //  
     sof = 0;
     SendByte (5);
     SendByte (1);
     //      
     #20;
     SendByte (1);
  end




En total, nuestro código de módulo completo se ve así:

Ver el código completo del módulo.
`timescale 1ns / 1ns
module parazit_tb  ; 
 
  reg    sof   ; 
  reg    we   ; 
  wire  [15:0]  sum   ; 
  reg  [7:0]  data   ; 
  reg    clk   ; 
  sum  
   DUT  ( 
       .sof (sof ) ,
      .we (we ) ,
      .sum (sum ) ,
      .data (data ) ,
      .clk (clk ) ); 


  always 
  begin
      clk = 0;
      #5;
      clk = 1;
      #5;
  end

task SendByte (input reg[7:0] D);
    begin
        data = D;
        we = 1;
        @(posedge clk);
        #1
        we = 0;
   end
endtask

// "Constant Pattern"
// Start Time = 0 ns, End Time = 100 us, Period = 0 ns
  initial
  begin
     sof = 0;
     we = 0;
     data = 0;
     #13;
     //   
     sof = 1;
     SendByte (1);
     //  
     sof = 0;
     SendByte (5);
     SendByte (1);
     //      
     #20;
     SendByte (1);
  end

endmodule






Completar la preparación del caso de prueba



Es hora de agregar este texto al conjunto de pruebas. Para ello, vamos al diálogo que ya conocemos, pero







ahora no creamos nuestro conjunto, sino que lo seleccionamos de la lista. En el futuro, la lista crecerá a medida que se agreguen los conjuntos ... Una vez seleccionado, presione el botón Editar. Hice tres ediciones en la configuración:

  1. Se agregó el archivo parazit_tb.v a la lista.
  2. Dado que en el archivo parazit_tb.v el módulo de nivel superior tiene el nombre parazit_tb (puede asegurarse mirando la fuente de la sección anterior), ingresé este nombre en el módulo de nivel superior en la línea del banco de pruebas .
  3. Dije que ejecutara la simulación durante 10 microsegundos y luego hiciera una pausa. En todo caso, lo haré presionando los botones de control manual.








Total



Cerramos todo. Ejecute ModelSim nuevamente. Vemos que todo funciona correctamente. Los datos entran y se cuentan en la cantidad. Si no hay datos en el reloj ( somos cero), la cantidad no aumenta.







Cómo utilizar el entorno de modelado en sí es un tema de varios artículos. Y más bien en formato de video. Pero, en general, nos familiarizamos con el método de preparar y ejecutar rápidamente pruebas en el lenguaje Verilog desde el entorno Quartus.



Ahora que sabemos cómo ejecutar rápidamente la simulación, podemos esbozar un modelo de entorno para nuestro cabezal analizador USB y probar su funcionamiento. Al mismo tiempo, no memorizamos un solo hechizo ModelSim, ya que Quartus te permite personalizar todo usando el "mouse". Él mismo genera todos los scripts necesarios y llama él mismo al entorno ModelSim. También creamos la base para el modelo en modo automático, aunque luego tuvimos que modificarlo manualmente.



Ay y ah. Uno de los elementos del entorno externo es el módulo ULPI. Para desarrollar su modelo por su cuenta, debe, en primer lugar, comprender cuidadosamente la lógica del funcionamiento de ese microcircuito. Y en el artículo anterior dije que es muy complicado. Y, en segundo lugar, necesita dedicar mucho tiempo a desarrollar el código del modelo. Y la eliminación de errores en él ... Está claro que es más fácil encontrar algo ya hecho. Pero el modelo listo para usar se encontró solo en el lenguaje SystemC. Por tanto, en el próximo artículo aprenderemos a modelar un sistema utilizando este lenguaje.



All Articles