การสร้างแบบจำลองและกำหนดเวลาพฤติกรรมใน Verilog

แบบจำลองพฤติกรรมใน Verilog ประกอบด้วยคำสั่งขั้นตอนซึ่งควบคุมการจำลองและจัดการตัวแปรของชนิดข้อมูล ข้อความทั้งหมดเหล่านี้มีอยู่ในขั้นตอน แต่ละโพรซีเดอร์มีโฟลว์กิจกรรมที่เกี่ยวข้อง

ในระหว่างการจำลองแบบจำลองพฤติกรรมโฟลว์ทั้งหมดที่กำหนดโดยคำสั่ง "always" และ "initial" จะเริ่มต้นพร้อมกันที่เวลาจำลอง "ศูนย์" คำสั่งเริ่มต้นจะดำเนินการเพียงครั้งเดียวและคำสั่ง always จะถูกดำเนินการซ้ำ ๆ ในโมเดลนี้ตัวแปรรีจิสเตอร์ a และ b จะเริ่มต้นเป็นไบนารี 1 และ 0 ตามลำดับที่เวลาจำลอง 'ศูนย์' จากนั้นคำสั่งเริ่มต้นจะเสร็จสมบูรณ์และจะไม่ดำเนินการอีกในระหว่างการดำเนินการจำลองนั้น คำสั่งเริ่มต้นนี้ประกอบด้วยบล็อกเริ่มต้น (หรือเรียกว่าบล็อกตามลำดับ) ของคำสั่ง ในบล็อกประเภทเริ่มต้นนี้ a จะเริ่มต้นก่อนตามด้วย b

ตัวอย่างการสร้างแบบจำลองพฤติกรรม

module behave; 
reg [1:0]a,b; 

initial 
begin 
   a = ’b1; 
   b = ’b0; 
end 

always 
begin 
   #50 a = ~a; 
end 

always 
begin 
   #100 b = ~b; 
end 
End module

การกำหนดขั้นตอน

การกำหนดขั้นตอนมีไว้สำหรับการอัพเดตตัวแปร reg, integer, time และ memory มีความแตกต่างอย่างมีนัยสำคัญระหว่างการมอบหมายขั้นตอนและการมอบหมายงานต่อเนื่องดังที่อธิบายไว้ด้านล่าง -

การกำหนดอย่างต่อเนื่องขับเคลื่อนตัวแปรสุทธิและได้รับการประเมินและอัปเดตเมื่อใดก็ตามที่ตัวถูกดำเนินการอินพุตเปลี่ยนค่า

การกำหนดขั้นตอนจะอัพเดตค่าของตัวแปรรีจิสเตอร์ภายใต้การควบคุมของโครงสร้างโฟลว์โพรซีเดอร์ที่ล้อมรอบ

ด้านขวามือของการกำหนดขั้นตอนอาจเป็นนิพจน์ใด ๆ ที่ประเมินเป็นค่า อย่างไรก็ตามส่วนที่เลือกทางด้านขวามือจะต้องมีดัชนีคงที่ ด้านซ้ายแสดงถึงตัวแปรที่รับงานจากด้านขวามือ ด้านซ้ายมือของการกำหนดขั้นตอนสามารถใช้รูปแบบใดรูปแบบหนึ่งต่อไปนี้ -

  • register, integer, real หรือ time variable - การกำหนดชื่ออ้างอิงของข้อมูลประเภทใดประเภทหนึ่งเหล่านี้

  • การเลือกบิตของตัวแปร register, จำนวนเต็ม, จริงหรือเวลา - การกำหนดให้กับบิตเดียวที่ทำให้บิตอื่น ๆ ไม่ถูกแตะต้อง

  • part-select of a register, integer, real หรือ time variable - การเลือกบางส่วนของบิตที่ต่อเนื่องกันตั้งแต่สองบิตขึ้นไปซึ่งจะทำให้ส่วนที่เหลือไม่ถูกแตะต้อง สำหรับรูปแบบการเลือกส่วนหนึ่งนิพจน์คงที่เท่านั้นที่ถูกกฎหมาย

  • องค์ประกอบหน่วยความจำ - คำเดียวของหน่วยความจำ โปรดทราบว่าการเลือกบิตและการเลือกบางส่วนไม่ถูกต้องในการอ้างอิงองค์ประกอบหน่วยความจำ

  • การเรียงต่อกันของข้อใดข้อหนึ่งข้างต้น - สามารถระบุการเรียงต่อกันของรูปแบบใดก็ได้จากสี่รูปแบบก่อนหน้าซึ่งแบ่งพาร์ติชันผลลัพธ์ของนิพจน์ด้านขวามือได้อย่างมีประสิทธิภาพและกำหนดส่วนพาร์ติชันตามลำดับไปยังส่วนต่างๆของการเรียงต่อกัน

