-
بافر صفحه كليد و بافرحلقوي
صفحه كليد از طريف وقفه سخت افزاري 9h كنترل ميشود . وقتي كه كليدي فشرده شده يا
رها شود اين وقفه فراخواني خواهد شد.
صفحه كليد هم مانند بسياري از وسايل جانبي مثل ديسك درايو و ... از طريق پورت
مخصوص به خودش با CPU مرتبط ميشود. وقتي كه كليدي فشرده ميشود پردازنده مخصوص
صفحه كليد كه يك تراشه 8048 است كدي موسوم به كد اسكن توليد كرده و در پورت 60h
قرار ميدهد. پس از آن وقفه 9h اين مقدار را از پورت 60h خوانده و در بافر صفحه
كليد قرار ميدهد . با فرصفحه كليد در ناحيه داده هاي بايوس يعني سگمنت شماره 40h
قرار دارد.
بافر حلقوي ----------
بافر صفحه كليد يك ناحيه 16 كلمه اي (32 بايتي ) در ناحيه داده هاي
كاراكتر بعدي از آنجا خوانده خواهد شد . كلمه ديگري بنام Tile هم به موقعيتي
اشاره ميكند كه كاراكتر بعدي كه تايپ ميشود در آن محل قرار ميگيرد.
وقتي يك كاراكتر تايپ ميشود head حركت ميكند و وقتي يك كاراكتر وارد ميشود Tile
يك خانه به جلو ميرود و وقتي هركدام به انتها رسيد به جاي اولش برميگردد. به
شكلي كه هميشه head در تعقيب tile است و وقتي بافر خالي باشد به آندو برهم منطبق
ميشوند . به خاطر اين شكل عملكرد بافر به آن بافرخلقوي ميگوئيم .
دستيابي به ناحيه داده ها و بافر صفحه كليد -----------------------------------------
براي دستيابي به يك سگمنت بايد دو موضوع جديد را ياد بگيريم . يكي تعريف يك
ناحيه بعنوان يك سگمنت و ديگري منطبق كردن يك ناحيه تعريف شده بر يك سگمنت حافظه
براي تعريف يك سگمنت از كلمه Segment استفاده ميكنيم . توجه داريم كه اين تعريف
حتما بايد قبل از code. باشد.
Bios_Data SEGMENT
:
:
Bios_Data Ends
به اين ترتيب يك ناحيه داده اي جديد به اسم Bios_data تعريف كرديم .
براي اينكه اين ناحيه را بر سگمنت 40h يا همان ناحيه داده هاي بايوس منطبق كنيم
راهنماي AT را هم به انتهاي تعريف سگمنت اضافه ميكنيم . Bios_Data SEGMENT AT 40H
:
Bios_Data Ends
حالا در داخل سگمنت تعريفي چند متغير را در آدرسهاي مخصوص تعريف ميكنيم . چون
بايتهاي مربوط به صفحه كليد در آفست 1Ah قرار دارند يك org 1Ah در نظر گرفته و
متغيرها را تعريف ميكنيم .
Bios_Data SEGMENT AT 40H
ORG 100H
HEAD DW ?
TAIL DW ?
BUFFER DW 10 DUP(?)
Bios_Data Ends
org 1ah
به اسمبلر ميگويد كه همه متغيرهائي كه در زير تعريف ميشوند را منطبق
بر آدرس 1ah قرار بدهد . اين كار باعث ميشود كه هميشه متغير head حاوي دوبايت 1ah
و 1bhو باشد.
ون هميشه مقدار آدرسها نسبت به محتواي DS سنجيده ميشوند ( مثلا mov al/[bx] با mov al/ds:[bx]
برابر است ) بايد به اسمبلر بگوئيم كه داده ها در كجا هستند.
براي اين منظور از ASSUME استفاده ميكنيم . به اين صورت
Bios_Data SEGMENT AT 40H
ORG 100H
HEAD DW ?
BUFFER DW 10 DUP(?)
Bios_Data Ends
. CODE
ORG 100H
START:
ASSUME DS:BIOS_DATA
بعد آدرس ناحيه Bios_data را به DS لود ميكنيم . ( با استفاده از رجيستر واسطه ) MOV BX/BIOS_DATA
MOV DS/BX
حال تست ميكنيم كه اگر headو tail برهم منطبق باشند يعني بافر خالي است و
شروع به خواندن كليد ها ميكنيم اما اگر برهم منطبق نباشند محتواي بافر را خوانده
و آن را خالي ميكنيم .
GETCHAR:
MOV BX/HEAD
CMP BX/TAIL
JE GETCHAR
واگر بافر خالي نبود BX محل آخرين كاراكتر داخل بافر را نشان ميدهد . پس محتواي
آن قسمت را خوانده و سپس Tail را هم به همان آدرس تنظيم ميكنيم كه Tailو Headو
بر هم منطبق شوند . ( يعني بافر خالي بشود) MOV DX/[BX]
و ميتوانيم تست كنيم كه اگر كليد خوانده شده Q ( به معني Quit) بود از برنامه
خارج شويم و در غير اينصورت يك كليد ديگر را بخوانيم و در صفحه چاپ كنيم .
آيا كاراكتر Q است ? ; CMP DDL/'Q' JE BYE ;
آيا كاراكتر q است ? ; CMP DL/'q' JE BYE ;
تابع 2 براي خواندن كليد ; .MOV AH/2 ; READ A CHAR
وقفه داس ; INT 21H
پرش به روتين برنامه ; JMP GETCHAR BYE :INT 20H
-
برنامه نويسي صفحه تصوير
ے بايوس كامپيوتر هاي PC شامل روالهائي براي كنترل و برنامه نويسي صفحه نمايش
هستند. متداولترين آنها وقفه 10h است و در زير متداولترين توابع آن را شرح ميدهيم
سرويس 2 براي تنظيم محل مكان نما
ورودي ها: AH=2
سطر و ستون موقعيت جديد DH/DL=
شماره صفحه BH=
ے شماره صفحه در حالت پيش فرض 0 است (BH=0) و گوشه بالا و سمت چپ صفحه نمايش
ے هم با مختصات (0/0) سنجيده ميشود . بنا براين درحالت 80x25 حداكثر شماره سطر و
ستون برابر 79x24 است .
سرويس 3 . دريافت موقعيت مكان نما
ورودي ها AH=3
شماره صفحه BH=
بعد از فراخواني وقفه 10h اين مقادير برگشت داده ميشوند:
سطر و ستون فعلي مكان نما DH/DL=
مثال
MOV AH/2 ; Set curson position .
MOV DH/20 ; X
MOV DL/10 ; Y
XOR BH/BH ; BH=0
INT 10H ; Call Interrupt 10h
لغزاندن صفحه به بالا يا پائين
ے با استفاده از دو تابع زير ميتوانيم بخشي از صفحه تصوير را به بالا يا پائين حركت
داده يا آن قسمت را پاك كنيم .
براي فراخواني اين توابع بايد رجيسترها را بصورت زير تنظيم كنيم
لغزش بطرف بالا AH=6
لغزش بطرف پائين AH=7
تعداد سطرهائي كه بايد حركت كند AL=
سطروستون گوشه سمت چپ و بالا Ch/Cl=
سطرو ستون گوشه سمت راست و پائين Dh/Dl=
مشخصه رنگ Bh=
ے اگر AH برابر 6 باشد محدوده تعريفي بطرف بالا و در صورتي كه 7 باشد بطرف پائين
حركت داده ميشود .
AL مشخص ميكند كه محدوده مورد نظر چند سطر بايد حركت كند .
ے اگر AL برابر 0 باشد محدوده تعريفي پاك ميشود . مثلا فرمان CLSدر DOSر از همين
وقفه استفاده كرده و كل صفحه نمايش را پاك ميكند.
ے مشخصه رنگي كه با BH تعريف ميشود معلوم ميكند كه فضاي خالي كه بعد از حركت دادن
محدوده بوجود مي آيد بايد با چه رنگي پر شود. اين مقدار از رابطه زير بدست
مي آيد:
رنگ زمينه +16*رنگ متن BH=
مثلا براي اينكه رنگ سفيد روي آبي داشته باشيم : BH=15+1*16=31
نوشتن كاراكتر و خصوصيات در محل مكان نما
ے با استفاده از تابع شماره 9h ميتوانيم كاراكتري را با خصوصيات مورد نظر در محل
مكان نما چاپ كنيم .
AH=9
كد اسكي AL=
شماره صفحه BH=
خصوصيات كاراكترBL=
تعداد دفعاتي كه كاراكتر چاپ ميشودCX=
ے خصوصيات كاراكتر از روشي كه در بالا توضيح داديم بدست مي آيد. رجيستر CX معلوم
ے ميكند كه كاراكتر مشخص شده با AL چند بار بايد چاپ شود. معمولا اين مقدار را 1
قرار ميدهيم .
مثال : چاپ رشته كاراكتري بصورت سفيد روي آبي
.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
MSG DB ' THIS IS AN EXAMPLE FOR INT 10H/FUNCTION 9H$'
SETCURSOR PROC ; SET CURSOR POSITION
MOV AH/2 ; FUNCTION 2 / INT 10H
MOV DH/10 ; ROW:10
PUSH BX ; SAVE BX VALUE
MOV BH/0
INT 10H
POP BX
RET
SETCURSOR ENDP
WRITE PROC ;WRITE A CHARACTER USING FUNCTION 9H/INT 10H
MOV AH/09
PUSH BX
XOR BH/BH
MOV BL/31
MOV CX/1
INT 10H
POP BX
RET
WRITE ENDP
MAIN:
LEA BX/MSG ; GET MSG ADDRESS
MOV DL/10 ; COLUMN : 10
CALL SETCURSOR
LOOP:_
MOV AL/[BX]
CMP AL/'$'
JZ QUIT
CALL WRITE
INC BX
INC DL ; SET NEW CURSOR LOCATION
CALL SETCURSOR
JMP LOOP_
QUIT:
INT 20H ; TERMINATE
END START
سرويس 0Eh براي چاپ بصورت تله تايپ
ے وقتي ميخواهيم با استفاده از سرويس 9h كاراكتري را چاپ كنيم خودمان بايد محل
ے مكان نما را معين كنيم . مثلا براي چاپ يك رشته كاراكتري بعد از چاپ هر كاراكتر
يكواحد به شماره ستون مكان نما اضافه كرده ، محل جديد آن را تنظيم مكنيم و... .
اما سرويس 0E بعد از چاپ هر كاراكتر مكان نما را يكخانه با راست انتقال ميدهد
به خاطر همين خصوصيت به اين روش چاپ " تله تايپ " ميگويند.
ے قبلا با اين سرويس كار كرده ايم بنا براين تنها به ياد آوري پارامترهاي لازم اكتفا
كرده و از آوردن مثال خودداري ميكنيم . ( مثال : فايل ALLCHAR.ASM)
بايد تنظيم شود: AH=0Eh
كد اسكي كاراكترAL=
شماره صفحه BH =
-
برنامه نويسي در مد گرافيك
ے تنها امكاني كه بايوس براي انجام كارهاي گرافيكي در اختيار ما قرار ميدهد روشن
ے كردن يك نقطه (Pixel) است . با استفاده از تابع مربوطه بايد زيربرنامه هائي
براي رسم ساير اشكال گرافيكي مثل مربع ، دايره و ... بنويسيم .
ے قبل از اينكه يك شكل گرافيكي رسم كنيم ، بايد ايتدا صفحه نمايش را در مد
ے گرافيكي قرار بدهيم . به عبارت ديگر چون در حالت عادي تعداد سطر و ستونهاي صفحه
ے تصوير كم ( مثلا در مد 25x80 برابر 2000 تا) است ، نميتوان شكل گرافيكي رسم كرد .
بهمين دليل صفحه نمايش را در مد گرافيكي مثلا 480x640 نقطه قرار ميدهيم و ... .
سرويس 0 از وقفه 10h براي تنظيم حالت صفحه نمايش =================================================
ے براي تنظيم حالت صفحه نمايش به يك حالت متني يا گرافيكي خاص بايد اين
پارامتر ها را تنظيم كنيم . AH=0
مود مورد نظر AL=
مود مورد نظر از جدولي بدست مي آيد كه خلاصه آن را در زير مي آوريم .
كد | وضوح | تعداد رنگ
16 | Text Mode | 03h
16 | 320x200 | 0Dh
16 | 640x200 | 0Eh
Mono | 640x350 | 0Fh
16 | 640x350 | 10h
2 | 640x480 | 11h
16 | 640x480 | 12h
256 | 320x200 | 13h
سرويس 0Ch از وقفه 10h براي نوشتن نقطه گرافيكي =============================================
براي روشن كردن يك پيكسل از تابع 0Ch استفاده ميكنيم .
AH= 0Ch
شماره رديف بسته به مود تصويري DX=
شماره ستون بسته به مد تصويري CX=
عدد رنگ بسته به مد تصويري AL=
شماره صفحه ، شماره 0 معمولا استفاده ميشودBh=
ے به عنوان مثال براي روشن كردن نقطه اي كه ( مد 640x480 ) در وسط صفحه است به
اينصورت بايد وقفه را فراخواني كنيم .
MOV AH/0CH
MOV DX/240
MOV CX/320
XOR BH/BH
ے مثال : برنامه زير200 رنگ از رنگهاي موجود در حالت 320x200 نقطه و 256 رنگ را
نمايش ميدهد.
.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 ; GET KEY
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
سرويس 10h از اينتراپت 10h براي تنظيم پالت رنگ ================================================
ے با استفاده از اين سرويس ميتوانيم رنگهاي فعلي سيستم را بصورت دلخواه خودمان
ے تعريف كنيم . در هر كارت گرافيكي مبتني بر VGA ثباتي بنام رجيستر DAC وجود
دارد كه مشخصات رنگ را بصورت زير نگهداري ميكند.
6 bytes
DAC Register : RRRRRRGGGGGGBBBBBB
6 bytes 6 bytes
ے هر رنگ از سه رنگ اصلي قرمز (R) ، سبز (G) و آبي (B) تشكيل ميشود . ثبات DAC
ے كه بصورت يك متغير 18 بيتي است ، مقدار هر كدام از رنگهاي اصلي كه در رنگ
ے مورد نظر شركت دارند را معين ميكند . هر كدام از اين مقدار ها يك داده 6 بيتي
ے هستند ، بنا براين عددي بين 0 تا 63 را نشان ميدهند . براي تنظيم اين رجيستر از
سرويس 10 استفاده ميكنيم .
AH= 10H
AL= 10H
كد مربوط به رنگ (0-255) BX=
شدت رنگ سبز CH=
شدت رنگ آبي CL=
شدت رنگ قرمز CH=
ے منظور از شدت رنگ ، همان عدد 6 بيتي است كه در بالا گفتيم . مثلا اگر بخواهيم كه
ے رنگ شماره 1 كه در حالت عادي آبي است را به قرمز تند تبديل كنيم از اين كد
استفاده ميكنيم .
MOV AX/1010H
MOV BX/1
MOV CH/1
MOV CL/1
MOV CH/60
INT 10H
پايان قسمت بيست ودوم
-
دسترسي مستقيم به حافظه ويدئو
ے در اين قسمت ميبينيم كه چطور در اسمبلي بدون استفاده از وقفه ، كاراكترها را در
صفحه نمايش چاپ كنيم . به همين صورت نوشتن نقاط گرافيكي را انجام ميدهيم و ..
ے كارت هاي گرافيكي مبتني بر CGA/EGA/VGA داراي قطعه حافظه ي مخصوصي هستند كه
ے اطلاعات صفحه نمايش در آن نگهداري ميشود . به عبارت ديگر هر چيزي در اين قسمت
از حافظه نوشته شود ، روي صفحه نمايش ائير صفحه نمايش ميگذارد .
ے در حالت گرافيكي اين قطعه از آدرس A000h و در مود متني از B000h يا B8000h شروع
ے ميشود . در حالت متني قطعه ويدئو در هر سگمنتي كه باشد ، هميشه بايتهاي زوج ( با
ے شروع از صفر) مربوط به كد اسكي كاراكتر بوده و بايتهاي فرد ( با شروع از يك )
ے مربوط به خصلت كاراكتر است . يعني خصلت كاراكتري كه در آفست n ام قرار دارد
در آفست n+1 ام قرار ميگيرد و ... .
خصلت مربوط به هر كاراكتر از فرمول زير محاسبه ميشود :
رنگ زمينه +16*رنگ متن = خصلت
بعنوان مثال اگر بخواهيم كه كاراكتر چاپ شونده با رنگ سفيد روي زمينه آبي ديده
شود داريم : = 31 َ= 15+1*16 خصلت .
( كد اسكي كاركتر) آفست 0
( بايت خصيصه ) آفست 1 | | |
| |
0 1 2 3 4 5 ......................................
| | | | | | | |
ے در كارتهاي گرافيكي تك رنگ (Monochrome) مانند CGA/MDA و ... قطعه حافظه ويدئو (
براي مود متني ) از آدرس B000h و در كارتهاي رنگي از آدرس B800h شروع ميشود .
ے مثال : برنامه زير تمام صفحه نمايش را با كاراكتر (.) و به رنگ سفيد روي زمينه
آبي پر ميكند.
مشخصه كاراكترها ; EQU 31 ATTR E
آدرس قطعه ويدئو ; VIDSEG EEQU 0B800H . MODEL SMALL
. CODE
ORG 100H
START :
JMP MAIN
DPRINT PROC
PUSH ES
MOV AX/VIDSEG
MOV ES/AX ;
كاراكتر براي چاپ MOV AL/'.' ; MOV ES:[BX]/AL ;
آفست قرار گيري بايت خصيصه INC BX ; MOV AL/ATTR
MOV ES:[BX]/AL
POP ES
RET
DPRINT ENDP
MAIN :
آفست شروع = صفر ; XOR BX/BX LOOP :_
CALL DPRINT
كاراكتر بعدي ; INC BX CMP BX/4000 ;( 80X25)x2
JNZ LOOP _
INT 20H
END START
ے در برنامه بالا محل آفست ها با BX مشخص ميشود . بنابراين ابتدا كد اسكي كاراكتر
را در آدرس ES:[BX] نوشته و سپس بايت مشخصه را در ES:[BX+1] قرار ميدهيم و..
ے چون صفحه نمايش داراي 80x25 عنصر بوده و هر كاراكتر 2 بايت ( كد كاراكتر و
ے بايت مشخصه ) اشغال ميكند بنا براين 80x25x2=4000 بايت طول دارد . بنا براين در
پايان برنامه تست ميكنيم كه آيا BX با آفست 4000 ام رسيده يا نه .
تمرين : برنامه اي بنويسيد و در آن پروسيجري طراحي كنيد كه يك رشته كاراكتري
را با اين روش بنويسد.
ے با همين روش ميتوانيم قسمتي از صفحه نمايش را ذخيره و بازيابي كنيم . برنامه
ے هائي كه در آنها از منوها و پنجره ها استفاده شده همگي از اين روشها استفاده
ے ميكنند . به اينصورت كه قبل از نمايش يك پنجره ( مثل يك Dialog box) ابتدا
محتواي پشت آن را ذخيره كرده و بعدا دوباره در همان محل قرار ميدهند.
برنامه زير ابتدا كل صفحه نمايش را در بافري ذخيره كرده و مجددا نمايش ميدهد
VIDSEG EQU 0B800h
.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
BUF DB 4000 DUP(0)
MSG DB ' NOW PRESS ANY KEY TO RESTORE SCREEN IMAGE$'
MAIN:
XOR BX/BX
PUSH ES
MOV AX/VIDSEG
MOV ES/AX
LOOP1:
MOV AL/ BYTE PTR ES:[BX]
MOV BUF[BX]/AL
INC BX
CMP BX/4000
JNZ LOOP1
; Clera screen.
MOV AL/0
MOV DH/24
MOV DL/79
XOR CX/CX
XOR BH/BH
MOV AH/7
INT 10H
; DISPLAY MESSAGE
MOV AH/9
LEA DX/MSG
INT 21H
; Wait for a key
MOV AH/0
INT 16H
XOR BX/BX
LOOP2:
MOV AL/BUF[BX]
MOV BYTE PTR ES:[BX]/AL
INC BX
CMP BX/4000
JNZ
-
دستورات مربوط به رشته ها
قبلا تا حدودي نحوه كار با كاراكتر ها و رشته هاي كاراكتري را ديديم و ميتوانيم
آنها را از طريق ورودي دريافت كرده يا روي صفحه نمايش چاپ كنيم .
بعلاوه عمليات فوق ، امكانات و دستورات ديگري هم در نظر گرفته شده اند . مثلا
پردازنده 8086 دو رجيستر SI/DI را براي پردازش رشته هاي كاراكتري در نظر گرفته .
اين دو براي انتقال داده ها بين دو آدرس مختلف يا انتقال محتواي يك رشته
كاراكتري به رشته كاراكتري ديگر بكار ميروند.
هميشه DS:SI(SI( مخفف Source Index است ) به رشته مبدا و ES:DI(Destination Index)
به رشته مقصد (يا آدرس مقصد) اشاره ميكند. وقتي كه يك بايت (يا كلمه ) بوسيله
دستورات مخصوص اينكار انتقال پيدا كرد، خود بخود SI يكواحد افزايش (يا كاهش )
پيدا ميكند.
*
دستور MOVSB
دستور MOVSB يك بايت را از آدرس DS:SI به آدرس ES:DI منتقل ميكند.
براي انتقال يكبايت ، ابتدا ثباتهاي DS:SI را به رشته مبدا و ES:DI را به رشته
مقصد تنظيم كرده و با تشكيل يك حلقه (Loop) به تعداد مورد نياز داده انتقال
ميدهيم .
در مثال زير ميخواهيم تمام محتواي رشته كاراكتري S1 را به رشته كاراكتري S2
انتقال داده و S2 را چاپ كنيم .
بنا براين دو رشته كاراكتري (با طول 20 حرف ) تعريف ميكنيم .
S1 DB ' THE SOURCE STRING $'
S2 DB ' $'
سپس ds:di را به طوري تنظيم ميكنيم كه به S1 اشاره كند. چون برنامه ما com. است
و محتواي ds ثابت ، فقط مقدار آفست s1 را به SI انتقال ميدهيم : lea ax/s1
mov ds/ax
براي تنظيم كردن آدرس مقصد، مقدار DS كه حاوي عدد قطعه S2 است را به ES انتقال
ميدهيم : mov ax/ds
mov es/ax
سپس مقدار آفست S2 را بدست آورده و در DI قرار ميدهيم : lea ax/s2
mov di/ax
الان آدرسهاي مبدا و مقصد معلوم شده اند، بنا براين كافيست 20 بار (براي انتقال 20
بايت ) ، دستور movsb را اجرا كنيم : mov cx/20 ; loop counter
loop :_
movsb
loop loop _
سپس با استفاده از تابه 9h از وقفه 21h محتواي S2 را چاپ ميكنيم و خواهيم ديد
كه عبارت داخل S1 چاپ ميشود .
ليست كامل : .286c
.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
S1 DB 'THE SOURCE STRING $'
S2 DB ' $'
MAIN:
LEA AX/S1
MOV SI/AX
LEA AX/S2
MOV DI/AX
;PUSH ES
MOV AX/DS
MOV ES/AX
MOV CX/20
CLD
LOOP:_
MOVSB
LOOP LOOP_
MOV AH/09
LEA DX/S1
INT 21H
INT 20H
END START
*
دستور MOVSW
دستور MOVSW دقيقا مانند MOVSB است با اين تفاوت كه بجاي يك بايت ، يك كلمه
(َ2 بايت ) منتقل ميكند . براي انتقال دو بايت بين دو آدرس كافيست مانند
عملياتي كه براي movsb توضيح داديم ، آدرسها را تنظيم كرده و از movsw استفاده
كنيم .
بعنوان مثال ، اگر بخواهيم در برنامه بالا بجاي movsbاز movswز استفاده كنيم ،
بايد حلقه اي كه تشكيل داديم 10 بار اجرا شود:
mov cx/10
loop :_
movsw
loop loop _
دستورات CLSو SLDو
وقتي كه از movsbيا movswا استفاده ميكنيم ، مقدار ثباتهاي SIو DIو يكواحد
افزايش پيدا ميكنند . در صورتي كه بخواهيم با اتقال هر بايت (يا كلمه ) مقدار
اين ثباتها كاهش پيدا كنند، قبل از movsbيا movswا يك دستور SLD قرار ميدهيم .
مثلا:
SLD
MOV CX/10 ; LOOP COUNTER
LOOP :_
MOVSB
LOOP LOOP _
دستور CLD عكس دستور SLD عمل كرده و مقدار ثباتهاي DIو SIو با انتقال هربايت يا
كلمه ، يكواحد افزايش پيدا ميكنند. اين عمل بطور پيش فرض توسط movsbو movswو
انجام ميشود ، با اينحال براي جلوگيري از تاثر SLD هاي قبلي و اطمينان بيشتر
معمولا از آن استفاده ميشود.
CLD
MOV CX/10 ; LOOP COUNTER
LOOP :_
MOVSB
LOOP LOOP _
CLS
*
مخفف CLear Direction flagو SLDو مخفف Set Direction flag است .
دستور REP
براي راحتي كار و اينكه مجبور به ايجاد حلقه توسط دستور Loop نباشيم ، دستورالعمل REP
در 8086 تعبيه شده . اين دستور مانند دستور Loop هر بار يكواحد از محتواي CX
كم كرده و تا صفر شدن CX به تكرار عمليات ادامه ميدهد . در واقع REP يك
دستورالعمل نبوده بلكه پيشوندي براي دستورات انتقال ( مانند movsb) است .
بعنوان مثال براي انتقال 20 بايت از رشته S1 به رشته S2 ( مثال بالا) ميتوانيم
حلقه را به اين صورت بنويسيم :
CLD
MOV CX/20
REP MOVSB
در قسمت بعد ، بقيه دستورات مربوط به رشته ها را باد ميگيريم .
-
دستورات مربوط به رشته ها
دستورات REPNE/REPE/CMPSW/CMPSB/CMPS
دستور CMPS براي مقايسه كردن دو رشته كاراكتري بكار ميرود. اين دستور دوبايت
واقع در ES:DIو DS:SIو را با هم مقايسه كرده و فلاگها را براساس نتيجه تنظيم
ميكند. سپس SIو DIو را افزايش (يا كاهش ) ميدهد. مثلا راي مقايسه كردن دو رشته
كاراكتري Str1وStr2و به اينصورت عمل ميكنيم : str1 db 'This is a set of chars$'
str2 db 'This is a set of chars$'
دقت كنيد كه در اين مثال دو رشته محتواي يكسان دارند . پس از آن آدرس اولين
رشته را در es:di و آدرس دومين رشته را در ds:si قرار ميدهيم .
lea si/str1
mov ax/ds
mov es/ax
lea di/str2
پس از آن چون ميخواهيم از بايت اول تا انتهاي رشته (22 بايت ) را مقايسه كنيم
ابتدا دستور CLS را براي افزاش si/di بكار برده ، و به شكل زير با تنظيم محتواي cx
به 22 ، 22 بايت دو رشته را مقايسه ميكنيم :
cld
mov cx/22
repe cmps str1/str2
jne mis_match
:
:
mis_mathc :
:
دستور Repe (مخفف Repeat while equal) تا زماني كه به اولين تفاوت برسد، بايتهاي
دو رشته كاراكتري را با هم مقايسه ميكند . وقتي به اولين مورد تفاوت برسيم فلاگ
وضعيت 1 شده و با دستور jne ميتوانيم به روال مورد نظر پرش كنيم .
تفاوت CMPSبا CMPSBاو CMPSWو در اينست كه CMPS به با توجه به نوع تعريفي رشته
ها عمل ميكند . يعني اگر رشته كاراكتري با تعريف DB ايجاد شده باشد، CMPS آندو
را بايت با بايت ، و اگر بصورت DW تعريف شده باشند، بصورت كلمه به كلمه
مقايسه ميكند .
اما CMPSB هميشه دو رشته كاراكتري را بايت به بايت مقايسه ميكند . و همينطور CMPSW
كه مقايسه را بصورت دوبايتي انجام ميدهد.
مزيت مهم cmpsbو cmpswوبر cmpsر اينست كه cmpsb/ccmpsw احتياج به اپراند ندارند
و تنها با اجراي cmpsbيا cmpswا بايتهاي لازم با هم مقايسه ميشوند .
مثال بالا را با استفاده از cmpsb مينويسيم :
:
cld
mov cx/22
RepNe cmpsb
je same
different :
:
:
ميبينيم كه در مقابل CMPSB هيچ اپراندي قرار ندارد . علاوه بر آن تغيير ديگري هم
ملاحظه ميكنيم : اينكه بجاي Repeاز Repneز (مخفف Repeat until not equal) استفاده
كرده ايم . RepNe تا وقتي كه به مورد مشابهي نرشد به مقايسه كردن رشته ها ادامه
ميدهد . وقتي به دو بايت يكسان برسد فلاگ وضعيت را طوري تغيير ميدهد كه بتوانيم
با JE به روتيني پرش كنيم كه ميخواهيم در صورت مساوي بودن رشته ها اجرا شود.
(در مثال بالا به same جهش كرده ايم ) .
دستورات SCAS/SCASB/SCASW
اين دستورات بايت واقع در AL با كلمه واقع در AX را با بايت با كلمات واقع در
رشته مقايسه ميكند . مانند CMPS، SCAS، به نوع تعريف رشته ها دقت ميكند و اگر
بصورت DB تعريف شده باشند ، بايت به بايت و اگر بصورت DW تعريف شده باشند
بصورت كلمه به كلمه جستجو ميكند . همچنين SCASBو SCASWو به اپراند احتياج ندارند
و فقط با تنظيم آدرسهاي DS:SIو ES:SIو ميتوانند بايت يا كلمه مورد نظر را جستجو
كنند.
مثال .
ميخواهيم برنامه اي بنويسيم كه محل اولين حرف 'a' را در رشته كاراكتري مورد نظر
پيدا كنيم . بنابراين ابتدا رشته كاراكتري را تعريف ميكنيم :
str db 'This is a sample text' ; 21 bytes .
سپس آدرس رشته را در DS:DI ، و 'a' را در نيم ثبات AL قرار ميدهيم .
mov al/'a'
lea di/str
پس از آن با عبارات زير عمل جستجو را آغاز ميكنيم . RepNe Scasb
JNE out
out
روتيني است كه در صورت يافته نشدن رشته كاراكتري بايد به آنجا جهش كنيم و
مثلا عبارتي مبني بر يافته نشدن رشته كاراكتري را چاپ كنيم . بدين ترتيب تمام
رشته كاراكتري را براي يافتن 'a' جستجو ميكنيم و درصورتي كه حداقل يك حرف 'a'
در رشته كاراكتري باشد ، با دستور JNE Out به روتين لازم جهش ميكنيم .
ليست كامل :
.286c
.MODEL SMALL
.CODE
ORG 100h
START:
JMP MAIN
STR1 DB 'This is a sample String' ; 25 Bytes
FOUND DB 'Match case found$'
NFOUND DB 'No Match case found$'
MAIN:
LEA DI/STR1
MOV CX/25
MOV AL/'a'
REPNE SCASB
JE OUT_
MOV AH/9
LEA DX/NFOUND
INT 21H
INT 20h
OUT:_
LEA DX/FOUND
MOV AH/9
INT 21H
INT 20H
END START
-
استفاده از ماوس
ے كاركردن با ماوس ساده تر و سريع تر از كار كردن با صفحه كليد است . بهمين علت
داشتن امكانات بكارگيري ماوس در برنامه ها، يك امتياز مهم محسوب ميشود.
ے براي اينكه برنامه اي بتواند از ماوس استفاده كند، بايد درايور مخصوص ماوس كه
ے عبارت از يك برنامه COM. (مانند MOUSE.COM) است را اجرا كنيم . اين درايور ها
روتينهاي مخصوص ماوس را در اينتراپت 33h لود ميكنند.
ے براي استفاده از ماوس ، پس از بارگذاري درايور مخصوص ، بايد ان درايور را فال
كنيم ، اين كار را با استفاده از سرويس 00h از وقفه 33h انجام ميدهيم :
براي اجرا باز ميگرداند
AX=0 =AX كد خطا
ے اگر راه اندازي ماوس موفقيت آميز باشد ، پس از فراخواني AX=0 خواهد بود در غير
ے اينصورت ، مثلا در مواقعي كه درايور ماوس نصب نشده باشد، AX حاوي كد خطا خواهد
بود.
ے مثال : اين برنامه ماوس را در صورت وجود راه اندازي ميكند و در صورت وقوع خطا
به نقطه لازم پرش ميكند: XOR AX/AX ;
INT 33H ;
آيا كد خطا وجود دارد? ; CMP AX/0
بله ، پرش به روتين خطا ; JNZ ERROR
ے بعد از آن بايد مكان نماي ماوس را نمايش بدهيم . براي اينكار كافيست كه AX را
برابر 1 قرار داده و INT 33h را اجرا كنيم . MOV AX/1
INT 33h
ے در صورتيكه درايور ماوس نصب يا راه اندازي نشده باشد، نتايج غير قابل پيش بيني
رخ خواهد بدست خواهد آمد.
ے به همين سادگي هم ميتوان مكان نماي ماوس را مخفي كرد. براي مخفي كردن مكان نماي
ماوس AX را برابر 2 تنظيم كرده و INT 33h را اجرا ميكنيم . MOV AX/2
INT 33h
ے بايد توجه كنيم كه اين سرويس را در حالتي كه مكان نماي ماوس فعال نيست اجرا
ے نكنيم . در صورتي كه عمل مخفي كردن مكان نماي ماوس را 2 بار انجام دهيم ، براي
ے ظاهر كردن آن هم بايد 2 بار متوالي سرويس راه اندازي مكان نماي ماوس را اجرا
كنيم .
ے در هنگام كار با ماوس لازم داريم كه موقعيت مكان نماي آن و هم چنين وضعيت
كليدهائي از ماوس كه فشرده يا رها شده اند را بدانيم .
ے براي دريافت اطلاعات ماوس از سرويس 3 وقفه 33h ، با پارامتر هاي زير استفاده
ميشود :
براي فراخواني برگردانده ميشود
AX=3 BX=0 هيچ دكمه اي فشرده نشده
BX=2 دكمه چپ فشرده شده است
BX=2 دكمه راست فشرده شده است
BX=3 هردو دكمه فشرده شده اند
CX: ستون فعلي مكان نما
DX: سطر فعلي مكان نما
ے همانطور كه ميبينيد، بعد از فراخواني وقفه ، رجيستر BX مشخص ميكند كه كدام
ے كليد(يا كليدها) فشرده شده اند. هم چنين موقعيت سطر و ستون مكان نما بر حسب
Pixel
بدست مي آيد.
ے بعنوان مثال اگر از ماوس در محيط گرافيكي با وضوح 480 َ640 استفاده ميكنيد ،
ے مقادير CXو DXو به ترتيب 640 و 480 خواهند بود . براي حالت متني كافيست كه
ے مقادير بدست آمده با CXو DXو را به 8 تقسيم و با 1 جمع كنيم تا موقعيت مكان
نما بر حسب سطر و ستون متني (Text) بدست بيايد.
مثال :
.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
MSG DB ' Press the Left Mouse Key to Terminate'/13/10/'$'
MAIN:
XOR AX/AX
INT 33H
MOV AX/1
INT 33H
MOV AX/3
LOOP:_
INT 33H
CMP BX/1
JNZ LOOP_
MOV AX/
-
بكارگيري Mouse
ے وقتي كه از سرويس 3h براي دريافت وضعيت ماوس استفاده ميكنيم ، تنها ميتوانيم
ے وضعيت ماوس در لحظه اجراي سرويس را بدست بياوريم . راه بهتر اينست كه از
ے سرويس 5h كه اعمال ماوس را در يك "صف " قرار ميدهد استفاده كنيم . در اين
ے حالت نيازي نيست كه اطلاعات فشرده شدن كليد را درست در همان لحظه دريافت كنيد
بلكه ميتوانيد آن را از "صف " برداريد.
سرويس 5h ، خواندن صف ماوس برميگردآند
AX=5 :BX تعداد دفعات فشرده شدن كليد ماوس
BX : 1: براي اطلاعات دكمه چپ :CX ستون فعلي مكان نما
0 براي اطلاعات دكمه راست :DX سطر فعلي مكان نما
ے اين سرويس به ما امكان ميدهد كه بدانيم دكمه مورد نظر بعد از آخرين دريافت
ے وضعيت چند مرتبه فشرده شده است . بهمين ترتيب ميتوانيم مختصات فعلي ماوس را
هم بدست بياوريم .
ے روش كار به اينصورت است كه ابتدا با قرار دادن 1يا 0ا در ثبات BX معلوم ميكنيم
ے كه اطلاعات كدام كليد را ميخواهيم دريافت كنيم . بعد از اجراي وقفه ، اطلاعات
ے كليد درخواستي از طريق ثبات BX و مختصات فعلي مكان نماي ماوس از طريق CX/DX
بدست مي آيد .
مثال :
ے اين مثال منتظر ميماند كه شما يكي از كليد هاي ماوس را فشار دهيد و در نهايت
به شما اعلام ميكند كه چند بار كليد سمت راست را فشار داده ايد.
.MODEL SMALL
.CODE
ORG 100H
START :JMP TOP
ANSWER DB " Number of times right botton was pressed"
TOP:
XOR AX/AX
INT 33H
MOV AX/1
INT 33H
MOV AH/7
INT 21H ; WAIT FOR A KEY
MOV BX/1
MOV AX/5
INT 33H
LEA DX/ANSWER
MOV AH/9
INT 21H
INT 20H
END START
ے سرويس 5h هنوز هم داراي محدوديتي است . به اين ترتيب كه موقعيت مكان نما در
ے زمان اجراي وقفه را برميگرداند. به همين خاطر مجبور خواهيد بود كه مرتبا با اجراي
ے اين سرويس ، اطلاعات ماوس را دريافت كنيد . براي حل اين مشكل از سرويس 6 كه
مكمل سرويس 5h است استفاده ميكنيم .
سرويس 6h از اينتراپت 33h
بايد تنظيم كنيم برميگرداند
AH=6h BX تعداد دفعات رها شدن دكمه ماوس
BX=1
اطلاعات دكمه چپ CX شماره ستون مكان نما در آخرين رها شدن
BX=0 اطلاعات دكمه راست DX شماره سطر مكان نما در آخرين رها شدن
ے مانند سرويس 5h بايد با قرار دادن 0يا 1ا در ثبات BX معلوم كنيم كه اطلاعات
ے كدام كليد را لازم داريم . اگرBX=1 باشد اطلاعات دكمه سمت چپ و در غير اينصورت
اطلاعات دكمه سمت راست بدست مي آيد.
ے بعد از فراخواني وقفه ، ثبات BX معلوم ميكند كه دكمه مورد نظر ، بعد از آخرين
ے دريافت وضعيت چند بار رها شده است . در مواقعي كه ميخواهيم چيزي را با ماوس
ے روي صفحه نمايش حركت بدهيم (مانند حركت دادن يك آيكون در ويندوز) رها شدن
دكمه هاي ماوس را هم بايد در نظر بگيريم .
حركت دادن مكان نماي ماوس
بعلاوه ميتوانيم مكان نماي ماوس را در موقعيت خاصي از صفحه نمايش قرار بدهيم .
كافيست كه از سرويس 4h به اين شكل استفاده كنيم . AX=4h
CX ستون جديد مكان نما
DX سطر جديد مكان نما
بعد از اجراي وقفه ، مكان نماي ماوس در محل مورد نظر قرار ميگيرد.
مثال :
.MODEL SMALL
.CODE
ORG 100H
START:
XOR AX/AX
INT 33H
MOV AH/7
INT 21H
XOR CX/CX
XOR DX/DX
MOV AX/4
INT 33H
MOV AH/7
INT 21H
INT 20H
END START
مويد باشيد
-
بكارگرفتن فايلها
ے تا قبل از DOS V.2 سيستم عامل داس براي كنترل فايلها از (Control Block
ے File)FCB استفاده ميكرد . اطلاعات هر فايل (شامل نام ، طول ، مسير و ... ) در
ے FCB قرار داشت و اين باعص ميشد نام فايل هميشه به 12 حرف محدود باشد. بنا
ے براين امكان ذكر مسير فايل به همراه اسم آن نبود . مثلا نميشد فايل SAMPLE.DAT
ے كه در C:\ قرار داشت را بصورت C:SSAMPLE.DAT نوشت . به همين دليل با انجام
ے تغيراتي در ساختار فايل گرداني DOS ، شناسه فايل (File Handle) ابداع شد و در
نگارشهاي 3/3 به بالاي DOS مورد استفاده قرار گرفت .
ے شناسه فايل يك كلمه (Word) 16 بيتي و معرف يك فايل در DOS است . هنگامي كه
ے ميخواهيد با فايلي كاركنيد ، نام آن را به DOS ميدهيد و DOS يك File Handle
به شما ميدهد . بعد از آن فقط با شناسه فايل كار داريم .
ے DOS بهمراه وقفه مخصوص خودش (Int 21h) ، سرويسهائي را بهمراه دارد كه براي
كاربا فايلها بكار ميرود .
ے اساسي ترين كار اينست كه بتوانيم يك فايل ايجاد كنيم . براي ايجاد فايل از
سرويس 3Ch به شكل زير استفاده ميكنيم .
AH=3CH
خصوصيات فايل CX=
اشاره به رشته كاراكتري محتوي نام فايل و مختوم به 0: DS:DX:
ے نام فايل بايد حتما به كاراكتر اسكي 0 مختوم باشد . CX مشخص كننده خصلت فايل
است و از جدول زير بدست مي آيد :
0
: فايل ساده 1
: فايل فقط خواندني 2
: فايل مخفي 4
: فايل سيستمي 8
: اسم ديسك اين خصلت را دارد 10h
: سابدايركتوري
ے مثال : در اين مثال يك فايل به اسم DUMMY.TXT ميسازيم . بعد از اجراي برنامه اگر
ے دستور DIR در سيستم عامل را اجرا كنيد ، فايلي به اسم DUMMY.TXT با طول صفر بايت
مشاهده ميكنيد.
.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
FILE DB 'DUMMY.TXT'/0
MAIN:
LEA DX/FILE
MOV AH/3CH
XOR CX/CX
INT 21H
INT 20H
END START
ے قدم بعدي نوشتن اطلاعات در فايل است . براي نوشتن در فايل ابتدا شناسه فايل را در
ے BX قرار ميدهيم . موقعيت محلي از حافظه كه داده ها از آن خوانده خواهند شد
ے با DS:DX و تعداد بايتهائي كه بايد منتقل شود با CX مشخص ميشود. در نهايت بايد
سرويس 40h را اجرا كنيم .
AH= 40H
اشاره به بافر DS:DX=
تعداد بايتها براي نوشتن CX=
شناسه فايل BX=
ے هر وقت يك فايل را ايجاد يا باز ميكنيم ، بايد آن را ببنديم مقداري از داده هاي
ے آن كه در حافظه مانده اند در فايل نوشته شده و حافظه اختصاص يافته به آن هم آزاد
ے شود . براي بستن يك فايل شناسه فايل را در BX قرار داده و وقفه 21h را با AH=3Eh
اجرا ميكنيم .
مثال :
ے قبلا در برنامه نويسي سيستم تصوير ديديم كه صفحه نمايش VGA در حالت 80x25
ے شامل 4000 بايت (80x25x2) براي كاراكتر و مشخصه است كه از آدرس 0000:َB800 شروع
ے ميشود . در اين مثال برنامه اي مينويسيم كه كل صفحه نمايش را از اين محل خوانده
و در فايل DUMMY.TXT ذخيره كند.
.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
BUF DB 4000 DUP(0)
FILE DB 'DUMMY.TXT'/0
HANDLE DW 0
MAIN:
LEA DX/FILE
MOV AH/3CH
XOR CX/CX
INT 21H
MOV HANDLE/AX
PUSH ES
MOV AX/DS
MOV ES/AX
LEA DI/BUF
PUSH DS
MOV AX/0B800H
MOV DS/AX
XOR SI/SI
MOV CX/4000
REP MOVSB
POP DS
POP ES
MOV AH/40H
MOV BX/HANDLE
MOV CX/4000
LEA DX/BUF
INT 21H
MOV AH/3EH
INT 21H
INT 20H
END START
ے ما همچنين ميتوانيم داده هاي يك فايل را بخوانيم و در محل خاصي از حافظه (معروف
ے به Buffer) قرار دهيم . براي خواندن از فايل سرويس 3Fh را با اين پارامترها بكار
ميبريم .
AH=3FH
شناسه فايل BX=
تعداد بايتها براي خواندن CX=
آدرس بافر براي انتقال داده هاDS:DX=
ے مثال : حالا برنامه اي مينويسيم كه فايل DUMMY.TXT ايجاد شده در مثال قبل را
ے خوانده و داده هاي آن را به بافر صفحه تصوير منتقل كند . به اين ترتيب محتواي
ے صفحه نمايش كه در هنگام اجراي SAVEFILE.COM ( برنامه مثال قبل ) ذخيره شده بود ،
مجددا نمايش داده ميشود.
.MODEL SMALL
.CODE
ORG 100H
START:
JMP MAIN
BUF DB 4000 DUP(0)
FILE DB 'DUMMY.TXT'/0
HANDLE DW 0
MAIN:
LEA DX/FILE
MOV AH/3DH
MOV AL/0 ; READ-ONLY
INT 21H
MOV BX/AX
MOV AH/3FH
MOV CX/4000
LEA DX/BUF
INT 21H
LEA SI/BUF
PUSH ES
MOV AX/0B800H
MOV ES/AX
XOR DI/DI
MOV CX/4000
REP MOVSB
POP ES
MOV AH/3EH
INT 21H
INT 20H
END START
-
دسترسي به پورتهاي كامپيوتر
تا اينجا برنامه نويسي خيلي از اجزاي كامپيوتر مثل صفحه كليد ، صفحه نمايش ،
ديسك و .. را ديديم . براي برنامه ريزي اينها از وقفه هاي BIOSيا DOSا استفاده
كرديم . وقفه هاي ياد شده همه زير برنامه هائي هستند كه به محض اجرا ، زير
برنامه هاي ديگري كه در بخشي از ROM كامپيوتر قرار دارند را به اجرا در مي
آورند . اين بخشها همگي داراي آدرسهائي هستند كه خارج از حوزه آدرس دهي CPU
قرار دارند . يعني نميتوان با الگوي Segment:Offset به آنها دسترسي پيدا كرد . در
عوض داراي شماره خاصي هستند كه به شماره Port معروفست . از طريق اين پورتها
ميتوانيم مستقيما و بدون واسطه به راهبري اجزاي كامپيوتر بپردازيم . مثلا ميتوانيم
با استفاده از پورت شماره 60h ، كار صفحه كليد را كنترل كنيم يا اينكه پورتهاي
...37Ah/379h/ به كنترل پورت موازي و چاپگر بپر دازيم . همينكار را وقفه 17h
(دسترسي به چاپگر) هم انجام ميدهد اما اين وقفه فقط براي كار با چاپگر طراحي شده
و نميتوانيم با استفاده از آن كار ديگري انجام بدهيم .
دستورات مربوط به پورتها
به هر پورتي ميتوان يك عدد تك بايتي فرستاد يا از آن خواند. براي نوشتن
در يك به روش زير عمل ميكنيم :
1- اگر عدد پورت كوچكتر از 255 باشد ، ميتوانيم با استفاده از دستور OUT و
بطور مستقيم عدد را به پورت بفرستيم . يعني بصورت OUT Portnumber/Value
مثال : OUT 80h/60
2
- اگر عدد مربوط به پورت از 255 ( يك بايت ) بيشتر باشد ، بايد ابتدا آن
را در ثبات DX قراردهيم ، سپس با استفاده از OUT ، مقدار را به پورت
بنويسيم .
مثلا براي نوشتن در پورت 3F8h ابتدا آن را در DX قرار ميدهيم و بعد عدد
را به پورت مشخص شده با DX انتقال ميدهيم . mov dx/3F8h
out dx/0FFh
در اين حالت يك بايت قابل انتقال است . براي ارسال يك عدد دوبايتي بايد
به سراغ نيم ثبات AL برويم . به اينصورت كه ابتدا 8 بايت سمت پائين
(سمت راست ) را در AL قرار داده و به پورت ميفرستيم . بعد بلافاصله 8 بايت
بالا را به همين ترتيب در پورت قرار ميدهيم . مثلا فر ض كنيد ميخواهيم عدد 0AFDh
را به پورت 61h بفرستيم :
mov ax/0AFDh
out 61h/al
shr ax/8
out 61h/al
براي خواندن پورت هم اگر شماره پورت از 255 بزرگتر باشد ، آن را در DX قرار
ميدهيم . وقتي ميخواهيم پورتي را بخوانيم ، بايد حتما اين كار را با كمك نيم
ثبات AL ، و با استفاده از دستور IN انجام دهيم . يعني بصورت :
IN AL/PortNo .
مثلا براي خواندن پورت 71h ، عبارت IN AL/71h را بكار ميبريم .
مثال :
عددي كه در پورت 61h قرار دارد براي بكار انداختن بلند گوي كامپيوتر بكار ميرود
( و برعكس براي از كار انداختن ) . اگر 3 بيت انتهائي آن 1 باشند ، بلندگوي
كامپيوتر ( با مشخصاتي كه در پورت هاي 41h و 43h قرار ميدهيم ) شروع به توليد
صوت ميكند . و اگر آن بيتها را بازهم 0 كنيم ، بلندگوي كامپيوتر از كار باز مي
ايستد . در اين برنامه بلند گوي كامپيوتر به كار مي افتد و بعد از فشردن يك
كليد مجددا" خاموش ميشود.
.MODEL SMALL
.CODE
ORG 100H
START:
IN AL/61H
OR AL/00000111B
OUT 61H/AL
XOR AH/AH
INT 16H
IN AL/61H
AND AL/11111000B
OUT 61H/AL
INT 20H
END START