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

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

Собрал наконец-то самостоятельно полностью newlib для ABI=call0 с поддержкой printf с floating point. Очень было нужно.

За основу брал всё тот-же небезызвестный newlib-esp32, которой использовал японец при построении тулчейна с помощью crosstool-ng.

В винде не получилось сделать Makefile, потому что MSYS на базе MinGW не очень любит сторонние таргеты. И намертво прибитый гвоздями к окружению Винды и MinGW он не давал корректного мейкфайла для xtensa. Тема:

https://electronix.ru/forum/index.php?/topic/173554-configureautoconf-хост-win32-таргет-xtensa/

Пришлось всё сделать в Линуксе. Там всё  оказалось намного проще.

Но есть две проблемы с исходниками.

Первая здесь:  https://github.com/espressif/newlib-esp32/blob/esp_based_on_4_1_0/newlib/libc/include/ieeefp.h#L152

Вылетала ошибка, в итоге плюнул и жёстко задал такую конфигурацию:

#define LDBL_MANT_DIG   53
#define	EXT_EXPBITS	11
#define EXT_FRACHBITS	20
#define	EXT_FRACLBITS	32
#define __ieee_ext_field_type unsigned long

Не знаю, насколько она правильна для компилятора и архитектуры xtensa.

 

Вторая здесь: https://github.com/espressif/newlib-esp32/blob/esp_based_on_4_1_0/libgloss/libnosys/pthread.c#L30

Компилятору не понравилось, что параметру функции не задали имя, а указали всего-лишь его тип.  И там таких ошибок много.

image.thumb.png.b23053fbdcf12e4c8da41b2e3e7ecccc.png

Непонятно, как эти треды затесались в билд, при построении использовал флаг - без тредов(об этом ниже) .

И не понятно как они С-компилятор заставили это компилить.  Какой ключ у Си есть чтобы это компилировать без ошибки?

 

 Пришлось скомпилировать этот исходник С++, который переваривает параметры без имён, не забыв добавить в начало:

#ifdef __cplusplus
extern "C" {
#endif

и в конец файла:

#ifdef __cplusplus
}
#endif

Иначе С++ создаст манглированные имена, которые не увидит С.

Флаги для конфигурации использовал такие:

./configure \
--with-newlib \
--enable-newlib-reent-small \
--enable-newlib-io-pos-args \
--enable-newlib-io-c99-formats \
--enable-newlib-io-long-long \
--enable-newlib-io-long-double \
--enable-newlib-io-float \
--disable-multilib \
--disable-newlib-multithread \
--disable-newlib-reent-check-verify \
--disable-newlib-supplied-syscalls \
--disable-newlib-nano-formatted-io \
--disable-newlib-mb \
--disable-newlib-atexit-dynamic-alloc \
--disable-option-checking \
--program-transform-name="s&^&xtensa-hifi4-elf-&" \
--with-target-subdir=xtensa-hifi4-elf \
--target=xtensa-hifi4-elf

Тоесть выкинул нафиг треды, проверку на повторное вхождение (мне оно не нужно).  А НАНО-опции отключил, потому что с ними printf не печатает float. А мульти-байты напротив - не нужны.

В итоге вылепил - конфету. :biggrin: Чему я собственно и рад! :sun_bespectacled:

 

P.S.  Ещё попутно нарвался на то, что если обработчик прерывания написан на С++, а используется в сишном или ассемблерном сорце,  то используется дефолтный обработчик -функция с атрибутом weak.  Тоесть - другой обработчик, который пустой )))   Добавил к С++ функции обработчика exten "C" и оно заработало как надо по вполне очевидным причинам (манглирование имён в С++).

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

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


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

Игнорировать отсутствие имён параметров фуекци это кажется плюсовая фича... по мне в си коое не должно жить.

 

Про парамеиры плавучки. Раз это сопррцессор арму то походе должен формат с тем что арм ядрах

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


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

24 минуты назад, GenaSPB сказал:

Игнорировать отсутствие имён параметров фуекци это кажется плюсовая фича... по мне в си коое не должно жить.

Нет, не плюсовая. В прототипах функций что в Си, что в C++ могут отсутствовать имена параметров, компилятору они не нужны.

P.S. Перешел по ссылке. Да, в сишном файле в определении функции не задано имя. Программисту оторвать руки:prankster2:

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


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

