آموزش FPGA : قسمت نوزدهم

آموزش FPGA : قسمت نوزدهم

for; در قسمت هجدهم از مجموعه آموزشی FPGA با شیفت رجیستر آشنا شدیم و مفصلا به تعریف آن پرداختیم، ساختارهای مختلف آن را با هم دیدیدم، همچنین عملکرد انواع شیفت رجیسترها را بررسی کردیم و آن‌ها را با رجیسترها مقایسه کردیم. در نهایت هم یک نوع از آن شیفت رجیسترها را یک بار با شیفت به راست و بار دیگر با شیفت به چپ با استفاده از کد VHDL توصیف کردیم. اما اگر می‌خواستیم عرض بیت شیفت رجیستر را افزایش بدهیم با یک مشکل جدی روبه‌رو بودیم، و باید تعداد خطوط کدی که می‌نوشتیم بیشتر و بیشتر می‌شد که این موضوع برای شیفت رجیسترهایی با تعداد بیت زیاد اذیت‌کننده است. چندین راه برای اینکه بتوانیم این مشکل را هموار کنیم وجود دارد یک راه استفاده از عملگرهاست، اما چون هنوز با عملگرها در زبان VHDL آشنا نیستیم نمی‌توانیم از آن‌ها استفاده کنیم. شما بعدا که با این عملگرها آشنا شدید، می‌توانید خودتان کد موردنظر را بنویسید. راه دیگر استفاده از ساختار for در زبان VHDL می‌باشد که ابتدا باید با این ساختار آشنا شویم و پس از اینکه با عملکرد این ساختار آشنا شدیم کدهای قسمت قبل را با این ساختار توصیف کنیم.

ساختار for در زبان VHDL

اگر قبلا با زبان‌های برنامه‌نویسی دست و پنجه نرم کرده باشید به احتمال زیاد با for آشنا هستید. ما نیز قصد نداریم که به تشریح حلقه‌ها و انواع آن‌ها بپردازیم بلکه توضیحاتی مختصر می‌دهیم تا هم یادآوری شود و هم بتوانیم ادامه صحبت‌مان را بهتر ارائه بدهیم تا موضوع به خوبی تفهیم شود. مثلا اگر می‌خواستیم در خانه‌های یک آرایه بنویسیم دو راه وجود داشت، یک راه اینکه با استفاده از اندیس آن آرایه در هر خط کد مقادیری را به خانه‌های آرابه اختصاص بدهیم که این کار اگر تعداد خانه‌های آرایه زیاد باشد کاری حوصله‌بر و وقت‌گیر است. راه دیگر این بود که با استفاده از حلقه for و تعیین شرطی متناسب با خانه‌های آرایه، فقط با چند خط در خانه‌های آرایه بنویسیم که راهی معقول‌تر و به نسبت خیلی راحت‌تر است. ما نیز قصد داریم که با همین ایده کدهای جلسه قبل را بهینه‌تر کنیم و تا هر مقدار که بخواهیم با تغییراتی بسیار کوچکی عرض بیت شیفت رجیستر را افزایش بدهیم. برای دسترسی به الگوی ساختار for در زبان VHDL می‌توانیم همانند تصویر زیر در نرم‌افزار ISE، ابتدا روی علامت لامپ روشن کلیک کنید و سپس طبق تصویر، For Loop را از دسته Loops انتخاب کنید تا به الگویی که در ادامه کد آن آورده می‌شود برسید.

for <variable_name> in <lower_limit> to <upper_limit> loop
   <statement>;
   <statement>;
end loop;

به این دلیل مشخصا اسم اندیس را به کار می‌بریم و نمی‌گوییم متغیر یا سیگنال، چون که قرار نیست variable_name در ابتدای کد به عنوان سیگنال یا متغیر تعریف شود و بعد در ساختار For Loop از آن استفاده کنیم، فقط و فقط به جای variable_name یک اندیس قرار می‌دهیم و در هیچ کجای کد این اندیس نه تعریف می‌شود و نه مقداردهی.
حال شاید برایتان سوال پیش آمده باشد که در زبان‌های برنامه‌نویسی ما اندیس‌ها یا همان شمارنده‌هایی که در حلقه‌ها به کار می‌بردیم را باید از قبل به عنوان متغیر تعریف می‌کردیم، اما چرا اینجا اینکار را نمی‌کنیم؟ به صورت خیلی خلاصه جواب این سوال برمی‌گردد به ساختار FPGA و CPU و کد نهایی که برای FPGA و CPU تولید می‌شود، اما چون این مبحث از حوصله‌ی این مقاله خارج است، پیدا کردن پاسخ را بر عهده خودتان می‌گذاریم.

معمولا اسم این اندیس را i می‌گذاریم و بعدا در کد اصلی از همین اندیس کمک خواهیم گرفت. به جای lower_limit از یک عدد صحیح مثبت به عنوان کران پایین اندیس i و به جای upper_limit از یک عدد صحیح مثبت به عنوان کران بالای اندیس i استفاده می‌کنیم. statementها هم همان ارجاعات هستند. در ادامه کدهای قسمت هجدهم را با ساختار for بازنویسی خواهیم کرد تا موضوعات بیان شده را به خوبی درک کنید. کد زیر همان شیفت رجیستری است که در قسمت قبل عمل شیفت به راست را انجام می‌داد:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
 
entity Shift_Register is
    Port (
Input : in   STD_LOGIC;
Clock : in   STD_LOGIC;
Output : out unsigned (7 downto 0)
);
 
end Shift_Register;
 
architecture Behavioral of Shift_Register is
 
signal Middle : unsigned (7 downto 0) := (others =>'0');
 
begin
 
Output <= Middle;
 
process(clock)
begin
 
if rising_edge(clock) then
Middle(7) <= Input;
 
for i in 0 to 6 loop
Middle(i) <= Middle(i+1);
end loop;
 
end if;
 
end process;
 
end Behavioral;

کد زیر همان شیفت رجیستری است که در قسمت قبل عمل شیفت به چپ را انجام می‌داد.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
 
entity Shift_Register is
    Port (
Input : in   STD_LOGIC;
Clock : in   STD_LOGIC;
Output : out unsigned (7 downto 0)
);
 
end Shift_Register;
 
architecture Behavioral of Shift_Register is
 
signal Middle : unsigned (7 downto 0) := (others =>'0');
 
begin
 
Output <= Middle;
 
process(clock)
begin
 
if rising_edge(clock) then
Middle(0) <= Input;
 
for i in 0 to 6 loop
Middle(i+1) <= Middle(i);
end loop;
 
end if;
 
end process;
 
end Behavioral;

کدهای بالا را با استفاده از generic می‌توانید بهینه‌تر نیز بنویسید که این موضوع را چون قبلا به آن پرداختیم به عهده خودتان می‌گذاریم. در قسمت بیستم در مورد عملگرها صحبت خواهیم کرد.

درباره نویسنده

نویسنده و طراح الکترونیکا هستم . سوالی داشتید در کامنت ها یا پیج های اینستاگرام و تلگرام سایت بپرسید .