Σειρά Ασκήσεων 8:
Δεύτερη Γνωριμία με τη Γλώσσα Verilog
Προθεσμία έως Δευτέρα 24 Μαρτίου (βδομάδα 6)
Υπενθύμιση: Διαγωνισμός Προόδου Σάββατο, 5 Απριλίου, ώρα 10:00 - 12:00
Ο σκοπός αυτής της σειράς ασκήσεων είναι
η παρουσίαση ορισμένων επιπλέον δυνατοτήτων της γλώσσας Verilog και
η περαιτέρω εξοικείωση σας με τα συναφή εργαλεία.
Συγκεκριμένα θα χρησιμοποιήσουμε:
- Συνδυαστικά και ακολουθιακά στοιχεία από τη βιβλιοθήκη του μαθήματος
(lib8_mux2, lib8_mux4, lib8_alu, lib8_reg).
- Σταθερές και σήματα πολλών bits.
- Ρολόϊ.
Οι επιμέρους άσκησεις της σειράς 8 περιλαμβάνουν:
-
Μελέτη ενός κυκλώματος και της περιγραφής του σε Verilog που δίδονται.
-
Προσομοίωση του κώδικα με τον interpreter της Verilog-XL.
-
Έλεγχος των εξόδων του συστήματος
με το εργαλείο κυματομορφών Signalscan.
-
Επέκταση του κώδικα για να περιλαμβάνει νέα κυκλώματα
και επαναπροσομοίωση και έλεγχο εξόδων.
Άσκηση 8.1:
Περιγραφή Κυκλώματος σε Verilog
Το κύκλωμα με το οποίο θα ξεκινήσουμε φαίνεται στο σχήμα δίπλα.
Τα άσπρα βέλη χρησιμοποιούνται για να δείξουν
ότι τα σύρματα αυτά είναι είσοδοι ή έξοδοι απο το σύστημα μας.
Το σύστημα διαβάζει τις εισόδους
in_a και
in_b
σε κάθε κύκλο ρολογιού
clk,
υπολογίζει την πράξη μεταξύ τους
--όπως ορίζει το
alu_op--
και τέλος αποθηκεύει στον καταχωρητή εξόδου
είτε το αποτέλεσμα αυτό ή την είσοδο
in_b
(από τον καταχωρητή εισόδου).
Ο κώδικας που περιγράφει το κύκλωμα αυτό σε Verilog
είναι ο εξής:
module ask8a (out, in_a, in_b, alu_op, mux_sel, clk);
output [31:0] out; // data output
input [31:0] in_a, in_b; // data inputs
input [1:0] alu_op; // control inputs
input mux_sel;
input clk; // clock
// declare internal signals:
wire [31:0] reg_a, reg_b, alu_out, mux_out;
// input registers:
lib8_reg #32 r0 (reg_a, in_a, clk);
lib8_reg #32 r1 (reg_b, in_b, clk);
// ALU:
lib8_alu #32 alu0 (alu_out, reg_a, reg_b, alu_op);
// mux:
lib8_mux2 #32 m0 (mux_out, alu_out, reg_b, mux_sel);
// output register:
lib8_reg #32 r2 (out, mux_out, clk);
endmodule
-
Μετά το όνομα του module τοποθετούμε τη λίστα των σημάτων
τα οποία αποτελούν τη διεπαφή (interface)
του module με το υπόλοιπο κύκλωμα.
Για κάθε σήμα ορίζουμε αν είναι είναι σήμα εισόδου ή σήμα εξόδου
καθώς και το πλάτος του (βλέπε επόμενη βούλα).
Ας σημειωθεί ότι για να ορίζαμε πλήρως τη διεπαφή ενός module
θα έπρεπε να περιγράψουμε και τη χρονική συμπεριφορά
των σημάτων εισόδου/εξόδου,
με τη βοήθεια κυμματομορφών παρόμοιων με αυτές του "signalscan".
Στο μάθημα αυτό δεν θα προχωρήσουμε τόσο πολύ
--όποτε χρειαστεί να περιγράψουμε χρονική συμπεριφορά εισόδων/εξόδων
θα το κάνουμε στο χαρτί.
-
Η γλώσσα Verilog υποστηρίζει και σήματα πολλών bits (vectors).
Π.χ. η δήλωση "wire [31:0] reg_a, reg_b, ..." σημαίνει ότι
τα σήματα reg_a και reg_b έχουν πλάτος 32 bits,
το πιο σημαντικό bit το ονομάζουμε bit 31,
και το λιγότερο σημαντικό bit το ονομάζουμε bit 0.
Μετά από μιά τέτοια δήλωση,
αν γράψουμε "reg_a[3]" σημαίνει
το bit 3 από το σήμα reg_a,
ενώ αν γράψουμε "reg[31:27]" σημαίνει
τα 5 πιό σημαντικά bits του reg_a.
-
Το κύκλωμα μας αποτελείται από
τρία αντίτυπα του module lib8_reg,
ένα αντίτυπo του module lib8_mux2, και
ένα αντίτυπo του module lib8_alu.
Η γλώσσα Verilog υποστηρίζει την παραμετροποίηση των modules,
δηλ. ένα module μπορεί να έχει μία ή περισσότερες παραμέτρους
στις οποίες δίνουμε τιμή
κάθε φορά που δημιουργούμε ένα αντίτυπο από το module.
Έτσι, το "#32" μεταξύ του "lib8_reg" (όνομα του module)
και του "r0" (όνομα του αντίτυπου)
δίνει την τιμή 32 σε μία παράμετρο
του module "lib8_reg" από τη βιβλιοθήκη του μαθήματος
η οποία δηλώνει το πλάτος του "lib8_reg",
δηλαδή πόσα bits έχει αυτός ο καταχωρητής.
-
Το module "lib8_alu" είναι μιά απλή αριθμητική/λογική μονάδα.
Η είσοδος ελέγχου της, alu_op, καθορίζει την πράξη που κάνει η μονάδα
ως εξής:
- 00
- πρόσθεση: out = inA + inB.
- 01
- αφαίρεση: out = inA - inB.
- 10
- bitwise OR: out = inA OR inB.
- 11
- bitwise AND: out = inA AND inB.
-
Για μεγαλύτερη αναγνωσιμότητα του κώδικα Verilog,
συνηθίζουμε να δημιουργούμε τα αντίτυπα των στοιχείων του κυκλώματος
με τη σειρά που εμφανίζονται στο κύκλωμα.
Γράψτε το παραπάνω module στο αρχείο "
ask8a.v"
--αυτή είναι η περιγραφή του κυκλώματος.
Σε αυτήν την άσκηση,
το περιβάλλον ελέγχου (test bench) θα είναι σε ξεχωριστό αρχείο,
και δίδεται έτοιμο:
~hy225/verilog/test/test8a.v
Αντιγράψτε το αρχείο αυτό στην περιοχή σας.
Η βασική δομή του έχει ως εξής:
`define clk_period 10
module test;
...
// clock:
reg clk;
initial clk = 1;
always begin
#(`clk_period / 2)
clk = ~clk;
end
...
// instantiate the design:
ask8a a0 (out, in_a, in_b, alu_op, mux_sel, clk);
...
// vectors:
initial begin
...
@(posedge clk);
#(`hold);
in_a = 3;
in_b = 'hFFFF;
alu_op = 0;
mux_sel = 1;
@(posedge clk);
...
end
...
endmodule
-
Το "`define" στη γλώσσα Verilog
είναι ανάλογο με το "#define" στη γλώσσα C.
Με τη βοήθεια της define ορίζουμε την σταθερά "clk_period"
που παρακάτω την χρησιμοποιούμε σαν περίοδο του ρολογιού μας.
Σε αυτή την άσκηση έχουμε θέσει τη μονάδα χρόνου στο 1 ns,
μέσω της βιβλιοθήκης lib8.v που θα χρησιμοποιήσετε.
Έτσι, το παραπάνω `define
θέτει την περίοδο του ρολογιού σε 10 ns.
-
Η εντολή "always" σημαίνει:
ξεκίνα τη χρονική στιγμή 0 και συνέχισε
εκτελώντας επαναληπτικά τις εντολές μέσα στο block που ακολουθεί.
Έτσι, το παραπάνω μπλόκ "always" για το ρολόι θα έχει σαν αποτελέσμα
να αλλάζει η τιμή του σήματος clk κάθε (`clk_period / 2) ns.
-
Η εντολή "@(event)" σημαίνει:
περίμενε μέχρι να συμβεί το event.
Το event μπορεί να είναι
είτε μια οποιαδήποτε αλλαγή στην τιμή ενός σήματος "sig",
το οποίο το δηλώνουμε σαν "@(sig)",
ή η θετική ακμή ενός σήματος "sig",
το οποίο το δηλώνουμε σαν "@(posedge sig)",
ή η αρνητική ακμή, "@(negedge sig)".
-
Αφού έρθει η θετική ακμή του ρολογιού,
δηλ. "@(posedge clk)",
περιμένουμε ακόμα λίγο, δηλ. "#(`hold)",
πριν αλλάξουμε τις τιμές στα σήματα εισόδου,
προκειμένου να μην παραβιάσουμε το "hold time"
για τους καταχωρητές του κυκλώματος.
-
Σταθερές πολλών bits δηλώνονται με τη μορφή
[πλάτος]'[βάση][τιμή].
-
To [πλάτος] είναι μία δεκαδική τιμή
που καθορίζει το πλάτος της σταθεράς σε bits,
δηλαδή πόσα bits θα έχει η σταθερά.
Εάν παραλειφθεί το [πλάτος],
το default εξαρτάται από το μηχάνημα όπου τρέχει η Verilog,
αλλά είναι τουλάχιστο 32 bits.
Επέκταση του πλάτους γίνεται με zero-filling
(εκτός των περιπτώσεων "x" και "z" που δεν θα ασχοληθούμε).
-
H [βάση] καθορίζει την αριθμητική βάση
στην οποία είναι γραμμένη η [τιμή] της σταθεράς.
Η δεκαδική βάση δηλώνεται με "d", η δυαδική με "b",
και η δεκαεξαδική με "h".
Εάν παραλειφθεί η [βάση],
το default είναι δεκαδική βάση.
Έτσι π.χ., η σταθερά "32'hF" έχει πλάτος 32 bits,
και έχει την δεκαεξαδική τιμή 0000000F,
οπότε μπορεί να γραφεί και ως
"32'b1111", ή "32'b00001111", ή "32'd15", ή κλπ.
Θα χρειαστεί επίσης να αντιγράψετε στην περιοχή σας το αρχείο:
~hy225/verilog/lib/lib8.v
που περιέχει τη βιβλιοθήκη των modules
που χρησιμοποιεί το
ask8a,
δηλ. καταχωρητές (
lib8_reg),
αριθμητική/λογική μονάδα (
lib8_alu),
και πολυπλέκτες (
lib8_mux2).
Για να τρέξετε την προσομοίωση ακολουθήστε βήματα
όπως εκείνα της άσκησης 4:
% xhost +
% rlogin [katalliloMixanima]
% setenv DISPLAY [arxikoMixanima]:0.0
% source ~hy225/verilog/scripts/cds_ldv.sh
% verilog lib8.v ask8a.v test8a.v
όπου
[arxikoMixanima] είναι το όνομα της μηχανής
από την οποία κάνετε rlogin,
και
[katalliloMixanima] είναι ένα από τα:
apraktias, livas, levantes, pounentes, graegos, zefyros
Ελέγξτε ότι οι έξοδοι έχουν σωστή τιμή με βάση τις εισόδους.
Προσοχή στο ποιές είσοδοι περνούν απο καταχωρητή και ποιές όχι!
Άσκηση 8.2: Έλεγχος Κυματομορφών με Signalscan
Χρησιμοποιήστε το εργαλείο
signalscan,
όπως στην
άσκηση 4.2,
γιά να δείτε τις κυματομορφές για τα σήματα του κυκλώματός.
-
Αφού τρέξει το γραφικό περιβάλλον του προγράμματος,
ακολουθήστε ανάλογα βήματα με την
άσκηση 4.2
για να δείτε τις κυματομορφές για όλα τα σήματα του test:
out, in_a, in_b, alu_op, mux_sel, clk.
Ελέγξτε και πάλι τις τιμές τους.
-
Πάλι με τον Design Browser,
αν επιλέξουμε "test" και μετά "a0"
(το "a0" είναι το instance name με το οποίο έχουμε δηλώσει
το αντίτυπο του module ask8a)
μπορούμε να διαλέξουμε και τα εσωτερικά σήματα του "a0".
Επιλέξτε τα κατάλληλα σήματα προκειμένου να μετρήσετε
την ελάχιστη και μέγιστη καθυστέρηση
clock-to-output του καταχωρητή,
και την ελάχιστη και μέγιστη καθυστέρηση
γιά τα συνδυαστικά blocks (alu και mux2).
Οι καθυστερήσεις είναι της τάξης των εκατοντάδων picoseconds.
-
Προαιρετική άσκηση:
Βρείτε το critical path του κυκλώματος και, αντίστοιχα,
την υψηλότερη συχνότητα ρολογιού στην οποία δουλεύει το κύκλωμα.
Εφαρμόστε την (θέτοντας κατάλληλα το "clk_period")
και δείτε ότι δουλεύει,
ενώ αν βάλετε λίγο γρηγορότερο ρολόι το κύκλωμα παύει να δουλεύει.
Οι χρόνοι setup και hold του καταχωρητή
είναι 0.2 ns και 0.1 ns αντίστοιχα.
ΠΡΟΣΟΧΗ:
σε ώρες πυκνής χρήσης, αποφύγετε να μένετε πολλή ώρα
μέσα στο εργαλείο signalscan:
έχουμε περιορισμένο αριθμό αδειών χρήσης (licenses),
κι έτσι άλλοι συνάδελφοί σας μπορεί να μην μπορούν να μπούν σε αυτό.
Άσκηση 8.3:
Τροποποίηση του Κυκλώματος
Τροποποιήστε το κύκλωμα που σας δόθηκε παραπάνω,
ώστε να γίνει όπως στο σχήμα εδώ.
Η καινούρια προσθήκη επιτρέπει το αποτέλεσμα να είναι ίσο με
(in_a + 4), όταν
mux_sel == 0.
Τα στοιχεία που είναι καινούρια,
ή που πρέπει να αλλάξουν απο το προηγούμενο σχέδιο,
είναι απεικονισμένα με παχύτερες γραμμές.
Γιά τον μεγαλύτερο πολυπλέκτη,
θα χρειαστεί να αλλάξετε το module
mux2
στο αμέσως μεγαλύτερο, "
mux4",
και να συνδέσετε μια τυχαία τιμή στην τελευταία του είσοδο
(π.χ. ένα σύρμα με την τιμή 0).
Οι πόρτες του module
mux4 έχουν δηλωθεί στη βιβλιοθήκη,
κατ' αναλογία με τις πόρτες του module
mux2,
με τη σειρά:
έξοδος, είσοδος00, είσοδος01, είσοδος10, είσοδος11, σήμα ελέγχου.
Σύρματα με σταθερές τιμές μπορείτε να ορίσετε π.χ. με:
wire [31:0] const_in;
assign const_in = 32'h4;
Υλοποιήστε την επέκταση αυτή σε ένα διαφορετικό αρχείο,
"
ask8b.v",
με όνομα module "
ask8b" αντί "
ask8a",
και δοκιμάστε την όπως προηγουμένως,
χρησιμοποιώντας όμως το αρχείο
"
~hy225/verilog/test/test8b.v".
Παραδώστε, όπως και στις προηγούμενες ασκήσεις,
τον κώδικά σας
ask8b.v,
ένα χαρακτηριστικό στιγμιότυπο από το signalscan της άσκησης 8.2,
και ένα άλλο από το Signalscan της άσκησης 8.3,
πακεταρισμένα στο αρχείο "
ask8.tar", μέσω:
tar -cvf ask8.tar ask8b.v signals82.jpg signals83.jpg
~hy225/bin/submit 8