دستورکار آزمایشگاه طراحی خودکار سیستمهای دیجیتال
نسخه 1.0
|
شماره نسخه |
تاریخ |
شرح تغییرات |
|
0.0 |
14/01/1393 |
نسخه اولیه |
|
1.0 |
01/11/1393 |
انجام اصلاحات نگارشی و تکمیل بخش دستورکار هر یک از آزمایشها |
|
|
|
|
|
|
|
|
|
|
|
|
پیشگفتار
هدف از آزمایشگاه طراحی خودکار، آَشنایی عملی دانشجویان با زبانهای توصیف سخت افزار و استفاده از این زبانها برای پیادهسازی سیستمهای دیجیتال روی FPGA میباشد. در این آزمایشگاه مراحل پیادهسازی یک مدار دیجیتال روی FPGA و نکات عملی آموزش داده میشود و دانشجو با ابزارهای مورد نیاز برای شبیهسازی، سنتز، پیادهسازی و دیباگ کردن این مدارها آشنا میشود. دستورکار این آزمایشگاه در قالب 9 آزمایش تهیه شده است.
در انتها از تمام همکاران و دانشجویان درخواست میکنم با طرح پیشنهادات مشخص و مدون خود برای رفع معایب، ارتقای کیفی و پویایی به عنوان یک ویژگی ضروریِ آزمایشگاه طراحی خودکار، ادامه دهندة راهی باشند که اولین گام آن برداشته شده است. لازم میدانم که از سرپرست محترم دانشکده مهندسی کامپیوتر جناب آقای دکتر شهرام اعتمادی و همچنین کارشناس محترم آزمایشگاه جناب آقای مهندس محمد علی آزادی که در تجهیز نمودن و به روز رسانی این آزمایشگاه از هیچگونه همکاری دریغ نفرمودند کمال تشکر را داشته باشم.
دکتر علی بهلولی
بهار 1393
فهرست مطالب
آزمایش اول: آشنایی با نرم افزار ISE و مراحل پیادهسازی کد VHDL روی FPGA
1-1-1 مراحل پیادهسازی کد VHDL روی FPGA
1-1-2 پیادهسازی یک مدار چشمک زن
آزمایش دوم: راه اندازی دکمههای فشاری و دیودهای نورانی روی بورد FPGA
آزمایش سوم: آشنایی با مباحث تاخیر و فرکانس کلاک در FPGA
3-1-1 محاسبه تاخیر در مدارهای ترتیبی
3-1-2 محاسبه تاخیر در مدارهای ترکیبی
آزمایش چهارم: آشنایی با نرم افزار CoreGenerator و نحوه بکارگیری Coreها
4-1-3استفاده از COREها در نرم افزار ISE
آزمایش پنجم: آشنایی با Block RAMها و زمانبندی خواندن و نوشتن در آنها
5-1-1 استفاده از Block Ramها در نرم افزار ISE
آزمایش ششم: آشنایی با FIFOها و نحوه استفاده از آنها
6-1-2 مراحل ساختن FIFO در نرم افزار ISE
آزمایش هفتم: آشنایی با ردههای مختلف شبیهسازی: فانکشنال و Post Route Simulation
7-1-1 انجام شبیهسازی در ردههای مختلف برای یک جمع کننده
آزمایش هشتم: آشنایی با نرم افزار ChipScope
8-1-1استفاده از نرمافزار ChipScope
آزمایش نهم: آشنایی با پردازندههای امبد شده در FPGA ((MicroBlaze
9-1-1 FPGA در محیطهای Embedded
9-1-2 آشنایی با نرم افزارهای EDK
9-1-3 قدمهای ایجاد یک سیستم Embedded در FPGA
9-1-6 برنامه نویسی در محیط SDK
1-1پیش آگاهی
هدف از این آزمایش، آشنایی با نرم افزار ISE میباشد. نرم افزار ISE از شرکت Xilinx است که برای شبیهسازی، سنتز و پیادهسازی[1] برنامههای نوشته شده به زبانهای توصیف سخت افزار قابل استفاده است. اصولا هر شرکت تولید کننده FPGA باید نرم افزاری جهت پیادهسازی کدهای توصیف سخت افزار داشته باشد.
1-1-1 مراحل پیادهسازی کد VHDL روی FPGA
برای پیادهسازی یک مدار روی FPGA مراحل زیر مورد نیاز است:
الف) طراحی مدار
ب) توصیف مدار با زبانهای توصیف سخت افزار
ج) شبیهسازی
د)سنتز
ه)پیادهسازی
در مرحله طراحی، با توجه به صورت مساله و ورودی/خروجیهای سیستم، روشی برای تولید خروجیها بر اساس ورودیها ارائه میشود(روشهای مختلف طراحی در درس طراحی خودکار سیستمهای دیجیتال ارائه میشود) سپس با به طراحی انجام شده، برنامه VHDL نوشته میشود و در مرحله سنتز، برنامه نوشته شده به زبان VHDL به المانهای دیجیتال نظیر فلیپ فلاپ، حافظه، دیکدر، مالتی پلکسر و ... تبدیل میشود و نهایتا در مرحله پیادهسازی، کدهای سنتز شده با المانهای موجود در FPGA جایگزین و فایل نهایی برای پراگرام کردن FPGA آماده میشود.
برای سنتز و پیادهسازی برنامه VHDL، نرم افزارهای مختلفی وجود دارد. با توجه به اینکه در طراحی بوردهای آزمایشگاه، از FPGAهای شرکت Xilinx استفاده شده است بنابراین از نرم افزار تولید شده شرکت زایلینکس برای سنتز و پیادهسازی کدهای VHDL نوشته شده استفاده میکنیم. در شکل 1-1، شکل ظاهر این نرم افزار نمایش داده شده است. در این شکل، قسمتهای مختلف این نرم افزار مشخص شدهاند. هنگام ایجاد یک پروژه جدید در این نرم افزار، باید نام خانواده FPGA، نام قطعه، نوع بسته بندی انتخاب گردد. مثلا FPGAهای استفاده شده در بوردهای آزمایشگاه از خانواده Spartan6 هستند و نام قطعه 6SLX9 ونوع بسته بندی تراشه TQG144 میباشد(تراشه از نوع چهارطرفه و دارای 208 پایه). بعد از اینکه در این نرم افزار پروژه خود را ایجاد کردید نام تراشه به صورت اختصار در قسمت فوقانی پنجره مینویسد. تراشه ای که در شکل 1-1 استفاده شده است xc6slx9-3tqg144 میباشد که حاوی تمام اطلاعات تراشه مورد نظر میباشد.

