تبلیغات :
آکوستیک ، فوم شانه تخم مرغی، صداگیر ماینر ، یونولیت
دستگاه جوجه کشی حرفه ای
فروش آنلاین لباس کودک
خرید فالوور ایرانی
خرید فالوور اینستاگرام
خرید ممبر تلگرام

[ + افزودن آگهی متنی جدید ]




صفحه 2 از 4 اولاول 1234 آخرآخر
نمايش نتايج 11 به 20 از 38

نام تاپيک: آموزش کامل عالی اسمبلی

  1. #11
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    در اين قسمت يك تمرين ديگر با هم انجام ميدهيم و برنامه اي مينويسيم كه تعداد 200
    رنگ از 256 رنگ موجود در حالت 320x200 گرافيكي را نمايش دهد .
    تابع شماره 00h از وقفه 10h مربوط به تعيين حالت نمايش است . كد مربوط به
    حالت صفحه نمايش در ثبات AL قرار گرفته و وقفه فراخواني ميشود:

    شماره تابع برابر AH=00h
    حالت صفحه نمايش با استفاده از جدول AL= INT 10h




    حالت صفحه نمايش در AL از جدول مخصوص موجود در كتابهاي اسمبلي بدست مي آيد.
    كد مربوط به حالت 256C َ320x200 برابر 13h است بنا براين AL را برابر 13h قرار
    ميدهيم .
    براي نمايش و روشن كردن يك نقطه (Pixel) در حالت گرافيكي از تابع 0Ch همين
    وقفه استفاده ميكنيم . يعني شماره ستون را در CX ، سماره سطر را در DX و شماره
    رنگ را در AL قرار داده و وقفه را اجرا ميكنيم . براي اينكه از ستون 199 تا ستون
    شماره صفر نقطه روشن كنيم ، CX را برابر 319 قرار داده و با دستور LOOP نقاط را
    در يك سطر روشن ميكنيم .


    MOV CX/319 ; COLUMN 319 = START COLUMN
    COL:
    INT 10H ; CALL INTERRUPT 10H
    LOOP COL
    سپس DX يا همان شماره سطر را يكواحد افزايش ميدهيم و مقدار آن را با 199 مقايسه
    ميكنيم (چون از 0 تا 199 سطر داريم ) و اگر برابر نبود دوباره عمليات بالا را
    انجام ميدهيم .

    بعد از اينكه اين عمليات انجام شد، تابع 00h از INT 16h را فراخواني ميكنيم تا
    منتظر دريافت يك كليد از صفحه كليد شود . به اين ترتيب ميتوانيم نتيجه برنامه
    را مشاهده كنيم و كليدي را براي اتمام برنامه بزنيم .
    در نهايت بايد حالت صفحه نمايش را به مود متني برگردانيم .
    براي اينكار از همان تابع تعيين مود نمايشي استفاده ميكنيم و حالت صفحه نمايش
    كه با AL مشخص ميشود را برابر 3 قرار ميدهيم .
    برنامه را با روش گفته شده تايپ و كامپايل كنيد . اگر از توربو اسمبلر استفاده
    ميكنيد با فرمان ASM/T.َTASM VGA256 آن را به فرم COM. ترجمه كنيد.


    . MODEL SMALL
    . CODE
    ORG 100H
    START :
    MOV AH/00H
    MOV AL/13H
    MOV BX/00H ; PAGE NUMBER
    INT 10H ; SET TO 320x200 256 COLORS

    MOV AH/0CH ; PUTPIXEL FUNCTION
    MOV AL/25 ; COLOR #25
    MOV DX/0 ; ROW 0
    ROW :
    MOV CX/319 ; COLUMN 319 = START COLUMN
    COL :
    INT 10H ; CALL INTERRUPT 10H
    LOOP COL ; DOWN TO CX=0
    INC DX ; DX=DX+1
    INC AL ; AL=AL+1( COLOR NUMBER )
    CMP DX/199 ; IF DX=199
    JNZ ROW ; ELSE JUMP TO ROW

    MOV AH/00H
    INT 16H

    MOV AH/00H ; VIDEO MODE SET
    MOV AL/03H ; 80x25 16 COLORS
    INT 10H ; CALL INT .10H
    INT 20H ; TERMINATE PROGRAM
    END START

    با انجام اين تمرين ساده ، يا گرفتيم كه دانستن يكسري از وقفه ها و توابع
    مربوط به آنها براي نوشتن برنامه هاي اسمبلي الزامي است .
    در قسمت بعدي نحوه تعريف متغير ها ، بدست آوردن آدرس آنها و چاپ
    پيغامها و جملات را ياد خواهيم گرفت .

  2. #12
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    حتما با ثابتها در زبانهائي مثل پاسكال آشنائي داريد . بعنوان مثال با جمله
    ے 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 از قسمت تعريف داده ها پرش كرده ايم .

    در قسمت بعد نحوه استفاده از متغيرها و بافرها (Buffers) را مطالعه
    ميكنيم . با همين معلومات برنامه اي براي نمايش محتواي سكتوهاي ديسك
    مينويسيم و پيغامهاي لازم را به آن اضافه ميكنيم .

    پيروز باشيد

  3. #13
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    در اين قسمت نحوه دسترسي به مقادير متغير ها را ياد ميگيريم .
    ے وقتي كه ميخواهيم مقدار يك متغير را به يك متغير يا ثبات ديگر منتقل كنيم بايد
    ے به اندازه آن توجه داشته باشيم . مثلا اگر متغيري بصورت LOCATE DB 10 تعريف كرده
    ے باشيم ، به دليل تك بايتي بودن ، نميتوانيم آن را به يك ثبات كامل مثل AX يا
    متغير دوبايتي كه با DW تعريف شده است ارسال كنيم .
    ے اما انتقال آن به يك نيم ثبات مثل ALيا AHا و ... مجاز است مانند . MOV BH/LOCATE


    ے از متغيرها بيشتر براي نگهداري موقت داده ها استفاده ميشود . مثلا وقتي كه
    ے برنامه اي براي كار با قطاعهاي ديسك مينويسيم ، بايد يك محل موقتي براي ذخيره
    ے محتواي قطاع هاي خوانده شده ايجاد كنيم . در اين موقع يك متغير به شكل (ترجيحا)
    آرايه تعريف ميكنيم .
    ے وقتي به اين شكل با متغيرها برخورد ميشود، به دانستن آدرس آن نياز پيدا ميكنيم
    فرض كنيد ميخواهيم جمله A QUICK START TO ASSEMBLY PROGRAMMING را چاپ كنيم .
    در قدم اول بايد متغيري تعريف كرده و اين جمله را داخل آن قرار دهيم .
    پس : MSG DB 'A QUICK START TO ASSEMBLY PROGRAMMING'/13/10/'$'


    ے اعداد 13وَ10 انتهاي رشته براي انتقال مكان نما به سطر بعد هستند و كاراكتر '$'
    ے از اين جهت وجود دارد كه تابع چاپ رشته انتهاي رشته كاراكتري را با بودن $
    تشخيص ميدهد.
    ے براي چاپ رشته كاراكتري راه هائي وجود دارد كه يكي از آنها استفاده از تابع 9h
    مربوط به INT 21h ميباشد .
    براي فراخواني آن بايد به اين صورت رجيستر ها را پر كنيم : AH=09H

    آدرس رشته كاراكتري DSX = INT 21H

    ے عبارت DSX نشان ميدهد كه مقدار قطعه (Segment) رشته كاراكتري ، يعني آن قطعه
    ے اي كه متغير تعريف شده در آن قرار گرفته است ، را بايد در DS قرار بدهيم . به
    همين صورت نيز مقدار آفست (Offset) آن را به DX انتقال ميدهيم .
    براي بدست آوردن شماره قطعه يك متغير از عملگر SEG استفاده ميكنيم .
    ے مثلا براي بدست آوردن شماره قطعه MSGاز MOV AX/Seg MSGز استفاده ميكنيم . اين
    دستور شماره سگمنت MSG را پيدا كرده و در AX قرار ميدهد .
    براي بدست آوردن شماره آفست هم از OFFSET استفاده ميكنيم مثلا MOV DX/OFFSET MSG
    پس براي چاپ رشته MSG بايد به اين صورت عمل كنيم :


    MOV AH/09H
    MOV DX/OFFSET MSG
    INT 21H



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

    ے يك دستور خلاصه براي بدست آوردن عدد آفست وجود دارد بنام LEA .كل كاري كه اين
    ے دستورالعمل انجام ميدهد اينست كه ديگر احتياج به نوشتن OFFSET نخواهد بود . به
    عنوان مثال MOV DX/OFFSET MSGبا LEA DX/MSGا برابر است .
    با اين تفاسير كل برنامه به اين شكل خواهد بود .

    . MODEL SMALL
    . CODE
    ORG 100H
    START :
    JMP MAIN ; skip to main codes
    MSG DB 'A QUICK START TO ASSEMBLY PROGRAMMING'/13/10/'$'
    MAIN :
    LEA DX/MSG ; get MSG offset
    MOV AH/09 ; write string function
    INT 21H ; call interrupt 21h
    INT 20H ; terminate program
    END START



    تمرين :
    ے براي اينكه تمرين بهتري داشته باشيم ، ميخواهيم خودمان و فقط با استفاده از وقفه
    ے مربوط به چاپ كاراكتر همين جمله را چاپ كنيم . قبلا گفتيم كه تابع 0Eh از وقفه
    ے 10h يك كاراكتر را در محل مكان نما چاپ كرده و مكان نما را يك خانه به راست
    انتقال ميدهد. ميخواهيم رشته كاراكتري بالا را تا رسيدن به علامت $ چاپ كنيم .
    ے بهترين كار اينست كه عدد آفست را در BX قرار بدهيم . در اينموقع آفست اولين
    ے كاراكتر در BX است . مقدار داخل اين آفست را بصورت MOV al/[bx] به ثبات AL
    ے منتقل كرده و بعد چاپ ميكنيم . براي كاراكتر بعدي يكواحد به BX اضافه ميكنيم و
    ے دوباره همان كارهاي قبلي ... . اين عمليات را بايد تا رسيدن به كاراكتر '$' ادامه
    بدهيم .
    ے ** اين برنامه را خودتان و بدون توجه به راه حل ارائه شده بنويسيد و فايل COM.
    آن را بسازيد.


    . MODEL SMALL
    . CODE
    ORG 100H
    START :
    JMP MAIN ; jump to MAIN
    MSG DB 'A QUICK START TO ASSEMBLY PROGRAMMING'/13/10/'$'
    MAIN :
    LEA BX/MSG ; get MSG offset
    MOV AH/0EH ; write char function
    LOOP :_
    MOV AL/[BX] ; move [BX] to AL: charactre code
    CMP AL/'$' ; if al is equal with '$'
    JE END _; then jump to END _
    INT 10H ; otherwise call interrupt 10h
    INC BX ; BX=BX+1
    JMP LOOP _; jump to next caharcter
    END :_
    INT 20H ; terminae program
    END START

  4. #14
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    در اين قسمت يك تمرين جديد انجام داده و بوسيله آن تجربيات خودمان را افزايش
    ميدهيم . اين تمرين اولين برنامه ما هست يك عمليات سطح پائين سيستم ، يعني
    دسترسي به ديسك ، را انجام ميدهد .

    تابع شماره 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

  5. #15
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    عملگرهاي بيتي

    عملگرهاي بيتي مانند عملوندهاي حسابي هستند با اين تفاوت كه روي بيت ها كار
    ميكنند. اين عملگرها عبارتند از : ... 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
    انتقال

    ادامه اين بحث را در قسمت بعد انجام ميدهيم .

  6. #16
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    در قسمت قبلي چند عملگر بيتي را ديديم . در اين قسمت هم اين مبحص را دنبال
    ميكنيم .
    عملگر 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

  7. #17
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    ضرب و تقسيم با 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



    تمرين :

    همين عمل را براي تقسيم نيز با ديباگ انجام بدهيد .

    در قسمت بعدي نوشتن رويه ها و برنامه هاي واحدي را
    ياد ميگيريم .

    پيروز باشيد

  8. #18
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    رويه ها (Procedures) .

    در برنامه نويسي با زبانهاي سطح بالا ، با زيربرنامه ها يا پروسيجر ها آشنا شديم .
    مثلا در زبان بيسيك به آنها Subroutine ميگوئيم يا در زبان پاسكال Procedure و..

    رويه ها نوشت برنامه هاي واحدي را ممكن و آسان ميسازند و از تكرار كدهاي
    برنامه جلوگيري ميكنند .

    در زبان اسمبلي براي ساختن يك زيربرنامه از اعلان Proc در مقابل نام آن استفاده
    ميكنيم . مثلا براي تعريف رويه Print آن را با Print Proc تعريف ميكنيم .
    در واقع Proc يك برچسب ( از نوع Near) است كه اسمبلر توجه بيشتري نسبت به
    يك برچسب عادي به آن ميكند.

    وقتي يك اعلان زيرروال را تعريف كرديم ، كد اجرائي آن را مينويسيم . مثلا اگر
    بخواهيم زير روال ما كاراكتر مشخص شده با AL را چاپ كند ميتوانيم با استفاده از
    تابع 0Eh از وقفه 10h چنين چيزي بنويسيم :


    Print Proc
    Mov Ah/0Eh
    Int 10h
    :
    :




    وقتي به انتهاي كد مورد نظر رسيديم ، با يك دستور Ret به محلي از برنامه اصلي كه
    زيرروال فراخواني شده بود برميگرديم .

    Print Proc
    Mov Ah/0Eh
    Int 10h
    Ret
    :



    و در پايان هم دوباره نام پروسيجر را به همراه يك كلمه End به معني پايان كار
    زيرروال مي آوريم . در مورد مثال ما

    : Print End Print Proc
    Mov Ah/0Eh
    Int 10h
    Ret
    Print End



    نكته مهمي كه بايد به آن توجه كنيم اينست كه اعلان Proc مانند يك برچسب است و
    در صورتي كه از روي آن با دستور JMP جهش نكنيم ، داخل پروسيجر هم اجرا خواهد شد
    بنا براين هميشه بعد از Org 100h يا پروسيجر ها را نوشته و با يك فرمان JMP از
    روي آنها به كداصلي پرش ميكنيم .


    . MODEL SMALL
    . CODE
    ORG 100H
    START :


    JMP MAIN
    پرش به | اعلان پروسيجر Print Proc
    قسمت اصلي | Mov Ah/0Eh
    برنامه | Int 10h Ret |

    | پايان رويه Print End
    :MAIN :
    :
    END START


    پس از آن ميتوانيم با يك فرمان Call رويه مورد نظر را فراخواني كنيم .
    مثلا Call print . قبل از فراخواني رويه مورد نظر بايد پارامترها و شراي اجراي آن
    را فراهم كرده باشيم . مثلا در مورد رويه Print بايد هميشه ثبات AL كه حاوي كد
    اسكي كاراكتر براي چاپ است ، مقدار دهي صحيح شده باشد .
    مثال :

    MAIN :
    Mov Al/65 ;'A'
    Call Print
    :
    END START



    مثال : اين همان برنامه چاپ كاراكترهاي اسكي با كد 128 تا 255 است كه قبلا بدون
    استفاده از رويه ها نوشتيم :

    . MODEL SMALL
    . CODE
    ORG 100H ; IP points to 100h / starting offset
    START
    JMP MAIN ; Jump over the procedure
    Print Proc ; procedure declaration
    Mov Ah/0Eh
    Int 10h
    Ret ; procedure ends
    Print End
    MAIN :; main program
    MOV BH/128
    LOOP :_
    MOV AL/BH ; AL = Ascii character code
    CALL PRINT ; Call procedure
    INC BH
    CMP BH/255
    JNP LOOP _; Jmp LOOP _if BH is below 255
    INT 20H ; otherwise terminate normally
    END START ; program ends according the START label

    **

    معمولا كد اصلي برنامه را هم بصورت يك Procedure مينويسند . مثلا در مثال بالا
    بعد از برچسب Main ميتوان يك Prog proc و در انتهاي برنامه هم يك Prog End
    قرار داد . اين امر تفاوتي در اجراي برنامه نخواهد داشت ولي معمولا و براي داشتن
    انعطاف بيشتر در نوشتن برنامه اين كار را انجام ميدهند.
    **
    اگر دستور Ret را در برنامه اصلي بكار ببريم ، برنامه پايان مي يابد .

    در قسمت بعدي با استفاده از رويه ها و اعمال بيتي و محاسباتي كه
    خوانديم ، رويه هائي براي چاپ اعداد در مبناهاي مختلف مينويسيم .

  9. #19
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    برنامه نويسي صفحه كليد

    ميخواهيم با مطالبي كه تا حالا ياد گرفتيم ، به برنامه نويسي اجزاي PC بپردازيم
    براي شروع هم ابتدا برنامه ريزي صفحه كليد را مطالعه ميكنيم .
    براي استفاده از صفحه كليد معمولا از توابع داس (Int 21h) يا BIOS استفاده ميشود
    با اينحال برنامه هاي حرفه اي و مخصوصا برنامه هاي رزيدنت از دسترسي مستقيم به
    بافر صفحه كليد سود ميبرند . بنا براين بعد از يادگيري توابع داس و بايوس ،
    روش دستيابي به بافر صفحه كليد را هم خواهيم خواند.

    تابع 1 از وقفه / INT 21h دريافت كاراكتر همراه با نمايش
    ورودي خروجي AH=1
    =AL كد اسكلي كليد فشرده شده
    كليد فشرده شده در صفحه هم به نمايش در مي آيد

    اولين و اساسي ترين روش خواندن كليد ها همين تابع از بايوس است . اين تابع
    كليدي را از صفحه خوانده و همزمان آن را در صفحه نير نشان ميدهد ضمن اينكه ^C
    را هم تست ميكند. بعد از فراخواني وقفه كد اسكي (ASCII) كليد فشرده شده در AL
    قرار ميگيرد.
    بعلاوه 3 تابع ديگر ( مجموعا 4 تا ) نيز در DOS براي خواندن كاراكتر ها داريم كه
    در جدول زير ميبينيد :

    ECHO دارد | تست | CCtrl-C متظر ميماند | شماره تابع
    1 | x | x | x
    6 | | |
    7 | x | |
    8 | x | x |


    براي فراخواني هر كدام از اين توابع ، عدد مربوط به تابع را در AH قرار داده و
    وقفه 21h را اجرا ميكنيم . پس از آن كد اسكي كليد فشرده شده در AL قرار ميگيرد.
    مثلا : MOV AH/01
    INT 21h

    اگر پس از خواندن كليد ، عدد 0در ALر قرار بگيرد ، يعني يكي از كليد هاي گسترش
    يافته مثل SHitيا Altا و .. فشرده شده است . وقتي اين امر صورت بگيرد 2 بايت
    كه محتوي يك 0 و كد اسكي كليد است در بافر صفحه كليد قرار ميگيرد . بنا براين
    براي خارج كردن بايت دوم از بافر صفحه كليد ، يك بار ديگر همان تابع را اجرا
    ميكنيم :

    MOV AH/1 ; Read Key with echo / ^C sensitivity
    INT 21H ; Call int 21h
    CMP AL/0 ; Enhanced key pressed?
    JNZ CONT ; No! jump to CONTinue
    INT 21H ; otherwise read the 2nd byte
    CONT :



    مثال : ميخواهيم برنامه بنويسيم كه يك رشته كاراكتري را گرفته و چاپ كند.
    در اين برنامه GETKEY يك پروسيجر است . اين رويه كاراكتري را با استفاهده از
    سرويس 1 داس ميخواند و كد آن را در AL قرار ميدهد . وقتي كه كاراكتري را به اين
    صورت خوانديم ، كد آن را به انتهاي رشته Str اضافه ميكنيم . سپس تست ميكنيم
    كه آيا كليد فشرده شده برابر 13 يا همان Enter است ? اگر اينچني باشد ، از حلقه
    خارج شده و با استفاده از سرويس 9 مربوط به Int 21h رشته دريافت شده را چاپ
    ميكنيم .( قبل از آن يك كاراكتر $ با انتهاي رشته كاراكتري اضافه كرده ايم )


    ENTER EQU 13
    .MODEL SMALL
    .CODE
    ORG 100H
    START:
    JMP MAIN
    GETKEY PROC ; getkey reads a key from keyboard
    MOV AH/1
    INT 21H
    RET
    GETKEY ENDP
    PUTCHAR PROC ; displays a character
    MOV AH/0EH
    INT 10H
    RET
    PUTCHAR ENDP

    STR DB 255 DUP(0) ; Buffer
    MAIN:
    LEA BX/STR ; 1st CHARACTER
    LOOP:_
    CALL GETKEY
    MOV [BX]/AL
    INC BX
    CMP AL/ENTER ; if Enter pressed then jump over the loop
    JNZ LOOP_

    MOV AL/'$' ; END OF STRING
    MOV [BX]/AL

    LEA DX/STR ; get the Str address

    MOV AL/10 ; CR
    CALL PUTCHAR

    MOV AL/13 ;LF
    CALL PUTCHAR

    MOV AH/9 ; Display Str

  10. #20
    آخر فروم باز Nesta's Avatar
    تاريخ عضويت
    Jan 2005
    محل سكونت
    tehran
    پست ها
    3,343

    پيش فرض

    برنامه نويسي صفحه كليد
    دريافت رشته كاراكتري

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

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

    ورودي خروجي
    AH=0Ah
    كليد هاي تايپ شده در بافري كه با DSX Dsx
    طول بافر مشخص ميشود قرار ميگيرند.

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

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

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

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

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

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

    مثال :
    برنامه زير يك بافر 100 حرفي بنام BUF تعريف كرده و با استفاده از اين
    تابع ، يك رشته كاراكتري را دريافت ميكند
    تمرين :
    به همين برنامه قسمتي اضافه كنيد كه رشته كاراكتري دريافت شده را چاپ
    كند
    راهنمائي :
    بعد از دريافت رشته كاراكتري بايد به انتهاي آن يك كاراكتر $ اضافه
    كنيد تا قابل چاپ توسط تابع 9 از وقفه 21h بشود . همچنين آفست شروع رشته كه در DSX
    قرار دارد را به DSX+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

Thread Information

Users Browsing this Thread

هم اکنون 1 کاربر در حال مشاهده این تاپیک میباشد. (0 کاربر عضو شده و 1 مهمان)

User Tag List

قوانين ايجاد تاپيک در انجمن

  • شما نمی توانید تاپیک ایحاد کنید
  • شما نمی توانید پاسخی ارسال کنید
  • شما نمی توانید فایل پیوست کنید
  • شما نمی توانید پاسخ خود را ویرایش کنید
  •