2011-02-10 27 views
5

Tôi có một số dữ liệu liên tục mà tôi muốn lưu trữ trong ROM vì có một số tiền hợp lý và tôi đang làm việc với thiết bị được gắn với bộ nhớ ARM7 bị hạn chế về bộ nhớ. Tôi đang cố gắng để làm điều này sử dụng cấu trúc giống như thế này:lưu trữ cấu trúc trong ROM trên thiết bị ARM

struct objdef 
{ 
    int x; 
    int y; 
    bool (*function_ptr)(int); 
    some_other_struct * const struct_array; // array of similar structures 
    const void* vp; // previously ommittted to shorten code 
} 

mà tôi sau đó tạo và khởi tạo như globals:

const objdef def_instance = { 2, 3, function, array, NULL }; 

Tuy nhiên, điều này ngốn khá nhiều RAM mặc dù const ngay từ đầu. Cụ thể hơn, nó làm tăng đáng kể lượng dữ liệu RW và cuối cùng làm cho thiết bị bị khóa nếu đủ trường hợp được tạo ra.

Tôi đang sử dụng uVision và trình biên dịch ARM, cùng với nhân RTX thời gian thực.

Có ai biết tại sao điều này không hoạt động hoặc biết cách tốt hơn để lưu trữ dữ liệu có cấu trúc không đồng nhất trong ROM?

Cập nhật

Cảm ơn tất cả các bạn cho câu trả lời của bạn và lời xin lỗi của tôi vì đã không liên lạc lại với các bạn trước đó. Vì vậy, đây là điểm số cho đến nay và một số quan sát bổ sung về phía tôi.

Đáng buồn thay, __attribute__ không ảnh hưởng đến RAM so với ROM và điều tương tự cũng xảy ra với static const. Tôi chưa có thời gian để thử tuyến đường lắp ráp.

Đồng nghiệp của tôi và tôi đã phát hiện ra một số hành vi bất thường hơn.

Trước tiên, tôi phải lưu ý rằng vì mục đích đơn giản, tôi đã không đề cập đến cấu trúc objdef của tôi có chứa trường const void*. Các lĩnh vực đôi khi được gán một giá trị từ một bảng chuỗi định nghĩa là

char const * const string_table [ROWS][COLS] = 
{ 
    { "row1_1", "row1_2", "row1_3" }, 
    { "row2_1", "row2_2", "row2_3" }, 
... 
} 

const objdef def_instance = { 2, 3, function, array, NULL };//->ROM 
const objdef def_instance = { 2, 3, function, array, string_table[0][0] };//->RAM 

string_table là trong ROM như mong đợi. Và đây là kicker: các trường hợp của objdef được đưa vào ROM cho đến khi một trong các giá trị trong string_table được gán cho trường const void* đó. Sau đó, cá thể struct được chuyển sang RAM.

Nhưng khi string_table được thay đổi để

char const string_table [ROWS][COLS][MAX_CHARS] = 
{ 
    { "row1_1", "row1_2", "row1_3" }, 
    { "row2_1", "row2_2", "row2_3" }, 
... 
} 

const objdef def_instance = { 2, 3,function, array, NULL };//->ROM 
const objdef def_instance = { 2, 3, function, array, string_table[0][0] };//->ROM 

những trường hợp objdef được đặt trong ROM mặc dù trước đó const void* assigment. Tôi không biết tại sao điều này lại quan trọng.

Tôi bắt đầu nghi ngờ rằng Dan nói đúng và cấu hình của chúng tôi bị rối ở đâu đó.

+0

Hãy thử khai báo là 'static const'. Tôi nhận thấy một số trình biên dịch sẽ sao chép dữ liệu từ ROM để ngăn xếp khi nó chỉ được khai báo là 'const'; truy cập trực tiếp vào ROM xảy ra khi 'static const' được áp dụng. –

+0

C++ 'const' không có nghĩa là" chỉ đọc thực ". Bạn có thể có const_cast, cho một điều .. –

+0

Tôi biết bạn luôn có thể thực hiện một const_cast, nhưng tôi đã xem qua một số tài nguyên trên web đã đề xuất sử dụng 'const' để lấy dữ liệu được lưu trữ trong ROM. Ngoài ra, tôi đã học được thông qua kinh nghiệm rằng 'const' đôi khi nhưng không phải lúc nào cũng có hiệu ứng này. Rõ ràng là tôi không hoàn toàn rõ ràng về thời điểm hoặc lý do. :) – dandan78

