계속해서 SystemVerilog의 고급 기능들을 살펴보겠습니다.
19. 고급 인터페이스 활용 (Advanced Interface Usage)
인터페이스를 더 효과적으로 활용하는 방법을 알아보겠습니다.
// 모듈러 인터페이스 정의
interface axi_if #(
parameter DATA_WIDTH = 32,
parameter ADDR_WIDTH = 32
)(
input logic clk,
input logic rst_n
);
// 인터페이스 신호
logic [ADDR_WIDTH-1:0] addr;
logic [DATA_WIDTH-1:0] wdata;
logic [DATA_WIDTH-1:0] rdata;
logic write;
logic read;
logic valid;
logic ready;
// 모듈러 포트 정의
modport master (
output addr, wdata, write, read,
input rdata, valid, ready
);
modport slave (
input addr, wdata, write, read,
output rdata, valid, ready
);
// 클럭킹 블록 정의
clocking cb @(posedge clk);
default input #1step output #1ns;
output addr, wdata, write, read;
input rdata, valid, ready;
endclocking
// 테스트 모듈포트 (클럭킹 블록 포함)
modport tb (
clocking cb
);
// 인터페이스에 태스크 정의
task automatic write_data(input logic [ADDR_WIDTH-1:0] a, input logic [DATA_WIDTH-1:0] d);
@(posedge clk);
addr <= a;
wdata <= d;
write <= 1'b1;
read <= 1'b0;
wait(ready);
@(posedge clk);
write <= 1'b0;
endtask
task automatic read_data(input logic [ADDR_WIDTH-1:0] a, output logic [DATA_WIDTH-1:0] d);
@(posedge clk);
addr <= a;
read <= 1'b1;
write <= 1'b0;
wait(valid);
d = rdata;
@(posedge clk);
read <= 1'b0;
endtask
endinterface
// 인터페이스 사용
module axi_master(
axi_if.master axi
);
// 마스터 로직 구현...
endmodule
module axi_slave(
axi_if.slave axi
);
// 슬레이브 로직 구현...
endmodule
module top_level;
logic clk = 0;
logic rst_n;
// 클럭 생성
always #5 clk = ~clk;
// 인터페이스 인스턴스화
axi_if #(.DATA_WIDTH(64), .ADDR_WIDTH(32)) axi_bus(.clk(clk), .rst_n(rst_n));
// 모듈 인스턴스화
axi_master master(.axi(axi_bus));
axi_slave slave(.axi(axi_bus));
initial begin
rst_n = 0;
#20 rst_n = 1;
// 인터페이스 태스크 직접 사용
axi_bus.write_data(32'h1000_0000, 64'hABCD_1234_5678_9ABC);
// 데이터 읽기
logic [63:0] read_val;
axi_bus.read_data(32'h1000_0000, read_val);
$display("Read data: %h", read_val);
end
endmodule
20. 디자인 파티션과 바인딩 (Design Partition and Binding)
계층적 설계와 코드 재사용을 위한 바인딩 기능입니다.
// 바인드 가능한 검증 모듈 정의
module check_protocol(
input logic clk,
input logic reset,
input logic req,
input logic ack
);
// 프로토콜 체킹 로직...
property req_ack_p;
@(posedge clk) disable iff (reset)
req |-> ##[1:3] ack;
endproperty
assert property (req_ack_p)
else $error("Protocol violation");
endmodule
// 설계 모듈
module my_design(
input logic clk,
input logic reset,
input logic start,
output logic done
);
logic internal_req, internal_ack;
// 설계 로직...
endmodule
// 검증 모듈 바인딩
bind my_design check_protocol checker_inst(
.clk(clk),
.reset(reset),
.req(internal_req),
.ack(internal_ack)
);
// 또는 특정 계층 경로에 바인딩
bind top.sub.my_design check_protocol checker_inst(...);
21. 시뮬레이션 제어 (Simulation Control)
시뮬레이션 환경을 제어하는 기능입니다.
module sim_control;
initial begin
// 시간 단위 및 정밀도 표시
$timeformat(-9, 3, " ns", 10);
// 값 출력
$display("Starting simulation at %t", $time);
// 시뮬레이션 제어
#100 $display("Time: %t", $time);
// 파일 열기
int file_handle;
file_handle = $fopen("output.log", "w");
// 파일에 쓰기
$fdisplay(file_handle, "Simulation log file");
$fwrite(file_handle, "Time: %t, Value: %d\n", $time, 42);
// 파일 닫기
$fclose(file_handle);
// 파일 읽기
file_handle = $fopen("input.txt", "r");
if (file_handle) begin
string line;
while ($fgets(line, file_handle))
$display("Read: %s", line);
$fclose(file_handle);
end
// 시뮬레이션 제어
#1000;
if (error_count > 0)
$error("Simulation failed with %0d errors", error_count);
else
$display("Simulation passed");
// 시뮬레이션 종료
$finish;
end
int error_count = 0;
// 파형 덤프 제어
initial begin
$dumpfile("wave.vcd");
$dumpvars; // 모든 변수 덤프
end
endmodule
22. UVM 기초 개념 (Universal Verification Methodology Basics)
UVM은 표준화된 검증 방법론입니다.
// UVM 패키지 가져오기
import uvm_pkg::*;
`include "uvm_macros.svh"
// UVM 트랜잭션 클래스
class my_transaction extends uvm_sequence_item;
// 트랜잭션 데이터 필드
rand bit [7:0] addr;
rand bit [31:0] data;
rand bit rw; // 0: 읽기, 1: 쓰기
// UVM 매크로
`uvm_object_utils_begin(my_transaction)
`uvm_field_int(addr, UVM_ALL_ON)
`uvm_field_int(data, UVM_ALL_ON)
`uvm_field_int(rw, UVM_ALL_ON)
`uvm_object_utils_end
// 생성자
function new(string name = "my_transaction");
super.new(name);
endfunction
// 제약 조건
constraint addr_c {
addr inside {[0:255]};
}
endclass
// UVM 시퀀스
class my_sequence extends uvm_sequence #(my_transaction);
`uvm_object_utils(my_sequence)
function new(string name = "my_sequence");
super.new(name);
endfunction
task body();
my_transaction tx;
repeat(10) begin
tx = my_transaction::type_id::create("tx");
start_item(tx);
if (!tx.randomize())
`uvm_error("SEQ", "Randomization failed")
finish_item(tx);
end
endtask
endclass
// UVM 시퀀서
class my_sequencer extends uvm_sequencer #(my_transaction);
`uvm_component_utils(my_sequencer)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
endclass
// UVM 드라이버
class my_driver extends uvm_driver #(my_transaction);
`uvm_component_utils(my_driver)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
my_transaction tx;
forever begin
seq_item_port.get_next_item(tx);
// 트랜잭션 처리 로직
`uvm_info("DRV", $sformatf("Got transaction: addr=%0h, data=%0h, rw=%0b",
tx.addr, tx.data, tx.rw), UVM_MEDIUM)
// DUT 인터페이스에 트랜잭션 적용
#10; // 시뮬레이션 시간 지연
seq_item_port.item_done();
end
endtask
endclass
// UVM 에이전트
class my_agent extends uvm_agent;
`uvm_component_utils(my_agent)
my_sequencer sqr;
my_driver drv;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
sqr = my_sequencer::type_id::create("sqr", this);
drv = my_driver::type_id::create("drv", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
drv.seq_item_port.connect(sqr.seq_item_export);
endfunction
endclass
// UVM 환경
class my_env extends uvm_env;
`uvm_component_utils(my_env)
my_agent agt;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
agt = my_agent::type_id::create("agt", this);
endfunction
endclass
// UVM 테스트
class my_test extends uvm_test;
`uvm_component_utils(my_test)
my_env env;
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
function void build_phase(uvm_phase phase);
super.build_phase(phase);
env = my_env::type_id::create("env", this);
endfunction
task run_phase(uvm_phase phase);
my_sequence seq;
phase.raise_objection(this);
seq = my_sequence::type_id::create("seq");
seq.start(env.agt.sqr);
#100;
phase.drop_objection(this);
endtask
endclass
// 최상위 모듈
module top;
initial begin
run_test("my_test");
end
endmodule
이것으로 SystemVerilog 기본 문법 가이드의 4부를 마치겠습니다. 이 가이드를 통해 SystemVerilog의 기본 구문부터 고급 기능까지 폭넓게 다루었습니다. 실제 설계와 검증 작업에서는 이러한 기능들을 상황에 맞게 조합하여 사용하게 됩니다.
SystemVerilog는 하드웨어 설계와 검증을 위한 강력한 도구이며, 이러한 기본 개념을 이해하는 것이 복잡한 디지털 시스템을 효과적으로 개발하는 데 큰 도움이 될 것입니다.
답글 남기기