سؤال

كنت أقرأ دليل تعليمات إنتل ولاحظت وجود تعليمات "NOP" لا تفعل شيئًا على وحدة المعالجة المركزية الرئيسية، وتعليمات "FNOP" لا تفعل شيئًا على وحدة FPU.لماذا هناك تعليمات منفصلة لعدم القيام بأي شيء؟

الشيء الوحيد المختلف الذي رأيته هو أنهم يطرحون استثناءات مختلفة، لذا يمكنك مراقبة استثناء من FNOP لاكتشاف ما إذا كانت هناك وحدة FPU متاحة.ولكن ألا توجد آليات أخرى مثل CPUID لاكتشاف ذلك؟ما السبب العملي لوجود تعليمات NOP منفصلة؟

هل كانت مفيدة؟

المحلول

بالتوسع في تعليقات ريموند تشن وهانز باسانت، هناك أسباب تاريخية لوجود تعليماتين منفصلتين ولماذا لا يكون لهما نفس التأثير تمامًا.

ولا من الأمرين NOP و FNOP, ، تم تصميمها في الأصل كتعليمات صريحة بعدم التشغيل.ال NOP التعليمات هي في الواقع مجرد اسم مستعار للتعليمات XCHG AX,AX.(أو في وضع 32 بت XCHG EAX, EAX.) في معالجات Intel المبكرة، لم تفعل شيئًا في الواقع.على الرغم من أنه لم يكن له أي تأثير مرئي من الخارج، إلا أنه تم تنفيذه داخليًا تمامًا مثل XCHG التعليمات، مع أخذ أكبر عدد ممكن من الدورات للتنفيذ.كان '486 هو أول وحدة معالجة مركزية من Intel تعالجها بشكل خاص، ويمكنها تنفيذ عملية NOP في دورة واحدة، بينما يستغرق الأمر 3 دورات لتنفيذ أي عملية تسجيل أخرى XCHG تعليمات.

علاج XCHG AX,AX تصبح التعليمات بشكل خاص مهمة جدًا في معالجات Intel الحديثة.إذا كان لا يزال يتبادل بالفعل نفس السجل مع نفسه، فيمكنه تقديم أكشاك خطوط الأنابيب إذا استخدمت تعليمات قريبة أيضًا AX يسجل.من خلال التعامل معها بشكل خاص، لا ينتهي الأمر بوحدة المعالجة المركزية إلى التفكير في NOP يحتاج إلى الانتظار للتعليمات السابقة التي تحدد AX أو أن التعليمات التالية تحتاج إلى انتظار NOP.

وهذا يوضح حقيقة أن هناك الكثير من التعليمات المختلفة التي لا تفعل شيئًا XCHG AX,AX هو الوحيد الذي يتكون من بايت واحد (كحالة خاصة لـ تبادل التسجيل مع المجمع بايت واحد XCHG الترميزات).في كثير من الأحيان يتم استخدام هذه التعليمات كبديل للتعليمات المتتالية NOP تعليمات، مثل عند محاذاة بداية الحلقة لأسباب تتعلق بالأداء.على سبيل المثال، إذا كنت تريد NOP بحجم 6 بايت، فيمكنك استخدامه LEA EAX,[EAX + 00000000].أضافت Intel في النهاية تعليمات NOP صريحة متعددة البايت.(حسنًا، لم تتم إضافة الكثير من التعليمات الموثقة رسميًا والتي كانت موجودة منذ Pentium Pro.) ومع ذلك، يتم التعامل بشكل خاص مع نموذج البايت الواحد فقط؛ستقوم NOPs متعددة البايتات بإنشاء أكشاك إذا كانت التعليمات القريبة تستخدم نفس السجلات.

عندما أضافت AMD دعم 64 بت إلى وحدات المعالجة المركزية الخاصة بها، ذهبت إلى أبعد من ذلك. NOP لم يعد يعادل XCHG EAX,EAX في وضع 64 بت.إحدى مشكلات مجموعة تعليمات Intel هي أن هناك الكثير من التعليمات التي تقوم بتعديل جزء فقط من السجل.على سبيل المثال MOV BX,AX يعدل فقط الأجزاء الـ 16 بت السفلية من EBX ترك الجزء العلوي ذو الـ 16 بت دون تعديل.هذه التعديلات الجزئية تجعل من الصعب على وحدة المعالجة المركزية تجنب التوقفات، لذلك قررت AMD منع ذلك عند استخدام تعليمات 32 بت في وضع 64 بت.عندما يتم تخزين نتيجة عملية 32 بت في سجل (64 بت)، القيمة صفر ممتدة إلى 64 بت بحيث يتم تعديل السجل بأكمله.هذا يعنى XCHG EAX,EAX لم يعد NOP، لأنه يمسح الجزء العلوي من 32 بت EAX (وبالتالي إذا كتبت صراحة XCHG EAX,EAX, ، لا يمكن تجميعه على 0x90 ويجب عليه استخدام 87 C0 التشفير).في وضع 64 بت NOP أصبح الآن NOP صريحًا بدون تفسير آخر.


