[Chapter Three]
[Previous] [Next] [Art of Assembly] [Randall Hyde]Art of Assembly: Κεφαλαιο 3
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)
Η αριθμητική και λογική μονάδα είναι εκεί όπου
λαμβάνουν χώρα οι περισσότερες λειτουργίες μέσα
στη CPU. Για παράδειγμα αν θέλουμε να προσθέσουμε
την αξία του 5 στον καταχωρητή AX η CPU :
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 θα χρησιμοποιούν ένα
διαφορετικό, πιο εύκολο σχήμα κωδικοποίησης.
Οι 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).
Art of Assembly: Κεφαλαιο 3 - 26 SEP 1996
[Chapter Three][Previous] [Next] [Art of Assembly][Randall Hyde]