Масштабирование 16-разрядных данных АЦП в 16-разрядный результат. http://caxapa.ru/135412.html
;*************************************************************************
; Умножение знаковых и беззнаковых 16-битных данных (d) на знаковый или
; беззнаковый 16-битный коэффициент k с получением 16-битного результата
; (например, для масштабирования значений АЦП).
;
; Диапазон беззнаковых значений: 0x0000..0xFFFF в прямом коде
; Диапазон знаковых значений: 0x8000..0x7FFF в дополнительном коде
; Интерпретация этих значений как действительных чисел зависит от под-
;  разумеваемого положения десятичных точек в каждом конкретном случае.
;
; Точность результатов без округления: [0,0..1,0) младшего разряда
; Точность результатов с округлением: [-0,5..0,5) младшего разряда
;
; Обсуждение в конфе AVR от 11.10.2008 - http://caxapa.ru/134681.html
;*************************************************************************
;-------------------------------------------------------------------------
; Scaling test code
;-------------------------------------------------------------------------
.equ    d = 0x40C0
.equ    k = 0x40C0
.include <m128def.inc>
        ldi r16, high(RAMEND)
        out SPH, r16
        ldi r16, low(RAMEND)
        out SPL, r16
scalings:
; unsigned*unsigned scaling test
;   1. Беззнаковые данные, беззнаковый коэффициент и беззнаковый результат.
        ldi     r20,low(d)          ; unsigned
        ldi     r21,high(d)
        ldi     r22,low(k)          ; unsigned
        ldi     r23,high(k)
        rcall   scale16uu           ; unsigned r19r18      
; signed*unsigned scaling test
;   2. Знаковые данные, беззнаковый коэффициент и знаковый результат.
        ldi     r20,low(d)          ; signed
        ldi     r21,high(d)
        ldi     r22,low(k)          ; unsigned
        ldi     r23,high(k)
        rcall   scale16su           ; signed r19r18         
; unsigned*signed scaling test
;   3. Беззнаковые данные, знаковый коэффициент и знаковый результат.
        ldi     r20,low(k)          ; signed
        ldi     r21,high(k)
        ldi     r22,low(d)          ; unsigned
        ldi     r23,high(d)
        rcall   scale16su           ; signed r19r18         
; signed*signed scaling test
;   4. Знаковые данные, знаковый коэффициент и знаковый результат.
        ldi     r20,low(d)          ; signed
        ldi     r21,high(d)
        ldi     r22,low(k)          ; signed
        ldi     r23,high(k)
        rcall   scale16ss           ; signed r19r18  
        rjmp    scalings
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
; Scaling routines
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
; Scales unsigned r21:r20 by unsigned r23:r22 value
;
; Any registers can be used as operands
;
; Result stored in r19:r18
; 17 program words, 20 clocks + ret
;
;   1. Беззнаковые данные, беззнаковый коэффициент и беззнаковый результат.
;   r21:r20 данные АЦП в диапазоне  0x0000..0xFFFF | 0.16-> 0,0..1,0 | 0.16-> 0,0..1,0
;   r23:r22 коэффициент в диапазоне 0x0000..0xFFFF | 0.16-> 0,0..1,0 | 16.0-> 0..65535
;   r19:r18 результат в диапазоне   0x0000..0xFFFF | 0.16-> 0,0..1,0 | 16.0-> 0..65535
;   r19:r18:r17 = r23:r22 * r21:r20
scale16uu:
        clr     r2
        mul     r23,    r21
        movw    r18,    r0
        mul     r22,    r20
        mov     r17,    r1
        mul     r23,    r20
        add     r17,    r0
        adc     r18,    r1
        adc     r19,    r2
        mul     r21,    r22
        add     r17,    r0
        adc     r18,    r1
        adc     r19,    r2
        subi    r17,    low(-128)       ; truncation
        sbci    r18,    high(-128)
        sbci    r19,    byte3(-128)
        ret        
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
; Scales signed r21:r20 by unsigned r23:r22 value
;
; Only r16..r23 registers can be used as operands
; due to the xMULSx command limitations
;
; Result stored in r19:r18
; 18 program words, 21 clocks + ret
;
;   2. Знаковые данные, беззнаковый коэффициент и знаковый результат.
;   r21:r20 данные АЦП в диапазоне  0x8000..0x7FFF | 0.16-> -0,5..0,5 | 0.16-> -0,5..0,5
;   r23:r22 коэффициент в диапазоне 0x0000..0xFFFF | 0.16->  0,0..1,0 | 16.0-> 0..65535
;   r19:r18 результат в диапазоне   0x8000..0x7FFF | 0.16-> -0,5..0,5 | 16.0-> -32767..32767
;   3. Беззнаковые данные, знаковый коэффициент и знаковый результат.
;   r21:r20 коэффициент в диапазоне 0x8000..0x7FFF | 0.16-> -0,5..0,5 | 16.0-> -32767..32767
;   r23:r22 данные АЦП в диапазоне  0x0000..0xFFFF | 0.16-> 0,0..1,0  | 0.16-> 0,0..1,0
;   r19:r18 результат в диапазоне   0x8000..0x7FFF | 0.16-> -0,5..0,5 | 16.0-> -32767..32767
;   r19:r18:r17 = r23:r22 * r21:r20
scale16su:
        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
        subi    r17,    low(-128)       ; truncation
        sbci    r18,    high(-128)
        sbci    r19,    byte3(-128)
        ret        
;-------------------------------------------------------------------------
;-------------------------------------------------------------------------
; Scales signed r21:r20 by signed r23:r22 value
;
; Only r16..r23 registers can be used as operands
; due to the xMULSx command limitations
;
; Result stored in r19:r18
; 20 program words, 23 clocks + ret
;
;   4. Знаковые данные, знаковый коэффициент и знаковый результат.
;   r21:r20 данные АЦП в диапазоне  0x8000..0x7FFF | 0.16-> -0,5..0,5 | 1.15-> -1,0..1,0
;   r23:r22 коэффициент в диапазоне 0x8000..0x7FFF | 1.15-> -1,0..1,0 | 0.16-> -0,5..0,5
;   r19:r18 результат в диапазоне   0x8000..0x7FFF | 0.16-> -0,5..0,5 | 0.16-> -0,5..0,5
;
;   r21:r20 данные АЦП в диапазоне  0x8000..0x7FFF | 1.15-> -1,0..1,0     | 0.16-> -0,5..0,5
;   r23:r22 коэффициент в диапазоне 0x8000..0x7FFF | 16.0-> -32767..32767 | 17.0-> -65535..65535
;   r19:r18 результат в диапазоне   0x8000..0x7FFF | 16.0-> -32767..32767 | 16.0-> -32767..32767
;   Для формата 17.0 в R21:R20 записывать только 16 старших разрядов коэффициента
;   r19:r18:r17 = ( r23:r22 * r21:r20 ) << 1
scale16ss:
        clr     r2
        fmuls   r23,    r21
        movw    r18,    r0
        fmul    r22,    r20
        adc     r18,    r2
        mov     r17,    r0
        fmulsu  r23,    r20
        sbc     r19,    r2
        add     r17,    r0
        adc     r18,    r1
        adc     r19,    r2
        fmulsu  r21,    r22
        sbc     r19,    r2
        add     r17,    r0
        adc     r18,    r1
        adc     r19,    r2
        subi    r17,    low(-128)       ; truncation
        sbci    r18,    high(-128)
        sbci    r19,    byte3(-128)
        ret        
;-------------------------------------------------------------------------