Table of Contents

Laboratorul 01 - Memorii

În acest laborator vom învăța despre memorii. Vom implementa memorii de tip ROM și RAM în Verilog, apoi ne vom familiariza cu scheletul de laborator pe care îl vom folosi în cadrul următoarelor laboratoare pentru implementarea unui microcontroller.

Introducere

Există situații în care vrem să folosim logica secvențială pentru a stoca mai multă informație decât simpla stare curentă a unui automat finit, ci mai degrabă informații/date de dimensiuni mari și uz general. Astfel au apărut aceste blocuri de circuite secvențiale de dimensiuni mari, numite memorii, și caracterizate de următoarele trăsături:

  • Dimensiune: măsurată în biți (b), octeți (B), și multiplii acestora.
  • Timp de acces: măsurat în submultiplii ai secundei, în general nanosecunde (ns).
  • Structura internă: un bloc mare de memorie este construit din mai multe module mai mici de memorie.
  • Volatilitatea datelor: determină dacă datele persistă în memorie după un ciclu de alimentare (on-off-on).
  • Alterarea datelor: posibilitatea de modificare a datelor post-fabricație.
  • Modul de acces al datelor: ordinea de accesare a datelor în raport cu timpul.
  • Număr de porturi: câte unități hardware pot avea acces simultan la memorie, în același ciclu de ceas.
  • Preț ($)
  • Tehnologia de fabricație: influențează caracteristicile menționate anterior.

Fiecare soluție este una de compromis 1), iar în aplicațiile de dimensiuni mari se adoptă o tehnică hibridă, numită ierarhie de memorii.

Ierarhia de memorii

Memoria unui calculator numeric este organizată ca o ierarhie de module de memorie. La baza ierarhiei se află memoria auxiliară/secundară 2), urmată de memoria principală 3), apoi de memoria cache 4), iar în vârful ierarhiei se află registrele generale ale procesorului 5).

Memoria cache este o memorie SRAM, utilizată pentru eficientizarea timpului de acces la date a procesorului. Aceasta este încapsulată împreună cu unitatea centrală de procesare (CPU) pentru a facilita viteza ridicată de transfer, eficiența energetică pentru transportul datelor și compensarea timpului de acces la memoria principală.

Criterii de clasificare

Mod de acces

Unul din cele mai simple criterii de clasificare este cel dupa modul de acces:

  1. memorii cu acces aleator (Random Access Memory)- datele pot fi citite sau scrise în orice ordine, fără a ține cont de locația fizică a datelor pe mediul de stocare
  2. memorii cu acces secvențial - datele sunt citite sau scrise într-o ordine strictă, de ex. succesiune liniară
    • Hard disk, CD-ROM - capetele de citire/scriere se deplasează de-a lungul mediului de stocare.
    • Bandă magnetică - pentru a accesa o anumită porțiune a benzii necesită derularea acesteia.

Posibilitatea de modificare a datelor

Din acest punct de vedere există:

  1. memorii care au conținut fixat din momentul fabricației (Read Only Memory)
  2. memorii care au un conținut pseudo-fixat (număr limitat de cicluri de scriere)
    • EEPROM/Flash: tehnologie pentru care scrierile degradează în timp celulele de memorie.
    • CD6)/DVD7)-ROM: datele sunt scrise o singură dată și nu pot fi modificate.
  3. memorii care au un continut alterabil
    • HDD, Flash Memory, RAM

Volatilitatea datelor

  1. memorii volatile: datele se pierd atunci când alimentarea cu energie este întreruptă.
    • RAM
  2. memorii non-volatile: datele persistă pe mediul de stocare pentru o perioadă îndelungată.
    • HDD, Flash Memory, ROM

În cadrul acestui laborator vom aprofunda memoriile cu acces aleator, volatile (RAM).

Tipuri memorii cu acces aleator (RAM)

RAM static (SRAM)

Sursă imagini

  • Un bit de memorie este implementat folosind bistabile sau latch-uri, fiind necesari între 4 și 6 tranzistori.
  • Design-ul facilitează un consum energetic extrem de eficient în idle, însă acesta crește odată cu frecvența acceselor.
  • Costul per bit este ridicat și densitatea de biți per chip este scazută.

RAM dinamic (DRAM)

Sursă imagine

  • Un bit de memorie este implementat folosind un tranzistor și un condensator.
  • Valoarea este memorată cu ajutorul condensatorului8):
    • 0 = un condensator descărcat (fără tensiune electrică între borne)
    • 1 = un condensator încărcat (cu tensiune electrică între borne)
  • Necesită circuit de refresh care să reîncarce periodic condensatorul.
  • Densitatea de biți per chip este mult mai buna decât la SRAM și se pot obține memorii de ordinul zecilor de GB (exemplu).

De ce este necesar circuitul de refresh?

De ce este necesar circuitul de refresh?

Din cauza imperfecțiunilor9), condensatoarele din chip-urile de RAM dinamic se descarcă singure în timp (de ordinul milisecundelor). Din acest motiv celulele trebuie citite periodic, iar cele ce stochează biți de 1 vor fi reîncărcate. Acest procedeu se numește refresh și reprezintă un overhead necesar doar pentru întreținere, RAM-ul fiind indisponibil în acest timp pentru accese utile (“închis pentru curățenie”).

Memorii SRAM sincrone

În cadrul acestui laborator vom implementa o memorie RAM statică sincronă.

Descrierea semnalelor

Toate operațiile necesare pentru interfațarea unui chip SRAM sincron sunt controlate de unul sau mai multe semnale externe de ceas. Pentru a funcționa corect toate semnalele de control trebuie să fie valide atunci când are loc tranziția respectivă a ceasului, adică să fie respectați timpii de setup și hold.

Functionarea unui SSRAM poate fi descrisa prin urmatoarele semnale:

  • Clock: semnalul de sincronizare care marchează momentele în care datele sunt citite sau scrise.
  • Address (ADDR or SAx): adresa la care se efectuează operația de citire sau scriere.
  • Data Inputs and Outputs (DQs or I/Os): Aceste semnale reprezintă datele care sunt scrise în memoria SSRAM în cazul operației de scriere, respectiv datele care sunt citite din memoria SSRAM în cazul operației de citire.
  • Chip Select (CS or SS): activează modulul de memorie, stabilind contextul pentru operațiile ulterioare de citire sau scriere.
  • Output Enable (OE or G): permite scrierea pe magistrală de date a informațiilor de la adresa specificată.
  • Write Enable (WE or RW): permite scrierea datelor în modulul de memorie, fiind prioritar fată de Output Enable.

Descriere elaborată a semnalelor

Descriere elaborată a semnalelor

  • Address (ADDR or SAx): acest semnal de intrare este folosit pentru a selecta o locație de memorie de pe chip. În realitate, pentru memorii mari construite din mai multe chip-uri, atunci când selectăm o adresă, de fapt selectăm mai multe celule de memorie, câte una pentru fiecare chip.
    • Obs. 1. Într-o memorie formată din 8 chip-uri, selectarea unei adrese conduce la 8 locații de memorie simultan. Mai departe, distincția dintre acestea se face decodificând biții suplimentari ai adresei.
  • Obs. 2. Dimensiunea adresei depinde de mărimea memoriei. O memorie SRAM de 32K x 8 va avea 15 biți de adresă (215 = 32K).
  • Data Inputs and Outputs (DQs or I/Os): Pinii de DQ sunt folosiți pentru intrarea și ieșirea datelor. Pe unele memorii pinii de intrare/ieșire sunt separați, iar pe altele sunt multiplexați pe aceiași pini. Spre exemplu, o memorie SRAM de 32K x 8 va avea 8 biți de date.
    • În timpul unei operații de scriere, un semnal de date se aplică pe pinii de Data Input. Aceste date sunt eșantionate și stocate în celula de memorie selectată prin biții de adresă.
    • În timpul unei operații de citire, datele de la adresa de memorie selectată vor apărea pe pinii de Data Output odată ce accesul s-a încheiat și Output Enable (OE) a fost activat.
    • În majoritatea timpului, pinii DQ sunt într-o stare de impedanță mărită, adică nu trag și nu dau curent. Ei nu prezintă niciun semnal către exterior, ca și când ar fi deconectați din circuit.
  • Output Enable (OE or G): (semnal descris în continuare ca activ high) atunci când OE este 0 ieșirile (DQ) sunt întotdeauna în stare de impedanță mărită. Când OE este 1, ieșirile sunt active, iar datele pot apărea pe pini atunci când sunt disponibile. OE este un semnal asincron: poate fi modificat în orice moment de timp, iar SRAM-ul va răspunde imediat schimbării.
    • În timpul unei operații de citire acest semnal se folosește pentru a bloca datele de a apărea la ieșire până atunci când sunt necesare.
    • Înaintea unei operații de scriere acest semnal este uneori folosit pentru a evita coliziuni pe magistrala de date prin tri-state.
    • În timpul operației de scriere propriu-zise semnalul OE este ignorat.
  • Clock: La SRAM-urile cu un singur semnal de ceas, acesta controlează momentul când semnalele de intrare sunt eșantionate de către memorie, la începutul unui ciclu de citire sau scriere, și când semnalele de ieșire devin vizibile pe pini.
  • Chip Select (CS or SS): (activ high) este folosit pentru a permite/bloca semnalele de intre/ieșire către/de la chip. De exemplu, atunci când CS este 0 semnalele de input aplicate pe pini sunt ignorate.
  • Write Enable (WE or RW): (activ high - 1 = write) semnalul este folosit pentru a alege dintre o operație de citire sau de scriere. Atunci când WE este 1 datele aplicate pe pinii de intrare sunt copiate în memorie. Când WE este 0 se începe un ciclu de citire, iar datele de pe linia de date sunt ignorate.