Trả lời

1

Bạn luôn có thể thử sử dụng ngôn ngữ lắp ráp.

Đặt thông tin bằng cách sử dụng các báo cáo DATA và xuất bản (công khai) địa chỉ xuất phát của dữ liệu.

Theo kinh nghiệm của tôi, dữ liệu chỉ đọc lớn được khai báo trong tệp nguồn là static const. Một hàm toàn cục đơn giản bên trong tệp nguồn sẽ trả về địa chỉ của dữ liệu.

+0

Tôi sẽ thử cả hai đề xuất đầu tiên vào buổi sáng. Cảm ơn. – dandan78

+0

Phần .data thường đọc dữ liệu ghi vì vậy điều này sẽ luôn được tải vào ram – doron

1

Tôi giả sử bạn có một tệp phân tán tách các phần RAM và ROM của bạn.Những gì bạn muốn làm là chỉ định cấu trúc của bạn với một thuộc tính cho phần nào sẽ được đặt, hoặc đặt nó trong tệp đối tượng riêng của nó và sau đó xác định rằng trong phần bạn muốn nó nằm trong tệp phân tán.

__attribute__((section("ROM"))) const objdef def_instance = { 2, 3, function, array }; 

Từ khóa C "const" không thực sự khiến trình biên dịch đưa nội dung vào phần văn bản hoặc phần const. Nó chỉ cho phép trình biên dịch cảnh báo bạn về các nỗ lực sửa đổi nó. Nó hoàn toàn hợp lệ để có được một con trỏ đến một đối tượng const, đưa nó vào một non-const, và ghi vào nó, và trình biên dịch cần hỗ trợ điều đó.

+0

Có, tôi có tệp phân tán và tôi tin rằng nó được thiết lập đúng cách. Tôi sẽ kiểm tra lại và thử giải pháp của bạn. Cảm ơn. – dandan78

+1

nó không phải là "hoàn toàn hợp lệ". Đó là hành vi Undefined, và một trình biên dịch có mọi quyền đặt một biến 'const' trong ROM. – MSalters

1

Nếu bạn đang làm công cụ trên ARM, bạn có thể đang sử dụng định dạng nhị phân ELF. Các tệp ELF chứa một số phần nhưng dữ liệu không đổi sẽ tìm đường vào phần .rodata hoặc .text của nhị phân ELF. Bạn có thể kiểm tra điều này bằng tiện ích GNU readelf hoặc tiện ích RVCT fromelf.

Bây giờ giả sử các ký hiệu của bạn tìm thấy chính xác trong phần chính xác của tệp elf, bây giờ bạn cần phải tìm hiểu cách trình tải RTX thực hiện công việc của nó. Cũng không có lý do tại sao các cá thể không thể chia sẻ cùng một bộ nhớ chỉ đọc nhưng điều này sẽ phụ thuộc vào bộ nạp. Nếu tệp thực thi được lưu trữ trong rom, nó có thể được chạy tại chỗ nhưng vẫn có thể được nạp vào RAM. Điều này cũng phụ thuộc vào bộ nạp.

+0

Tôi đang sử dụng uVision và trình biên dịch ARM trên Windows và cài đặt Cygwin không phải là thứ tôi muốn làm trên máy phát triển của mình. Tôi chỉ cần kiểm tra thư mục đầu ra của tôi và không có .elf. Những gì tôi có là một thùng, mà tôi có thể tải lên trực tiếp từ uVision hoặc sử dụng bộ nạp khởi động tùy chỉnh trên thiết bị. – dandan78

2

Suy nghĩ của bạn là chính xác và hợp lý. Tôi đã sử dụng Keil/uVision (đây là v3, có lẽ cách đây 3 năm?) Và nó luôn hoạt động như bạn mong đợi, tức là nó đặt dữ liệu const vào flash/ROM.

Tôi nghi ngờ cấu hình/tập lệnh liên kết của bạn. Tôi sẽ cố gắng quay lại công việc cũ của mình & xem cách tôi đã định cấu hình nó. Tôi không phải thêm chỉ thị #pragma hoặc __attribute__, tôi chỉ cần đặt nó .const & .text trong flash/ROM. Tôi đã thiết lập bản đồ cấu hình/bộ nhớ liên kết khá lâu trước đây, vì vậy thật không may, việc thu hồi của tôi không phải là rất mới mẻ.

