Mempercepat program untuk prosesor Redd yang disintesis tanpa optimisasi: mengganti jam

Sampai sekarang, kami telah membahas topik tentang cara meningkatkan kecepatan sistem menggunakan beberapa metode intensif. Namun pada kenyataannya, ada metode yang luas. Sekarang kami bekerja pada frekuensi clock 50 MHz, yang dikaitkan dengan penggunaan komponen dari set untuk program universitas (dan tanpa itu tidak mungkin untuk clock SDRAM, yang mengharuskan pulsa clock pergi ke sirkuit mikro digeser relatif terhadap yang utama). Ketika saya memperkenalkan komponen ini ke permainan, saya memperingatkan bahwa solusi ini bersifat sementara. Lalu saya membuang begitu banyak informasi baru pada pembaca sehingga kebosanan ekstra dapat menyebabkan seru: "Nah, FPGA ini, semuanya sangat rumit di sini!" Sekarang kita sudah dengan mudah dan alami membangun sistem prosesor, semua hal buruk ada di belakang kita. Saatnya untuk mencari tahu bagaimana Anda dapat membuat komponen Anda sendiri, yang memungkinkan Anda untuk meningkatkan frekuensi clock dari prosesor dan periferal yang terhubung dengannya.



Artikel sebelumnya dalam seri:


  1. Pengembangan "firmware" paling sederhana untuk FPGA yang dipasang di Redd, dan debugging menggunakan tes memori sebagai contoh.
  2. Pengembangan "firmware" paling sederhana untuk FPGA yang dipasang di Redd. Bagian 2. Kode program.
  3. Pengembangan intinya sendiri untuk ditanamkan dalam sistem prosesor berbasis FPGA.
  4. Pengembangan program untuk prosesor pusat Redd pada contoh akses ke FPGA.
  5. Eksperimen pertama menggunakan protokol streaming pada contoh koneksi CPU dan prosesor di FPGA kompleks Redd.
  6. Merry Quartusel, atau bagaimana prosesor telah hidup seperti itu.
  7. Metode Optimasi Kode untuk Redd. Bagian 1: efek cache.
  8. Metode Optimasi Kode untuk Redd. Bagian 2: memori non-cache dan operasi bus paralel.

Sedikit alasan teoretis


Mari kita perkirakan frekuensi apa yang bisa kita atur tanpa henti untuk pencatatan semua besi kita. Chip SDRAM yang digunakan dalam kompleks memungkinkan frekuensi frekuensi 133 MHz. Untuk kecepatan jam prosesor, lihat Tolok Ukur Kinerja Nios II . Di sana, untuk FPGA Cyclone IV E kami, frekuensi inti Nios II / f 160 MHz dijamin. Saya bukan pendukung memeras semua jus dari sistem, jadi kita akan berbicara tentang bekerja pada frekuensi 100 MHz.

Sejujurnya, saya masih belum terinspirasi oleh metodologi untuk menghitung pergeseran frekuensi jam yang diberikan dalam bagian 32.7. Jam, PLL, dan Pertimbangan Waktu untuk Panduan Pengguna Perangkat IP Tertanam , tetapi sepertinya saya bukan satu-satunya. Setidaknya, pencarian panjang di internet tidak menuntun saya ke artikel yang akan berisi hasil yang dihitung dengan cara yang sama, tetapi tidak untuk frekuensi yang diberikan dalam dokumen utama (50 MHz yang sama).

Ada artikel menarik yang akan saya berikan tautan langsung www.emb4fun.de/fpga/nutos1/index.html . Seseorang dapat merujuknya dan mengatakan "Mari kita lakukan sebagai penulis", jika bukan untuk satu "tetapi": penulis artikel ini menggunakan blok PLL (dalam bahasa Rusia - PLL, dan di tingkat rumah tangga - konverter frekuensi), memasukkan kode sendiri dalam VHDL. Saya, sebagaimana telah dicatat dalam artikel tentang kesenangan Quartusel , mematuhi ideologi bahwa sistem prosesor harus berada di tingkat atas hirarki proyek. Tidak diperlukan penyisipan dalam bahasa apa pun, baik itu VHDL atau Verilog. Baru-baru ini, pendekatan saya ini telah menerima satu konfirmasi lagi: kami memiliki karyawan baru, seorang siswa yang belum berbicara Verilog, tetapi membuat kode untuk kompleks Redd dengan sempurna, karena pendekatan yang dipilih memungkinkan ini.

