ZPOC 9: Základy programovania v strojovom kóde
Zo stránky SensorWiki
Tieto jednoduché programy budeme analyzovať v simulátore procesora 8080. Pri práci je dobrou pomôckou tento ťahák s výberom inštrukcií. Obsluhu simulátora sme vysvetlili na cvičeniach, preto tu nájdete len tento stručný obrázok s opisom.
Časť I.
Nulovanie pamäťového miesta
Vynulujte obsah pamäťového miesta 0010h, do ktorého sme vložili naschvál nejaké číslo (55h), aby ste vedeli skontrolovať, že program naozaj danú pamäťovú bunku vynuluje. Obsah pamäte môžete meniť aj ručne.
V prvom stĺpci je intuitívne riešenie, na ktoré asi prídete hneď - má dĺžku 5 Bajtov a trvá 20 strojových cyklov. V druhom stĺpci je profesionálnejšie riešenie, ktoré je kratšie (4B, 17T) a aj nastaví príznaky. V treťom stĺpci je riešenie pomocou pseudoinštrukcie EQU, ktorá zjednoduší a sprehľadní programovanie. Porovnajte.
POZN.: toto sú programy napísané pre porovnanie vedľa seba, do simulátora musíte napísať len jeden zo stĺpcov, takže Copy/Paste odtiaľto vám nebude fungovať!
myData equ 0010h
org 0010h org 0010h org myData
db 55h db 55h db 55 ; nejake data aby sme mali co vymazat
org 0000h org 0000h org 0000h ; program uloz od 0000h
mvi a,00h sub A sub A ; najprv vynulujem akumulator sub A: A <- A-A = 0
sta 0010h sta 0010h sta myData ; a potom ho presuniem do pamäte
hlt hlt hlt ; stop, koniec
Presuny sem a tam
Tento program nerobí nič užitočné, len presúva data hore dole pomocou rozličných inštrukcií. Program je tu zámerne aj so strojovým kódom a adresami, takže sa nedá Copy/Paste do simulátora. Je to tak preto, že kopírovaním sa nič nenaučíte, je potrebné ten program naozaj napísať.
0000 .ORG 0000h ; tu hovorime, ze program zacne od adresy 0
0000 3E 07 MVI A,07h ; A = 07h - uloz do akumulatora cislo 7
0002 47 MOV B,A ; B = A - obsah akumulatora skopiruj aj do B
0003 4A MOV C,D ; C = D - neviem co je v D, ale skopiruj to do C
0004 32 10 00 STA 0010h ; [0010] = A - to je vlastne MOV [0011],A cize presun (skopiruj) to co je v A do pamate
0007 3E 00 MVI A,00h ; A = 0, mozeme nahradit aj kratsim SUB A - cim vynulujeme A
0009 32 11 00 STA 0011h ; [0011] = A - to je vlastne MOV [0011],A cize presun (skopiruj) to co je v A do pamate
000C 3A 10 00 LDA 0010h ; A = [0010] a toto je vlastne MOV A, [0010], cize presun z pamate do A
000F 76 HLT
Súčet dvoch 8-bitových čísel
Spočítajte dve 8-bitové čísla v pamäti. Prvý aj druhý sčítanec sú uložené v pamäti [0010h] a [0011h], výsledok chceme vrátiť tiež do pamäte za oba sčítance, teda na adresu [0012h].
Odskúšajte pre rozličné vstupné data. Ako vieme, že výsledok je OK? Skúste aj také čísla, ktorými prekročíte rozsah. Čo sa stane?
Po preklade spočítajte koľko bajtov zaberajú obe riešenia a koľko SC spotrebujú.
0010 ORG 0010H
0010 02 03 00 DB 02H,03H,00H ; tri cisla v pamati, tretie je 0 rezervovana pre vysledok
0000 ORG 0000
0000 3A 0D 00 LDA 0010H ; do Akumulatora prve cislo z adresy 0010
0003 47 MOV B,A ; presun zatial do B
0004 3A 0E 00 LDA 0011H ; do Akumulatora druhe cislo z nasledujucej adresy
0007 80 ADD B ; A <-- A + B
0008 32 0F 00 STA 0012H ; vysledok odloz na nasledujucu adresu
000B 76 HLT
Tu je nepovinná ukážka, ako sa to dá spraviť aj celkom inak. Sú tam však inštrukcie, ktoré prekračujú rámec povinností na cvičeniach.
0010 .ORG 0010H
0010 02 03 00 DB 02H,03H,00H
0000 .ORG 0000
0000 21 10 00 LXI H,0010h ; do HL adresu prveho cisla na adrese 0010
0003 7E MOV A,M ; do Akumulatora prve cislo z adresy {HL}
0004 23 INX H ; HL <-- HL + 1
0005 86 ADD M ; A <-- A + {HL}
0006 23 INX H ; HL <-- HL + 1
0007 77 MOV M,A ; uloz do pamate {HL}
0008 76 HLT
Výmena
V pamäti sú za sebou uložené dve čísla. Vymeňte ich navzájom.
Pred spustením programu
0010 42 0011 55
Po vykonaní programu
0010 55 0011 42
Program môže vyzerať napríklad takto, znova je vo formáte, ktorý sa nedá Copy/Paste do simulátora. Viete prečo...
0010 .ORG 0010h
0010 42 55 DB 42h,55h
0000 .ORG 0000h
0000 3A 10 00 LDA 0010h ; 1: precitaj do A z 010h
0003 47 MOV B,A ; 2: odloz A do B
0004 3A 11 00 LDA 0011h ; 3: precitaj do A z 011h
0007 32 10 00 STA 0010h ; 4: to rovno zapisem do 010h
000A 78 MOV A,B ; 5: vrat do A to z B
000B 32 11 00 STA 0011h ; 6: zapis to do 011h
000E 76 HLT ; - hotovo
Precvičovanie
Preštudujte si nasledovný program:
ORG 0000h
MVI A,07h
MOV B,A
MVI A,03h
MOV C,A
HLT
Preštudujte si nasledovný program:
ORG 0040h
DB 01h,03h,05h,07h
ORG 0000h
LDA 0041h
MOV B,A
LDA 0040h
ADD B
STA 0042h
HLT
Preštudujte si nasledovný program:
ORG 0040h
DB 01h,03h,05h,07h
ORG 0000h
LDA 0043h
MOV B,A
LDA 0042h
SUB B
STA 0041h
SUB A
STA 0040h
HLT
Časť II.
Programy, ktoré vidíte na tejto stránke sa nedajú jednoducho skopírovať do simulátora cez Copy/Paste, pretože si myslíme, že naučiť sa to dá len tak, že si tie programy sami napíšete krok za krokom aby ste vedeli čo ktorá inštrukcia robí.
Pri práci môžete používať ťahák s inštrukciami.
Vypočítajte dvojkový komplement čísla
V registri D máme čislo, ktorého dvojkový doplnok by sme chceli vypočítať. Výsledok uložíme do registra E.
.ORG 0000
0000 16 03 MVI D,03h
0002 7A MOV A,D
0003 2F CMA
0004 3C INR A
0005 5F MOV E,A
0006 76 HLT
Ako skúšku správnosti spravte naviac súčet výsledku a pôvodného čísla. Čo dostanete?
Test, či je číslo v pamäti nula
Pred delením musíme skontrolovať, či deliteľ na adrese 0020h náhodou nie je nula.
0020 ORG 0020h
0020 03 DB 03h
0000 ORG 0000h
0000 06 00 MVI B,00h ; Do B si odlozime to co ideme testovat
0002 3A 20 00 LDA 0020h ; Do A nacitame cislo ktore ideme testovat
0005 B8 CMP B ; test: je Akumulator = B, teda 0?
0006 CA 0B 00 JZ JeToNula ; Ano, je to tak
0009 00 NIEJENULA: NOP ; Tuto skoncime
000A 76 HLT
000B 00 JETONULA: NOP ; Nie, nie je to tak
000C 76 HLT
Nájdi väčšie z dvoch čísel
V pamäti sú za sebou uložené dve čísla. Nájdi väčšie z nich a ulož ho na ďalšiu pozíciu v pamäti.
0010 ORG 0010H
0010 03 02 00 DB 02H,04H,00H ; tri cisla v pamati, tretie je 0 rezervovana pre vysledok
0000 ORG 0000
0000 3A 10 00 LDA 0010h ; do Akumulatora prve cislo z adresy 0010h
0003 47 MOV B,A ; odlozime do B
0004 3A 11 00 LDA 0011h ; do Akumulatora druhe cislo z adresy 0011h
0007 B8 CMP B ; porovnaj B a Akumulátor
0008 D2 0C 00 JNC HOTOVO ; ak A > B skoc na HOTOVO:
000B 78 MOV A,B ; v opacnom pripade presun do A druhu hodnotu
000C 32 12 00 HOTOVO: STA 0012h ; uloz vysledok na nasl. adresu
000F 76 HLT
Inštrukcia CMP B spraví simulovaný rozdiel. Teda nastaví register F tak, ako keby bol obsah z B odpočítaný od obsahu A. Na rozdiel od inštrukcie SUB B však obsah Akumulátora ostáva nezmenený. Zhrnutie: Príznaky F sú nastavené nasledovne:
Zero = 1 if A = B Zero = 0 if A ≠ B Carry = 1 if A < B Carry = 0 if A ≥ B
(A a B chápeme ako neznamienkové binárne čísla)
Poznámka: Ak by to niekoho zaujímalo, tak na presuny medzi pamäťou a procesorom existujú aj trocha efektívnejšie inštrukcie a postupy. Napríklad by to mohlo vyzerať takto:
0010 ORG 0010H
0010 03 02 00 DB 03H,02H,00H ; tri cisla v pamati, tretie je 0 rezervovana pre vysledok
0000 ORG 0000
0000 21 10 00 LXI H,0010h ; do HL adresu prveho cisla na adrese 0010
0003 7E MOV A,M ; do Akumulatora prve cislo z adresy {HL}
0004 23 INX H ; HL <-- HL + 1
0005 BE CMP M ; porovnaj {HL} a Akumulátor
0006 D2 0A 00 JNC HOTOVO ; ak A > {HL} skoc na HOTOVO:
0009 7E MOV A,M ; v opacnom pripade presun do A druhu hodnotu
000A 23 HOTOVO: INX H ; HL <-- HL + 1
000B 77 MOV M,A ; uloz vysledok na nasl. adresu
000C 76 HLT
Vynásobenie dvoch čísel
Toto bude príklad na celkom jednoduché násobenie, nebudeme riešiť ani záporné čísla ani pretečenie.
Vynásobte dve čísla, uložené na adresách 0041h a 0042h. Výsledok uložte na 0040h.
0040 ORG 0040h
0040 03 04 00 DB 00h,03h,04h
0000 ORG 0000h
0000 06 00 MVI B,00 ; sem do B si budeme ukladat medzivysledky
0002 1E 00 MVI E,00 ; toto je nula, ktoru budeme testovat
0004 3A 40 00 LDA 0041h ; prvy cinitel z pamati do A
0007 57 MOV D,A ; odlozime si ho do D
0008 3A 41 00 LDA 0042h ; druhy cinitel z pamati do A
000B 4F SEM: MOV C,A ; odlozime si ho do C - counter
000C BB CMP E ; test: je uz Akumulator = E, teda 0?
000D CA 18 00 JZ KONIEC ; ak ano, tak uz mame hotovo
; ak nie, pripocitame dalsi krat
0010 78 MOV A,B ; v B mame medzivysledok, presunieme do A
0011 82 ADD D ; pripocitame znova D
0012 47 MOV B,A ; a odlozime medzisucet spat do B
0013 79 MOV A,C ; teraz kukneme na pocitadlo
0014 3D DCR A ; odpocitame jednotku
0015 C3 0B 00 JMP SEM ; a pokracujeme znova
0018 78 KONIEC: MOV A,B ; ak sme sa dostali az sem, tak medzivysledok
0019 32 42 00 STA 0040h ; ulozime na spravne miesto do pamati
001C 76 HLT
Pre hĺbavejších študentov sú určené nasledovné dva programy:
Spočítajte N čísel
Spočítajte N čísel so začiatkom na adrese 031h, pričom ich počet je na 030h. Výsledok uložte na 040h.
.ORG 0030h
DB 03h,01h,02h,03h
.ORG 0000
LDA 0030H
MOV C,A ; Initialize C-counter
SUB A ; sum = 0
LXI H,0031H ; Initialize pointer
BACK: ADD M ; SUM = SUM + data
INX H ; increment pointer
DCR C ; Decrement counter
JNZ BACK ; if counter 0 repeat
STA 040H ; Store sum
HLT ; Terminate program execution
Nájdi maximum v bloku hodnôt.
V pamäti je uložený blok dát. Prvé číslo v bloku je počet dát, nasleduje neusporiadaná množina 8-bitových hodnôt.
.org 0020H
db 03h,02h,03h,01h ; tri cisla = { 02, 03, 01 }
.org 0000
lda 0020H
mov C,A ; Initialize counter
sub A ; Maximum = Minimum possible value = 0
lxi H,0021H ; Initialize pointer
BACK: cmp M ; Is number > maximum
jnc SKIP ; Yes, replace maximum
mov A,M
SKIP: inx H
dcr C
jnz BACK
sta 0040H ; Store maximum number
HLT ; Terminate program execution
Precvičovanie II
Aj teraz tu máte pripravených niekoľko úloh na precvičenie na doma ako prípravu na písomku a upevnenie si znalostí.
1. Preštudujte si nasledovný program:
ORG 0010h
DB 51h,52h,53h,54h
ORG 0000h
MVI A,07h
MOV B,A
MOV C,D
STA 0010h
MVI A,00h
STA 0011h
LDA 0012h
HLT
1. Preštudujte si nasledovný program:
ORG 0020h
DB XXh
ORG 0000h
MVI B,00h
LDA 0020h
CMP B
JNZ SKOK
MVI B,02h
HLT
SKOK: MVI B,04h
HLT
Domáca úloha
Naprogramujte postupne zadané úlohy. Riešte ich postupne a spájajte ich do jedného komplexného programu. Ak si myslíte, že váš program je už hotový (alebo ak už viac neviete spraviť), vyplňte v Classroome formulár, do ktorého vyplníte stav registrov v ktorom ste skončili.
Najprv do pamäte na adresy 70h až 74h vložte hodnoty zodpovedajúce ASCII kódom prvých piatich písmen vášho krstného mena. Použite všetky písmená veľké
Napríklad pre mňa by obsah pamäte vyzeral takto
0068 00 00 00 00 | 00 00 00 00 0070 52 49 43 48 | 41 00 00 00 0078 00 00 00 00 | 00 00 00 00
- Skopírujte (presuňte) obsah pamäťového miesta 71h na adresu 72h.
- Na adresu 75h vložte hodnotu 1 (01b, 1 desiatkovo, 01h, nie ASCII).
- Vypočítajte dvojkový doplnok z čísla uloženého na adrese 73h a výsledok uložte do 74h
- Odčítajte od 71h obsah 72h a výsledok zapíšte späť do 71h
- Sčítajte obsah pamäťových miest 71h a 75h a výsledok uložte do 72h
- Sčítajte obsah pamäťových miest 73h a 74h a výsledok uložte do 73h
Keď skončíte, vložte do formulára v Classroome odpoveď na otázku, aký bude na konci, po vykonaní všetkých inštrukcií, obsah v pamäti na adresách 70h až 73h a aký bude stav príznakov Z (Zero) a P (Parity) v registri F.
[70] = ? [71] = ? [72] = ? [73] = ? Flag Z = ? Flag P = ?
Poznámka: Ak budete ASCII hodnoty vkladať do pamäte pomocou pseudoinštrukcie DB, dávajte pri simulácii pozor, pretože tieto hodnoty sa tam vložia len raz, pri zapnutí emulátora (F10). Ak spustíte program druhý raz, napríklad po stlačení RST, v pamäti ostanú hodnoty tak, ako ste ich tam zanechali. Ak chcete mať znova vložené správne hodnoty, musíte sa prepnúť do editora a späť.