Trataré de darle una idea de cómo están diseñados los circuitos digitales para resolver problemas de procesamiento digital utilizando los problemas que plantea: cómo las CPU implementan adiciones y multiplicaciones.
En primer lugar, eliminemos la pregunta directa: cómo un lenguaje de programación evalúa eficientemente las multiplicaciones y las sumas. La respuesta es simple, los compilan en multiplicar y agregan instrucciones. Por ejemplo, el siguiente código:
a = 1 + 1;
b = a * 20;
simplemente se compila a algo como:
ADD 1 1 a
MUL a 20 b
(tenga en cuenta que el ensamblaje anterior es para una CPU imaginaria que no existe, por simplicidad).
En este punto, se da cuenta de que la respuesta anterior simplemente cambia el problema y lo resuelve con magia de hardware. La pregunta de seguimiento es, obviamente, ¿cómo funciona esa magia de hardware?
Veamos primero el problema más simple: la suma.
Primero hacemos un problema familiar, agregando números regulares de base 10:
17
+28
El primer paso sería agregar 7 y 8. Pero esto da como resultado 15, que es más que un solo dígito. Entonces llevamos el 1:
(1)
17
+28
= 5
Ahora sumamos 1, 1 y 2 juntos:
17
+28
=45
Entonces de esto obtenemos las siguientes reglas:
cuando el resultado de la suma es más de un dígito, mantenemos el dígito menos significativo y llevamos el dígito más significativo hacia adelante
si tenemos un dígito transferido a nuestra columna, lo agregamos junto con los números que estamos agregando
Ahora es el momento de interpretar las reglas anteriores en la base 2: álgebra booleana.
Entonces, en álgebra booleana, sumar 0 y 1 juntos = 1. Sumar 0 y 0 = 0. Y sumar 1 y 1 = 10, que es más de un dígito, entonces llevamos el 1 hacia adelante.
De esto podemos construir una tabla de verdad:
a b | sum carry
-------------------
0 0 | 0 0
0 1 | 1 0
1 0 | 1 0
1 1 | 0 1
A partir de esto, podemos construir dos circuitos / ecuaciones booleanas: una para la salida de suma y otra para la salida de acarreo. La forma más ingenua es simplemente enumerar todas las entradas. Cualquier tabla de verdad, no importa cuán grande y complejo se pueda replantear de esta forma:
(AND inputs in first row) OR (AND of inputs in second row) OR ...
Esto es básicamente la suma de productos de forma. Solo miramos las salidas que dan como resultado un 1 e ignoramos los 0:
sum = (NOT a AND b) OR (a AND NOT b)
Reemplacemos AND AND y NOT con símbolos de lenguaje de programación para que sea más fácil de leer:
sum = (!a & b) | (a & !b)
Básicamente, hemos convertido la tabla de esta manera:
a b | sum equation
-------------------
0 0 | 0
0 1 | 1 (!a & b)
1 0 | 1 (a & !b)
1 1 | 0
Esto se puede implementar directamente como un circuito:
_____
a ------------| |
\ | AND |-. ____
\ ,-NOT--|_____| \ | |
\/ `--| OR |----- sum
/\ _____ ,--|____|
/ `-NOT--| | /
/ | AND |-`
b ------------|_____|
En este punto, los lectores observadores notarán que la lógica anterior se puede implementar como una sola puerta, una puerta XOR que convenientemente tiene el comportamiento requerido por nuestra tabla de verdad:
_____
a ------------| |
| XOR |---- sum
b ------------|_____|
Pero si su hardware no le proporciona una puerta XOR, los pasos anteriores son cómo definiría e implementaría en términos de puertas AND, OR y NOT.
La forma en que convertiría las puertas lógicas en hardware real depende del hardware que tenga. Se pueden implementar utilizando diversos mecanismos físicos siempre que el mecanismo proporcione algún tipo de comportamiento de conmutación. Las puertas lógicas se han implementado con todo, desde chorros de agua o bocanadas de aire (fluidos) hasta transistores (electrónicos) y canicas que caen. Es un gran tema en sí mismo, así que voy a pasarlo por alto y decir que es posible implementar puertas lógicas como dispositivos físicos.
Ahora hacemos lo mismo para la señal de transporte. Como solo hay una condición en la que la señal de transporte es verdadera, la ecuación es simplemente:
carry = a & b
Así que llevar es simple:
_____
a ------------| |
| AND |---- carry
b ------------|_____|
Combinándolos juntos obtenemos lo que se conoce como el medio sumador:
_____
a ------;-----| |
| | XOR |---- sum
b --;---|-----|_____|
| | _____
| '-----| |
| | AND |---- carry
'---------|_____|
Por cierto, las ecuaciones para el circuito anterior se ven así:
sum = a ^ b
carry = a & b
Al medio sumador le falta algo. Hemos implementado la primera regla, si el resultado es más de un dígito que el avance, pero no hemos implementado la segunda regla, si hay un acarreo, agréguelo junto con los números.
Entonces, para implementar un sumador completo, un circuito de suma que pueda agregar números que tengan más de un dígito, necesitamos definir una tabla de verdad:
a b c | sum carry
---------------------
0 0 0 | 0 0
0 0 1 | 1 0
0 1 0 | 1 0
0 1 1 | 0 1
1 0 0 | 1 0
1 0 1 | 0 1
1 1 0 | 0 1
1 1 1 | 1 1
La ecuación para la suma es ahora:
sum = (!a & !b & c) | (!a & b & !c) | (a & !b & !c) | (a & b & c)
Podemos pasar por el mismo proceso para factorizar y simplificar la ecuación e interpretarla como un circuito, etc., como hemos hecho anteriormente, pero creo que esta respuesta se está haciendo demasiado larga.
A estas alturas ya debería tener una idea de cómo está diseñada la lógica digital. Hay otros trucos que no he mencionado, como los mapas de Karnaugh (utilizados para simplificar las tablas de verdad) y los compiladores lógicos como el espresso (para que no tenga que factorizar ecuaciones booleanas a mano), pero lo básico es básicamente lo que he resaltado arriba:
Descomponga el problema hasta que pueda trabajar a nivel de un solo bit (dígito).
Defina las salidas que desea utilizando una tabla de verdad.
Convierta la tabla a una ecuación booleana y simplifique la ecuación.
Interpreta la ecuación como puertas lógicas.
Convierta su circuito lógico en circuitos de hardware real mediante la implementación de puertas lógicas.
Así es como realmente se resuelven los problemas fundamentales (o más bien, de bajo nivel): muchas, muchas tablas de verdad. El verdadero trabajo creativo consiste en desglosar una tarea compleja como la decodificación de MP3 a nivel de bits para que pueda trabajar en ella con tablas de verdad.
Lo siento, no tengo tiempo para explicar cómo implementar la multiplicación. Puede intentar descifrarlo descubriendo las reglas de cuánto tiempo funciona la multiplicación, luego interpretándola en binario y luego intente dividirla en tablas de verdad. O puede leer Wikipedia: http://en.wikipedia.org/wiki/Binary_multiplier