거북이처럼 천천히

Verilog RTL 설계 (6월 13일 - 1) 본문

Verilog/Verilog RTL 설계

Verilog RTL 설계 (6월 13일 - 1)

유로 청년 2024. 6. 14. 08:40

1.What is the Dataflow modeling?

  • Dataflow modleling은 논리 회로내에서 데이터의 흐름에 따라 논리회로를 설계하는 기법을 의미한다.
  • 따라서 Dataflow modeling은 "입력 데이터가 어떠한 과정을 거쳐 어떻게 출력 단자로 출력되는가?"를 중심으로 회로를 설계한다.
  • Dataflow modelingd은 특징은 다음과 같다.
    1. 산술, 논리, 비트 연산자를 사용할 수 있다.
    2. "assign" 키워드를 통해 입력 포트의 변화가 발생하면 이를 다시 연산한다.
    3. 모든 assign 문은 프로그래밍 언어처럼 순차적으로 수행하는 것이 아닌 모든 assign문을 
        병렬 처리를 수행하여 동시에 처리 및 출력한다.

 

2. 그럼, assign 키워드는 무엇이며, 어떤 역활을 수행하는가?

  • 이에 대한 해답을 하기 위해서는 먼저 "모듈은 각각의 Modeling에 대해서 어떻게 입력 값의 변화에 즉각적으로 대응하는가?" 에 대해서 생각해볼 필요가 있다.
  • behavior modeling은 always 블록을 통해 sensitive 변수의 변화가 발생하면 이에 대응한다.
  • structural modeling은 두 가지 경우 (1. library gate, 2. 사용자 정의 모듈을 이용하는 경우) 모두 모듈 내에서 입력 값의 변화에 따라 즉각적으로 대응한다.
  • Q) 그럼, 누가 Dataflow modeling에서 입력값의 변화에 대해서 누가 즉각적으로 대응하는가?
    A) 바로 assign 키워드가 입력값의 변화에 대해서 관찰하다가 변화가 발생하면 즉각적으로 대응한다.
  • 사실 assign 키워드가 있는 명령어를 보면 '마치 대입 연산자를 통해 단순히 할당'한 것처럼 보인다.
  • 하지만, 이는  assign 키워드를 통해 단순한 대입 연산자가 아니라 입력 값의 변화에 따라 재연산한 후, 다시 출력 값에 변화에 따른 대응을 해주게 된다.

 

 

3. Half adder의 Dataflow modeling

- 어제는 Half adder을 structural modeling, behavioral modeling으로 구현하였으며, 이번에는 Dataflow modeling으로 Half adder를 구현해보겠다.

- Half adder를 Dataflow modeling으로 구현하면 다음과 같다.

module Half_adder_Data_Flow_Modeling (
    input a, b,
    output sum, carry );
    
    // Initialization about Wire
    // 출력 wire와 외부 모듈과의 Interface를 위해 wire 자료형으로 설정
    // result_half_adder는 2bit 크기를 갖는 wire 자료형 변수이다.
    wire[1:0] result_half_adder;
    
    // result_half_adder 변수에 half adder의 연산 결과 저장
    assign result_half_adder = a + b;
    
    // a + b 에서 +는 단순한 연산자가 아니라 덧셈 회로를 이용하여 연산하겠음을 의미
    // 덧셈 연산의 결과를 result_half_adder에 저장되면
    // 2비트 배열 형태로 저장되며, bit 0 = sum, bit 1 = carry가 저장
    assign sum = result_half_adder[0];
    assign carry = result_half_adder[1];
    
endmodule

 

 

- 위 소스 코드에서 핵심적인 포인트는 두 가지이다.
  ●  wire[1:0] result_half_adder;
  ●  assign result_half_adder = a + b;

 

 

Q1) wire[1:0] result_half_adder; 명령어는 어떤 의미를 담고 있는가?

 

  • result_half_adder는 입력 포트 a, b의 덧셈 연산의 결과인 sum, carry를 저장하는 변수이다.
  • sum, carry 출력 포트는 각 1bit이기 때문에 이를 모두 담기 위해서는 2bit 변수 크기가 필요하다.
  • wire 자료형이여야 하는 이유는 "sum, carry 값을 단순히 모듈내에서만 활용하는 것이 아닌 외부 모듈과의 상호 작용 과정에서 활용해야 하기 때문에" 이를 위해 외부 모듈과의 상호 작용할 수 있는 wire 자료형을 사용해야한다. 

 

Q2) assign result_half_adder = a + b; 명령어는 어떤 의미를 담고 있는가?

  

  • 만약 assign 키워드가 없었다면 단순히 위 명령어는 단 한 번만 수행되는 대입 연산자 였을 것이다. 
  • 하지만, 모듈은 입력값의 변화에 따라서 즉각적으로 대응할 필요가 있고, 이를 위해서는 입력 포트의 변화를 계속 해서 감시하는 동시에 변화에 대해 즉각적으로 대응할 수 있는 기능이 필요한데, 이를 수행하는 것이 바로 assign 키워드이다. 
  • 따라서 assign result_half_adder = a + b; 는 단순히 단 한 번만 수행되는 명령어가 아닌 입력 포트의 변화를 감지할 때마다 즉각적으로 변화에 대해 대응해 나아가는 명령어라 할 수 있다.

 

 

4. Full adder (Behavioral Modeling)

< Source code >

// Behavior modeling of Full adder.
module Full_adder_behavior_modeling (
    input a, b, Cin,
    output reg sum, carry);
    
    always @(a, b, Cin) begin
        case({a, b, Cin}) 
            3'b 000 : begin sum = 0; carry = 0; end
            3'b 001 : begin sum = 1; carry = 0; end
            3'b 010 : begin sum = 1; carry = 0; end
            3'b 011 : begin sum = 0; carry = 1; end
            3'b 100 : begin sum = 1; carry = 0; end
            3'b 101 : begin sum = 0; carry = 1; end
            3'b 110 : begin sum = 0; carry = 1; end
            3'b 111 : begin sum = 1; carry = 1; end
         endcase
    end 
    
 endmodule

 

< Simulation result >

Simulation of behavioral modeling of Full adder

 

 

5. Full adder (Structural Modeling)

< Source code >

// AND Gate Module (Behavioral modelng)
module and_gate (
    input a, b,
    output reg out);
    
    always @(a, b) begin 
        case({a, b}) 
            2'b00 : out = 0;
            2'b01 : out = 0;
            2'b10 : out = 0;
            2'b11 : out = 1;
        endcase
    end 
endmodule

// XOR Gate Moudle (Behavioral modeling)
module xor_gate (
    input a, b,
    output reg out);
    
    always @(a, b) begin
        case({a, b})
            2'b00 : out = 0;
            2'b01 : out = 1;
            2'b10 : out = 1;
            2'b11 : out = 0;
        endcase
    end
 endmodule

// Half adder Module (Structural modeling)
module half_adder (
    input a, b,
    output sum, carry);
    
    and_gate and_gate0 (.a(a), .b(b), .out(carry));
    xor_gate xor_gate0 (a, b, sum);
    
 endmodule

// Full adder Module (Strutural modeling)
module Full_adder_structural_modeling(
       input a, b, Cin,
       output sum, carry);
       
       // Full adder에는 2개의 half adder와 OR gater로 구성
       // 여기서 각 게이트를 연결 하기 위해서는 3개의 wire가 필요하다.
       // wire는 자료형이기도 하지만, 게이트의 출력 값을 임시저장하는 역활도 수행한다.
       wire sum_0, carry_0, carry_1;
       
       // Full adder의 논리 회로를 보고 이해 할 것!
       half_adder half_adder0 (.a(a), .b(b), .sum(sum_0), .carry(carry_0));
       half_adder half_adder1 (sum_0, Cin, sum, carry_1);
       
       xor_gate xor_gate0 (carry_0, carry_1, carry);
       
endmodule

 

< Simulation result >

Simulation result of Structural Modeling of Full adder

 

 

 

6. Full adder (Dataflow Modeling)

< Source code >

 module Full_adder_DataFlow_Modeling (
    input a, b, Cin,
    output sum, carry );
    
    // 덧셈 회로 연산의 결과값을 저장할 수 있는 변수 선언
    wire[1:0] result_value;
    
    // 덧셈 회로를 이용하여 Full adder 동작
    assign result_value = a + b + Cin;
    assign sum = result_value[0];
    assign carry = result_value[1];
    
endmodule

 

< Simulation result >