ΗΥ-120: Ψηφιακή Σχεδίαση
Φθινόπωρο 2013 |
Τμ. Επ. Υπολογιστών © Πανεπιστήμιο Κρήτης |
[Up - Table of Contents] [Prev - 6. Signed Int., Subtr.] |
[printer version - PDF] [8. Edge Trigger, Counter - Next] |
[Βιβλία: προαιρετικά μπορείτε να διαβάσετε: Wakerly: το κεφ. 7 μέχρι και την § 7.2.4 (σελ. 625-639)· Mano: § 5.1-5.3 (σελίδες 182-188)].
Η λύση είναι να βάλουμε στο βρόχο ανάδρασης και μιά πύλη AND και μιά πύλη OR, η πρώτη γιά να γράφουμε 0 ("reset") και η δεύτερη γιά να γράφουμε 1 ("set"), όπως φαίνεται στο σχήμα (b). Όταν R=S=0 (R'=1), οι πύλες AND και OR απλώς περνούν τη δεύτερη είσοδό τους στην έξοδο, άρα η λογική τιμή που υπήρχε στο βρόχο συνεχίζει ες αεί να "κυκλοφορεί" σε αυτόν, επομένως το κύκλωμα παραμένει στην μία από τις δύο σταθερές καταστάσεις του, δηλαδή απομνημονεύει 1 bit πληροφορίας. Όταν S=1, η έξοδος Q τίθεται σε κατάσταση 1, ανεξαρτήτως της προηγούμενής της κατάστασης. Όταν R=1, δηλ. R'=0 (και S=0), η έξοδος Q επαναφέρεται στην κατάσταση 0, πάλι ανεξαρτήτως της προηγούμενής της κατάστασης. Αυτές οι δύο συνθήκες, S=1 ή R=1 (R'=0), είναι οι συνθήκες εγγραφής· όταν οι είσοδοι εγκαταλείψουν μιά συνθήκη εγγραφής και επιστρέψουν στη συνθήκη απομνημόνευσης (S=R=0), η πληροφορία που είχε εγγραφεί παραμένει. Συνήθως αποφεύγουμε το κύκλωμα να έρχεται στη συνθήκη ταυτόχρονης εγγραφής και 1 και 0 (S=R=1), διότι αν τα S και R εγκαταλείψουν αυτή τη συνθήκη "ταυτόχρονα" είναι απροσδιόριστο το τι τιμή θα μείνει αποθηκευμένη στο μανταλωτή.
Στην τεχνολογιά CMOS, οι πύλες AND και OR δεν υπάρχουν, και πρέπει να συντεθούν από NAND/NOR· μπορούμε να κερδίσουμε σε κατασκευαστική απλότητα μετατρέποντας το κύκλωμα (b) στο κύκλωμα (c), εισάγοντας δύο αντιστροφές στο βρόχο ανάδρασης. Η μία αντιστροφή προσάπτεται στην έξοδο της πύλης OR, μετατρέποντας την έτσι σε πύλη NOR, η δε άλλη αντιστροφή προσάπτεται στις εισόδους της πύλης AND (αλλάζοντας και την πολικότητα του σήματος R' σε R), μετατρέποντας την έτσι και αυτήν σε πύλη NOR (κανόνας DeMorgan). Ξανασχεδιάζοντας το κύκλωμα (c) με ισοδύναμη τοπολογιά και σύμβολα, παίρνουμε το "κλασσικό" κύκλωμα μανταλωτή τύπου RS με πύλες NOR που φαίνεται στο σχήμα (d). Ένα άλλο πλεονέκτημα που κερδίζουμε πηγαίνονας από μη αντιστρέφουσες πύλες (AND, OR) σε αντιστρέφουσες (NOR), είναι ότι τώρα έχουμε στη διάθεσή μας και τις δύο πολικότητες της αποθηκευμένης πληροφορίας, Q και Q'. Παρατηρήστε ότι στην πραγματικότητα η έξοδος που ονομάζουμε Q' είναι το συμπλήρωμα της Q μόνον όταν οι είσοδοι R και S δεν είναι στην "ανεπιθύμητη" συνθήκη R=S=1.
Εναλλακτικά, το κύκλωμα (b) μπορεί να μετατραπεί στο κύκλωμα (e),
εισάγοντας τις δύο αντιστροφές
σε διαφορετικό σημείο του βρόχου ανάδρασης.
Το κύκλωμα (f) που προκύπτει, με πύλες NAND αντί NOR,
είναι εξ' ίσου "κλασσικό" με το (d), και είναι απλά το δυϊκό του·
εδώ, τα σήματα εισόδου, S' και R', έχουν αρνητική πολικότητα.
Ο μανταλωτής RS βολεύει σε εφαρμογές όπου οι αιτίες "θέσης" (εγγραφής 1)
είναι διαφορετικές από τις αιτίες επαναφοράς (εγγραφής 0).
Γιά παράδειγμα, έστω ότι υπάρχουν κάμποσοι ανιχνευτές
σφαλμάτων ή ανεπιθύμητων καταστάσεων,
και ότι χρειαζόμαστε μιάν ένδειξη "συναγερμού"
που να μας ενημερώνει ότι κάτι πήγε στραβά
από την τελευταία φορά που κοιτάξαμε.
Τότε μπορούμε να χρησιμοποιήσουμε έναν μανταλωτή RS
και να τροφοδοτήσουμε την είσοδό του S από μιά πύλη Ή
που δέχεται σαν εισόδους τα σήματα όλων των ανιχνευτών·
η έξοδος Q του μανταλωτή θα θυμάται αν κάτι πήγε στραβά,
μέχρις ότου ο χειριστής τον επαναφέρει στην κατάσταση ηρεμίας,
ενεργοποιώντας στιγμιαία το σήμα R.
Στις περισσότερες εφαρμογές, όμως, οι ανάγκες είναι διαφορετικές: θέλουμε να αποθηκεύσουμε στο μανταλωτή τη λογική τιμή ενός σήματος (είτε αυτή είναι 0 είτε 1) όταν ένα άλλο σήμα μας λέει ότι ήλθε η ώρα να την αποθηκεύσουμε. Γιά τις εφαρμογές αυτές, το κατάλληλο κύκλωμα μανταλωτή είναι αυτό που φαίνεται δίπλα. Εδώ έχουμε ένα μανταλωτή RS του οποίου προηγείται λίγη συνδυαστική λογική: οι δύο πύλες ΚΑΙ φροντίζουν ώστε έγγραφή στο μανταλωτή να γίνεται τότε και μόνο τότε όταν το σήμα Load ("φόρτωσε") είναι ενεργό (Load=1), και ο αντιστροφέας φροντίζει ώστε, όποτε γίνεται εγγραφή (Load=1), ένα και μόνον ένα από τα σήματα R και S να είναι ενεργό (1), καθορίζοντας έτσι το ποιά τιμή θα γραφτεί, και αποκλείοντας την ανεπιθύμητη συνθήκη R=S=1· το ποιό από τα R ή S θα ενεργοποιηθεί καθορίζεται από την είσοδο Data, που φέρνει τα δεδομένα εγγραφής. Το συνολικό αυτό κύκλωμα του μανταλωτή με τη συνδυαστική λογική στην είσοδό του ονομάζεται μανταλωτής τύπου D (D-type latch), παίρνοντας το όνομά του από την είσοδο D (Data).
Το "διάγραμμα χρονισμού" (κάτω από το κύκλωμα)
δείχνει τη συμπεριφορά του μανταλωτή D στο χρόνο.
Ο οριζόντιος άξονας εξυπακούεται ότι είναι ο χρόνος.
Όταν Load=0 (αριστερά και δεξιά στο διάγραμμα),
οι έξοδοι Q και Q' παραμένουν σταθερές,
είτε στο 0 είτε στο 1, όπως δείχνουν οι οριζόντιες γραμμές,
ανάλογα με το ποιά τιμή είχε αποθηκευτεί στο μανταλωτή
την τελευταία φορά που ήταν αναμένο το Load.
Όταν Load=1 (στο μέσον του διαγράμματος),
η έξοδος Q ισούται με την είσοδο Data (με μιά μικρή καθυστέρηση),
η δε έξοδος Q' είναι το συμπλήρωμά τους.
Η σκιασμένη περιοχή στο διάγραμμα της εισόδου Data
δείχνει ότι η είσοδος αυτή μπορεί να μεταβάλεται
στο χρονικό αυτό διάστημα,
δηλαδή να "ανεβοκατεβαίνει",
χωρίς βέβαια να αποκλείεται και να είναι σταθερή,
σε όλο ή σε μέρος αυτού του διαστήματος.
Η είσοδος Data ζητάμε να παραμένει σταθερή, έχοντας την τιμή "A",
μόνο σε ένα "χρονικό παράθυρο"
γύρω από την "κατερχόμενη ακμή" του σήματος Load,
ούτως ώστε η τιμή αυτή A
να προλάβει να μπεί και να αποθηκευτεί με ασφάλεια στο μανταλωτή
προτού σβήσει το σήμα Load,
και να είναι η τελευταία τιμή που μπήκε εκεί πριν σβήσει το Load,
ούτως ώστε να είναι και η τιμή που θα παραμείνει τελικά αποθηκευμένη,
ανεξαρτήτως του ότι η είσοδος Data μπορεί να ξαναλλάξει τιμή
μετά το σβήσιμο του Load.
Το σχήμα δίπλα δείχνει δύο απλά παραδείγματα επαναχρησιμοποίησης ενός αθροιστή. Υποθέτουμε ότι η είσοδος δεδομένων (πλάτους n bits) που έρχεται από αριστερά μας φέρνει μιά συνεχή (χρονική) σειρά από αριθμούς, A[j]. Γιά την τροφοδότηση αυτών των αριθμών θα χρειαστούν προφανώς σήματα χρονισμού, αλλά αυτά δεν θα μας απασχολήσουν προς το παρόν. Στο σχήμα (a), θεωρούμε ότι η χρονική σειρά αποτελείται από ζευγάρια αριθμών, A[2i] και A[2i+1], γιά i=0, 1, 2, ..., και ότι εμείς θέλουμε να υπολογίζουμε το άθροισμα S[i] = A[2i] + A[2i+1] κάθε τέτοιου ζευγαριού αριθμών. Γιά να υπολογίσουμε το S[i], πρέπει να περιμένουμε να έλθει το A[2i+1]· όταν όμως έλθει το A[2i+1], το A[2i] έχει ήδη περάσει και φύγει, άρα γιά να μπορούμε να το προσθέσουμε πρέπει να το έχουμε κρατήσει κάπου --προφανώς σε έναν καταχωρητή. Το κύκλωμα που χρειαζόμαστε λοιπόν φαίνεται στο σχήμα (a). Κάθε φορά που στην είσοδο των αριθμών υπάρχει ο πρώτος από ένα νέο ζευγάρι αριθμών, τον φορτώνουμε (αποθηκεύουμε) στον καταχωρητή (n μανταλωτές). Γιά να γίνει η αποθήκευση αυτή, χρειαζόμαστε ένα σήμα χρονισμού, "newPair", που να μας λέει ότι αυτή τη στιγμή έρχεται ο πρώτος αριθμός ενός νέου ζευγαριού αριθμών· υποθέτουμε ότι το σήμα αυτό μας το δίνει η ίδια πηγή που μας δίνει και τους αριθμούς. Μετά από λίγο, όταν στη είσοδο έχει φτάσει ο δεύτερος αριθμός του ζευγαριού, ο αθροιστής θα βλέπει τους δύο αριθμούς του ζευγαριού στις δύο εισόδους του, κι επομένως θα παράγει (μετά από μιά μικρή καθυστέρηση) το άθροισμά τους στην έξοδό του.
Στο σχήμα (b), τα πράγματα είναι δυσκολότερα. Εδώ θέλουμε να υπολογίζουμε το σωρευτικό άθροισμα S[i] όλων των αριθμών που μας ήλθαν από την αρχή του χρόνου: S[i] = A[0] + A[1] + A[2] + ... + A[i]. Γιά να το πετύχουμε αυτό, κρατάμε το μέχρι προ ολίγου σωρευτικό άθροισμα, S[i-1], σ' έναν καταχωρητή, και προσθέτουμε σε αυτό τον νέο αριθμό, A[i], που μας έρχεται αυτή τη στιγμή. Μόλις γίνει η πρόσθεση αυτή, πρέπει το νέο άθροισμα που υπολογίσαμε, S[i], να αντικαταστήσει το προηγούμενο S[i-1] στον καταχωρητή, ούτως ώστε να είναι έτοιμο γιά την επόμενη πρόσθεση, με τον A[i+1]. Το πρόβλημα όμως είναι το εξής. Μόλις ανάψει το σήμα φόρτωσης του καταχωρητή, Load, ο αριθμός S[i] μπαίνει μέσα στους n μανταλωτές, και αμέσως εμφανίζεται στις εξόδους τους, καταστρέφοντας την τιμή S[i-1] που υπήρχε εκεί πριν ανάψει το Load.
Μόλις όμως καταστραφεί η είσοδος S[i-1] του αθροιστή,
καταστρέφεται και η έξοδος του αθροιστή,
δεδομένου ότι ο αθροιστής είναι συνδυαστικό κύκλωμα
(δεν θυμάται το παρελθόν --κοιτάζει μόνο το παρόν).
Με την καταστροφή της εξόδου του αθροιστή,
καταστρέφεται και η είσοδος του καταχωρητή,
και επειδή το Load δεν πρόλαβε ακόμα να σβήσει,
καταστρέφεται και η τιμή S[i] που είχε προς στιγμήν αποθηκευτεί εκεί.
Μία λύση θα ήταν το Load να σβήσει "πολύ γρήγορα",
πριν προλάβει η καταστροφή της εξόδου του καταχωρητή
να περάσει από τον αθροιστή
και να επιστρέψει στην είσοδο του καταχωρητή.
Σε σπάνιες περιπτώσεις χρησιμοποιείται αυτή η λύση,
αλλά είναι πολύ δύσκολο να επιτευχθεί η ακρίβεια
της χρονικής διάρκειας του Load που απαιτείται.
Αντ' αυτής, υπάρχει μιά απλούστερη λύση
(και οι παραλλαγές της που θα πούμε σε λίγο)
που την ακολουθούμε στη συντριπτική πλειοψηφία των περιπτώσεων.
Η απλούστερη, ασφαλέστερη, και καλύτερη λύση είναι να χρησιμοποιήσουμε μιάν ενδιάμεση, προσωρινή (temporary) θέση αποθήκευσης, tmp, όπως φαίνεται στο σχήμα δίπλα (η τεχνική αυτή λέγεται "double buffering" σε άλλες εφαρμογές στην επιστήμη υπολογιστών). Γιά να αρχίσει μιά νέα πρόσθεση, αντιγράφουμε το προηγούμενο σωρευτικό άθροισμα από την προσωρινή θέση στον καταχωρητή εισόδου του αθροιστή· η τιμή της προσωρινής θέσης δεν επηρεάζεται. Όταν τελειώσει η πρόσθεση, αντιγράφουμε το νέο άθροισμα στην προσωρινή θέση· η τιμή του καταχωρητή εισόδου δεν επηρεάζεται, άρα ούτε και η έξοδος του αθροιστή επηρεάζεται.
Γιά να γίνουν οι δύο αυτές χωριστές μεταφορές χρειαζόμαστε δύο χωριστά σήματα σήματα χρονισμού, φ1 και φ2, σαν σήματα φόρτωσης των καταχωρητών. Επειδή τα σήματα αυτά είναι περιοδικά και μας καθορίζουν το ρυθμό εργασίας του κυκλώματος, τα λέμε "ρολόγια". Επειδή έχουν την ίδια περίοδο και είναι στενά αλληλεξαρτημένα, λέμε ότι πρόκειται γιά τις δύο φάσεις, φ1 και φ2, ενός διφασικού ρολογιού (two-phase clock). Η ιδιότητα που έχουν αυτές οι δύο φάσεις είναι ότι ανάβουν εναλλάξ, και ότι ποτέ δεν είναι αναμένες και οι δύο ταυτόχρονα. Επειδή ποτέ δεν ανάβουν ταυτόχρονα οι φ1 και φ2, ποτέ δεν θα υπάρχει ανοικτός δρόμος διαμέσου ολόκληρου του κύκλου που υπάρχει στο κύκλωμά μας.
Οι λεπτομέρειες της λειτουργίας του κυκλώματος
φαίνονται στο διάγραμμα χρονισμού.
Όταν ανάβει η φάση φ1 του ρολογιού,
η τιμή tmp, που ήταν το προηγούμενο άθροισμα, έστω S[3] εδώ,
μπαίνει στον καταχωρητή S[i-1]
και εμφανίζεται στην είσοδο του αθροιστή.
Αμέσως, η παλαιά τιμή στην έξοδο του αθροιστή, S[i], καταστρέφεται,
αλλά αυτό δεν επηρεάζει την αποθηκευμένη τιμή tmp,
επειδή η φ2 είναι σβηστή.
Αργότερα, μετά την πάροδο της (σημαντικής) καθυστέρησης του αθροιστή,
η έξοδός του, S[i], αποκτά την σωστή τιμή του νέου αθροίσματος, S[4].
Εν τω μεταξύ, η φ1 έχει σβήσει,
και μετά η φ2 έχει ανάψει.
Μόλις ανάψει η φ2 καταστρέφεται η παλαιά τιμή του tmp, S[3],
αλλά αυτό δεν μας πειράζει πιά,
διότι την έχουμε ήδη αντιγράψει στον καταχωρητή S[i-1],
όπου δεν κινδυνεύει πιά, αφού η φ1 έχει σβήσει.
Όταν υπολογιστεί το νέο άθροισμα, S[4],
αυτό αποθηκεύεται στον καταχωρητή tmp,
όπου και παραμένει εν ασφαλεία μετά το σβήσιμο της φ2,
ανεξαρτήτως του ότι η έξοδος του αθροιστή θα αλλάξει σε λίγο.
Πριν φτάσετε στο εργαστήριο
κάντε ένα λεπτομερές σχεδιάγραμμα του κυκλώματος,
όπως στην §4.10.
Επίσης, σκεφτείτε τι θα συμβεί
αν ενεργοποιήστε και τις 2 φάσεις του ρολογιού ταυτόχρονα.
Πώς θα συμπεριφερθεί ο βρόχος αριστερά με τον αντιστροφέα;
Τι θα κάνει η υπόλοιπη αλυσίδα των μανταλωτών;
Στο εργαστήριο, επιβεβαιώστε τη σωστή λειτουργία:
γεννήστε τις 2 φάσεις του ρολογιού πατώντας τους 2 διακόπτες εναλλάξ,
και παρακολουθήστε την "κίνηση" των bits στις LED's.
Δοκιμάστε να ενεργοποιήστε και τις 2 φάσεις του ρολογιού ταυτόχρονα,
και δείτε αν επιβεβαιώνονται οι προβλέψεις σας.
[Up - Table of Contents] [Prev - 6. Signed Int., Subtr.] |
[printer version - PDF] [8. Edge Trigger, Counter - Next] |
Up to the Home Page of CS-120
|
© copyright
University of Crete, Greece.
last updated: 15 Nov. 2011, by M. Katevenis. |