Menu

אופרטורי Bitwise ו-Reduction ב-Verilog

האופרטורים ברמת הביט ב-Verilog: AND/OR/XOR ביט אחר ביט, צורות ההיפוך, ואופרטורי ה-reduction שמכווצים וקטור שלם לביט יחיד.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

שני תפקידים לאותו סימן

&, |, ^ והאחים ההפוכים שלהם מופיעים בשתי צורות שונות:

  • צורה בינארית (שני אופרנדים): a & b, פעולה ביט אחר ביט בין וקטורים באותו רוחב.
  • צורה אונרית (אופרנד אחד): &a, צמצום של כל הביטים של a לביט יחיד.

הקומפיילר מבחין ביניהן לפי מספר האופרנדים. המוסכמה המקובלת היא לקרוא לצורה הבינארית "אופרטורי bitwise" ולצורה האונרית "אופרטורי reduction".

Bitwise: ביט אחד בכל פעם

הסט המלא:

אופרטורשםביט הפלט במיקום N
a & bANDa[N] AND b[N]
a | bORa[N] OR b[N]
a ^ bXORa[N] XOR b[N]
a ~& bNANDNOT (a[N] AND b[N])
a ~| bNORNOT (a[N] OR b[N])
a ~^ bXNORNOT (a[N] XOR b[N])
~aNOTNOT a[N]

שימו לב ש-~&, ~|, ~^ נכתבים עם הטילדה קודם והאופרטור אחריה. הם טוקן אחד, בלי רווח ביניהם.

כשלשני האופרנדים יש רוחב שונה, הצר מביניהם מורחב באפסים בצד הביטים העליונים כדי להשתוות. אם רוצים הרחבת סימן, משתמשים במפורש באופרנדים עם סימן בעזרת $signed().

Reduction: מהרבה ביטים לאחד

הצורות האונריות של אותם אופרטורים מכווצות וקטור לביט יחיד:

מה כל אחד אומר:

  • &data מחזיר 1 אם כל הביטים של data הם 1, אחרת 0. שימושי לבדיקות "האם הכול אחדות?".
  • |data מחזיר 1 אם ביט כלשהו של data הוא 1, אחרת 0. שימושי לבדיקות "האם זה שונה מאפס?".
  • ^data מחזיר את ה-parity, כלומר XOR של כל הביטים. 1 אם מספר האחדות אי זוגי, 0 אם זוגי.
  • ~&data, ~|data, ~^data הם ההיפוכים של אלה.

תראו אותם בכל מקום בקוד אמיתי:

wire empty       = ~|fifo_count;       // empty רק אם count הוא אפס
wire all_ones    = &mask;              // כל הביטים דולקים
wire parity_bit  = ^data;              // parity של בייט
wire any_request = |request_vector;    // האם משהו התבקש?

צורות ה-reduction תמציתיות ועוברות סינתזה לעצי שערים ברורים: & הופך לשער AND עם כניסות רבות, | לשער OR עם כניסות רבות, ו-^ לעץ XOR (שהוא גם מחולל ה-parity בחומרה).

תבניות נפוצות

הדלקה וכיבוי של ביטים

wire [7:0] data;
wire [7:0] mask = 8'b0000_1000;

wire [7:0] set     = data | mask;     // מכריח את ביט 3 להיות 1
wire [7:0] cleared = data & ~mask;    // מכריח את ביט 3 להיות 0
wire [7:0] toggled = data ^ mask;     // הופך את ביט 3
wire [7:0] tested  = data & mask;     // אפס אם ביט 3 היה 0, אחרת שונה מאפס

אלה אותם ניבים של מניפולציית ביטים שהייתם משתמשים בהם ב-C. הם עוברים סינתזה לפעולות של שער יחיד.

בדיקה אם ערך שווה לכל האחדות

wire is_max = &counter;       // 1 אם כל ביט של counter הוא 1

