אנו יכולים לייצג שערים לוגיים שראינו במספר דרכים, בין אם שרטוט ובין אם טבלת אמת. אנו הולכים ללמוד פה דרך נוספת לתאר מעגלים לוגיים - שפות תיאור חומרה.
זוהי אינה שפת תכנות. זוהי דרך לתאר את המחשב על מרכיביו הבסיסיים ביותר.
logic Z;
assign Z = X ~& Y;
logic Z;
always_comb
if (X) Z = ~Y;
else Z = 1;
הדרך שבה אנו לוקחים "קוד" בשפת תיאור חומרה והופכים אותו לחומרה אמיתית היא יחסית דומה לדרך שבה מהדר מבצע הידור לשפת תכנות.
קוד המקור מתורגם ל- ומשם לחומרה. (מה זה נראה בהמשך)
שפת תיאור החומרה שאנו נראה בסדנאות היא , שהיא השפה שלרוב מתמשים בה בתעשייה(בחשמל כמובן ולא במדמח)
כעת, בואו נתחיל מהבסיס:
מודול -
כל דבר שאנו רוצים לתאר יהיה מודול. זוהי בעצם קופסה שמקבלת קלט ופולטת פלט(זה בייסיקלי פונקציה)
כל מודול מתחיל במילה ולאחריו שם. כל מודול מסתיים במילה והרי דוגמה:
module my_module(
output logic out1,
output logic out2,
...,
input logic inN
);
... // declarations
... // description of f
endmodule
שימו כי אין נקפ"ץ אחרי .
סוגי שמירת מידע
חוט/ביט -
סוג המידע מייצג חוט חשמל(ביט 1). אנו יכולים להגדירו כך:
logic a, b, c, d;
logic e;
משתנים מסוג יכולים להיות מהסוגים הבאים:
- - אפס, וכו'
- - אחד, וכו'
- - או לא מאותחל או התנגשות
- - לא מחובר
כשאנחנו רואים זה לאו דווקא רע אבל זה יכול להיות רע. את הערך אנחנו לא נרצה לראות.
קבוצות של ביטים -
במשמעות שלנו, וקטור הוא לא כמו וקטור באלגברה - אלא הוא פשוט אוסף של מספרים.
logic [7:0] w1;
פה יצרנו וקטור(מערך) של 8 ביטים כאשר הוא ה-.
כתבו מעטפת למודול .
module mux4to1(
output logic O,
input logic D0,
input logic D1,
input logic D2,
input logic D3,
input logic E,
input logic [1:0] S
);
... // declarations
... // description of a mux
endmodule
פעולות על וקטורים
- בחירת ביט מסויים:
w1[3] - בחירת תת וקטור:
w1[3:2] - הכנסת משתנים לוקטורים:
ניתן בנוסף לחזור על אותו הביט כמה פעמים כך:vec = {x, y, z};vec = {16{x}}; // 16 copies of x - הוצאת משתנים מוקטורים:
{carry, sum} = vec[1:0];
החליפו את ארבעת הביטים() הגבוהים והנמוכים של ושימו אותם ב-.
logic [7:0] w1;
logic [7:0] w2;
w2 = {w1[3:0], w1[7:4]};
מה הקוד הבא עושה?
logic [7:0] out;
logic [3:0] A;
out = {{4{0}}, A[3:0]};
נשים לב כי אנו לא יודעים האם המספר חיובי או שלילי, אם המספר חיובי אז הכל אחלה(וייייי) אם המספר שלילי, סימנו יתהפך ויהיו מלא בעיות.
הפעולה שביצענו נקראת Unsigned extension.
מה הקוד הבא עושה?
out = {{4{A[3]}}, A[3:0]};
פה אנחנו משכפלים את הביט האחרון ולכן אנו לא משנים את הערך ולא משנים את הסימן.
הפעולה נקראת Signed extension.
הרכבת מודולים
אנחנו לא נרצה לעשות הכל במודול אחד, בדיוק כמו שאנו לא נרצה לעשות הכל בפונקציה אחת. לשם כך אנחנו בעצם נקח מודולים ונשים אותם במודולים אחרים.
פה נראה שתי צורות קריאה למודולים מתוך מודולים אחרים
module_name instance_name1 (
my_out1,
my_out2,
...,
my_inN
);
פה אנחנו יודעים מה המשתנים לפי סדר הכנסתם. במידה ואנו רוצים לוודא שאנו מכניסים את הדברים נכון נוכל לעשות:
module_name instance_name2 (
.out1(my_out1),
.out2(my_out2),
...,
.inN(my_in1)
);
מודולים בסיסיים
בהקבלה לפקודות של שפת תכנות שמגיעות עם השפה(כגון או פקודות הספרייה הסטנדרטית) גם ב-SystemVerilog יש לנו מודולים בסיסיים שמגיעים עם השפה והם:
- AND
- OR
- NOT
- XOR
- NAND
- NOR
- XNOR
ונשתמש בהם כך:
gateName(output, input1, <input2>)
not(O1, A);
nor(O2, A, B);
בואו ניצור Half Adder. אנחנו עוד נראה את זה בהרצאה ובתרגול וכך זה נראה:
התוצאה שאנו מקבלים היא
כעת נכתוב את הקוד שיתאים ב-SystemVerilog:
module HA (
output logic S,
output logic C,
input logic A,
input logic B
);
xor(S, A, B);
and(C, A, B);
endmodule
הפקודה
אם נרצה להחליט בין שני וקטורים ולבחור באחד מהם, בעצם נרצה לבנות שכזה, נוכל להשתמש ב- של ביט יחיד מלא פעמים, אבל זה הרבה לכתוב וזה מאוד חזרתי ולכן לא נרצה לעשות זאת. לשם כך נוכל להשתמש בפקודה שבעצם יוצרת חומרה בשבילנו. נראה שימוש בה:
module mux2to1_32 (
output logic [31:0] O,
input logic [31:0] A,
input logic [31:0] B,
input logic S
);
genvar i;
generate
for (i = 0; i < 32; i++)
begin
mux2to1 mux_inst(.O(O[i]), .S(S), .A(A[i]), .B(B[i]));
end
endgenerate
endmodule