מה "אופרטור" אומר ב-Verilog
אופרטורים מקבלים ביטויים שנושאים אותות ומפיקים ביטויים חדשים שנושאים אותות. a + b הוא חומרה: הסינתיסייזר הופך אותו למחבר. a == b הוא חומרה: הוא בונה משווה. שום דבר מזה אינו "קוד שרץ"; הכול הוא "מעגלים שהאופרטור מתאר".
תפריט האופרטורים המלא קטן מספיק כדי לשנן אותו. המסמך הזה עוסק באופרטורים האריתמטיים, אופרטורי ההשוואה, הלוגיים והמותנה. Bitwise ו-Reduction עוסק באופרטורים ברמת הביט שאין להם מקבילה ישירה בתוכנה.
אריתמטיקה: + - * / %
שלושה דברים שכדאי לדעת:
- חילוק הוא חילוק שלמים.
7/2הוא3, לא3.5. ל-Verilog אין טיפוס float (טוב, ישreal, אבל הוא לסימולציה בלבד). - חילוק ושארית יקרים בחומרה.
/4זה בסדר (הסינתיסייזר הופך אותו להזזה ימינה), אבל/nעםnשמשתנה בזמן ריצה בונה מחלק רב מחזורי שכמעט אף פעם לא תרצו. - גלישה מתגלגלת. חיבור של שני ערכים בלי סימן של N ביטים שחורג מ-N ביטים נקטם ל-N ביטים. אם רוצים ללכוד את הנשא, מצהירים על התוצאה ברוחב של ביט אחד יותר:
wire [7:0] a, b;
wire [8:0] sum = a + b; // 9-bit sum captures carry out
השוואה: == != < > <= >=
כל ששת אופרטורי ההשוואה מחזירים תוצאה של ביט יחיד: 1 אם אמת, 0 אם שקר, x אם באחד האופרנדים יש ביט x או z. כדי לטפל במקרה של x/z, פנו ל-=== ול-!== (אופרטורי ה-case equality) שמוסברים ב-ערכי X ו-Z.
<= כאן הוא אופרטור ההשוואה (קטן או שווה). אותם תווים משמשים גם להשמה לא חוסמת בבלוק פרוצדורלי (q <= d). ההקשר מבחין ביניהם: בתוך ביטוי זו השוואה; אחרי היעד של השמה, זו ההשמה. החפיפה מבלבלת, אבל חד משמעית עבור המפענח.
לוגיקה: && || !
אופרטורים לוגיים מתייחסים לאופרנדים שלהם כערכים בוליאניים (כל דבר שונה מאפס הוא אמת, אפס הוא שקר) ומפיקים תוצאה של ביט יחיד:
ההבחנה הקריטית שצריך להפנים: && לוגי אינו & ביט אחר ביט.
4'b1100 && 4'b0011 // 1 (both are non-zero, logical AND is true)
4'b1100 & 4'b0011 // 4'b0000 (no bit positions are 1 in both)
אותו דבר לגבי || מול |. השתמשו באופרטורים לוגיים בתנאי if ובפרדיקטים של ?:; השתמשו ב-bitwise כשרוצים שכל מיקום ביט יעבור AND/OR באופן עצמאי.
&& ו-|| מבצעים short-circuit במובן של C: צד ימין לא מחושב אם התוצאה כבר נקבעה על ידי צד שמאל. זה חשוב ב-testbenches שבודקים מצביעים או קריאות לפונקציות; זה לעיתים רחוקות משנה ב-RTL בר סינתזה, שבו הכול קורה במקביל בכל מקרה.
האופרטור המותנה: ?:
האופרטור התלת מקומי הוא החבר הכי טוב שלכם לבניית muxes וביטויים מותנים:
התבנית cond ? a : b היא בחומרה multiplexer של 2 ל-1 עם בורר של ביט אחד. שרשור שלהם בסדר לבחירות של 3 ו-4 כיוונים, אבל מעבר לזה משפט case (מוסבר ב-משפט case) קריא הרבה יותר.
האופרטור ?: הוא גם הדרך הסטנדרטית לתת לאוגר ערך ברירת מחדל שדורסים רק לפעמים:
next_value = update ? new_data : next_value;
כללי רוחב: המלכודת של המתחילים
כללי הרוחב של Verilog לאופרטורים אריתמטיים ידועים כמפתיעים. הגרסה הקצרה:
- הרוחב של התוצאה הוא המקסימום של רוחבי הכניסות.
- אם התוצאה מושמת למשהו רחב יותר, היא מורחבת באפסים (או מורחבת סימן אם היא עם סימן).
- הרוחב של חישובי ביניים הוא גם רוחב התוצאה, כלומר הגלישה קורית כבר בחישוב הביניים.
הכפל הראשון גולש כי רוחבי שני האופרנדים הם 8 ביטים, ולכן רוחב התוצאה הוא 8 ביטים, ו-40000 לא נכנס. השני עובד כי הרחבנו את a במפורש לפני הכפל.
טכניקות התיקון:
- השתמשו באופרטור השרשור
{8'b0, a}כדי להרחיב באפסים. - השתמשו ב-
$unsigned(a)או ב-$signed(a)כדי להשפיע על הפרשנות. - כשיש ספק, המירו ביטויי ביניים לרוחבים גדולים יותר.
קדימות אופרטורים
לא תשננו את הטבלה, אבל תסמכו על כמה כללים:
*,/,%נקשרים חזק יותר מ-+,-.- השוואה נקשרת חזק יותר מאופרטורים לוגיים (
&&,||). - לאופרטור המותנה
?:יש קדימות נמוכה מאוד: בביטויים גדולים יותר בדרך כלל צריך סוגריים סביב הענפים שלו. - כשיש ספק, שימו סוגריים. הסימולטור לא גובה לפי תו.
out = (mode == 2'd0) ? a + b : a - b; // clearer with parens
מה הלאה
כיסיתם את כל האופרטורים שנראים כמו בני הדודים שלהם בתוכנה. המסמך הבא, Bitwise ו-Reduction, עוסק באופרטורים שאין להם מקבילה ישירה בתוכנה: AND/OR/XOR לכל ביט, וצורות ה-reduction שמכווצות וקטור שלם לביט יחיד.
שאלות נפוצות
באילו אופרטורים Verilog תומכת?
ל-Verilog ארבע משפחות רחבות של אופרטורים: אריתמטיים (+, -, *, /, %), השוואה (==, !=, <, >, <=, >=), לוגיים (&&, ||, !), ו-bitwise/reduction (&, |, ^, ~, ~&, ~|, ~^). ובנוסף אופרטורי הזזה (<<, >>, <<<, >>>), שרשור {}, שכפול {N{...}}, והאופרטור המותנה ?:.
מה ההבדל בין && ל-& ב-Verilog?
&& הוא AND לוגי: הוא מתייחס לכל אופרנד כערך בוליאני (אפס או לא אפס) ומחזיר תוצאה של ביט אחד. & הוא AND ביט אחר ביט: הוא מצמיד ביטים לפי מיקום. 4'b1100 && 4'b0011 הוא 1 (שניהם שונים מאפס); 4'b1100 & 4'b0011 הוא 4'b0000. השתמשו ב-&& בתנאים, וב-& לפעולות ברמת הביט.
איך חילוק עובד ב-Verilog?
חילוק שלמים: החלק השברי נזרק. 7 / 2 הוא 3, לא 3.5. האופרטור % נותן את השארית: 7 % 2 הוא 1. חילוק באפס מפיק x (לא ידוע) בסימולציה. שני האופרטורים ניתנים לסינתזה מבחינה טכנית, אבל מייצרים חומרה גדולה ואיטית מאוד ב-FPGAs וב-ASICs: הימנעו מהם במסלולים ברי סינתזה, אלא אם המחלק הוא חזקה של 2.
מה זה האופרטור המותנה ב-Verilog?
?: הוא האופרטור התלת מקומי או המותנה, שהועתק מ-C. cond ? a : b מחושב ל-a אם cond אמת (שונה מאפס) ול-b אחרת. זה המבנה הנפוץ ביותר ללוגיקה בסגנון multiplexer: out = sel ? in1 : in0 בונה mux של 2 ל-1. שרשראות של ?: בונות muxes רחבים יותר, אם כי case בדרך כלל ברור יותר מעבר לשתי כניסות.