Perché x86 è brutto? Perché è considerato inferiore rispetto ad altri? [chiuso]


105

Recentemente ho letto alcuni archivi SO e ho riscontrato dichiarazioni contro l'architettura x86.

e molti altri commenti mi piace

Ho provato a cercare ma non ho trovato alcun motivo. Non trovo che x86 sia dannoso probabilmente perché questa è l'unica architettura con cui ho familiarità.

Qualcuno può gentilmente darmi ragioni per considerare x86 brutto / cattivo / inferiore rispetto ad altri.


1
Vado con S&A sulla base delle risposte finora, ma noterò di sfuggita che CISC non è un problema per il set di istruzioni m68k. x86 è quello che è e puoi mantenerlo.
dmckee --- gattino ex moderatore

cos'è "S&A"? "CISC non è un problema per il set di istruzioni m68k." -- Perchè no?
artigli

5
I chip motorala serie 68000 hanno un'architettura altamente CISC, ma hanno un set di istruzioni uniforme, abbastanza ortogonale e molto semplice. Perché la differenza da x86? Non lo so. Ma si noti che c'è una grande differenza tra complessità nel chip e complessità nel set di istruzioni (cioè nell'interfaccia che vede un programmatore di assembly).
dmckee --- gattino ex moderatore

4
+1 per una domanda molto interessante.
Turing Completa il

1
Recente studio sull'efficienza energetica di diversi processori trovato qui, con una buona discussione di ciò che ha guidato i progetti CISC e RISC. extremetech.com/extreme/...

Risposte:


93

Un paio di possibili ragioni per questo:

  1. x86 è un ISA relativamente vecchio (i suoi progenitori erano gli 8086, dopotutto)
  2. x86 si è evoluto molte volte in modo significativo, ma è necessario hardware per mantenere la retrocompatibilità con i vecchi binari. Ad esempio, l'hardware x86 moderno contiene ancora il supporto per l'esecuzione di codice a 16 bit in modo nativo. Inoltre, esistono diversi modelli di indirizzamento della memoria per consentire l'interoperabilità del codice precedente sullo stesso processore, come la modalità reale, la modalità protetta, la modalità 8086 virtuale e la modalità lunga (amd64). Questo può creare confusione per alcuni.
  3. x86 è una macchina CISC. Per molto tempo questo ha significato che era più lento delle macchine RISC come MIPS o ARM, perché le istruzioni hanno interdipendenza dei dati e flag che rendono difficile implementare la maggior parte delle forme di parallelismo a livello di istruzione. Le implementazioni moderne traducono le istruzioni x86 in istruzioni simili a RISC chiamate " micro-op " sotto le coperte per rendere questo tipo di ottimizzazioni pratiche da implementare nell'hardware.
  4. Per alcuni aspetti, x86 non è inferiore, è solo diverso. Ad esempio, l'input / output viene gestito come mappatura della memoria nella stragrande maggioranza delle architetture, ma non in x86. (NB: Le moderne macchine x86 in genere hanno una qualche forma di supporto DMA e comunicano con altro hardware attraverso la mappatura della memoria; ma ISA ha ancora istruzioni I / O come INe OUT)
  5. L' ISA x86 ha pochissimi registri architetturali, che possono forzare i programmi a fare il round trip nella memoria più frequentemente di quanto sarebbe altrimenti necessario. Le istruzioni aggiuntive necessarie per eseguire questa operazione richiedono risorse di esecuzione che potrebbero essere spese in un lavoro utile, sebbene in modo efficiente per l'inoltro del negoziomantiene bassa la latenza. Le implementazioni moderne con la ridenominazione dei registri su un file di registro fisico di grandi dimensioni possono mantenere molte istruzioni in volo, ma la mancanza di registri architettonici era ancora una debolezza significativa per x86 a 32 bit. L'aumento di x86-64 da 8 a 16 registri interi e vettoriali è uno dei maggiori fattori nel fatto che il codice a 64 bit è più veloce di 32 bit (insieme alla più efficiente chiamata di registro ABI), non l'aumento della larghezza di ciascun registro. Un ulteriore aumento da 16 a 32 registri interi aiuterebbe alcuni, ma non tanto. (AVX512 aumenta a 32 registri vettoriali, tuttavia, perché il codice a virgola mobile ha una latenza più elevata e spesso richiede più costanti.) ( Vedi commento )
  6. Il codice assembly x86 è complicato perché x86 è un'architettura complicata con molte funzionalità. Un elenco di istruzioni per una tipica macchina MIPS si adatta a un singolo foglio di carta formato lettera. L'elenco equivalente per x86 occupa diverse pagine e le istruzioni fanno semplicemente di più, quindi spesso è necessaria una spiegazione più ampia di ciò che fanno di quanto un elenco possa fornire. Ad esempio, l' MOVSBistruzione necessita di un blocco relativamente grande di codice C per descrivere cosa fa:

    if (DF==0) 
      *(byte*)DI++ = *(byte*)SI++; 
    else 
      *(byte*)DI-- = *(byte*)SI--;
    

    Questa è una singola istruzione che esegue un caricamento, una memorizzazione e due addizioni o sottrazioni (controllate da un input flag), ciascuna delle quali sarebbe istruzioni separate su una macchina RISC.

    Anche se la semplicità di MIPS (e architetture simili) non li rende necessariamente superiori, per insegnare un'introduzione alla classe assembler ha senso iniziare con un ISA più semplice . Alcune classi di assembly insegnano un sottoinsieme ultra-semplificato di x86 chiamato y86 , che è semplificato oltre il punto da non essere utile per un uso reale (ad es. Nessuna istruzione di spostamento), o alcune insegnano solo le istruzioni x86 di base.

  7. L'x86 utilizza codici operativi a lunghezza variabile, che aggiungono complessità hardware rispetto all'analisi delle istruzioni. Nell'era moderna questo costo sta diventando incredibilmente piccolo poiché le CPU diventano sempre più limitate dalla larghezza di banda della memoria che dal calcolo grezzo, ma molti articoli e atteggiamenti "x86 bashing" provengono da un'era in cui questo costo era relativamente molto più grande.
    Aggiornamento 2016: Anandtech ha pubblicato una discussione sulle dimensioni del codice operativo in x64 e AArch64 .

EDIT: Questo non dovrebbe essere un bash x86! festa. Non avevo altra scelta che fare un po 'di pestaggi visto il modo in cui era formulata la domanda. Ma ad eccezione di (1), tutte queste cose sono state fatte per buone ragioni (vedi commenti). I progettisti Intel non sono stupidi: volevano ottenere alcune cose con la loro architettura, e queste sono alcune delle tasse che hanno dovuto pagare per rendere queste cose una realtà.


17
È un compromesso. È un punto di forza in quanto la dimensione binaria potrebbe essere inferiore, ma è un punto debole in quanto è necessario disporre di hardware molto complicato per implementare un parser per queste istruzioni. La stragrande maggioranza delle istruzioni ha comunque la stessa dimensione - la maggior parte dei motivi per gli opcode a lunghezza variabile su x86 è perché quando hanno deciso di aggiungere funzionalità e hanno scoperto che non potevano rappresentare ciò che volevano nel numero di bit con cui dovevano lavorare . La stragrande maggioranza delle persone non si preoccupa delle dimensioni binarie quanto della complessità dell'hardware o del consumo energetico.
Billy ONeal

8
@ Joey Adams: confronta le istruzioni di lunghezza variabile di x86 con la modalità Thumb di ARM ( en.wikipedia.org/wiki/ARM_architecture#Thumb ). La modalità Thumb si traduce in un codice oggetto significativamente più piccolo per ARM perché le istruzioni più brevi mappano direttamente alle normali istruzioni. Ma poiché esiste una mappatura 1: 1 tra le istruzioni più grandi e quelle più piccole, l'hardware di analisi è semplice da implementare. Le istruzioni a lunghezza variabile di x86 non hanno questi vantaggi perché non sono state progettate in questo modo in primo luogo.
Billy ONeal

7
(6) Non tutti i codici operativi devono essere utilizzati da tutti i programmi, ma dannazione, quando ho bisogno di SSE3, sono contento di averlo.
Chris K,

4
@ Chris Kaminski: In che modo questo non influisce sull'hardware? Certo, su un moderno computer di dimensioni standard non importa a nessuno, ma se sto realizzando qualcosa come un telefono cellulare, mi preoccupo più del consumo di energia che di qualsiasi altra cosa. Gli opcode a lunghezza variabile non aumentano il tempo di esecuzione ma l'hardware di decodifica richiede ancora alimentazione per funzionare.
Billy ONeal

5
Che è una delle cose che rende il set di istruzioni x86 così brutto, dal momento che non può decidere se si tratta di un accumulatore o di un'architettura basata su file di registro (sebbene questo sia stato per lo più risolto con il 386, che ha reso il set di istruzioni molto più ortogonale , indipendentemente da ciò che ti dicono i fan di 68k).
ninjalj

25

Il principale impatto contro x86 nella mia mente sono le sue origini CISC: il set di istruzioni contiene molte interdipendenze implicite. Queste interdipendenze rendono difficile fare cose come il riordino delle istruzioni sul chip, perché gli artefatti e la semantica di queste interdipendenze devono essere preservati per ogni istruzione.

Ad esempio, la maggior parte delle istruzioni di aggiunta e sottrazione di interi x86 modificano il registro dei flag. Dopo aver eseguito un'addizione o una sottrazione, l'operazione successiva è spesso quella di guardare il registro dei flag per verificare la presenza di overflow, bit di segno, ecc. Se c'è un'altra aggiunta dopo, è molto difficile dire se è sicuro iniziare l'esecuzione della seconda aggiunta prima che si conosca il risultato della prima aggiunta.

Su un'architettura RISC, l'istruzione add specifica gli operandi di input e i registri di output e tutto ciò che riguarda l'operazione avverrebbe utilizzando solo quei registri. Questo rende molto più facile disaccoppiare le operazioni di aggiunta vicine l'una all'altra perché non ci sono registri dei flag di bloomin che costringono tutto ad allinearsi ed eseguire un singolo file.

Il chip DEC Alpha AXP, un progetto RISC in stile MIPS, era dolorosamente spartano nelle istruzioni disponibili, ma il set di istruzioni era progettato per evitare le dipendenze implicite dei registri tra le istruzioni. Non esisteva alcun registro dello stack definito dall'hardware. Non c'era alcun registro dei flag definiti dall'hardware. Anche il puntatore dell'istruzione era definito dal sistema operativo: se volevi tornare al chiamante, dovevi capire come il chiamante ti avrebbe fatto sapere a quale indirizzo tornare. Questo di solito era definito dalla convenzione di chiamata del sistema operativo. Su x86, però, è definito dall'hardware del chip.

Ad ogni modo, su 3 o 4 generazioni di progetti di chip Alpha AXP, l'hardware è passato dall'essere un'implementazione letterale del set di istruzioni spartano con 32 registri int e 32 registri float a un motore di esecuzione massicciamente fuori servizio con 80 registri interni, ridenominazione dei registri, inoltro dei risultati (in cui il risultato di un'istruzione precedente viene inoltrato a un'istruzione successiva che dipende dal valore) e tutti i tipi di booster di prestazioni folli e folli. E con tutte quelle campane e fischietti, il die del chip AXP era ancora notevolmente più piccolo del die chip Pentium comparabile di quel tempo, e l'AXP era molto più veloce.

Non si vedono quei tipi di esplosioni di prestazioni che aumentano le cose nell'albero genealogico x86 in gran parte perché la complessità del set di istruzioni x86 rende molti tipi di ottimizzazioni di esecuzione proibitivamente costose se non impossibili. Il colpo di genio di Intel è stato quello di rinunciare all'implementazione del set di istruzioni x86 nell'hardware: tutti i chip x86 moderni sono in realtà core RISC che in una certa misura interpretano le istruzioni x86, traducendole in microcodice interno che conserva tutta la semantica dell'originale x86 istruzioni, ma consente un po 'di quel RISC fuori servizio e altre ottimizzazioni sul microcodice.

Ho scritto molto per l'assembler x86 e posso apprezzare appieno la comodità delle sue radici CISC. Ma non ho apprezzato appieno quanto fosse complicato x86 fino a quando non ho passato un po 'di tempo a scrivere l'assembler Alpha AXP. Sono rimasto sbalordito dalla semplicità e dall'uniformità di AXP. Le differenze sono enormi e profonde.


6
Non ascolterò alcun attacco al CISC di per sé a meno che e fino a quando non sarai in grado di spiegare m68k.
dmckee --- gattino ex moderatore

2
Non ho familiarità con l'M68k, quindi non posso criticarlo.
dthorpe

4
Non penso che questa risposta sia abbastanza brutta da sottovalutare, ma penso che l'intero argomento "RISC è più piccolo e più veloce del CISC" non sia realmente rilevante nell'era moderna. Certo, l'AXP avrebbe potuto essere molto più veloce per il suo tempo, ma il nocciolo della questione è che i RISC moderni e i CISC moderni sono più o meno gli stessi quando si tratta di prestazioni. Come ho detto nella mia risposta, la leggera penalità di potenza per la decodifica x86 è una ragione per non usare x86 per qualcosa come un telefono cellulare, ma questo è un piccolo argomento per un desktop o notebook di dimensioni standard.
Billy ONeal

4
@Billy: la dimensione è più della dimensione del codice o della dimensione dell'istruzione. Intel paga una bella penalità sulla superficie del chip per implementare la logica hardware per tutte quelle istruzioni speciali, core del microcodice RISC sotto il cofano o meno. La dimensione dello stampo influisce direttamente sui costi di produzione, quindi è ancora una preoccupazione valida per i design dei sistemi moderni.
dthorpe

1
@dthorpe: non sono d'accordo con la maggior parte se non tutto ciò che hai scritto. Fin dall'8086, non dovevi preoccuparti se fosse sicuro eseguire uno adddopo l'altro add. Le regole sono chiare. Inoltre, non è necessario che tu ti occupi del riordino delle istruzioni. Sin dal Pentium Pro a metà degli anni '90, la CPU lo fa per te. Quello che stai menzionando potrebbe essere stato un problema 20 anni fa, ma non vedo alcun motivo per tenerlo contro l'architettura x86 al giorno d'oggi.
Nathan Fellman

21

L'architettura x86 risale al design del microprocessore 8008 e dei suoi parenti. Queste CPU sono state progettate in un'epoca in cui la memoria era lenta e se si poteva farlo sulla CPU morire, spesso era molto più veloce. Tuttavia, anche lo spazio della CPU era costoso. Questi due motivi sono perché ci sono solo un piccolo numero di registri che tendono ad avere scopi speciali e un insieme di istruzioni complicato con tutti i tipi di trucchi e limitazioni.

Anche altri processori della stessa epoca (ad esempio la famiglia 6502) hanno limitazioni e stranezze simili. È interessante notare che sia la serie 8008 che la serie 6502 erano intese come controller integrati. Anche allora, i controller integrati dovevano essere programmati in assembler e in molti modi si rivolgevano al programmatore di assembly piuttosto che a chi scriveva il compilatore. (Guarda il chip VAX per quello che succede quando ti occupi della scrittura del compilatore.) I progettisti non si aspettavano che diventassero piattaforme informatiche generiche; ecco a cosa servivano i predecessori dell'archicture POWER. La rivoluzione dell'Home Computer ha cambiato tutto, ovviamente.


4
+1 per l'unica risposta qui da qualcuno che sembra effettivamente avere un background storico sulla questione.
Billy ONeal

3
La memoria è sempre stata lenta. Forse è (relativamente parlando) più lento oggi di quanto non fosse quando ho iniziato con gli Z80 e il CP / M nel 1982. L'estinzione non è l'unico percorso evolutivo perché con l'estinzione quella particolare direzione evolutiva si ferma. Direi che l'x86 si è adattato bene nei suoi 28 anni (finora esistenza).
Olof Forshell

4
La velocità della memoria ha brevemente raggiunto la quasi parità con le CPU intorno al periodo dell'8086. Il 9900 di Texas Instruments ha un design che funziona solo perché questo è accaduto. Ma poi la CPU è andata di nuovo avanti ed è rimasta lì. Solo ora ci sono cache per aiutarti a gestirlo.
staticsan

3
@ Olof Forshell: era compatibile con l'assembler in quanto il codice assembly 8080 poteva essere tradotto in codice 8086. Da quel punto di vista, era 8080 più estensioni, proprio come potresti vedere 8080 come 8008 più estensioni.
David Thornley

3
@ Olof Forshell: Tranne che l'8086 è stato progettato per questo. Era un'estensione dell'8080 e la maggior parte (forse tutte) le istruzioni dell'8080 mappate una a una, con semantica ovviamente simile. Questo non è vero per l'architettura IBM 360, indipendentemente dal modo in cui si desidera spingerla.
David Thornley

13

Ho alcuni aspetti aggiuntivi qui:

Considera che l'operazione "a = b / c" x86 lo implementerebbe come

  mov eax,b
  xor edx,edx
  div dword ptr c
  mov a,eax

Come bonus aggiuntivo dell'istruzione div, edx conterrà il resto.

Un processore RISC richiederebbe prima il caricamento degli indirizzi di bec, il caricamento di bec dalla memoria ai registri, la divisione e il caricamento dell'indirizzo di a, quindi la memorizzazione del risultato. Dst, src sintassi:

  mov r5,addr b
  mov r5,[r5]
  mov r6,addr c
  mov r6,[r6]
  div r7,r5,r6
  mov r5,addr a
  mov [r5],r7

Qui di solito non ci sarà un resto.

Se qualsiasi variabile deve essere caricata tramite i puntatori, entrambe le sequenze possono diventare più lunghe sebbene ciò sia una possibilità minore per il RISC perché potrebbe avere uno o più puntatori già caricati in un altro registro. x86 ha meno registri, quindi la probabilità che il puntatore si trovi in ​​uno di essi è minore.

Pro e contro:

Le istruzioni RISC possono essere mescolate con il codice circostante per migliorare la pianificazione delle istruzioni, questa è una possibilità minore con x86 che invece fa questo lavoro (più o meno bene a seconda della sequenza) all'interno della CPU stessa. La sequenza RISC sopra sarà in genere lunga 28 byte (7 istruzioni di larghezza di 32 bit / 4 byte ciascuna) su un'architettura a 32 bit. Ciò farà sì che la memoria off-chip funzioni di più durante il recupero delle istruzioni (sette recuperi). La sequenza x86 più densa contiene meno istruzioni e anche se la loro larghezza varia, probabilmente stai osservando una media di 4 byte / istruzione anche lì. Anche se hai cache di istruzioni per accelerare questo sette recuperi significa che avrai un deficit di tre altrove da compensare rispetto a x86.

L'architettura x86 con meno registri da salvare / ripristinare significa che probabilmente eseguirà interruzioni di thread e gestirà gli interrupt più velocemente di RISC. Più registri da salvare e ripristinare richiedono più spazio temporaneo nello stack RAM per eseguire gli interrupt e più spazio nello stack permanente per memorizzare gli stati del thread. Questi aspetti dovrebbero rendere x86 un candidato migliore per eseguire RTOS puro.

Su una nota più personale trovo più difficile scrivere un assembly RISC rispetto a x86. Lo risolvo scrivendo la routine RISC in C, compilando e modificando il codice generato. Questo è più efficiente dal punto di vista della produzione del codice e probabilmente meno efficiente dal punto di vista dell'esecuzione. Tutti quei 32 registri di cui tenere traccia. Con x86 è il contrario: 6-8 registri con nomi "reali" rendono il problema più gestibile e infonde più fiducia che il codice prodotto funzionerà come previsto.

Brutta? È negli occhi di chi guarda. Preferisco "diverso".


a, bec nei miei esempi dovrebbero essere visti come variabili basate sulla memoria e non su valori immediati.
Olof Forshell,

... "dword ptr" è usato per specificare la dimensione di una variabile la cui dimensione non è nota se, per esempio, è semplicemente dichiarata come esterna o se sei stato pigro.
Olof Forshell

2
Non è la prima volta che sento il suggerimento di scriverlo prima in C e poi distillarlo in assembler. Questo sicuramente aiuta
Joe Plante

All'inizio tutti i processori erano RISC. CISC è nata come strategia di mitigazione per i sistemi di memoria con nucleo ferrico che erano MOLTO lenti, quindi CISC, con meno istruzioni più potenti, ha messo meno stress sul sottosistema di memoria e ha fatto un uso migliore della larghezza di banda. Allo stesso modo, i registri erano originariamente pensati come posizioni di memoria su chip e nella CPU per fare accumuli. L'ultima volta che ho valutato seriamente una macchina RISC è stato il 1993: SPARC e HP Prisim. SPARC è stato orribile su tutta la linea. Prisim era fino a 20 volte più veloce di un 486 su add / sub / mul, ma faceva schifo sui trascendentali. CISC è migliore.

@OlofForshell Dici there typically won't be a reminderma wiki dice che i mips ce l'hanno: en.wikipedia.org/wiki/MIPS_instruction_set#Integer
Alex Zhukovskiy

10

Penso che questa domanda abbia un falso presupposto. Sono principalmente solo accademici ossessionati dai RISC che definiscono brutto x86. In realtà, l'ISA x86 può eseguire in una singola istruzione operazioni che richiederebbero 5-6 istruzioni su ISA RISC. I fan di RISC potrebbero ribattere che le moderne CPU x86 suddividono queste istruzioni "complesse" in microop; però:

  1. In molti casi questo è solo parzialmente vero o non è affatto vero. Le istruzioni "complesse" più utili in x86 sono cose come ad mov %eax, 0x1c(%esp,%edi,4)esempio le modalità di indirizzamento, e queste non sono suddivise.
  2. Ciò che spesso è più importante sulle macchine moderne non è il numero di cicli spesi (poiché la maggior parte delle attività non sono vincolate alla CPU) ma l'impatto del codice nella cache delle istruzioni. 5-6 istruzioni a dimensione fissa (di solito a 32 bit) avranno un impatto sulla cache molto più di un'istruzione complessa che raramente supera i 5 byte.

x86 ha veramente assorbito tutti gli aspetti positivi di RISC circa 10-15 anni fa, e le restanti qualità di RISC (in realtà quella che definisce - il set di istruzioni minimo) sono dannose e indesiderabili.

A parte il costo e la complessità della produzione di CPU e il loro fabbisogno energetico, x86 è il miglior ISA . Chiunque ti dica il contrario lascia che l'ideologia o l'agenda interferiscano con il loro ragionamento.

D'altra parte, se stai prendendo di mira dispositivi embedded in cui conta il costo della CPU, o dispositivi embedded / mobili in cui il consumo di energia è una delle principali preoccupazioni, ARM o MIPS probabilmente hanno più senso. Tieni presente, tuttavia, che dovrai comunque occuparti della ram aggiuntiva e della dimensione binaria necessaria per gestire codice che è facilmente 3-4 volte più grande e non sarai in grado di avvicinarti alle prestazioni. Se questo è importante dipende molto da ciò che dovrai eseguire.


3
dove il consumo di energia è una delle principali preoccupazioni, ARM o MIPS probabilmente hanno più senso ... quindi, se c'è almeno un aspetto in cui ARM o MIPS hanno più senso, non rende x86 non necessariamente il miglior ISA?
Shahbaz

Ecco perché ho qualificato "i migliori" con "a parte il costo ... e il loro fabbisogno energetico".
R .. GitHub STOP AIUTO AL GHIACCIO

1
Penso che Intel abbia ridotto la velocità della CPU e le dimensioni inferiori dei die abbiano ampiamente eliminato il differenziale di potenza. La nuova doppia CPU Celeron a 64 bit con cache L1 da 64k e L2 da 1 MB è un chip da 7,5 watt. È la mia macchina da ritrovo "Starbucks" e la durata della batteria è ridicolmente lunga e funzionerà ad anelli attorno a una macchina P6. Come ragazzo che fa per lo più calcoli in virgola mobile, ho rinunciato a RISC molto tempo fa. Striscia e basta. SPARC in particolare era atrocemente glaciale. L'esempio perfetto del motivo per cui RISC fa schifo è stata la CPU Intel i860. Intel non ci è mai andata di nuovo.

@RocketRoy: 7,5 watt non sono realmente accettabili per un dispositivo alimentato 24 ore su 24, 7 giorni su 7 (e che non esegue calcoli utili per tutto il tempo) o che funziona con una batteria da 3,7 V / 2000 mAh.
R .. GitHub SMETTA DI AIUTARE IL GHIACCIO

2
@RocketRoy "CPU Intel i860. Intel non ci è mai andata di nuovo." Dopo un po 'di ricerca, l'i860 suona molto come Itanium: VLIW, parallelismo di istruzioni ordinato dal compilatore ...
Jonathon Reinhart

9

Il linguaggio assembler x86 non è così male. È quando arrivi al codice macchina che inizia a diventare davvero brutto. Le codifiche delle istruzioni, le modalità di indirizzamento, ecc. Sono molto più complicate di quelle per la maggior parte delle CPU RISC. E c'è un divertimento extra integrato per scopi di compatibilità con le versioni precedenti: cose che si attivano solo quando il processore è in un certo stato.

Nelle modalità a 16 bit, ad esempio, l'indirizzamento può sembrare decisamente bizzarro; c'è una modalità di indirizzamento per [BX+SI], ma non per [AX+BX]. Cose del genere tendono a complicare l'utilizzo del registro, dal momento che è necessario assicurarsi che il proprio valore sia in un registro che è possibile utilizzare quando necessario.

(Fortunatamente, la modalità a 32 bit è molto più sana (anche se a volte è ancora un po 'strana, ad esempio la segmentazione) e il codice x86 a 16 bit è più in gran parte irrilevante al di fuori dei boot loader e di alcuni ambienti embedded.)

Ci sono anche gli avanzi dei vecchi tempi, quando Intel stava cercando di rendere x86 il processore definitivo. Istruzioni lunghe un paio di byte che eseguivano compiti che nessuno in realtà fa più, perché erano francamente troppo lente o complicate. Le istruzioni ENTER e LOOP , per due esempi - notare che il codice dello stack frame C è come "push ebp; mov ebp, esp" e non "enter" per la maggior parte dei compilatori.


2
Credo che il problema "invio" rispetto a "push / mov" sia sorto perché su alcuni processori, "push / mov" è più veloce. Su alcuni processori, "invio" è più veloce. È la vita.
Dietrich Epp

4
Quando sono stato costretto a utilizzare una macchina basata su x86 e ho iniziato a darci un'occhiata (avendo un background m68k), ho iniziato a sentirmi frustrante la programmazione asm, ... come se avessi imparato a programmare con un linguaggio come C, e poi essere costretto a entrare in contatto con asm ... si "sente" di perdere forza espressiva, disinvoltura, chiarezza, "coerenza", "intuizione". Sono sicuro che se avessi iniziato la programmazione asm con x86, avrei pensato non è così male ... forse ... ho fatto anche MMIX e MIPS, e il loro "asm lang" è molto meglio di x86 (se questo è il PoV giusto per il Q, ma forse non lo è)
ShinTakezou

Il problema della modalità di indirizzamento è stato risolto nell'80386. Solo il codice a 16 bit ha modalità di indirizzamento limitate, il codice a 32 bit è molto meglio. È possibile ottenere le modalità di indirizzamento a 32 bit in codice a 16 bit utilizzando un prefisso speciale e viceversa.
fuz

@ FUZxxl: Sì ... probabilmente avrei dovuto dire che la bruttezza è per lo più limitata al codice a 16 bit. Risolto (credo). :)
cHao

L'ineleganza percepita deriva principalmente dall'idea sbagliata che i registri di un 8086 siano registri di uso generale; non è corretto. Ognuno di loro ha uno scopo speciale e se non ti attieni ai loro scopi, ti divertirai.
fuz

3

Non sono un esperto, ma sembra che molte delle caratteristiche per cui alle persone non piacciono possano essere le ragioni per cui funziona bene. Diversi anni fa, avere registri (invece di uno stack), frame di registro, ecc. Erano visti come buone soluzioni per rendere l'architettura più semplice agli umani. Tuttavia, al giorno d'oggi, ciò che conta sono le prestazioni della cache e le parole di lunghezza variabile di x86 consentono di memorizzare più istruzioni nella cache. La "decodifica delle istruzioni", che credo gli avversari indicarono una volta che occupava metà del chip, non è più così tanto così.

Penso che il parallelismo sia uno dei fattori più importanti al giorno d'oggi, almeno per gli algoritmi che funzionano già abbastanza velocemente da essere utilizzabili. L'espressione di un elevato parallelismo nel software consente all'hardware di ammortizzare (o spesso nascondere completamente) le latenze di memoria. Naturalmente, il futuro dell'architettura più lontano è probabilmente in qualcosa come l'informatica quantistica.

Ho sentito da nVidia che uno degli errori di Intel era che tenevano i formati binari vicini all'hardware. Il PTX di CUDA esegue alcuni calcoli di utilizzo del registro veloce (colorazione del grafico), quindi nVidia può utilizzare una macchina di registrazione invece di una macchina di stack, ma ha ancora un percorso di aggiornamento che non interrompe tutto il vecchio software.


9
RISC non è stato progettato pensando agli sviluppatori umani. Una delle idee alla base di RISC era scaricare parte della complessità del chip su chiunque avesse scritto l'assembly, idealmente il compilatore. Più registri significavano un minore utilizzo della memoria e meno dipendenze tra le istruzioni, consentendo pipeline più profonde e prestazioni più elevate. Si noti che x86-64 ha il doppio dei registri generali di x86 e questo da solo è responsabile di miglioramenti significativi delle prestazioni. E le istruzioni sulla maggior parte dei chip x86 vengono decodificate prima di essere memorizzate nella cache, non dopo (quindi le dimensioni non contano qui).
Dietrich Epp

3
@Dietrich Epp: Non è del tutto vero. L'x86-64 ha più registri visibili nell'ISA, ma le moderne implementazioni x86 di solito hanno un file di registro in stile RISC che è mappato ai registri dell'ISA su richiesta per accelerare l'esecuzione.
Billy ONeal

"Ho sentito da nVidia che uno degli errori di Intel è stato di mantenere i formati binari vicini all'hardware". - Non ho ricevuto questo e la parte PTX del CUDA.
artigli

1
@Dietrech Epp: "E le istruzioni sulla maggior parte dei chip x86 vengono decodificate prima di essere memorizzate nella cache, non dopo" Non è vero. Vengono memorizzati nella cache prima di essere decodificati. Credo che il Pentium 4 avesse una cache di traccia aggiuntiva che viene memorizzata nella cache dopo la decodifica, ma è stata interrotta.
Nathan Fellman

non è vero, i più recenti processori "sandy bridge" usano una specie di trace cache (come quella per il pentium 4, oh quel vecchio ragazzo: D), quindi le tecnologie se ne vanno e tornano ...
Quonux

3

Oltre ai motivi che le persone hanno già menzionato:

  • x86-16 aveva uno schema di indirizzamento della memoria piuttosto strano che consentiva di indirizzare una singola posizione di memoria in un massimo di 4096 modi diversi, limitava la RAM a 1 MB e costringeva i programmatori a gestire due diverse dimensioni di puntatori. Fortunatamente, il passaggio a 32 bit ha reso questa caratteristica non necessaria, ma i chip x86 portano ancora la cruft dei registri di segmento.
  • Anche se non un difetto di x86 per sé , convenzioni di chiamata x86 non erano standardizzati come MIPS era (soprattutto perché MS-DOS non è venuto con qualsiasi compilatori), lasciandoci con il pasticcio di __cdecl, __stdcall, __fastcall, etc.

Hmm .. quando penso ai concorrenti x86, non penso ai MIPS. ARM o PowerPC forse ...
Billy ONeal

@ Billy: x86 è in circolazione da quasi sempre. Un tempo MIPS era un concorrente x86. Mi ricordo che x86 ha avuto il suo bel da fare per arrivare a un livello in cui era competitivo con MIPS. (Ai tempi in cui MIPS e SPARC stavano combattendo nell'arena delle workstation.)
Shannon Severance

@ Shannon Severance: Solo perché qualcosa era una volta non significa qualcosa che lo sia.
Billy ONeal

2
@supercat: quello che le persone nell'era del modello di memoria flat x86-32 tendono a dimenticare è che 16 bit significa 64k di memoria (chiunque si preoccupi di fare i conti capirà che la magia non è possibile, che l'8086 non era un brutta punizione per programmatori ignari). Ci sono pochi modi per aggirare i 64k ma la soluzione 8086 era un buon compromesso.
Olof Forshell

2
@OlofForshell: Penso che molte persone si siano lamentate del fatto che l'8086 non fosse bello come il 68000 (che aveva uno spazio di indirizzamento lineare di 16 MB e un percorso chiaro per 4 giga). Certamente passare a un processore a 32 bit renderà più facile accedere a più di 64K, ma l'8086 è un'architettura a 16 bit che è stata progettata per essere un passo avanti rispetto all'8080 a 8 bit. Non vedo motivo per cui Intel avrebbe dovuto saltare direttamente da uno a 8 bit a uno a 32 bit.
supercat

3

Penso che otterrai una parte della risposta se mai proverai a scrivere un compilatore che abbia come target x86, o se scrivi un emulatore di macchina x86, o anche se provi a implementare l'ISA in un progetto hardware.

Anche se capisco che "x86 è brutto!" argomenti, penso ancora che sia più divertente scrivere assembly x86 rispetto a MIPS (ad esempio) - quest'ultimo è semplicemente noioso. È sempre stato pensato per essere gentile con i compilatori piuttosto che con gli umani. Non sono sicuro che un chip potrebbe essere più ostile agli scrittori di compilatori se provasse ...

La parte più brutta per me è il modo in cui funziona la segmentazione (in modalità reale): qualsiasi indirizzo fisico ha 4096 segmenti: alias offset. Quando ne hai avuto bisogno l' ultima volta ? Le cose sarebbero state molto più semplici se la parte del segmento fosse strettamente bit di ordine superiore di un indirizzo a 32 bit.


m68k è molto più divertente e piacevole per gli umani molto più di x86 (che non può sembrare così "umano" a molti programmatori m68k), se il PoV giusto è il modo in cui gli umani possono scrivere codice in quegli assembly.
ShinTakezou

Il segmento: indirizzamento offset era un tentativo di rimanere compatibile in una certa misura con il mondo CP / M. Una delle peggiori decisioni mai prese.
Turing Completa il

@Turing Complete: segment: offset NON era principalmente un tentativo di rimanere compatibile con il mondo CP / M. Quello che era è stato un tentativo molto riuscito di consentire a un processore a 16 bit di indirizzare più di 64 KByte inserendo codice, dati, stack e altre aree di memoria in segmenti diversi.
Olof Forshell

1
In realtà, collocare dati e stack in segmenti diversi era del tutto inutile per C; era utilizzabile solo per asm. In C, un puntatore può puntare a dati con durata di archiviazione statica, automatica o allocata dinamicamente, quindi non c'è modo di elide il segmento. Forse era utile per Pascal o Fortran o qualcosa del genere, ma non per C, che era già la lingua dominante all'epoca ...
R .. GitHub STOP HELPING ICE

2
@ Bernd: Il motivo per cui fs / gs è stato scelto per l'archiviazione locale del thread non è che i registri di segmento siano utili per questo. È solo che x86 è seriamente affamato di registri e i registri di segmento erano inutilizzati. Un registro generico che punta alla struttura del thread avrebbe funzionato altrettanto bene, e infatti molti sistemi RISC con più registri ne usano uno come puntatore al thread.
R .. GitHub SMETTA DI AIUTARE IL GHIACCIO

1
  1. x86 ha un insieme molto, molto limitato di registri per scopi generali

  2. promuove uno stile di sviluppo molto inefficiente al livello più basso (inferno CISC) invece di una metodologia di caricamento / immagazzinamento efficiente

  3. Intel ha preso la decisione orribile di introdurre il modello di indirizzamento della memoria chiaramente stupido di segmento / offset per rimanere compatibile con (in questo momento già!) Tecnologia obsoleta

  4. In un momento in cui tutti andavano a 32 bit, l'x86 ha frenato il mondo dei PC mainstream essendo un misero 16 bit (la maggior parte di loro - l'8088 - anche solo con percorsi dati esterni a 8 bit, il che è ancora più spaventoso!) CPU


Per me (e sono un veterano del DOS che ha visto ogni generazione di PC dal punto di vista degli sviluppatori!) Il punto 3. era il peggiore.

Immagina la seguente situazione che abbiamo avuto all'inizio degli anni '90 (mainstream!):

a) Un sistema operativo che aveva limitazioni folli per motivi legacy (640kB di RAM facilmente accessibile) - DOS

b) Un'estensione del sistema operativo (Windows) che poteva fare di più in termini di RAM, ma era limitata quando si trattava di cose come giochi, ecc ... e non era la cosa più stabile sulla Terra (fortunatamente questo è cambiato in seguito, ma io sto parlando dei primi anni '90 qui)

