Un processore esegue il cosiddetto ciclo fetch-decode-execute. Le istruzioni del codice macchina sono abbastanza di basso livello (cioè non fanno molto di più in una singola istruzione).Ad esempio, l'aggiunta di due numeri avrebbe una sequenza di istruzioni con semantica come:
- Carica un puntatore all'indirizzo dell'operando 1 nel registro 1
- Caricare il valore memorizzato all'indirizzo memorizzato nel registro 1 nel registro 2
- Carica un puntatore all'indirizzo dell'operando 2 nel registro 1
- Caricare il valore memorizzato all'indirizzo nel registro 1 nel registro 3
- Aggiungere il contenuto del registro 2 e registrare 3 e memorizzarlo nel registro 4
- Caricare un puntatore alla destinazione nel registro 1
- Conservare il contenuto del registro 4 nell'indirizzo specificate nel registro 1
All'interno del processore è un insieme particolare di memoria veloce noto come 'di registri' , che contiene la memoria utilizzata dal processore per memorizzare i dati su cui sta lavorando al momento. Il file di registro ha diversi registri, che sono identificati in modo univoco. Le istruzioni in genere funzionano sui registri, in particolare sulle architetture RISC; mentre questo non è sempre il caso è un'astrazione abbastanza buona per il momento.
In genere un processore deve caricare o archiviare dati in un registro per fare qualsiasi cosa con esso. Operazioni come il lavoro aritmetico sui registri, prendendo gli operandi da due registri e inserendo il risultato in un terzo (a beneficio della galleria di arachidi, I hanno un valore di utilizzato un 6502: non si può confondere il problema ;-). Il processore ha istruzioni speciali per il caricamento o la memorizzazione dei dati dai registri nella memoria principale della macchina.
Un processore ha un registro speciale chiamato "contatore di programma" che memorizza l'indirizzo della prossima operazione da eseguire. Pertanto, la sequenza per l'esecuzione di un'istruzione equivale approssimativamente a:
- Scarica l'istruzione memorizzata nell'indirizzo corrente nel contatore del programma.
- Decodifica l'istruzione, separando l'operazione effettiva, ciò che registra utilizza, la "modalità di indirizzamento" (come funziona dove ottenere o memorizzare i dati) e alcuni altri bit e bob.
- Eseguire l'istruzione.
L'esecuzione dell'istruzione cambierà i valori in vari registri. Ad esempio, un'istruzione 'carica' copierà un valore in un registro. Un aritmetico o logico (And, Or, Xor) prenderà due valori e calcolerà un terzo. Un'istruzione di salto o salto cambierà l'indirizzo sul contatore del programma in modo che il processore inizi a recuperare le istruzioni da una posizione diversa.
Il processore può disporre di registri speciali. Un esempio di tale è il contatore del programma sopra descritto. Un altro tipico è un registro delle condizioni. Questo avrà diversi bit con significati speciali. Ad esempio può avere un flag che viene impostato se il risultato dell'ultima operazione aritmetica è zero. Questo è utile per le operazioni condizionali. È possibile confrontare due numeri. Se sono uguali, viene impostato il flag 'zero'. Il processore può avere un'istruzione condizionale che viene eseguita solo se questo flag è impostato.
In questo caso, è possibile decrementare un contatore in un registro e se era zero, viene impostato un flag di condizione. Un condizionale (ramo su zero) può essere utilizzato per un ciclo in cui si decrementa un contatore e si esce dal ciclo se il risultato dell'istruzione di decremento è zero. Su alcuni processori (ad es.la famiglia ARM) tutte le istruzioni sono condizionali, con una speciale condizione "fai sempre" per istruzioni non condizionali.
Alcuni esempi di istruzioni tipici processore sono:
- incrementare o decrementare un registro
- carico o memorizzare il contenuto di un registro nella memoria. È inoltre possibile avere l'indirizzo per caricare o memorizzare l'offset in base al contenuto di un altro registro. Ciò consente di eseguire facilmente il loop su una matrice di dati incrementando l'altro registro.
- Aggiungere, sottrarre, moltiplicare, operazioni logiche per calcolare i valori. Questi prendono gli operandi da due registri e inseriscono il risultato in un terzo.
- Passare a un'altra posizione: sposta il contenuto della posizione nel contatore del programma e inizia a recuperare le istruzioni dalla nuova posizione.
- Spingere o inserire i valori su una pila.
This stackoverflow post presenta un esempio di un piccolo frammento di codice C compilato e l'uscita linguaggio assembly da quel frammento. Dovrebbe darti un esempio del tipo di relazione tra un linguaggio di alto livello e l'output del codice macchina che esso compila.
Il modo migliore per imparare questo è ottenere un assemblatore e provarlo. Questo era molto più semplice su computer più vecchi e semplici come i micros a 8 bit degli anni '80. La cosa più vicina a questo tipo di architettura disponibile in questi giorni sono i sistemi incorporati. È possibile ottenere una scheda di sviluppo per un processore embedded come un PIC Microchip abbastanza a buon mercato. Dato che questo tipo di architettura ha meno bagagli di un moderno sistema operativo, ci sono meno i-tracing e t-crossing per usare le chiamate di sistema. Ciò renderà più semplice il bootstrap di un programma in linguaggio assembly su questo tipo di architettura; anche l'architettura più semplice è più facile da capire.
Un'altra opzione è ottenere un emulatore come SPIM. Questo emulerà una CPU e ti consentirà di assemblare ed eseguire programmi su di essa. Il vantaggio di un simile emulatore è che avranno anche funzionalità per singoli programmi stepping (molto simili a un debugger) e mostreranno il contenuto del file di registro. Questo può essere utile per ottenere informazioni su cosa sta realmente accadendo.
Fidati di me, un corso di CS probabilmente non sarebbe d'aiuto in queste cose. :( –
La maggior parte dei gradi CS ha un documento di architettura che copre le basi di questa roba – ConcernedOfTunbridgeWells
http://en.wikipedia.org/wiki/Integrated_circuit – vartec