PE3 Dimiourgia ekpaideutikou kuklwmatos 1 - ellak-monades-aristeias/HDL-HELP GitHub Wiki
Σχεδιασμός κυκλώματος λειτουργίας τρίλιζας
Στην προηγούμενη ενότητα (ΠΕ2 – «Σχεδιασμός και επεξήγηση βασικών υποκυκλωμάτων») έγινε η παρουσίαση των ελεγκτών VGA και PS/2 που θα αποτελέσουν δομικούς λίθους για τα δύο πλήρη κυκλώματα που θα παρουσιαστούν στη συνέχεια (ΠΕ3 & ΠΕ4). Έχοντας εξασφαλίσει την διασύνδεση της πλακέτας FPGA με τα δύο αυτά περιφερειακά θα πρέπει πλέον να σχεδιαστεί το ενδιάμεσο κύκλωμα που θα τα χρησιμοποιεί για να επιτύχει ένα συγκεκριμένο σκοπό. Σε αυτή την ενότητα η επιθυμητή λειτουργία που θέλουμε να εκτελείται στο FPGA board είναι η λειτουργία ενός παιχνιδιού τρίλιζας, όπου δύο παίκτες εισάγουν εναλλάξ από ένα σύμβολο ‘Χ’ ή ‘Ο’ μέσω του πληκτρολογίου, σε ένα ταμπλό που εμφανίζεται στην οθόνη και ανανεώνεται με την εισαγωγή νέου συμβόλου στην αντίστοιχη θέση που επιλέγει κάθε φορά ο κάθε παίκτης.
Για την επεξήγηση της μεθοδολογίας προγραμματισμού σε VHDL θα παρουσιαστεί σε αυτή την ενότητα ο σχεδιασμός των υποκυκλωμάτων που λειτουργούν ως ενδιάμεσος κρίκος μεταξύ των δύο ελεγκτών για να προσδώσουν στο κύκλωμα την επιθυμητή λειτουργία. Τα αρχεία των ελεγκτών που βρίσκονται στον φάκελο “FPGA controllers” θα τροποποιηθούν κατάλληλα για τις ανάγκες του κάθε παραδείγματος λειτουργίας (εδώ τρίλιζας). Οι τελικές εκδόσεις όλων των αρχείων βρίσκονται αναρτημένες στο αποθετήριο του έργου στο φάκελο “Ex1: Παιχνίδι Τρίλιζας”.
Η δήλωση ακολουθεί την ίδια λογική με αυτή που αναλύθηκε στην προηγούμενη ενότητα (ΠΕ2 - Σχεδιασμός και επεξήγηση βασικών κυκλωμάτων).
Τα σήματα εισόδου περιλαμβάνουν το ρολόι του κυκλώματος (clk, clk : in std_logic), το σήμα για την επαναφορά του κυκλώματος στην αρχική του κατάσταση (rst, rst : in std_logic) κατά τη λειτουργία του και το κανάλι εξόδου του ελεγκτή του PS/2 πληκτρολογίου που περιέχει τον κωδικό του πλήκτρου που πατήθηκε (keyboard_data : in std_logic_vector(7 downto 0)).
Τα σήματα εξόδου αντίστοιχα περιλαμβάνουν το κανάλι που περιέχει την πληροφορία για την κατάσταση του ταμπλό της τρίλιζας σχετικά με το ποιες θέσεις είναι καταλυμένες και ποιες όχι (board_status : out std_logic_vector(17 downto 0)), ένα σήμα για την ένδειξη του αριθμού νικών του παίκτη με το σύμβολο ‘Χ’ (scoreX : out std_logic_vector(6 downto 0)) και ένα σήμα για την ένδειξη του αριθμού νικών του παίκτη με το σύμβολο ‘Ο’ (scoreO : out std_logic_vector(6 downto 0)). Περισσότερες πληροφορίες για τη συμπεριφορά των σημάτων εξόδου δίνονται στα τμήματα 6 & 7 παρακάτω, όπου και δηλώνεται η λειτουργία του κυκλώματος ελέγχου του ταμπλό της τρίλιζας.
Η δήλωση των σημάτων γίνεται όπως και στην οντότητα με τη χρήση της δεσμευμένης για αυτό το σκοπό λέξης “signal” να προηγείται πάντα της ονομασίας του σήματος. Η δήλωση ακολουθεί την ίδια λογική με αυτή που αναλύθηκε στην προηγούμενη ενότητα (ΠΕ2 - Σχεδιασμός και επεξήγηση βασικών κυκλωμάτων). Όλα τα σήματα που πρόκειται να χρησιμοποιηθούν στην εσωτερική δομή της αρχιτεκτονικής του κυκλώματος θα πρέπει να δηλωθούν ρητά εδώ. Η FSM που δηλώνεται αρχικά εδώ και θα οριστεί στη συνέχεια θα χρησιμοποιηθεί για τον έλεγχο της σειράς που εκτελούν κινήσεις στο ταμπλό οι παίκτες (type state_type is (playX,playO,none)).
Για να αναγνωριστεί η επιθυμία του προγραμματιστεί να ορίσει μια FSM από το Quartus, ώστε να γίνει σωστά η σύνθεσή της, θα πρέπει να πληρούνται κάποιοι κανόνες. Η πρώτη process δηλώνει την εναλλαγή των καταστάσεων μόνο σε κάθε θετική ακμή του ρολογιού (elsif rising_edge(clk) then current_state <= next_state;). Σε αυτό το στάδιο ορίζεται ως αρχική κατάσταση να παίζει πάντα πρώτος ο παίκτης που θα έχει το σύμβολο ‘Χ’ (if rst='0' then current_state <= playX;).
Η δεύτερη process καθορίζει τη σειρά της ακολουθίας καταστάσεων (από ‘playX’ σε ‘playO’ ή ‘none’, από ‘playO’ σε ‘playX‘ ή ‘none’ και από ‘none’ σε ‘playX’). Η αλλαγή στην κατάσταση ένδειξης του ποιος παίκτης θα κάνει την επόμενη κίνηση γίνεται μόλις γίνει η αλλαγή στο ταμπλό της τρίλιζας από την επιλογή του άλλου παίκτη (elsif status_changed='1' then next_state <= playO/Χ;). Αρχική κατάσταση ορίζεται η τοποθέτηση πρώτα του συμβόλου ‘X’ και μετά εναλλάξ κάθε φορά που επιλέγεται έγκυρη θέση πάνω στο ταμπλό. Η κατάσταση ‘none’ γίνεται έγκυρη μόνο όταν ανιχνευθεί ότι κάποιος από τους δύο παίκτες συμπλήρωσε τρία διαδοχικά σύμβολα πάνω στο ταμπλό και κέρδισε τη συγκεκριμένα παρτίδα (if winner='1' then next_state <= none;).
Η τρίτη process δηλώνει την τιμή κάποιων σημάτων ελέγχου ανάλογα με την τρέχουσα κατάσταση του συστήματος της FSM. Αυτή η process ολοκληρώνει την FSM ως προς τη λειτουργία της, δηλαδή του ελέγχου διάφορων σημάτων ανάλογα με την τρέχουσα κατάσταση του συστήματος. Το σήμα ‘newX’ δηλώνει ότι η επόμενη κίνηση ανήκει στον παίκτη που έχει το σύμβολο ‘Χ’ και γίνεται έγκυρο στην κατάσταση ‘playX’ (when playX => newX <= '1';) το σήμα ‘newΟ’ δηλώνει ότι η επόμενη κίνηση ανήκει στον παίκτη που έχει το σύμβολο ‘Ο’ και γίνεται έγκυρο στην κατάσταση ‘playΟ’ (when playO => newO <= '1';). Τα δύο αυτά σήματα είναι ανενεργά στην κατάσταση ‘none’ καθώς η παρτίδα ολοκληρώθηκε με νίκη κάποιου παίκτη και δεν θα πρέπει να επιτρέπεται η εισαγωγή νέων τιμών ακόμα και αν υπάρχουν κενές θέσεις στο ταμπλό. Το σήμα ‘checkBoard’ αντίθετα γίνεται ενεργό μόνο στην κατάσταση ‘none’.
Σε αυτό το τμήμα του σχεδιασμού στόχος είναι να διαβάζονται τα περιεχόμενα του καναλιού ‘keyboard_data*’* που περιέχουν τον κωδικό του πλήκτρου που πιέστηκε ώστε, αν αυτό αντιστοιχεί σε έγκυρη θέση, να ανανεωθεί το σήμα ελέγχου του ταμπλό ‘sig_board_status’ που καθορίζει ποιο σύμβολο τοποθετείται σε ποια θέση. Στο συγκεκριμένο παράδειγμα επιλέχθηκαν τα πλήκτρα ‘Q’,’W’,’E’ για τις τρεις θέσεις της πάνω σειράς από αριστερά προς τα δεξιά, τα πλήκτρα ‘Α’,’S’,’D’ για τις τρεις θέσεις της μεσαίας σειράς από αριστερά προς τα δεξιά και τα πλήκτρα ‘Ζ’,’Χ’,’C’ για τις τρεις θέσεις της κάτω σειράς από αριστερά προς τα δεξιά. Το πλήκτρο ‘N’ επιλέχθηκε για την επαναφορά του ταμπλό της τρίλιζας με όλα τα πεδία κενά, ώστε να ξεκινάει νέα παρτίδα σε περίπτωση νίκης κάποιου παίκτη. Οι κωδικοί για το κάθε πλήκτρο δίνονται στο Σχήμα 1.
Σχήμα 1. Γραφική αναπαράσταση των κωδικών του κάθε πλήκτρου, (http://retired.beyondlogic.org/keyboard/keybrd.htm).
Ανάλογα με την συνθήκη που ενεργοποιείται από τον κωδικό που στέλνεται από το πληκτρολόγιο, θα γίνει η ανάθεση τιμών στο σήμα ‘sig_board_status’. Το σήμα αποτελείται από 18 ψηφία και ο τρόπος που χρησιμοποιείται κρύβει μια ιδιαίτερη κωδικοποίηση. Ανά δύο τα ψηφία του σήματος αντιστοιχίζονται σε μια από τις 9 θέσεις του ταμπλό (για αυτό και 18 ψηφία συνολικά) ξεκινώντας από την πάνω αριστερά προς την κάτω δεξιά γωνία (τα δύο λιγότερο σημαντικά ψηφία πάνω αριστερά, τα δύο επόμενα πάνω και στη μέση, κοκ). Κατά την έναρξη της πρώτης παρτίδας (if rst='0' then sig_board_status <= (others => '0');) ή κατά την επαναφορά του ταμπλό με το πλήκτρο ‘Ν’ (when "00110001" => sig_board_status <= (others => '0');), όλες οι δυάδες ψηφίων του ‘sig_board_status’ έχουν τιμή ‘00’ που σημαίνει ότι σε όλες τις θέσεις μπορεί να τοποθετηθεί κάποιο σύμβολο καθώς η συνθήκη if sig_board_status(a downto b)="00" then είναι αληθείς για όλα τα πλήκτρα. Με την επιλογή κάποιας θέσης, η αντίστοιχη δυάδα τιμών θα πάρει την τιμή ‘01’ ή ‘10’ αν είναι η σειρά του παίκτη ‘Χ’ (if newX='1' then sig_board_status(1 downto 0) <= "01";) ή ‘Ο’ (elsif newO='1' then sig_board_status(1 downto 0) <= "10";) αντίστοιχα. Έτσι το σύστημα θα εμποδίσει σε μελλοντική στιγμή κάποιον παίκτη από το να προσθέσει τιμή σε ήδη καταλυμένη θέση του ταμπλό είτε από τον ίδιο είτε από την συμπαίκτη. Τέλος το σήμα ‘status_changed’ παίρνει για ένα κύκλο ρολογιού την τιμή ‘1’ (status_changed <= '1';), για να γίνει η εναλλαγή στη σειρά κίνησης των παικτών όπως ορίστηκε προηγουμένως στην FSM.
Το σήμα ‘newRound’ ενεργοποιείται στην περίπτωση που πατηθεί το πλήκτρο ‘Ν’ για να γίνει εκκαθάριση του ταμπλό και να ξεκινήσει νέο παιχνίδι. Η δυνατότητα δίνεται πρωταρχικά για την περίπτωση νίκης, όπου το πλήκτρο ‘Ν’ είναι πρακτικά το μόνο ενεργό πλήκτρο του πληκτρολογίου, ώστε να ξεκινήσει νέα παρτίδα, αλλά η εκκαθάριση μπορεί να γίνει και σε οποιαδήποτε άλλη φάση του παιχνιδιού.
Το επόμενο σημαντικό υποκύκλωμα του συστήματος της τρίλιζας είναι η ανίχνευση της περίπτωσης όπου κάποιος παίκτης έχει τοποθετήσει σε τρεις διαδοχικές θέσεις του ταμπλό το σύμβολό του, ώστε να σημειωθεί η νίκη και να πιστωθεί στο σκορ του. Για το σκοπό αυτό το σήμα ‘sig_board_status’, που περιέχει την πληροφορία των καταλυμένων και ελεύθερων θέσεων του ταμπλό, θα πρέπει να ελέγχεται συνεχώς για όλες τις πιθανές περιπτώσεις συμπλήρωσης τρίλιζας από κάποιον παίκτη. Ο έλεγχος αυτός γίνεται εξετάζοντας τις αντίστοιχες δυάδες, που αντιστοιχίστηκαν στην κάθε θέση του ταμπλό όπως εξηγήθηκε προηγουμένως, για κοινή ακολουθία τιμών ‘01’x3 για το ‘Χ’ και ‘10’x3 για το ‘Ο’ (π.χ. sig_board_status(5 downto 0)="010101" για την πάνω γραμμή και το σύμβολο ‘Χ’ ). Αντίστοιχα προκύπτουν και οι υπόλοιπες συνθήκες. Το σύμβολο ‘&’ χρησιμοποιείται εδώ για να ενώσει μη διαδοχικά τμήματα του ‘sig_board_status’, όπως στην περίπτωση της διαγώνιας και κάθετης τρίλιζας. Το σκορ κρατείται στα σήματα ‘sig_winX’ και ‘sig_winΟ’ αντίστοιχα για κάθε παίκτη και ανανεώνονται σε κάθε νίκη (sig_winX <= sig_winX + 1; και sig_winO <= sig_winO + 1;). Το σήμα ‘winner’ ενεργοποιείται σε περίπτωση νίκης για να προκαλέσει τη μετάβαση της FSM στην κατάσταση ‘none’.
Το τελευταίο υποκύκλωμα του παιχνιδιού σχεδιάστηκε για να μεταφέρει την πληροφορία του τρέχοντος σκορ στους παίκτες. Για το σκοπό αυτό χρησιμοποιούνται δύο πίνακες ένδειξης 7 τιμών (7-segment Display) οι οποίοι χρειάζονται ένα είδος αποκωδικοποίησης της τιμής του σκορ για να λειτουργήσουν σωστά. Το Hex Display ελέγχεται από 7 σήματα που καθορίζουν αν το LED τμήμα που ελέγχουν θα είναι αναμμένο ή σβηστό με τη σειρά που φαίνεται στο Σχήμα 2.
Σχήμα 2. Η κωδικοποίηση της οθόνης ένδειξης 7 σημείων.
Για παράδειγμα για να δειχθεί ο αριθμός 1 θα πρέπει να είναι αναμμένα μόνα τα τμήματα δεξιά της οθόνης που ελέγχονται από το δεύτερο και τρίτο λιγότερο σημαντικό ψηφίο αντίστοιχα (when "0001" => winX <= "1111001";). Οι δύο process ρυθμίζουν την αναπαράσταση των αριθμών για το σκορ του παίκτη ‘Χ’ και ‘Ο’ αντίστοιχα.
Η λειτουργία του ελεγκτή VGA παρουσιάστηκε με λεπτομέρεια στην προηγούμενη ενότητα ενώ ο κώδικας βρίσκεται αντίστοιχα στο αποθετήριο της σελίδας του έργου. Στο παράδειγμα της τρίλιζας που εξετάζεται σε αυτή την ενότητα, το αρχείο ‘vga_controller_v1’ θα τροποποιηθεί κατάλληλα για να ταιριάξει στις απαιτήσεις του σχεδίου. Οι βασικές αρχές στα επιμέρους τμήματα της σχεδίασης εντοπίζονται: (α) στη μη χρήση της ενδιάμεσης μνήμης ‘vgaBuffer’ και (β) στην διαφοροποίηση του τμήματος 8 που είναι υπεύθυνο για την προβολή των ενεργών pixel στην οθόνη.
Σε ότι αφορά την μνήμη που εμπεριέχονταν στον κώδικα της προηγούμενης ενότητας, επειδή το ταμπλό της τρίλιζας και οι θέσεις των συμβόλων μέσα σε αυτό έχουν συγκεκριμένες θέσεις προβολής, η εικόνα έχει μια στατική ιδιότητα που διευκολύνει τη μη χρήση της δυναμικής μνήμης για την οικονομία των πόρων της πλακέτας. Έτσι πλέον τα περιεχόμενα του παιχνιδιού προβάλλονται σε σχέση με την εκάστοτε τιμή των μετρητών ‘hcount’ και ‘vcount’ και την τιμή που πρέπει να έχει εκείνη τη στιγμή το κάθε ενεργό pixel. Για παράδειγμα για τις γραμμές του ταμπλό οι συνθήκες:
if ( ( hcount>200 and hcount<220 ) or ( hcount>420 and hcount<440 ) ) then
elsif ( ( vcount>150 and vcount<170 ) or ( vcount>310 and vcount<330) ) then
δημιουργούν τις 4 γραμμές της τρίλιζας με άσπρο χρώμα (red <= (others => '1'); green <= (others => '1'); blue <= (others => '1');) στο μαύρο φόντο της εικόνας χωρίς να απαιτείται η δυναμική αλλαγή στο vgaBuffer.
Tα πρώτα κομμάτια του κώδικα (1-7) έχουν την ίδια λογική με τα αντίστοιχα του ελεγκτή VGA που αναλύθηκαν στην προηγούμενη ενότητα και γι’ αυτό το λόγο δεν αναφέρονται και εδώ.
Εφόσον η μνήμη ‘vgaBuffer’ δεν χρησιμοποιείται σε αυτό το παράδειγμα, για την απεικόνιση των συμβόλων από τα δύο μικρά μπλοκ μνήμης (ROMX, ROMO) θα πρέπει να γίνει συγχρονισμός μεταξύ των κυκλωμάτων ώστε τα περιεχόμενά τους να προβάλλονται στην κατάλληλη θέση και με τη σωστή σειρά για να είναι αναγνώσιμα από του παίκτες. Η process στο τμήμα αυτό του σχεδιασμού έχει το διπλό ρόλο: (α) να επιλέγει αν και ποιο σύμβολο πρέπει να προβάλει σε κάθε θέση του ταμπλό ανάλογα με τα περιεχόμενα του ‘board_status’ και (β) να προβάλει σωστά τα περιεχόμενα των ‘ROMX’ και ‘ROMO’ όταν απαιτείται, ρυθμίζοντας τις τιμές των διευθύνσεων των μνημών (addressX & addressO) με βάση το ‘vcount’ και επιλέγοντας το κατάλληλο ψηφίο από τα δεδομένα εξόδου των μνημών με βάση το ‘hcount’.
Για να επιτευχθούν τα παραπάνω είναι απαραίτητος ο έλεγχος δύο συνθηκών για κάθε μια από τις 9 θέσεις συμβόλων του ταμπλό. Στην πρώτη συνθήκη:
π.χ. if ( ( hcount>68 and hcount<=132 ) and ( vcount>50 and vcount<99 ) ) then
εντοπίζονται τα χρονικά διαστήματα μέσα στα οποία το ενεργό pixel που αποστέλλεται στην οθόνη, βρίσκεται εντός των ορίων του πλαισίου 48x64 pixels που απαιτείται για την προβολή των περιεχομένων της μνήμης ‘ROMX’ και ‘ROMO’. Η συνθήκη του παραδείγματος είναι ενεργή και οριοθετεί ένα κουτί 48x64 pixels μεταξύ των pixel 69-132 των γραμμών 51-98 της οθόνης. Τα παραπάνω νούμερα έχουν υπολογιστεί ώστε το πεδίο προβολής του συμβόλου να κεντράρεται όσο το δυνατόν καλύτερα στη θέση στην πάνω αριστερά γωνία του ταμπλό.
Μετά τον καθορισμό των ορίων προβολής του κάθε συμβόλου στις αντίστοιχες θέσεις η δεύτερη συνθήκη ελέγχει τα περιεχόμενα της αντίστοιχης δυάδας ψηφίων του ‘board_status’ για να καθοριστεί αν πρέπει να γίνει προβολή κάποιου συμβόλου στην θέση αυτή (όταν η τιμή της δυάδας είναι διάφορη του ‘00’) και αν απαιτείται προβολή, το είδος του συμβόλου που πρέπει να προβληθεί (‘01’ για το ‘Χ’ και ‘10’ για το Ο):
π.χ. if ( board_status(1 downto 0)="01") then dataX
-
elsif ( board\_status(1 downto 0)="10") then dataO*
-
else μαύρο χρώμα φόντου*
Επειδή για το παράδειγμα της τρίλιζας η μόνη χρωματική πληροφορία που απαιτείται στην οθόνη είναι ο διαχωρισμός με άσπρο χρώμα των γραμμών και των συμβόλων κόντρα στο μαύρο φόντο του ταμπλό, όλα τα bit των καναλιών RGB έχουν ταυτόχρονα είτε την τιμή του λογικού ‘0’ (όλα σβηστά για μαύρο χρώμα) είτε την τιμή του λογικού ‘1’ (όλα αναμμένα για λευκό χρώμα). Για αυτό χρησιμοποιείται η σύνταξη:
red <= (others => x );
green <= (others => x );
blue <= (others => x );
όπου x το λογικό ‘1’ ή ‘0’.
Τέλος, για το συγχρονισμό των περιεχομένων των μνημών ‘ROMX/O’, με δεδομένο ότι η αρχική συνθήκη εξασφαλίζει ότι βρισκόμαστε εντός της ενεργής ζώνης προβολής του συμβόλου, το μόνο που απαιτείται είναι να αφαιρείται η διαφορά μεταξύ τρέχουσας τιμής ‘hcount’ και ‘vcount’ όταν φτάνουμε στο αριστερό άκρο του κάθε πλαισίου προβολής συμβόλου από κάθε επόμενη και όσο χρόνο παραμένουμε εντός πλαισίου. Για παράδειγμα για τη θέση πάνω και αριστερά, όταν ο «κέρσορας» του ενεργού pixel φτάσει στο σημείο με συντεταγμένες οθόνης (69,51) για να γίνει σωστά η ανάγνωση σχετικά με τις συντεταγμένες ‘hcount’ και ‘vcount’ θα πρέπει:
-
να αφαιρεθεί από το ‘vcount’ το 51 για να διαβαστεί η μηδενική διεύθυνση (addressX <= vcount-51;) και
-
να αφαιρεθεί από το ‘hcount’ το 69 για να διαβαστεί το πρώτο ψηφίο της μηδενικής διεύθυνσης που επιλέχθηκε προηγουμένως (red <= (others => dataX( (conv_integer(hcount) - 69)));).
Χάρη στη συνάρτηση conv_integer(), από τις βιβλιοθήκες της VHDL, που μετατρέπει τα περιεχόμενα ενός σήματος σε ακέραιο αριθμό για την εκτέλεση πράξεων, η αφαίρεση αυτή μπορεί να γίνεται καθώς μετατοπίζεται το ενεργό pixel σε διπλανά κελιά και αυξάνεται το ‘hcount’.
Η παραπάνω λογική εφαρμόζεται με διαφορετικά όρια σε όλες τις πιθανές θέσεις του ταμπλό της τρίλιζας (π.χ. για την πάνω γραμμή και στη μέση: ( hcount>288 and hcount<=352 ) and ( vcount>50 and vcount<99 )) για να γίνει η σωστή προβολή των συμβόλων καθώς εξελίσσεται το παιχνίδι και αυτά εισάγονται σε νέες θέσεις.
Τα αρχεία ‘RomX.vhd’ και ‘RomO.vhd’ περιέχουν την απαραίτητη χρωματική πληροφορία για την απεικόνιση των συμβόλων ‘Χ’ και ‘Ο’, αντίστοιχα. Επειδή το περιβάλλον της οθόνης στο συγκεκριμένο παράδειγμα είναι μονοχρωματικό μεταξύ άσπρου και μαύρου, κάθε pixel του συμβόλου απαιτεί ένα μόνο ψηφίο που θα δηλώνει αν πρέπει να είναι άσπρο (λογικό ‘1’) ή μαύρο (λογικό ‘0’). Όπως φαίνεται από τον ορισμό της οντότητας στο “Part 2”, οι μνήμες αυτές έχουν μία είσοδο τη διεύθυνση της μνήμης και μία έξοδο τα περιεχόμενα της διεύθυνσης αυτής, χωρίς να χρειάζονται κάποιο επιπλέον εσωτερικό σήμα (βλ. “Part 3”). Η ανάθεση των περιεχομένων γίνεται με τη χρήση μια απλής συνθήκης όπου δηλώνονται ανεξάρτητα τα περιεχόμενα για κάθε διεύθυνση (π.χ. για την πρώτη διεύθυνση του πίνακα: when "000000" => data <=0000000000000000000000000001111111100000000000000000000000000000";). Όπως είναι εμφανές από τη δομή του κώδικα, τα κελιά με τιμή ‘1’ σχηματίζουν το περίγραμμα του συμβόλου ‘Χ’ ή ‘Ο’ αντίστοιχα.
Ο ελεγκτής του πληκτρολογίου που χρησιμοποιήθηκε σε αυτό το παράδειγμα είναι ίδιος με τον αντίστοιχο που παρουσιάστηκε στην προηγούμενη ενότητα (ΠΕ2 – «Σχεδιασμός και επεξήγηση βασικών υποκυκλωμάτων») και βρίσκεται αναρτημένος στον φάκελο «FPGA controllers/keyboard» του repository.
Όλα τα παραπάνω υποκυκλώματα σχεδιάστηκαν για να εκτελέσουν μια συγκεκριμένη διαδικασία από τον έλεγχο της οθόνης και του πληκτρολογίου μέχρι τον καθορισμό των κινήσεων των παικτών. Στο τελικό στάδιο του σχεδιασμού θα πρέπει να δημιουργηθεί ένα αρχείο στο οποίο όλα τα υποκυκλώματα θα καλούνται και θα συνδέονται μεταξύ τους για να δημιουργήσουν το ενιαίο λειτουργικό κύκλωμα. Για το παράδειγμα της τρίλιζας το αρχείο αυτό είναι το ‘tictactoe.vhd’.
Στο τελικό κύκλωμα της τρίλιζας θα πρέπει να δηλωθούν τα σήματα αλληλεπίδρασης μεταξύ του FPGA και των περιφερειακών του. Έτσι ως είσοδο για το τελικό κύκλωμα δηλώνονται τα σήματα ρολογιού (‘clk’) και επαναφοράς (‘rst’) μέσω κουμπιού που βρίσκεται πάνω στην πλακέτα και τα δύο σήματα λειτουργίας του πληκτρολογίου PS/2 (‘kClk’ & ‘kData’). Στην έξοδο αντίστοιχα δίνονται τα απαραίτητα σήματα για τη λειτουργία της οθόνης μέσω VGA (‘hsync’, ’vsync’, ’red’, ’green’, ’blue’) και τα δύο κανάλια για την ένδειξη του σκορ στις οθόνης 7 τμημάτων που αναλύθηκαν προηγουμένως (‘scoreX’ & ‘scoreO’). Αξίζει να σημειωθεί ότι τα τρία σήματα που παρατίθενται εδώ ως σχόλια (‘vgaCLK’, ‘blank’, ‘sync’) είναι απαραίτητα για τη λειτουργία του VGA ελεγκτή μόνο σε ορισμένα μοντέλα FPGA (π.χ. DE2-115) και όχι στο μοντέλο (DE1) που χρησιμοποιήθηκε για τον έλεγχο των κυκλωμάτων σε αυτό το έργο. Για λόγους πληρότητας παρέμειναν υπό τη μορφή σχολίου. Επίσης για τον ίδιο λόγο το εύρος των τριών καναλιών ’red’, ’green’, ’blue’, αν και στην πράξη για το μοντέλο DE1 πρέπει να έχει τιμή 4 bit δηλώνεται ως σήμα με 8 bit. Αυτά θα εμφανιστούν απλώς ως warnings κατά την σύνθεση του κυκλώματος από το Quartus και δεν αποτελούν αντικείμενο ανησυχίας.
Όπως έχει παρουσιαστεί και προηγουμένως, τα υποκυκλώματα θα πρέπει αρχικά να δηλωθούν (βλ. Part 3) με βάση την αντίστοιχη μορφή των οντοτήτων τους, και έπειτα να αρχικοποιηθούν (βλ. Part 5) και να συνδεθούν με τα εσωτερικά σήματα (βλ. Part 4). Ως πρόταση καλής πρακτικής προτείνεται τα εσωτερικά σήματα που θα χρησιμοποιηθούν για την ένωση των υποκυκλωμάτων να έχουν ένα ενιαίο πρόθεμα για τον διαχωρισμό τους, διατηρώντας παράλληλα το όνομα του σήματος της οντότητας του υποκυκλώματος που θα συνδέσουν (π.χ. εδώ το πρόθεμα ‘sig_’ πριν την ονομασία).
Όπως φαίνεται από την ένωση των υποκυκλωμάτων στο συγκεκριμένο παράδειγμα, το υποκύκλωμα ‘MoveGen’ παρεμβάλλεται ανάμεσα στους δύο ελεγκτές για να προσδώσει την επιθυμητή λειτουργία της τρίλιζας ελέγχοντας από τα δεδομένα που εισάγονται τα δεδομένα που εξάγονται στην οθόνη. Ο ελεγκτής του πληκτρολόγιου παίρνει την πληροφορία από το πληκτρολόγιο μέσω των σημάτων ‘kClk’ και ‘kData’ και στέλνει τον κωδικό του πλήκτρου το οποίο περνάει στον υποκύκλωμα ελέγχου της τρίλιζας (ένωση μέσω του σήματος ‘sig_keyboard_data’). Από την άλλη πλευρά το υποκύκλωμα ελέγχου της τρίλιζας δίνει στο ελεγκτή της οθόνης την πληροφορία για την κατάσταση του ταμπλό (ένωση μέσω του σήματος ‘sig_board_status’) και τα σήματα του σκορ των δύο παικτών απευθείας στις οθόνες 7 τμημάτων (‘sig_scoreX’ & ‘sig_scoreO’). Τέλος, ο ελεγκτής VGA δίνει τα σήματα συγχρονισμού και χρωμάτων (‘sig_hsync’, ‘sig_vsync’, ‘sig_red’, ‘sig_green’, ‘sig_blue’) στην οθόνη που είναι συνδεμένη στην πλακέτα. Τα σήματα εισόδου ‘clk’ και ‘rst’ μοιράζονται σε όλα τα υποκυκλώματα για την ομαλή λειτουργία του ενιαίου κυκλώματος του παιχνιδιού.
Το τελευταίο βήμα για την ολοκλήρωση του κυκλώματος είναι να αντιστοιχιστούν τα εσωτερικά σήματα εξόδου με εκείνα που έχουν δηλωθεί ως σήματα εξόδου στην οντότητα του αρχείου (π.χ. hsync <= sig_hsync; vsync <= sig_vsync;). Τα περιττά σήματα για την λειτουργία του ελεγκτή παρατίθενται και εδώ ως σχόλια.
Έχοντας ολοκληρώσει το σχεδιασμό του κυκλώματος, μπορεί να ξεκινήσει η μεταφορά του στην πλακέτα. Η όλη διαδικασία για τα μοντέλα της Altera, όπως το DE1 που χρησιμοποιήθηκε για τον έλεγχο εδώ, γίνεται μέσω του λογισμικού Quartus ΙΙ. Αρχικά όλα τα αρχεία που είναι διαθέσιμα στο φάκελο “Ex1: Παιχνίδι Τρίλιζας” θα πρέπει να τοποθετηθούν σε έναν οποιοδήποτε φάκελο του χρήστη. Έπειτα ακολουθείται η διαδικασία όπως περιγράφηκε βήμα προς βήμα στην ενότητα 1 («ΠΕ1 – Παρουσίαση βασικών εργαλείων σχεδίασης») για τη δημιουργία ενός καινούριου project μέσω του wizard της Altera. Προσοχή χρειάζεται στα ακόλουθα σημειά:
-
Το όνομα του project θα πρέπει να ταυτίζεται με αυτό του τελικού κυκλώματος ‘tictactoe’ για να γίνει σωστά η σύνθεση και το path θα πρέπει να δείχνει τον φάκελο που αποθηκεύτηκαν τα αρχεία.
-
Μετά την επιλογή του ονόματος η επόμενη καρτέλα προτρέπει την εισαγωγή αρχείων και θα πρέπει σε αυτή τη φάση να εισαχθούν όλα τα αρχεία επιλέγοντάς τα και πατώντας ‘Add’.
-
Στην επιλογή του κατάλληλου μοντέλου FPGA στην αντίστοιχη καρτέλα του wizard (εδώ το μοντέλο Cyclone II EP2C20F484C7).
Μετά την ολοκλήρωση του Wizard ανοίγει το παρακάτω παράθυρο από όπου με διπλό κλικ ανοίγουμε το βασικό αρχείο του κυκλώματος της τρίλιζας ‘tictactoe’.
Μόλις ανοίξει το αρχείο επιλέγουμε Start Compilation ή πατάμε F5 για να ξεκινήσει ο έλεγχος των αρχείων και η σύνθεση του κυκλώματος όπως φαίνεται στην παρακάτω εικόνα.
Αν όλα γίνουν σωστά όλα τα βήματα του compile θα πάρουν ένα πράσινο τικ και θα εμφανιστεί σχετικό παράθυρο που θα ενημερώνει για την επιτυχή ολοκλήρωση της διαδικασίας, δίνοντας και έναν αριθμό από warnings. Τα πλέον σημαντικά καταχωρούνται την καρτέλα “Critical Warnings” και ενδέχεται να κρύβουν ζητήματα που πρέπει να ληφθούν υπόψιν για να διασφαλιστεί η σωστή λειτουργία του κυκλώματος όταν μεταφερθεί στην πλακέτα.
Στην παρούσα φάση το πρώτο πράγμα που αναμένεται να ζητήσει το Quartus είναι να αντιστοιχίσουμε τα σήματα εξόδου και εισόδου του FPGA με τα πραγματικά κανάλια που βρίσκονται περιμετρικά του chip και το ενώνουν στο φυσικό χώρο με τα περιφερειακά όπως το πληκτρολόγιο και η οθόνη:
Critical Warning (169085): No exact pin location assignment(s) for Χ pins of Υ total pins.
Ο πιο εύκολος τρόπος για να γίνει αναζήτηση του αρχείου tictactoe.qsf που δημιουργείται αυτόματα στον ίδιο φάκελο με το που ολοκληρωθεί η δημιουργία του νέου project. Το όνομα του .qsf αρχείου ταυτίζεται πάντα με το όνομα της οντότητας του project (εδώ tictactoe). Για ευκολία το αρχείο θα πρέπει να αντικατασταθεί με το υπάρχον στο repository του έργου και να ξαναγίνει Compile του project για να αναγνωριστούν οι αλλαγές.
Το επόμενο Critical Warning αναμένεται να τονίζει ότι δεν υπάρχει δήλωση σήματος ρολογιού για το συγκεκριμένο project. Αυτό προκύπτει γιατί το Quartus δεν είναι σε θέση να αναγνωρίσει αυτόματα ότι το σήμα ‘clk’ που χρησιμοποιήθηκε παντού ως σήμα ρολογιού είναι πράγματι το σήμα που πρέπει να θεωρήσει ως ενιαίο ρολόι. Αυτό γίνεται μέσα από τη δήλωση του αρχείου ‘tictactoe.sdc’ το οποίο επίσης είναι διαθέσιμο στο repository και θα πρέπει να τοποθετηθεί στο φάκελο του project.
Critical Warning (332012): Synopsys Design Constraints File file not found: 'xx.sdc'. A Synopsys Design Constraints File is required by the TimeQuest Timing Analyzer to get proper timing constraints. Without it, the Compiler will not properly optimize the design.
Μετά τις παραπάνω αλλαγές το compile αναμένεται να δώσει ένα αποτέλεσμα όπως αυτό που φαίνεται στην παρακάτω εικόνα. Τα 12 pins που δεν έχουν τοποθετηθεί είναι τα 4 πιο σημαντικά ψηφία των καναλιών ‘red’, ‘green’, ‘blue’ που δηλώθηκαν με εύρος 8 bit ενώ απαιτούνται 4. Το συγκεκριμένο warning δεν αποτελεί λόγος ανησυχίας και μπορούμε να συνεχίσουμε με τη μεταφορά του κυκλώματος στην πλακέτα.
Για τον προγραμματισμό της πλακέτας θα πρέπει πρώτα να συνδεθεί μέσω USB με τον υπολογιστή του χρήστη. Επιπλέον, θα πρέπει να συνδεθούν στην πλακέτα και τα απαραίτητα περιφερειακά (πληκτρολόγιο και οθόνη) στις αντίστοιχες υποδοχές. Η τροφοδοσία για το μοντέλο DE1 γίνεται μέσω του USB καλωδίου και δεν απαιτείται επιπρόσθετη παροχή ρεύματος. Η πλακέτα τίθεται σε λειτουργία πατώντας το κόκκινο κουμπί στην αριστερή πλευρά. Μόλις ενεργοποιηθεί, η πλακέτα θα προβάλει μια εικόνα με το σήμα της Altera στην οθόνη που είναι προ-εγκατεστημένη στο εσωτερικό της και θα μείνει αδρανής περιμένοντας τον προγραμματισμό της.
Για να «κατεβάσουμε» το πρόγραμμα από το Quartus στην πλακέτα επιλέγουμε το εικονίδιο του “Programmer” όπως φαίνεται στην παρακάτω εικόνα:
Η καρτέλα που ανοίγει είναι η ακόλουθη:
Αν δεν έχει αναγνωριστεί αυτόματα, από την επιλογή “Hardware Setup” επιλέγουμε τον οδηγό “USB-Blaster” και επιλέγουμε “Start”. Η μπάρα “Progress” θα ξεκινήσει να γεμίζει καθώς τα δεδομένα μεταφέρονται στην πλακέτα για τον προγραμματισμό της. Μόλις ολοκληρωθεί η διαδικασία αυτή το κύκλωμα έχει κατεβεί με επιτυχία και η πλακέτα είναι έτοιμη για χρήση.
ΠΡΟΣΟΧΗ! Πριν από τη χρήση ανεξαρτήτως παραδείγματος και κυκλωμάτων προτείνεται να γίνει η επαναφορά στην αρχική του κατάσταση όπως αυτή έχει δηλωθεί κατά το σχεδιασμό για να μην υπάρχουν αποκλίσεις στη συμπεριφορά του.
Οι παρακάτω εικόνες είναι ενδεικτικές του πως αναμένεται να λειτουργήσει το κύκλωμα της τρίλιζας που σχεδιάστηκε σε αυτή την ενότητα:
Εικόνα 1. Η αρχική κατάσταση του κυκλώματος της τρίλιζας μετά την μεταφορά του κώδικα στην πλακέτα.
Εικόνα 2. Εισάγοντας τιμές από το πληκτρολόγιο σε διάφορες θέσεις του ταμπλό πατώντας τα αντίστοιχα πλήκτρα.
Εικόνα 3. Συμπλήρωση τριών όμοιων συμβόλων και καταχώρηση νίκης για το παίκτη ‘Χ’.
Εικόνα 4. Επαναφορά του ταμπλό σε νέα παρτίδα από το πληκτρολόγιο με το πλήκτρο ‘Ν’.