ΗΥ-225: Οργάνωση Υπολογιστών
Άνοιξη 2021
Τμ. Επ. Υπολογιστών
© Πανεπιστήμιο Κρήτης

Ασκήσεις 1: Εισαγωγή, Καταχωρητές, add/sub, addi,
Γλώσσα Assembly και ο Προσομοίωτης RARS

Προθεσμία έως Τετάρτη 24 Φεβρουαρίου 2021 (βδ. 2.2) (από βδ. 1.2)
[Up: Table of Contents]
[Prev: Course Description]

[Next: 2. Loops, I/O]

Αγγλικό Βιβλίο (RISC-V): Διαβάστε την αρχή του κεφαλαίου 2 (§2.1, το μεγαλύτερο μέρος της §2.2, και την αρχή της §2.3): σελ. 62-63 και 65-67. (Στις διαλέξεις των Ασκ. 2 θα αναφερθούμε λίγο και στον Assembler, Linker και συναφή· αυτά υπάρχουν στην §2.12, σελίδες 124 και πέρα, σε αυξανόμενο βάθος, μεγαλύτερο απ' όσο αντιστοιχεί σε αυτό το μάθημα).
Ελληνικό Βιβλίο (MIPS): Διαβάστε την αρχή του κεφαλαίου 2 (§2.1, το μεγαλύτερο μέρος της §2.2, και την αρχή της §2.3): σελίδες 114-116 και 118-121. (Στις διαλέξεις των Ασκ. 2 θα αναφερθούμε λίγο και στον Assembler, Linker και συναφή· αυτά υπάρχουν στην §2.12, σελίδες 182-191, αν και το βιβλίο εκεί πηγαίνει σε περισσότερες λεπτομέρειες απ' όσο αντιστοιχεί σε αυτό το μάθημα).

1.1   Βασική Λειτουργία του Υπολογιστή:

Οι υπολογιστές αποτελούνται από:

Μιά απόφαση πρωταρχικής σημασίας στην οργάνωση των υπολογιστών είναι ότι στη μνήμη αποθηκεύουμε και τα δεδομένα (αριθμούς, πληροφορίες), και τις "εντολές" (instructions) –τις οδηγίες δηλαδή προς τον υπολογιστή για το τι είδους πράξεις και επεξεργασίες αυτός πρέπει να κάνει πάνω στα δεδομένα. Από φιλοσοφική άποψη, με το να αποθηκεύονται και τα δεδομένα και οι εντολές στην ίδια μνήμη, κωδικοποιημένα και τα δύο με παρόμοιους τρόπους (σαν δυαδικές λέξεις π.χ. των 32 ή 64 bits καθεμία), ανοίγει ο δρόμος στο να μπορεί να δει και να επεξεργαστεί ο υπολογιστής τις ίδιες του τις εντολές σαν δεδομένα, αν και σπανιότατα το κάνουν αυτό τα προγράμματα γιά τον εαυτό τους: ο μεταφραστής (compiler) είναι το βασικό πρόγραμμα υπολογιστή που γεννά εντολές –αλλά γιά ένα άλλο πρόγραμμα· από την άλλη, τα "αυτομεταβαλόμενα προγράμματα" (self-modifying code) αποτελούν εφιάλτη γιά το debuuging, και γι' αυτό τα αποφεύγουμε. Από πρακτική άποψη, το να είναι μαζί τα δεδομένα και το πρόγραμμα στην ίδια μνήμη επιτρέπει την πλήρη αξιοποίηση όλου του χώρου μνήμης, χωρίς να μένουν αχρησιμοποίητα κενά, π.χ. όταν έχουμε μικρό πρόγραμμα με μεγάλα δεδομένα, ή μεγάλο πρόγραμμα με μικρά δεδομένα.

Ο υπολογιστής λειτουργεί με τον εξής βασικό επαναληπτικό τρόπο. Ο επεξεργαστής διαβάζει μια εντολή από τη μνήμη. Στη συνέχεια την αποκωδικοποιεί για να καταλάβει τι λέει, και κάνει τις δουλειές που αυτή λέει, δηλαδή την εκτελεί. Οι δουλειές αυτές είναι συνήθως απλές, όπως π.χ. μεταφορά δεδομένων από ή προς τη μνήμη, ή από ή προς περιφερειακές συσκευές, ή αριθμητικές πράξεις πάνω σε δεδομένα, ή αποφάσεις "αλλαγής πορείας". Μετά, μόλις τελειώσει η εκτέλεση της εντολής, ο επεξεργαστής διαβάζει από τη μνήμη και εκτελεί την "επόμενη" εντολή, και ούτω καθ' εξής επ' αόριστο. Η "επόμενη" εντολή συνήθως είναι η εντολή που βρίσκεται αποθηκευμένη στην επόμενη λέξη μνήμης, εκτός αν η εκτέλεση της προηγούμενης εντολής πει στον επεξεργαστή να "αλλάξει πορεία"....

Γιά να ξέρει ο επεξεργαστής ποια είναι η "επόμενη" εντολή που πρέπει να διαβάσει και εκτελέσει, υπάρχει μέσα του ένας ειδικός καταχωρητής, ο "Μετρητής Προγράμματος" (program counter - PC) –ίσως μιά σωστότερη ονομασία να ήταν "δείκτης προγράμματος" (program pointer) ή "δείκτης εντολών" (instruction pointer), αλλά έχει μείνει από παλιά η ονομασία "PC". Στο τέλος της εκτέλεσης μιας εντολής, ο PC περιέχει τη διεύθυνση μνήμης της επόμενης εντολής που πρέπει να διαβαστεί από τη μνήμη και να εκτελεστεί. Αν φανταστούμε τη μνήμη σαν έναν μεγάλο πίνακα (array), M[ ], τότε η "διεύθυνση μνήμης" είναι ο δείκτης (index), i, που μας λέει να διαβάσουμε την επόμενη εντολή από το M[ i ]. Με όρους της γλώσσας C, η διεύθυνση μνήμης της επόμενης εντολής είναι ένας pointer στην επόμενη εντολή.

1.2   Γλώσσες Μηχανής:

Οι επεξεργαστές καταλαβαίνουν και εκτελούν εντολές από ένα ρεπερτόριο πολύ μικρότερο και απλούστερο από τις γλώσσες υψηλού επιπέδου (High Level Languages - HLL). Οι εντολές που δέχεται και εκτελεί το hardware είναι αναγκαστικά κωδικοποιημένες σαν δυαδικά σύμβολα, και λέγονται Γλώσσα Μηχανής (Machine Language). Κάθε οικογένεια επεξεργαστών που είναι μεταξύ τους "binary compatible" έχει την ίδια γλώσσα μηχανής, που είναι διαφορετική από τη γλώσσα μηχανής άλλων οικογενειών. Ένα δημοφιλές σήμερα στυλ γλωσσών μηχανής ("αρχιτεκτονικών") είναι αυτές που έχουν σχετικά λίγες και απλές μόνο εντολές, και που γι' αυτό περιγράφονται σαν Υπολογιστές Ελαττωμένου Ρεπερτορίου Εντολών (Reduced Instruction Set Computers - RISC). Ενα υποσύνολο ενός τέτοιου ρεπερτορίου εντολών, του ονομαζόμενου RISC-V (RISC five, RISC πέντε, μερικές φορές "RV"), θα χρησιμοποιήσουμε σαν παράδειγμα σε αυτό το μάθημα. Αλλες γλώσσες μηχανής στυλ RISC είναι αυτές των ARM, MIPS, PowerPC, SPARC, Alpha. Η σειρά x86 της Intel έχει πιο πολύπλοκη γλώσσα μηχανής, όπως επίσης και οι ιστορικού ενδιαφέροντος υπολογιστές VAX της δεκαετίας του '80 που θα τους αναφέρω κατά καιρούς σαν αντιπαράδειγμα. Στο μάθημα αυτό, μέχρι και το 2018, χρησιμποποιούσαμε σαν παράδειγμα το ρεπερτόριο εντολών του MIPS αντί τώρα του RISC-V.

Το ρεπερτόριο εντολών RISC-V δημιουργήθηκε τη δεκαετία του '10, είναι το πρώτο ανοικτό (open) ρεπερτόριο εντολών, κερδίζει συνεχώς σε δημοτικότητα τα τελευταία χρόνια, και υπάρχουν σημαντικές ενδείξεις ότι μπορεί να εξελιχθεί σε δημοφιλέστατο διεθνές standard. Η ιστοσελίδα γιά το RISC-V είναι η riscv.org και η βασική αναφορά γιά το ρεπερτόριο εντολών είναι στη σελίδα riscv.org/specifications/ όπου μπορείτε να διαβάσετε ή "κατεβάσετε" τη σχετική προδιαγραφή (PDF, 145 σελίδες, 600 KBytes). Ένα πρόσθετο ενδιαφέρον γιά εμάς είναι ότι το μεγάλο τρέχον Ευρωπαϊκό εγχείρημα European Processor Initiative (EPI) (δείτε π.χ. μιά συνέντευξη εδώ ή ένα video εδώ) (στο οποίο συμμετέχει και το ΙΤΕ-ΙΠ εδώ στο Ηράκλειο της Κρήτης) περιλαμβάνει και δραστηριότητες βασισμένες στο RISC-V.

Κάθε εντολή γλώσσας μηχανής αποτελείται από έναν κώδικα πράξης (operation code - opcode), και από τελεστέους (operands) που περιγράφουν πάνω σε τι θα γίνει η πράξη. Οι τελεστέοι των εντολών αριθμητικών πράξεων του RISC-V είναι πάντα καταχωρητές γενικού σκοπού (registers) του επεξεργαστή, ή σταθερές ποσότητες, αλλά όχι θέσεις μνήμης. Ο βασικός RISC-V έχει 32 καταχωρητές των 32 bits καθένας: 32 bits είναι το μέγεθος λέξης (word) αυτού του βασικού RISC-V. Πιο σύγχρονα μοντέλα επεξεργαστών, σήμερα, έχουν μέγεθος λέξης 64 bits. Το (Αγγλικό) βιβλίο στηρίζεται σε μιά τέτοια πιό σύγχρονη έκδοση του RISC-V που είναι 64-μπίτη, δηλαδή έχει (32) καταχωρητές των 64 bits καθένας. Οι εντολές αριθμητικών πράξεων του RISC-V έχουν πάντα τρεις (3) τελεστέους, για λόγους ομοιομορφίας. Η ομοιομορφία μεταφράζεται σε απλότητα του hardware, πράγμα που ευνοεί την υψηλότερη ταχύτητα.

1.3   Η Γλώσσα Assembly του RISC-V:

Για να γίνει η γλώσσα μηχανής λίγο πιο φιλική προς τον άνθρωπο, χρησιμοποιούμε ένα συμβολικό όνομα για κάθε επιτρεπτό opcode, ένα δεκαδικό ή δεκαεξαδικό αριθμό με μερικά απλά σύμβολα για κάθε τελεστέο, και γράφουμε αυτά τα στοιχεία της κάθε εντολής σε μία χωριστή γραμμή. Αυτή είναι η γλώσσα Assembly, η οποία μπορεί να μεταφραστεί σε γλώσσα μηχανής από ένα σχετικά απλό πρόγραμμα υπολογιστή –τον λεγόμενο Assembler. Οι γλώσσες υψηλού επιπέδου (HLL) (όπως η C) μεταφράζονται σε Assembly από ένα σημαντικά πολυπλοκότερο πρόγραμμα, τον Compiler. Γιά έναν υπολογισμό συνθετότερης αριθμητικής έκφρασης, δείτε το παράδειγμα στη σελ. 67-68 του Αγγλικού βιβλίου ή σελ. 121 του Ελληνικού βιβλίου. Εκτός από τα ονόματα x0, x1, ..., x31 γιά τους 32 καταχωρητές του RISC-V, χρησιμοποιούνται και τα λίγο πιό αφηρημένα ονόματα t0, t1, ... (temporary), s0, s1, ... (saved), a0, a1, ... (argument), κ.α., ανάλογα με τη χρήση που επιφυλάσσουν σε καθένα τους οι συμβάσεις καλέσματος διαδικασιών (procedure calling conventions), όπως θα δούμε στις διαλέξεις 6. (Στον MIPS, τα ονόματα των καταχωρητών άρχιζαν με "$" αντί "x", π.χ. $7 αντί x7).

Γιά να εκτελεστεί ένα πρόγραμμα, οι εντολές του γράφονται στην κεντρική μνήμη η μία "κάτω" από την άλλη, δηλαδή σε συνεχόμενες θέσεις (διευθύνσεις) μνήμης. Μετά την ανάγνωση και εκτέλεση μιάς εντολής, ο επεξεργαστής αυξάνει τον PC κατά το μέγεθος της εντολής που εκτελέστηκε, οπότε αυτός (ο PC) δείχνει στην επόμενη (την "από κάτω") εντολή. Η σειριακή αυτή εκτέλεση εντολών διακόπτεται όταν εκτελείται μιά εντολή μεταφοράς ελέγχου (control transfer instruction - CTI). Τέτοιες, όπως θα δούμε, είναι, μεταξύ άλλων, οι διακλαδώσεις (branch) και τα άλματα (jump). Η ψεύδοεντολη "j label" (jump to label, ή παλαιότερα goto label, που ο Assembler την μεταφράζει σε άλλη, γενικότερη εντολή άλματος) κάνει ώστε η επόμενη εντολή που θα εκτελεστεί να είναι η εντολή στη διεύθυνση μνήμης label, αντί να είναι η "από κάτω" εντολή. Με άλλα λόγια, η (ψεύδο)εντολή "j label" φορτώνει τη διεύθυνση label στον καταχωρητή PC.

1.4   Ο Προσομοιωτής RARS:

Προγράμματα γραμμένα σε γλώσσα Assembly του RISC-V μπορεί να τα δοκιμάσει κανείς και να παρακολουθήσει πώς τρέχουν χρησιμοποιώντας τον προσομοιωτή RARS (RISC-V Assembler and Runtime Simulator), γραμμένο σε Java, διαθέσιμο δημόσια μέσω GitHub: github.com/TheThirdOne/rars . Οι προσομοιωτές είναι προγράμματα υπολογιστή που προσπαθούν να συμπεριφέρονται όσο πιο παρόμοια γίνεται, από ορισμένες απόψεις, με ένα φυσικό σύστημα. Εν προκειμένω, ο RARS συμπεριφέρεται σαν ένα τσιπάκι RISC-V από την άποψη των περιεχομένων των καταχωρητών και της μνήμης μετά την εκτέλεση κάθε εντολής· από την άλλη μεριά, πάντως, δεν δίνει καμία πληροφορία, π.χ., για το χρόνο εκτέλεσης της κάθε εντολής (ποιες εντολές εκτελούνται γρήγορα και ποιες αργά), όπως και για άλλες απόψεις του φυσικού συστήματος.

Οδηγίες: κατεβάστε τη νεότερη σταθερή έκδοση, 1.5, από το directory github.com/TheThirdOne/rars/releases/tag/v1.5 –δηλαδή το αρχείο rars1_5.jar που βρίσκεται στα assets, από το σύνδεσμο → github.com/TheThirdOne/rars/releases/download/v1.5/rars1_5.jar

Αν το πρόγραμμα τρέξει κανονικά, θα δείτε την αρχική οθόνη με τα 3 βασικά παράθυρα, τους Registers δεξιά, και αριστερά 2 tabs, το Edit και το Execute, και κάτω άλλα 2 tabs, το Messages και το Run I/O. Μπορεί τα παράθυρα να είναι minimized ή να μην φαίνονται καλά· αν υπάρχει τέτοιο πρόβλημα προσπαθήστε να κλικάρετε μερικές φορές.

Άσκηση 1.5:   Κώδικας Γνωριμίας με τον RARS

Αντικείμενο της παρούσας άσκησης είναι να γνωριστείτε με τη γλώσσα Assembly του RISC-V και με τη χρήση του RARS. Για το σκοπό αυτό, μελετήστε και αντιγράψτε σε ένα αρχείο (π.χ. "ex01.asm") τον παρακάτω κώδικα –ή διάφορες παραλλαγές του που προτιμάτε– και τρέξτε τον στον RARS.
     .text  # Directive ".text": put the following into program memory
            # Register use:  x6: variable "i"; x7: variable "k";
main:                      # label "main" = address for "j" to jump to
     addi   x6, x0,  10    # init. i=10; (x0==0 always)
     addi   x7, x0,  64    # init. k=64; (64 decimal = 40 hex)
     add    x28, x6, x7    # x28 := i+k = 74 dec = 4a hex
     add    x28, x28, x28  # x28 := 74+74=148 dec = 94 hex
     add    x28, x28, x7   # x28 := 148+64=212 dec = d4 hex
     addi   x7, x7, -1     # k := k-1 = 63 dec = 3f hex
     sub    x7, x7, x6     # k := k-i = 53 dec = 35 hex
     j      main           # jump back to main (infinite loop)
Ξεκινήστε τον RARS με τον τρόπο που είπαμε παραπάνω, στην §1.4. Χρησιμοποιήστε τη δυνατότητα "single step" για να εκτελούνται μια-μια οι εντολές και να τις βλέπετε. Παρακολουθήστε ότι μετά από κάθε τέτοια προσομοίωση ο PC έχει αυξηθεί κατά 4 (επειδή οι εντολές του RISC-V έχουν μέγεθος 4 Bytes καθεμία), και ότι αλλάζουν οι τιμές (περιεχόμενα) των καταχωρητών όπου γράφει η κάθε εντολή. Τα περιεχόμενα αυτά ο RARS τα δείχνει στο δεκαεξαδικό by default, αν και αυτό μπορείτε να το αλλάξετε από τα "Settings". Όταν η εκτέλεση φτάσει στην (ψεύδο)εντολή j main, παρατηρήστε ότι ο PC παίρνει ξανά την τιμή 00400000 (δεκαεξαδικό), και ξαναρχίζει η εκτέλεση του ίδιου προγράμματός μας, από την αρχή.

1.6   Ο εφεδρικός προσομοιωτής Venus:

Εάν δεν καταφέρετε να εγκαταστήσετε την Java και τον RARS στον υπολογιστή σας, μπορείτε εναλλακτικά να χρησιμοποιήσετε έναν παρόμοιο προσομοιωτή, ονόματι Venus, που βρίσκεται προεγκατεστημένος και τρέχει έτοιμος μέσω του web browser σας στη διεύθυνση: www.kvakil.me/venus/
Κάντε copy-paste το πρόγραμμά σας στην καρτέλα "Editor", και αυτόματα, μόλις πάτε στην άλλη καρτέλα, "Simulator", το πρόγραμμά σας είναι έτοιμο assembled και μπορείτε να το τρέξετε βήμα-βήμα ("Step") (το "Run" δεν δείχνει τίποτα ιδιαίτερο, λόγω του άπειρου βρόχου). Μερικές οδηγίες χρήσης, εάν χρειαστείτε, υπάρχουν στο: github.com/kvakil/venus/wiki . Πάντως, ο προσομοιωτής Venus έχει λιγότερες δυνατότητες από τον RARS –ιδιαίτερα δεν έχει environment (system) calls γιά να διαβάζει είσοδο από το πληκτρολόγιο– επομένως δεν θα μπορέσει να σας εξυπηρετήσει σε επόμενες ασκήσεις που θα χρειάζονται τέτοια είσοδο.

Τρόπος Παράδοσης:
Κάντε αυτή την άσκηση γιά να μάθετε τη χρήση του RARS, τον οποίο θα χρειαστείτε στις επόμενες ασκήσεις. Φέτος δεν θα βαθμολογηθεί αυτή η πρώτη σειρά ασκήσεων, άρα δεν έχετε να παραδώσετε τίποτα (αλλά μην καθυστερήσετε να την κάνετε, διότι ακολουθούν οι άλλες...).


© copyright University of Crete, Greece. Last updated: 17 Feb. 2021 by M. Katevenis.