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

AVI-crak

Участник
  • Постов

    367
  • Зарегистрирован

  • Посещение

Сообщения, опубликованные AVI-crak


  1. Нашлось решение. https://godbolt.org/z/G3M64K7nz

    Для cortex без вставки не обойтись, вообще ни как, чисто физически.

    #if (defined __ARM_ARCH && __ARM_FEATURE_DSP) 

    Но вставка умудрялась встраиваться народном cortex m3 (тот самый stn32f103), а не должна - там не такой инструкции. Оказалось что подобные длинные и страшные инструкции для cortex - это часть DSP. И встречаются подобные инструкции даже в очень древних архитектурах - и всегда в списках DSP.

    Однако компания STM, а за ней и все остальные - дружно подложили жирную свинью. Инструкция u64=u32+u32+u32*u32 находится в общем разделе - попробуй догадайся.

    Для х86-64 ещё веселей - дополняется проверка на существование типа uint128_t, и тогда вся функция выполняется одной инструкцией.

  2. On 8/12/2023 at 9:37 PM, EdgeAligned said:

    "меня гложут смутные сомнения"

    Например ARM выполняет честную арифметику с плавающей точкой, с округлением к нулю. Всё что не влезает в итоговый результат - просто отбрасывается. x86-64 учитывает результат намного глубже, а в части операций производит округление к единице. Если вычислений слишком много - то ошибка накапливается в младших знаках, и её уже становится видно.

  3. Расширенным поиском нашлось очень много материала на данную тему, в том числе очень старые темы.

    В целом ситуация странная. С очень давних времён была написана функция с ошибкой, которая вошла во все компиляторы без исключения. Создано огромное количество программного обеспечения, и даже аппаратные решения в новых процессорах подогнаны под ошибочные результаты. А всё потому, что если сделать правильно - то отвалится чуть-ли не половина созданного ранее. Дабы сделать плавный переход на верные результаты - практически все компиляторы исключили нативную поддержку чисел выше int64_t. Для того чтобы общество само разобралось чего кому нужно, и чтоб ненужное и глюкавое отвалилось само собой.

    Плавный переход затянулся на 12 лет.

    Числа большой разрядности необходимы для программной эмуляции long double : мантисса 64 бита, степень 15 бит, знак 1 бит. Когда-то очень давно для интела появилась аппаратная поддержка double, так вот внутри оно обрабатывалось как long double, и не очень честно.

    uint64_t mult64toH128(uint64_t val1, uint64_t val2, int32_t* ord)
    {
        uint32_t c1c0 = (uint64_t) (val1 & 0xffffffff) * (val2 & 0xffffffff) >> 32;
        uint64_t a2a1 = (val1 & 0xffffffff) * (val2 >> 32) ;
        uint64_t b2b1 = (a2a1 & 0xffffffff)+ c1c0 + (val1 >> 32) * (val2 & 0xffffffff);
        uint64_t c3c2 = (a2a1 >> 32) + (b2b1 >> 32) + (val1 >> 32) * (val2 >> 32) ;
        *ord += c3c2 >> 63;
        if((c3c2 >> 63) == 0){
            c3c2 <<= 1;
            c3c2 |= (b2b1 >> 31) & 1;
        };
        return c3c2;
    }

    Шланг 16,0,0 делает простой и быстрый код для кортекса М4 и выше.

      push {r4, lr}
      umull r12, lr, r2, r0
      ldr r4, [sp, #8]
      umull r12, r0, r3, r0
      umaal lr, r12, r2, r1
      umaal r0, r12, r3, r1
      ldr r1, [r4]
      lsr.w r3, lr, #31
      lsl.w r2, r12, #1
      cmp.w r12, #0
      add.w r1, r1, r12, lsr #31
      itt pl
      orrpl.w r12, r2, r0, lsr #31
      orrpl.w r0, r3, r0, lsl #1
      str r1, [r4]
      mov r1, r12
      pop {r4, pc}

    Команда umaal работает так: u64 = u32+u32+u32*u32, при этом два первых операнда находятся в выходных регистрах. Так вот, GCC отказывается применять эту команду, хотя прекрасно знает о её существовании. А всё потому что очень боится переполнения, и боится не без причины. Дело в том что аппаратная поддержка double выполняется на том-же куске кремния что и простое умножение. Однако если простое умножение ограничено в разрядности, то умное от интел имеет более высокую разрядность и автоматическое округление. Ситуации когда из длинного FFFFF.... получаются нули - не столь уж и редки.

    Описать ситуации исключения переполнения для double и простого умножения - для GCC оказалось непосильной задачей. А потому там просто пометка - низя.

    Похоже ждать у моря погоды придётся очень долго. Даже раст отказался от поддержки int128_t - напоролся на те-же грабли.  

  4. Пока ещё не обрабатываются, и куча дополнительных условий без обработки. На данный момент у меня борьба с последним битом double.

    В общем оригинальный православный sscanf(), так-же как ptintf() - содержит в себе полноценную таблицу множителей на все степени двойки. 40килобайт - это от жирной таблицы. У мня есть желание избавится от таблицы, и упаковаться в размер меньше 1 килобайта. Фетиш такой, под старость лет.

  5. Ок, переключился на ARM GCC 9.2.1, вижу umlal, но не понимаю отчего так код разбух. У меня на асме получалось всего 18 команд, и я хотел-бы увидеть то-же от GCC. 

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

    Тогда просто буду ждать у моря погоды, когда оно само исправится. 

  6. On 8/6/2023 at 6:45 PM, jcxz said:

    Скармливаю ваш код GCC

    Как у вас это получилось? Потому как мой вариант компилируется так-же как в онлан сервисе.

    20000E6E	push	{r4, r5, r6, lr}
    20000E70	umull	r6, r5, r0, r2
    20000E74	ldr	r4, [sp, #16]
    20000E76	umull	r0, r6, r0, r3
    20000E7A	adds	r5, r5, r0
    20000E7C	umull	r2, r0, r2, r1
    20000E80	umull	r3, r1, r3, r1
    20000E84	adc.w	r6, r6, #0
    20000E88	adds	r2, r2, r5
    20000E8A	adc.w	r0, r0, #0
    20000E8E	adds	r3, r3, r6
    20000E90	adc.w	r1, r1, #0
    20000E94	adds	r0, r0, r3
    20000E96	adc.w	r1, r1, #0
    20000E9A	cmp	r1, #0
    20000E9C	blt.n	0x20000ea8 <mult64toH128+58>
    20000E9E	adds	r0, r0, r0
    20000EA0	adcs	r1, r1
    20000EA2	orr.w	r0, r0, r2, lsr #31
    20000EA6	pop	{r4, r5, r6, pc}
    20000EA8	ldr	r3, [r4, #0]
    20000EAA	adds	r3, #1
    20000EAC	str	r3, [r4, #0]
    20000EAE	b.n	0x20000ea6 <mult64toH128+56>

     

    On 8/6/2023 at 6:45 PM, jcxz said:

    Причём тут long double - вообще не понял.

    Эта функция используется вместо встроенной лапши на 6 килобайт.

  7. А так вообще пропало умножение u64=u32*u32. 

    Моя функция "uint64_t mult64toH128(uint64_t val1, uint64_t val2, int32_t* nr)" используется для замены встроенной функции умножения чисел long double. Там по дефолту такая дикая ересь добавляется на 6 килобайт, и всё это тормозит как стадо егэшников на экзамене.

    Логика умножения long double простая как тапок: u64=(u128)u64*u64>>64;. Если число получается больше или равным (1<<63) - тогда к сумме степеней (двоичное со знаком) первого и второго числа добавляется единица. В оригинале там степень использует число без знака с диким легаси в обработке, мне такого не надо.

    On 8/6/2023 at 5:57 PM, jcxz said:

    И что именно не устраивает в результате GCC?

    Полное описание в первом сообщении, с картинками.😁

  8. Вот о чём я говорил чуть выше "((uint32_t) (val2 >> 32))" - val2 в этом преобразовании уже имеет размер uint32_t, соответственно результат ноль, и сокращение одной операции умножения. Операций умножения должно быть 4, иначе фигня получится. Тут очень просто, все биты первого числа перемножаются на все биты второго, со смещением и последующим сложением. Столбиком (ненавижу это слово). 

  9. Очень просто, для него все операции имеют входные и выходные операнды размером с регистр. Нужно дополнительно указывать варианты событий с иным результатом. В моём случае это дополнительное (uint64_t), без него будет выполнено обычное умножение u32=u32*u32.

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

    Для того чтобы меньше путаться, я дал имена переменным согласно позиции в числе uint128.

    uint64_t mult64toH128(uint64_t val1, uint64_t val2, int32_t* nr)
    {
        uint64_t c1c0 = (uint64_t) (val1 & 0xffffffff) * (val2 & 0xffffffff);
        uint64_t a2a1 = (uint64_t) (val1 & 0xffffffff) * (val2 >> 32) + (c1c0 >> 32);
        uint64_t b2b1 = (uint64_t) (val1 >> 32) * (val2 & 0xffffffff) + (a2a1 & 0xffffffff);
        uint64_t c3c2 = (uint64_t) (val1 >> 32) * (val2 >> 32) + (a2a1 >> 32);
        c3c2 = (uint64_t) c3c2 + (b2b1 >> 32);
        if((c3c2 >> 63) == 0){
            c3c2 <<= 1;
            c3c2 |= (b2b1 >> 31) & 1;
    
        }else *nr += 1;
        return c3c2;
    }

    Эта функция выдаёт примерно такой код (на ARM): mult64toH128:  Топорное использование umull - умножение без накопления u64=u32*u32, и только потом добавляет u32. ARM и другие архитектуры имеют команды u64 +=u32*u32 (UMLAL для ARM). В этом случае например "(c1c0 >> 32)" нужно поместить в "a2a1", или в наглую использовать "(c1c0 >> 32)" по месту создания и очистить свободный регистр. Я считаю что команда записи нуля и умножение с накоплением дают в сумме меньший код. На чистой асме у меня получилось написать компактно (18 команд), тесты на скорость показали ускорение. Но заставить GCC использовать "UMLAL" у меня не получается.

    Встроенные функции дают невообразимо длинную лапшу, использовать нельзя.

     

  11. On 6/25/2023 at 10:38 PM, Arlleex said:

    И это время не специфицировано (я не нашел сходу в описании).

    Время свободной шины BUSTURN -   FSMC целиком блокируется на несколько тактов, линия данных отключается, но емкости дорожек и контактов достаточно для удержания уровня. в режиме NAND возможно аппаратное управление контактом дисплея "команда". Надо просто добавить немного логики. 

  12. У меня тоже есть stm32f030f4p6 и STLINK-V3MINI, всё прекрасно работает, но отладчик сильно нагревается, примерно до 60-70С (все напряжения в норме).

    Меня интересует температура вашего STLINK-V3MINI, может оно не должно так греться...

  13. Кхм, наверное лучше поздно чем никогда - сахар для WCH.

    #define _VAL2FLD(field, w_value)    \
        ((sizeof(field) == 4) ? (((uint32_t)(w_value) << __builtin_ctz(field)) & field) : \
         ((sizeof(field) == 2) ? (((uint16_t)(w_value) << __builtin_ctz(field)) & field) : \
          (((uint8_t)(w_value) << __builtin_ctz(field)) & field)))
    
    #define _FLD2VAL(field, r_value)    (((uint32_t)(r_value) & field) >> __builtin_ctz(field))

     GCC имеет много костылей для подобных финтов. Многие из них не всегда имеют аппаратные команды, так-что осторожнее.

    __builtin_popcount(x)// подсчитывает количество единиц (установленных битов) в целом числе
    __builtin_parity(x)// проверяет четность числа, false(0)= четное количество установленных битов
    __builtin_clz(x)// подсчитывает начальное количество нулей целого числа
    __builtin_ctz(x)// подсчитывает конечное количество нулей целого числа

     

    • Downvote 1
  14. On 4/11/2023 at 7:41 PM, EdgeAligned said:

    Третий пример. В графическом интерфейсе на дисплее есть экранная кнопка. С нажатием в область её координат всё понятно. А что произойдет, если было касание в области кнопки, затем палец, не отрывая от дисплея, сдвинули и ушли за границу этой кнопки, да еще и попали на соседнюю кнопку?

    Вот так легко перечеркнул все наработки фирмы ST в графических библиотеках - оно там крашется на раз в подобных случаях.

  15. FMC имеет раздельные настройки для записи и чтения, а вот конкретно st7799 имеет время чтения 350nc - в 23 раза больше записи. И кажется не поддерживает автоадрес.

    То-есть читать рам память - это к огромным тормозам. 

  16. On 2/8/2023 at 7:34 PM, Oleg_IT said:

    Использую программатор CH341A как переходник UART-USB

    У этой компании есть более современный чип CH347. Стоит дороговато, но зато очень быстрый. Программатор spi / i2c / jtag на нём тоже можно сделать. Например 25q64 зашивается за 36 секунд. 

  17. 4 часа назад, RusikOk сказал:

    как запретить отладчику перебрасывать меня в обработчик прерывания если оно произошло пока программа была на паузе

    Эту функцию отладчика ещё не изобрели, хотя проблеме более 20 лет. И не только в IAR, но и во всех остальных IDE. Есть костыльные попытки с запретом прерываний, когда это выполняет скрипт в реальном времени. Но стабильность результата ниже уровня плинтуса. 

    Это даже не проблема свистка, и не ide как таковой - проблема в физической реализации алгоритма на кристалле чипа. Там всё застыло на 30 лет с момента принятия промышленного стандарта, и теперь всем страшно его трогать - потому что сломается вообще все и сразу.

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