Вот два примера, когда Ваша подпрограмма, выставленная в исходниках, работает неправильно. http://src.caxapa.ru/329
http://caxapa.ru/135412.html
;-------------------------------------------------------------------------
; Scaling test code
;-------------------------------------------------------------------------
.include <m128def.inc>
ldi r16, high(RAMEND)
out SPH, r16
ldi r16, low(RAMEND)
out SPL, r16
scalings:
; unsigned*signed scaling test
; Проверяем правильность работы Вашей подпрограммы на таких данных
ldi r16,low(0x2080) ; coeff = 0,25390625
ldi r17,high(0x2080)
ldi r18,low(0x4000) ; myint = 16384
ldi r19,high(0x4000)
; 0,25390625*16384=4160=0x1040 Microsoft Калькулятор
rcall scale16us
; r9r8 = 0x1020
; Результат неправильный!!!
; Это не неточность вычисления а неправильность вычисления
; изза совместного (неправильного) использования fmulх и mulх
; Проверяем правильность работы моей подпрограммы
; У меня диапазон коэффициента -0,5..0,5 в формате 0.16
ldi r20,low(0x4100) ; coeff = 0,25390625
ldi r21,high(0x4100)
ldi r22,low(0x4000) ; myint = 16384
ldi r23,high(0x4000)
rcall scale16us_
; r19r18 = 0x1040
; Результат правильный!!!
; Вывод: Нельзя использовать MULx совместно с FMULx без учета
; сдвига результата последней командой.
; Теперь проверим как Ваш вариант справится с значением 0xB000.
; Это значение нормально попадает в 16-ти разр-й unsigned. И коэф = 0,75
ldi r16,low(0x6000) ; coeff = 0,75
ldi r17,high(0x6000)
ldi r18,low(0xB000) ; myint = 45056
ldi r19,high(0xB000)
; 0,75*45056=33792=0x8400 Microsoft Калькулятор
; Сразу видно что не помещается в 16-ти разр-й signed
; Вместо положительного результата ожидается отрицательный
rcall scale16us
; r9r8 = 0x8400 = -31744
; Результат неправильный!!!
; Вывод: Нельзя использовать FMULx для unsigned*signed scaling,
; возможно переполнение.
; Проверяем правильность работы моей подпрограммы
; У меня диапазон коэффициента -0,5..0,5 в формате 0.16
; Поэтому такое-же двоичное значение означает другое десятичное
ldi r20,low(0x6000) ; coeff = 0,75/2=0,375
ldi r21,high(0x6000)
ldi r22,low(0xB000) ; myint = 45056
ldi r23,high(0xB000)
; 0,375*45056=16896=0x4200 Microsoft Калькулятор
rcall scale16us_
; r19r18 = 0x4200
; Результат правильный!!!
; Переполнение при тех-же двоичных данных не возникает.
rjmp scalings
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
; Scaling routines
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
; Scales unsigned int r19r18 by signed r17r16 value
; presented as signed fractional (0x8000 = -1, 0x7FFF = +0.99998)
;
; Only r16..r23 registers can be used as operands
; due to the xMULSx command limitations
;
; Result stored in r9r8
; 15 program words, 18 clocks + ret
;
; (c) 2008 leon_, MBedder
;
scale16us:
clr r2
fmulsu r17,r19 ; r19r18 = 23456, r17r16 =~ -0.76543*32768
movw r8,r0
mul r18,r16
mov r7,r1
mul r19,r16
add r7,r0
adc r8,r1
adc r9,r2
fmulsu r17,r18
sbc r9,r2
add r7,r0
adc r8,r1
adc r9,r2 ; r9r8 =~ 23456*-0.76543 ~= 0xB9DC =~ -17956
ret
;-------------------------------------------------------------------------
; 3. Беззнаковые данные, знаковый коэффициент и знаковый результат.
; данные АЦП в диапазоне 0x0000..0xFFFF | 0.16-> 0,0..1,0 | 0.16-> 0,0..1,0
; коэффициент в диапазоне 0x8000..0x7FFF | 0.16-> -0,5..0,5 | 16.0-> -32767..32767
; результат в диапазоне 0x8000..0x7FFF | 0.16-> -0,5..0,5 | 16.0-> -32767..32767
; r19:r18:r17:r16 = r23:r22 * r21:r20
scale16us_:
clr r2
mulsu r21, r23
movw r18, r0
mul r22, r20
mov r17, r1
mul r23, r20
add r17, r0
adc r18, r1
adc r19, r2
mulsu r21, r22
sbc r19, r2
add r17, r0
adc r18, r1
adc r19, r2
ret
http://caxapa.ru/135412.html
-
- Спасибо, позже перепроверю/доработаю - MBedder(22.10.2008 16:24)