12 minutes ago, Arlleex said:

В прототипах функций что в Си, что в C++ могут отсутствовать имена параметров, компилятору они не нужны.

В моём случае это не прототипы.  А функции с телами.  Надо попробовать -std=gnu99.

 

Про то, что в прототипах можно указывать типы без имён - знаю. Это вполне логично.  Ну они могли бы  пойти и дальше - разрешить указывать параметры без имен, если они не используются. Например если это заглушки.  Хотя это будет нагрузка на стек. Или лишние присвоения регистров.  Зависит от конвенции передачи параметров.

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

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


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

42 minutes ago, GenaSPB said:

Про парамеиры плавучки. Раз это сопррцессор арму то походе должен формат с тем что арм ядрах

Сравнил со встроенными дефайнами тулчейна:

echo | %TOOLCHAIN%gcc -dM -E - > output.txt
#define __FLT32X_MANT_DIG__ 53
#define __FLT64_MANT_DIG__ 53
#define __FLT_MANT_DIG__ 24
#define __FLT32_MANT_DIG__ 24
#define __LDBL_MANT_DIG__ 53
#define __DBL_MANT_DIG__ 53
#define __SIZEOF_LONG_DOUBLE__ 8
#define __SIZEOF_DOUBLE__ 8

Вроде выбрал опции в ieeefp.h правильно.

Как  я понял, чудес на этой архитектуре ждать не приходится : LONG DOUBLE = DOUBLE. У обоих мантисса 53 бита, а общая длина 64 бита(8 байт).

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

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


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

49 minutes ago, repstosw said:

В моём случае это не прототипы.  А функции с телами.  Надо попробовать -std=gnu99.

Не помогло.

