Diferencia al programar verilog en Quartus o en Xilinx

Temas de diseño con HDL que no dependen de un lenguaje en particular, o que pueden aplicarse a cualquier lenguaje (diseño óptimo de FSM, optimizaciones para facilitar el timing closure, etc). Si hay que poner algún ejemplo podrá usarse VHDL o Verilog (o idealmente, el mismo ejemplo en ambos lenguajes)
Responder
Avatar de Usuario
jepalza
Spartan 3
Mensajes: 226
Registrado: 14 Ago 2018, 18:51

Diferencia al programar verilog en Quartus o en Xilinx

Mensaje por jepalza » 03 Sep 2018, 12:21

Estoy haciendo unas pruebas con un core que quiero llevar al UnAmiga y al mismo tiempo al ZXDOS.
Unamiga se programa con Quartus, ZXDOS con Xilinx, ambos en verilog. Pero me he encontrado una diferencia notable entre unoy otro sistema, que aún desconozco su razón de ser.
El mismo código compilado en Xilinx da errores de "variables ya creadas por defecto", mientras que en Quartus, no dice nada, y compila bien.

Al parecer, Xilinx, si se encuentra una referencia a una variable (wire) "no" declarada previamente, la declara por defecto, pero si luego, mas adelante, se encuentra con la variable ya declarada, da el error indicado.
Explicado mejor: si en un código verilog, dentro de xilinx, hacemos referencia a un wire, arriba del todo, por ejemplo, "assign prueba = 1'b1;" y luego, mas abajo del código, lo definimos con "wire prueba;" el compilador da error y se detiene, diciendo que la variable "prueba" ya ha sido definida anteriormente por defecto.
En cambio, el Quartus, no dice nada, y le da igual si definimos al revés la variable.
Lo normal, para que no de error, es poner el "wire prueba;" arriba del todo, y luego, por debajo de la difinición, la usamos con "assign prueba=1'b1; " y de ese modo, funciona bien tanto en Quartus como en Xilinx.

desconozco la razón, solo sé que ocurre. Es bueno saberlo.

En concreto, esto lo he descubierto en el core el "Sinclair QL"

carmeloco
GAL
Mensajes: 51
Registrado: 20 Ago 2018, 15:32

Re: Diferencia al programar verilog en Quartus o en Xilinx

Mensaje por carmeloco » 03 Sep 2018, 15:23

Pues pensaba que estos lenguajes de programación eran más estandarizados, y sin diferencias de "personalizaciones" entre marcas. Es bueno saberlo.

Avatar de Usuario
mcleod_ideafix
Site Admin
Mensajes: 80
Registrado: 14 Ago 2018, 01:15

Re: Diferencia al programar verilog en Quartus o en Xilinx

Mensaje por mcleod_ideafix » 03 Sep 2018, 16:45

carmeloco escribió:
03 Sep 2018, 15:23
Pues pensaba que estos lenguajes de programación eran más estandarizados, y sin diferencias de "personalizaciones" entre marcas. Es bueno saberlo.
Las únicas "personalizaciones" que tiene Verilog, hasta donde yo sé, es en las tareas del sistema que se hayan implementado y si han puesto alguna "customizada". Lo que es el lenguaje en sí es un estándar del IEEE. De hecho, hay varios estándares, desde el 2001 hasta el 2012, así que puede pasar que en ISE se use un cierto estándar, y en Quartus, otro. De hecho probablementeg Quartus acepte un estándar más moderno que ISE, que sólo soporta hasta el estándar Verilog 2001. A partir del 2005, los estándares para Verilog y SystemVerilog se fusionan y pasan a ser un único estándar.

Sobre lo que pasa con los wires redefinidos y esas cosas:
Verilog, por defecto, asume que cualquier variable que no ha sido definida explicitamente, lo es como un "wire". Esto es un comportamiento, a mi gusto peligroso, porque impide que te des cuenta de errores de tecleado cuando nombras variables y las usas después.

Para evitarlo, se pone arriba del todo en el código fuente lo siguiente:

Código: Seleccionar todo

