Shallow Copy vs. Deep Copy
Shallow Copy (Copia Superficial): Una copia superficial crea un nuevo objeto, pero comparte los sub-objetos. Si se modifica un sub-objeto en la copia, el original también cambia.
class Header;
rand int len; // Longitud de la cabecera
function new();
this.len = $urandom_range(10, 20);
endfunction
endclass
class Packet;
Header hdr; // Handle a otro objeto
int id;
function new();
this.id = $urandom_range(1, 5);
this.hdr = new(); // Creamos el objeto cabecera
endfunction
endclass
module test_shallow;
initial begin
Packet p1 = new();
$display("[Inicial] p1.id=%0d, p1.hdr.len=%0d", p1.id, p1.hdr.len);
// Creamos una copia superficial de p1
Packet p2 = new p1;
$display("[Copia] p2.id=%0d, p2.hdr.len=%0d", p2.id, p2.hdr.len);
// Modificamos la cabecera e ID a través de p2
p2.hdr.len = 99;
p2.id=25;
$display("[Resultado] p2.id=%0d, p2.hdr.len=%0d", p2.id, p2.hdr.len);
// Verificamos p1... ¡Ha cambiado también la cabecera, no así el ID!
$display("[Resultado] p1.id=%0d, p1.hdr.len=%0d", p1.id, p1.hdr.len);
end
endmodule

Deep Copy (Copia Profunda): Una copia profunda crea un nuevo objeto y nuevas instancias de todos sus sub-objetos. Requiere un método de copia personalizado.
class Header; rand int len; // Longitud de la cabecera function new(); this.len = $urandom_range(10, 20); endfunction function void copy(Header other); this.len = other.len; endfunction endclass class Packet; Header hdr; // Handle a otro objeto int id; function new(); this.id = $urandom_range(1, 5); this.hdr = new(); // Creamos el objeto cabecera endfunction // Constructor de copia profunda function void copy(Packet other); this.id = other.id; this.hdr.copy(other.hdr); // Se copia el objeto endfunction endclass

Clonado: Es una buena práctica implementar un método clone() que devuelva una copia del objeto.
class Packet;
Header hdr; // Handle a otro objeto
int id;
function new();
this.id = $urandom_range(1, 5);
this.hdr = new(); // Creamos el objeto cabecera
endfunction
function void copy(Packet other);
this.id = other.id;
this.hdr.copy(other.hdr); // Se copia el objeto
endfunction
function Packet clone();
clone=new();
clone.copy(this); // Se copia el objeto
endfunction
endclass
module test_clone;
initial begin
Packet p1 = new();
Packet p2;
$display("[Inicial] p1.id=%0d, p1.hdr.len=%0d", p1.id, p1.hdr.len);
// Creamos una copia profunda usando clone
p2 = p1.clone();
$display("[Copia] p2.id=%0d, p2.hdr.len=%0d", p2.id, p2.hdr.len);
// Modificamos la cabecera a través de p2
p2.hdr.len = 99;
$display("n[Modificado] p2.hdr.len ahora es 99");
// Verificamos p1... ¡Permanece intacto!
$display("[Resultado] p1.id=%0d, p1.hdr.len=%0d", p1.id, p1.hdr.len);
end
endmodule

Uso de packages
- ¿Qué es un package?
- Un package es un contenedor o espacio de nombres que agrupa definiciones comunes para que puedan ser compartidas fácilmente a través de múltiples archivos en un entorno de diseño o verificación.
- ¿Qué puede contener?
- parameter y localparam: Constantes globales.
- typedef: Definiciones de tipos de datos personalizados (structs, enums, etc.).
- function y task: Rutinas de utilidad reutilizables.
- class: Definiciones de clases para la verificación orientada a objetos (muy usado en UVM).
- import: Puede importar definiciones de otros paquetes.
Vamos a ver el siguiente ejemplo utilizando packages. Antes de ello supongamos que
- Vamos escribiendo las diferentes clases en ficheros systemverilog independientes
- Habrá relaciones «is a» y «has a» en muchos de ellos. Esto condiciona clarísimamente el orden en que dichos ficheros deben de ser compilados; pero vamos a realizar una salvaguarda que es la utilización de la definición con typedef de las diferentes clases que vamos utilizando. Eso nos va a permitir incluir esos ficheros systemverilog en cualquier orden.
package definitions_pkg;
typedef class Packet;
typedef class Header;
`include “Packet.sv”
`include “Header.sv"
endpackage: definitions_pkg
function Packet clone();
clone=new();
clone.copy(this); // Se copia el objeto
endfunction
endclass
module test_clone;
initial begin
definitions_pkg::Packet p1 = new();
definitions_pkg::Packet p2;
$display("[Inicial] p1.id=%0d, p1.hdr.len=%0d", p1.id, p1.hdr.len);
// Creamos una copia profunda usando clone
p2 = p1.clone();
$display("[Copia] p2.id=%0d, p2.hdr.len=%0d", p2.id, p2.hdr.len);
// Modificamos la cabecera a través de p2
p2.hdr.len = 99;
$display("n[Modificado] p2.hdr.len ahora es 99");
// Verificamos p1... ¡Permanece intacto!
$display("[Resultado] p1.id=%0d, p1.hdr.len=%0d", p1.id, p1.hdr.len);
end
endmodule

Convenciones del Curso
- Deberiamos escribir las clases en ficheros systemverilog independientes.
- Incluir como hemos visto dichos ficheros en un package que los agrupe.
- Los handles a clases deben denominarse con el sufijo _h.
- Al pasar un handle como argumento en funciones de clase, usar el nombre genérico rhs_h.
- Usar el prefijo p_ o i_ para los argumentos de funciones.
- Usar el prefijo m_ para los miembros de una clase.
- Usar el sufijo _t para los
typedef. - Usar el sufijo e_ para los enumerados.