(Tôi hơi bối rối bởi những người đang nói về việc đúc & con trỏ const, v.v ... Bạn không hỏi bất cứ điều gì về điều đó & bạn dường như hiểu cách "const" hoạt động. Bạn muốn đặt dữ liệu khởi tạo trong flash/ROM để tiết kiệm RAM (không phải ROM-> RAM khi khởi động), chưa kể đến một chút tăng tốc lúc khởi động, phải không? Bạn không hỏi liệu có thể thay đổi nó hay bất cứ thứ gì ...)

EDIT/UPDATE:

tôi chỉ nhận thấy trường cuối cùng trong (const) struct của bạn là một (không đổi con trỏ some_other_struct * const đến một some_other_ struct). Bạn có thể muốn thử biến con trỏ thành hằng số (hằng số) thành hằng số some_other_struct [some_other_struct const * const] (giả sử nó trỏ đến thực sự là hằng số). Trong trường hợp đó, nó có thể hoạt động. Tôi không nhớ các chi tiết cụ thể (xem một chủ đề ở đây?), Nhưng điều này dường như bắt đầu có vẻ quen thuộc. Ngay cả khi mục tiêu con trỏ của bạn không phải là mục const và cuối cùng bạn không thể thực hiện việc này, hãy thử thay đổi định nghĩa struct & khởi tạo nó bằng con trỏ tới const và chỉ xem liệu nó có rơi vào ROM hay không. Mặc dù bạn có nó như một con trỏ const và nó không thể thay đổi khi cấu trúc được xây dựng, tôi dường như nhớ cái gì đó nếu mục tiêu không phải là const, mối liên kết không nghĩ rằng nó có thể được khởi tạo hoàn toàn tại thời gian liên kết & sẽ tắt khởi tạo khi mã khởi động thời gian chạy C được thực hiện, bao gồm. bản sao ROM sang RAM của bộ nhớ RW khởi tạo.

+0

Cảm ơn, tôi đã thử con trỏ const để tiếp cận kiểu const là tốt, nhưng không có may mắn. Tuy nhiên, hành vi kỳ lạ khác đã được quan sát. Kiểm tra cập nhật của tôi cho câu hỏi khi bạn có thể. – dandan78

0

Một ví dụ hoàn chỉnh sẽ là tốt nhất.Nếu tôi mất một cái gì đó như thế này:

 
typedef struct 
{ 
    char a; 
    char b; 
} some_other_struct; 

struct objdef 
{ 
    int x; 
    int y; 
    const some_other_struct * struct_array; 
}; 

typedef struct 
{ 
    int x; 
    int y; 
    const some_other_struct * struct_array; 
} tobjdef; 


const some_other_struct def_other = {4,5}; 
const struct objdef def_instance = { 2, 3, &def_other}; 
const tobjdef tdef_instance = { 2, 3, &def_other}; 

unsigned int read_write=7; 

Và biên dịch nó với CodeSourcery mới nhất Lite

 
arm-none-linux-gnueabi-gcc -S struct.c 

tôi nhận được

 
    .arch armv5te 
    .fpu softvfp 
    .eabi_attribute 20, 1 
    .eabi_attribute 21, 1 
    .eabi_attribute 23, 3 
    .eabi_attribute 24, 1 
    .eabi_attribute 25, 1 
    .eabi_attribute 26, 2 
    .eabi_attribute 30, 6 
    .eabi_attribute 18, 4 
    .file "struct.c" 
    .global def_other 
    .section .rodata 
    .align 2 
    .type def_other, %object 
    .size def_other, 2 
def_other: 
    .byte 4 
    .byte 5 
    .global def_instance 
    .align 2 
    .type def_instance, %object 
    .size def_instance, 12 
def_instance: 
    .word 2 
    .word 3 
    .word def_other 
    .global tdef_instance 
    .align 2 
    .type tdef_instance, %object 
    .size tdef_instance, 12 
tdef_instance: 
    .word 2 
    .word 3 
    .word def_other 
    .global read_write 
    .data 
    .align 2 
    .type read_write, %object 
    .size read_write, 4 
read_write: 
    .word 7 
    .ident "GCC: (Sourcery G++ Lite 2010.09-50) 4.5.1" 
    .section .note.GNU-stack,"",%progbits 

