Menu

פורטים של מודול ב-Verilog: input, output ו-inout

איך מצהירים על פורטים של מודול, input, output ו-inout, רשימת הפורטים בסגנון ANSI, ומתי פלט צריך להיות wire ומתי reg.

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

הממשק של מודול

רשימת הפורטים של מודול היא הממשק שלו: כל מה שהעולם החיצון יכול לראות ולגעת בו. בתוך המודול, הגוף מחשב פלטים מכניסות. הפורטים הם ה-wires שחוצים את הגבול.

ההצהרה המודרנית בסגנון ANSI שמה כיוון, טיפוס ורוחב באותה שורה:

module my_module(
    input  wire        clk,
    input  wire        reset,
    input  wire [7:0]  data_in,
    output reg  [7:0]  data_out,
    output wire        valid
);
    // body
endmodule

זו כל הצורה. לכל פורט יש:

  • כיוון: input, output או inout.
  • טיפוס: wire או reg (או logic ב-SystemVerilog).
  • רוחב: טווח כמו [7:0], או ביט יחיד אם משמיטים אותו.
  • שם: המזהה שתשתמשו בו בתוך הגוף.

שלושת הכיוונים

input: מוזן מבחוץ

כניסות הן תמיד wire. מקור ההזנה נמצא מחוץ למודול: אות של מודול ברמה גבוהה יותר, או reg של ה-testbench. בתוך המודול הזה אפשר לקרוא כניסות בביטויים, אבל אף פעם לא לבצע אליהן השמה:

module reader(input wire [7:0] data);
    initial $display("data = %h", data);
endmodule

כתיבת data = ... בתוך המודול הייתה שגיאה.

output: מוזן מבפנים

יציאות מוזנות על ידי משהו בתוך המודול הזה. הן יכולות להיות wire (מוזנות על ידי assign או פלט של תת מודול) או reg (מוזנות מ-always/initial).

module driver(
    input  wire       a,
    input  wire       b,
    input  wire       clk,
    output wire       y,    // wire: מוזן על ידי assign
    output reg        q     // reg: מוזן על ידי always
);
    assign y = a & b;       // תקין כי y הוא wire

    always @(posedge clk)
        q <= a;             // תקין כי q הוא reg
endmodule

ניסיון לבצע השמה ל-y בתוך בלוק ה-always, או להזין את q עם assign, היה שגיאת קומפילציה. בחירת מילת המפתח חייבת להתאים למקור ההזנה.

inout: דו כיווני

פורטים מסוג inout הם wires שיכולים להיות מוזנים לסירוגין על ידי המודול או על ידי מה שמחובר מבחוץ. הם מופיעים בגבולות השבב: קווי SDA של I²C, פיני GPIO דו כיווניים, אפיקי נתונים משותפים. בתוך המודול שולטים בכיוון עם תבנית tri-state:

module bidir_pin(
    input  wire data_out,
    input  wire output_enable,
    output wire data_in,
    inout  wire pin
);
    assign pin     = output_enable ? data_out : 1'bz;
    assign data_in = pin;
endmodule

pin הוא ה-wire המשותף. כש-output_enable גבוה, המודול מזין את pin בערך של data_out. כשהוא נמוך, המודול משחרר את הפין לעכבה גבוהה (z), ומאפשר למקור הזנה חיצוני להשתמש בו. data_in תמיד רואה את מה שנמצא כרגע על הפין.

inout נדיר בלוגיקה פנימית טהורה. אם אתם בונים בקר זיכרון, ליבת מעבד או pipeline לעיבוד תמונה, ייתכן שלעולם לא תצטרכו אותו. זו יכולת בשביל טבעת ה-I/O בגבולות השבב.

פורטים של ביט אחד מול כמה ביטים

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

input wire valid,         // 1 bit
input wire [7:0] data,    // 8 bits
input wire [31:0] addr,   // 32 bits

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

