Cara menemukan bug di mikroprosesor yang dirilis tiga puluh lima tahun yang lalu

K1801VM1A


Sulit dipercaya, tetapi terkadang kesalahan pada prosesor pada dasarnya hidup lebih lama dari prosesor itu sendiri. Baru-baru ini saya kebetulan diyakinkan tentang hal ini dengan contoh mikroprosesor 16-bit 1801BM1A , yang menjadi dasar pembuatan keluarga komputer rumah tangga BK-0010 / 11M di USSR pada satu waktu. Tentang keluarga ini di Habré berulang kali menulis.


Periode kehidupan aktif BeKashek jatuh pada akhir 80-an - awal 90-an abad terakhir. Pada tahun-tahun ini, melalui upaya banyak penggemar tunggal, serta kelompok anggota lingkaran dan kooperator, susunan utama program aplikasi BC dikembangkan: game, utilitas, berbagai "DOS" (sistem operasi disk). Sejalan dengan pengembangan perangkat lunak, perangkat dibuat di mana perangkat lunak sistem mereka ditulis. Secara umum, ekosistem dari komputer mirip-PDP 16-bit ini dikembangkan sesuai dengan prinsip-prinsip yang sama, seperti, misalnya, arsitektur terbuka 8-bit awal berbasis Intel 8080 dan bus S-100 dikembangkan. Kemudian, ketika kita menjauh dari peran utilitarian BC, fokus dalam pemrograman telah bergeser ke arah demoscene.


Volume perangkat lunak untuk BC dapat diperkirakan dengan mengunjungi situs umum dengan koleksi program . Tentu saja, sebagai perbandingan, misalnya, dengan ZX-Spectrum, volume ini jauh lebih sederhana. Namun demikian, bahkan volume seperti itu, tampaknya, sudah cukup untuk menyiasati semua celah dan celah kode mesin. Apakah mungkin untuk menemukan sesuatu yang tidak biasa dalam perilaku prosesor, setelah lebih dari tiga puluh tahun berlatih menggunakannya? Ternyata - ya! Ini akan dibahas di bawah.


Mungkin masuk akal untuk menceritakan kisah ini dalam urutan kronologis. Pertama-tama, saya harus segera mencatat bahwa saya sama sekali bukan "programmer dengan pengalaman", baik oleh pekerjaan, maupun dengan menjadi anggota kelompok penggemar SM, tentang siapa yang saya tulis di atas. Saya datang ke BC secara tidak langsung, sebagian melalui nostalgia untuk hobi masa kanak-kanak dan remaja (elektronik analog dan digital, majalah Young Technician , UT-88 dan kerajinan tangan dan ketidaksempurnaan lainnya), dan sebagian lagi karena minat saya pada arsitektur dan sistem komando PDP-11 . Saya tidak punya BK "di perangkat keras" dan saya biasanya menjalankan program untuk BK dan men-debug-nya di emulator bkemu di tablet untuk Android.


Beberapa waktu yang lalu, saya tertarik pada program Kaleidoskop, yang ditulis oleh Li-Chen Wang-a . Program ini ditulis dalam kode mesin pada tahun 1976, untuk mikroprosesor Intel 8080 sebagai bagian dari komputer Altair 8800 dengan adaptor grafis Cromemco Dazzler . Saya ingin menganalisis algoritma Li-Chen Wang-a secara rinci dan, pada saat yang sama, port ke BC. Saya harus mengatakan bahwa keinginan untuk mengirim Kaleidoscope ke BC telah diungkapkan di antara para demoscener sebelumnya, dan bahkan ada upaya untuk menguraikan algoritma, tetapi mereka tidak berhasil.