أما بالنسبة لل FNOP التعليمات، في الإصدار 8087 الأصلي، ليس من الواضح تمامًا كيف تعاملت FPU مع هذه التعليمات، لكنني متأكد تمامًا من أنه لم يتم التعامل معها باعتبارها عملية عدم عملية صريحة أيضًا.دليل Intel قديم واحد على الأقل، الدليل المرجعي للغة ASM86 يقوم بالتوثيق على أنه يفعل شيئًا بدون تأثير ("يخزن الجزء العلوي من المكدس في أعلى المكدس").من موقعه في خريطة كود التشغيل، يبدو أنه قد يكون اسمًا مستعارًا لأي منهما FST ST أو FLD ST, ، وكلاهما من شأنه نسخ الجزء العلوي من المكدس إلى الجزء العلوي من المكدس.ومع ذلك، فقد حصلت على بعض المعاملة الخاصة، حيث تم تنفيذها في متوسط ​​13 دورة بدلاً من 18 أو 20 دورة في المتوسط ​​لتكديس المكدس FST أو FLD التعليمات على التوالي.إذا تم التعامل معها على أنها تعليمات عدم التشغيل، كنت أتوقع أن تكون أسرع، حيث يوجد عدد من التعليمات 8087 التي يمكن تنفيذها في نصف الوقت.

والأهم من ذلك FNOP التعليمات تتصرف بشكل مختلف عن NOP بسبب كيفية تنفيذ تعليمات FPU على معالجات Intel.لم تكن وحدة المعالجة المركزية نفسها تدعم حساب الفاصلة العائمة، وبدلاً من ذلك تم إلغاء تحميل هذه الواجبات على معالج مساعد اختياري للفاصلة العائمة، وهو في الأصل 8087.أحد الأشياء اللطيفة في المعالج الثانوي هو أنه ينفذ التعليمات بالتوازي مع وحدة المعالجة المركزية.ولكن هذا يعني أن وحدة المعالجة المركزية تحتاج أحيانًا إلى الانتظار حتى تنتهي وحدة FPU من العملية.تنتظر وحدة المعالجة المركزية تلقائيًا حتى تنتهي من تنفيذ التعليمات السابقة قبل إعطائها تعليمات أخرى، ولكن سيحتاج البرنامج إلى الانتظار بشكل صريح (باستخدام WAIT التعليمات) قبل أن يتمكن من قراءة النتيجة التي كتبها المعالج المساعد إلى الذاكرة.

نظرًا لأن المعالج المساعد يعمل بالتوازي، فهذا يعني أيضًا أنه إذا قامت تعليمات FPU بإنشاء استثناء للفاصلة العائمة، بحلول الوقت الذي اكتشفت فيه هذا، فإن وحدة المعالجة المركزية ستكون قد انتقلت بالفعل لتنفيذ التعليمات التالية.عادةً عندما تولد إحدى التعليمات استثناءً على وحدة المعالجة المركزية، تتم معالجتها أثناء تنفيذ هذه التعليمات، ولكن عندما تولد تعليمات FPU استثناءً، تكون وحدة المعالجة المركزية قد أكملت بالفعل تنفيذ تلك التعليمات عن طريق تسليمها إلى FPU.بدلاً من مقاطعة وحدة المعالجة المركزية وتقديم استثناء الفاصلة العائمة بشكل غير متزامن، يتم إعلام وحدة المعالجة المركزية فقط عندما تنتظر المعالج الثانوي، سواء بشكل صريح أو ضمني.

في المعالجات الحديثة، لم تعد FPU معالجًا مساعدًا، بل أصبحت جزءًا لا يتجزأ من وحدة المعالجة المركزية.وهذا يعني أن البرامج لم تعد بحاجة إلى الانتظار حتى تقوم وحدة FPU بكتابة القيم في الذاكرة.ومع ذلك، لم تتغير كيفية التعامل مع استثناءات FPU.(اتضح أنه من الصعب تنفيذ تقديم الاستثناءات على الفور على وحدات المعالجة المركزية الحديثة، لذا فقد استفادوا من الحالة الوحيدة التي لم يكن عليهم فعل ذلك فيها.) لذا، إذا أدت تعليمات FPU السابقة إلى إنشاء استثناء فاصلة عائمة لم يتم تسليمه، NOP اترك الاستثناء دون تسليمه، بينما FNOP, نظرًا لأنها تعليمات FPU، فسوف تقوم بإجراء "انتظار" ضمني يؤدي إلى تسليم استثناء الفاصلة العائمة.

وهذا المثال يوضح الفرق:

FLD1       ; push 1.0 onto the FPU stack
FLDZ       ; push 0.0
FDIV       ; divide 1.0 by 0.0
NOP        ; does nothing
NOP        ; does nothing
FNOP       ; signals a FP zero-divide exception and then does nothing
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top