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

Σειρά Ασκήσεων 2:
Βρόχοι και Επικοινωνία Κονσόλας στον RARS

Προθεσμία έως Κυρ. 28 Φεβρουαρίου 2021, ώρα 23:59 (βδομάδα 2.4) (από βδ. 2.1)
[Up: Table of Contents]
[Prev - 1. Assembly Introduction]

[3. Memory Accesses - Next]

2.1   Ολίγα περί Εντολών Διακλάδωσης υπό Συνθήκη

Όπως λέγαμε και στην §
1.3, για να εκτελεστεί ένα πρόγραμμα, οι εντολές του γράφονται στην κεντρική μνήμη η μία "κάτω" από την άλλη, δηλαδή σε συνεχόμενες θέσεις (διευθύνσεις) μνήμης. Μετά την ανάγνωση και εκτέλεση μιας εντολής, ο επεξεργαστής αυξάνει τον PC κατά το μέγεθος της εντολής που εκτελέστηκε (κατά 4 στον βασικό RISC-V, αφού οι εντολές του έχουν μέγεθος 4 Bytes), οπότε αυτός (ο PC) δείχνει στην επόμενη (την "από κάτω") εντολή. Η σειριακή αυτή εκτέλεση εντολών διακόπτεται όταν εκτελείται μιά εντολή μεταφοράς ελέγχου (CTI - control transfer instruction). Είδαμε ήδη μία τέτοια, την (ψεύδο)εντολή άλματος j label ("jump" to label), που κάνει ώστε η επόμενη εντολή που θα εκτελεστεί να είναι η εντολή στη διεύθυνση μνήμης label, αντί να είναι η "από κάτω" εντολή. Με άλλα λόγια, η (ψεύδο)εντολή j label φορτώνει τη διεύθυνση label στον καταχωρητή PC. Χρησιμοποιώντας αυτήν στην άσκηση 1 φτιάξαμε έναν "άπειρο βρόχο", δηλαδή κάναμε τον υπό προσομοίωση υπολογιστή να εκτελεί συνεχώς το ίδιο "μπλόκ" εντολών.

Γιά να φτιάξουμε έναν κανονικό (όχι άπειρο) βρόχο χρειαζόμαστε μια εντολή διακλάδωσης υπό συνθήκη (conditional branch), δηλαδή μια εντολή που μερικές φορές προκαλεί διακλάδωση και μερικές φορές όχι, ανάλογα με το αν ισχύει ή δεν ισχύει κάποια κατάλληλη συνθήκη. Η βασική τέτοια εντολή είναι η beq (branch if equal): Η εντολή "beq x26, x27, label" διαβάζει τους καταχωρητές 26 και 27, και τους συγκρίνει. Εάν τους βρει ίσους (equal) διακλαδίζεται στη θέση label, δηλαδή κάνει τον επεξεργαστή να διαβάσει και εκτελέσει την εντολή από εκείνη τη διεύθυνση σαν επόμενη εντολή. Αλλιώς, δεν κάνει τίποτα το ξεχωριστό, οπότε σαν επόμενη εντολή θα διαβαστεί και εκτελεστεί η "από κάτω" εντολή. Η εντολή bne (branch if not equal) κάνει τα ανάποδα, δηλαδή διακλαδίζεται εάν βρει τους καταχωρητές άνισους (not equal), αλλιώς συνεχίζει "από κάτω".

2.2   Κώδικας Βρόχου και Εισόδου/Εξόδου Κονσόλας

Για να επικοινωνούν τα προγράμματα που τρέχουμε στον RARS με τον έξω κόσμο, ο RARS προσομοιώνει μερικές υποτυπώδεις υπηρεσίες λειτουργικού συστήματος για είσοδο/έξοδο (I/O) στην "κονσόλα" (ένα απλό τερματικό ASCII). Οι κλήσεις στο λειτουργικό σύστημα λέγονταν παραδοσιακά "system call", αλλά ο RISC-V υιοθετεί το γενικότερο όνομα "environment call (ecall)" διότι μπορούν να χρησιμοποιηθούν και γιά την κλήση άλλων περιβαλλόντων ελέγχου (π.χ. hypervisor κλπ). Δεν είναι ανάγκη προς στιγμήν να καταλάβετε όλες τις λεπτομέρειες του πώς γίνονται αυτές οι κλήσεις –αρκεί να μιμηθείτε το παρακάτω παράδειγμα και να καταλάβετε τις εξηγήσεις που δίνονται κάτω από αυτό. Μελετήστε και αντιγράψτε σε ένα αρχείο (π.χ. "ex02.asm") τον παρακάτω κώδικα –ή διάφορες παραλλαγές του που προτιμάτε– και τρέξτε τον στον RARS:

                # compute s = 1+2+3+...+(n-1),  for n>=2
                # register x26: n
                # register x27: s
                # register x28: i

        .data           # init. data memory with the strings needed:
str_n:  .asciz "n = "
str_s:  .asciz "       s = "
str_nl: .asciz "\n"

        .text           # program memory:

