مقدمه
تا الان این CPU که در این پست نوشته ایم از کدهای دستوری BSF، BCF، GOTO و NOP پشتیبانی می کند، حالا زمان ایجاد رجیستر W و نوشتن کد های دستوری برای کنترل آن و راه اندازی console برای نمایش پیام های می باشد.
رجیستر W چیست
رجیستر W یک رجیستر عمومی است که می توان آن را با هر عددی مقدار دهی کرد، یا مقدار آن را به آدرس دیگر انتقال داد، و هربار مقدار جدیدی که به این رجیستر داده می شود جای مقدار قبلی را می گیرد.
اضافه کردن opcode های جدید به اسمبلر
حالا opcode های زیر را به Assembler اضافه می کنیم: که سه دستور اول مربوط به رجیستر W می باشند.
- MOVLW
- MOVWF
- CLRW
- CLRF
- SLEEP
دستور MOVLW
این دستور مقدار عددی داده شده (از 0 تا 255) را در رجیستر W قرار می دهد:
در MOVLW چهار بیت اول بیانگر opcode مربوط به دستور و هشت بیت بعدی برای مقدار دستور می باشند.
مثال: MOVLW 55 که مقدار 55 را در رجیستر W ذخیره می کند
دستور MOVWF
این دستور مقدار رجیستر W را در آدرس داده شده قرار می دهد (در این CPU ما 10 آدرس برای رجیستر و 16 آدرس برای RAM در دسترس داریم)
در این کد 5 بیت از سمت راست بیانگر آدرس داده شده می باشد
مثال: MOVWF 06H که مقدار رجیستر W را در آدرس 06H به صورت هگز (برابر با 0x06) قرار می دهد، که رجیستر 6 مربوط به ورودی / خروجی ها می باشد.
دستور CLRW
این دستور برای پاک کردن (برابر با 0 قرار دادن) مقدار رجیستر W می باشد
این دستور همانند NOP می باشد و عملوندی ندارد و به صورت یکتا استفاده می شود و opcode آن همیشه ثابت است.
مثال: CLRW که مقدار رجیستر W را برابر با 0 قرار می دهد
دستور CLRF
این دستور مقدار آدرس داده شده را پاک می کند (برابر با 0 قرار می دهد).
در این دستور 5 بیت از سمت راست بیانگر آدرس داده شده می باشند و 7 بیت آخر برای opcode مربوط به دستور
مثال: CLRF 06H که مقدار آدرس 6 (پایه ورودی / خروجی CPU) را برابر با 0 قرار می دهد.
دستور SLEEP
این دستور CPU را به حالت خواب می برد و بعد از آن اتفاقی در CPU نمی افتد و PC یا شمارنده داخل CPU تغییری نمی کند و برای خروج از این حالت، نیاز هست که CPU را ریست (reset) کنیم.
این دستور نیز مانند CLRW و NOP دارای کد دستوری 12 بیتی و همیشه ثابتی می باشد و عملوندی ندارد.
مثال: SLEEP که CPU را به حالت خواب می برد.
اضافه کردن دستور ها به CPU
بعد از مشخص شدن دستور ها برای assembler حالا زمان اضافه کردن آنها به CPU و تشخیص و اجرای آنها می باشد، قبلا بخش های مربوط به اضافه کردن دستورها را در پست که مربوط به CPU و پست مربوط به Wokwi گفته شده، حالا با تغییر و اضافه کردن کدهای آخرین پست، کدها را به CPU اضافه می کنیم.
اول از همه enum مربوط به opcode ها را آپدیت می کنیم و دستورات جدید را به آنها اضافه می کنیم:
از خط های 6 تا 10 دستور های جدید می باشند
حالا تابع decode_inst را آپدیت میکنیم، که بخش تشخیص دستورا ها را دارد:
کد بالا مربوط به بخش تشخیص opcode ها برای CPU می باشد که به تابع decode_inst اضافه شده است، و با توجه به هر opcode اطلاعات مربوط به صورت یک structure بازگردانده می شوند که برای بخش اجرا شدن مفید می باشند.
بعد از این کار زمان تغییر تابع soft_execute است، و دستور SLEEP را به آن اضافه می کنیم:
کد مربوط به SLEEP از خط های 11 تا 13 می باشد.
کد زیر مربوط به حلقه اصلی CPU می باشد:
دستور SLEEP یکی دیگر از دستور هایی می باشد که تاثیری در حافظه نمی گذارد، حالا با تغییر حلقه اصلی بخش مربوط به اجرای دستور SLEEP را اضافه می کنیم:
در کد بالا در صورتی که دستور SLEEP تشخیص داده شد و در نهایت در soft_execute مشخص شد دیگر شمارنده برنامه (PC) تغییری نمی کند و دستوری اجرا نمی شود (CPU به حالت “خواب” می رود)
بعد از اینکار زمان تغییر تابع execute می باشد اما اول نیاز است که توابع مربوط به رجیستر W را بنویسم:
در خط 1 متغیری برای رجیستر W مشخص شده و در خط های 4 و 9 دو تابع برای گرفتن مقدار رجیستر W و قراردادن مقداری برای آن وجود دارند (دلیل این که از این توابع برای این کار استفاده می کنیم این است که به خوانایی کد کمک می کند و می توان این متغیر ها را در فایلی دیگر قرار داد).
تغییرات تابع execute به صورت زیر می باشد:
با استفاده از کد بالا دستور های جدید با استفاده از آدرس و یا بیت های گرفته شده اجرا می شوند و memory مربوط به CPU آپدیت می شود
راه اندازی Console
قبل از راه اندازی console اول باید ببینیم که نحوه کار آن چگونه می باشد:
کنسول با استفاده از خروجی GPIO یا رجیستر 6 کار می کند، هنگامی که بیت 8 ام (شروع از 1) پایه برابر با 1 می شود، وظیفه emulator می باشد که 7 بیت قبلی را تبدیل به کاراکتر کند (مقدار عددی کاراکتر) و پس از آن می توان آن کاراکتر را به printf و “c%” در خروجی چاپ کرد:
چاپ کردن Hello World با استفاده از Console
تا الان با نحوه کارکرد کنسول آشنا شده ایم، حالا برنامه ای می نویسیم که با استفاده از آن پیام “Hello, World” را در console چاپ کنیم.
برای این کار از opcode های جدیدی که مشخص کرده ایم استفاده می کنیم، هر حرف به صورت زیر نوشته می شود:
- در خط 1 مقدار عددی حرف H را به رجیستر W می دهیم
- در خط 2 مقدار رجیستر W را به پایه 6 (GPIO) که برای ورودی خروجی می باشد، می دهیم و console نیز از این پایه استفاده می کند
- در خط 3 با استفاده از دستور BSF بیت 8 ام (شروع از 0) را برابر با 1 قرار می دهیم، به صورت کلی قرار گرفتن این بیت به console می گوید که کاراکتر را چاپ کن
حالا این کار را برای تمام حروف ها انجام می دهیم و نتیجه به صورت زیر می شود:
برای دریافت برنامه assembly از این لینک استفاده کنید:
https://github.com/Empitrix/assembler/blob/master/examples/hello.asm
برای دیدن دستور های مربوط به assembler:
https://github.com/Empitrix/assembler
برای دیدن دستور های مربوط به CPU (میکروکنترلر):