This is an old revision of the document!
Cum citim un datasheet? ATTiny20
Mai jos avem reprezentarea binară a instrucțiunii add R5, R3
:
Bit index | 15 | 14 | 13 | 12 | 11 | 10 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Bit value | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0 | 1 | 0 | 0 | 1 | 1 |
Bit significance | opcode | Rd | Rr | Rd | Rr |
Fiindcă register file-ul procesorului nostru (ATtiny20) are doar 16 registre, putem ignora biții Rr
si Rd
de pe pozițiile 9 și 8 (Atmel garantează că, din motive de compatibilitate, vor fi mereu setați pe 1, sau, echivalent, vor fi folosite numai registrele R16
→ R31
).
Așadar, instrucțiunile add R21, R19
și add R5, R3
sunt echivalente în implementarea noastră.
Mereu filtrați de la instrucțiunile cele mai particulare (cele care au partea constanta cea mai mare) până la cele mai generale (au partea constanta mai mica). Adică? dintre opcode-ul 1) 0000_1111_1010_0101 și opcode-ul 2) 1111_0101_10rr_rddd mai particulara este 1.
Pentru a asigura comunicația dintre procesor, memorie și periferice le vom interconecta pe toate într-o topologie de tip magistrala. Aceasta este un mediu partajat de comunicație, în sensul că există un singur set de semnale (de control, date și adrese) la care au acces toate modulele conectate (spre deosebire de o topologie point-to-point unde există o legătură separată între fiecare modul care dorește să comunice cu altul).
Magistrala de sistem este, pe scurt, o magistrală care conectează procesorul de memoria principala și de periferice. Magistrala de sistem trebuie sa aibă, în general, 3 componente:
În general, pentru comunicația mai multor module pe o magistrala, trebuie stabilit un protocol de comunicație (trebuie evitată situația în care există mai mulți vorbitori concomitenți pe aceeași linie, fiindcă acest gen de conflicte pot duce la scurtcircuite și alte probleme de natură electrică. În practică, există un bus master și mai mulți bus slaves. Nu întâmplător, în cazul nostru bus master va fi CPU-ul iar, momentan, singurul slave de pe system bus este memoria.
Un exemplu de system bus este Wishbone, un standard open-source folosit în multe design-uri IP (vezi OpenCores). De asemenea, ISA bus este un exemplu de system bus, folosit în strămoșul calculatoarelor desktop moderne, IBM PC.
Ierarhii de magistrale În sistemele desktop, system bus, adică o singură magistrala general-purpose, a fost demult înlocuita cu o ierarhie de magistrale (unele locale, altele externe) de viteze si lățimi de bandă diferite. Astfel, pentru asigurarea conectivității la memorie, un CPU x86 folosește un memory controller hub, care se ocupă de interfațarea propriu-zisă (generarea semnalelor de control) pentru memoria SDRAM conectată pe placa de bază.
Istoric, acest controller de memorie s-a aflat pe un chip extern procesorului, dar situat pe placa de baza în apropierea acestuia, numit Northbridge. Magistrala de mare viteza dintre CPU și Northbridge se numește Front-side bus (sau FSB, pe scurt) pentru sistemele Intel, sau EV6, pentru implementarea cu același rol de la AMD.
Despre FSB:
Modurile de adresare a memoriei descriu metoda prin care este calculată adresa efectivă a datelor accesate, folosind informații constante și/sau conținute în registre. Pentru a fi mai flexibil pentru programatori un ISA va implementa mai multe moduri de adresare a memoriei, fiecare cu avantaje și dezavantaje. Aceste moduri pot fi folosite prin diferite instrucțiuni. Mai departe ne vom uita peste modurile de adresare a memoriei de date disponibile pe arhitectura AVR.
Adresa de memorie dorită se află chiar în corpul instrucțiunii. Un exemplu de instrucțiune ce folosește adresare directa este LDS (16-bit).
Biții marcați cu k formează o constantă ce reprezintă adresa de memorie de unde sunt citite datele, iar aceste date sunt scrise în registrul Rd.
Adresa de memorie dorită se află în registrul X, Y sau Z. O instrucțiune ce folosește adresare indirectă cu deplasament este LDD (i).
Conform datasheetului când ne referim la registrul X, Y sau Z ne referim de fapt la grupări de câte doua registre:
Există desigur și variații Adresare indirectă cu offset: Adresa de memorie dorită se află în registrul Y sau Z, la care se adaugă un deplasament găsit în corpul instrucțiunii. O instrucțiune ce folosește adresare indirectă cu deplasament este LDD (iv).
Biții marcați cu q formează o constantă ce reprezintă deplasamentul ce trebuie adăugat adresei de memorie găsită în registrul Y sau Z. Datele sunt scrie în registrul Rd.
Adresare indirectă cu pre-decrementare
Adresa de memorie dorită se afla în registrul X, Y sau Z, care este decrementată înainte de a fi folosită. O instrucțiune ce folosește adresare indirectă cu deplasament este LDD (iii).
Adresare indirectă cu post-incrementare
Adresa de memorie dorita se afla în registrul X, Y sau Z, care este incrementata după ce este folosită. O instrucțiune ce folosește adresare indirectă cu deplasament este LDD (ii).
Procesorul pe care îl implementăm la laborator are o arhitectura de tip Harvard. Asta înseamnă că vom avea 2 memorii separate pentru instrucțiuni și date.
* Memoria de instrucțiuni este de tip ROM (2048 bytes) și se găsește în rom.v adresele sunt pe 8 biți datele au 16 biți (adică lungimea unei instrucțiuni) * Memoria de date este un SRAM sincron de tip pipeline (128 bytes) și se găsește în sram.v adresele sunt pe 7 biți datele au 8 biți (= dimensiunea unui registru)
Procesorul lucrează cu 16 registre “general purpose” de 8 biți. Teoretic există 32 registre, însă implementarea noastră nu va folosi niciodată primele 16. Astfel când scriem cod AVR vom putea folosi numai registrele din intervalul R16 → R31.
Totuși, după cum ați văzut în laboratorul trecut, nu vom lucra direct cu aceste registre, ci vom folosi registrul sursa Rr și registrul sursă/destinație Rd. Aceștia în spate adresează cele 16 registre. Puteți vedea acest lucru în sursa register_file.v în care este implementat un Dual Port SRAM. Acesta garantează accesul concomitent (într-un ciclu de ceas) atât la Rd, cât și la Rr.
Driver-ul de memorie pentru modulul dual_port_sram este reg_file_interface_unit definit în fișierul reg_file_interface_unit.v. Aici vom seta biții de *cs*, *we* si *oe*, precum și liniile de date și adrese ce sunt necesare pentru lucrul cu memoria.
În cazul memoriei Dual Port SRAM din laborator, vom avea acești biți atât pentru Rd, cât și pentru Rr (*rr_cs, rd_cs*, etc). Similar, vor exista linii de date și adrese distincte pentru fiecare dintre Rd si Rr.
Fata de laboratorul anterior, veți găsi o serie de semnale noi ce au fost adăugate unor modulelor procesorului nostru pentru a putea permite implementarea instrucțiunilor de lucru cu memoria. În această secțiune va fi explicat pe scurt rolul acestor semnale noi și utilitatea lor.
Instrucțiunile pe care le veți implementa în acest laborator diferă putin de cele UAL pe care le-ați întâlnit pana acum. În aceasta secțiune va fi explicat pe scurt cum trebuie citit si interpretat datasheet-ul în cazul acestor instrucțiuni.
Instrucțiunile prezentate pot fi grupate și după tipurile de memorie intre care transfera date, astfel: