چرا دستورات سختافزاری ساده نگه داشته میشوند
یک پردازنده عبارات غنی و بیانگر را آنطور که یک زبان برنامهنویسی قابلفهم برای انسان دارد، نمیفهمد. در عوض، واژگانی کوچک و ثابت از عملیاتهای بسیار ساده را اجرا میکند، که در مجموع 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 قرار میدهد.
چرا این تمایز برای کارایی اهمیت دارد
دسترسی به یک رجیستر زمان بسیار کمتری نسبت به دسترسی به حافظه میبرد. بهدلیل این شکاف، یکی از وظایف اصلی هم کامپایلرها و هم برنامهنویسانی که کد حساس به کارایی مینویسند، به حداقل رساندن جابهجایی غیرضروری داده بین حافظه و رجیسترهاست، و نگهداشتن مقادیر پراستفاده در رجیسترها تا حد امکان.