Εργαστήριο Δομής και Λειτουργίας Μικροϋπολογιστών Βοήθημα εκτέλεσης εργαστηριακής άσκησης 3: Εντολές λογικών πράξεων και εντολές κλήσης ρουτινών Άσκηση 1 (σύνοψη της εκφώνησης) [Εκτέλεση λογικών πράξεων] Φορτώστε προγραμματιστικά στον συσσωρευτή το byte 10111001B. Στη συνέχεια γράψτε πρόγραμμα το οποίο να: α) μηδενίζει τα δύο περισσότερο σημαντικά bits του συσσωρευτή, β) μετατρέπει σε άσσους τα δύο λιγότερο σημαντικά bits και γ) αντιστρέφει τα υπόλοιπα bits. Κώδικας σε φυσική γλώσσα Ξεκινήστε τη συγγραφή του προγράμματος στη διεύθυνση 0000H της ROM. Φόρτωση του συσσωρευτή με τη δυαδική τιμή 10111001Β (δηλ. τη δεκαεξαδική Β9h). Μηδενισμός των δύο περισσότερο σημαντικών bits με χρήση της εντολής ΑΝL. Μετατροπή σε άσους των δύο λιγότερο σημαντικών bits με χρήση της εντολής ORL. Αντιστροφή των υπόλοιπων bits με χρήση της εντολής XRL. Άσκηση 2 (σύνοψη της εκφώνησης) [Μια εφαρμογή των λογικών πράξεων] Να γράψετε πρόγραμμα το οποίο να μετρά το πλήθος των άρτιων αριθμών που βρίσκονται αποθηκευμένοι στις θέσεις της εσωτερικής μνήμης RAM που έχουν διευθύνσεις από 49h έως και 50h. Στην αρχή του προγράμματός σας κάντε ενεργό την ομάδα καταχωρητών 2 και αποθηκεύστε το αποτέλεσμα του προγράμματος στον καταχωρητή R1 αυτής της ομάδας. Κώδικας σε φυσική γλώσσα Ξεκινήστε τη συγγραφή του προγράμματος στη διεύθυνση 0100H της ROM. Επειδή το πρόγραμμά μας αναφέρεται σε επεξεργασία ενός μπλοκ από συνεχόμενες θέσεις μνήμης, αντιλαμβανόμαστε ότι για τη σύνταξή του θα απαιτηθεί γραφή ενός βρόχου (loop). Πιο συγκεκριμένα, τα βήματα του προγράμματος έχουν ως εξής: Επιλέξτε προγραμματιστικά την register bank 2 (με όποιον τρόπο σας είναι πιο εύκολος, για παράδειγμα με χρήση των εντολών SETB RS1, SETB RS0). 1
Ο καταχωρητής R0 θα παίξει τον ρόλο του δείκτη (pointer). Φορτώστε τον με τη μικρότερη από τις διευθύνσεις του μπλοκ που μας ενδιαφέρει. Ο καταχωρητής R2 θα παίξει τον ρόλο του μετρητή (counter). Φορτώστε τον με την τιμή που αντιστοιχεί στο πλήθος των θέσεων μνήμης του μπλοκ που μας ενδιαφέρει. Στον καταχωρητή R1 θα αποθηκεύσουμε το αποτέλεσμα του προγράμματος. Για αυτόν τον λόγο, ο R1 αρχικοποιείται με την τιμή μηδέν. LOOP: Έναρξη του βρόχου. Το περιεχόμενο της θέσης μνήμης στην οποία «δείχνει» ο R0, τοποθετείται στον συσσωρευτή. Τα 7 περισσότερο σημαντικά bit του συσσωρευτή μηδενίζονται, ενώ το λιγότερο σημαντικό bit αυτού παραμένει αμετάβλητο. Αυτό γίνεται με κατάλληλη χρήση της εντολής ANL. Αν ο συσσωρευτής εμπεριέχει αυτή τη στιγμή μη μηδενική τιμή (φυσικά, την τιμή 00000001), τότε ο αρχικός αριθμός με τον οποίο φορτώθηκε ήταν περιττός. Στην περίπτωση αυτή, προχώρα παρακάτω με την εντολή με ετικέτα NEXT (δηλ., αν ο συσσωρευτής είναι μη μηδενικός, κάνε jump στην εντολή με ετικέτα ΝΕΧΤ). Διαφορετικά (αν δηλαδή ο συσσωρευτής είναι μηδενικός), έχει εντοπιστεί άρτιος αριθμός. Στην περίπτωση αυτή, αύξησε το περιεχόμενο του καταχωρητή R1 κατά 1. ΝΕΧΤ: Ετοιμάσου για την επόμενη επανάληψη του βρόχου. Για αυτόν τον λόγο, αύξησε τον δείκτη R0 κατά 1, ώστε αυτός να δείχνει στην επόμενη θέση του μπλοκ. Ελάττωσε τον μετρητή R2 κατά 1 και, αν αυτός είναι διάφορος του μηδενός, κάνε jump στην εντολή με ετικέτα LOOP. Φτάσαμε στο τέλος του προγράμματος, κάνε άλματα επί τόπου. Τεστάρισμα Γεμίστε χειροκίνητα τις θέσεις μνήμης 49h έως 50h με τις τιμές 2Εh, C3h, 23h, AAh, EFh, 10h, 89h, EDh. Πόσοι από τους αριθμούς αυτούς είναι άρτιοι; Συμφωνεί το αποτέλεσμα του προγράμματος με την απάντησή σας; Άσκηση 3 (σύνοψη της εκφώνησης) [Προετοιμασία για την άσκηση 4] Ξεκινήστε τη συγγραφή του προγράμματος στη διεύθυνση 0200Η της ROM. Να γράψετε πρόγραμμα το οποίο να μετρά το πλήθος των άσσων του περιεχομένου του συσσωρευτή. Στην αρχή του προγράμματός σας κάντε ενεργό την ομάδα καταχωρητών 0 και αποθηκεύστε το αποτέλεσμα του προγράμματος στον καταχωρητή R0 αυτής της ομάδας. 2
Κώδικας σε φυσική γλώσσα Το ζητούμενο πλήθος άσσων θα υπολογισθεί ολισθαίνοντας σταδιακά όλα τα bits του συσσωρευτή εντός του carry flag. Για το λόγο αυτό θα απαιτηθούν οκτώ ολισθήσεις, όσα και τα bits του συσσωρευτή. Αυτές οι οκτώ ολισθήσεις θα πραγματοποιηθούν με τη βοήθεια βρόχου (loop). Αναλυτικότερα, το πρόγραμμα έχει ως εξής: Επιλέξτε προγραμματιστικά την register bank 0 (με όποιον τρόπο σας είναι πιο εύκολος). Αρχικοποίηση του R1. Ο R1 θα παίξει τον ρόλο του μετρητή (counter). Θα χρειαστούμε βρόχο με οκτώ επαναλήψεις, κάθε επανάληψη και μία ολίσθηση. Το πλήθος των υπολογιζόμενων άσσων θα σχηματιστεί προοδευτικά στον καταχωρητή R0. Για αυτόν τον λόγο, αρχικοποιούμε τον R0 μηδενίζοντάς τον. LOOP: Αρχή του βρόχου. Ολισθήστε δεξιά τον συσσωρευτή μέσω του carry flag. Αν το carry είναι μηδέν, τότε συνεχίστε με την επόμενη επανάληψη του βρόχου, κάνοντας jump στην εντολή με ετικέτα ΝΕΧΤ. Δηλ., αν το carry είναι ίσο με μηδέν, κάνε jump στην εντολή με ετικέτα ΝΕΧΤ. Διαφορετικά, δηλ. αν το carry είναι ένα, αυξήστε τον R0 κατά 1. ΝΕΧΤ: Προετοιμασία για την επόμενη επανάληψη του βρόχου. Ελαττώστε τον μετρητή R1 και αν αυτός δεν είναι μηδέν κάντε jump στην εντολή με ετικέτα LOOP. Κάντε μία ακόμη δεξιά ολίσθηση του συσσωρευτή μέσω του carry flag, ώστε ο συσσωρευτής να ανακτήσει την αρχική του τιμή (εφόσον αυτό απαιτείται). Τέλος του προγράμματος, άλματα επιτόπου. Τεστάρισμα Ελέγξτε την ορθότητα του προγράμματος, φορτώνοντας χειροκίνητα τον συσσωρευτή με την τιμή 97h. Συμφωνεί το αποτέλεσμα του προγράμματος με όσα αναμένετε θεωρητικά; Άσκηση 4 (σύνοψη της εκφώνησης) [Κλήση υπορουτίνας] Να γράψετε πρόγραμμα, το οποίο να μετρά το πλήθος των άσσων στο μπλοκ της μνήμης RAM από τη διεύθυνση 30h έως και τη διεύθυνση 34h. Ενεργός ομάδα καταχωρητών να είναι η μηδενική (προγραμματιστική επιλογή) και το αποτέλεσμα να αποθηκευθεί στον καταχωρητή R3 αυτής. Το 3
πρόγραμμα να υλοποιηθεί με τη βοήθεια υπορουτίνας, η οποία θα μετρά το πλήθος των άσσων του συσσωρευτή. Η υπορουτίνα θα κληθεί για κάθε μία από τις διευθύνσεις μνήμης της περιοχής ενδιαφέροντος. Ξεκινήστε το πρόγραμμα σας στη διεύθυνση 0300Η της ROM. Σε αυτή τη διεύθυνση θα δοθεί η ετικέτα COUNT. COUNT: Ξεκινά η υπορουτίνα. Μία καλή προγραμματιστική πρακτική για κάθε υπορουτίνα είναι η προστασία του PSW με τη φύλαξη του στο σωρό. Συνεπώς PUSH PSW. Η υπορουτίνα θα μετράει το πλήθος των άσσων του συσσωρευτή, χρησιμοποιώντας ουσιαστικά τον κώδικα της Άσκησης 3. Το αποτέλεσμα της καταμέτρησης θα το αποθηκεύει στον καταχωρητη R0 και από εκεί θα το ανασύρει το κυρίως πρόγραμμα. Η συγκεκριμένη υπορουτίνα υλοποιεί βρόχο και χρησιμοποιεί ως μετρητή του βρόχου τον καταχωρητή R1. Επειδή ο ίδιος καταχωρητής χρησιμοποιείται και από το κυρίως πρόγραμμα για άλλο σκοπό, θα πρέπει η τιμή του να προστατευθεί με την τοποθέτησή του στο σωρό. Έτσι, η επόμενη εντολή της υπορουτίνας θα είναι η PUSH 01h (ο assembler του προγράμματος προσομοίωσης θα την εμφανίσει στην οθόνη ως PUSH R1). Οι εντολές που ακολουθούν με italics έχουν ήδη υλοποιηθεί στην Άσκηση 3. Η επιλογή της ενεργού ομάδας καταχωρητών θα γίνει στο κυρίως πρόγραμμα και γι αυτόν τον λόγο, παραλείπεται στην υπορουτίνα. Αρχικοποίηση του R1. Ο R1 θα παίξει τον ρόλο του μετρητή (counter). Θα χρειαστούμε βρόχο με οκτώ επαναλήψεις, κάθε επανάληψη και μία ολίσθηση. Το πλήθος των υπολογιζόμενων άσσων θα σχηματιστεί προοδευτικά στον καταχωρητή R0. Για αυτόν τον λόγο, αρχικοποιούμε τον R0 μηδενίζοντάς τον. LOOP: Αρχή του βρόχου. Ολισθήστε δεξιά τον συσσωρευτή μέσω του carry flag. Αν το carry είναι μηδέν, τότε συνεχίστε με την επόμενη επανάληψη του βρόχου, κάνοντας jump στην εντολή με ετικέτα ΝΕΧΤ. Δηλ., αν το carry είναι ίσο με μηδέν, κάνε jump στην εντολή με ετικέτα ΝΕΧΤ. Διαφορετικά, δηλ. αν το carry flag είναι ένα, αυξήστε τον R0 κατά 1. ΝΕΧΤ: Προετοιμασία για την επόμενη επανάληψη του βρόχου. Ελαττώστε τον μετρητή R1 και, αν αυτός δεν είναι μηδέν, κάντε jump στην εντολή με ετικέτα LOOP. Κάντε μία ακόμη δεξιά ολίσθηση του συσσωρευτή μέσω του carry flag, ώστε ο συσσωρευτής να ανακτήσει την αρχική του τιμή (εφόσον αυτό απαιτείται). (Η εντολή αυτή της άσκησης 3 μπορεί παραληφθεί στην τρέχουσα άσκηση. Γιατί;) 4
(Νέος κώδικας, επιπλέον όσων είχαμε γράψει στην άσκηση 3) Στο σημείο αυτό η υπορουτίνα έχει ήδη υπολογίσει το πλήθος των άσσων του συσσωρευτή και έχει τοποθετήσει το αποτέλεσμα στον καταχωρητή R0, απ όπου και θα το «διαβάσει» το κυρίως πρόγραμμα. Συνεπώς, στο σημείο αυτό, λίγο πριν την επίσημη ολοκλήρωση της υπορουτίνας αποκαθιστούμε την τιμή του R1 που είχαμε φυλάξει στον σωρό: POP 01h (ο assembler του προγράμματος προσομοίωσης θα την εμφανίσει την οθόνη ως POP R1). Κατά παρόμοιο τρόπο αποκαθιστούμε την τιμή του PSW: POP PSW Επιστροφή από την υπορουτίνα: RET Ακολουθεί το κυρίως πρόγραμμα. Ξεκινήστε τη συγγραφή του από τη διεύθυνση 0330Η της ROM. Επιλέξτε προγραμματιστικά την register bank 0 (με όποιον τρόπο σας είναι πιο εύκολος, π.χ. CLR RS1, CLR RS0). Αρχικοποιήστε τον καταχωρητή SP (stack pointer, δείκτη σωρού) με την τιμή 70h. Η καταμέτρηση των άσσων που πραγματοποιεί το κυρίως πρόγραμμα θα πραγματοποιηθεί στον καταχωρητή R3. Για αυτόν τον λόγο, ο καταχωρητής αυτός αρχικοποιείται με την τιμή μηδέν. Ο καταχωρητής R1 θα παίξει, στο κυρίως πρόγραμμα, τον ρόλο του δείκτη (pointer). Για αυτόν το λόγο, αρχικοποιείται με τη μικρότερη από τις διευθύνσεις του μπλοκ που μας ενδιαφέρει. Ο καταχωρητής R2 θα παίξει τον ρόλο του μετρητή (counter). Αρχικοποιείται με το πλήθος των θέσεων μνήμης της περιοχής που μας ενδιαφέρει. PALI: Αρχίζει ο βρόχος! Το περιεχόμενο της θέσης μνήμης που «δείχνει» ο R1 μεταφέρεται εντός του συσσωρευτή. Καλείται η υπορουτίνα για να μετρήσει τους άσσους του συσσωρευτή: LCALL COUNT. Το αποτέλεσμα του υπολογισμού της υπορουτίνας είναι ήδη αποθηκευμένο στον καταχωρητή R0. Προετοιμαζόμαστε για πρόσθεση και τοποθετούμε το περιεχόμενο του R0 στον συσσωρευτή. Προσθέτουμε το περιεχόμενο του R3 στον συσσωρευτή. Τοποθετούμε το περιεχόμενο του συσσωρευτή στον R3. Με αυτόν τον τρόπο, η τιμή του R3 επαυξάνεται κατά το πλήθος των άσσων που μέτρησε η υπορουτίνα. Προετοιμαζόμαστε για την επόμενη επανάληψη του βρόχου: Αυξάνουμε τον δείκτη R1. 5
Ελαττώνουμε τον μετρητή R2 και, αν αυτός είναι διάφορος του μηδενός, κάνουμε jump στην εντολή με ετικέτα PALI. Διαφορετικά, το πρόγραμμα έχει τελειώσει, άλματα επί τόπου. Τεστάρισμα Πριν εκτελέσετε το πρόγραμμά σας γεμίστε χειροκίνητα την περιοχή 30h-34h της RAM με τις τιμές 49h, AEh, 12h, 89h, EEh. Συμφωνεί η θεωρητική σας προσδοκία με τα αποτελέσματα του προγράμματος; Παρατήρηση Μην ξεχνάτε ότι η μέγιστη τιμή του πλήθους των άσσων που μπορούν να βρεθούν μέσα σε 5 bytes είναι 40, συνεπώς το πλήθος των άσσων μπορεί άνετα να αποθηκευθεί εντός του καταχωρητή R3 χωρίς υπερχείλιση. 6