ΑΡΙΣΤΟΤΕΛΕΙΟ ΠΑΝΕΠΙΣΤΗΜΙΟ ΘΕΣΣΑΛΟΝΙΚΗΣ ΣΧΟΛΗ ΘΕΤΙΚΩΝ ΕΠΙΣΤΗΜΩΝ ΤΜΗΜΑ ΦΥΣΙΚΗΣ ΤΟΜΕΑΣ ΗΛΕKΤΡΟΝΙΚΗΣ ΚΑΙ ΗΛΕΚΤΡΟΝΙΚΩΝ ΥΠΟΛΟΓΙΣΤΩΝ ΠΤΥΧΙΑΚΗ ΕΡΓΑΣΙΑ Σχεδιασμός επεξεργαστή RISC με VHDL MΕΡΕΤΗΣ ΕΥΑΓΓΕΛΟΣ-ΓΕΩΡΓΙΟΣ Επιβλέπων καθηγητής: κ. Νικολαΐδης Σπυρίδων ΘΕΣΣΑΛΟΝΙΚΗ 2017 1
Ευχαριστίες Για την ολοκλήρωση της πτυχιακής εργασίας θα ήθελα να ευχαριστήσω θερμά για την πολύτιμη καθοδήγηση και την αμέριστη βοήθεια σε κάθε στάδιο της εργασίας τον επιβλέποντα καθηγητή κ. Νικολαΐδη Σπυρίδων. Ευχαριστώ θερμά τον συμφοιτητή Εμμανουηλίδη Αλέξανδρο για την βοήθεια του σε θέματα υπολογιστικού προγραμματισμού και γραφικού περιβάλλοντος. Επίσης ευχαριστώ από καρδιάς την οικογένεια μου, για την υλική και ηθική υποστήριξη σε όλη τη διάρκεια των σπουδών μου. 2
ΤΙΤΛΟΣ: Σχεδιασμός επεξεργαστή RISC με VHDL ΠΕΡΙΛΗΨΗ: Για την παρούσα πτυχιακή εργασία υλοποιήθηκε ένας επεξεργαστής ο οποίος επεξεργάζεται δεδομένα των 16 bit. Η αρχιτεκτονική του βασίζεται στην RISC αρχιτεκτονική (Reduced Instruction Set Architecture) και πιο συγκεκριμένα υλοποιείται με αρχιτεκτονική συνόλου εντολών τύπουmips. Η αρχιτεκτονική συνόλου εντολών της συγκεκριμένης μονάδας επεξεργασίας περιγράφεται αναλυτικά στο πρώτο κεφάλαιο. Στη συνέχεια περιγράφεται η συνολική λειτουργία της μονάδας επεξεργασίας και παρουσιάζεται ως συνολικό κύκλωμα με τη μορφή σχηματικού διαγράμματος.έπειτα περιγράφονται πλήρως όλες οι επιμέρους μονάδες που αποτελούν τον επεξεργαστή. Για την καλύτερη λειτουργία και για βελτίωση της απόδοσης η υλοποίηση πραγματοποιήθηκε με εκτέλεση των εντολών σε στάδια δηλαδή για την ολοκλήρωσή της κάθε μιας απαιτείται πάνω από ένας κύκλος ρολογιού. Η τεχνική αυτή αναλύεται εκτενώς καθώς και ο τρόπος που επηρεάζει τη σχεδίαση, κυρίως τη μονάδα ελέγχου. Για την υλοποίηση χρησιμοποιήθηκε η γλώσσα περιγραφής υλικού VHDL (VHSIC Hardware Description Language). Το λογισμικό το οποίο χρησιμοποιήθηκε για την αναπαράσταση σε VHDL είναι η πλατφόρμα ISE Design (14.7 edition) της Xilinx. Για το σχεδιασμό τον σχηματικών διαγραμμάτων χρησιμοποιήθηκε το πρόγραμμα SmartDraw Software. Στις τελευταίες σελίδες της πτυχιακής εργασίας δίνεται ο κώδικας σε VHDL. TITLE: RISC processor design with VHDL ABSTRACT: For this thesis, a processor has been implemented that processes 16-bit data. Its architecture is based on RISC architecture (Reduced Instruction Set Architecture) and more specifically it is implemented with MIPS-style instruction set architecture. The instruction set architecture of this processing unit is described in detail in chapter one. After that, the overall operation of the processing unit is described and represented as a complete circuit in the form of a block diagra. Consequently all the individual components that compose the processor are fully described. To succeed better operation and performance improvement, implementation was accomplished by executing the instructions in stages, that means more than one clock cycle is required for an instruction to complete. This technique is thoroughly analyzed along with the way that it affects the design, especially the control unit. For the implementation, the hardware description language that has been used is VHDL (VHSIC hardware description language). The software that was used to represent the design with VHDL is the Xilinx ISE Design (14.7 edition) platform. SmartDraw Software was used to design the block diagrams. The code in VHDL is given in the last thesis' pages. 3
ΠΕΡΙΕΧΟΜΕΝΑ Εισαγωγή...5 Κεφ.1: Αρχιτεκτονική συνόλου εντολών...7 Κεφ.2: Κύκλος εντολής και συνολικό κύκλωμα επεξεργαστή...11 2.1 Κύκλος εντολής...11 2.2 Μονάδα ελέγχου/ Control unit...11 2.3 Συνολικό κύκλωμα μονάδας επεξεργασίας...13 Κεφ.3: Περιγραφή των επιμέρους μονάδων...15 3.1 Αριθμητική/λογική μονάδα και μονάδα ολίσθησης...15 3.2 Αποκωδικοποιητής εντολών/ Instruction decoder...18 3.3 Μετρητής προγράμματος/ Program counter...21 3.4 Καταχωρητές γενικού σκοπού/ Register file...22 3.5 Μνήμη δεδομένων/ Data memory...26 Κεφ.4: Δοκιμή του επεξεργαστή...27 4.1 Προσομοίωση Εντολών..27 4.2 Χρήση κυκλωμάτων του τσιπ..33 Παράρτημα: Κώδικας σε VHDL...34 i. Arithmetic - logic unit/ ALU...34 ii. Instruction decoder...38 iii. Program counter...41 iv. Register file...42 v. Ram...43 vi. Control unit...45 vii. Processing unit - Top module...46 viii. Test bench...50 Κατάλογος σχημάτων...57 Βιβλιογραφία/ Πηγές...58 4
ΕΙΣΑΓΩΓΗ Στη σύγχρονη εποχή τα ψηφιακά ηλεκτρονικά συστήματα χρησιμοποιούνται ευρέως. Όσο η τεχνολογία εξελίσσεται όλο και περισσότερες συσκευές αποκτούν κάποια υπολογιστική ικανότητα με αποτέλεσμα να υπάρχει συνεχώς η ανάγκη για σχεδίαση πιο γρήγορων, πιο οικονομικών και συνολικά αποδοτικότερων υπολογιστικών μονάδων. Οι επεξεργαστές είναι από τα πιο σημαντικά στοιχεία ενός υπολογιστή και όλων των υπολογιστικών συστημάτων γενικότερα. Η κεντρική μονάδα επεξεργασίας - ΚΜΕ (central processing unit - CPU) είναι το πιο σημαντικό στοιχείο για έναν ηλεκτρονικό υπολογιστή μαζί με τη μνήμη και την μονάδα εισόδου/εξόδου. Είναι το σύστημα το οποίο επεξεργάζεται δεδομένα, ελέγχει τη λειτουργία ενός υπολογιστή και διαχειρίζεται τις εντολές. Επεξεργαστές βρίσκονται ενσωματωμένοι σε όλες τις ηλεκτρονικές συσκευές οι οποίες έχουν κάποια υπολογιστική ικανότητα. Αναφέρουμε χαρακτηριστικά τα κινητά, τις ψηφιακές κάμερες και άλλες παρόμοιες συσκευές. Η ΚΜΕ αποτελείται από τρία σημαντικά στοιχεία, τους καταχωρητές, την αριθμητική και λογική μονάδα (arithmetic and logic unit - ALU) και τη μονάδα ελέγχου (control unit). Οι καταχωρητές είναι μικρά στοιχεία μνήμης τα οποία αποθηκεύουν δεδομένα προσωρινά, όσο αυτά υφίστανται επεξεργασία. Μέσα σε μία μονάδα επεξεργασίας υπάρχουν πολλά είδη καταχωρητών όπως ο μετρητής προγράμματος, ο καταχωρητής των εντολών (ή μνήμη εντολών) κ.ά. Στην αριθμητική και λογική μονάδα (ALU) εκτελούνται όλες οι αριθμητικές και λογικές πράξεις. Η μονάδα ελέγχου ελέγχει τη ροή των δεδομένων που εισέρχονται και εξέρχονται από και προς το σύστημα. Η κύρια λειτουργία των επεξεργαστών είναι να εκτελούν διαδοχικά συγκεκριμένες εντολές. Για να μπορέσει να πραγματοποιηθεί αυτή η λειτουργία, είναι απαραίτητη η κωδικοποίηση των διαθέσιμων εντολών. Μία εντολή μπορεί να επεξεργαστεί δεδομένα ή να επηρεάσει τη ροή του προγράμματος. Κατα τη διάρκεια επεξεργασίας δεδομένων κατάλληλες εντολές προσθέτουν, αφαιρούν, πολλαπλασιάζουν δεδομένα και εκτελούν πολλές ακόμα πράξεις μεταξύ των δεδομένων. Οι εντολές που επηρεάζουν τη ροή της εκτέλεσης του προγράμματος είναι οι εντολές διακλάδωσης που ουσιαστικά είναι μία μορφή βρόχων επιλογής και επανάληψης. Κατα την κωδικοποίηση της εντολής πρέπει να λαμβάνονται υπόψην οι απαραίτητες πληροφορίες οι οποίες πρέπει να αντλούνται από αυτήν. Κάθε εντολή θα πρέπει να καθορίζει τη λειτουργία της, την πηγή των δεδομένων που είναι απαραίτητα καθώς και τη διεύθυνση στην οποία μπορεί να χρειαστεί να γραφτούν νέα δεδομένα. Η κωδικοποίηση των εντολών δίνεται σε ένα ή και παραπάνω bytes. Ένας σχεδιαστικός στόχος είναι να προκύψουν όσο γίνεται λιγότερα bytes. Συνήθως οι εντολές αποτελούνται από δύο τμήματα. Το πρώτο περιέχει τον κωδικό λειτουργίας (opcode) και ορίζει ποια λειτουργία θα συμβεί. Το δεύτερο μας δίνει διευθύνσεις καταχωρητών στους οποίους βρίσκονται τα δεδομένα προς επεξεργασία ή σε ποιους θα συμβεί αποθήκευση του αποτελέσματος. Πολλές φορές οι εντολές περιέχουν και απευθείας δεδομένα προς επεξεργασία. Ουσιαστικά οι εντολές είναι μία ακολουθία δυαδικών αριθμών οι οποίοι έχουν αντιστοιχηθεί σε μία λειτουργία. Αν θέλουμε να κάνουμε τις εντολές μας πιο κατανοητές μπορούμε να τις αναπαραστήσουμε σε δεκαεξαδικό σύστημα ή σε συμβολική γλώσσα. Το χρονικό διάστημα που απαιτείται από την έναρξη εκτέλεσης της εντολής μέχρι το τέλος της ονομάζεται κύκλος εντολής. Ο κύκλος εντολής περιέχει τέσσερα στάδια την ανάκληση της εντολής (fetch), την αποκωδικοποίησή της (decode), την εκτέλεση (execute) και τέλος την αποθήκευση/εγγραφή του αποτελέσματος (writeback). Κατα την ανάκληση καλείται η εντολή από τη θέση της μνήμης στην οποία βρίσκεται. Στο στάδιο της αποκωδικοποίησης η εντολή αποκωδικοποιείται, δηλαδή ενεργοποιούνται οι απαραίτητες μονάδες και ξεκαθαρίζεται ποια λειτουργία θα εκτελεστεί. Στη συνέχεια ακολουθεί η εκτέλεση εντολής. Κατα το στάδιο αυτό η λειτουργία η οποία έχει ήδη αποκωδικοποιηθεί εκτελείται από την κατάλληλη μονάδα. Τέλος, 4κατά την αποθήκευση τα αποτελέσματα αποθηκεύονται στους καταχωρητές και αν κριθεί απαραίτητο αποθηκεύονται στη μνήμη με νέα εντολή. Έτσι ο κύκλος εντολής ολοκληρώνεται. 5
Οι επεξεργαστές είναι σύγχρονα κυκλώματα. Δηλαδή λειτουργούν σύμφωνα με το σήμα ρολογιού, το οποίο είναι ένα ηλεκτρικό σήμα χρονισμού. Το ρολόι είναι τετραγωνικός παλμός και εναλλάσσεται μεταξύ '0' και '1' περιοδικά. Περίοδος του ρολογιού είναι ο χρόνος που χρειάζεται το ρολόι για να πραγματοποιήσει έναν κύκλο ρολογιού δηλαδή να μεταβεί από το λογικό '0' σε λογικό '1' και ξανά σε λογικό '0'. Η συχνότητα με την οποία γίνεται αυτή η αλλαγή ονομάζεται συχνότητα του ρολογιού. Ως κύκλο ρολογιού ορίζουμε το μικρότερο χρονικό διάστημα στο οποίο μπορεί να συμβεί μια λειτουργία. Μία λειτουργία μπορεί να χρειάζεται έναν ή και περισσότερους κύλους ρολογιού για την ολοκλήρωσή της. Η συχνότητα ρολογιού για τη μονάδα επεξεργασίας που σχεδιάστηκε έχει οριστεί στα 1GHz (Τ = 1ns). Η μονάδα επεξεργασίας που σχεδιάστηκε χρησιμοποιεί αρχιτεκτονική συνόλου εντολών (instruction set architecture - ISA) σύμφωνα με το πρότυπο RISC (Reduced Instruction Set Architecture). Η αρχιτεκτονική συνόλου εντολών ενός υπολογιστή συνδέεται κυρίως με τον προγραμματισμό του και περιλαμβάνει τις εντολές και τις λειτουργίες του υπολογιστή, τους καταχωρητές, την αρχιτεκτονική της μνήμης, τον τρόπο με τον οποίο γίνεται η διευθυνσιοδότηση αλλά και τον τρόπο διασύνδεσης με εξωτερικές μονάδες εισόδου/εξόδου. Επίσης περιλαμβάνει και όλους τους κωδικούς λειτουργίας (opcode). Το πρότυπο RISC εντολών χρησιμοποιεί πολλές και σχετικά απλές εντολές, οι οποίες χρησιμοποιούν λίγους κύκλους ρολογιού για να πραγματοποιηθούν. Ο κύριος λόγος που επιλέχθηκε αυτό το πρότυπο είναι κυρίως για να γίνει το σύστημά μας πιο γρήγορο, δηλαδή για αύξηση της απόδοσης. Επίσης επειδή οι εντολές αρχιτεκτονικής RISC είναι σχετικά απλές η σχεδίασή μας και η συγγραφή προγράμματος γίνονται αυτόματα πιο κατανοητές διαδικασίες. Οι επεξεργαστές αποτελούνται από ένα σύνολο ψηφιακών κυκλωμάτων. Τα ψηφιακά κυκλώματα αποτελούνται από πολύ υλικό (hardware) και είναι σχετικά πολύπλοκα, πράγμα που καθιστά την "με το χέρι" σχεδίασή τους αδύνατη. Για το λόγο αυτό η σχεδίασή τους επιτυγχάνεται με το κατάληλο λογισμικό, τις γλώσσες περιγραφής υλικού (hardware description language - HDL). Μία γλώσσα περιγραφής υλικού είναι μία γλώσσα προγραμματισμού η οποία χρησιμοποιείται για την περιγραφή ψηφιακών ηλεκτρονικών κυκλωμάτων. Οι γλώσσες αυτές, είναι γλώσσες ταυτόχρονου προγραμματισμού κάτι που είναι λογικό αφού ο χρόνος είναι σημαντικός για οποιοδήποτε κύκλωμα/hardware. Οι κυρίαρχες γλώσσες περιγραφής υλικού σήμερα είναι η Verilog και η VHDL. Για τη σχεδίαση του συγκεκριμένου επεξεργαστή επιλέχθηκε η VHDL. Τα εργαλεία με τα οποία χρησιμοποιούνται οι γλώσσες αυτές για σχεδίαση διαθέτουν πάντα και λογισμικό προσομοίωσης (simulation) έτσι ώστε να μπορεί να δοκιμασθεί ψηφιακό κύκλωμα που σχεδιάστηκε. Το γεγονός αυτό μας προσφέρει ένα βασικό πλεονέκτημα, μπορούμε πάντα να ελέγξουμε αν το κύκλωμά μας λειτουργεί σωστά και στη συνέχεια να το υλοποίσουμε σε μία πλακέτα κατεβάζοντάς το σε αυτή. Ο επεξεργαστής που σχεδιάστηκε δεν υλοποιήθηκε σε αναπτυξιακή πλακέτα αλλά έχει ελεγχθεί πλήρως μέσω του λογισμικού που χρησιμοποιήθηκε για μελλοντική χρήση. Η VHDL (VHSIC hardware description language) επιλέχθηκε γιατί έχει πολλά πλεονεκτήματα. Το βασικό της πλεονέκτημα είναι ότι επιτρέπει τη μοντελοποίηση και την προσομοίωση του συστήματος πριν γίνει η "μετάφραση" σε φυσικό κύκλωμα με λογικές πύλες και γραμμές διασύνδεσης. Ένα επίσης πολύ σημαντικό πλεονέκτημα είναι ότι επιτρέπει τα ταυτόχρονα συστήματα (concurrent systems) αλλά διαθέτει και ακολουθιακή εκτέλεση εντολών, αν αυτό είναι επιθυμητό. Μία σύνθεση που έχει γραφτεί σε VHDL μπορεί να τροποποιηθεί και να μεταφερθεί εύκολα. 6
ΚΕΦΑΛΑΙΟ 1: ΑΡΧΙΤΕΚΤΟΝΙΚΗ ΣΥΝΟΛΟΥ ΕΝΤΟΛΩΝ Η μονάδα επεξεργασίας που έχει σχεδιαστεί ακολουθεί το πρότυπο της RISC αρχιτεκτονικής (Reduced Instruction Set Architecture). Χρησιμοποιεί εντολές προσπέλασης της μνήμης, αριθμητικές και λογικές εντολές και εντολές διακλάδωσης. Η κάθε εντολή αποτελείται από 16 bit με τα πρώτα 4 bit να αποτελούν τον κωδικό λειτουργίας της και τα υπόλοιπα για τη διευθυνσιοδότηση των καταχωρητών, όπου είναι απαραίτητο ή για απευθείας επεξεργασία δεδομένων. Συνολικά ο επεξεργαστής διαθέτει 14 εντολές. Πίνακας 1.1 εντολών: 7
Μορφλες εντολών: ) RRR -> Destination Register 2 Source Registers ) RRs -> 2 Source Registers και προεραιτικό immediate value ) RRd -> 1 Destination Register, 1 Source Register και προεραιτκο immediate ) R -> 1 Source Register ) RImm-> Destination Register και 8-bit immediate value ) Imm -> 8-bit immediate value. Προαιρετικά μπορείνα χρησιμοποιεί τα [11:9] για να επεκτείνει την τιμή Layout εντολών: 15 1 0 RRR N/U RRs Im[1:0] RRd Immediate R RImm immediate Imm immediate 14 13 12 11 10 9 8 OPCODE F OPCODE Imm[4:2] F OPCODE rd F OPCODE rd F Unused OPCODE OPCODE rd F 8-bit Option Imm F 8-bit rd 7 6 5 4 3 ra rb ra rb ra 5-bit 2 Εντολες: ) ADD (RRR) -> rd = ra + rb Η εντολή ADD εκτελεί την πράξη της πρόσθεσης. Το επόμενο πεδίο (rd) περιέχει τον αριθμό αναφοράς του καταχωρητή στον οποίο θα αποθηκευτεί το αποτέλεσμα της πράξης. Τα επόμενα δύο πεδία (ra και rb) περιέχουν τους αριθμούς αναφοράς των καταχωρητών στους οποίους βρίσκονται οι όροι της πρόσθεσης. F -> flag για χρήση προσημασμένων ή όχι αριθμών. F = 0 -> unsigned F = 1 -> signed ) SUB (RRR) -> rd = ra - rb F -> flag για χρήση προσημασμένων ή όχι αριθμών. F = 0 -> unsigned F = 1 -> signed ) MUL (RRR) -> rd = ra F -> flag για επιλογή F = 0 -> lower byte : F = 1 -> upper byte : 8 rb του upper/lower byte των καταχωρητών rd = lower(ra) lower(rb) rd = upper(ra) upper(rb)
) OR (RRR) -> rd = ra OR rb F -> unused ) AND (RRR) -> rd = ra AND rb F -> unused ) XOR (RRR) -> rd = ra XOR rb F -> unused ) NOT (RRd) -> rd = NOT ra F -> unused ) LOAD (RImm) -> Η εντολή LOAD φορτώνει δεδομένα στους καταχωρητές γενικού σκοπού από τη μνήμη δεδομένων. Το επόμενο πεδίο (rd) περιέχει τον αριθμό αναφοράς του καταχωρητή στον οποίο θα γραφτούν τα δεδομένα. Το πεδίο ra περιέχει τον αριθμό αναφοράς του καταχωρητή στον οποίο βρίσκεται η διεύθυνση της θέσης μνήμης δεδομένων από την οποία αντλούνται τα δεδομένα. F -> Flag για την επιλογή του upper/lower byte του καταχωτή που θα γραφεί F = 0 -> lower byte : rd = 0x00FF AND Immediate F = 1 -> upper byte : rd = 0xFF00 AND (Immediate << 8) ) SHL (RRR) -> rd = ra << rb κάνει αριστερό shift στα δεδομένα του ra κατά την τιμή του rb F -> unused ) SHR (RRR) -> rd = ra >> rb κάνει δεξί shift στα δεδομένα του ra κατά την τιμή του rb F -> unused ) WRITE (RRs) -> Memory[rB] = ra + Imm γράφει στη θέση της μνήμης που δείχνει ο rb τα δεδομένα του ra + ένα offset από το immediate Immediate = 5-bit Imm & "000" ) CMP (RRR) -> rd = compare ra to rb συγκρίνει τα περιεχώμενα των καταχωρητών ra και rb και αποθηκεύει το αποτέλεσμα στον rd το αποτέλεσμα αποτελείται από flags και αδιάφορα bits με την ακόλουθει μορφή. 151413121110 9 8 7 6 5 4 3 21 -------------------------------------------xrararararb x x x x x x x x x = > < = = rbrbrb 0 0 9
F -> flag για χρήση προσημασμένων ή όχι αριθμών στις συγκρίσεις. F = 0 -> unsigned F = 1 -> signed ) JUMP (RRd) F -> Flag για F = 0 -> jump PC = ra F = 1 -> jump PC = ra + να γίνει jump σε register/immediate to register : to register + immediate : Imm ) JUMPEQ (RRS) κάνει Jump (ίδιο με πάνω), εφόσον στον rd έχει αποθηκευτεί αποτέλεσμα από προηγούμενη compare. Το ποια συνθήκη θα πρέπει να ισχύει για να γίνει το Jump εξαρτάται από τα bits [8,1:0]: 000 001 010 011 100 101 110 10 -> -> -> -> -> -> -> ra rb rb ra rb ra ra = rb = 0 = 0!= 0!= 0 > rb < rb
ΚΕΦΑΛΑΙΟ 2 : ΚΥΚΛΟΣ ΕΝΤΟΛΗΣ ΚΑΙ ΣΥΝΟΛΙΚΟ ΚΥΚΛΩΜΑ ΕΠΕΞΕΡΓΑΣΤΗ 2.1 Κύκλος εντολής Η τεχνική που χρησιμοποιήθηκε δηλαδή η χρήση σταδίων για την ολοκλήρωση μίας εντολής ονομάζεται pipeline. To pipeline είναι ένα σύνολο στοιχείων που συνδέονται σε σειρά με τέτοιο τρόπο ώστε η έξοδος του ενός να είναι η είσοδος του επόμενου. Ο πιο συνηθισμένος τρόπος να πετύχουμε την τεχνική αυτή είναι με τη διαίρεση μίας πολύπλοκης διαδικασίας σε πιο απλές. Στο σημείο αυτό πρέπει να αναφέρουμε ότι η τεχνική αυτή μπορεί να ονομάζεται pipeline αλλά δεν πρέπει να συγχεέται με την τεχνική μερικώς επικαλυπτόμενων λειτουργιών (instruction pipelining). Στη συγκεκριμένη περίπτωση όταν αναφερόμαστε στο pipeline δεν εννοούμε την τεχνική αυτή, αλλά το διαχωρισμό των διαδικασιών σε απλούστερες. Θεωρούμε ότι κάθε εντολή αποτελείται από κάποια επιμέρους βήματα: προσκόμιση εντολής, αποκωδικοποίηση, εκτέλεση, προσπέλαση μνήμης, αποθήκευση αποτελεσμάτων. Το κάθε βήμα εκτελείται σε έναν κύκλο ρολογιού. Για τη συγκεκριμένη μονάδα επεξεργασίας χρησιμοποιούνται 4 στάδια ανα κύκλο εντολής: - Αποκωδικοποίηση εντολής - Ανάγνωση δεδομένων από τους καταχωρητές γενικού σκοπού - Εκτέλεση πράξης - Αποθήκευση αποτελεσμάτων στους καταχωρητές και προσκόμιση επόμενης εντολής Η μονάδα η οποία καθορίζει τον κύκλο εντολής είναι η μονάδα ελέγχου (control unit) η οποία περιγράφεται πλήρως στην επόμενη παράγραφο. Θεωρήθηκε σκόπιμο να μην περιγραφεί στην προηγούμενη ενότητα όπου αναλύθηκαν όλες οι επιμέρους μονάδες του επεξεργαστή γιατί για την πλήρη κατανόηση της λειτουργίας της είναι απαραίτητο να έχει προηγηθεί μία συνοπτική εξήγηση της τεχνικής μερικώς επικαλυπτόμενων λειτουργιών (pipeline). 2.2 Μονάδα ελέγχου/ Control unit Η μονάδα ελέγχου παράγει σήματα συγχρονισμού και τα στέλνει σε όποια μονάδα θέλουμε να λειτουργήσει. Γενικότερα ελέγχει τη ροή των δεδομένων. Στη συγκεκριμένη μονάδα επεξεργασίας δίνει ως έξοδο έναν αριθμό των 4 bit (state) που ορίζει σε ποιο βήμα της εντολής βρισκόμαστε και ποια μονάδα είναι ενεργοποιημένη. Το κάθε bit του σήματος αυτού ενεργοποιεί και μία μονάδα ως εξής: state(0) = 1 : Έχω ενεργοποίηση του αποκωδικοποιητή εντολών. Κατά το βήμα αυτό γίνεται προσκόμιση και αποκωδικοποίηση της εντολής. state(1) = 1 : Έχω ενεργοποίηση των καταχωρητών γενικού σκοπού. Κατά το βήμα αυτό διαβάζονται τα δεδομένα που θα χρησιμοποιηθούν στην πράξη. state(2) = 1 : Έχω ενεργοποίηση της αριθμητικής/λογικής μονάδας. Κατά το βήμα αυτό εκτελείται η πράξη. state(3) = 1 : Έχω ενεργοποίηση των καταχωρητών γενικού σκοπού αλλά αυτή τη φορά για εγγραφή των αποτελεσμάτων. Για τη σωστή εκτέλεση τα bit του παραγόμενου σήματος αλλάζουν διαδοχικά ανα ένα κύκλο ρολογιού από τη θέση 0 ως τη θέση 3 ως εξής: Πρώτος κύκλος: state "0001" Δεύτερος κύκλος: state "0010" Τρίτος κύκλος: state "0100" Τέταρτος κύκλος: state "1000" Οι μόνες είσοδοι που εισέρχονται στην μονάδα ελέγχου είναι φυσικά η είσοδος ρολογιού και 11
μία είσοδος η οποία αρχικοποιεί τη μονάδα ελέγχου (reset). Η μονάδα ελέγχου μηδενίζεται για reset = '1'. Η μονάδα ελέγχου αρχικοποιείται στην κατάσταση "0001". Παρατηρώντας την εναλλαγή των καταστάσεων παρατηρούμε ότι πρόκειται για καταχωρητή ολίσθησης με είσοδο reset. Στο σχήμα 2.2.1 απεικονίζεται το κύκλωμα της μονάδας ελέγχου. Σχήμα 2.2.1 Μνήμη ελέγχου/ Control unit υλοποιημένη ως barrel shifter Σχήμα 2.2.2 Μνήμη ελέγχου/ Control unit 12
2.3 Συνολικό κύκλωμα μονάδας επεξεργασίας Στο σημείο αυτό έχουν περιγραφεί πλήρως όλες οι επιμέρους μονάδες του συγκεκριμένου επεξεργαστή. Στο τελευταίο αυτό στάδιο θα εξηγηθεί η λειτουργία της μονάδας επεξεργασίας συνολικά. Το ολοκληρωμένο κύκλωμα του επεξεργαστή απεικονίζεται στο σχήμα 2.3.1. Σχήμα 2.3.1 Αναπαράσταση του επεξεργαστή με block diagram Ο μετρητής προγράμματος αρχικά δίνει τη διεύθυνση της μνήμης ROΜ στη θέση της οποίας βρίσκεται η επόμενη προς εκτέλεση εντολή. Στη συνέχεια η εντολή αποκωδικοποιείται μέσω του αποκωδικοποιητή εντολών. Ο αποκωδικοποιητής εντολών παράγει τους αριθμούς αναφοράς των καταχωρητών στους οποίους θέλουμε να γράψουμε ή από τους οποίους θέλουμε να διαβάσουμε. Η ALU εκτελεί την απαραίτητη εντολή και παράγει τις εξόδους. Στη συνέχεια το αποτέλεσμα γράφεται στους καταχωρητές γενικού σκοπού. Σε περίπτωση που έχουμε εντολή LOAD ή STORE ενεργοποιείται και η μνήμη των δεδομένων με την οποία αλληλεπιδρά το σύστημά μας. Τέλος, μένει να εξηγήσουμε πως καθορίζεται η τιμή του pc_opcode δηλαδή ποια λειτουργία θα εκτελέσει ο μετρητής προγράμματος. Παρουσιάζουμε τον πίνακα 2.3.1 για να θυμηθούμε τις λειτουργίες του μετρητή προγράμματος: Πίνακας 2.3.1:Κωδικός λειτουργίας του μετρητή προγράμματος PC_opcode Λειτουργία 00 Καμία λειτουργία 01 Επόμενη εντολή 10 Διακλάδωση 11 Reset/Μηδενισμός 13
Άρα όταν η είσοδος reset της μονάδας ελέγχου είναι ίση με '1' θα πρέπει ο pc_opcode να έχει την τιμή "11". Στην περίπτωση διακλάδωσης θα πρέπει να ελεγχθεί η συνθήκη διακλάδωσης. Άρα θα πρέπει να ισχύει Branch_en = '1' και state(2) = '1'. Αυτό γιατί θα πρέπει να έχω ενεργοποίηση διακλάδωσης αλλά και ενεργοποίηση της ALU ώστε να ελεγχθεί η συνθήκη διακλάδωσης. Ακολουθώντας το ίδιο σκεπτικό συμπεραίνουμε ότι για να εκτελεστεί η αμέσως επόμενη εντολή θα πρέπει Branch_en = '0' και state(2) = '1'. Έτσι καταλήγουμε στο κύκλωμα του σχήματος 2.3.2. Το κύκλωμα αυτό δεν σχεδιάστηκε στο συνολικό σχέδιο για να μην οδηγηθούμε σε εξαιρετικά πολύπλοκη ανάγνωση του σχήματος. Σχήμα 2.3.2 Υπολογισμός pc_opcode για τη λειτουργία του μετρητή προγράμματος Η μονάδα επεξεργασίας που σχεδιάστηκε έχει περιγραφεί ως ολική κατασκευή. Το επόμενο βήμα είναι να αναλύσουμε τα επιμέρους τμήματα που την απαρτίζουν. 14
ΚΕΦΑΛΑΙΟ 3 : ΠΕΡΙΓΡΑΦΗ ΤΩΝ ΕΠΙΜΕΡΟΥΣ ΜΟΝΑΔΩΝ Στην ενότητα αυτή περιγράφονται λεπτομερώς οι επιμέρους μονάδες που αποτελούν την μονάδα επεξεργασίας που σχεδιάστηκε. Για κάθε μονάδα εξηγείται πλήρως η λειτουργία της, η αρχιτεκτονική της καθώς και ο ρόλος της στο συνολικό αποτέλεσμα. 3.1 Αριθμητική/λογική μονάδα και μονάδα ολίσθησης Στην αριθμητική και λογική μονάδα (ALU) μίας μονάδας επεξεργασίας εκτελούνται οι περισσότερες πράξεις. Οι δυαδικοί αριθμοί που χειρίζεται είναι προσημασμένοι και των 16 bit. Τα δεδομένα παρέχονται στην ALU από τους καταχωρητές γενικού σκοπού (register file). Στη συνέχεια αφού αποκωδικοποιηθεί ο κωδικός λειτουργίας (opcode) εκτελείται η κατάλληλη πράξη. Τέλος, τα αποτελέσματα που προκύπτουν μεταφέρονται στους καταχωρητές γενικού σκοπού ή αποθηκεύονται στη μνήμη δεδομένων αν είναι απαραίτητο. Στη συγκεκριμένη ALU εκτελούνται όλες οι εντολές, δηλαδή εκτός από τις πράξεις που έχουν ήδη αναφερθεί ελέγχονται και οι συνθήκες διακλάδωσης. Αρχικά έχουμε σχεδιάσει έναν αποκωδικοποιητή 5-to-32 (5-to-32 decoder) όπου σαν είσοδο δέχεται τον κωδικό λειτουργίας και ανάλογα με την τιμή του εκτελεί την κατάλληλη πράξη. O κωδικός λειτουργίας έχει παραχθεί στο στάδιο της αποκωδικοποίησης της εντολής και εισέρχεται σαν είσοδος της ALU. Ο αποκωδικοποιητής της ALU φαίνεται στο σχήμα 2.1.1. Σχήμα 3.1.1 Αποκωδικοποιητής της ALU. Η ALU επίσης έχει μία είσοδο ενεργοποίησης (enable) η οποία όταν είναι '1' θέτει την ALU σε λειτουργία ενώ όταν είναι '0' δεν την ενεργοποιεί. Το σήμα εισόδου ενεργοποίησης παράγεται από 15
τη μονάδα ελέγχου. H ALU έχει και μία είσοδο ρολογιού συχνότητας 1ns το οποίο ενεργοποιεί το κύκλωμά μας στη θετική ακμή του σήματός του. Επίσης σαν είσοδοι δίνονται τα δεδομένα που θέλουμε να επεξεργαστούμε τα οποία προέρχονται από τους καταχωρητές (ra_data, rb_data) καθώς και ο δυαδικός αριθμός immediate ο οποίος χρησιμοποιείται για απευθείας υλοποίηση μιας πράξης. Όλες οι αριθμητικές και λογικές πράξεις υλοποιήθηκαν με τους ενσωματωμένους τελεστές του εργαλείου WebISE της Xilinx. Αφού εκτελεστούν οι αριθμητικές ή οι λογικές πράξεις το αποτέλεσμα εξέρχεται από το κύκλωμα σαν έξοδος (DataOut). Όταν εκτελούνται αριθμητικές πράξεις είναι απαραίτητο να ελέγξουμε το carry flag και το overflow flag. Carry flag: Σε μία αριθμητική πράξη δυαδικών αριθμών θα προκύψει carry flag όταν προσθέτω δύο αριθμούς και σαν αποτέλεσμα θα έχω υπερχείλιση, δηλαδή ο αριθμός που προκύπτει ξεπερνάει το εύρος των διαθέσιμων bit. Το carry flag μας ενδιαφέρει για μη προσημασμένους αριθμούς. Επειδή στη μονάδα επεξεργασίας που σχεδιάστηκε έχω προσημασμένους πρέπει να αναφέρουμε ότι το υπόλοιπο δεν μας δίνει κάποια πληροφορία για το αν υπάρχουν σφάλματα. Ωστόσο το υπολογίζουμε και το μεταφέρουμε στην έξοδο C_flag. Για να το υπολογίσω θα οδηγήσω σε μία πύλη XOR τα δύο πιο σημαντικά ψηφία του αποτελέσματος και η έξοδός της θα είναι το carry flag. Overflow flag: Σε μία αριθμητική πράξη δυαδικών αριθμών θα προκύψει overflow flag όταν προσθέτω δύο αριθμούς ίδιου προσήμου και προκύπτει ένας αριθμός αντίθετου προσήμου. Στις πράξεις προσημασμένων αριθμών σε συμπλήρωμα ως προς 2 το overflow flag ορίζει αν έχω σφάλμα. Σε περίπτωση που αυτό είναι '1' σημαίνει ότι το αποτέλεσμα δεν είναι σωστό. Όταν συμβεί αυτό θα πρέπει να κόψω το LSB του τελικού αποτελέσματος για να μπορέσω να θέσω ως MSB το πραγματικό πρόσημο του αριθμού αυτού. Αφού το overflow flag υπολογιστεί το μεταφέρουμε στην έξοδο V_flag. Για να το υπολογίσω κατά την πράξη της πρόσθεσης αρχικά θα ελέγξω αν οι δύο προσθετέοι είναι ομόσημοι. Αν αυτοί είναι ομόσημοι το overflow flag θα είναι '1' μόνο αν το πρόσημο του αθροίσματος είναι διαφορετικό. Δηλαδή θα πρέπει να υλοποιηθεί η εξής συνάρτηση: overflow_flag = A n B n sum n ' + A n 'B n 'sum n. Όπου οι n όροι είναι τα πιο σημαντικά ψηφία για τους δύο όρους και το άθροισμα δηλαδή τα πρόσημα. Το κύκλωμα υπολογισμού του V_flag φαίνεται στο σχήμα 3.1.2. Σχήμα 3.1.2 Κύκλωμα υπολογισμού overflow_flag Διακλαδώσεις: Στην ALU αναφέραμε ότι ελέγχονται και οι συνθήκες διακλάδωσης. Για το λόγο αυτό είναι απαραίτητο η ALU εκτός από την έξοδο του αποτελέσματος λογικών και αριθμητικών πράξεων να υπάρχει και μία έξοδος (ShouldBranch) η οποία θα ορίζει αν πραγματοποιείται διακλάδωση. Ο έλεγχος των συνθηκών διακλάδωσης και ο υπολογισμός του BranchEn πραγματοποιείται με πολυπλέκτες. Στην περίπτωση των BRE, BNE χρησιμοποιείται και αφαιρέτης για τον έλεγχο της συνθήκης. Όταν αυτή θα είναι '1' ο μετρητής προγράμματος θα πραγματοποιεί διακλάδωση και 16
όταν είναι '0' η ροή του προγράμματος θα συνεχίζεται κανονικά. Η έξοδος ShouldBranch θα είναι '0' ούτως ή άλλως για όλους τους κωδικούς λειτουργίας που δεν αφορούν εντολές διακλάδωσης.για την εντολή JMP (unconditional branch) έχω πάντα διακλάδωση και απλώς θα θέσω σε '1' την ενεργοποίηση διακλάδωσης (ShouldBranch). Όταν συμβαίνει μία από τις BRC, BRC', BRV, BRV' αρκεί να ελέγξω την τιμή του κατάλληλου flag. Δηλαδή: "10001" Branch if Carry_flag = '0' ShouldBranch = not (C_flag) "10010" Branch if Carry_flag = '1' ShouldBranch = C_flag "10011" Branch if Overflow_flag = '0' ShouldBranch = not (V_flag) "10100" Branch if Overflow_flag = '1' ShouldBranch = V_flag Προσπέλαση της μνήμης: Για τις εντολές προσπέλασης της μνήμης αυτό που κάνει η ALU είναι να καθορίζει το σήμα ενεργοποίησης εγγραφής στη μνήμη των δεδομένων. Εγγραφή στη μνήμη δεδομένων έχω μόνο για τις εντολές STORE, IN οπότε μέσω αποκωδικοποιητή που δέχεται τον κωδικό λειτουργίας καθορίζει το σήμα ενεργοποίησης εγγραφής στο '1' όταν εκτελούνται αυτές οι δύο εντολές. Στην παρούσα σχεδίαση εμφανίζονται στην έξοδο τα δεδομένα που γράφτηκαν η διαβάστηκαν. Αυτό δεν ήταν κάτι απαραίτητο αλλά πραγματοποιήθηκε για να γίνει το περιβάλλον της σχεδίασης πιο κατανοητό και φιλικό προς το σχεδιαστή, ειδικά σε ό,τι αφορά τη δοκιμή του κυκλώματος. Ολισθήσεις: Στην ALU εκτελούνται και οι ολισθήσεις των εισόδων. Για να πραγματοποιηθούν έχει σχεδιαστεί μία μονάδα ολίσθησης ως υπομονάδα της ALU. Η μονάδα ολίσθησης που σχεδιάστηκε δέχεται ως είσοδο τον αριθμό ο οποίος θα υποστεί ολίσθηση, έναν έλεγχο ο οποίος ορίζει τι είδους ολίσθηση θα πραγματοποιηθεί και έναν αριθμό ο οποίος ορίζει κατά πόσα ψηφία θα πραγματοποιηθεί η ολίσθηση. Η μονάδα ολίσθησης ενεργοποιείται με τους κατάλληλους κωδικούς λειτουργίας. Επίσης οι κωδικοί λειτουργίας λειτουργούν και σαν έλεγχος του είδους της ολίσθησης (Πίνακας 3.1.1) Πίνακας 3.1.1 Λειτουργίες του ολισθητή opcode ολίσθηση 1010 Λογική ολίσθηση αριστερά 1011 Λογική ολίσθηση δεξιά Υπάρχουν αρκετοί τρόποι υλοποίησης της ολίσθησης. Ένας από τους πιο γνωστούς και απλούς ειναί o καταχωρητής ολίσθησης (shift register). Η αριθμητική/λογική μονάδα έχει περιγραφεί πλήρως. Στο σχήμα 3.1.3 απεικονίζεται σαν σύνολο μαζί με όλες τις εισόδους και εξόδους της. 17
Σχήμα 3.1.3 Συνολική απεικόνιση της ALU 3.2 Αποκωδικοποιητής εντολών / Instruction decoder Ο αποκωδικοποιητής εντολών δέχεται σαν είσοδο δεδομένα από την μνήμη των εντολών και τις αποκωδικοποιεί. Δηλαδή απομονώνει τον κωδικό λειτουργίας άρα καθορίζει και την διαδικασία που θα εκτελεστεί. Επίσης αποκωδικοποιεί τους αριθμούς αναφοράς καταχωρητών δηλαδή καθορίζει απο ποιους καταχωρητές του register file θα διαβάσουμε δεδομένα και σε ποιον καταχωρητή του θα γράψουμε. Απομονώνει και το πεδίο immediate το οποίο μπορεί να χρησιμοποιηθεί για ορισμένες απ'ευθείας πράξεις. Τέλος, παράγει και σήμα εγγραφής για το register file το οποίο ορίζει αν έχουμε εγγραφή ('1') ή όχι ('0'). Διαθέτει επίσης είσοδο εγγραφής (enable/en) και είσοδο ρολογιού. Τα πρώτα 4 bit της εισόδου (InstructionSet) αποτελούν τον κωδικό λειτουργίας. Οπότε θα οδηγηθούν σε έναν αποκωδικοποιητή ώστε να καθοριστεί η εντολή που θα εκτελεστεί. Ο αποκωδικοποιητής είναι παρόμοιος με αυτόν που υπάρχει στην είσοδο της ALU και φαίνεται στο σχήμα 3.2.1. 18
Σχήμα 3.2.1 Αποκωδικοποιητής του Instruction Decoder (Αποκωδικοποιητής εντολών). Ανάλογα με το ποια έξοδος του αποκωδικοποιητή είναι '1' οι αριθμοί αναφοράς των καταχωρητών θα πάρουν τις κατάλληλες τιμές καθώς και το σήμα ενεργοποίησης εγγραφής στο register file. Για την υλοποίηση του αποκωδικοποιητή εντολών χρησιμοποιήθηκαν αρκετά κυκλώματα επειδή δόθηκε μεγαλύτερη σημασία στην ταχύτητα και όχι στο κόστος. Στον πίνακα 3.2.1 απεικονίζονται οι εντολές και οι κατάλληλες τιμές για τους αριθμούς αναφοράς καταχωρητών. Εδώ είναι χρήσιμο να αναφέρουμε ότι έχω εγγραφή στους καταχωρητές με δείκτη αναφοράς rd_select και ανάγνωση από τους ra_select και rb_select. Πίνακας 3.2.1 Αποκωδικοποίηση εντολών στον αποκωδικοποιητή εντολών 19
Πίνακας 3.2.2 Αποκωδικοποίηση εντολών στον αποκωδικοποιητή εντολών Όταν το πεδίο στο οποίο θα θέσουμε μία τιμή δεν χρησιμοποιείται τότε θα έχουμε αδιάφορες συνθήκες. Αυτό σημαίνει ότι δεν επηρεάζεται η λειτουργία του κυκλώματος ούτε και αυτή των μονάδων που ακολουθούν τον αποκωδικοποιητή εντολών στο συνολικό κύκλωμα από τις τιμές των εξόδων. Θα αναλύσουμε κάθε έξοδο ξεχωριστά και θα παρουσιάσουμε το κύκλωμά της. Οι καταχωρητές με δείκτη αναφοράς rd έχουν την τιμή του πεδίου 11 9 της εντολής ή δεν χρησιμοποιούνται (αδιάφορες συνθήκες) δηλαδή δεν έχουμε εγγραφή. Έτσι μπορούμε μόνιμα να δώσουμε στον αριθμό αναφοράς καταχωρητή rd την τιμή του πεδίου 11 9 της εντολής (Instruction Set). Με τον ίδιο τρόπο, παρατηρούμε ότι όταν γίνεται ανάγνωση από καταχωρητή με αριθμό αναφοράς ra τότε αυτός ορίζεται από το πεδίο 7 5 όταν έχω και εγγραφή κάποιου αποτελέσματος ενώ όταν έχω μόνο ανάγνωση χωρίς εγγραφή, ο αριθμός αναφοράς ορίζεται από το πεδίο 15 12 της εντολής. Όπως αναφέρθηκε και πριν, στην περίπτωση που δε χρησιμοποιείται ο αριθμός αναφοράς ra θα έχω αδιάφορες συνθήκες. Έτσι ο ra ορίζεται ως εξής: ra InstrSet (15 12) αν δεν έχω εγγραφή (write enable = 0) ra InstrSet (11 9) αν έχω εγγραφή (write enable = 1). 20
Η ίδια λογική ακολουθείται και για το πεδίο rb το οποίο χρησιμοποιείται επίσης μόνο για ανάγνωση. Στην περίπτωση αυτή ορίζεται από το πεδίο 4 2 όταν έχω και εγγραφή κάποιου αποτελέσματος ενώ όταν έχω μόνο ανάγνωση χωρίς εγγραφή, ο αριθμός αναφοράς ορίζεται από το πεδίο 15 12 της εντολής. Στις περιπτώσεις όπου δεν χρησιμοποιείται υπάρχουν αδιάφορες συνθήκες. Δηλαδή: rβ_sel InstrSet (15 12) αν δεν έχω εγγραφή (write enable = 0) rβ_sel InstrSet (4 2) αν έχω εγγραφή (write enable = 1). Τέλος, το πεδίο immediate θα χρησιμοποιεί πάντα τα 11 τελευταία bit της εντολής. Αν αυτό δε χρησιμοποιείται θα ορίζεται ως αδιάφορες συνθήκες. O αποκωδικοποιητής εντολών έχει περιγραφεί πλήρως. Στο σχήμα 3.2.2 απεικονίζεται σαν σύνολο μαζί με όλες τις εισόδους και εξόδους του. Σχήμα 3.2.2 Συνολική απεικόνιση του αποκωδικοποιητή εντολών (instruction decoder) 3.3 Μετρητής προγράμματος / Program Counter Ο μετρητής προγράμματος δέχεται σαν είσοδο έναν κωδικό λειτουργίας των 2 bit που καθορίζει τη λειτουργία του μετρητή προγράμματος (pc_opcode). Επίσης δέχεται σαν είσοδο μία διεύθυνση στην οποία θα μεταπηδήσει αν συμβεί διακλάδωση/branch (pc_in). Διαθέτει επίσης είσοδο ρολογιού. O μετρητής προγράμματος δε διαθέτει είσοδο ενεργοποίησης (enable) επειδή πάντα πρέπει να είναι ενεργοποιημένος και να μετράει τις εντολές που εκτελούνται. Η μόνη έξοδος που παράγει είναι η νέα διεύθυνση στην οποία βρίσκεται η προς εκτέλεση εντολή. Αρχικά ορίζεται ο κωδικός λειτουργίας του μετρητή προγράμματος (pc_opcode) και ποιες λειτουργίες εκτελούνται ανάλογα με την τιμή του. Ο τρόπος λειτουργίας του φαίνεται στον πίνακα 3.3.1 21
Πίνακας 3.3.1 Κωδικός λειτουργίας του μετρητή προγράμματος Pc_opcode Λειτουργία 00 Καμία λειτουργία 01 Επόμενη εντολή 10 Διακλάδωση 11 Reset/Μηδενισμός Ο μετρητής προγράμματος έχει σχεδιαστεί σαν απλό ακολουθιακό κύκλωμα. Όταν ο pc_opcode είναι "00" η έξοδος θα παραμείνει στην ίδια τιμή. Όταν αυτός θα είναι "01" στην έξοδο θα προστεθεί 1 και θα προχωρήσουμε στην επόμενη διεύθυνση. Η πρόσθεση γίνεται μέσω της άθροισης η οποία χρησιμοποιεί την ενσωματωμένη άθροιση της VHDL. Όταν θα είναι "10" στην έξοδο θα περάσει η διεύθυνση της εισόδου pc_in δηλαδή η διεύθυνση στην οποία μεταπηδάμε σε περίπτωση διακλάδωσης και τέλος για "11" ο μετρητής μηδενίζεται (reset). O μετρητής προγράμματος έχει περιγραφεί πλήρως. Στο σχήμα 3.3.1 απεικονίζεται σαν σύνολο μαζί με όλες τις εισόδους και εξόδους του. Σχήμα 3.3.1 Συνολική απεικόνιση του μετρητή προγράμματος (program counter) 3.4 Καταχωρητές γενικού σκοπού / Register file Το register file είναι ένα σύνολο καταχωρητών στους οποίους γράφονται δεδομένα είτε διαβάζονται δεδομένα από αυτούς. Οι καταχωρητές αποτελούνται από μία ομάδα flip-flop (στην περίπτωσή μας D f/f) τα οποία μπορούν να αποθηκεύσουν 1 bit. Στο συγκεκριμένο register file κάθε καταχωρητής αποτελείται από 16 flip-flop αποθηκεύει δηλαδή 16 bit. Το register file δέχεται ως είσοδο σήμα ενεργοποίησης εγγραφής (write enable) το οποίο όταν είναι '1' δηλώνει εγγραφή ενώ όταν είναι '0' δηλώνει ανάγνωση. Διαθέτει δύο πόρτες ανάγνωσης και μία εγγραφής. Επίσης δέχεται είσοδο εγγραφής (enable/en) και είσοδο ρολογιού. Όλα τα flip flops και κατά συνέπεια και όλοι οι καταχωρητές μοιράζονται το ίδιο ρολόι. Ανάγνωση: Οι καταχωρητές γενικού σκοπού διαθέτουν δύο εξόδους δεδομένων οι οποίες 22
εμφανίζουν δεδομένα από κάποιους καταχωρητές σε περίπτωση που το σήμα ενεργοποίησης εγγραφής είναι '0', δηλαδή όταν συμβαίνει ανάγνωση. Τα δεδομένα εισόδου δεν χρησιμοποιούνται. Εγγραφή: Κατά την εγγραφή η μόνη διεργασία που πραγματοποιείται είναι να αποθηκευτούν τα δεδομένα εισόδου σε κάποιο καταχωρητή. Το σήμα ενεργοποίησης εγγραφής είναι '1' και τα σήματα εξόδου δεν χρησιμοποιούνται. Τέλος, πρέπει με κάποιο τρόπο να οριστούν οι αριθμοί αναφοράς καταχωρητών στους οποίους γίνεται ανάγνωση ή εγγραφή. Για το σκοπό αυτό έχουν οριστεί τρεις είσοδοι των 4 bit οι οποίες καθορίζουν σε ποιον καταχωρητή θα γίνει εγγραφή (rd_select) και από ποιους θα γίνει ανάγνωση (ra_select, rb_select). Η μονάδα επεξεργασίας που έχει σχεδιαστεί χρησιμοποιεί 16 καταχωρητές των 16 bit. Δηλαδή συνολικά χρησιμοποιούνται 16x16 = 256 D flip-flops. Οι αριθμοί αναφοράς καταχωρητών έχουν εύρος από 0 (0000) ως 15 (1111) και είναι θετικοί ακέραιοι αριθμοί. Περνώντας στην υλοποίηση του κυκλώματος αρχικά χρησιμοποιείται ένας αποκωδικοποιητής 4-σε-16 (4-to-16 decoder) ο οποίος παίρνει σαν είσοδο τον αριθμό αναφοράς του καταχωρητή στον οποίο θα έχω εγγραφή (rd_select). Στη συνέχεια οι γραμμές που προκύπτουν θα οδηγηθούν σε μία πύλη AND μαζί με το σήμα ενεργοποίησης εγγραφής. Έτσι θα έχω εγγραφή αν και μόνο αν το σήμα ενεργοποίησης εγγραφής είναι '1' και αν η γραμμή εξόδου του αποκωδικοποιητή είναι '1'. Τα δεδομένα εισόδου οδηγούνται σε όλους τους καταχωρητές αλλά γράφονται σε αυτόν που οδηγεί η έξοδος του αποκωδικοποιητή και το σήμα ενεργοποίησης εγγραφής. Για να "διαβάσω" από τους καταχωρητές γενικού σκοπού χρησιμοποιώ 16-σε-1 πολυπλέκτες (16-to-1 multiplexers). Οι έξοδοι των καταχωρητών θα περάσουν σε δύο τέτοιους πολυπλέκτες οι οποίοι δέχονται ως έλεγχο τους αριθμούς αναφοράς καταχωρητών από τους οποίους γίνεται ανάγνωση (ra_select, rb_select). Έτσι συνολικά έχω δύο τέτοιους πολυπλέκτες για κάθε bit άρα συνολικά 32 πολυπλέκτες 16-σε-1. Στην έξοδο εμφανίζονται τα δεδομένα των συγκεκριμένων καταχωρητών. Το κύκλωμα των καταχωρητών γενικού σκοπού απεικονίζεται στο σχήμα 3.4.1. Στη συνέχεια θα περιγραφεί συνοπτικά και ο καταχωρητής για να δοθεί μια ολοκληρωμένη εικόνα της λειτουργίας των καταχωρητών γενικού σκοπού. 23
Σχήμα 3.4.1 Καταχωρητές γενικού σκοπού/register file Τα δεδομένα εισόδου (DataIn) εισέρχονται σε όλους τους καταχωρητές. Δεν σχεδιάστηκαν οι γραμμές διασύνδεσεις οι οποίες θα καθιστούσαν το σχήμα εξαιρετικά πολύπλοκο. 24
Στο σχήμα 3.4.2 το register file απεικονίζεται σαν σύνολο μαζί με όλες τις εισόδους και εξόδους του. Σχήμα 3.4.2 Συνολική απεικόνιση του register file. 25
3.5 Μνήμη δεδομένων/ Data memory Η μνήμη δεδομένων διαθέτει 16 θέσεις μνήμης των 16 bit, δηλαδή είναι των 32 byte. Στη μνήμη δεδομένων μπορούν να αποθηκευτούν δεδομένα με τις εντολές STORE, ΙΝ είτε να ανακτηθούν δεδομένα από αυτήν με την εντολή LOAD. Έτσι στη μνήμη αυτή πρέπει να μπορούμε και να γράψουμε αλλά και να διαβάσουμε από αυτήν. Για το λόγο αυτό θα πρέπει να δέχεται ως είσοδο δεδομένα προς εγγραφή, καθώς και είσοδο ενεργοποίησης εγγραφής (write enable) η οποία καθορίζει αν γίνεται εγγραφή (write enable = '1') ή ανάγνωση (write enable = '0'). Εκτός από αυτές τις εισόδους δέχεται επίσης και είσοδο ρολογιού και εννοείται ότι θα χρησιμοποιεί και είσοδο διεύθυνσης. Οι εντολές LOAD και STORE στη συγκεκριμένη μονάδα επεξεργασίας εκτελούνται στην ALU. Έτσι η ALU θα παράγει το σήμα ενεργοποίησης εγγραφής και θα δίνει τις διευθύνσεις και τα δεδομένα στην περίπτωση που θέλουμε να γράψουμε στη μνήμη δεδομένων ή να διαβάσουμε από αυτήν. Η μνήμη δεδομένων έχει σχεδιαστεί με τη χρήση flip-flops. Αρχικά χρησιμοποιείται ένας αποκωδικοποιητής 4-σε-16 (4-to-16 decoder) για διευθυνσιοδότηση με τον ίδιο τρόπο όπως και στην μνήμη εντολών. Στη συνέχεια οι έξοδοι του αποκωδικοποιητή θα οδηγηθούν σε πύλες AND μαζί με το σήμα ενεργοποίησης εγγραφής για να ενεργοποιούνται τα flip-flop όταν θέλουμε να γράψουμε στη μνήμη. Επίσης στα flip-flop εισέρχονται τα δεδομένα εισόδου (input_data) και το ρολόι. Οι έξοδοι των flip-flop οδηγούνται σε πολυπλέκτες 16-σε-1 (16-to-1 multiplexer) όπου καθένας από αυτούς σαν έλεγχο δέχεται τη διεύθυνση από την οποία θέλουμε να διαβάσουμε και εμφανίζει τα κατάλληλα δεδομένα στην έξοδο (output_data). Στο σχήμα 3.5.1 η μνήμη δεδομένων απεικονίζεται σαν σύνολο μαζί με όλες τις εισόδους και εξόδους της. Σχήμα 3.5.1 Συνολική απεικόνιση της μνήμης δεδομένων. 26
ΚΕΦΑΛΑΙΟ 4 : ΔΟΚΙΜΗ ΤΟΥ ΕΠΕΞΕΡΓΑΣΤΗ Στο στάδιο αυτό η σχεδίαση έχει ολοκληρωθεί. Όμως για να βεβαιωθούμε ότι η μονάδα επεξεργασίας που σχεδιάστηκε είναι πλήρως λειτουργική πρέπει να κάνουμε προσωμοίωση του σχεδίου μας χρησιμοποιώντας το isim. Έχουμε γράψει κάποιες εντολές στην ram για να βεβαιωθούμε πως το κύκλωμα μας λειτουργεί χωρίς προβλήματα. 4.1 Προσομοίωση Εντολών. Σχήμα 4.1.1 Εντολές Ram 27
Πρώτα θα παρουσιάσουμε την εντολή Load. Θέλουμε να φορτώσουμε στον καταχωρητή R0 τον αριθμό 01. Στο σχήμα 4.2 φαίνεται η προσωμοίωση της ενολής Load. Σχήμα 4.1.2 Εντολή Load. Όπως βλέπουμε εκτελείται η εντολή Load η οποία βρίσκεται στην θέση 0 της ram. Η εντολή είναι η 8101 δηλαδή ο κωδικός λειτουργίας είναι ο 8(1000) που αντιστοιχεί στην εντολή Load. Ο αριθμός του καταχωρητή είναι 1 και ο αριθμός immediate είναι 01 άρα στον καταχωρητή 1 γράφεται το Χ01. Βλέπουμε ότι όντως το seld είναι το 1 όπου γράφεται ο αριθμός Χ01. Στην συνέχεια θα παρουσιάσουμε την εντολή Add. Θέλουμε να γράψουμε στον καταχωρητή R0 το άθροισμα των δεδομένων που βρίσκονται στους καταχωρητές 1 & 2. Στο σχήμα 4.3 φαίνεται η προσωμοίωση της ενολής Add. 28
Σχήμα 4.1.3 Εντολή Add. Όπως βλέπουμε εκτελείται η εντολή Add η οποία βρίσκεται στην θέση 8 της ram. Η εντολή είναι η 0028 δηλαδή ο κωδικός λειτουργίας είναι ο 0(0000) που αντιστοιχεί στην εντολή Add.To Flag είναι 0 γιατί πρόκειται για μη προσιμασμένους αριθμούς. Οι αριθμοι των καταχωρητων στούς οποίους βρίσκονται τα δεδομένα που αθροίζονται είναι 1&2(αναπαριστώμενοι ως 2&8). Το Dataresult είναι όπως βλέπουμε το 0005. 29
Στην συνέχεια θα παρουσιάσουμε την εντολή Or. Θέλουμε να γράψουμε στον καταχωρητή R0 το αποτέλεσμα της λογικής πράξης Or των δεδομένων που βρίσκονται στους καταχωρητές 1&2. Στο σχήμα 4.4 φαίνεται η προσωμοίωση της ενολής Or. Σχήμα 4.1.4 Εντολή Or. Όπως βλέπουμε εκτελείται η εντολή Or η οποία βρίσκεται στην θέση 12 της ram. Η εντολή είναι η 2028 δηλαδή ο κωδικός λειτουργίας είναι ο 2(0010) που αντιστοιχεί στην εντολή Or.To Flag είναι 0 γιατί πρόκειται για μη προσιμασμένους αριθμούς. Οι αριθμοι των καταχωρητων στούς οποίους βρίσκονται τα δεδομένα που θέλουμε να επεξεργαστούμε είναι 1&2(αναπαριστώμενοι ως 2&8). Το Dataresult είναι όπως βλέπουμε το 0003. 30
Στην συνέχεια θα παρουσιάσουμε την εντολή Shift Left, πρόκειται για λογική ολίσθηση. Θέλουμε να γράψουμε στον καταχωρητή R0 τον αριθμό που βρίσκεται στον καταχωρητή 1 ολισθημένο κατα πλήθος ψηφίων το οποίο βρίσκεται στον καταχωρητή 2. Στο σχήμα 4.5 φαίνεται η προσωμοίωση της ενολής Shift Left. Σχήμα 4.1.5 Εντολή Shift Left. Όπως βλέπουμε εκτελείται η εντολή Shift Left η οποία βρίσκεται στην θέση 16 της ram. Η εντολή είναι η a028 δηλαδή ο κωδικός λειτουργίας είναι ο 10(1010) που αντιστοιχεί στην εντολή SHL.To Flag είναι 0 γιατί πρόκειται για μη προσιμασμένους αριθμούς. Οι αριθμοι των καταχωρητων στούς οποίους βρίσκονται τα δεδομένα που θέλουμε να επεξεργαστούμε είναι 1&2(αναπαριστώμενοι ως 2&8). Το Dataresult είναι όπως βλέπουμε το 0000. Το αποτέλεσμά μας είναι σωστό γιατί η ολίσθηση είναι λογική πράγμα που σημαίνει ότι το 0010 μετα απο 3 shift left( κατα τον καταχωρητή r2) χάνεται. 31
Στην συνέχεια θα παρουσιάσουμε την εντολή Multiply. Θέλουμε να γράψουμε στον καταχωρητή R0 το γινόμενο των αριθμών που βρίσκονται στους καταχωρητες 2&4. Στο σχήμα 4.6 φαίνεται η προσωμοίωση της εντολής Multiply. Σχήμα 4.1.6 Εντολή Multiply. Όπως βλέπουμε εκτελείται η εντολή Multiply η οποία βρίσκεται στην θέση 18 της ram. Η εντολή είναι η f050 δηλαδή ο κωδικός λειτουργίας είναι ο 15(1111) που αντιστοιχεί στην εντολή Mul.To Flag είναι 0 γιατί πρόκειται για μη προσιμασμένους αριθμούς. Οι αριθμοι των καταχωρητων στούς οποίους βρίσκονται τα δεδομένα που θέλουμε να επεξεργαστούμε είναι 2&4(αναπαριστώμενοι ως 5&0). Το Dataresult είναι όπως βλέπουμε το 000f. Το αποτέλεσμά μας είναι σωστό γιατί το γινόμενο των καταψωρητων 2&4 είναι 15(f). Στην συνέχεια θα παρουσιάσουμε την εντολή Jump. Θέλουμε να μεταπηδήσουμε απο την θέση 20 της ram στην θέση 22. Στο σχήμα 4.7 φαίνεται η προσωμοίωση της εντολής Jump. Σχήμα 4.1.7 Εντολή Jump. 32
Όπως βλέπουμε εκτελείται η εντολή Jump η οποία βρίσκεται στην θέση 20 της ram. Η εντολή είναι η c116 δηλαδή ο κωδικός λειτουργίας είναι ο c(1100) που αντιστοιχεί στην εντολή Jump.To Flag είναι 1 γιατί πρόκειται για διακλάδωση στη διεύθυνση Ra+immediate. Παρατηρούμε ότι μεταπηδάμε απο την θέση 20 της ram στην θέση 22. Το αποτέλεσμα είναι ορθό γιατί ο καταχωρητής R0 στη φάση αυτή περιέχει την τιμή 0. Ενω το πεδίο immediate είναι ο αριθμός 22. 4.2 Χρήση κυκλωμάτων του τσιπ. Τελειώνοντας είναι χρήσιμο να παρουσιάσουμε πόσο χώρο πιάνει το κύκλωμα που σχεδιάσαμε πάνω στο τσιπ. Η πληροφορία αυτή μας δίνεται από το λογισμικό που χρησιμοποιήθηκε για τη σχεδίαση το Web ISE. Τα κυκλώματα που χρησιμοποιήθηκαν παρουσιάζονται στον πίνακα 4.2.1 Πίνακας 4.2.1 Device utilization summary Logic Utilization Used Available Utilization Number of Slice Flip Flops 63 10968 1,00% Number of 4 input LUTs 218 10968 2,00% Number of occupied Slices 108 5484 2,00% Number of Slices containing only related logic 146 146 100,00% Number of Slices containing unrelated logic 0 146 0,00% Total Number of 4 input LUTs 220 10968 2,00% Παρατηρούμε ότι χρησιμοποιείται μόνο ένα μικρό μέρος του ολοκληρωμένου κυκλώματος. Χρειάζονται 270 LUTs (λογικές πύλες) δηλαδή μόλις το 2% των συνολικών πυλών και 174 slices (σύνολο απο LUTs και flip-flops), επίσης 2%. 33
Παράρτημα: Κώδικας σε VHDL i. Arithmetic - logic unit/ ALU ----------- clk -----> en -----> --/16--> data out write enable -----> ALU ra data --/16--> rb data --/16--> PC --/16--> -----> should branch immediate --/16--> -----> write enable ALU op --/05--> library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use work.tpu_constants.all; entity alu is Port ( I_clk : in STD_LOGIC; I_en : in STD_LOGIC; I_dataDwe : in STD_LOGIC; I_dataA : in STD_LOGIC_VECTOR (15 downto 0); I_dataB : in STD_LOGIC_VECTOR (15 downto 0); I_aluop : in STD_LOGIC_VECTOR (4 downto 0); I_PC : in STD_LOGIC_VECTOR (15 downto 0); I_dataIMM : in STD_LOGIC_VECTOR (15 downto 0); O_dataResult : out STD_LOGIC_VECTOR (15 downto 0); O_dataWriteReg : out STD_LOGIC; O_shouldBranch : out std_logic ); end alu; architecture Behavioral of alu is -- The internal register for results of operations. -- 16 bit + carry/overflow signal s_result: STD_LOGIC_VECTOR(17 downto 0) := (others => '0'); signal s_shouldbranch: STD_LOGIC := '0'; begin process (I_clk, I_en) variable signal_cat : std_logic_vector(2 downto 0); begin if rising_edge(i_clk) and I_en = '1' then O_dataWriteReg <= I_dataDwe; case I_aluop(4 downto 1) is when OPCODE_ADD => if I_aluop(0) = '0' then 34
s_result(16 downto 0) <= std_logic_vector(unsigned('0' & I_dataA) + unsigned( '0' & I_dataB)); else s_result(16 downto 0) <= std_logic_vector(signed(i_dataa(15) & I_dataA) + signed( I_dataB(15) & I_dataB)); end if; s_shouldbranch <= '0'; when OPCODE_SUB => if I_aluop(0) = '0' then s_result(16 downto 0) <= std_logic_vector(unsigned('0' & I_dataA) - unsigned( '0' & I_dataB)); else s_result(16 downto 0) <= std_logic_vector(signed(i_dataa(15) & I_dataA) - signed( I_dataB(15) & I_dataB)); end if; s_shouldbranch <= '0'; when OPCODE_MUL => if I_aluop(0) = '0' then s_result(16 downto 0) <= '0' & std_logic_vector(unsigned(i_dataa(7 downto 0)) unsigned(i_datab(7 downto 0))); else s_result(16 downto 0) <= '0' & std_logic_vector(unsigned(i_dataa(15 downto 8)) unsigned(i_datab(15 downto 8))); end if; s_shouldbranch <= '0'; when OPCODE_OR => s_result(15 downto 0) <= I_dataA or I_dataB; s_shouldbranch <= '0'; when OPCODE_AND => s_result(15 downto 0) <= I_dataA and I_dataB; s_shouldbranch <= '0'; when OPCODE_XOR => s_result(15 downto 0) <= I_dataA xor I_dataB; s_shouldbranch <= '0'; when OPCODE_NOT => s_result(15 downto 0) <= not I_dataA; s_shouldbranch <= '0'; when OPCODE_LOAD => if I_aluop(0) = '0' then s_result(15 downto 0) <= I_dataIMM(7 downto 0) & X"00"; else s_result(15 downto 0) <= X"00" & I_dataIMM(7 downto 0); end if; s_shouldbranch <= '0'; when OPCODE_CMP => if I_dataA = I_dataB then s_result(cmp_bit_eq) <= '1'; else 35
s_result(cmp_bit_eq) <= '0'; end if; if I_dataA = X"0000" then s_result(cmp_bit_az) <= '1'; else s_result(cmp_bit_az) <= '0'; end if; if I_dataB = X"0000" then s_result(cmp_bit_bz) <= '1'; else s_result(cmp_bit_bz) <= '0'; end if; if I_aluop(0) = '0' then if unsigned(i_dataa) > unsigned(i_datab) then s_result(cmp_bit_agb) <= '1'; else s_result(cmp_bit_agb) <= '0'; end if; if unsigned(i_dataa) < unsigned(i_datab) then s_result(cmp_bit_alb) <= '1'; else s_result(cmp_bit_alb) <= '0'; end if; else if signed(i_dataa) > signed(i_datab) then s_result(cmp_bit_agb) <= '1'; else s_result(cmp_bit_agb) <= '0'; end if; if signed(i_dataa) < signed(i_datab) then s_result(cmp_bit_alb) <= '1'; else s_result(cmp_bit_alb) <= '0'; end if; end if; s_result(15) <= '0'; s_result(9 downto 0) <= "0000000000"; s_shouldbranch <= '0'; when OPCODE_SHL => s_result(15 downto 0) <= std_logic_vector(shift_left(unsigned(i_dataa), to_integer(unsigned(i_datab(3 downto 0))))); s_shouldbranch <= '0'; when OPCODE_SHR => s_result(15 downto 0) <= std_logic_vector(shift_right(unsigned(i_dataa), to_integer(unsigned(i_datab(3 downto 0))))); s_shouldbranch <= '0'; when OPCODE_JUMPEQ => -- set branch target regardless s_result(15 downto 0) <= I_dataB; 36
-- the condition to jump is based on aluop(0) and dataimm(1 downto 0); signal_cat := I_aluop(0) & I_dataIMM(1 downto 0); case (signal_cat) is when CJF_EQ => s_shouldbranch <= I_dataA(CMP_BIT_EQ); when CJF_AZ => s_shouldbranch <= I_dataA(CMP_BIT_Az); when CJF_BZ => s_shouldbranch <= I_dataA(CMP_BIT_Bz); when CJF_ANZ => s_shouldbranch <= not I_dataA(CMP_BIT_AZ); when CJF_BNZ => s_shouldbranch <= not I_dataA(CMP_BIT_Bz); when CJF_AGB => s_shouldbranch <= I_dataA(CMP_BIT_AGB); when CJF_ALB => s_shouldbranch <= I_dataA(CMP_BIT_ALB); when others => s_shouldbranch <= '0'; end case; when OPCODE_JUMP => if I_aluop(0) = '0' then s_result(15 downto 0) <= I_dataA; -- register value else s_result(15 downto 0) <= I_dataIMM; -- Immediate value end if; s_shouldbranch <= '1'; when OPCODE_WRITE => s_result(15 downto 0) <= std_logic_vector(signed(i_dataa) + signed(i_dataimm(15 downto 11))); s_shouldbranch <= '0'; --...Other OPCODEs go here... when others => s_result <= "00" & X"FEFE"; end case; end if; end process; O_dataResult <= s_result(15 downto 0); O_shouldBranch <= s_shouldbranch; end Behavioral; 37
ii. Instruction decoder ------------------------------------------------38 OPPERATION FUNCTION --------------------------------------------------------------------- ADD D = A+ B SUBSTACT D =A- B MUL D =A B BITWISE OR D = A or B BITWISE XOR D = A xor B BITWISE AND D = A and B BITWISE NOT D = not A READ D = memory[a] WRITE memory[a] = B LOAD D = 8-bit immediate value COMPARE D = cmp(a,b) SHIFT LEFT D = A << B SHIFT RIGHT D = A >> B JUMP/BRANCH PC = a register/immediate value JUMP/BRANCH CONDITIONALLY PC = register (if condition)/nop FORM OVERVIEW EXAMPLE INSTRUCTION -------------------------------------------------------------------- RRR OPCODE rd, ra, rb ADD RRd OPCODE rd, ra NOT RRs OPCODE ra, rb Memory Write R OPCODE ra Branch to register value Rlmm OPCODE rd, immediate LOAD lmm OPCODE immediate Branch to immediate value WRITE OPCODE OPPERATION FORM REGISTER COMMENTS ------------------------------------------------------------------ 0000 ADD RRR Yes 0001 SUB RRR Yes 0010 OR RRR Yes 0011 XOR RRR Yes 0100 AND RRR Yes 0101 NOT RRd Yes 0110 READ RRd Yes 0111 WRITE RRs No Flag bit -> high/low 1000 LOAD Rlmm Yes 1001 CMP RRR Yes Flag -> comparison sign 1010 SHL RRR Yes 1011 SHR RRR Yes 1100 JUMP R,lmm No Flag -> jump to reg/immediate 1101 JUMPEQ RRs No 1110 RESERVED --- --- 1111 MUL RRR YES Flag bit -> high/low byte