repstosw 18 9 сентября, 2023 Опубликовано 9 сентября, 2023 (изменено) · Жалоба 19 hours ago, GenaSPB said: Возможно что-то про register window, но я вроде все для этого сделал. Ну и не вполне вкурил архитектуру в части автосохранения регистров при вызовах. Ваш пример из ветки develop заработал. Но всё также - при большой вложенности функций и обилия переменных работа обрывается. Из того, что удалось сделать: переписал скрипт линкера, теперь переменные-константы (.data, .rodata) хранятся в IRAM и при запуске программы константы копируются в DRAM0/1. Неинициализированные переменные (.bss) обнуляются перед их использованием. Это всё до входа в main(). В итоге, получившийся бинарник вместо over 64K стал весить несколько байт. Также настроил стек (.stack) и кучу (.heap). На счёт повисания во вложенных функциях - нужно писать обработчик исключения переполнения регистрового окна (запись-чтение в стек, прокрутка окна). Иначе, число вложенных вызовов ограничивается. Вполне исчерпывающе объясняется здесь: https://sachin0x18.github.io/posts/demystifying-xtensa-isa/ Quote Доступ к любой ячейке памяти, кроме регистра, происходит очень медленно, и в результате сохранение/восстановление будет иметь негативное влияние на производительность. Таким образом, использование соглашения об оконном регистре экономит нам накладные расходы на такие сохранения/восстановления, а также уменьшает размер кода. Что происходит, когда есть функция, которая вызывает другую функцию, которая вызывает другую и так далее, так что окно продолжает вращаться и перемещаться, указывая на фрейм первой функции? Перезаписывает ли он данные и повреждает ли данные первой функции? Если нет, то где хранятся данные первой функции? Когда программа пытается выполнить запись в регистр, который уже содержит данные одной из родительских подпрограмм, генерируется исключение переполнения окна, и обработчик исключений переполнения окна отвечает за сохранение данных в перекрывающихся регистрах в регистре стека, прежде чем он будет перезаписан. Сам механизм довольно интересен - не хранить и восстанавливать регистры в стеке, а перемещаться по окнам. Но на большой вложенности, эта архитектура приносит проблемы. Изменено 9 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 9 сентября, 2023 Опубликовано 9 сентября, 2023 (изменено) · Жалоба Кстати, спасибо за последнюю картинку. Она здорово объясняет. Прояснилось теперь. Хотя референс мануал по архитектуре зачитал до дыр. Изменено 9 сентября, 2023 пользователем GenaSPB Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 9 сентября, 2023 Опубликовано 9 сентября, 2023 (изменено) · Жалоба 27 minutes ago, GenaSPB said: Прояснилось теперь. Хотя референс мануал по архитектуре зачитал до дыр. Сделал обработку исключений переполнения регистрового окна. Вложенные вызовы заработали. Сейчас тестирую. Попутно заставил работать штатные malloc/free, strcpy/sprintf. Пришлось дописать некоторые вещи (__getreent, _sbrk, _sbrk_r), потому что часть стандартных библиотек этого компилятора ориентированы на RTOS (многозадачность) и для BareMetal не годятся. Изменено 9 сентября, 2023 пользователем repstosw 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 9 сентября, 2023 Опубликовано 9 сентября, 2023 (изменено) · Жалоба Из стартапа call0 работает? Изменено 9 сентября, 2023 пользователем GenaSPB Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 9 сентября, 2023 Опубликовано 9 сентября, 2023 (изменено) · Жалоба 17 hours ago, GenaSPB said: Из стартапа call0 работает? Работает. Но на возврат обратно в стартап не проверял, так как мне это не нужно. 18 hours ago, repstosw said: Сейчас тестирую. Оттестировал. Работает на оптимизациях: -Ofast, -O3, -O2. На остальных не работает. Пришлось 6 обработчиков исключений использовать. Подробности в комментариях в коде. HiFi4_app.zip Смещения обработчиков исключений: Window exception handlers Exception Offset WindowOverflow4 0x000 WindowUnderflow4 0x040 WindowOverflow8 0x080 WindowUnderflow8 0x0C0 WindowOverflow12 0x100 WindowUnderflow12 0x140 Actually useful exception handlers Exception Offset UserException 0x340 Level2Interrupt 0x180 Level3Interrupt 0x1c0 Less useful exception handlers Exception Offset Level4Interrupt 0x200 Level5Interrupt 0x240 DebugException 0x2c0 NMIException 0x300 KernelException 0x340 DoubleException 0x3c0 Reset 0x400 Должно работать вот так: UART и AVS_TIMER должны быть проинициализированы T113-s3! ❗ Изменено 10 сентября, 2023 пользователем repstosw 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 9 сентября, 2023 Опубликовано 9 сентября, 2023 (изменено) · Жалоба С какого адреса запускать? Что пишется в DSP0_CFG->DSP_ALT_RESET_VEC_REG Ответ 0x00028800 upd: но с кешированной памятью перестало работать Изменено 9 сентября, 2023 пользователем GenaSPB Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 49 9 сентября, 2023 Опубликовано 9 сентября, 2023 · Жалоба 2 часа назад, GenaSPB сказал: С какого адреса запускать? Что пишется в DSP0_CFG->DSP_ALT_RESET_VEC_REG Не подскажете, где в ваших исходниках идет загрузка программы дсп в память и ее запуск? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 9 сентября, 2023 Опубликовано 9 сентября, 2023 (изменено) · Жалоба Поищите в tests.c использование процитированного регистра. Бранч develop Изменено 9 сентября, 2023 пользователем GenaSPB Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 49 9 сентября, 2023 Опубликовано 9 сентября, 2023 · Жалоба 28 минут назад, GenaSPB сказал: Поищите в tests.c и Нашел, спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 10 сентября, 2023 Опубликовано 10 сентября, 2023 (изменено) · Жалоба 9 hours ago, GenaSPB said: С какого адреса запускать? Что пишется в DSP0_CFG->DSP_ALT_RESET_VEC_REG Ответ 0x00028800 Я запускаю с адреса 0x28000: Там стоит прыжок на 0x28800. Ниже инструкции прыжка - таблица литералов. Она должна быть в самом начале, перед использованием имён переменных. Сдвинуть её не получается - линковщик сыпет dangerous rellocations of literals L32R. С адреса 0x28800 - стартап: В стартапе - минимальный инит и прыжок на сишную функцию libc_init. А из неё - вызов в main. Обратите внимание - этот DSP не загружает адреса в прямом виде - он их берёт из таблицы литералов: l32r a2, 0x20028004 //литерал wsr.vecbase a2 Содержимое памяти по адресу 20028004 : 20028400 20028400 - стартовый адрес векторов исключений (определён hifi4.ld) Карта памяти: 1) 0x28000 : прыжок на код на 0x28800 2) Таблица литералов 3) Таблица векторов исключений (не все!) 4) 0x28800: стартап: инит, libc_init, main,... 9 hours ago, GenaSPB said: upd: но с кешированной памятью перестало работать Это который 0x20028000 ? Проверил - работает. В скрипте линкера переправил адреса: И задал загрузку/старт со стороны T113-s3: 0x20028000 sunxi_dsp_init(main_bin /*адрес бинарника*/ ,0x20028000 /*куда грузить*/ ,0 /*номер DSP*/ ,sizeof(main_bin) /*размер бинарника*/); Результат: 9 hours ago, GenaSPB said: upd: но с кешированной памятью перестало работать Проверил с вашим вариантом - да, НЕ работает! С вариантом загрузчика из uboot-driver - работает. sunxi_dsp_init(main_bin /*адрес бинарника*/ ,0x20028000 /*куда грузить*/ ,0 /*номер DSP*/ ,sizeof(main_bin) /*размер бинарника*/); Мой вариант загрузки: dsp.c sunxi_dsp_init( ) - переделанный вариант от uboot-driver tututu( ) - вариант от GenaSPB Изменено 10 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 49 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 4 часа назад, repstosw сказал: Это который 0x20028000 ? Проверил - работает. А здесь не надо двойку добавлять? #define DSP0_IRAM /*0x00400000*/ 0x00028000 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 1 hour ago, mantech said: А здесь не надо двойку добавлять? #define DSP0_IRAM /*0x00400000*/ 0x00028000 Не нужно тут добавлять. Это адрес со стороны T113-s3. Указание кешированных адресов важно только с точки зрения DSP - как он их видит. 16 hours ago, repstosw said: Работает на оптимизациях: -Ofast, -O3, -O2. На остальных не работает. Проблема была в libc_init, подправил. Теперь работает на всех оптимизациях, в том числе и на : -Os, -O0, -O1. Вылезла новая проблема: alloca() на нулевом уровне оптимизации завершается аварийно. Покурил, нужно в исключении пользователя UserException (IntLevel1) отлавливать обращение к инструкции movsp и городить сложный обработчик - тоже щёлкать стеком. В моём стартапе код для alloca() есть, но он не заведен в UserException. И там не только alloca, но ещё и другие способы обширных аллокаций из стека: https://chromium.googlesource.com/chromiumos/third_party/sound-open-firmware/+/5b43730e8620c60b4170231f7e9d91d2d2d89652/src/arch/xtensa/up/xtos/exc-alloca-handler.S Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 49 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 2 часа назад, repstosw сказал: Не нужно тут добавлять. Это адрес со стороны T113-s3. Понял, спасибо. 2 часа назад, repstosw сказал: И там не только alloca, но ещё и другие способы Там еще есть много асмового кода, в частности по прерываниям, но чет уж много очень, что там за контроллер прерываний такой, походу сложный(( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 10 сентября, 2023 Опубликовано 10 сентября, 2023 · Жалоба 2 hours ago, repstosw said: Проблема была в libc_init, подправил volatile? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 11 сентября, 2023 Опубликовано 11 сентября, 2023 (изменено) · Жалоба 15 hours ago, GenaSPB said: volatile? Нет. Цикл копирования из LMA в VMA. Вот так будет работать на любой оптимизации: extern char _sidata,_sdata,_edata; //set by linker extern char _sbss,_ebss; //set by linker void libc_init(void) { memcpy(&_sdata,&_sidata,&_edata-&_sdata); //copy LMA to VMA memset(&_sbss,0,&_ebss-&_sbss); //clear BSS main(); } Заставил работать функции rand(), srand(). Для этого подправил ещё одну функцию: struct _reent *_EXFUN(__getreent,(void)) { static struct _reent REENT; //memory space for srand() & rand() return &REENT; } 15 hours ago, mantech said: Там еще есть много асмового кода, в частности по прерываниям, но чет уж много очень, что там за контроллер прерываний такой, походу сложный(( Второй день бьюсь над тем, чтобы заставить DSP нормально выдавать прерывание. Вначале пытался сделать UserException, затем пока временно оставил его и начал возиться с таймерами DSP. Таймеры работают. Пара функций: void Timer_Init(void) { u32 ccount=0; __asm__ __volatile__ ("rsr.ccount %0" : "=r"(ccount)); ccount+=7506204; __asm__ __volatile__ ("wsr.ccompare0 %0" :: "r"(ccount)); ccount+=7506204; __asm__ __volatile__ ("wsr.ccompare1 %0" :: "r"(ccount)); u32 intenable; __asm__ __volatile__ ("rsr.intenable %0" : "=r"(intenable)); intenable|=(1<<2); //бит 1 - timer1, бит 2 - timer 0 __asm__ __volatile__ ("wsr.intenable %0" :: "r"(intenable)); } u32 Timer_Get(void) { u32 ccount; __asm__ __volatile__ ("rsr.ccount %0" : "=r"(ccount)); return ccount; } При разрешении прерывания от таймера (биты 1,2 в регистре intenable) при достижении таймера до значения ccompare0,1 должно происходить прерывание. Но программа зависает. Причем время до зависания зависит от - ccompare0,1 : тоесть я делаю вывод, что прерывание именно от таймера по достижении значения. Но почему оно не работает? Причём, я определил все вектора прерываний с адресов 0x180 до 0x3C0 (шаг +64): просто поставил команду перехода в код выдачи байта по UART: .org 0x180 j OutChar .org 0x1C0 j OutChar //... .org 0x340 //UserException j OutChar .org 0x380 j OutChar .org 0x3C0 j OutChar //... #define UART_NUMBER 3 /* UART Number: 0..5 */ #define UART_BASE (0x02500000+(0x400*UART_NUMBER)) #define UART_THR (UART_BASE+0x00) /* transmit holding register */ OutChar: movi a8,UART_THR movi a9,101 memw s32i.n a9,a8,0 Loop: j Loop Но символ не печатается из прерывания. Отдельно проверял код с метки OutChar - он работает. Со стороны T113-s3 проверил статус из регистра - DSP_STAT_REG : значение 2 - BIT_PFAULT_ERROR. В нормальном состоянии должно быть =0 . Всё сложно. При этом обработчики исключений переключения окна (смещения 0 ... 0x140 от базы вектров прерываний - задан в регистре vecbase) работают нормально. Что я делаю не так? Чего не хватает, чтобы заработало прерывание таймера? Изменено 11 сентября, 2023 пользователем repstosw Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться