• Уважаемые посетители сайта esp8266.ru!
    Мы отказались от размещения рекламы на страницах форума для большего комфорта пользователей.
    Вы можете оказать посильную поддержку администрации форума. Данные средства пойдут на оплату услуг облачных провайдеров для сайта esp8266.ru
  • Система автоматизации с открытым исходным кодом на базе 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походу ничего этого нет.
 
Последнее редактирование:
Сверху Снизу