باتوجهبه زمان زیادی که از انتشار دو قسمت قبل آموزش RTOS گذشته است، توصیه میکنم قسمتهای قبل مقاله رو بخوانید حتی به شکل مرور تیتروار(آشنایی با مفهوم چندوظیفهگی)! در قسمت قبلی همونطورکه از عنوان نوشته برمیآید، توضیحدادیم که چندوظیفهگی چطور میتواند توی خردکردن یک پروژه بزرگ به بخشهای کوچک به ما کمک کنه و چطور میتواند با مدیریت منابع باعث سادگی در ساختار کد شود، اما سوال اساسی که مطرح میشود این است که چطور باید چند وظیفه مختلف را به یک پردازنده(CPU) بسپاریم؟ مگر این نیست که تمام پردازندهها تنها یک نقطه شروع بعداز ریست دارند پس چطور میتوان چند کار مختلف را به یک پردازنده سپرد! در این قسمت مقاله سعی میکنیم به این سوال کلیدی پاسخ بدهیم، با ما همراه باشید.
آشنایی با ساختار CPU
برای اینکه بتوانیم یک سیستمعامل را پیادهسازی کنیم، لازماست وارد جزییات سختافزاری شویم، جزییاتی در حد رجیسترهای cpu و ساختار و نحوه عملکرد آن! درواقع تا مادامی که نتوانیم درککنیم cpu برای اجرای برنامه از چه الگویی پیروی میکند نخواهیم توانست عملکرد سیستمعامل را درک کنیم. همانطورکه احتمالا میدانید cpu برای اینکه بتواند دستورات را اجرا کند لازماست آنها را از محلی بخواند، بسته به ساختار سختافزار این محل میتواند حافطه RAM یا flash یا دیسک یا هر نوع حافظه دیگری باشد اما نکتهای که در این گفتمان وجود دارد این که است که cpu چگونه میتواند بفهمد تا کجای برنامه را خواندهاست؟
رجیستر PC
برای این کار رجیستر منحصربهفردی در cpu وجود دارد که وظیفه آن شمارش دستورات خواندهشدهاست یا بهصورت دقیقتر وظیفه آن نگهداری آدرسی است که قرار است دستور بعدی از آنجا خواندهشود. احتمالا شنیدهباشید که فلان cpu قادر به آدرسدهی فلان مقدار حافظه است، این گفته دقیقا اشاره به تعداد بیتهای درنظرگرفتهشده برای این رجیستر دارد. برای مثال وقتی میگوییم که میکروکنترلر AVR قادر به آدرس دهی ۶۴کیلوبایت حافظه است یعنی رجیستر شمارنده برنامه ۱۶ بیت است و یا وقتی میگوییم که میکروکنترلر ARM قادر به آدرسدهی ۴ گیگابایت حافظه است یعنی طول این رجیستر در این مدل میکروکنترلر ۳۲ بیت است(البته با ملاحظاتی که بعدا به آن اشارهخواهیمکرد). احتمالا حدسزدهاید که اسم اختصاری این رجیستر PC است به معنی program counter و احتمالا بهوفور با آن در عکسها و شماتیکالهای CPU برخوردکردهباشید.
بعداز ریست، این رجیستر با مقدار صفر بارگذاری میشود و پردازنده با مراجعه به آدرس صفر حافظه(دقتداشتهباشید این آدرس میتواند مقدار دیگری هم باشد) سعی در واکشی و اجرای دستورات اسمبلی دارد. بعداز واکشی و اجرای اولین دستور مقدار این رجیستر اضافه میشود تا دستور بعد را اجرا کند این روند تا وقتی که رجیستر سرریز کند ادامه پیدا میکند. اما چرا برنامههای کوچکتر از مقدار آدرسدهی PC میتوانند به خوبی و بدون مشکل اجرا شوند؟ بگذارید کمی واضحتر سوال را مطرحکنیم. فرضکنید برنامه چشمکزن در میکروکنترلر AVR نیاز به ۲۰ دستور اسمبلی دارد درحالیکه PC برای سرریزشدن باید ۶۴هزار دستور را اجرا کند! پس چه میشود که برنامههای کوچک بدون مشکل اجرا میشوند؟ جواب سوال ساده است، دستوراتی وجود دارند که میتوانند مقدار PC را برنامهریزی و طی برقراربودن یا نبودن شرایط خاصی، آدرس دلخواهی را در آن بارگذاری کنند. این دقیقا همان اتفاقی است که درهنگام استفادهاز شرطها در برنامهنویسی میافتد یا هنگام صدازدن یک فانکشن خاص.
رجیستر Link
همانطورکه در بخش قبل گفتیم دستوراتی وجود دارند که قادر هستند کنترل برنامه(PC) رو به آدرس دیگری منتقل کنند، وجود این دستورات برای پیادهسازی ساختارهای شرطی، اساسی و لازم هستند اما فکر کنید قصد داشتهباشیم در برنامه یک تابع را فراخوانی کنیم! اکنون چکار باید کرد؟ اگر از دستورات شرطی معمولی استفادهکنیم کنترل برنامه به محل تابع منتقل میشود و بعداز اینکه دستورات تابع اجرا شد باید به آدرس قبلی برگردد اما چطور این اتفاق میافتد؟ در استفادهاز دستورات پرش شرطی این اتفاق نمی افتد! چرا که آدرس جاری برنامه در جایی ذخیره نمیشود. اما دستورهایی وجود دارند که هنگام پرش، آدرس جاری را در رجیستری تحتعنوان رجیستر LINK ذخیره میکنند تا بعداز اتمام کار تابع این آدرس در رجیستر PC قرار بگیرد و کنترل برنامه به محل قبل بازگردانده شود(منظور یک دستور بعداز آدرس پرش است). رجیستر لینک بعداز رجیستر PC یکیاز کلیدیترین رجیسترهای هر پردازندهای است چرا که برنامهنویسی به شکلزیر برنامه را در اختیار ما قرار میدهد و همه خوب میدانیم که این شکل از برنامهنویسی چقدر میتواند برنامهنویسی را ساده کند.
رجیستر SP
بعداز رجیسترهای PC و Link یکیدیگر از رجیسترهای مهم CPU رجیستر SP که مخفف stack pointer است. کار این رجیستر درواقع نگهداری آدرس stack است. اما استک چیست و به چه دردی میخورد؟ استک داخل ram پردازنده تعریف میشود و کار آن این است که متغییرهای محلی را در خودش ذخیرهکند! خوب این یعنیچی! وقتی شما تابعی مینویسید و داخل تابع یک متغییر ایجاد میکنید، چون متغییر قرار نیست در دسترس همه قرار بگیرد و احتمالا چون بعداز اتمام تابع باید ازبین برود! بهجای اینکه داخل رم اصلی قرار بگیرد، داخل استک قرار میگیرد! یا فرضکنید وقتی تابعی را داخل تایع دیگری صدا میزنیم چطور باید آدرس برگشت را ذخیرهکنیم؟ مگر نه اینکه تنها یک رجیستر LINK وجود دارد؟! قبلاز صدازدن تابع جدید میتوانیم مقدار رجیستر لینک را داخل استک ذخیرهکنیم! و به این شکل موقع برگشت از تابعی که صدا زدهایم مقدار رجیستر LINK را بازیابی کنیم. تمام توضیحات بالا مربوط به استک بود، و اما رجیستر sp رجیستری است داخل cpu که به محل استک اشاره میکند. تنها نکتهای که باید به آن توجهداشت این است که با اضافهشدن مقدار استک مقدار sp کاهش پیدا میکند، چراکه همیشه استک از انتهای رم شروع به پرشدن میکند. برای همین آدرس آن باید با ذخیره متغییر داخل آن کاهش پیدا کند. درمورد استک احتمالا در قسمتهای آینده بیشتر صحبتخواهیمکرد چرا که یکیاز مفاهیم مهم برنامهنویسی است و البته برای مدیریت وظیفهها در سیستمعامل زیاد با آن سروکار پیداخواهیمکرد.
رجیستر وضعیت
این رجیسترها معمولا برای انجام پرشهای شرطی و پردازش حالتهای خاص مورداستفاده قرار میگیرند! و بااستفادهاز آنها قادر به پیادهسازی انواع شرطهای پیچیده هستیم البته در محاسبات ریاضی نیز میتوانند کاربرد داشته باشند که زیاد موردبحثما نیست.
رجیسترهای عمومی
این رجیسترها که معمولا تعداد زیادی هم دارند میتوانند برای انجام انواع عملیات مورداستفاده قرار بگیرند و دقیقا همانند اسم خود کاربرد عمومی دارند. باتوجهبه اینکه رجیسترهای موجود در میکروکنترلرهای ARM و البته مدیریت آنها در مقایسه با پردازندههای جنرال متفاوت است در قسمت بعد به بررسی رجیسترهای Cortex-M3 و حالتهای خاص آنها خواهیمپرداخت.
منبع: سیسوگ