[Chapter Three][Previous] [Next] [Art of Assembly] [Randall Hyde]

Art of Assembly: Κεφαλαιο 3


3.3 Οι 886, 8286, 8486, 8686 "υποθετικοί" επεξεργαστές

3.3.1 Οι καταχωρητές της Κεντρικής Μονάδας Επεξεργασίας (CPU)
3.3.2 Αριθμητική και λογική μονάδα (Arithmetic & Logical Unit, ALU)
3.3.3 Η Μονάδα Διεπαφής Διάυλου (BIU)
3.3.4 Η μονάδα ελέγχου και το σετ εντολών
3.3.5 To x86 σετ εντολών
3.3.6 Τύποι διευθυνσιοδότησης στον επεξεργαστή x86
3.3.7 Κωδικοποιώντας x86 εντολές
3.3.8 Βηματική εκτέλεση εντολών
3.3.9 Οι διαφορές μεταξύ των x86 επεξεργαστών
 


3.3 Οι 886, 8286, 8486, 8686 "υποθετικοί" επεξεργαστές

Για να κατανοήσουμε πώς μπορούμε να βελτιώσουμε την απόδοση του συστήματος, πρέπει να εξερευνήσουμε την εσωτερική λειτουργία της CPU. Δυστυχώς οι επεξεργαστές 80x86 είναι ιδιαίτερα πολύπλοκοι. Έτσι θα χρησιμοποιήσουμε τους 886, 8286, 8486, 8686. Αυτοί οι επεξεργαστές είναι ακραίες απλοποιήσεις ενός μεγάλου αριθμού μελών της 80x86 οικογένειας επεξεργαστών και τονίζουν τα σημαντικότερα θέματα αρχιτεκτονικής των 80x86.
 
 


3.3.1 Οι καταχωρητές της Κεντρικής Μονάδας Επεξεργασίας (CPU)

Οι καταχωρητές της CPU είναι πολύ ειδικές θέσεις μνήμης αποτελούμενες από flip-flops. Δεν αποτελούν τμήμα της κύριας μνήμης. Η CPU τις εκτελεί on-chip. Το μέγεθος των καταχωρητών ποικίλει στους διάφορους επεξεργαστές της οικογένειας 80x86. Οι 886, 8286, 8486 και 8686 CPU έχουν 4 καταχωρητές, όλοι μεγέθους 16 bits. Όλες οι αριθμητικές και μεταθετικές λειτουργίες λαμβάνουν χώρα στους καταχωρητές της CPU.

Επειδή ο x86 επεξεργαστής  έχει τόσο λίγους καταχωρητές, θα δώσουμε σε κάθε καταχωρητή ένα όνομα και θα αναφερόμαστε σ' αυτόν με το όνομα του και όχι με τη διεύθυνση του. Για τον x86 επεξεργαστή τα ονόματα των καταχωρητών είναι :

AX: Αθροιστής (accumulator register)
BX: Καταχωρητής Βάσης (base address register)
CX: Μετρητής (counter register)
DX: Καταχωρητής δεδομένων (data register)

Εκτός από τους παραπάνω καταχωρητές που είναι ορατοί στον προγραμματιστή, ο x86 επεξεργαστής έχει επίσης έναν καταχωρητή δείκτη εντολών (instruction pointer register), που περιέχει τη διεύθυνση της επόμενης εντολής για εκτέλεση. Επίσης υπάρχει ένας καταχωρητής σημαίας (flags register), που κρατάει το αποτέλεσμα από μια σύγκριση. Ο καταχωρητής σημαίας θυμάται αν μια αξία ήταν μικρότερη, ίση ή μεγαλύτερη από μια άλλη.

