да было что-то, да где-то?
Ну не на ЖКИ а вообщем, работа с FP.
где взял не помню. Извините, если что!!!
;************************************************* **************************
;* Пакет процедур выполнения основных математических операций над числами *
;* в формате с плавающей запятой *
;* *
;* используется косвенная адресация через регистры R31:R30 (Z) *
;* изменяются также регистры r0, r1, r2, r3, r16, r17, r18, r20, FlagS *
; * сохраните пакет в формате “txt” и подключайте директивой “.include” *
;************************************************* **************************
.def FlagS =r27 ; регистр флагов операции
.equ S1 =0 ; знак первого операнда
.equ S2 =1 ; знак второго операнда
.equ SwP =2 ; признак перестановки операндов
.equ Z1 =3 ;первый операнд нулевой
.equ Z2 =4 ; второй операнд нулевой
.equ oper =5 ;знак операции (0 - сложение, 1 -вычитание)
;* ;преобразование целого 6 - ти байтового числа в представление с плавающей запятой
;* той же длины. Z (r31:r30) - указывает на начальный (младший) байт исходного числа
;* результат располагается в тех же адресах. Использует регистры :
;* r16 - рабочий регистр, r17 - временное сохранение порядка, r18 - счетчик байтов
I_flo: rcall if_0 ;проверить на “0”
breq IFZ ;число нулевое - нечего преобразовывать
ldi r17,127+40 ;исходный порядок для 5-ти байтовой мантисы
subi r30,-6
IF1: ld r16,-Z ;старший байт исходного числа
tst r16
breq IF3 ;число короче 5 байтов
IFM: clc ;придется терять младшие цифры
ror r16 ;сдвигая число вправо
st Z,r16
ldi r18,5
rcall s_R1 ;сдвинуть вправо
inc r17
subi r30,-6 ;указатель на старший байт
rjmp IF1
IF3: subi r30,5 ;указатель на младший байт
ldi r18,5
rcall s_L ;сдвинуть влево
dec r17 ;уменьшить порядок
brcc IF3
clc ;знак числа положительный
ror r17
st Z,r17 ;запомнить порядок
ldi r18,5
rcall s_R1 ;сдвинуть вправо
IFZ: ret
if_0: ldi r18,6 ;проверка операнда на 0
clr r16
IF_r: ld r17,Z+
or r16,r17
dec r18
brne IF_r
subi r30,6 ;восстановить указатель на младший байт
tst r16
ret
;* преобразование 6-ти байтового числа с плавающей запятой в 40 разрядное целое
;* Z (R31:r30) - указывают на начальный (младший) байт исходного числа
;* результат располагается в тех же адресах. Использует регистры :
;* r16 - рабочий регистр, r17 - временное сохранение порядка, r18 - счетчик байтов
;* переполнение приведет к ошибочному результату
f_int: rcall if_0 ;проверить на “0”
breq IFZ ;число нулевое - нечего преобразовывать
subi r30,-4 ;указатель на старший байт мантисы
ldi r18,2
rcall s_L ;восстановить порядок числа
clt ;сбросить бит знака
brcc FiP ;число было положительным
set
FiP: dec r30 ;указатель на порядок числа
sec ;установить бит переноса
ld r16,-Z ;загрузить старший байт мантисы
ror r16 ;восстановить ведущую единицу
st Z+,r16 ;сохранить восстановленную мантису
ld r17,Z ;загрузить порядок
subi r17,127+40 ; здесь должно получиться ‹0
com r17 ; иначе – переполнение
brmi f_i2 ; оставим старшие биты при переполнении
breq f_i2 ;требуемое количество сдвигов равно 0
f_i1: clc
ldi r18,5
rcall s_R1 ;сдвинуть вправо
subi r30,-5
dec r17
brne f_i1
f_i2: clr r16
st Z,r16 ;очистить порядок
subi r30,5 ;указатель вернуть на младший байт
ret
;************************************************* ***********************************
; умножение 40-битовое без знака , вход r1 - адрес 1-го сомножителя, r2 - второго, r0 - результат
;* использует регистры r3, r16, r17, r18, r19, r20
; ************************************************** *********************************
m40u: mov r3,r0
sub r3,r2 ;смещение от результата до второго сомножителя
cbr FlagS,1‹‹oper ;операция сложения
mov r30,r0 ;указатель на адрес результата
sub r16,r16 ;очистить бит переноса
ldi r18,5 ;и 5 байтов результата
m40_1: st Z+,r16 ;очистить
dec r18
brne m40_1
ldi r17,41 ;счетчик циклов
rjmp m40_3
m40_2: brcc noad40 ;if bit 0 of multiplier set
rcall Nasa ;сложить аккумулятор со вторым сомножителем
noad40: mov r30,r0 ; результат
rcall R_S5 ;сдвинуть вправо
m40_3: mov r30,r1 ;через первый множитель
rcall R_S5
dec r17 ;счетчик
brne m40_2 ;не 0 - повторить
ret
R_S5: ldi r18,5 ;сдвиг 5 байтов вправо (только мантисы)
s_R: in r20,Sreg ;сдвиг числа вправо; (r1
байт
add r30,r18 ;указатель после старшего байта
out Sreg,r20 ;восстановить бит переноса
s_R1: ld r16,-Z
ror r16 ;сдвинем вправо байты
st Z,r16
dec r18
brne s_R1 ;все, сколько заказано
ret
L_S5: ldi r18,5 ;сдвиг 5 байтов влево (только мантисы)
s_L: ld r16,Z ;сдвиг числа влево; (r1
байт
rol r16 ;сдвинуть влево на 1 бит
st Z+,r16
dec r18
brne s_L
ret
neit: cbr FlagS,1‹‹oper ;восстановление делимого после неудачного уменьшения
Nasa: mov r30,r0 ;указатель на аккумулятор с плавающей запятой
ldi r18,5 ;байтов
;* суммирования / вычитание 2-х многобайтовых чисел, регистры r31:r30 указывают на
;* первое из них, а в регистре r3 содержится разность начальных адресов операндов
;* r18 - количество байтов, результат помещается на место первого слагаемого
;* требуемая операция указывается в бите “oper” регистра “FlagS”
a_s: sub r16,r16 ;очистить бит переноса
in r20,Sreg ;сохранить для первого сложения
a_s_2: ld r16,Z ; байт первого слагаемого
sub r30,r3 ;указатель на второе слагаемое
ld r19,Z ;второе слагаемое
out Sreg,r20 ;восстановить бит переноса
sbrc FlagS,oper ;если сложение - пропустить строку
rjmp a_s_3
adc r16,r19 ;сложить с переносом
rjmp a_s_4
a_s_3: sbc r16,r19 ;вычесть с переносом
a_s_4: in r20,Sreg ;сохранить статус
add r30,r3 ;указатель на первое слагаемое, в нем
st Z+,r16 ;сохранить сумму, увеличить указатель
dec r18 ;для всех байтов
brne a_s_2
out Sreg,r20 ;восстановить бит переноса
ret
SwapO: push r1 ;перестановка операндов
mov r1,r2 ;переставим операнды местами
pop r2 ; (только указатели )
push r17
ldi r17,1‹‹SwP
eor FlagS,r17 ;инвертировать флаг перестановки операндов
mov r17,r18 ; переставим “выделенные” порядки операндов
pop r18
ret
;* подготовка операндов для всех операций: восстановление ведущих единиц мантис,
;* выделение порядков в регистры r17 и r18 для первого и второго операндов соответственно
O_pre: mov r30,r1 ;адрес первого операнда
clr FlagS ;очистить регистр флагов
rcall if_0 ;1-й операнд не нулевой
brne Op1 ;нет
sbr FlagS,1‹‹Z1 ;установить флаг нуля 1
Op1: subi r30,-4 ;указатель на старший байт мантисы
ldi r18,2 ;сдвинем 2 байта
rcall s_L ;для восстановления порядка
mov r17,r16 ; порядок 1-го операнда
brcc Op2 ;знак операнда положительный
sbr FlagS,1‹‹S1 ;сохраним знак 1-го операнда
Op2: mov r30,r1
subi r30,-5 ;указатель перед старшим байтом
ldi r18,1 ;обратно сдвинем только мантису (1 байт)
sec ;для восстановления ведущей единицы
rcall s_R1 ;вправо
mov r30,r2
push r17
rcall if_0 ;операнд не нулевой
pop r17
brne Op3 ;нет
sbr FlagS,1‹‹Z2 ;установить флаг нуля 2
Op3: subi r30,-4 ;указатель на старший байт мантисы
ldi r18,2 ; сдвинем 2 байта
rcall s_L
mov r18,r16 ;порядок второго операнда
brcc Op4 ;знак операнда положительный
sbr FlagS,1‹‹S2 ;сохраним знак 2-го операнда
Op4: mov r30,r2 ;восстановим мантису 2-го операнда
subi r30,-5 ;указатель перед старшим байтом
sec ;для ведущей единицы
push r18
ldi r18,1 ;сдвинем 1 байт
rcall s_R1 ;вправо
pop r18
ret
P_com: sbrc FlagS,Z1 ;выравнивание порядков для “ + ” и “ - ”
ret ; первый операнд =0, чего выравнивать
sbrc FlagS,Z2 ;проверка второго операнда на 0
Pc0: ret
Pc3: cp r17,r18
breq Pc0 ;порядки одинаковые
Pc1: brcs Pc2 ;порядок второго слагаемого больше
rcall SwapO ;корректировать можно только первый операнд
Pc2: push r18 ;будет использоваться - сохраним
mov r30,r1 ; увеличить порядок первого слагаемого
ldi r18,5 ;сдвинув мантису из 5 байт
clc ;с добавлением нуля слева
rcall s_R ;вправо на один бит
pop r18
inc r17 ;что и отметим в порядке
rjmp Pc3 ;повторим до выравнивания
Copy: mov r30,r16 ;копирование блока байтов длиной r18 из (r16) в (r17)
ld r19,Z+
mov r16,r30
mov r30,r17
st Z+,r19
mov r17,r30
dec r18
brne Copy
ret
M_com: push r16 ;дополнение (смена знака) мантисы для “ + ” и “ - ”
push r17
sub r17,r17 ;очистить уменьшаемый регистр и перенос
mc1: ld r16,Z
sbc r17,r16 ;вычесть прежнюю мантису
st Z+,r17 ;сохранить разность
clr r17
dec r18
brne Mc1
pop r17
pop r16
ret
F_sub: mov r30,r2 ;процедура вычитания 6-ти байтовых плавающих
rcall PCM ;сменить знак второго операнда
rcall F_add ;сложить операнды
mov r30,r2
PCM: subi r30,-5 ;смена знака операнда без коррекции мантисы
ld r16,Z ;порядок операнда
subi r16,-128 ;сменить знак числа
st Z,r16 ;сохранить с измененным знаком
ret
inv_T: bld r16,0 ;инвертирование бита Т регистра статуса
inc r16 ;сменим младший бит на противоположный
bst r16,0 ;сохраним
ret
Nul_1: mov r16,r2 ;сложение второго операнда с нулевым первым
bst FlagS,S2 ;знак сохраним в бите “Т” регистра статуса
rjmp Nul_a
Nul_2: mov r16,r1 ; сложение первого операнда нулевым вторым
bst FlagS,S1 ;знак сохраним в бите “Т” регистра статуса
Nul_a: mov r17,r0 ;адрес результата
ldi r18,6
rcall Copy ;переслать операнд в сумму
rjmp NorM ;нормализовать и закончить
F_add: rcall O_pre ; процедура сложения 6-ти байтовых плавающих
sbrc FlagS,Z1 ;проверка первого операнда на 0
rjmp Nul_1 ; сумма = второй операнд
sbrc FlagS,Z2 ;проверка второго операнда на 0
rjmp Nul_2 ; сумма = первый операнд
bst FlagS,S1 ;знак результата сохраним в бите “Т” регистра статуса
sbrs FlagS,S1 ; первый операнд отрицательный
rjmp p1x ; положительный
sbrs FlagS,S2 ; второй отрицательный
rjmp Fa3 ; положительный: знаки разные - вычитание
rjmp Fa2 ;оба отрицательных
p1x: sbrs FlagS,S2 ; а второй отрицательный ?
rjmp Fa2 ; оба положительных - сложение
Fa3: sbr FlagS,1‹‹oper ; вычитание
rcall Fa_sU ;выполнить операцию
sbrc FlagS,SwP ;если операнды переставлены, то
rcall inv_T ;проинвертировать бит знака результата
brcc Fa2_0 ;заем не нужен
mov r30,r0 ;указатель на результат
ldi r18,5 ;5 байтов мантисы
rcall M_com ;проинвертировать мантису
rcall inv_T ;проинвертировать бит знака результата
clc
rjmp Fa2_0 ;восстановление порядка результата
Fa2: cbr FlagS,1‹‹oper ; суммирование
rcall Fa_sU ;выполнить сложение беззнаковых
Fa2_0: inc r17
Fa2_1: brcs Fa1 ;ведущая единица присутствует
mov r30,r0
ldi r18,5
rcall s_L ;сдвинуть влево
dec r17 ;уменьшить порядок
rjmp Fa2_1 ;повторить до завершения нормализации
Fa1: mov r30,r0 ;адрес результата
subi r30,-6
st -Z,r17 ;записать порядок
NorM: ;процедура нормализации операндов и результата
sbrs FlagS,SwP ;операнды переставлены ?
rjmp Nrm1 ;нет
rcall SwapO ;переставить операнды местами
Nrm1: BLD r17,0 ;вызвать знак результата
ror r17 ;в бит переноса
mov r30,r0 ; результат
ldi r18,6 ; все 6 байтов
rcall s_R ;привести в стандартный вид
Nrm2: mov r30,r2 ;восстановим второй операнд
subi r30,-4 ;старший байт мантисы
ld r16,Z ;погасить ведущую единицу
rol r16
st Z,r16
ldi r18,2 ;сдвинем порядок и старший байт
clc
sbrc FlagS,S2 ;если второй операнд отрицательный
sec ;вернуть ему знак
rcall s_R
ret
Fa_sU: ;процедура сложения / вычитания мантис
rcall P_com ;выровняем порядки
push r17 ;сохраним общий порядок
mov r16,r1 ;первый операнд
mov r17,r0 ;на место суммы
ldi r18,5 ; 5 байтов мантисы
rcall Copy ; скопируем
mov r3,r0
sub r3,r2 ;смещение от результата до второго слагаемого
rcall Nasa ;произвести операцию в аккумуляторе
pop r17 ;восстановим порядок результата
ret
NuM_1: rcall Null
rjmp Nrm2 ;восстановить второй операнд
Null: mov r30,r0 ;очистка аккумулятора мантис
ldi r18,6
Nul1: clr r16
st Z+,r16
dec r18
brne Nul1
ret
CsmD: clr r16 ;формирование знака произведения и частного
sbrc FlagS,S1 ;знак первого операнда
inc r16 ;отрицательный
sbrc FlagS,S2 ;второго
inc r16 ;знак результата - сумма знаков операндов
bst r16,0 ;в бит “Т” регистра статуса
ret
F_mul: rcall O_pre ;умножение с плавающей точкой
sbrc FlagS,Z1 ;проверка первого операнда на 0
rjmp NuM_1 ; результат тоже 0
sbrc FlagS,Z2 ;проверка второго операнда на 0
rjmp NuM_1
rcall CsmD ;определить знак результата
subi r17,127 ;компенсируем добавку порядка
add r17,r18 ;порядки сложим для операции умножения
push r17 ;запомнить порядок
rcall m40u ;перемножить мантисы
pop r17
inc r17
rjmp Fa2_0 ;завершить
F_div: rcall O_pre ; деление с плавающей точкой
sbrc FlagS,Z1 ;проверка первого операнда на 0
rjmp NuM_1 ; результат тоже 0
sbrc FlagS,Z2 ;проверка второго операнда на 0
rjmp NuM_1
sub r17,r18 ;вычтем порядки для операции деления
subi r17,-127 ;добавка смещения порядка
push r17 ;сохранить порядок
rcall Null ;очистить аккумулятор - младшие биты делимого
rcall d40u ;поделим мантисы - целочисленно
pop r17
brtc Fd1 ;дополнительная коррекция не требуется
dec r17 ;уменьшить порядок
Fd1: dec r17
rcall CsmD ;определить знак результата
rjmp Fa2_0 ;завершить
;************************************************* ***********************************
; Деление 40 (80) - битовое без знака. Использует регистры r3, r16, r17, r18, r19, r20.
;* для целых: вход d40I. (r0) - старшие 5 байт делимого, (r1) - 5 младших, (r2) - делитель
;* для мантис: вход d40u. (r1) - делимое, (r2) - делитель, (r0) - результат
;* После операции в (r1) остаток от деления, в (r0) - частное
; ************************************************** *********************************
d40I: mov r3,r0 ;вход при операциях с целыми
sub r3,r2 ;смещение от делимого до делителя
rjmp d40_11
d40u: push r0 ;для использования уже отлаженных процедур
mov r0,r1 ;делимое переставим с результатом (указатели)
pop r1
mov r3,r0
sub r3,r2 ;смещение от делимого до делителя
sbr FlagS,1‹‹oper ; вычитание
rcall Nasa ;выполнить
in r17,Sreg ;сохранить статус
rcall neit ;восстановить делимое
out Sreg,r17 ;восстановить результат вычитания - сравнения
set ; установить бит Т
brcs d40_1 ;делимое не корректируем, порядок - да
clt ;сбросить признак коррекции порядка
clc
mov r30,r0 ;делимое, как и делитель
rcall R_S5 ;сдвинем вправо на 5 битов
d40_1: clc
mov r30,r2 ;делитель
rcall R_S5 ;сдвинем вправо для освобождения старшего бита
d40_11: ldi r17,41 ;счетчик циклов
d40_2: sbr FlagS,1‹‹oper ; вычитание
rcall Nasa ;выполнить
brcc d40_3 ;if result negative
rcall neit ;восстановить делимое
clc ; clear carry to be shifted into result
rjmp d40_4 ;else
d40_3: sec
d40_4: mov r30,r1 ;временное хранение результата
rcall L_S5 ;задвинуть результирующий бит
mov r30,r0 ;частный остаток
rcall L_S5 ;также сдвинуть влево
dec r17
brne d40_2
mov r30,r0
rcall R_S5 ;восстановить остаток
push r0
mov r0,r1 ; поместить результат на место (указатели)
pop r1
ret