LUCRAREA nr. 2

Instrucțiunile microprocesorului Z80

1. Obiectivele lucrării

În cadrul acestei lucrări de laborator se vor prezenta instrucțiunile microprocesorului Z80 și modurile lui de adresare. Se va realiza un program de înmulțire a două numere hexa citite de la tastatură iar rezultatul va fi afișat pe ecran. Ca mediu de lucru se va folosi emulatorul de Z80 pentru PC.

2. Considerații teoretice

Z80 este un procesor pe 8 biți a cărui structură internă este prezentată în figura 2.1:

UAL – Unitatea aritmetică și logică;
RI – Registrul de instrucțiuni;
UCC – Unitatea de comandă și control.

2.1 Registrele microprocesorului Z80

Registrele microprocesorului Z80 formează trei grupuri distincte:

  1. registre de uz general;
  2. registre cu destinație specială;
  3. bistabile pentru controlul întreruperilor.

Primul grup conține două seturi de registre pe 8 biți: unul principal și unul secundar. Trecerea de la setul principal la cel secundar se face cu ajutorul unei instrucțiuni. Ambele seturi constau dintr-un acumulator A (A’), un registru al indicatorilor de condiții F (F’) și șase registre de uz general B, C, D, E, H, L (B’, C’, D’, E’, H’, L’). Registrele de uz general pot să fie utilizate individual, ca registre de 8 biți, sau în perechi, ca registre de 16 biți: BC, DE, HL (BC’, DE’, HL’)(figura 2.2).

Indicatorii de condiții sunt următorii:

  1. CARRY (C) – este poziționat la operațiile aritmetice (indicând transportul sau împrumutul) și la operațiile de rotire și deplasare;
  2. ZERO (Z) – se poziționează pe “1” când rezultatul unei operații aritmetice sau logice este zero;
  3. SIGN (S) – se poziționează în conformitate cu semnl rezultatului (copiază rangul 7 al rezultatului);
  4. PARITY/OVERFLOW (P/V) – pentru operațiile logice are semnificația de indicator de paritate, poziționându-se la “1” dacă rezultatul are un număr par de “1”;
  5. – pentru operațiile aritmetice cu operanzi cu semn are semnificația de depășire indicând depășirea capacității de memorare;

  6. AUXILIAR CARRY (A) – utilizat de procesor atunci când se execută operații aritmetice cu operanzi în BCD și indică transportul sau împrumutul între cei doi digiți ai unui octet;
  7. NEGATIVE (N) – arată dacă operația în BCD este adunare sau scădere.

Al doilea grup conține registrele cu destinație specială (figura 2.3):

  1. numărătorul de program (PC), care conține adresa pe 16 biți a locației de memorie de unde se va aduce următoarea instrucțiune;
  2. indicatorul de stivă (SP), care conține adresa pe 16 biți a vârfului stivei, care funcționează după principiul LIFO (Last In First Out);
  3. registrele IX, IY, care conțin câte o adresă de bază, pe 16 biți, utilizată în modul de adresare indexată;
  4. registrul I, de adresă al paginii de întrerupere; conține cei 8 biți superiori ai adresei la care se va face un apel indirect de subrutină ca răspuns la o cerere de întrerupere, cei 8 biți inferiori ai adresei fiind furnizați de dispozitivul care a generat întreruperea;
  5. registrul (R), de reîmprospătare a memoriei; este pe 7 biți, incrementat după fiecare aducere a unei instrucțiuni din memorie; conținutul său este plasat pe liniile inferioare ale magistralei de adrese, împreună cu activarea unui semnal de refresh, în timp ce unitatea centrală decodifică și execută instrucțiunea adusă.

Al treilea grup este format din două bistabile pentru controlul întreruperilor, IFF1 și IFF2, și o pereche adițională de bistabile care ajută la identificarea în orice moment a modului de tratare a întreruperilor.

2.2 Programarea microprocesorului Z80

Funcția de bază a microprocesorului este de a aduce o instrucțiune din memorie, de a o decodifica, de a executa operația codificată de către instrucțiunea respectivă și în final, eventual, de a transfera rezultatul operației efectuate în memoria sistemului. Mai multe instrucțiuni înlănțuite formează un program, prin intermediul căruia se poate efectua o anumită operație.

2.2.1 Modurile de adresare

Modurile de adresare implementate în microprocesorul Z80 permit un transfer eficient de date între registre, memoria externă și dispozitivele periferice. Prin mod de adresare se înțelege mecanismul prin care procesorul calculează adresa datelor (operanzilor) necesare în execuția fiecărei instrucțiuni. Microprocesorul Z80 are 10 moduri de adresare, și sunt prezentate în continuare:

  1. Adresare imediată: Operandul este furnizat în cadrul instrucțiunii. Octetul care se găsește în memorie după codul instrucțiunii reprezintă operandul necesar:
  2. COD OPERAȚIE

    1 sau 2 octeți

    OPERAND

    Exemplu: LD A, 103 – încarcă registrul A cu valoarea zecimală 103.

  3. Adresare imediată extinsă: Diferă de modul de adresare precedent prin faptul că operandul ocupă doi octeți. Cei doi octeți ce se găsesc în memorie după codul instrucțiunii reprezintă operandul necesar. Operandul este memorat cu octetul cel mai puțin semnificativ la adresa mai mică.
  4. COD OPERAȚIE

    1 sau 2 octeți

    OPERAND

    OPERAND

    Exemplu: LD BC, 0a312h – încarcă registrul dublu BC cu valoarea hexa a312.

  5. Adresare directă în pagina zero: Cu ajutorul unei instrucțiuni de restart, de un octet, se poate specifica adresa completă a unei locații din pagina zero. De obicei, la această locație se plasează începutul unei subrutine, apelarea ei necesitând doar un singur octet.
  6. COD OPERAȚIE

    1 octet

    Exemplu: RST n n = 0,7 – apelul subrutinei aflate la adresa 8Śn.

  7. Adresare directă: Adresa operandului este furnizată în cadrul instrucțiunii. Cei doi octeți care urmează codului instrucțiunii constituie o adresă de salt sau o adresă de operand. Adresa este memorată cu octetul cel mai puțin semnificativ la adresa mai mică.
  8. COD OPERAȚIE

    1 sau 2 octeți

    ADRESĂ L.

    ADRESĂ H.

    Exemplu: LD C, (4000h) – încarcă registrul C cu conținutul locației de memorie a cărei adresă este 4000h.

  9. Adresare relativă: Octetul care se găsește în memorie după codul instrucțiunii reprezintă un deplasament. Acest deplasament (un număr pe 8 biți cu semn) scris în complement fată de 2 se adună la adresa instrucțiunii următoare pentru a se obține noua adresă. Acest tip de adresare este folosit la instrucțiunile de salt relativ. Deplasamentul este reprezentat pe 8 biți cu semn, astfel încât se pot efectua salturi în intervalul (-128, +127).
  10. COD OPERAȚIE

    1 octet

    DEPLASAMENT

    Exemplu: JR Z, 06 – dacă indicatorul Z este setat atunci se execută un salt relativ în sensul de creștere a adreselor, cu 6 octeți față de adresa instrucțiunii următoare;

    JR 0FAh – salt relativ necondiționat înapoi cu 6 octeți față de adresa instrucțiunii următoare celei de JR.

  11. Adresare indexată: Octetul care urmează codului instrucțiunii este un deplasament ce se adună la conținutul unuia dintre cele două registre index pentru a forma o adresă de memorie. Acest deplasament este un număr cu semn reprezentat în complement față de 2 (-128, +127).
  12. COD OPERAȚIE

    1 octet

    1 octet

    COD OPERAȚIE

    DEPLASAMENT

    Exemplu: LD (IX+5), B – salvează registrul B în locația de memorie a cărei adresă este IX+5.

  13. Adresare implicită: Microprocesorului nu trebuie să i se comunice de unde să ia operandul. La operațiile aritmetice de exemplu unul dintre operanzi este în acumulator iar rezultatul se depune tot în acumulator.
  14. COD OPERAȚIE

    1 octet

    Exemplu: CP E – compară registrul A cu registrul E.

  15. Adresare de registru: Operanzii sunt în regiștrii, iar rezultatul se depune în unul din regiștrii. Codul instrucțiunii specifică explicit registrele utilizate de instrucțiune.
  16. COD OPERAȚIE

    1 octet

    Exemplu: EX DE, HL – interschimbă conținutul registrelor DE și HL.

  17. Adresare indirectă cu regiștre: Codul instrucțiunii precizează un registru dublu (HL, BC) care conține adresa de memorie.
  18. COD OPERAȚIE

    1 octet

    Exemplu: LD (HL), D – salvează registrul D în locația de memorie a cărei adresă este indicată de registrul dublu HL.

  19. Adresare pe bit: Codul instrucțiunii de prelucrare pe bit specifică bitul asupra căruia se execută operația.
  20. COD OPERAȚIE

    1 octet

    1 octet

    COD OPERAȚIE

    Exemplu: SET 3, A – setează bitul 3 din registrul A.