c) La maggior parte del software era ancora DOS e dovevamo creare dischi di avvio spesso per software speciale, perché c'era questo EMM386.exe che alcuni programmi piacevano, altri odiavano (specialmente i giocatori - e io ero un giocatore AVID in questo momento - sai cosa ho sto parlando di qui)

d) Eravamo limitati a MCGA 320x200x8 bit (ok, c'era un po 'di più con trucchi speciali, 360x480x8 era possibile, ma solo senza il supporto della libreria runtime), tutto il resto era disordinato e orribile ("VESA" - lol)

e) Ma in termini di hardware avevamo macchine a 32 bit con pochi megabyte di RAM e schede VGA con supporto fino a 1024x768

Perché questa brutta situazione?

Una semplice decisione di progettazione da parte di Intel. Livello di istruzione macchina (NON livello binario!) Compatibilità con qualcosa che stava già morendo, credo fosse l'8085. Gli altri problemi apparentemente non correlati (modalità grafiche, ecc ...) erano legati per motivi tecnici e per via del architettura di mentalità che la piattaforma x86 ha portato con sé.

Oggi la situazione è diversa, ma chiedi a qualsiasi sviluppatore dell'assemblatore o alle persone che creano backend del compilatore per x86. Il numero follemente basso di registri di uso generale non è altro che un orribile killer delle prestazioni.