make[3]: Entering directory `/c/newlib-esp32/xtensa-hifi4-elf/libgloss/libnosys'

xtensa-hifi4-elf-cc -B/c/newlib-esp32/xtensa-hifi4-elf/newlib/ -isystem /c/newlib-esp32/xtensa-hifi4-elf/newlib/targ-include \ 
  -isystem /c/newlib-esp32/newlib/libc/include -B/c/newlib-esp32/xtensa-hifi4-elf/libgloss/xtensa \ 
  -L/c/newlib-esp32/xtensa-hifi4-elf/libgloss/libnosys -L/c/newlib-esp32/libgloss/xtensa  \
  -g -O2 -std=gnu99 -O2 -I. -I../../.././libgloss/libnosys/.. -c -g -O2 -std=gnu99 ../../.././libgloss/libnosys/pthread.c

image.thumb.png.63e3a1e2dd3353b28c946f78bc9689bd.png

И всё-же - как это переварить С ? Интересно...🤣

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


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

Его наверное собирали g++. Забей. Поправьте нормалтно.

Я еще встречал в линукс драйверах как забывают писать struct при использовании типов. А это уже точно не расширения. Это с++ .

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

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


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

Сделал замену функции printf.

Ранее использовался вариадический макрос, что вызывало определённые неудобства: нужно было постоянно инклудить хедер с этим макросом в каждый файл, где используется printf.

Реализация printf:

void UART_putc(u8 c)
{
 while(!(UART_LSR&(1<<6)));
 UART_THR=c;
}

void UART_puts(const char *s)
{
 while(*s)
 {
  if(*s=='\n')UART_putc('\r');
  UART_putc(*s++);
 }
}

#include <stdio.h>
#include <stdarg.h>

#include "UART.h"

#define PRINTF_BUFFER_SIZE 256

static char printf_buffer[PRINTF_BUFFER_SIZE];

int puts(const char *s)
{
 UART_puts(s);
 UART_putc('\r');
 return '\n';
}

int printf(const char *format,...)
{
 memset(printf_buffer,0,PRINTF_BUFFER_SIZE); //? можно убрать
 va_list args;
 va_start(args,format);
 int r=vsprintf(printf_buffer,format,args)-1; //на 1 меньше, так как символ конца строки(=0) не считается в printf
 va_end(args);
 UART_puts(printf_buffer);
 return r;
}

 

Дополнительно объявлена замена функции puts, потому что при сильной оптимизации компилятор вместо вывозва printf подсовывает puts - в случаях, когда указана просто одна  строка:

 printf("\nHiFi4 DSP...\n\n");

 

puts можно исключить, добавив флаг компиляции: -fno-builtin-printf.

Тупо замена функции _write( ), как это делается в STM'ах или ARM'ах - тут не прокатывает.  Потому что newlib взята от самого IBM, а они любят усложнизмы.  Там куча проверок на реентабельность и завязано всё на файловый ввод-вывод.

Тест:

 printf("\nHiFi4 DSP...\n\n");

 long double x=2.01234567890123456789012345678901234567890123456789;
      double y=2.01234567890123456789012345678901234567890123456789;
       float z=2.01234567890123456789012345678901234567890123456789;

 printf("%1.50Lf\n",x);
 printf("%1.50lf\n",y);
 printf("%1.50f\n\n",z);

 unsigned long long temp=0x123456789ABCDEF0;

 printf("temp=0x%llX\n",temp);

Выход:


HiFi4 DSP...

2.01234567890123461353368838899768888950347900390625
2.01234567890123461353368838899768888950347900390625
2.01234579086303710937500000000000000000000000000000

temp=0x123456789ABCDEF0

 

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

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


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

Возвращаемся значение что у printf,  что у vsprintf одинаковый смысл имеют.

Зы: откройте для себя  vsnprintf

Кстати в стандарте говорится о том что эффект от переопределения у себя функций стандартный библиотеки может вам удивить...

Сделайте себе UART_printf  и нет даже потенциальных проблем...

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

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


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

1 hour ago, GenaSPB said:

Возвращаемся значение что у printf,  что у vsprintf одинаковый смысл имеют.

Здесь почему-то сказано, что vsprintf возвращает число символов включая завершающий ноль:

https://vsokovikov.narod.ru/New_MSDN_API/Add_func_runtime_C/fn_vsprintf.htm

 

Quote

Функции vsprintf and vswprintf возвращают число записанных символов, включая символ завершающего нуля, или отрицательное значение, если происходит ошибка при выводе.

Хотя другие источники говорят, что без завершающего.

 

1 hour ago, GenaSPB said:

Зы: откройте для себя  vsnprintf

Чем он лучше, чем vsprintf ?  Более стандартизирован возвращаемому значению числа выведенных символов не включая \0 ?

 

1 hour ago, GenaSPB said:

Кстати в стандарте говорится о том что эффект от переопределения у себя функций стандартный библиотеки может вам удивить...

Перекомпилировал все проекты, где есть много вызовов printf в разных файлах.   Подвоха не заметил.

И почему сделан упор на "стандартную" библиотеку? В чём её стандартность заключается?  Она никуда не прибита намертво, и она пересобирается. Так что не знаю на счёт стандартности, по мне - обычная библиотека, как и все другие.

 

1 hour ago, GenaSPB said:

Сделайте себе UART_printf  и нет даже потенциальных проблем...

Вы предлагаете переправлять в нескольких десятках файлов чужих исходников  printf на UART_printf ?

Переопределение printf как раз было задумано, чтобы вызовы printf не приводили к зависаниям, а программисту - не переправлять тонны исходников.

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

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


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

31 minutes ago, repstosw said:

Чем он лучше, чем vsprintf ?  Более стандартизирован возвращаемому значению числа выведенных символов не включая \0 ?

Да. Лучше. Стандартизировано возвращаемое значение. И безопаснее. Позволяет заранее узнать размер строки и выделить динамически память под строку.

Так как использую GCC с разрешением VLA, то вместо malloc/free можно использовать VLA.

Код printf теперь такой:

int printf(const char *format,...)
{
 va_list args;
 va_start(args,format);
 size_t n=vsnprintf(NULL,0,format,args)+1; //+1 for the '\0'
 char buf[n];
 int r=vsnprintf(buf,n,format,args);
 va_end(args);
 UART_puts(buf);
 return r;
}

Помогло понять вот это:

https://stackoverflow.com/questions/7315936/which-of-sprintf-snprintf-is-more-secure

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

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


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

Screenshot_20231008_100529_OneDrive.jpg

Screenshot_20231008_100935_OneDrive.jpg

Нет отличий. Обращайтесь к первоисточник.

C99

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

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


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

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

Переопределение printf как раз было задумано, чтобы вызовы printf не приводили к зависаниям, а программисту - не переправлять тонны исходников.

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

 

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

выделить динамически память под строку.

 

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

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


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

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

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

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

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

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

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

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

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

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