Địa chỉ tuyệt đối của một chức năng trong Microchip XC16


8

Thiết bị: DSPIC33FJ128GP802

Tôi có một số tệp * .s như sau

.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

Tôi đã khai báo tương tự trong một * .h

extern void D1(void);

Bây giờ tôi chuyển D1 đến một chức năng đọc bảng

nowPlaying.file1 = (unsigned long) D1;
function(nowPlaying.file1);

Vấn đề của tôi là, nếu địa chỉ của D1 trên 0X8000, thì thói quen không đúng. Tôi đã thử các mô hình mã lớn và nhỏ, nhưng kết quả là như nhau. Tôi nghĩ điều này là do giới hạn 16 bit của con trỏ Có phương pháp nào để truy cập địa chỉ tuyệt đối của D1 trực tiếp từ mã. Có thể là một cái gì đó như được xây dựng trong chức năng hoặc macro.


Tôi chưa bao giờ sử dụng chuỗi DSPIC, nhưng lý do nào bạn không thể sử dụng mảng C const thay vì trình biên dịch chương trình? Tôi nghĩ rằng có các tùy chọn để đặt nó tại các vị trí mã cụ thể (nếu bạn cần vì một số lý do khác). Chỉ cần suy nghĩ có thể một số tối ưu hóa trình biên dịch rút ngắn các con trỏ bởi vì nó không mong đợi được tham chiếu dữ liệu tại các vị trí bộ nhớ cao hơn.
PeterJ

Có, hướng dẫn trình biên dịch cho biết tất cả các con trỏ bao gồm các con trỏ hàm là 16 bit. Tôi đang tìm kiếm một số phương pháp khác để truy cập địa chỉ bộ nhớ. Nếu chúng ta sử dụng mảng const, chúng ta không thể sử dụng byte trên của một từ 3 byte trong DSPIC. Một lý do khác là, tập tin lắp ráp được tạo bởi một phần mềm máy tính được cung cấp bởi vi mạch để nén dữ liệu giọng nói.
Saneesh TẠI 2/213

Câu hỏi liên quan: Electronics.stackexchange.com/questions/56058/ (mặc dù điều này là dành cho PIC, nhưng DSPIC có thể hoạt động như nhau)

Là dữ liệu D1được cho là đại diện cho một chức năng hoặc một mảng dữ liệu?
Photon

2
@Saneesh Vì vậy, trả lời câu hỏi của tôi . Đây là mã hay là dữ liệu? Nếu là mã, hệ thống không hỗ trợ nó ngoài không gian địa chỉ 16 bit, vì vậy những gì bạn đang cố gắng thực hiện là không thể cho dù bạn thể hiện nó như thế nào. Nếu đó là dữ liệu, vui lòng nói như vậy và vui lòng thử giải quyết nó dưới dạng const short D1[].
dùng207421

Câu trả lời:


4

Dữ liệu bạn mô tả (sử dụng toàn bộ bộ nhớ chương trình 24 bit để lưu trữ dữ liệu) không thể được xác định và khởi tạo trong C và không thể đọc trực tiếp qua C; cách duy nhất để truy cập nó là bằng cách gói gọn trong một hàm lắp ráp có thể gọi được bằng C hoặc nội tại.

Thực sự có hai câu hỏi ở đây:

  1. Làm thế nào để chơi độc đáo với trình biên dịch, trình biên dịch và trình liên kết, để khi bạn xác định dữ liệu 24 bit của mình trong tệp lắp ráp là dữ liệu có thể định vị lại bằng một tên tượng trưng D1, thay vì dữ liệu không tên ở một địa chỉ cố định, trình biên dịch có thể thấy biến này để xác định địa chỉ của nó

  2. làm thế nào để truy cập dữ liệu

Câu hỏi thứ 2 (cách truy cập dữ liệu) được trả lời cho các phần 33EP trong DS70613C và phải được trả lời cho các phần 33FJ trong DS70204C (nhưng các ví dụ trong hướng dẫn 33FJ chỉ sử dụng 16 bit thấp). Dưới đây là đoạn mã ví dụ từ tài liệu tham khảo 33EP hoạt động cho các bộ phận 33EP + nên cho 33FJ (Tôi không có sẵn thiết bị 33FJ):

