Me encuentro con una situación bastante confusa donde estaba escribiendo un código para un monitor UVM. Este módulo realiza estas operaciones en orden:
- Escuche el canal (interfaz virtual) hasta que intercepte uno o varios eventos en el nivel de pin.
- Rellene una estructura de datos con cualquier valor que pueda leerse en los puertos de entrada de la interfaz.
- Genere un hilo secundario para esperar la respuesta y vuelva al paso 1.
Spawning está usando la construcción SystemVerilog Fork .. JOIN_NONE y estaba destinado a iniciar una tarea que solo espera la respuesta en la interfaz y luego continuar con la tarea principal - SIN tener que esperar a que la tarea generada finalice. Dentro de FORK JOIN, hay una tarea de SystemVerilog con argumentos de entrada que se pasan por valor. Cuando se inicia el programa, índice = 0. Cuando se ejecuta get_output (data_struct, index) dentro de FORK..JOIN, el índice sigue siendo 0. ¡Sin embargo, cambia una vez dentro de la tarea generada! Por favor, mire cuidadosamente donde coloco mis impresiones de depuración del índice variable. La primera imprime el índice = 0 y la segunda imprime el índice = 1. No es posible en mi opinión que esto pueda suceder, porque primero, las variables se pasan por valor a la tarea y el segundo índice se incrementa después de que la tarea se llama asumiendo instrucciones tener lugar en un orden secuencial dentro de la tarea run_phase. Quiero saber por qué el índice cambia dentro de la tarea generada por sí mismo. El ajuste que encontré para mantener el valor pasado es agregar una declaración de espera de 1ns después de que se haya llamado a la tarea generada.
Aquí está el código:
task run_phase(uvm_phase phase);
int unsigned index;
dpu_input_str data_struct;
//monitoring
index = 0;
//wait until NOT reset
@(posedge vif.rst_n);
forever begin
//listen to channel: wait for any change in the IF signals
fork
@(vif.ctrl_0);
@(vif.ctrl_1);
...
join_any
disable fork; //kill outstanding waiting processes
//create intermediate struct
data_struct.ctrl_0 = vif.ctrl_0;
data_struct.ctrl_1 = vif.ctrl_1;
..
//wait for the output
//spawn a task to perform that and get back to channel listening
//again
fork
get_output(data_struct, index);
join_none
$display("Value of index after calling the task is: %d", index);
//#1;
index++;
end
endtask: run_phase
task get_output(input dpu_input_str data_struct,
input int unsigned index);
dpu_simple_transaction dpu_tr;
int unsigned delay_cnt;
int i;
//create analysis transaction
dpu_tr = dpu_simple_transaction::type_id::create
(.name("dpu_tr_dut_mon"),
.contxt(get_full_name));
$display("Value of index inside the task is: %d", index);
// fill in data back into analysis transaction
// pay attention to cast when writing numeric values to enum datatypes
dpu_tr.ctrl_0 = dpu_control_type'(data_struct.ctrl_0);
dpu_tr.ctrl_1 = dpu_control_type'(data_struct.ctrl_1);
...
// decide about the delay
...
endtask