חזור לתיקייה: סדנה

3 - SystemVerilog III

חיפוש בתיקיה
Ctrl K
לחץ כאן או הקש Ctrl K כדי לחפש בכל התיקיה
  • אופרטורים נוספים
  • תנאים
  • זיכרון ובלוקים סינכרוניים
  • עוד קצת על ניסויים
  • דוגמה: מונה פשוט

3 - SystemVerilog III

00440252

מערכות ספרתיות ומבנה המחשב

רשימות הרצאה לקריאה בשבת

SystemVerilog III

הופק מתוך תקיית התואר של שקד

uni-folder.vercel.app

אופרטורים נוספים

אופרטורמשמעות
<<<קטן מ
<=< =<=קטן או שווה ל
>>>גדול מ
>=> =>=גדול או שווה ל
======שווה ל
!=! =!=לא שווה ל
&&\&\&&&וגם לוגי
∣∣||∣∣או לוגי
!!!היפוך לוגי

תנאים

תנאי ififif הוא די פשוט רק שאנו מחליפים את הסוגריים המסולסלים במילים המשונות begin,endbegin,endbegin,end כך:

if (condition) begin
	<statement>;
end
else if (condition2) begin
	<statement>;
end
else begin
	<statement>;
end
דוגמה (בורר - muxmuxmux)

