La CPU (acronimo di Central Processing Unit, detta comunemente processore) è l'implementazione fisica di uno dei due componenti della macchina di Turing (l'altro è la memoria).
Compito della CPU è quello di leggere le istruzioni e i dati dalla memoria ed eseguire le istruzioni; il risultato della esecuzione di una istruzione dipende dal dato su cui opera e dallo stato interno della CPU stessa, che tiene traccia delle passate operazioni.
In base all'organizzazione della memoria si possono distingure due famiglie di CPU:
Qualunque CPU contiene:
A proposto di registri le CPU si distinguono in:
Una CPU è un circuito digitale sincrono: vale a dire che il suo stato cambia ogni volta che riceve un impulso da un segnale di sincronismo detto CLOCK: quindi il tempo di esecuzione di una istruzione si misura in cicli di clock, cioè in quanti impulsi di clock sono necessari perché la CPU la completi. In effetti, una parte importante e delicata di ogni CPU è il sistema di distribuzione che porta il segnale di clock alle varie unità e sottounità di cui è composta, per fare in modo che siano sempre in sincronia: tale sistema si dirama in una struttura ad albero con divisori e ripetitori che giunge ovunque nella CPU. Nei processori più moderni (Pentium, Athlon, PowerPC) questa "catena di ingranaggi" elettronica arriva ad impiegare circa il 30% di tutti i transistor disponibili. La velocità di questa distribuzione determina in maniera diretta la massima frequenza operativa di una CPU: nessuna CPU può essere più veloce del suo critical path, cioè del tempo che impiega il clock per percorrere il tratto più lungo in tutto l'albero di distribuzione del clock. Per esempio, se il segnale di clock di una data CPU impiega un nanosecondo per attraversare tutto il chip ed arrivare fino all'ultima sottounità, questa CPU potrà operare a non più di 1 GHz, perché altrimenti le sue componenti interne perderebbero la sincronizzazione, con risultati imprevedibili (per motivi di tolleranze e margini di sicurezza, il limite pratico sarà anzi ben minore di 1GHz).
Per una persona, stendere programmi scrivendo direttamente gli opcode è estremamente noioso e prono all'errore. Per questo motivo si utilizza l'assembly. L'assembly associa un simbolo mnemonico ad ogni istruzione della CPU e introduce una sintassi che permette di esprimere i vari metodi di indirizzamento.
Una caratteristica importante dell'insieme (set) delle istruzioni di una CPU è la sua ortogonalità: vale a dire, il fatto che ogni istruzione che usi i registri possa usarli tutti indifferentemente (tranne quelli "speciali" come l'IP) e che nessun registro sia in qualche modo privilegiato rispetto agli altri perché su di esso si possono compiere operazioni particolari: è stato dimostrato che un set di istruzioni ortogonali, a parità di tempo di esecuzione delle istruzioni e di numero dei registri, è più efficiente di uno non ortogonale.
Una generica CPU deve gestire una serie di operazioni sincronizzandole con il resto del sistema: perciò è dotata, oltre a quanto sopra elencato, anche di uno o più bus interni che si occupano di collegare registri, ALU, unità di controllo e memoria: inoltre, all'unità di controllo interna della CPU fanno capo una serie di segnali elettrici esterni che si occupano di tenere la CPU al corrente dello stato del resto del sistema e di agire su di esso. Il tipo e il numero di segnali esterni gestiti possono variare ma alcuni, come il RESET, le linee di IRQ e il CLOCK sono sempre presenti.
Il normale ciclo di operazioni di una CPU è il seguente: l'unità di controllo legge la locazione di memoria indicata dal registro IP, incrementa il registro IP di uno e la decodifica; se la decodifica indica che l'istruzione è più lunga di una locazione di memoria, legge anche il resto dell'istruzione e incrementa l'IP del numero di locazioni lette; esegue l'istruzione; se necessario scrive in memoria (o in altri registri) il risultato. Dopodiché torna a leggere l'indirizzo puntato da IP per caricare ed eseguire un'altra istruzione, all'infinito.
Questo ciclo elementare può essere migliorato in vari modi: per esempio, la decodifica di una istruzione può essere fatta contemporaneamente all'esecuzione della precedente e alla lettura dalla memoria della prossima (instruction prefetch) e lo stesso può essere fatto con i dati che si prevede saranno necessari alle istruzioni (data prefetch). La stessa esecuzione delle istruzioni può essere suddivisa in passi più semplici, da eseguire in stadi successivi, organizzando la unità di controllo e la ALU in stadi consecutivi, come delle catene di montaggio (pipeline): in questo modo più istruzioni possono essere eseguite "quasi contemporaneamente", ciascuna occupando ad un certo istante uno stadio diverso della pipeline.
Il problema di questo approccio sono le istruzioni di salto condizionato, cioè istruzioni che impostano il valore stesso del registro IP, ma solo se al momento della loro esecuzione sono verificate certe condizioni (particolari valori di registri). La CPU non può sapere a priori se dovrà eseguire o no il salto prima di aver eseguito quelle precedenti, così deve decidere se impostare la pipeline tenendo conto del salto o no: e in caso di previsione errata la pipeline va svuotata completamente e le istruzioni in corso di decodifica rilette da capo, perdendo molto tempo: e si perde tanto più tempo quanti più stadi ha la pipeline. Per evitare questo i processori moderni hanno unità interne (Branch prediction unit) il cui scopo è tentare di prevedere se, data una istruzione di salto condizionato e quelle eseguite in precedenza, il salto dovrà essere eseguito o no.
Il set di istruzioni associato a CPU di tipo CISC è molto esteso e composto in genere di alcune centinaia di codici operativi diversi che svolgono funzioni anche molto complesse, fra cui sono caratteristici i trasferimenti memoria-memoria, assenti nei RISC; le istruzioni hanno lunghezza variabile e possono presentarsi in formati diversi, e sono necessari due o più (a volte molti di più) cicli di clock per completare una istruzione; è possibile specificare la posizione dei dati necessari alle istruzioni usando molti metodi di indirizzamento diversi. Il ridotto numero di registri interni obbliga questi processori a scrivere in memoria ogni volta che si verifica una chiamata di funzione, che si verifica un context switch o che viene salvato un registro nello stack.
Programmare in Assembler una CPU CISC è un compito (relativamente) facile, perché le istruzioni presenti sono più vicine a quelle dei linguaggi ad alto livello.
Nel caso di context-switch o di chiamata a subroutine o comunque di uso dello stack i RISC invece di accedere alla memoria di sistema usano un meccanismo chiamato register renaming, che consiste nel rinominare i registri in modo da usare per la nuova esecuzione una diversa zona del file di registri, senza dover accedere alla memoria ogni volta.
La complessità nei RISC si sposta dall'hardware al software: un compilatore che genera codice per CPU RISC deve affrontare un duro lavoro per generare codice compatto ed efficiente, che in ogni caso sarà più grande ed occuperà più memoria dell'equivalente per CISC.
Processador | Procesor | Central Processing Unit | Hauptprozessor | Central processing unit | CPU | CPU | Suoritin | Processeur | CPU | מעבד | Procesor | CPU | CPU | 중앙처리장치 | Mîkroprosesor | Processor centralis | Unit Pemproses Pusat | Processor | CPU | CPU | Procesor | Unidade Central de Processamento | Procesor | CPU | หน่วยประมวลผลกลาง | 中央处理器