La generación y sincronización precisa de las señales de reloj (clk) y reset (rstn) es fundamental en el diseño de una plataforma de verificación. Este artículo explora prácticas comunes para su implementación, el control de aserciones durante los dominios de reset y la gestión de escenarios específicos.
1. Módulo de Generación de Estímulos Básicos
Un punto de partida es crrear un módulo que proporcione los estímulos iniciales. El siguiente código ejemplifica la creación de un reloj con un período configurable y una secuencia de reset controlada, donde los tiempos de activación se aleatorizan para cubrir diferentes condiciones de inicio.
module signal_generator;
timeunit 1ps;
timeprecision 1ps;
real period_ns = 500.0; // Ejemplo: genera un reloj de 2 GHz
logic sys_clk;
logic async_rstn;
// Generación del reloj
initial begin
int unsigned clk_startup_delay;
sys_clk = 1'b0;
clk_startup_delay = $urandom_range(12, 25);
#clk_startup_delay;
forever #(period_ns / 2.0) sys_clk = ~sys_clk;
end
// Generación del reset
initial begin
int unsigned rst_assert_time, rst_deassert_delay;
async_rstn = 1'bx;
rst_assert_time = $urandom_range(1, 3);
#rst_assert_time;
async_rstn = 1'b1;
#rst_assert_time;
async_rstn = 1'b0; // Reset activado
rst_deassert_delay = $urandom_range(1, 30); // Desalineado con el reloj
#rst_deassert_delay;
async_rstn = 1'b1; // Reset desactivado
end
endmodule
2. Sincronización de Aserciones con el Reset
Las aserciones basadas en reloj a menudo deben inhabilitarse durante el reset. Una práctica estándar es utilizar la señal rstn en una cláusula disable iff.
property register_overflow_check(input logic [7:0] counter, input logic enable, input logic [7:0] limit);
@(posedge sys_clk) disable iff (!async_rstn)
enable |-> (counter <= limit);
endproperty
Sin embargo, en sistemas complejos donde diferentes IP tienen dominios de reset independientes, utilizar el reset global del testbench puede causar falsas fallas. Es necesario introducir una señal de habilitación (enable) específica para las aserciones de ese bloque.
module assertions_with_enable (
input logic sva_clk,
input logic sva_rstn,
input logic specific_ip_rstn,
input logic assertion_enable
);
property reset_sequence_check;
@(posedge sva_clk) disable iff (!specific_ip_rstn || !assertion_enable)
$fell(request) |-> ##[1:100] $fell(grant);
endproperty
assert property(reset_sequence_check)
else $error("La secuencia de reset del IP fallo.");
endmodule
3. Propagación de Estados 'X' en Simulación
Para verificar el comportamiento del diseño frente a condiciones no inicializadas, se puede habliitar la propagación de valores 'X' durante la simulación. Esto se configura típicamente en el comando del simulador.
// Ejemplo de directiva de simulador para habilitar xprop en el DUT
// instance {testbench.dut} {xpropOn};
Con xprop activado, una señal no conducida por un driver de reloj mantendrá el estado 'X', propagándose a través de la lógica combinacional y secuencial, lo que ayuda a detectar diseños no robustos.
4. Consideraciones para Resets Parciales
Los resets parciales, donde solo una porción del diseño se reinicia, presentan desafíos únicos.
- Acceso a Registros: Durante un reset parcial, el acceso a registros en el dominio que se está reiniciando debe ser bloqueado por el firmware o software de control. Intentar leer o escribir puede dar lugar a datos inválidos o comportamientos inesperados en el bus.
- Control de Hilos en Estímulos: Es necesario gestionar los hilos de generación de estímulos que interactúan con una región bajo reset parcial. Un enfoque común es terminar explícitamente los hilos afectados antes de activar el reset.
fork
begin : stimulus_thread
automatic process::job_t job_handle;
job_handle = process::self();
vseq.start(env.bus_vsqr);
end
begin : reset_monitor
repeat(5) begin
int unsigned reset_gap = $urandom_range(500, 1500);
#(reset_gap * 1ns);
trigger_partial_reset();
// Forzar la terminación del hilo de estímulos asociado
stimulus_thread.job_handle.kill();
end
end
join
5. Sentencias de Espera y Sincronziación
Existen múltiples formas de sincronizar el flujo de la verificación con señales de reloj y reset.
Espera directa en señales de interfaz:
// Espera en cualquier flanco del reloj
@(system_bus.clk);
// Espera solo en el flanco ascendente
@(posedge system_bus.clk);
Uso de bloques de sincronización (clocking blocks): Estos proporcionan una capa de abstracción y permiten definir tiempos de setup y hold.
interface bus_interface(input logic clk, input logic rst_n);
parameter setup_time = 2ns;
parameter hold_time = 1ns;
clocking driver_cb @(posedge clk);
default input #setup_time output #hold_time;
output data;
output address;
input acknowledge;
endclocking
endinterface
// Espera al siguiente evento del bloque de sincronización del driver
@(bus_vif.driver_cb);