Î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.
Z80 este un procesor pe 8 biți a cărui structură internă este prezentată în figura 2.1:
Registrele microprocesorului Z80 formează trei grupuri distincte:
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:
pentru operațiile aritmetice cu operanzi cu semn are semnificația de depășire indicând depășirea capacității de memorare;
Al doilea grup conține registrele cu destinație specială (figura 2.3):
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.
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.
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:
COD OPERAȚIE |
1 sau 2 octeți |
OPERAND |
Exemplu: LD A, 103 încarcă registrul A cu valoarea zecimală 103.
COD OPERAȚIE |
1 sau 2 octeți |
OPERAND |
|
OPERAND |
Exemplu: LD BC, 0a312h încarcă registrul dublu BC cu valoarea hexa a312.
COD OPERAȚIE |
1 octet |
Exemplu: RST n n = 0,7 apelul subrutinei aflate la adresa 8Śn.
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.
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.
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.
COD OPERAȚIE |
1 octet |
Exemplu: CP E compară registrul A cu registrul E.
COD OPERAȚIE |
1 octet |
Exemplu: EX DE, HL interschimbă conținutul registrelor DE și HL.
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.
COD OPERAȚIE |
1 octet 1 octet |
COD OPERAȚIE |
Exemplu: SET 3, A setează bitul 3 din registrul A.
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)
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).
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
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
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:
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
Î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
Conversia unui caracter ASCII în cifra hexa corespunzătoare se face cu ajutorul procedurii:
dacă A < 0 atunci
Sunt prezentate două posibile rutine de conversie binar ASCII:
* se definește un tabel care conține șirul 0123456789ABCDEF
E
sau:
E
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: