Jadi, dalam
artikel terakhir, kami mengembangkan sistem prosesor yang paling sederhana, dengan bantuan yang kami rencanakan untuk menguji chip RAM yang terhubung ke FPGA kompleks Redd. Hari ini, kami akan membuat program C ++ untuk lingkungan perangkat keras ini, dan kami juga akan mencari cara untuk menyuntikkan program ini, dan yang paling penting, debug itu.

Program ini dikembangkan di lingkungan Eclipse. Untuk memulainya, pilih item menu
Tools-> Nios II Software Build Tools for Eclipse .

Kita perlu membuat proyek dan BSP untuk itu. Untuk melakukan ini, klik tombol kanan mouse di area Project Explorer dan pilih
New-> Nios II Application dan BSP dari item menu
Template .

Templat dasar yang menjadi dasar proyek akan dibuat dibuat selama pembuatan sistem prosesor. Oleh karena itu, kami menemukan file yang mengandungnya.

Kami juga akan memberikan nama proyek (saya memilikinya
SDRAMtest ) dan pilih jenis proyek. Saya memilih
Hello World Small . Saya ingin memilih
Tes Memori , kami melakukan tes memori, tetapi sekarang kami sedang mempertimbangkan cara umum untuk membuat aplikasi. Karena itu, kami memilih opsi umum.

Kami telah menciptakan dua proyek. Yang pertama adalah proyek kami, yang kedua adalah BSP (Paket Dukungan Dewan, secara umum, perpustakaan untuk bekerja dengan peralatan).

Hal pertama yang biasanya saya lakukan adalah mengedit pengaturan BSP. Untuk melakukan ini, saya memilih proyek kedua yang dibuat, tekan tombol kanan mouse dan pilih item menu
Nios II -> BSP Editor .

Dalam editor, semuanya dibagi menjadi beberapa kelompok:

Tetapi agar tidak berjalan bersama mereka, saya akan memilih akar pohon, elemen
Pengaturan , dan mempertimbangkan semuanya secara linear. Saya akan mencantumkan apa yang harus Anda perhatikan. Layar pengaturan awal:

Dukungan untuk keluar dan dukungan untuk pengupasan saat keluar dinonaktifkan, yang mengeluarkan potongan besar yang tidak perlu dari kode, tetapi awalnya dinonaktifkan. Gagak ini dimatikan, karena saya memilih opsi minimum
Halo, Dunia . Saat memilih jenis kode lain, lebih baik untuk menghapus daw ini juga. Saya tidak bisa menolak dan mengaktifkan dukungan C ++. Anda juga perlu menghapus cek
SysID , jika tidak, tidak akan ada yang berhasil. Faktanya adalah saat membuat sistem perangkat keras, saya tidak menambahkan blok yang sesuai. Pengaturan yang tersisa cukup jelas dan belum diubah. Sebenarnya, saya belum mengubah pengaturan lain juga. Sebentar lagi kita akan kembali ke sini, tetapi untuk sekarang kita tekan tombol Generate. Kami membuat versi baru BSP berdasarkan pengaturan yang dibuat. Di akhir, klik Keluar.
Sekarang kesenangan dimulai. Cara merakit proyek. Tekan
Ctrl + B yang biasa - kami mendapat kesalahan. Kesalahan decoding no:

Tidak ada yang masuk akal di konsol juga:

Pilih
Proyek Bangun untuk proyek
SDRAMtest , kami mendapatkan penjelasan yang masuk akal:

Faktanya, templat yang tidak berfungsi adalah identitas korporat Quartus. Ini adalah alasan lain mengapa saya tidak memilih
Tes Memori . Semakin banyak berjalan. Di sini jelas apa masalahnya.
Fungsi file
alt_putstr.c ini gagal :
/* * Uses the ALT_DRIVER_WRITE() macro to call directly to driver if available. * Otherwise, uses newlib provided fputs() routine. */ int alt_putstr(const char* str) { #ifdef ALT_SEMIHOSTING return write(STDOUT_FILENO,str,strlen(str)); #else #ifdef ALT_USE_DIRECT_DRIVERS ALT_DRIVER_WRITE_EXTERNS(ALT_STDOUT_DEV); return ALT_DRIVER_WRITE(ALT_STDOUT_DEV, str, strlen(str), 0); #else return fputs(str, stdout); #endif #endif }
Kami akan memperbaikinya nanti (untuk ini kita perlu memperumit sistem perangkat keras). Hari ini kita tidak membutuhkannya. Ganti tubuhnya dengan
kembali 0 . Proyek mulai berkumpul.
Bagus Kami sudah memiliki
file elf siap (bahkan jika itu tidak melakukan fungsi yang berguna) dan kami memiliki peralatan di mana Anda dapat
mengunggah file hex (ingat bagaimana kami memberi tahu kompiler Quartus bahwa data RAM harus dimuat darinya dengan mengatur Onchip RAM?). Bagaimana kita mengonversi
elf ke
hex ? Sangat sederhana. Kami bangun di proyek yang bekerja, tekan tombol mouse kanan, pilih item menu
Make Target -> Build :

Di jendela yang muncul, cobalah dulu untuk memilih opsi pertama (
mem_init_install ):

Tidak akan terjadi apa-apa. Tetapi dari pesan kesalahan yang diberikan kepada kami, kami belajar bagaimana menyelesaikan proyek untuk Quartus:
../SDRAMtest_bsp//mem_init.mk:230: *** Deprecated Makefile Target: 'mem_init_install'. Use target 'mem_init_generate' and then add mem_init/meminit.qip to your Quartus II Project. Stop.
Kami
akan memilih build untuk tujuan
mem_init_generate , setelah itu (setelah !!!) kami akan menambahkan
file qip yang ditentukan ke proyek perangkat keras (kami sudah belajar cara menambahkan file ketika kami menambahkan sistem prosesor ke proyek).

Nah,
file hex itu sendiri juga bisa dirasakan dengan tangan Anda. Ini dia:

Bagus Kami memiliki segalanya untuk mulai mengisi program dengan fungsi nyata. Kami pergi ke file
hello_world_small.c . Jujur, saya sedikit tersinggung dengan bekerja dengan C. murni Karena itu, saya akan mengganti nama menjadi cpp. Dan agar tidak ada yang salah, saya akan menambahkan mantra ajaib ke teks yang ada:

Teks yang sama: extern "C" { #include "sys/alt_stdio.h" } int main() { alt_putstr("Hello from Nios II!\n"); /* Event loop never exits. */ while (1); return 0; }
Penting untuk melakukan operasi
Proyek Bersih setelah mengubah jenis file, jika tidak kompiler akan menampilkan pesan kesalahan bahwa file
* .c tidak ditemukan berdasarkan pada beberapa informasi yang di-cache.
Kami akan membuat tes memori sederhana. Saya tidak memiliki tugas mengajar pembaca untuk menguji chip RAM dengan benar. Kami hanya memastikan bahwa alamat dan bus data tidak lengket dan tidak ada istirahat. Artinya, kami menulis di setiap sel semua nol dan alamat sel. Tugas kita adalah membuat kode kerja, dan yang lainnya (konstanta pengisian dan penundaan lainnya untuk memverifikasi bahwa data sedang dibuat ulang) adalah detail implementasi yang menyulitkan teks tetapi tidak mengubah esensinya.
Mari kita mulai dengan pertanyaan sederhana dan alami: "Di mana SDRAM berada di ruang alamat?" Saya ingat bahwa kami memanggil fungsi penetapan alamat otomatis, tetapi bahkan tidak melihat alamat yang ditugaskan. Bahkan, bahkan sekarang kita tidak akan melihat ke sana. Semua informasi yang diperlukan ada di file:
... \ SDRAMtest_bsp \ system.h .
Hasilnya, kami mendapatkan kode berikut: extern "C" { #include "sys/alt_stdio.h" #include <stdint.h> #include "../SDRAMtest_bsp/system.h" #include <altera_avalon_pio_regs.h> } int main() { bool bRes = true; volatile static uint32_t* const pSDRAM = (uint32_t*)NEW_SDRAM_CONTROLLER_0_BASE; static const int sizeInDwords = NEW_SDRAM_CONTROLLER_0_SPAN / sizeof (uint32_t); // for (int i=0;i<sizeInDwords;i++) { pSDRAM [i] = 0; } // for (int i=0;i<sizeInDwords;i++) { if (pSDRAM [i] != 0) { bRes = false; } } // for (int i=0;i<sizeInDwords;i++) { pSDRAM [i] = i; } // for (int i=0;i<sizeInDwords;i++) { if (pSDRAM [i] != i) { bRes = false; } } if (bRes) { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x01); } else { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x02); } /* Event loop never exits. */ while (1); return 0; }
Kami mengumpulkan
file hex (saya ingatkan itu melalui dialog ini):

Kemudian kita mengkompilasi peralatan di Quartus dan memasukkan programmer untuk memuat "firmware" yang dihasilkan dengan kode program yang diinisialisasi ke dalam chip.

Tuang dalam "firmware" dan dapatkan pesan bahwa sistem hanya akan hidup ketika terhubung ke JTAG (fitur-fitur dari lisensi kernel SDRAM di lingkungan pengembangan gratis). Sebenarnya, untuk kasus Redd, ini tidak kritis. JTAG ini ada di sana sepanjang waktu.

Hasil tes RAM dapat dilihat pada konektor, kontak C21 (berhasil) atau B21 (kesalahan). Kami terhubung dengan mereka dengan osiloskop.

Kedua output berada di nol. Ada yang salah di sini. Masih harus mengerti apa sebenarnya. Faktanya, program yang tidak beroperasi sangat bagus, karena sekarang kita akan mulai mempelajari debugging JTAG. Kami membidik proyek, pilih
Debug As-> Nios II Hardware .

Pertama kali sistem tidak menemukan perangkat keras. Ini terlihat seperti ini (perhatikan palang merah di tajuk tab yang disorot):

Beralih ke tab
Target Connection dan centang kotak
Ignore Mismatching System ID . Selama percobaan berikutnya, saya kadang-kadang juga harus mengatur
Timestamp Abaikan Sistem Abaikan . Untuk jaga-jaga, saya akan menyorotnya dalam gambar bukan dengan merah, tetapi dengan bingkai kuning untuk menekankan bahwa tidak perlu menginstalnya sekarang, tetapi jika tombol
Debug tidak diaktifkan, mungkin sudah saatnya untuk menginstalnya.
Terapkan (
Terapkan ), lalu klik
Refresh Connections (tombol ini disembunyikan, Anda perlu menggulirnya):

Seorang debugger muncul dalam daftar, Anda dapat mengklik
Debug ...

Kami berhenti di fungsi
utama () . Jika diinginkan, Anda dapat meletakkan breakpoint di akhir algoritma dan memeriksa apakah program mencapainya:

Jalankan program:

Breakpoint tidak berfungsi. Mari kita menghentikan program dan melihat di mana ia berjalan.

Semua itu buruk. Programnya jelas macet. Mengatur breakpoint secara berurutan, lalu berhenti (dengan tombol merah "Stop") dan memulai kembali program (menggunakan tombol dengan bug), kami menemukan area masalah.
Semuanya mati saat baris ini dieksekusi untuk elemen pertama:

Teks yang sama: for (int i=0;i<sizeInDwords;i++) { if (pSDRAM [i] != 0) { bRes = false; } }
Dari sudut pandang C ++, semuanya bersih di sini. Tetapi jika Anda membuka kode yang dibongkar, Anda dapat melihat bahwa ada terlalu banyak perintah seragam di sana. Tampaknya kode itu telah terhapus dengan sendirinya. Dan dia bisa melakukan ini jika linker meletakkannya di SDRAM (konten yang ditimpa kode ini).

Kami berhenti debugging, tutup perspektif debugging.

Kami pergi ke editor BSP, di mana kami berada di awal artikel ini, tetapi ke tab
Linker Script . Jika saya memperbaiki tab ini di awal, saya tidak akan dapat menunjukkan teknik untuk memasukkan debugging JTAG (dan menekankan semua kekuatannya dibandingkan dengan output debugging sederhana, karena fakta kode macet selama debugging JTAG menarik perhatian saya). Begitulah. Linker yang baik menempatkan semuanya dalam memori, yang ukurannya lebih besar.

Kami mengalihkan semuanya ke
onchip_memory ... Sekarang kami memiliki SDRAM - itu hanya sepotong memori, yang kinerjanya belum kami jamin. Anda tidak dapat memberikannya ke tindakan kompiler otomatis apa pun.

Kami membangun kembali
bsp , membangun kembali proyek. Apakah saya perlu membuat ulang gambar memori dan membebani FPGA? Kemudian, untuk pekerjaan semi-otonom, itu akan diperlukan, tetapi saat debugging sedang berlangsung - tidak. Versi baru program akan segera dimuat ke dalam RAM ketika sesi debugging baru dimulai. Tetapi agar pada boot FPGA berikutnya tidak perlu memulai debugger, buat
file HEX baru di akhir debugging dan diinginkan untuk mengumpulkan βfirmwareβ FPGA dengannya.
Untuk kode baru, sebuah breakpoint telah tercapai, hasil tes
benar :

Osiloskop telah menghibur: sinar kuning telah terbang di unit.

Tes berlalu. Mari kita sedikit rumit dan secara bersamaan memeriksa kinerja sistem. Mari kita buat final seperti ini:
// GPIO if (bRes) { while (true) { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x01); IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x00); } } else { while (true) { IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x02); IOWR_ALTERA_AVALON_PIO_DATA (PIO_0_BASE,0x00); } }
Akibatnya, kami memiliki berliku-liku pada osiloskop (semuanya terhubung melalui loop panjang, jadi ujung kapasitif muncul di baris kedua, jangan perhatikan itu):

Hasilnya adalah frekuensi sekitar 8,3 MHz pada frekuensi clock 50 MHz tanpa menyempurnakan inti prosesor dan mengoptimalkan kode program. Artinya, akses ke port berjalan pada frekuensi yang sedikit lebih tinggi dari 16 MHz, yang sesuai dengan sepertiga dari frekuensi sistem. Bukan berarti itu benar-benar berbeda, tetapi lebih baik dari 4 MHz pada frekuensi clock 925 MHz untuk Cyclone V SoC ... Tidak, prosesor NIOS II itu sendiri beberapa kali lebih lambat daripada inti kelima ARM Cyclone, tetapi prosesor, seperti yang saya katakan , kita memiliki x64 dalam sistem, di sini kita membutuhkan lebih banyak kernel, yang menyediakan logika dari besi. Dan logika ini disediakan tepatnya melalui kerja dengan port. Jika bekerja dengan port lambat, maka semua hal lain akan menganggur secara teratur, menunggu bus selesai bekerja. Karakteristik yang diungkapkan adalah batas akses prosesor ke porta, tetapi bukan perangkat keras secara keseluruhan. Namun, bagaimana cara mengimplementasikan pekerjaan secara keseluruhan, kami akan pertimbangkan di artikel selanjutnya.
Kesimpulan
Artikel ini menunjukkan cara membuat dan mengkonfigurasi proyek di C ++ untuk lingkungan prosesor paling sederhana yang dikembangkan untuk kompleks Redd. Metode mengakses peralatan, serta teknik debug JTAG ditampilkan. Unduh perangkat keras / perangkat lunak yang diperoleh saat menulis artikel di
sini .