בלוק פרוצדורלי חד פעמי
initial begin ... end הוא האח של always. ההבדל: initial רץ בדיוק פעם אחת, מתחיל בזמן 0, ואז מסתיים. אין רשימת רגישות ואין חזרה.
הוא קיים מסיבה אחת: הכנת testbench. קביעת ערכים התחלתיים, התחלת הגירוי, פתיחת קובצי לוג, קריאה ל-$finish אחרי זמן סימולציה קבוע: כל הדברים שרוצים שיקרו פעם אחת בתחילת הריצה, בסדר ידוע.
עברו על מה שהסימולטור עושה:
- הזמן מתקדם ל-0.
- בלוק ה-
initialמתחיל. ה-$displayהראשון מדפיס. dataמקבל את הערך8'hA5.#10מקדם את הזמן המדומה ב-10 יחידות.- ה-
$displayהשני מדפיס. $finishמסיים את הסימולציה.
הבלוק רץ פעם אחת. אין מעבר שני.
שלד ה-testbench הקנוני
כמעט כל testbench שתכתבו אי פעם משתמש בבלוק initial כזה:
הסתכלו על הצורה: זו תבנית ה-testbench שתחזרו אליה בכל פעם:
- פתיחת קובץ ה-VCD (
$dumpfile,$dumpvars), מוסבר ב-Dumpfile ו-VCD. - קביעת ערכים התחלתיים והחזקת reset לכמה מחזורים.
- הזנת גירוי דרך סדרה של שינויים, עם השהיות
#ביניהם. $finishכדי לסיים את הסימולציה בצורה נקייה.
זה הכול. כל בדיקת Verilog שתראו, כולל אלה שבדוגמאות של היצרנים, בנויה לפי התבנית הזו.
כמה בלוקי initial רצים במקביל
כמה בלוקים של initial באותו מודול מתחילים כולם בזמן 0 בו זמנית. כל אחד מריץ את ההוראות שלו בפרוסת זמן משלו:
הסימולטור מתחיל את שני הבלוקים בזמן 0. ה-$display הראשון של בלוק B רץ מיד. בלוק A מחכה 5 יחידות לפני שהוא מדפיס. בלוק B מדפיס שוב בזמן 2. ההדפסה השנייה של בלוק A מופעלת בזמן 15. ה-$finish של בלוק B עוצר את הסימולציה בזמן 22.
פיצול ההכנה, יצירת השעון והגירוי לבלוקים נפרדים של initial הוא סגנון נפוץ: כל בלוק קצר ועושה דבר אחד.
אתחול בתוך ההצהרה
צורה קומפקטית נפוצה: לאתחל reg כבר בזמן ההצהרה. רוב הסימולטורים מתייחסים לזה כמו ל-initial:
reg clk = 0;
reg reset = 1;
reg [7:0] count = 0;
זה שקול ל:
reg clk;
reg reset;
reg [7:0] count;
initial begin
clk = 0;
reset = 1;
count = 0;
end
את הצורה הקומפקטית תראו ב-testbenches: היא שמה את הערך ההתחלתי ממש ליד ההצהרה, שם קל לסרוק אותו.
initial הוא לסימולציה בלבד
כלי סינתזה מתעלמים מבלוקים של initial. לחומרה אמיתית אין "רגע אפס" שבו רץ קוד הכנה: יש הדלקה, אותות reset, והתצורה שנובעת מהאירועים האלה. אם צריך שאוגר יתחיל במצב ידוע בחומרה אמיתית, מזינים אותו עם אות reset בתוך always @(posedge clk):
always @(posedge clk) begin
if (reset) state <= IDLE;
else state <= next_state;
end
הענף if (reset) הוא המקבילה ברת הסינתזה של initial state = IDLE. Reset הוא התשובה לשאלה "איך מאתחלים אוגר בחומרה אמיתית?"
חלק מתהליכי ה-FPGA כן מקבלים initial מוגבל לערכי reset של אוגרים (הכלים של Xilinx, למשל), אבל זו הרחבה של יצרן מסוים. אל תסמכו עליה בקוד נייד.
דברים שתראו בתוך initial
כמה תבניות נפוצות מעבר לשלד ה-testbench הסטנדרטי:
סיום אחרי השהיה
initial begin
#1000 $finish; // safety net: kill the sim after 1000 time units
end
initial נפרד שכל תפקידו לשים גבול עליון קשיח לסימולציה. גם אם בלוק הגירוי הראשי נתקע בהמתנה לאות שלא מגיע, הבלוק הזה מופעל ומסיים את הריצה.
הגדרת waveform
initial begin
$dumpfile("dump.vcd");
$dumpvars(0, test); // dump everything under the `test` scope
end
שתי השורות האלה אומרות לסימולטור לכתוב קובץ VCD עם כל אות בתחום הבדיקה. בלעדיהן אין waveform.
תמונת זיכרון התחלתית
reg [7:0] memory [0:255];
initial begin
$readmemh("image.hex", memory);
end
$readmemh טוען קובץ בפורמט הקסדצימלי לתוך המערך. משתמשים בזה ב-testbenches של מעבדים כדי לטעון מראש את זיכרון ההוראות. לסימולציה בלבד.
טעויות נפוצות
שימוש ב-initial ללוגיקה ברת סינתזה. זה לא יעבור סינתזה. השתמשו באותות reset במקום.
שכחת $finish. בלעדיו הסימולטור רץ עד שמשהו אחר עוצר אותו (מגבלת זמן ברירת מחדל, עצירה ידנית וכו'). לבדיקה מהירה זה בסדר; בסקריפט רגרסיה, תמיד $finish.
שכחת #delay בין השמות של גירוי. אם כותבים a = 0; b = 1; בלי השהיה, שתיהן קורות באותו זמן סימולציה, וה-DUT עשוי לראות אותן בו זמנית ולא כאירועים נפרדים. הכניסו #1 או יותר בין אירועי גירוי נפרדים.
ניסיון להזין wire מתוך initial. אותו כלל כמו ב-always: רק reg הוא יעד חוקי.
מה הלאה
ראיתם את שני סוגי הבלוקים הפרוצדורליים. המסמך הבא עוסק בנושא שמבלבל הכי הרבה מתחילים ב-Verilog: השמה חוסמת מול לא חוסמת. לדעת מתי להשתמש ב-= ומתי ב-<= זה ההבדל בין flip-flop שעובד לבין בלגן של race conditions.
שאלות נפוצות
מה זה בלוק initial ב-Verilog?
initial begin ... end הוא בלוק פרוצדורלי שרץ בדיוק פעם אחת בתחילת הסימולציה, בזמן 0. זה המקום הסטנדרטי להכין את מצב ה-testbench: לאתחל אותות, לפתוח קובצי לוג, לקרוא ל-$dumpfile/$dumpvars, להזין גירוי, ולסיים את הסימולציה עם $finish. כמה בלוקים של initial יכולים להתקיים יחד במודול; כולם מתחילים בזמן 0 במקביל.
מה ההבדל בין initial ל-always ב-Verilog?
initial רץ פעם אחת בזמן 0 ואז מסתיים. always רץ שוב ושוב לנצח: יש לו רשימת רגישות, והוא מתעורר בכל פעם שהאותות ברשימה משתנים. משתמשים ב-initial כמעט רק ב-testbenches. always הוא סוס העבודה גם של testbenches וגם של RTL בר סינתזה.
האם בלוק initial ניתן לסינתזה?
לא ב-Verilog רגיל. כלי סינתזה מתעלמים מבלוקים של initial, כי לחומרה אמיתית אין רגע 'זמן אפס' שבו רץ קוד הכנה. חלק מכלי ה-FPGA מקבלים צורה מוגבלת כדי לקבוע ערכי reset של אוגרים, אבל במקרה הכללי זה לסימולציה בלבד. השאירו בלוקים של initial ב-testbenches, והשתמשו באותות reset כדי לאתחל לוגיקה ברת סינתזה.
אפשר כמה בלוקי initial במודול Verilog אחד?
כן. כל בלוק initial מתחיל בזמן 0 ורץ עד הסוף באופן עצמאי. פיצול ההכנה לכמה בלוקים הוא תבנית נפוצה ב-testbench: בלוק אחד ליצירת שעון, אחד לגירוי, אחד לשמירת waveforms. הם רצים במקביל מזמן 0; הסימולטור משלב את ההוראות שלהם ככל שהזמן מתקדם.