Dalam instruksi mikroprosesor 8085, ada operasi kontrol mesin "nop" (tidak ada operasi). Pertanyaan saya adalah mengapa kita perlu operasi no? Maksud saya jika kita harus mengakhiri program, kita akan menggunakan HLT atau RST 3. Atau jika kita ingin pindah ke instruksi selanjutnya kita akan memberikan instruksi selanjutnya. Tetapi mengapa tidak ada operasi? Apa yang dibutuhkan?
microprocessor
Demietra95
sumber
sumber
Jawaban:
Salah satu penggunaan instruksi NOP (atau NOOP, no-operasi) dalam CPU dan MCU adalah untuk memasukkan sedikit, dapat diprediksi, keterlambatan dalam kode Anda. Meskipun NOP tidak melakukan operasi apa pun, perlu beberapa waktu untuk memprosesnya (CPU harus mengambil dan mendekodekan opcode, sehingga perlu sedikit waktu untuk melakukan itu). Sekurang-kurangnya 1 siklus CPU "terbuang" untuk menjalankan instruksi NOP (biasanya angka yang dapat disimpulkan dari lembar data CPU / MCU), oleh karena itu menempatkan N NOP secara berurutan adalah cara mudah untuk memasukkan penundaan yang dapat diprediksi:
di mana K adalah jumlah siklus (paling sering 1) diperlukan untuk pemrosesan instruksi NOP, dan adalah periode jam.Tc l o c k
Kenapa kamu ingin melakukan itu? Mungkin berguna untuk memaksa CPU untuk menunggu sedikit untuk perangkat eksternal (mungkin lebih lambat) untuk menyelesaikan pekerjaan mereka dan melaporkan data ke CPU, yaitu NOP berguna untuk keperluan sinkronisasi.
Lihat juga halaman Wikipedia terkait di NOP .
Penggunaan lain adalah untuk menyelaraskan kode pada alamat tertentu dalam memori dan "trik perakitan" lainnya, seperti yang dijelaskan juga dalam utas ini pada Programmers.SE dan pada utas lainnya pada StackOverflow .
Artikel menarik lainnya tentang masalah ini .
Tautan ini ke halaman buku Google terutama mengacu pada CPU 8085. Kutipan:
EDIT (untuk mengatasi masalah yang diungkapkan dalam komentar)
sumber
Jawaban lain hanya mempertimbangkan NOP yang sebenarnya dieksekusi di beberapa titik - yang digunakan cukup umum, tetapi itu bukan satu-satunya penggunaan NOP.
The non-melaksanakan NOP juga cukup berguna ketika menulis kode yang dapat ditambal - pada dasarnya, Anda akan pad fungsi dengan beberapa NOP setelah itu
RET
(atau instruksi serupa). Ketika Anda harus menambal executable, Anda dapat dengan mudah menambahkan lebih banyak kode ke fungsi mulai dari yang asliRET
dan menggunakan sebanyak mungkin NOP yang Anda butuhkan (misalnya untuk lompat jauh atau bahkan kode inline) dan menyelesaikan dengan yang lainRET
.Dalam kasus penggunaan ini, noone pernah mengharapkan
NOP
untuk mengeksekusi. Satu-satunya titik adalah untuk memungkinkan menambal executable - dalam dieksekusi non-empuk teoretis, Anda harus benar-benar mengubah kode fungsi itu sendiri (kadang-kadang mungkin sesuai dengan batas asli, tetapi cukup sering Anda akan memerlukan lompatan pula ) - itu jauh lebih rumit, terutama mempertimbangkan perakitan yang ditulis secara manual atau kompilator yang mengoptimalkan; Anda harus menghormati lompatan dan konstruksi serupa yang mungkin menunjuk pada beberapa kode penting. Secara keseluruhan, cukup rumit.Tentu saja, ini jauh lebih banyak digunakan di masa lalu, ketika berguna untuk membuat tambalan seperti ini kecil dan online . Hari ini, Anda hanya akan mendistribusikan biner yang dikompilasi dan selesai dengan itu. Masih ada beberapa yang menggunakan patching NOP (mengeksekusi atau tidak, dan tidak selalu huruf
NOP
s - misalnya, Windows menggunakanMOV EDI, EDI
untuk patching online - itu adalah jenis di mana Anda dapat memperbarui perpustakaan sistem saat sistem benar-benar berjalan, tanpa perlu restart).Jadi pertanyaan terakhir adalah, mengapa memiliki instruksi khusus untuk sesuatu yang tidak benar-benar melakukan apa-apa?
MOV AX, AX
akan melakukan hal yang persis sama, tetapi jangan memberi sinyal maksud dengan jelas.NOP
cukup banyak; kode rakitan terkompilasi yang sebenarnya tidak lagi memilikinya. Perlu dicatat bahwa itu bukan x86NOP
.NOP
s, membuat pembongkaran jauh lebih mudah untuk dibaca) dan untuk hot-patching (meskipun saya sejauh ini lebih suka Edit dan Lanjutkan di Visual Studio: P).Untuk menjalankan NOP, tentu saja ada beberapa poin lagi:
MOV EDI, EDI
, ada NOP lain yang efektif selain literalNOP
.MOV EDI, EDI
memiliki kinerja terbaik sebagai NOP 2-byte pada x86. Jika Anda menggunakan duaNOP
s, itu akan menjadi dua instruksi untuk dieksekusi.EDIT:
Sebenarnya, diskusi dengan @DmitryGrigoryev memaksa saya untuk memikirkan hal ini sedikit lebih banyak, dan saya pikir ini merupakan tambahan yang berharga untuk pertanyaan / jawaban ini, jadi izinkan saya menambahkan beberapa bit tambahan:
Pertama, poin, jelas - mengapa ada instruksi yang melakukan sesuatu seperti
mov ax, ax
? Sebagai contoh, mari kita lihat kasus 8086 kode mesin (lebih tua dari 386 kode mesin):0x90
. Ini masih saat ketika banyak orang menulis dalam pertemuan, ingatlah. Jadi, bahkan jika tidak adaNOP
instruksi khusus ,NOP
kata kunci (alias / mnemonic) akan tetap berguna dan akan memetakannya.MOV
benar - benar memetakan ke banyak opcode yang berbeda, karena menghemat waktu dan ruang - misalnya,mov al, 42
adalah "pindahkan byte langsung keal
register", yang diterjemahkan menjadi0xB02A
(0xB0
menjadi opcode,0x2A
menjadi argumen "langsung"). Jadi itu membutuhkan dua byte.mov al, al
(karena pada dasarnya itu hal yang bodoh untuk dilakukan), jadi Anda harus menggunakanmov al, rmb
overload (rmb "register or memory"). Itu sebenarnya membutuhkan tiga byte. (walaupun mungkin akan menggunakan yang kurang spesifikmov rb, rmb
, yang seharusnya hanya membutuhkan dua bytemov al, al
- byte argumen digunakan untuk menentukan sumber dan register target; sekarang Anda tahu mengapa 8086 hanya memiliki 8 register: D). Bandingkan denganNOP
, yang merupakan instruksi byte tunggal! Ini menghemat memori dan waktu, karena membaca memori pada 8086 masih cukup mahal - belum lagi memuat program itu dari kaset atau disket atau sesuatu, tentu saja.Jadi dari mana datangnya
xchg ax, ax
? Anda hanya perlu melihat opcodes darixhcg
instruksi lainnya . Anda akan melihat0x86
,0x87
dan akhirnya,0x91
-0x97
. Jadinop
dengan itu0x90
sepertinya cocok untukxchg ax, ax
(yang, sekali lagi, bukanxchg
"kelebihan" - Anda harus menggunakanxchg rb, rmb
, pada dua byte). Dan pada kenyataannya, saya cukup yakin ini adalah efek samping yang bagus dari arsitektur mikro saat itu - jika saya ingat dengan benar, mudah untuk memetakan seluruh jajaran0x90-0x97
"xchg, bertindak atas registerax
danax
-di
" ( operan menjadi simetris, ini memberi Anda jangkauan penuh, termasuk nopxchg ax, ax
; perhatikan bahwa pesanannya adalahax, cx, dx, bx, sp, bp, si, di
-bx
setelahdx
,ax
; ingat, nama register adalah mnemonik, bukan nama yang dipesan - akumulator, penghitung, data, basis, penunjuk tumpukan, penunjuk dasar, indeks sumber, indeks tujuan). Pendekatan yang sama juga digunakan untuk operan lain, misalnyamov someRegister, immediate
set. Di satu sisi, Anda bisa menganggap ini seolah-olah opcode sebenarnya bukan byte penuh - beberapa bit terakhir adalah "argumen" untuk operan "nyata".Semua ini dikatakan, pada x86,
nop
dapat dianggap sebagai instruksi nyata, atau tidak. Mikro-arsitektur asli memang memperlakukannya sebagai varianxchg
jika saya ingat dengan benar, tetapi sebenarnya disebutkannop
dalam spesifikasi. Dan karenaxchg ax, ax
tidak benar-benar masuk akal sebagai instruksi, Anda dapat melihat bagaimana para perancang 8086 menghemat transistor dan jalur dalam decoding instruksi dengan mengeksploitasi fakta yang0x90
memetakan secara alami ke sesuatu yang sepenuhnya "noppy".Di sisi lain, i8051 memiliki opcode yang sepenuhnya dirancang untuk
nop
-0x00
. Agak praktis. Desain instruksi pada dasarnya menggunakan nibble tinggi untuk operasi dan nibble rendah untuk memilih operan - misalnya,add a
adalah0x2Y
, dan0xX8
berarti "register 0 direct", demikian0x28
jugaadd a, r0
. Menghemat banyak pada silikon :)Saya masih bisa melanjutkan, karena desain CPU (belum lagi desain kompiler dan desain bahasa) adalah topik yang cukup luas, tapi saya pikir saya telah menunjukkan banyak sudut pandang berbeda yang masuk ke dalam desain dengan cukup baik.
sumber
NOP
biasanya merupakan alias untukMOV ax, ax
,ADD ax, 0
atau instruksi serupa. Mengapa Anda merancang instruksi khusus yang tidak melakukan apa-apa ketika ada banyak di luar sana.MOV ax, ax
;NOP
akan selalu memiliki jumlah siklus yang tetap untuk eksekusi. Tapi saya tidak melihat bagaimana itu relevan dengan apa yang saya tulis dalam jawaban saya.MOV ax, ax
jauh, karena pada saat mereka tahu itu sudahMOV
instruksi dalam pipa.NOP
danMOV ax, ax
). CPU modern jauh lebih kompleks daripada kompiler oldschool C :))LD r, r
instruksi di manar
ada satu register, mirip denganMOV ax, ax
instruksi Anda . Alasannya 7 dan bukan 8 adalah karena salah satu instruksi kelebihan beban menjadiHALT
. Jadi 8080 dan Z80 memiliki setidaknya 7 instruksi lain yang melakukan hal yang samaNOP
! Cukup menarik, meskipun instruksi ini tidak secara logis terkait dengan pola bit, mereka semua mengambil 4 T Negara untuk dieksekusi sehingga tidak ada alasan untuk menggunakanLD
instruksi!Kembali di akhir 70-an, kami (saya adalah seorang mahasiswa peneliti muda saat itu) memiliki sistem dev kecil (8080 jika memori berfungsi) yang berjalan di 1024 byte kode (yaitu UVEPROM tunggal) - hanya memiliki empat perintah untuk memuat (L ), simpan (S), cetak (P), dan hal lain yang saya tidak ingat. Itu didorong dengan teletype dan punch tape nyata. Itu dikodekan dengan ketat!
Salah satu contoh penggunaan NOOP adalah dalam layanan rutin interrupt (ISR), yang ditempatkan dalam interval 8 byte. Rutin ini berakhir dengan 9 byte yang berakhir dengan lompatan (panjang) ke alamat yang sedikit lebih jauh ke ruang alamat. Ini berarti, mengingat urutan byte endian kecil, bahwa byte alamat tinggi adalah 00j, dan ditempatkan ke byte pertama dari ISR berikutnya, yang berarti bahwa itu (ISR berikutnya) dimulai dengan NOOP, supaya 'kita' dapat masuk kode di ruang terbatas!
Jadi NOOP berguna. Plus, saya curiga paling mudah bagi intel untuk mengkodekannya seperti itu - Mereka mungkin memiliki daftar instruksi yang ingin mereka terapkan dan dimulai pada '1', seperti semua daftar yang dilakukan (ini adalah hari-hari FORTRAN), jadi nol Kode NOOP menjadi rontok. (Saya belum pernah melihat artikel yang menyatakan bahwa NOOP adalah bagian penting dari teori Ilmu Komputasi (sama seperti Q: apakah matematikawan memiliki nul op, berbeda dari nol teori grup?)
sumber
0x00
untuknop
jawaban saya. Singkatnya, menghemat instruksi decoding -xchg ax, ax
mengalir secara alami dari cara instruksi decoding bekerja, dan ia melakukan sesuatu yang "noppy", jadi mengapa tidak menggunakannya dan menyebutnyanop
, kan? :) Digunakan untuk menghemat sedikit pada silikon untuk instruksi decoding ...Pada beberapa arsitektur,
NOP
digunakan untuk menempati slot tunda yang tidak digunakan . Misalnya, jika instruksi cabang tidak menghapus pipa, beberapa instruksi setelah itu dieksekusi:Tetapi bagaimana jika Anda tidak memiliki instruksi yang berguna untuk dicocokkan setelah
JMP
? Dalam hal ini Anda harus menggunakanNOP
s.Slot keterlambatan tidak terbatas pada lompatan. Pada beberapa arsitektur, bahaya data dalam pipa CPU tidak diselesaikan secara otomatis. Ini berarti bahwa setelah setiap instruksi yang memodifikasi register ada slot di mana nilai baru register belum dapat diakses. Jika instruksi berikutnya membutuhkan nilai itu, slot harus ditempati oleh
NOP
:Juga, beberapa instruksi pelaksanaan bersyarat ( Jika-Benar-Salah dan serupa) menggunakan slot untuk setiap kondisi, dan ketika kondisi tertentu tidak memiliki tindakan yang terkait dengannya, slotnya harus ditempati oleh
NOP
:sumber
Contoh lain penggunaan untuk NOP dua byte : http://blogs.msdn.com/b/oldnewthing/archive/2011/09/21/10214405.aspx
sumber