ΗΥ-225: Οργάνωση Υπολογιστών
Άνοιξη 2020 |
Τμ. Επ. Υπολογιστών © Πανεπιστήμιο Κρήτης |
[Up - Table of Contents] [Prev - 7. Linked List] |
[printer version - PDF] [9. Pipelining - Next] |
Βιβλίο: (α) Προσημασμένοι αριθμοί: Διαβάστε την §2.4 (σελίδες 127-134 στο Ελληνικό βιβλίο, pp. 74-81 στο Αγγλικό), και ξαναθυμηθείτε το Εργαστήριο 6 της Ψηφιακής Σχεδίασης. (β) Υλοποίηση Επεξεργαστή: Διαβάστε την §4.4 (σελίδες 374-389 στο Ελληνικό βιβλίο, pp. 251-262 στο Αγγλικό)· επιπροσθέτως, οι ενότητες 4.1 - 4.3 (σελ. 356-374, pp. 236-251) περιέχουν εισαγωγικό υλικό, χρήσιμο γιά την αρχική κατανόηση, αλλά υπερκαλύπτονται, όσον αφορά την τελική εκμάθηση, από την §4.4. (γ) Immediate fields in instructions: σχετικές είναι οι σελίδες 113-121 του Αγγλικού βιβλίου.
Σε αυτό το δεύτερο μέρος του μαθήματος
θα δούμε πώς υλοποιείται σε υλικό (hardware ψηφιακά κυκλώματα)
ένας επεξεργαστής RISC-V με ένα αντιπροσωπευτικό υποσύνολο των εντολών
του πραγματικού RISC-V.
Ξεκινάμε, σε αυτήν εδώ τη σειρά 8 σημειώσεων και ασκήσεων
με μιά πολύ απλή υλοποίηση, ανάλογη εκείνης του
απλού υπολογιστή του μαθήματος της Ψηφιακής Σχεδίασης,
όπου όλες οι εντολές εκτελούνται σε έναν (μεν) μόνον κύκλο ρολογιού,
ο οποίος όμως είναι πολύ μακρύς
(μεγάλη περίοδος ρολογιού = μικρή συχνότητα ρολογιού).
Όπως και τότε, θα χρειαστούμε
το Μετρητή Προγράμματος (PC - Program Counter),
τη Μνήμη Εντολών (Instruction Memory),
τη Μνήμη Δεδομένων (Data Memory),
μιάν Μονάδα γιά τις Αριθμητικές & Λογικές Πράξεις
(ALU - Arithmetic-Logic Unit),
και κάμποσους πολυπλέκτες
(αντί και του Bus, που σήμερα σπανίως χρησιμοποιείται)·
στη θέση του ενός, τότε, Συσσωρευτή (ACC - Accumulator)
τώρα θα έχουμε μιά μικρή (και γρήγορη) μνήμη με τους 32 καταχωρητές
–ξεκινάμε με αυτήν.
Γιά να διαβάσουμε (επιλέξουμε) έναν από τους 4 ή 32 καταχωρητές, όπως σε κάθε μνήμη, χρειαζόμαστε έναν 64-μπιτο πολυπλέκτη 4-σε-1 ή 32-σε-1, ο οποίος φυσικά χρειάζεται 2 ή 5 εισόδους (2 ή 5 bits) επιλογής γιά να του λένε ποιόν από τους 4 ή 32 καταχωρητές θέλουμε να διαβάζουμε (επιλέγουμε) κάθε στιγμή· αυτά τα 2 (στο σχήμα) ή 5 (στον RISC-V) bits είναι η διεύθυνση ανάγνωσης. Εάν τώρα προσθέσουμε και έναν δεύτερο ανάλογο πολυπλέκτη (64-μπιτο και αυτόν), και τον ελέγξουμε με 2 ή 5 άλλα bits "διεύθυνσης" (που έχουν εν γένει διαφορετική τιμή από τα πρώτα, χωρίς και να απαγορεύεται μερικές φορές να παίρνουν και την ίδια τιμή), τότε αυτός ο δεύτερος πολυπλέκτης θα μας διαβάζει (επιλέγει) έναν άλλον, δεύτερο καταχωρητή από τους 32 (που είναι εν γένει άλλος από τον πρώτον, χωρίς όμως και να αποκλείεται μερικές φορές να είναι ο ίδιος, εάν έτσι δοθούν οι δύο διευθύνσεις ανάγνωσης). Έτσι φτιάξαμε ένα αρχείο καταχωρητών Δίπορτης Ανάγνωσης (2-port read), δηλαδή, ανά πάσα στιγμή, μπορούμε να επιλέγουμε και βλέπουμε, στις δύο (64-μπιτες) εξόδους δεδομένων, τα περιεχόμενα δύο οιωνδήποτε από τους 32 καταχωρητές (διαφορετικών ή ίδιων, μεταξύ τους). Από άποψη καθυστέρησης, οι δύο πολυπλέκτες δουλεύουν εν παραλλήλω –ταυτόχρονα δηλαδή– και άρα μέσα στο χρόνο μιάς και μόνο ανάγνωσης από μονόπορτο RF, εδώ επιτυγχάνουμε δύο αναγνώσεις αντί μίας.
Ταυτόχρονα με τα παραπάνω, εάν υπάρχει και ένας τρίτος αποκωδικοποιητής 2-σε-4 ή 5-σε-32 (τρίτο τον λέμε επειδή οι δύο πολυπλέκτες ανάγνωσης κρύβουν μέσα τους και από έναν αποκωδικοποιητή διεύθυνσης, καθένας), και εάν αυτόν τον τρίτο αποκωδικοποιητή τον χρησιμοποιήσουμε γιά να ελέγξουμε τα 4 ή 32 σήματα ενεργοποίησης φόρτωσης (load enable) των 4 ή 32 καταχωρητών, τότε ταυτόχρονα με την ανάγνωση των δύο καταχωρητών, θα μπορούμε να έχουμε και εγγραφή σε έναν τρίτο (διαφορετικό ή και τον ίδιο με τους δύο πρώτους). Φυσικά, η έξοδος 00 ή 00000 του αποκωδικοποιητή δεν χρησιμοποιείται, αφού τυχόν εγγραφή στον x0 δεν έχει κανένα αποτέλεσμα. Γιά να λειτουργήσει καθώς πρέπει η εγγραφή, και να μην εγγράφουμε σε κάποιον καταχωρητή σε κάθε κύκλο ρολογιού, καταστρέφοντας έτσι τα παλαιά περιεχόμενά του ακόμα κι αν δεν έχουμε τίποτα χρήσιμο να γράψουμε, χρειαζόμαστε κι ένα συνολικό σήμα ελέγχου εγγραφής, RegWrite, που όταν είναι μηδέν αδρανοποιεί την εγγραφή γενικά, σε όλους τους καταχωρητές.
Όπως είπαμε στην §4.3, ο RISC-V έχει σε σταθερή πάντα θέση μέσα στην εντολή τα πεδία rs1 και rs2 των καταχωρητών πηγής και ομοίως του καταχωρητή προορισμού rd –όταν αυτοί υπάρχουν. Ακριβώς αυτά τα τρία πεδία της εντολής είναι οι είσοδοι "διεύθυνσης" γιά τις τρείς πόρτες του RF: δύο γιά τους πολυπλέκτες ανάγνωσης, και το τρίτο γιά τον αποκωδικοποιητή εγγραφής. Οι εντολές που δεν έχουν ένα ή και τα δύο από τα πεδία rs1, rs2, απλώς διαβάζουν τον έναν ή και τους δύο "τυχαίους" καταχωρητές που τυχαίνει να υποδεικνύουν εκείνα τα bits όποιων άλλων πεδίων βρίσκονται στις θέσεις εκείνες, και στη συνέχεια αγνοούν αυτή τη μία ή και τις δύο αναγνωσθείσες τιμές. Αυτό είναι ταχύτερο από το να περιμένουμε πρώτα να αποκωδικοποιήσουμε τον opcode γιά να διαπιστώσουμε εάν και πόσους καταχωρητές χρειαζόμαστε και στη συνέχεια να διαβάσουμε μόνον όσους χρειαζόμαστε, έστω και ελαφρώς σε βάρος της κατανάλωσης ενέργειας γιά την ανάγνωση όταν δεν τους χρειαζόμαστε. Οι εντολές που δεν γράφουν κανένα αποτέλεσμα σε καταχωρητή θα έχουν σβηστό το συνολικό σήμα ελέγχου εγγραφής, RegWrite, άρα θα αγνοούν τα 5 bits του πεδίου "rd" της εντολής, που στην πραγματικότητα, σε αυτές τις εντολές, είναι "τυχαίο" κομάτι άλλου πεδίου.
Έστω ο προσημασμένος ακέραιος As,k με k bits, τον οποίο θέλουμε να μετατρέψουμε στον ίδιο αριθμό As,n με n bits: As,n = As,k όπου n>k. Εάν τα bits του As,k τα ερμηνεύσουμε σαν μη προσημασμένο (unsigned) ακέραιο, τότε θα μοιάζουν με (θα δηλώνουν) έναν αριθμό που ας το ονομάσουμε Au,k και ομοίως εάν τα bits του As,n τα ερμηνεύσουμε σαν unsigned τότε θα μοιάζουν με τον Au,n . Εάν ο As,k = As,n είναι μη αρνητικός (δηλ. θετικός ή μηδέν), τότε, κατά τον ορισμό της κωδικοποίησης συμπληρώματος ως-προς-2, (α) το αριστερό bit τους θα είναι μηδέν, και (β) οι απρόσημες ερμηνίες τους θα είναι: Au,k = As,k και Au,n = As,n , και αφού As,n = As,k τότε θα είναι και: Au,n = Au,k. Αυτοί οι δύο τελευταίοι, αφού είνα unsigned ακέραιοι, με n και k bits αντίστοιχα, και είναι ίσοι μεταξύ τους, προκύπτει ότι ο Au,n που έχει περισσότερα bits θα είναι ίδιος με τον Au,k αλλά με n-k μηδενικά προστεθημένα αριστερά από τον Au,k .
Αλλιώς, εάν οι As,n = As,k είναι αρνητικοί, τότε, κατά τον ορισμό μας, (α) το αριστερό bit τους θα είναι ένα, και (β) οι απρόσημες ερμηνίες τους θα είναι: Au,k = As,k + 2k και Au,n = As,n + 2n . Δεδομένου ότι: As,n = As,k προκύπτει ότι θα είναι και: Au,n - 2n = Au,k - 2k . Επομένως, η αναπαράσταση που ψάχνουμε είναι η: Au,n = Au,k - 2k + 2n = Au,k + (2n - 2k) = (2n-k - 1) · 2k + Au,k . Σε αυτήν την τελευταία έκφραση, ο μεν αριστερός προσθετέος, (2n-k - 1) · 2k, αποτελείται από (n-k) το πλήθος άσσους (που είναι ο αριθμός 2n-k - 1) ολισθημένους αριστερά κατά k θέσεις bits (που είναι ο πολλαπλασιασμός επί 2k), ο δε δεξιός προσθετέος, Au,k , είναι τα αρχικά k bits του αρχικού αριθμού που μας δόθηκε. Δεδομένου ότι ο πρώτος προσθετέος έχει όλο μηδενικά στις k δεξιές θέσεις, ο δε δεύτερος προσθετέος έχει όλο μηδενικά στις (n-k) αριστερές θέσεις, το άθροισμά τους θα είναι προφανώς απλώς η "συγκόλληση" (concatenation) των δύο αυτών ποσοτήτων. Επομένως, η αναπαράσταση με n bits του αρχικού αριθμού που μας δόθηκε θα αποτελείται από τα αρχικά k bits, δεξιά, μαζί με (n-k) άσσους κολλημένους ακριβώς αριστερά τους.
Συνολικά λοιπόν, γιά να μετατρέψουμε ένα προσημασμένο (signed) ακέραιο από k (λιγότερα) bits σε n (περισσότερα) bits, δεν έχουμε παρά να κάνουμε το εξής: Τοποθετούμε αριστερά από τα bits που μας δόθηκαν (n-k) επιπλέον bits τα οποία είναι όλα τους αντίγραφα του αριστερού (most significant) bit του αριθμού που μας δόθηκε, δηλαδή αντίγραφα του bit που υποδεικνύει το πρόσημο του δοθέντος αριθμού (0 γιά θετικούς ή το μηδεν, 1 γιά αρνητικούς). Η πράξη αυτή ονομάζεται επομένως, προφανώς, επέκταση προσήμου (sign extension).
Στη συνήθη χρήση της ακολουθείται από μιάν εντολή addi (add immediate), η οποία προσθέτει στον ίδιο καταχωρητή το 12-μπιτο Immediate της. Δεδομένου ότι η lui έβαλε 12 μηδενικά δεξιά στον καταχωρητή, η πρόσθεση καταλήγει στο να αφήσει στα 12 δεξιά bits τη σταθερή ποσότητα από την εντολή addi. Στον 32-μπιτο RISC-V, στα 20 αριστερά bits του καταχωρητή, η μεν εντολή lui έβαλε την 20-μπιτη σταθερά της, η δε εντολή addi προσθέτει σε αυτήν είτε (α) 20 μηδενικά εάν η (12-μπιτη) σταθερά της έχει 0 στο αριστερό bit της, είτε (β) 20 άσους εάν η (12-μπιτη) σταθερά της έχει 1 στο αριστερό bit της. Στη μεν περίπτωση (α) τα 20 μηδενικά αφήνουν αναλοίωτα τα 20 αριστερά bits, στη δε περίπτωση (β) η πρόσθεση 20 άσων ισοδυναμεί με την πρόσθεση του αριθμού -1 (μείον 1) σε αυτά τα 20 bits. Έτσι τελικά μπορούμε να συνθέσουμε την οιαδήποτε αυθαίρετη 32-μπιτη σταθερά, βάζοντας τα μεν 12 δεξιά bits της στο Immediate της addi, τα δε 20 αριστερά bits της, είτε αυτούσια είτε αυξημένα κατά +1, στο Immediate της lui – όπου η επιλογή "αυτούσια" ή "αυξημένα κατά +1" γίνεται όταν τα 12ο από δεξιά bit είναι 0 ή 1, αντίστοιχα. Στο βιβλίο η εντολή αυτή, καθώς και η τυπική χρήση της, περιγράφονται στην αρχή της §2.10.
Επίσης ο RISC-V προσφέρει υποστήριξη γιά Relocatable Code, δηλαδή κώδικα Assermbly/Object τον οποίο μπορεί εύκολα ο Linker να αλλάξει (ή ακόμα και να μην χρειάζεται καμία αλλαγή) προκειμένου να τον συνενώνει (link) με άλλον κώδικα, τοποθετώντας (φορτώνοντάς) τον σε αυθαίρετη θέση στη μνήμη (δηλαδή να τον κάνει rellocate), όπως π.χ. χρειάζεται γιά τη δυναμική συνένωση διαδικασιών βιβλιοθήκης (dynamically linked libraries - §2.12, pp. 130-132 Αγγλικού βιβλίου). Το βασικό addressing mode (τρόπος δημιουργίας διευθύνσεων μνήμης) γιά σκοπούς εύκολου relocation είναι το PC-relative: όταν μιά διεύθυνση μνήμης εκφράζεται σαν σχετική απόσταση από την τιμή του PC της εντολής που την γεννά, τότε αυτή η απόσταση δεν αλλάζει κατά το relocation. Γιά τις διακλαδώσεις υπό συνθήκη, η διεύθυνση προορισμού δίδεται πάντα σαν PC-relative όπως έχουμε δεί, με βεληνεκές ±4 KBytes. Το ίδιο ισχύει και γιά το κάλεσμα διαδικασίας (jal), καθώς και γιά το απλό άλμα (jump) του συντίθεται ως ψευδοεντολή μέσω αυτού, με βεληνεκές ±1 MByte. Ο RISC-V προσφέρει μία ακόμα εντολή, την auipc (add upper immediate to PC), προκειμένου (α) να επεκτείνει το κάλεσμα/άλμα σε οιαδήποτε αυθαίρετη 32-μπιτη απόσταση, και (β) να προσφέρει επίσης PC-relative addressing, και μάλιστα με αυθαίρετη 32-μπιτη απόσταση, γιά εντολές load και store δεδομένων, ως εξής.
Η εντολή auipc rd, Imm20 (add upper immediate to PC), με format επίσης "U" όπως και η lui, πρώτα κατασκευάζει την ίδια σταθερή ποσότητα όπως και η lui, και στη συνέχεια προσθέτει αυτή τη σταθερή ποσότητα στην τιμή του PC της και γράφει το αποτέλεσμα της πρόσθεσης στον καταχωρητή rd· με άλλα λόγια, είναι σαν να κάνει: lui rd, Imm20 και αμέσως μετά να κάνει: rd ← PC+rd. Ή αλλιώς μπορούμε να πούμε ότι η auipc rd, Imm20 κάνει: rd ← PC + (sign-extended)Imm20×212. Όπως και η lui, η auipc μπορεί να χρησιμοποιηθεί σαν η πρώτη εντολή σε ένα ζευγάρι εντολών με δεύτερη εντολή είτε ένα κάλεσμα/άλμα είτε μία load/store, γιά να προκαλέσει κάλεσμα/άλμα ή προσπέλαση δεδομένων PC-relative στη διεύθυνση PC+Const32, όπου Const32 είναι μιά αυθαίρετη 32-μπιτη σταθερά αποτελούμενη από δύο κομάτια, HI τα 20 αριστερά bits, και LO τα 12 δεξιά bits, ως εξής. Η πρώτη εντολή του ζεύγους κατασκευάζει την τιμή PC+ΗΙ×212 και την τοποθετεί σ' έναν προσωρινό καταχωρητή, π.χ. τον t0: auipc t0, HI (ή auipc t0, HI+1 εάν το κομάτι LO αρχίζει με 1, όπως σχολιάζαμε παραπάνω και γιά την lui). Η δεύτερη εντολή του ζεύγους είναι είτε jalr γιά κάλεσμα/άλμα είτε load/store, όπου και στις δύο περιπτώσεις χρησιμοποιείται σαν pointer ο προηγούμενος καταχωρητής t0, και σαν Offset τα δεξιά 12 bits της Const32, το LO, άρα τελικά η διεύθυνση είναι η PC+ΗΙ×212+LO = PC+Const32:
Όπως είχαμε δεί στην §4.3, σταθερές "Immediate" υπάρχουν στα format I, B, S (σταθερές των 12 bits) και J, U (σταθερές των 20 bits) του RISC-V. Οι μορφές B και S είναι παραλλαγές της I που απλώς κόβουν το 12-μπιτο Immediate σε δύο κομάτια προκειμένου να μένουν πάντα σε σταθερή θέση τα πεδία των καταχωρητών. Οι B και S είναι ίδιες μεταξύ τους εκτός από το ότι η B χρησιμοποιείται στις διακλαδώσεις (Branch), όπου το Immediate12 πολλαπλασιάζεται επί 2 πριν προστεθεί στον PC, ενώ η S χρησιμοποιείται στις εγγραφές μνήμης (Store), όπου δεν υπάρχει πολλαπλασιασμός πριν τη χρήση. Αντίστοιχα, η μορφή J χρησιμοποιείται από την εντολή jal, όπου το Immediate20 πολλαπλασιάζεται επί 2 πριν προστεθεί στον PC, ενώ η μορφή U (Upper) χρησιμοποιείται από τις εντολές lui και auipc, όπου το Immediate20 πολλαπλασιάζεται επί 212 πριν χρησιμοποιηθεί.
Με δεδομένο το πού μέσα στην εντολή
μπαίνουν οι σταθερές ποσότητες Imm12 και Imm20
όπως είδαμε στην §4.3,
θα περίμενε κανείς τα bits τους να γράφονται
με την "φυσιολογική" τους σειρά μέσα στην εντολή,
όπως δείχνει το πρώτο σχήμα εδώ, που όπως θα εξηγήσουμε όμως
δεν είναι αυτό που κάνει ο RISC-V.
Στα σχήματα παριστάνουμε τα 12 bits του Imm12 ως
i11, i10,... i2, i1, i0 όπου
i11 είναι το περισσότερο σημαντικό (most significant - MS) bit, και
i0 είναι το λιγότερο σημαντικό (least significatn - LS) bit.
Ομοίως παριστάνουμε τα 20 bits του Imm20 ως i19, i18,... i2, i1, i0
όπου i19 είναι το MS, και i0 είναι το LS.
Τα bits αυτά,
μετά από επέκταση προσήμου (§8.2),
τροφοδοτούν συνήθως τη δεύτερη είσοδο μιάς αριθμητικής/λογικής μονάδας (ALU)
όπου την πρώτη είσοδο τροφοδοτεί ο καταχωρητής rs1 ή ο PC.
Οι βελτιστοποιήσεις αυτής της παραγράφου αφορούν ιδιαίτερα
επεξεργαστές μικρού κόστους,
όπου ο ίδιος αθροιστής μπορεί να χρησιμοποιείται
και γιά τις πράξεις όπως addi, load/store address,
και γιά τον υπολογισμό της διεύθυνσης προορισμού των branch/jump.
Όταν συμβαίνει αυτό, η δεύτερη είσοδος αυτού του αθροιστή
πρέπει να τροφοδοτηθεί με 5 διαφορετικές παραλλαγές της σταθερής ποσότητας,
ανάλογα εάν η εντολή είναι τύπου I, S, B, J, ή U.
Έστω ότι αυτή η δεύτερη είσοδος του αθροιστή αποτελείται από τα 32 bits:
b31, b30,... b2, b1, b0
όπου b31 είναι το MS, και b0 είναι το LS.
Όπως δείχνει το σχήμα (μπλέ γράμματα),
στις περιπτώσεις B και J όπου απαιτείται πολλαπλασιασμός επί 2,
κάθε bit i πρέπει να ολισθήσει μία θέση αριστερά
και να τροφοδοτήσει το διπλανό του προς τα αριστερά bit b.
Οι ολισθήσεις αυτές, και οι παραλλαγές θέσης των Immediates
θα απαιτούσαν αρκετούς πολυπλέκτες
στην είσοδο b31,... b0 του αθροιστή,
όπως φαίνεται στο σχήμα·
γιά απλότητα, το πρώτο αυτό σχήμα δεν περιλαμβάνει τις εντολές U.
Αντί γιά την παραπάνω απλοϊκή/διαισθητική
τοποθέτηση των bits των Immediates μέσα στις εντολές,
ο RISC-V παρατηρεί ότι δεν υπάρχει κανένας λόγος
ο πολλαπλασιασμός επί 2, ή άλλες μετακινήσεις bits,
να γίνονται από το hardware
την κάθε φορά και στον κάθε κύκλο ρολογιού
που χρησιμοποιείται ένα Immediate,
αλλά αντιθέτως αρκεί πολλά από αυτά να τα κάνει μία φορά ο Assembler
και να τα βρίσκει έτοιμα το υλικό (hardware)!
Το αποτέλεσμα είναι η τοποθέτηση των bits των Immediates μέσα στην εντολή
που δείχνει το δεύτερο σχήμα, όπως δηλαδή ορίζει ο RISC-V.
Η τοποθέτηση αυτή ναι μεν μοιάζει παράξενη και ανακατωμένη
στον ανθρώπινο παρατηρητή,
πλήν όμως ελαχιστοποιεί τις εισόδους πολυπλεκτών
που απαιτούνται στο hardware,
ενώ το κόστος της γιά τον Assembler είναι μηδαμινό.
Παρατηρήστε σε αυτό το δεύτερο σχήμα τα εξής. Συγκρίνοντας τη μορφή (format) B προς την S, βλέπουμε ότι στην B τα bits του Imm12 είναι ήδη ολισθημένα μία θέση αριστερά από τον Assembler, άρα έτοιμα στην θέση που πρέπει γιά την είσοδο b31,... b0. Εξαιρέσεις, σημειωμένες με κίτρινο, αποτελούν τα εξής: Το MS bit, b12 = i11, που θα τροφοδοτήσει την επέκταση προσήμου, παραμένει πάντα σε σταθερή θέση –την αριστερότερη: το bit αυτό τροφοδοτεί πολλούς ακροατές, δηλαδή έχει μεγάλο "fan-out", άρα απαιτεί ενίσχυση προκειμένου να μην είναι πολύ αργό, άρα θέλουμε να αποφύγουμε έξτρα πολυπλέκτη πριν τον ενισχυτή που θα αύξανε την καθυστέρηση (βλ. ΗΥ-120 §12.8). Το επόμενο bit, b11 = i10, που "εκδιώχθηκε" από τη θέση του λόγω αριστερής ολίσθησης, τοποθετείται στη "κενωθείσα" θέση του bit b0 που είναι πάντα 0, άρα περιττό να γραφτεί στην εντολή.
Στη συνέχεια, παρατηρήστε τις εντολές U: αυτές χρησιμοποιούν το Imm20 στα 20 "αριστερά" (MS) bits του αθροιστή (πρόσθεση γιά την auipc, απλό πέρασμα γιά την lui), άρα, όπως δείχνει το σχήμα, το MS bit i19 του Imm20 πρέπει να οδηγηθεί στο MS bit b31 του αθροιστή, το LS bit i0 στο bit b12 του αθροιστή, ενώ τα υπόλοιπα 12 LS bits του αθροιστή, b11,... b0, πρέπει να είναι 0. Γιά τις εντολές U, τα bits του Imm20 τοποθετούνται στις "φυσιολογικές" θέσεις που θα περίμενε κανείς.
Τώρα κοιτάξτε τη θέση των bits του Imm20 στην εντολή jal, μορφής J: μοιάζουν πολύ ανακατωμένα, αλλά η θέση τους είναι η βέλτιστη όταν την συγκρίνουμε με τις θέσεις των bits στις εντολές U και I. Πρώτα παρατηρούμε ότι επειδή η εντολή jal χρησιμοποιεί το Imm20 πολλαπλασιασμένο επί 2, το MS bit i19 του Imm20 πρέπει να οδηγηθεί στο bit b20 του αθροιστή, το LS bit i0 στο bit b1 του αθροιστή, κ.ο.κ., όπως δείχνει το σχήμα. Τώρα δείτε ότι: (α) το bit i19=b20, που θα τοροφοδοτήσει την επέκταση προσήμου, βρίσκεται στη στάνταρ θέση γι' αυτό το σκοπό, αριστερά· (β) τα επόμενα 8 bits, i18,... i11, που θα τροφοδοτήσουν τα bits b19,... b12 του αθροιστή, βρίσκονται στην ακριβώς ίδια θέση όπως και τα bits των εντολών U που τροφοδοτούν τα ίδια bits του αθροιστή· (γ) τα 10 LS bits του Imm20, i9,... i0, που θα τροφοδοτήσουν τα bits b10,... b1 του αθροιστή, βρίσκονται στην ακριβώς ίδια θέση όπως και τα bits των εντολών I (καθώς και των εντολών S και B γιά τα 6 αριστερά τους) που τροφοδοτούν τα ίδια bits του αθροιστή· και (δ) το ένα bit i10=b11, που περίσσεψε, τοποθετείται στην κενή θέση του i0 των εντολών I, η οποία εδώ είναι κενή αφού το b0=0 λόγω πολλαπλασιασμού επί 2.
Με αυτή την τοποθέτηση των bits των σταθερών ποσοτήτων λοιπόν, που επέλεξε σκόπιμα ο RISC-V, οι πολυπλέκτες που απαιτούνται στη δεύτερη είσοδο του αθροιστή, γιά να τροφοδοτήσουν το κάθε bit του από τα όποια διαφορετικά bits της εντολής (ή μηδέν) απαιτείται, είναι αυτοί που φαίνονται στο δεύτερο σχήμα. Όπως βλέπουμε, χρειάζονται 31 πολυπλέκτες, από τους οποίους οι 25 είναι μεγέθους 2-σε-1, οι 5 είναι μεγέθους 3-σε-1, και ένας είναι 4-σε-1. Αυτοί είναι πολύ οικονομικότεροι από το τι θα χρειάζονταν εάν τα bits των σταθερών ποσοτήτων ετοποθετούντο μέσα στις εντολές με τον απλοϊκό, διαισθητικά "προφανή" τρόπο που έδειχνε το πρώτο σχήμα. Στο πρώτο εκείνο σχήμα είχαμε παραλείψει, γιά απλότητα, τις εντολές U. Εάν φανταστούμε τώρα ότι περιλαμβάνμουμε και τις U, αυτές θα προσέθεταν μία ακόμα είσοδο πολύπλεξης στα bits από b30 έως και b1. Το αποτέλεσμα θα ήταν 31 πολυπλέκτες, εκ των οποίων 11 μεγέθους 2-σε-1 (γιά τα bits b30,... b20), 9 μεγέθους 3-σε-1 (γιά τα bits b19,... b12 και το b0), 7 μεγέθους 4-σε-1 (γιά τα bits b11,... b5), και 4 μεγέθους 5-σε-1 (γιά τα bits b4,... b1), δηλαδή συνολικά σημαντικά μεγαλύτεροι πολυπλέκτες απ' όσο χρειάζεται με τις βελτιστοποιήσεις τοποθέτησης των bits των σταθερών ποσοτήτων που κάνει ο RISC-V, έστω και εάν αυτές μοιάζουν σαν "ανακάτωμα" των bits.
Όπως είπαμε, το βιβλιο υλοποιεί μόνον τις εντολές ld, sd, beq, και τέσσερεις εντολές πράξεων τύπου R (add, sub, and, or). Οι τέσσερεις εντολές πράξεων κάνουν ακριβώς τις ίδιες λειτουργίες και οι τέσσερεις στο υπόλοιπο datapath, εκτός στην ALU όπου η καθεμιά τους κάνει διαφορετική πράξη. Έτσι, όλα τα υπόλοιπα σήματα ελέγχου των ALU control lines είναι κοινά και γιά τις τέσσερεις. Με αυτό το σκεπτικό, όσον αφορά όλα τα υπόλοιπα σήματα ελέγχου, το βιβλίο είναι σαν να υλοποιεί μόνον τέσσερεις εντολές: ld, sd, beq, και "ALU", τις οποίες και μπορεί να ξεχωρίσει μεταξύ τους από τον βασικό opcode και μόνον, όπως αναφέραμε συγκεκριμένα πιό πάνω. Αυτό το κάνει το Αγγλικό βιβλίο στη σελ. 261, figure 4.22, που είναι ο Πίνακας Αληθείας του κυρίως κυκλώματος ελέγχου (Control) (σχεδιασμένος λίγο ανορθόδοξα, στριμένος κατά 90 μοίρες). Όσον αφορά τον έλεγχο της ALU, ο κυρίως έλεγχος γεννά 2 σήματα, ALUop, τα οποία λένε σε ένα δευτερεύον κύκλωμα ελέγχου ("ALU control"): είτε (α) "κάνε πρόσθεση ανεξαρτήτως της τιμής των funct3, funct7" (κωδικός 00), είτε (β) "κάνε αφαίρεση ανεξαρτήτως της τιμής των funct3, funct7" (κωδικός 01), είτε (γ) "κάνε ό,τι πράξη σου υποδεικνύουν τα funct3, funct7" (κωδικός 10). Με βάση αυτή την κωδικοποίηση, το σχήμα 4.13 (σελ. 253) του Αγγλικού βιβλίου δίνει τον πίνακα αληθείας του δευτερεύοντος κυκλώματος, ALU control (οι αριστερές στήλες θα έπρεπε να λένε "01", "10", και όχι "x1", "1x", τα οποία είναι διφορούμενα διότι κάνουν και τα δύο match την περίπτωση "11"). Με αυτές τις διευκρινίσεις, διαβάστε από το Αγγλικό βιβλίο την §4.4, με την εξής σειρά: figure 4.22 (p. 261), και μετά τις 4 πρώτες σελίδες (pp. 251-254).
(β) Γιά να γίνει η προσθήκη (α) θα πρέπει να συμπληρωθεί ο πίνακας αληθείας του κυρίως κυκλώματος ελέγχου, σε σχέση με αυτόν που δίνει το (Αγγλικό) βιβλίο στο fig. 4.22 (p. 261). Επειδή η addi είναι η μόνη από τις εντολές πράξεων-Immediate –δηλαδή τις εντολές με βασικό Opcode = 0010011– που θέλουμε να προσθέσουμε, θα αρκεστούμε να την αναγνωρίζουμε από τον βασικό opcode, σύμφωνα με όσα είπαμε ακριβώς παραπάνω (§8.6), και θα αγνοήσουμε το funct3 (που κανονικά θα έπρεπε να το ελέγχουμε και να είναι 000 γιά την addi όπως είπαμε στην §8.6). Κάντε λοιπόν αυτή την αλλαγή στον πίνακα του σχ. 4.22 του βιβλίου, προσθέτοντας την περίπτωση του opcode των εντολών πράξεων-Immediate, και γιά αυτή την περίπτωση προδιαγράφοντας τις τιμές των 8 σημάτων έλεγχου που είναι οι έξοδοι αυτού του κυκλώματος ελέγχου του σχ. 4.22.
(γ) Στη συνέχεια θέλουμε να προσθέσουμε, εκτός από την εντολή beq που υπάρχει, και τις εντολές bne, blt, και bge, οι οποίες υλοποιούνται κατ' αντιστοιχία των όμοιών τους που είχαμε και στον "Απλό Υπολογιστή" του μαθήματος της Ψηφιακής Σχεδίασης. Γιά να το πετύχουμε, χρειαζόμαστε, εκτός από την έξοδο Zero της ALU, και άλλη μία έξοδο, Sign, που θα είναι το πρόσημο (bit63) της εξόδου της ALU. Επίσης, γιά να ξέρουμε ποιά από τις 4 εντολές διακλάδωσης που θα έχουμε είναι η παρούσα, θα χρειαστεί να κοιτάμε δύο από τα bits του πεδίου funct3 της εντολής: πείτε ποιά δύο bits. Σχεδιάστε το νέο κύκλωμα που θα αντικαταστήσει στο σχ. 4.21 (σελ. 260) του (Αγγλικού) βιβλίου την πύλη AND που ελέγχειο τον πολυπλέκτη που γεννά τη νέα τιμή του PC (υπόδειξη: η λύση υπήρχε σχεδόν έτοιμη στο κύλκωμα ελέγχου του "Απλού Υπολογιστή" του μαθήματος της Ψηφιακής Σχεδίασης).
(δ) Τέλος, θέλουμε να προσθέσουμε και την εντολή jalr (jump-and-link-register - §6.4). Παρατηρήστε πρώτον ότι η διεύθυνση μνήμης στην οποία αυτή κάνει άλμα προκύπτει με ακριβώς τον ίδιο τρόπο όπως μιά ήδη υπάρχουσα εντολή: με ποιάν και ποιός είναι ο τρόπος; Γιά να μπορέσει να γίνει το άλμα θα πρέπει να προσθέσετε έναν ακόμη πολυπλέκτη, μετά τον ήδη υπάρχοντα γιά τις διακλαδώσεις, στο δρόμο δημιουργίας της νέας τιμής του PC, και να τον τροφοδοτήστε από το κάταλληλο σημείο: σχεδιάστε τα σχετικά κομάτια του datapath (δεν χρειάζεται ολόκληρο το datapath), και δείξτε τις προσθήκες. Ο πολυπλέκτης αυτός θα πρέπει να ελέγχεται από ένα σήμα που θα ενεργοποιείται όταν opcode = 1100111 και funct3 = 000, όπως είπαμε παραπάνω (§8.6) (δεν ζητείται να σχεδιάσετε αυτή την αποκωδικοποίηση). Επίσης η εντολή αυτή, σαν εντολή καλέσματος διαδικασίας, γράφει την τιμή PC+4 στον καταχωρητή προορισμού της, rd. Η τιμή PC+4 υπάρχει ήδη κάπου στο datapath; Γιά να μπορέσει η τιμή αυτή να έλθει και να γραφτεί στον καταχωρητή προορισμού, θα πρέπει να προσθέσετε έναν ακόμη πολυπλέκτη, μετά τον ήδη υπάρχοντα γιά τις εγγραφές, στο δρόμο προς την είσοδο Write data του αρχείου των καταχωρητών, και να τον ελέγξετε με το ίδιο παραπάνω σήμα ελέγχου. Δείξτε και αυτές τις προσθήκες στα σχετικά κομάτια του datapath που σχεδιάσατε και που θα παραδώσετε με τις απαντήσεις σας.
Έστω ότι προσθέτουμε και εντολή διαίρεσης,
η οποία κάνει την ALU να έχει καθυστέρηση 4400 ps, αντί 400 ps προηγουμένως.
Τότε, πόση θα γίνει η μέγιστη δυνατή συχνότητα ρολογιού;
Πόσες φορές πιό αργός θα γίνει τότε ολόκληρος ο υπολογιστής,
επειδή η κάθε εντολή, που παίρνει πάντα έναν ολόκληρο κύκλο ρολογιού,
θα αργεί τόσες φορές περισσότερο
όσο η συχνότητα του ρολογιού είναι τώρα χαμηλότερη;
Τρόπος Παράδοσης:
Παραδώστε την άσκηση αυτή on-line, σε μορφή PDF (μόνον)
(μπορεί να είναι κείμενο μηχανογραφημένο ή/και "σκαναρισμένο" χειρόγραφο,
αλλά μόνον σε μορφή PDF).
Παραδώστε μέσω turnin ex08@hy225 [directoryName]
ένα αρχείο ονόματι ex08.pdf
που θα περιέχει τις απαντήσεις σας σε όλες τις ερωτήσεις.