Kompilasi kode untuk dijalankan dari RAM eksternal

13

Saya sedang mempertimbangkan desain untuk sistem permainan minimalis berdasarkan PIC18F85J5. Bagian dari desain saya adalah bahwa game dapat dimuat dari kartu SD tanpa memprogram ulang chip atau mem-flash memori program. Saya memilih chip itu karena memiliki antarmuka memori eksternal yang memungkinkan saya menjalankan kode dari SRAM eksternal.

Ide dasarnya adalah bahwa memori program internal akan berisi antarmuka untuk menelusuri kartu sd, dan begitu pengguna memilih program itu akan menyalin file hex dari kartu sd ke ram eksternal, dan kemudian melompat eksekusi ke ruang ram eksternal .

Memori program internal juga akan memiliki berbagai perpustakaan untuk grafik, input pengontrol dan berbagai utilitas lainnya.

Saya cukup yakin saya tahu cara membuat bagian firmware internal berfungsi dengan baik. Masalahnya adalah membuat program untuk dijalankan dari RAM eksternal. Rasanya tidak sama dengan menargetkan gambar biasa, dan perlu mengetahui fungsi perpustakaan yang tersedia di memori internal, tetapi tidak mengkompilasi ulang, hanya tautan ke mereka. Ini juga harus mulai menggunakan alamat setelah 32k flash internal, bukan nol. Apakah ada cara yang baik untuk mengkompilasi program menggunakan jenis kendala ini?

Saya menggunakan MPLab IDE, tetapi saya tidak terlalu mengenalnya, atau bagaimana melakukan penyesuaian seperti ini.

captncraig
sumber
Salah satu pertanyaan terbaik yang pernah saya lihat di sini sebentar ... Saya menantikan untuk mendengar ide dan jawaban.
Jon L
Beberapa pendekatan alternatif yang menarik dibahas dalam electronics.stackexchange.com/questions/5386/…
Toby Jaffey
Saya melihat itu, tetapi mereka kebanyakan merekomendasikan menulis ke flash, yang ingin saya hindari. Desain perangkat keras saya akan menyerupai angka 6 dalam catatan aplikasi dalam jawaban yang diterima.
captncraig

Jawaban:

8

Anda memiliki dua masalah terpisah:

  1. Membangun kode untuk kisaran alamat RAM eksternal.

    Ini sebenarnya sangat mudah. Yang harus Anda lakukan adalah membuat file tautan yang hanya berisi rentang alamat yang Anda inginkan untuk ditempati kode. Perhatikan bahwa Anda tidak hanya perlu memesan rentang alamat memori program tertentu untuk aplikasi eksternal ini, tetapi juga beberapa ruang RAM. Ruang RAM ini, seperti alamat memori program, perlu diperbaiki dan diketahui. Cukup sediakan hanya rentang alamat tetap dan dikenal yang tersedia untuk digunakan dalam file tautan. Jangan lupa untuk membuatnya TIDAK tersedia dalam file linker kode dasar.

    Setelah kode dasar memuat aplikasi baru ke dalam memori eksternal, ia harus tahu cara menjalankannya. Yang paling mudah adalah memulai eksekusi di lokasi RAM eksternal pertama. Ini berarti kode Anda akan memerlukan satu bagian KODE di alamat awal absolut itu. Ini berisi GOTO di sebelah kanan label di sisa kode, yang semuanya akan dipindahkan.

  2. Menautkan aplikasi ke rutinitas perpustakaan di kode dasar.

    Tidak ada cara sederhana untuk melakukan ini dengan alat Microchip yang ada, tetapi juga tidak seburuk itu.

    Masalah yang jauh lebih besar adalah bagaimana Anda ingin berurusan dengan perubahan kode dasar. Strategi sederhananya adalah membuat kode dasar Anda, menjalankan program di atas file peta yang dihasilkan untuk memanen alamat global, lalu minta ia menulis file impor dengan pernyataan EQU untuk semua simbol yang ditentukan secara global. File impor ini kemudian akan dimasukkan dalam semua kode aplikasi. Tidak ada yang ditautkan, karena kode sumber aplikasi pada dasarnya berisi referensi alamat tetap ke titik entri kode dasar.

    Itu mudah dilakukan dan akan berhasil, tetapi pertimbangkan apa yang terjadi ketika Anda mengubah kode dasar. Bahkan perbaikan bug kecil dapat menyebabkan semua alamat berpindah, dan semua kode aplikasi yang ada tidak akan bagus dan harus dibangun kembali. Jika Anda tidak pernah berencana untuk memberikan pembaruan kode dasar tanpa memperbarui semua aplikasi, maka mungkin Anda bisa lolos dengan ini, tapi saya pikir itu ide yang buruk.

    Cara yang lebih baik adalah dengan memiliki area antarmuka yang ditentukan pada alamat yang diketahui tetap dikenal dalam kode dasar. Akan ada satu GOTO untuk setiap subrutin yang dapat dipanggil oleh kode aplikasi. GOTO-GOTO ini akan ditempatkan di alamat yang sudah diketahui, dan aplikasi eksternal hanya akan memanggil ke lokasi tersebut, yang kemudian akan melompat ke mana pun subrutin tersebut benar-benar berakhir dalam pembuatan kode dasar. Ini membutuhkan 2 kata memori program per subrutin yang diekspor dan dua siklus tambahan pada saat dijalankan, tetapi saya pikir ini sangat berharga.

    Untuk melakukan ini dengan benar, Anda perlu mengotomatiskan proses menghasilkan GOTO dan file ekspor yang dihasilkan yang akan diimpor aplikasi eksternal untuk mendapatkan alamat subrutin (sebenarnya pengarah GOTO). Anda mungkin dapat melakukan dengan penggunaan makro MPASM yang cerdik, tetapi jika saya melakukan ini saya pasti akan menggunakan preprocessor saya karena dapat menulis ke file eksternal pada waktu preprocessing. Anda dapat menulis makro preprocessor sehingga setiap redirector dapat didefinisikan oleh satu baris kode sumber. Makro melakukan semua hal buruk di bawah tenda, yaitu untuk menghasilkan GOTO, referensi eksternal ke rutin target aktual, dan menambahkan baris yang sesuai ke file ekspor dengan alamat konstan yang diketahui dari rutin itu, semua dengan nama yang sesuai. Mungkin makro hanya membuat banyak variabel preprocessor dengan nama biasa (seperti array run-time diperluas), dan kemudian file ekspor ditulis setelah semua panggilan makro. Salah satu dari banyak hal yang dapat dilakukan preprocessor saya yang tidak dapat dilakukan macro MPASM adalah melakukan manipulasi string untuk membangun nama simbol baru dari nama lain.

    Preprosesor saya dan banyak hal terkait lainnya tersedia secara gratis di www.embedinc.com/pic/dload.htm .

Olin Lathrop
sumber
Saya sangat suka ide meja lompat tetap. Saya hanya bisa mulai dari akhir memori flash dan memiliki lokasi tetap untuk setiap panggilan sistem. Saya bahkan mungkin bisa pergi dengan file header yang dikelola secara manual dengan alamat semua subrutin jika saya tidak tahu semua preprocessor voodoo yang Anda gambarkan.
captncraig
5

Opsi 1: Bahasa yang Diartikan

Ini tidak langsung menjawab pertanyaan (yang merupakan pertanyaan luar biasa, BTW, dan saya berharap dapat belajar dari jawaban yang mengatasinya secara langsung), tetapi sangat umum ketika melakukan proyek yang dapat memuat program eksternal untuk menulis program eksternal dalam bahasa yang ditafsirkan. Jika sumber daya terbatas (yang akan berada pada prosesor ini, pernahkah Anda berpikir tentang menggunakan prosesor PIC32 atau ARM kecil untuk ini?), Itu umum untuk membatasi bahasa ke subset dari spesifikasi lengkap. Lebih jauh ke bawah rantai adalah bahasa-bahasa khusus domain yang hanya melakukan beberapa hal.

Sebagai contoh, proyek elua adalah contoh dari bahasa yang ditafsirkan dengan sumber daya rendah (64 kB RAM). Anda dapat menekan ini hingga 32k RAM jika Anda menghapus beberapa fitur (Catatan: Ini tidak akan bekerja pada prosesor Anda saat ini, yang merupakan arsitektur 8-bit. Menggunakan RAM eksternal mungkin akan terlalu lambat untuk grafis). Ini memberikan bahasa yang cepat dan fleksibel di mana pengguna baru dapat dengan mudah memprogram game jika Anda menyediakan API minimal. Ada banyak dokumentasi yang tersedia untuk bahasa online. Ada bahasa lain (seperti Forth dan Basic) yang dapat Anda gunakan dengan cara yang sama, tapi saya pikir Lua adalah pilihan terbaik saat ini.

Dengan nada yang sama, Anda dapat membuat bahasa khusus domain Anda sendiri. Anda harus menyediakan API dan dokumentasi eksternal yang lebih lengkap, tetapi jika semua gim serupa maka ini tidak akan terlalu sulit.

Bagaimanapun, PIC18 mungkin bukan prosesor yang saya gunakan untuk sesuatu yang melibatkan pemrograman kustom / scripting dan grafik. Anda mungkin akrab dengan kelas prosesor ini, tetapi saya menyarankan agar ini saat yang tepat untuk menggunakan sesuatu dengan driver layar dan lebih banyak memori.

Opsi 2: Hanya memprogram ulang semuanya

Namun, jika Anda sudah merencanakan pemrograman sendiri semua game di C, maka jangan repot-repot hanya memuat logika game dari kartu SD. Anda hanya memiliki 32kB Flash untuk memprogram ulang, dan dapat dengan mudah mendapatkan kartu microSD 4 GB untuk ini. (Catatan: kartu yang lebih besar biasanya SDHC, yang lebih sulit untuk dihubungkan). Dengan asumsi bahwa Anda menggunakan setiap byte terakhir dari 32 kB Anda, yang memberikan ruang pada kartu SD untuk 131.072 salinan firmware Anda dengan logika permainan apa pun yang Anda butuhkan.

Ada banyak catatan aplikasi untuk menulis bootloader untuk PIC, seperti AN851 . Anda harus merancang bootloader Anda untuk menempati wilayah memori tertentu (mungkin bagian atas wilayah memori, Anda akan menentukan ini di tautan), dan menentukan bahwa proyek firmware penuh tidak mencapai wilayah ini. Catatan appnote ini lebih terinci. Cukup ganti "Bagian boot dari PIC18F452" dengan "Bagian boot yang saya tentukan di tautan" dan semuanya akan masuk akal.

Kemudian, bootloader Anda hanya perlu memungkinkan pengguna untuk memilih program untuk dijalankan dari kartu SD, dan menyalin semuanya. UI bisa jadi bahwa pengguna harus menahan tombol untuk masuk ke mode pemilihan. Biasanya, bootloader hanya akan memeriksa status tombol ini saat reset, dan, jika tidak ditekan, boot ke dalam gim. Jika tertahan, pengguna harus memilih file pada kartu SD, menyalin program, dan melanjutkan boot ke gim [baru].

Ini rekomendasi saya saat ini.

Opsi 3: Sihir yang dalam melibatkan hanya menyimpan sebagian dari file hex

Masalah dengan mekanisme yang Anda bayangkan adalah bahwa prosesor tidak berurusan dengan API dan pemanggilan fungsi, ini berkaitan dengan angka - alamat yang dapat dilompati oleh penunjuk instruksi dan mengharapkan ada kode yang mengeksekusi pemanggilan fungsi sesuai dengan spesifikasi API. Jika Anda mencoba mengkompilasi hanya sebagian dari program, linker tidak akan tahu apa yang harus dilakukan ketika Anda menelepon check_button_status()atau toggle_led(). Anda mungkin tahu bahwa fungsi-fungsi itu ada di file hex pada prosesor, tetapi perlu tahu persis di mana mereka berada.

Linker telah memecah kode Anda menjadi beberapa bagian; Anda secara teoritis dapat memecah ini menjadi bagian tambahan dengan beberapa -sectiondan #pragmamantra. Saya belum pernah melakukan ini, dan tidak tahu caranya. Sampai kedua metode di atas gagal saya (atau seseorang memposting jawaban yang luar biasa di sini), saya mungkin tidak akan mempelajari mekanisme ini, jadi saya tidak bisa mengajarkannya kepada Anda.

Kevin Vermeer
sumber
Keberatan saya untuk nomor 2 adalah bahwa memori flash memiliki jumlah siklus penghapusan yang terbatas dalam masa pakai chip. Saya tidak ingin menggunakan MCU yang lebih besar karena saya akan menggunakan minimal 8-bit.
captncraig
@CMP - Ini memiliki setidaknya 10.000 siklus hapus. Jika seseorang memainkan permainan yang berbeda setiap hari, itu akan bertahan hingga tahun 2039. Flash hampir pasti akan bertahan lebih lama dari sisa sirkuit. Saya tidak berpikir Anda perlu khawatir tentang hal ini kecuali itu akan diputar puluhan kali setiap hari.
Kevin Vermeer
1
Kedua, minimalis 8-bit mungkin terlihat keren, tetapi itu payah untuk pemrograman. Jauh lebih mudah untuk mendapatkan mikrokontroler yang kokoh dan membuatnya terlihat retro daripada dipaksa untuk membuatnya terlihat retro karena Anda mendorong batas prosesor Anda.
Kevin Vermeer
1
Keduanya poin yang sangat adil. Bahkan jika pergi untuk jumlah bagian yang rendah, pic32 tidak jauh berbeda dalam biaya atau komponen eksternal daripada ini, dan jika ia memiliki 512K flash internal bahkan menang.
captncraig
Sepertinya solusi praktis adalah menggunakan pic32 dan menulis bootloader untuk direflash dari kartu sd. Saya akan mengalami kesulitan menggunakan kembali fungsi baik bootloader dan kode pengguna perlu, tetapi selama saya menyimpannya di 12k boot flash itu harus memberikan kode pengguna seluruh chip, dan mereka dapat memasukkan perpustakaan apa pun yang mereka inginkan pada sumbernya tingkat.
captncraig