2.2.2 Clasificare instrucțiunilor

Pe baza funcției lor am împărțit cele 696 de instrucțiuni ale microprocesorului Z80 în 12 clase distincte:

Clasa 1. Instrucțiuni de transfer pe 8 biți (LD);

Clasa 2. Instrucțiuni de transfer pe 16 biți (LD, EX, EXX, PUSH, POP);

Clasa 3. Instrucțiuni de transfer pe blocuri de date (LDI, LDIR, LDD, LDDR);

Clasa 4. Instrucțiuni aritmetice și logice pe 8 biți (ADD, ADC, SUB, SBC, AND, XOR, OR, CP, INC, DEC, CPL, NEG, DAA, RLCA, RRCA, TLA, RRA);

Clasa 5. Instrucțiuni aritmetice pe 16 biți (ADD, ADC, SBC, INC, DEC);

Clasa 6. Instrucțiuni logice pe blocuri de date (CPI, CPIR, CPD, CPDR);

Clasa 7. Instrucțiuni orientate pe bit (BIT, SET, RES, SCF, CCF);

Clasa 8. Instrucțiuni de salt (JP, JR, DJNZ);

Clasa 9. Instrucțiuni de apel și revenire din subrutină (CALL, RET, RST);

Clasa 10. Instrucțiuni de rotire și deplasare ( RLC, RRC, RL, RR, SLA, SRA, SRL, RLD, RRD);

Clasa 11. Instrucțiuni de intrare/ieșire (IN, IND, INDR, INI, INIR, OUT, OUTD, OTDR, OUTI, OTIR);

Clasa 12. Instrucțiuni de control (DI, EI, HALT, IM, NOP, RETI, RETN)

2.3 Emulatorul Z80MU

Z80MU este un emulator software al procesorului ZILOG Z80, care rulează pe un calculator compatibil IBM PC. În plus mai oferă și o emulare a sistemului de operare CP/M (versiunea 2.2).

2.3.1 Comenzile emulatorului

Un număr poate fi introdus în una dintre următoarele forme:

FFFF Hexa

.99999 Zecimal

%1111111111111111 Binar

'c caracter ASCII

'\c Escape char c (\r, \n, etc)

'\xFF Hexa byte FF

Comenzi de bază:

HELP [<keyword>] - afișează help-ul pentru o anumită comandă;

EXIT - ieșirea din emulator.

Pentru fișere există următoarele comenzi:

DIR <filename_pattern> - afișează numele de fișiere de pe disc care se potrivesc cu tiparul dat

Exemplu: - afișiază toate fișierele cu extensia com din catalogul curent

Z80 C>dir *.com
Volume in drive C has no label
Volume Serial Number is 2B30-18DD
Directory of C:\TEMP\Z80

820INIT COM 640 11-24-85 12:02a
ZLINK COM 11520 04-17-92 9:10a
ZMASM COM 20224 04-15-92 6:19p
EX COM 128 01-16-98 9:39a

4 file(s) 32512 bytes
64299008 bytes free

R(EAD) [n] <filename.typ> - încarcă în memorie un fișier începând cu adresa n (implicit de la adresa 0100h)

Exemplu: - încarcă fișierul ex.com în memorie începând de la adresa 400h

Z80 C>read 400 ex.com
*** Low = 0400H Next = 0480H

W(RITE) nlo nhi <filename.typ> - salvează într-un fișier conținutul memoriei între adresele nlo și nhi

<filename.com> - încarcă un program .com în memorie începând cu adresa 0100h și îl rulează

Comenzi pentru operarea cu programele și cu memoria:

B(REAK) - afisează toate breakpoint-urile;

B(REAK) CLEAR - șterge toate adresele de breakpoint;

B(REAK) CLEAR n [n...] - șterge adresele de breakpoint specificate;

B(REAK) SET n [n...] - setează adresele de breakpoint specificate;

Exemplu: - setează două breakpoint-uri, le afișează și sterge unul dintre ele

Z80 C>break set 100
1 Breakpoints set - 1 now in table

Z80 C>break
Current Breakpoints:
0100H
1 Breakpoints currently set

Z80 C>b set 102
1 Breakpoints set - 2 now in table

Z80 C>b
Current Breakpoints:
0100H 0102H
2 Breakpoints currently set

Z80 C>break clear 100
1 Breakpoints cleared, 1 left

Z80 C>b
Current Breakpoints:
0102H
1 Breakpoints currently set

D(UMP) [n1 [n2]] - afișează pe ecran conținutul memoriei începând cu adresa n1 și până la adresa n2;

Exemplu: - afișează conținutul memoriei începând de la adresa 100h

Z80 C>d 100

ADDR 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 01234567 89ABCDEF
---- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -------- --------
0100: 3E 0A 06 20 80 0E 19 5F CD 05 00 0E 00 00 00 00 >.. ..._ M.......
0110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0120: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........
0130: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ........ ........

G(O) [n] - execută programul începând cu adresa n;

X(REG) [rr n] - dacă comanda nu are parametri, se afișează toate registrele;

- dacă comanda are parameti se setează registrul dat cu valoarea n;

Exemplu: - încarcă registrele A și HL cu niște valori și apoi afișează toate registrele

Z80 C>x
A F B C D E H L IX IY I R SP PC IFF1 IFF2 IMF
0200 0000 002A 0002 0000 0000 00 00 FEFC FEFE 0 0 0
0000'0000'0000'0000'SF=0 ZF=0 HF=0 P/V=0 NF=0 CF=0
LFEFE: 76 HALT

Z80 C>x A 23

Z80 C>x HL a46f

Z80 C>x
A F B C D E H L IX IY I R SP PC IFF1 IFF2 IMF
2300 0000 002A A46F 0000 0000 00 00 FEFC FEFE 0 0 0
0000'0000'0000'0000'SF=0 ZF=0 HF=0 P/V=0 NF=0 CF=0
LFEFE: 76 HALT

T(RACE) [n] - execută n instrucțiuni începând cu cea adresată de PC;

Exemplu: - trace

Z80 C>t
A F B C D E H L IX IY I R SP PC IFF1 IFF2 IMF
0A00 0000 002A A46F 0000 0000 00 00 FEFC 0102 0 0 0
0000'0000'0000'0000'SF=0 ZF=0 HF=0 P/V=0 NF=0 CF=0
L0102: 06 20 LD B,' '

M(OVE) nlo nhi ndest - mută blocul de memorie cuprins între adresele nlo și nhi la adresa ndest;

L(IST) [n1 [n2]] [>outfile | >>outfile] - dezasamblează instrucțiunile începând cu adresa n1 și sfârșind cu adresa n2.

Exemplu: - listează programul încărcat în memorie începând cu adresa 100h

Z80 C>list 100
L0100: 3E 0A LD A,0A
L0102: 06 20 LD B,' '
L0104: 80 ADD A,B
L0105: 0E 19 LD C,19
L0107: 5F LD E,A
L0108: CD 05 00 CALL L0005
L010B: 0E 00 LD C,NUL
L010D: 00 NOP

2.3.2 Apelul funcțiilor BDOS din emulator

Pentru interfața cu dispozitivele de intrare/ ieșire emulatorul oferă un set de funcții numite funcții BDOS. Aceste funcții BDOS implementate în emulator vor apela funcțiile DOS corespunzătoare.

O funcție BDOS se poate apela cu secvența de instrucțiuni de mai jos:

LD C, numărul_funcției
CALL 0005h

Subrutina apelată prin CALL 0005h modifică regiștri. Deci înainte de apelul acestei subrutine ar trebui salvate pe stivă registrele folosite în program iar la ieșire ar trebui reîncărcate de pe stivă.

Funcțiile cele mai des folosite în cadrul laboratorului sunt prezentate în tabelul 2.1. În plus față de aceste funcții de citire/ scriere de caractere de la dispozitivul standard de intrare/ ieșire, mai există un număr de funcții pentru operațiile cu fișiere, care nu au mai fost prezentate.

Funcția BDOS

Acțiunea funcției

00h

Reset – preia emulatorul comanda. Nu alterează memoria.

01h

Citește un caracter de la intrarea standard în registrul A

02h

Scrie caracterul al cărui cod ASCII este în E la ieșirea standard

05h

Trimite caracterul din E la dispozitivul PRN

06h

Dacă E = 0FFh returnează în A următorul caracter de la intrarea standard, iar dacă nu există un caracter returnază 00h

Dacă E <> 0FFh se trimite registrul E la ieșirea standard

09h

Scrie un șir de caractere a cărui adresă de început este în registrul DE la ieșirea standard. Șirul trebuie încheiat cu $

0Ah

Citește o linie de la intrarea standard și se stochează în memorie începând cu adresa (DE)

0Bh

Returnează 0FFh în registrul A dacă intrarea standard are un caracter disponibil și 00h în caz contrar

Tabelul 2.1

2.4 Conversia ASCII – binar și binar – ASCII

2.4.1 Conversia ASCII – binar

În continuare este prezentată la nivel de principiu o rutină de conversie ASCII-binar. Cu această procedură se citește un număr hexa pe 8 biți de la tastatură și acest număr este convertit din codurile ASCII corespunzătoare celor două cifre hexa într-un număr binar.

* citește un caracter în registrul A
* convertește caracterul ASCII în binar
D
Ź A
D
ŹD << 4
* citește un caracter în registrul A
* convertește caracterul ASCII în binar
D
Ź D+A
* în D este numărul pe 8 biți citit de la tastatură

Conversia unui caracter ASCII în cifra hexa corespunzătoare se face cu ajutorul procedurii:

dacă A < ‘0’ atunci

return eroare dacă A <= ‘9’ atunci
A Ź A - ‘0’
return A
dacă A < ‘A’ atunci
return eroare dacă A <= ‘F’ atunci
A Ź A - ‘A’ + 10
return A
dacă A < ‘a’ atunci
return eroare dacă A <= ‘f’ atunci
A Ź A - ‘a’ + 10
return A
return eroare

2.4.2 Conversia binar – ASCII

Sunt prezentate două posibile rutine de conversie binar – ASCII:

* se definește un tabel care conține șirul ‘0123456789ABCDEF’
E
Ź A
E
Ź E >> 4
D
Ź 0
IX
Ź DE
E
Ź tab + IX
* afișez caracterul din registrul E
E
Ź A
E
Ź E & 0Fh
IX
Ź DE
E
Ź tab + IX
* afișez caracterul din registrul E

sau:

E Ź A
E
Ź E >> 4
dacă E <= 9 atunci

E Ź E + ‘0’ altfel
E Ź E + ‘A’ -10 * afișez caracterul din registrul E
E
Ź A
E
Ź E & 0Fh
dacă E <= 9 atunci
E Ź E + ‘0’ altfel
E Ź E + ‘A’ -10 * afișez caracterul din registrul E

3. Mersul lucrării

Să se realizeze un program pentru înmulțirea a două numere hexa pe un octet citite de la tastatură. Programul va conține următoarele trei proceduri:

  1. o rutină de conversie din ASCII în binar, pentru citirea operanzilor;
  2. o rutina de conversie din binar în ASCII, pentru afișarea rezultatului;
  3. o rutină de înmulțire implementată printr-una din metodele cunoscute.