توسط احمد ثقفی 

19 خرداد, 1397

ساختارهای شرطی در زبان VHDL

فکر می‌کنید اگر یک کد بزرگ به زبان VHDL یا Verilog را بررسی کنید، چه ساختاری بیش از بقیه در آن به کار رفته است؟

احتمالا درست حدس زدید…

ساختارهای شرطی.

بنابراین به نظر منطقی است که توجه ویژه‌ای به این ساختار و تکنیک‌های استفاده صحیح از آن داشته باشیم، چون عمده کد شما از آن تشکیل شده است.

در این مقاله، ساختارهای شرطی در زبان VHDL را به صورت کاملا مفهومی بررسی می‌کنم و نکات فوق‌العاده کاربردی و اثرگذار در استفاده بهینه از این ساختارها را به شما معرفی می‌کنم.

More...

ساختارهای شرطی اصلی در زبان VHDL

زبان VHDL دارای دو ساختار شرطی اصلی if و case است. شما در نهایت خواهید دید که عمده مداری که به کمک زبان VHDL یا Verilog توصیف می‌کنید از ساختارهای شرطی تشکیل شده است و عمده این ساختارهای شرطی هم، ساختار شرطی if است.

برای دانلود فایل PDF این مقاله، روی دکمه زیر کلیک کنید:

به همین دلیل، باید در مورد این ساختار دقیق‌تر باشید و نکاتی را که برای پیاده‌سازی صحیح آن وجود دارد، در نظر داشته باشید تا کدهایی که پیاده‌سازی می‌کنید، سرعت بیشتری داشته باشند و منابع سخت‌افزاری کمتری استفاده کنند.

برای آشنایی با ساختار if در محیط پراسس، این برنامه ویدئویی را ببینید…

تفاوت ساختار شرطی IF و CASE در پیاده‌سازی

اولین نکته‌ای که در مورد ساختار if باید بدانید، این است که ساختار if وقتی پیاده‌سازی می‌شود، به صورت سری پیاده‌سازی می‌شود که در ادامه در مورد این موضوع بیشتر توضیح خواهم داد. اما این سری بودن پیاده‌سازی، باعث تأخیر زیاد این ساختار می‌شود. برعکس آن، ساختار case به صورت موازی پیاده‌سازی می‌شود و تأخیر کمتری دارد.

اما ساختار if، علی‌رغم اینکه در پیاده‌سازی ممکن است باعث ایجاد تأخیر شود، بسیار پرکاربردتر است، به دلیل اینکه بسیار منعطف‌تر است. همانطور که می‌دانید ساختار case، ساختار بسیار محدودی است.

در ساختار case شما فقط می‌توانید روی یک سیگنال خاص، شرط مساوی بودن قرار دهید. مثلا سیگنال X اگر برابر با مقدار یک شد، یک عملیاتی انجام شود، اگر برابر با مقدار دو شد، یک سری ارجاعات دیگر انجام می‌شود و همین‌طور الی‌آخر.

اما شما با ساختار case، نمی‌توانید مثلا شرط‌ بزرگتر-مساوی (=<) ایجاد کنید. شما با ساختار case نمی‌توانید شرط‌های ترکیبی ایجاد کنید. مثلاً نمی‌توانید شرط A>B and C=۱ داشته باشید. این نوع شرط‌های منعطف و متنوع را، فقط با ساختار if می‌توانید درست کنید. بنابراین، ساختار if بسیار پرکاربردتر است.

با این حال استفاده از ساختار case، در صورت امکان به if ارجح است، به این دلیل که case، به صورت موازی پیاده‌سازی می‌شود و دارای تأخیر انتشار کمتری است.

در شکل زیر شما یک ساختار if-then-elsif را مشاهده می‌کنید که شرط یک، دو، سه، چهار و یک else و تعدادی ارجاع در آن وجود دارد:

if (Condition1) then
     Output <= A;
elsif (Condition2) then
     Output <= B;
elsif (Condition3) then
     Output <= C;
elsif (Condition4) then
     Output <= D;
else
     Output <= E;
end if;

با توجه به شرط‌هایی که داریم، پیاده‌سازی آن تقریباً به صورت شکل زیر می‌شود:

پیاده‌سازی ساختار شرطی if

البته در FPGAهای مختلف و در شرایط مختلف، ممکن است که ظاهر این پیاده‌سازی کمی فرق کند، ولی مفهوم و ماهیت پیاده‌سازی تقریباً به این صورت است.

در این جا اگر شرط یک (Condition1) برقرار باشد به کمک مالتی‌پلکسر اول، A به خروجی متصل می‌شود. اگر این شرط برقرار نشود، ورودی شماره صفر به خروجی متصل می‌شود، و ورودی صفر خودش خروجی یک مالتی‌پلکسر دیگر است که بر مبنای شرط دو، نتیجه‌اش مشخص می‌شود.

اگر شرط دو برقرار باشد، B به خروجی متصل می‌شود و در نتیجه، B به خروجی اصلی (Output) متصل می‌شود. در غیر این‌صورت باید به مالتی‌پلکسر قبلی مراجعه کنیم و همین طور الی‌آخر.

اگر شرط چهار برقرار باشد و مثلاً قرار باشد D به خروجی متصل شود، D باید از چهار مالتی‌پلکسر بگذرد. یعنی D، برای اینکه به خروجی برسد، یک تأخیر انتشار (Propagation Delay) معادل چهار‌ مالتی‌پلکسر را در مقابل خودش خواهد داشت که این باعث تأخیر انتشار احتمالاً زیادی می‌شود و این هم به نوبه خود باعث کاهش سرعت مدار شما می‌شود.

نکته‌ای که باید در این ساختار به آن توجه کنیم، این است که در شاخه‌های مختلف شرط if، هر شاخه‌ای که بالاتر است، تاخیر انتشار کمتری دارد. مثلاً اگر شرط یک برقرار باشد و سیگنال A قرار باشد به خروجی متصل شود، فقط تاخیر معادل یک مالتی‌پلکسر را می‌بیند. اما همان‌طور که گفتم، سیگنال D یا سیگنال E، تاخیری معادل چهار مالتی‌پلکسر را تا خروجی خواهند داشت. بنابراین، اگر سیگنال دیتایی در یک مسیر تاخیر انتشار طولانی‌تری قرار گرفته است که باعث کاهش حداکثر فرکانس کلاک قابل اعمال به مدارتان شده است، بهتر است که چنین سیگنال حساسی را در شرط‌های اولیه if قرار دهید تا حداقل ساختار if روی آن یک تاخیر انتشار مضاعف ایجاد نکند.

نکات مهم در هنگام استفاده از ساختارهای شرطی

به طور کلی چه در مورد ساختار شرطی if و چه در مورد ساختار شرطی case، چند نکته را باید رعایت کنید تا مدارتان از سرعت بیشتری برخوردار شود. 

از شرط‌های تو در تو کمتر استفاده کنید

نکته اول این است که تا جایی که می‌توانید، از شرط‌های تو در تو کمتر استفاده کنید. من پیشنهاد می‌کنم، بیش از سه شرط تو در تو استفاده نکنید و مطمئن باشید که بیشتر از این هم لازم ندارید. حتی اگر توانستید کمتر از سه شرط استفاده کنید، خیلی می‌تواند در پیاده‌سازی بهینه مدار شما و افزایش سرعت مدار شما کمک کند. 

عبارت شرط را تا حد امکان ساده کنید

نکته دوم این است که تا حد امکان عبارت شرط را ساده بگیرید. منظورم از عبارت شرط، همان معادله یا رابطه‌ای است که به عنوان شرط نوشته‌اید. مثلاً ساده‌ترین عبارت شرط، عبارت ’A=’۰ است. حال اگر فرض کنیم که A، یک سیگنال تک‌بیتی است، ’A=’۰، ساده‌ترین شرط ممکن است.

اما شرط‌های پیچیده‌تر مثل A>B (فرض کنید که مثلاً A و B، ده‌بیتی هستند)، یا شرط‌های ترکیبی مثل، A>B and C=10 باعث ایجاد تاخیر انتشار در مدار شما می‌شوند و سرعت مدارتان را کاهش می‌دهند. 

ارجاعاتی را که لازم نیست، درون شرط قرار ندهید

