Digitális technika 2 - Házi második részére példa
A VIK Wikiből
Figyelem! A programot kizárólag azért töltöttem fel, hogy részleteiben esetleg ötleteket adhasson a házi feladat készítése közben, vagy még inkább annak megírása után esetleges referenciaként szolgálhasson. A programot akár csak részleteiben lemásolni és házi feladatként beadni szigorúan tilos, és veszélyes. Természetesen más az alábbitól eltérő megoldási módok is léteznek, és természetesen el is fogadják őket házifeladat-beadásban.
Palotás Boldizsár, 2012 tavasz
; BEMENET:
; DE: kezdőcím
; BC: hossz
; feltöltés: ~(hi^lo) (az alsó és felső címbájt kizáró vagykapcsolatának negáltja)
;
; KIMENET
; DE: legalacsonyab című hiba vagy kezdőcím
; HL: hibák száma
; Z = 1: volt hiba
ELLENOR: ; A feladatkiírás szerinti rutin
PUSH PSW ; Mentés
PUSH B ; a darabszámra is szükség lesz később
; HL <- kezdőcím (ciklus előfeltétel)
MOV H, D
MOV L, E
CIKLUS_FELTOLT: ; Feltöltő ciklus. HL mutat az aktuális címre.
MOV A, B ; Ciklusfeltétel ellenőrzése
ORA C ; BC = 0 ?
JZ CIKLUS_FELTOLT_VEGE
; Kiszámítjuk a felső és alsó bájt kizáró vagy kapcsolatának negáltját
MOV A, H
XRA L ; A = H XOR L
CMA ; A = ~A, negálás
MOV M, A ; Kiírjuk a memóriába
INX H ; Következő cím
DCX B ; Egyel kevesebb cím van hátra
JMP CIKLUS_FELTOLT
CIKLUS_FELTOLT_VEGE:
; Ellenőrzés:
; A stackben tároljuk a legalacsonyabb hibacímet, a hibák számát pedig a DE regiszterben.
POP B ; BC <- a memóriablokk hossza (visszaállítjuk a stackből az értéket)
PUSH B ; De a stackben is ott hagyjuk
PUSH D ; Elmentjük a memóriablokk kezdőcímét a stackbe. Az első hibánál felülírjuk majd.
; Innentől: SP <- kezdőcím / első hiba
MOV H, D
MOV L, E ; HL <- kezdőcím (ciklus előfeltétel)
LXI D, 0 ; DE <- eddigi hibaszám
; Változók: DE hibaszám
; HL aktuális memóriacím
; BC maradék blokk hossza
; Stack:
; +-------------------------+
; | E *kezdőcím / első hiba | <-- SP
; | D *kezdőcím / első hiba |
; | C eredeti hossz |
; | B eredeti hossz |
; | PSW (flags) |
; | PSW (A) |
; | ... |
CIKLUS_ELL: ; Ellenőrzőciklus
MOV A, B ; ciklusfeltétel ugyanaz, mint a feltöltéskor: hátralévő blokkhossz BC != 0
ORA C
JZ CIKLUS_ELL_VEGE
; Ellenőrző kód kiszámítása
MOV A, H
XRA L
CMA ; A = ~(H XOR L)
; Összevetés a memóriával. Ugyanaz -> A = 0, Z = 1
XRA M
JZ ELL_FOLYT
; HIBA VAN (Z = 0)
MOV A, D
ORA E ; Ha nem volt még hiba, akkor A = DE = 0, Z = 1
JNZ VOLT_MAR_HIBA
; ELSŐ HIBA (Z = 1), mentsük el a helyét
INX SP
INX SP ; POP (kezdőcím)
PUSH H ; SP <- első hiba címe
VOLT_MAR_HIBA:
INX D ; Hibaszám növelése
ELL_FOLYT: ; Ciklus folytatása
INX H ; következő memóriacím
DCX B ; egyel kevesebb van hátra
JMP CIKLUS_ELL
CIKLUS_ELL_VEGE: ; ellenőrzés vége, visszatérés a kiírás szerint
XCHG ; HL <- hibaszám, DE <- x
POP D ; DE <- kezdőcím / első hiba címe (végleges kimenet)
POP B ; stack ürítése, B visszaállítása, SP <- PSW (flagek)
MOV A, H
ORA L ; HL = hibaszám = 0 ? Z flaget állítja.
XTHL ; L <- flagek, H <- A (PSW), SP <- HL (hibaszám)
MOV A, L ; a flageket (Z-t) fogjuk állítani
JZ NINCS_HIBA ; hibaszám = 0, Z = 1 volt
; VOLT HIBA
ORI 64 ; 6. bit (Z) 1-be állítva (64 = 0100 0000)
JMP VEGE
NINCS_HIBA:
ANI 191 ; 6. bit (Z) 0-ba állítva (191 = 1011 1111)
VEGE:
MOV L, A
XTHL ; Stack <- PSW (Z felülírva), HL <- hibaszám (végleges kimenet)
POP PSW ; flagek visszaállítva, Z felülírva (végleges kimenet)
RET
A programot írta Boldi (vita).
Ace Techs, 2012 ősz
/* A házid szubrutin írós feladatát úgy kell kezdeni, hogy megkérdezed a gyakvezedet, hogy melyik regiszterek tartalmát kell megõrizned. Én ezzel sok fejfájástól megkíméltem volna magam. Ebben a megoldásban én megõrzöm: az Akumlátort, a flageket (Z -t külön manipulálom a megoldásnak megfelelõen), DE a feladatnak megfelelõ mem. címre mutat, BC pedig az eredeti hosszal egyenlõ. HL a feladatnak megfelelõen egy számot tartalmaz. HINT: A házifeladat megoldása közben halgassatok zúzós Rock zenét!!! */ ELLENOR: PUSH PSW /*Az akumlátor és a flagek kimentése a stack re*/ PUSH B /*DE és BC regiszter párok értékére késõbb is szükség lesz*/ PUSH D FELTOLT: MOV A,E /*A D regiszter a memória rekesz címének felõs, az E az alsó 8 bitjét tartalmazza*/ INR A /*cím+1*/ CMA /*negálás*/ STAX D /* Az akumlátor tartalmát vissza írom oda ahvova DE mutat*/ INX D DCX B /*tovább lépek a következõ rekeszre és csökkentem a hosszt*/ MOV A,B ORA C JNZ FELTOLT /*ha a B regiszter és a C regiszter logikai vagy kapcsolata csupa 0000 0000 akumlátort eredményez => Z=1 az az véget értünk a feltöltéssel*/ POP D POP B /*DE és BC regiszter párok eredeti értékére szükség van*/ PUSH B PUSH D /*DE és BC regiszter párok értékére késõbb is szükség lesz*/ LXI H,0000H /*kinullázzuk HL-t*/ CHECK: LDAX D /*betöltjük az aksiba azt az adatot ami ott van ahova DE mutat*/ CMA DCR A /*vissza alakítjuk*/ XRA E JZ VEGE_E /*ha A==E, renben van az adat és ugrunk, ha nem akkor hiba történt és ennek megfelelõen járünk el*/ MOV A,H ORA L JNZ N_EDIK_HIBA/*Ha HL nem csupa 0 akkor abból következik, hogy volt már hibás adat és ilyenkor ugrunk*/ POP H /*Ez trükkös. HL rp ba vesszük ki azt az adatot amit DE bõl PUSH oltunk ki a stack re. Azért nem DE be vesszük vissza mint rendesen mert abban értékes adat van és így nem veszik el. HL könnyen helyre hozható.*/ PUSH D /*Az 1. hibás adat helyét push oljuk ki*/ LXI H,0000H/*HL-t 0 ázzuk mert a kövi utasítással 1 el növeljük*/ N_EDIK_HIBA: INX H /*Növeljük a megtalált hibák számát*/ VEGE_E: /*Le ellenõrizzük, hogy végeztünk-e már a mem. terület ellenõrzésével, ha még van hátra ugrunk a CHECK cimkére*/ INX D DCX B MOV A,B ORA C JNZ CHECK MOV A,H ORA L /*Ha HL csupa 0 akkor nem volt hiba =>Z=1 ha volt hiba HL ben akkor van legalább 1 db 1-es az aksiban => Z=0*/ POP D /*DE ettõl kezdve vagy az elsõ megtalált hiba címét tartalmazza vagy az elsõ adatét(ha nem volt hiba)*/ POP B /*BC = a hosszal*/ JZ NINCS_HIBA XTHL /*ez az utasítás kicseréli HL és stack tartalmát. Ebben az esetben H=az eredeti akumlátorral, L=az eredeti flagekkel*/ MOV A,L ORI 40H /*A régi flageket megtartva Z=1, direk manipuláció*/ MOV L,A XTHL POP PSW RET /*szubrutinból visszatérünk*/ NINCS_HIBA: XTHL MOV A,L ANI BFH /*A régi flageket megtartva Z=0, direk manipuláció*/ MOV L,A XTHL POP PSW RET
Második verzió:
/* A házid szubrutin írós feladatát úgy kell kezdeni, hogy megkérdezed a gyakvezedet, hogy melyik regiszterek tartalmát kell megõrizned. Én ezzel sok fejfájástól megkíméltem volna magam. Ebben a megoldásban én megõrzöm: az Accumlátort, a flageket (Z -t külön manipulálom a megoldásnak megfelelõen), DE a feladatnak megfelelõ mem. címre mutat, BC pedig az eredeti hosszal egyenlõ. HL a feladatnak megfelelõen egy számot tartalmaz. HINT: A házifeladat megoldása közben halgassatok zúzós Rock zenét!!! */ ELLENOR: PUSH PSW /*Az akumlátor és a flagek kimentése a stack re*/ PUSH B /*DE és BC regiszter párok értékére késõbb is szükség lesz*/ PUSH D FELTOLT: MOV A,E /*A D regiszter a memória rekesz címének felõs, az E az alsó 8 bitjét tartalmazza*/ XRA D CMA /*negálás*/ STAX D /* Az akumlátor tartalmát vissza írom oda ahvova DE mutat*/ INX D DCX B /*tovább lépek a következõ rekeszre és csökkentem a hosszt*/ MOV A,B ORA C JNZ FELTOLT /*ha a B regiszter és a C regiszter logikai vagy kapcsolata csupa 0000 0000 akumlátort eredményez => Z=1 az az véget értünk a feltöltéssel*/ POP D POP B /*DE és BC regiszter párok eredeti értékére szükség van*/ PUSH B PUSH D /*DE és BC regiszter párok értékére késõbb is szükség lesz*/ LXI H,0000H /*kinullázzuk HL-t*/ CHECK: PUSH D /* Szükség van egy regiszterre az ellenõrzéshez, de nincs egy használaton kívüli sem. Ki mentjük DE-t a stackre*/ MOV A,D XRA E CMA MOV E,A /*elvégezzük a szükséges mûveleteket és E ben tároljuk az eredményüket LDAX D /*betöltjük az aksiba azt az adatot ami ott van ahova DE mutatott*/ XRA E /*megnézzük egyezik-e az adat az E regiszter tartalmával POP D /*helyre állítjuk DE regiszter párt*/ JZ VEGE_E /*ha A==E, renben van az adat és ugrunk, ha nem akkor hiba történt és ennek megfelelõen járünk el*/ MOV A,H ORA L JNZ N_EDIK_HIBA/*Ha HL nem csupa 0 akkor abból következik, hogy volt már hibás adat és ilyenkor ugrunk*/ POP H /*Ez trükkös. HL rp ba vesszük ki azt az adatot amit DE bõl PUSH oltunk ki a stack re. Azért nem DE be vesszük vissza mint rendesen mert abban értékes adat van és így nem veszik el. HL könnyen helyre hozható.*/ PUSH D /*Az 1. hibás adat helyét push oljuk ki*/ LXI H,0000H/*HL-t 0 ázzuk mert a kövi utasítással 1 el növeljük (HL helyre hozása)*/ N_EDIK_HIBA: INX H /*Növeljük a megtalált hibák számát*/ VEGE_E: /*Le ellenõrizzük, hogy végeztünk-e már a mem. terület ellenõrzésével, ha még van hátra ugrunk a CHECK cimkére*/ INX D DCX B MOV A,B ORA C JNZ CHECK MOV A,H ORA L /*Ha HL csupa 0 akkor nem volt hiba =>Z=1 ha volt hiba HL ben akkor van legalább 1 db 1-es az aksiban => Z=0*/ POP D /*DE ettõl kezdve vagy az elsõ megtalált hiba címét tartalmazza vagy az elsõ adatét(ha nem volt hiba)*/ POP B /*BC = a hosszal*/ JZ NINCS_HIBA XTHL /*ez az utasítás kicseréli HL és stack tartalmát. Ebben az esetben H=az eredeti akumlátorral, L=az eredeti flagekkel*/ MOV A,L ORI 40H /*A régi flageket megtartva Z=1, direk manipuláció*/ MOV L,A XTHL POP PSW RET /*szubrutinból visszatérünk*/ NINCS_HIBA: XTHL MOV A,L ANI BFH /*A régi flageket megtartva Z=0, direk manipuláció*/ MOV L,A XTHL POP PSW RET