Ternyata kami hanya mengambil sebagai dasar bahwa semuanya bekerja untuk penulis pada pergeseran minus 54 derajat (derajat apa yang dijelaskan dalam artikel, tautan yang saya berikan paragraf di atas).

Selanjutnya, perhatikan artikel menarik lainnya asral.unimap.edu.my/wp-content/uploads/2019/07/2019_IJEECS_Chan_Implementation-Camera-System.pdf . Semuanya bekerja untuk penulis dengan perubahan minus 65 derajat.

Mari kita coba membuat sistem kita menggunakan nilai dari rentang ini. Jika selama tes harian RAM tidak ada kerusakan tunggal, maka kita akan membiarkan nilai ini sebagai pertempuran. Kami memiliki hak, karena โ€œfirmwareโ€ yang dikembangkan untuk Redd tidak akan diberikan kepada Pelanggan, tetapi akan digunakan untuk kebutuhan internal, dan dalam jumlah satuan. Jika ada, akan selalu memungkinkan untuk memperbaiki semuanya tanpa kesulitan yang tidak perlu (kesulitan muncul ketika perlu memperbarui "firmware" di ribuan perangkat yang dijual, dan hanya di Pelanggan jarak jauh).

Konfigurasi perangkat keras baru


Untuk beberapa alasan, menurut saya sistem prosesor untuk artikel ini lebih mudah dilakukan dari awal daripada membuat ulang dari yang lama. Hanya bagaimana mendemonstrasikan proses "memutar, memelintir, ingin membingungkan", terus mengacu pada artikel sebelumnya, saya lebih suka menunjukkan semuanya lagi dari awal. Pada saat yang sama, kami memperbaiki materi. Jadi, mari kita mulai.

Pada awalnya, kami ditunjukkan sistem yang benar-benar kosong yang hanya berisi jam dan mengatur ulang sumber sinyal.



Biasanya saya tidak mengubah apa pun di sana, tetapi hari ini saya akan membuat pengecualian. Saya tidak ingin terganggu oleh rangkaian reset, karena kami masih akan bekerja dari bawah debugger. Oleh karena itu, saya akan beralih kondisi reset dari level ke perbedaan negatif, dan kaki itu sendiri kemudian akan dibatalkan.



Tetapi di sini sinyal clock memiliki frekuensi 50 MHz (frekuensi ini diatur oleh karakteristik generator yang disolder ke papan). Pada artikel pertama yang saya sebutkan di atas, blok PLL ditambahkan ke proyek utama digunakan. Di mana kita mendapatkannya di sini? Dan ini dia!



Ini adalah blok yang sama, tetapi di sini kita tidak perlu menyematkan kode apa pun di Verilog atau VHDL. Semuanya sudah dimasukkan untuk kita! Benar, pengaturan untuk berbagai jenis FPGA berbeda sedikit lebih dari sepenuhnya. Lebih tepatnya, parameter yang dapat disetel kurang lebih sama, tetapi mereka berada di tempat yang berbeda secara mendasar dalam dialog konfigurasi. Karena Cyclone IV E FPGA digunakan di kompleks Redd, kami akan mempertimbangkan konfigurasi opsi ini.

Pada tab pertama, ganti frekuensi input dengan 50 MHz (secara default adalah 100) dan pergi ke tab berikutnya (klik Next, untuk Cyclone IV E kita harus melakukan ini berkali-kali).



Hapus centang input dan output tambahan. Kami tidak membutuhkannya:



Kami melewatkan beberapa tab berikutnya hingga kami dapat mengatur output C0. Di sana kami beralih tombol radio untuk mengatur frekuensi dan memasukkan nilai 100 MHz:



Dengan C1, segalanya menjadi sedikit lebih rumit. Pertama, pilih kotak centang yang mengatakan bahwa itu juga harus digunakan. Kedua, kami juga mengatur frekuensi 100 MHz. Nah, dan ketiga, kami mengatur pergeseran frekuensi. Yang mana untuk bertanya? Kurang 58 atau minus 65? Tentu saja, saya mencoba kedua opsi tersebut. Keduanya mendapatkan saya. Tetapi argumen pada topik minus 58 terlihat sedikit kurang meyakinkan, jadi di sini saya akan merekomendasikan untuk memasukkan nilai minus 65 derajat (sementara otomatisasi akan memberi tahu saya bahwa nilai aktual yang dicapai akan minus 63 derajat).



Yah, itu dia. Sekarang Anda dapat melangkah melalui tombol Berikutnya sampai akhir, atau Anda cukup mengklik Selesai . Kami menghubungkan input inclk_interface dan inclk_interface_reset . Output c0 akan digunakan sebagai jam untuk seluruh sistem. Output c1 diekspor untuk clocking chip sdram . Di masa depan, Anda harus ingat untuk menghubungkan bus data ke input pll_slave . Untuk Cyclone V, ini tidak perlu.



Bagian perangkat keras lainnya, murni untuk memperbaiki bahan


Tambahkan inti prosesor. Hari ini, SDRAM kami akan diuji. Jadi, kode itu tidak boleh berada di dalamnya. Dan ini, pada gilirannya, berarti bahwa semua kode akan ditempatkan di RAM internal FPGA. Artinya, kita tidak perlu cache instruksi. Matikan, hemat memori FPGA. Kami juga menghubungkan satu bus instruksi dan data yang sangat terhubung. Tidak diperlukan pengaturan yang lebih menarik untuk inti prosesor.



Dengan gerakan tangan yang biasa, tambahkan dua blok RAM internal FPGA. Satu adalah port ganda dengan kapasitas 16 kilobyte dan satu adalah port tunggal dengan kapasitas 4 kilobyte. Bagaimana menamai mereka dan bagaimana menghubungkan, saya harap semua orang ingat. Terakhir kali saya suka menyoroti ban dengan bunga, mungkin untuk kemudahan membaca, saya akan melakukannya di artikel ini.



Jangan lupa untuk menetapkan blok memori ini alamat khusus dalam rentang pribadi dan menguncinya. Biarkan CodeMemory ditugaskan ke 0x20000000, dan DataMemory ke 0x20004000.

Baiklah, mari kita tambahkan blok SDRAM ke sistem, pengaturannya, serta blok JTAG-UART untuk menampilkan pesan dan GPIO bit-tunggal, di mana kami akan mengukur frekuensi nyata untuk memastikan bahwa itu meningkat. Untuk referensi, berikut adalah beberapa pengaturan yang tidak jelas:







Total, kami mendapatkan sistem seperti itu (saya menyoroti bus data, karena memindai di semua perangkat eksternal):



Kami menetapkan vektor ke prosesor, secara otomatis menetapkan alamat, secara otomatis menetapkan angka interupsi, ke sistem pembangkit.

Kami menghubungkan sistem ke proyek, melakukan perakitan kasar, menetapkan nomor kaki, dan kali ini kami membuat virtual tidak hanya CKE , tetapi juga reset_n (bagaimana ini dilakukan, saya katakan di salah satu artikel sebelumnya , cari Virtual Pin di sana). Kami membuat perakitan akhir, mengisi peralatan di FPGA. Itu saja. Kami telah menyelesaikan peralatan, buka bagian perangkat lunak.

Kami menyiapkan BSP untuk lingkungan kami


Untuk perubahan, mari buat proyek berdasarkan templat bukan dari Hello World Small , tetapi dari Memory Test Small :