`default_nettype none
Y a partir de ahí, toda señal que no tenga una definición explícita dará un error. Si se quiere volver al comportamiento por defecto, hacer:

Código: Seleccionar todo

`default_nettype wire
jepalza escribió:Lo normal, para que no de error, es poner el "wire prueba;" arriba del todo, y luego, por debajo de la difinición, la usamos con "assign prueba=1'b1; " y de ese modo, funciona bien tanto en Quartus como en Xilinx.
Efectivamente. Esto es lo que debería tener el código. Lo otro que te has encontrado es sencillamente de código obsoleto o ingeniero que no cumple los estándares.

También te digo otra cosa: el sintetizador del ISE (XST) no acepta algunas cosas que son perfectamente legales en Verilog y que son sintetizables. Sencillamente, "no lo hemos implementado, y ya si eso lo ponemos en Vivado". Vamos, que el soporte de Verilog en XST tiene algunos flecos que no han resuelto, y que no piensan resolver. Cuando estaba probando el módulo de display de entrenamiento en ZXDOS me encontré que el generador de caracteres para pintar los dígitos funcionaba mal, aunque en UnAmiga lo hacía perfectamente, y el código era completamente legal. Todo se solucionó cuando quité un acceso a la block RAM de un case. Es decir, yo tenía algo como esto (ejemplo simplificado)

Código: Seleccionar todo

reg [7:0] mem[0:1023];
reg [7:0] dato;
always @(posedge clk) begin
  case (posicion)
    'b00: dato <= memoria[dir0];
    'b01: dato <= memoria[dir1];
    'b10: dato <= memoria[dir2];
    'b11: dato <= memoria[dir3];
    default: dato <= 0;
  endcase
end
Es decir, en función del valor de "posicion", en dato se guarda el valor de una cierta posición de memoria, diferente para cada caso.

Este código de arriba es perfectamente legal, funciona en las simulaciones, y funciona en Quartus. Sin embargo, en ISE no lo hace. ¿Por qué? Ni idea. No es la primera vez que me ha pasado, de hecho. El código del reproductor de PZX también me dio quebraderos de cabeza por razones similares.

Recordé precisamente lo que tuve que hacer en aquella ocasión: evitar múltiples referencias a memoria desde el mismo bloque always, con diferentes direcciones. Así, el código anterior lo sustituí por algo como esto, funcionalmente equivalente:

Código: Seleccionar todo

reg [7:0] mem[0:1023];
reg [7:0] dato;
reg [9:0] dir;
reg leer;
always @* begin
  leer = 1;  // valores por defecto
  dir = 0;   // como buen always combinacional que es
  case (posicion)
    'b00: dir = dir0;
    'b01: dir = dir1;
    'b10: dir = dir2;
    'b11: dir = dir3;
    default: leer = 0;
  endcase
end

always @(posedge clk) begin
  if (leer == 1)
    dato <= memoria[dir];
  else
    dato <= 0;
end
La pequeña-gran diferencia de este código con el anterior es que en este último, la lectura de memoria sólo se hace en un sitio, en un único always, en lugar de hacerse en varios sitios, aunque por el comportamiento se deduzca que sólo se haría la lectura en uno de esos sitios. Es como si con el primer código, el sintetizador fuera incapaz de darse cuenta de que el multiplexor que debe inferir en el "case" es para las direcciones y no para los accesos completos. La verdad es que el segundo código es más explícito en esto, además de que así favorezco el que la memoria inferida pueda ser block RAM y no distribuida.

A saber la de código que hay por ahí que funciona en Altera (y por tanto en UnAmiga) y no lo hace en XST (y por tanto en ZXDOS) por chorradas como esta, que simulan bien pero sintetizan mal.

Avatar de Usuario
yombo
Veroboard
Mensajes: 18
Registrado: 17 Ago 2018, 10:51

Re: Diferencia al programar verilog en Quartus o en Xilinx

Mensaje por yombo » 03 Sep 2018, 21:25

A mí me pasó ese mismo problema en una implementación del cartucho 9 de Videopac, y lo solucioné de la misma forma.
ERROR:NgdBuild:455 - logical net 'yombo' has multiple driver(s):
ERROR:NgdBuild:924 - input pad net 'yombo' is driving non-buffer primitives:

Responder

Volver a “General”