¿Cómo verilog evalúa las asignaciones en conflicto?

0

¿Es legal el código como el siguiente o daría un comportamiento indefinido en caso de que se establezca el reinicio? ¿El compilador convertiría la asignación inicial en un condicional o aumentaría primero el contador y luego se restablecería a 0? Si esto se ejecuta secuencialmente, ¿cómo se representan estas relaciones secuenciales en hardware?

always @ (posedge clk) begin
  counter <= counter + 1;

  if (reset)
    counter <= 0;
end
    
pregunta rumpel

2 respuestas

2

Este código es legal. Dentro de un bloque always , el orden de las declaraciones importa; por lo tanto, en su caso, la asignación de counter <= 0 en el caso de que se establezca la señal reset anulará la asignación de counter <= counter + 1 .

  

¿El compilador convertiría la asignación inicial en un condicional o aumentaría primero el contador, luego se restablecería a 0?

Lo más probable es que se realice como una lógica con el registro counter de actualización de la señal de selección de fuente.

  

Si esto se ejecuta de forma secuencial, ¿cómo se representan estas relaciones secuenciales en el hardware?

No no ejecutado . Verilog no es un lenguaje de programación, está describiendo hardware - circuitos electrónicos. Por lo tanto, este código que escribió se convertirá en elementos lógicos y registros, no en códigos de operación para ejecutar.

El orden de las declaraciones en el bloque always es tratado por Verilog compiler de forma secuencial. Dos ejemplos

always @ (posedge clk) begin
  counter <= counter + 1;
  if (reset)
    counter <= 0;
end

con counter <= 0 anulando counter <= counter + 1 si reset es 1;

always @ (posedge clk) begin
  if (reset)
    counter <= 0;
  counter <= counter + 1;
end

con el contador que siempre termina con counter <= counter + 1 porque esta declaración aparece después de la declaración condicional anterior. Creo que el compilador debe lanzar una advertencia para este código porque debe ver que la declaración anterior nunca está vigente.

Más aún, este orden de declaración en always es una función, y puede usarlo para su beneficio teniendo alguna acción predeterminada en el registro (como en el caso de aumentar el valor de registro), y anular acciones en circunstancias específicas (como en su caso, restablecer este registro).

    
respondido por el Anonymous
2

Como dijo Anonymous: la última tarea gana. Lo uso mucho para hacer que las máquinas de estado sean más legibles. En lugar de hacer una asignación en cada estado, hago una en la parte superior y solo la sobrescribo donde la necesite. Pero siempre agrego un comentario con 'Predeterminados' en él para alertar al usuario de que esas asignaciones serán anuladas más abajo. Aquí hay un extracto de un UART, el FSM de transmisión.

//
// Transmit FSM
//

// Defaults for TX FSM
nxt_tx_state    = tx_state;
nxt_tx_bit_cnt  = tx_bit_cnt;
nxt_tx_samp_cnt = tx_samp_cnt;
nxt_shift_out   = shift_out;

case (tx_state)
TX_IDLE :
   begin
     // wait for write to TX register
     // catch the write data and go wait for a tick
     ser_out = 1'b1;
     if (cpu_write & data_select)
     begin
        nxt_shift_out  = cpu_wdata[7:0];
        // if (samp_tick).. could go straight to TX_SS
        // but this is a short wait and saves logic
        nxt_tx_state   = TX_TICK;
     end
   end
TX_TICK :
   begin
      // wait for sample tick
      nxt_tx_samp_cnt = 3'h0;
      nxt_tx_bit_cnt  = 3'h0;
      ser_out =  1'b1;
      if (samp_tick)
         nxt_tx_state = TX_SS;
   end
TX_SS :
   // combined start/stop state
   // Saves one FF in state
   // Re-using 3 bit comperator from TX_DATA
   begin
      ser_out = (tx_bit_cnt==3'h7) ? 1'b1 : 1'b0;
      if (samp_tick)
      begin
         nxt_tx_samp_cnt = tx_samp_cnt + 3'h1;
         if (tx_samp_cnt==3'h7)
         begin
            if (tx_bit_cnt==3'h7)
               nxt_tx_state = TX_IDLE;
            else
               nxt_tx_state = TX_DATA;
         end
      end
   end
TX_DATA :
   begin
      ser_out = shift_out[0];
      if (samp_tick)
      begin
         nxt_tx_samp_cnt = tx_samp_cnt + 3'h1;
         if (tx_samp_cnt==3'h7)
         begin
            nxt_shift_out= {1'b1,shift_out[7:1]}; // LS first
            if (tx_bit_cnt==3'h7)
               nxt_tx_state = TX_SS;
            else
               nxt_tx_bit_cnt = tx_bit_cnt + 3'h1;
         end
      end
   end
endcase // Transmit FSM
    
respondido por el Oldfart

Lea otras preguntas en las etiquetas