Diferență între revizuiri ale paginii „CID aplicatii 4 : Alte circuite combinationale”
Cbira (discuție | contribuții) (Pagină nouă: == Memoria ROM== Memoria este un dispozitiv electronic utilizat pentru stocarea datelor. Aceasta poate fi de mai multe feluri, având diverse caracteristici, cum ar fi capacitatea...) |
m (→Exercițiul 1) |
||
Linia 149: | Linia 149: | ||
== Exerciții:== | == Exerciții:== | ||
=== Exercițiul 1=== | === Exercițiul 1=== | ||
− | Completați codul din Exemplul 2 astfel încât să se poată reprezenta toate numerele în bază | + | Completați codul din Exemplul 2 astfel încât să se poată reprezenta toate numerele în bază 16 (hexazecimal), conform Anexei 1 |
=== Exercițiul 2=== | === Exercițiul 2=== |
Versiunea de la data 17 februarie 2023 15:48
Memoria ROM
Memoria este un dispozitiv electronic utilizat pentru stocarea datelor. Aceasta poate fi de mai multe feluri, având diverse caracteristici, cum ar fi capacitatea de a-și păstra sau nu conținutul după întreruperea alimentării sau capacitatea de a-și modifica sau nu conținutul după terminarea procesului de producție.
Memoria ROM (Read-Only Memory) este un circuit combinational folosit pentru stocarea unor date ce pot fi accesate cu ajutorul unei intrari de adresă. Asa cum sugerează și numele, memoria ROM clasică nu poate fi modificată. În plus, datorită modului în care este implementată, ea își păstrează conținutul după întreruperea alimentării (este nevolatilă).
Pentru a înțelege termenul de memorie, putem face următorul exercițiu de imaginație: să ne gândim la un dulap cu mai multe sertare. Conținutul memoriei este reprezentat de conținutul sertarelor, iar adresele sunt reprezentate de etichetele lipite pe aceste sertare pentru a le identifica. Dacă avem nevoie de conținutul unui sertar, va trebui să știm eticheta aferentă acestuia (adresa).
O memorie ROM are următorii parametri: numărul de biți ai adresei, care este legat de numarul de locații de memorie (cu n biți de adresă putem forma 2𝑛 combinații diferite, deci putem accesa maxim 2𝑛 locații de memorie) și dimensiunea locației de memorie, care ne spune cât de multă informație poate stoca o locație de memorie.
Să urmărim exemplul din figura următoare:
Aici, adresa are dimensiunea de 4 biți, asadar putem accesa cu aceasta 16 locații diferite de memorie. Dimensiunea fiecărei locații este de 8 biți, așadar fiecare locație de memorie poate stoca numere de 8 biți. Spunem că memoria ROM este o memorie 16x8. Capacitatea acestei memorii este de 16 x 8 biți = 128 biți.
Exemple
Exemplul 1: Decodorul
Decodorul este circuitul care, pentru o anumită valoare a intrării, va genera la ieșire un șir binar care conține 1 pe poziția cu indicele egal cu valorea intrării și 0 in rest. De exemplu, decodorul de mai jos pe 2 biți va avea următoarea corespondență intrare-iesire:
in | out |
2'b00 | 4'b0001 |
2'b01 | 4'b0010 |
2'b10 | 4'b0100 |
2'b11 | 4'b1000 |
Vom implementa acest circuit ca memorie ROM.
Implementarea Verilog a circuitului
module Decoder(
input [1:0] in,
output reg [3:0] out
);
always@(in) begin
case(in)
2'b00: out = 4'b0001;
2'b01: out = 4'b0010;
2'b10: out = 4'b0100;
2'b11: out = 4'b1000;
default: out = 4'b0000;
endcase
end
endmodule
Implementarea Verilog a modulului de test
`timescale 1ns/1ps
module Decoder_TB();
reg [1:0] in_tb;
wire [3:0] out_tb;
integer idx;
initial begin
for(idx=0; idx<4; idx = idx + 1) begin
in_t = idx;
#1;
end
#2 $stop();
end
Decoder DUT(
.in(in_tb),
.out(out_tb)
);
endmodule
Observații:
- Circuitul Decoder va avea o intrare pe 2 biți, care va reprezenta adresa memoriei ROM și o iesire pe 4 biți, reprezentând conținuturile memoriei ROM corespunzătoare fiecărei combinații de la intrare.
- Chiar dacă în interiorul instrucțiunii case se acoperă toate cazurile posibile (toate combinațiile de 2 biți), este bine sa punem și un default pentru a evita inserarea în locul circuitului combinațional dorit (aici, memoria ROM) a unui latch.
Exemplul 2: Transcodorul
Trancodorul este o memorie ROM care asociază unei anumite intrări, reprezentată de adresă, un anumit cod, reprezentat de conținutului locației de memorie asociată acelei adrese.
In acest exemplu, vom folosi transcodorul pentru a realiza un modul ce controlează afișajul cu 7 segmente. Acest dispozitiv de afișare este format, așa cum sugerează și numele, din 7 segmente ce pot fi controlate separat. Putem aprinde sau stinge fiecare segment controlând tensiunea aplicată pe acesta. Pentru acest afișaj, comanda este negativă: aplicând 0 logic pe un segment acesta se va aprinde, iar aplicând 1 logic, acesta se va stinge.
Structura unui afisaj cu 7 segmente este prezentată în imaginea de mai jos:
Pentru a realiza controlul afișării, avem nevoie de o memorie ROM ce trebuie să asocieze codului binar al fiecărui element ce poate fi afișat un șir de biți care sting sau aprind diversele segmente ale afișajului, astfel încât să apară imaginea elementului dorit.
Pentru a reprezenta, de exemplu, cele 16 numere hexa, segmentele trebuie aprinse conform Anexei 1. De exemplu, pentru primele 8 numere (0 până la 7), tabelul de asociere este următorul:
Număr | Cod intrare | Șir de afisare |
0 | 4'b0000 | 7'b100_0000 |
1 | 4'b0001 | 7'b111_1001 |
2 | 4'b0010 | 7'b010_0100 |
3 | 4'b0011 | 7'b011_0000 |
4 | 4'b0100 | 7'b001_1001 |
5 | 4'b0101 | 7'b001_0010 |
6 | 4'b0110 | 7'b000_0010 |
7 | 4'b0111 | 7'b111_1000 |
Implementarea Verilog a modulului Display7Seg
module Display7Seg(
input [3:0] in,
output reg [6:0] out
);
always@(in) begin
case(in)
4'd0: out = 7'b1000000;
4'd1: out = 7'b1111001;
4'd2: out = 7'b0100100;
4'd3: out = 7'b0110000;
4'd4: out = 7'b0011001;
4'd5: out = 7'b0010010;
4'd6: out = 7'b0000010;
4'd7: out = 7'b1111000;
default: out = 7'b0000110;
endcase
end
endmodule
Exerciții:
Exercițiul 1
Completați codul din Exemplul 2 astfel încât să se poată reprezenta toate numerele în bază 16 (hexazecimal), conform Anexei 1
Exercițiul 2
Un procesor are nevoie de un șir de biți numit instrucțiune pentru a știi ce trebuie să facă. Această instrucțiune codează în șirul său de biți toate informațiile necesare.
De exemplu, pentru un grup de instrucțiuni care operează cu registre, aceste informații pot fi:
- codul instrucțiunii (operation code - opcode): un șir de biți care ne spune ce operație se execută.
- destinația: un șir de biți care codează numărul registrului destinație.
- sursa1: un șir de biți care codează numărul registrului folosit ca operand 1.
- sursa2: un șir de biți care codează numărul registrului folosit ca operand 2.
Vom considera codul operației pe 4 biți, ceea ce inseamnă ca putem avea 16 instrucțiuni diferite. ]n plus, câmpurile care codează destinația și cei doi operanzi vor avea fiecare câte 4 biți, ceea ce inseamnă că vom avea 16 registre cu care putem lucra (R0 ... R15). Adunând dimensiunile fiecărui câmp, vom obține o instrucțiune pe 16 biți.
Instrucțiunile și codul operațiilor:
Vom considera ca procesorul nostru elementar poate suporta următoarele instrucțiuni:
Operație | Cod operație | Sintaxă | Descriere |
ADD | 4'b0000 | ADD Rd Rs1 Rs2 | Rd = Rs1 + Rs2 |
SUB | 4'b0001 | SUB Rd Rs1 Rs2 | Rd = Rs1 - Rs2 |
OR | 4'b0010 | OR Rd Rs1 Rs2 | Rd = Rs1 OR Rs2 |
AND | 4'b0011 | AND Rd Rs1 Rs2 | Rd = Rs1 AND Rs2 |
LOADC | 4'b0100 | LOADC Rd, const | Rd = const |
Pentru instrucțiunile prezentate mai sus, vom avea următoarele moduri de codare (de împărțire a informației în cadrul instrucțiunii):
Registrele:
Cele 16 registre vor fi codate cu un număr egal cu indexul său. De exemplu, R0 va avea codul 4'b000, R1 va avea codul 4'b0001 și așa mai departe.
Considerând cele spuse mai sus, vom avea următoarele exemple de instrucțiuni:
Având toate informațiile de mai sus, descrieți o memorie ROM cu adresă pe 4 biți și locații pe 16 biți, care să conțină următorul program, începând cu adresa 0:
LOADC R0, 2h
LOADC R1, 5h
LOADC R2, 7h
ADD R3, R1, R0
SUB R4, R2, R1
OR R5, R3, R4
Exercițiul 3
Proiectați un Codor Cezar cu cheie fixă sub forma unei memorii ROM.
Un Codor Cezar preia un mesaj și codează independent fiecare literă a acestuia pentru a obține un mesaj cifrat. El se folosește de o cheie fixă care se adună la fiecare literă a mesajului. De exemplu, pentru cheia "+3": a->d; b->e; c->f;...; y->b; z->c. Observați că atunci când alfabetul a ajuns la capăt, se reia de la început. Pentru decodare, se va folosi procedura inversă: pentru fiecare literă, vom aplica cheia cu semn invers (în exemplul nostru, cheia de decodare este "-3").
Observații, sfaturi, task-uri suplimentare:
- Codorul va putea prelucra doar litere mici și spațiu gol (acesta rămâne neschimbat).
- Cel mai usor mod de a scrie această funcționalitate este folosind un bloc de tip case.
- Pentru testare, se pot folosi în testbench variabile de tip reg pe 8 biți, astfel:
reg [7:0] litera;
litera = "A";
- Avansat: În SystemVerilog există și tipul de date string, ceea ce permite parcurgerea cu un for a mesajului. În Verilog clasic, astfel de parcurgeri sunt posibile, dar sintaxa este mai complicată.
- Se va folosi codul ASCII pentru valori. Pentru o ușoara vizualizare a datelor în simulare, se poate schimba radix-ul în ASCII.
- Avansat: Pentru a testa automat codul, se poate instanția încă un modul în testbench cu aceeași funcționalitate pe post de "golden model". Acest modul nu trebuie să fie sintetizabil și atunci sintaxa permite mai multă libertate (cum ar fi operația de modulo "%", utilă pentru testare, dar care determină un circuit complicat dacă ar fi sintetizată). Ieșirile celor două module din testbench sunt apoi comparate pentru a se verifica că ambele implementări oferă același rezultat.
- Implementați și Decodorul Cezar și testați Codorul împreună cu acesta. Aveți grijă ca cele două module să aibă aceeași cheie.