Categorías
Diseño digital

Circuitos aritméticos

Máxima frecuencia de trabajo

La frecuencia máxima de trabajo de un diseño digital, viene marcado por los tiempos de flip-flop, el tiempo de propagación en la lógica combinacional y el tiempo de setup. Para registar un dato a la salida de un flip-flop, es necesario un tiempo para pasar el nivel de entrada D1 a la salida Q1, lo que se conoce como tiempo de propagación de flip-flop. Luego, esta señal pasará a través de una lógica combinacional que añadirá un retardo. Este retardo en la figura anterior es \(t_{pLCR}\). Finalmente, para que último flip-flop pueda registrar el nivel de entrada, es necesario que este dato se mantenga al menos un tiempo de setup \(t_{su}\). Por tanto, el periodo mínimo de el ciclo de reloj debe ser:

\[ T_{p~min} = t_{pFF} + t_{pLCR} + t_{su} \]

Y la frecuencia máxima, será la inversa del periodo mínimo:

\[f_{max} = \frac{1}{T_{p~min}} \]

Los tiempo de setup y de flip-flop vienen determinados por la tecnología con la que se ha fabricado la FPGA. Por lo tanto, estos dos parámetros quedan invariables en un diseño. Para poder aumentar la frecuencia de trabajo, es necesario disminuir el tiempo de retardo que se produce en la lógica combinacional. Para ello, es necesario añadir registros en medio de la lógica combinacional que hagan que el retardo máximo entre flip-flops se minimice. Esto se conoce como pipelining.

Sin embargo, al añadir registros, el número de ciclos que tardará en salir el primer dato a la salida del sistema aumentará. El número de ciclos que tarda el primer dato en salir se conoce como latencia.

Para obtener el número negativo de un número en codificación Ca2, hay que negar todos los bit y sumar 1.

Cast de signed y unsigned

Para realizar la conversión números signed y unsigned en Verilog, existe la macro $signed() y $unsigned()

La macro $signed() extiende el bit de signo, de manera que si el valor de la variable unsigned tenía el MSB a 1, al hacer la conversión mediante la macro se obtendrá un valor negativo, machacando el valor original que tenía en formato unsigned.

A U[3,0] = 111 = 7
$signed(A) = -1

Sin embargo, si el número unsigned tenía el MSB a 0, el valor correspondiente después de la conversión será el mismo.

Cast a signed. Si el valor del MSB de uA está a 1, el valor de sA se modificará

Cuando se quiere pasar un número en formato signed a unsigned utilizando la macro $unsigned(), se hace una copia bit a bit del valor signed. Si son necesarios más bits porque la variable donde se copiará el valor posee más bits, se rellenará con ceros.

Aumentando el rango pero mateniendo el mismo tipo

Cuando se quiere aumentar el rango de una variable manteniendo el mismo formato de los números, Verilog sintetiza de manera diferente en función del formato original. En un formato signed, se hace una copia del bit de signo en todos los bits añadidos. En el caso de un formato unsigned, simplemente añade ceros.

Extensión de rango en formato signed
Extensión de rango en formato unsigned

Reduciendo el rango del número

Cuando se reduce el rango del número, se puede proceder de dos maneras. Una es con la técnica wrap, que consiste en no hacer nada. Los bits que ya no caben en el nuevo formato reducido, permanecen desconectados.

La otra manera, es utilizando el overflow. Con overflow, se consigue si al reducir el rango de un número, este supera el rango máximo representable, el valor definitivo queda como el máximo que se puede representar. Este técnica necesita de bloques adicionales para detectar si el número a reducir es mayor que el nuevo rango reducido y asignarle el máximo valor representable.

Bloques para detectar el overflow

Si el formato es con signo, la saturación puede ser positiva o negativa, por tanto hay que controlar ambos casos.

assign As = (A > SATpos) ? SATpos : (A<SATneg) ? SATneg : A[7:0];

Cambiando el ancho de palabra

Reduciendo la precisión con truncado

Para reducir la precisión de un formato, es decir, pasar de A[8,7] a B[5,4], por ejemplo, cuyo rango es [0,1] para ambos pero la precisión en A es de 0.0078125 y en B es de 0.0625, hay que coger los bits que correspondan.


En Verilog esto equivale a:

wire [7:0] A;
wire [4:0] B;

assign B = A[7:3];

Reduciendo la precisión con redondeo

Si hacemos la misma operación pero utilizando el redondeo, hay que tener en cuenta el bit anterior al menos significativo de los que estamos cogiendo para la nueva variable. De esta manera, si está 1, se redondeará hacia arriba y si está a 0 se redondeará hacia abajo.

wire [7:0] A;
wire [4:0] B;

assign B = A[7:3] + A[2];

Aumentando la precisión (o disminuyendo el escalado)

Cuando se añaden bits extras extremo de los LSB se aumenta la precisión del formato. Sin embargo, hay que posicionar correctamente los bits para que tengan el peso adecuado. A nivel de implementación consiste en conector todos los bits a la parte alta de la nueva variable.

En Verilog hay dos maneras de hacerlo. Asignar todos los bits de A a la parte alta de B y añadir 0 por abajo:

wire [4:0] A;
wire [7:0] B;

assign B = {A, 3'b0};

O asignando A a B desplazado 3 bits, ya que al mover rellenará con ceros.

wire [4:0] A;
wire [7:0] B;

assign B = A << 3;

Desplazamiento por una constante

Cuando se desplaza una variable por una constante, existen dos operadores para realizar el desplazamiento: >> y >>> (y sus equivalentes para la otra dirección de desplazamiento).

>> corresponde a un desplazamiento lógico, en el que no se tiene en cuenta si el MSB de la variable corresponden al bit de signo. Por tanto, al desplazar hacia la derecha pondrá ceros en la parte alta de la variable.

>>> corresponde a un desplazamiento aritmético, en el que sí se tiene en cuenta que el MSB es el bit de signo, de manera que al desplazar hacia la derecha hará una copia del signo. Por tanto, cada vez que se esté utilizando una variable signed, será necesario utilizar el desplazamiento aritmético (<<</>>>) para mantener el valor del signo.

Hay que tener en cuenta que si la variable destino a la que estamos asignando el desplazamiento tiene el mismo tamaño que la variable origen, se van a perder los bits que desplacemos. Por tanto, si queremos mantener esos bits que se desplazan la variable destino debe ser n bits mayor, donde n es el número de bits desplazados.

Las FPGAs como Altera Cyclone IV llevan incorporados arrays de bloques lógicos (LAB). Estos LABs en su interior están formados por Logic Elements (LE) que a su vez incorporan una LUT, un seguidor de acarreo y un registro.

Estos elementos son los componentes básicos para realizar operaciones de suma y multiplicación de una FPGA.

Suma

Suma manteniendo precisión

Al sumar manteniendo la precisión, es suficiente con alinear correctamente los bits y que la variable de destino tenga bits suficientes para alojar el resultado.

Suma recortando precisión

Al recortar la precisión, no hay que sumar todos los bits de los operandos. Solo hay que seleccionar los que se vayan a incorporar a la variable destino.

Resta

La resta (A-B) equivale a realizar un suma de A y con la inversión mediante Ca2 de B.  Para implementarla no es necesario añadir un sumador más y multiplexar la salida en función del signo. Simplemente hay que negar B y sumarlo con A.

 

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.