حمیدرضا کلباسی
حمیدرضا کلباسی
خواندن ۶ دقیقه·۶ سال پیش

بیایید یک کامپیوتر بسازیم ( قسمت چهارم: ALU )

در قسمت قبل با نحوه ساخت رجیستر ها آشنا شدیم. در این قسمت واحد منطق ریاضی ( arithmetic logic unit ) را می سازیم.

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

کامپیوتر ما نیز می تواند ضرب و تقسیم و هر کار محاسبه پذیری را انجام دهد ( بدون در نظر گرفتن محدودیت رم ) اگر برنامه آن را به کامپیوتر بدهیم، اما اگر این کار به صورت سخت افزاری توسط ALU انجام شود، در مقدار ثابتی از از زمان انجام می شود ( به عبارت دیگر O(1) واحد طول می کشد. ) اما اگر توسط برنامه انجام شود مقداری که طول می کشد به الگوریتم ما بستگی دارد و ممکن است با بزرگ شدن اعداد ورودی، زمان بیشتری برای محاسبه طول بکشد و زمان اجرا به ورودی بستگی داشته باشد. مثلا اگر شما برنامه ای بنویسید که با فراخوانی ALU ضرب را حساب کند، اجرا شدن برنامه تان مستقل از اعداد ورودی مثلا ده کلاک طول می کشد؛ اما اگر همین کار را به این صورت انجام دهید که تا زمانی که عدد اول ۰ نیست، متغیری را با عدد دوم جمع کنید و از عدد اول یک واحد کم کنید، این کار مثلا دو برابر عدد اول کلاک طول می کشد.

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

اعداد چگونه در کامپیوتر نگه داشته می شود؟

در قسمت قبل گفتیم که رجیستر های آ و ب می توانند ۸ بیت داده را ذخیره کنند. اما چگونه به این ۸ بیت به عنوان یک عدد نگاه کنیم؟ مثلا یک روش می تواند این باشد که تعداد بیت های با ولتاژ بالا یا ۱ را به عنوان عدد متناظر با آن نگاه کنیم، مثلا عدد ۱۰۰۱۱۰۰۰ برابر ۳ می شود. این گونه می توانیم یک عدد از ۰ تا ۹ را درون ۸ بیت ذخیره کنیم.

اما روش بالا بهینه نیست، زیرا اعداد نمایش های تکراری دارند. مثلا ۰۱۱۰۰۰۰۰ و ۰۰۱۰۰۰۱۰ هر دو نمایش دهنده عدد ۲ هستند. به وسیله نمایش اعداد در مبنای دو، می توان 256 عدد مختلف را نمایش داد. ( ابتدا می خواستم مبنای دو را در این نوشته توضیح دهم، اما به این نتیجه رسیدم که اگر ویکی‌پدیا را تر و تمیز کنم افراد بیشتری از آن استفاده می کنند، پس اگر نمی دانید مبنای دو چیست، لینک را ببینید ).

جمع

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

مدار جمع کننده کامل ( Full Adder )
مدار جمع کننده کامل ( Full Adder )

در مدار بالا A و B دو رقمی هستند که می خواهیم جمع بزنیم، Cin رقم حمل شده یا دو بر یک است، S نتیجه و Cout مقداری است که باید به جایگاه بعدی حمل شود. با ترکیب n نسخه از این مدار، می توان یک جمع کننده n بیتی ساخت که دو عدد n رقمی را جمع بزند.

این مدار دو عدد ۴ بیتی A و B را جمع زده و آن را به عنوان S خروجی می دهد
این مدار دو عدد ۴ بیتی A و B را جمع زده و آن را به عنوان S خروجی می دهد


تفریق

تفریق اگرچه ظاهرا با جمع بسیار تفاوت دارد، اما می توانیم از همان مدار جمع برای تفریق نیز استفاده کنیم. با کمی دقت در می یابیم که مدار جمع ما برای اعداد بزرگ به درستی کار نمی کند. اگر جمع دو عدد بزرگ تر از محدوده اعداد ما باشد ( در کامپیوتر ۸ بیتی ما ۲۵۶ و در کامپیوتر ۶۴ بیتی شما چیزی در حدود هیجده میلیارد میلیارد ) مقدار حمل شده توسط مدار آخر یک می شود، اما از آن استفاده ای نمی شود و مقدار آن از دست می رود. مثلا اگر ما در کامپیوترمان ۲۵۰ را با ۱۰ جمع بزنیم، جواب ۴ می شود! به این اتفاق overflow می گویند.

مدار ما در حقیقت دو عدد را جمع نمی زند، بلکه آن ها را جمع می زند و سپس نتیجه را به پیمانه محدوده ( در این جا ۲۵۶ ) اعلام می کند. از این خاصیت پیمانه ای می توانیم برای عمل تفریق استفاده کنیم.

می دانیم:

a - b = a - b + p = a + ( p - b ) ( mod p )

پس می توانیم به جای تفریق دو عدد، اولی را با ۲۵۶ منهای دومی جمع بزنیم. اما چگونه ۲۵۶ منهای یک عدد را در مبنای دو حساب کنیم؟ ساده است. اگر تمام بیت های یک عدد هشت بیتی را برعکس کنیم، برابر ۲۵۵ منهای آن عدد می شود ( درستی را خودتان بررسی کنید ) سپس این عدد را با یک جمع می زنیم و ۲۵۶ منهای آن به دست می آید.

توجه کنید که اگر نتیجه مثبت باشد تفریق ما درست کار می کند اما اگر منفی باشد، نتیجه یک عدد مثبت بزرگ خواهد بود؛ زیرا کامپیوتر ما از اعداد منفی پشتیبانی نمی کند :) . اما اگر علاقه مندید که اعداد منفی در کامپیوتر چگونه پشتیبانی می شود، روش مکمل دو را ببینید.

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

پیاده سازی

مدار ALU
مدار ALU


در این جا ورودی های A و B به طور مستقیم مقدار رجیستر های آ و ب را به واحد ریاضی منتقل می کند. پین SU که از واحد کنترل می آید، تعیین می کند که باید جمع زده شود یا تفریق انجام شود ( ولتاژ زیاد برابر تفریق است ) . قطعه های 74LS283 یک جمع زننده چهار بیتی هستند که با ترکیب دو تا از آن ها یک جمع زننده ۸ بیتی ساخته ایم. SU با تمام بیت های B ایکس اور گرفته می شود تا اگر در حالت تفریق بودیم، تمام بیت های B برعکس شوند و به ورودی حمل کردن در جمع زننده وصل می شود تا در حالت منها جواب به اضافه یک شود. ورودی EO نیز کنترل می کند که جواب در باس نوشته شود یا خیر. این ورودی نیز توسط مدار کنترل تعیین می شود.

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


جمعریاضی
شاید از این پست‌ها خوشتان بیاید