6 خرداد, 1399

کاربردهای تبدیب نوع در زبان VHDL

در پیاده‌سازی مدارات دیجیتال به کمک زبان VHDL گاهی نیاز دارید انواع داده را به یکدیگر ارجاع دهید.

از طرف دیگر، با توجه به قوانین ارجاع در زبان VHDL، نوع (type) تمام سیگنال‌های حاضر در یک ارجاع باید یکسان باشد.

بنابراین، در کدنویسی VHDL نیاز دارید از قابلیت «تبدیل نوع»‌ یا «Type Conversion» استفاده کنید.

برای این کار توابع مختلفی وجود دارد.

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

More...

قوانین ارجاع در زبان VHDL

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

قانونی که برای تمامی ارجاعات در زبان VHDL وجود دارد این است که باید نوع تمامی داده‌های حاضر در یک ارجاع یکسان باشد.

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

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


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

برای مثال، همه‌ی سیگنال‌های موجود در یک ارجاع باید از نوع بدون‌ علامت، علامت‌دار و یا std_logic_vector باشند.

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

قانون ارجاع ساده

در ارجاع ساده، باید عرض بیت سیگنال‌ها در دو سمت ارجاع با هم برابر باشد. برای مثال، در کد زیر، باید عرض بیت دو سیگنال A و B با هم برابر باشد:

A <= B;

قانون ارجاع جمع

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

برای مثال، در کد زیر اگر عرض بیت سیگنال A برابر با ۱۵ بیت باشد، عرض بیت یکی از سیگنال‌های سمت راست ارجاع باید ۱۵ بیت باشد و سایر سیگنال‌ها می‌توانند عرض بیت کمتری داشته باشند.

A <= B + C – D; 

قانون ارجاع ضرب

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

برای مثال، اگر در یک کد VHDL، ارجاع زیر را بنویسید، یک ضرب‌کننده در FPGA پیاده‌سازی می‌شود:

A <= B * C;

اما قانون ارجاع ضرب در زبان VHDL به این صورت است که باید عرض بیت سیگنال سمت چپ با مجموع عرض بیت‌های سیگنال‌های سمت راست برابر باشد.

برای مثال، اگر در کد بالا عرض بیت سیگنال‌های B و C به ترتیب برابر با ۱۰ بیت و پنج بیت باشد، عرض بیت سیگنال A، باید برابر با ۱۵ بیت باشد؛ در غیر این صورت، قانون ارجاع ضرب در زبان VHDL رعایت نشده است و از طرف نرم‌افزار پیاده‌ساز با خطا مواجه می‌شوید.

قانون ارجاع Concatenation

همان‌طور که احتمالاً می‌توانید حدس بزنید، قانون ارجاع concatenation کاملاً مشابه قانون ارجاع ضرب است؛ به عبارت دیگر، مجموع عرض بیت سیگنال‌هایی که با هم concat می‌کنید، باید برابر با هرض بیت سیگنال سمت چپ باشد.

اکنون که قوانین ارجاع را دیدیم به سراغ توابع تبدیل نوع می‌رویم.

به طور کلی، در زبان VHDL چهار نوع‌ داده‌ی برداری داریم:

  • std_logic_vector
  • بدون علامت یا unsigned
  • علامتدار یا signed
  • integer

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

اما در مواردی، به اجبار با نوع std_logic_vector نیز سر و کار داریم؛ برای مثال، در مبحث IPها باید با نوع std_logic_vector در تعامل باشیم.

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

توابع تبدیل نوع در زبان VHDL

توابع تبدیل نوع را در سه گروه زیر می‌توانیم طبقه‌بندی کنیم:

گروه اول توابع تبدیل نوع در زبان VHDL: کاربرد در برقراری قوانین ارجاع

این دسته شامل تبدیل نوع std_logic_vector ،unsigned و signed به یکدیگر است.

در ادامه، به کمک چند مثال، توابع این گروه را به طور کامل توضیح خواهم داد.

فرض کنید می‌خواهیم سیگنالی به نام A و از نوع std_logic_vector را به سیگنال علامت‌داری به نام B ارجاع دهیم؛ مانند کد زیر:

ارجاع سیگنالی از نوع std_logic_vector به سیگنالی از نوع signed

ارجاع سیگنالی از نوع std_logic_vector به سیگنالی از نوع signed

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

برای این ‌که بتوانیم محتوای سیگنال A را به سیگنال B منتقل کنیم، باید تبدیل نوع انجام دهیم.

به نظر شما باید نوع سیگنال A به نوع سیگنال B تبدیل شود یا برعکس، نوع سیگنال B به A تبدیل شود؟

طبق قواعد زبان VHDL، همیشه باید نوع سیگنالی که قرار است به سیگنال دیگر منتقل شود را تغییر دهید.

به عبارت دیگر، هیچ‌گاه نمی‌توانید نوع سیگنال سمت چپ ارجاع را که می‌خواهید مقداری به آن منتقل کنید را تغییر دهید.

بنابراین، در این مثال باید نوع سیگنال A را به نوع علامت‌دار تغییر دهید. برای این کار، می‌توانید مطابق کد زیر، به سادگی کلمه‌ی "signed" را پیش از سیگنال A بنویسید و سیگنال A را درون پرانتز قرار دهید:

تبدیل نوع STD_Logic_Vector به نوع signed در زبان VHDL

تبدیل نوع std_logic_vector به نوع signed در زبان VHDL

به این ترتیب، نوع سیگنال A به علامت‌دار تغییر می‌کند و قابل ارجاع به سیگنال B است.

حال، مثال دیگری را بررسی می‌کنم.

فرض کنید قصد داریم سیگنالی به نام D و از نوع علامت‌دار را به سیگنال بدون‌ علامتی به نام C منتقل کنیم:

ارجاع سیگنالی از نوع signed به سیگنالی از نوع unsigned

ارجاع سیگنالی از نوع signed به سیگنالی از نوع unsigned

نوع کدام سیگنال می‌تواند تغییر کند؟ بله، نوع سیگنال D واقع در سمت راست ارجاع می‌تواند تغییر کند. بنابراین، به صورت کد زیر عمل می‌کنیم:

تبدیل نوع signed به نوع unsigned در زبان VHDL

به این ترتیب، نوع سیگنال D به بدون علامت تغییر می‌کند و قابل ارجاع به سیگنال C است.

حال فرض کنید می‌خواهیم سیگنال بدون‌ علامت F را به سیگنال E، از نوع std_logic_vector منتقل کنیم:

ارجاع سیگنالی از نوع unsigned به سیگنالی از نوع std_logic_vector

بنابراین، باید مطابق کد زیر، نوع سیگنال F را به std_logic_vector تبدیل کنیم:

تبدیل نوع unsigned به نوع std_logic_vector در زبان VHDL

تبدیل نوع unsigned به نوع std_logic_vector در زبان VHDL

توجه کنید این تبدیلات علاوه بر ارجاع ساده، در ارجاعات دیگر از جمله ارجاع جمع نیز کاربرد دارند.

برای مثال، وقتی همانند کد زیر می‌خواهیم سیگنال H و J را با هم جمع کنیم و به سیگنال G منتقل کنیم، باید تبدیل نوع انجام دهیم:

لزوم یکسان بودن نوع سیگنال‌ها در ارجاع جمع

طبق قانون ارجاع جمع، باید نوع تمامی سیگنال‌هایی که با هم جمع می‌شوند، با نوع سیگنال سمت چپ برابر باشد. بنابراین، مطابق کد زیر، باید نوع سیگنال J را به نوع بدون‌ علامت تغییر دهیم:

تبدیل نوع در ارجاع جمع در زبان VHDL

تبدیل نوع در ارجاع جمع در زبان VHDL

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

به طور کلی، اگر شما یک پورت را در بخش Entityی کد و یا یک سیگنال را در قسمت معرفی مربوط به بخش Architecture تعریف کنید، هیچ‌گاه ماهیت آن قابل تغییر نیست. وقتی از مسئله‌ی تبدیل نوع صحبت می‌کنیم، به این معنی است که صرفاً در هنگام ارجاع، نوع سیگنال تغییر می‌کند، تا قاعده‌ی زبان VHDL رعایت شود؛ به عبارت دیگر، هر سیگنالی با هر نوعی که تعریف شده باشد، برای همیشه در کد شما با همان نوع باقی خواهد ماند.

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

گروه دوم توابع تبدیل نوع در زبان VHDL: کاربرد در اشاره به اندیس داده‌های برداری

گروه دوم تبدیل نوع‌ها، تبدیل انواع unsigned و signed به integer است. این گروه از تبدیل‌ها در تعیین اندیس سیگنال‌های برداری کاربرد دارند.

فرض کنید همانند شکل زیر، یک سیگنال هشت‌بیتی به نام X و یک سیگنال تک‌بیتی به نام Y دارید.

می‌خواهید کدی بنویسید که در هر کلاک، یک بیت از سیگنال X را به سیگنال تک‌بیتی Y ارجاع دهد.

یعنی در کلاک اول، X(0) (یعنی بیت با اندیس صفر از X) به Y داده ارجاع داده شود؛ در کلاک دوم، X(1) به Y، در کلاک سوم، X(2) به Y و به همین ترتیب در کلاک هشتم X(7) به Y ارجاع داده شود و از کلاک نهم به بعد نیز همین روند تکرار شود.

رجیستر هشت‌بیتی X و رجیستر تک‌بیتی Y

رجیستر هشت‌بیتی X و رجیستر تک‌بیتی Y

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

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

بنابراین، مطابق کد ‏زیر، به کمک یک سیگنال سه‌بیتی از نوع unsigned به نام Counter، یک شمارنده ایجاد می‌کنم:

process(Clock) 
begin 
	if rising_edge(Clock) then 
		Counter <= Counter + 1; 
		Y <= X(Counter); 
	end if; 
end process;

در خط چهارم این کد، یک شمارنده تعریف کرده‌ام که به صورت free running از صفر تا هفت می‌شمارد و پس از رسیدن به مقدار هفت، دوباره صفر می‌شود.

از این شمارنده به عنوان اندیس یا آرگومان سیگنال X استفاده کرده‌ام.

بنابراین، در کلاک اول، X(0) به Y ارجاع داده می‌شود؛ در کلاک دوم X(1) به Y و در کلاک سوم X(2) به Y ارجاع داده می‌شود و این روند به همین ترتیب ادامه می‌یابد.

اما این کد دارای خطا است. دلیل آن چیست؟

دلیل آن این است که اندیس یا آرگومان سیگنال (یعنی همان مقداری که درون پرانتز می‌نویسیم) باید یک مقدار integer باشد.

برای مثال، وقتی اندیس را به صورت عددی مشخص می‌کردیم، آن را به صورت X(0) یا X(5) می‌نوشتیم؛ یعنی درون پرانتز یک عدد integer می‌نوشتیم.

سیگنال Counter به صورت یک سیگنال بدون‌ علامت تعریف شده است؛ زیرا همان‌طور که در مقاله‌ی "شمارنده چگونه می‌تواند مشکلات شما در پیاده‌سازی را حل کند؟" توضیح دادم، معمولاً Counter را به صورت بدون‌ علامت تعریف می‌کنیم.

برای آشنایی با نحوه پیاده‌سازی شمارنده و کاربردهای آن، این مقاله را مطالعه کنید...

بنابراین، در این کد باید نوع سیگنال Counter را از unsigned به integer تبدیل کنیم. پس به صورت کد زیر عمل می‌کنیم:

process(Clock) 
begin 
	if rising_edge(Clock) then 
		Counter <= Counter + 1; 
		Y <= X(to_integer(Counter)); 
	end if; 
end process;

در واقع، در کد بالا به کمک تابع ()to_integer، نوع سیگنال Counter را از unsigned به integer تبدیل کردیم.

توجه کنید که برای تبدیل یک سیگنال علامت‌دار به integer نیز از تابع ()to_integer استفاده می‌کنیم.

گروه سوم توابع تبدیل نوع در زبان VHDL: کاربرد در مقداردهی سیگنال‌ها

این گروه از تبدیل‌ها، تبدیل نوع integer به نوع بدون‌ علامت و علامت‌دار است؛ کابرد این تبدیل‌ها در مقداردهی سیگنال‌های علامت‌دار و بدون‌ علامت است.

اگر به شما گفته شود که یک سیگنال ۱۳‌بیتی بدون‌ علامت به نام X داریم و می‌خواهیم مقدار ۴۴ را به آن ارجاع دهیم، این مقداردهی را به چه صورت انجام می‌دهید؟

یک روش مقداردهی به صورت کد زیر است؛ یعنی عدد باینری معادل ۴۴ را بین دو علامت دابل‌کوتیشن (") می‌نویسیم:

X <= "0000000101100";

باید بدانید که این روش برای مقداردهی سیگنال، یک روش غیرحرفه‌ای است و کد را ناخوانا می‌کند.

زیرا در هر بار مقداردهی سیگنال، باید مقدار باینری معادل عدد را دستی و یا به کمک یک ماشین‌حساب محاسبه کنید و سپس این مقدار باینری را در کد تایپ کنید.

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

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

روش اصولی‌تر و حرفه‌ای‌تر برای مقداردهی سیگنال، استفاده از تبدیل نوع integer به unsigned به صورت زیر است:

X <= to_unsigned(44,13);

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

در واقع، تبدیل to_unsigned، یک عدد integer را به یک عدد بدون‌ علامت تبدیل می‌کند.

در این روش، عدد integer مورد نظرتان را درون پرانتز به صورت دسیمال می‌نویسید؛ سپس یک ویرگول قرار می‌دهید و پس از آن عرض بیت را می‌نویسید.

در این روش اگر نیاز به تغییر عدد ۴۴ داشتید، به راحتی و بدون نیاز به محاسبات باینری می‌توانید عدد جدید را جایگزین ۴۴ کنید.

ارجاع به این روش، بسیار خوانا و واضح است و با یک نگاه به آن، متوجه سه نکته می‌شوید:

  • مقدار ارجاع داده شده، عدد ۴۴ است.
  • سیگنال X یک سیگنال بدون‌ علامت است؛ زیرا از تبدیل to_ unsigned استفاده شده است.
  • سیگنال X یک سیگنال ۱۳‌بیتی است؛ زیرا تعداد بیت در آرگومان to_unsigned قید می‌شود.

حال، مثالی برای ارجاع یک عدد منفی را بررسی می‌کنیم؛ فرض کنید سیگنال Y یک سیگنال علامت‌دار و ۱۲‌بیتی است و می‌خواهیم مقدار ۲۹- را به آن ارجاع دهیم.

اگر تبدیل نوع integer به علامت‌دار را بلد نباشید، قاعدتاً ابتدا باید عدد باینری معادل مقدار ۲۹ را روی کاغذ بنویسید و مکمل دو آن را حساب کنید؛ این کار سخت و زمان‌بر است و کد را ناخوانا می‌کند.

از طرف دیگر، از آنجا که مقدار ۲۹- یک مقدار منفی است، با نگاه به کد باینری آن، نمی‌توانید به مقدار آن پی ببرید و حتماً باید مکمل دو آن را حساب کنید.

اما به کمک تبدیل to_signed، می‌توانید این کار را به راحتی انجام دهید.

چون سیگنال Y یک سیگنال علامت‌دار است، مطابق کد ‏زیر، از تبدیل to_signed به جای to_unsigned استفاده می‌کنیم:

Y <= to_signed(-29,12);

مشاهده می‌کنید که به سادگی، عدد ۲۹- را تایپ می‌کنیم و به کمک این تبدیل نوع، مقدار ۲۹- به صورت یک سیگنال علامت‌دار ۱۲بیتی و به فرم مکمل دو، به سیگنال Y ارجاع داده می‌شود.

بنابراین، توصیه می‌کنم از این پس برای ارجاع مقادیر به سیگنال‌ها حتماً از تبدیل‌های to_unsigned و to_signed استفاده کنید.

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

کاربرد مقداردهی به روش باینری

در برخی موارد، ارجاع به صورت باینری روش مناسب‌تری است.

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

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

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

هر سون‌سگمنت هشت LED دارد.

هر سون‌سگمنت هشت LED دارد.

بنابراین، هرگاه قصد ارجاع یک مقدار عددی به یک سیگنال را دارید، از تبدیل‌های to_unsigned و to_signed استفاده کنید و هرگاه مقداری که قصد ارجاع آن را دارید یک کد یا یک مقدار Logical است، بهتر است ارجاع را به صورت باینری انجام دهید.

کاربرد مقداردهی به روش هگزا دسیمال

برای مقداردهی سیگنال‌ها روش دیگری به نام روش هگزا دسیمال نیز وجود دارد.

شرط امکان انجام مقداردهی به این روش این است که عدد شما باید دارای عرض بیتی با مضرب چهار باشد؛ زیرا هر رقم هگزا دسیمال چهاربیتی است.

برای مثال، سیگنال Y یک سیگنال ۱۲بیتی است که برای ارجاع یک مقدار هگزا دسیمال به آن، مطابق کد زیر ابتدا حرف X را می‌نویسیم و سپس مقدار هگزا دسیمال را درون دو علامت دابل کوتیشن قرار می‌دهیم:

Y <= x”FE3”;

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

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

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

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

دو نکته‌ی بسیار مهم از مبحث تبدیل نوع در زبان VHDL

به عنوان آخرین مطلب این مقاله، به دو نکته‌ی بسیار مهم از مبحث تبدیل نوع در زبان VHDL می‌پردازم؛ این نکات بسیار مهم هستند و بسیاری از افراد در این زمینه ابهام دارند.

نکته‌ی اول این است که در هنگام تبدیل نوع، مقدار سیگنال تغییر نمی‌کند.

برای مثال، فرض کنید مطابق کد ‏زیر سیگنال C که یک سیگنال بدون‌ علامت چهار‌بیتی است (U4) را به سیگنال E که یک سیگنال علامت‌دار چهار‌بیتی است (S4)، ارجاع دهید.

فرض کنید که محتوای C برابر با مقدار ۱۰۰۱ است.

استفاده از تبدیل نوع در ارجاع ساده در زبان VHDL

استفاده از تبدیل نوع در ارجاع ساده در زبان VHDL

با توجه به این ‌که C از نوع بدون‌ علامت و E از نوع علامت‌دار است، باید از تبدیل نوع استفاده کنیم و سیگنال C را به یک سیگنال علامت‌دار تبدیل کرده و به E منتقل کنیم.

زمانی که C بدون‌ علامت است، مقدار ۱۰۰۱ را دارد که معادل با ۹+ است. باید به این موضوع دقت کنید که وقتی شما C را با عملیات تبدیل نوع، به E ارجاع می‌دهید، هیچ تغییری در محتوای C ایجاد نمی‌شود.

به عبارت دیگر، پس از این انتقال، درون سیگنال E نیز مقدار ۱۰۰۱ وجود دارد. آن چیزی که در سیگنال E تغییر می‌کند، تفسیر محتوای آن است.

هنگامی که ۱۰۰۱ در سیگنال C وجود داشت، به دلیل بدون علامت بودن این سیگنال، مقدار ۹+ از آن برداشت می‌شد.

اما وقتی که این عدد بدون هیچ تغییری در محتوا، به E منتقل می‌شود، با توجه به علامت‌دار بودن E، تفسیر دیگری از آن می‌شود. در این حالت، با توجه به اینکه مقدار موجود در یک سیگنال siged دارای نمایش مکمل دو است، بنابراین تفسیر ۱۰۰۱ در E، مقدار ۷- خواهد بود.

بنابراین، گرچه محتوای سیگنال هیچ تغییری نمی‌کند و در هر دو رجیستر C و E، محتوای سیگنال، ۱۰۰۱ است، اما تعبیر سیگنال متفاوت خواهد بود.

وقتی مقدار ۱۰۰۱ در سیگنال C است، به معنای عدد ۹+ است و وقتی که این مقدار در سیگنال E است، به معنای عدد ۷- است. حتماً به این نکته در پیاده‌سازی‌هایتان توجه داشته باشید.

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

فرض کنید می‌خواهید همانند کد زیر،‌ عدد B را در عدد C ضرب کنید و به رجیستر A منتقل کنید:

ارجاع ضرب در کد VHDL

ارجاع ضرب در کد VHDL

عدد B، نُه‌بیتی و از نوع علامت‌دار است (S9) و عدد C، چهار‌بیتی و از نوع بدون‌ علامت است (U4). عدد A نیز ۱۳‌بیتی و از نوع علامت‌دار است (S13).

ارجاع بالا، از نظر رعایت عرض بیت‌ها در قانون ارجاع ضرب، صحیح است؛ زیرا یک عدد نُه‌بیتی را در یک عدد چهار بیتی ضرب کرده‌ایم و مجموع نُه و چهار برابر ۱۳ می‌شود و رجیستر A نیز ۱۳‌بیتی است.

اما از نظر نوع‌ها، با توجه به این ‌که A و B از نوع علامت‌دار هستند، نوع C هم باید علامت‌دار باشد. بنابراین نوع C باید از بدون‌ علامت به علامت‌دار تغییر یابد.

با تغییر کد و انجام این تبدیل نوع مطابق کد زیر، کد شما از نظر نرم‌افزار خطایی نخواهد داشت؛ زیرا هر دو قانون ارجاع ضرب را رعایت کرده‌­اید.

 یک ارجاع به همراه تبدیل نوع در کد VHDL

یک ارجاع ضرب به همراه تبدیل نوع در کد VHDL

اما نتیجه این حاصل‌ضرب در بعضی از موارد می‌تواند اشتباه باشد.

برای مثال، اگر مقدار سیگنال C برابر ۱۰۰۱ باشد و آن را بدون علامت در نظر بگیریم، عدد ۱۰۰۱، بیانگر مقدار ۹+ است.

اما اگر C را علامت‌دار در نظر بگیریم، همانطور که در بالا هم اشاره شد، مقدار آن برابر ۷- در نظر گرفته خواهد شد.

به عبارت دیگر، شما با ضرب C در B در کد ‏بالا، انتظار داشتید که عدد ۹+ در B ضرب شود، اما به دلیل عملیات تبدیل نوع، به صورت ناخواسته سیگنال B را در عدد ۷- ضرب کرده‌اید و این مسئله در محاسبات و کار شما خطا ایجاد می‌کند.

راه‌حل جلوگیری از بروز این مشکل چیست؟

راه‌حل، بسیار ساده است؛ شما می‌توانید مطابق کد زیر، سیگنال C را با یک تک‌بیت صفر، concat کنید:

در تبدیل اعداد بدون علامت به علامت‌دار یک صفر را با عدد concat می‌کنیم تا محاسبات به‌طور صحیح انجام شوند.

در تبدیل اعداد بدون علامت به علامت‌دار یک صفر را با عدد concat می‌کنیم تا محاسبات به‌طور صحیح انجام شوند.

اگر سیگنال C را با یک تک‌بیت صفر، concat کنید، همواره در سنگین‌ترین بیت سیگنال C یک "صفر" وجود دارد. وقتی سنگین‌ترین بیت یک عدد صفر باشد، در هر دو حالت علامت‌دار و بدون‌ علامت، مقدارش یکسان است.

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

در تبدیل نوع اعداد بدون علامت به علامت‌دار در ارجاعات جمع و ضرب، به کمک عملیات concat کردن، یک صفر به سمت چپ عدد اضافه می‌کنیم تا با تبدیل نوع، تفسیر عدد تغییر نکند و محاسبات به‌ صورت صحیح انجام شوند؛ زیرا وقتی سنگین‌ترین بیت یک عدد صفر باشد، مقدارش در هر دو حالت علامت‌دار و بدون‌ علامت یکسان است.

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

بنابراین، برای صحیح بودن عرض بیت‌ها از دیدگاه قانون ارجاع ضرب باید عرض بیت سیگنال A را از ۱۳‌بیت به ۱۴‌بیت افزایش دهیم:

برقراری قانون ارجاع در زبان VHDL از نظر نوع داده و عرض بیت سیگنال‌ها

برقراری قانون ارجاع در زبان VHDL از نظر نوع داده و عرض بیت سیگنال‌ها

این موضوع به خصوص در پیاده‌سازی الگوریتم‌های پردازش سیگنال‌های دیجیتال با FPGA که با چنین محاسباتی زیاد سروکار دارید بسیار مهم است؛ زیرا در این الگوریتم‌ها، محاسبات پیچیده و متنوع ریاضی بیشتری دیده می‌شود.

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

این مقاله، برگرفته از دوره طراحی دیجیتال با FPGA بود.

برای اطلاع از جزئیات این دوره، روی دکمه زیر کلیک کنید:

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

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

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

نویسنده: فاطمه مشاک

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

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

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

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

>