Structura interioară a unui chip SRAM 2^h x g

Stabilirea nivelelor logice pe care sunt active semnalele este o chestiune ce ține strict de convenție, și este de preferat păstrarea aceleiași convenții pe întreg parcursul unui proiect. Pentru a asigura compatibilitatea între module cu convenții diferite de polaritate, se pot utiliza porți logice inversoare.

TL;DR

Memoriile pot fi clasificate în funcție de

  • mod de acces: aleator, secvențial
  • posibilitatea de modificare a datelor: fixat, pseudo-fixat, alterabil
  • volatilitatea datelor: volatil, persistent

Tipuri de memorii cu acces aleator (RAM)

  • static: 4-6 tranzistori, rapid, densitate mică de biți
  • dinamic: 1 tranzistor + 1 condensator, mai puțin rapid, densitate mare de biți, necesită circuit de refresh

Ierarhii de memorii

  • reducerea costului
  • optimizarea timpului de acces la date

Pentru operarea unui modul de memorie se vor folosi semnalele:

  • Address: adresa zonei de memorie
  • Data Inputs and Outputs: datele scrise/citite
  • Chip Select: activarea chip-ului de memorie
  • Output Enable: permiterea scrierii datelor la ieșire
  • Write Enable: permiterea scrierii în memorie

Exerciții

Task 00: Descărcați scheletul de laborator de aici și deschideți fișierul .xpr cu programul Vivado.

Task 01: Jocuri de lumini, memoria ROM (3p):

  • Analizați codul memoriei ROM din fișierul task01.v. Ce capacitate are această memorie ROM? Câți biți? Câți octeți?
  • Observați vreo greșeală în modulul rom din fișierul task01.v ? Dacă da, corectați aceste erori.
  • Analizați codul Verilog din fișierul read_rom.v. Modulul read_rom va citi conținutul memoriei rom și îl va afișa pe ledurile plăcii Nexys A7.
  • Completați TODO 1.1 din read_rom.v - adică instanțiați modulul rom.
  • Generați bitstream-ul pentru modulul read_rom. Încarcați acest bitstream pe placa FPGA. Modificați valoarea intrării read_frequency din switch-urile din dreapta de pe placa FPGA. Ce se afișează pe cele 16 leduri ?
  • (Opțional) Completați TODO 1.2 din fișierul task01.v, în interiorul modului rom pentru a încărca și un alt joc de lumini.

Semnalul data trebuie declarat ca reg din cauza restricției sintactice a limbajului Verilog, ca toate semnalele atribuite în interiorul unui bloc always să fie de tipul reg. Blocul always trebuie să fie asincron față de ceas deci trebuie să fie declarat @*

În realitate, memoria va fi sintetizată ca un mare multiplexor, cu intrările hardcodate pentru fiecare selecție posibilă. Memoria ROM cu conținut cu adevărat nemodificabil nu este nimic altceva decăt un circuit combinațional care primește ca intrare o adresă și scoate la ieșire o valoare hardcodată pentru acea adresă.

Pentru a adresa toți cei 16 octeți este nevoie de o lățime a adreselor de 4 biți.

// Pseudocod pentru o memorie ROM cu conținutul [1,2,4,8,16,32,64,128,170,85,3,5,1,0,53,13,0]:

module rom (input[4] adress, output[8] data)
{
    always
        case(adress)
            4'd0:    data = 8'd1
            4'd1:    data = 8'd2
            4'd2:    data = 8'd4
            4'd3:    data = 8'd8
            4'd4:    data = 8'd16
            4'd5:    data = 8'd32
            4'd6:    data = 8'd64
            4'd7:    data = 8'd128
            4'd8:    data = 8'd170
            4'd9:    data = 8'd85
            4'd10:   data = 8'd3
            4'd11:   data = 8'd5
            4'd12:   data = 8'd1
            4'd13:   data = 8'd0
            4'd14:   data = 8'd53
            4'd15:   data = 8'd13
            default: data = 8'd0
        end case
    end always
}

Task 02: Memoria SRAM (4p) Implementați o memorie SRAM în fișierul task02.v pornind de la pseudocodul de mai jos și de la Structura interioară a unui bloc SRAM.

  • Urmăriți și rezolvați TODO-urile din task02.v
  • Completați TODO-urile din modulul de simulare test_sram existent în fișierul task02_test.v
  • Rulați simularea pentru modulul test_sram. Asigurați-vă că scrierile și citirile se fac corect.
  • Dacă ați completat toate TODO-urile ar trebui să vedeți în simulare ceva similar cu Simulare task 02
  • De ce data_out este 'Z' după 650 ns ?
  • Activați Constraint file-ul pentru task-ul 02 astfel:
  1. Dezactivați fișierul Nexys-A7-100T-Master.xdc: Click dreapta -> Disable File
  2. Activați fișierul Nexys-A7-100T-Master_task02.xdc: Click dreapta -> Enable File
  • Generați bitstream-ul pentru modulul task02 și încărcați-l pe placa FPGA.
  • La fel ca în simulare scrieți valorile 0,1 și 2 la adresele 0x00, 0x01 și 0x02.

/*
 * clk - clock
 * oe - output enable, active high
 * cs - chip select, active high
 * we - write enable: 0 = read, 1 = write
 * adresa - adrese pentru 32 de intrari
 * data_in - intrare de date de 8 biti
 * data_out - iesire de date de 8 biti
 */
module sram (input clk, input oe, input cs, input we, input[5] adresa, input[8] data_in, output[8] data_out)
{
    registru[8] memorie
    registru[8] buffer
    
    always (clk)
        if cs:
            if we:
                memorie[adresa] = data_in
            else:
                buffer = memorie[adresa]
            end if
        end if
    end always
    
    if cs & oe & !we:
        data_out = buffer
    else:
        data_out = 8'bz
    end if  
}

Atentie! Porturile de date vor fi de tip wire. Asta înseamna că nu vom mai putea face atribuiri pe aceste porturi în interiorul blocurilor procedurale. Va trebui să găsiți o altă metodă de a modifica aceste porturi, care să fie validă în interiorul acestor blocuri. Utilizați pseudocodul de mai jos pentru a rezolva exercițiul și pentru a identifica modul în care a fost rezolvată problema porturilor de tip wire.

Task 03 (3p) Descărcați scheletul Verilog al microcontrolerului de aici. Acest schelet îl vom folosi în laboratoarele viitoare. Astăzi ne vom familiariza cu structura acestuia. Identificați memoria de instrucțiuni. Ce tip de memorie este aceasta? Identificați modulele din cheatsheet-ul de mai sus.

În scheletul de laborator sunt câteva fișiere de interes:

  • alu.v execută operații aritmetice și logice. Aici vom calcula rezultatele operațiilor aritmetice.
  • checker Acest fișier instanțiază modulul principal - cpu.
  • check_view și checker vor fi utilizate doar pentru a simula procesorul și a verifica funcționalitatea acestuia înainte de a fi sintetizat pe FPGA
  • decode_unit.v se ocupă de decodificarea instrucțiunilor. Aici vom adăuga logica de decodificare pentru instrucțiunile noi.
  • control_unit.v implementează logica de control. Aici vom translata opcode_type primit de la decode_unit în alu_opsel - semnal transmis mai departe la unitatea aritmetică logică.
  • rom.v conține codul ce va fi executat (instrucțiunile în cod mașină)

Găsiți răspunsurile pentru următoarele întrebări:

  1. Deschideți modulul cpu. Cum se numește parametrul ce definește lățimea datelor? Pe câți biți e definit ?
  2. Câte registre generale are procesorul din schelet în memoria SRAM ? Care e lățimea registrelor ? (Nr. biti)
  3. Câți bytes poate stoca memoria rom folosită pentru instrucțiuni așa cum e instanțiată în modulul cpu ? Câți bytes sunt scriși deja în memorie (cât ocupă instrucțiunile deja scrise)?
  4. Câte stagii are pipeline-ul procesorului ? (Deschideți modulul state_machine)
  5. Cu se stagiu al pipeline-ului se ocupă alu.v ? (Deschideți modulul control_unit)
  6. Care este valoarea inițială a registrului r7 ?
  7. Registrul SREG este registrul Status Register. Citiți despre acest registru în setul de instructiuni AVR. Pentru procesorul din schelet acest registru conține 8 flag-uri, fiecare de câte un bit. Ce reprezintă flag-ul S? Cum și unde este calculat pentru instrucțiunea (implementată deja) Add with Carry din schelet?

Cheatsheet:
 Cheatsheet schelet laborator

Resurse

1) putem alege să optimizăm cel mult două dintre: preț, dimensiune sau performanță
2) lentă, dar de capacitate foarte mare
3) cunoscută ca memorie RAM
4) foarte rapidă, dar de capacitate foarte mică
5) memorie de ordinul octeților, care rulează la viteza procesorului
6) Compact Disc
7) Digital Video/Versatile Disc
8) Poate reține o sarcina electrică pe termen nedefinit.
9) dielectricul, din care sunt fabricate condensatoarele, nu este izolator perfect și există curenți de scurgere