Ketika itu dibuat, buka editor BSP. Seperti biasa, hal pertama yang kami lakukan adalah mematikan pemeriksaan SysID dan mengizinkan penggunaan C ++ (meskipun kali ini saya tidak akan mengubah jenis file, tetapi sudah menjadi kebiasaan bagi saya):



Tetapi hal terpenting yang harus kita perbaiki pada tab Skrip Linker . Otomasi mengakui bahwa bus instruksi hanya pergi ke memori CodeMemory , sehingga ia menempatkan bagian kode (disebut .text ) dalam memori CodeMemory . Tetapi merawat kami, dia menempatkan segala sesuatu yang lain di wilayah data terbesar, yang terletak di SDRAM . Bagaimana dia tahu bahwa kita tanpa ampun akan menghapus ingatan ini?



Kita harus secara manual, baris demi baris, mengganti wilayah dengan DataMemory (daftar pilihan akan muncul di sana, pemilihan harus diatur ulang di dalamnya). Kita harus mendapatkan gambar ini:



Eksperimen Program


Kami keluar dari editor, menghasilkan BSP, mencoba menjalankan program untuk debugging. Kami mendapatkan teks berikut:



Jika saya menekan Enter, saya tidak berhasil. Saya memasukkan sesuatu (ya bahkan spasi) dan kemudian menekan Enter. Kemudian mereka bertanya kepada saya:



Jam demi jam tidak mudah. Dan alamat apa yang akan dimasukkan? Anda dapat membuka Perancang Platform dan melihat nilainya di sana. Tapi saya biasanya melihat file system.h referensi universal (path lengkap untuk proyek saya adalah C: \ Work \ CachePlay5 \ software \ MemoryTest_bsp \ system.h). Di sana kami tertarik pada dua baris:



Teks yang sama
#define ALT_MODULE_CLASS_new_sdram_controller_0 altera_avalon_new_sdram_controller #define NEW_SDRAM_CONTROLLER_0_BASE 0x0 #define NEW_SDRAM_CONTROLLER_0_CAS_LATENCY 3 #define NEW_SDRAM_CONTROLLER_0_CONTENTS_INFO #define NEW_SDRAM_CONTROLLER_0_INIT_NOP_DELAY 0.0 #define NEW_SDRAM_CONTROLLER_0_INIT_REFRESH_COMMANDS 2 #define NEW_SDRAM_CONTROLLER_0_IRQ -1 #define NEW_SDRAM_CONTROLLER_0_IRQ_INTERRUPT_CONTROLLER_ID -1 #define NEW_SDRAM_CONTROLLER_0_IS_INITIALIZED 1 #define NEW_SDRAM_CONTROLLER_0_NAME "/dev/new_sdram_controller_0" #define NEW_SDRAM_CONTROLLER_0_POWERUP_DELAY 100.0 #define NEW_SDRAM_CONTROLLER_0_REFRESH_PERIOD 15.625 #define NEW_SDRAM_CONTROLLER_0_REGISTER_DATA_IN 1 #define NEW_SDRAM_CONTROLLER_0_SDRAM_ADDR_WIDTH 0x18 #define NEW_SDRAM_CONTROLLER_0_SDRAM_BANK_WIDTH 2 #define NEW_SDRAM_CONTROLLER_0_SDRAM_COL_WIDTH 9 #define NEW_SDRAM_CONTROLLER_0_SDRAM_DATA_WIDTH 16 #define NEW_SDRAM_CONTROLLER_0_SDRAM_NUM_BANKS 4 #define NEW_SDRAM_CONTROLLER_0_SDRAM_NUM_CHIPSELECTS 1 #define NEW_SDRAM_CONTROLLER_0_SDRAM_ROW_WIDTH 13 #define NEW_SDRAM_CONTROLLER_0_SHARED_DATA 0 #define NEW_SDRAM_CONTROLLER_0_SIM_MODEL_BASE 0 #define NEW_SDRAM_CONTROLLER_0_SPAN 33554432 #define NEW_SDRAM_CONTROLLER_0_STARVATION_INDICATOR 0 


