En SystemVerilog, la transmisión de parámetros a funciones y procedimientos se basa en dos reglas fundamentales: transmisión por valor y transmisión por referencia. A continuación, se analizan los tipos de parámetros ref, input, output e inout, con ejemplos para tipos básicos y clases.
1. Parámetros de tipo input
Para tipos de datos básicos como int, el parámetro input actúa como transmisión por valor. La función trabaja con una copia del valor original, por lo que cualquier modificación interna no afecta a la variable externa.
module modulo_ejemplo;
int contador_global = 1;
function void prueba_input(input int valor);
$display("Dentro de prueba_input:");
valor += 1;
$display("valor = %0d", valor);
endfunction
function void mostrar_global();
$display("Valor global: %0d", contador_global);
endfunction
initial begin
mostrar_global();
prueba_input(contador_global);
mostrar_global();
end
endmodule
Salida esperada:
Valor global: 1
Dentro de prueba_input:
valor = 2
Valor global: 1
Para clases, el parámetro input pasa el identificador del objeto. La función modifica el objeto a través del mismo identificador, afectando los datos en el espacio compartido.
module modulo_clase;
class datos;
int valor_interno;
function void imprimir();
$display("Valor interno en datos: %0d", valor_interno);
endfunction
endclass
function void usar_input(input datos ref_obj);
$display("Modificando objeto:");
ref_obj.valor_interno = 5;
$display("valor_interno = %0d", ref_obj.valor_interno);
endfunction
initial begin
datos obj = new();
obj.valor_interno = 0;
obj.imprimir();
usar_input(obj);
obj.imprimir();
end
endmodule
Salida:
Valor interno en datos: 0
Modificando objeto:
valor_interno = 5
Valor interno en datos: 5
2. Parámetros de tipo output
Para tipos básicos, output transmite la dirección de una nueva variable interna al exterior. Al finalizar la función, la variable externa apunta a la dirección de la variable interna, actualizando su valor.
module modulo_output;
int dato_externo = 1;
function void prueba_output(output int param);
$display("Asignando nuevo valor:");
param = 10;
$display("param = %0d", param);
endfunction
function void mostrar_externo();
$display("dato_externo = %0d", dato_externo);
endfunction
initial begin
mostrar_externo();
prueba_output(dato_externo);
mostrar_externo();
end
endmodule
Salida:
dato_externo = 1
Asignando nuevo valor:
param = 10
dato_externo = 10
Para clases, output pasa el identtificador del objeto al inicio de la función, similar a input. Las modificaciones afectan directamente al objeto.
module modulo_output_clase;
class configuracion;
int ajuste;
function void mostrar();
$display("Ajuste: %0d", ajuste);
endfunction
endclass
function void configurar_objeto(output configuracion cfg);
cfg.ajuste = 100;
$display("Ajuste configurado: %0d", cfg.ajuste);
endfunction
initial begin
configuracion mi_cfg = new();
mi_cfg.ajuste = 50;
mi_cfg.mostrar();
configurar_objeto(mi_cfg);
mi_cfg.mostrar();
end
endmodule
Salida:
Ajuste: 50
Ajuste configurado: 100
Ajuste: 100
3. Parámetros de tipo ref
Para tipos básicos, ref trasnmite la dirección de la variable original. La función trabaja directamente con la misma dirección, modificando el valor externo.
module modulo_ref;
int variable_compartida = 1;
function void modificar_ref(ref int puntero);
$display("Modificando vía ref:");
puntero += 5;
$display("puntero = %0d", puntero);
endfunction
function void ver_variable();
$display("variable_compartida = %0d", variable_compartida);
endfunction
initial begin
ver_variable();
modificar_ref(variable_compartida);
ver_variable();
end
endmodule
Salida:
variable_compartida = 1
Modificando vía ref:
puntero = 6
variable_compartida = 6
Para clases, ref pasa el identificador del objeto, permitiendo modificaciones directsa en el objeto compartido.
module modulo_ref_clase;
class registro;
int dato;
function void leer();
$display("Dato en registro: %0d", dato);
endfunction
endclass
function void actualizar_ref(ref registro reg);
reg.dato = 999;
$display("Dato actualizado: %0d", reg.dato);
endfunction
initial begin
registro mi_reg = new();
mi_reg.dato = 100;
mi_reg.leer();
actualizar_ref(mi_reg);
mi_reg.leer();
end
endmodule
Salida:
Dato en registro: 100
Dato actualizado: 999
Dato en registro: 999
4. Parámetros de tipo inout
Para tipos básicos, inout realiza dos transmisiones por valor: al inicio de la función copia el valor externo a una variable interna, y al finalizar copia el valor interno de vuelta al externo.
module modulo_inout;
int acumulador = 1;
function void ajustar_inout(inout int numero);
$display("Ajustando:");
numero += 3;
$display("numero = %0d", numero);
endfunction
function void ver_acumulador();
$display("acumulador = %0d", acumulador);
endfunction
initial begin
ver_acumulador();
ajustar_inout(acumulador);
ver_acumulador();
end
endmodule
Salida:
acumulador = 1
Ajustando:
numero = 4
acumulador = 4
Para clases, inout pasa el identificador del objeto al inicio, similar a los otros mecanismos.
module modulo_inout_clase;
class contador;
int cuenta;
function void incrementar();
cuenta++;
$display("Cuenta: %0d", cuenta);
endfunction
endclass
function void modificar_inout(inout contador cnt);
cnt.cuenta = 10;
$display("Cuenta modificada: %0d", cnt.cuenta);
endfunction
initial begin
contador mio = new();
mio.cuenta = 0;
mio.incrementar();
modificar_inout(mio);
mio.incrementar();
end
endmodule
Salida:
Cuenta: 1
Cuenta modificada: 10
Cuenta: 11
En resumen, para tipos de datos básicos, input es transmisión por valor, output y ref son transmisión por referencia, e inout es transmisión por valor doble. Para clases, todos los tipos transmiten el identificador del objeto al inicio de la función, lo que permite modificaciones directas en el objeto compartido.