module mux(
	input logic A,
	input logic B,
	input logic sel,
	output logic Q
);
	always_comb begin
		if (sel == 1'b0) begin
			Q = A;
		end
		else begin
			Q = B;
		end
	end
endmodule

התנאי casecasecase מאפשר לנו להשוות בין מספר ערכים עבור אותו משתנה כך:

case (<signal/expression>)
	<value1>: begin
		<statement>;
	end
	<value2>: begin
		<statement>;
	end
	default: begin
		<statement>;
	end
endcase
דוגמה

module case_example ( 
	input logic A, 
	input logic B, 
	input logic [1:0] w, 
	output logic Y
);
	always_comb begin
		case (w)
			2'b00: Y = A & B;
			2'b01: Y = A | B;
			2'b10: Y = A ^ B;
			default: Y = ~B;
		endcase
	end
endmodule

ישנם שני סוגים של בלוקים של casecasecase והם casez,casexcasez,casexcasez,casex. ההבדל ביניהם הוא שב-zzz הערכים ??? ו-zzz בלבד נחשבים ל-∅\varnothing∅ וב-xxx הערך xxx גם הוא(בנוסף לאחרים) נחשב ל-∅\varnothing∅.

דוגמה

casez (w)
	2'b1?: A = B + C; // if we get 10 we do A=B+C and also, if we get 11 we do the same
	2'b01: A = B ^ C;
	default: A = B - C;
endcase
הערה

הבלוק always_combalways\_combalways_comb נועד ללוגיקה קומבינטורית ללא זיכרון.
אם אנו משנים ערך אך לא נותנים אופציה לכל מצב, המהדר מניח שאנו רוצים לשמור את הערך הקודם של המשתנה אך זה לא אפשרי בלוגיקה קומבינטורית שכן זה דורש latchlatchlatch התלוי בשעון.

כדי שלא יהיו לנו בעיות, תמיד נשים elseelseelse או defaultdefaultdefault אם אנו יוצרים תנאים בתוך always_combalways\_combalways_comb.

זיכרון ובלוקים סינכרוניים

ראינו בלוקים קומבינטוריים שמיישמים מעגלים צירופיים. כעת נרצה לממש גם מעגלים סינכרוניים התלויים בשעון. לשם כך יש לנו את הבלוק always_ffalways\_ffalways_ff.

always_ff @(posedge clock) begin
	<sync statement>;
end
דוגמה (flip−flopflip-flopflip−flop)

logic a, in;
always_ff @(posedge clock) begin
	a <= in;
end
הערה

האופרטור <=<=<= פה משמש כהשמה לא חוסמת. כלומר, השמה המיועדת ספציפית ללוגיקה עם שעון אשר "דוגמת" את כל הערכים בכניסות בזמן עליית השעון ומעדכנת את כל היציאות בו-זמנית.

אם נרצה לעשות אתחול לשעון נוכל לעשות זאת בשני דרכים:

  • אתחול א-סינכרוני:
    always_ff @(posedge clock, posedge reset) begin
        if (reset == 1'b1) begin
      	  <reset statement>;
      	end
      	else begin
      		<sync statement>;
      	end
    end
    
  • אתחול סינכרוני:
    always_ff @(posedge clock) begin
      if (reset == 1'b1) begin
      	<reset statement>;
      end
      else begin
      	<sync statement>;
      end
    end
    
דוגמה 1 (flip−flopflip-flopflip−flop עם אתחול)

logic a, in; 
always_ff @(posedge clock, posedge reset) begin 
	if (reset == 1'b1) begin 
		a <= 1'b0; 
	end 
	else begin 
		a <= in; 
	end 
end
דוגמה (לוגיקה שהיא גם סנכרונית וגם א-סנכרונית)

​נדרששםקצראוקי-אוקי.png
נראה איך המעגל הזה נבנה ב-SystemVrilogSystemVrilogSystemVrilog בשתי דרכים.

module my_module (
	input logic clock,
	input logic reset,
	input logic A,
	output logic B
);
	logic and_out, or_out;
	always_ff @(posedge clock, posedge reset)
	begin
		if (reset == 1'b1) begin
			A <= 1'b0;
			B <= 1'b1;
		end
		else begin
			A <= or_out;
			B <= and_out;
		end
	end
	
	always_comb begin
		and_out = A & B;
		or_out = A | B;
	end
endmodule

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

module my_module (
	input logic clock,
	input logic reset,
	input logic A,
	output logic B
);
	always_ff @(posedge clock, posedge reset)
	begin
		if (reset == 1'b1) begin
			A <= 1'b0;
			B <= 1'b1;
		end
		else begin
			A <= A | B;
			B <= A & B;
		end
	end
endmodule

עוד קצת על ניסויים

כשנרצה ליצור שעון נוכל לבנות בלוק alwaysalwaysalways אשר יהפוך את השעון שלנו כל 101010 שניות כך:

initial begin
	Clock = 1'b0;
end
// ...
always begin
	#10 Clock = ~Clock;
end

בנוסף, יש לנו בלוח חזרתיות אשר מתנהג כך:

repeat (num_of_times) begin
	<statement>;
end
דוגמה (המתנה ל-4 מחזורי שעון)

initial begin
	repeat(4) begin
		@(posedge clock);
	end
end

נסתכל עכשיו על דוגמה ל-TestBenchTestBenchTestBench מלא:

module my_module_tb;

	logic clock, reset;
	logic A, B;
	
	my_module inst(.clock(clock), .reset(reset), .A(A), .B(B));
	
	always_begin
		#10 clock = ~clock;
	end
	
	initial begin
		clock = 1'b0;
		reset = 1'b1;
		@(posedge clock);
		#7
		reset = 1'b0;
		repeat(2) begin
			@(posedge clock);
		end
	end
endmodule

דוגמה: מונה פשוט

logic [3:0] next_counter, current_counter;

always_ff @(posedge clock, posedge reset) begin
	if (reset == 1'b1) begin
		current_counter <= 4'b0;
	end
	else begin
		current_counter <= next_counter;
	end
end

always_comb begin
	next_counter = current_counterr + 1;
end

ניתן לעשות את זה גם בדרך דומה:

 logic [3:0] current_counter;

always_ff @(posedge clock, posedge reset) begin
	if (reset == 1'b1) begin
		current_counter <= 4'b0;
	end
	else begin
		current_counter <= current_counter + 1;
	end
end