Ликбез по ассемблеру RISC-V (часть 1, часть 2) был бы неполным без вещественной арифметики. Редкий микроконтроллер имеет плавающую точку, да ещё 64-битную. Получим же от неё удовольствие на PIC64. 😀
Вычислим что-нибудь простое но нетривиальное, скажем кубический корень. Итеративный алгоритм Ньютона вполне годится. Добывая корень из числа n, следующую итерацию x вычисляем как next_x = (n/x/x + x + x) / 3. На ассемблере будет выглядеть так:
Вычислим что-нибудь простое но нетривиальное, скажем кубический корень. Итеративный алгоритм Ньютона вполне годится. Добывая корень из числа n, следующую итерацию x вычисляем как next_x = (n/x/x + x + x) / 3. На ассемблере будет выглядеть так:
На этот раз мне лениво писать на ассемблере печать вещественного числа. Воспользуемся стандартной функцией printf(). Её вариант __printf_chk можно вызывать прямо из ассемблера..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
Компилируем, запускаем..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