Επειδή η CPU χειρίζεται τους καταχωρητές ιδιαιτέρα και βρίσκονται on-chip, είναι πολύ γρηγορότεροι από τη μνήμη. Η πρόσβαση σε μια θέση μνήμης απαιτεί έναν ή περισσότερους κύκλους ρολογιού. Η πρόσβαση δεδομένων σε καταχωρητή συνήθως χρειάζεται 0 κύκλους ρολογιού. Γι' αυτό θα πρέπει να προσπαθούμε να αποθηκεύουμε μεταβλητές στους καταχωρητές. Οι ομάδες καταχωρητών είναι πολύ μικρές και οι περισσότεροι έχουν συγκεκριμένους ειδικούς σκοπούς, που περιορίζουν τη χρήση τους ως μεταβλητές, όμως αποτελούν το κατάλληλο μέρος για την αποθήκευση προσωρινών δεδομένων.
 


3.3.2 Αριθμητική και λογική μονάδα (Arithmetic & Logical Unit, ALU)


3.3.3 Η Μονάδα Διεπαφής Διάυλου (BIU)

Η BIU είναι υπεύθυνη για τον έλεγχο των δίαυλων διευθύνσεων και δεδομένων, όταν γίνεται προσπέλαση στην κύρια μνήμη. Αν υπάρχει κρυφή μνήμη (cache) στο chip της CPU, τότε η BIU  είναι επίσης υπεύθυνη για την προσπέλαση δεδομένων στην κρυφή μνήμη.
 


3.3.4 Η μονάδα ελέγχου και το σετ εντολών

Μια λογική ερώτηση που προκύπτει είναι η εξής : "Πώς ακριβώς εκτελεί η CPU καθορισμένες εργασίες;". Αυτό επιτυγχάνεται δίνοντας στη CPU ένα καθορισμένο σετ εντολών για να δουλέψει. Οι σχεδιαστές CPU κατασκευάζουν αυτούς τους επεξεργαστές, χρησιμοποιώντας λογικές πύλες για να εκτελούνται οι εντολές αυτές. Για να τηρείται ο αριθμός των λογικών πυλών σε ένα μικρό αριθμό (δεκάδες ή εκατοντάδες ή χιλιάδες) οι σχεδιαστές CPU πρέπει να περιορίζουν τον αριθμό και την πολυπλοκότητα των εντολών που αναγνωρίζει η CPU. Αυτό το μικρό σετ εντολών είναι το σετ εντολών της CPU.

Στα πρώτα υπολογιστικά συστήματα τα προγράμματα ήταν συχνά hard-wired στο κύκλωμα. Αυτό σημαίνει ότι η καλωδίωση του Η/Υ καθόριζε τι πρόβλημα θα έλυνε αυτός. Κάποιος έπρεπε να αλλάξει τα σύρματα-καλώδια στο κύκλωμα προκειμένου να αλλάξει το πρόγραμμα. Η επόμενη βελτίωση στον σχεδιασμό Η/Υ ήταν το προγραμματιζόμενο υπολογιστικό σύστημα, που επέτρεπε στον προγραμματιστή να "αλλάξει την καλωδίωση" του υπολογιστικού συστήματος εύκολα, χρησιμοποιώντας μια ακολουθία από υποδοχές και βυσματοειδή καλώδια. Ένα πρόγραμμα αποτελούνταν από ένα σετ από γραμμές με τρύπες (υποδοχές), κάθε μια από τις οποίες παρίστανε μια λειτουργία του προγράμματος. Ο προγραμματιστής μπορούσε να επιλέγει μια από τις εντολές, βάζοντας ένα καλώδιο στη συγκεκριμένη υποδοχή για την επιθυμούμενη εντολή.
 
   

Βέβαια αυτή η μέθοδος, περιόριζε τον αριθμό των πιθανών εντολών, από τον αριθμό των υποδοχών που μπορούσαν να τοποθετηθούν σε μια γραμμή. Γρήγορα όμως οι σχεδιαστές CPU ανακάλυψαν ότι με ένα μικρό ποσό πρόσθετου λογικού κυκλώματος, μπορούσαν να μειώσουν τον αριθμό των υποδοχών, που απαιτούνταν, από n υποδοχές για n εντολές σε logn με τρύπες για n εντολές. Το κατάφεραν αυτό αναθέτοντας έναν αριθμητικό κώδικα σε κάθε εντολή και μετά κωδικοποιώντας αυτή την εντολή σαν ένα δυαδικό αριθμό, χρησιμοποιώντας logn υποδοχές :

 
   

