El Doblemente, convierte el binario en BCD mediante desplazamientos repetidos. Cada repetición reduce a la mitad el número binario restante y duplica el número BCD, tras el desplazamiento del valor binario completo se obtiene el resultado. Después de cada desplazamiento se aplica una corrección a cada columna BCD de 4 bits (o a las que tienen más de 3 bits desplazados en ese punto). Esta corrección busca los dígitos que "desbordarán el BCD" decimal 9 -> 10 en el siguiente turno y parchea el resultado con añadiendo tres .
¿Por qué tres? Los dígitos BCD en el rango de cero a cuatro (0,1,2,4) se duplicarán naturalmente a 0,2,4,8 después del desplazamiento. Examinar el 5 b 0101
que se desplazará a b 1010
(0xA), que no es un dígito BCD. Por lo tanto, el 5 se corrige a (3+5), es decir b 1000
(0x8) que durante el desplazamiento se duplica a 16 decimal (0x10), representando un acarreo de 1 al siguiente dígito y el esperado cero.
Las implementaciones repiten este proceso, bien de forma sincrónica en el tiempo utilizando un registro de desplazamiento y 'n' ciclos para una entrada de n bits, o bien en el espacio colocando los circuitos lógicos para la corrección alimentándose unos a otros y realizando el desplazamiento con cableado. Hay un camino de acarreo a través de cada dígito, y la lógica de acarreo no se adapta a la lógica de cadena de acarreo de la FPGA (binaria), por lo que la implementación en el espacio suele dar resultados de sincronización inaceptables para entradas grandes. Una compensación típica de ingeniería.
Para una conversión paralela (asíncrona)
Para valores estrechos como los suyos Sitio del Dr. John Loomis tiene una guía de la estructura lógica necesaria para implementar en hardware. La lógica reprogramable moderna puede hacer 8 bits de ancho hasta quizás 100mhz después de una síntesis agresiva. El módulo add3
toma una entrada de 4 bits y la emite textualmente, o si son más de cuatro, añade tres:
module add3(in,out);
input [3:0] in;
output [3:0] out;
reg [3:0] out;
always @ (in)
case (in)
4'b0000: out <= 4'b0000; // 0 -> 0
4'b0001: out <= 4'b0001;
4'b0010: out <= 4'b0010;
4'b0011: out <= 4'b0011;
4'b0100: out <= 4'b0100; // 4 -> 4
4'b0101: out <= 4'b1000; // 5 -> 8
4'b0110: out <= 4'b1001;
4'b0111: out <= 4'b1010;
4'b1000: out <= 4'b1011;
4'b1001: out <= 4'b1100; // 9 -> 12
default: out <= 4'b0000;
endcase
endmodule
Combinando estos módulos se obtiene el resultado.
Para una variante secuencial (multiciclo, canalizada)
Para las señales anchas, una técnica en serie descrita en Xlinx App Note "XAPP 029" corre 1 bit por ciclo, probablemente a más de 300mMhz.
Si alguien conoce una buena técnica híbrida me interesaría conocerla. He modelado ambos en Verilog con bancos de pruebas en mi verilog-utils colección.