شکل 1-1: قسمتهای مختلف نرم افزار ISE
بعد از ایجاد پروژه و اضافه کردن فایلها به آن، با دابل کلیک کردن روی گزینه Synthesize، عملیات سنتز شروع میگردد. گزارش مربوط به سنتز کردن را در پنجره console (قسمت پایینی پنجره) نمایش میدهد. در صورت موفقیت آمیز بودن عملیات سنتز، میتوان گام بعدی که پیادهسازی طرح باشد را شروع کرد. برای شروع عملیات پیادهسازی باید روی گزینه Implement Design دابل کلیک کنید. همانطور که در شکل 1-1 مشاهده میشود عملیات پیادهسازی از سه گام به نامهای Translate، Map و Place & Route تشکیل شده است. برای ایجاد فایل نهایی باید روی گزینه Generate Programming… دابل کلیک کنید.
برای پراگرام کردن FPGA میتوان مستقیما روی گزینه Configure Target Device دابل کلیک کرد یا اینکه از نرم افزار Impact استفاده کرد. این نرم افزار جزء مجموعه ISE است و به صورت اتوماتیک هنگام نصب نرم افزار ISE، نصب میگردد.
1-1-2 پیادهسازی یک مدار چشمک زن
اصولا در سیستمهای دیجتال برای اینکه نشان داده شود سیستم زنده و در حال کار میباشد، یک LED روی بورد مربوطه تعبیه میشود و با روشن شدن سیستم، این LED با روشن و خاموش شدن متوالیش، زنده بودن سیستم را نشان میدهد. در این قسمت قصد داریم به عنوان اولین آزمایشی که با بوردهای آزمایشگاه انجام میدهیم یک مدار چشمک زن را پیادهسازی کنیم.
برنامه VHDL مورد نیاز برای یک LED چشمک زن به صورت زیر است
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.std_logic_unsigned.all;
entity BlinkingLED is
Port (
Clk : in STD_LOGIC;
Led : out STD_LOGIC
);
end BlinkingLED;
architecture Behavioral of BlinkingLED is
signal delay_counter: std_logic_vector(31 downto 0);
begin
Led <= delay_counter(24);
process(Clk)
begin
if(Clk='1' and Clk'event)then
delay_counter<=delay_counter+1;
end if;
end process;
end Behavioral;
1-2پیش گزارش
1- نرم افزار ISE را طبق صحبتهای انجام شده در آزمایشگاه، نصب کنید. سپس با انتخاب گزینه New Project … از منوی File، یک پروژه جدید به نام BlinkingLED ایجاد کنید( تنظیمات مورد نیاز در شکل 1-2 نشان داده شده است)
2- یک فایل جدید ایجاد کنید و برنامه نوشته شده در قسمت پیش گزارش را در آن کپی کنید. برای ایجاد یک فایل جدید باید روی اسم تراشه(در پنجره سمت چپ)، کلیک راست نموده و گزینه New Source… را انتخاب کنید سپس در پنجره ظاهر شده، گزینه VHDL Module را انتخاب کنید و نام فایل را نیز در قسمت مربوطه بنویسید.(مراحل انجام آن در شکلهای 1-3 و 1-4 نشان داده شده است)
3- برنامه را سنتز کنید و مشاهدات خود از خروجی سنتز (پنجره کنسول که در شکل 1-1 نشان داده شده است) را بنویسید.(تعداد فلیپ فلاپها، بلوکهای تشخیص داده شده در کد VHDL و Warningها) (جواب این سوال را روی کاغذ بنویسید و به صورت حضوری در آزمایشگاه تحویل دهید)
.
شکل 1-2: تنظیمات مربوط به تراشه مورد استفاده در بوردهای آزمایشگاه

شکل 1-3: نحوه ایجاد یک فایل جدید

شکل 1-4: انتخاب فایل VHDL و نامگذاری آن
1-3 دستورکار
1- در نرم افزار ISE یک پروژه جدید به نام BlinkingLED ایجاد کنید تراشه را XC6LXو پکیج آن را TQG144 انتخاب کنید.
2- برنامه VHDLی بنویسید که فرکانس کلاک ورودی را که 50مگاهرتز است را به 1 هرتز تبدیل کند.
3- برنامه را سنتز کنید و مشاهدات خود از خروجی سنتز (پنجره کنسول که در شکل 1-1 نشان داده شده است) را بنویسید.(تعداد فلیپ فلاپها، بلوکهای تشخیص داده شده در کد VHDL و Warningها)
4- برای برنامه فوق یک فایل UCF بنویسید به نحوی که پایه کلاک را به اسیلاتور روی بورد متصل و سیگنال 1 هرتز را به LED روی بورد متصل کند.
5- بیت فایل را ایجاد کنید و با کمک نرم افزار impact آن را روی بورد پراگرام کنید و نتیجه را به مسئول آزمایشگاه نشان دهید.
2-1پیش آگاهی
هدف از این آزمایش، کار با دکمههای فشاری روی بورد آموزشی میباشد. بعد از اینکه برنامه VHDL نوشته شد و شبیهسازی آن به اتمام رسید، برای پیادهسازی نهایی آن روی سخت افزار، باید فایلی را آماده کرد که پورتهای Entity نوشته شده را به پایههای تراشه FPGA مپ کند. به این فایل اصطلاحا ucf (User Constraint File) گفته میشود. فرمت این فایل به صورت زیر است:
NET "CLK25M" LOC = "AA14" | IOSTANDARD = LVTTL ;
سطر فوق به این مفهوم است که سیگنال CLK25M که در برنامه VHDL استفاده شده است (یکی از پورتهای Entity است) به پایهای به نام AA14(نام پایهها را باید از کاتالوگ تراشه FPGA استخراج کنید) متصل شود و استاندارد ولتاژ آن پایه نیز LVTTL است.
2-2دستور کار
1- با استفاده از شماتیک بورد آزمایشگاه، به سوالات زیر پاسخ دهید:
الف) چند عدد دکمه فشاری روی بورد وجود دارند؟ نام آنها را یادداشت کنید؟
ب)کدام یک از دکمههای فشاری مستقیما به پایههای FPGA متصل هستند؟ شمارههای پایه FPGA را نیز مشخص کنید.
2- به برنامه جلسه گذشته یک پورت جدید به نام Enable اضافه کنید. عملکرد این پایه به این صورت است که اگر مقدار آن "1" باشد آنگاه، LED چشمک زن باشد و اگر مقدار آن "0" بود آنگاه LED خاموش شود.
3- برای برنامه فوق، یک فایل ucf ایجاد کنید و با توجه به شماتیک بورد، پایههای مناسب را به پورتهای Entity خود اضافه کنید.
4- بیت فایل را ایجاد کنید و با کمک نرم افزار impact آن را روی بورد پراگرام کنید و نتیجه را به مسئول آزمایشگاه نشان دهید
5-
برنامهای به زبان VHDL بنویسید که یک عدد BCD دریافت کند و معادل 7seg آن را تولید کند.
6- با استفاده از دستور for generate، یک جمع کننده 512 بیتی را با استفاده از Full Adder پیادهسازی کنید.
3-1پیش آگاهی
هدف از این آزمایش، آشنایی با مباحث تاخیر و فرکانس کلاک در FPGA میباشد. در این آزمایش به عنوان نمونه، نحوه محاسبه تاخیر یک جمع کننده 32 بیتی آزمایش میگردد.
یکی از سوالهای مهم در هنگام پیادهسازی یک مدار دیجیتال با استفاده از FPGA، این است که مدار پیادهسازی شده حداکثر با چه فرکانسی کار خواهد کرد. یا اگر مدار به صورت ترکیبی باشد آنگاه تاخیر این مدار ترکیبی چقدر خواهد بود.
3-1-1 محاسبه تاخیر در مدارهای ترتیبی
برای محاسبه تاخیر و حداکثر فرکانس کلاک در مدارهای ترتیبی کافی است در فایل ucf، یک محدودیت برای سیگنال کلاک تعریف شود. اگر فرض کنیم CLK نام سیگنال کلاک باشد آنگاه با اضافه کردن دو دستور زیر در فایل ucf، به نرم افزار اعلام میکنیم که قصد داریم به پریود کلاک برابر 3 نانوثانیه برسیم.
NET "CLK" TNM_NET = "SYS_CLK";
TIMESPEC "TS_SYS_CLK" = PERIOD "SYS_CLK" 3 ns HIGH 50 %;
نرم افزار ISE سعی میکند در مراحل map و place and route، زمان ذکر شده در فایل ucf را برآورده کند. در نهایت تاخیرها و فرکانس کلاک دست یافتنی را در گزارش place and route ارائه میدهد. این گزارش در فایلی با پسوند par ذخیره میشود.
(گزارش مربوط به مرحله سنتز در فایلی با پسوند syr و گزارش مربوط به مرحله MAP در فایلی با پسوند map ذخیره میشود)
برای دیدن پارامترهای زمانی طرح ایمپلیمنت شده میتوان از طریق دابل کلیک روی & Route Static Timing Analyze Post-Place از زیر مجموعه Place & Route اقدام کرد. در شکل 3-1، محل این گزینه نمایش داده شده است.

شکل 3-1: نحوه بررسی نتایج زمانی مربوط به ایمپلیمنت طرح
3-1-2 محاسبه تاخیر در مدارهای ترکیبی
برای محاسبه تاخیر در مدارهای ترکیبی، میتوان ورودیها و خروجیهای طرح را رجیستر و مدار را به یک مدار ترتیبی تبدیل کرد. سپس مدار ترتیبی بدست آمده را مشابه روش ذکر شده در بخش 3-1-1 تحلیل زمانی کرد.
به عنوان مثال فرض کنید یک بلوک جمع کننده به صورت نمایش داده شده در شکل 3-1 را در اختیار داریم.
|
|
|
|
شکل 3-1: یک جمع کننده که به صورت ترکیبی پیادهسازی شده است. |
شکل 3-3: اضافه کردن رجیستر به ورودیها و خروجیهای جمع کننده |
برای بدست آوردن تاخیر این جمع کننده باید یک فایل جدید ایجاد شود و مدار نمایش داده شده در شکل 3-3 در آن پیادهسازی گردد. همانطور که در شکل ملاحظه میگردد، با اضافه کردن سه رجیستر به نامهای a_r، b_r و c_r مدار نمایش داده شده در شکل 3-1 به یک مدار ترتیبی تبدیل شده است. در شکل 3-4، برنامه مربوط به مدار شکل 3-3 نمایش داده شده است.

شکل 3-4: برنامه VHDL مربوط به مدار نمایش داده شده در شکل 3-3
بعد از اتمام مرحله Place & Route، دوره تناوب بدست آمده برای کلاک را میتوان در فایل با پسوند par مشاهده نمود. همانطور که در شکل 3-5 نشان داده شده است، دوره تناوب کلاک میتواند حداقل 2.539ns باشد. این نکته به این مفهوم است که تاخیر جمع کننده برابر با 2.539ns است.

شکل 3-5: قسمتی از نتیجه Place & Route که حاوی اطلاعاتی در مورد Constraint قرار داده شده برای کلاک میباشد.
3-2دستور کار
7- تاخیر یک جمع کننده 32 بیتی را برای تراشههای مختلف XC6SLX4 و XC6SLX9 را بدست آورید
8- با تغییر تعداد بیتهای جمع کننده رابطه بین تعداد بیتها و میزان تاخیر را در تراشه XC6SLX9 را بدست آورید.
9- تاخیر دو مدار زیر را برای محاسبه جمع چهار عدد 32 بیتی بدست آورید