نکته بعدی این است که تا جای ممکن ارجاعاتی را که لازم نیست، درون شرط قرار ندید. مساله‌ای که وجود دارد این است که بسیاری از افراد به اشتباه و ناخودآگاه، خیلی از ارجاعاتی را که اصلاً لازم نیست درون یک شرط باشند، درون شرط‌ها قرار می‌دهند و همین باعث کاهش سرعت مدار می‌شود.

بنابراین، به هر ارجاعی که درون شرط قرار می‌دهید، کاملاً دقت کنید و از خودتان بپرسید که آیا واقعاً این ارجاع لازم است که درون این شرط قرار داده شود، یا می‌تواند بیرون این شرط قرار داده شود و اگر شما بتوانید آن را بیرون از شرط قرار دهید و درون یک if را تا جای ممکن خلوت‌تر کنید، سرعت مدارتان حتما بیشتر خواهد شد. 

مقدار خروجی‌ها را در تمام شاخه‌های شرط مشخص کنید

نکته دیگری که در استفاده از ساختارهای if و case باید رعایت کنید، این است که مقدار خروجی‌ها را در تمام شاخه‌های شرط مشخص کنید. منظور از شاخه‌ها همانطور که گفتم، هر کدام از شرط‌ها است. مثلاً if A=’۰’ then می‌شود یک شاخه. بعد از آن ممکن است بنویسید elsif B=’۱’ then، که این هم می‌شود یک شاخه دیگر و همین‌طور الی‌آخر.

در هر کدام از این شاخه‌ها، به سیگنال‌ها مقادیری را ارجاع می‌دهید. نکته‌ای که باید در نظر داشته باشید این است که در تمام شاخه‌ها، تکلیف همه سیگنال‌ها را مشخص کنید. مثلاً فرض کنید که در شاخه اول به سیگنال A مقداری را ارجاع می‌کنید و در دو شاخه بعد مقداری را ارجاع نمی‌کنید و بعد دوباره در شاخه چهارم، مقداری را به A، ارجاع می‌کنید. این روش درستی نیست.

اگر شما در تمام شاخه‌ها مقدار خروجی را مشخص نکنید، باعث می‌شود که در مدارتان لچ‌ها و Clock Enableهای ناخواسته ایجاد شود و خود این باعث افزایش حجم و کاهش سرعت مدارتان می‌شود. بنابراین، پیشنهادی که می‌توانم برای جلوگیری از این موضوع ارائه کنم، این است که یا در تمام شاخه‌های شرط، به خروجی، ارجاع داشته باشید، یا اینکه یک مقدار پیش‌فرضی را، قبل از شرط، یعنی قبل از ساختار if یا ساختار case، به آن خروجی اعمال کنید و بعد در هر‌کدام از شاخه‌ها که لازم بود ارجاع کنید و در هر‌کدام از شاخه‌ها که لازم نبود ارجاع نکنید.

در این حالت، دیگر اهمیتی ندارد که حتما در تمام شاخه‌ها ارجاع به آن سیگنال خاص را داشته باشید. به این دلیل که شما یک بار در بیرون if و بالای شرط، یک ارجاع به آن خروجی داشتید. حالا اگر ارجاع دیگری در یکی از شاخه‌ها رخ داد که انجام می‌شود. اگر ارجاعی رخ نداد، مهم نیست. چون تکلیف سیگنال در آن کلاک و بیرون شرط مشخص شده است. 

پایپ‌لاین کردن ساختارهای شرطی در زبان VHDL

آخرین موضوعی که در این مقاله می‌خوام مطرح کنم، در زمینه پایپ‌لاین کردن شرط‌هاست. همانطور که گفتم، مساله پایپ‌لاین کردن بسیار مهم است و در موارد مختلفی در کدتان شما می‌توانید عمل پایپ‌لاین کردن را انجام دهید. یکی از مواردی که افراد معمولا کمتر در مورد پایپ‌لاین کردن آن فکر می‌کنند، پایپ‌لاین کردن خود شرط‌ها است.

برای آشنایی با مفهوم پایپ‌لاین و نحوه پایپ‌لاین کردن مدار در زبان VHDL این مقاله را بخوانید…

همانطور که گفتم، هر چقدر عبارت شرط شما پیچیده‌تر باشد، احتمال کاهش سرعت مدار شما بیشتر است. بنابراین، از تکنیک پایپ‌لاین می‌توانید استفاده کنید برای اینکه شرط‌ها را ساده کنید. مثلاً به کد ساده زیر دقت کنید:

process (Clock)
begin
     if rising_edge(Clock) then
          if (En = ‘۱’ and G1 = ‘۱’) then
               B <= A;
          end if;
     end if;
end process;

در این کد ساده، ما فلیپ‌فلاپی تعریف کردیم که دارای یک Clock Enable (فعال‌ساز کلاک) است و شرط این فعال‌ساز برابر با ’En=’۱’ and G1=’۱ است. مدار معادل این کد در FPGA، در شکل زیر نشان داده شده است:

ساختار if بدون پایپ‌لاین

برای این کار، گیتی پیاده‌سازی می‌شود که حاصل ’En=’۱’ and G1=’۱ را محاسبه می‌کند و به عنوان Clock Enable به فلیپ‌فلاپ اعمال می‌کند. شرطی که در این‌جا داریم، یک شرط ترکیبی است که به کمک گیت and ایجاد شده است.

همین شرط می‌تواند تا حدی سرعت را کاهش دهد. البته در نظر داشته باشید که پیاده‌سازی چنین شرطی در یک مدار پیچیده، خیلی مشکل‌ساز نیست و من این تکنیک را فقط برای استفاده در زمانی پیشنهاد می‌کنم که شما مطمئن باشید که این شرط، باعث کاهش سرعت مدارتان شده است و در غیر این صورت، این شرط، اصولا شرط خیلی پیچیده‌ای حساب نمی‌شود.

اما اگر فرض کنیم که این شرط باعث شده است که مدار شما کند شود و شما اگر این شرط را ساده کنید، سرعت مدارتان بیشتر می‌شود، تکنیکی که می‌توانید برای ساده‌سازی آن استفاده کنید، تکنیک پایپ‌لاین کردن شرط است.

چطور این کار را انجام دهیم؟

خیلی راحت شما می‌توانید شرط ’En=’۱’ and G1=’۱ را، به صورت زیر تغییر دهید:

process (Clock)
begin
     if rising_edge(Clock) then
         Enable <= En and G1;
          if (Enable = ‘1’) then
               B <= A;
          end if;
     end if;
end process;

یک سیگنال داخلی تعریف می‌کنید و اسم آن را مثلا Enable انتخاب می‌کنید. در محیط پراسس می‌نویسید:

Enable <= En and G1;

حالا خیلی ساده در شرط if می‌نویسیم:

if (Enable = ‘1’) then

عملکرد این مدار کاملاً مشابه عملکرد مدار قبلی است، با این تفاوت که شرط، بسیار ساده شده است. در واقع شرط به ساده‌ترین نوع خودش تغییر پیدا کرده است؛ یعنی مقایسه یک سیگنال تک‌بیتی با صفر یا یک.

اما تغییری که در پیاده‌سازی اتفاق افتاده است، این است که یک فلیپ‌فلاپ در خروجی گیت and قرار گرفته است. در واقع مسیر قبلی، حالا پایپ‌لاین شده است. این تغییر را می‌توانید در شکل زیر ببینید:

ساختار if به صورت پایپ‌لاین

یک مثال پیچیده‌تر از پایپ‌لاین کردن شرط IF

اجازه دهید یک مثال پیچیده‌تر را به صورت پایپ‌لاین پیاده‌سازی کنیم. فرض کنید شرطی که می‌خواهید پیاده‌سازی کنید، به صورت زیر است:

process (Clock)
begin
     if rising_edge(Clock) then
          if (> D) then
              B <= A;
          end if;
end if;
end process;

یعنی شرط C>D و فرض کنیم که این شرط باعث شده است که سرعت مدار شما کاهش پیدا کند. یعنی اگر این شرط را ساده کنیم، سرعت مدار بهبود پیدا می‌کند. چطور می‌توانیم این شرط را پایپ‌لاین کنیم؟

این هم بسیار ساده است.

