ΗΥ-120: Ψηφιακή Σχεδίαση
Φθινόπωρο 2003 |
Τμ. Επ. Υπολογιστών © Πανεπιστήμιο Κρήτης |
Στο τελευταίο αυτό μέρος του μαθήματος θα δούμε πώς μπορούμε να φτιάξουμε έναν απλό υπολογιστή χρησιμοποιώντας μόνο λίγους βασικούς δομικούς λίθους αυτού του μαθήματος: καταχωρητές, μνήμες, αθροιστές, πολυπλέκτες, και ένα απλό συνδυαστικό κύκλωμα ή μιά απλή FSM γιά να ελέγχει τα παραπάνω. Παρ' ότι πολύ απλός (απλοϊκός) --και εξαιρετικά αργός!-- θα είναι ένας κανονικός υπολογιστής, ικανός να εκτελεί (σχεδόν) το κάθε πρόγραμμα· τα μόνα που θα του λείπουν θα είναι σχετικά δευτερεύουσες λεπτομέρειες, και όχι κάτι εννοιολογικά κεντρικό. Ο υπολογιστής μας θα είναι δεκαεξάμπιτος (16-bit), δηλαδή θα δουλεύει με λέξεις των 16 bits· δεν θα ασχοληθούμε καθόλου με bytes (8 bits).
Εκτός από τον δεκαεξάμπιτο αθροιστή, η ALU θα έχει και 16 πύλες ΚΑΙ και 16 πύλες Ή γιά να μπορεί να κάνει τις αντίστοιχες λογικές πράξεις πάνω στις λέξεις εισόδου· πρόκειται γιά λογικές πράξεις bit-προς-bit (bitwise operations), δηλαδή το bit i της εξόδου θα είναι το λογικό ΚΑΙ ή το λογικό Ή του bit i της εισόδου A και του bit i της εισόδου B. Κάθε τέτοια δεκαεξάδα πυλών φαίνεται σχεδιασμένη σαν μία πύλη κάτω από τον αθροιστή. Ο πολυπλέκτης δεξιά επιλέγει αν επιθυμούμε η έξοδος της ALU να είναι το αποτέλεσμα της αριθμητικής πράξης που κάνει ο αθροιστής, ή το αποτέλεσμα της λογικής πράξης που κάνουν οι πύλες· ο πολυπλέκτης κάτω επιλέγει αν το αποτέλεσμα της λογικής πράξης θα είναι το λογικό ΚΑΙ ή το λογικό Ή. Τέλος, ο αριστερός επάνω πολυπλέκτης επιλέγει αν η πράξη θα γίνει με την πρώτη είσοδο της ALU, A, ή με τον αριθμό μηδέν· εάν επιλέξουμε τον αριθμό 0, ο αθροιστής θα δώσει έξοδο 0+B = B ή 0+(B')+1 = -B, οι πύλες ΚΑΙ θα δώσουν έξοδο 0, και οι πύλες Ή θα δώσουν έξοδο B ή B' (ΌΧΙ B). Έτσι, συνολικά, διαπιστώνουμε ότι η ALU μπορεί να κάνει τις παρακάτω πράξεις, ανάλογα με την εκάστοτε τιμή των τεσσάρων σημάτων ελέγχου της, mode. Η ένδειξη "x" στο mode σημαίνει ότι η ALU κάνει την ίδια πράξη όποια τιμή και να έχει το αντίστοιχο bit του mode (συνθήκη αδιαφορίας - §4.3). Οι πράξεις που μας ενδιαφέρουν να χρησιμοποιήσουμε στον υπολογιστή μας σημειώνονται με παχειά γράμματα.
mode: Πράξη: (όνομα) 0x01 ALUout = 0 0011 ALUout = B 00x0 ALUout = B (passB) 0111 ALUout = NOT B (not) 01x0 ALUout = -B 1001 ALUout = A AND B (and) 10x0 ALUout = A+B (add) 1011 ALUout = A OR B (or) 11x0 ALUout = A-B (sub) 1101 ALUout = A AND (NOT B) 1111 ALUout = A OR (NOT B)
Στο σχήμα φαίνεται η απαιτούμενη συνδεσμολογιά γιά να γίνονται οι πράξεις όπως τις περιγράψαμε. Ο συσσωρευτής είναι ένας ακμοπυροδότητος καταχωρητής (§8.4), που σημειώνεται σαν "ACC". Ένα εξωτερικό κύκλωμα, που θα δούμε σε λίγο, τροφοδοτεί τη διεύθυνση Addr στη μνήμη δεδομένων, καθώς και τα σήματα ελέγχου ανάγνωσης (dm_re - read enable) και εγγραφής (dm_we - write enable), προκαλώντας την ανάγνωση μιάς λέξης (δηλ. ενός αριθμού) από τη θέση μνήμης Addr. Η ALU παίρνει το περιεχόμενο του συσσωρευτή ACC στη μιά της είσοδο, και τον αριθμό που διαβάσαμε από τη μνήμη στην άλλη· το εξωτερικό κύκλωμα ελέγχου προσδιορίζει, μέσω του alu_md, το είδος της πράξης που πρέπει να γίνει, και το αποτέλεσμα της πράξης δίδεται σαν είσοδος στο συσσωρευτή. Όταν έλθει η ενεργή ακμή του ρολογιού, το αποτέλεσμα αυτής της πράξης αντικατθιστά το παλαιό περιεχόμενο του συσσωρευτή. Κατά καιρούς, πρέπει το αποτέλεσμα των πράξεων να αποθηκεύεται (γράφεται) σε μιά επιθυμητή θέση (λέξη) μνήμης, προκειμένου μετά να ξεκινήσει κάποια νέα σειρά πράξεων στο συσσωρευτή. Γιά να γίνεται η αποθήκευση αυτή προβλέφτηκε ένας τρικατάστατος οδηγητής, δεξιά κάτω, ο οποίος τοποθετεί το περιεχόμενο του ACC πάνω στη λεωφόρο (bus), απ' όπου και το παραλαμβάνει η μνήμη γιά να γίνει η εγγραφή. Τα σήματα ελέγχου που πρέπει να ενεργοποιηθούν είναι τα acc2bus (ACC προς bus - ACC to bus, όπου το "2" είναι ομόηχο με το "to") και dm_we.
Ο κάθε υπολογιστής "καταλαβαίνει", δηλαδή μπορεί να αναγνωρίσει και να εκτελέσει, ορισμένες μόνο, συγκεκριμένες εντολές ή τύπους εντολών· αυτές τις ονομάζουμε σύνολο ή ρεπερτόριο εντολών (instruction set) του υπολογιστή. Οι εντολές του δικού μας υπολογιστή θα αποτελούνται από δύο κομάτια καθεμία: έναν "κώδικα πράξης" (operation code, ή opcode εν συντομία), και μιά διεύθυνση Addr. Κάθε εντολή μας θα είναι 16 bits, από τα οποία τα 4 MS bits θα είναι ο opcode και τα 12 LS bits θα είναι η διεύθυνση. Γιά να μπορεί ο υπολογιστής μας να εκτελεί τις αριθμητικές και λογικές πράξεις που περιγράψαμε παραπάνω, το ρεπερτόριό του πρέπει να περιλαμβάνει τις εξής εντολές:
load Addr ACC <- DM[Addr] not Addr ACC <- NOT DM[Addr] add Addr ACC <- ACC + DM[Addr] and Addr ACC <- ACC AND DM[Addr] sub Addr ACC <- ACC - DM[Addr] or Addr ACC <- ACC OR DM[Addr] store Addr DM[Addr] <- ACC
Δίπλα στο συμβολισμό Assembly της κάθε εντολής, στο παραπάνω πινακάκι, υπάρχει μία "εξίσωση μεταφοράς καταχωρητών" (register transfer equation), η οποία περιγράφει τις ενέργειες που πρέπει να γίνουν προκειμένου ο υπολογιστής να εκτελέσει την εντολή. Σε αυτές τις εξισώσεις, το αριστερό βέλος υποδεικνύει μεταφορά και εγγραφή πληροφορίας (εκχώρηση - assignment). Ο συμβολισμός "DM[Addr]" σημαίνει τη θέση (λέξη) της μνήμης δεδομένων στη διεύθυνση Addr. Όταν ο συσσωρευτής, ACC, εμφανίζεται και δεξιά και αριστερά από το βέλος, τότε δεξιά μεν σημαίνει το παλαιό περιεχόμενό του (πριν την ακμή ρολογιού), αριστερά δε σημαίνει τη νέα τιμή του (μετά την ακμή ρολογιού).
Έτσι, η εντολή load Addr (φόρτωσε)
διαβάζει τον αριθμό που περιέχεται στη διεύθυνση Addr της μνήμης,
δηλαδή διαβάζει το DM[Addr],
και το αντιγράφει στο συσσωρευτή.
Η εντολή add Addr
προσθέτει το παλαιό περιεχόμενο του ACC
με τον αριθμό που περιέχεται στη διεύθυνση Addr της μνήμης,
και γράφει το αποτέλεσμα στον ACC.
Αντίστοιχα, οι εντολές sub, not, and, or
κάνουν άλλες παρόμοιες πράξεις.
Τέλος, η εντολή store Addr (αποθήκευσε)
αντιγράφει το περιεχόμενο του ACC
στη θέση (λέξη) μνήμης με διεύθυνση Addr.
Γιά παράδειγμα, λοιπόν, αν η μνήμη δεδομένων
περιέχει τους αριθμούς που φαίνονται στο παραπάνω σχήμα,
τότε το πρόγραμμα:
"load 11; add 12; add 13; store 14;"
θα προκαλέσει τις εξής ενέργειες.
Πρώτα θα διαβαστεί ο αριθμός 110 από τη θέση 11
και θα γραφτεί στο συσσωρευτή·
μετά, θα διαβαστεί ο αριθμός 120 και θα προστεθεί στον 110,
και το αποτέλεσμα 230 θα γραφτεί στο συσσωρευτή·
εν συνεχεία, θα διαβαστεί το 130 από τη θέση 13, θα προστεθεί στο 230,
και το αποτέλεσμα 360 θα μείνει στο συσσωρευτή·
και τέλος, το περιεχόμενο 360 του συσσωρευτή
θα γραφτεί στη θέση μνήμης 14.
Γιά να μπορέσει το κύκλωμά μας να εκτελέσει μιάν εντολή, πρέπει να την διαβάσει από τη μνήμη εντολών, και γιά το σκοπό αυτό χρειάζεται τη διεύθυνση της μνήμης αυτής όπου βρίσκεται η επιθυμητή εντολή. Αυτός είναι ο ρόλος του καταχωρητή PC: να θυμάται τη διεύθυνση αυτή. Στο παράδειγμα του σχήματος, ο PC περιέχει τον αριθμό 3, ο οποίος δίδεται σα διεύθυνση στη μνήμη εντολών· η μνήμη εντολών διαβάζει και μας δίνει το περιεχόμενο της θέσης 3, το οποίο εδώ τυχαίνει να είναι η εντολή load 11 --κωδικοποιημένη σε γλώσσα μηχανής φυσικά, δηλαδή "0000000000001011" όπως θα δούμε σε λίγο. Κάθε λέξη της μνήμης εντολών είναι 16 bits, και περιέχει μιάν εντολή. Τα 16 σύρματα ανάγνωσης που βγαίνουν από τη μνήμη αυτή, τα χωρίζουμε σε 4 αριστερά (MS) σύρματα που πηγαίνουν στο κύκλωμα ελέγχου, και 12 δεξιά (LS) σύρματα που πηγαίνουν σαν διεύθυνση στη μνήμη δεδομένων. Αφού όλες οι εντολές του υπολογιστή μας αποτελούνται από έναν opcode στα 4 MS bits και μία διεύθυνση στα 12 LS bits, με τη συνδεσμολογία αυτή πηγαίνει ο opcode στο κύκλωμα ελέγχου και η διεύθυνση στη μνήμη δεδομένων. Στο παράδειγμά μας, ο opcode είναι 0000 (που σημαίνει load), και η διεύθυνση είναι 000000001011 (δηλ. 11 δεκαδικό). Το κύκλωμα ελέγχου, βλέποντας την εντολή load, θα ζητήσει ανάγνωση από τη μνήμη δεδομένων (dm_re=1, dm_we=0, acc2bus=0) και θα θέσει την ALU σε λειτουργία passB (alu_md=0000 ή 0010). Η μνήμη δεδομένων, βλέποντας τη διεύθυνση 11 και ότι της ζητείται ανάγνωση, θα τοποθετήσει τον αριθμό 110 στη λεωφόρο· η ALU, εκτελώντας λειτουργία passB, θα περάσει τον αριθμό 110 στην έξοδό της· στην ενεργή ακμή του ρολογιού, ο αριθμός αυτός θα γραφτεί στο συσσωρευτή ACC, ολοκληρώνοντας έτσι την εκτέλεση της εντολής load 11.
Μετά την εκτέλεση της εντολής load 11 από τη θέση 3 της μνήμης εντολών, πρέπει να εκτελεστεί η επόμενη εντολή. Κατά πάγια σύμβαση, εκτός ειδικών εξαιρέσεων που θα δούμε σε λίγο, η επόμενη εντολή βρίσκεται γραμμένη στην ακριβώς επόμενη θέση μνήμης --εδώ, στη διεύθυνση 4. Γιά να προκύψει η επόμενη αυτή διεύθυνση γιά τη μνήμη εντολών, χρησιμοποιούμε τον αυξητή (incrementor) που φαίνεται αριστερά στο σχήμα, δηλαδή έναν αθροιστή με δεύτερη είσοδο το +1. Έτσι, στην ίδια παραπάνω ενεργή ακμή του ρολογιού που γράφεται ο αριθμός 110 στο συσσωρευτή ACC, γράφεται και το αποτέλεσμα της πρόσθεσης 3+1=4 στον καταχωρητή PC. Το αποτέλεσμα είναι ότι στον επόμενο κύκλο ρολογιού ο PC θα περιέχει 4· η μνήμη εντολών θα διαβάσει και θα μας δώσει το περιεχόμενο "0010000000001100" της θέσης 4, δηλαδή την εντολή add 12· το κύκλωμα ελέγχου, βλέποντας opcode=0010 (add), θα δώσει dm_re=1, dm_we=0, acc2bus=0, και alu_md=10x0 (δηλ. add)· η μνήμη δεδομένων, βλέποντας διεύθυνση 12 και dm_re=1, θα διαβάσει και θα δώσει στη λεωφόρο τον αριθμό 120· η ALU, βλέποντας ACC=110, στη λεωφόρο το 120, και alu_md=add, θα προσθέσει 110+120 και θα δώσει στην έξοδό της 230· και ο αθροιστής/αυξητής αριστερά, βλέποντας PC=4, θα δώσει στην έξοδό του 4+1=5. Μόλις έλθει η επόμενη ενεργή ακμή ρολογιού, το 230 θα μπεί στον ACC, και το 5 θα μπεί στον PC, ολοκληρώνοντας έτσι την εκτέλεση της εντολής add 12, και προετοιμάζοντάς μας γιά την επόμενη εντολή, add 13, από τη θέση 5.
Ο καταχωρητής PC ονομάζεται "Μετρητής Προγράμματος" (Program Counter - PC), επειδή είναι κατά βάση ένας μετρητής που αυξάνεται κατά 1 στο τέλος της εκτέλεσης κάθε εντολής γιά να μας δώσει τη διεύθυνση της επόμενης εντολής· ο πολυπλέκτης που υπάρχει στην είσοδό του προορίζεται γιά την αρχικοποίησή του, όταν δίδεται σήμα reset. Το κύκλωμα ελέγχου (control) είναι υπεύθυνο γιά τη δημιουργία όλων των σημάτων ελέγχου που λένε σε κάθε μονάδα τι να κάνει κάθε φορά. Όλες οι εντολές που είδαμε μέχρι στιγμής διαβάζονται και εκτελούνται σε έναν κύκλο ρολογιού η καθεμία, και γι' αυτό το κύκλωμα ελέγχου, μέχρι στιγμής, είναι ένα απλό συνδυαστικό κύκλωμα. Ο πίνακας αληθείας του προκύπτει αν σκεφτούμε τι εργασίες πρέπει να γίνουν γιά την εκτέλεση κάθε εντολής:
reset: opcode: md_re: md_we: alu_md: acc2bus: pc_md: 1 xxxx 0 0 0x01 (zero) 0 0 0 0000 (load) 1 0 00x0 (passB) 0 1 0 0001 (store) 0 1 00x0 (passB) 1 1 0 0010 (add) 1 0 10x0 (add) 0 1 0 0011 (sub) 1 0 11x0 (sub) 0 1 0 0100 (and) 1 0 1001 (and) 0 1 0 0101 (or) 1 0 1011 (or) 0 1 0 0111 (not) 1 0 0111 (not) 0 1
Στο σχήμα βλέπουμε ένα παράδειγμα προγράμματος
που υπολογίζει το άθροισμα 10+9+8+...+3+2+1
και το γράφει στη θέση 14 της μνήμης δεδομένων.
Ο υπολογισμός γίνεται χρησιμοποιώντας κυρίως
τις θέσεις 12 και 13 της μνήμης δεδομένων (κάτω μέρος σχήματος),
οι οποίες έχουν αρχική τιμή 10 (η μεταβλητή "n")
και 0 (η μεταβλητή "s") αντίστοιχα.
Οι τρείς πρώτες εντολές του προγράμματος (θέσεις 3, 4, και 5)
διαβάζουν την τρέχουσα τιμή της μεταβλητής s,
της προσθέτουν την τρέχουσα τιμή της μεταβλητής n,
και γράφουν το αποτέλεσμα πίσω στην s.
Την πρώτη φορά που εκτελούνται αυτές οι εντολές,
αυξάνουν το s από 0 σε 10.
Οι τρείς επόμενες εντολές (θέσεις 6, 7, και 8)
ελάττώνουν τη μεταβλητή n κατά 1·
την πρώτη φορά που εκτελούνται, αλλάζουν το n από 10 σε 9.
Στη συνέχεια εκτελείται η εντολή bne 3 από τη θέση 9·
η εντολή αυτή σημαίνει εάν ο συσσωρευτής δεν ισούται με μηδέν,
διακλαδώσου (πήγαινε) στην εντολή 3
(branch if ACC not equal to zero - brach not equal - bne).
Επειδή εκείνη την ώρα ο συσσωρευτής περιέχει το n=9,
που είναι διάφορο του μηδενός,
η συνθήκη της διακλάδωσης είναι αληθής
και η διακλάδωση επιτυγχάνει (πραγματοποιείται).
Έτσι, επόμενες εντολές εκτελούνται οι εντολές 3, 4, και 5,
αυξάνοντας το s από 10 σε 19,
και μετά οι 6, 7, και 8, μειώνοντας το n από 9 σε 8.
Μετά, ξαναεκτελείται η bne 3·
επειδή ο συσσωρευτής περιέχει το 8, η διακλάδωση επιτυγχάνει και πάλι.
Έτσι, οι εντολές 3 έως και 9 θα ξαναεκτελεστούν κάμποσες φορές ακόμα,
αυξάνοντας διαδοχικά το s κατά 8, 7, ..., 2, και 1,
και μειώνοντας το n διαδοχικά σε 7, 6, ..., 1, και 0.
Την τελευταία φορά, στο συσσωρευτή θα έχει μείνει n=0.
Τότε, η διακλάδωση bne 3 θα αποτύχει,
διότι ο συσσωρευτής δεν είναι πλέον διάφορος του μηδενός·
έτσι, η επόμενη εντολή δεν θα διαβαστεί από τη θέση 3 όπως πρίν,
αλλά από τη θέση 10, δηλαδή από την "από κάτω" θέση,
όπως κάνουν και όλες οι άλλες εντολές που δεν είναι διακλαδώσεις.
Τώρα, οι εντολές 10 και 11 θα αντιγράψουν το τελικό αποτέλεσμα
10+9+8+...+3+2+1 = 55 από τη θέση 13 (s) στη θέση 14 (S)
και ο στόχος του προγράμματος θα έχει επιτευχθεί.
Γιά να μπορέσει ο υπολογιστής μας να εκτελεί εντολές διακλάδωσης (υπό συνθήκη) και άλματος (χωρίς συνθήκη), απαιτείται μιά προσθήκη στο κύκλωμα του PC, η οποία φαίνεται στο σχήμα δίπλα, και μιά αλλαγή στο κύκλωμα ελέγχου. Στον PC, μεγαλώσαμε τον πολυπλέκτη εισόδου του απο 2-σε-1 σε 4-σε-1, ούτως ώστε να προσφέρουμε περισσότερες επιλογές γιά τον τρόπο προσδιορισμού της επόμενης τιμής του PC, δηλαδή του ποιά θα είναι (από ποιά διεύθυνση) η επόμενη εντολή. Η νέα επιλογή που προσθέτουμε είναι το πεδίο Addr της παρούσας εντολής· έτσι, όταν εκτελούμε μιάν εντολή διακλάδωσης ή άλματος, όπως bne 3, το πεδίο διεύθυνσής της (εδώ το "3") μπορεί να αποτελέσει την επόμενη τιμή του PC όταν η εντολή είναι άλμα ή επιτυχημένη διακλάδωση. Η είσοδος "10" του πολυπλέκτη προορίζεται γιά τις προσθήκες της επομένης παραγράφου. Όσον αφορά το κύκλωμα ελέγχου, αυτό χρειάζεται περισσότερες εισόδους τώρα, γιά να ξέρει να ελέγξει σωστά τη λειτουργία του υπολογιστή: δεν αρκεί πλέον να ξέρει μόνο τον opcode της παρούσας εντολής (και το αν κάνουμε reset ή όχι), αλλά πρέπει να ξέρει και το αν ο συσσωρευτής είναι μηδέν ή όχι, δεδομένου ότι από αυτό εξαρτάται η έκβαση της εντολής bne. Αυτός είναι ο ρόλος της προσθήκης "sign, zero" (πρόσημο, μηδέν) που κοιτάζει το περιεχόμενο του συσσωρευτή, ACC.
Ο υπολογιστής μας θα έχει τέσσερεις εντολές διακλάδωσης υπό συνθήκη: (α) bne (branch not equal): διακλαδώσου εάν ACC διάφορος του μηδενός· (β) beq (branch equal): διακλαδώσου εάν ACC ίσος με το μηδέν· (γ) bge (branch greater or equal): διακλαδώσου εάν ACC μεγαλύτερος ή ίσος του μηδενός· και (δ) blt (branch less than): διακλαδώσου εάν ACC μικρότερος του μηδενός· επίσης θα έχει μιάν εντολή άλματος χωρίς συνθήκη, jump, η οποία αλλάζει πάντοτε την επόμενη εντολή. Γιά να εκτελεστούν οι εντολές διακλάδωσης πρέπει να ξέρουμε το πρόσημο του συσσωρευτή καθώς και αν αυτός είναι μηδέν ή όχι. Όπως είδαμε στην §6.3, το πρόσημο ενός αριθμού κωδικοποιημένου σε συμπλήρωμα ως προς 2 είναι το περισσότερο σημαντικό (MS) bit του (το αριστερότερο bit): όταν αυτό είναι 1 τότε ο αριθμός είναι αρνητικός, ενώ όταν το MS bit είναι 0 ο αριθμός είναι θετικός ή μηδέν. Η ανίχνευση του εάν ο αριθμός είναι μηδέν ή διάφορος του μηδενός απαιτεί μιά πύλη NOR με τόσες εισόδους όσα τα bits του αριθμού. Αφού η έξοδος μιάς πύλης NOR είναι 1 όταν και μόνον όταν όλες οι είσοδοί της είναι μηδέν, συνδέοντας κάθε bit του συσσωρευτή σε μίαν είσοδο της NOR έχουμε την έξοδό της να ανάβει όταν και μόνον όταν όλα τα bits του συσσωρευτή είναι μηδέν, δηλαδή όταν ο ACC περιέχει τον αριθμό μηδέν. Ονομάζουμε accSign το MS bit του ACC, ονομάζουμε accZero την έξοδο της πύλης NOR 16 εισόδων, και παρέχουμε στο κύκλωμα ελέγχου αυτά τα δύο σήματα σαν εισόδους του. Τώρα, ο πίνακας αληθείας του κυκλώματος ελέγχου πρέπει να μετατραπεί ως εξής, σε σχέση με αυτόν που είδαμε στο τέλος της §11.4:
reset: opcode: accZero: accSign: md_re,we: alu_md: acc2bus: pc_md: 1 xxxx x x 0 0 zero 0 00 0 0000 (load) x x 1 0 passB 0 01 0 0001 (store) x x 0 1 passB 1 01 0 ... (add,...) x x 1 0 add,... 0 01 0 1000 (bne) 0 x 0 0 passB 1 11 0 1000 (bne) 1 x 0 0 passB 1 01 0 1001 (beq) 0 x 0 0 passB 1 01 0 1001 (beq) 1 x 0 0 passB 1 11 0 1010 (bge) x 0 0 0 passB 1 11 0 1010 (bge) x 1 0 0 passB 1 01 0 1011 (blt) x 0 0 0 passB 1 01 0 1011 (blt) x 1 0 0 passB 1 11 0 1100 (jump) x x 0 0 passB 1 11
Γιά να μπορεί να εκτελεί εντολές όπως η παραπάνω addx, ο υπολογιστής μας χρειάζεται τις προσθήκες που φαίνονται στο επόμενο σχήμα: ένα πολυπλέκτη στην είσοδο διευθύνσεων της μνήμης δεδομένων, προκειμένου η διεύθυνση αυτή να μπορεί να προέρχεται είτε από την εντολή, είτε από ένα δεδομένο που διαβάσαμε από την ίδια τη μνήμη δεδομένων. Επειδή πρέπει να γίνουν δύο αναγνώσεις από τη μνήμη δεδομένων, η μία μετά την άλλη, χρειαζόμαστε και έναν καταχωρητή, tmp, που να κρατάει το αποτέλεσμα της πρώτης ανάγνωσης διαθέσιμο γιά τη δεύτερη. Το κύκλωμα ελέγχου, τώρα, δεν μπορεί πλέον να είναι συνδυαστικό: επειδή η εντολή addx χρειάζεται δύο κύκλους ρολογιού, το κύκλωμα ελέγχου πρέπει να περιέχει και 1 bit κατάστασης που να μας πληροφορεί αν τώρα βρισκόμαστε στον πρώτο ή στο δεύτερο κύκλο της εκτέλεσης· επομένως, το κύκλωμα ελέγχου τώρα θα είναι μιά μικρή FSM δύο καταστάσεων. Επίσης, χρειαζόμαστε μιά μέθοδο ώστε οι καταχωρητές ACC και PC να μπορούν να διατηρούν την τιμή τους αμετάβλητη τον πρώτο από τους δύο αυτούς κύκλους ρολογιού. Η λύση είναι η χρήση καταχωρητών με ένα μικρό εσωτερικό πολυπλέκτη ανακύκλωσης· αυτοί ονομάζονται καταχωρητές με είσοδο ελέγχου επίτρεψης φόρτωσης (load enable).
Παρόμοια με την εντολή addx, θα χρειαστούμε σίγουρα και μιάν εντολή storex, και βολική θα είναι και μία loadx. Μιά άλλη δυνατότητα που δεν είχε η προηγούμενη μορφή του υπολογιστή μας, και που προστέθηκε εδώ, είναι η δυνατότητα εντολής άλματος jumpx Addr με μεταβλητή διεύθυνση προορισμού: η εντολή αυτή διαβάζει έναν αριθμό από τη θέση Addr της μνήμης δεδομένων και τον γράφει στον PC. Με τον τρόπο αυτό, η επόμενη εντολή που θα εκτελεστεί θα είναι μιά εντολή που μπορεί να την επιλέξει και να τη μεταβάλει το ίδιο το πρόγραμμα την ώρα που τρέχει! Όπως θα δούμε στο μάθημα "Οργάνωση Υπολογιστών" (ΗΥ-225), με την εντολή αυτή μπορούμε να υλοποιούμε διαδικασίες (procedures) και άλλες προηγμένες δυνατότητες των οντοκεντρικών γλωσσών προγραμματισμού.
Εκτός από την ταχύτητα ενός κυκλώματος,
το άλλο σημαντικό χαρακτηριστικό που μας απασχολεί
είναι η κατανάλωση ενέργειας ανά μονάδα χρόνου (ηλεκτρική ισχύς):
πόσο γρήγορα ξοδεύει την μπαταρία,
ή πόσο πολύ ζεσταίνεται (πόσους ανεμιστήρες ή κλιματιστικά χρειάζεται).
Η μεγαλύτερη συνηθισμένη πηγή κατανάλωσης ισχύος των chips CMOS
είναι η ενέργεια φόρτισης και εκφόρτισης
των παρασιτικών χωρητικοτήτων που αυτά έχουν μέσα τους.
Κάθε φορά που η λογική τιμή ενός ηλεκτρικού κόμβου
ανεβαίνει από το 0 στο 1 και μετά ξαναπέφτει στο 0,
χάνεται (μετατρέπεται σε θερμότητα) ποσότητα ενέργειας
ίση πρός C·V2,
όπου C η παρασιτική χωρητικότητα του κόμβου
και V η τάση τροφοδοσίας.
Αυτός είναι ο κύριος λόγος γιά τον οποίο οι νεότερες γενιές chips
έχουν χαμηλότερη τάση τροφοδοσίας (π.χ. 2.5 V, 1.8 V, 1.2 V)
από τις παλαιότερες.
Γιά δοσμένη τάση τροφοδοσίας,
όσο περισσότεροι, και μεγαλύτερης χωρητικότητας, ηλεκτρικοι κόμβοι
ανεβοκατεβαίνουν (αναβοσβήνουν) μέσα σε ένα chip,
και όσο περισσότερες φορές ανά δευτερόλεπτο το κάνουν αυτό,
τόσο μεγαλύτερη ισχύ καταναλώνει το chip αυτό.
Άρα, γιά μικρή κατανάλωση, πρέπει ένα κύκλωμα
να είναι μικρό (λίγες πύλες, μικρή χωρητικότητα),
ή να δουλεύει αργά (λιγότερα ανεβοκατεβάσματα ανά δευτερόλεπτο),
ή να δουλεύει γιά λίγο και μετά να κάθεται (να μην αλλάζει κατάσταση),
ή τις περισσότερες φορές
να εργάζεται ένα μικρό μόνο μέρος του κυκλώματος
και το υπόλοιπο να κάθεται.
Up to the Home Page of CS-120
|
© copyright
University of Crete, Greece.
Last updated: 09 Jan. 2004, by M. Katevenis. |