Αυτή η πρόσθεση απαιτεί 8 λογικές συναρτήσεις για την αποκωδικοποίηση των A, B, C bits από το patch panel, αλλά το επιπλέον κύκλωμα αξίζει το κόστος, γιατί μειώνει τον αριθμό των υποδοχών που πρέπει να επαναληφθούν για κάθε εντολή.

Βέβαια πολλές εντολές CPU δεν στέκονται μόνες τους. Για παράδειγμα η εντολή move μετακινεί δεδομένα από μια θέση του Η/Υ σε μια άλλη (π.χ από έναν καταχωρητή σε έναν άλλο). Έτσι η move εντολή απαιτεί 2 τελεστές : ένα τελεστή πηγής και ένα τελεστή προορισμού. Οι σχεδιαστές CPU συνήθως κωδικοποιούν αυτούς τους τελεστές σαν να είναι τμήμα της εντολής μηχανής, συγκεκριμένες υποδοχές αντιστοιχούν στον τελεστή πηγής και άλλες στον τελεστή προορισμού.
 

     
 

Η εντολή move θα μεταφέρει δεδομένα από τον καταχωρητή πηγής στον καταχωρητή προορισμού. Η εντολή Add θα προσθέσει την αξία του καταχωρητή πηγής στον καταχωρητή προορισμού κ.ο.κ.
 

Μια από τις βασικές βελτιώσεις που παρέχουν οι VNA μηχανές είναι η έννοια του αποθηκευμένου προγράμματος. Ένα μεγάλο πρόβλημα της μεθόδου πλεγμάτων υποδοχών (patch panel) είναι ότι ο αριθμός των εντολών μηχανής του προγράμματος περιορίζεται από τον αριθμό των γραμμών υποδοχών που είναι διαθέσιμες στη μηχανή. Ο John Von Neumann και οι άλλοι αναγνώρισαν μια σχέση μεταξύ των υποδοχών στο patch panel και των bits στη μνήμη.  Σκέφτηκαν λοιπόν ότι μπορούσαν να αποθηκεύσουν τα δυαδικά ισοδύναμα ενός προγράμματος μηχανής στην κύρια μνήμη και να καλούν κάθε πρόγραμμα από τη μνήμη, να το φορτώνουν σε έναν ειδικό καταχωρητή - αποκωδικοποιητή, που να συνδέεται άμεσα με το κύκλωμα αποκωδικοποίησης των εντολών της CPU.

Το κόλπο ήταν να προσθέσουν ακόμη περισσότερο κύκλωμα στη CPU. Αυτό το κύκλωμα, η μονάδα ελέγχου (CU) καλεί κωδικούς εντολών (γνωστοί ως operation codes ή opcodes) από τη μνήμη και τους μεταφέρει στον καταχωρητή  αποκωδικοποίησης εντολών. Η CU περιέχει έναν ειδικό καταχωρητή, τον IP (Instruction Pointer) που περιέχει τη διεύθυνση μιας εκτελέσιμης εντολής. Αφού εκτελεστεί μια εντολή, η μονάδα ελέγχου προσαυξάνει τον IP και καλεί την επόμενη εντολή από τη μνήμη για εκτέλεση κ.ο.κ.

