loading...
دانلود سرای دانشجویی

در اين صفحه دستورات حلقه و نحوه پياده سازی ساختارهای حلقه های تکرار توضيح داده می شود.

LOOP
LOOPE/LOOPZ
حلقه های تکرار ديگر


LOOP

در زبان اسمبلی از دستور loop برای ساختن حلقه های شمارشی کاهشی با بدنه کوچک استفاده می شود. فرم کلی آن به صورت زير است:

loop target

دستورالعمل loop ثبات CX را يک واحد کم می کند سپس اگر مقدار جديد CX مخالف با صفر باشد به آدرس target پرش می کند. اگر CX برابر با صفر باشد دستور بعدی اجرا می شود.

ثبات CX به عنوان شمارنده عمل می کند و تعداد تکرار حلقه بايد ابتدا در ثبات CX قرار بگيرد.


مثال. دستورات زير مجموع اعداد 1 تا 10 را محاسبه و در ثبات AX ذخيره می کند.

      mov AX, 0
      mov CX, 10
lbl:
      add AX, CX
      loop lbl


توجه کنيد چون اين دستور ابتدا از CX يک واحد کم می کند، اگر CX قبلا حاوی صفر باشد بعد از کاهش برابر با مقدار 65535 می شود بنابراين حلقه 65536 بار تکرار خواهد شد.

دستورالعمل loop مشابه دستورات پرش کوتاه محدوده به 128 بايت است و برای حلقه با بدنه کوچک مناسب است. برای حلقه های تکرار با بدنه بيشتر می توانيد از دستورات پرش برای ساختن حلقه تکرار استفاده نمائيد.

اگرچه از نام دستورالعمل loop اينطور برمی آيد که حلقه تکرار ايجاد می کند اما به خاطر داشته باشيد که تمام کاری که انجام می دهد اين است که از ثبات CX يک واحد کم کرده اگر بعد از کاهش CX حای صفر نبود به آدرس مقصد پرش می کند.

دستورالعمل loop روی هيچکدام از ثبات ها تاثير ندارد.


LOOPE/LOOPZ

دستورالعمل های loopz و loope مشابه دستور loop می باشند با اين تفاوت که پرش در صورتی انجام می گيرد که CX مخالف با صفر و فلگ Z مساوی با يک باشد.

اين دستورات برای استفاده بعد از دستور cmp مفيد است.


مثال. دستورات زير اولين عنصر غيرصفر را در آ رايه 15 تائی Array جستجو می کند. اگر کليه عناصر آرايه صفر باشد بعد از اجرای حلقه به آدرس AllZero پرش می کند.

      lea SI, Array
      dec SI
      mov cx, 15
Search:
      inc SI
      cmp byte ptr [SI], 0
      loope Search
      je AllZero


حلقه های تکرار ديگر

از دستورات هم پرش می توان برای ساختن حلقه های تکرار استفاده کرد. به مثال های زير توجه کنيد.

مثال. دستورات زير مجموع اعداد 1 تا 10 را محاسبه و در ثبات AX ذخيره می کند.

       mov AX, 0
       mov CX, 1
For:
      cmp CX, 10
      jle Repeat
      jmp EndFor
Repeat:
      add AX, CX
      inc CX
      jmp For
EndFor:

مثال. دستورات زير کاراکترهائی را از کاربر گرفته و در يک آرايه ذخيره می کند تا وقتی که کليد enter وارد شود.

      lea SI, Array
Readkey:
      mov AH, 1
      int 21h           ;Get a character
      cmp AL, 13     ;Carriage return ASCII code
      je EndLoop
      mov [SI],AL    ;Save input character in Array
      inc SI
      jmp Readkey
EndLoop:

ساختارهای کنترلی نظير عبارات شرطی و حلقه های تکرار توسط دستورات پرش ساخته می شود. 8086 چند نوع دستورالعمل پرش را در اختيار می گذارد.

دستور پرش بدون شرط
دستورات پرش شرطی
ساختار شرط


دستورات برنامه پشت سر هم اجرا می شوند يعنی پردازنده دستورات را به ترتيبی که در برنامه ظاهر شده اند اجرا می کند. ساختارهای کنترلی نظير عبارات شرطی، حلقه ها و فراخوانی زيربرنامه روال اجرای برنامه را تغيير می دهد. زبان های سطح بالا ساختارهای کنترلی سطح بالا مانند دستورات if و while را دراختيار می گذارند که اجرای برنامه را کنترل می کنند. زبان اسمبلی چنين ساختارهای پيچيده ای را ندارد در عوض از دستورات پرش برای پياده سازی اين ساختارهای کنترلی استفاده می شود(که البته استفاده نامناسب آن باعث کد اسپاگتی می شود).

دستورات پرش اجرای برنامه را به نقطه دلخواهی منتقل می کنند. دو نوع دستورالعمل پرش وجود دارد:

• دستورات پرش بدون شرط
• دستورات پرش شرطی

گونه های مختلفی از دستورات پرش وجود دارند:

• کوتاه (short). اين نوع پرش بسيار محدود است و تنها می تواند 128 بايت بالا يا پايين بپرد. مزيت آن در مصرف کمتر حافظه است. ميزان جابجائی تنها توسط يک بايت مشخص می شود که تعيين می کند چند بايت جلوتر يا عقب تر برود. اين فاصله به ثبات IP اضافه می شود.
• نزديک (near). اين نوع پرش می تواند به هر موقعيت درون يک سگمنت پرش کند.
• دور (far). اين نوع پرش اجازه حرکت به سگمنت های ديگر را می دهد.

دستور پرش بدون شرط

دستورالعمل (jump) jmp بدون هيچ شرطی کنترل را به نقطه ديگری در برنامه منتقل می کند و مشابه دستور goto در زبان های سطح بالا عمل می کند. فرم کلی آن به صورت زير است:

jmp target

target می تواند آدرسی درون همين سگمنت يا سگمنت کد ديگری باشد. معمولا آدرس مقصد توسط يک برچسب معين می شود. برچسب شناسه ای است که بدنبال آن علامت کلون (:) می آيد. اسمبلر با توجه به آفست دستور بعد از برچسب، فاصله پرش را به طور اتوماتيک محاسبه می کند.

دستورالعمل بعد از jmp هيچوقت اجرا نمی شود مگر اين که از دستور ديگری به آن پرش شده باشد.

دستور jmp به تنهائی در برنامه موثر نيست و برای ساختن ساختارهای کنترلی همراه با دستورات پرش شرطی استفاده می شود.


مثال. حلقه زير مرتب از پورت موازی داده را می خواند و بيت صفر آنرا عکس می کند. اين باعث توليد يک سيگنال مربعی روی يکی از خطوط پورت پرينتر شود.

               mov DX, 378h   ;Parallel printer port address.
Forever: in AL, DX           ;Read character from input port.
               xor AL, 1           ;Invert the L.O. bit.
               out DX, AL        ;Output data back to port.
               jmp Forever      ;Repeat forever.


دستورات پرش شرطی