module bus #(
    parameter WIDTH = 32
)(
    input  wire [WIDTH-1:0] in,
    output wire [WIDTH-1:0] out
);
    assign out = in;
endmodule

סגנון ANSI מול Verilog-1995

מדי פעם תראו קוד ישן שמפצל את רשימת הפורטים ואת ההצהרות:

// סגנון Verilog-1995 ישן: אל תעשו את זה בקוד חדש
module foo(clk, data_in, data_out);
    input clk;
    input [7:0] data_in;
    output reg [7:0] data_out;
    // ...
endmodule

רשימת הפורטים מכילה רק שמות; כל פורט מוצהר אחר כך בנפרד בתוך הגוף. זה ארוך, מועד לשגיאות מסוג "מופיע ברשימת הפורטים אבל לא הוצהר אף פעם", ודורש פי שניים הקלדה. סגנון ANSI-2001 (זה שמוצג לאורך כל המסמכים האלה) מחליף את שניהם:

module foo(
    input  wire       clk,
    input  wire [7:0] data_in,
    output reg  [7:0] data_out
);
    // ...
endmodule

השתמשו בסגנון ANSI. הכלים תומכים בו מאז 2001.

דוגמה מלאה

במודול היחיד הזה יש:

  • פרמטר (WIDTH).
  • כניסות לשעון, ל-reset, ל-load enable, לנתונים ול-shift enable.
  • יציאת reg (data_out) שמוזנת בתוך בלוק always.
  • יציאת wire (msb_out) שמוזנת על ידי השמה רציפה.
  • הצהרה מלאה בסגנון ANSI שמציינת לכל פורט כיוון, טיפוס ורוחב באותה שורה.

כך בנוי כמעט כל מודול בר סינתזה שתכתבו.

מה הלאה

המסמך הבא, יצירת מופעים של מודולים, מראה איך לקחת את המודול הזה ולהשתמש בו בתוך תכנון גדול יותר. ה-shifter שכתבתם זה עתה לא שימושי לבדו; הוא מצדיק את קיומו כשמשהו יוצר ממנו מופע ומחבר אותו למערכת.

שאלות נפוצות

מה שלושת כיווני הפורטים ב-Verilog?

input, output ו-inout. input מוזן מחוץ למודול. output מוזן מתוך המודול. inout הוא דו כיווני: שימושי לאפיקי tri-state שבהם המודול גם מזין וגם קורא את אותו פין. הרוב המוחלט של הפורטים הפנימיים הם input או output; inout מופיע רק בפינים של השבב.

מה ההבדל בין output wire ל-output reg?

output wire אומר שהפלט מוזן על ידי השמה רציפה או על ידי פלט של תת מודול, כלומר כל מה שמחוץ לבלוק always. output reg אומר שהוא מוזן מבלוק פרוצדורלי (initial או always). מילת המפתח קובעת אם אפשר לכתוב לאות מתוך always, ולא אם החומרה אחרי הסינתזה מכילה flip-flop.

מה זה סגנון ANSI לפורטים ב-Verilog?

סגנון ANSI מצהיר על הכיוון והטיפוס של כל פורט ישירות ברשימת הפורטים: module foo(input wire [7:0] data, output reg [7:0] result);. סגנון Verilog-1995 הישן רק מנה שמות ברשימת הפורטים והצהיר עליהם שוב בתוך המודול. תמיד השתמשו בסגנון ANSI בקוד חדש: הוא קצר יותר, פחות מועד לטעויות, והסטנדרט בכל מקום מודרני.

אפשר כמה כניסות ויציאות במודול Verilog?

כן, למודול יכולים להיות כמה פורטים שצריך, בכל צירוף של כיוונים. מפרידים ביניהם בפסיקים ברשימת הפורטים. הסדר ברשימה קובע את סדר החיבור לפי מיקום ביצירת מופע, אבל כמעט תמיד משתמשים בחיבורים לפי שם (.port(signal)) כדי לא להסתמך על הסדר.

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

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

להתחיל