מודול הוא יחידת הבסיס של Verilog
כל דבר ב-Verilog חי בתוך module. מודול עוטף חלק ממעגל: הוא מצהיר אילו אותות נכנסים, אילו אותות יוצאים, ואילו wire-ים, רגיסטרים ולוגיקה נמצאים ביניהם. כל שבב שראיתם אי פעם הוא עץ של מודולים שיוצרים מופעים של מודולים אחרים, עד לרמת השערים הבסיסיים שהיצרן מספק.
הצורה תמיד זהה:
module name(port_list);
// הצהרות: wire, reg, parameter
// גוף: assigns, מופעים, בלוקי always
endmodule
נבנה מודול שלם בשלבים.
המודול השימושי הקטן ביותר: שער AND עם שתי כניסות
אנחנו צריכים משהו פשוט ועצמאי. שער AND עם שתי כניסות מושלם: שתי כניסות, יציאה אחת ושורה אחת של לוגיקה.
הריצו את הקוד. אתם אמורים לראות את ארבע השורות של טבלת האמת של AND. בואו נעבור על כל חלק.
קריאת הצהרת המודול
module and_gate(
input wire a,
input wire b,
output wire y
);
module and_gateמצהיר על מודול בשםand_gate. דרך השם הזה מודולים אחרים ייצרו ממנו מופעים.- הרשימה בסוגריים היא רשימת הפורטים: האותות שנראים מבחוץ.
input wire a:aהוא פורט כניסה, והואwire(מוזן מבחוץ).output wire y:yהוא פורט יציאה שמוזן על ידי משהו בתוך המודול.
אם רוצים לקצר אפשר לכתוב input a במקום input wire a: הכיוון לבדו קובע שהטיפוס המוגדר כברירת מחדל הוא wire. אבל להיות מפורשים זה הרגל ששווה לפתח. פורטים של מודול מכסה את כל צורות הפורטים.
הגוף
assign y = a & b;
זו השמה רציפה. היא אומרת "בכל פעם ש-a או b משתנים, חשב מחדש את y כ-AND ביטי של שניהם". אין שעון ואין תזמון: הקשר תמיד מתקיים. זו לוגיקה צירופית טהורה.
endmodule סוגר את הבלוק. המודול גמור.
ה-testbench
אי אפשר להריץ את and_gate לבד. צריך מודול שני שמזין את הכניסות שלו וצופה ביציאות. זה ה-testbench, ולפי המוסכמה קוראים לו test, tb או <design>_tb.
module test;
reg a, b;
wire y;
and_gate dut(.a(a), .b(b), .y(y));
...
endmodule
שלושה דברים לשים לב אליהם:
- אין רשימת פורטים. testbench הוא הרמה העליונה של הסימולציה: אין שום דבר מחוצה לו.
reg a, bו-wire y. הכניסות של התכנון שנבדק (DUT) הןregב-testbench, כי אנחנו מזינים אותן מתוך בלוק פרוצדורלי. היציאה היאwire, כי ה-DUT מזין אותה.and_gate dut(.a(a), .b(b), .y(y)). זו יצירת מופע (instantiation). אנחנו מייצרים עותק שלand_gateוקוראים לוdut(שם נפוץ, קיצור של "design under test"). התחביר.a(a)אומר "חבר את הפורט בשםaבמופע לאות המקומי בשםa". יצירת מופע של מודול נכנס לעומק.
הגירוי
initial begin
a = 0; b = 0; #1 $display("a=%b b=%b y=%b", a, b, y);
a = 0; b = 1; #1 $display("a=%b b=%b y=%b", a, b, y);
a = 1; b = 0; #1 $display("a=%b b=%b y=%b", a, b, y);
a = 1; b = 1; #1 $display("a=%b b=%b y=%b", a, b, y);
$finish;
end
בלוק ה-initial רץ פעם אחת בתחילת הסימולציה. בתוכו:
a = 0; b = 0;מזינים את הכניסות. אלה השמות blocking: הסדר חשוב, וכל אחת מתבצעת לפני הבאה.#1מקדם את זמן הסימולציה ביחידה אחת. צריך את זה כדי ש-yיספיק להתייצב אחרי שהכניסה משתנה. בלי ה-#1,$displayהיה מדפיס את הערך הישן שלy.$display(...)מדפיס לקונסולת הסימולציה. מחרוזת הפורמט עובדת כמוprintfשל C:%bהוא בינארי,%dהוא עשרוני,%hהוא הקסדצימלי,%tהוא זמן הסימולציה.$finishמסיים את הסימולציה. בלעדיו הסימולטור היה ממשיך לקדם את הזמן לנצח ולחכות לאירוע שלא מגיע.
נסו לשבור את זה
שנו את המודול לשער OR (החליפו את & ב-|) והריצו שוב. טבלת האמת משתנה. עכשיו נסו XOR:
אותו שלד. אופרטור אחר. זה כל הסיפור בלוגיקה צירופית: מצהירים על פורטים, כותבים assign, עוברים על הכניסות וצופים ביציאות.
מודול עם שתי יציאות
למודולים יכולה להיות יותר מיציאה אחת. הנה חצי מחבר: שתי כניסות, סכום ונשא יוצא:
שתי פקודות ה-assign יושבות זו ליד זו אבל מתרחשות במקביל: אין כאן "קודם מחשבים את הסכום ואז את הנשא". שתיהן מתקיימות תמיד. זה המקביליות שדיברנו עליה בחומרה מול תוכנה, בצורה מוחשית.
מה אתם יודעים עכשיו
ראיתם את כל השלד של קובץ Verilog: מודול תכנון עם פורטים מוצהרים וגוף, ועוד מודול testbench שיוצר ממנו מופע, מזין את הכניסות שלו בבלוק initial ומדווח על התוצאות. כמעט כל קובץ מקור של Verilog שתקראו אי פעם מתאים לתבנית הזו. שאר השפה הוא פשוט מילוי של לוגיקה עשירה יותר, אותות מרובי ביטים, התנהגות מתוזמנת בשעון ו-testbench גדולים יותר.
בהמשך: הערות וסגנון קוד, כדי שהמודולים שלכם יישארו קריאים ככל שהם גדלים.
שאלות נפוצות
מהו מודול ה-Verilog הפשוט ביותר?
מודול ה-Verilog החוקי הקטן ביותר הוא פשוט module name; endmodule: בלי פורטים ובלי גוף. הקטן ביותר ששימושי הוא מודול עם פלט אחד: module and_gate(input wire a, input wire b, output wire y); assign y = a & b; endmodule. זה קטע אמיתי של לוגיקה צירופית שאפשר לשלב בכל תכנון גדול יותר.
איך מריצים מודול Verilog?
אי אפשר להריץ מודול לבד: הוא תיאור של מעגל, לא תוכנית. כותבים מודול testbench שיוצר מופע של התכנון ומזין את הכניסות שלו, ואז מקמפלים את שניהם עם iverilog -o sim design.v test.v ומריצים vvp sim. העורך בדפדפן שבדף הזה מבצע את שני השלבים בשבילכם כשמריצים את הקוד.
מה זה testbench ב-Verilog?
testbench הוא מודול שני, בדרך כלל בלי פורטים, שתפקידו להפעיל את התכנון שלכם. הוא יוצר מופע של התכנון, משנה את הכניסות שלו דרך בלוק initial, צופה ביציאות עם $display או $monitor, וקורא ל-$finish בסיום. testbench לא ניתן לסינתזה: הוא קיים רק כדי לאמת התנהגות.
למה הקוד שלי ב-Verilog צריך $finish?
כי חומרה אף פעם לא עוצרת. סימולטור מדמה זמן שעובר, ובלי $finish מפורש הוא ימשיך להתקדם לנצח ולחכות לאירועים חדשים. $finish אומר לסימולטור 'סיימנו, צא בצורה מסודרת'. ב-testbench זו השורה האחרונה בבלוק ה-initial: מריצים את הבדיקה ואז מסיימים.