di mana desimal 33554432 sama dengan hex 0x2000000. Oleh karena itu, jawaban saya dan hasil pekerjaan harus terlihat seperti ini:



Bagus, tetapi ini tidak baik untuk tes harian. Saya menulis ulang fungsi utama seperti ini:

 int main(void) { int step = 0; while (1) { if (step++%100 == 0) { alt_printf ("."); } if (MemTestDevice(NEW_SDRAM_CONTROLLER_0_BASE, NEW_SDRAM_CONTROLLER_0_SPAN)!=0) { printf ("*"); } } return (0); } 

Titik-titik menunjukkan bahwa program tidak "membeku". Jika ada kesalahan, tanda bintang akan ditampilkan. Untuk reliabilitas, Anda dapat menempatkan breakpoint pada outputnya, lalu jangan tidur.

Benar, poin "kiri" naik dari suatu tempat. Ternyata mereka ditampilkan di dalam fungsi MemTestDevice () . Di sana saya menghapus kesimpulan mereka. Tes berhasil. Sistem yang dihasilkan dapat digunakan, setidaknya untuk kebutuhan internal (yaitu, pengembangan tersebut dilakukan di bawah kompleks Redd).

Memeriksa kinerja sistem


Tapi saya sudah terbiasa dengan fakta bahwa ketika bekerja dengan peralatan Anda tidak bisa mempercayai apa pun. Semuanya harus diperiksa dengan cermat. Mari kita pastikan bahwa kita bekerja pada frekuensi dua kali lipat dibandingkan artikel sebelumnya. Tambahkan fungsi MagicFunction1 () yang terkenal.

Biarkan saya mengingatkan Anda bagaimana penampilannya.
 void MagicFunction1() { IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); IOWR (PIO_0_BASE,0,1); IOWR (PIO_0_BASE,0,0); } 


Kami akan memanggilnya dari main () , kami akan menangkap pulsa pada osiloskop, tetapi kali ini kami akan memperhatikan tidak hanya keindahannya, tetapi juga pada frekuensinya (izinkan saya mengingatkan Anda bahwa setiap drop setidaknya naik, bahkan turun adalah satu perintah, sehingga Anda dapat mengukur jarak antara tetesan )



Hanya 50 megahertz. Apakah frekuensinya benar-benar tidak meningkat? Bandingkan dengan frekuensi dari kode yang dikembangkan saat menulis artikel terakhir, dan kami memahami bahwa semuanya beres. Hanya saja, unit pio biasa membutuhkan 2 siklus clock per output ke port (dalam home-made saya mendapat 1 jam, tapi di sini cukup bagi kami untuk memastikan bahwa kinerja sistem berlipat ganda).



Kesimpulan


Alih-alih menggunakan osilator frekuensi tetap, kami belajar cara menggunakan unit PLL khusus. Benar, konstanta yang terdeteksi dimaksudkan untuk frekuensi 100 MHz, tetapi semua orang dapat menyesuaikannya dengan frekuensi lain baik menggunakan perhitungan terkenal, atau dengan coba-coba. Kami juga memperkuat keterampilan menciptakan sistem prosesor yang optimal dan memastikan bahwa memori pada frekuensi yang lebih tinggi bekerja secara stabil, dan frekuensinya benar-benar meningkat.

Secara umum, kita sudah dapat menghasilkan segala hal komputasi, kita bahkan dapat bertukar dengan prosesor sentral, tetapi prosesor pusat kompleks akan mengatasi perhitungan sepele lebih efisien. FPGA ditambahkan ke Redd untuk mengimplementasikan antarmuka berkecepatan tinggi atau menangkap arus informasi (well, atau play). Kami telah menguasai dasar-dasar mendesain, kami telah belajar bagaimana memberikan kinerja yang kurang lebih tinggi. Saatnya untuk terus bekerja dengan antarmuka, yang akan kita lakukan di artikel selanjutnya. Lebih tepatnya, satu set artikel, memperhatikan aturan "satu artikel - satu hal."

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


All Articles