Όταν σχεδιάζεται ένα σετ εντολών, οι σχεδιαστές CPU γενικά επιλέγουν κωδικούς εντολών που είναι πολλαπλάσιοι των 8 bits έτσι η CPU μπορεί εύκολα να καλεί πλήρεις εντολές από τη μνήμη. Ο σκοπός των CPU σχεδιαστών είναι είναι να αναθέσουν έναν κατάλληλο αριθμό από bits στο πεδίο εντολών(move, add, subtract κ.τ.λ) και στο πεδίο τελεστών. Επιλέγοντας  περισσότερα bits για το πεδίο εντολών δίνει πιο πολλές εντολές, επιλέγοντας πρόσθετα bits για το πεδίο τελεστών δίνει ένα μεγαλύτερο αριθμό τελεστών (π.χ καταχωρητών, θέσεων μνήμης). Υπάρχουν πρόσθετες πολυπλοκότητες. Μερικές εντολές  έχουν έναν τελεστή ή κανέναν. Αντί να σπαταλούνται τα bits γι' αυτά τα πεδία, οι CPU σχεδιαστές συχνά ξαναχρησιμοποιούν αυτά τα πεδία για να κωδικοποιήσουν πρόσθετους κωδικούς εντολών, για μια ακόμη φορά με πρόσθετο κύκλωμα. Οι Intel 80x86 CPU έχουν εντολές που εκτείνονται από 1 ως 10 bytes. Επειδή αυτό είναι πολύπλοκο, σ' αυτό το πρωταρχικό επίπεδο οι x86 CPU θα χρησιμοποιούν ένα διαφορετικό, πιο εύκολο σχήμα κωδικοποίησης.
 
 
 


3.3.5 To x86 σετ εντολών

Οι x86 CPU παρέχουν 20 βασικές τάξεις εντολών. Οι 7 από αυτές τις εντολές έχουν 2 τελεστές, 8 από αυτές έχουν έναν τελεστή και 5 εντολές δεν έχουν καθόλου τελεστές. Οι εντολές είναι οι εξής: Mov (έχει 2 τύπους), add, sub, cmp, and, or, not, je, jne, jb, jbe, ja, jae, jmp, brk, iret, halt, get και put. Οι παρακάτω παράγραφοι περιγράφουν πως λειτουργούν οι εντολές αυτές.

Η εντολή mov είναι στην πραγματικότητα 2 τάξεις εντολών συγχωνευμένες στην ίδια εντολή. Οι δύο μορφές της εντολής mov παίρνουν τους ακόλουθους τύπους :

mov           reg, reg/memory/constant
mov           memory, reg

όπου reg είναι οποιοσδήποτε ax, bx, cx ή dx καταχωρητής. Η constant είναι μια αριθμητική σταθερά (χρησιμοποιώντας δεκαεξαδική σημειογραφία) και memory είναι ένας τελεστής που ορίζει μια θέση μνήμης. Το επόμενο τμήμα περιγράφει τις πιθανές μορφές που μπορεί να πάρει ένας τελεστής μνήμης. Η φράση " reg,memory/constant" σημαίνει ότι ο συγκεκριμένος τελεστής μπορεί να είναι καταχωρητής, θέση μνήμης ή σταθερά.

Οι αριθμητικές και λογικές εντολές παίρνουν τις παρακάτω μορφές :

add               reg,reg/memory/constant
sub                reg,reg/memory/constant
cmp               reg,reg/memory/constant
and               reg,reg/memory/constant
or                  reg,reg/memory/constant
not                reg/memory
 

Ο έλεγχος (control) μεταφέρει εντολές, διακόπτει την ακολουθιακή εκτέλεση εντολών στη μνήμη, είτε άνευ όρων είτε μετά από εξέταση του αποτελέσματος της προηγούμενης cmp εντολής. Αυτές οι εντολές περιλαμβάνουν τα ακόλουθα :

Ja                dest                            _ _ jump if above
Jae              dest                            _ _ jump if above or equal
Jb                dest                            _ _ jump if below
Jbe              dest                            _ _ jump if below or equal
Je                dest                            _ _ jump if equal
Jne              dest                            _ _ jump if not equal
Jmp             dest                            _ _ unconditional  jump
Iret                                                 _ _ return from an interrupt
 

Οι πρώτες 6 εντολές στην τάξη αυτή, εξετάζουν το αποτέλεσμα της προηγούμενης εντολής για >, >=, <, <=, = ή ?. Για παράδειγμα αν συγκρίνουμε τους ax και bx καταχωρητές με την cmp εντολή και εκτελέσουμε την ja εντολή, η x86 CPU θα πάει στην καθορισμένη θέση προορισμού αν ισχύει ax>bx. Αν το ax δεν είναι μεγαλύτερο του bx, τότε ο έλεγχος θα πάει στην επόμενη εντολή του προγράμματος. Η jmp εντολή άνευ όρων μεταφέρει τον έλεγχο στην εντολή της διεύθυνσης προορισμού. Η iret εντολή επιστρέφει τον έλεγχο από μια διακοπή (θα συζητήσουμε αργότερα για αυτή).