ความล่าช้าในการมอบหมายงาน (ไม่ใช่สำหรับการสังเคราะห์)

ในการมอบหมายงานล่าช้าหน่วยเวลาจะผ่านไปก่อนที่คำสั่งจะถูกดำเนินการและทำการกำหนดทางซ้าย ด้วยความล่าช้าภายในการมอบหมายงานด้านขวาจะได้รับการประเมินทันที แต่มีความล่าช้าก่อนที่ผลลัพธ์จะถูกวางไว้ในการมอบหมายด้านซ้ายมือ หากขั้นตอนอื่นเปลี่ยนสัญญาณด้านขวามือระหว่างΔtจะไม่มีผลกับเอาต์พุต เครื่องมือสังเคราะห์ไม่รองรับความล่าช้า

ไวยากรณ์

  • Procedural Assignmentตัวแปร = นิพจน์

  • Delayed assignment# Δtตัวแปร = นิพจน์;

  • Intra-assignment delayตัวแปร = # Δtนิพจน์;

ตัวอย่าง

reg [6:0] sum; reg h, ziltch; 
sum[7] = b[7] ^ c[7]; // execute now. 
ziltch = #15 ckz&h; /* ckz&a evaluated now; ziltch changed 
after 15 time units. */ 

#10 hat = b&c; /* 10 units after ziltch changes, b&c is
evaluated and hat changes. */

การบล็อกงาน

คำสั่งกำหนดขั้นตอนการบล็อกจะต้องดำเนินการก่อนการดำเนินการของคำสั่งที่ตามมาในบล็อกตามลำดับ คำสั่งกำหนดขั้นตอนการบล็อกไม่ได้ป้องกันการดำเนินการของคำสั่งที่ตามมาในบล็อกคู่ขนาน

ไวยากรณ์

ไวยากรณ์สำหรับการกำหนดขั้นตอนการบล็อกมีดังนี้ -

<lvalue> = <timing_control> <expression>