L'unico problema principale con l'architettura segmentata 8086 era che c'era un solo registro di segmento non dedicato (ES) e che i linguaggi di programmazione non erano progettati per funzionare con esso in modo efficace. Lo stile di indirizzamento in scala che usa funzionerebbe molto bene in un linguaggio orientato agli oggetti che non si aspetta che gli oggetti possano iniziare da indirizzi arbitrari (se si allineano oggetti sui limiti di paragrafo, i riferimenti agli oggetti dovranno essere solo due byte anziché quattro). Se si confronta il codice del primo Macintosh con il codice del PC, l'8086 in realtà sembra piuttosto buono rispetto a 68000.
supercat

@supercat: in realtà, il registro es ERA dedicato a qualcosa, vale a dire a quelle istruzioni di stringa che richiedevano l'archiviazione (movs, stos) o la scansione (cmps e scas). Dato l'indirizzamento di 64 KiB da ogni registro di segmento, es fornisce anche il "collegamento mancante" alla memoria diversa dal codice, dai dati e dalla memoria dello stack (cs, ds, ss). I registri di segmento fornivano una sorta di schema di protezione della memoria in quanto non era possibile indirizzare al di fuori dei blocchi di memoria da 64 KB dei registri. Quale soluzione migliore proponete visto che l'x86 era un'architettura a 16 bit e i vincoli litografici dell'epoca?
Olof Forshell

@OlofForshell: ES è stato utilizzato per le istruzioni di stringa, ma potrebbe essere utilizzato come registro non vincolato per il codice che non le utilizza. Un modo per alleviare il collo di bottiglia del seg-reg senza richiedere troppo spazio per il codice operativo sarebbe quello di avere un prefisso "rseg" che specifichi che per le seguenti istruzioni in formato r / m il campo "r" selezionerebbe da CS / SS / DS / ES / FS / GS / ?? / ?? invece di AX / BX / CX / DX / SI / DI / SP / BP e di avere prefissi per FS / GS e istruzioni per LFS e LGS (come LDS e LES). Non so come fosse strutturata la microarchitettura per l'8086, ma penso che qualcosa del genere avrebbe potuto funzionare.
supercat

@supercat: come ho scritto, "i registri forniscono anche l'anello mancante alla memoria oltre a ..." Fs e gs non arrivarono fino al 386 come ricordo.
Olof Forshell

1
@OlofForshell: Non l'hanno fatto, il che ha reso l'architettura 80286 ancora peggiore dell'architettura 8086 sotto molti aspetti. Il punto era che l'aggiunta di un paio di registri di segmento in più (o anche uno, se è per questo) avrebbe reso l'architettura 8086 molto più utile e il set di istruzioni avrebbe potuto essere più pulito e più utile se si potesse accedere ai registri di segmento in modo molto simile al gli altri.
supercat
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.