1. مهمان گرامی، جهت ارسال پست، دانلود و سایر امکانات ویژه کاربران عضو، ثبت نام کنید.
    بستن اطلاعیه

آموزش اسمبلی از پایه تا پیشرفته

شروع موضوع توسط minaaa ‏26/1/11 در انجمن Assembly

  1. کاربر پیشرفته

    تاریخ عضویت:
    ‏9/12/10
    ارسال ها:
    19,795
    تشکر شده:
    6,456
    امتیاز دستاورد:
    113
    حتما با ثابتها در زبانهائي مثل پاسكال آشنائي داريد . بعنوان مثال با جمله
    ے Const MaxLen=1024; ، ثابتي بنام MaxLen تعريف شده و مقدار آن برابر 1024 قرار
    ے قرار ميگيرد . پس از آن كامپايلر در هرجا كه MaxLen را مشاهده كند عدد 1024 را
    بجاي آن قرار ميدهد .
    در زبان اسمبلي براي تعريف يك ثابت از معرفه EQU به شكل زير استفاده ميكنيم

    مقدار EQU نام ثابت
    مثلا : MaxLen EQU 1024
    ے به اين ترتيب اسمبلر هميشه بجاي MaxLen عدد 1024 را قرار ميدهد . بهمين دليل
    ثابتهاي برنامه را بايد قبل از جمله CODE. بنويسيم . مثال :


    . MODEL SMALL
    SECTORS EQU 18
    SIDES EQU 2
    . CODE
    :
    :


    ے به اين خاطر ثابتها را قبل از CODE. تعريف ميكنيم كه در برنامه كامپايل شده اثري
    از نام ثابت نبوده بلكه مقدار هر ثابت در جاي لازم قرار گرفته است .
    مثال :

    . MODEL SMALL
    BELL EQU 7
    . CODE
    ORG 100H
    MOV AH/0EH
    MOV AL/BELL
    INT 10H
    INT 20H
    END



    متغيرها

    ے از متغيرها براي نگهداري موقتي داده ها استفاده ميكنيم . مثلا در زبان پاسكال
    ے ميتوانيم با عبارت Var يك متغير تعريف كنيم مثل Var Buffer:Byte; و در زبان
    سي مثل unsigned char Buffer; .
    ے متغيرها در زبان اسمبلي بايد حتما در داخل قطعه داده (DS) تعريف بشوند و در
    ے برنامه هاي COM. هم از آنجائي كه قطعه داده ها و كد يكي است ميتوانيم در قطعه كد
    نيز تعريف كنيم .
    ے براي تعريف يك متغير بايد بعد از نام آن يكي از عبارات ..DB/DW/DD/ را
    ے بياوريم . DB مشخصه نوع بايت ،DW مشخصه نوع Word (دوبايتي ) و DD مشخصه نوع
    (Double Word) 4 بايتي است .
    مثلا :

    . CODE
    SIZE DW 1024
    BELL DB 7


    ے در اين مثال Size يك متغير دو بايتي بوده و مقدار اوليه ان 1024 است و BELL نيز
    يك متغير تك بايتي با مقدار 7 ميباشد .
    ے اگر نميخواهيم به متغير مقدار اوليه بدهيم ، ميتوانيم از علامت (?) بجاي مقدار
    استفاده كنيم مانند : MaxLen DW ?

    ے براي تعريف يك رشته كاراكتري از معرفه DB استفاده كرده و محتواي رشته را داخل
    ('') يا ("") قرار ميدهيم . مثلا :

    MSG DB "ASSEMBLY / A QUICK LOOK ! "


    ے در اين مثال MSG يك متغير كاراكتري است . در اسمبلي ميتوانيم از كد اسكي
    ے كاراكتر ها نيز استفاده كنيم . مثلا اگر در تعريف DB بخواهيم كدهاي اسكي 13و 10
    را به MSG اضافه كنيم ميتوانيم با كاما اين كار را انجام دهيم :


    MSG DB "ASSEMBLY / A QUICK LOOK ! "/13/10


    يا : MSG DB "ASSEMBLY / A QUICK LOOK ! "/0Ah/0Dh

    يا حتي : MSG DB "ASSEMBLY / A QUICK LOOK ! "/0Ah/0Dh/'$'


    اين تركيبها همه يك رشته كاراكتري معرفي ميكنند .

    براي تعريف آرايه ها نيز از روشي مشابه و به شكل زير استفاده ميكنيم :

    (مقدار اوليه )DUP تعداد عناصر DB/DW/DD نام متغير
    مانند: BUFFER DB 1024 DUP(0 )

    كه ارايه اي يك كيلوبايتي تعريف كرده و همه عناصر آن را با 0 پر ميكند.
    اگر نخواهيم مقدار اوليه اي در نظر گرفته شود از ? استفاده ميكنيم .
    مانند: BUFFER DB 1024 DUP(? )

    و براي تعريف يك آرايه حرفي بايد با يك حرف يا عبارت آن را پر كنيم : BUFFER DB 1024 DUP("A" )

    و حتي : BUFFER DB 1024 DUP("STACK" )


    ے گفتيم كه متغيرها هميشه (در برنامه هاي COM.) در قطعه كد و بعد از CODE. نوشته
    ے ميشوند ، بنا براين اسمبلر هميشه سعي خواهد كرد كه آنها را بصورت يك كدماشين
    ے قابل اجرا تفسير كند. به همين دليل هميشه بايك دستور JMP از روي آنها پرش
    ميكنيم . مثال :


    . MODEL SMALL
    RDISK EQU 2
    . CODE
    ORG1 100H
    START :
    JMP MAIN
    BUFFER DB 512 DUP(0 )
    MSG DB "DISK DUP."/13/10/'$'
    MAIN :


    مجموعه كدهاي اجرايي برنامه :
    : END START

    همانطور كه ميبينيد با دستور JMP MAIN از قسمت تعريف داده ها پرش كرده ايم .
     
  2. کاربر پیشرفته

    تاریخ عضویت:
    ‏9/12/10
    ارسال ها:
    19,795
    تشکر شده:
    6,456
    امتیاز دستاورد:
    113
    در اين قسمت يك تمرين جديد انجام داده و بوسيله آن تجربيات خودمان را افزايش
    ميدهيم . اين تمرين اولين برنامه ما هست يك عمليات سطح پائين سيستم ، يعني
    دسترسي به ديسك ، را انجام ميدهد .

    تابع شماره 2(AH=2() از وقفه 13h كه وقفه ديسك ميباشد ، براي خواندن سكتورهاي
    ديسك بكار ميرود . وقتي شماره هد، شيار،سكتور و ... را مشخص كرده و وقفه را
    فراخواني نموديم ، محتواي قطاع خوانده شده در محلي كه با جفت ثبات ES:BX مشخص
    ميشود قرار ميگيرد. به همين دليل ما يك آرايه تعريف ميكنيم وآدرس آن را در ES:BX
    قرار ميدهيم تا اطلاعات خوانده شده در آن قرار بگيرد. BUF DB 512 DUP(0)

    در اين مثال ما ميخواهيم برنامه اي بنويسيم كه محتواي قطاع بوت كننده ديسكي را
    خوانده و نمايش دهد . چون ميخواهيم يك سكتور را بخوانيم و اندزه هر قطاع 512
    بايت است ، پس آرايه اي با 512 عنصر تك بايتي تعريف كرده ايم .
    در قدم بعدي شماره شيار (0-79) را در CH، شماره قطاع (1-18) را در CL، شماره
    درايو را در DL(.../.:0=A ) ، رويه ديسك را در DH(0=1st Side() و تعداد قطاعهائي
    كه بايد خوانده شوند را در AL قرار ميدهيم .

    MOV AX/0201H
    MOV CH/0 ;TRACK NUMBER
    MOV CL/1 ;SECTOR NUMBER
    MOV DH/0 ; SIDE #1
    MOV DL/0 ; 0=A / 1=B /( ...DRIVE NUMBER )



    حالا بايد آدرس بافر تعريف شده (BUF) را به ES:BX منتقل كنيم . گفتيم كه براي
    بدست آوردن شماره سگمنت هر متغير از Seg و براي بدست آوردن مقدار آفست از Offset
    استفاده ميكنيم . چون برنامه ما COM. است ، پس عدد سگمنت بطور خودكار در
    ثبات DS هست و احتياجي به يافتن آن نداريم . بلكه فقط بايد آن را به ES منتقل
    كنيم .
    گفتيم كه نميتوانيم ثبات ESو DSو را مستقيما و با MOV به هم منتقل كنيم ، بلكه
    بايد از يك ثبات همه منظوره مثل AX كمك بگيريم . بنا براين و براي اينكه مقدار
    فعلي ثبات AX از بين نرود، ابتدا AX را در Stack قرار داده و مقدار DS را در آن
    قرار ميدهيم : PUSH AX ; SAVE AX
    MOV AX/DS

    و پس از آن محتواي AX را به ES داده و دوباره مقدار AX را از پشته POP ميكنيم : MOV ES/AX
    POP AX

    پس از آن با دستور LEA مقدار آفست BUF را بدست مي آوريم : LEA BX/BUF

    و در نهايت فراخواني اينتراپت 13h. INT 13H


    بقيه برنامه عبارتست از چاپ كاراركترهاي داخل آرايه BUF كه قبلا آن را ياد
    گرفتيم . فقط به اين نكته توجه ميكنيم كه كدهاي اسكي كوچكتر از 32 كدهاي كنترلي
    بوده و به جاي آنها بايد كاراكتر (.) چاپ كنيم به همين دليل هم قطعه كدي براي آن
    نوشته ايم :


    MOV AL/BUF[BX]
    CMP AL/32
    JB SKIP
    :
    :
    SKIP :
    MOV AL/'.'
    INT 10H
    :
    :


    ليست كامل :

    .MODEL SMALL
    .CODE
    ORG 100H
    START:
    JMP MAIN
    BUF DB 512 DUP(0)
    MAIN:
    MOV AX/0201H
    MOV CH/0 ;TRACK NUMBER
    MOV CL/1 ;SECTOR NUMBER
    MOV DH/0 ; SIDE #1
    MOV DL/0 ; 0=A / 1=B /( ...DRIVE NUMBER)
    PUSH AX ; SAVE AX
    MOV AX/DS
    MOV ES/AX
    POP AX
    LEA BX/BUF
    INT 13H

    MOV BX/1
    MOV AH/0EH ; WRITE CHAR.
    PRINT:
    MOV AL/BUF[BX]
    CMP AL/32
    JB SKIP
    INT 10H
    JMP CONT
    SKIP:
    MOV AL/'.'
    INT 10H
    CONT:
    INC BX
    CMP BX/513
    JNZ PRINT
    INT 20H
    END START
     
  3. کاربر پیشرفته

    تاریخ عضویت:
    ‏9/12/10
    ارسال ها:
    19,795
    تشکر شده:
    6,456
    امتیاز دستاورد:
    113
    عملگرهاي بيتي

    عملگرهاي بيتي مانند عملوندهاي حسابي هستند با اين تفاوت كه روي بيت ها كار
    ميكنند. اين عملگرها عبارتند از : ... AND/OR/XOR/SHR/SHL/RCL/RCR/ .

    عملگر AND : اين اپراتور بيتهاي دو عدد(متغير) را با هم AND كرده و حاصل را در
    متغير (يا ثبات ) سمت چپ قرار ميدهد . اگر فرض كنيم كه هميشه 1 بودن بيت به
    معناي Trueو 0و بودن آن به معناي False است ، AND هميشه در صورتيكه هر دوبيت
    مقايسه شونده 1 باشند، حاصل 1يا Trueا را بر ميگرداند .
    جدول ارزشي AND :
    X | Y | X and Y |

    1 | 1 | 1 |
    1 | 0 | 0 |
    0 | 1 | 0 |
    0 | 0 | 0 |


    پس وقتي ما عملوند AND را با دو رجيستر بكار ميبريم ، بصورتي كه گفته شد بيتها
    با هم مقايسه شده و حاصل مقايسه در محل متناظر بيتها در ثبات سمت چپ قرار
    ميگيرند . مثلا اگر دستور AND Ah/Dh را اجرا كنيم ، حالتي نظير شكل زير را داريم :
    AH : 01101010
    DH : 01111101

    AH :AH AND DH : 01101000


    به نتيجه بدست آمده توجه كنيد .
    هر وقت كه بخواهيم بيت هاي خاصي از يك رجيستر را 0 كنيم ، يك عدد باينري كه
    همه بيتهاي آن ، بجز بيتهاي مورد نظر 1 هستند را در نظر گرفته با رجيستر مورد نظرAND
    ميكنيم .مثلا اگر بخواهيم بيتهاي دوم و سوم ثبات AX را صفر كنيم : AND AX/11111001b

    عملگر OR :
    اين عملوند بيتهاي دو عدد را با هم مقايسه كرده و اگر يكي از آن دو 1 بود ، بيت
    متناظر در ثبات سمت چپ را 1 ميكند . مثلا با دستور OR AH/DH بيتهاي AHبا DHا
    مقايسه شده و هر دو بيت متناظر كه با هم 0 بودند ، بيت تناظر در AHهم 0 ميشود
    AH : 01101010
    DH : 01111100

    AH : AH OR DH : 01111110


    هرگاه كه بخواهيم بيت هاي خاصي از يك متغير يا رجيستر را 1 كنيم ، يك عدد
    باينري كه همه بيتهاي آن غير از بيتهاي مورد نظر 0 هستند در نظر گرفته و با ثبات
    مورد نظر OR ميكنيم . مثلا اگر بخواهيم دو بيت پائين AHرا 1ا كنيم منويسيم : OR AH/00000011b


    عملگر : XOR
    عملوند XOR تنها در صورتي نتيجه 1 ميدهد كه دو بيت مقايسه شونده غيرهم ارزش
    باشند . يعني يكي 1 و ديگري 0 باشد .
    بعنوان مثال با اجراي XOR AH/DH اين عمليات روي بيتها انجام ميشود
    AH : 01101010
    DH : 01111100

    AH : AH XOR DH : 11101001


    وقتي بخواهيم يك مقدار ثبات را برابر صفر قرار بدهيم ، معمولا از آن را با خودش XOR
    ميكنيم . مثلا XOR CX/CX محتواي ثبات CX را برابر 0 قرار ميدهد .

    عملگرهاي SHRو SHLو :

    اين عملگرها، بيتها را به راست و چپ شيفت ( انتقال ) ميدهند .
    SHR Reg.nnum و SHL Reg.nnum
    .Reg اسم يك ثبات است مثلا AXو numو معلوم ميكند كه چند بيت بايد به طرف
    راست يا چپ انتقال پيدا كند . مثلا SHR AX/6 بيتهاي AXرا 6ا واحد به راست
    انتقال داده و بيتهاي چپ را با 0 پر ميكند . AX :10100010
    AX :SHR AX/4 : 00001010

    SHL
    هم عكس اين عمل را انجام ميدهد . يعني بيتها را به چپ شيفت داده و از
    طرف راست با 0 پر ميكند . AX :10100010
    AX :SHR AX/4 : 00100000

    مثال : اگر بخواهيم كه محتواي نيم ثبات CL را به نيم ثبات CH منتقل كنيم ،
    كافيت كه CXرا 8ا بيت به سمت چپ شيفت بدهيم . يعني SHL CX/8

    CL CH | 10110100 | 00101101 |


    محتواي اوليه CX CX

    CL CH | 00101101 | 00000000 |


    محتواي CX بعد از SHL CX/8
    انتقال
     
  4. کاربر پیشرفته

    تاریخ عضویت:
    ‏9/12/10
    ارسال ها:
    19,795
    تشکر شده:
    6,456
    امتیاز دستاورد:
    113
    در قسمت قبلي چند عملگر بيتي را ديديم . در اين قسمت هم اين مبحص را دنبال
    ميكنيم .
    عملگر Not : عملوند Not ارزش همه بيتهاي يك بايت يا كلمه را برعكس ميكند .
    يعني تمام بيتهاي 1را 0ا و تمام بيتهاي 0را 1ا ميكند . بعنوان مثال اگر AH حاوي
    مقدار 10101101 باشد، بعد از اجراي Not Al ، محتواي AL بصورت 01010010 خواهد
    بود.

    جدول ارزشي Not Not X X N
    F | T
    T | F



    عملگر Neg . اين اپراتور معمولا با Not اشتباه ميشود در صورتي كه كمتر شباهتي بين
    آنها وجود دارد . Neg ارزش عددي يك عدد علامتدار را برعكس ميكند . يعني يك عدد
    منفي را مثبت ميكند و برعكس . در اعداد علامتدار ( همانطور كه بعدا هم خواهيم
    ديد )، اولين بيت سمت چپ ( بيت هشتم ) بيت علامت است . 1 بودن آن نشاندهنده
    منفي بودن و 0 بودن آن نشان دهنده مثبت بودن است .
    عملگر Neg با عكس كردن بيت علامت ، ارزش عدد را عكس ميكند .
    اين عملوند را در مبحث اعداد علامتدار مفصلا ميخوانيم .
    مثال : ميخواهيم برنامه اي بنويسيم كه تمام حروف كوچك يك عبارت را به حروف
    بزرگ تبديل كند . از نظر مقدار عددي ، تفاوت حروف كوچك و بزرگ در اينست كه
    بيت پنجم در حروف بزرگ برابر 0 و در حروف كوچك 1 است . مثلا كداسكي حرف a
    به باينري برابر 01100001 و كد A برابر 01000001 است . پس برنامه اي مينويسيم
    كه تمام كاراكترهاي رشته كاراكتري مورد نظر را خوانده و بيت پنچم آنها را 0 كند
    . در قسمت قبلي ديديم كه براي 0 كردن يك بيت ، يك عدد باينري كه تمام بيتهاي
    آن 1 ، و بيت مورد نظر (براي 0 كردن ) 0 باشد را با عدد مورد نظر AND ميكنيم .


    . MODEL SMALL
    . CODE
    ORG 100H
    START :
    JMP MAIN
    MSG DB ' this is an example/ ..$'
    MAIN :


    بدست آوردن آدرس رشته ; LEA BX/MSG LOOP :_

    قرار دادن كاركتر در AL ; MOV AL/[BX]
    آيا كاراكتر $ است ? ; CMP AL/'$'
    بله ، به MAIN برو ; _JZ END
    بيت پنجم را صفر كن ; AND [BX]/11011111B
    يكواحد به BX اضافه كن - كاراكتر بعدي ; INC BX JMP LOOP _;
    END :_

    قرار دادن آفست رشته در DX ; MOV DX/BX
    تابع 9 براي نمايش رشته ; MOV AH/9
    قفه 21h ; INT 21H
    پايان برنامه ; INT 20H END START


    معمولا برنامه هائي كه پيغامهاي خود را كد ميكنند ( مثل ويروسها ) از اين روش يا
    روشي مشابه براي Decode كردن پيغامها استفاده ميكنند .

    مثال :
    بايت وضعيت صفحه كليد كه مربوط به وضعيت كليد هاي كنترلي CapsLock/NumLock
    در بايوس هاي AT/PS2 در آدرس 0017h:0040h قرار دارد.
    بيتهاي اين بايت نشان ميدهد كه كدام كليد فعال است . 1 بودن به معني روشن بودن
    و 0 به معني خاموش بودن آن است . در مثال زير بيت ششم براي كليد CapsLockرا 1ا
    ميكنيم تا Capslock روشن شود .


    .MODEL SMALL
    .CODE
    ORG 100h
    START:
    PUSH ES
    MOV AX/0040h
    MOV ES/AX
    MOV AL/ES:[17h]
    OR AL/32
    MOV BYTE PTR ES:[17h]/AL
    POP ES
    MOV AH/1
    INT
     
  5. کاربر پیشرفته

    تاریخ عضویت:
    ‏9/12/10
    ارسال ها:
    19,795
    تشکر شده:
    6,456
    امتیاز دستاورد:
    113
    ضرب و تقسيم با 8088
    8088
    براي ضرب دو عدد از دستورالعمل MUL با كد ماشين F7h استفاده ميكند .
    اين دستورالعمل روي كلمه ها ( دوبايتي ها) كار ميكند . بنا براين حاصلضرب دو عدد16
    بيتي ميتواند 32 بيتي يا 2 كلمه اي باشد . به همين دليل براي ذخيره نتيجه ضرب
    يك ثبات تنها كافي نيست . MUL
    هميشه محتواي يك ثبات را در محتواي ثبات AX ضرب كرده و حاصلضرب را در
    جفت ثبات DX:AX ذخيره ميكند . به اينصورت كه دوبايت بالا را در DX و كلمه
    پائين را در AX قرار ميدهد. وقتي از حساب 8088 صحبت ميكنيم ، نوشتن DX:AX به
    معني نگهداري عدد 32 بيتي در آن جفت ثبات است نه محلي از حافظه كه با DX:AX
    مشخص ميشود.
    براي ضرب محتواي يك رجيستر در AX ( هميشه در AX ضرب ميشود) از MUL بصورت زير
    استفاده ميكنيم : MUL Register


    كه منظور از رجيستر يك ثبات مانند DXيا BXا است .
    چون هميشه محتواي رجيستر مورد نظر در AX ضرب ميشود، نيازي به نوشتن AX نداريم .

    بعنوان مثال اگر AX برابر 100hو BXو برابر 7C4Bh باشد ، حاصل MUL BX برابر 7C4B00h
    ميشود و چون اين مقدار يك عدد 32 بيتي است ، در جفت ثبات DX:AX
    نگهداري ميشود به شكلي كه DX=7C4Bhو AXو برابر 0000h باشد.

    عمل تقسيم هم به شيوه مشابهي انجام ميشود.
    وقتي كه دوعدد را به هم تقسيم ميكنيم حاصل تقسيم ( قسمت صحيح يا خارج قسمت ) در AX
    و باقيمانده در DX قرار ميگيرد.

    براي تقسيم كردن دو ثبات به هم ، از دستور DIV استفاده ميكنيم . وقتي از DIV براي
    تقسيم استفاده ميكنيم ، CPU محتواي جفت ثبات DX:AX را بر محتواي ثبات ذكر
    شده تقسيم ميكند بنا براين در هنگام استفاده از DIV فقط نام همان ثبات را ذكر
    ميكنيم . مثلا اگر بخواهيم ( برعكس ضربي كه در بالا انجام داديم ) عدد 7CB400h را
    بر 100h تقسيم كنيم ، BX را برابر 100h و جفت ثبات Dx:Ax را برابر 7CB4100h
    قرار ميدهيم . براي اينكار عدد 7CB4100h را به دو نيمه 007Ch و 4100h تقسيم كرده
    و در DXو AXو قرار ميدهيم . (/ DX:007Ch AX=4100h) . در نهايت با DIV BX عمل
    تقسيم را انجام ميدهيم .
    بعد از انجام تقسيم 7C4Bhدر AXر و 0000hدر DXر قرار ميگيرد.

    مثال براي ضرب

    براي ديدن مطالب گفته شده ، همان دو عدد 100hو 4CBhو را با ديباگ در هم ضرب
    ميكنيم .
    بنا براين Debug را اجرا كرده و سطرهاي زير را وارد ميكنيم .


    17AA:0100 mov ax/100
    17AA:0103 mov bx/4cb
    17AA:0106 mul bx
    17AA:0108 int 20
    17AA:010A
    - t


    پس از وارد كردن برنامه بالا ، از دستور T ( مخفف Trace) كه براي رديابي اجراي
    برنامه بكار ميرود استفاده ميكنيم . با هربار اجراي اين دستور يك خط از برنامه
    اجرا شده و محتواي ثباتها بعلاوه وضعيت فلاگها نمايش داده ميشوند.

    در اين سطر محتواي AX برابر 0100 است


    AX=0100 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
    DS=17AA ES=17AA SS=17AA CS=17AA IP=0103 NV UP EI PL NZ NA PO NC
    17AA:0103 BBCB04 MOV BX/04CB
    - t


    محتواي BX برابر 0$CB شده ...

    AX=0100 BX=04CB CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000
    DS=17AA ES=17AA SS=17AA CS=17AA IP=0106 NV UP EI PL NZ NA PO NC
    17AA:0106 F7E3 MUL BX
    - t


    بعد از انجام ضرب ، محتواي DX برابر 4 و محتواي AX برابر CB00 شد ه . بنابراين
    جفت ثبات DX:AX مقدار 4CB00 را نشان ميدهد . يعني همان عددي كه قبلا هم بدست
    آورده بوديم .


    AX=CB00 BX=04CB CX=0000 DX=0004 SP=FFEE BP=0000 SI=0000 DI=0000
    DS=17AA ES=17AA SS=17AA CS=17AA IP=0108 OV UP EI PL NZ NA PO CY
    17AA:0108 CD20 INT 20
    - t
    - q



    تمرين :

    همين عمل را براي تقسيم نيز با ديباگ انجام بدهيد .
     
  6. کاربر پیشرفته

    تاریخ عضویت:
    ‏9/12/10
    ارسال ها:
    19,795
    تشکر شده:
    6,456
    امتیاز دستاورد:
    113
    برنامه نويسي صفحه كليد
    دريافت رشته كاراكتري

    نوشتن رويه اي كه با استفاده از توابع دريافت كاراكتر ، رشته اي كاراكتري را
    دريافت كند مشكل است . مخصوصا اگر بخواهيم بوسيله كليد BackSpace اشتباهات را
    هم جبران كنيم .

    خود Dos تابعي براي دريافت رشته كاراكتري دارد: تابع شماره 0Ah از وقفه 21h

    ورودي خروجي
    AH=0Ah
    كليد هاي تايپ شده در بافري كه با DS:DX Ds:Dx
    طول بافر مشخص ميشود قرار ميگيرند.

    كليد هاي تايپ شده در صفحه نمايش ديده ميشوند . و ميتوان با كليد Ctrl-C به عمل
    ريافت رشته كاراكتري بطور غير نرمال پايان داد.

    براي دريافت رشته كاراكتري بوسيله اين تابع ، ابتدا AH را برابر 0Ah قرار ميدهيم
    بايتي كه DS:DX به آن اشاره ميكند ( اولين بايت بافر) برابر بيشترين كاراكتر
    مجاز است . مثلا اگر بخواهيم طول رشته كاراكتري از 100 حرف تجاوز نكند بايد
    اين بايت را با 100 پر كنيم . مانند اينكه در زبان پاسكال يك متغير را به شكل String[100]
    تعريف كنيم .
    بايت دوم بعد از اينكه عمل دريافت رشته را با Enter پايان داديم پر ميشود.
    به اين صورت كه تعداد كاراكتر هاي تايپ شده در آن بايت قرار ميگيرند.
    مثلا اگر كلمه تايپ شده ALI باشد ، بايتي كه در DS:DX+1 قرار دارد برابر 3
    ميشود . هنگام دريافت رشته ، ميتوان با كليد BackSpace كاراكترهاي قبلي را پاك
    كرد .

    كاراكترهاي تايپ شده از اينجا در بافر قرار ميگيرند DS:DX | |

    |1|2|3| .................................... | | | | |

    | |
    DS:DX
    به اين بايت اشاره ميكند و(حداكثر طول باف ) |

    تعداد كاراكترهائي كه كاربر تايپ كرده

    مثال :
    برنامه زير يك بافر 100 حرفي بنام BUF تعريف كرده و با استفاده از اين
    تابع ، يك رشته كاراكتري را دريافت ميكند
    تمرين :
    به همين برنامه قسمتي اضافه كنيد كه رشته كاراكتري دريافت شده را چاپ
    كند
    راهنمائي :
    بعد از دريافت رشته كاراكتري بايد به انتهاي آن يك كاراكتر $ اضافه
    كنيد تا قابل چاپ توسط تابع 9 از وقفه 21h بشود . همچنين آفست شروع رشته كه در DS:DX
    قرار دارد را به DS:DX+2 تبديل كنيد تا بايتهاي اول و دوم كه مربوط به طول
    شته و تعداد كاراكتر ها هستند چاپ نشوند.

    .MODEL SMALL
    .CODE
    ORG 100H
    START:
    JMP MAIN
    BUF DB 101 DUP(0)/'$'

    MAIN:
    LEA DX/BUF
    MOV BX/DX
    MOV AL/100
    MOV [BX]/AL
    MOV A