دستورات پرش شرطی برای ساختن حلقه ها و عبارات شرطی مانند if بکار می روند. پرش های شرطی يک يا چند فلگ را بررسی می کنند و با توجه به وضعيت آنها کنترل را به آدرس معينی منتقل می کنند. اگر پرش انجام نشود اجرا از دستورالعمل بعد از ادامه پيدا می کند.

با توجه به اينکه دستورات پرش شرطی فلگ ها را بررسی می کنند قبل از دستور پرش بايد دستوری وجود داشته باشد که روی فلگ ها تاثير بگذارد. برای مثال بعد از اجرای دستور shl می توانيد فلگ Carry را تست کنيد تا ببينيد بيت 1 از سمت چپ عدد خارج شده است يا خير. يا بعد از دستورالعمل test می توانيد فلگ Zero را بررسی کنيد تا ببينيد بيت های مشخصی در يک عدد 1 بوده اند يا خير. البته در اکثر موارد ساختارهای کنترلی بر اساس مقايسه مقادير و توسط cmp پياده سازی می شوند. دستورالعمل cmp با توجه به حاصل تفريق دو عملوند خود فلگ ها را تنظيم می کند بنابراين می تواند برای بررسی بزرگتر، کوچکتر يا مساوی بودن مقادير استفاده شود. برای مقدارهای بدون علامت دو فلگ Carry و Zero از ثبات پرچم مهم هستند و برای اعداد علامتدار فلگ های Sign و Zero اهميت دارند. فلگ Zero در صورتی که مساوی بودن عملوند را نشان می دهد.

دستورات پرش تنها فلگ ها را بررسی می کنند و روی آنها تاثيری ندارند.

دستورالعمل های پرش شرطی انواع مختلفی دارند که همگی با حرف J شروع می شوند و بعد از آن حروف ديگر قرار می گيرند. بدنبال دستور يک آدرس يا برچسب ذکر می شود. اين دستورات را به سه دسته کلی می توان تقسيم کرد:

• دستورات پرش بر اساس فلگ ها
• دستورات پرش بعد از مقايسه عملوندهای بدون علامت
• دستورات پرش بعد از مقايسه عملوندهای علامتدار

توجه داشته باشيد که پرش های شرطی از نوع کوتاه هستند و طول پرش محدود به 128 بايت است برای غلبه براين محدوديت می توانيد ساختار شرط را توسط پرش متضاد بسازيد.

در 8086 دستورات مترادفی برای تعدادی از دستورات پرش شرطی وجود دارد. جداول زير مترادف های هر دستور را ليست می کنند. در اين جداول همچنين دستورات متضاد هر دستور شرطی نيز بيان شده است.

دستورات پرش بر اساس فلگ ها

دستورالعمل
شرط
شرح
مترادف
متضاد
jc Carry = 1 پرش در صورتی که رقم نقلی وجود دارد jb, jnae jnc
jnc Carry = 0 پرش در صورتی که رقم نقلی وجود ندارد jnb, jae jc
jz Zero = 1 پرش در صورتی که صفر است je jnz
jnz Zero = 0 پرش در صورتی که صفر نيست jne jz
js Sign = 1 پرش در صورتی که مثبت است - jns
jns Sign = 0 پرش در صورتی که منفی است - js
jo Overflow=1 پرش در صورتی که سرريزی وجود دارد - jno
jno Overflew=0 پرش در صورتی که سرريزی وجود ندارد - jo
jp Parity = 1 پرش در صورتی که پريتی زوج است jpe jnp
jnp Parity = 0 پرش در صورتی که پريتی فرد است jpo jp

دستورات پرش بعد از مقايسه بدون علامت

دستورالعمل
شرط
شرح
مترادف
متضاد
ja Carry=0, Zero=0 پرش در صورتی که بالاتر است jnbe jna
jnbe Carry=0, Zero=0 پرش در صورتی که پايين تر يا مساوی نيست ja jbe
jae Carry = 0 پرش در صورتی که بالاتر يا مساوی است jnc, jnb jnae
jnb Carry = 0 پرش در صورتی که پايين تر نيست jnc, jae jb
jb Carry = 1 پرش در صورتی که پايين تر است jc, jnae jnb
jnae Carry = 1 پرش در صورتی که بالاتر يا مساوی نيست jc, jb jae
jbe Carry = 1 يا Zero = 1 پرش در صورتی که پايين تر يا مساوی است jna jnbe
jna Carry = 1 يا Zero = 1 پرش در صورتی که بالاتر نيست jbe ja
je Zero = 1 پرش در صورتی که مساوی است jz jne
jne Zero = 0 پرش در صورتی که نامساوی است jnz je

دستورات پرش بعد از مقايسه علامتدار

دستورالعمل
شرط
شرح
مترادف
متضاد
jg Sign = Overflow يا Zero=0 پرش در صورتی که بزرگتر است jnle jng
jnle Sign = Overflow يا Zero=0 پرش در صورتی که کوچکتر يا مساوی نيست jg jle
jge Sign = Overflow پرش در صورتی که بزرگتر يا مساوی است jnl jge
jnl Sign = Overflow پرش در صورتی که کوچکتر نيست jge jl
jl Sign Overflow پرش در صورتی که کوچکتر است jnge jnl
jnge Sign Overflow پرش در صورتی که بزرگتر يا مساوی نيست jl jge
jle Sign Overflow يا Zero=1 پرش در صورتی که کوچکتر يا مساوی است jng jnle
jng Sign Overflow يا Zero=1 پرش در صورتی که بزرگتر نيست jle jg
je Zero = 1 پرش در صورتی که مساوی است jz jne
jne Zero = 0 پرش در صورتی که نامساوی است jnz je

ساختار شرط

از دستورات پرش شرطی می توان برای ساختن عبارات if استفاده کرد. به مثال های زير دقت کنيد.

مثال. در دستورات زير اگر Sum>0 باشد به AH مقدار يک را اختصاص می دهد درغير اينصورت BH را يک می کند.

          cmp Sum, 0
          jg Then
          jmp Else
Then: mov AH,1
          jmp EndIf
Else:   mov BH,1
EndIf:

مثال. در دستورات زير اگر Total>=100 and Count =0 باشد مقدار Value را با AX جمع می کند.

          cmp total, 100
          jge C2
          jmp EndIf
C2:     cmp Count, 10
          je Then
          jmp EndIf
Then: add AX, Value
EndIf:


دستورات چرخش رشته های بيتی را به صورت دايره ای حرکت می دهد اين دستورات مشابه شيفت عمل می کنند با اين تفاوت که بيتی که از يک طرف از داده خارج می شود به طور دوار از جهت ديگر وارد آن می شود. پردازنده 8086 چهار دستورالعمل چرخش (rol ، ror ، rcl و rcr) دارد.

ROL
ROR
RCL
RCR


ROL

دستورالعمل (rotate left) rol بيت های عملوند خود را به سمت چپ چرخش می دهد. فرم کلی آن به صورت زير است:

rol dest, count

دستورالعمل rol بيت های عملوند مقصد خود را به تعداد count به سمت چپ چرخش می دهد. بيتی که از سمت چپ خارج می شود از سمت راست وارد عملوند می شود.با ارزش ترين بيت عدد در فلگ carry کپی می شود.

