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

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

مجموعه دستوراتعملیات‌های ماشینرجیسترها و عملوندها

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

چرا دستورات سخت‌افزاری ساده نگه داشته می‌شوند

یک پردازنده عبارات غنی و بیانگر را آن‌طور که یک زبان برنامه‌نویسی قابل‌فهم برای انسان دارد، نمی‌فهمد. در عوض، واژگانی کوچک و ثابت از عملیات‌های بسیار ساده را اجرا می‌کند، که در مجموع Instruction Set نامیده می‌شود. کوچک و منظم نگه‌داشتن این مجموعه، سخت‌افزاری که دستورات را decode و اجرا می‌کند را ساده‌تر، ارزان‌تر و سریع‌تر برای ساخت می‌کند.

این اصل ارتباط نزدیکی با فلسفه پشت طراحی‌های RISC (Reduced Instruction Set Computer) مانند RISC-V دارد، جایی که هر دستور یک عمل کاملاً مشخص انجام می‌دهد به‌جای ترکیب چند عملیات در یک دستور پیچیده واحد.

عملیات‌های اصلی که یک پردازنده انجام می‌دهد

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

  • Arithmetic Operations مانند جمع و تفریق، که مقادیر عددی را مستقیماً دستکاری می‌کنند.
  • Data Transfer Operations، که مقادیر را بین حافظه و ذخیره‌سازی داخلی سریع پردازنده جابه‌جا می‌کنند.
  • Logical Operations، که بیت‌های تکی را دستکاری می‌کنند.
  • Conditional Operations، که جریان معمولی و پی‌درپی اجرا را بر اساس یک مقایسه تغییر می‌دهند.

یک دستور جمع نماینده در اسمبلی RISC-V به این شکل است:

add a, b, c

این یک خط به سخت‌افزار دستور می‌دهد مقادیر نگه‌داشته‌شده در b و c را جمع کند، سپس نتیجه را در a قرار دهد. توجه کنید که این دستور همیشه دقیقاً یک عملیات و تعداد ثابت و کمی عملوند مشخص می‌کند — این نظم عمدی است و یکی از هشت ایده اصلی طراحی است که پیش‌تر در این مجموعه بررسی شد.

عملوندها کجا زندگی می‌کنند: رجیسترها و حافظه

یک دستور به جایی برای خواندن مقادیر ورودی خود و جایی برای نوشتن نتیجه‌اش نیاز دارد. این مکان‌ها Operands نامیده می‌شوند، و سخت‌افزار دو مکان بسیار متفاوت برای ذخیره آن‌ها فراهم می‌کند.

رجیسترها: ذخیره‌سازی سریع اما محدود

Registers مکان‌های ذخیره‌سازی کوچکی هستند که مستقیماً داخل پردازنده ساخته شده‌اند. دسترسی به آن‌ها بسیار سریع است اما تعدادشان محدود است — یک پردازنده RISC-V، برای مثال، دقیقاً ۳۲ رجیستر همه‌منظوره فراهم می‌کند. چون تعداد رجیسترها این‌قدر کم است، یک کامپایلر باید با دقت تصمیم بگیرد کدام مقادیر در هر لحظه شایسته اشغال این ذخیره‌سازی سریع هستند.

حافظه: ذخیره‌سازی بزرگ اما کندتر

وقتی یک برنامه نیاز دارد با داده‌ای بیشتر از آنچه رجیسترهای موجود می‌توانند نگه دارند کار کند — مانند یک آرایه کامل — آن داده به‌جای آن در Memory نگه داشته می‌شود. حافظه به‌صورت یک آرایه بزرگ از Bytes قابل‌آدرس‌دهی جداگانه سازمان‌دهی شده است، و جابه‌جایی داده بین حافظه و رجیسترها نیازمند دستورات صریح انتقال داده است.

یک دستور معمول که یک مقدار را از حافظه به یک رجیستر بارگذاری می‌کند به این شکل است:

ld a, offset(b)

در اینجا، پردازنده یک آدرس حافظه را با افزودن یک آفست ثابت به آدرس ذخیره‌شده در رجیستر b محاسبه می‌کند، مقدار ذخیره‌شده در آن آدرس حافظه را بازیابی می‌کند، و آن را در رجیستر a قرار می‌دهد.

چرا این تمایز برای کارایی اهمیت دارد

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

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

مقالات مرتبط

سخت‌افزار چگونه تقسیم انجام می‌دهد: خارج‌قسمت، باقیمانده و موارد خاص

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

ادامه

سخت‌افزار چگونه اعداد را ضرب می‌کند: از منطق ساده تا مدارهای واقعی

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

ادامه

سخت‌افزار چگونه جمع و تفریق انجام می‌دهد و سرریز را تشخیص می‌دهد

سخت‌افزار چگونه جمع و تفریق انجام می‌دهد و سرریز را تشخیص می‌دهد

ادامه

آرایه‌ها در مقابل اشاره‌گرها در سطح سخت‌افزار

در C، آرایه‌ها و اشاره‌گرها اغلب قابل‌تعویض به‌نظر می‌رسند، و بسیاری از برنامه‌نویسان با آن‌ها به‌عنوان یک چیز واحد رفتار می‌کنند. با این حال در سطح سخت‌افزار، آن‌ها به توالی‌های دستوری قابل‌توجهی متفاوت با ویژگی‌های کارایی متفاوت کامپایل می‌شوند. این مقاله این دو رویکرد را با استفاده از اسمبلی RISC-V مقایسه می‌کند تا دقیقاً نشان دهد چرا کد مبتنی بر اشاره‌گر اغلب سریع‌تر است.

ادامه

از کد منبع تا یک فرآیند در حال اجرا: ترجمه و یک مثال کامل مرتب‌سازی

تبدیل یک برنامه C به چیزی که سیستم‌عامل واقعاً بتواند اجرا کند شامل چندین مرحله ترجمه مجزاست، که هرکدام یک فایل میانی متفاوت تولید می‌کنند. این مقاله کل این خط لوله را از کامپایلر تا loader مرور می‌کند، سپس مفاهیم این فصل را روی یک مثال کامل و واقعی به‌کار می‌برد: ترجمه گام‌به‌گام یک روال مرتب‌سازی C به اسمبلی RISC-V.

ادامه

مدیریت آدرس‌های بزرگ و همگام‌سازی در RISC-V

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

ادامه