Arqitektonik Upologist n Mìsqoglou Stulianìc stelios@moschoglou.com AEM: 6978 1 IounÐou 2010 Proptuqiakìc Hlektrolìgoc Mhqanikìc & Mhqanikìc Upologist n, A.P.J. 1
ΠΕΡΙΕΧ ΟΜΕΝΑ 2 Perieqìmena 1 Πρόλογος 3 2 Ανάλυση μικροεντολών 3 2.1 Αρχείο ijvm.conf........................... 3 2.2 Αρχείο mic1ijvm.mal......................... 4 3 Ανάλυση μακροεντολών 5 3.1 Αρχείο project2.jas.......................... 5 4 Εικονική παρουσίαση 9 5 Επίλογος 9
1 ΠΡ ΟΛΟΓΟΣ 3 1 Prìlogoc Το παρόν έγγραϕο δημιουργήθηκε με L A TEX2ε. Αϕορά την εποπτική παρουσίαση της δεύτερης εργασίας στα πλαίσια του μαθήματος Αρχιτεκτονικής Υπολογιστών. Στόχος της εργασίας είναι η υλοποίηση του πολλαπλασιασμού δύο ακέραιων αριθμών, σύμϕωνα με τον αλγόριθμο του Booth. 2 Anˆlush mikroentol n Στο συγκεκριμένο μέρος, θα αναλύσουμε τις τροποποιήσεις που έχουμε κάνει σε επίπεδο μικροεπεξεργαστή (mic1) και οι οποίες διευκόλυναν κατά πολύ την επίλυση του προβλήματος. Για λόγους πλουραλισμού, αξίζει να αναϕερθεί ότι το πρόβλημα υλοποιείται και χωρίς τη δημιουργία επιπλέον μικροεντολών. Σε αυτή την περίπτωση όμως ο επεξεργαστής θα χρειαστεί να εκτελέσει περισσότερους κύκλους (cycles) για να εμϕανίσει το τελικό αποτέλεσμα. 2.1 ArqeÐo ijvm.conf Ουσιαστικά, η μόνη επιπλέον εντολή που προσθέσαμε ήταν η SHIFTR, η οποία το μόνο που κάνει είναι η δεξιά ολίσθηση του εκάστοτε αριθμού που βρίσκεται στον καταχωρητή TOS κατά ένα bit. Ως γνωστόν, το αρχείο ijvm.conf είναι το configuration file, δηλαδή το αρχείο όπου δηλώνονται όλες οι εντολές του μικροπρογραμμάτος, μαζί με τις διευθύνσεις τους. Σημείωση: Η διεύθυνση που δηλώνεται δίπλα από κάθε εντολή είναι η πρώτη από την οποία ξεκινάει ώστε να την εκτελέσει. Γενικά, οι επόμενες διευθύνσεις είναι τυχαίως επιλεγμένες από τον μικροεπεξεργστή (randomly chosen). Στο ήδη υπάρχον ijvm.conf αρχείο, προσθέσαμε στο τέλος την εξής γραμμή: 0x1D SHIFTR // shifts a word one bit right Προσοχή! Οπως θα δείτε και στο αρχείο ijvm.conf, η συγκεκριμένη διεύθυνση που δηλώσαμε (0x1D), δείχνει μόνο στην SHIFTR και πουθενά αλλού. Σε διαϕορετική περίπτωση, θα είχαμε εμπλοκή (conflict).
2 ΑΝ ΑΛΥΣΗ ΜΙΚΡΟΕΝΤΟΛ ΩΝ 4 2.2 ArqeÐo mic1ijvm.mal Το συγκεκριμένο αρχείο είναι αυτό που περιέχει τις μικροεντολές και το οποίο είναι ο πυρήνας ουσιαστικά για τα όποια προγράμματα γράϕουμε σε *.jas μορϕή, αϕού χωρίς το μικροπρόγραμμα καμία λειτουργία δε μπορεί να εκτελεστεί. Ως γνωστόν, εδώ είναι που δηλώνονται εκτενώς όλες οι μικροεντολές, όπως οι BI- PUSH, POP,.... Εμείς το ήδη υπάρχον αρχείο το τροποποιούμε ώστε να συμπεριλά ουμε και την SHIFTR. Κάνουμε τις εξής προσθήκες: α) Στην αρχή του αρχείου, όπου δηλώνονται τα labels (δηλαδή οι μικροεντολές και οι διευθύνσεις στις οποίες δείχνουν):.label in1 0xFC.label shiftr1 0x1D // default instruction to place in any // unused addresses of the control store.default goto err1 Ωραία λοιπόν, δηλώσαμε την SHIFTR. Τώρα, ας την ορίσουμε κιόλας! β) Ορίζουμε την εντολή στο τέλος του αρχείου με τις εξής προσθήκες: shiftr1 shifrt2 shiftr3 MAR=SP;rd H=TOS MDR=TOS=H>>1;wr;goto Main1 Με την εντολή MAR=SP;rd, κάνουμε ανάγωση της πρώτης λέξης από τη στοίβα. Συγκεκριμένα, ο καταχωρητής MAR (Memory Access Register) είναι αυτός που είναι υπεύθυνος για τις διευθυνσιοδοτήσεις. Από την άλλη, ο καταχωρητής SP (Stack Pointer) είναι αυτός που μας δείχνει στην πρώτη λέξη της στοίβας. Στη συνέχεια, στον καταχωρητή H εκχωρείται η κορυϕή της στοίβας, μέσω του καταχωρητή TOS (Top of Stack). Τέλος, ο καταχωρητής MDR (Memory Data Register), αλλά και ο TOS παίρνουν την τιμή του καταχωρητή H, ολισθημένου κατά ένα bit δεξία (η εντολή H >> 1 αυτό ακριβώς δηλώνει).
3 ΑΝ ΑΛΥΣΗ ΜΑΚΡΟΕΝΤΟΛ ΩΝ 5 3 Anˆlush makroentol n Τώρα, είμαστε σε θέση να αρχίσουμε να γράϕουμε το μακροπρόγραμμά μας. Σημειώνουμε πως ακολουθήσαμε το sample του κώδικα, όπως έχει δοθεί στο e- thmmy. Σε αυτό το μέρος της θεωρητικής ανάλυσης, θα δούμε τι ακριβώς γρά- ϕουμε στο αρχείο project2.jas, το οποίο αργότερα θα κάνουμε compile, για να λάβουμε τελικώς το αρχείο project2.ijvm, το οποίο και θα τρέξουμε στον simulator, για να ελένξουμε αν ο κώδικας που έχουμε γράψει είναι σωστός και να κάνουμε το debug. 3.1 ArqeÐo project2.jas Ξεκινάμε τον κώδικά μας, όπως είναι ήδη γνωστό από άλλες γλώσσες προγραμματισμού, με τη δήλωση των σταθερών. Στην προκειμένη περίπτωση σταθερές είναι οι δύο ακέραιοι αριθμοί, των οποίων το γινόμενο επιθυμούμε να βρούμε. Ας διαλέξουμε τυχαία τους αριθμούς 124 και -8..constant a 124 b -8 OBJREF 0x40 d1 10000 d2 1000.end-constant Αϕού αρχίσουμε να γράϕουμε το κύριο μέρος του κώδικά μας, το πρώτο πράγμα που κάνουμε είναι να δηλώσουμε τα ονόματα των μεταβλητών που πρόκειται να χρησιμοποιήσουμε καθοδόν. Αυτά είναι multiplicand, multiplier, result. Οι μεταβλητές multiplicand, multiplier είναι αυτές που εκπροσωπούν τους αριθμούς 124, 8, αντίστοιχα. Τέλος, η μεταβλητή result είναι το αποτέλεσμα που τελικά είναι και η απάντηση στη λύση του γρίϕου μας..main.var multiplicand multiplier result.end-var Στη συνέχεια, μεταϕορτώνουμε τις σταθερές 124, 8 στις μεταβλητές multiplicand, multiplier, αντίστοιχα. Καλούμε έπειτα τη μέθοδο multiplication, που θα εκτελέσει τον πολλαπλασιασμό και αϕού επιστρέψουμε από τη μέθοδο, αποθηκεύουμε το αποτέλεσμα στη μεταβλητή result. Τέλος, τη ϕορτώνουμε στη στοίβα, καλούμε τη μέθοδο print sdec και την τυπώνουμε.
3 ΑΝ ΑΛΥΣΗ ΜΑΚΡΟΕΝΤΟΛ ΩΝ 6 start: LDC_W a ISTORE multiplicand LDC_W b ISTORE multiplier LDC_W OBJREF INVOKEVIRTUAL multiplication ISTORE result LDC_W OBJREF ILOAD result INVOKEVIRTUAL print_sdec POP HALT.end-main Τώρα, θα ορίσουμε τη μέθοδο multiplication, που εκτελεί τον πολλαπλασιασμό. Αρχικά, κι εδώ δηλώνουμε μεταβλητές, οι οποίες είναι οι count, result. Η μεταβλητή count είναι ο μετρητής του label mult loop που ακολουθεί, ενώ η result, είναι το τελικό αποτέλεσμα, που θα μεταϕορτώσουμε στο κυρίως πρόγραμμα..method multiplication(multiplicand, multiplier).var count result.end-var Μεταβαίνουμε στο label initialize mult. Αρχικοποιούμε το result σε 0, μέσω των εντολών BIPUSH, ISTORE. Επίσης, αρχικοποιούμε και τον count σε 8, μιας και μιλάμε για 8bit ακέραιους αριθμούς. Τέλος, ϕορτώνουμε τον multiplier στη μέθοδο. Συγκρίνουμε αν είναι < 0 μέσω της εντολής IFLT και αν είναι, πηγαίνουμε στο label negate. Αν δεν είναι, συνεχίζουμε στο label mult loop. initialize_mult: BIPUSH 0 ISTORE result BIPUSH 8 ISTORE count IFLT negate
3 ΑΝ ΑΛΥΣΗ ΜΑΚΡΟΕΝΤΟΛ ΩΝ 7 Μπαίνουμε στο label mult loop. Θέτουμε το 1 στην κορυϕή της στοίβας, μέσω της εντολής BIPUSH. Φορτώνουμε τον multiplier μέσω της εντολής ILOAD και συγκρίνουμε λογικά το 1 με τον multiplier, μέσω της εντολής IAND. Αν το αποτέλεσμα της λογικής σύγκρισης είναι 0, μέσω της εντολής IFLT, πηγαίνουμε στο label shift values. Σε διαϕορετική περίπτωση (δηλαδή αν το αποτέλεσμα είναι 1), συνεχίζουμε κανονικά στο label add. mult_loop: BIPUSH 1 IAND IFEQ shift_values Τώρα, ϕορτώνουμε το result και multiplier, μέσω της εντολής ILOAD και τα προσθέτουμε μέσω της εντολής IADD. add: ILOAD result IADD ISTORE result Συνεχίζουμε με το label shift values. Εδώ, αρχικά ϕορτώνουμε κατά τα γνωστά τον multiplier και τον ολισθένουμε δεξιά κατά ένα bit μέσω της εντολής SHIFTR που ορίσαμε ανωτέρω. Στη συνέχεια τον αποθηκεύουμε. Κατόπιν, ϕορτώνουμε τον multiplicand δύο ϕορές και το άθροισμα αυτό μέσω της εντολής IADD, το α- ποθηκεύουμε στον multiplicand. Στη συνέχεια, αϕού ϕορτώσουμε τον count, τον μειώνουμε κατά ένα μέσω των εντολών BIPUSH και ISUB. Τον αποθηκεύουμε και τον ξαναϕορτώνουμε. Ελέγχουμε αν είναι 0 μέσω της εντολής IFEQ. Αν είναι, τότε μεταβαίνουμε στο label end of multiplication. Αν δεν είναι, επιστρέϕουμε στο label mult loop. shift_values: SHIFTR ISTORE multiplier IADD ISTORE multiplicand ILOAD count BIPUSH 1 ISUB
3 ΑΝ ΑΛΥΣΗ ΜΑΚΡΟΕΝΤΟΛ ΩΝ 8 ISTORE count ILOAD count IFEQ end_of_multiplication GOTO mult_loop Το προτελευταίο label είναι το label negate. Σε αυτό, αντιστρέϕουμε τους αριθμούς, αν ο multiplicand είναι μικρότερος του 0. Συγκεκριμένα, αυτό το πετυχαίνουμε θέτοντας το 0 στη στοίβα μέσω της εντολής BIPUSH, ϕορτώνοντας εν συνεχεία τον multiplicand και κάνοντας την αϕαίρεση μέσω της εντολής I- SUB. Εντελώς αντίστοιχη διαδικασία εκτελούμε και με τον multiplier. Τελικά, επιστρέϕουμε στο label mult loop. negate: BIPUSH 0 ISUB ISTORE multiplicand BIPUSH 0 ISUB ISTORE multiplier GOTO mult_loop Το τελευταίο label που μας απομένει για να οριστεί πλήρως η μέθοδος είναι το label end of multiplication. Στο συγκεκριμένο label ϕορτώνουμε το result και μέσω της εντολής IRETURN επιστρέϕουμε τη συγκεκριμένη τιμή στο κυρίως πρόγραμμα. end_of_multiplication: ILOAD result IRETURN Στο τέλος του αρχείου υπάρχει ορισμένη μία ακόμη μέθοδος, η sdec. Ουσιαστικά είναι η μέθοδος udes, απλώς τροποποιημένη έτσι στο μέρος του label neg number, ώστε να δίνει αποτέλεσμα και για αρνητικούς αριθμούς. Συγκεκριμένα, η επεξεργασία που κάναμε σε αυτό το label ήταν αρχικά να τυπώσουμε τον χαρακτήρα ASCII για το, ώστε να υποδεικνύει ακριβώς αυτό: ότι το αποτέλεσμα είναι αρνητικός αριθμός. Στη συνέχεια, αντιστρέϕουμε το res για να γίνει θετικός. Αυτό το πετυχαίνουμε ϕορτώνοντας αρχικά το 0 στη στοίβα μέσω της εντολής BIPUSH, ϕορτώνοντας το res μέσω της εντολής ILOAD και τέλος κάνοντας την αϕαίρεση μέσω της εντολής ISUB. Τελικώς, επιστρέϕουμε στο label loop1.
4 ΕΙΚΟΝΙΚ Η ΠΑΡΟΥΣ ΙΑΣΗ 9 neg_number: BIPUSH 0x2D OUT BIPUSH 0 ILOAD res ISUB ISTORE res GOTO loop1 4 Eikonik parousðash Το αποτέλεσμα του προγραμμάτος εικονικά ϕαίνεται παρακάτω: Και όπως παρατηρούμε, είναι το σωστό, μιάς και... 124*(-8)=-992! 5 EpÐlogoc Στα αρχεία που θα βρείτε μέσα στο *.zip, περιλαμβάνονται σε όλα σχόλια (comments) δίπλα στον κώδικα, όπου χρειάζονται. Οσον αϕορά τον IJVM, υπάρχει μια πλούσια πηγή πληροϕοριών στην επίσημη ιστοσελίδα της SUN. Ευχαριστώ για το χρόνο που διαθέσατε να τη διαβάσετε. Οποιαδήποτε επισήμανση είναι ευπρόσδεκτη.