-
[SystemVerilog] 인터페이스 2개발/SystemVerilog 2022. 1. 16. 21:38
모듈을 파라미터로 인스턴스 할 수 있듯이, 인터페이스도 파라미터로 정의 가능하다.
// paramterized interface with default value interface busA #(DATAWIDTH = 32, ADDRWIDTH = 16) (input clk); logic [DATAWIDTH-1 : 0] data; logic [ADDRWIDTH-1 : 0] addr; ... endinterface interface busB (input clk); // internal parameter parameter WIDTH = 8; logic [WIDTH-1 : 0] data; logic [WIDTH-1 : 0] addr; ... endinterface module top; logic clk = 0; // positional busA #(16, 8) bus1(clk); // DATAWIDTH = 16, ADDRWIDTH = 8 // named busA #(.ADDRWIDHT(32)) bus2(clk); // DATAWIDTH = 32, ADDRWIDTH = 32 ... endmodule
이전글의 예제에서 인터페이스 블럭으로 연결만 해주었다.
모듈끼리 연결을 위해서는 각 모듈에 맞게 신호들의 방향을 정해야한다.
modport 문법으로 각 블럭마다 신호들의 방향을 따로 지정해줄 수 있다.
interface mod_if; logic a, b, c, d; modport master ( input a, b, output c, d ); modport slave ( input c, d, output a, b ); modport subset ( input a, output c ); endinterface
어떤 마스터와 슬레이브가 1:1 연결되었다고 가정하자.
마스터 입장에서 a, b, 는 입력이고 c, d는 출력이다. 그렇다면 슬레이브는 반대로 a, b가 출력이고, c, d는 입력이 되야한다. modport 는 인터페이스 신호들 중 일부만 방향을 지정하는것도 가능하다.
module masterModule(mod_if.master mbus); ... endmodule module slaveModule(mod_if.slave sbus); ... endmodule module top mod_if bus; masterModule master(.mbus(bus)); slaveModule slave(.sbus(bus)); endmodule
모듈의 포트를 정의할때 modport를 포함할 수 있다.
모듈포트에 modport를 포함시킨다면, 굳이 bus.master / bus.slave 으로 쓰지 않아도 알아서 modport를 mapping 해준다.
module masterModule(mod_if mbus); ... endmodule module slaveModule(mod_if sbus); ... endmodule module top mod_if bus; masterModule master(.mbus(bus.master)); slaveModule slave(.sbus(bus.slave)); endmodule
만약 modport를 포함하지 않고 그냥 인터페이스만으로 모듈의 포트를 선언했다면,
인터페이스를 인스턴스하고 각 모듈에 연결할 땐 bus.master / bus.slave 처럼 modport를 참조해야한다.
인터페이스 내부에 task / function 정의할 수 있다. 이를 인터페이스의 메서드라고 한다.
interface simple_bus(input clk); logic req, start, gnt, rdy; logic [1:0] mode; logic [7:0] addr; wire [7:0] data; task read (input [7:0] address, output [7:0] r_data); @(negedge clk) addr = address; ... endtask task write (input [7:0] address, w_data); @(negedge clk) addr = address; data = w_data; ... endtask endinterface module cpuModule(simple_bus bus); ... bus.read(); ... endmodule
만약에 인터페이스의 메서드가 없다면, 버스에 연결된 각각의 master / slave 내부에 트랜잭션을 만드는 태스크를 정의 해야한다. 이는 코드가 복잡해지고 유지보수가 어려워진다.
반면 인터페이스에서 읽기, 쓰기 등의 메서드를 정의하면, 해당 인터페이스에 연결된 master / slave의 내부에 태스크를 정의할 필요 없이 인터페이스의 메서드를 사용 할 수 있다. 즉 인터페이스를 이용해서 트랜잭션을 만들 수 있다.
또한 코드가 간결해지고 유지보수가 쉬워진다.
인터페이스에 연결된 어떤 모듈은 특정 태스크만 사용할 수 있게 만들 수 있다.
modport 를 이용해서 import <task> 로 지정하면, 해당 modport로 선언된 모듈은 그 태스크만 접근할 수 있다.
interface simple_bus(input clk); logic req, start, gnt, rdy; logic [1:0] mode; logic [7:0] addr; wire [7:0] data; modport master( input clk, gnt, rdy, output start, req, mode, addr, inout data, import read ); task read (input [7:0] address, output [7:0] r_data); @(negedge clk) addr = address; ... endtask endinterface module cpuModule(simple_bus.master bus); ... bus.read(); ... endmodule
modport 내부엔 신호들의 방향과 함께 메서드가 임포트 되어있다.
cpuModule은 read 태스크만 접근하여 사용 할 수 있다.
'개발 > SystemVerilog' 카테고리의 다른 글
[SystemVerilog] 클래스 1 (0) 2022.01.17 [SystemVerilog] 데이터 타입 5 string (0) 2022.01.17 [SystemVerilog] 인터페이스 1 (0) 2022.01.16 [SystemVerilog] packed / unpacked array (0) 2022.01.15 [SystemVerilog] 데이터 타입 4 struct (0) 2022.01.15