Перейти к содержанию
    

Allwinner T113-s3 уделал HiFi4 DSP. Смеяться или плакать?

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

Доступ к любой ячейке памяти, кроме регистра, происходит очень медленно, и в результате сохранение/восстановление будет иметь негативное влияние на производительность. Таким образом, использование соглашения об оконном регистре экономит нам накладные расходы на такие сохранения/восстановления, а также уменьшает размер кода. Что происходит, когда есть функция, которая вызывает другую функцию, которая вызывает другую и так далее, так что окно продолжает вращаться и перемещаться, указывая на фрейм первой функции? Перезаписывает ли он данные и повреждает ли данные первой функции? Если нет, то где хранятся данные первой функции?

Когда программа пытается выполнить запись в регистр, который уже содержит данные одной из родительских подпрограмм, генерируется исключение переполнения окна, и обработчик исключений переполнения окна отвечает за сохранение данных в перекрывающихся регистрах в регистре стека, прежде чем он будет перезаписан.

image.thumb.png.3120bea12f9fdad17d725d4fb90daccf.png

Сам механизм довольно интересен - не хранить и восстанавливать регистры в стеке, а перемещаться по окнам.

image.thumb.png.3406d7cc7599d37eb94cde01ec9fd89c.png

Но на большой вложенности, эта архитектура приносит проблемы.

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Кстати, спасибо за последнюю картинку. Она здорово объясняет. Прояснилось теперь. Хотя референс мануал по архитектуре зачитал до дыр.

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

27 minutes ago, GenaSPB said:

Прояснилось теперь. Хотя референс мануал по архитектуре зачитал до дыр.

Сделал обработку исключений переполнения регистрового окна.   Вложенные вызовы заработали.  Сейчас тестирую.

Попутно заставил работать штатные malloc/free, strcpy/sprintf.   Пришлось дописать некоторые вещи (__getreent, _sbrk, _sbrk_r), потому что часть стандартных библиотек этого компилятора ориентированы на RTOS (многозадачность) и для BareMetal не годятся.

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Из стартапа call0 работает?

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Должно работать вот так:

image.png.496e7231a50582d670811e5fd9348c40.png

UART и AVS_TIMER должны быть проинициализированы T113-s3!

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

С какого адреса запускать? Что пишется в DSP0_CFG->DSP_ALT_RESET_VEC_REG

 

Ответ 0x00028800

upd: но с кешированной памятью перестало работать

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, GenaSPB сказал:

С какого адреса запускать? Что пишется в DSP0_CFG->DSP_ALT_RESET_VEC_REG

Не подскажете, где в ваших исходниках идет загрузка программы дсп в память и ее запуск?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поищите в tests.c использование процитированного регистра.

Бранч develop

Изменено пользователем GenaSPB

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

9 hours ago, GenaSPB said:

С какого адреса запускать? Что пишется в DSP0_CFG->DSP_ALT_RESET_VEC_REG

 

Ответ 0x00028800

Я запускаю с адреса 0x28000:

image.png.4687cdbeea389fa1e4d728b91c67fc7b.png

Там стоит прыжок на 0x28800.  Ниже инструкции прыжка - таблица литералов. Она должна быть в самом начале, перед использованием имён переменных.

Сдвинуть её не получается - линковщик сыпет dangerous rellocations of literals L32R.

С адреса 0x28800 - стартап:

image.png.5ed796becd0f127e41924597be16cf2c.png

В стартапе - минимальный инит и прыжок на сишную функцию 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  ?   Проверил - работает.

В скрипте линкера переправил адреса:

image.png.22225c9b8dd5171eeed92c078d7e1b95.png

 

И задал загрузку/старт  со стороны T113-s3: 0x20028000

 sunxi_dsp_init(main_bin /*адрес бинарника*/ ,0x20028000 /*куда грузить*/ ,0 /*номер DSP*/ ,sizeof(main_bin) /*размер бинарника*/);

Результат:

image.thumb.png.fc6bd1f8dbce085173b40818f1c33a89.png

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

 

 

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, repstosw сказал:

Это который 0x20028000  ?   Проверил - работает.

А здесь не надо двойку добавлять?

#define DSP0_IRAM /*0x00400000*/ 0x00028000 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, repstosw сказал:

Не нужно тут добавлять.  Это адрес со стороны T113-s3.

Понял, спасибо.

2 часа назад, repstosw сказал:

И там не только alloca, но ещё и другие способы

Там еще есть много асмового кода, в частности по прерываниям, но чет уж много очень, что там за контроллер прерываний такой, походу сложный((

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 hours ago, repstosw said:

Проблема была  в libc_init, подправил

volatile?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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) работают нормально.

Что я делаю не так? Чего не хватает, чтобы заработало прерывание таймера?

Изменено пользователем repstosw

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...