عملوند اول عملوند مقصد است و عملوند دوم تعداد شيفت ها را مشخص می کند و می تواند عدد 1 يا برای تعداد بيشتر ثبات CL باشد. نوشتن عدد فوری بيشتر از 1 مستقيما در دستور غير مجاز است.

دستورالعمل rol به شکل های زير می تواند استفاده شود:

rol register, 1
rol memory, 1
rol register, CL
rol memory, CL

دستورالعمل rol بيت های فلگ را به صورت زير تغيير می دهد:

• فلگ carry حاوی آخرين با ارزش ترين بيت عملوند می شود.
• اگر تعداد چرخش يکبار باشد و علامت عدد بعد از چرخش تغيير کند فلگ overflow يک می شود. برای چرخش بيشتر از يکبار نامعين است.
• روی فلگ های Sign ، Zero ، Parity و Auxiliary carry تاثير ندارد. اگر نيازداريد مقدار اين فلگ ها را بعد از عمل چرخش بدانيد نتيجه را با صفر مقايسه کنيد تا اين فلگ ها تنظيم شوند.


مثال.

mov AX, C123h
mov CL,3
rol AX, CL    ;AX = 091Eh, CF = 0


ROR

دستورالعمل (rotate right) ror بيت های عملوند خود را به سمت راست چرخش می دهد. فرم کلی آن به صورت زير است:

ror dest, count

دستورالعمل ror بيت های عملوند مقصد خود را به تعداد count به سمت راست چرخش می دهد. بيتی که از سمت راست خارج می شود از سمت چپ وارد عملوند می شود.

مشابه دستورالعمل rol عملوند دستورالعمل ror می تواند ثبات يا حافظه باشد. تعداد چرخش عدد 1 يا ثبات CL است.

کم ارزش ترين بيت عملوند وارد فلگ carry می شود. بقيه فلگ ها مشابه دستورالعمل rol تاثير می پذيرند.


مثال.

mov AX, C123h
mov Cl,2
ror AX, CL     ;AX = F048h, CF = 1


RCL

دستورالعمل (rotate through carry left) rcl همانطور که از نامش پيدا است، بيت ها را از طريق فلگ carry به سمت چپ می چرخاند. شکل کلی آن به صورت زير است:

rcl dest, count

دستورالعمل rcl محتوای فلگ Carry را از سمت راست وارد عملوند مقصد می کند، سپس بيت های عملوند را به سمت چپ شيفت می دهد و آخرين بيت سمت چپ را وارد فلگ Carry می شود.

دستورالعمل rcl مشابه rol استفاده می شود و روی فلگ ها تاثير می گذارد.


RCR

دستورالعمل (rotate through carry right) rcr بيت های داده را از طريق فلگ carry به سمت راست می چرخاند. شکل کلی آن به صورت زير است:

rcr dest, count

دستورالعمل rcr محتوای فلگ Carry را از سمت چپ وارد عملوند مقصد می کند، سپس بيت های عملوند را به سمت راست شيفت می دهد و آخرين بيت سمت راست را وارد فلگ Carry می شود.

دستورالعمل rcr مشابه ror استفاده می شود و روی فلگ ها تاثير می گذارد.

دستورات شیفت يک رشته بیتی را به سمت راست يا چپ حرکت می دهند. توسط اين دستورات می توان روی بيت های داده کار کرد؛ داده را ادغام يا جدا کرد و عمليات محاسباتی را انجام داد. ريزپردازنده 8086 سه دستورالعمل شيفت (shl/sal، shr و sar) دارد. بخش زير هر يک از اين دستورالعمل ها را شرح می دهد.

SHL/SAL
SHR
SAR
کاربردهای شيفت


عمل شيفت بيت های داده را حرکت می دهد. حرکت بيت ها می تواند به سمت چپ (به سمت بيت های با ارزش) يا راست (به سمت بيت های کم ارزش) باشد. فلگ Carry معمولا آخرین بيت شیفت داده شده که از عملوند خارج می شود را می گيرد.

دو نوع شيفت وجود دارد: شيفت منطقی و شيفت رياضی. شيفت منطقی ساده ترين شيفت است که به طريق ساده ای بيت ها را شيفت می دهد. در شيفت رياضی علامت عدد حفظ می شود.


مثال. يک عدد شيفت داده شده يک بايتی نشان داده شده است.

Shift Example

توجه کنيد که بيت های جديدی که وارد می شوند هميشه صفر هستند.


SHL/SAL

دستورالعمل (shift left) shl يا (shift arithmetic left) sal بيت های داده را به سمت چپ حرکت می دهد. فرم کلی آنها به صورت زير است:

shl dest, count
sal dest, count

shl و sal معادل هستند و يک دستورالعمل را نشان می دهند يعنی کد يکسانی دارند. اين دستورالعمل ها هر بيت عملوند مقصد را به سمت چپ عدد به تعداد عملوند count حرکت می دهند. از سمت راست عدد 0 وارد عدد می شود و آخرين بيتی که از سمت چپ خارج می شود وارد فلگ carry می شود.

عملوند اول مقداری است که شيفت داده می شود و عملوند مقصد است. count تعداد شيفت ها را مشخص می کند و می تواند عدد 1 يا برای تعداد شيفت های بالاتر ثبات CL باشد. نوشتن تعداد شيفت بيشتر از 1 مستقيما در دستور غير مجاز است.

دستورالعمل shl/sal می تواند به صورت های زير بکار رود:

shl register, 1
shl memory, 1
shl register, CL
shl memory, CL

دستورالعمل shl/sal به صورت زير روی فلگ تاثير می گذارد:

• اگر تعداد شيفت صفر باشد فلگ ها تغييری نمی کنند.
• فلگ carry آخرين بيت خارج شده از سمت چپ عملوند را نگه می دارد.
• فلگ overflow در يک بيت شيفت يک می شود اگر دو بيت آخرعملوند متفاوت باشند. به عبارت ديگر بعد از عمل شيفت بيت علامت عدد تغيير کند. برای شيفت های بيشتر از يکبار نامعين است.
• فلگ zero، sign و parity با توجه به نتيجه تغيير می کنند.
• فلگ Auxilury Carry نامعين است.


مثال.

mov AX, 4123h
shl AX, 1    ; shift 1 bit to left, ax = 8246H, CF = 0


SHR

دستورالعمل (shift right) shr بيت های داده را به سمت راست حرکت می دهد. فرم کلی آنها به صورت زير است:

shr dest, count

دستورالعمل shr کليه بيت های عملوند مقصد را به تعداد count به سمت راست شيفت منطقی می دهد. از سمت چپ صفر وارد عملوند می شود و آخرين بيتی که از سمت راست خارج می شود وارد فلگ Carry می شود.

دستورالعمل shr مانند shl استفاده می شود؛ عملوند آن می تواند ثبات يا مکانی از حافظه باشد و تعداد شيفت ها می تواند عدد 1 يا ثبات CL باشد.

دستورالعمل shr فلگ ها را به صورت زير تنظيم می کند:

• اگر تعداد شيفت صفر باشد فلگ ها تغييری نمی کنند.
• فلگ carry آخرين بيت خارج شده از سمت راست عملوند را نگه می دارد.
• در يک بيت شيفت فلگ overflow يک می شود اگر دو بيت آخرعملوند متفاوت باشند. به عبارت ديگر اگر بعد از عمل شيفت بيت علامت عدد تغيير کند. برای شيفت های بيشتر از يکبار نامعين است.
• فلگ zero، sign و parity با توجه به نتيجه تغيير می کنند.
• فلگ Auxilury Carry نامعين است.


مثال.

mov AX, C1A5h
mov CL,3
shr AX, CL    ; shift 3 bit to right, ax = 1834h, CF = 1


SAR

دستورالعمل (shift arithmetic right) sar مانند دستورالعمل shr است با اين تفاوت که علامت عملوند تغيير را نمی دهد. فرم کلی آن به صورت زير است:

sar dest, count

اين شيفت برای اعداد علامتدار طراحی شده است و بيت های عملوند مقصد را به سمت راست شيفت رياضی می دهد و بيت علامت را در خودش کپی می کند.

دستورالعمل sar مشابه دستورالعمل shr بکار می رود و به همان صورت روی فلگ ها تاثير می گذارد.


مثال.

mov AX, C1A5h
sar AX, 1    ; shift 1 bit to right, ax = E0D2h, CF = 1


کاربردهای شيفت

مثال. فرض کنيد می خواهيد دو نيبل پائينی ثبات های AL و AH را با هم به صورت زير ترکيب کنيد. کد زير اين کار را انجام می دهد.

mov CL, 4
shl AH, CL
and AL, 0Fh
or AL, AH

مثال. فرض کنيد می خواهيد دو نيبل ثبات AL را از هم جدا کرده و نيمه سمت چپ را در ثبات AH و نيمه سمت راست را در ثبات AL به صورت زير قرار دهيد. کدهای زير اين عمل را انجام می دهد.

mov AH, AL
mov CL, 4
shr AH, CL
and AL, 0Fh

مثال. هر شيفت به چپ باعث دو برابر شدن عملوند می شود که سرعت بيشتری نسبت به عمل mul دارد. دستورالعمل های shl/sal برای ضرب مقادير علامت دار يا بدون علامت در توان های 2 استفاده می شود. دستور زير مقدار ثبات AX را در عدد 4 ضرب می کند.

mov CL,2
shl AX, CL

مثال. برای محاسبه 10×AX می توانيد به روش زير از دستورشيفت چپ استفاده کنيد (با توجه به اينکه 10×AX=8×AX + 2×AX).

shl AX, 1
mov BX, AX
shl AX, 1
shl AX, 1
add AX, BX

مثال. کدهای زير حاصلضرب AX×7 را محاسبه می کنند (با توجه به اينکه ax×7 = (ax×8)-ax ).

mov BX, AX
shl AX, 1
shl AX, 1
shl AX, 1
sub AX, BX

مثال. چون يک شيفت منطقی به سمت راست مقدار يک عدد صحيح بدون علامت را نصف می کند می توان برای تقسيم بر توان های 2 از آن استفاده کرد. دستورات زير خارج قسمت مقدار ثبات AX بر 8 را محاسبه می کنند.

mov CL,3
shr AX, CL

مثال. برای انجام تقسيم علامتدار بر توان های 2 از شيفت رياضی راست استفاده می شود. دستور زير مقدار ثبات AX را بر عدد 32 تقسيم می کند.

mov CL,5
sar AX, CL

مثال. توجه کنيد اگر عملوند منفی باشد نتيجه دو دستور sar و idiv متفاوت می شود. به دستورات زير دقت کنيد.

mov ax, -15
cwd
mov bx, 2
idiv            ;خارج قسمت 7- مي شود

mov ax, -15
sar ax, 1    ;خارج قسمت 8- مي شود

مثال. از شيفت رياضی راست می توانيد برای گسترش رياضی یک عدد علامتدار استفاده کنيد. به کدهای زير دقت کنيد.

; CBW معادل دستور:
mov AH, AL
mov CL, 7
sar AH, CL

; CWD معادل دستور:
mov DX, AX
mov CL, 15
sar DX, CL

البته وقتی يک دستور cbw يا cwd برای گسترش وجود دارد کسی از دو دستور استفاده نمی کند، ولی دستور شيفت اجازه می دهد که مقدار يک ثبات را در هر ثبات ديگرهم اندازه ای به طور رياضی گسترش دهيد:

; DX:BX به BX گسترش رياضی:
mov DX, BX
mov CL, 15
sar DX, CL

 

آماده سازی منطق برنامه

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

تهيه کد برنامه

کد برنامه (source code) مجموعه عبارات يا دستوراتی است کامپيوتر را هدايت می کند تا عمل موردنظر شما انجام بپذيرد. از يک ويرايشگر متن برای وارد کردن کد برنامه استفاده کنيد. اغلب کامپايلرهای نظير Borland's Turbo C++ و Visual C/C++ همراه با يک محيط مجتمع (IDE) می آيند که اجازه تايپ، کامپايل و لينک برنامه را در يک محيط مناسب می دهند. در غيراينصورت از ويرايشگرهای متن ديگر مانند Edit، Notepad و Microsoft Windows می توانيد استفاده کنيد و برنامه خود را با فرمت ASCII روی ديسک ذخيره نمائيد.

کد برنامه را با پسوند cpp. ذخيره کنيد.

ترجمه کد برنامه

برای ترجمه يک برنامه C/C++ کامپايلرهای مختلفی وجود دارد. نسخه رايگان کامپايلر Borland C++ محيط مجتمع پياده سازی ندارد و يک کامپايلر خط فرمانی است يعنی بايد در محيط سيستم عامل DOS فرمان ترجمه برنامه صادر شود.

مثال. اگر Borland's Turbo C++ را استفاده می کنيد، برای ترجمه برنامه Hello.cpp فرمان زير را در خط فرمان سيستم عامل بايد وارد نمائيد:

bcc Hello.cpp

ترجمه برنامه در کامپايلرهای با محيط مجتمع (مانند Borland C++ 3.1) يا محيط گرافيکی (مانند Microsoft Visual C++) راحت تر صورت می گيرد. کافی است ازمنو گزينه Compile يا Run را انتخاب کنيد.

اگر کامپايلر خطائی در برنامه مشاهده نکرد فايل مقصد حاوی کد زبان ماشين برنامه هم نام برنامه و با پسوند obj. ايجاد می شود. اگر خطائی در برنامه وجود داشته باشد گزارش خطا توسط کامپايلر تهيه می شود در اينصورت بايد به کد برنامه مراجعه کرده خطا را برطرف کنيد.

تهيه برنامه اجرائی

وقتی از توابع کتابخانه ای استفاده می کنيد، فايل مقصد توليد شده بايد با کد مقصد تابع کتابخانه ترکيب شود تا فايل اجرائی نهائی شکل بگيرد. اين فرآيند linking نام دارد که توسط برنامه لينکر (linker) انجام می گيرد. اگر لينکر در اين فرآيند با مشکلی مواجه نشود، يک برنامه اجرائی روی ديسک هم نام برنامه و با پسوند exe. ايجاد می شود.