Οι εντολές get και put μας επιτρέπουν να γράψουμε και να διαβάσουμε ακέραιες τιμές. Η get θα σταματήσει , θα ζητήσει από το χρήστη μια δεκαεξαδική τιμή  και θα την αποθηκεύσει στον καταχωρητή ax. Η put εμφανίζει (σε δεκαεξαδικό σύστημα) την αξία του ax καταχωρητή.

Οι υπόλοιπες εντολές δεν απαιτούν τελεστές και είναι οι halt και brk. Η Halt  τερματίζει την εκτέλεση του προγράμματος και η brk σταματά το πρόγραμμα σε μια κατάσταση, από την οποία μπορεί να ξαναξεκινήσει.

Οι x86 επεξεργαστές χρειάζονται ένα μοναδικό opcode για κάθε διαφορετική εντολή, όχι απλά για κάθε τάξη εντολών. Παρόλο που η "mov  ax, bx" και "mov  ax, cx" ανήκουν στην ίδια τάξη, πρέπει να έχουν διαφορετικά opcodes για να τις ξεχωρίζει η CPU. Πριν δούμε όμως όλους τους δυνατούς κωδικούς εντολών, ίσως θα ήταν καλή ιδέα να μελετήσουμε όλους τους πιθανούς τελεστές για τις εντολές αυτές.
 

3.3.6 Τύποι διευθυνσιοδότησης στον επεξεργαστή x86

Οι x86 εντολές χρησιμοποιούν 5 διαφορετικούς τύπους τελεστών : καταχωρητές, σταθερές και τρία σχήματα διευθύνσεων μνήμης. Κάθε μορφή καλείται ως τύπος διευθυνσιοδότησης. Οι x86 επεξεργαστές υποστηρίζουν τους τύπους διευθυνσιοδότησης καταχωρητών, τον άμεσο τύπο διευθυνσιοδότησης, τον έμμεσο τύπο διευθυνσιοδότησης, τον δεικτοδοτούμενο τύπο διευθυνσιοδότησης και τον απόλυτο τύπο διευθυνσιοδότησης. Οι παρακάτω παράγραφοι εξηγούν κάθε έναν από αυτούς τους τύπους.

Οι καταχωρητές είναι οι πιο κατανοητοί από όλους τους τελεστές. Δείτε τις παρακάτω μορφές της mov:

Mov                 ax,ax
Mov                 ax,bx
Mov                 ax,cx
Mov                 ax,dx

Η πρώτη εντολή δεν πετυχαίνει τίποτα. Αντιγράφει την αξία του ax πίσω στον ax καταχωρητή. Οι υπόλοιπες τρείς εντολές αντιγράφουν την αξία των bx, cx, dx αντίστοιχα στον ax. Μπορούμε να μετακινήσουμε τιμές σε καθέναν από τους παραπάνω καταχωρητές.

Οι σταθερές είναι επίσης εύκολες στο χειρισμό. Δείτε τις παρακάτω εντολές :

Mov              ax, 1000
Mov              ax,25
Mov              ax,[bx]
Mov              ax, [100+bx]

Η πρώτη εντολή παραπάνω χρησιμοποιεί τον απόλυτο τύπο διευθυνσιοδότησης, για να φορτώσει τον ax με την 16bit αξία που είναι αποθηκευμένη στη μνήμη ξεκινώντας στη θέση 1000 hex. Η δεύτερη εντολή φορτώνει τον ax από τη θέση της μνήμης που ορίζεται από τα περιεχόμενα του bx καταχωρητή. Αυτός είναι ένας έμμεσος τύπος διευθυνσιοδότησης. Σημειώστε ότι οι δύο εντολές

Mov                    bx,1000
Mov                    ax, [bx]

είναι ισοδύναμες με την εντολή :

Mov                ax, [1000]
 
