jepalza escribió:Para mi, todo lo que significa escribir un programa, es programar. Para gustos los colores.
Es que ahí está el quid de la cuestión: no estás escribiendo un programa, estás escribiendo una descripción. Estás usando HDL para hacer tu descripción. HDL significa "Lenguaje de Descripción de Hardware". De igual forma que si escribes código HTML no se te ocurre decir que estás "programando" en HTML, sino que estás escribiendo la descripción visual de una página web. O si escribes código en Latex, no "programas" en Latex, sino que describes un documento con sus pies de página, sus fotos, etc.
El que se use un lenguaje que "parece" o "recuerda" a lo que uno conoce de programación en C (Verilog) o Ada (VHDL) no significa que al usar esos lenguajes estés programando. Sencillamente se usa la riqueza sintáctica de esos lenguajes de referencia para permitir al ingeniero describir su circuito.
Conceptualmente, esto:
Lo entiende cualquiera que haya programado en C (o en PHP, o en JAVA, o....) aunque lo del "always" le pille un poco con el paso cambiado (conceptualmente, el always de ahí significa "haz esto cada vez que cambie alguna de las señales que intervienen en el bloque"). Dado que el comportamiento de un multiplexor es el mismo que este trozo de código, era lógico suponer que los creadores del HDL Verilog usaran esta misma construcción para decirle al sintetizador "infiere un multiplexor cuando veas esto". Esto está muy bien porque permite que gente como tú, con experiencia en C, pille "a la primera" la esencia del lenguaje. Para pillar el resto de sutilezas, como ya sabes, más vale que sepas de electrónica digital

Pero si te olvidas de que esto es una descripción en lugar de un programa, antes o después cometerás errores. Es decir, si echas a un lado tu formación en electrónica y piensas en un código como el anterior como en un programa, te puedes llevar alguna que otra sorpresa. Por ejemplo... ¿qué ocurre si completo la secuencia de código de arriba con la definición de lo que es s,a,y,b?
Código: Seleccionar todo
reg [127:0] a;
reg [127:0] b;
reg [127:0] y;
wire s;
always @(*) begin
if (s)
y = a;
else
y = b;
end
¡Ay va! Resulta que esto no infiere un simple multiplexor... sino que infiere 128 multiplexores de dos entradas cada uno. Visualízalo: es como un montón de chips 74LS157 (32 para ser exactos) trabajando en paralelo, con la señal "s" aplicada a esos 128 multiplexores.
¿Y? Pues que el programador obvía un detalle que no pasará por alto al ingeniero electrónico: resulta que la señal "s" está siendo aplicada a 128 cargas (la entrada de selección de cada uno de los 128 multiplexores). Cuando este circuito se sintetice posiblemente no funcione bien, porque estaremos pidiendo que una señal esté conectada a la entrada de 128 circuitos. La señal podría no ser suficientemente fuerte, o bien la capacidad parásita de esas 128 entradas podría hacer que la señal se retrasara más de la cuenta. Y ya sabemos lo importante que es que una señal no sea aplicada a más cargas de la cuenta (fue el error que me tuvo en jaque con mi Jupiter ACE, por no usar un chip 74HCT y poner en su lugar un 74LS... con ese chip, la señal que alimentaba a una parte del circuito no tenía suficiente fuerza, y veía "extraños" en la pantalla)
¿La solución? Pues algo en lo que no caería el programador, y que de hecho no tendría ningún sentido para él, pero sí para alguien que ve el código no como un programa sino como una descripción de un cableado: replicar la señal "s" varias veces, y replicar el multiplexor tantas veces como copias tengas de "s", aplicando cada copia de "s" a uno de esos multiplexores. Cada multiplexor se encargará de multiplexar una parte del vector a,b,y
Código: Seleccionar todo
reg [127:0] a;
reg [127:0] b;
reg [127:0] y;
wire s;
/* se le dice al sintetizador que no intente simplicar esto, sino que asigne un BUF para cada assign
Esto se hace con comentarios parecidos a los pragma de C, pero no recuerdo cuál es el que se usa
en Verilog para este caso concreto */
wire s1=s;
wire s2=s;
wire s3=s;
wire s4=s;
/* Cada "always" es un bloque multiplexor de 32 canales, o mejor dicho, 32 multiplexores.
No se "ejecutan" de arriba a abajo. Todos funcionan a la vez */
always @(*) begin
if (s1)
y[31:0] = a[31:0];
else
y[31:0] = b[31:0];
end
always @(*) begin
if (s2)
y[63:32] = a[63:32];
else
y[63:32] = b[63:32];
end
always @(*) begin
if (s3)
y[95:64] = a[95:64];
else
y[95:64] = b[95:64];
end
always @(*) begin
if (s4)
y[127:96] = a[127:96];
else
y[127:96] = b[127:96];
end
Ahora la señal de selección maestra "s" se aplica a 4 cargas: los cuatro bufferes que generan las señales s1 a s4. A su vez, cada señal s1,...,s4 se aplica a 32 cargas. Es decir, hemos pasado de tener una señal aplicada a 128 cargas a tener señales aplicadas a 32 cargas (en el peor de los casos). El circuito resultante tiene el mismo comportamiento que el que debería tener el original (si acaso, con algún que otro nanosegundo de retraso en la conmutación del multiplexor por culpa de los buffers).
El nuevo código modificado le parecerá redundante al programador (y se sentirá tentado de simplificarlo para dejarlo como estaba al principio), pero tendrá todo el sentido del mundo al que lo lee como si fuera un esquemático.