اجرای برنامه

با توليد برنامه اجرائی، می توانيد آنرا اجرا کنيد. بايد برنامه را تست کنيد تا مطمئن شويد درست کار می کند. اگر نتايجی متفاوت از آنچه انتظار داشتيد دريافت کرديد بايد به قدم اول برگشته علت خطا را پيدا کنيد و کد برنامه را اصلاح کنيد و مجددا برنامه را ترجمه، لينک و اجرا کنيد.

در اکثر کامپايلرها امکان انجام مراحل ترجمه، لينک و اجرا در يک مرحله وجود دارد، گرچه در اينجا به عنوان مراحل جداگانه مطرح شد.


مثال. اگر برنامه Hello.cpp موفق ترجمه و لينک شود فايل های Hello.obj که شامل کد زبان ماشين برنامه و Hello.exe که برنامه اجرائی توليد شده است روی ديسک ايجاد می شود. با اجرای برنامه جمله Hello, World! روی صفحه مشاهده می شود.

 

برای آشنائی سريعتر با ساختار برنامه ++C يک برنامه ساده کوچک در اينجا ارائه می شود که ممکن است در وحله اول کاملا قابل درک نباشد. توضيحات بيشتر درباره برنامه در دنباله آن داده شده است.


مثال. برنامه Hello.cpp يک پيغام را روی صفحه نمايش می دهد.

/* HELLO.CPP */
#include <iostream>
using namespace std;
int main()
{
   //print hello word on the screen
   cout << "Hello World!n";
   return 0;
}


تابع اصلی

در زبان C برنامه از يک سری تابع (function) تشکيل می شود (توضيحات بيشتر درباره تابع). هر برنامه الزاما يک تابع اصلی به نام main دارد که برنامه از آن شروع به اجرا می کند.

نوع برگشتی تابع در خط اعلان تابع و قبل از نام تابع تعيين می شود. که برای تابع اصلی معمولا نوع صحيح يا int درنظر گرفته می شود. چون برخی از سيستم عامل ها نيازدارند برنامه مقداری را به آنها برگرداند تابع main يک عدد صحيح را بر می گرداند تا سيستم عامل متوجه بشود که همه چيز درست است. البته در بعضی موارد تابع اصلی را می توان به صورت void main() هم تعريف کرد. کلمه void مشخص می کند تابع چيزی بر نمی گرداند.

مقداری که تابع بر می گرداند در مقابل دستور return نوشته می شود. اگر تابعی مقداری برنگرداند و از نوع void تعريف شده باشد نيازی به استفاده از دستور return در تابع نيست.

بدنه توابع و بلوک های کد مابين دو کروشه باز و بسته { } قرار می گيرند. کروشه مرز يک بلاک از کد را معين می کند. وقت کنيد که برای هر کروشه باز { يک کروشه بسته } بايد وجود داشته باشد.

int main()
{
   return 0;
}


فايل های ضميمه

معمولا اولين عمل در هر برنامه C++ ضميمه کردن فايل های هدر است. فايل های هدر (include file) فايل هائی شامل تعاريف توابع يا کلاس ها هستند. اگر توابع يا متغيرهائی وجود دارند که در برنامه های مختلف مورد استفاده قرار می گيرند بهتر است در يک فايل هدر قرار داده شوند، سپس فايل هدر در هرجائی که از آن استفاده می شود ضميمه شود.

برای ضميمه کردن يک فايل به برنامه علامت # سپس include و نام فايل ضميمه در داخل < > ذکر می شود.

اولين خط برنامه Hello.cpp فايل هدر iostream.h را ضميمه برنامه می کند.

#include <iostream.h>

تعداد زيادی از فايل های هدر در ++C برای استفاده از توابع کتابخانه ای همراه با نصب کامپايلر در اختيار برنامه نويس قرار می گيرند. يکی از اين فايل ها فايل هدر iostream.h است که توابعی برای عمليات ورودی و خروجی دارد. اگر اين فايل در ابتدای برنامه ضميمه شود کليه کلاس ها و توابع تعريف شده در آن قابل دسترسی هستند.

پسوند .h مشخص مي کند يک فايل هدر است. اگر کامپايلر C را استفاده می کنيد پسوند .h بايد مشخص شود ولی در ++C نياز نيست. البته بهتر است که ذکر شود تا توسط کامپايلرها پشتيبانی شود.


نمايش پيغام

تابع cout برای نمايش داده ها و پيغام ها روی صفحه نمايش بکار می رود. اين توابع در فايل هدر iostream قرار دارد که بايد به برنامه ضميمه شده باشد.

cout << "Hello World!n";

در زبان ++C يک رشته کاراکتری بايد بين دو علامت " " محصور شود

n به کامپايلر می گويد از يک خط جديد شروع کند.


فضای اسمی

فضای اسمی (namespace) اجازه گروه بندی مجموعه ای از توابع يا اشيای سراسری را تحت يک نام می دهد (توضيحات بيشتر درباره فضاهای اسمی). وقتی يک فايل هدر اضافه می شود محتويات آن در فضای اسمی استاندارد std قرار می گيرد. برای دسترسی به کتابخانه های استاندارد درون std بايد از عملگر :: استفاده شود.

مثال. وقتی iostream در برنامه ضميمه شده است برای دسترسی به تابع cout از اين کتابخانه بايد فضای اسمی std قبل از آن و بدنبالش علامت :: تعيين شود:

Std::cout <<"Hello World!n";

البته به سادگی می توان با استفاده از عبارت using فضای اسمی مورد استفاده را در برنامه تعيين کرد و به عناصر درون std تنها با صدازدن نامشان دسترسی پيدا کرد.

وقتی پسوند .h اضافه می شود نيازی به اضافه کردن فضای اسمی استاندارد نيست ولی به طور معمول بهتر است که از استاندارد ANSI/ISO تبعيت بشود و فضای اسمی std توسط عبارت using تعيين شود.

نکته. کامپايلرهای قديمی عبارت using را قبول نمی کنند.


توضيحات

توضيحات (comment) عباراتی هستند که هنگام ترجمه ناديده گرفته می شوند. توضيحات شرح مرحله به مرحله از عمليات برنامه را برای برنامه نويس، يا هر فردی که روی کد برنامه کار می کند، ارائه می دهد.

در ++C دو روش برای ساختن توضيح وجود دارد؛ يک روش که برای توضيحات کوتاه است با علامت // شروع می شود. کامپايلر از اين علامت تا انتهای خط را به عنوان توضيح درنظر می گيرد.

روش ديگر که معمولا برای توضيحات طولانی تر استفاده می شود بستن توضيحات بين علائم /* */ است.

//print hello word on the screen
/* This is my first program in C++ */

نکته. توضيحات يک خطی به دنبال علامت // تنها در کامپايلرهای ++C قابل استفاده است.

 