4-1پیش آگاهی
هدف از این آزمایش، آشنایی با Coreهای سخت افزاری و نحوه تولید آنها توسط نرم افزار ISE میباشد.
COREها، برنامههای آماده و سنتز شده ای هستند که میتوان از آنها در برنامههای VHDL استفاده نمود. نکته ی اصلی اینجاست که امکان دسترسی به source code این برنامهها وجود ندارد و تنها میتوان از آنها در برنامههای گوناگون استفاده نمود.
4-1-1دسته بندی COREها
COREها به دو دسته تقسیم میشوند:
یک دسته از COREها، از قبل و به صورت انحصاری توسط شرکتهای سازنده ی FPGA با توجه به ساختار داخلی آن، طراحی و عرضه میشود. مثلا برای استفاده از حافظه ی داخلی یا میکروکنترلر تعبیه شده در FPGA میتوان از COREهای مخصوص آن استفاده کرد. در اینجا کد VHDL واقعی وجود ندارد و در واقع Core به عنوان یک wrapper برای آن بلوک سخت افزاری میباشد.
دسته ی دوم، برنامههای عمومیای هستند که به زبان توصیف سخت افزار نوشته و سنتز شدهاند و فایل سنتز شده ی آن عرضه میشود. مثلا برای ارتباط وسایل جانبی با FPGA میتوان از این دسته COREها استفاده نمود. در اینجا کد VHDL، واقعا وجود دارد ولی در دسترس نمیباشد. ( ممکن است شرکتهای سازنده ی FPGA، این دسته از COREها را هم تولید نمایند.)
4-1-2 استفاده از COREها
حداقل به دو فایل برای استفاده از COREها در برنامه ی VHDL نیاز است: فایل سنتز شده و Component مورد استفاده (یعنی اطلاع از نام پورتها و مشخصات آنها)
4-1-3استفاده از COREها در نرم افزار ISE
استفاده از COREها در نرم افزار ISE را با یک مثال پی میگیریم:
ابتدا یک پروژه ی جدید با نام Multiply ایجاد میکنیم:

حالا در پروژه، روی گزینه ی New Source... کلیک میکنیم:

حال در صفحه ی باز شده، گزینه ی IP (CORE Generator & Architecture Wizard) را انتخاب میکنیم:
![]()

و Next را میزنیم؛ حال پنجره ی New Source Wizard باز میشود:

در اینجا فهرست کاملی از COREهای تعبیه شده در نرم افزار وجود دارد که میتوان برای برنامههای گوناگون از آن استفاده نمود. در قسمت Search IP Catalog هم میتوان CORE مورد نظر را جستجو کرد.
در اینجا ما برای پیادهسازی یک ضرب کننده ی 8بیتی، از شاخه ی Math Functions، گزینه ی Multiplier را انتخاب میکنیم.
![]()

Next را میزنیم. حالا پنجره ی دیگری باز میشود که در آن میتوان خصوصیات CORE انتخابی را مشاهده و مدیریت نمود:

با انتخاب دکمه Datasheet میتوان به اطلاعات اصلی CORE دسترسی یافت. در این مثال خاص میتوان مثلا اندازه ی هر یک از عناصر ضرب شونده (PORTA و PORTB) را تعیین نمود که در اینجا ما هر دو را 8بیتی در نظر میگیریم و اعداد را علامتدار انتخاب میکنیم. و Next را میزنیم.

در این صفحه جدید میتوان خصوصیات دیگری را تنظیم نمود. مثلا در قمست Multiplier Construction میتوان تعیین کرد که پیادهسازی ضرب کننده چگونه باشد. ما در اینجا Use Mults را انتخاب میکنیم. در این حالت پیادهسازی ضرب کننده به وسیله ی ضرب کنندههای داخلی FPGA انجام میپذیرد. در این پنجره، همچنین گزینههایی راجع به بهینه سازی وجود دارد. دکمه ی Next را میزنیم.

در پنجره آخر هم اطلاعاتی وجود دارد. مثلا میتوان اندازه ی خروجی ضرب کننده را تعیین نمود که در اینجا با توجه به اندازه ی عناصر ورودی (8 بیتی)، اندازه ی خروجی به طور پیش فرض 16 بیت در نظر گرفته شده که البته میتوان آن را تغییر داد.
نهایتا دکمه ی Generate را میزنیم. همه ی فایلهای مورد نیاز در پوشه ای به نام ipcore_dir قرار دارد. از مهمترین فایلهایی که در این پوشه ساخته میشود عبارتند از فایلی با پسوند vho و دیگری با پسوند veo. این دو فایل به ترتیب حاوی تعریف component و نحوه Port Map کردن Core ایجاد شده به زبانهای VHDL و Verilog میباشد.

![]()

همچنین در پنجره ی پایینی، گزینه ی CORE Generator ایجاد میشود که قسمتهای مختلفی را برای مدیریت و استفاده از CORE به دست میدهند. هم اکنون فایل سنتز شده ی موردنیاز نیز به طور خودکار ایجاد شده است. همان طور که گفته شد غیر از فایل سنتز شده به مشخصات پورتهای CORE نیز نیازمندیم. این اطلاعات در قسمت View HDL Instantiation Template وجود دارد. با دوبار کلیک کردن روی این گزینه، یک فایل متنی باز میشود که حاوی اطلاعات پورتها برای افزودن Component و سپس Port Map کردن است:

حالا میتوان یک برنامه به زبان VHDL به صورت top module نوشت و از CORE به عنوان یک Component استفاده کرد. به همین منظور یک فایل VHDL به نام top میسازیم و کد آن را به این صورت دستکاری میکنیم:

حالا میتوان با استفاده از یک برنامه Test Bench، برنامه ی بالا را شبیهسازی نمود. اگر در برنامه TestBench دستورات زیر را قرار دهیم:

آنگاه نتیجه شبیهسازی به صورت زیر خواهد شد:

همان طور که در نتیجه شبیهسازی مشاهده میشود تاخیر ضرب کننده 5 نانوثانیه بوده و ضرب دو عدد 3 و 4 و همچنین ضرب اعداد 12- و 83 (در مبنای 10) را به درستی انجام داده است.
4-2دستور کار
10-با استفاده از Core ضرب کننده و جمع کننده در نرم افزار ISE، مدار زیر را طراحی و شبیهسازی کنید.

11-با اضافه کردن Constraint برای کلاک، و اضافه کردن رجیستر در ورودی و خروجیهای مدار فوق، حداکثر فرکانس کلاک برای مدار فوق را بدست آورید.
12-فایل ucf برای طرح بالا ایجاد کنید و سپس اعداد را از طریق DIP switchهای روی بورد به سیستم اعمال کنید و نتیجه را روی 16 LED مشاهده کنید و نتیجه را به مسئول آزمایشگاه نشان دهید.
5-1 پیش آگاهی
هدف از این آزمایش، آشنایی با Block Ramها و نحوه تولید آنها توسط نرم افزار ISE میباشد و زمانبندی خواندن و نوشتن در آن و شبیهسازی آن میباشد. Block Ramها قطعات سخت افزاری هستند کهRam را پیادهسازی میکنند و در اکثر طرحهای سخت افزاری به کار میروند که معمولا در اندازههای 2کیلو بایتی(18کیلو بیت) میباشند.
Block Ram یکی از اجزای اصلی FPGA است. در مشخصات FPGAها دو نوع Ram وجود دارد: Distributed Ram و Block Ram.
Distributed Ram حافظه ی RAMاست که از کنار هم قرار دادن LUTهای FPGA ایجاد میشود. در مواردی که بخواهیم از حافظههای کوچک استفاده کنیم به کار میرود.
5-1-1 استفاده از Block Ramها در نرم افزار ISE
ابتدا یک پروژه جدید با نام blkram_exe1 ایجاد میکنیم.

برای ایجاد یک block ram، باید یک core جدید ایجاد کنیم. همانند آزمایش 4 مراحل زیر را تکرار میکنیم.
بر روی پروژه کلیک راست کرده و گزینه new source را انتخاب میکنیم.
در پنجره باز شده IP(CORE Generator & Architecture Wizard) را انتخاب میکنیم و نام core را در قسمت file name
مینویسیم. در اینجا حافظه مورد نظر ما یک حافظه 1k*8bit است. بنابراین نام حافظه را blkram1kx8bits قرار میدهیم.

در قسمت New Source Wizard، با جستجوی عبارت memory، Block Memory Generator را انتخاب میکنیم.

بلاک دیاگرام Ram در سمت چپ تصویر نشان داده شده که پایههای فعال و غیرفعال آن در شکل مشخص شده است. در این حافظه پورت خواندن و نوشتن از یکدیگر مجزا هستند و به همین دلیل به سیگنال کنترلی read نیازی ندارد. خواندن همیشه فعال است. آدرس را که قرار دهیم، Data پس از یک CLK برابر محتویات آن خانه از حافظه میشود. به این صورت که Data همیشه یک CLK شیفت دارد. اگر در یک CLK داده را قرار دهیم، در CLK بعدی میتوانیم داده را استفاده کنیم.
در اینجا ما دو نوع Interfaceداریم: AXI وNative. اگر AXI را انتخاب کنیم، Interface مستقیما بهAXI Busمتصل میشود که ما در اینجا از آن استفاده نمیکنیم و Native را انتخاب میکنیم.

Memory Type:
با انتخاب هر یک از انواع حافظه زیر، پورتهای بلاک دیاگرام سمت چپ تغییر میکند. Single Port Ram: فقط یک Busآدرس دارد. همزمان نمیتوان به خانههای مختلف حافظه دسترسی داشت ولی میتوانیم در یک خانه از حافظه بنویسیم و بخوانیم.
True Dual port: یک حافظه با دو پورت کاملا مجزا است. ( پورت A و B)
Simple dual port: پورت A امکان خواندن و نوشتن را دارد ولی پورت B فقط امکان خواندن دارد.
Single port Rom: یک مقدار اولیه به آن داده میشود و همه از همان مقدار اولیه استفاده میکنند و دیگرنمیتوان در آن نوشت.
Dual port Rom: دو پورت آدرس دارد و امکان نوشتن ندارد.
در این مرحله Single Port Ram را انتخاب میکنیم.
ECC(Error Correction Code):
چون در حافظهها امکان خطا وجود دارد، به ازای هر 8 بیت، یک بیت اضافه میکند و parity را در آن ذخیره میکند. گفتیم حافظهها معمولا 2کیلوبایتی هستند که برابر 16 کیلو بیت است که با درنظرگرفتن دو بیت برای parity، 18کیلوبیت خواهیم داشت.
Byte Write Enable:
برای حافظههایی که بیشتر از 8 بیت عرض دارند، مشخص میکند که در یک سطر کدام بایتها نوشته شوند.
در قسمت Algorithm نیز با توجه به هدف پروژه، یکی از سه مورد آن را انتخاب میکنیم.

در اینجا میخواهیم یک حافظه 1k x 8bit را پیادهسازی کنیم. بنابراین عرض داده را 8 بیتی و تعداد کلمات را 1024=
(10 خط آدرس)قرار میدهیم.
Operating Mode اولویتهای ReadوWrite را مشخص میکند. ما در اینجا write first را انتخاب میکنیم.
در قسمت Enable نیز always enable را انتخاب میکنیم.

در مرحله بعد، قسمتOptional output Register مشخص میکند خروجی که از حافظه میگیریم یک طبقه رجیستر شود یا خیر.
معایب رجیستر کردن: تعدادی فلیپ فلاپ مصرف میشود و یک فاز تاخیر بیشتر داریم.
حسن رجیستر کردن:
(Pipelining) باعث میشود که تاخیر خارج شدن داده از حافظه، از تاخیرهای بعدی جداشود.
Memory Initialization: میتوان به حافظه مقدار اولیه داد. اگر تیک Load init file را فعال کنیم، میتوانیم محتویات خانههای حافظه را از یک فایل متنی با پسوند.COE بگیریم. در قسمت fill remaining memory locations نیز میتوان بقیه خانههای حافظه که در فایل متنی مقدار دهی نشدهاند را مقداردهی کرد. تیکها را فعال نمیکنیم تا مقدار اولیه به صورت پیش فرض، صفر درنظر گرفته شود.

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

مرحله بعد گزینههایی برای شبیهسازی دارد. در هنگام ایجاد هر core یک functional model نیز برای آن ایجاد میشود. در اینجا میتوان مشخص کرد که functional model روی چه چیزهایی warning دهد. وقتی All فعال باشد زمان شبیهسازی بیشتر میشود ولی برای طرحهای کوچک این زمان بسیار ناچیز است.


قسمت Information نیز گزارشی از ram که قرار است ایجاد شود را به ما میدهد. همان طور که در شکل مشاهده میشود ما دو نوع block ram داریم: 9k و 18k. Read Latency مدت زمان ظاهرشدن داده، بعد از قراردادن آدرس آن را مشخص میکند که در اینجا در یک سیکل این کار انجام میشود. Address Width نیز نشان دهنده این است که خطوط آدرس 10 بیتی هستند.
حال core را Generate میکنیم.
اکنون باید یک فایل top_blkram بسازیم و blkram را در آن port map کنیم.
New -> new source -> VHDL Module
پورتهای ورودی و خروجی را مانند شکل زیر مینویسیم و next میزنیم.

حال باید blkram را در فایل top، port map کنیم. قسمتهای مشخص شده در شکل زیر را به فایل top اضافه میکنیم. به این صورت که بر روی blkram کلیک کرده، فایل view HDL Instantiation tempرا انتخاب کرده و محتویات آن را copy میکنیم.
در این مرحله پورتها نیز اصلاح میشوند. باید به تفاوت نوع پایههای write(wr) و write enable(wea) توجه داشته باشیم. wr از نوع STD_LOGIC و wea از نوعSTD_LOGIC_VECTOR است. در نتیجه یک سیگنال برداری را تعریف میکنیم.(سیگنال wr_sig) برای مقدار دهی حتما باید index سیگنال گذاشته شود. فایل را save میکنیم.
![]()



شبیهسازی حافظه:
حال باید یک فایل testbench بسازیم و نام آن را TB_top_blkram انتخاب میکنیم.
خط زیر را به فایل TB اضافه میکنیم تا آدرس را برابر با صفر قرار دهیم.
![]()

فایل را ذخیره کرده و simulation را انجام میدهیم. نتیجه شبیهسازی در شکل صفحه بعد مشخص است:

در مرحله بعد میتوانیم مقادیر را خودمان وارد کنیم. مثلا بخواهیم در یک خانه حافظه بنویسیم و محتویات آن خانه از حافظه را بخوانیم پس باید پایههای حافظه را مقداردهی کنیم. در اینجا میخواهیم در خانه صفر حافظه عدد AA را write کنیم. پایه write را 1 میکنیم و بعد از 10ns دوباره آن را صفر میکنیم.
![]()

اگر در کد تغییراتی دادیم و خواستیم در شبیهسازی هم اعمال شود Re_launchرا میزنیم. در این حالت شبیهساز را مجددا run کرده ایم.
نتیجه شبیهسازی:
![]()

در مثالی دیگر بعد از اینکه wr را صفر کردیم، آدرس را عوض میکنیم. به اندازه 100ns، wait انجام میدهیم و سپس مجددا آدرس را به خانه صفر برمیگردانیم.


دوباره re_launch میکنیم:

ابتدا عمل write انجام میشود.سپس از خانه صفر حافظه عمل خواندن صورت میگیرد و 100ns بعد از خانه یک حافظه عمل خواندن انجام میشود. داده در لبه بالارونده روی باس قرار میگیرد. نتایج شبیهسازی در شکل بالا مشخص است.
5-2دستور کار
13-یک حافظه BlockRAM با اندازه 512x8 ایجاد کنید. سپس یک برنامه VHDL با نام mem1024x16 ایجاد کنید و با Port Map کردن چهار عدد از حافظه بلاک رم ایجاد شده، یک حافظه 1024x16 ایجاد کنید و آن را شبیهسازی کنید(در شبیهسازی در 2 آدرس حافظه بنویسید و سپس از همان 2 آدرس بخوانید، آدرسها را به گونه ای انتخاب کنید که در هر یک از چهار حافظه عملیات خواندن و نوشتن انجام شده باشد)
14-با استفاده از دیتاشیت بلاک رم، فرمت فایلهای coe را مطالعه کنید سپس یک فایل coe ایجاد کنید و برای یک حافظه با مشخصه 8x40 یک فایل coe ایجاد کنید(محتویات آدرس صفر حافظه را شماره دانشجویی خود قرار دهید و برای آدرسهای بعدی به ترتیب یک واحد به شماره دانشجویی خود اضافه کنید) سپس یک حافظه BlockRAM با اندازه 8x40 ایجاد کنید و آن را با فایل coe ایجاد شده، مقداردهی اولیه کنید. سپس یک TestBench بنویسید که با خواندن محتویات حافظه، از صحت مقادیر اولیه اطمینان حاصل کنید.
15-با استفاده از نرم افزار ISE و ایجاد انواع Coreهای حافظه از نوع distributed، و سنتز و ایمپلیمنت آن، رابطه ای بین تعداد بیتهای حافظه از این نوع و تعداد LUTهای مصرفی بدست آورید. (راهنمایی: یک حافظه 64x16 ایجاد کنید سپس یک فایل top برای آن بنویسید و آنرا ایمپلیمنت کنید و با باز کردن فایل با پسوند par، تعداد LUTهای مصرف شده را استخراج کنید سپس این کار را برای چند حافظه با اندازههای دیگر تکرار کنید و رابطه را بدست آورید)
6-1 پیش آگاهی
هدف از این آزمایش، آشنایی با FIFO و نحوه تولید آنها توسط نرم افزار ISE میباشد و زمانبندی خواندن و نوشتن در آن و شبیهسازی آن میباشد.
FIFO، سخت افزاری است که برای ذخیره و بازیابی دادهها به صورت صف مورد استفاده قرار میگیرد. پیادهسازی آن به صورت BlockRAM دو پورته است. در FIFO با هر بار خواندن شمارندهی آدرس خواندن جلو میرود و با هر بار نوشتن آدرس یک واحد زیاد میشود.
برای پیادهسازی FIFO از BlockRAM یا حافظهی Distributed استفاده میشود. در سختافزار FIFO شرط پربودن و خالی بودن آن وجود دارد که میتوان آنها را با رجیسترها تعیین کرد.
6-1-1 کاربردهای مهم FIFO
1- صف: بافر کردن دادهها به صورت موقت؛ مثلاً اگر جایی سرعت پردازش اطلاعات با سرعت ورودی یا خروجی اطلاعات یکی نیست، میتوان از این امکان FIFO استفاده کرد. یا در بحث شبکه، وقتی بستههای دریافتی کامل شد آنها را برای پردازش بفرستد. و برای این مورد اگر در FIFO بنویسیم بهتر از حافظه است چون نیازی نیست آدرس آن را خودمان تولید کنیم.
2- کاربرد مهمتر این است که وقتی در مدار دو کلاک داشته باشیم و بخواهیم بین این دو قسمت از برنامه داده جابهجا کنیم، بین آنها یک FIFO قرار میدهیم و قسمت اول با کلاک خودش در FIFO مینویسد و دومیبا کلاک خودش از FIFO میخواند، بنابراین مشکل عدم پایداری به وجود نمیآید.
مورد دیگر: در پردازش اطلاعات شبکه کلاک پردازش شبکه و کلاک پردازش داخلی متفاوت است، برای حل این مشکل هم از FIFOاستفاده میکنیم.
6-1-2 مراحل ساختن FIFO در نرم افزار ISE
ابتدا پروژه جدیدی ایجاد میکنیم و سپس راست کلیک روی پروژهی ساخته شده و New Source را انتخاب میکنیم و گزینهی
) IP(CORE Generator & Architecture Wizard را انتخاب میکنیم. در اینجا میخواهیم یک FIFO با اندازه ی 16K که هر کلمهی آن 8 bit است بسازیم.


پس از آن در قسمت search عبارت FIFO را جستجو میکنیم و Fifo Generator را انتخاب کرده و Next را انتخاب میکنیم.

کمترین تعداد پورتهای Fifo ، 6 تا است که در شکل نشان داده شده اگر RST را حذف کنیم بقیه پورتها 6 تا هستند. ( به غیر از clock ). در این مرحله Native را انتخاب کرده و سپس Next.

در این قسمت گزینههای مختلفی میبینید که چهار گزینهی اول مربوط به ساختن Fifo با یک کلاک هستند که Synchronous Fifo است. و سه گزینهی بعد مربوط به ساختن Fifo با دو کلاک است که ASynchronous Fifo است.
همچنین در اینجا نوع حافظهای که میخواهید Fifo با آن ساخته شود را انتخاب میکنید. برای مثال ساختن با
Shift register ، Block RAM ،Distributed RAM.
- Built-in-FIFO، Fifoی است که خودش پیادهسازی شده و مدارها را دارد.
بر اساس محدودیت سخت افزاری که داریم، اینکه FIFO با چه ساخته میشود را انتخاب میکنیم. مثلا اگر BlockRAMها را میخواهیم در جای دیگر استفاده کنیم، در اینجا این گزینه را انتخاب نمیکنیم. به طور کلی همهی اینها از نظر سرعت یکسانند، بسته به مدار یکی را انتخاب میکنیم. که در اینجا همان گزینهی اول را انتخاب کنید و سپس Next.

در این قسمت ابتدا نوع خواندن (Read Mode) را انتخاب میکنیم.
- Standard FIFO: با انتخاب این گزینه تا زمانی که سیگنال Read را فعال نکنیم داده روی خروجی نمیآید و وقتی سیگنال Read را فعال کردیم، یک پالس بعد داده روی خروجی میآید.
- First-Word Fall- Through: با انتخاب این گزینه اولین داده به محض انجام شدن Write روی خروجی میآید و نیازی به فعال کردن سیگنال Read برای آن نیست ولی دادههای بعدی مانند گزینهی اول، پس از فعال شدن سیگنال Read روی خروجی ظاهر میشوند.
در اینجا ما گزینهی اول را انتخاب میکنیم چون فرقی بین کلمهها نمیگذارد!
Built-in FIFO Options:
اگر در قسمت کلاک، کلاکها را متفاوت در نظر میگرفتیم در این قسمت باید اندازهی آنها را مشخص میکردیم.
Data Port Parameters:
در این قسمت طول کلمه و تعداد کلمات را برای Fifo انتخاب میکنیم. و سپس Next.

کاربرد Flagهای مختلف:
- Write Acknowledge Flag:
اگر قبل از انجام عمل write ، پر بودن Fifo را چک کردیم نیازی به این Flag نیست. اما اگر اینکار را انجام ندادیم، با چک کردن این Flag متوجه میشویم که عمل نوشتن به درستی انجام شده است یا خیر. چون ممکن است Fifo پر بوده باشد و ما عمل نوشتن را انجام دهیم و نوشتن انجام نگیرد.
- Overflow Flag:
وقتی Fifoپر باشد و ما عمل نوشتن را انجام دهیم این پرچم فعال میشود.
- Valid Flag:
وقتی داده روی پورت قرار گرفت، یک کلاک بعد این Flag فعال میشود و با فعال شدن آن میتوانیم داده را بخوانیم.
- Underflow Flag:
وقتی Fifo خالی بوده و ما عمل خواندن انجام دادیم، این Flag فعال میشود.
در این مرحله میتوانیم هر کدام از پرچمهایی که میخواهیم را فعال کرده و سپسNext.

در این مرحله میتوانیم انتخاب کنیم که میخواهیم Reset Pin داشته باشیم یا نه و Reset ما به صورت Synchronous باشد یا Asynchronous.
- Full Flags Reset Value: اگر مقدار یک را انتخاب کنیم، یعنی وقتی Reset فعال شد، Full یک میشود و اجازه ی نوشتن داده نمیشود و در واقع کسی که داده مینوشته دیگر نمینویسد. و در قسمت پایین آن انتخاب میکنیم که وقتی Reset فعال شود، چه مقداری روی خروجی نشان داده شود.
- Programmable Full Type: وقتی میخواهیم فعال شدن full زودتر به ما اطلاع داده شود. و در واقع تعداد کلمات به حدی که میخواهیم رسید full فعال شود.
- Full Threshold Assert Value: مقداری که در این قسمت تعیین میکنیم، وقتی تعداد کلمات به این مقدار رسید به ما هشدار میدهد.
- Full Threshold Negate Value: وقتی تعداد کلمات به این مقدار برسد، full فعال میشود.
همچنین با انتخاب گزینهی Single Programmable Full Threshold Input Port از قسمت Programmable Full Type میتوانیم، از طریق دادن ورودی میتوانیم این محدوده را مشخص کنیم و از این طریق میتوان به صورت پویا محدوده را عوض کرد.
در مورد Empty هم به همین صورت است. مثلا تعیین میکنیم اگر دو کلمه نوشته شد، Empty غیر فعال شود.

کاربرد Data Count به این صورت است که با دانستن ظرفیت و مقدار Data Count میتوانیم بفهمیم چقدر از Fifo پر شده است. در این قسمت همچنین میتوانیم تعیین کنیم طول Data Count چقدر باشد. برای مثال اگر طول داده در Fifo با 14 رسید یکی بشمارد.

اگر در مرحلهی اول گزینهی AXIS را به جای Native انتخاب میکردیم تنظیمات این مرحله قابل تغییر بود.

در مرحله ی آخر یک سری اطلاعات از Fifo که قرار است ساخته شود به ما میدهد. در این مرحله Generate را انتخاب میکنیم و Fifo با تنظیمات انتخاب شده توسط ما ساخته میشود.

پس از ساخته شدن Fifo یک فایل FIFO_TOP برای آن، با مشخصات زیر میسازیم.

با انتخاب فایل Fifo ساخته شده و باز کردن فایل View HDL Instantation Template میتوانید قطعه کد Component و Port Map را در فایل FIFO_TOP کوپی کنید.

شکل زیر تغییرات انجام شده پس از کپی کردن PortMap و Component در فایل FIFO_TOP را هم نشان میدهد.

پس از آن از فایل TOP یک فایل TestBench میسازیم. با دادن مقادیر زیر میتوانیم هر یک از دستورات Reset، Write و Read را امتحان کنیم.

در شبیهسازی که طبق مقادیر داده شده در شکل قبل انجام میشود، مشاهده میکنید که هم زمان با فعال شدن Reset،Full هم فعال شده و تا 3 کلاک پس از غیر فعال شدن Reset هم فعال باقی مانده است. و این نشان دهندهی این است که بلافاصه بعد از Reset کردن نمیتوانیم در Fifo عمل نوشتن را انجام دهیم.

در فایل TestBench اگر لیست حساسیت در Process بنویسیم، دیگر نیازی به نوشتن Wait نیست و مدار Syncron با کلاک عمل میکند و مشکلی به وجود نمیآید.
مانند شکل زیر اگر در فایل Test Bench لیست حساسیت بنویسیم دیگر نیازی به استفاده از wait نیست. توجه شود که در شکل زیر از counter برای شمردن استفاده شده است. روش دیگر برای نوشتن لیست حساسیت استفاده از state Machine است که counter خود یک state Machine است. توجه کنید در اینجا چون از عملگر + استفاده شده باید USE ieee.std_logic_unsigned.ALLبه عنوان کتابخانه اضافه شود. در این قسمت مقدار wr صفر داده شده و در زمآنهایی که میخواهیم فقط مقدارش یک میشود. در مورد rd این طور نیست و وقتی که مقدارش را یک کنیم تا وقتی که دوباره با شرط آن را تغییر نداده ایم، یک باقی میماند.
در شبیهسازی میتوانید متوجه این موضوع شوید.

6-2دستور کار
1- برنامهای بنویسید که مدار شکل روبرو را پیادهسازی کند. ساختار داخلی این مدار به این صورت است که یک فیفو با عمق 128 و عرض 16 بیت است که امکان نوشتن دیتا از بیرون را دارد و هر وقت لبه بالارونده روی سیگنال Start مشاهده شد، خواندن از فیفو شروع میشود و تا موقعی که فیفو خالی شود مقادیر داخل آن را با همدیگر جمع میزند.
![]()
برای مدار فوق یک TestBench بنویسید که مقادیر 1 تا 10 را در فیفو بنویسد سپس یک لبه بالارونده روی Start ایجاد کند.
2- برنامهای بنویسید که مدار شکل روبرو را پیادهسازی کند. در این مدار از دو بلاک رم از نوع Simple Dual Port با اندازه 128x8 استفاده شده است. پورت A از بلاک رم BRAM1 از بیرون قابل دسترس است و میتوان در آن عمل نوشتن را انجام داد. عملکرد مدار به این گونه باشد که با دیدن لیه بالا رونده روی پورت Copy، محتویات آدرسهای 0 تا 10 بلاک رم 1 خوانده شده و با عدد 55 جمع زده میشود و در بلاک رم 2 نوشته میشود. با دیدن لیه پایین رونده روی پورت Show، محتویات آدرسهای 0 تا 10 از بلاک رم2 خوانده شده و روی پورت Dout گذاشته میشود.
برای مدار فوق یک TestBench بنویسید که مقادیر 100 تا 110 را در آدرسهای صفر تا 10 بلاک رم 1 بنویسد و سپس یک لبه بالارونده روی Copy ایجاد کند و نهایتا یک لیه پایین رونده روی سیگنال Show ایجاد کند.
![]()
7-1 پیش آگاهی
هدف از این آزمایش، آشنایی با ردههای مختلف شبیهسازی با استفاده از نرم افزار ISE میباشد.
برای اینکه از صحت عملکرد یک برنامه VHDL اطمینان حاصل شود باید آن را در مراحل مختلف شبیهسازی کرد. علت این امر را با یک مثال روشن میکنیم. ممکن است شما برنامه VHDL خود را شبیهسازی کنید و خروجیهای مدار دقیقا همان نتایج مورد انتظار شما باشد ولی وقتی که برنامه سنتز میشود، قسمتهایی از برنامه حذف گردند (مثلا از دستورات تاخیر در برنامه استفاده کرده باشید که قابل سنتز نیستند) بنابراین وقتی که مدار خود را روی FPGA پیادهسازی میکنید، نتیجه مورد انتظار تولید نخواهد شد. برای اینکه مشکلاتی از قبیل فوق رخ ندهد و شما بتوانید از صحت عملکرد مدار خود بعد از انجام مراحل سنتز، MAP و Place and Route اطمینان حاصل کنید، در نرم افزار ISE این قابلیت فراهم شده است تا برنامه خودر را در ردههای زیر شبیهسازی کنید:
الف) شبیهسازی فانکشنال یا رفتاری (Behavioral simulation)
ب) شبیهسازی بعد از مرحله Translate (Post Translate simulation)
ج) شبیهسازی بعد از انجام مرحله MAP (Post MAP simulation)
د) شبیهسازی بعد از مرحله Place and Route (Post Route simulation)
در ادامه با ذکر یک مثال، روش انجام شبیهسازی در ردههای مختلف بیان میشود.
7-1-1 انجام شبیهسازی در ردههای مختلف برای یک جمع کننده
ابتدا به عنوان نمونه یک جمع کننده 8 بیتی ایجاد کرده و سپس تست بنچ مربوط به آن را مینویسیم.

نمونه کد یک جمع کننده 8 بیتی در زیر مشاهده میشود. دقت کنید که کتابخانه unsigned نیز در پروژه استفاده شده است.

حال نوبت به نوشتن تست بنچ مربوطه است.

اگر نوع شبیهسازی را از نوع Behavioral انتخاب کنیم نتیجه شبیهسازی بدون در نظر گرفتن تأخیرهای سخت افزاری به ما نشان داده میشود. (فقط رفتار کد ما شبیهسازی میشود ) و اگر Post-Translate انتخاب کنیم شبیهسازی کد Translate شده انجام میشود و همینطور اگر Post – Route را انتخاب کنیم مدار Route شده شبیهسازی میشود. )


نمونه شبیهسازی شده ( مرحله Behavioral) را در شکل زیر مشاهده میکنید.
نمونه شبیهسازی شده ( مرحله Post – Route ) را در شکل زیر مشاهده میکنید. ( دلیل قرمز بودن برخی سیگنالها تأخیرهای سخت افزاری پیادهسازی کد بر روی تراشه میباشد )

7-2 دستورکار
1- ![]()
با استفاده از ماشین حالت، برنامهای بنویسید که مدار شکل روبرو را پیادهسازی کند. عملکرد این مدار به این صورت است که رشته ای از بیتها را به صورت سریال دریافت میکند و تعداد دفعات تکرار رشته 110010 را شمارش میکند. با فعال شدن سیگنال Rst، مقدار شمارنده خروجی، صفر خواهد شد. رشته ورودی به صورت سریال از پورت Serial_In وارد میشود و سیگنال Valid، معتبر بودن بیت موجود روی پورت Serial_In را مشخص میکند.(توجه کنید که رشته بیتهای وارد شده به ماجول از کم ارزش به پر ارزش است)
2- شبیهسازی فانکشنال یا رفتاری (Behavioral simulation) را برای مدار فوق انجام دهید و نتایج را به مسئول آزمایشگاه نشان دهید.
3- شبیهسازی بعد از مرحله Translate (Post Translate simulation) را برای مدار فوق انجام دهید و نتایج را به مسئول آزمایشگاه نشان دهید.
4- شبیهسازی بعد از انجام مرحله MAP (Post MAP simulation) را برای مدار فوق انجام دهید و نتایج را به مسئول آزمایشگاه نشان دهید.
5- شبیهسازی بعد از مرحله Place and Route (Post Route simulation) را برای مدار فوق انجام دهید و نتایج را به مسئول آزمایشگاه نشان دهید.
از برنامه زیر به عنوان TestBench استفاده کنید:
بعد از شبیهسازی اولیه، برنامه TestBench را به گونه ای تغییر دهید که شماره دانشجویی شما به صورت باینری وارد ماجول Pattern_count شود و الگوی 110010 در آن جستجو گردد.
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.math_real.ALL; -- for UNIFORM, TRUNC functions
USE ieee.numeric_std.ALL; -- for TO_UNSIGNED function
ENTITY TB_Pattern_Count IS
END TB_Pattern_Count;
ARCHITECTURE behavior OF TB_Pattern_Count IS
COMPONENT pattern_count
PORT(
Clk : IN std_logic;
Rst : IN std_logic;
valid : IN std_logic;
Serial_in : IN std_logic;
Count : OUT std_logic_vector(7 downto 0)
);
END COMPONENT;
--Inputs
signal Clk : std_logic := '0';
signal Rst : std_logic := '0';
signal valid : std_logic := '0';
signal Serial_in : std_logic := '0';
--Outputs
signal Count : std_logic_vector(7 downto 0);
-- Clock period definitions
constant Clk_period : time := 10 ns;
signal pattern:std_logic_vector(31 downto 0):="11001011011011001011001001001011";
type s_type is(idle,working,random_wait,finish);
signal tb_state :s_type:=idle;
signal wait_counter: integer range 0 to 7:=0; -- Random integer value in range 0..7
signal Serial_counter: integer range 0 to 255:=0;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: pattern_count PORT MAP (
Clk => Clk,
Rst => Rst,
valid => valid,
Serial_in => Serial_in,
Count => Count
);
-- Clock process definitions
Clk_process :process
begin
Clk <= '0';
wait for Clk_period/2;
Clk <= '1';
wait for Clk_period/2;
end process;
process(clk)
variable rand: real; -- Random real-number value in range 0 to 1.0
variable seed1, seed2: positive; -- Seed values for random generator
begin
if(clk='1' and clk'event)then
valid <='0';
Rst <='0';
case tb_state is
when idle =>
Rst <='1';
tb_state <= working;
when working =>
Serial_in <= pattern(0);
Serial_counter <=Serial_counter+1;
pattern <= '0' & pattern(31 downto 1);
valid <='1';
UNIFORM(seed1, seed2, rand) ;
wait_counter<= INTEGER(TRUNC(rand*5.0));
if(Serial_counter=32)then
tb_state <= finish;
else
tb_state <= random_wait;
end if;
when random_wait =>
wait_counter <= wait_counter-1;
if(wait_counter=0)then
tb_state <= working;
end if;
when finish =>
null;
when others =>
tb_state <= working;
end case;
end if;
end process;
-- Stimulus process
stim_proc: process
begin
-- hold reset state for 100 ns.
wait for 100 ns;
wait for Clk_period*10;
-- insert stimulus here
wait;
end process;
END;
8-1 پیش آگاهی
هدف این آزمایش آشنایی با نرمافزار ChipScope میباشد. این نرمافزار جزو قابلیتهای ISE میباشد که این امکان را فراهم میکند که بتوان سیگنالهای داخلFPGA را مانند اسیلوسکوپ نمونه برداری کنیم و توسط کابل JTAG در کامپیوتر نشان دهیم.
8-1-1استفاده از نرمافزار ChipScope
استفاده از نرمافزار ChipScope را با یک مثال برای یک شمارنده پی میگیریم:
بعد از پیادهسازی شمارنده،برای استفاده از نرمافزار ChipScope از قسمت New Source گزینه ChipScope Definition and Connection File را انتخاب میکنیم. سپس یک اسم انتخاب میکنیم.

بعد از انجام این کار یک فایل با پسوند cdc به پروژه اضافه میشود. بر روی آن کلیک میکنیم تا تنظیمات لازم را انجام دهیم. در قسمت اول و دوم Next را میزنیم. سپس به قسمتی میرسیم که در آن مشخص میکنیم که چه سیگنالهایی نشان داده شود.

بررسی سیگنالها به صورت آنلاین نمیباشد، بلکه به صورت تریگر میباشد. به این صورت که سیگنال مورد نظر را به عنوان تریگر معرفی کرده، و سپس در نرمافزار ChipeScope مشخص میکنیم که در چه صورتی مقدار آن نمونه برداری شود. سیگنال تریگر میتواند به صورت تک بیت یا به صورت باس باشد. در این قسمت سیگنالهای تریگر را مشخص میکنیم.
در این مثال میخواهیم دو سیگنال ریست و هشت بیت از بیتهای شمارند را به عنوان تریگر داشته باشیم. برای این کار ابتدا عدد دو را در قسمت
Trigger Input and Match Unit Settings انتخاب میکنیم، سپس تعداد بیتهای سیگنالهای تریگر را در قسمت Trigger Width مشخص میکنیم. سپس به قسمت بعدی میرویم.

در این مرحله تعداد نمونهها را مشخص میکنیم. به این معنی که مشخص میکنیم که هرگاه شرط مورد نظر برقرار شد، چند تا نمونه برداشته شود. تعداد نمونهها را در قسمتData Depth مشخص میکنیم. در این مثال عدد 1024 را انتخاب میکنیم. سپس به قسمت بعدی میرویم.

در این قسمت، تریگرها را به سیگنالهای داخلی وصل میکنیم. برای این کار گزینه Modify Connections را انتخاب میکنیم.
سپس در قسمت Clock Signals مشخص میکنیم که بر اساس چه کلاکهایی نمونهها برداشته شود. برای انتخاب سیگنالهای کلاک،سیگنالهای مورد نظر را از لیست سیگنالهای داخلی FPGA که در قستمت سمت چپ قابل مشاهده هستند، انتخاب و سپس Make Connection را انتخاب میکنیم.

برای وصل کردن سیگنالهای تریگر قسمت Trigger/Data Signals را انتخاب میکنیم. سپس سیگنالهای داخلی FPGA را مانند قبل متصل میکنیم. برای وصل کردن سیگنال تریگر دوم از قسمت پایین TP1 را انتخاب میکنیم. سپس مانند قبل عمل میکنیم. سپس OK را انتخاب میکنیم.


در قسمت جدید گزینه Return to Project Navigator را انتخاب میکنیم. بعد از آن باید پروژه را سنتز و ایمپلیمنت کنیم.
بعد از آن گزینه Analyze Design Using ChipScope که جدید اضافه میشود را انتخاب میکنیم.

سپس نرمافزار ChipeScope باز میشود. از همین برنامه میتوان برای پروگرم کردن FPGA نیز استفاده کرد. برای این کار کابل JTAG را وصل میکنیم و سپس JTAG Chain را میزنیم و گزینه okانتخاب میکنیم. بعد از آن در قسمت بالای صفحه به منو Device میرویم و FPGA مورد نظر را انتخاب و بعد از آن گزینهConfigure را انتخاب میکنیم. در نهایت گزینه okانتخاب میکنیم تا FPGA پروگرم شود.

بعد از آن بر روی Waveform و Trigger Setup دابل کلیک میکنیم تا به قسمت سمت راست اضافه شوند. در قسمت Trigger Setup میتوان تریگر را تعریف کرد. در این مثال تریگر را یک شدن رقم اول شمارند در نظر میگیریم. برای این کار رقم اول value سیگنال اول را از X به یک تغییر میدهیم. سپس گزنیه PLAY را از بالای صفحه انتخاب میکنیم. در قسمت Waveform نمونهها قابل مشاهده هستند.

برای اضافه کردن تریگر دوم بر روی M0 کلیک کرده و در منو جدید مشخص میکنیم که شرط تریگر کدام سیگنالها باشد. امکان and و or کردن شرطها نیز وجود دارد. بعد از آن مقدار تریگر سیگنال دوم را در قسمت Trigger Setup مانند قبل تعیین میکنیم.

8-2 دستورکار
1- ![]()
در این آزمایش قصد داریم برای ماجول UART یک TestBench تهیه کنیم سپس با استفاده از نرم افزار ChipScope سیگنالهای درونی آن را ببینیم.
با توجه به اینکه خطوط Tx و Rx این ماجول به صورت سریال است، نوشتن تست بنچ و همچنین چک کردن بیتهای ارسالی کاری پیچیده است. برای ساده تر شدن تست این ماجول طرحی به صورت زیر پیشنهاد میشود که در داخل تست بنچ از دو ماجول UART استفاده شود سپس برای تست، در یک ماجول یک بایت نوشته شود(با استفاده از خطوط Tx_wr و Tx_Data) و منتظر بمانیم تا در ماجول دوم خط Rx_Done فعال شود. با این تست به راحتی قسمت فرستنده و گیرنده ماجول UART تست خواهد شد. (راهنمایی: وقتی با استفاده از نرم افزار ISE، تست بنچ را ایجاد کردید، پورت مپ شدن ماجول UART را تکرار کنید و سیگنالهای مورد نیاز را تعریف کنید و طبق شکل زیر، پورتهای Rx و Tx را به یکدیگر متصل کنید)

9-1 پیش آگاهی
موضوع این جلسه ی آزمایشگاه در مورد پیادهسازی محیطهای Embedded در بوردهای FPGA میباشد. به گونه ای که بتوان بستر نرم افزاری برای برنامه نویسی سطح بالا در FPGA را فراهم کرد.
9-1-1 FPGA در محیطهای Embedded
FPGAها با تمام قابلیتها و ساختاری که در خود دارند، در طراحیها انعطاف پذیری کمیاز خود نشان میدهند. در واقع نیاز به یک تغییر کوچک در یک مدار ممکن است نیاز به تغییر در کل طراحی و ساختار برنامه ی نوشته شده داشته باشد. به همین منظور بعضی از پردازشها در بوردها به صورت نرم افزاری انجام میشود. به عبارت دیگر میتوان قسمتهای مهم کد را در قالب کد VHDL (شتاب دهنده ی سخت افزاری) و سایر پردازشها را از طریق برنامه نویسی نرم افزاری (بستر نرم افزاری) انجام داد.
برای ایجاد بستر نرم افزاری نیاز به یک پردازنده داخل FPGA است که برنامه ی نرم افزاری را بتواند اجرا کند. ایدههای مطرح شده برای ایجاد این پردازنده به دو صورت Soft Processor و Hard Processor میباشد.
در ایده ی Soft Processor هدف ایجاد یک پردازنده به کمک کد VHDL مثل پردازنده ی مانو است. در این حالت منابع FPGA مانند LUTها و Flip Flopها مصرف خواهند شد. یکی از این نوع پردازندهها Pico Blaze است که طراحی آن بسیار بهینه و با دستورات کمی ایجاد شده که منابع بسیار کمی از بورد را استفاده میکند. نوع دیگر از این نوع پردازندهها Micro Blaze است که بعد از Pico Blaze توسط شرکت Xilinx پشتیبانی شده و اولین Soft Processor تجاری به شمار میرود.
در حالت Hard Processor با اضافه کردن IC و مدارهای مورد نیاز یک پردازنده به FPGA، پردازنده ی مورد نیاز برای بستر نرم افزاری ایجاد میشود که در این حالت منابع FPGA مصرف نخواهند شد و Performance مدار نیز افزایش خواهد یافت. به عنوان مثال برای این نوع میتوان به هسته ی پردازنده ی Cortex شرکت ARM و Power PC اشاره کرد.
9-1-2 آشنایی با نرم افزارهای EDK
EDK (Embedded Development Kit) بخشی از نرم افزار ISE است که در آن میتوان یک سیستم Embedded را ایجاد و آن را مدیریت نمود. فولدر EDK شامل دو بخش XPS (Xilinx Platform Studio) و SDK (Xilinx Software Development Kit) است. XPS برای مشخص کردن ساختار سخت افزاری استفاده میشود (مثلا نوع و تعداد پردازندهها، پورتها، محدوده ی آدرسها و ...). بعد از این که این ساختار مشخص شد، XPS با ساختن یک فایل Bit ما را به نرم افزار SDK هدایت میکند تا در آن قسمت برنامههای مورد نیاز خود را برای پردازش به زبان سطح بالا بنویسیم. به عبارت دیگر در نرم افزار XPS ساختار سخت افزاری سیستم خود را مشخص و در نرم افزار SDK برای آن ساختار، برنامه نویسی سطح بالا انجام میدهیم.
9-1-3 قدمهای ایجاد یک سیستم Embedded در FPGA
بعد از باز کردن نرم افزار XPS مطابق شکل زیر خواهیم
داشت:
مطابق شکل اولین گزینه Base System Builder است که به صورت پیش فرض نیز انتخاب شده است. اصطلاحا به اجزای سخت افزاری که کنار هم گذاشته میشود، Base System گفته میشود که در واقع سیستم پایهای است که برنامههای نوشته شده روی آن سوار خواهد شد. با انتخاب گزینه ی Base System، در مرحله ی بعد نام و مسیر دلخواه خود را (اشاره به یک فولدر خالی) به فیلدهای موجود میدهیم )مسیر داده شده نباید شامل Space باشد).
مرحله ی بعد انتخاب کردن نوع باس سیستم از دو نوع PLB (یک نوع باس شرکت IBM) و AXI (یک نوع باس از Xilinx که برای بوردهای جدید طراحی شده) میباشد که برای راحتی کار و جهت استفاده از بوردهای قدیمی، از نوع PLB استفاده میکنیم. باسهای مختلف در پشتیبانی کردن آدرسها، پهنای باند، تعداد دستگاههای I/O و ... با هم متفاوت اند.

9-1-4 ساخت یک Base System
با انتخاب گزینه ی OK وارد Base System Builder Wizard میشویم که شامل مراحلی برای ساخت Base System است.
اولین قدم مرحله ی Welcome است. این مرحله میتوان یک طراحی جدید ایجاد کرد یا از طراحیهای قبلی استفاده کرد.
با انتخاب ایجاد یک طراحی جدید، وارد مرحله ی Board میشویم. هدف اصلی در این مرحله انتخاب بورد پایه برای ساخت Base System است تا نرم افزار بتواند بر اساس اجزا و مشخصات آن بورد، Wizard را آماده کرده و جزئیات بیشتری درباره ی صفات سخت افزاری سیستم از ما بخواهد (این که مثلا از کدام یک از ویژگیهای بورد و هر کدام به چه تعداد استفاده کرده ایم).
بوردهای از پیش ساخته شده ی شرکت Xilinx به طور خودکار به این نرم افزار شناسانده شده و میتوان از آنها به عنوان Base System استفاده کرد. با اضافه کردن فایلی با پسوند BST (که دارای مشخصات بوردها است) میتوان بوردهای غیر استانداردی که به این نرم افزار شناسانده نشدهاند را، معرفی کرد تا به منظور Base System مورد استفاده قرار گیرند.
با انتخاب هر بورد به عنوان Base System مشخصات سخت افزاری بورد از جمله پورتها، میزان Support حافظهها و ...، در پایین wizard نمایش داده میشوند.

در مرحله ی System تعداد پردازندههای سیستم درخواستی از کاربر پرسیده میشود که به صورت default روی گزینه ی Single Processor قرار دارد.
باز زدن گزینه ی Next وارد مرحله ی انتخاب نوع پردازنده Processor میشویم. با در نظر گرفتن توضیحات داده شده در بالا میتوان از انواع Micro Blaze، Pico Blaze، Power Pc و ... استفاده کرد. اما با توجه به نوع بورد FPGA انتخابی در ابتدای Wizard، این بورد فقط شامل هسته ی پردازنده ی Micro Blaze است. بنابراین نوع پردازنده ای که بخواهیم استفاده کنیم، به نوع بورد FPGA انتخابی وابسته است که آیا Core پردازندههای مختلف را Support میکند یا خیر. همچنین مطابق شکل زیر در این مرحله میتوان فرکانس سیستم را انتخاب کرد که با افزایش آن سرعت سیستم نیز افزایش مییابد اما منابع بیشتری مصرف خواهند شد و زمان سنتز و ایمپلیمنت نیز افزایش خواهد یافت. علاوه بر آن با انتخاب قسمت Floating Point دستورات اعداد اعشاری به سیستم اضافه میشود که باعث افزایش زمان سنتز و ایمپلیمنت خواهد شد.

در مرحله ی Peripheral نرم افزار دو جدول را به ما ارائه میکند. جدول سمت چپ Peripheralهای آماده روی بورد را نشان میدهد (ویژگیهایی که در سیستم وجود دارد) و سمت راست ویژگیهایی است که میتوان به سیستم اضافه کرد. برای مثال بیان میکند که DIP_Switches_8Bit از xps_gpio به عنوان Core استفاده میکند (با فعال کردن Interrupt هنگام فشرده شدن به پردازنده وقفه خواهد داد). به همین ترتیب انواع مشخصات سخت افزاری را میتوان به جدول سمت راست Add یا از آن remove کرد. تعداد امکانات سخت افزاری با توجه به ماهیت آنها تأثیر زیادی در زمان سنتز و ایمپلیمنت کردن سیستم پایه دارد.

در مرحله ی Cache میتوان برای سیستم حافظه ی cache انتخاب کرد که مانند موارد قبلی علی رغم افزایش سرعت سیستم، زمان سنتز و ایمپلیمنت را افزایش خواهد داد.
در مرحله ی Summary نرم افزار با ارائه ی گزارشی درباره ی سیستم ایجاد شده و آدرسهای استفاده شده، مراحل ساخت سیستم را به پایان میرساند.
با انتخاب گزینه ی Finish، محیط XPS مشخصات کامل سیستم ساخته شده را از طریق Tabهای Bud Interface، Port و Addresses به ما ارائه میدهد. مثلا این که هر Device به کدام باس متصل شده و محدوده ی آدرس آن چیست. به ازای تک تک این ویژگیها کدهای VHDL ای نوشته شده است که با تغییر آنها کدها به صورت اتوماتیک توسط نرم افزار تغییر داده میشوند (این کدها در مسیر ساخته شده برای فایل XMP که در ابتدا کار دادیم، قرار دارند). همچنین با تغییر این مشخصات (مثلا عوض کردن محدوده ی آدرسها) در صورت بروز خطا نرم افزار پیغام خطا خواهد داد.

نهایتا با تکمیل ویژگیهای سخت افزاری با انتخاب کردن گزینه ی Export Hardware Design to SDK از منوی Project و انتخاب گزینه ی Export&Launch SDKاز پنجره ی باز شده، برنامه سنتز و ایمپلیمنت شده و وارد محیط نرم افزار SDK میشویم.


با انتخاب گزینه ی گفته شده، نرم افزار شروع به Export کردن سیستم برای نرم افزار SDK میکند که زمان مصرف شده ی آن بسته به عوامل گفته شده در بالا خواهد بود.
9-1-5 فایلهای UCF و MHS
با پست سر گذاشتن مراحل Wizard که در بالا گفته شد، در نهایت دو فایل MHS و UCF ساخته خواهد شد. این یعنی برای انجام بعضی تغییرات (مثل اضافه کردن یک Device جدید) نیازی به رجوع به Wizard نیست و میتوان تغییرات را مستقیما در این فایلها ایجاد کرد.

با فایل UCF از قبل آشنا هستیم (Deviceها به کدام پایههای FPGA متصل شوند). فایل MHS همان اطلاعاتی را که در محیط گرافیکی و Wizard آمده است، در قالب کد آورده است. قسمت گرافیکی و فایل متنی MHS با هم ارتباط دو طرفه دارند. این یعنی تغییر در هر کدام موجب آپدیت شدن دیگری میشود.
9-1-6 برنامه نویسی در محیط SDK
با اتمام کار نرم افزار XPS، نرم افزار SDK به طور اتوماتیک باز خواهد شد. محیط نرم افزار SDK همان محیط Eclipse است که به عنوان IDE برای توسعه ی اپلیکیشنها و برنامهها از آن استفاده میشود. فایل Bit ساخته شده توسط XPS (که در ابتدای کار به آن اشاره شد در بخش Project Explorer نرم افزار، در قسمت hw_platform_0 مشاهده میشود).
حال مطابق شکل زیر میتوانیم از محیط نرم افزاری ارائه شده توسط SDK استفاده و برنامه نویسی نرم افزاری را با ساختن یک پروژه ی جدید آغاز نماییم. همچنین Template پروژه ی مورد نظر را میتوانیم از Templateهایی که به صورت Default در نرم افزار قرار دارند، انتخاب کنیم.


در مرحله ی آخر ساخت یک پروژه ی جدید، میبایست Board Support Package را برای پروژه مشخص کنیم. به عبارت دیگر به توابعی که اجازه ی برقراری ارتباط بین نرم افزار و سخت افزار را میسر میسازند، Board Support Package یا Driver میگویند. برای ساخت پروژه میتوان این توابع را از اول ایجاد و یا از در صورت وجود به برنامه Import کرد.

در نهایت با ساخته شدن پروژه، با ورود به قسمت src پروژه و باز کردن فایل اجرایی برنامه (در این مثال helloworld.c)، برنامههای خود را به زبان C در آن بنویسم. همچنین با انتخاب گزینه ی Launch on Hardware از شاخه ی Run as در منوی Run و همچنین اتصال کامپیوتر به FPGA با کابل JTAG، میتوان برنامه ی نوشته شده را روی بورد پیادهسازی کرد.
نرم افزار با کامپایل کردن برنامه ما، فایل نهایی اجرایی به زبان ماشین را در قالب فایلی با پسوند ELF میسازد. این فایل شامل کدهای زبان ماشین است، بنابراین برای اجرا میبایست در مکانی قرار گیرد (به عنوان مثال این مکان میتواند یک Block Ram یا حافظه ی DDR که از بیرون به بورد متصل کرده ایم، باشد). برای تنظیم کردن این مورد و تنظیمات حافظه ای مشابه دیگر، میتوان فایل lscript.ld (که در قسمت src قرار دارد) را باز و تغییرات را در آن انجام داد. همچنین با انتخاب Generate Linker Script از منوی Xilinx Tools میتوان این تنظیمات را از طریق یک Wizard اعمال نمود.

در شکل روبرو فایلهای ELF و LD را که توسط نرم افزار ساخته اند را مشاهده میکنید:

9-2 دستورکار
1- با توجه به پیش آگاهی ارائه شده در بخش 9-1، یک پروژه XPS برای بورد آزمایشگاه ایجاد کنید و از بین Peripheralهای آن فقط پورت UART و کلیدهای دیپ سویچ و.LEDها را انتخاب کنید.
2- بیت فایل پروژه ایجاد شده را ایجاد کنید و آن را به محیط SDK منتقل کنید.
3- برنامهای به زبان C بنویسید که هرگاه کلید فشرده شده شد، عبارت a key was pressed را از طریق پورت سریال به کامپیوتر ارسال کند.
4- برنامه HyperTerminal را در PC اجرا کنید و تنظیمات پورت سریال را روی 9600 تنظیم کنید، سپس برنامهای در SDK بنویسید که وقتی بایتی از طریق HyperTerminal ارسال میشود، یکی از LEDها را روشن کند.
5- برنامه SDK را کاملتر کنید تا بتوان توسط برنامه HyperTerminal شماره LED ارسال کرد و فقط همان LED روشن شود.

