Perangkat: dsPIC33FJ128GP802
Saya memiliki beberapa file * .s sebagai berikut
.global _D1
.section .speex, code
_D1:
.pword 0x66C821, 0x1B0090, 0xD96C36, 0x9B60B0, 0xDD4E36, 0xBF4E53
.pword 0xD1098B, 0x719BD9, 0x873989, 0x003B69, 0x279035, 0xED4244
.pword 0xE1403C, 0x54D439, 0x826550, 0xC59627, 0xDD0432, 0x88FA29
Saya telah mendeklarasikan hal yang sama dalam *. H
extern void D1(void);
Sekarang saya meneruskan D1 ke fungsi membaca tabel
nowPlaying.file1 = (unsigned long) D1;
function(nowPlaying.file1);
Masalah saya adalah, jika alamat D1 di atas 0X8000, rutin tidak benar. Saya mencoba model kode besar dan kecil, tetapi hasilnya sama. Saya pikir ini karena keterbatasan 16 bit dari pointer Apakah ada metode untuk mengakses alamat absolut D1 langsung dari kode. Mungkin sesuatu seperti fungsi bawaan atau makro.
microcontroller
pic
microchip
compiler
Saneesh AT
sumber
sumber
D1
seharusnya mewakili suatu fungsi atau array data?const short D1[]
.Jawaban:
Data yang Anda gambarkan (penggunaan 24-bit penuh dari memori program untuk menyimpan data) tidak dapat didefinisikan dan diinisialisasi dalam C, dan tidak dapat membaca langsung melalui C; satu-satunya cara untuk mengaksesnya adalah dengan merangkum dalam fungsi perakitan C-callable atau intrinsik.
Sebenarnya ada dua pertanyaan di sini:
cara bermain apik dengan kompiler, assembler, dan tautan, sehingga ketika Anda mendefinisikan data 24-bit dalam file rakitan sebagai data yang dapat dipindahkan dengan nama simbolis
D1
, daripada data yang tidak disebutkan namanya di alamat tetap, kompiler dapat melihat variabel ini untuk menentukan alamatnyacara mengakses data
Pertanyaan ke-2 (bagaimana mengakses data) dijawab untuk bagian 33EP di DS70613C dan harus dijawab untuk bagian 33FJ di DS70204C (tetapi contoh dalam manual 33FJ hanya menggunakan bit 16 rendah). Berikut ini cuplikan contoh kode dari manual referensi 33EP yang berfungsi untuk 33EP bagian + seharusnya untuk 33FJ (Saya tidak punya perangkat 33FJ yang mudah tersedia):
(catatan: penggunaan kode
int
, sedangkan akan lebih baik digunakanuint16_t
dan#include <stdint.h>
)Anda akan mencatat bahwa fungsi builtin
__builtin_tblrdl()
dan__builtin_tblrdh()
digunakan untuk membaca kata-kata data 16-bit yang rendah dan tinggi dari lokasi memori program, dan__builtin_tblpage() and __builtin_tbloffset()
dapat digunakan untuk mengekstrak halaman dan mengimbangi alamat. Dalam contoh khusus ini, array highWord selalu 0, dan array lowWord cocok dengan prog_data yang didefinisikan dan diinisialisasi dalam C.Harap dicatat tidak ada petunjuk yang digunakan di sini! Meskipun dimungkinkan untuk menggunakan variabel normal yang ditandai
const
, sehingga mereka ditempatkan oleh linker di ruang program read-only, dan agar Anda dapat membaca memori menggunakan teknik pointer C standar, dengan kompiler secara otomatis mengelola register paging. untuk Anda, Anda hanya dapat menyimpan data 16-bit. Anda perlu mengakses fungsi built-in TBLRDL dan TBLRDH untuk mendapatkan semua 24 bit data.Adapun cara bermain dengan kompiler / linker / etc, Anda harus menipu kompiler dan mengatakan itu hanya melihat data 16-bit. Berikut adalah contoh yang berfungsi untuk mendapatkan pada variabel D1 yang dideklarasikan di tempat lain:
Ini benar membaca nilai 24-bit dan menyimpannya di bagian bawah 24 bit dari uint32_t. Variabel D1 extern yang dideklarasikan dalam C adalah variabel dummy yang hanya digunakan untuk mendapatkan alamat awal dengan memanfaatkan cara kompiler / assembler / penghubung bekerja bersama. Fungsi builtin menangani sisa pekerjaan.
Yang saya tidak tahu adalah bagaimana cara secara otomatis mendapatkan ukuran data, karena itu ditentukan + diinisialisasi dalam perakitan.
sumber
Jangan mengubahnya menjadi lama dan mundur tanpa tanda tangan. Meminta masalah. Anda pada dasarnya berbohong kepada kompiler. Deklarasi yang benar untuk nowPlaying.file1 adalah
Dan juga untuk function ():
dan hapus semua typecast.
Atau, jika @PeterJ menyarankan, ini adalah data, itu harus dinyatakan sebagai extern short D1 [] di kedua tempat: dan Anda tidak benar-benar membutuhkan assembler; Anda bisa mendeklarasikan semuanya dalam C sebagai const short D1 [] = {...}; Compiler harus memasukkannya ke dalam segmen kode karena const.
sumber
Sepertinya jawaban sederhana adalah menulis subrutin dalam assembler. Jika saya ingat benar, C30 tidak mengakses memori program sebagai data menggunakan pointer 24 bit. Paling-paling ia dapat mengakses memori program melalui jendela PSV, tetapi kemudian Anda hanya dapat melihat 16 bit rendah dari setiap kata memori program 24 bit.
Jika akan sangat sederhana untuk menulis assembler rutin yang dapat dipanggil dari C30 yang mengembalikan 24 bit data yang diberikan alamat memori program 24 bit. Namun, apakah data Anda kumpulan dari nilai 24 bit atau benar-benar daftar byte yang dikemas 3 per kata? Jika yang terakhir, maka itu bahkan lebih mudah. Tulis rutin assembler yang memberi Anda tampilan byte-address dari memori program. Alamatnya masih harus 24 bit, tetapi nilai data sekarang hanya 8 bit.
Atau cukup tulis seluruh rutin dalam assembler. Jika Anda melakukan pembelahan byte tingkat rendah dan pengemasan memori, mungkin ini lebih mudah. Di assembler Anda bisa melakukan apa yang Anda inginkan dengan cara yang diinginkan mesin. Dalam C Anda harus mencari tahu mantera apa yang harus digumamkan ke kompiler untuk membuatnya menulis kode mesin untuk Anda. Terkadang lebih mudah melakukannya sendiri secara langsung. Arsitektur dsPIC sangat mudah untuk menulis kode assembly, jelas lebih mudah daripada PIC 16.
sumber
__builtin_tblrdX()
fungsinya. Saya setuju dengan Anda + mendapat tendangan dari ungkapan Anda "Di C Anda harus mencari tahu mantera apa yang harus digumamkan ke kompiler". Ironisnya, jika Anda benar-benar mencoba memeras kinerja maksimum, kadang-kadang__builtin()
fungsinya lebih baik, karena kompiler dapat mengoptimalkan cara menghasilkan kode, sedangkan itu harus memperlakukan fungsi perakitan kode tangan sebagai kotak hitam yang tidak dapat diubah .