Dalam artikel saya berikutnya, saya mungkin akan menganalisis algoritma ini secara rinci (dan untuk yang tidak sabar, saya akan memposting tautan ke sumber lintas-platform Kaleidoscope di bawah libSDL di C). Untuk masa depan, itu akan cukup untuk menunjukkan bahwa masalah telah terpecahkan, dan Kaleidoscope berhasil diangkut ke BC. Selain itu, generasi suara ditambahkan ke algoritma pada CD, dan, karena gambar dan suara dihasilkan oleh kode yang sama, kita dapat mengatakan bahwa gambar itu sendiri berbunyi (seluruh demo cocok dengan kurang dari 256 byte kode mesin, dan, Saya berharap ini akan disajikan kepada publik di CAFe Demoparty 2019 di Kazan pada akhir Oktober).


Setelah selesai menulis dan men-debug program saya di emulator, saya menoleh ke Damir ("Adamych") Nasyrov (dia adalah salah satu penyelenggara CAFe Demoparty dan orang yang sangat terkenal di kalangan pembuat demos) dengan permintaan untuk memeriksa eksekusi program pada BC yang sebenarnya. Saya terutama tertarik pada reproduksi suara, karena timing di emulator dapat berbeda dari timing pada hardware nyata. Apa kekecewaan saya ketika Damir memberi tahu saya bahwa ada gambar pada BC nyata, tetapi tidak ada suara!


Beberapa malam berikutnya dihabiskan dengan mencoba mengurangi dari dokumentasi sistem pada BK-0011M dan diagram sirkuit , di mana mungkin ada kesalahan dengan suara. Suara di BC diatur cukup sederhana: bit ke-6 dalam register I / O dengan alamat oktal 177716 (register kontrol perekam kaset) adalah output melalui buffer ke speaker piezoelektrik (pager). Selain kategori 6, bit 2 dan 5 dari register yang sama terhubung ke konverter digital-ke-analog paling sederhana dengan 4 resistor. Dari output konverter ini, suara dapat masuk ke tape recorder. Semuanya sangat jelas dan logis, tetapi tidak ada suara keras kepala pada BK nyata, terlepas dari kombinasi bitmask yang saya coba terapkan pada output data ke register ini. Secara paralel, semua emulator BK yang saya tahu dipasang dan diuji - dan suaranya bekerja di semua orang!


Pada titik tertentu, saya bahkan hampir berhasil meyakinkan Damir bahwa BK-nya salah, tetapi perilaku itu diulang pada BK-0011M langsung lainnya, juga pada BK-0010. Saya kehabisan ide, dan penduduk saluran telegram pada tema BC, juga tidak bisa mengatakan apa-apa ... Namun, insiden itu membantu, seperti biasa. Dalam perjalanan salah satu percobaan, Damir meluncurkan demo pada emulator untuk memastikan bahwa ada suara di emulator. Dan di sini dia berhasil memperhatikan bahwa tidak hanya ada suara di emulator, tetapi tidak pada BC, tetapi juga gambar-gambar di emulator dan pada BC live berbeda! Di sini saya harus mengingatkan Anda bahwa dalam program saya gambar dan suara dihasilkan oleh satu kode. Oleh karena itu, selama ini saya mencari alasan di tempat yang salah: alasannya adalah dalam kode yang menghasilkan data untuk isi layar.


Damir mengirimi saya tangkapan layar, dan menjadi jelas bahwa algoritma menghasilkan byte dengan konten nol dari 4 bit tertinggi, dan, secara kebetulan, bit ini adalah output ke suara (mis., Selalu nol). Namun, alasan mengapa algoritma berperilaku seperti ini tetap tidak jelas. Ini adalah tempat dalam kode (assembler macro11 dari PDP-11, register r0-r5 diganti nama!):


; renamed registers a = %0 b = %1 c = %2 d = %3 e = %4 h = %5 ... ... asr b ; sets CF bic #177760, b bis b, c bis (h)+, c ; screen address in c movb (c), a ; get a byte from screen RAM bcc 1$ ; check CF bic #177760, a ; keep bits 0-3, clear rest bisb d, a ; fill bits 4-7 br 2$ 1$: bic #177417, a ; keep bits 4-7, clear rest bisb e, a ; fill bits 0-3 2$: ... ... 

Untuk beberapa alasan, pada SM nyata, lompatan bersyarat pada tanda $ 1 selalu dilakukan. Artinya, instruksi bcc selalu menganggap flag carry sebagai reset, meskipun instruksi shift ASR dapat mengatur flag ini menjadi 0 atau 1. Bagaimana ini bisa terjadi, karena menurut dokumentasi prosesor, bukan BIC, atau BIS, atau MOVB harus mempengaruhi bendera carry ?!


Selain itu, di semua emulator (yang ditulis sesuai dengan dokumentasi untuk prosesor!) Begitulah: instruksi ini tidak menyentuh bendera C. Menjadi jelas bahwa prosesor nyata 1801BM1A tidak bekerja dalam kasus ini sesuai dengan dokumentasi. Masih untuk mengkonfirmasi ini.


Sebagai permulaan, perbaikan cepat yang jelas:


  ... asr b ; sets CF mfps -(sp) ; store PSW on stack bic #177760, b bis b, c bis (h)+, c ; screen address in c movb (c), a ; get a byte from screen RAM mtps (sp)+ ; restore PSW from stack bcc 1$ ; check CF ... 

Menyimpan bendera pada tumpukan segera setelah instruksi shift dan mengembalikannya sebelum lompatan bersyarat segera menyelesaikan masalah, yang menunjukkan bahwa saya berada di jalur yang benar. Masih mempersempit "lingkaran tersangka." Untuk menguji hipotesis, tes sintetis semacam itu pertama kali ditulis (register tidak diganti namanya di sini; inisialisasi dihilangkan agar tidak mengacaukan kode; emt 64 adalah program interupsi untuk mencetak baris):


  ... mov #1, r1 jsr pc, test clr r1 jsr pc, test halt test: mov #40000, r2 ; r2 points to screen RAM mov #dummy, r5 ; r5 points to dummy = 200 ; *** begin *** asr r1 ; affects CF bic #177760, r1 bis r1, r2 bis (r5)+, r2 movb (r2), r0 ; *** end *** jsr pc, prt rts pc prt: mov #msg1, r0 bcs l1 mov #msg2, r0 l1: emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ dummy: .word 200 ... 

Dan tesnya ... tidak berhasil! Program dicetak di layar


Tandai CF set
Tandai CF jelas


Apa yang terjadi? Ternyata asumsi awal bahwa fragmen kode antara mulai dan akhir hanya merusak flag C salah dan perlu diklarifikasi. Apa perbedaan antara tes ini dan kode sumber? Dan fakta bahwa instruksi lain muncul antara blok perintah "mencurigakan" dan lompatan bersyarat. Tidak memengaruhi flag C, namun tetap mengubah status internal prosesor. Oleh karena itu, tes berikut seperti ini:


  ... mov #1, r1 jsr pc, test clr r1 jsr pc, test halt test: mov #40000, r2 mov #dummy, r5 ; *** begin *** asr r1 ; affects CF bic #177760, r1 bis r1, r2 bis (r5)+, r2 movb (r2), r0 bcc l1 ; *** end *** mov #msg1, r0 emt 64 rts pc l1: mov #msg2, r0 emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ dummy: .word 200 ... 

Dan sekarang tes ini telah dicetak pada BK-0011M nyata:


Tandai CF jelas
Tandai CF jelas


Pada emulator, seperti sebelumnya,


Tandai CF set
Tandai CF jelas


Selanjutnya adalah masalah teknologi. Dengan penyederhanaan bertahap, tes minimal seperti itu diperoleh di mana bug direproduksi (saya kutip seluruh sumber):


  .title test .psect code .=.+1000 mov #15, r0 emt 63 sec jsr pc, test clc jsr pc, test halt test: movb r0, r0 bcc l1 mov #msg1, r0 emt 64 rts pc l1: mov #msg2, r0 emt 64 rts pc msg1: .asciz /Flag CF set/ msg2: .asciz /Flag CF clear/ .end 

