Cercherò di darti un'idea di come i circuiti digitali sono progettati per risolvere i problemi di elaborazione digitale utilizzando i problemi che poni: come le CPU implementano aggiunte e moltiplicazioni.
Innanzi tutto, lasciamo che la domanda diretta si allontani: in che modo un linguaggio di programmazione valuta in modo efficiente le moltiplicazioni e le aggiunte. La risposta è semplice, li compilano in moltiplicano e aggiungono istruzioni. Ad esempio, il seguente codice:
a = 1 + 1;
b = a * 20;
è semplicemente compilato per qualcosa come:
ADD 1 1 a
MUL a 20 b
(nota che il suddetto assembly è per una CPU immaginaria che non esiste, per semplicità).
A questo punto ti rendi conto che la risposta di cui sopra sposta semplicemente il problema e risolverlo con la magia dell'hardware. La domanda di follow-up è ovviamente come funziona quella magia hardware?
Vediamo prima il problema più semplice: aggiunta.
Per prima cosa facciamo un problema familiare, aggiungendo regolarmente numeri di base 10:
17
+28
Il primo passo sarebbe quello di aggiungere 7 e 8. Ma questo risulta in 15 che è più di una singola cifra. Quindi portiamo il 1:
(1)
17
+28
= 5
Ora aggiungiamo 1, 1 e 2 insieme:
17
+28
=45
Quindi da questo otteniamo le seguenti regole:
quando il risultato dell'addizione è più di una cifra, manteniamo la cifra meno significativa e portiamo avanti la cifra più significativa
se abbiamo una cifra portata avanti nella nostra colonna, la aggiungiamo insieme ai numeri che stiamo aggiungendo
Ora è il momento di interpretare le regole sopra nella base 2 - algebra booleana.
Quindi, nell'algebra booleana, aggiungendo 0 e 1 insieme = 1. Aggiungendo 0 e 0 = 0. E aggiungendo 1 e 1 = 10 che è più di una cifra, quindi portiamo avanti 1.
Da questo possiamo costruire una tabella di verità:
a b | sum carry
-------------------
0 0 | 0 0
0 1 | 1 0
1 0 | 1 0
1 1 | 0 1
Da questo, possiamo costruire due circuiti / equazioni booleane - uno per l'output della somma e uno per l'output di carry. Il modo più ingenuo è semplicemente elencare tutti gli input. Qualsiasi tabella di verità, non importa quanto grande e complessa possa essere riformulata in questa forma:
(AND inputs in first row) OR (AND of inputs in second row) OR ...
Questa è sostanzialmente la somma dei prodotti. Osserviamo solo gli output che generano un 1 e ignoriamo gli 0:
sum = (NOT a AND b) OR (a AND NOT b)
Sostituiamo AND OR e NOT con i simboli del linguaggio di programmazione per facilitare la lettura:
sum = (!a & b) | (a & !b)
Fondamentalmente, abbiamo convertito la tabella in questo modo:
a b | sum equation
-------------------
0 0 | 0
0 1 | 1 (!a & b)
1 0 | 1 (a & !b)
1 1 | 0
Questo può essere implementato direttamente come un circuito:
_____
a ------------| |
\ | AND |-. ____
\ ,-NOT--|_____| \ | |
\/ `--| OR |----- sum
/\ _____ ,--|____|
/ `-NOT--| | /
/ | AND |-`
b ------------|_____|
I lettori osservanti noteranno a questo punto che la logica di cui sopra può effettivamente essere implementata come un singolo gate - un gate XOR che ha convenientemente il comportamento richiesto dalla nostra tabella di verità:
_____
a ------------| |
| XOR |---- sum
b ------------|_____|
Ma se il tuo hardware non ti fornisce un gate XOR, i passaggi sopra indicati riguardano come definirlo e implementarlo in termini di porte AND, OR e NOT.
Il modo in cui dovresti convertire i gate logici in hardware reale dipende dall'hardware che hai. Possono essere implementati utilizzando vari meccanismi fisici purché il meccanismo fornisca una sorta di comportamento di commutazione. Le porte logiche sono state implementate con qualsiasi cosa, dai getti d'acqua o sbuffi d'aria (fluidica) ai transistor (elettronica) ai marmi che cadono. È un grande argomento a sé stante, quindi ho intenzione di sorvolarlo e dire che è possibile implementare le porte logiche come dispositivi fisici.
Ora facciamo lo stesso per il segnale carry. Poiché esiste una sola condizione in cui il segnale carry è vero, l'equazione è semplicemente:
carry = a & b
Quindi trasportare è semplice:
_____
a ------------| |
| AND |---- carry
b ------------|_____|
Combinandoli insieme otteniamo quello che è noto come il mezzo sommatore:
_____
a ------;-----| |
| | XOR |---- sum
b --;---|-----|_____|
| | _____
| '-----| |
| | AND |---- carry
'---------|_____|
Le equazioni per il circuito sopra riportato sembrano così:
sum = a ^ b
carry = a & b
Il mezzo sommatore manca qualcosa. Abbiamo implementato la prima regola - se il risultato è più di una cifra rispetto al riporto, ma non abbiamo implementato la seconda regola - se c'è un riporto aggiungilo insieme ai numeri.
Quindi per implementare un sommatore completo, un circuito di aggiunta che può aggiungere numeri che sono più di una cifra, dobbiamo definire una tabella di verità:
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
L'equazione per la somma è ora:
sum = (!a & !b & c) | (!a & b & !c) | (a & !b & !c) | (a & b & c)
Possiamo passare attraverso lo stesso processo per scomporre e semplificare l'equazione e interpretarla come un circuito ecc. Come abbiamo fatto sopra, ma penso che questa risposta stia diventando eccessivamente lunga.
Ormai dovresti avere un'idea di come è progettata la logica digitale. Ci sono altri trucchi che non ho menzionato come le mappe di Karnaugh (utilizzate per semplificare le tabelle di verità) e i compilatori logici come l'espresso (in modo da non dover considerare le equazioni booleane a mano) ma la base è fondamentalmente ciò che ho descritto sopra:
Decomponi il problema fino a quando non puoi lavorare a livello di singolo bit (cifra).
Definire gli output desiderati utilizzando una tabella di verità.
Converti la tabella in un'equazione booleana e semplifica l'equazione.
Interpreta l'equazione come porte logiche.
Converti il tuo circuito logico in circuiti hardware reali implementando porte logiche.
Ecco come i problemi fondamentali (o meglio, di basso livello) sono davvero risolti: un sacco di tabelle di verità. Il vero lavoro creativo è la scomposizione di un'attività complessa come la decodifica MP3 a livello di bit in modo da poter lavorare su di essa con tabelle di verità.
Mi dispiace non ho il tempo di spiegare come implementare la moltiplicazione. Puoi provare a prenderlo in giro capendo le regole su quanto funziona la moltiplicazione, quindi interpretandolo in binario e poi provando a scomporlo in tabelle di verità. Oppure puoi leggere Wikipedia: http://en.wikipedia.org/wiki/Binary_multiplier