++C بر مبنای زبان برنامه نويسی C است. زبان C در سال 1972 در آزمايشگاه Bell Telephone نوسط Dennis Ritchie به عنوان زبان پياده سازی برای سيستم عامل يونيکس طراحی شد. مقدار زيادی از برنامه نويسی يونيکس با زبان C انجام شده است. C در نتيجه تکوين پروسه ای است که با يک زبان قديمی تر به نام BCPL شروع شده بود. زبان BCPL زبانی بر اساس زبان B بوده است که توسط Ken Thompson در آزمايشگاه Bell طراحی شده بود.

به دليل اينکه C زبان قدرتمند و انعطاف پذيری بود، سريعا گسترش پيدا کرد. برنامه نويسان شروع به استفاده از آن برای انواع برنامه ها کردند. سازمان های مختلف شروع به پياده سازی نسخه های C خود شدند. تا اينکه در سال 1983، ANSI استاندارد C را تنظيم کرد که به عنوان ANSI Standard C شناخته می شود. کامپايلرهای بعدی C از اين استاندارد پيروی کردند.

زبان برنامه نويسي ++C بر اساس زبان C توسط Bjarne Stroustrup ابداع شد. آنچه امروزه ++C ناميده مي شود از سال 1979 آغاز شده است. نسخه اوليه آن "C with classes" ناميده شد که بعدا به ++C تغيير کرد. ++C کليه ويژگی های زبان C را داراست. تفاوت بين آنها اينستکه ++C شي گرائی را پشتيبانی می کند. البته پيشرفت های ديگری هم دارد برای مثال کار با رشته ها و سروکارداشتن با خطاها در آن قوی تر است.

نسخه اول ++C ابتدا در AT&T در سال 1983 استفاده شد. اولين نسخه تجاری آن در اکتبر 1985 به بازار آمد. در سال 1998 ANSI و ISO متفقا ++C را استاندارد کردند. به همين دليل اغلب ++C محض را ANSI Standard ++C يا ISO Standard ++C می نامند.

با تکامل ++C يک کتابخانه استاندارد هم با آن شکل گرفت. اولين کتابخانه استاندارد ++C کتابخانه stream I/O بود که امکاناتی برای جايگزينی توابع قديمی C مانند printf و scanf مهيا کرد. بعد از آن مهمترين کتابخانه استاندارد کتابخانه Standard Template بود.

توجه داشته باشيد که کد C در کامپايلر ++C کامپايل می شود اما عکس آن صادق نيست و کد ++C لزوما در کامپايلر C کامپايل نمی شود.

دستورات منطقی 8086 عمليات منطقی and، or، xor و not را به صورت بيت به بيت روی عملوندها انجام می دهند.

AND
OR
XOR
NOT
TEST
دستکاری بيت ها


AND

دستورالعمل and عمل and منطقی را روی دو عملوند خود انجام می دهد و نتيجه را در عملوند اول ذخيره می کند. فرم کلی آن به صورت زير است:

and dest, src

طبق جدول زير عمل and روی بيت های متناظر دو عملوند انجام می شود. هر بيت نتيجه در صورتی يک است که بيت های متناظر هر دو عملوند يک باشند در غير اينصورت صفر می شود.

A
B
A and B
1 1 1
1 0 0
0 1 0
0 0 0

دستورالعمل and به شکل های زير می تواند بکار برود:

and register, register
and memory, register
and register, memory
and register, immediate data
and memory, immediate data
and /AL, immediate data

دستورالعمل and روی فلگ های زير تاثير می گذارد:

• فلگ carry و overflow را صفر می کند.
• فلگ های zero، sign و parity با توجه به نتيجه تاثير می پذيرند.

فلگ zero وقتي دو عملوند در هيچ مکانی بيت مشابه نداشته باشند يک می شود.


مثال

mov AX, C123h
and AX, 82F6h

AND Example


دستورالعمل and برای محاسبه سريع باقيمانده يک عدد بر توانی از 2 می تواند استفاده شود. برای پيدا کردن باقيمانده عملوندی بر مقدار 2n کافيست and عملوند با مقدار 2n-1 محاسبه شود.


مثال. دستور زير باقيمانده بر عدد 8 را محاسبه می کند.

and AX, 7


OR

دستورالعمل or عمل or منطقی را روی عملوندهای خود انجام می دهد. فرم کلی آن به صورت زير است:

or dest, src

عمل or، طبق جدول زير، روی عملوندها بيت به بيت انجام می گيرد. هر بيت نتيجه دستور or در صورتی صفر است که بيت های متناظر هر دو عملوند صفر باشند در غير اينصورت يک می شود.

A
B
A or B
1 1 1
1 0 1
0 1 1
0 0 0

دستورالعمل or مشابه عمل and روی فلگ های Carry، Zero، Sign، Overflow و Parity تاثير می گذارد. فلگ zero وقتی يک می شود که هردو عملوند صفر باشند.

عملوندهای دستورالعمل or مشابه دستورالعمل and می تواند ثبات، حافظه يا داده فوری باشد.


مثال.

mov AX, C123h
or AX, E831h

OR Example


XOR

دستورالعمل xor عمل xor منطقی را روی بيت های دو عملوند خود انجام می دهد و نتيجه را در عملوند اول ذخيره می کند. فرم کلی آن به صورت زير است:

xor dest, src

هر بيت نتيجه دستورالعمل xor مطابق جدول زير تنظيم می شد. بيت نتيجه زمانی صفر است که هردو بيت عملوند مشابه هم باشند درغير اينصورت يک می شود.

A
B
A xor B
1 1 0
1 0 1
0 1 1
0 0 0

دستورالعمل xor مشابه عمل and روی فلگ ها تاثير می گذارد. اگر هردو عملوند دستورالعمل مساوی باشند نتيجه صفر می شود و در نتيجه فلگ zero يک می شود.

برای صفر کردن ثبات ها می توان از دستورالعمل xor register, register استفاده کرد که کوتاهتر از دستورالعمل mov register,0 است.


مثال.

mov AX, C123h
xor AX, E831h

XOR Example


NOT

دستورالعمل not مکمل يک عملوند خود را محاسبه و در آن ذخيره می کند. فرم کلي آن به صورت زير است:

not dest

دستورالعمل not بيت های عملوند را عکس می کند؛ صفرها را به يک و يک ها را به صفر تبديل می نمايد.

دستورالعمل not به يکی از دو حالت زير می تواند استفاده شود:

not register
not memory

دستورالعمل not روی هيچکدام از فلگ ها تاثير ندارد.


مثال.

mov AX, C123h
not

NOT Example


TEST

دستورالعمل test مشابه and است و عمل and منطقی را روی دو عملوند خود انجام می دهد با اين تفاوت که نتيجه را جائی ذخيره نمی کند.

test dest, src

فلگ های Carry، Zero، Sign، Overflow و Parity مشابه دستورالعمل and تاثير می پذيرند.

دستورالعمل test برای بررسی يک بودن بيتی می تواند استفاده شود.


مثال. دستور زير مقدار 1 را با ثبات AL به طور منطقی and می کند. اگر بيت شماره 0 ثبات AL صفر باشد نتيجه دستور صفر شده و فلگ zero برابر با يک می شود در غير اينصورت فلگ zero صفر می شود. بررسی فلگ zero بعد از اين اجرای دستور نشان می دهد که بيت صفر ثبات AL يک بوده است يا خير.

