In che modo l'ALU in un microprocessore distingue tra un numero con segno, -7 indicato con 1111 e un numero senza segno 15, indicato anche con 1111?
In che modo l'ALU in un microprocessore distingue tra un numero con segno, -7 indicato con 1111 e un numero senza segno 15, indicato anche con 1111?
Risposte:
La risposta breve e semplice è: non lo è. Nessuna ISA CPU tradizionale moderna funziona come credi.
Per la CPU, è solo un po 'di modello. Spetta a te, il programmatore, tenere traccia di ciò che significa quel modello di bit.
In generale, gli ISA non distinguono tra diversi tipi di dati, quando si tratta di archiviazione. (Ignorando i registri per scopi speciali come i registri fluttuanti in una FPU.) È solo un modello insignificante di bit per la CPU. Tuttavia, ISA fare hanno diversi tipi di istruzioni che possono interpretare lo schema di bit in modi diversi. Ad esempio, le istruzioni aritmetiche come MUL
, DIV
, ADD
, SUB
interpretano la sequenza di bit come una sorta di numero, mentre istruzioni logiche quali AND
, OR
, XOR
interpretarlo come un array di booleani. Quindi, spetta al programmatore (o all'autore dell'interprete o del compilatore se si utilizza un linguaggio di livello superiore) scegliere le istruzioni corrette.
Ad esempio, potrebbero esserci istruzioni separate per numeri firmati e non firmati. Alcuni ISA hanno anche istruzioni per l'aritmetica con decimali con codice binario.
Tuttavia, nota che ho scritto "ISA mainstream moderno" sopra. Esistono infatti ISA non tradizionali o storici che funzionano in modo diverso. Ad esempio, sia l'ISA CISC originale a 48 bit dell'IBM AS / 400 che l'attuale ISA RISC a 64 bit basato sul POWER del sistema ora chiamato IBM i, distinguono tra puntatori e altri valori. I puntatori sono sempre taggati e includono informazioni sul tipo e gestione dei diritti. La CPU sa se un valore è o meno un puntatore e solo il kernel i / OS privilegiato può manipolare liberamente i puntatori. Le applicazioni utente possono solo manipolare i puntatori che possiedono per puntare alla memoria di loro proprietà usando un piccolo numero di istruzioni sicure.
C'erano anche alcuni progetti storici ISA che includevano almeno una forma limitata di consapevolezza del tipo.
char
, che è un tipo senza segno a 16 bit. Naturalmente, non ci sono ancora istruzioni aritmetiche senza segno nel bytecode Java, poiché qualsiasi char
valore viene automaticamente promosso a int
(con segno a 32 bit) per l'aritmetica.
Versione breve: non lo sa. Non c'è modo di dirlo.
Se 1111
rappresenta -7, allora hai una rappresentazione di magnitudine segno , dove il primo bit è il segno e il resto dei bit è la magnitudine. In questo caso, l'aritmetica è alquanto complicata, poiché un'aggiunta senza segno e un'aggiunta con segno usano una logica diversa. Quindi probabilmente avresti un SADD
e un UADD
codice operativo, e se scegli quello sbagliato otterrai risultati insensati.
Più spesso, tuttavia, 1111
rappresenta -1, in quella che viene chiamata rappresentazione del complemento a due . In questo caso, l'ALU semplicemente non si preoccupa se i numeri sono firmati o non firmati! Ad esempio, prendiamo l'operazione di 1110 + 0001
. In aritmetica firmata, questo significa "-2 + 1" e il risultato dovrebbe essere -1 ( 1111
). In aritmetica senza segno, questo significa "14 + 1" e il risultato dovrebbe essere 15 ( 1111
). Quindi l'ALU non sa se si desidera un risultato con o senza segno e non gliene importa. Fa semplicemente l'aggiunta come se non fosse firmata, e se vuoi trattarla come un intero con segno in seguito, dipende da te.
EDIT: Come Ruslan e Daniel Schepler sottolineano giustamente nei commenti, alcuni operandi hanno ancora bisogno di versioni separate con segno e senza segno, anche su una macchina a due complementi. Addizione, sottrazione, moltiplicazione, uguaglianza e così via funzionano bene senza sapere se i numeri sono firmati o meno. Ma la divisione e ogni confronto maggiore o minore devono avere versioni separate.
MODIFICA MODIFICA: Ci sono anche altre rappresentazioni, come il complemento a una persona , ma queste non sono praticamente più utilizzate, quindi non dovresti preoccuparti di loro.
<
<=
>=
>
sono diversi per gli operandi con segno e non con segno mentre ==
e !=
sono indipendenti dalla firma.
Uno dei grandi vantaggi della matematica a due complementi, che usano tutte le architetture moderne, è che le istruzioni di addizione e sottrazione sono esattamente le stesse per operandi con o senza segno.
Molte CPU non hanno nemmeno istruzioni per la moltiplicazione, la divisione o il modulo. In tal caso, devono avere forme separate e non firmate dell'istruzione e il compilatore (o il programmatore del linguaggio assembly) sceglie quello appropriato.
Le CPU generalmente hanno anche istruzioni diverse per confronti con o senza segno. Ad esempio, x86 potrebbe seguire una CMP
con JL
(Vai se inferiore) se il confronto deve essere firmato, oJB
(Vai se al di sotto) se il confronto dovrebbe essere firmato. Ancora una volta, il compilatore o il programmatore sceglierebbe l'istruzione corretta per il tipo di dati.
Alcune altre istruzioni vengono spesso in varianti firmate e non firmate, come spostamento a destra o caricamento di un valore in un registro più ampio, con o senza estensione del segno.
smulh
e umulh
che restituiscono solo i bit superiori della moltiplicazione e le istruzioni con e senza segno che restituisce il risultato in un registro due volte più largo degli operandi di origine.
Non Il processore si affida al set di istruzioni per dirgli quale tipo di dati sta guardando e dove inviarlo. Non c'è nulla circa 1 e 0 nell'operando stesso che può intrinsecamente segnalare all'ALU se i dati sono un carattere, float, int, firmato int, ecc. Se quell'1111 sta andando su un circuito elettrico che si aspetta un complemento 2s, sta andando da interpretare come un complemento 2s.
char
a livello hardware. Forse una volta, ai tempi delle teleprinter meccaniche. Ma oggi, a char
è solo un numero per quanto riguarda l'hardware. Il motivo per cui numeri diversi corrispondono a forme diverse di lettere sullo schermo è che quei numeri vengono utilizzati per selezionare bitmap diverse o diverse routine di disegno da una grande tabella (cioè da un "carattere").
Vorrei aggiungere un'aggiunta alle risposte già fatte:
Nella maggior parte delle altre risposte si nota che nell'aritmetica a due complementi il risultato è lo stesso per i numeri con e senza segno:
-2 + 1 = -1 1110 + 0001 = 1111
14 + 1 = 15 1110 + 0001 = 1111
Tuttavia , ci sono eccezioni:
Division:
-2 / 2 = -1 1110 / 0010 = 1111
14 / 2 = 7 1110 / 0010 = 0111
Comparison:
-2 < 2 = TRUE 1110 < 0010 = TRUE
14 < 2 = FALSE 1110 < 0010 = FALSE
"Typical" (*) multiplication:
-2 * 2 = -4 1110 * 0010 = 11111100
14 * 2 = 28 1110 * 0010 = 00011100
(*) Su molte CPU il risultato di una moltiplicazione di due numeri n-bit è largo (2 * n).
Per tali operazioni le CPU hanno istruzioni diverse per l'aritmetica firmata e non firmata.
Ciò significa che il programmatore (o il compilatore) deve utilizzare altre istruzioni per l'aritmetica firmata e non firmata.
La CPU x86 ad esempio ha un'istruzione chiamata div
per fare una divisione senza segno e un'istruzione chiamata idiv
per fare una divisione firmata.
Esistono anche diverse istruzioni "condizionali" (salti condizionali, set-bit-on-condition) e istruzioni di moltiplicazione per l'aritmetica con o senza segno.