• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

rodata и RAM

Sermus

New member
Господа, есть ли у кого-нибудь идеи возможно ли на ESP8266 сделать так, чтобы константные данные, ну например const uint16_t buf[]={...} можно было использовать напрямую из флеша, не отображая их в RAM? Это вообще возможно?
 

Andy Korg

Moderator
Команда форума
использовать напрямую из флеша, не отображая их в RAM
Вроде как нет. Только загрузка по мере использования "руками", но могу и ошибаться, спец по чипу из меня еще тот.
В прошивке pvvx есть такой код:
Код:
Указание компилятору сунуть строку HTTPsfupload во flash память:
const uint8 HTTPsfupload[] ICACHE_RODATA_ATTR = "<html><body...../html>";
#define sizeHTTPsfupload 220
и ниже
Код:
        Достаем ручками из флаша.
        .....
        pdata = (uint32)((void *)HTTPsfupload);
        size = sizeHTTPsfupload;
        break;
    }
    if(pdata != 0 && size != 0) {
        spi_flash_read_array(pdata&MASK_ADDR_FLASH_ICACHE_DATA, pbuf, size);
....
Одно время у меня было заблуждение, что xtensa имеет гарвардскую архитектуру памяти, но я ошибался :)
 

Andy Korg

Moderator
Команда форума
Хм, а как его потом обратно выпинуть из RAM?
ээээ... не понял вопроса. Вроде как это константа и по определению она не изменяется, зачем ее обратно переписывать?
Анекдот вспомнился: "Я скачала файл из интернета, он мне больше не нужен, как закачать его обратно? :)
 

pvvx

Активный участник сообщества
В прошивке pvvx есть такой код...
А дальше и так
Код:
#define tcp_puts_fd(fmt, ...) do { \
        static const char flash_str[] ICACHE_RODATA_ATTR = fmt;    \
        web_conn->msgbuflen += os_sprintf(&web_conn->msgbuf[web_conn->msgbuflen], ets_strcpy(UartDev.rcv_buff.pRcvMsgBuff, flash_str), ##__VA_ARGS__); \
        } while(0)
#define tcp_strcpy_fd(fmt) do { \
        static const char flash_str[] ICACHE_RODATA_ATTR = fmt;    \
        web_conn->msgbuflen += ets_strlen(ets_strcpy(&web_conn->msgbuf[web_conn->msgbuflen], ets_strcpy(UartDev.rcv_buff.pRcvMsgBuff, flash_str))); \
        } while(0)
Чтобы такое
Код:
tcp_puts_fd("HTTP/1.1 %u %s\r\nServer: " WEB_NAME_VERSION "\r\nConnection: close\r\n", CurResp->status, CurResp->headers);
помещало во flash.
Но тут, для перетусовки, используется пустой буфер UART UartDev.rcv_buff.pRcvMsgBuff оставшийся от BIOS в её сегменте данных. Он 256 + 100 байт. Жалко что пропадает :)
ets_strcpy() находится в ROM и может обращаться к данным во Flash, не вызывая "протектед" и она там сама align(4) делает....
Прямой вызов os_sprintf (и многих других процедур) c указанием строки во flash = "протектед".
Там раздают $200 баксов за ошибки в SDK - таких ошибок в SDK море :) Когда будут давать от $5000 за одну - я им 1000 ошибок официально пришлю, и если не заплатят, то истрачу аналогичную сумму на закрытие данной конторы :)
 
Последнее редактирование:

Sermus

New member
зачем ее обратно переписывать
Я может не правильно понял суть фокуса. Я думал эта конструкция заставляет ESP не маппить этот массив в RAM сразу, а сделать это позже. Если это так, то без возможности отменить этот маппинг, это очень сомнительная фича, ведь если в конце концов все эти данные все равно окажутся в RAM это почти то же самое, как если бы я их вначале все туда загрузил. Какая разница когда я подойду к моменту "кончилась RAM" в начале или чуть попозже, когда мне эти данные каждый по разу понадобятся? Вот если бы у меня была возможность подтянуть данные, а потом выкинуть их из RAM, была бы польза. С другой стороны, чем тогда этот фокус отличается от динамического выделения + инициализации данными из flash и последующим освобождением?
 

Andy Korg

Moderator
Команда форума

Sermus

New member
это он и есть на мой взгляд.
Так если можно сделать os_malloc + заполнить из флэша, а потом еще и os_free, оно удобнее получается, я хотя бы могу когда мне данные не нужны будут память обратно получить, а тут уже не могу. Где и что я не понимаю?
 

Andy Korg

Moderator
Команда форума
если вы про этот пример:
pdata = (uint32)((void *)HTTPsfupload);
то я там не привел объявление pbuf поскольку считал что в контексте обсуждения это не важно. На самом деле pbuf это локальный массив объявленный так;
uint8 pbuf[mMAX(sizeHTTPdefault,sizeHTTPsfupload)]; Поэтому память освобождается "автоматически"
 

pvvx

Активный участник сообщества
Ах вон оно что. Все, теперь картинка сложилась, спасибо.
Но есть ещё беда - почему-то одинаковые стринги в ICACHE_RODATA_ATTR компилятор не видит и дублирует. Возможно какая опция ещё нужна...
Но вся ICACHE_RODATA заполнена одинаковыми сообщениями из SDK:
Код:
0002D240:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D250:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D260:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D270:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D280:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D290:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D2A0:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D2B0:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D2C0:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D2D0:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D2E0:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D2F0:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D300:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D310:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D320:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D330:  25 73 20 25│75 0A 00 00│25 73 20 25│75 0A 00 00  %s %u◙  %s %u◙
0002D340:  25 73 20 25│75 0A 00 00│00 00 00 00│00 00 00 00  %s %u◙
Т.е. китайцам всё равно и они это даже не смотрели....

Как-бы продолжение, про это всё, является организация оверлеев в IRAM. Но народ протестует :)
Загружаем оверлей, он инит себе кусок памяти в heap (если оно ему надо) и исполняется. По исполнению память в heap высвобождается, а в ту память IARM загружается другой оверлей... И т.д. Ядро у ESP8266 всё равно одно и всё исполняется последовательно.
 
Последнее редактирование:

Andy Korg

Moderator
Команда форума
вся ICACHE_RODATA заполнена одинаковыми сообщениями из SDK
У меня небольшой опыт в компиляторах си, но вроде бы ни один компилятор и не пытается анализировать константные строки на предмет повторения. Может быть китайцы наобъявляли кучу одинаковых стрингов, например в разных модулях.
 

pvvx

Активный участник сообщества
У меня небольшой опыт в компиляторах си, но вроде бы ни один компилятор и не пытается анализировать константные строки на предмет повторения. Может быть китайцы наобъявляли кучу одинаковых стрингов, например в разных модулях.
Любой компилятор это делает.
Найдите в rodata одинаковые стринги. Именно по этому и использовалась разбивка имен переменных на одинаковые куски - чтобы не следить за их количеством - компилятор сам слинкует в один адрес одинаковые. Иногда даже по концовке текста некоторые объединяют. Типа "Hello!" и "o!" будет один стринг в памяти, но указатели разные...
Сложнее только скопмилировать разные процедуры в один исполняемый адрес :). Как раз это и надо для оверлеев... и не все компиляторы это поддерживают "элегантно" :)
С текущим UDK пока не справился... надо время на это.

Даже такие константы объединяются по всей прошивке (но возможно, и если находятся только в одной либе - не проверял):
Код:
40269fe7:  5d9401    l32r  a0, 40241638 <system_get_checksum+0x3c>
40269fea:  0000c0    callx0  a0
Тут константа грузится с адреса 40241638, а код её сидит в 40269fe7. Интересночто говорит об этом кеш? Некоторые процедуры грузят константы со всей области flash. А они должны быть закешированы или будет лишнее чтение кеша… короче - тормоз. По этому очень сложный “профайллер” в Xplorer-3.0.1 cоптимизацией по кешу… а в UDKпоходу ничего этого нет.
 
Последнее редактирование:
Сверху Снизу