-
[digital] 구조적 모델링개인 공부/회로 2024. 12. 19. 22:30
Verilog HDL을 이용한 여러 모델링과 문법
두번째로 살펴볼 것은 바로 "구조적 모델링"이다.
구조적 모델링
- Verilog HDL에서 하드웨어를 설게하는 기본 단위는 모듈이다.
- 구조적 모델링에서, 하나의 모듈은, 다른 모듈들을 이용하여 계층적으로 설계된다.
⇒ 상위 수준의 모듈은 하위 수준의 모듈을 인스턴스하고, 입력/출력/양방향 포트들을 통해 모듈들 간 신호를 전달해준다. - EX) PCB보드는 여러 IC칩들을 인스턴스하여 구성된다.
또한, 각 IC 칩들은 플립플롭, MUX, ALU등과 같은 하위 모듈들을 인스터스하여 구성되고
그러한 모듈들 또한 여러 하위 인스턴스들을 통해 계층적으로 구성된다.
모듈
⇒ 머리부, 선언부, 몸체로 구성된다.
module and_gate #( parameter N = 4 )( input [N-1:0] a, // 입력 A input [N-1:0] b, // 입력 B input cin, // 입력 Cin output [N-1:0] sum, // 출력 sum output cout // 출력 Cout ); reg [N-1:0] a, b; reg cin; wire [N-1:0] sum; wire cout; // 논리 회로 wire [N-1:0] axb_cin; wire [N-1:0] axb; wire [N-1:0] ab; and (axb_cin, a, b); and (axb, a, b); or (cout, axb, axb_cin); assign sum = a ^ b ^ cin; endmodule
위 코드를 머리부/선언부/몸체부로 구분하여 살펴보자!
머리부
: 모듈명, 파라미터 및 포트 목록
module and_gate #( parameter N = 4 )( input [N-1:0] a, // 입력 A input [N-1:0] b, // 입력 B input cin, // 입력 Cin output [N-1:0] sum, // 출력 sum output cout // 출력 Cout ); ...
- module 키워드
- 모듈 이름 (and_gate)
- parameter 목록 (N)
- 포트 목록 (port_list) 또는 포트 선언 ⇒ 위 예시는 선언이 사용됨
선언부
: port, parameter, net, var 선언
reg [N-1:0] a, b; reg cin; wire [N-1:0] sum; wire cout; wire [N-1:0] axb_cin; wire [N-1:0] axb; wire [N-1:0] ab;
- 머리부에 포트가 선언된 경우에는 재선언하지 ❌
- 포트들의 선언 순서는 인스턴스화 될 때 포트 매핑에 영향을 미친다!
몸체부
: 회로의 동작, 기능, 구조를 모델링
and (axb_cin, a, b); and (axb, a, b); or (cout, axb, axb_cin); assign sum = a ^ b ^ cin;
인스턴스
- 설계된 모듈을 다른 모듈 내에서 재사용하는 것
- 모듈을 인스턴스화하면, 그 모듈이 내부에서 정의한 신호, 입력, 출력을 외부 설계와 연결할 수 있다.
인스턴스 사용
- 하위 모듈을 인스턴스로 사용할 때는 각각의 인스턴스 이름을 반드시 지정해주어야 한다.
- 인스턴스 이름은 해당 모듈의 복사본을 구별하는 데 사용된다.
(📌단, 게이트 프리미티브의 인스턴스 이름은 생략하고 그냥 인스턴스종류만 작성해주어도 된다.)
EX) full_adder 모듈을 인스턴스로 사용하여 4bit adder 구현
module ripple_carry_adder ( input [3:0] a, // 4비트 입력 A input [3:0] b, // 4비트 입력 B input cin, // 초기 입력 캐리 output [3:0] sum, // 4비트 출력 합계 output cout // 최종 출력 캐리 ); wire c1, c2, c3; // 내부 캐리 신호 // Full Adder 인스턴스 (포트 순서: a, b, cin, sum, cout) full_adder fa0(a[0], b[0], cin, sum[0], c1); // 인스턴스 이름 : fa0 full_adder fa1(a[1], b[1], c1, sum[1], c2); // 인스턴스 이름 : fa1 full_adder fa2(a[2], b[2], c2, sum[2], c3); full_adder fa3(a[3], b[3], c3, sum[3], cout); endmodule
⇒ 여기서, full_adder 인스턴스를 fa0, fa1, fa2, fa3 과 같이 각각 이름을 지정하여 사용한 것을 알 수 있다.
인스턴스 포트 매핑
- 하위 모듈을 인스턴스로 사용할 때는 각각의 인스턴스 이름을 반드시 지정해주어야 한다.
- 인스턴스 이름은 해당 모듈의 복사본을 구별하는 데 사용된다.
EX)
module full_adder ( input a, // 입력 A (1비트) input b, // 입력 B (1비트) input cin, // 입력 캐리 output sum, // 출력 합계 output cout // 출력 캐리 ); assign sum = a ^ b ^ cin; // XOR 연산으로 합계 계산 assign cout = (a & b) | (cin & (a ^ b)); // 캐리 계산 endmodule
위와 같이 구현된 모듈을 인스턴스로 사용할 때,
포트 매핑은 다음과 같이 이루어질 수 있다.1. 순서에 따른 매핑
: 인스턴스 되는 모듈에 작성된 포트 목록 순서에 맞춰 포트매칭이 이루어 진다.
full_adder fa0(sum[0], c1, a[0], b[0], cin); // full_adder 모듈에서 정의한 순서대로 a,b, cin, sum, cout으로 매핑된다.
2. 이름에 따른 매핑
: 인스턴스 되는 모듈에 작성한 이름을 명시적으로 지정함으로써 포트매칭이 이루어 진다.\
full_adder fa0 ( .a(a[2]), .sum(sum[2]), .cin(c2), .cout(c3), .b(b[2]), );
포트의 선언
- 한 번 포트선언에 사용된 이름은 다른 포트 선언/자료형 선언에서 다시 선언될 수 없다.
- 명시적인 선언이 없는 net은 unsigned로 취급된다.
EX)
input wire signed [7:0] a, // signed 8비트 입력 신호 a input wire [3:0] b, // unsigned 4비트 입력 신호 b output reg signed [15:0] result, // signed 16비트 출력 레지스터 result inout wire [7:0] data_bus, // unsigned 8비트 양방향 신호 data_bus output wire valid, // unsigned 단일 비트 출력 신호 valid input tri0 [3:0] control // tri0 기본값을 가지는 4비트 3상 네트워크
parameter
- parameter는 모듈 내부에서 상수처럼 사용되는 자료형이다.
- 상수를 정의하거나, 모듈의 동작 및 크기(구조)를 매개변수화하는 데 사용된다.
- 모듈 정의 시 초기값을 설정해야 하며, 이후에는 변경 불가능하다. (상수)
- 📌 단, 모듈을 인스턴스화 하여 사용할 때는 명시적 재정의 문법 #(.PARAM_NAME(VALUE)) 을 통해 재정의 가능하다
- 해당 모듈내에서만 사용하는 상수는 localparam 자료형으로 선언되며, 이는 내/외부에서 재정의 불가능하다.
parameter 활용 예시
예를 들어, 다음과 같이 하나의 adder 모듈을 만들었다고 가정하자.
module adder #( parameter WIDTH = 8 // 기본 비트 폭 8 )( input [WIDTH-1:0] a, // 입력 A input [WIDTH-1:0] b, // 입력 B output [WIDTH-1:0] sum // 출력 합계 ); assign sum = a + b; endmodule
한 모듈에서는 4bit adder가 필요하고, 다른 모듈에서는 16bit adder가 필요하다면,
adder_4, adder_8, adder_16를 각각 다르게 작성해주어야 할까?⇒ NO!!
기본 비트폭을 parameter로 설정하고,
인스턴스로 사용 될 때 원하는 bit대로 parameter를 재정의 해주면 된다.다음은 위와 같이 구현된 모듈을 16bit adder로 사용하는 코드이다.
module top; wire [15:0] sum; adder #(.WIDTH(16)) u1 ( // WIDTH를 16으로 재설정 .a(16'hA5A5), .b(16'h5A5A), .sum(sum) ); endmodule
⇒ adder 인스턴스 선언시, WIDTH 파라미터를 16으로 재설정 한 것을 볼 수 있다!
[보충] generate-endgenerate 키워드 (동적 생성)
- 코드가 컴파일 될 때,
- 동일한 하드웨어 블록을 반복적으로 생성하거나
- 조건에 따라 선택적으로 하드웨어 블록을 생성해주는 키워드
- 설계의 유연성과 간결성을 크게 향상시킬 수 있다.
특징
- generate 블록은 컴파일 시간에 처리된다.
- 반복 생성
- genvar 변수를 이용해 generate 블록 내에서 반복을 제어할 수 있다.
- 조건부 생성
- if-else나 case를 사용하여 특정 조건에 따라 하드웨어를 생성할 수 있다.
활용 예시
예를 들어, 다음과 같이 크기가 명확하고 반복적인 조건이 없는 경우,
컴파일러가 모든 할당을 정적으로 확인할 수 있으므로 generate를 사용하지 않아도 된다.EX) 고정된 4bit_and
module and_gate ( input [3:0] a, input [3:0] b, output [3:0] y ); assign y[0] = a[0] & b[0]; assign y[1] = a[1] & b[1]; assign y[2] = a[2] & b[2]; assign y[3] = a[3] & b[3]; endmodule
하지만, 다음과 같이 크기나 동작이 변경 가능할 경우, 반복이나 조건부 생성을 위해 generate가 필요하다.
EX) 변경가능한 비트수를 가지는 Nbit and_gate
module and_gate #( parameter N = 8 // 비트 폭 )( input [N-1:0] a, input [N-1:0] b, output [N-1:0] y ); generate genvar i; for (i = 0; i < N; i = i + 1) begin assign y[i] = a[i] & b[i]; // 각 비트마다 AND 연산 end endgenerate endmodule
그렇다면, for, while 과 같은 반복문이 있을 때는 무조건 generate 를 작성해주어야 할까?
⇒ NO!!
generate 블록은 컴파일 시간에, 하드웨어 블록을 반복적/선택적으로 생성할 때 사용된다는 것에 주의해야 한다.
📌하드웨어 블록?
: Verilog 코드가 매핑되는 실제 논리 회로 구성 요소. (논리 게이트, 플립플롭, 레지스터 등등…)예를 들어, 다음과 같은 코드를 생각해보자
odule decoder_while ( input [2:0] in, // 3비트 입력 output reg [7:0] out // 8비트 출력 ); integer i; // 반복 변수 always @(*) begin out = 8'b0; // 출력 초기화 i = 0; while (i < 8) begin if (i == in) // 입력 값에 해당하는 출력 비트 활성화 out[i] = 1; i = i + 1; end end endmodule
⇒ 주어진 코드에 대해 요구되는 하드웨어 블록은 위와 같이 고정적이다.
즉, 반복문은 있으나, 고정된 3to8 decoder 하드웨어 구성 요소를 가지고 수행되므로 generate를 작성하지 않는다.하지만, 다음과 같이 코드를 작성한다면
module decoder_generate #( parameter N = 3 // 입력 비트 수 )( input [N-1:0] in, // N비트 입력 output [2**N-1:0] out // 2^N 비트 출력 ); generate genvar i; for (i = 0; i < (1 << N); i = i + 1) begin assign out[i] = (in == i); // 입력과 일치하는 출력 비트 활성화 end endgenerate endmodule
⇒ N 값 따라 입력 비트 수와 출력 비트수가 동적으로 결정되므로 요구되는 하드웨어 블록이 각각 다르다
⇒ generate를 작성해주어야 한다!'개인 공부 > 회로' 카테고리의 다른 글
[digital] 게이트수준 모델링 (1) 2024.12.19 [digital] Verilog HDL 모델링 (4) 2024.12.02 [digital] PLD 종류 (SPLD, CPLD) (1) 2024.12.01 [digital] PLD란? (2) 2024.11.30