اسمبلی (فصل هفتم)
rofessional Site For Computer Students
 

 

 

 

 

 

پرسشهای شرطی و تکرار

 

 

 

 

 

 

Post پرسشهای شرطی و تکرار

 


 

 

پرشهاي غير شرطي

 اگر با زبانهائي مثل
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
سرويس 0
Eh براي چاپ كاراكتر ; MOV AH/0EH
اينتراپت 10
h ; 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 معمولي است ولي آرگومان ندارد .