Φυσικά, η δεύτερη σειρά είναι προτιμότερη. Παρόλα αυτά υπάρχουν περιπτώσεις, όπου η χρήση του έμμεσου τύπου διευθυνσιοδότησης είναι γρηγορότερη και καλύτερη.

Ο τελευταίος τύπος διευθυνσιοδότησης είναι ο δεικτοδοτούμενος. Ένα παράδειγμα αυτού του τύπου είναι το εξής:

Mov             ax, [1000+bx]

Αυτή η εντολή προσθέτει τα περιεχόμενα του bx με 1000 για να παράγει τη διεύθυνση της μνήμης που θα καλέσει. Αυτή η εντολή είναι χρήσιμη για την προσπέλαση στοιχείων πινάκων, εγγραφών και άλλων δομών δεδομένων.
 
 
 
 


3.3.7 Κωδικοποιώντας x86 εντολές

Παρόλο που θα μπορούσαμε να αναθέτουμε αυθαίρετα κωδικούς εντολών (opcodes) σε κάθε x86 εντολή, πρέπει να έχουμε στο μυαλό μας ότι μια πραγματική CPU, χρησιμοποιεί λογικό κύκλωμα για να αποκωδικοποιήσει τους κωδικούς εντολών και ενεργεί κατάλληλα σ΄αυτούς. Μια τυπική CPU χρησιμοποιεί στον κωδικό εντολής ένα συγκεκριμένο αριθμό bits για να δηλώσει την τάξη της εντολής (π.χ mov, add κ.ο.κ) και έναν αριθμό bits για να κωδικοποιήσει τους τελεστές. Μερικά συστήματα όπως π.χ τα CISC κωδικοποιούν αυτά τα πεδία με περίπλοκο τρόπο, παράγοντας πολύ συμπαγείς εντολές. Η οικογένεια Intel 80x86 είναι σίγουρα CISC και έχει ένα από τα πιο πολύπλοκα σχήματα αποκωδικοποίησης  κωδικών εντολών. Ο σκοπός των υποθετικών x86 επεξεργαστών είναι να παρουσιάσει την έννοια της κωδικοποίησης εντολών, χωρίς την πολυπλοκότητα των 80x86 επεξεργαστών, αλλά παρουσιάζοντας την κωδικοποίηση CISC.
       

Για να καθορίσουμε ένα συγκεκριμένο κωδικό εντολής χρειάζεται μόνο να επιλέξουμε τα κατάλληλα bits για τα πεδία iii, rr και mmm. Για παράδειγμα για να κωδικοποιήσουμε την mov ax,bx  εντολή θα διαλέγαμε iii=110, rr=00 και mmm=001 (bx), όπως βλέπουμε από το σχήμα. Αυτό παράγει την εντολή ενός byte 11000001 ή 0C0h.

Μερικές x86 εντολές απαιτούν περισσότερο από ένα byte. Για παράδειγμα η εντολή mov ax,[1000] φορτώνει τον ax καταχωρητή από τη θέση μνήμης 1000. Η κωδικοποίηση για τον κωδικό εντολής είναι 11000110 ή 0C6h. ακόμη η κωδικοποίηση κωδικών εντολών για την mov  ax, [2000] είναι επίσης 0C6h. Αυτές οι δύο εντολές κάνουν διαφορετικά πράγματα, η μία φορτώνει τον ax από τη θέση μνήμης 1000h ενώ η άλλη φορτώνει τον ax από τη θέση μνήμης 2000. Για να κωδικοποιήσουμε μια διεύθυνση με τον [xxxx] ή [xxxx+bx] τύπο διευθυνσιοδότησης, ή για να κωδικοποιήσουμε τη σταθερά με τον άμεσο τύπο διευθυνσιοδότησης, πρέπει να ακολουθήσουμε τον κωδικό εντολής με τη 16-bit διεύθυνση ή σταθερά, με το λιγότερο σημαντικό byte (L.O) να ακολουθεί τον κωδικό εντολής στη μνήμη και το H.O byte να ακολουθεί μετά. Έτσι η 3 byte κωδικοποίηση για τη mov   ax, [1000] θα είναι η 0C6h, 00h, 10h και η 3 byte κωδικοποίηση για τη mov   ax, [2000] θα είναι η 0C6h, 00h, 20h.

