آموزش FPGA : قسمت ششم

آموزش FPGA : قسمت ششم

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

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

در این قسمت ما قصد داریم یک ALU را با استفاده از ساختار ارجاع شرطی زبان VHDL توصیف و سپس آموزش دهیم که چگونه این مدار را شبیه‌سازی کنیم.

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

ALU چیست؟

ALU یک مدار دیجیتال می‌باشد که می‌تواند عملیات جبری و منطقی را روی ورودی‌های n بیتی محاسبه کند و نتیجه را در خروجی برگرداند. در بازار تراشه‌های مختلفی برای انجام این کار وجود دارند، اما ما نمی‌خواهیم از این تراشه‌ها استفاده کنیم، بلکه قصد داریم عملکرد یکی از این تراشه‌ها را با استفاده از کد VHDL توصیف کنیم و در نهایت کد موردنظر را شبیه‌سازی کنیم تا از عملکرد صحیح مدار توصیف شده، مطمئن شویم.

در اینگونه تراشه‌ها معمولا دو ورودی و یک خروجی وجود دارد. و همچنین ورودی دیگری برای اینکه چه عملیاتی روی دو ورودی که در ابتدا بیان کردیم صورت بگیرد نیز وجود دارد.

در زیر، جدولی را مشاهده می‌کنید که بیان می‌کند با توجه به ارزش ورودی 3 بیتی S، چه عملیاتی روی دو ورودی A و B صورت بگیرد.

 

 

ما قصد داریم عملیات جدول بالا را مرحله به مرحله روی دو ورودی 4 بیتی اعمال کرده و سپس نتیجه این عملیات را به یک خروجی 4 بیتی ارجاع دهیم و نتیجه را مشاهده کنیم.

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

ساختار ارجاع شرطی

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

در ادامه کدی خواهیم نوشت که شما با توجه به این کد، می‌توانید با الگوی ساختار ارجاع شرطی آشنا شوید.

ابتدا یک فایل برای توصیف کد ALU ایجاد می‌کنیم، که در زیر می‌توانید این کد را مشاهده کنید.

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
 
entity ALU is
    Port (
A : in   signed (3 downto 0);
B : in   signed (3 downto 0);
S : in   unsigned (2 downto 0);
F : out signed (3 downto 0)
);
end ALU;
 
architecture Behavioral of ALU is
 
signal B_A     : signed (3 downto 0) := (others=>'0');
signal A_B     : signed (3 downto 0) := (others=>'0');
signal AADDB   : signed (3 downto 0) := (others=>'0');
signal AXORB   : signed (3 downto 0) := (others=>'0');
signal AORB    : signed (3 downto 0) := (others=>'0');
signal AANDB   : signed (3 downto 0) := (others=>'0');
 
begin
 
B_A     <= B - A;
A_B     <= A - B;
AADDB <= A + B;
AXORB <= A xor B;
AORB <= A or B;
AANDB <= A and B;
 
F <= "0000" when s="000" else
B_A when s="100" else
A_B when s="010" else
AADDB when s="110" else
AXORB when s="001" else
AORB when s="101" else
AANDB when s="011" else
"1111";
 
 
end Behavioral;

در ابتدا سه پورت A, B, F همه را به صورت چهار بیتی و از نوع علامت‌دار و همچنین پورت S را به صورت سه بیتی و از نوع بدون علامت تعریف می‌کنیم. سوالی که ممکن است برایتان پیش بیایید، این است که چه موقع پورت‌ها را علامت‌دار و چه موقع بدون علامت تعریف می‌کنیم؟ توجه کنید از این به بعد پورت‌ها یا سیگنال‌هایی که قرار است محاسبات ریاضی روی آن‌ها صورت گیرد را از نوع علامت‌دار، و پورت‌ها یا سیگنال‌هایی که قرار نیست محاسبات ریاضی روی آن‌ها صورت گیرد و صرفا از آن‌ها به عنوان شمارنده یا مشخص کردن حالت‌های مختلف کاری، شبیه کاری که ما در این پروژه انجام دادیم استفاده می‌کنیم، را از نوع بدون علامت تعریف می‌کنیم.

قبل از begin مربوط به architecture سیگنال‌های علامت‌داری برای انجام عملیات مختلفی که در جدول بالا مشاهده کردید تعریف می‌کنیم.

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

حال زمان آن رسیده است که از عملکرد کد مربوطه مطمئن شویم، برای این کار باید یک فایل جداگانه برای شبیه‌سازی ایجاد کنیم، که به فایل Test Bench معروف است. برای ساختن این فایل در قسمت Hierarchy راست کلیک کرده و گزینه New Source را انتخاب می‌کنیم. پنجره‌ای که باز خواهد شد برای شما جدید نمی‌باشد، چون قبلا ما در همین پنجره یک فایل VHDL Module ایجاد کردیم. اما اکنون قصد داریم با نوعی فایل جدید به اسم VHDL Test Bench آشنا شویم که از این فایل برای شبیه‌سازی استفاده می‌کنیم.

 

شبیه تصویر بالا حواستان باشد گزینه‌ی VHDL Test Bench را انتخاب کرده باشید، چون در غیر این‌صورت ممکن است فایلی با نوعی دیگر برایتان ایجاد گردد.

پس از طی مراحل بالا، فایل Test Bench برای شما ساخته خواهد شد، اما شما این فایل را مشاهده نمی‌کنید!

برای رفع این مشکل همانند تصویر بالا، در بالای قسمت Hierarchy، گزینه View را روی حالت Simulation قرار دهید. سپس با دو بار کلیک کردن روی فایل ALU_tb، این فایل برایتان باز خواهد شد.

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

شما اگر قصد دارید این پروژه را خودتان انجام دهید و مرحله به مرحله پیش بروید فایل Test Bench مورد نظر را مانند کدی که در زیر خواهیم آورد ویرایش کنید.

قاعدتا برای اینکه شبیه‌سازی انجام شود، بایستی یک سری ورودی به مدار اعمال شود. برای این کار مانند کد زیر در قسمت insert stimulus here مقادیری را به پورت‌های ورودی اعمال خواهیم کرد.

LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;
 
ENTITY ALU_tb IS
END ALU_tb;
 
ARCHITECTURE behavior OF ALU_tb IS
 
    -- Component Declaration for the Unit Under Test (UUT)
 
    COMPONENT ALU
    PORT(
         A : IN   signed (3 downto 0);
         B : IN   signed (3 downto 0);
         S : IN   unsigned (2 downto 0);
         F : OUT   signed (3 downto 0)
        );
    END COMPONENT;
    
 
   --Inputs
   signal A : signed (3 downto 0) := (others => '0');
   signal B : signed (3 downto 0) := (others => '0');
   signal S : unsigned (2 downto 0) := (others => '0');
 
--Outputs
   signal F : signed (3 downto 0);
   -- No clocks detected in port list. Replace <clock> below with
   -- appropriate port name
 
 
BEGIN
 
-- Instantiate the Unit Under Test (UUT)
   uut: ALU PORT MAP (
          A => A,
          B => B,
          S => S,
          F => F
        );
 
   -- Clock process definitions
 
 
 
   -- Stimulus process
   stim_proc: process
   begin
      -- hold reset state for 100 ns.
      wait for 100 ns;
 
 
 
      -- insert stimulus here
 
A <= "0011";
B <= "0100";
S <= "110";
 
 
      wait;
   end process;
 
END;

اگر به کد بالا دقت کنید ما مقدار”0011″ به منزله‌ی 3 دهدهی را به ورودی A و مقدار “0100” به منزله‌ی 4 دهدهی را به ورودی B، و همچنین مقدار “110” را به ورودی S اعمال کردیم که با این مقدار، طبق جدول بالا، باید حالت A Plus B فعال شود و ارزش عددی A و B با همدیگر جمع شده و در خروجی F نمایش داده شود. پس ما باید در شبیه‌سازی مقدار “0111” یا همان 7 دهدهی را در خروجی مشاهده کنیم.

حال برای مشاهده‌ی نتایج شبیه‌سازی باید ابتدا فایل ALU_tb را انتخاب کرده و سپس مانند تصویر زیر، در قسمت Processes، با دو بار کلیک کردن روی گزینه Simulate Behavioral Model محیط شبیه‌سازی یا همان نرم‌افزار ISim باز خواهد شد.

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

خب همانطور که در تصویر بالا مشاهده می‌کنید مقدار خروجی “0111” می‌باشد، و برابر با مقدار مورد انتظار است. شاید شما بخواهید این اعداد را به صورت دهدهی نیز مشاهده نمائید، بدین منظور همه‌ی ورودی-خروجی‌ها را انتخاب کرده و سپس با راست کلیک کردن بر روی آن‌ها از گزینه Radix حالت Signed Decimal را انتخاب نمائید.

 

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

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

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

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