|
پرشهاي غير شرطي
اگر با زبانهائي مثل Basicيا Pascalا برنامه نويسي كرده باشيد حتما از دستور Goto
هم استفاده كرده ايد بوسيله اين فرمان ، ما ميتوانستيم روال
اجراي برنامه را به
يك نقطه مشخص انتقال بدهيم بدون اينكه نياز به برقراري شرط خاصي باشد .
در زبان اسمبلي هم چنين دستوري داريم : دستورالعمل JMP
دستور JMP به اين شكل استفاده ميشود:
برچسب JMP
منظور از برچسب مكاني از برنامه است . در اسمبلي براي اينكه يك نقطه
از برنامه
را علامت بزنيم ، نام برچسب مورد نظر را مينويسيم و براي اينكه اسمبلر
آن را با
يك دستورالعمل اجرائي اشتباه نكند، كاراكتر را در مقابل آن قرار
ميدهيم
مانند: :Start
سپس ميتوانيم با دستور JMP به آنجا پرش كنيم :
Start :
:
:
Jmp Start
دقت كنيد كه بعد از Start ي كه در مقابل JMP نوشتيم علامت قرار نداده ايم .
اين JMP ها از نوع JUMP NERA هستند و نوعي ديگر بنام JUMP FAR هم وجود دارد .
مثال : برنامه اي كه در مثالهاي قبل نوشتيم را در نظر بگيريد
اگر ما از روي
دستورالعملهاي برنامه با JMP پرشي انجام دهيم هيچكدام از آن كدها اجرا نخواهندشد:
1] JMP
Quit _
2] mov ax/0E07h
3] int 10h
4] Quit :_
5] int 20h
برنامه از روي سطرهاي 2وَ3 پرش خواهد كرد .
ثبات پرچم (Flags)
ثبات پرچم يك ثبات 16 بيتي است كه 1يا 0ا بودن بيتهاي آن نشانه درست
يا
نادرست بودن يك شرط است . مثلا اگر با دستورالعمل خاصي (ميخوانيم )
تست كنيم
كه آيا ثبات BX
مقدار 0 را دارد ، در اين صورت بيت 6 برابر 0 ميشود و ... .
از اين 16 بيت فقط 9 بيت استفاده ميشود كه به شرح زير هستند :
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
* * * * * O
D I T S Z * A * P * C
علامت * به معناي بي استفاده بودن است .
1- پرچم نقلي يا (CF) . بيت 0 در نتيجه اجراي وقفه ها يا بعضي اعمال حسابي تغيير
ميكند .
2-پرچم توازن (ZF) . بر اساس يك عمل مقايسه اي يا حسابي تغيير ميكند . اگر
نتيجه يك عبارت 0 باشد مقدار 1 و اگر نتيجه 1 باشد مقدار 0 ميگيرد.
3-پرچم وقفه (IF) . اگر 0 باشد هيچ وقفه اي نميتواند اجرا شود و اگر 1 باشد
ميتوان وقفه ها را فراخواني كرد .
**********************************************************************************
دستور مقايسه اي CMP
براي مقايسه مقاديراز
دستور CMP (مخفف CoMPare) استفاده ميكينم . اين
دستور
مقدار داخل يك ثبات يا متغير را با مقداري ديگر مقايسه كره و روي ثبات
هاي
CFو ZFو تاثير ميگذارد . بعد از مقايسه ميتوانيم بر حسب وضعيت پرچمها پرش
لازم را انجام دهيم .
مثلا CMP
BX/0 تست
ميكند كه آيا مقدار BX برابر 0 است يا نه . در صورتي كه برابر
0
باشد ،پرچم ZF برابر 1 ميشود .
با همين دستور CMP
ميتوانيم كوچكتر،بزرگتر و .... را هم تست كنيم .
پرشهاي شرطي
براي پرشهاي شرطي از دستورهاي زير درست مثل JMP استفاده ميكنيم .
JE/JZ : اگر محتواي ZF صفر باشد جهش ميكند . اگر دو مقداري كه مقايسه كرده ايم
برابر باشد پرش انجام مي شود.
JNE/JNZ : برعكس JZو JEو هستند و اگر ZF يك باشد (بعبارتي دو مقداري
كه مقايسه
كرديم برابر نباشند) جهش انجام ميشود.
JA/JNBE . اگر محتواي ثبات يا متغيري كه مقايسه كرده ايم بزرگتر از عدد مورد
نظر
باشد پرش انجام ميدهد . مثلا :
mov bh/1
cmp bh/10
ja Dest
مقدار BH
برابر 1 است و در سطر دوم تست آن را با 10 مقايسه ميكنيم . در سطر سوم چون BH بزرگتر از 1 نيست ، پس پرش JA Dest انجام نميشود .
JAE/JNB : اگر بزرگتر يا مساوي باشد ، پرش انجام ميشود.
JB/JNAE: در صورتي كه كوچكتر باشد
پرش انجام ميشود.
JBE : در صورتي كه كوچكتر يا مساوي
باشد پرش انجام ميشود .
مثال :
ميخواهيم برنامه اي بنويسيم كه تمام كاراكترهاي بين 128 تا 255 را
چاپ كند.
. MODEL SMALL
. CODE
ORG 100H
START :
كاراكتر 128 براي شروع ; MOV CH/128 CHARS :
كداسكي را درAL
قرار ميدهيم تا چاپ شود ; MOV AL/CH
سرويس 0Eh براي چاپ كاراكتر ; MOV AH/0EH
اينتراپت 10h
; INT 10H
يكواحد به CH اضافه كن ; INC CH
مقايسه CH با 255 ; CMP CH/255
اگر مساوي نباشد به CHARS پرش ميكند ; JNZ CHARS
پايان ; INT
20H END START
تمام برنامه ساده و روشن است ولي در
سطر آخر نكته جديدي وجود دارد . بعد از
END نام برچسب Start را آورده ايم نكته اي
كه در نوشتن برنامه هاي اسمبلي بايد
مراعات كنيم اينست كه : اگر از برچسبي در برنامه استفاده ميكنيم ،
اسمبلر بايد
يك برچسب را به عنوان نقطه آغاز كدبرنامه ببيند . به همين خاطر علاوه
بر برچسب
CHARS يك برچسب بنام Start هم در ابتداي برنامه تعريف
كرده و براي اينكه
اسمبلر بداند که ما كدام برچسب را براي اینكار اينخاب كرده ايم ، نام
آن را در
مقابل END مي آوريم ، يعني END START .
نكته ديگر اينكه ، در اسمبلر هر چيزي كه بعد از كاراكتر
فرض شده و اصلا ترجمه نميشود . (مثل REM در بيسيك و .. ) . هر comment
بايد در يك سطر جاي داده شود و اگر از اين مقدار بيشتر بود ميتوانيم
در سطر بعد
هم يك كاراكتر درج كرده و ادامه توضيحات را بعد از آن بياوريم .
*********************************************************************************************
دستورالعمل LOOP
تا اينجا هروقت كه ميخواستيم يك حلقه ايجاد كنيم از دستورالعمل CMP و پرشهاي
شرطي استفاده ميكرديم . راه ساده تري براي اجراي مكرر دستورالملها وجود دارد
و آن
استفاده از LOOP است . دستور LOOP به تعداد دفعاتي كه با ثبات
CX مشخص ميكنيم
حلقه اي را ايجاد ميكند .
براي ايجاد چنين حالتي ابتدا مقدار لازم را در ثبات CX قرار ميدهيم . دستور Loop
هميشه از مقدار CX
يك واحد،يك واحد كم ميكند تا به 0 برسد . وقتي كه مقدار CX
برابر 0 شد ، از حلقه خارج ميشود . بنا براين براي ايجاد حلقه اي كه 100 بار
تكرار شود، CX را برابر 100 قرار ميدهيم .
MOV
CX/100
حلقه مورد نظر بين دستور loop و يك برچسب انجام مي شود . برچسب
، در ابتداي حلقه
و دستور loop در انتهاي آن قرار ميگيرد.
MOV
CX/100
LPCNT :
:
:
:
LOOP
LPCNT
در بالا با mov cx/100 ميخواهيم حلقه اي داشته باشيم كه 100 بار انجام بشود. وقتي
به loop lpcnt ميرسيم ، يكواحد از مقدار CX كاسته شده و مجددا به lpcnt پرش
ميكنيم .
تمرين : برنامه اي بنويسيد كه كاراكتر هاي با كد اسكي 32 تا 255 را نمايش
دهد.
راهنمائي :
چون هميشه CX در حال كاهش است ، براي
اينكه بتوانيم از 32 تا 255 برويم ، بايد
عدد داخل CX را برابر 31=224-َ255 قرار
بدهيم تا تعداد 254 حرف چاپ بشود. سپس
مقدار CX را از 255 كم كرده و داخل AL قرار ميدهيم تا با تابع 0Eh ار وقفه 10h
چاپ شود اين وقفه را در برنامه ALLCHR.ASM توضيح داديم .
پشته (Stack) ، ذخيره و بازيابي ثباتها
ما تعدادي ثبات براي نگهداري و انتقال اعداد و مقادير داريم ولي كافي نيستند
.
بخصوص در DEBUG كه نميتوانيم متغيرتعريف
كنيم . يا در برنامه پيش مي آيد
بخواهيم براي يك كار خاص و بطور موقت مقدار ثبات را تغيير دهيم ،در اين
مواقع
مقدار ثبات را در پشته ذخيره كرده و بعدا مجددا بازيابي ميكنيم .
در برنامه هاي EXE.
پشته يا Stack يك سگمنت مستقل است و آدرس
آن در ثبات SS
(Stack
Segment)
قرار دارد . در برنامه هاي COM. پشته به آن صورت وجود ندارد و
خود DOS فضاي لازم را براي برنامه
فراهم ميكند . در هر صورت ما به اينكه پشته در
كجاست كاري نداريم و به يك شكل مقادير را به پشته فرستاده (PUSH) يا از آن
خارج ميكنيم (POP)
.
خاصيت مهمي كه در PUSHو POPو كردن مقادير به پشته
وجود دارد اينست كه هميشه
اولين مقداري كه به پشته فرستاده ميشود، آخرين مقداري است كه از پشته خوانده
ميشود . مثلا فرض كنيد كه ابتدا AX و بعد CX را به پشته ميفرستيم . حال براي خارج كردن
درست اين مقادير، ابتدا CX و بعد AX را خارج ميكنيم .
اين قانون اسمبلي است و به (FILO=First In Last Out) معروف است .
براي فرستادن مقدار يك ثبات به پشته از دستور PUSH استفاده ميكنيم .
مثلا براي قرار دادن AX مينويسيم : PUSH AX . PUSH
نميتواند
مقدار يك نيم ثبات را در پشته
قرار دهد و حتما بايد يك ثبات كامل دوبايتي باشد .
وقتي ثباتي را PUSH كرديم ، مقدار آن در Stack نگهداري ميشود و ميتوانيم مقدار آن
را تغيير دهيم .
پس از آن ، از دستور POP براي خارج كردن ثبات از پشته استفاده ميكنيم مانند . POP AX
مثال :
1] MOV
AX/0AH ; ax = 0Ah
2] MOV
BX/0BH ; bx = 0Bh
3] PUSH AX ; push ax to stack
4] PUSH
BX ; hold bx in stack
5] MOV
AX/5 ; now ax=5
6] MOV
BX/2AH ; and bx=2Ah
7] : ; other
commands and
8] : ; statements ...
9] POP
BX ; POP bx from stack
10] POP
AX ; read ax from stack
در سطر 3وَ4 مقادير axو bxو را به پشته ميفرستيم . در سطر 5و 6و مقادير جديد به ax
bx/ ميدهيم و بعد از آن يكسري دستورات ديگر هستند
... . در سطر 10 مقدار BX
از داخل Stack بيرون كشيده ميشود . توجه
داشته باشيد كه bx را بعد از ax در پشته
قرار داده ايم ولي در هنگام خارج كردن به ترتيب عكس عمل ميكنيم .
بعلاوه دستور PUSHF به معني PUSH FLAGS ، ثبات پرچم را در پشته قرار ميدهد . نحوه
كار با آن هم مثل PUSH معمولي است ولي آرگومان ندارد .
|