آموزش اسمبلی
هزینه 5 هزار تومان
هزینه 5 هزار تومان
هر برنامه شامل يک يا چند سگمنت است. هنگامی که برنامه دارد اجرا می شود ثبات های سگمنت به سگمنت های جاری اشاره می کنند. چهار سگمنت را در آن واحد می توان داشت؛ کد، داده، پشته و اضافی. در مد حقيقی هر سگمنت حداکثر 64KB است. البته معمولا برنامه ها کمتر از 64KB را استفاده می کنند. اسمبلر اندازه سگمنت را بر اساس تعداد بايت های مورد استفاده سگمنت تنظيم می کند. بنابراين اگر برنامه ای برای نمونه تنها 10KB برای ذخيره داده نياز دارد سگمنت داده 10KB می شود نه 64KB.
برنامه های .exe سه سگمنت اول را بايد داشته باشند.
• سگمنت داده برای ذخيره متغيرهاست. آدرس متغيرها به صورت
آفستی از شروع اين سگمنت محاسبه می شوند.
• سگمنت کد شامل دستورالعمل های اجرائی برنامه است.
• سگمنت پشته برای نگهداری داده های موقتی و آدرس های برگشتی از برنامه پشته رزرو
می شود. آدرس های پشته به صورت آفستی از ابتدای اين سگمنت محاسبه می شوند.
وقتی اجرای برنامه آغاز می شود سيستم عامل دو ثبات سگمنت CS و SS را برای اشاره به کد برنامه و سگمنت پشته مقداردهی می کند. برای دسترسی به سگمنت داده ثبات ds بايد حاوی آدرس سگمنت داده باشد. قبل از دسترسی به هر داده ای برنامه بايد آدرس سگمنت را در ثبات DS ذخيره کند.
سگمنت ها در برنامه اسمبلی توسط راهنماهای segment و ends مشخص می شوند. يک سگمنت به فرم کلی زير مشخص می شود:
segmentname
segment {READONLY} {align} {combine} {use} {'class'}
segmentname ends
segmentname شناسه ای است که نام سگمنت معين می کند. نام سگمنت برای بدست آوردن آدرس آنها توسط اسمبلر استفاده می شود. نام سگمنت بايد در راهنمای ends هم مشخص شود.
align می تواند يکی از کلمات byte، word، dword، para يا page باشد. اين پارامتر مشخص می کنند سگمنت در محدوده بايت، کلمه، کلمه مضاعف، پاراگراف يا صفحه بار شود. اگر بايت باشد سگمنت از اولين بايت آزاد بعد از آخرين سگمنت ذخيره می شود. اين فيلد می تواند حذف شود. پيش فرض پاراگراف است. پاراگراف مضربی از 16 بايت است.
فيلد combine ترتيبی را که سگمنت های هم نام در فايل مقصد توسط اسمبلر نوشته می شوند را کنترل می کند و می تواند يکی از کلمات public، stack، common يا memory باشد. نوع stack برای سگمنت های پشته و public برای بقيه سگمنت ها استفاده می شود.
مثال.
DSEG segment
Item1 byte 0
Item2 word 0
DSEG ends
CSEG segment
mov AX, 10
add AX, Item1
ret
CSEG ends
هرزمان نام سگمنت به عنوان عملوند دستوری بکار برود اسمبلر بلافاصله آدرس سگمنت را جايگزين می کند.
مثال. دستور زير آدرس سگمنت داده را در ثبات DS قرار می دهد.
mov AX,
dseg ;Loads AX with segment address of dseg.
mov DS, AX ;Point ds at
dseg.
راهنماهای .stack، .data و .code راهنماهای ساده شده سگمنت هستند که محل شروع سگمنت های پشته، داده و کد را مشخص می کنند. راهنمای .stack فضائی را برای پشته برنامه رزرو می کند. اندازه پشته در مقابل آن ذکر می شود. پيش فرض مقدار پشته 512 بايت درنظر گرفته می شود.
سگمنت ها به ترتيبی که در برنامه تعريف شده اند در حافظه بار می شوند.
SSeg
SEGMENT PARA
DW 32 dup(0)
SSeg ENDS
DSeg SEGMENT PARA
;declarations
DSeg ENDS
CSeg SEGMENT PARA
Main PROC FAR
ASSUME SS:SSeg, DS:DSeg, CS:CSeg
mov AX,DSeg
mov DS,AX
...
mov AX,4c00h
int 21h
Main ENDP
CSeg ENDS
END Main
.MODEL
small
.STACK [size]
.DATA
;declarations
.CODE
Main:
mov AX,@Data
mov DS,AX
...
mov AX,4c00h
int 21h ;return to DOS
END Main
نکته. ابتدای هر برنامه اسمبلی بايد آدرس سگمنت داده در ثبات DS قرار گيرد.
مثال. برنامه first.asm برای نمايش پيغام روی صفحه.
;
First.asm
;
.MODEL small
.STACK [size]
.DATA
message db "Hello world, I'm learning Assembly !!!", "$"
.CODE
main PROC
mov AX,seg message
mov DS,AX
mov AH,09
lea DX,message
int 21h
mov AX,4c00h
int 21h ;return to DOS
main ENDP
END main
تعريف داده ها در سگمنت داده صورت می گيرد که با راهنمای .data شروع می شود.
يک ثابت واقعی ثابتی است که مقدارش صريحا ذکر شده است. ثابت های واقعی نمايش آنچه هستند که معمولا برای مقدار دنيای واقعی انتظار داريم. ماکرو اسمبلر دارای انواع مختلفی از ثابت های صحيح، حقيقی، رشته و غيره است.
مثال.
123
3.14159
"Literal String Constant"
0FABCh
'A'
يک ثابت عددی مقداری است که می تواند در مبنای 2، 10 يا 16 نوشته شود. برای مشخص کردن مبنای عدد از پسوندهای جدول زير استفاده می شود. اگر مبنا صريحا ذکر نشود پيش فرض مبنای 10 است.
|
مبنا |
پسوند |
|
Binary |
B يا b |
|
decimal |
D يا d يا T يا t |
|
hexadecimal |
H يا h |
ثابت های رشته ای درون گيومه (") يا تک گيومه (') قرار می گيرند.
مثال. ثابت های عددی.
0F000h
12345d
0110010100b
مثال. ثابت های رشته ای.
"This
is a string"
'So is this'
'Doesn''t this look weird?'
"Doesn't this look weird?"
"Microsoft claims ""Our software is very fast."" Do
you believe them?"
'Microsoft claims "Our software is very fast." Do you believe them?'
ثابت نامدار (named constant) نام سمبليکی است که نشانگر مقدار ثابتی طی فرآيند اسمبلی است. ثابت ها به صورت کلی زير تعريف می شوند:
ConstantName
EQU Value
ConstantName = Value
ConstantName نام ثابت است و Value مقداری است که به ثابت اختصاص داده می شود.
مثال.
One
equ 1
Minus1 equ -1
TryAgain equ 'Y'
String equ "Hello there"
Num = 16
Size = Count * Element
نکته. علامت مساوی تنها برای مقدارهای عددی بکار می رود.
متغيرها را در هر سگمنتی می توان تعريف کرد اما اکثر برنامه نويسان همه آنها را در سگمنت داده تعريف می کنند. هر متغير به فرم کلی زير تعريف می شود:
VariableName Type InitialValue|?
Type نوع متغير را مشخص می کند که می تواند يکی از نوع های جدول زير باشد. نوع هائی که اغلب مورد استفاده قرار می گيرند DB و DW هستند. InitialValue مقداراوليه متغير است. اگر نخواهيم مقدار اوليه بدهيم علامت سوال (?) می گذاريم.
|
تعداد بايت |
نوع |
|
1 |
byte/sbyte/db |
|
2 |
word/sword/dw |
|
4 |
dword/sdword/dd |
|
8 |
qword/dq |
|
10 |
tbyte/dt |
مثال.
num db
25h
sum dd ?
ANum db -4
مثال. محل های پشت سر هم که دارای يک نوع هستند آرايه ناميده می شود. رشته ها توسط راهنمای db اعلان می شوند.
X dw
040Ch,10b,-13,0
Y db 'This is an array'
Z dd 10, 13, 'A','B','C'
مثال. برای تعريف يک متغير آرايه از راهنمای dup استفاده می شود.
Memory
db 30 dup('$')
BigAry dw 100 dup(?)
دستورالعمل های برنامه در سگمنت کد قرار می گيرند. کد معمولا در زير برنامه نوشته می شود. برای پايان اجرای برنامه و بازگشت به محيط سيستم عامل تابع 4c از وقفه 21h در انتهای هر برنامه بايد فراخوانی شود. اگر کد صفر در ثبات AL ذخيره شود به معنی اينستکه برنامه با موفقيت به پايان رسيده است. در انتهای هر برنامه دستورات زير بايد اضافه شود.
Mov
AX,4c00h
Int 21h
راهنمای end انتهای سگمنت کد و پايان برنامه را برای اسمبلر مشخص می کند. عملوندی که در مقابل آن ذکر می شود نقطه آغاز اجرا يا نام تابع اصلی برنامه را به سيستم عامل می گويد و باعث می شود انتقال کنترل اجرا هنگام شروع اجرای برنامه می شود. در واقع ثبات های CS و IP را تنظيم می کند. نقطه شروع الزاما بلافاصله بعد از راهنمای .code نيست. اگر اين عملوند نباشد سيستم عامل از اولين بايت سگمنت کد شروع به اجرا می کند.
برای ايجاد برنامه به سه ابزار نياز است: يک اديتور متن، يک اسمبلر برای تبديل برنامه به فايل مقصد و يک لينکر برای توليد فايل اجرائی.
برنامه اسمبلی را در يک اديتور متن نوشته و با پسوند .asm ذخيره کنيد. فراموش نکنيد که حتما از يک اديتور اسکی استفاده کنيد. توسط اسمبلر (masm.exe يا tasm.exe) از فايل مبدا .asm فايل مقصد .obj را ايجاد کنيد. اسمبلر برنامه زبان اسمبلی را به کد ماشين تبديل می کند. اگر خطائی در برنامه وجود داشته باشد اسمبلر خطا را گزارش می دهد. لينکر (link.exe يا tlink.exe) از يک يا ترکيب چند فايل .obj يک برنامه قابل اجرا از نوع .exe يا .com را می سازد.
مثال. برنامه first.asm را در اديتور متن ذخيره کنيد. سپس در خط فرمان سيستم عامل، در محلی که اسبلر نصب شده است، دستورات زير را به ترتيب وارد کنيد تا فايل اجرائی first.exe ايجاد شود.
C:\masm>masm
first
C:\masm>link first
C:\masm>first
مثال: در برنامه زير دو عدد با هم جمع می شود.
.MODEL
small
.STACK [size]
.DATA
number1 DW 0800h ;=128
number2 DW ffebh ;=-493
sum DW ?
;store result
.CODE
begin:
mov AX,@Data
mov DS,AX
mov AX,number1 ;get first number in AX
add AX,number2 ;add AX with second number
mov sum,AX ;store result in Sum
mov AX,4c00h
int 21h
END begin
مثال: تکه برنامه زير اعداد 1 تا 10 را در آرايه ای از نوع word ذخيره می نمايد.
.MODEL
small
.STACK [size]
.DATA
Array DW 10 dup(?)
.CODE
begin:
mov AX,@Data
mov DS,AX
mov CX,1
mov SI, offset Array
Forl:
mov [SI], CX
inc SI
inc SI
cmp CX,10
je endf
inc CX
jmp forl
Endf:
mov AX,4c00h
int 21h
END begin
برای دسترسی به عناصر آرايه معمولا از عملوند غيرمستقيم ثباتی استفاده می شود. برای تخصیص آدرس آفست يک آرايه می توان از دستور LEA هم استفاده کرد. دقت کنيد چون عناصر آرايه دو بايتی هستند هربار دو واحد به SI اضافه می شود. در حالتی که عناصر آرايه از نوع بايت تعريف می شوند به اشاره گر آرايه يک واحد اضافه می شود.
مثال: کاراکتر * را نمايش می دهد.
.MODEL small
.STACK [size]
.CODE
main PROC
mov AH,2h
mov DL,2ah
int 21h
mov AX,4c00h
int 21h
main ENDP
END main
ماکرو
ماکرو مجموعه ای از دستورات است که مشابه زيربرنامه يکبار نوشته می شود و چندين بار استفاده می شود.
ماکرو (macro) نام مخففی برای مجموعه ای از دستورالعمل ها، راهنماها يا ماکروهای ديگر است که يکبار نوشته می شود و به هر تعداد دفعات لازم قابل استفاده است.
اسمبلر هنگام ترجمه برنامه در مواجهه با نام ماکرو دستورات معادل را قرار می دهد.
تعريف ماکرو
تعريف ماکرو توسط برنامه نويس و با استفاده از راهنمای macro صورت می گيرد. فرم کلی تعريف ماکرو به شکل زير است:
MacroName MACRO
[parameter1, parameter2...]
...
MacroName ENDM
تعريف ماکرو با راهنمای macro شروع و با راهنمای endm پايان می پذيرد. نام ماکرو قبل از هر دو راهنمای بايد يکسان باشد.
در ماکرو، برخلاف زيربرنامه، ارسال پارامتر امکان پذير است.
مثال. تعريف ماکرو ExitPgm برای خروج از برنامه و برگشت به محيط سيستم عامل.
; ExitPgm- Returns
control to MS-DOS
ExitPgm MACRO
mov AH, 4ch
int 21h
ExitPgm ENDM
مثال. ماکرو که مکان نما را به موقعيت داده شده منتقل می کند.
Position MACRO Row,
Column
push AX
push BX
push DX
mov AH, 02H
mov DH, Row
mov DL, Column
mov BH, 0
int 10H
pop DX
pop BX
pop AX
Position ENDM
برای استفاده از ماکرو تنها کافی است نام آنرا مشابه هر دستور ديگری فراخوانی کنيم. فراخوانی ماکرو مانند زيربرنامه نيازمند دستور call نيست.
ماکرو فوق به صورت زير فراخوانی می شود.
Position 8, 6
کتابخانه ماکرو
يکی از مزايای استفاده از ماکرو ها ايجاد کتابخانه ای از ماکروهاست که می تواند در برنامه ضميمه شود. برای ايجاد کتابخانه کافی است کليه ماکروها را درون يک فايل متن جداگانه ذخيره کنيد. برای استفاده از اين ماکروها بايد ابتدا فايل ماکرو به فايل برنامه با راهنمای include ضميمه کنيد..دستور include معمولا در ابتدای برنامه قبل از راهنمای .model نوشته می شود.
INCLUDE NameOfTheFile
اين صفحه نگاهی به زيربرنامه ها در زبان اسمبلی دارد. چگونگی تعريف زيربرنامه، دستورات فراخوانی و برگشت از زيربرنامه و نحوه ارسال و دريافت پارامترها شرح داده خواهد شد.
تعريف
زيربرنامه
زيربرنامه
های near و far
دستورات
فراخوانی و بازگشت زيربرنامه
ارسال
و دريافت پارمترها
زير برنامه (procedure) مجموعه ای از دستورات است که يکبار تعريف و به دفعات استفاده می شود. با بکارگيری زيربرنامه خوانائی برنامه بالاتر رفته و از تکرار دستورات مشابه جلوگيری می شود. علاوه براين اشکال زدائی و تغيير برنامه آسان تر انجام گيرد.
وقتی يک زيربرنامه فراخوانی می شود کنترل اجرای برنامه به زيربرنامه هدايت می شود. آدرس دستورالعمل بعدی در پشته ذخيره می شود بنابراين هنگامی که زيربرنامه اجرا شد کنترل اجرا قادر خواهد بود به خط بعد از فراخوانی زيربرنامه بر می گردد.
تعريف زيربرنامه بايد در سگمنت کد انجام بگيرد. از دو راهنمای proc و endp برای تعيين بلاک زيربرنامه استفاده می شود.
ProcedureName
PROC [NEAR|FAR]
...
RET
ProcedureName ENDP
Procedurename نام زيربرنامه است که قبل از راهنماهای proc و endp قرار می گيرد و بايد يکسان باشد. عملوند near يا far اختياری است. کلمه near به اسمبلر می گويد که زيربرنامه از نوع داخلی است. برای تعريف يک زيربرنامه خارجی از کلمه far به جای near استفاده می شود.
دستور ret باعث خروج از زيربرنامه و برگشت به فراخواننده می شود.
نکته. اگر عملوندی مقابل تعريف زيربرنامه قرار نگيرد از
نوع near در نظر گرفته می شود.
نکته. اگرچه تعريف يک زيربرنامه که عملا داخلی است به صورت خارجی اشکالی ايجاد نمی
کند ولی بهتر است اين کار را نکنيد.
مثال. زيربرنامه جمع دو عدد در AH و AL و نگهداری مجموع در ثبات BX.
Adding
PROC near
mov BX, AL
add BX, AH
ret
Adding ENDP
مثال: زيربرنامه Putc برای نمايش کاراکتری که در ثبات al قرار دارد.
Putc
PROC
mov DL,AL
mov AH,02
int 21h
ret
Putc ENDP
دو نوع زيربرنامه وجود دارد داخلی (intrasegment) و خارجی (intersegment).
• زيربرنامه های داخلی در همان سگمنتی که تعريف شده اند
قابل فراخوانی هستند و در تعريف آنها از صفت near استفاده
می شود.
• زيربرنامه های خارجی روال هائی که در سگمنت ديگری قرار دارند و از ساير سگمنت ها
قابل فراخوانی می باشند و در تعريف آنها از صفت far استفاده
می شود. زيربرنامه های خارجی درفايل جداگانه ای قرار دارد و هنگام لينک کردن بايد
به برنامه پيوند داده شوند. نتيجه کار بعد از لينک مانند زيربرنامه داخلی است.
فراخوانی از نوع near کنترل را درون همان سگمنت کد جابجا می کند وتنها مقدار IP در پشته ذخيره می شود. فراخوانی far کنترل را بين سگمنت های مختلف عبور می دهد. هر دو مقادير CS و IP در پشته قرار می گيرند.
نکته. دستورات call و ret نوع فراخوانی را مشخص نمی کنند بلکه عملوند near|far راهنمای proc به اسمبلر می گويد فراخوانی از کدام نوع است.
دودستورالعمل که پشته را استفاده می کنند و فراخوانی و برگشت زيربرنامه را انجام می دهند call و ret هستند. برای هدايت کنترل اجرا به زيربرنامه بايد آنرا فراخوانی کرد. زيربرنامه ها در هر کجای برنامه که به آن نياز داريم با دستور call فراخوانی می شوند. دستور call به صورت زير است:
call ProcedureName
دستورالعمل call باعث يک پرش غير شرطی به زيربرنامه می شود و آدرس دستورالعمل بعدی را در پشته ذخيره می کند. CPU در برخورد با دستور call به آدرس شروع زيربرنامه رجوع می کند و دستورات آنرا اجرا می نمايد. با برخورد به دستور ret به برنامه فراخوان بر می گردد و دستورات بعد از call را اجرا می نمايد.
مثال. فراخوانی زيربرنامه Putc.
call Putc
CPU در برخورد با دستور Call عمليات زير را انجام می دهد:
فراخوانی از نوع داخلی
1. مقدار ثبات IP (که حاوی آدرس
دستور بعد از call است ) را در پشته ذخيره می کند.
2. آدرس ذکر شده مقابل دستور call را در ثبات IP قرار می دهد.
فراخوانی از نوع خارجی
1. مقدار ثبات CS را در پشته
ذخيره می کند.
2. بخش سگمنت آدرس ذکر شده مقابل دستور call را در ثبات CS قرار می
دهد.
3. مقدار ثبات IP را در پشته ذخيره می کند.
4. بخش آفست آدرس ذکر شده در جلوی دستور call را در ثبات IP قرار می
دهد.
دستورالعمل ret آدرس ذخيره شده IP را از پشته بر می دارد و به برنامه اصلی بر می گردد. CPU در برخورد با دستور Ret عمليات زير را انجام می دهد:
بازگشت از زيربرنامه داخلی
1. مقدار ذخيره شده در پشته را در داخل ثبات IP قرار می دهد.
بازگشت از زيربرنامه خارجی
1. مقدار ذخيره شده در پشته را در داخل ثبات IP قرار می
دهد.
2. مقدار ذخيره شده در پشته را در داخل ثبات CS قرار می
دهد.
نکته. اگر دستور ret در انتهای
زيربرنامه حذف شود کنترل اجرای برنامه به زيربرنامه بعدی می رود نه دستورالعمل
بعدی در برنامه اصلی.
نکته. معمولا در ابتدای هر زيربرنامه بهتر است مقادير ثبات هائی که تغيير می کنند
را در پشته ذخيره نمائيم و در انتهای زيربرنامه و قبل از دستور ret مقادير
آنها را از پشته بازيابی کنيم. بايد توجه کنيم که دستورات pop متناظر
با دستورات push باشند و کليه داده هائی که در زيربرنامه در پشته push شده اند
بايد pop شوند وگرنه به با دستور ret به آدرس درست
پرش نمی کند.
مثال. زيربرنامه برای نمايش 40 کاراکتر space. توجه کنيد زيربرنامه Putc درون زيربرنامه PrintSpaces فراخوانی شده است.
PrintSpaces
PROC near
push
AX
push
CX
mov
AL, ' '
mov
cx, 40
PSLoop: call putc
loop
PSLoop
pop
CX
pop
AX
ret
PrintSpaces ENDP
در ابتدای زيربرنامه ثبات های AX و CX در پشته قرار می گيرند و در انتها به ترتيب عکس بازيابی می شوند. زيربرنامه فوق به صورت زير فراخوانی می شود.
call PrintSpaces
پارامترها مقاديری هستند که می توانيد به زيربرنامه بدهيد يا بگيريد. برای ارسال يا دريافت پارامترها معمولا از ثبات، متغيرهای سراسری يا پشته استفاده می شود.
مثال. زيربرنامه زير طول يک رشته را محاسبه و در ثبات CX برمیگرداند. آدرس شروع رشته در ثبات SI قرار دارد.
StrLen
PROC
push SI
mov CX,0
Whl: cmp Byte Ptr[SI],'$'
jc EndW
inc CX
inc SI
jmp Whl
EndW: pop SI
ret
StrLen ENDP
پارامترهائی که به زيربرنامه داده می شوند را می توان قبل از فراخوانی زيربرنامه در پشته اضافه کرد. پارامترها در زيربرنامه pop نمی شوند بلکه مستقيما از پشته دسترسی می شوند زيرا قبل از دستور call در پشته اضافه شده اند و آدرس برگشتی بعد از آن اضافه می شود. علاوه براين چون ممکن است در چندين جای زيربرنامه استفاده شوند معمولا درون ثبات نگهداری نمی شوند و بهتر است در حافظه پشته باقی بمانند.
يک برنامه خارجی که يک پارامتر از طريق پشته را ارسال می کند در نظربگيريد. وقتی زيربرنامه درخواست می شود پارامتر می تواند با آدرس دهی غيرمستقيم [SP+4] دسترسی شود. اگر پشته هم در زيربرنامه برای ذخيره داده استفاده شود عدد بيشتری بايد به SP اضافه شود. ثبات BP را برای ارجاع به داده های درون پشته می توان به کار برد. ثبات SP با هر push و pop تغيير می کند اما BP ابتدا برابر با SP می شود و سپس ثابت می ماند در انتهای زيربرنامه مقدار اوليه BP بايد برگردانده شود. بعد از اينکه زيربرنامه تمام شد پارامترهائی که در پشته اضافه شده اند بايد حذف شوند.
مثال. تابع زير طول رشته را محاسبه و آدرس شروع رشته از طريق پشته به زيربرنامه ارسال می شود.
StrLen
PROC
push BP
mov BP,SP
mov SI,[BP+4]
sub CX,0
Whl: cmp byte ptr [SI],'$'
jc Endw
inc CX
inc SI
jmp Whl
EndW: pop BP
ret
StrLen ENDP
مثال. محاسبه مجموع سه عدد که از طريق پشته به زيربرنامه ارسال شده اند
کد گذاری ASCII(American Standard Code for Information Interchange) به حروف، ارقام، علائم و کاراکترهای مختلف يک عدد باينری 7 بيتی نسبت می دهد و هشتمين بيت را 0 درنظر می گيرد. به اين صورت هر کاراکتر يک بايت را اشغال می کند.
روشن است که اين روش برای نمايش اعداد مناسب نيست، چون در فرمت باينری يک بايت اعداد 0 تا 255 را نمايش می دهد، اما با کد ASCII يک بايت تنها برای نمايش يک رقم کافی است. به همين دليل کلا اين روش برای نمايش متن در حافظه استفاده می شود.
مثال. نمايش عدد 123 با دو فرمت ASCII و باينری
نوع توسعه يافته اين سيستم شامل 8 بيت برای هر کاراکتر است و 256 حالت مختلف را شامل می شود. کدهای 0 تا 127 برای کاراکترهای استاندارد، کدهای کنترلی و ارتباطی و مقادير 128 تا 255 برای نمايش سمبل های گرافيکی و حروف يونانی هستند.
مثال. رشته "ABC123" به صورت 41h 42h 43h 30h 31h 32h نشان داده می شود.
يک کدگذاری کامل تر که جای ASCII را دارد می گيرد Unicode است. تفاوت کليدی بين اين دو نوع کدگذاری در اين است که ASCII يک بايت را برای کدکردن يک کاراکتر استفاده می کند در حاليکه Unicode برای هر کاراکتر دو بايت را درنظر می گيرد. بنابراين کاراکترهای بيشتری را می تواند نمايش دهد که اين برای نمايش کاراکترهای کليه زبان های دنيا کاربردی است.
مثال. کدگذاری ASCII کد 41h يا 65 را به کاراکتر A می دهد. کدگذاری Unicode کد 0041h هگز را می دهد.
نکته1. تفاوت يک حرف بزرگ با يک حرف کوچک تنها در بيت
شماره 5 است؛ اين بيت در حروف بزرگ 0 و در حروف کوچک 1 است. ("m"= 01101101 و "M"=
01001101)
نکته2. ارقام 0 تا 9 کدهای 30h تا 39h را دارا می باشند.
نکته3. کاراکترهای قابل چاپ بين 20h تا 7Eh است.
نکته4. کاراکترهای 0 تا 1Fh و 7Fh کاراکترهای کنترلی نام دارند که قابل رويت نمی باشند.
نکته5. کاراکتر ESC با کد 1Bh همراه با کاراکترهای ديگر اغلب برای يک عمل خاص به دستگاه های
جانبی ارسال می شود.
نکته6. کدهای 41 تا 5Ah کاراکترهای A تا Z و کدهای 61 تا 7Ah کاراکترهای a تا z هستند.
نکته7. کاراکتر CR و LF با کدهای 0Dh و 0Ah به ترتيب باعث حرکت مکان نما به شروع خط جاری و خط بعد می شود.
در اسمبلی کليه داده ها اندازه مشخص شده ای دارند. گاهی ناچار به تغيير اندازه داده هستيم. برای کاهش اندازه داده کافی است بيت های با ارزش حذف شوند. اين روش برای اعداد بدون علامت و علامت دار کار می کند. قاعده کلی اين است که برای اعداد بدون علامت کليه بيت های حذف شده بايد صفر باشند. و برای اعداد علامت دار بيت های حذف شده بايد همگی يا 1 و يا 0 باشند. البته اگر عدد را نتوان به طرز صحيح در اندازه کوچکتر نمايش داد کاهش اندازه کار نمی کند.
افزايش داده پيچيده تر از کاهش است. عدد هگز FF را اندازه بگيريد. گسترش آن بستگی دارد که آن را چطور تفسير کنيم. اگر آن را يک عدد بدون علامت درنظربگيريم(يعنی عدد 255)، به صورت 00FF گسترش داده می شود و اگر علامت دار باشد(يعنی 1-) به صورت FFFF. به طور کلی برای گسترش اعداد بدون علامت کليه بيت های جديد عدد گسترش يافته صفر می شوند ولی برای گسترش يک عدد علامت دار بايد بيت علامت را بسط داد، به اين معنا که.بيت های جديد بيت علامت را در خود کپی می کنند.
اين بخش شرح مختصری پيرامون اجزاي اصلی يک سيستم کامپيوتری (حافظه و پردازنده)می دهد، که باعث می شود کاربر درک بيشتری نسبت به مفاهيمی که در طی برنامه اسمبلی با آن ها سرو کار دارد پيدا کند.
يک سيستم کامپيوتری ترکيب کاملي از سخت افزار و نرم افزارهای سيستمی است که باعث می شود ماشين مفيد و وظيفه مندي برای کار معينی بشود.
اجزای اصلی سخت افزار يک ريز کامپيوتر شامل:
• پردازنده مرکزی
• حافظه
• صفحه کليد به عنوان ورودی
• صفحه نمايش به عنوان خروجی
• يک يا چند ديسک درايو برای ذخيره برنامه ها و داده ها
حافظه مکان ذخيره برنامه ها و داده ها با امکان دسترسی مجدد به آنها است. حافظه اصلی از ديد برنامه نويس از تعدادی بيت تشکيل شده است که قادر به نگهداری صفر يا يک است. مکانيسم دسترسی به اطلاعات درون حافظه آدرس دهی است. بيت هائی که دارای آدرس يکسان هستند را سلول حافظه (cell) می نامند. هر سلول تنها می تواند شامل يک مقدارعددی باشد. طول سلول(Lc) توسط تعداد بيت های سلول مشخص می شود. در ريز کامپيوترها طول سلول هشت بيت است که به آن بايت نيز گفته می شود. خاصيت مهم سلول آدرس پذيری است، يعنی هر سلول دارای يک آدرس منحصر بفرد است. بنابراين هر بايت درحافظه نيز دارای يک آدرس منحصر بفرد است.
اغلب حافظه ها در اندازه های بزرگتراز بايت نظير کيلوبايت (1KB=210=1,024 bytes)، مگابايت (1MB=220= 1,048,576 bytes) و گيگابايت (1GB=230=1,073,741,824 bytes) بيان می شوند. يک کامپيوتر با 32 مگابايت حافظه قادر است تقريبا 32 ميليون بايت از اطلاعات را نگهداری کند.
نکته. تعداد بيت های يک کلمه بستگی به سخت افزار دارد و با Lw نشان داده می شود. همواره رابطه Lw≥Lc برقرار است. آدرس هر کلمه آدرس اولين سلول آن است.
آدرس های حافظه از عدد صفر شروع می شوند. اگر حافظه ای دارای n سلول باشد آدرس های آن از 0 تا n-1 خواهد بود. کامپيوتری که سيستم عددی باينری را استفاده می کند برای بيان آدرس نيز همان روش را به کار می برد. تعداد بيت های آدرس تعداد سلول های قابل دسترس حافظه را نشان می دهد و ربطی به طول سلول ندارد. فضای آدرسی بيشترين ميزان حافظه است که يک پردازنده می تواند آدرس دهی کند.
اگر آدرسی m بيت طول داشته باشد بيشترين تعداد سلول های قابل آدرس دهی 2m خواهد بود.
پردازنده يا واحد پردازش مرکزی (Central Processing Unit) يا (CPU) از واحد کنترل و واحد محاسبات و منطق ساخته شده است. وظيفه آن خواندن و نوشتن محتويات سلول حافظه، انتقال داده بين سلول های حافظه و ثبات های خاص، رمزبرداری و اجرای دستورالعمل های ذخيره شده در حافظه اصلی است.
CPU هر دستورالعمل را در يک سری مراحل اجرا می کند و برای همگام کردن سيکل اجرای دستورالعمل از يک ساعت (Clock) استفاده می کنند. ساعت در يک فرکانس ثابت پالس می زند که سرعت ساعت ناميده می شود. اين ساعت دقيقه و ثانيه را نگه نمی دارد بلکه فقط در نرخ ثابتی ضربان دارد. مدارهای الکترونيکی کامپيوتر از اين ضربان ها برای انجام صحيح عمليات خود استفاده می کنند. تعداد ضربه ها يا اصطلاحا سيکل های مورد نياز يک دستورالعمل بستگی به نسل و مدل CPU دارد.
مثال. وقتی يک کامپيوتر 1.5GHz می خريد، 1.5 GHz فرکانس اين ساعت است. يعنی در هر ثانيه 1.5 ميليارد پالس می زند (گيگاهرتز GHz يا يک ميليارد سيکل در ثانيه است).
مجموعه ای از تمام دستورالعمل هائی که يک نوع پردازنده می تواند اجرا می کند مجموعه دستورالعمل (Instruction Set) ناميده می شوند که درواقع زبان ماشين آن نوع پردازنده را شکل می دهد. دستورالعمل های زبان ماشين به صورت اعداد رمز می شوند و عموما ساده هستند. زيرا زبان ماشين با اين هدف طراحی می شود که پردازنده قادر باشد مقصود دستورالعمل را سريع کشف کند تا بتواند به طور موثر آن را اجرا کند..
هر پردازنده زبان ماشين منحصر بفرد خود را دارد. و مجموعه دستورالعمل از ماشينی به ماشين ديگر متفاوت است. به همين دليل مثلا برنامه های نوشته شده برای Mac نمی توانند روی يک IBM-PC اجرا شوند. برنامه های نوشته شده در زبان های ديگر بايد توسط کامپايلر به زبان ماشين پردازنده ای که روی آن اجرا می شود تبديل شود. معمولا عملکرد کامپايلرها بر روی ماشين با دستورالعمل کمتر آسان تر است.
دستورالعمل ها ممکن است نياز به داده ای داشته باشند تا روی آن عمل کند. هر پردازنده دارای يکسری سلول های حافظه است که داده های دستورالعمل را در خود ذخيره می کنند. اين سلول ها ثبات (register) ناميده می شوند و درون خود پردازنده قرار دارند. پردازنده می تواند به داده درون ثبات سريع تر از داده درون حافظه دسترسی پيدا کند. اغلب کامپيوترها مجموعه ای از ثبات ها را برای ذخيره موقت داده دارند. البته تعداد ثبات های پردازنده اندک است، بنابراين برنامه نويس ناچار است تنها داده های جاری را در ثبات ذخيره نمايد.
پردازنده ها به گروه های زير دسته بندی می شوند:
1. Complex
Instruction Set Computers - CISC
• پردازنده هائی که مجموعه دستورالعمل کاملی با
پشتيبانی سخت افزاری برای انواع وسيعی ازعمليات را دارند. در عمليات علمی، مهندسی
و رياضی معمولا اکثر کارها را در کوتاهترين زمان انجام می دهند.
2. Reduced
Instruction Set Computers - RISC
• پردازنده هائی که مجموعه دستورالعمل فشرده و
کوچکی دارند. در کاربردهای تجاری و برنامه هائی که توسط کامپايلر ايجاد شده اند
معمولا اکثر کارها را در کوتاهترين زمان انجام می دهند.
3. Hybrid
• پردازنده هائی که ترکيبی از روش CISC و RISC هستند و
سعی دارند تعادلی بين مزايای هر دو روش برقرار کنند.
4. Special
purpose
• پردازند هائی که برای وظايف خاصی بهينه شده اند. Digital signalprocessors و انواع co-processors نوع متعارف اين دسته هستند.
5. Hypothetical
• پردازنده هائی که هنوز وجود ندارند يا هرگز وجود
نداشته اند. پردازنده هائی که در فاز طراحی هستند يا برای کارهای نظری درنظر گرفته
شده اند. معروف ترين آنها MIX است که يک پردازنده فرضی آموزش ساخته شده توسط Donald E. Knuth برای ارائه الگوريتم های کامپيوتری است.
با توجه به اينکه دستورات اسمبلي 8086 در قسمت ها آينده بررسي مي شوند، در اين صفحه با نحوه آدرس دهي حافظه و ثبات هاي اين پردازنده آشنا خواهيد شد.
خانواده 80x86
آدرس دهي سگمنتي
مدهاي اجرا
مجموعه ثبات ها
کليه کامپيوترهای شخصی IBM پردازنده ای از خانواده 80×86 دارند. پردازند های اين خانواده همگی دارای ويژگي های مشترکی ازجمله زبان ماشين پايه يکسان هستند. البته اعضای جديد ويژگي های خود را به ميزان زيادی افزايش داده اند.
تعدادی از پردازنده های اين خانواده بدين شرح می باشند:
(1979)8088,(1978)8086
• اين CPU ها، که از
ديدگاه برنامه نويسی برابر هستند، پردازنده هائی بودند که روی اولين کامپيوترهای
شخصی به کار رفته اند. دارای ثبات های 16 بيتی (AX، BX، CX، DX، SI، DI، BP، SP، CS، DS، SS، ES، IP و FLAGS ) هستند
و تنها در مد حقيقی عمل می کردند. 8086 دارای گذرگاه داده 16 بيتی و گذرگاه آدرس
20 بيتی بود و بنا براين قابليت آدرس دهی تا 1 مگابايت حافظه را داشت و می توانست
با داده های 8 يا 16 بيتی همزمان کار کند. 8088 با گذرگاه داده 8 بيتی به طراحان
اجازه پيچيدگی کمتر و ارزانتر سيستم های کامپيوتری را می داد.
(1983)80286
• اين پردازنده، که در کامپيوترهای شخصی کلاس AT استفاده
شد، دستورالعمل های جديدی را به زبان ماشين 8086/88 اضافه کرد. اما ويژگی اصلی آن
مد محافظت شده 16 بيتی بود که در اين حالت می توانست تا 16 مگابايت حافظه را
دسترسی پيدا کند. البته برنامه ها همچنان به سگمنت هائی تقسيم بندی می شدند که نمی
توانستند بيشتر از 64K باشند.
(1986)80386
• اولين پردازنده 32 بيتی که توسط اينتل معرفی شد
80386 DX بود که علاوه بر حفظ سازگاری با پردازنده های قبلی اجرای عالی
داشت. اين پردازنده چند ثبات را به 32 بيتی گسترش داد (EAX, EBX, ECX, EDX, ESI,
EDI, EBP,ESP, EIP) و دو ثبات جديد 16 بيتی FS و GS را
اضافه کرد. دارای گذرگاه های آدرس 32 بيتی بود و در مد محافظت شده 32 بيتی می
توانست تا 4 گيگابايت حافظه فيزيکی را آدرس دهی کند. برنامه ها دوباره به سگمنت ها
تقسيم می شدند اما اندازه هر سگمنت می توانست تا 4 گيگا بايت باشد. نسخه 16 بيتی
آن 80386 SX با گذرگاه آدرس 24 و داده 16 بيتی در 1988 بيرون آمد که تنها تا
16 مگابايت را دسترسی داشت.
(1989)80486
• 80486 DX دارای حافظه نهان
و کمک پردازنده رياضی در يک تراشه بود که حدود 50% سريع تر از 80386 بود. 80486 SX را هم
معرفی شد که تنها پيوند آن با ميکروپروسسور رياضی وجود نداشت.
( 1993)Pentium/Pentium Pro
• پردازنده های 64 بيتی پنتيوم، که چند دستورالعمل
را در يک زمان اجرا می کند، سرعت اجرای دستورالعمل ها را بالابردند. اين پردازنده
ها دارای گذرگاه داده 64بيتی و گذرگاه آدرس 32 بيتی هستند. پنتيوم از نظر کارائی
دوبار سريع تر از 80486 است و عمليات مميزشناور را سريع تر انجام می دهد درعين حال
که کاملا با قبلی ها سازگاری دارد.
PentiumMMX
• اين پردازنده دستورات MMX (MultiMedia eXtensions) را به پنتيوم اضافه کرد. اين دستورالعمل ها می توانند عمليات
گرافيکی معمول را سرعت ببخشند.
(1997)Pentium II
• اين پردازنده توسعه يافته پنتيوم است که قادر است
4 پردازنده را همزمان پشتيبانی کند و به 64 گيگابايت حافظه دسترسی دارد. درواقع يک
پردازنده پنتيوم پرو همراه با دستورالعمل های MMX است.
(1999)Pentium III/(2002)Pentium IV
• اين پردازنده ها تنها سرعت اجرای دستورالعمل ها
را بالا بردند.
پردازنده های 8086 دارای گذرگاه 20 بيتی هستند، بنابراين
می تواند تا 1 مگابايت حافظه را آدرس دهد(از آدرس 00000 تا 1MB=1048575=FFFFF). اين
آدرس ها به يک عدد 20 بيتی احتياج دارند. روشن است که يک عدد 20 بيتی را نمی توان
در ثبات های 16 بيتی 8086 جا داد. اينتل اين مشکل را با آدرس دهی سگمنتی (segment addressing) حل کرد. سگمنت يک تکه از حافظه با اندازه 64 کيلوبايت است. يک
محل از حافظه با يک آدرس سگمنت و يک آفست (offset) مشخص می شود که
به صورت دو عدد 16 بيتی نشان داده می شوند. آدرس سگمنت به سگمنتی در حافظه اشاره
می کند که حاوی محل مورد نظر است. هر سگمنت از يک پاراگراف می تواند شروع شود. هر
پاراگراف 16 بايـت دارد، بنابراين سگمنت از آدرسی که مضربی از 16 است شروع می شود.
يعنی سگمنت اول از آدرس 00000، سگمنت دوم از آدرس 00010، بعدی از آدرس 00020 و الی
آخر شروع می شود. در نتيجه آدرس شروع هر سگمنت از سمت راست به صفر ختم می شود که
از آن صرفنظر می شود. بنابراين آدرس سگمنت هميشه به صورت يک عدد 4 رقمی هگز نوشته
می شود.
آفست فاصله بايت مورد نظر از ابتدای سگمنت را مشخص می کند. با توجه به اينکه هر
سگمنت 64KB حافظه دارد، آفست می تواند بين 0000 تا ffff باشد.
بنابراين آفست نيز هميشه يک عدد 4 رقمی هگز است.
آدرس سگمنتی به صورت آفست:سگمنت نوشته می شود.
مثال 1. آدرس فيزيکی 18A3:5B27 به بايتی در سگمنت 18A30 اشاره دارد که از ابتدای اين سگمنت 5B27 بايت فاصله دارد.
مثال 2. آدرس فيزيکی 04808 می تواند توسط 047C:0048 رجوع شود.
آدرس های سگمنت-آفست يک آدرس منطقی را تعيين می کنند. برای ساختن آدرس فيزيکی 20 بيتی طبق فرمول زير محتوای آدرس سگمنت را در 16 ضرب کرده با آدرس آفست جمع می کنيم:
16× segment + offset
ضرب در 16 آسان است کافی است يک صفر در سمت راست عدد گذاشته شود.
مثال 3. آدرس فيزيکی رجوع شده توسط 047C:0048 برابر است با:
047C0+0048=04808
سگمنت ها روی هم می توانند قرار بگيرند بنابراين يک بايت، با داشتن آدرس فيزيکی منحصر بفرد در حافظه، می تواند از طريق چندين ترکيب سگمنت:آفست بدست می آيد.
مثال 4. آدرس فيزیکی 04808 می تواند توسط 047C:0048، 047D:0038، 047E:0028 يا 047B:0058 رجوع شود.
سه ناحيه از سگمنت های حافظه که هر يک می توانند 64KB باشند برای يک برنامه در نظر گرفته می شوند:
1. سگمنت کد
• شامل دستورالعمل های زبان ماشين برنامه ای که
دارد اجرا می شود. اولين دستور اجرائی برنامه در ابتدای اين سگمنت قرار دارد و
سيستم عامل CPU را برای اجرای برنامه به اين محل ارجاع می دهد.
2. سگمنت داده
• شامل داده های تعريف شده و ناحيه کاری که برنامه
نياز دارد.
3. سگمنت پشته
• شامل آدرس های برگشتی از زيربرنامه ها و داده های
محلی است .
نکته 1. برنامه و داده در هر سگمنتی از حافظه می توانند قرار گيرند، فقط آدرس شروع سگمنت بايد برای CPU تعريف شده باشد. اين آدرس ها در ثبات های سگمنت ذخيره می شوند و اغلب درطول اجرای برنامه ثابت باقی می مانند. در عمل هنگام برنامه نويسی تنها از آدرس 4 رقمی آفست استفاده می شود.
نکته 2. سگمنت ها می توانند روی همديگر بيافتند. در بعضی مواقع که برنامه کوتاه است سگمنت داده می تواند از داخل سگمنت کد شروع شود به شرط اينکه تداخل رخ ندهد.
پردازنده های 80286 به بعد دارای دو مد حقيقی (real mode) و محافظت شده (protected mode) براي اجرا هستند. تعاريف سگمنت داده شده در قسمت بالا بر اساس مد حقيقی است.
در مد حقيقی پردازنده مانند 8086 عمل می کند. ارجاع به حافظه توسط يک آفست 16 بيتی درون يک سگمنت تعيين می شود. آدرس فيزيکی 20بيتی طبق فرمول آفست + 16×سگمنت بدست می آيد. به اين طريق تا يک 1MB حافظه قابل آدرس دهی است. اما در هر لحظه فقط تا 64KB را می توان آدرس داد. در اين حالت يک برنامه به هر آدرسی از حافظه دسترسی دارد حتی حافظه برنامه های ديگر که باعث می شود اشکالزدائی و امنيت بسيار دشوار بشود.
کليه برنامه های تحت DOS در مد مجازی اجرا می شوند.
در مد محافظت شده پردازنده می تواند از قابليت های خود در گذرگاه های آدرس و داده به طور کامل استفاده کنند. در اين مد می تواند حافظه بيشتری را آدرس دهی کند و برنامه ها را از دسترسی حافظه های يکديگر محافظت می کرد.
مد محافظت شده تکنيکی به نام حافظه مجازی را استفاده می کند که برپايه نگهداری قسمتی از داده و کد در حافظه است که برنامه دارد اجرا می کند. بقيه داده و کد تا زمانی که مورد نياز باشند روی ديسک نگهداری می شوند. سگمنت ها بين حافظه و ديسک در صورت نياز منتقل می شوند و برخلاف مد حقيقی مکان های ثابتی در حافظه ندارند. اطلاعات سگمنت ها درون جدولی ذخيره می شود. ايندکس جدول هنگام آدرس دهی در ثبات سگمنت قرار می گيرد.
پردازنده 8086 دارای 14 ثبات 16 بيتی با کاربردهای متفاوت است. اين ثبات ها را می توان به صورت زير گروه بندی کرد:
1. ثبات های همه منظوره : AX، BX، CX و DX
2. ثبات های ايندکس : SIو DI
3. ثبات های آدرسی : BP،SP و IP
4. ثبات های سگمنت : CS، DS، SS و ES
5. ثبات های وضعيتی : Flag
دياگرام ثبات هاي ريزپردازنده 8086
CPU اوليه 8086 با چهار ثبات همه منظوره طراحی شد که در دستورات محاسباتی و ورودی/خروجی استفاده می شوند. هرکدام از اين ثبات ها يک يا چند وظيفه خاص هم دارند.
ثبات های همه منظوره می توانند به صورت 8 يا 16 بيتی استفاده شوند.هر کدام از آنها از دو بايت تشکيل شده اند؛ بايت سمت چپ را Low Order و سمت راست را High Order می نامند.
|
AX |
Accumulator Register |
همه منظوره ترين ثبات است و معمولا برای هر کاری از جمله عملياتورودی/خروجی،رشته ای و محاسباتی به کار می رود از دو جزء AL و. AH تشکيل شدهاست |
|
BX |
Base Register |
تنها ثباتی که می تواند بعنوان ايندکس در آدرس دهی مورد استفادهقرار می گيرد. شامل دو قسمت BL و BH است |
|
CX |
Count Register |
بعنوان شمارنده در کنترل تعداد دفعات تکرار در دستور حلقه استفادهمی شود. دارای دو قسمت CL و CH است |
|
DX |
Data Register |
در اعمال ورودی/خروجی و عمليات ضرب و تقسيم استفاده می شود. دارایدو بخش DL و DH است |
برای آدرس دهی به هر يک از اين سگمنت های برنامه يک ثبات وجود دارد که مشخص می کند کدام بخش حافظه برای قسمت های مختلف برنامه به کار رفته است.
|
CS |
Code Segment |
شامل آدرس شروع سگمنت کد، که به CPU می فهماند دستورالعمل هایبرنامه در کجا قرار دارند |
|
DS |
Data Segment |
شامل آدرس شروع سگمنت داده که به پردازنده می فهماند داده ها وفضای کاری در کجا قرار دارد |
|
SS |
Stack Segment |
آدرس شروع سگمنت پشته را در خود ذخيره می کند |
|
ES |
Extra Segment |
آدرس شروع سگمنت اضافی، سگمنت دادهدوم |
دو ثبات 16 بيتی ايندکس وجود دارد که اغلب به عنوان اشاره گر به همراه DS به کار می روند تا به داده های موجود در سگمنت داده دسترسی شود. اما می توانند به همان منظورهای ديگر، مانند ثبات های همه منظوره، هم استفاده شود؛ گرچه نمی توانند به دو بخش 8 بيتی تجزيه شوند.
|
SI |
Source Index |
برای آدرس دهی و در عمليات رشته ای بعنوان مبدا استفاه میشود |
|
DI |
Destination Index |
برای آدرس دهی و در عمليات رشته ای بعنوان مقصد استفاه میشود |
ثبات های اشاره گر نگهدارنده بخش آفست در آدرس دهی هستند و همراه با يکی از ثبات های سگمنت به محلی از حافظه اشاره دارند. طبق پيش فرض ثبات های همه منظوره و ايندکس همراه با DS و ثبات های پشته همراه با SS و IP همراه با CS استفاده می شوند.
|
IP |
Instruction Pointer |
همراه با ثبات CS به دستورالعمل بعدی که بايد توسط CPU اجرا شوداشاره می کند |
|
SP |
Stack Pointer |
آفست مکانی از سگمنت پشته که عمل قرار گرفتن داده در پشته صورت میگيرد. به عبارت ديگرSS:SP به بالای پشته اشاره دارد |
|
BP |
Base Pointer |
برای دسترسی به متغيرهای محلی که در پشته قرار دارند استفاده میشود |
فلگ ها اطلاعاتی درباره نتايج اجرای دستورالعمل قبلی را
نگه می دارند. اين نتايج به صورت بيت های مجزا در ثبات وضعيت FLAGS ذخيره
می شوند. 9 بيت از 16 بيت اين ثبات برای تعيين وضعيت فعلی ماشين و نتيجه اجرای
دستورالعمل به کار می روند. هر کدام از اين بيت ها هم فلگ ناميده می شوند زيرا می
توانند 1 (Set) يا 0 (Not
Set) باشند. بسياری از دستورالعمل ها وضعيت اين بيت ها را تغيير می
دهند. گرچه کليه دستورات روی فلگ تاثير نمی گذارند.
اين ثبات فاقد آدرس است و به طور مستقيم توسط برنامه نويس قابل دسترس نمی باشد.
|
CF |
Carry Flag |
محتوی رقم نقلی بوجود آمده از باارزش ترين بيت در عمليات محاسباتیيا چرخش |
|
PF |
Parity Flag |
برای کنترل صحت انتقال داده. اگر صفر باشد تعداد بيتهای انتقالیفرد است و اگر يک باشد زوج است |
|
AF |
Auxiliary Carry |
محتوی رقم نقلی از بيت سوم به چهارم در يک بايت است. در عمليات BCD کاربرد دارد |
|
ZF |
Zero Flag |
اگر نتيجه عمليات محاسباتی صفر باشد اين بيت 1 است در غير اينصورتصفر است |
|
SF |
Sign Flag |
در صورت منفی بودن نتيجه عمليات اين بيت 1 است در غير اينصورت صفزاست |
|
TF |
Trap Flag |
برای اجرای دستورالعمل به صورت دستور به دستور اين بيت بايد 1باشد |
|
IF |
Interrupt Flag |
اگر 1 باشد وقفه فعال است و اگر صفر باشد وقفه غير فعال است يعنیسيستم وقوع وقفه را ناديده می گيرد |
|
DF |
Direction Flag |
اگر 1 باشد عمل مقايسه يا انتقال داده از سمت راست به چپ صورت میگيرد در غير اينصورت از چپ به راست |
|
OF |
Overflow Flag |
اگر در باارزش ترين بيت سرريزی وجود داشته باشد اين بيت يک می شود. (توضيحات بيشتر درمحاسبات مکمل 2داده شدهاست) |
هگزادسيمال (يا به طور خلاصه هگز) روش فشرده تری را برای نمايش اعداد باينری ارائه می دهد به همين دليل توسط اسمبلر و ديباگر برای مختصر نوشتن اعداد باينری بکار می رود.
اعداد هگز مبنای 16 را استفاده می کنند و از 16 رقم (0-15) تشکيل شده اند. برای نمايش ارقام بعد از 9 از حروف A تا F استفاده می شود. به عبارت ديگر 16 رقم هگز شامل 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F است که حروف A-F ارقام 10-15 را نشان می دهند (A=10، B=11، C=12، D=13، E=14 وF=15).
هر رقم هگز معادل چهار بيت باينری است. يک عدد چهار بيتی يک نيبل (Nibble) نام دارد. پس هر رقم هگز معادل يک نيبل است. دو نيبل يک بايت (Byte) را می سازد بنابراين هر بايت می تواند دو رقم هگز را نشان بدهد. مقدار يک بايت می تواند از 00000000 تا 11111111 باينری، 00 تا FF در هگز و 0 تا 255 در دسيمال باشد.
ارزش هر رقم هگز با توانی از 16 مشخص می شود. برای تبديل اعداد از مبنای 16 به 10 هر رقم عدد در ارزش مکانی اش ضرب می شود.
جدول اعداد 0 تا 15 به صورت باينري و هگز
مثال. تبديل عدد 3BA4h به مبنای 10.
Hex
: 3BA4
Decimal: 3×16^3 + 11×16^2 + 10×16^1 + 4× 16^0
= 3×4096 + 11×256 + 10×16 +
4×1
= 15268
برای تبديل دسيمال به هگز مانند باينری تقسيم های متوالی بر 16 انجام می شود.
مثال. تبديل عدد 589 به هگز
|
عدد |
خارج قسمت |
باقيمانده |
|
589 ÷ 16 |
36 |
13 |
|
36 ÷ 16 |
2 |
4 |
|
2 ÷ 16 |
0 |
2 |
با قرار دادن باقيمانده های تقسيم از پايين به بالا عدد باينری 24D بدست می آيد.
تبديل هگز به باينری ساده است. کافی است هر رقم هگز به يک عدد چهار رقمی باينری تبديل شود.
مثال. تبديل عدد 160794h به باينری.
Hex:
1 6 0 7 9 4
Binary: 0001 0110 0000 0111 1001 0100
توجه کنيد که صفرهای ابتدای چهار بيت اهميت دارند. اگر اين صفرها برای ارقام ميانی قرار نگيرند حاصل اشتباه است.
تبديل از باينری به هگز هم ساده است. ابتدا عدد باينری از راست به چپ به گروه های چهاربيتی تقسيم شده (اگر آخرين گروه سمت چپ کمتر از چهار بيت بود صفر اضافه می شود)، سپس هر بخش به يک رقم هگز تبديل می شود.
مثال. تبديل عدد 101100000011110010100b به هگز
Binary:
0001 0110 0000 0111 1001 0100
Hex : 1 6 0 7 9 4
= 160794h
چند جمع ساده در مبنای 16.
7 + 3 = A
6 + 7= D
F + 1 = 10
10 + 30 = 40
F + F = 1E
38 + 18 = 50
FF + 1 = 100
جمع دو عدد هگز
|
1 |
1 |
|||
|
7 |
E |
C |
6 |
|
|
+ |
3 |
4 |
0 |
A |
|
|
B |
2 |
D |
0 |
6 + A = 6 + 10 = 16 => 10h
C + 0 + 1 = 12 + 0 + 1 = 13 => Dh
E + 4 = 14 + 4 = 18 => 12h
7 + 3 + 1 = 11 => Bh
اکثر ساختمان های داده انتزاعی هستند که توسط برنامه نويس با مجموعه ای از دستورالعمل ها تعريف می شوند. نوع های داده پايه (نظير اعداد باينری صحيح يا مميز شناور، رشته های بيتی، کاراکترها و غيره ) مستقيما در سخت افزار همراه با مجموعه ای از دستورالعمل طراحی می شوند. يک برنامه نويس زبان اسمبلی بايد بداند چگونه سخت افزار اين انواع داده های اصلی را پياده سازی می کند.
واحدهای اطلاعاتی
روش های نمايش داده ها
نمايش اعداد صحيح
کدگذاری ASCII
کاهش و افزايش طول داده
هر رقم در يک عدد باينری يک بيت (bit) ناميده می شود. بيت کوچکترين واحد اطلاعاتی در کامپيوتر است.
بيت ها به گروه های بزرگتری سازماندهی می شوند؛ در کامپيوترهای امروزی هر هشت بيت يک بايت (Byte) درنظر گرفته می شود که کوچکترين مکان آدرس پذير حافظه است (که می تواند متفاوت از مقدار حافظه واکشی شده درهربار مراجعه باشد). يک بايت می تواند حاوی يک دستورالعمل ماشين، يک کاراکتر، يا يک عدد باشد.
يک نيبل (nibble) نيمه يک بايت يا چهار بيت است.
نوع بزرگتر ذخيره سازی يک کلمه (word) است که روی پردازنده های اينتل 2 بايت (16 بيت) است. يک کلمه طول پيش فرض داده است که توسط طراح پردازنده انتخاب شده است و منعکس کننده برخی نکات سخت افزاری نظير گذرگاه های درونی و بيرونی است. کاميپوترهای شخصی اوليه با پردازنده های اينتل دارای عملوندهای 16 بيتی بودند به همين دليل کلمه به صورت 16 بيتی تعريف شد. در پردازنده های ديگر طول کلمه الزاما 2 بايت نيست.
يک کلمه مضاعف (doubleword) چهار بايت يا 32 بيت طول دارد و يک کلمه چهارگانه (quadword) دارای هشت بايت يا 64 بيت است.
يک نکته مهم ديگر بعد از تعداد بيت ها ترتيب قرار گيری بايت های داده در حافظه است که بايد موردتوجه برنامه نويس اسمبلی باشد. درحينی که پردازنده به طور نامحسوس endian را استفاده می کند، برای دسترسی به داده های چندبايتی حافظه و کارکردن با هر بايت بطور جداگانه، دانستن endian حياتی است. endian ترتيب قرار گيری بايت ها در حافظه را برای داده های چندبايتی معين می کند. فرمت های زير برای ذخيره يک مقدار چندبايتی وجود دارد:
1. Big-endian
• داده ها را به ترتيب طبيعی خودشان ذخيره می کند. بايت
با ارزش در کمترين آدرس قرار می گيرد. اکثر پردازنده های RISC و Motorola 68300 از اين دسته هستند.
2. Little-endian
• بايت با ارزش کمتر در آدرس های پائين تر حافظه ذخيره می
شود. پردازنده های Intel
x86 و Pentium از اين نمونه هستند.
3. Bi-endian
• پردازنده هائی مانند Motorola/IBM PowerPC می تواند در مد big-endian يا little-endian تحت کنترل نرم افزار کار کند.
مثال. داده چهار بايتی هگزAABBCCDD را درنظر بگيريد. نحوه تخصيص حافظه به اين داده در دو فرمت endian به صورت زير نشان داده شده است. مشاهده می شود که اين دو فرمت عکس يکديگر هستند.
اطلاعات معمولا به دو صورت استفاده می شوند: داده عددی ( صحيح و مميرشناور) و داده حرفی. نحوه نگهداری اطلاعات در حافظه را نمايش داده می گويند. روش های نگهداری داده ها بسته به نوع آنها متفاوت است.
اعداد صحيح باينری به دو شکل ديده می شوند:
1. اعداد
صحيح بدون علامت (unsigned
Integer) که شامل اعداد صحيح غير منفی هستند.
2. اعداد صحيح علامت دار (signed
Integer) که می توانند مثبت يا منفی باشند.
در اعداد صحيح بدون علامت کليه بيت ها به داده اختصاص داده می شود. کمترين مقدار ممکن يک عدد صحيح بدون علامت وقتی است که کليه بيت ها صفر باشد که معادل عدد 0 است. در بزرگترين عدد صحيح بدون علامت کليه بيت های عدد يک است.
جدول تعداد بيت ها و محدوده مقادير ممکن داده های عددی صحيح بدون علامت
اعداد صحيح علامت دار ممکن است مثبت يا منفی باشند. برای تشخيص علامت عدد يکی از بيت ها را به بيت علامت اختصاص می دهند. سه تکنيک برای نمايش علامت عدد وجود دارد که در نمايش اعداد صحيح علامت دار در حافظه استفاده می شده اند. در کليه اين روش ها با ارزش ترين بيت (سمت چپ ترين بيت) را به عنوان بيت علامت (sign bit) درنظر می گيرند. اگر اين بيت 0 باشد عدد مثبت و اگر 1 باشد عدد منفی است.
روش های نمايش اعداد صحيح علامت دار عبارتند از:
1. علامت مقدار
2. مکمل 1
3. مکمل 2
دو روش اول در کامپيوترهای اوليه به کار می رفتند. کامپيوترهای امروزی روش سوم به نام نمايش مکمل 2 را استفاده می کنند. مکمل2 يک عدد در دو مرحله بدست می آيد:
1- پيداکردن مکمل1 عدد
2- اضافه کردن 1 واحد به نتيجه مرحله اول
مثال. برای بدست آوردن مکمل2 عدد 56 ابتدا مکمل1 آن محاسبه سپس يک واحد به آن اضافه می شود.
56 = 00111000b
1’s complement = 11000111
2’s Complement = 11000111+1
=11001000
سيستم مکمل2 روش خوبی برای ذخيره اعداد صحيح علامت دار به صورت باينری است. طول نمايش يا تعداد بيت هایی که استفاده می شود بايد قبلا تعيين شده باشد. برای نمايش يک عدد صحيح مثبت در فرم مکمل2، عدد مانند اعداد بدون علامت به سادگی در مبنای 2 نوشته شده و به اندازه کافی صفر در سمت چپ آن اضافه می شود تا طول نمايش را بسازد. برای نمايش يک عدد صحيح منفی در فرم مکمل2، ابتدا عدد را به مبنای 2 برده، سمت چپ آن صفر اضافه می شود تا طول نمايش را بسازد سپس مکمل 2 عدد گرفته می شود.
مثال. نمايش عدد +1116 به فرم مکمل2 در يک کلمه به صورت زير نمايش داده می شود.
+1116 = 0000 0100 0101 110b =045ch
مثال: نمايش عدد -97 به فرم مکمل2 در يک بايت
Decimal: -97
Binary: 01100001b
1’Complement: 10011110
2’Complement: 10011111
= 9fh
عمل مکمل گيری مانند عمل منفی کردن است، به همين دليل با گرفتن مکمل2 از يک عدد منفی به عدد مثبت مطابق آن می رسيم و برعکس.
مثال. بنابراين عدد 11001000 نمايش عدد -56 در مثال اول است.
برای اعداد مثبت بيت علامت بايد صفر باشد يعنی آخرين رقم هگز عدد بين 0 تا7 خواهد بود. عدد منفی به بيت علامت 1 ختم می شود و می تواند ارقام بين 8 تا f را در آخرين رقم هگز داشته باشد. وقتی علامت عدد مکمل2 بدست آمد پيدا کردن عدد در مبنای 2 مشکل نيست برای اعداد مثبت کافی است به مبنای 10 برده شود و اعداد منفی ابتدا مکمل2 گرفته می شود سپس به مبنای 10 برده می شود.
مثال. 0d43h يک عدد مکمل 2 با طول 16 بيت است که معادل مبنای 10 آن عدد +3395 است.
مثال. b2ebh نمايش يک عدد صحيح در سيستم مکمل 2 است معادل آن در مبنای 10 به صورت زير بدست می آيد.
b2ebh =1011001011101011b
2’s Compl. =0100110100010101
=19733 ==> -19733
روش مکمل2 اشکالات روش های قبل را برطرف می کند و تنها يک نمايش برای صفر وجود دارد و اين محاسبات مکمل2 را ساده تر از روش های قبلی می کند. جمع و تفريق نمايش مکمل 2 همانند اعداد باينری انجام می شود. نمايش مکمل دو باعث می شود اعداد منفی يکی بيشتر از اعداد مثبت باشند(وقتی همه بيت ها 1 است).
در روش مکمل2 اعداد قابل نمايش با طول m بيت در بازه [-(2m-1),2m-1-1]قرار می گيرند.
جدول تعداد بيت ها و محدوده مقادير ممکن داده های عددی صحيح علامت دار به روش مکمل2
نکته 1. تعداد بيت های عدد قبل از عمل مکمل گيری حتما بايد
برابر طول نمايش باشد. در غير اينصورت عدد حاصل اشتباه است.
نکته 2. اگر طول بيت ها برابر با طول نمايش باشد و نتوان آنرا افزايش داد حاصل
اشتباه می شود.
نکته 3. از مبنای 16 برای ساده تر بيان کردن اعداد مبنای 2 استفاده می شود.
آموزش زبان اسمبلی
هدف اين درس درک عميق تر نحوه کار کامپيوتر در سطح پايين و در نتيجه
توليد نرم افزارهای کارآمدتر در سطوح بالا می باشد. يادگيری زبان اسمبلی به آشنائی
بيشتر با طريقه کارکردن سخت افزار، برنامه ها و سيستم عامل با يکديگر کمک می کند.
در اين درس استفاده از دستورات اسمبلي و نوشتن برنامه هاي ساده اسمبلي را
فراخواهيد گرفت.
مقدمه
زبان اسمبلی قديمی ترين زبان برنامه نويسی سطح پايين بعد از زبان ماشين است که ساختار و عملکردی وابسته به ماشين دارد و وسيله خوبی برای يادگيری نحوه کار کامپيوتر، سيستم عامل، کامپايلرها و زبان های سطح بالا است .
مقايسه زبان اسمبلی و زبان های سطح بالا
زبان ماشين
زبان اسمبلي چيست؟
اسمبلر
هدف از یادگيری زبان اسمبلی
مقايسه زبان اسمبلی و زبان های سطح بالا
دو دسته اصلی زبان های برنامه نويسی عبارتند از:
1. زبان های سطح بالا
• مانند C++، Pascal، Java و Visual Basic.
2. زبان های سطح پايين
• زبان ماشين
• زبان اسمبلی
اکثر برنامه نويسان در لايه زبان سطح بالا کار می کنند که هر عبارت آن به چند دستورالعمل ماشين ترجمه می شود. برنامه های نوشته شده در زبان های سطح بالا خصوصا زبان های شی گرا راحت تر، سريع تر و با هزينه کمتر پياده سازی و نصب می شوند.
زبان اسمبلی يک زبان سطح پايين است و اغلب هنگام ارتباط با سيستم عامل، دسترسی مستقيم به خواص کليدی ماشين يا برای بهينه کردن قسمت های حساس برنامه های کاربردی و افزايش سرعت اجرای آنها استفاده می شود. برنامه نويسی زبان اسمبلی نسبت به زبان های سطح بالا دشوارتر است. برنامه نويس بايد به جزئيات توجه بيشتری نشان دهد و اطلاعات کافی نسبت به پردازنده مورد استفاده داشته باشد. اما برنامه های اسمبلی که ماهرانه نوشته شده باشند می توانند سريع تر و با حافظه کمتری از برنامه های مشابه نوشته شده با زبان سطح بالا اجرا شوند.
هر خانواده ای از پردازنده ها دارای مجموعه ای از دستورالعمل های منحصر بفرد است که زبان ماشين ناميده می شود. مجموعه دستورالعمل های يک پردازنده (Instruction Set) مجموعه ای از اعداد دودوئی است که ماشين می تواند آنها را درک و اجرا کند. هر نوع CPU تنها زبان مخصوص خود را درک می کند و دارای مفسری بنام microprogram است که دستورات زبان ماشين را به سيگنال های سخت افزاری تفسير و ترجمه می کند.
مثال 1. اعداد دودئی زير يک دستورالعمل ماشين اينتل است که عدد 5 را در ثبات AL قرار می دهد.
1011 0000 0000 0101
مثال 2. دستور زير ثبات های EAX و EBX را جمع کرده و حاصل را در ثبات EAX ذخيره کند.
0000 0011 1100 0011
هر دستورالعمل زبان ماشين شامل کد منحصر بفردی دارد که کدعملياتی (OperationCode) يا Opcode ناميده می شود. Opcode هميشه در ابتدای دستورالعمل قرار می گيرد. اکثر دستورات شامل داده هم هستند که توسط دستورالعمل استفاده می شود و عملوند (Operand) نام دارند.
کاملا واضح است که برنامه نويسی به زبان ماشين بسيار دشوار است. درک معنی دستورالعمل های کدشده زبان ماشين برای انسان کار خسته کننده ای است. خوشبختانه برای هر خانواده از پردازنده ها يک زبان اسمبلی ارائه می شود که دستورالعمل های زبان ماشين را به صورت نمادی و قابل فهم تر نشان می دهند.
زبان اسمبلی که يک زبان برنامه نويسی سطح پايين است که ساختار و عملکردی وابسته به ماشين دارد. بين عبارات آن و دستورالعمل های زبان ماشين کامپيوتر تناظر يک به يک برقرار است. يعنی هر دستورالعمل اسمبلی دقيقا يک دستورالعمل زبان ماشين را نشان می دهد، در حاليکه در زبان سطح بالا يک عبارت معمولا به چندين دستورالعمل ماشين تبديل می شود.
يک برنامه اسمبلی مانند برنامه های سطح بالا به صورت text نوشته می شود. هر دستورالعمل زبان اسمبلی يک نمايش نمادی (يک کد الفبائی کوتاه) از يک دستورالعمل ماشين است، که به اين صورت معنی دستور واضح تر از کد زبان ماشين می شود.
مثال 1. کلمه mov نمادی برای عمل انتقال داده است. دستور اسمبلی زير جمع ثبات AL و عدد 5 را نشان می دهد.
mov AL,5
مثال 2. کلمه add يک نماد برای دستورالعمل جمع است. دستور جمع ثبات های EAX و EBX به صورت زير نوشته می شود.
add EAX, EBX
مشاهده می شود که به اينصورت درک معنی دستور بسيار روشن تر از کد ماشين معادل است.
مثال 3. دستوری که عملوندی ندارد و فلگ carry را صفر می کند.
clc
مثال 4. دستور زير عدد يک را به ثبات AX اضافه می کند.
inc AX
مثال 5. دستور جمع مقدار متغير Count با محتوای ثبات به صورت زير است.
mov AX,Count
هر دستور اسمبلی می تواند همراه با ليستی از عملوند ها باشد. فرم کلی دستورالعمل های اسمبلی به صورت زير است:
mnemonic operand(s)
عملوند دستورالعمل می تواند از انواع زير باشد :
• ثبات. عملوندهائی که
مستقيما به محتوای ثبات های پردازنده مراجعه می کنند. مانند ثبات AL در مثال 1.
• متغير يا حافظه ای. عملوندهائی که به داده ای در حافظه اشاره دارند. مانند متغير
Count در
مثال 5.
• فوری. اين عملوندها مقادير ثابتی هستند که در داخل دستورالعمل قرار می گيرند. در
مثال 1عدد 5 يک عملوند فوری است.
• ضمنی. عملوندهائی که صريحا در دستور ذکر نمی شوند. در مثال 4عدد يک با ثبات AL جمع می شود. عدد يک عملود
ضمنی است.
يک کامپيوتر نمی تواند مستقيما زبان اسمبلی را تفسير کند و تنها قادر به اجرای کدهای زبان ماشين است. اسمبلر برنامه ای است که فايل متنی حاوی دستورات اسمبلی را خوانده و نمادهای اسمبلی را به کدهای زبان ماشين تبديل می کند. البته کامپايلرها هم برنامه هائی هستند که عمل مشابه را برای زبان های سطح بالا انجام می دهند، اما اسمبلر به مراتب از کامپايلر ساده تر است، زيرا هرعبارت زبان اسمبلی تنها يک دستورالعمل ماشين را نشان می دهد. عبارات زبان سطح بالا پيچيده تر هستند و ممکن است به دستورالعمل های ماشين بيشتری نياز داشته باشند.
يک تفاوت مهم ديگر بين اسمبلی و زبان های سطح بالا اين است که هر نوع CPU زبان ماشين و زبان اسمبلی مخصوص به خود را دارد. انتقال برنامه های اسمبلی روی معماری های مختلف کامپيوتر به راحتی برنامه های سطح بالا نيست.
محبوب ترين اسمبلرها برای پردازنده ها ی خانواده اينتل عبارتند از:
• ماکرواسمبلر Microsoft’s Assembler MASM
• توربو اسمبلر Borland’sAssembler TASM
• و ASM86
برنامه ديگری که برای رديابی اجرای برنامه و بررسی محتوای حافظه کاربرد دارد ديباگر(Debugger) است که استفاده از آن بهترين راه برای يادگيری برنامه های اسمبلی و روند اجرای آنهاست. ديباگر برنامه ای است که اجازه بررسی ثبات ها و حافظه را بعد از اجرای هر دستور برنامه می دهد و خصوصا برای تست برنامه های اسمبلی مفيد است.
برنامه Debug از جمله ساده ترين ديباگرهاست که توسط MS-DOS عرضه شده است. CodeView همراه با ميکروسافت اسمبلر می آيد که اجازه می دهد کد منبع برنامه ها، بلاک های حافظه و ثبات ها را مشاهده کنيد. Turbo Debugger بورلند هم به همين صورت است.
يک برنامه ديگر همراه با اسمبلر برنامه لينکر(Linker) است که فايل های مجزای توليد شده توسط اسمبلر يا کامپايلر را به يک برنامه اجرائی تبديل می کند. برنامه Link که همراه فايل های MS-DOS می باشد يکی از متداولترين برنامه های لينکر می باشد.
يادگيری زبان اسمبلی بايد با فراگيری مفاهيم سيستم عامل و معماری کامپيوتر توام باشد تا به درک بهتر برنامه های اسمبلی و تعامل آن با کامپيوتر کمک کند. به چند دليل ممکن است کسی بخواهد زبان اسمبلی را ياد بگيرد و از آن استفاده کند:
• زبان اسمبلی وسيله خوبی برای يادگيری نحوه کار کامپيوتر،
کامپايلرها و زبان های سطح بالا است و به درک عميق تر معماری کامپيوتر، مفاهيم
سيستم عامل، نمايش داده ها و دستگاه های سخت افزاری کمک می کند که دانستن آنها
باعث می شود برنامه نويس از عهده اشکالزدائی و رفع مسائل برنامه نويسی در سطح بالا
بهتر برآيد و نرم افزارهای پربارتری را در زبان های سطح بالا مانند ++C پياده سازی کند.
• برنامه های اسمبلی سريع تر، کوچکتر و با توانائی های بيشتر از زبان های ديگر
هستند و معمولا حافظه و زمان اجرای کمتری را نياز دارد. گاهی نوشتن کد در اسمبلی
سريعتر و کوتاهتر از کدکامپايل شده می شود. يک برنامه ويژوال بيسيک می تواند
زيربرنامه های DLL نوشته شده در زبان اسمبلی
را برای افزايش سرعت برنامه در حالات بحرانی فراخوانی کند.
• برنامه های اسمبلی می توانند براحتی از محدوديت های موجود در زبان های سطح بالا
عبور کنند و کنترل بيشتری نسبت به نيازمندی های سخت افزاری خاص ارائه دهند. برخی
از اعمال در زبان های سطح بالا دشوار يا غير ممکن است، مانند ارتباط با سيستم عامل
يا دسترسی مستقيم به کنترلرها. يک برنامه نويس مجرب می تواند با نوشتن کد بيشتر
راهی برای گذشتن از اين محدوديت ها پيدا کند اما خوانائی برنامه کاهش پيدا می کند.
زبان اسمبلی، در مقابل، محدوديت های کمی دارد و تقريبا همه چير را به نظر برنامه
نويس واگذار می کند.
اين دلايل نشان می دهند که فراگرفتن اسمبلی می تواند مفيد باشد حتی اگر هيچوقت با آن برنامه ای نوشته نشود.
امروزه توليد برنامه ای که کاملا با زبان اسمبلی باشد غير معمول است، زيرا برنامه نويسی در زبان سطح بالا بسيار ساده تر از اسمبلی است علاوه براين استفاده از اسمبلی باعث می شود حمل برنامه به کامپيوترهای مختلف دشوارتر شود. در حقيقت بندرت کسی کاملا در زبان اسمبلی برنامه می نويسد. در عوض اسمبلی برای بهينه سازی بخش های حساس برنامه و افزايش سرعت و دسترسی به سخت افزار و نوشتن برنامه های PROM استفاده می شود.
البته زبان برنامه نويسی C کيفيت منحصر به فردی در عرضه کردن مصالحه بين ساختار سطح بالا و جزئيات سطح پايين دارد. اکثر کامپايلرهای C توانائی توليد کد منبع اسمبلی را دارند. برنامه نويسان اغلب ترکيب C و اسمبلی را در برنامه های کاربردی به کار می برند.
محاسبات کامپيوتري در مبناي دو انجام مي شود. به طور معمول از سيستم عددي هگزادسيمال براي نمايش اعداد باينري استفاده مي شود.
سيستم هاي عدد نويسي
سيستم عددی اعشاری
سيستم عددی دودوئی
سيستم عددی هگز
در کارهای روزمره از سيستم عددی اعشاری يا مبنای 10 استفاده می شود. اين سيستم برای کامپيوتر مناسب نيست و برای سادگی سخت افزار، کليه اطلاعات به شکل بيت های روشن و خاموش رمز می شوند. بنابراين سيستم عددی باينری که تنها شامل ارقام صفر و يک است برای اين منظور بسيار مناسب است. عدد 1 (on) مشخص کننده +5 ولت و عدد صفر (off) مشخص کننده 0.5 ولت است.
برای تعيين مبنای عدد يک حرف کوچک در انتهای آن قرار می گيرد. مثاال 45h به معنی عدد 45 در مبنای شانزده است. و 11010011b يعنی اين عدد در مبنای 2 است. اين روشی است که اسمبلر اعداد را در برنامه های اسمبلی تشخيص می دهد.
اعداد اعشاری يا مبنای 10 از 10 رقم (0 تا 9) تشکيل شده اند. هر رقم به توانی از 10 مرتبط است که نشان دهنده ارزش مکانی رقم در عدد است.
234 = 2 × 102 + 3
× 101 + 4 × 100
= 200 + 30 + 4
سيستم باينری بر اساس تنها دو وضعيت است: روشن (1) يا خاموش (0)، بنابراين درمبنای 2 است. يک رقم باينری يک بيت ناميده می شود (در واقع کلمه Bit مخفف BinaryDigit است).
جدول توان هاي 2
جدول
نمايش اعداد 0 تا 15 در مبنای دو
مقدار يک عدد باينری بر اساس بيت های 1 و ارزش مکانی آنها بدست می آيد. ارزش مکانی هر بيت توانی از 2 است. برای محاسبه مقدار اعشاری يک عدد باينری، کافی است هر رقم از راست به چپ در ارزش مکانی اش ضرب شده سپس کليه اعداد با هم جمع شوند.
مثال 1. تبديل عدد 11001b به مبنای 10.
Binary:
11001
Decimal: 1 × 2^4 + 1 × 2^3 + 0 × 2^2 + 0 × 2^1 + 1 × 2^0
= 16 + 8 + 0 + 0 + 1
= 25
مثال 2. تبديل عدد باينری 10010000 به مبنای 10.
Binary:
1 0 0 1 0 0 0 0
Decimal: 1×2^7 + 0×2^6 + 0×2^5 + 1×2^4 + 0×2^3 + 0×2^2 +
0×2^1 + 0×2^0
=128 + 0 + 0 + 16 + 0 + 0 +
0 + 0
=144
کاراکتر ^ نشان دهنده عمل توان است.
چندين روش برای تبديل اعداد اعشاری به باينری وجود دارد. يک روش متداول تقسيم های متوالی بر 2 است. به اين ترتيب که عدد اعشاری بر 2 تقسيم می شود، باقيمانده بعنوان رقم باينری نگهداشته و خارج قسمت مجدد بر 2 تقسيم می شود اين عمل تا زمانی که خارج قسمت صفر شود ادامه پيدا می کند.
مثال. تبديل عدد 43 به مبنای 2
|
عدد |
خارج قسمت |
باقيمانده |
|
43 ÷ 2 |
21 |
1 |
|
21 ÷ 2 |
10 |
1 |
|
10 ÷ 2 |
5 |
0 |
|
5 ÷ 2 |
2 |
1 |
|
2 ÷ 2 |
1 |
0 |
|
1 ÷ 2 |
0 |
1 |
با قرار دادن باقيمانده های تقسيم از پايين به بالا عدد باينری 101011 بدست می آيد.
جمع باينری ساده به صورت زير محاسبه می شود:
0 + 0 = 0
0 + 1 = 1
1 + 1 = 10
1 + 1 + 1 = 11
برای جمع و عدد باينری کافی است بيت به بيت از سمت راست به چپ عمل جمع انجام شود. رقم نقلی حاصل از هر ستون در جمع ستون بعدی اعمال می شود.
|
1 |
1 |
||||
|
1 |
1 |
0 |
1 |
1 |
|
|
+ |
0 |
0 |
0 |
0 |
1 |
|
|
1 |
1 |
1 |
0 |
0 |