Bloqueo de combinación síncrono

1

Estoy intentando implementar un bloqueo de combinación síncrono que se desbloqueará una vez que reciba "101011" usando verilog. Tiene una entrada: x, y tres salidas: desbloqueo, listo y error. Siguiendo estas reglas:

  • En estado inicial listo = 1. Permanece en inicial mientras que x = 0
  • Al recibir 101011 en x, desbloquear = 1. Permanece en desbloqueo mientras x = 1
  • Si está en estado de desbloqueo y x = 0, irá al estado inicial
  • En todos los estados que no sean inicial y desbloqueo, si la entrada en x no avanza la secuencia (101011), error = 1.
  • Permanecer en estado de error mientras que x = 1. Si x = 0 en estado de error, vaya al estado inicial

A partir de estas reglas, creé el diagrama de estado a continuación (etiqueté el estado inicial s_reset, ya que la inicial es 000000): Lohetratadocomoundetectordesecuenciasyacabodecrearunmontóndeestados.Aquíestámicódigoacontinuación:

modulelock(inputwireclock,inputwirereset,inputwirex,outputregready,outputregunlock,outputregerror);reg[2:0]state;reg[2:0]next_state;localparams_reset=3'b000,s1=3'b001,s2=3'b010,s3=3'b011,s4=3'b100,s5=3'b101,open=3'b110,s_error=3'b111;s_error=3'b111;always@(posedgeclock,posedgereset)beginif(reset)state<=s_reset;elsestate<=next_state;endalways@*begincase(state)s_reset:if(x==1'b1)beginnext_state=s1;unlock=1'b0;ready=1'b0;error=1'b0;endelsebeginnext_state=s_reset;unlock=1'b0;ready=1'b1;error=1'b0;ends1:if(x==1'b0)beginnext_state=s2;unlock=1'b0;ready=1'b0;error=1'b0;endelsebeginnext_state=s_error;unlock=1'b0;ready=1'b0;error=1'b1;ends2:if(x==1'b1)beginnext_state=s3;unlock=1'b0;ready=1'b0;error=1'b0;endelsebeginnext_state=s_error;unlock=1'b0;ready=1'b0;error=1'b1;ends3:if(x==1'b0)beginnext_state=s4;unlock=1'b0;ready=1'b0;error=1'b0;endelsebeginnext_state=s_error;unlock=1'b0;ready=1'b0;error=1'b1;ends4:if(x==1'b1)beginnext_state=s5;unlock=1'b0;ready=1'b0;error=1'b0;endelsebeginnext_state=s_error;unlock=1'b0;ready=1'b0;error=1'b1;ends5:if(x==1'b1)beginnext_state=open;unlock=1'b0;ready=1'b0;error=1'b0;endelsebeginnext_state=s_error;unlock=1'b0;ready=1'b0;error=1'b1;endopen:if(x==1'b0)beginnext_state=s_reset;unlock=1'b1;ready=1'b0;error=1'b0;endelsebeginnext_state=open;unlock=1'b1;ready=1'b0;error=1'b0;ends_error:if(x==1'b0)beginnext_state=s_reset;unlock=1'b0;ready=1'b1;error=1'b0;endelsebeginnext_state=s_error;unlock=1'b0;ready=1'b0;error=1'b1;enddefault:beginnext_state=s_reset;unlock=1'b0;ready=1'b1;error=1'b0;endendcaseendendmodule

Testbenchacontinuación

moduletestbench;regclock;//Freerunningclockregreset;//Resetactivehighregx;//Input-Xwireready;//Output-readyforcombinationwireunlock;//Output-unlockedwireerror;//Output-errorincombinationinitialbegin$dumpfile("dump.vcd" );
        $dumpvars;

        clock = 0;          // Set initial values for inputs 
        reset = 0;
        x = 0;              

        #1 reset = 1;
        #9 reset = 0;

        #30                 // Wait to make sure system is idle

        // Test good sequence
        x = 1;
        #10 x = 0;
        #10 x = 1;
        #10 x = 0;
        #10 x = 1;
        #10 x = 1;

        // Test to see if stays unlocked and then returns to ready
        #30 x = 0;

        // Test 1011 which should go into error on the fourth digit
        #30 x = 1;
        #10 x = 0;
        #10 x = 1;
        #10 x = 1;

        // Stay in error until x -> 0
        #30 x = 0;

        // Wait in ready and test error on a zero
        #30 x = 1;
        #10 x = 0;
        #10 x = 1;
        #10 x = 0;  

        #30 $finish;
    end

    always
        #5 clock = ~clock;

    lock u1
    (
        .clock( clock ),
        .reset( reset ),
        .x( x ),
        .ready( ready ),
      .unlock( unlock ),
        .error( error )
    );
endmodule

EDITAR: el segundo bloque siempre cambiado a always@* ahora desbloqueado y listo parece funcionar, pero el error será igual a uno incluso si la secuencia es correcta. Salida de forma de onda que se muestra a continuación:

    
pregunta tlb

2 respuestas

1

Está viendo un comportamiento defectuoso en las señales como error porque son lógica combinacional pura y la entrada y la máquina de estado están fuera de fase. Deberías cambiar tus salidas.

Puedes hacer algo como esto (como ejemplo):

reg  next_ready;
reg  next_unlock;
reg  next_error;
always @ (posedge clock, posedge reset) begin
   if(reset) begin
    state  <= S_RESET;
    ready  <= 1'b0;
    unlock <= 1'b0;
    error  <= 1'b0;
  end
  else begin
    state  <= next_state;
    ready  <= next_ready;
    unlock <= next_unlock;
    error  <= next_error;
  end
end

always @* begin
  // default assignment
  next_ready  = 1'b0;
  next_unlock = 1'b0;
  next_error  = error; // <-- keeps previous values unless needed to be changed
  //
  case(state)
    S_RESET : begin
      if(x==1'b1) begin 
        next_state = S1; 
      end
      else begin
        next_state = S_RESET;
        next_ready = 1'b1;
      end
    end

    S1 : begin
      if(x==1'b0) begin 
        next_state = s2;
      end
      else begin
        next_state = S_ERROR;
        next_error = 1'b1; 
      end
    end

    ....

  endcase
end

Aumenté los parámetros en mi ejemplo para que coincidan con la mayoría de las líneas de gremio de codificación. Esto ayuda a evitar que se confundan con las redes / variables.

    
respondido por el Greg
0

Quizás me esté perdiendo algo, pero parece que una máquina de estados es demasiado complicada para esta tarea. Utilice un registro de desplazamiento con salida en paralelo (verilog prestowed ):

module shift (C, SI, PO); 
input  C,SI; 
output [7:0] PO; 
reg [7:0] tmp; 

  always @(posedge C) 
  begin 
    tmp = {tmp[6:0], SI}; 
  end 
  assign PO = tmp; 
endmodule 

Tome el paralelo y compárelo con su combinación. Si realmente desea agregar algo de memoria de estado, puede agregar una entrada de restablecimiento y alguna lógica externa a esto, pero un registro de desplazamiento parece ser el punto de inicio claro para resolver este problema. Más sencillo de depurar también.

    
respondido por el slightlynybbled

Lea otras preguntas en las etiquetas