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