In a previous post, we discussed key topics on class handles and objects. Understanding these concepts is essential to grasp how shallow and deep copy operations work in SystemVerilog.
Key Concepts Covered:
- Class Handles and Objects
- Shallow Copy
- Deep Copy
Shallow Copy in SystemVerilog
When copying one object to another, SystemVerilog offers two types of copying mechanisms: shallow copy and deep copy. Let’s first discuss shallow copy, a simpler form of copying.
Shallow Copy Example
In shallow copying, the content of one object is transferred to another. However, the nested objects (i.e., objects inside other objects) are not completely copied. Instead, only their handles are assigned to the new object. This means that both the original and the new object share the same instance of the nested object.
Here’s an example to demonstrate shallow copying in SystemVerilog:
class Header;
int id;
function new (int id);
this.id = id;
endfunction
function showId();
$display("id=0x%0d", id);
endfunction
endclass
class Packet;
int addr;
int data;
Header hdr; // Nested class object
function new (int addr, int data, int id);
hdr = new(id);
this.addr = addr;
this.data = data;
endfunction
function display (string name);
$display("[%s] addr=0x%0h data=0x%0h id=%0d", name, addr, data, hdr.id);
endfunction
endclass
module tb;
Packet p1, p2;
initial begin
// Create a new packet object called p1
p1 = new(32'hface_cafe, 32'h1234_5678, 26);
p1.display("p1");
// Shallow copy p1 into p2
p2 = new p1;
p2.display("p2");
// Modify p1's data
p1.addr = 32'habcd_ef12;
p1.data = 32'h5a5a_5a5a;
p1.hdr.id = 17;
p1.display("p1");
// Print p2 and notice the shared hdr.id
p2.display("p2");
end
endmodule
What Happens in Shallow Copy?
In this example:
- A
Packet
objectp1
is created with specific values. - We use shallow copy (
p2 = new p1
) to createp2
with the same values asp1
. - After modifying
p1
, notice that thehdr.id
value is not changed inp2
even thoughp1
‘shdr.id
was updated.
Simulation Output:
[p1] addr=0xfacecafe data=0x12345678 id=26
[p2] addr=0xfacecafe data=0x12345678 id=26
[p1] addr=0xabcdef12 data=0x5a5a5a5a id=17
[p2] addr=0xfacecafe data=0x12345678 id=17
As seen in the output, p2
shares the same handle for the nested object hdr
as p1
. Changing hdr.id
in p1
also affects p2
.
Deep Copy in SystemVerilog
Unlike shallow copy, deep copy copies everything, including nested objects. A deep copy requires custom code because SystemVerilog doesn’t support deep copying by default.
Deep Copy Example
In a deep copy, all objects, including nested ones, are copied fully, not just their handles. Here’s how to implement a deep copy in SystemVerilog:
class Packet;
...
function copy(Packet p);
this.addr = p.addr;
this.data = p.data;
this.hdr.id = p.hdr.id; // Full copy of nested object
endfunction
...
endclass
module tb;
Packet p1, p2;
initial begin
p1 = new(32'hface_cafe, 32'h1234_5678, 32'h1a);
p1.display("p1");
p2 = new(1, 2, 3);
p2.copy(p1);
p2.display("p2");
// Modify p1's data
p1.addr = 32'habcd_ef12;
p1.data = 32'h5a5a_5a5a;
p1.hdr.id = 32'h11;
p1.display("p1");
// Now print p2 and notice the change in p2's hdr.id
p2.display("p2");
end
endmodule
What Happens in Deep Copy?
In the above example, we defined a custom copy()
function that performs a full copy of p1
into p2
. This ensures that the nested object hdr
inside Packet
is also copied completely, not just the handle.
Simulation Output:
[p1] addr=0xfacecafe data=0x12345678 id=26
[p2] addr=0xfacecafe data=0x12345678 id=26
[p1] addr=0xabcdef12 data=0x5a5a5a5a id=17
[p2] addr=0xfacecafe data=0x12345678 id=26
In this case, even though p1
‘s hdr.id
changes, p2
retains its original id
since the copy function created a deep copy of all its data, including the nested Header
object.
Key Differences Between Shallow and Deep Copy
Here’s a quick comparison of shallow copy and deep copy:
Feature | Shallow Copy | Deep Copy |
---|---|---|
Handles copied? | Yes, only handles of nested objects. | Yes, actual objects are fully copied. |
Nested objects copied? | No, only handles to nested objects. | Yes, nested objects are fully copied. |
Performance | Faster due to fewer data copied. | Slower due to full object copying. |
Use case | When object independence is not required. | When object independence is required. |
Conclusion: When to Use Shallow or Deep Copy
- Use shallow copy when you want faster performance and don’t need full independence between objects.
- Use deep copy when you require full independence between objects, ensuring that all nested objects are copied fully.