CID aplicatii 13 : Automate finite

De la WikiLabs
Versiunea din 29 mai 2022 07:17, autor: Gvpopescu (Discuție | contribuții) (Exerciții)

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).

[[Fsm.png]]

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:

Organigrama FSM 111000.png

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 == 0)
        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 = 0;
    #2  reset_t = 1;
    #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:

Organigrama FSM rising edge.png

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 == 0)
        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 = 0;
    #2  reset_t = 1;
    #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:

Graf FSM falling edge.png

Exercițiul 2

Implementați un automat finit ce detectează atât fronturile crescătoare, cât și 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:

FSM Exercitiu.png

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.