โดยที่ lvalue เป็นชนิดข้อมูลที่ถูกต้องสำหรับคำสั่งการกำหนดขั้นตอน = คือตัวดำเนินการกำหนดและการควบคุมเวลาคือความล่าช้าภายในที่เป็นทางเลือก ความล่าช้าในการควบคุมเวลาอาจเป็นได้ทั้งการควบคุมการหน่วงเวลา (เช่น # 6) หรือการควบคุมเหตุการณ์ (ตัวอย่างเช่น @ (posedge clk)) นิพจน์คือค่าด้านขวามือที่เครื่องมือจำลองกำหนดให้ทางด้านซ้ายมือ ตัวดำเนินการ = ที่ใช้โดยการบล็อกการกำหนดขั้นตอนยังใช้โดยการกำหนดขั้นตอนต่อเนื่องและการมอบหมายงานต่อเนื่อง

ตัวอย่าง

rega = 0; 
rega[3] = 1;            // a bit-select 
rega[3:5] = 7;          // a part-select 
mema[address] = 8’hff;  // assignment to a memory element 
{carry, acc} = rega + regb;  // a concatenation

การมอบหมายการไม่ปิดกั้น (RTL)

การกำหนดขั้นตอนที่ไม่ปิดกั้นช่วยให้คุณสามารถกำหนดเวลาการมอบหมายงานได้โดยไม่ปิดกั้นขั้นตอน คุณสามารถใช้คำสั่งขั้นตอนการไม่ปิดกั้นเมื่อใดก็ตามที่คุณต้องการทำการมอบหมายการลงทะเบียนหลายรายการภายในขั้นตอนเวลาเดียวกันโดยไม่คำนึงถึงลำดับหรือการพึ่งพาซึ่งกันและกัน

ไวยากรณ์

ไวยากรณ์สำหรับการกำหนดขั้นตอนที่ไม่ปิดกั้นมีดังนี้ -

<lvalue> <= <timing_control> <expression>

โดยที่ lvalue เป็นชนิดข้อมูลที่ถูกต้องสำหรับคำสั่งการกำหนดขั้นตอน <= คือตัวดำเนินการกำหนดที่ไม่ปิดกั้นและการควบคุมเวลาคือการควบคุมเวลาภายในที่กำหนดซึ่งเป็นทางเลือก ความล่าช้าในการควบคุมเวลาอาจเป็นได้ทั้งการควบคุมการหน่วงเวลาหรือการควบคุมเหตุการณ์ (ตัวอย่างเช่น @ (posedge clk)) นิพจน์คือค่าด้านขวามือที่เครื่องมือจำลองกำหนดให้ทางด้านซ้ายมือ ตัวดำเนินการกำหนดแบบไม่ปิดกั้นเป็นตัวดำเนินการเดียวกับที่ตัวจำลองใช้สำหรับตัวดำเนินการเชิงสัมพันธ์ที่มีคุณภาพน้อยกว่า ตัวจำลองตีความตัวดำเนินการ <= เป็นตัวดำเนินการเชิงสัมพันธ์เมื่อคุณใช้ในนิพจน์และตีความว่าตัวดำเนินการ <= เป็นตัวดำเนินการกำหนดเมื่อคุณใช้ในโครงสร้างการกำหนดขั้นตอนที่ไม่ปิดกั้น

วิธีที่เครื่องจำลองประเมินการกำหนดขั้นตอนที่ไม่ปิดกั้นเมื่อเครื่องจำลองพบการกำหนดขั้นตอนที่ไม่ปิดกั้นเครื่องจำลองจะประเมินและดำเนินการการกำหนดขั้นตอนที่ไม่ปิดกั้นในสองขั้นตอนดังนี้ -

  • เครื่องจำลองจะประเมินทางด้านขวามือและกำหนดเวลาการกำหนดค่าใหม่ที่จะเกิดขึ้นในเวลาที่กำหนดโดยการควบคุมเวลาตามขั้นตอน เครื่องจำลองจะประเมินทางด้านขวามือและกำหนดเวลาการกำหนดค่าใหม่ที่จะเกิดขึ้นในเวลาที่กำหนดโดยการควบคุมเวลาตามขั้นตอน

  • ในตอนท้ายของขั้นตอนเวลาซึ่งความล่าช้าที่กำหนดได้หมดลงหรือเหตุการณ์ที่เหมาะสมเกิดขึ้นตัวจำลองจะดำเนินการมอบหมายโดยกำหนดค่าให้ทางด้านซ้ายมือ

ตัวอย่าง

module evaluates2(out); 
output out; 
reg a, b, c; 
initial 

begin 
   a = 0; 
   b = 1; 
   c = 0; 
end 
always c = #5 ~c; 
always @(posedge c) 

begin 
   a <= b; 
   b <= a; 
end 
endmodule

เงื่อนไข

คำสั่งเงื่อนไข (หรือคำสั่ง if-else) ใช้ในการตัดสินใจว่าจะดำเนินการคำสั่งหรือไม่

อย่างเป็นทางการไวยากรณ์มีดังนี้ -

<statement> 
::= if ( <expression> ) <statement_or_null> 
||= if ( <expression> ) <statement_or_null> 
   else <statement_or_null> 
<statement_or_null> 

::= <statement> 
||= ;

<expression> ได้รับการประเมิน; ถ้าเป็นจริง (นั่นคือมีค่าที่ไม่รู้จักเป็นศูนย์) คำสั่งแรกจะดำเนินการ ถ้าเป็นเท็จ (มีค่าเป็นศูนย์หรือค่า x หรือ z) คำสั่งแรกจะไม่ดำเนินการ หากมีคำสั่ง else และ <expression> เป็นเท็จคำสั่ง else จะดำเนินการ เนื่องจากค่าตัวเลขของนิพจน์ if ถูกทดสอบว่าเป็นศูนย์จึงสามารถใช้ทางลัดบางอย่างได้

ตัวอย่างเช่นสองคำสั่งต่อไปนี้แสดงตรรกะเดียวกัน -

if (expression) 
if (expression != 0)

เนื่องจากส่วนอื่นของ if-else เป็นทางเลือกอาจมีความสับสนเมื่อส่วนอื่นถูกละไว้จากลำดับ if ที่ซ้อนกัน สิ่งนี้แก้ไขได้โดยการเชื่อมโยงสิ่งอื่นกับสิ่งที่ใกล้เคียงที่สุดก่อนหน้านี้เสมอหากไม่มีสิ่งอื่น

ตัวอย่าง

if (index > 0) 
if (rega > regb) 
   result = rega; 
   else // else applies to preceding if 
   result = regb; 

If that association is not what you want, use a begin-end block statement 
to force the proper association 

if (index > 0) 
begin 

if (rega > regb) 
result = rega; 
end 
   else 
   result = regb;

โครงสร้างของ: if- else- if

การก่อสร้างต่อไปนี้เกิดขึ้นบ่อยครั้งมากจนควรมีการอภิปรายแยกกันสั้น ๆ

Example

if (<expression>) 
   <statement> 
   else if (<expression>) 
   <statement> 
   else if (<expression>) 
   <statement> 
   else  
   <statement>

ลำดับของ if นี้ (เรียกว่าโครงสร้าง if-else-if) เป็นวิธีทั่วไปที่สุดในการเขียนการตัดสินใจหลายทาง นิพจน์ได้รับการประเมินตามลำดับ หากนิพจน์ใด ๆ เป็นจริงคำสั่งที่เกี่ยวข้องจะถูกดำเนินการและสิ่งนี้จะยุติห่วงโซ่ทั้งหมด แต่ละคำสั่งเป็นทั้งคำสั่งเดียวหรือบล็อกของคำสั่ง

ส่วนอื่นสุดท้ายของโครงสร้าง if-else-if จัดการกับกรณีที่ "ไม่มีข้อใดข้อหนึ่งข้างต้น" หรือกรณีเริ่มต้นโดยที่เงื่อนไขอื่นไม่เป็นไปตาม บางครั้งไม่มีการดำเนินการที่ชัดเจนสำหรับค่าเริ่มต้น ในกรณีนั้นสามารถละเว้นอื่น ๆ ต่อท้ายหรือสามารถใช้สำหรับการตรวจสอบข้อผิดพลาดเพื่อตรวจจับเงื่อนไขที่เป็นไปไม่ได้

คำชี้แจงกรณี

คำชี้แจงกรณีเป็นคำสั่งการตัดสินใจหลายทางแบบพิเศษที่ทดสอบว่านิพจน์ตรงกับนิพจน์อื่น ๆ หรือไม่และแตกแขนง คำสั่ง case มีประโยชน์สำหรับการอธิบายตัวอย่างเช่นการถอดรหัสคำสั่งของไมโครโปรเซสเซอร์ คำสั่ง case มีไวยากรณ์ต่อไปนี้ -

Example

<statement> 
::= case ( <expression> ) <case_item>+ endcase 
||= casez ( <expression> ) <case_item>+ endcase 
||= casex ( <expression> ) <case_item>+ endcase 
<case_item> 
::= <expression> <,<expression>>* : <statement_or_null> 
||= default : <statement_or_null> 
||= default <statement_or_null>

สำนวนคดีจะได้รับการประเมินและเปรียบเทียบตามลำดับที่ได้รับ ในระหว่างการค้นหาเชิงเส้นหากหนึ่งในนิพจน์ไอเท็มเคสตรงกับนิพจน์ในวงเล็บคำสั่งที่เกี่ยวข้องกับไอเท็มเคสนั้นจะถูกดำเนินการ หากการเปรียบเทียบทั้งหมดล้มเหลวและมีการกำหนดรายการเริ่มต้นระบบจะดำเนินการคำสั่งรายการเริ่มต้น หากไม่ได้กำหนดคำสั่งเริ่มต้นและการเปรียบเทียบทั้งหมดล้มเหลวจะไม่มีการเรียกใช้งานคำสั่ง case item

นอกเหนือจากไวยากรณ์คำสั่ง case แตกต่างจากการสร้าง if-else-if แบบหลายทางในสองวิธีที่สำคัญ -

  • นิพจน์เงื่อนไขในโครงสร้าง if-else-if มีลักษณะทั่วไปมากกว่าการเปรียบเทียบนิพจน์หนึ่งกับนิพจน์อื่น ๆ เช่นในคำสั่ง case

  • คำสั่ง case ให้ผลลัพธ์ที่ชัดเจนเมื่อมีค่า x และ z ในนิพจน์

คำสั่งวนซ้ำ

คำสั่งวนซ้ำมีสี่ประเภท พวกเขาให้วิธีการควบคุมการดำเนินการของคำสั่งศูนย์หนึ่งครั้งหรือมากกว่านั้น

  • ดำเนินการคำสั่งอย่างต่อเนื่องตลอดไป

  • ทำซ้ำดำเนินการคำสั่งตามจำนวนครั้งที่กำหนด

  • ในขณะที่ดำเนินการคำสั่งจนกว่านิพจน์จะกลายเป็นเท็จ ถ้านิพจน์เริ่มต้นเป็นเท็จจะไม่มีการดำเนินการคำสั่งเลย

  • สำหรับการควบคุมการดำเนินการของคำสั่งที่เกี่ยวข้องโดยกระบวนการสามขั้นตอนดังต่อไปนี้ -

    • ดำเนินการมอบหมายตามปกติที่ใช้เพื่อเริ่มต้นตัวแปรที่ควบคุมจำนวนลูปที่ดำเนินการ

    • ประเมินนิพจน์ - ถ้าผลลัพธ์เป็นศูนย์สำหรับลูปจะออกและถ้าไม่ใช่ศูนย์ for loop จะรันคำสั่งที่เกี่ยวข้องจากนั้นดำเนินการขั้นตอนที่ 3

    • ดำเนินการมอบหมายตามปกติที่ใช้เพื่อแก้ไขค่าของตัวแปร loopcontrol จากนั้นทำซ้ำขั้นตอนที่ 2

ต่อไปนี้เป็นกฎไวยากรณ์สำหรับคำสั่งวนซ้ำ -

Example

<statement> 
::= forever <statement> 
||=forever 
begin 
   <statement>+ 
end  

<Statement> 
::= repeat ( <expression> ) <statement> 
||=repeat ( <expression> ) 
begin
   <statement>+ 
end  

<statement> 
::= while ( <expression> ) <statement> 
||=while ( <expression> ) 
begin 
   <statement>+ 
end  
<statement> 
::= for ( <assignment> ; <expression> ; <assignment> ) 
<statement> 
||=for ( <assignment> ; <expression> ; <assignment> ) 
begin 
   <statement>+ 
end

การควบคุมความล่าช้า

การควบคุมความล่าช้า

การดำเนินการของคำสั่งขั้นตอนสามารถควบคุมความล่าช้าได้โดยใช้ไวยากรณ์ต่อไปนี้ -

<statement> 
::= <delay_control> <statement_or_null> 
<delay_control> 
::= # <NUMBER> 
||= # <identifier> 
||= # ( <mintypmax_expression> )

ตัวอย่างต่อไปนี้ทำให้การดำเนินการมอบหมายล่าช้าไป 10 หน่วยเวลา -

# 10 rega = regb;

สามตัวอย่างถัดไปแสดงนิพจน์ตามหลังเครื่องหมายตัวเลข (#) การดำเนินการของความล่าช้าในการมอบหมายตามจำนวนเวลาจำลองที่ระบุโดยค่าของนิพจน์

การควบคุมเหตุการณ์

การดำเนินการของคำสั่งขั้นตอนสามารถซิงโครไนซ์กับการเปลี่ยนแปลงค่าบนเน็ตหรือรีจิสเตอร์หรือการเกิดเหตุการณ์ที่ประกาศโดยใช้ไวยากรณ์การควบคุมเหตุการณ์ต่อไปนี้ -

Example

<statement> 
::= <event_control> <statement_or_null> 

<event_control> 
::= @ <identifier> 
||= @ ( <event_expression> ) 

<event_expression> 
::= <expression> 
||= posedge <SCALAR_EVENT_EXPRESSION> 
||= negedge <SCALAR_EVENT_EXPRESSION> 
||= <event_expression> <or <event_expression>>

* <SCALAR_EVENT_EXPRESSION> คือนิพจน์ที่แก้ไขเป็นค่าหนึ่งบิต

การเปลี่ยนแปลงมูลค่าบนมุ้งและรีจิสเตอร์สามารถใช้เป็นเหตุการณ์เพื่อทริกเกอร์การดำเนินการของคำสั่ง สิ่งนี้เรียกว่าการตรวจจับเหตุการณ์โดยปริยาย ไวยากรณ์ Verilog ยังช่วยให้คุณตรวจจับการเปลี่ยนแปลงตามทิศทางของการเปลี่ยนแปลงนั่นคือไปยังค่า 1 (posedge) หรือไปที่ค่า 0 (negedge) พฤติกรรมของ posedge และ negedge สำหรับค่านิพจน์ที่ไม่รู้จักมีดังนี้ -

  • ตรวจพบ negedge ในการเปลี่ยนจาก 1 เป็นไม่ทราบและจากไม่ทราบเป็น 0
  • มีการตรวจพบ posedge ในการเปลี่ยนจาก 0 เป็นไม่ทราบและจากไม่ทราบเป็น 1

ขั้นตอน: เสมอและบล็อกเริ่มต้น

ขั้นตอนทั้งหมดใน Verilog ถูกระบุไว้ในหนึ่งในสี่บล็อกต่อไปนี้ 1) บล็อกเริ่มต้น 2) บล็อกเสมอ 3) ภารกิจ 4) ฟังก์ชัน