(lưu ý: sử dụng mã int, trong khi đó sẽ tốt hơn khi sử dụng uint16_t#include <stdint.h>)

int prog_data[10] __attribute__((space(prog))) =
  {0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888, 0x9999};

unsigned int lowWord[10], highWord[10];
unsigned int tableOffset, loopCount;

int main(void){
    TBLPAG = __builtin_tblpage (prog_data);
    tableOffset = __builtin_tbloffset (prog_data);
    /* Read all 10 constants into the lowWord and highWord arrays */
    for (loopCount = 0; loopCount < 10; loopCount ++)
    {
        lowWord[loopCount] = __builtin_tblrdl (tableOffset);
        highWord[loopCount] = __builtin_tblrdh (tableOffset);
        tableOffset +=2;
    }
    while(1)
        ;
}

Bạn sẽ lưu ý rằng các hàm dựng sẵn __builtin_tblrdl()__builtin_tblrdh()được sử dụng để đọc các từ dữ liệu 16 bit thấp và cao từ một vị trí bộ nhớ chương trình và __builtin_tblpage() and __builtin_tbloffset()có thể được sử dụng để trích xuất trang và phần bù của địa chỉ. Trong ví dụ cụ thể này, mảng highWord luôn là 0 và mảng lowWord khớp với prog_data được xác định và khởi tạo trong C.

Xin lưu ý không có con trỏ được sử dụng ở đây! Mặc dù có thể sử dụng các biến thông thường được gắn thẻ const, để chúng được đặt bởi trình liên kết trong không gian chương trình chỉ đọc và để bạn có thể đọc bộ nhớ bằng các kỹ thuật con trỏ C tiêu chuẩn, với trình biên dịch tự động quản lý các thanh ghi phân trang đối với bạn, bạn chỉ có thể lưu trữ dữ liệu 16 bit. Bạn cần truy cập các hàm dựng sẵn TBLRDL và TBLRDH để có được tất cả 24 bit dữ liệu.

Về cách chơi độc đáo với trình biên dịch / linker / etc, bạn phải đánh lừa trình biên dịch và nói với nó rằng nó chỉ nhìn thấy dữ liệu 16 bit. Đây là một ví dụ hoạt động để lấy biến D1 được khai báo ở nơi khác:

#define D1_SIZE 18
extern uint16_t __attribute__((space(prog))) D1[D1_SIZE];

#define READ_DATA(dst, v, len) readData(dst, __builtin_tblpage(v), __builtin_tbloffset(v), len)
void readData(uint32_t *pdst, uint16_t page, uint16_t offset, uint16_t len)
{
    TBLPAG = page;
    while (len-- > 0)
    {
        uint16_t lo = __builtin_tblrdl (offset);
        uint16_t hi = __builtin_tblrdh (offset);
        *pdst++ = (((uint32_t)(hi)) << 16) | ((uint32_t)(lo));
        offset += 2;
    }
}

...

uint32_t d1copy[D1_SIZE];
READ_DATA(d1copy, D1, D1_SIZE);

Điều này không đọc chính xác các giá trị 24 bit và lưu trữ chúng trong 24 bit dưới cùng của uint32_t. Biến D1 bên ngoài được khai báo trong C là biến giả chỉ được sử dụng để lấy tại địa chỉ bắt đầu bằng cách tận dụng cách trình biên dịch / trình biên dịch / trình liên kết làm việc cùng nhau. Các hàm dựng sẵn xử lý phần còn lại của công việc.

Những gì tôi không biết là làm thế nào để tự động lấy kích thước của dữ liệu, vì nó được xác định + khởi tạo trong lắp ráp.


1

Đừng chuyển đổi nó thành dấu dài và không dấu. Hỏi rắc rối. Về cơ bản bạn đang nói dối với trình biên dịch. Khai báo đúng cho nowPlay.file1 là

struct
{
    // other stuff ...
    void (*D1)(void);
    // other stuff ...
} nowPlaying;

Và tương tự cho hàm ():

extern void function(void (*file)(void));

và loại bỏ tất cả các kiểu chữ.

Hoặc, nếu @PeterJ gợi ý, đó là dữ liệu, thì nó phải được khai báo là D1 bên ngoài ngắn [] ở cả hai nơi: và bạn không thực sự cần trình biên dịch; bạn có thể đã khai báo tất cả bằng C là const D1 [] = {...}; Trình biên dịch nên đặt nó vào đoạn mã vì nó là const.


Trừ khi tôi nhớ đọc một cái gì đó D1 không phải là một con trỏ tới một hàm, dữ liệu đó sẽ được lưu trữ trong không gian mã.
PeterJ

1
@PeterJ Sau đó, nó không nên được khai báo là khoảng trống bên ngoài D1 (void), nó nên được định nghĩa là D1 ngoài ngắn []. Không ai trong số này thuyết phục tôi rằng câu hỏi không thuộc về SO.
dùng207421

Những gì OP đang nói về không thể được thể hiện bằng C, nó cần được gói gọn bởi chức năng lắp ráp có thể gọi được bằng C hoặc nội tại.
Jason S

@JasonS Không có bằng chứng nào về câu hỏi đó và OP đã không làm rõ.
dùng207421

Có, nếu bạn quen thuộc với kiến ​​trúc PIC33F / PIC33E.
Jason S

0

Có vẻ như câu trả lời đơn giản là viết chương trình con trong trình biên dịch chương trình. Nếu tôi nhớ đúng, C30 không truy cập bộ nhớ chương trình dưới dạng dữ liệu bằng cách sử dụng con trỏ 24 bit. Tốt nhất là nó có thể truy cập bộ nhớ chương trình thông qua cửa sổ PSV, nhưng sau đó bạn chỉ có thể thấy 16 bit thấp của mỗi từ bộ nhớ chương trình 24 bit.

Nếu rất đơn giản để viết một trình biên dịch chương trình biên dịch có thể gọi được từ C30, trả về 24 bit dữ liệu được cung cấp một địa chỉ bộ nhớ chương trình 24 bit. Tuy nhiên, dữ liệu của bạn có phải là tập hợp của các giá trị 24 bit hay thực sự là một danh sách các byte xảy ra được đóng gói 3 mỗi từ? Nếu sau này, nó thậm chí còn dễ dàng hơn. Viết một thường trình biên dịch chương trình cung cấp cho bạn một khung nhìn địa chỉ byte của bộ nhớ chương trình. Địa chỉ vẫn cần là 24 bit, nhưng giá trị dữ liệu bây giờ chỉ còn 8 bit.

Hoặc chỉ cần viết toàn bộ thói quen trong trình biên dịch chương trình. Nếu bạn đang thực hiện kiểu đập byte và đóng gói bộ nhớ mức thấp này, có lẽ sẽ dễ dàng hơn. Trong trình biên dịch chương trình, bạn có thể thực hiện những gì bạn muốn theo cách mà máy muốn thực hiện. Trong C, bạn phải tìm ra câu thần chú nào để lẩm bẩm trình biên dịch để nó viết mã máy cho bạn. Đôi khi nó chỉ dễ dàng hơn để làm điều đó trực tiếp. Kiến trúc DSPIC đặc biệt dễ dàng để viết mã lắp ráp, chắc chắn dễ dàng hơn PIC 16.


TBLRDL và TBLRDH là chìa khóa ở đây, cho dù bạn sử dụng lắp ráp hay các __builtin_tblrdX()chức năng. Tôi đồng ý với bạn + đã loại bỏ cụm từ của bạn "Trong C, bạn phải tìm ra câu thần chú nào để lẩm bẩm với trình biên dịch". Tuy nhiên, trớ trêu thay, nếu bạn thực sự cố gắng tăng hiệu suất tối đa, đôi khi các __builtin()chức năng lại tốt hơn, bởi vì trình biên dịch có thể tối ưu hóa cách tạo mã, trong khi nó phải xử lý các hàm lắp ráp được mã hóa bằng tay vì các hộp đen không thể thay đổi .
Jason S
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.