Với phần đánh dấu là .rodata, mà tôi sẽ giả định khao khát. Sau đó, nó là đến kịch bản liên kết để đảm bảo rằng dữ liệu ro được đặt trong rom. Và lưu ý biến read_write là sau khi chuyển từ .rodata sang .data được đọc/ghi.

Vì vậy, để thực hiện điều này một nhị phân đầy đủ và xem nếu nó được đặt trong rom hoặc ram (.text hoặc .data) sau đó

start.s

 

.globl _start 
_start: 
    b reset 
    b hang 
    b hang 
    b hang 

    b hang 
    b hang 
    b hang 
    b hang 

reset: 
hang: b hang 

Sau đó

 
# arm-none-linux-gnueabi-gcc -c -o struct.o struct.c 
# arm-none-linux-gnueabi-as -o start.o start.s 
# arm-none-linux-gnueabi-ld -Ttext=0 -Tdata=0x1000 start.o struct.o -o struct.elf 
# arm-none-linux-gnueabi-objdump -D struct.elf > struct.list 

Và chúng tôi nhận được

 

Disassembly of section .text: 

00000000 <_start>: 
    0: ea000006 b 20 <reset> 
    4: ea000008 b 2c <hang> 
    8: ea000007 b 2c <hang> 
    c: ea000006 b 2c <hang> 
    10: ea000005 b 2c <hang> 
    14: ea000004 b 2c <hang> 
    18: ea000003 b 2c <hang> 
    1c: ea000002 b 2c <hang> 

00000020 <reset>: 
    20: e59f0008 ldr r0, [pc, #8] ; 30 <hang+0x4> 
    24: e5901000 ldr r1, [r0] 
    28: e5801000 str r1, [r0] 

0000002c <hang>: 
    2c: eafffffe b 2c <hang> 
    30: 00001000 andeq r1, r0, r0 

Disassembly of section .data: 

00001000 <read_write>: 
    1000: 00000007 andeq r0, r0, r7 

Disassembly of section .rodata: 

00000034 <def_other>: 
    34: 00000504 andeq r0, r0, r4, lsl #10 

00000038 <def_instance>: 
    38: 00000002 andeq r0, r0, r2 
    3c: 00000003 andeq r0, r0, r3 
    40: 00000034 andeq r0, r0, r4, lsr r0 

00000044 <tdef_instance>: 
    44: 00000002 andeq r0, r0, r2 
    48: 00000003 andeq r0, r0, r3 
    4c: 00000034 andeq r0, r0, r4, lsr r0 

Và điều đó đã đạt được kết quả mong muốn. Biến read_write nằm trong ram, các cấu trúc nằm trong rom. Cần phải chắc chắn rằng cả hai khai báo const đều ở đúng vị trí, trình biên dịch không đưa ra cảnh báo về việc đặt một const trên một số con trỏ tới cấu trúc khác mà nó không thể xác định tại thời gian biên dịch như là một const, và thậm chí với tất cả kịch bản trình liên kết (nếu bạn sử dụng một) để làm việc như mong muốn có thể mất một chút công sức. ví dụ: công cụ này dường như hoạt động:

 

MEMORY 
{ 
    bob(RX) : ORIGIN = 0x0000000, LENGTH = 0x8000 
    ted(WAIL) : ORIGIN = 0x2000000, LENGTH = 0x8000 
} 

SECTIONS 
{ 
    .text : { *(.text*) } > bob 
    .data : { *(.data*) } > ted 
} 

+0

Việc đăng toàn bộ phần mã sẽ là một phần lớn đối với hầu hết mọi người, đó là lý do tại sao tôi đưa ra một phiên bản ngưng tụ thể hiện cùng một vấn đề. Bên cạnh đó, tôi tin rằng ví dụ của bạn dựa trên chuỗi công cụ GNU. Tôi đang sử dụng cái được cung cấp bởi ARM. – dandan78

+0

Của tôi xấu, xin lỗi, didnt xem tham khảo trình biên dịch cánh tay. Trình biên dịch cánh tay nào? Keil? RVCT? hoặc ADS cũ hơn hoặc trước đó tôi không thể nhớ tên của nó (SBT?). Ít nhất trong những ngày ADS hỗ trợ kỹ thuật ARM rất tốt (cần thiết để có được một cái gì đó cho tiền trả cho những công cụ). họ có cung cấp thông tin chi tiết nào không? –

Các vấn đề liên quan