Математика в assembler

Тема в разделе "Микроконтроллеры AVR", создана пользователем a1000, 3 фев 2020.

  1. a1000

    a1000 Гуру

    Продолжаю свои неуверенные попытки разобраться с ASM. Почему не С, не спрашивайте. Вразумительного ответа кроме - я мазохист, у меня нет.
    То, что математика на ASM это полный мрак догадывался и раньше, но теперь столкнулся с этим в полный рост. Возникла необходимость извлечь квадратный корень. При этом аргумент не помещается ни 8 ни в 16 бит. Длительные поиски в инете готовых решений (не у меня-же первого возникла такая необходимость) выдали вот это

    Код (C++):
    ;*******************************************************************************
    *********************
    ;*
    ;*         Подпрограмма вычисления квадратного корня для 24-ти битного аргумента                 *
    ;*         (c) 1998 Alexander Trush http://trush.da.ru trush@ropnet.ru 2:5020/392.40
    ;*
    ; Вы можете свободно использовать, распространять, модифицировать этот
    ; код до тех пор, пока вы указываете моё авторство и распространяете
    ; это требование. Кроме того, я хотел бы получать уведомление о
    ; применении этого кода по e-mail (trush@kbotd.ru).
    sqrt24:
    ldi     mask,1; Используем маску в регистре, т.к. команды EORI нет...
    ldi     count,12; Последний бит значения корня не требует специального
           ; подхода - есть запас от потери битов аж 4 бита
    clr16 work_h, work_l
    clr16 dist_h, dist_l; Очистка накопителя значения корня

    sqrt24_1:    
    cpi     src_h, 64
    cpc     work_l, dist_l
    cpc     work_h, dist_h
    brcs sqrt24_2
         subi src_h, 64
         sbc work_l, dist_l
         sbc work_h, dist_h
    sqrt24_2:    
    rol     dist_l  
    rol     dist_h  
    eor     dist_l, mask; Инверсия младшего бита значания корня,
                        ; т.к. при заёме должны писать 0, и 1 при отсутствии
    lsl     src_l; Сдвиг аргумента на 2 бита
    rol     src_m; work_h:work_l:src_h:src_m:src_l <<= 2
    rol     src_h
    rol     work_l
    rol     work_h
    lsl     src_l
    rol     src_m
    rol     src_h
    rol     work_l
    rol     work_h
    dec     count; Получили ли все биты значения корня кроме последнего?..
    brne sqrt24_1
    cp     dist_l, work_l
    cpc     dist_h, work_h
    adc     dist_l, src_m; Команды ADCI нет, а src_m точно здесь равен 0
    adc     dist_h, src_m
    ret
    ;******************************************************************************

    В логику нахождения корня пока даже не пытаюсь вникнуть. Прошу помочь разобраться с задействованными регистрами. Всего подпрограмма использует 9 регистров.
    mask - маска для eor (присваивается в программе)
    count - счётчик
    work_h, work_l - рабочая пара для вычислений
    dist_h, dist_l - пара регистров в которой будет результат
    src_h, src_m, src_l - 3 байта аргумента
    Я правильно разобрался?
    И возникают сомнения команды
    Код (C++):
    clr16 work_h, work_l
    clr16 dist_h, dist_l;
    Как я понял это очистка регистровой пары. Но что-то в справочнике по ASM AVR я таких не видел. Оно на Atmega8 работать будет?
     
  2. microsystems

    microsystems Нерд

    crc16 - это макрос. ассемблерной команды такой нету.
     
  3. a1000

    a1000 Гуру

    Странный макрос, заменить две команды одним вызовом макроса.
     
  4. Asper Daffy

    Asper Daffy Иксперд

    А что странного-то?
     
  5. parovoZZ

    parovoZZ Гуру

    А классический math.h почему не подошёл?
     
  6. SergeiL

    SergeiL Оракул Модератор

    Несколько лет осваивал Unix, уже писал программы на Си, RSX-11M и фортран - не в счет, RSX-11M ушел на покой.
    Начал освоение Си под MS-DOS, и тут меня перевели из отдела прикладного программирования в отдел системного программирования...
    Первое, что начальник отдела дал из заданий - написать калькулятор на ассемблере под MS-DOS.
    Как хочешь. Графика, псевдографика но чтобы можно было пользоваться под MS-DOS.
    Как это было сложно после Си. :mad:
    Потом освоился.
    Потом смог часть простых программ уже писать в отладчике на асме и сохранить в файл с расширением .com Без компиляторов.
    Потом 80386, 80486, SX, DX, Pentium. И везде есть отличия в ассемблерных командах.
    А Си не изменился!!! Причем нисколько! ;)
    В С++ появились дополнительные возможности, но блин Си который начал осваивать в 1987, работает до сих пор!!!
    Да и UNIX, который был 1987, тот же Linux сейчас.
    Порой сидишь, тупишь а из памяти всплывают и команды и параметры.
    Может Си?
    ИМХО: Асм нужен только профессионалам, работающих под конкретный проц, и пишущих нижний уровень. Я писал на Асме библиотеки для Си под свою ОС.
     
    Un_ka нравится это.
  7. SergeiL

    SergeiL Оракул Модератор

    В свое время году в 2004, на AtMega8 делал устройство для выбора оптимальной фазы из трех входящих в дом.
    Тоже возник вопрос вычисления квадратного корня без float.
    Вот функция из того проекта:
    Код (C++):

    unsigned sqrt_cpu2(long l)
    {
          long rslt_2;
          long div_2;
          rslt_2 = l;
          div_2 = l;
          if (l <= 0)
                return 0;
          while (1)
          {
                div_2 =  (l / div_2 + div_2) / 2;
                if (rslt_2 > div_2)
                       rslt_2 = div_2;
                else
                       return (unsigned) rslt_2;
          }
          return (unsigned)rslt_2;
    }
     
     
    Последнее редактирование: 4 фев 2020
  8. a1000

    a1000 Гуру

    Вместо
    Код (C++):
    clr16 work_h
    clr16 work_l
    писать
    Код (C++):
    clr16 work_h, work_l
    Не вижу выигрыша от применения макроса.
    Это-же для С. Или его как-то можно в ASM применить?
    Как я уже писал - я не профессионал. Это хобби. Пишу для собственного удовольствия. На данном этапе мне интересен ассемблер. Пробую в нём разобраться. Сроки у меня не горят. Вот и пробую то, что мог на Arduino написать менее чем за день, изобразить в кодах ассемблера.
     
  9. Asper Daffy

    Asper Daffy Иксперд

    Напрасно. Очень часто макросом (инлайн или constexpr функцией) заменяют даже одну единственную команду. А выигрыш, ну прикинь, что лучше для дальнейшего сопровождения программы, запись
    Код (C++):
    PORTB |= (1 << 4);
    или запись
    Код (C++):
    turmScreenLightON();
    Если не видишь разницы, то ... со временем увидишь :)
     
    Andrey12 и parovoZZ нравится это.
  10. a1000

    a1000 Гуру

    Кто-бы спорил, я не буду. Как говорится - великое видится на расстоянии.:)
    И да, код из первого поста проверил в симуляторе. Всё работает. В регистры src_h, src_m, src_l кидаешь 24 бита аргумента и в регистры dist_h, dist_l выпадает целая часть корня квадратного. При этом дробная часть не просто отбрасывается а происходит округление по всем правилам математики.
    Может кому сгодится.
     
    parovoZZ нравится это.
  11. parovoZZ

    parovoZZ Гуру

    А сколько тактов уходит на расчет?
     
  12. a1000

    a1000 Гуру

    Если я правильно разобрался с симулятором то получается следующее
    Загнал FF FF FF - получил 289 тактов
    Загнал 3 миллиона 2D C6 C0 - получил 271 такт
    Отбросил старший байт 00 C6 C0 - получил 260 тактов.
    Количество тактов практически не зависит от размера аргумента.
     
  13. Daniil

    Daniil Гуру

    Там есть counter=12. Пока он не дойдет до 0 из цикла не выйдем. Цикл занимает большую часть кода.
    Мне показалась задачка интересной, но увы, я не выдержал и 3ех кругов. В экселе завел все переменные в столбцы и начал шагать по тактам. С асмом плохо знаком, поэтому приходилось каждый раз читать про команду, следить за С...не, не запрыгну на коня.
    Лучшее что я нашел по описаниям команд это евстисфеев. На гавру описания команд те же, что и у автора, но куцообрезанные.
    Да и по этим трем тактам я не понял что за маневр прибавлять 64 к старшему байту, а потом выдвигание его в край, это добавило отчаяния в разбор кода...
    В вашей симуляции можно по шагам пройтись? Если да, то проделайте это и соберите все результаты за каждый такт и проанализируйте уже готовое.
     
    SergeiL нравится это.
  14. SergeiL

    SergeiL Оракул Модератор

    Вот поэтому я говорю, что Асм штука интересная, но для профессионалов, которые пишут под один МК или проц долгое время.
    Для любителей, склонных менять МК, слишком нецелесообразно каждый раз, к архитектуре МК и его управляющим регистрам еще и разбираться с Асмом, когда есть универсальный Си. Но это ИМХО.
     
    Daniil и Andrey12 нравится это.
  15. parovoZZ

    parovoZZ Гуру

    Я думаю, что надо поискать математическое извлечение квадратного корня. Тогда и код станет понятным.
     
  16. a1000

    a1000 Гуру

    Есть краткий справочник и нашёл переведённое фирменное описание
     

    Вложения:

  17. a1000

    a1000 Гуру

    Тут не всё так просто. Существует несколько разных методов. Половинного деление, метод Ньютона, преобразования прямоугольника в квадрат и.т.д. Прямого метода расчёта нет, все методы основаны на последовательных итерациях до заданной точности. Учитывая отсутствие аппаратного делителя их самостоятельная реализация для ASM, да ещё для 2х и более байтных чисел для начинающего неподъёмная задача.
     
    Daniil нравится это.
  18. Daniil

    Daniil Гуру

    Конечно, я порыскал в гугле, но тут влезает штука с битом переполнения (бит С), которая и сбила меня.
    За час не смог разобраться, больше уделить времени не могу.
    институтские задачки я щелкал, а тут, признаюсь, не мое;)
     
  19. parovoZZ

    parovoZZ Гуру

    Я может что-то не понимаю или ещё чего, но строчка
    Код (C++):
    b = sqrt(a);
    вычисляет квадратный корень из 3000000 за 15 тактов на 328PB.
    Это в симуляторе по таймеру без прескалера))
     
    SergeiL нравится это.
  20. SergeiL

    SergeiL Оракул Модератор

    Вот об этом я и говорил.
    Не, я на ассемблер, причем незнакомый, только тогда когда без этого уже не обойтись.
    А так - только Си. А свободное время лучше на что-то полезное потратить. ;)