test AL, 1

مثال. دستور زيرا برای بررسی بيت های 0، 2 و 8 ثبات DX می تواند استفاده شود. اگر همگی صفر باشند فلگ zero يک می شود.

test DX, 105h


دستکاری بيت ها

از دستورات منطقی برای دستکاری بيت های معينی از عملوند مقصد بدون تاثير روی بيت های ديگر آن می استفاده می شود. برای اين منظور يک ماسک ساخته می شود. يک ماسک مقدار است که بيت های مشخصی از يک عملوند را صفر يا يک می کند بدون اينکه نغييری روی بقيه بيت های آن داشته باشد.

صفر کردن بيت ها با دستورالعمل AND

با دقت در جدول and می توان مشاهده کرد که نتيجه and عدد صفر با هر بيتی برابر با صفر می شود. اگر عدد يک با بيتی and شود نتيجه همان بيت می شود. از اين خاصيت برای صفر کردن بيت های انتخابی يک مقدار بدون تاثير روی بقيه بيت ها می توان استفاده کرد.

مثال. درمثال زير بيت شماره 5 ثبات صفر می شود و بقيه بيت ها بدون تغيير باقی می مانند.

mov AX, C123h
and AX, FFDFh

يک کردن بيت ها با دستورالعمل OR

دستورالعمل or را می توانيد برای يک کردن بيت های انتخابی يک عدد بکار ببريد.

مثال. درمثال زير بيت شماره 3 ثبات يک می شود و بقيه بيت ها بدون تغيير باقی می مانند.

mov AX, C123h
or AX, 8

تعدادی از دستورات 8086 که برای انجام عمليات جمع و تفريق بر روی اعداد صحيح بکار می روند عبارتند از:

ADD
ADC
INC
SUB
SBB
DEC
NEG
CMP


ADD

اين دستورالعمل حاصل جمع صحيح دو عملوند خود را محاسبه و نتيجه را در عملوند اول قرار می دهد.

add dest, src

دستورالعمل add محتوای عملوند src را با عملوند dest جمع می کند و نتيجه را در dest ذخيره می کند (dest := dest + src).

دستورالعمل add به شکل های زير می تواند استفاده شود:

add register, register
add register, memory
add memory, register
add register, immediate data
add memory, immediate data
add AX/AL, immediate data


مثال. دستور زير محتوای ثبات های AX و BX را جمع کرده و حاصل را در ثبات AX ذخيره می کند.

add AX,BX


فلگ های زير با توجه به نتيجه دستورالعمل add تاثير می پذيرند:

• فلگ Overflow اگر يک شوددلالت بر سرريزی در محاسبات علامتدار است.
• فلگ Carry اگر يک شود دلالت بر سرريزی در محاسبات بدون علامت دارد.
• فلگ Sign اگر يک شود نشان می دهد که نتيجه منفی بوده است. يعنی با ارزش ترين بيت عدد يک است.
• فلگ Zero اگر يک شود بيان کننده اين است که نتيجه جمع صفر بوده است.
• فلگ Auxiliary Carry شامل سرريزی BCD از نيبل پايين است.
• فلگ Parity با توجه به 8 بيت پايين نتيجه تغييرمی کند. اگر تعداد بيت های يک نتيجه زوج باشد اين فلگ يک می شود. و اگر تعداد فردی بيت 1 در نتيجه باشد اين فلگ صفر می شود.
روی بقيه فلگ ها اثر ندارند.

نکاتی که درمورد دستور mov بايد رعايت شود در مورد دستور add نيز صادق است. علاوه بر اين که با اين دستور نمی توان يک ثبات سگمنت را با مقداری جمع کرد.

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

چون جمع حافظه و حافظه وجود ندارد اگر بخواهيد دو متغير را با هم جمع کنيد بايد عملوندهای حافظه را در ثبات ها منتقل کنيد.


مثال. يک حالت ممکن برای انجام عمل جمع متغيرها به صورت J := K + M + N + P; می تواند به شکل زير باشد:

mov BX, K
mov AX, M
add BX, N
add AX, P
add AX, BX
mov J, AX

مثال. می توان يک ثبات را با محلی از حافظه جمع کرد. اجباری نيست که هردو عملوند ثبات باشد.

mov AX, K
add J, AX

مثال. می توان يک مقدار ثابت را با حافظه جمع کرد.

add J, 2


ADC

دستورالعمل (add with carry) adc مشابه دستورالعمل add است با اين تفاوت که حاصل جمع دو عملوند و فلگ Carry را محاسبه می کند (dest :=dest+source+CF). بنابراين اگر Carry صفر باشد نتيجه مشابه add می شود.


INC

دستورالعمل (increment) inc يک واحد به عملوند خود اضافه می کند. شکل کلی آن به صورت زير است:

inc dest

اين دستورالعمل عدد 1 را با dest جمع و حاصل را در خود dest ذخيره می کند.

دستور inc به شکل های زير می تواند باشد:

inc register
inc memory

عملوند دستور می تواند ثبات يا مکانی از حافظه باشد. اندازه عملوند می تواند 8 يا 16 بيتی باشد.

دستور inc فشرده تر و اغلب سريع تر از دستور add است.

به استثنای فلگ Carry بقيه فلگ ها مشابه دستورالعمل add تغيير می کنند. توجه کنيد که اين دستور بر روی فلگ Carry تاثير ندارد و برای تاثير روی فلگ Carry بايد از دستورالعمل ADD استفاده شود.

افزايش شمارنده حلقه و انديس آرايه يکی از متداولترين کاربردهای دستور inc است.


SUB

دستورالعمل (subtract) sub حاصل تفريق عملوند دوم از عملوند اول را محاسبه می کند. شکل کلی آن به صورت زير است:

sub dest, src

دستورالعمل sub مقدار src را از dest کم کرده حاصل را در dest ذخيره می کند.

مشابه دستورالعمل add، دستور sub به صورت های زير می تواند باشد:

sub register, register
sub register, memory
sub memory, register
sub register, immediate data
sub memory, immediate data
sub AX/AL, immediate data

دستور sub به طريق زير فلگ ها را تغيير می دهد:

• اگر نتيجه صفر شود فلگ Zero يک می شود. اين در حالتی اتفاق می افتد که عملوندها با هم برابر باشند.
• اگر نتيجه منفی شود فلگ sign يک می شود.
• اگر سرريزی رخ دهد فلگ overflow يک می شود.
• فلگ Auxiliary Carry در صورت نياز برای عمليات BCD يک می شود.
• فلگ Parity با توجه به تعداد بيت های يک نتيجه تنظيم می شود.
• فلگ Carry در صورت بروز سرريزی در محاسبات بدون علامت يک می شود.

توجه داشته باشيد که تفريق خاصيت جابجائی ندارد.


مثال. دستورات زير عمل J := J - K; را انجام می دهند.

mov ax, K
sub J, ax

مثال. دستورات زير عمل J := K - J; را انجام می دهند.

mov ax, K
sub ax, J
mov J, ax


بعد از عمل تفريق از مقادير فلگ های Carry، Sign، Overflow و Zero می توان برای بررسی مساوی، نامساوی، بزرگتر يا کوچکتر بودن هر عملوند با ديگری استفاده کرد. جزئيات بيتشر در دستور cmp گفته خواهد شد.


SBB

دستورالعمل (subtract with borrow) sbb مشابه دستور sub است با اين تفاوت که حاصل تفريق عملوند دوم و CF از عملوند اول را محاسبه می نمايد(dest:=dest-src-CF)


DEC

دستورالعمل (decrement) dec يک واحد از عملوند خود کم می کند و حاصل را در خود عملوند دخيره می نمايد.

dec dest

عملوند دستور dec می تواند ثبات يا حافظه باشد.

به استثنای فلگ Carry بقيه فلگ ها مشابه دستورالعمل sub تغيير می کنند.


NEG

دستورالعمل (negate) neg مکمل2 عملوند خود را محاسبه می کند. فرم کلی ان به صورت زير است:

neg dest

دستور neg حاصل تفريق تنها عملوند خود را از عدد صفر را محاسبه کرده (عملوند را منفی می کند) و نتيجه را در آن ذخيره می کند. درنتيجه اجرای دستور علامت عملوند عکس می شود.

عملوند دستور neg می تواند ثبات يا محلی از حافظه باشد:

neg register
neg memory

اين دستور روی فلگ ها به صورت زير تاثيرمی گذارد:

• اگر نتيجه برابر با صفر شود فلگ Carry صفر و در غير اين صورت يک می شود. اگر عملوند صفر بوده باشد دستور اثری روی آن نمی گذارد ولی فلگ Carry را صفر می کند. منفی کردن هر مقدار ديگر فلگ Carry را يک می کند.
• اگر عملوند يک بايتی و حاوی مقدار -128 باشد و يا دوبايتی و حاوی عدد -32768 باشد، منفی کردن عملوند را تغييير نمی دهد اما فلگ Overflow را يک می کند.
• روی فلگ های S، P و Z مانند دستور sub اثر می گذارد.


مثال. دستور زير علامت متغير J عکس می شود.

neg J

مثال. دستورات اسمبلی زير مکمل K را محاسبه و در J ذخيره می کند(J=-k;).

mov AX, K
neg AX
mov J, AX


CMP

دستوالعمل (compare) cmp مانند دستور sub است با اين تفاوت که حاصل تفريق را ذخيره نمی کند(dest-src). نحوه کلی آن به صورت زير است:

cmp dest.src

به صورت های زير می تواند استفاده شود:

cmp register, register
cmp register, memory
cmp memory, register
cmp register, immediate data
cmp memory, immediate data
cmp AX/AL, immediate data

فلگ ها مانند دستورالعمل sub با توجه به نتيجه تفريق تغيير می کنند.

دستور زير را درنظر بگيريد:

cmp AX, BX

اين دستور حاصل AX-BX را محاسبه می کند و با توجه به حاصل فلگ ها را تنظيم می کند. فلگ ها به صورت زير تغيير می کنند و می توانند برای بررسی نتيجه مقايسه بکار برده شوند:

• فلگ Zero يک می شود اگر AX=BX باشد. مساوی يا نامساوی بودن دو عملوند را مشخص می کند.
• فلگ Carry وقتی يک می شود که در محاسبات بدون علامت AX<BX باشد. يعنی تفريق BX از AX احتياج به رقم قرضی داشته باشد.
• فلگ Sign به همراه فلگ Overflow در محاسبات علامتدار نشان می دهد کدام عملوند بزرگتر است.
• دستورالعمل cmp روی فلگ های Parity و Auxiliary Carry هم تاثير دارد ولی بندرت هنگام مقايسه مورد بررسی قرار می گيرند.

به طور خلاصه برای مقايسه دو عملوند با توجه به فلگ های زير می توان نتيجه گيری کرد:

عملوندهای بدون علامت
فلگ ها
AX = BX Z=1
AX ≠ BX Z=0
AX < BX C=1
AX >= BX C=0
عملوندهای علامتدار
فلگ ها
AX = BX Z=1
AX ≠ BX Z=0
AX < BX (S=0 and O=1)or(S=1 and O=0)
AX >= BX (S=0) and (O=0) or (S=1) and (O=1)

برای افزايش اندازه يک مقدار به کلمه يا کلمه مضاعف، با حفظ علامت، از دستورات گسترش استفاده می شود. دستورات گسترش بيت علامت ثبات انباشتگر(AL/AX) را بسط می دهند.

CBW
CWD


در بعضی از محاسبات خصوصا تقسيم و ضرب نياز به افزايش اندازه داده از يک بايت به يک کلمه يا از يک کلمه به يک کلمه مضاعف است. اعداد بدون علامت با اضافه کردن صفر در سمت چپ به سادگی گسترش می يابند. ولی برای افزايش طول يک عدد علامتدار بايد بيت علامت در سمت چپ عدد تکرار شود. دستورات تبديل بيت علامت بسط می دهند.


CBW

دستور (convert byte to word) cbw محتوای بيت شماره هفت ثبات AL را در AX بسط می دهد. يعنی بيت شماره هفت ثبات AL را در کليه بيت های ثبات AH کپی می کند. درنتيجه مقدار رياضی بايت AL به يک کلمهAX گسترش پيدا می کند.

دستور هيچ عملوندی ندارد:

cbw

دستور cbw روی هيچيک از فلگ ها تاثير ندارد.

دستور cbw در محاسبه تقسيم يک بايتی کاربرد دارد.


CWD

دستور (convert word to double word) cwd محتوای بيت شماره پانزده ثبات AX را در کليه بيت های ثبات DX کپی می کند. درنتيجه مقدار رياضی AX به يک کلمه مضاعف در DX:AX گسترش پيدا می کند.

دستور هيچ عملوندی ندارد:

cwd

دستور cbw روی هيچيک از فلگ ها تاثير ندارد.

دستور cbw در عمليات تقسيم دوبايتی نقش بازی می کند.


مثال. برای گسترش مقدار 8 بيتی AL به يک مقدار 32 بيتی در DX:AX دو دستور پشت سر هم نوشته می شوند.

mov AL,85h
cbw
cwd

چون بيت علامت عدد 85h يک است تبديل به عدد FFFFFF85h می شود که 16بيت پايين آن در ثبات AX و 16بيت بالای آن در ثبات DX قرار می گيرد. يعنی AX=FF85h و DX=FFFFh می شود.

تعداد صفحات : 425

اطلاعات کاربری
آمار سایت
  • کل مطالب : 4247
  • کل نظرات : 0
  • افراد آنلاین : 10
  • تعداد اعضا : 2927
  • آی پی امروز : 38
  • آی پی دیروز : 199
  • بازدید امروز : 124
  • باردید دیروز : 1,059
  • گوگل امروز : 0
  • گوگل دیروز : 19
  • بازدید هفته : 4,920
  • بازدید ماه : 32,818
  • بازدید سال : 248,197
  • بازدید کلی : 8,426,891
  • کدهای اختصاصی