Uložme si omezení na použití dalších registrů mimo těch, v kterých vnášíme do procedury vstupní údaje (s výjimkou pracovních: Acc a B). Dvojitá úspora (času a registrové paměti) je totiž přesně v duchu "softwarové ekologie" a její nosné myšlenky: z procesoru je možno vytěžit nejvíce, když maximálně šetříme jeho "vnitřní zdroje". Navíc v programech aplikovaná formální konvence volby přiřazení registrů odstraňuje potřebu tzv. "jalových přesunů dat" a podporuje "in-flow" zřetězení rutin podle potřeby
1.Násobení word x word
Postup bude vysvětlen na násobení m16 × 16 bez znaménka.
Protože instrukční soubor rodiny 8051 má pouze násobení byte × byte, běžně je používána rutina s postupným binárním přičítáváním násobence. Tato rutina má pro rozsah word × word celkově 16 iteračních cyklů. Celkový počet cyklů procesoru je pak větší jako 170 cyklů.
Nabízím popis velmi rychlého řešení násobení word x word pro procesory rodiny 8051 (resp. i pro ostatní procesory vybavené 8bitovým násobením) bez použití výše uvedené časově náročné iterační smyčky.
Mějme čísla v bin tvaru v registrech ren3 (Hi byte = m1H) a ren2 (Lo byte = m1L) - pro první násobenec a v registrech ren5 (Hi byte = m2H) a ren4 (Lo byte = m2L) - pro druhý násobenec. Jejich vynásobení pak můžeme zapsat ve tvaru:
(256*ren3 + ren2)*(256*ren5 + ren4) =
po úpravě dostaneme:
65536*(ren3*ren5) + 256(ren2*ren5 + ren4*ren3) + ren2*ren4
nebo podle konvence použité v popisu programu:
65536*(m1H*m2H) + 256(m1H*m2L + m2H*m1L) + m1L*m2L
Vidíme, že potřebujeme pouze 4krát násobení byte × byte - "mul
ab" a vhodný způsob sčítání. Navíc, při zvolení si vhodného
postupu matematických úkonů, nebudeme potřebovat další pomocné registry (kromě
dvou: Acc a B) pro odkládání mezivýsledků při výpočtu.
Výpis programu:
;*********************************************
; násobení 16b x 16b bez znaménka - výsledek 32b
; superrychlá - 54 cykly procesoru
; rozsah kodu (8051) - 50 byte
;*********************************************
; kontrola na nulu násobitele nebo násobence
; není nutná !! (pouze pro skrácení času)
; - max 15 cyklů procesoru, rozsah kódu - 18 byte
; dobu exekuce mul16x16 zvětší o max 9 cyklů
;*********************************************
;vstup v ren3 je bajt_H a ren2 je bajt_L násobence - m1
; v ren5 je bajt_H a ren4 je bajt_L násobitele - m2
;v ren 5 je tedy m2H, v ren4 - m2L,v ren3 - m1H a v ren2 -m1L
;
;výstup v ren5 je 4_byte a ren4 je 3_byte
; v ren3 je 2_byte a ren2 je 1_byte
; v popisu označíme výsledek res po bajtech res4..res1
;v ren 5 je tedy res4, v ren4 - res3,v ren3 - res2 a v ren2 -res1
; mění reg.: Acc,ren2,ren3,ren4,ren5,Psw
; možnost zvolit si prac. registry
ren2 equ r2
ren3 equ r3
ren4 equ r4
ren5 equ r5
;*******
mul16x16k:
clr a
cjne ren5,#0,mul16x16 ;kontrola m2H na 0
cjne ren4,#0,mul16x16e ;kontrola m2L na 0
mov ren2,a ;0 -> m1L
mov ren3,a ;0 -> m1H
mul16x16e:
cjne ren3,#0,mul16x16 ;kontrola m1H na 0
cjne ren2,#0,mul16x16 ;kontrola m1L na 0
mov ren4,a ;0 -> m2L
mov ren5,a ;0 -> m2H
ret
;*******
mul16x16:
push B
mov a,ren5 ;musí odložit m2H
push acc
mov a,ren2 ;m1L do acc
mov b,ren4 ;m2L do B
mul ab ;násobí m1L* m2L
xch a,ren2 ;res1 do ren2 ,m1L do acc
xch a,b ;do b m1L, res2 do acc
xch a,ren5 ;res2 do ren5 , m2H do acc
mul ab ;násobí m2H*m1L
add a,ren5 ;připočítá res2
xch a,ren4 ;res2 do ren4 , m2L do acc
xch a,b ;m2L do b, res3 do acc
addc a,#0 ;zohledni přenos z 2_B do 3
mov f0,C ;zapamatuje přenos z 3_B do 4
xch a,ren3 ;res3 do ren3 , m1H do acc
mov ren5,a ;m1H odloží do ren5
mul ab ;násobí m1H*m2L
add a,ren4 ;připočítá předch. výsled v res2
xch a,ren3 ;res2 do ren3 , res3 do acc
addc a,b ;připočítá novy mezivýsledek ku res3
xch a,ren5 ;m1H do acc , res3 do ren5
mov b,a ;m1H do b
clr a
rlc a ;přenos do 4-bajtu
mov C,f0
addc a,#0 ;přenos do 4-bajtu
mov ren4,a ;ulozi res4 do ren4
pop acc ;m2H do acc
mul ab ;násobí m1H*m2H
add a,ren5 ;připecte res3
xch a,ren4 ;res3 do ren4 , res4 do acc
addc a,b
mov ren5,a ;výsledek 4_bajt
pop b
ret
;*******
1.1.Shrnutí
Z výše uvedeného plyne, že algoritmus nemá žádnou iterační smyčku, je jednoprůchodový, tudíž exekuční doba je konstantní a nezávislá na hodnotě vstupních číslech. Navíc jeho použití přináší trojnásobné zkrácení doby výpočtu oproti klasickému řešení. Násobení word × word pro čísla se znaménkem je potřeba doplnit o znaménkovou aritmetiku.
2. Dělení word / word
Jako u násobení m16 × 16 postup bude vysvětlen na dělení d16/16 bez znaménka. Protože instrukční soubor rodiny 8051 má pouze dělení byte / byte, běžně je používána rutina s postupným binárním odpočítáváním dělitele. Tato rutina má pro rozsah word / word celkově 17 iteračních cyklů. Celkový počet cyklů procesoru je pak větší než 280 až 310 cyklů.
Nabízím popis poměrně rychlého řešení dělení word / word s použitím instrukcí "mul ab" a "div ab". Mějme čísla v bin tvaru v registrech DH (Hi byte ) a DL (Lo byte) - pro dělence a v registrech dih a dil - pro dělitele. Jejich vydělení pak můžeme zapsat ve tvaru:
(256*DH + DL) / (256*dih + dil)
nyní provedeme rozbor možností podle horního bytu dělitele:
A - pro dih různé od 0 dostaneme:
AA - pro DH rovno 0 je výsledek 0, protože:
(256*DH + DL) < (256*dih + dil)
AB - pro DH různé od 0 v první kroku vyžijme toho, že 256*dih >> dil, tedy chyba přiblížení je menší než 1*256 neboli ±1 ve vztahu k dih, pak výraz upravíme do tvaru:
(256*DH + DL) / 256*dih = (DH / dih) + (DL/256* dih)
tj. celá část podílu má pouze dolní byte (DH / dih) s případnou odchylkou -1 a zbytek. Pro DH < dih je výsledek 0. Hodnotu podílu P vypočteme P = div (DH)(dih). Zbytek a korekci určíme odpočítáním od hodnoty dělence výsledku násobení: (256*dih + dil) * P. Jedná se o dělení w/w.
B - pro dih rovno 0 dostaneme:
BA - pro DH rovno O dostaneme:
- div (DL)(dil)
- je to dělení By/By - instrukce "div ab".
BB - pro DH různé od 0 dostaneme dělení w/B výraz můžeme přepsat do tvaru :
(256*DH + DL) / (dil)= div (DH)(dil) * 256 + div (DL)(dil).
Horní byte podílu je roven celé části div (DH)(dil), označme zb/dil - zbytek div (DH)(dil) potom dolní byte podílu vypočteme z výrazu:
(zb/dil)*256 + (DL)/(dil) = (zb*256 + DL)/ dil.
Všimněme si, že dělíme pouze číslem v rozsahu 1 byte, a dále požadovaná operace je totožná s principem binárního dělení (Boothův algoritmus - odečítaní dělitele od zbytku po bitech a přiřazení bitového výsledku 1 když je rozdíl kladný). Víme, že (zb/dil) < dil, počet opakování je 8 (dil je Byte). Všimněme si, že (2*(zb/dil) + bit)/ dil může po použití instrukce "div ab" dáti výsledek pouze 0 nebo 1 plus zbytek v registru B. Zápis řešení vidíme ve smyčce za návěštím divBB1. Pro dělitele > 81H je třeba ošetřit přetečení během kompletace nového dělence.
Poznámka: prvním úkonem podprogramu musí samozřejmě býti kontrola na dělení nulou !! Opět, zvolením si vhodné posloupnosti matematických úkonů, nebudeme potřebovat další pomocné registry (kromě obligátních: Acc a B).
Výpis programu:
;********************************************* ; dělení 16b / 16b bez znaménka ;doba exekuce - min 7 cyklů pro div by 0 ; - w/w max 39 cyklů ; - w/B max 143 cyklů ; - B/B max 27 cyklů ; - průměr 70 cyklů ; rozsah kódu (8051) - 93 byte ;********************************************* ;vstup v DH je bajt_H a DL je bajt_L dělence ;vstup v dih je bajt_H a dil je bajt_L dělitele ;výstup Cy =1 pro div by 0, jinak Cy =0 a ; v DH je bajt_H a DL je bajt_L - zbytku ; v dih je bajt_H a dil je bajt_L - podílu ; ; mění reg.: Acc,DH,DL,dH,dL,b,Psw ; možnost zvolit si prac. registry***** DH equ r3 DL equ r2 dih equ r5 dil equ r4 ;******* div16x16: cjne dih,#0,divAA cjne dil,#0,divBA setb C ret ;divide by 0 divAA: mov a,DH mov b,dih div ab jnz divAB ;výsledek ma H_bajt mov dih,a mov dil,a ret ;divide finalized, result=0 divAB: push b ;odlož zbytek mov DH,a ;ulož vysl_L do rp mov b,dil mul ab xch a,DL subb a,DL xch a,DL pop acc subb a,b jnc divABcont dec DH xch a,DL add a,dil xch a,DL addc a,dih clr C divABcont: xch a,DH mov dil,a mov dih,#0 ret ;divide finalized divBA: mov b,dil mov a,DH div ab mov dih,a ;ulož H_podíl mov DH,b cjne DH,#0,divBB mov b,dil mov a,DL div ab mov dil,a mov DL,b ret divBB: mov DH,#8 divBB1: mov a,DL rlc a mov DL,a mov a,dil xch a,b rlc a jc divBB2 div ab rrc a djnz DH,divBB1 mov a,b xch a,DL ;zbytek do DL, do acc mezivysl_L rlc a mov dil,a ret divBB2: clr C subb a,b mov b,a djnz DH,divBB1 mov a,b xch a,DL ;zbytek do DL, do acc mezivysl_L rlc a mov dil,a ret ;*******
2.1 Shrnutí
Z výše uvedeného plyne, že algoritmus se rozpadne do tří samostatných větví. Pouze tá poslední (dělení word/byte ) má krátkou (a navíc dělenou) iterační smyčku, ale s pevným počtem průchodů. Exekuční doba není proto konstantní a je závislá na hodnotě vstupních čísel. Navíc použití tohoto algoritmu přináší více jako trojnásobné zkrácení doby výpočtu oproti klasickému řešení. Dělení word / word pro čísla se znaménkem je potřeba doplnit o znaménkovou aritmetiku.
3. Převod čísla BCD - 5 nibble -> do tvaru bin word
Opět variace na optimalizované násobeni pro procesory rodiny 8051.
Mějme číslo v BCD tvaru n5, n4n3, n2n1, pak jeho převod do binárního tvaru můžeme zapsat:
(10000D)*n5 + (1000D)*n4 +(100D)*n3 + (10D)*n2 + n1
jednotlivé půlbajty (nibbles) jsou samozřejmě v rozsahu bajtu (<0AH), převeďme konstanty do hexa tvaru :
(2710H)*n5 + (03E8H)*n4 +(64H)*n3 + (0AH)*n2 + n1 =
256*(n5*27H) + n5*10H + 256(n4*03H) + n4*0E8H + n3*64H +n2*0AH + n1 =
256*(n5*27H + 2*n4 +n4) + (n4*0E8H + n3*64H + n2*0AH + n1 + swap(n5))
kde n4*03H jsme nahradili rychlejším násobením 2 a připočtením původní hodnoty a pro n5*10H si stačí uvědomit, pro čísla < 10H jedná se o výměnu nibblů v rámci bajtu - instrukce "swap a". Vidíme, že potřebujeme pouze 4krát násobení byte × byte - "mul ab" a vhodný způsob sčítání. Také zde zvolením si vhodného postupu matematických úkonů, ušetříme na dalších pomocných registrech (kromě Acc a B) pro odkládání mezivýsledků při výpočtu.
Výpis programu:
;*********************************************
; konverze BCD -> bin rozsah čísla do 99 999 (65 535)
; superrychlá - 69 cyklu (max), 54(min)
; rozsah kodu (8051) - 72 byte
;*********************************************
;vstup v re3 je tis_sta a re2 je des_jed
; v acc desítky tisíc
;vystup v re3 je udaj_H a re2 je udaj_L
;
; mění reg.: Acc,re2,re3,psw
; možnost zvolit prac registry******
re2 equ r2
re3 equ r3
;*******
bcd_bin:
push B
push acc ;desítky tisíc do stacku
mov a,re2
anl a,#0F0H ;desítky
swap a
mov b,#10D
mul ab ;n2*0AH
xch a,re2
anl a,#0FH ;jednotky
add a,re2
mov re2,a ;desítky a jednotky spolu bin
mov b,#100D
mov a,re3
anl a,#0FH ;stovky
mul ab ;n3*64H
add a,re2 ;připočti k průběžnému výsledku
mov re2,a
clr a
addc a,b
xch a,re3
anl a,#0F0H ;tisíce -> acc
swap a
mov b,a ;tisíce -> b
add a,acc ;acc * 2
add a,b ;spolu acc = 3* tisíce
add a,re3 ;připočti k průběžnému výsledku
mov re3,a
mov a,#0E8H ;L_byte of 03E8H=1000D
mul ab ;n4*0E8H
add a,re2 ;připočti k průběžnému výsledku
mov re2,a
mov a,b
addc a,re3
mov re3,a
pop acc ;obnoví desítky_tisíc ze stacku
jz converBCDbin_end
mov b,a ;desítky_tisíc -> b
swap a ;násobeni* 10H - L_byte čísla 2710H=10000D
add a,re2
mov re2,a
clr a ;přenos C
addc a,re3
mov re3,a
mov a,#27H ;H_byte čísla 2710H=10000D
mul ab ;n5*27H
add a,re3 ;připočti k průběžnému výsledku
mov re3,a
orl C,b.0 ;carry pro čísla > 65 535
converBCDbin_end:
pop b
ret
;*******
3.1 Shrnutí
Pro vstupní údaj > 65 535D nastane přetečení do 17 bitu, který při výstupu je v příznaku carry (C).
4. Převod čísla word ve tvaru bin -> do tvaru BCD
Pro převody čísel větších jako 100D je všeobecně používaná iterační smyčka s odpočítáváním jednotlivých dekadických řádů (10000D,1000D a 100D), počítadlem průchodů a testem na znaménko výsledku odpočtu. Tato metoda je velmi přehledná a jednoduchá, má však tyto dvě základní nevýhody:
- rychlost převodu závisí od velikosti vstupního čísla (počet průchodů smyčkou)
- po ukončení smyčky pro příslušný řád dostaneme záporný
výsledek, který musíme korigovat na kladný (připočtením dříve
odečítaného
čísla) před spuštěním převodu v dalším desetinném řádu.
Obě nevýhody zpomaluji rychlost převodu a také zvětšují rozsah programu. Mějme číslo v bin tvaru v registrech rii (Hi byte) a ri (Lo byte) v rozsahu od 0 po 65 535D - tj. 0FFFFH. Pro převod potřebujeme zjistit počet obsažených jednotlivých řádů - to jest vydělit vstupní údaj 100D, 1000D a 10000D. Mějme na zřeteli následující skutečnosti:
A - když zjistíme počet tisíců v čísle, tak v něm máme obsažený i počet desetitisíců tj. dostaneme číslo max 65D, z kterého desetitisíce "vyseparujeme" pomocí instrukce "div ab" pro b=10D. Počet tisíců v čísle zjistíme pomocí matematicé konverze - viz bod C.
B - instrukční sada 8051 však obsahuje pouze dělení v rozsahu 8 bitů! Stačí, když si uvědomíme, že 100 = 4*25 (a podobně 1000 = 4*250 a 10000 = 4*2500), jinak řečeno když vstupní údaj vydělíme 4 (dva binární posuvy doprava) - potom výsledek po dělení čtyřmi se nám vejde do rozsahu 1 byte (pro určení počtu stovek), který pak vydělíme 25 - s použitím instrukci div ab. Počet stovek bude v registru A. Celkový zbytek po dělení 100D rekonstruujeme v opačném pořadí - zbytek po dělení (v registru B) násobíme 4 a připočteme zbytek po dělení 4, které jsme navrhli na začátku odseku B.
C - když vydělení vstupního čísla "číslem 4" aplikujeme před určením počtu tisíců - viz odsek A, potom musíme místo číslem 1000D dělit číslem 250D = 0FAH. Vstupní údaj vydělený 4 označme rii/4 horní bajta ri/4 dolní bajt. Co můžeme zapsat ve tvaru :
(rii/4)*256D + (ri/4) = (rii/4)*(250D + 6) + (ri/4) = (rii/4)* 250D + ( (rii/4)*6 + (ri/4) )
z výše uvedeného plyne, že (rii/4) je předběžným počtem tisíců !! Zůstane nám výraz : ( (rii/4)*6 + (ri/4) ), který může mít hodnotu > 256D = 0FFH (ale vždy je menší jako 6*(3FH) + 0FFH = 279H ) Označme horní bajt výsledku výrazu u_H a horní bajt u_L můžeme pak zapsat :
( (rii/4)*6 + (ri/4) ) = u_H*256D + u_L = u_H*250D + (u_H*6 + u_L)
podle přecházejíci úvahy připočteme u_H ku (rii/4) s přihlednutím na případný přenos z výrazu (u_H*6 + u_L) a máme finální počet tisíců! Výsledek výrazu (u_H*6 + u_L) má hodnotu < 256D podle požadavku bodu A.
D - Musíme však pamatovat na specifický případ, že do výpočtu stovek vstupuje hodnota dolního bajtu vstupního údaje, která může býti > 250D (transponovaný tisíc). Podíl takého čísla dělitelem 25D (transponovaná stovka) je pak 0AH = 10D. Potom stačí inkrementovat počet tisíců a vynulovat počet stovek. Jako v programech uvedených dříve, vhodnou posloupností matematických úkonů, se vyhneme nutnosti použití dalších pomocných registrů (kromě : Acc , B pro instrukce "mul", "div" ) pro odkládání mezivýsledků při výpočtu.
Příklad výpisu programu:
;********************************************* ; konverze bin -> BCD pro rozsah čísla do 65 535 ; superrychlá - max 84 cyklů procesoru ; rozsah kodu (8051) - 85 byte ;********************************************* ;vstup v re3 je udaj_H a re2 je udaj_L ;vystup v re3 je tis_sta a re2 je des_jed ; v acc desítky tisíc ; ; mění reg.: Acc,re2,re3, psw ; možnost zvolit prac registry****** re2 equ r2 re3 equ r3 ;******* bin_bc: push B ;odlož obsah B mov a,re3 clr C rrc a ;vydělí re3 číslem 2 = posune o 1 doprava xch a,re2 ;re2->acc, re3/2 ->re2 rrc a ;vydělí re2 číslem 2, b0 re2->C mov f0,C ;bit0 z re2 schová do f0 xch a,re2 ;re2/2->re2 , re3/2->acc clr C rrc a ;vydělí re3/2 číslem 2 = posune o 1 doprava xch a,re2 ;re2/2->acc, re3/4 ->re2 rrc a ;vydělí re2/2 číslem 2, b1 re2->Cy push psw ;odloží b1 re2 do Cy xch a,re2 ;re3/4->acc, re2/4 ->re2 mov re3,a ;re3/4 -> re3 mov b,#06H mul ab add a,re2 ;připočte re2/4 xch a,b ;bajt_H ->acc , bajt_L -> b addc a,#0H jz correct1 xch a,r3 add a,re3 ;konečný počet tisíců xch a,re3 ;konečný počet tisíců -> re3,bajt_H ->acc add a,#06H jbc acc.0,correct4 ;acc byl 1 add a,#04H ;acc byl 2 correct4: add a,b jnc correct3 ;přenos z výrazu (u_H*6 + u_L) - bod C inc r3 add a,#06H correct3: mov b,a correct1: mov a,#25D ;bude dělit 25D tj. 100/4 xch a,b ;b->25D,zbytek po dělení 1000D -> acc div ab ;v acc stovky , v b zbytek cjne a,#10D,correct2 ;viz bod D clr a inc re3 correct2: mov re2,a ;re2 ->počet stovek mov a,#10D ;pro určení desítek xch a,b ;b->10D,zbytek po dělení 100D -> acc pop psw ;;obnoví b1 z re2 v Cy rlc a mov C,f0 ;násobí 4 a doplňuje odložené rlc a ;bity div ab swap a orl a,b ;BCD desítky_jednotky -> acc xch a,re3 ;acc -> re3,konečný počet tisíců -> acc mov b,#10D ;pro urceni desitek tisic div ab ;v acc desitky tisic , v b tisice xch a,b ; acc <-> b swap a ;tisice do H_nibble orl a,re2 ;BCD tisíce a sta -> acc xch a,re3 ;BCD desítky_jednotky -> acc,BCD tisice a sta -> re3 mov re2,a ;BCD desítky_jednotky -> re2 mov a,b ;odložené des_tisíc do Acc pop b ;obnova b ret ;*******
4.1. A teď trochu rozšířená funkčnost procedúry:
( doufám, že anglický komentař není prřekážkou)
;********************************************* ; konverze bin -> BCD pro rozsah čísla do to 131 071 ; superrychlá - průměr 85 cyklů procesoru ; max 100 cyklů procesoru ; velkost kodu - 77 byte ;********************************************* ;vstup v re3 je udaj_H a re2 je udaj_L ; v Cy je bit b17 - v bin formatu ;vystup v re3 je tis_sta a re2 je des_jed ; v acc stovky_tisíc a desítky_tisíc- v BCD formatu ; ; mění reg.: Acc,re2,re3, psw ; možnost zvolit prac registry****** re2 equ r2 re3 equ r3 ;******* bin_bc16: clr C bin_bc17: push B ;store content of B mov a,re3 rrc a ;to divide re3 with 2 = to shift one right xch a,re2 ;re2->acc, re3/2 ->re2 rrc a ;to divide re2 with 2, b0 re2->C mov f0,C ;bit0 from re2 in f0 xch a,re2 ;re2/2->re2 , re3/2->acc clr C rrc a ;to divide re3/2 with 2 = to shift one right xch a,re2 ;re2/2->acc, re3/4 ->re2 rrc a ;to divide re2/2 with 2, b1 re2->C push psw ;store b1 re2 in Cy xch a,re2 ;re3/4->acc, re2/4 ->re2 mov re3,a ;re3/4 -> re3 corre4: mov b,#06H mul ab add a,re2 ;to add re2/4 mov re2,a ;store result xch a,b ;byte_H ->acc , byte_L -> b addc a,#0H jz corre1 xch a,r3 add a,re3 ;final count of thousands xch a,re3 ;final count of thousands -> re3,bajt_H ->acc sjmp corre4 corre1: mov a,#25D ;will to divide 250 = 100/4 xch a,b ;b->25D,remainder of divide 1000D -> acc div ab ;in acc hundreds , in b remainder cjne a,#10D,corre2 clr a inc re3 corre2: mov re2,a ;count of hundreds -> re2 mov a,#10D ;for tens xch a,b ;b->10D,remainder of divide 100D -> acc pop psw ;restore b1 of re2 in Cy rlc a mov C,f0 ;to multiply by 4 and to comlete rlc a ;stored bits div ab swap a orl a,b ;BCD tens and units -> acc xch a,re3 ;acc -> re3,final count of thousands -> acc mov b,#10D ;for calculate tenththousands div ab ;in acc tenththousands , in b thousands xch a,b ; acc <-> b swap a ;thousands into H_nibble orl a,re2 ;BCD thousands and hundreds -> acc xch a,re3 ;BCD tens and units -> acc,BCD thousands_hundreds -> re3 mov re2,a ;BCD tens and units -> re2 mov a,b ;stored tenththousands into Acc add a,#0 da a ;tenththousands into BCD pop b ;rebuilt of reg b ret
4.2.Shrnutí
Z výše uvedeného plyne, že 1.algoritmus nemá žádnou iterační smyčku, je jednoprůchodový a proto je extrémně rychlý. Druhý má krátkou korekční smyčku (návěští - "corre4: " s max počtem průchodů -2).
Pro úplnost připojuji banální rutiny pro sčítání a odčítání.
5.Sčítání word+ word
;********************************************* ; součet 16b + 16b - result 16b ; rychlý - 8 cycklů processoru ; kód - 7 byte ;********************************************* ;Vstup v ren3 je byte_H , ren2 je byte_L prvního sčítance -m1 ; v ren5 je byte_H , ren4 je byte_L druhého sčítance -m2 ; tj.:v ren 5 je m2H, v ren4 - m2L, ren3 - m1H , ren2 -m1L ; ;výstup v ren5 je byte_H , ren4 je byte_L součtu ;v příznaku Cy může být přetečení ; mění reg.: Acc,re4,re5, psw ; možnost zvolit prac registry****** ren2 equ r2 ren3 equ r3 ren4 equ r4 ren5 equ r5 ;******* add16to16: xch a,ren4 ;m2L <-> acc add a,ren2 xch a,ren5 ;m2H <-> result of Lbytes sum addc a,ren3 xch a,ren5 ;result of Lbytes sum <-> result of Hbytes sum xch a,ren4 ;acc <-> result of Lbytes sum ret ;*******
6.Sčítání word - word
Analogicky jakou součet.
;********************************************* ; rozdíl 16b + 16b - result 16b ; rychlý - 9 cycklů processoru ; kód - 8 byte ;********************************************* ;Vstup: v ren3 je byte_H , ren2 je byte_L odčítance -m1 ; v ren5 je byte_H , ren4 je byte_L odčítatele -m2 ; tj.:v ren 5 je m2H, v ren4 - m2L, ren3 - m1H , ren2 -m1L ; ;výstup: v ren5 je byte_H , ren4 je byte_L rozdílu ;v příznaku Cy může být přetečení, v příznaku OV - znaménko ; mění reg.: Acc,re4,re5, psw ; možnost zvolit prac registry****** ren2 equ r2 ren3 equ r3 ren4 equ r4 ren5 equ r5 ;******* sub16to16: xch a,ren4 ;m2L <-> acc clr C ;necessarily subb a,ren2 xch a,ren5 ;m2H <-> result of Lbytes odds subb a,ren3 xch a,ren5 ;result of Lbytes odds <-> result of Hbytes odds xch a,ren4 ;acc <-> result of Lbytes odds ret ;*******
7. O nepoužití registru pro počítadlo
Na konci navrhneme řešení pro zdánlivě nesouvisející úlohu - převod byte do inverzního tvaru (tj.:b0 na pozici b7, b1->b6,....,b7->b0), ale bez použití pomocného počítadla. Stačí, když si uvědomíme, že bajt se skládá s osmi bitů.
Vše je jasné z výpisu programu:
;************************************** ;inverze znaku b7b6...b1b0 na b0b1..b6b7 ;**************************************** ; vstup - rei, vystup - rei ; mění registry: Acc, psw a rei ; možnost zvolit prac registr********** rei equ r3 inverze: mov a,#01H ;ve funkci počítadla x8 inverze1: ;pro posuv doleva xch a,rei ;acc <-> rei rrc a xch a,rei ;acc <-> rei rlc a jnc inverze1 xch a,rei ;výsledek -> rei ret ;*******
Tento způsob úspory počítadla můžeme použít vždy, je-li počet opakování 8 a současně v těle smyčky máme posuv o jeden bit.Další aplikací této "finty" může býti sériový příjem (vyslání) byte.
Závěr
Algoritmy první a třetí jsou aplikovatelné nejen na procesorech rodiny 8051 ale i na ostatních procesorech (např. řada ATmega rodiny AVR od Atmelu ) vybavených instrukcí "mul8x8".
Druhý a čtvrtý algoritmus už není tak široce použitelný - používá 8bitovou instrukci "div ab", která mimo rodiny 8051 už není tak běžně zastoupená v instrukčních sadách jiných procesorů. Zkrácení exekuční doby oproti použití klasických algoritmů je zhruba 3 až 4násobné. Princip použitý v prvních dvou procedurách ( tj. expanze z osmi bitů na 16 pro 8bitový procesor je možno také použít pro případnou expanzí ze 16 bitů na 32 bity pro vhodný 16bitový procesor.
Další podrobnosti na e- adrese: brudny@atlas.cz .
DOWNLOAD & Odkazy
- Stažení rutin - programy.rar