2024-11-09

vak: (Default)
Ликбез по ассемблеру RISC-V (часть 1, часть 2) был бы неполным без вещественной арифметики. Редкий микроконтроллер имеет плавающую точку, да ещё 64-битную. Получим же от неё удовольствие на PIC64. 😀

Вычислим что-нибудь простое но нетривиальное, скажем кубический корень. Итеративный алгоритм Ньютона вполне годится. Добывая корень из числа n, следующую итерацию x вычисляем как next_x = (n/x/x + x + x) / 3. На ассемблере будет выглядеть так:
        .text
cubic_root:
fmv.d fa3, fa0 # n in register fa3
fld fa2, three, a5 # constant 3.0
fld fa0, one, a5 # x = 1.0, initial guess
loop:
fdiv.d fa5, fa3, fa0 # n / x
fmv.d fa4, fa0 # old x in register fa4
fdiv.d fa5, fa5, fa0 # n / x / x
fadd.d fa5, fa5, fa0 # + x
fadd.d fa5, fa5, fa0 # + x
fdiv.d fa0, fa5, fa2 # divide by 3.0
feq.d a5, fa4, fa0 # nx == x?
beqz a5, loop # otherwise to next iteration
ret

one: .double 1.0
three: .double 3.0
На этот раз мне лениво писать на ассемблере печать вещественного числа. Воспользуемся стандартной функцией printf(). Её вариант __printf_chk можно вызывать прямо из ассемблера.
        .globl  main
main:
fld fs0, input, a5 # input value
fmv.d fa0, fs0 # copy to permanent register
call cubic_root

li a0, 2
lla a1, format
fmv.x.d a2, fs0 # input value
fmv.x.d a3, fa0 # square root
call __printf_chk

li a0, 0 # exit status
call _exit

input: .double 2.0
format: .string "cubic root of %.15g is %.15g\n"
Компилируем, запускаем.
$ cc -o cubic_root cubic_root.s

$ ./cubic_root
cubic root of 2 is 1.25992104989487
Всё оказывается ничуть не сложнее, чем с целочисленными вычислениями.