CID aplicatii 11 : Automate finite
Automate finite
Automatul finit este folosit pentru a descrie sisteme ce tranziteaza un numar finit de stari. Acest tip de sistem este foarte util atunci cand starile nu sunt tranzitate intr-un mod simplu, evident sau repetitiv.
Automatul finit, numit și FSM (Finite State Machine), este un model matematic de computație, definit de următoarele elemente:
- O mulțime finită de simboluri de intrare, numită alfabet de intrare;
- O mulțime finită și nevidă de simboluri de ieșire, numită alfabet de ieșire;
- O mulțime finită și nevidă de stări, din care doar una, numită starea curentă, este activă la un moment dat;
- O stare inițială, care face parte din mulțimea stărilor;
- O funcție de tranziție a stărilor, care calculează starea următoare a automatului în funcție de starea curentă și de simbolul de intrare;
- O funcție de calcul a ieșirii, care determină simbolul de ieșire în funcție de starea curentă (în cazul automatelor de tip Moore) sau în funcție de starea curentă și de simbolul de intrare (în cazul automatelor de tip Mealy).
La fiecare front al ceasului, valoarea stării următoare, calculată de către CLC, va fi încărcată în registru. Dacă registrul are n biți, numărul maxim de stări care pot fi reprezentate este 2n. Acest număr poate fi mai mic, în funcție de schema de codare a stărilor. De exemplu, pentru n = 4, folosind codarea binară se pot reprezenta cel mult 16 stări (0000, 0001, 0010, ..., 1111), în timp ce pentru codarea one-hot, în care doar un singur bit poate lua valoarea 1, se pot reprezenta 4 stări (1000, 0100, 0010, 0001).
Pentru a reprezenta comportamentul unui automat finit, putem folosi grafuri sau organigrame, conventiile de notare depinzand de tipul automatului (Moore sau Mealy).
Exemple
Exemplul 1: Automat ce detecteaza secvente de tipul 11....100....0
In acest exemplu va fi implementat un automat care detecteaza secventele de tipul 11....100....0. Pentru aceasta, automatul va avea o intrare pe un bit (in, pe care va veni secventa de biti) si doua iesiri: detectOk, care semnalizeaza prin 1 ca nu a fost inca detectata o secventa ilegala si detectFail, care semnalizeaza prin 1 ca a fost detectata o secventa ilegala (un 1 dupa 0).
Automatul va avea 3 stari:
- Q0 - STATE_READ1: automatul intra in aceasta stare la reset si va ramane in aceasta atata timp cat intrarea este 1 (inca nu a aparut niciun 0).
- Q1 - STATE_READ0: automatul intra in aceasta stare atunci cand apare pe intrare primul 0 si va ramane in aceasta atata timp cat pe intrare este 0.
- Q2 - STATE_ERROR: automatul intra in aceasta stare atunci cand apare un 1 dupa 0 si va ramane blocat aici pana la reset.
Pentru a coda cele 3 stari avem nevoie de minim 2 biti: STATE_READ1 = 2'b00, STATE_READ0 = 2'b01, STATE_ERROR = 2'b10.
Graful automatului este:
Implementarea automatului
module FSM1(
input clock,
input in,
input reset,
output detectOk,
output detectFail
);
//Se asociaza sirurilor de biti folositi pentru codarea starilor nume ce pot fi folosite mai usor in cod.
//La compilare, numele vor fi inlocuite in cod cu numerele asociate la inceput.
localparam STATE_READ1 = 2'b00;
localparam STATE_READ0 = 2'b01;
localparam STATE_ERROR = 2'b10;
reg [1:0] state, state_next;
//registrul de stare
always@(posedge clock) begin
if(reset == 1)
state <= STATE_READ1;
else
state <= state_next;
end
//circuit combinational pentru calculul starii urmatoare
always@(*) begin
state_next = state;
case(state)
STATE_READ1: begin
if(in == 0) state_next = STATE_READ0;
end
STATE_READ0: begin
if(in == 1) state_next = STATE_ERROR;
end
STATE_ERROR: state_next = STATE_ERROR;
default: state_next = STATE_READ1;
endcase
end
//circuit combinational pentru calculul iesirilor
assign detectOk = (state == STATE_READ0) || (state == STATE_READ1);
assign detectFail = (state == STATE_ERROR);
endmodule
Implementarea unui modul de test pentru FSM1
module FSM1_TB();
reg clock_t;
reg reset_t;
reg in_t;
wire detectOk_t;
wire detectFail_t;
initial begin
clock_t = 0;
forever #1 clock_t = ~clock_t;
end
initial begin
in_t = 1;
reset_t = 1;
#2 reset_t = 0;
#10 in_t = 0;
#10 in_t = 1;
#10 $stop();
end
FSM1 DUT(
.clock(clock_t),
.reset(reset_t),
.in(in_t),
.detectOk(detectOk_t),
.detectFail(detectFail_t)
);
endmodule
Exemplul 2: Automat ce detecteaza fronturile crescatoare ale unui semnal
Automatul ce detecteaza fronturile crescatoare are un singur semnal de intrare in, care reprezinta semnalul analizat si o singura iesire, out, generand pe aceasta un puls lung cat o perioada de ceas la fiecare aparitie a unui front crescator pe in.
Vom avea nevoie de 3 stari:
- Q0: automatul intra in aceasta stare la reset si va ramane in aceasta atata timp cat intrarea este 0 (inca nu a aparut niciun front crescator).
- Q1: automatul intra in aceasta stare atunci cand apare pe intrare un front crescator. Dupa aparitia frontului crescator sunt doua posibilitati: linia ramane in 1, ceea ce duce la trecerea in starea Q2 care va duce iesirea in 0 dupa o perioada de ceas, sau linia trece in 0 dupa un ciclu de ceas, ceea ce duce la revenirea in starea Q0.
- Q2: automatul intra in aceasta stare atunci cand linia de intrare ramane in 1 mai mult de o perioada de ceas. Automatul va ramane in aceasta stare atata timp cat in ramane in 1 si va reveni in starea Q0 imediat ce in revine in 0.
Graful automatului este:
Implementarea automatului
module FSM2(
input clock,
input in,
input reset,
output out
);
localparam Q0 = 2'b00;
localparam Q1 = 2'b01;
localparam Q2 = 2'b10;
reg [1:0] state, state_next;
always@(posedge clock) begin
if(reset == 1)
state <= Q0;
else
state <= state_next;
end
always@(*) begin
state_next = state;
case(state)
Q0: begin
if(in == 1) state_next = Q1;
end
Q1: begin
if(in == 0) state_next = Q0;
if(in == 1) state_next = Q2;
end
Q2: begin
if(in == 0) state_next = Q0;
end
default: state_next = Q0;
endcase
end
assign out = (state == Q1);
endmodule
Implementarea unui modul de test pentru FSM2
module FSM2_TB();
reg clock_t;
reg reset_t;
reg in_t;
wire out_t;
initial begin
clock_t = 0;
forever #1 clock_t = ~clock_t;
end
initial begin
in_t = 0;
reset_t = 1;
#2 reset_t = 0;
#10 in_t = 1;
#5 in_t = 0;
#10 in_t = 1;
#5 in_t = 0;
#10 $stop();
end
FSM2 DUT(
.clock(clock_t),
.reset(reset_t),
.in(in_t),
.out(out_t)
);
endmodule
Exerciții
Exercițiul 1
Implementați un automat finit ce detectează fronturile descrescătoare. Acesta are un singur semnal de intrare in, care reprezintă semnalul analizat și o singură ieșire out, generând pe această un puls lung cât o perioadă de ceas la fiecare apariție a unui front descrescător pe in.
Realizați implementarea Verilog plecând de la graful automatului:
Exercițiul 2
Implementați un automat finit ce detectează atât fronturile crescătoare, cât și pe cele descrescătoare.
Exercițiul 3
Să se implementeze un circuit care generează un semnal PWM cu un factor de umplere ce variază triungular, la fiecare front descrescător al unui semnal de intrare.
Schema circuitului este:
Modulele componente ale circuitului sunt:
- FallingEdgeDetector: Automat ce detectează fronturile descrescătoare ale semnalului de intrare.
- TriangularCounter: Automat ce generează la iesire secvența de numere 64, 128, 192, 255, 192, 128, 64.
- Counter: Numărător pe 8 biți cu reset sincron.
- COMP: Comparator cu două intrări pe 8 biți. Ieșirea sa va fi 1 atunci când counter < out și 0 în rest.