main:                       # (1) PRINT A PROMPT:
        addi    x17, x0, 4      # environment call code for print_string
        la      x10, str_n      # pseudo-instruction: address of string
        ecall                   # print the string from str_n
                            # (2) READ n (MUST be n>=2 --not checked!):
        addi    x17, x0, 5      # environment call code for read_int
        ecall                   # read a line containing an integer
        add     x26, x10, x0    # copy returned int from x10 to n
                            # (3) INITIALIZE s and i:
        add     x27, x0, x0     # s=0;
        addi    x28, x0, 1      # i=1;
loop:                       # (4) LOOP starts here
        add     x27, x27, x28   # s=s+i;
        addi    x28, x28, 1     # i=i+1;
        bne     x28, x26, loop  # repeat while (i!=n)
                            #     LOOP ENDS HERE
                            # (5) PRINT THE RESULT:
        addi    x17, x0, 4      # environment call code for print_string
        la      x10, str_s      # pseudo-instruction: address of string
        ecall                   # print the string from str_s
        addi    x17, x0, 1      # environment call code for print_int
        add     x10, x27, x0    # copy argument s to x10
        ecall                   # print the integer in x10 (s)
        addi    x17, x0, 4      # environment call code for print_string
        la      x10, str_nl     # pseudo-instruction: address of string
        ecall                   # print a new-line
                            # (6) START ALL OVER AGAIN (infinite loop)
        j       main            # unconditionally jump back to main
Ο κώδικας αυτός υπολογίζει το άθροισμα s=1+2+3+...+(n-1), για n μεγαλύτερο ή ίσο του 2 --προσοχή: αν δοθεί n μικρότερο του 2, ο κώδικας θα μπει σε (σχεδόν) άπειρο βρόγχο! Η "καρδιά" του κωδικά είναι τα κομμάτια (3) --αρχικοποιήσεις-- και (4) --βρόγχος υπολογισμού. Προσέξτε τις παρακάτω εξηγήσεις:

Άσκηση 2.3:   Τρέξιμο στον RARS

Εάν δεν σας δουλεύει ο RARS και πρέπει να χρησιμοποιήστε τον Venus:
Εάν δεν καταφέρατε να εγκαταστήσετε την Java και τον RARS, και θέλετε να κάνετε αυτή την άσκηση με τον
www.kvakil.me/venus/ που λέγαμε στην §1.5, θα πρέπει να κάνετε τρείς αλλαγές στο πρόγραμμα σας: Πρώτον, η οδηγία ".asciz" του RARS γράφεται με δύο "i" στον Venus: ".asciiz". Δεύτερον, ο κωδικός του ecall περνιέται μέσω του καταχωρητή x10 στον Venus (αντί μέσω του x17 στον RARS), και το όρισμα (argument) του ecall περνιέται μέσω του x11 στον Venus (αντί μέσω του x10 στον RARS) –δείτε τις οδηγίες στο github.com/kvakil/venus/wiki (item: Environmental Calls). Και τρίτον, ο Venus δεν έχει ecall γιά ανάγνωση εισόδου (user input), άρα στη θέση του read_int ecall θα πρέπει να γράψετε μιάν εντολή π.χ. addi x26, x0, 77 που να αρχικοποιεί π.χ. n=77, και κάθε φορά που θέλετε να τρέξετε το πρόγραμμά σας με άλλη τιμή του n να αλλάζετε με τον Editor το "77" μέσα στο πρόγραμμα στη νέα τιμή που θέλετε.

Τρόπος Παράδοσης:
Θα παραδώσετε ηλεκτρονικά ένα στιγμιότυπο της οθόνης καθώς τρέχετε το πρόγραμμα "RARS" και αυτό βρίσκεται σ' ένα "ενδιαφέρον" ενδιάμεσο breakpoint της επιλογής σας (όχι στην αρχή και όχι στο τέλος του προγράμματος). Το στιγμιότυπο μπορείτε να το πάρετε π.χ. όπως παρακάτω, θα το ονομάσετε ex02.jpg, και θα το παραδώσετε ως εξής:

Γιά να παραδώσετε τις ασκήσεις σας γενικά και αυτήν εδώ ειδικά, συνδεθείτε σε ένα μηχάνημα Linux του Τμήματος. Ετοιμάστε ένα directory με το(α) αρχείο(α) που σας ζητάει η άσκηση. Ας υποθέσουμε ότι το όνομα του directory είναι [somepath]/mydir. Μετακινηθείτε στο directory [somepath], και εκτελέστε την εντολή:
          turnin ex02@hy225 mydir
Η διαδικασία turnin θα σας ζητήσει να επιβεβαιώσετε την αποστολή των αρχείων. Περισσότερες πληροφορίες και αναλυτικές οδηγίες για τη διαδικασία turnin είναι διαθέσιμες στην ιστοσελίδα
https://www.csd.uoc.gr/index.jsp?custom=use_the_turnin ή εκτελώντας man turnin σε κάποιο από τα μηχανήματα Linux του Τμήματος. Γιά επαλήθευση της υποβολής μπορείτε να εκτελέσετε: verify-turnin ex02@hy225


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