Ο ειδικός κωδικός εντολής επιτρέπει στην x86 CPU να επεκτείνει το σετ των διαθέσιμων εντολών της. Αυτός ο κωδικός εντολής χειρίζεται διάφορα μηδέν   και εντολές ενός τελεστή, όπως φαίνεται στα παρακάτω δύο σχήματα :
 
       

Υπάρχουν 4 κλάσεις εντολών ενός τελεστή. Η πρώτη κωδικοποίηση (00) επεκτείνει παραπέρα το σετ εντολών με ένα σετ από εντολές χωρίς τελεστές. Ο δεύτερος κωδικός εντολής είναι επίσης μια επέκταση του κωδικού εντολής, που παρέχουν όλες οι x86 jump εντολές :
 

   

Ο τρίτος κωδικός εντολής είναι η not. Πρόκειται για τη λογική not λειτουργία, που αντιστρέφει όλα τα bits στον καταχωρητή προορισμού ή στον τελεστή μνήμης. Η τέταρτη εντολή με έναν τελεστή προς το παρόν δεν έχει προσδιοριστεί. Κάθε προσπάθεια να εκτελέσουμε αυτόν τον κωδικό εντολής θα σταματήσει τον επεξεργαστή εμφανίζοντας μήνυμα λάθους εντολής (error). Οι σχεδιαστές CPU συχνά διατηρούν τέτοιους κωδικούς εντολών, για να επεκτείνουν το σετ εντολών  στο μέλλον (όπως έγινε με την Intel, στη μετάβαση από τους επεξεργαστές 80286 στους 80386).

Υπάρχουν 7 jump εντολές στο σετ εντολών. Όλες έχουν την ακόλουθη μορφή :

Jxx       διεύθυνση

Η jmp εντολή αντιγράφει την 16-bit αξία (διεύθυνση) που ακολουθεί τον κωδικό εντολής στον IP (Instruction Pointer) καταχωρητή. Έτσι η CPU θα καλέσει την επόμενη εντολή, που αντιστοιχεί στη διεύθυνση-στόχο. Αποτελεσματικά, το πρόγραμμα "πηδάει" από το σημείο της εντολής jmp στην εντολή που αντιστοιχεί στη διεύθυνση στόχο.

Η jmp εντολή είναι ένα παράδειγμα εντολής jump χωρίς όρους. Πάντα μεταφέρει τον έλεγχο στη διεύθυνση-στόχο. Οι υπόλοιπες jump εντολές είναι υποθετικές. Εξετάζουν κάποια υπόθεση κι αν αυτή είναι αληθινή εκτελούνται. Αλλιώς αν η υπόθεση είναι λάθος πηγαίνουν στην επόμενη εντολή. Αυτές οι 6 εντολές ja, jae, jb, jbe, je και jne μας επιτρέπουν να εξετάσουμε  για ανισοτικούς περιορισμούς (>, >=, <, <=, = ή ?). Φυσιολογικά εκτελούνται αμέσως μετά από μια εντολή cmp, η οποία κάνει τη σύγκριση που θέτει τις σημαίες μικρότερο από ή ίσο και της  ίσοτητας, που εξετάζουν οι υποθετικές εντολές jump. Υπάρχουν 8 πιθανοί jump κώδικες εντολών, αλλά ο x86 επεξεργαστής χρησιμοποιεί μόνο 7 από αυτούς. Ο όγδοος κωδικός είναι ένας ακόμη παράνομος κωδικός εντολής.