เปิดใช้งานคำสั่งเริ่มต้นและเสมอเมื่อเริ่มต้นการจำลอง บล็อกเริ่มต้นดำเนินการเพียงครั้งเดียวและกิจกรรมจะตายเมื่อคำสั่งเสร็จสิ้น ในทางตรงกันข้ามบล็อกเสมอจะดำเนินการซ้ำ ๆ กิจกรรมจะตายก็ต่อเมื่อการจำลองสิ้นสุดลง ไม่มีการ จำกัด จำนวนบล็อกเริ่มต้นและบล็อกเสมอที่สามารถกำหนดได้ในโมดูล งานและฟังก์ชันคือโพรซีเดอร์ที่เปิดใช้งานจากที่หนึ่งหรือหลายแห่งในโพรซีเดอร์อื่น

บล็อกเริ่มต้น

ไวยากรณ์สำหรับคำสั่งเริ่มต้นมีดังนี้ -

<initial_statement> 
::= initial <statement>

ตัวอย่างต่อไปนี้แสดงให้เห็นถึงการใช้คำสั่งเริ่มต้นสำหรับการกำหนดค่าเริ่มต้นของตัวแปรเมื่อเริ่มต้นการจำลอง

Initial 
Begin 
   Areg = 0; // initialize a register 
   For (index = 0; index < size; index = index + 1) 
   Memory [index] = 0; //initialize a memory 
   Word 