عبارت شرط برابر با C>D است و اگر D را به سمت چپ شرط منتقل کنید، می‌شود C-D>0 که معنی آن این است که باید C منهای D، بزرگتر از صفر باشد یا C منهای D، باید مثبت باشد.

بنابراین می‌توانید C منهای D را در محیط پراسس محاسبه کنید و در یک سیگنال میانی مثل E بریزید. یعنی می‌نویسید:

<= C – D;

فرض کنید که C و D و E، هشت بیتی‌اند. یعنی سنگین‌ترین بیت E، که دارای اندیس هفت است، (E(7، همان بیت علامت سیگنال E است.

شرط اصلی، بزرگتر بودن C از D بود. به عبارت دیگر، C منهای D مثبت باشد. حاصل C منهای D را به E ارجاع دادیم. اگر E مثبت باشد، یعنی سنگین‌ترین بیت آن که همان (E(7 است باید صفر باشد. بنابراین شرط را می‌توانید خیلی ساده به صورت زیر بازنویسی کنید:

process (Clock)
begin
     if rising_edge(Clock) then
         E <= C  D;
          if (E(7) = ‘0’) then
               B <= A;
          end if;
end if;
end process;

همانطور که می‌بینید، در این مثال هم، یک شرط سنگین و پیچیده مقایسه‌ای، تبدیل شد به یک شرط تک‌بیتی. فقط نکته‌ای را که باید در نظر داشته باشید این است که وقتی شرط را به دلیل استفاده از روش پایپ‌لاین، به اندازه یک کلاک عقب می‌اندازید، در واقع ارجاعات داخل آن را هم (در این مثال، ارجاع A به B) یه کلاک عقب می‌اندازید.

پس در بقیه مدار باید دقت داشته باشید، اگر مقدار سیگنال B باید در زمان خاصی با بخش دیگری از مدار در یک محاسبه مشترک استفاده شوند، باید در آن بخش هم یک کلاک تاخیر ایجاد کنید تا زمان محاسبه B با زمان محاسبه آن بخش از مدارتان همزمان شود و ارتباطات زمانی مدارتان به هم نخورد.

امیدوارم که مطالب این مقاله هم برای شما مفید بوده باشد و از همین امروز آنها را در پروژ‌های خودتان استفاده کنید. لطفا نظرتان را در مورد این مقاله در بخش نظرات برای من به اشتراک بگذارید.

 

آیا مقاله رمز و راز ساختارهای شرطی در زبان VHDL برای شما مفید بود؟

لطفا نظرتان را در مورد این برنامه در پایین همین پست با دیگران به اشتراک بگذارید. همچنین با کلیک روی هر کدام از دکمه‌های اشتراک گذاری ابتدای این مطلب و به اشتراک‌گذاری آن در شبکه‌های اجتماعی می‌توانید افراد بیشتری را در یادگیری این مطالب سهیم کنید.

کانال تلگرام آموزش FPGA از صفر

برای عضویت در کانال تلگرام و دسترسی به آموزش‌های بیشتر و اطلاع سریع از زمان انتشار آموزش‌ها و تخفیف‌های ویژه، روی دکمه زیر کلیک کنید:

شاید به این موضوعات نیز علاقه داشته باشید:

  • سلام. برای پیاده سازی یک جدول صحت بزرگ چه توصیه ای دارید. فرض کنید ۹ سیگنال ورودی داریم که قصد داریم از آنها سه سیگنال کنترلی خروجی بسازیم و با توجه به شرط های سیستممون ورودی و خروجی ها رو در یک جدول صحت مرتب کرده ایم. در کل برای پیاده سازی جدول صحت چه ساختار شرطی توصیه می کنید؟ و اینکه بزرگ بودن این ساختار از نظر پیاده سازی و سرعت چه اشکالاتیو میتونه ایجاد کنه

    • پیاده سازی شما قطعا باید با case انجام بشه، اینکه چقدر باعث کاهش سرعت میشه، بستگی به شرط ها و میزان اشتراکاتشون داره و قابل پیشبینی نیست. در صورتی که نیاز به مشاوره بیشتر دارید از طریق ID تلگرام ask_linx@ سوالتون رو مطرح کنید.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

    ۷ تکنیک پیشرفته کدنویسی برای FPGA

    >