Η τελευταία ομάδα εντολών, είναι οι εντολές που δεν έχουν τελεστές. Οι τρεις από αυτές τις εντολές είναι παράνομες. Η brk εντολή σταματάει τη CPU μέχρι ο χρήστης να την επανεκκινήσει. Αυτό είναι χρήσιμο για να σταματάμε ένα πρόγραμμα κατά την εκτέλεση του, προκειμένου να δούμε τα αποτελέσματα. Η iret (interrupt return) εντολή επιστρέφει τον έλεγχο από μια διακοπή (interrupt service routine).  Η εντολή halt τερματίζει την εκτέλεση του προγράμματος. Η get διαβάζει μια δεκαεξαδική αξία από το χρήστη και επιστρέφει την αξία στον ax. Η put αποδίδει την αξία στον ax.
 
 


3.3.8 Βηματική εκτέλεση εντολών

Οι x86 CPU δεν εκτελούν μια εντολή μέσα σε έναν κύκλο μνήμης. Η CPU εκτελεί διάφορα βήματα για κάθε εντολή. Για παράδειγμα για την εντολή mov  reg, reg/memory/constant εκτελεί τα ακόλουθα βήματα:
 

Συνολικά η εντολή mov χρειάζεται 5 με 11 κύκλους.

Για την εντολή mov       memory, reg   η CPU κάνει τα ακόλουθα βήματα :

Ο χρόνος που απαιτείται για αυτή την εντολή είναι ο ίδιος με την προηγούμενη, εκτός από τα δύο τελευταία βήματα, γιατί η προηγούμενη μπορούσε να διαβάσει δεδομένα από τη μνήμη, ενώ αυτή η μορφή της mov "φορτώνει" τα δεδομένα από καταχωρητή. Αυτή η εντολή χρειάζεται 5 με 11 κύκλους ρολογιού για να εκτελεστεί..

Οι εντολές add, sub, cmp, and, or κάνουν τα ακόλουθα :
 

Αυτές οι εντολές χρειάζονται μεταξύ 8 και 17 κύκλους ρολογιού για να εκτελεστούν.

Η εντολή not είναι σχετική με τις προηγούμενες αλλά γρηγορότερη μια και έχει έναν τελεστή :
 

Η εντολή not  χρειάζεται 6 με 15 κύκλους ρολογιού.

Οι υποθετικές jump εντολές δουλεύουν ως εξής:
 

Η χωρίς όρους jump εντολή μοιάζουν στη λειτουργία με την εντολή  mov      reg, xxxx εκτός από το ότι ο τελεστής-προορισμός είναι ο x86 IP καταχωρητής και όχι οι ax, bx, cx ή dx καταχωρητές.

Οι brk, iret, halt, put και get εντολές δεν μας ενδιαφέρουν εδώ.
 
 


3.3.9 Οι διαφορές μεταξύ των x86 επεξεργαστών

Όλοι οι x86 επεξεργαστές έχουν το ίδιο σετ εντολών, τους ίδιους τύπους διευθυνσιοδότησης και εκτελούν τις εντολές χρησιμοποιώντας την ίδια σειρά βημάτων. Η διαφορά στην απόδοση των επεξεργαστών αυτών σχετίζεται με τέσσερα στοιχεία του hardware : ουρές προ-ανάκλησης(Pre-fetch queues), κρυφή μνήμη(cache memory), σωληνώσεις(pipelines), υπερβαθμωτός σχεδιασμός(superscalar designs).
 

3.3 Οι 886, 8286, 8486, 8686 "υποθετικοί" επεξεργαστές
3.3.1 Οι καταχωρητές της Κεντρικής Μονάδας Επεξεργασίας (CPU)
3.3.2 Αριθμητική και λογική μονάδα (Arithmetic & Logical Unit, ALU)
3.3.3 Η Μονάδα Διεπαφής Διάυλου (BIU)
3.3.4 Η μονάδα ελέγχου και το σετ εντολών
3.3.5 To x86 σετ εντολών
3.3.6 Τύποι διευθυνσιοδότησης στον επεξεργαστή x86
3.3.7 Κωδικοποιώντας x86 εντολές
3.3.8 Βηματική εκτέλεση εντολών
3.3.9 Οι διαφορές μεταξύ των x86 επεξεργαστών

 


Art of Assembly: Κεφαλαιο 3 - 26 SEP 1996

[Chapter Three][Previous] [Next] [Art of Assembly][Randall Hyde]