End

การใช้งานทั่วไปอีกประการหนึ่งของบล็อกเริ่มต้นคือข้อกำหนดของคำอธิบายรูปคลื่นที่ดำเนินการครั้งเดียวเพื่อกระตุ้นให้เกิดส่วนหลักของวงจรที่กำลังจำลอง

Initial 
Begin 
   Inputs = ’b000000; 
   // initialize at time zero 
   #10 inputs = ’b011001; // first pattern 
   #10 inputs = ’b011011; // second pattern 
   #10 inputs = ’b011000; // third pattern 
   #10 inputs = ’b001000; // last pattern 
End

บล็อกเสมอ

คำสั่ง 'เสมอ' จะทำซ้ำอย่างต่อเนื่องตลอดการดำเนินการจำลองทั้งหมด ไวยากรณ์สำหรับคำสั่ง always แสดงไว้ด้านล่าง

<always_statement> 
::= always <statement>

คำสั่ง 'เสมอ' เนื่องจากลักษณะการวนซ้ำจึงมีประโยชน์เมื่อใช้ร่วมกับการควบคุมเวลาบางรูปแบบเท่านั้น หากคำสั่ง 'always' ไม่ให้เวลาล่วงหน้าคำสั่ง 'always' จะสร้างเงื่อนไขการหยุดชะงักจำลอง ตัวอย่างเช่นรหัสต่อไปนี้สร้างลูปดีเลย์เป็นศูนย์ที่ไม่มีที่สิ้นสุด -

Always areg = ~areg;

การให้การควบคุมเวลาให้กับโค้ดด้านบนจะสร้างคำอธิบายที่เป็นประโยชน์ดังตัวอย่างต่อไปนี้ -

Always #half_period areg = ~areg;