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
Ez a feladat a 2012. évi tavaszi félévben lett elfogadva.
; 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