Pada BK-0011M nyata, tes ini ditampilkan


Tandai CF jelas
Tandai CF jelas


Artinya, instruksi MOVB yang langsung di depan instruksi cabang bersyarat adalah yang harus disalahkan, dan penampilan operan pertama tidak penting. Jika, misalnya, NOP dimasukkan antara MOVB dan BCC, perilaku tersebut akan kembali ke yang telah didokumentasikan, dan program akan mencetak


Tandai CF set
Tandai CF jelas


Itu memungkinkan untuk merumuskan hipotesis yang disempurnakan (saya kutip sendiri dari saluran telegram):


... Mengenai bug: perilaku tersebut sepertinya sudah beres. Seperti yang saya bayangkan, MOVB src, dst (omong-omong, tampaknya operan tidak penting), karena beberapa fitur arsitektur, sementara merusak bendera C di dalam prosesor, tetapi tidak fatal, karena persen sepertinya menyimpan salinan bendera ini. Akibatnya, jika antara MOVB dan cabang kondisional ada perintah lain (tidak mempengaruhi C), misalnya, NOP, maka perilaku tersebut seperti yang dijelaskan dalam dokumentasi.

Apa yang terjadi selanjutnya? Selanjutnya, rekan-rekan dari saluran membantu membawa Vyacheslav (@ K1801BM1, lelaki legendaris yang sebelumnya membalikkan prosesor ini pada level transistor) ke diskusi. Reaksi Vyacheslav (Yuot) ketika ia menguji perilaku di atas dudukan dengan 1801BM1A nyata (ejaan dan tanda baca dipertahankan):


Stanislav Maslovski:
setidaknya diperlukan dua perintah untuk reproduksi
movb dan lompatan bersyarat dalam C
Nah, sebelum itu, atur flag C ke status diketahui

Yuot:
Bendera dengan reset selalu diperoleh

Stanislav Maslovski:
iya
sekarang masukkan nop

Yuot:
Sekarang tidak pernah

Yuot:
Bergantian 0 1
Ini memalukan

Dengan bantuan Vyacheslav, perinciannya ditemukan, yaitu, bahwa alasan bug tersebut ada pada prosesor, selain PSW, ada register 4-bit lain, yang biasanya menyimpan salinan bendera dari PSW. Register ini terhubung dengan firmware otomatis dan transisi bersyarat mengambil nilai bendera darinya. Ketika menjalankan instruksi MVB, SWAB, MFPS dengan register penerima, karena kekhasan memproses ekstensi tanda dan karena kesalahan dalam mikrokode, salinan flag C dalam register ini dibuang dan transisi kondisional menggunakan flag ini tidak berfungsi dengan benar. Namun, dengan mengikuti instruksi di bawah ini, nilai register sementara dipulihkan dari PSW. Itu sebabnya, penyisipan NOP mengembalikan perilaku yang benar.


Sebagai penutup, saya juga ingin mengucapkan terima kasih kepada pelanggan saluran telegram Dunia BK0010 / 11M untuk berpartisipasi dalam diskusi bug ini, dan untuk komentar yang dibuat pada teks artikel. Foto judul untuk artikel ini adalah milik Manwe_SandS . Lebih menarik lagi, Manwe hampir menemukan bug yang sama, hampir pada saat yang sama ketika saya dan Damir berjuang untuk menyelesaikan masalah suara!


Sekarang terserah kecil (hanya bercanda) - bawa semua emulator sejalan dengan perilaku prosesor yang sebenarnya. Lagi pula, prosesor itu sendiri, sayangnya, tidak bisa lagi diperbaiki.


Tentang ini saya akan berakhir. Saya harap itu menarik.

Source: https://habr.com/ru/post/id471020/


All Articles