reduction AND עם שער אחד, לעומת כתיבה של counter == 8'hFF (שגם עובדת; סינתיסייזרים בדרך כלל מייצרים חומרה זהה).

יצירת ביט parity

זיהוי אות פעיל כלשהו

wire any_pending = |request_vector;

אם request_vector רחב (נגיד 64 מבקשים), ה-reduction OR מתכווץ לאות יחיד שאפשר להזין ל-priority encoder או ל-arbiter.

אופרטורי הזזה

וכבר כשמדברים על אופרטורים ברמת הביט, הנה ההזזות:

  • a << N מזיז את a שמאלה ב-N מיקומי ביטים, וממלא באפסים את הביטים התחתונים.
  • a >> N מזיז את a ימינה ב-N מיקומי ביטים, וממלא באפסים את הביטים העליונים.
  • a <<< N הזזה אריתמטית שמאלה (זהה ל-<< בערכים בלי סימן).
  • a >>> N הזזה אריתמטית ימינה: ממלאת בביט הסימן כש-a הוא עם סימן.

הזזה בכמות קבועה היא בחינם בחומרה (רק חיווט מחדש). הזזה במשתנה שנקבע בזמן ריצה מייצרת barrel shifter, שהוא גדול יותר אבל עדיין זול.

מה הלאה

ראיתם עכשיו כל אופרטור שמחזיר ערך יחיד. המסמך הבא, שרשור ושכפול, עוסק בתחביר {} ו-{N{...}} שבונה וקטורים רחבים יותר מחלקים, ותשתמשו בו כל הזמן כשמחברים בין מודולים ברוחבים שונים.

שאלות נפוצות

מה הם אופרטורי bitwise ב-Verilog?

אופרטורי bitwise משלבים שני וקטורים באותו רוחב, מיקום אחר מיקום. a & b מבצע AND בין ביט 0 של a לביט 0 של b, בין ביט 1 לביט 1 וכן הלאה, ומפיק וקטור ברוחב של הכניסות. הסט המלא הוא & (AND), | (OR), ^ (XOR), ~ (NOT), וצורות ההיפוך ~&, ~|, ~^ (NAND, NOR, XNOR).

מה זה אופרטור reduction ב-Verilog?

אופרטור reduction הוא צורה אונרית של אופרטור bitwise, שמכווצת וקטור שלם לביט יחיד. &data מחזיר 1 רק אם כל הביטים של data הם 1. |data מחזיר 1 אם ביט כלשהו הוא 1. ^data מחזיר את ה-XOR של כל הביטים, כלומר את הזוגיות (parity). לצורות ה-reduction אין אופרנד לפני האופרטור, רק אחריו.

מה ההבדל בין & לבין && ב-Verilog?

& הוא AND ביט אחר ביט: הוא מצמיד ביטים לפי מיקום, והתוצאה באותו רוחב כמו האופרנדים. && הוא AND לוגי: הוא מתייחס לכל אופרנד כערך בוליאני (אפס או לא אפס) ומחזיר תוצאה של ביט אחד. 4'b1100 & 4'b0011 הוא 4'b0000; 4'b1100 && 4'b0011 הוא 1.

איך מחשבים parity ב-Verilog?

משתמשים באופרטור ה-reduction XOR: parity = ^data. הוא מבצע XOR בין כל הביטים של data. בווקטור של 8 ביטים זה data[7] ^ data[6] ^ ... ^ data[0]. התוצאה היא 1 אם מספר הביטים הדולקים אי זוגי, ו-0 אם הוא זוגי. היפוך עם ~^ נותן parity זוגי.

מה עושה ~ ב-Verilog?

~ הוא NOT ביט אחר ביט: הוא הופך כל ביט של האופרנד. ~4'b1100 הוא 4'b0011. אל תבלבלו אותו עם ! (NOT לוגי), שמכווץ את האופרנד לערך בוליאני של ביט אחד והופך אותו. !4'b1100 הוא 1'b0 (האופרנד שונה מאפס, והיפוך ערך האמת נותן 0).

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל