عملیات‌های منطقی و دستورات تصمیم‌گیری در RISC-V

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

عملیات‌های منطقیشاخه‌زنی شرطیدستورات بیتی

~3 دقیقه مطالعه · آخرین به‌روزرسانی ۱۵ شهریور ۱۴۰۵

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

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

  • AND در هر موقعیت بیتی فقط جایی که هر دو عملوند ۱ داشته باشند، ۱ تولید می‌کند، که معمولاً برای پاک کردن بیت‌های خاص استفاده می‌شود، عملیاتی به نام Masking.
  • OR در هر موقعیت بیتی که حداقل یک عملوند ۱ داشته باشد، ۱ تولید می‌کند، که معمولاً برای تنظیم بیت‌های خاص استفاده می‌شود.
  • Shift Left (sll) و Shift Right (srl) همه بیت‌های یک مقدار را به تعداد ثابتی موقعیت جابه‌جا می‌کنند، که همچنین روشی کارآمد برای ضرب یا تقسیم بر توان‌های دو است.

مثالی از یک دستور AND منطقی در اسمبلی RISC-V:

and a, b, c

این دستور یک AND بیتی بین مقادیر رجیسترهای b و c انجام می‌دهد و نتیجه را در a ذخیره می‌کند.

تصمیم‌گیری: شاخه‌زنی در سطح سخت‌افزار چگونه کار می‌کند

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

دو دستور شاخه‌زنی بنیادین در RISC-V، مستقیماً دو مقدار رجیستر را مقایسه می‌کنند:

beq a, b, Label
bne a, b, Label

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

ساخت حلقه‌ها و دستورات if از شاخه‌ها

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

مثال: یک دستور if سطح بالای ساده و ترجمه مفهومی آن:

سطح بالا:
if (i == j) f = g + h;

مفهوم ترجمه‌شده:
bne i, j, Exit
add f, g, h
Exit:

در اینجا، اگر i و j برابر نباشند، اجرا مستقیماً از روی جمع عبور کرده و به برچسب Exit می‌پرد و آن را نادیده می‌گیرد. اگر برابر باشند، شاخه گرفته نمی‌شود و جمع به‌طور معمول اجرا می‌شود.

پرش‌های بدون‌شرط

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

چرا این مجموعه کوچک از دستورات کافی است

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

نوشته و پژوهش‌شده توسط دکتر شاهین صیامی

مقالات مرتبط

کامپیوترها چگونه اعداد را نمایش می‌دهند و دستورات را به باینری کدگذاری می‌کنند

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

ادامه

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

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

ادامه

دیوار توان و گذار به سمت پردازنده‌های چندهسته‌ای

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

ادامه

درون ماشین: اجزای سخت‌افزاری، فناوری ساخت تراشه و سنجش سرعت

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

ادامه

از کد تا اجرا: اصولی که پشت معماری کامپیوترها قرار دارند

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

ادامه