본문 바로가기

Programming/SystemVerilog

항상 헷갈리는 시스템베릴로그 $cast - Up-Casting과 Down-Casting

SystemVerilog $cast는 봐도 봐도 헷갈림 ㅠ

Down - Casting

down casting : child class handle은 parent class 핸들로 copy 될 수 있다.

 

왜 down casting이냐면, child-class는 parent class에는없는 child class 고유의 속성들도 갖고 있기 때문이다. ( 이하 P 와 C )

P class 핸들로 C class handle을 복사하면, C class에만 있던 클래스 멤버들은 P class 핸들로는 접근할 수 없게 된다.

P class 핸들은 P class member 들만 접근 가능하다. 따라서 down-casting이라고 한다. ==> 축소 개념

여기서 알아둬야 할 것은, P class가 여전히 C class instance를 포함하고 있다는 사실이다. accessibility만 축소된 것이다.

다시말해 C class instance를 base class에 assign 하면, C class properties는 보이지 않는다.

parent class의 member와 method만 visible.

 

 

 

class base_frame;
	...
	function void hello();
		$display("hello, base_frame hello is called");
	endfunction
	...
endclass

class shortframe extends base_frame;
	logic sig1;
	
	function void hello();
		$display("hello, shortframe hello is called");
	endfunction
endclass

이렇게 base frame과 extended class인 shortframe을 정의했을 때 !!

testbench에서 parent class handle에 child class instance를 assign 해보자.

 

base_frame bf1;
// class declaration으로 핸들을 생성. 
// base_frame은 constructor인 new()를 호출하지 않았기 때문에 아직 객체가 생성되지는 않다. 

shortframe sf1 = new();
// child class 핸들도 생성하고, new를 통해 instantiation도 함.

initial begin
	bf1 = sf1;
	bf1.hello(); 
    // bf1은 child class인 shortframe object sf1을 갖고 있음에도, 
    // 핸들이 base_frame의 것인 bf1이므로, base_frame의 hello가 호출됨.
	bf1.sig1 = 1'b1; // Error!
    // sig1은 child class인 shortframe의 member. parent handle에게는 보이지 않는다. 
	...
end

 

 

 

Up-Casting

 

반대로 parent-class handle은 subclass(child class)handle로 복사될 수 없다.

parent class handle이지만, 그 핸들이 실제로는 child class instance를 가리키고 있다면 가능하지만, 그렇지 않다면 불가능하다.

Child class instance를 갖는 parent class handle을 child class handle로 복사하려고 할 때, 이를 Up - Casting이라고 한다.

Up -Casting의 경우 system task인 $cast 필요

만약에, parent class handle이 실제로 child class instance를 담고 있지 않을때, child class handle로 복사가 불가능하므로 Up-cast는 fail!

$cast가 0을 return 할거야 아마.

 

 

class base_frame;
	...
	function void hello();
		$display("hello, base_frame!");
	endfunction
	...
endclass

class shortframe extends base_frame;
	logic sig1;
	
	function void hello();
		$display("hello, shortframe!");
	endfunction
endclass
base_frame bf1;
shortframe sf1 = new()
shortframe sf2;

initial begin
	bf1 = sf1;
	bf1.hello();   // "hello, base_frame!"
	$cast(sf2, bf1);	
	sf2.hello(); // "hello, shortframe!"
	...
end

 

 

$cast

$cast는 subprogram이다.

function과 task 두 형태로 모두 쓰일 수 있다. (어쩌라구.. 어쩔때 function이고 어쩔때 task란거야.. 몬소리야)

 

  • $cast의 syntax

$cast(destination, source)

만약에 source( parent class handle )가 destination(child class handle)에 맞는 인스턴스(child class instance)를 갖고 있지 않다면,

$cast function는 0 을 return한다.

$cast가 task라면 run-time error를 발생시킴

 

 

package p1;
	class baseframe;
		...
	endclass
	
	class shortframe extends baseframe;
		...
	endclass
endpackage
import p1::*; // 위에서 작성했던 package를 import

module my_module (output var baseframe bf1); 
	shortframe sf = new();
	
	initial begin
		bf1 = sf ; // copy child class to parent class handle ==> down-casting
		
		...
	end
endmodule

그런데 var keyword는 뭐지? 열심히 구글링 해보니...
SystemVerilog also created a var keyword to explicitly declare a variable, mainly to deal with a problem in port declarations. The default signal kind for a port is a wire, so if you have the var keyword is used to change that default.

system verilog에서는 port declaration에서 해당 port가 net이 아닌 variable을 명시적으로 선언하기 위해서 var keyword를 만들었다. 원래 port에서 var keyword를 사용하지 않으면 default signal은 wire임.

import p1::*;
module my_second_module(input var baseframe bf2);
	shortframe sf2 = new();

	always @(bf2) begin
		assert($cast(sf2, bf2)); 
        // 부모클래스 핸들인 bf2 포트로부터 child class 핸들 sf2로 up-cast
        // up-cast to child class handle from parent class handle port bf2
		...
endmodule

argument가 net type이 아닌 variable type임을 명시적으로 나타내기 위해서 var이라는 키워드를 사용한다.

위 코드에서 실제 instance를 생성한 것은 child class인 shortframe 이고,

인스턴스를 넘겨주는 포트는 parent인 baseframe 이다.

bf2 라는 baseframe port로 부터 subclass 인 shorframe instance를 받는다.

만약 bf2로 child class 인스턴스가 아닌 부모 인스턴스가 들어온다면.... $cast fail~!