📄 math.asm
字号:
;==============================================================================
; Procedury matematyczne
; Projekt: Miernik energii i mocy na ADE7759
;==============================================================================
; r0, r1, r2 -rejestry operacyjne, r2=0
.def bit0 =r27
.def bit1 =r28
.def p0 =r24
.def p1 =r25
.def p2 =r26 ; wynik pierwiastka
.def n0 =r10
.def n1 =r11
.def n2 =r12
.def n3 =r13
.def n4 =r14
.def n5 =r15 ; liczba pierwiastkowana
; wynik kwadratu
;.def kwd5:0 =r23:r18 ; deklaracja w int2.asm
; takie rozmieszczenie rejestrow nie powoduje koniecznosci zapisu r9::r4 (i_suma) do RAM
.cseg
;------------------------------------------------------------------------------
KWADRAT_16: ; (p1:p0)^2 ==> kwd3:kwd2:kwd1:kwd0
; korzysta z r0, r1, r2 oraz r2=0
clr r2 ; r2 zawsze rowny 0
mul p1, p1
movw kwd2, r0 ; kwd3:kwd2 <== r1:r0
mul p0, p0
movw kwd0, r0 ; kwd1:kwd0 <== r1:r0
mul p1, p0
lsl r0
rol r1
rol r2 ; wynik ostatniego mul razy 2
add kwd1, r0
adc kwd2, r1
adc kwd3, r2 ; dodaj podwojony iloczyn
ret
; cykli 15+ret
;==============================================================================
; PIERW_32
; Pierwiastek z liczby 4-bajtowej (typ BISEKCJA)
; PIERW_32 -> wejscie w N3:N2:N1:N0, wyjscie w P1:P0
; cykle: max 470, min 60
;==============================================================================
PIERW_32:
ldi kwd0, 0b10000000 ; bit1:bit0 = 2^15
mov bit1, kwd0 ; zaladowanie licznika bitowego
clr bit0
clr p1
clr p0
clr r2
P32_P: add p0, bit0 ; liczba petli nie wieksza niz ilosc bitow zmiennej bit (16)
adc p1, bit1
rcall KWADRAT_16 ; (P1:P0)^2 = kwd3:kdw2:kwd1:kwd0
cp kwd0, n0
cpc kwd1, n1
cpc kwd2, n2
cpc kwd3, n3 ; porownanie kwadratu pierwiastka (p) z liczba pierwiastkowana
brlo P32_MNIEJ ; skacz jesli kwd3:... mniejsze od n3:...
breq P32_KON ; skacz jesli rowne
sub p0, bit0
sbc p1, bit1 ; jesli kwd3:... wieksze to odejmij
P32_MNIEJ: lsr bit1 ; przesun bit w prawo
ror bit0
brcc P32_P ; jesli bit nie wyszedl do C to nastepna petla
P32_KON: ret ; P1:P0 zawiera pierwiastek calkowity z N3::N0
;==============================================================================
; DIV_48_16
; Dzielenie bez znaku liczby 6-bajtowej przez 2 bajtowa
; n5::n0 = n5::n0 / y1:y0, reszta w rsz1:rsz0
; UWAGA: rejestry dzielnej (n) sa zmieniane
; cykli: okolo 910
;==============================================================================
; dzielnik:
;.def n5:0 =r15:r10 deklaracja w PIERW_48
.def y0 =r30 ; (probek0)
.def y1 =r31 ; (probek1)
.def rsz0 =r0
.def rsz1 =r1 ; reszta (niewykorzystywana w RMS)
.def dic =r24 ; licznik
DIV_48_16: ldi dic, 49 ;init loop counter
clr rsz0 ;clear remainder Low byte
sub rsz1, rsz1 ;clear remainder High byte and carry
rjmp D48_1
D48_0: sec
D48_1: rol n0 ;shift left dividend
rol n1
rol n2
rol n3
rol n4
rol n5
dec dic ;decrement counter
breq D48_2 ;if done (zero) - return
rol rsz0 ;shift dividend into remainder
rol rsz1
brcs D48_3 ; jesli bit wychodzi z rsz1 nalezy go wprowadzic do n0
sub rsz0, y0 ;remainder = remainder - divisor
sbc rsz1, y1
brcc d48_0 ;if result negative
add rsz0, y0 ; restore remainder
adc rsz1, y1
clc ; clear carry to be shifted into result
rjmp D48_1 ;else get next bit
D48_3: sub rsz0, y0 ; rsz = rsz - y (poniewaz rsz jest wieksze)
sbc rsz1, y1
rjmp d48_0
D48_2: ret
;==============================================================================
; MUL_16_16
; mnozenie 16bit przez 16bit => 32bit
; kwd3::kwd0 = n1:n0 * mn1:mn0
; cykli: 17+ret
;==============================================================================
; korzysta z r0, r1, r2 oraz:
.def mn0 =r24
.def mn1 =r25 ; mnoznik
;.def n1:0 =r11:r10 deklaracja w PIERW_48
;.def kwd5:0 =r23:r18 ; deklaracja w int2.asm
MUL_16_16: clr r2
mul mn1, n1
movw kwd2, r0
mul mn0, n0
movw kwd0, r0
mul mn1, n0
add kwd1, r0
adc kwd2, r1
adc kwd3, r2
mul mn0, n1
add kwd1, r0
adc kwd2, r1
adc kwd3, r2
ret
;==============================================================================
; MUL_24_16
; mnozenie 24bit przez 16bit => 40bit
; kwd4::kwd0 = n1:n0 * mn2::mn0 (mn2::mn0 = p2::p0)
; cykli: 31+ret
;==============================================================================
.def mn2 =r26 ; mnoznik, bajt trzeci
MUL_24_16: rcall MUL_16_16 ; mnozenie dwoch mlodszych bajtow: n1:n0 x mn1:mn0
clr kwd4
;clr r2 ; w MUL_16_16
mul n0, mn2
add kwd2, r0
adc kwd3, r1
adc kwd4, r2
mul n1, mn2
add kwd3, r0
adc kwd4, r1
ret
;==============================================================================
; MUL_32_16
; mnozenie 32bit przez 16bit => 48bit
; kwd5::kwd0 = n3::n0 * mn1:mn0, ale wykorzystuje n5::n0 !
; cykli: 52+ret
;==============================================================================
MUL_32_16: rcall MUL_16_16 ; mnozenie dwoch mlodszych bajtow: n1:n0 x mn1:mn0
movw n0, n2 ; przerzut starszych bajtow do mlodszych
movw n2, kwd0
movw n4, kwd2 ; kopia wyniku
rcall MUL_16_16 ; mnozenie n3:n2 x mn1:mn0
movw kwd4, kwd2
movw kwd2, kwd0 ; starsze bajty na starsze miejsca wyniku
movw kwd0, n2 ; dodanie pierwszego mnozenia
add kwd2, n4
adc kwd3, n5
adc kwd4, r2
adc kwd5, r2
ret
;==============================================================================
; BIN_7_BCD (max. 0x63=99d)
; konwersja niepelnego bajtu na BCD (2 bajty)
; wejscie w bcd0, wyjscie w bcd1:bcd0
; cykli: 5/50 +ret
; words: 7
;==============================================================================
BIN_7_BCD: clr bcd1 ;clear result MSD
B7B_1: subi bcd0, 10 ;input = input - 10
brcs B7B_2 ;abort if carry set
inc bcd1 ;inc MSD
rjmp B7B_1 ;loop again
B7B_2: subi bcd0, -10 ;compensate extra subtraction
ret
;==============================================================================
; BIN_16_BCD
; konwersja 2 bajtow do spakowanego BCD (3 bajty)
; wejscie w bin1:bin0, wyjscie w bcd2::bcd0
; rejestry bin? sa zmieniane!
; cykli: 760+ret
; words: 32
; Pointers used: Y
;==============================================================================
.equ adrbcdl =18 ; adres rejestru LSB(bcd)
.equ adrbcdh =20 ; adres rejestru MSB(bcd)
.def bin0 =r6 ;binary value Low byte
.def bin1 =r7
.def bin2 =r8
.def bin3 =r9
.def bcd0 =r18 ;BCD value digits 1 and 0
.def bcd1 =r19 ;BCD value digits 3 and 2
.def bcd2 =r20 ;BCD value digit 5 i 4
.def bcd3 =r21 ;BCD value digit 7 i 6
.def bcd4 =r22 ;BCD value digit 9 i 8
.def lcz16 =r10 ;loop counter
BIN_16_BCD: ldi temp, 16
mov lcz16, temp ;Init loop counter
clr bcd4 ;clear result (5 bytes)
clr bcd3
clr bcd2 ;clear result (3 bytes)
clr bcd1
clr bcd0
clr yh
B16B_1: lsl bin0 ;shift input value
rol bin1 ;through all bytes
rol bcd0 ;
rol bcd1
rol bcd2
dec lcz16 ;decrement loop counter
brne B16B_2 ;if counter not zero
ret
B16B_2: ldi yl, adrbcdh+1 ; Y points to result adr(bcd2)+1
B16B_3:
ld temp, -Y ;get (Y) with pre-decrement
subi temp, -0x03 ;add 0x03
sbrc temp, 3 ;if bit 3 not clear
st Y, temp ; store back
ld temp, Y ;get (Y)
subi temp, -0x30 ;add 0x30
sbrc temp, 7 ;if bit 7 not clear
st Y, temp ;store back
cpi yl, adrbcdl ;done all three?
brne B16B_3 ;loop again if not
rjmp B16B_1
;==============================================================================
; BIN_32_BCD
; konwersja 4 bajty do spakowanego BCD (5 bajtow)
; wejscie w bin3::bin0, wyjscie w bcd4::bcd0
; rejestry bin? sa zmieniane!
; cykli: okolo 2500
; words: 26
; Pointers used: Y
;==============================================================================
.equ adrbcd32l =18 ; adres rejestru LSB(bcd)
.equ adrbcd32h =22 ; adres rejestru MSB(bcd)
; reszta deklaracji jak wyzej
.def lcz32 =r10 ;loop counter
BIN_32_BCD: ldi temp, 32
mov lcz32, temp ;Init loop counter
clr bcd4 ;clear result (5 bytes)
clr bcd3
clr bcd2
clr bcd1
clr bcd0
clr yh
B32B_1: lsl bin0 ;shift input value
rol bin1 ;through all bytes
rol bin2
rol bin3
rol bcd0 ;
rol bcd1
rol bcd2
rol bcd3
rol bcd4
dec lcz32 ;decrement loop counter
brne B32B_2 ;if counter not zero
ret
B32B_2: ldi yl, adrbcd32h+1 ; Y points to result adr(bcd4)+1
B32B_3:
ld temp, -Y ;get (Y) with pre-decrement
subi temp, -0x03 ;add 0x03
sbrc temp, 3 ;if bit 3 not clear
st Y, temp ; store back
ld temp, Y ;get (Y)
subi temp, -0x30 ;add 0x30
sbrc temp, 7 ;if bit 7 not clear
st Y, temp ;store back
cpi yl, adrbcd32l ;done all three?
brne B32B_3 ;loop again if not
rjmp B32B_1
;==============================================================================
; ROZPAKUJ_BCD
; konwersja spakowanego bcd do rozpakowanych cyfr po jednej na bajt
; + korekta na tablice znakow LCD
; wejscie w bcd4::bcd0, wyjscie w cyfra9::cyfra0
; cykli: 86
; words: 18
; Pointers used: X, Y
;==============================================================================
.equ adrcyfra0 =6
.def cyfra0 =r6
.def cyfra1 =r7
.def cyfra2 =r8
.def cyfra3 =r9
.def cyfra4 =r10
.def cyfra5 =r11
.def cyfra6 =r12
.def cyfra7 =r13
.def cyfra8 =r14
.def cyfra9 =r15
.def lic_cf =r1
ROZPAKUJ_BCD:
clr yh
ldi yl, adrcyfra0 ; adres rejestrow cyfra
clr xh
ldi xl, adrbcd32l ; adres rejestrow bcd
ldi temp, 5
mov lic_cf, temp ; licznik na 10 cyfr
RB_1: ld temp, x ; zaladuj wartosc bcd (spakowana)
andi temp, 0x0F ; dolna polowka bajtu
ori temp, 0b00110000 ; poprawne ustawienie cyfry w tablicy znakow
st y+, temp ; zapis cyfry
ld temp, x+ ; zaladuj wartosc bcd (spakowana)
swap temp
andi temp, 0x0F ; gorna polowka bajtu
ori temp, 0b00110000 ; poprawne ustawienie cyfry w tablicy znakow
st y+, temp ; zapis cyfry
dec lic_cf
brne RB_1
ret
;==============================================================================
; BCD_8_BIN
; konwersja 1 bajtu spakowanego BCD na 1 bajt bin
; wejscie w bcd0, wyjscie w bin0
; cykli: 12+ret
; words: 10
; rejestry: bcd0, bin0, r0, r1, temp
;==============================================================================
BCD_8_BIN:
push bcd0 ; kopia
swap bcd0 ; gorna polowka
andi bcd0, 0x0F
ldi temp, 10
mul bcd0, temp ; mnozenie: "dziesiatek" x 10
pop bcd0
andi bcd0, 0x0F ; dolna polowka
add r0, bcd0 ; suma dziesiatek i jednosci
mov bin0, r0
ret
;==============================================================================
.exit
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -