HDL 기반 시스템 반도체 설계 과정 

 

verilog compile 과정 

 

verilog code (sw) -> (1) synthesis -> H/W circuit -> fpga implementation -> bitstream (fpga 등 h/w 회로 파일, xxx.bit) 

-> synthesis 과정에서 net list가 생성됨 

* net list : 정렬되지 않은 형태의 H/W 정보 

(1) synthesis : verilog 코드를 design compiler를 이용해 gate-level netlist로 변환하는 과정 

(2) implementation : gate, tr 상태에서의 회로 배치 

 

gate
  • gates.v - verilog code 

and / nand / or / nor / xor / xnor / not gate 를 연속 할당문(continuous assignment) 으로 구현 

`timescale 1ns / 1ps

module gates(      // chip name 
    // port list 
    input a,
    input b,
    output y0, 
    output y1,
    output y2,
    output y3,
    output y4,
    output y5,
    output y6
    );
    
    // circuit architecture 
    assign y0 = a & b;      // and oper
    assign y1 = ~ (a & b);  // nand oper
    assign y2 = a | b;      // or oper
    assign y3 = ~ (a | b);  // nor oper 
    assign y4 = a ^ b;      // xor oper 
    assign y5 = ~ (a ^ b);  // exnor oper 
    assign y6 = ~ a; 
    
endmodule

 

  • RTL analysis 

1) 코드가 gate level로 분석되어 출력되는 것을 확인할 수 있다

 

2) 보드에 올리기 위한 pin 설정 

package pin, I/O std 설정 후 ctrl+s → xdc (constraint file) 생성

I/O PINS
xdc (constraint) file

  • testbench.v
`timescale 1ns / 1ps

module tb_gates();

reg a;
reg b;
wire y0; 
wire y1;
wire y2;
wire y3;
wire y4;
wire y5;
wire y6;

gates dut(    // dut(design under test, 관용어) -> 시뮬레이션 대상 instance, instanciation
    .a(a),    // .포트이름(변수)
    .b(b),
    .y0(y0), 
    .y1(y1),
    .y2(y2),
    .y3(y3),
    .y4(y4),
    .y5(y5),
    .y6(y6)
);

initial begin 
    #00 a = 1'b0; b = 1'b0;
    #10 a = 1'b0; b = 1'b1;
    #10 a = 1'b1; b = 1'b0; 
    #10 a = 1'b1; b = 1'b1; 
    #10 $finish; 
end 

endmodule
  • simulation 

 

🚩 verilog 변수 타입 
- reg : 값을 저장 가능 
- wire : 값을 저장할 수 X 

 

half_adder

 

half adder는 1bit를 연산할 때 사용된다. 

xor gate와 and gate를 이용해 sum과 carry를 출력한다. 

 

  • half_adder.v
`timescale 1ns / 1ps

module half_adder(
    input wire i_a,
    input wire i_b,
    output sum, 
    output carry 
);

assign sum = i_a ^ i_b;     // 연속할당문 
assign carry = i_a & i_b; 

endmodule
  • RTL Analysis 

 

1bit full_adder 

 

full adder는 1bit를 계산시 carry를 받아서 계산한다. 

half adder 두개와 carry끼리 연산하는 or gate로 구성된다. 

 

 

  • full_adder.v
`timescale 1ns / 1ps

// full adder
module full_adder(
    input i_fa_a,
    input i_fa_b,
    input i_cin,
    output fa_sum_o,
    output fa_carry_o
);

wire sum1, carry1, sum2, carry2; 

half_adder U_HA1(
    .i_a(i_fa_a),
    .i_b(i_fa_b),
    .ha_sum_o(sum1), 
    .ha_carry_o(carry1) 
);


half_adder U_HA2(
    .i_a(sum1),
    .i_b(carry1),
    .ha_sum_o(sum2),
    .ha_carry_o(carry2)
); 

assign fa_carry_o = carry1 | carry2;
assign sum = sum2; 

endmodule


// half adder
module half_adder(
    input i_a,
    input i_b,
    output ha_sum_o, 
    output ha_carry_o 
);

assign ha_sum_o = i_a ^ i_b; 
assign ha_carry_o = i_a & i_b; 

endmodule

 

  • RTL Analysis 

  • testbench.v
`timescale 1ns / 10ps

module tb_adder();

reg i_fa_a;
reg i_fa_b; 
reg i_cin; 
wire fa_sum_o;
wire fa_carry_o; 

full_adder dut(
    .i_fa_a(i_fa_a),
    .i_fa_b(i_fa_b),
    .i_cin(i_cin),
    .fa_sum_o(fa_sum_o),
    .fa_carry_o(fa_carry_o)
);

initial begin
    #00 i_cin = 0; i_fa_b = 0; i_fa_a = 0; 
    #10 i_cin = 0; i_fa_b = 0; i_fa_a = 1; 
    #10 i_cin = 0; i_fa_b = 1; i_fa_a = 0; 
    #10 i_cin = 0; i_fa_b = 1; i_fa_a = 1; 
    #10 i_cin = 1; i_fa_b = 0; i_fa_a = 0; 
    #10 i_cin = 1; i_fa_b = 0; i_fa_a = 1; 
    #10 i_cin = 1; i_fa_b = 1; i_fa_a = 0; 
    #10 i_cin = 1; i_fa_b = 1; i_fa_a = 1; 
    #10 $finish;
end

endmodule

 

4bit full_adder

 

4bit full adder는 1bit full adder 4개로 구성된다.

  • fullAdder_4bit.v
`timescale 1ns / 10ps

module fullAdder_4bit(
    input [3:0] i_fa4_a,
    input [3:0] i_fa4_b,
    input i_fa4_cin, 
    output [3:0] fa4_sum_o,
    output fa4_carry_o 
);

wire [3:0] carry_w; 
// assign carry_w[0] = i_fa4_cin;

full_adder U_FA1(
    .i_fa_a(i_fa4_a[0]),
    .i_fa_b(i_fa4_b[0]),
    .i_cin(i_fa4_cin),
    .fa_sum_o(fa4_sum_o[0]),
    .fa_carry_o(carry_w[0])
);

full_adder U_FA2(
    .i_fa_a(i_fa4_a[1]),
    .i_fa_b(i_fa4_b[1]),
    .i_cin(carry_w[0]),
    .fa_sum_o(fa4_sum_o[1]),
    .fa_carry_o(carry_w[1])
); 

full_adder U_FA3(
    .i_fa_a(i_fa4_a[2]),
    .i_fa_b(i_fa4_b[2]),
    .i_cin(carry_w[1]),
    .fa_sum_o(fa4_sum_o[2]),
    .fa_carry_o(carry_w[2])
); 

full_adder U_FA4(
    .i_fa_a(i_fa4_a[3]),
    .i_fa_b(i_fa4_b[3]),
    .i_cin(carry_w[2]),
    .fa_sum_o(fa4_sum_o[3]),
    .fa_carry_o(carry_w[3])
); 

assign fa4_carry_o = carry_w[3]; 

endmodule

 

  • RTL Analysis 

 

  • testbench.v
`timescale 1ns / 10ps

module tb_fullAdder_4bit();

reg [3:0] i_fa4_a;
reg [3:0] i_fa4_b;
reg i_fa4_cin; 
wire [3:0] fa4_sum_o;
wire fa4_carry_o;

fullAdder_4bit dut(
    .i_fa4_a(i_fa4_a),
    .i_fa4_b(i_fa4_b),
    .i_fa4_cin(i_fa4_cin),
    .fa4_sum_o(fa4_sum_o),
    .fa4_carry_o(fa4_carry_o)
);

initial begin
    i_fa4_a = 4'b0000; i_fa4_b = 4'b0000; i_fa4_cin = 1'b0;

    #10 i_fa4_a = 4'b0001; i_fa4_b = 4'b0001; i_fa4_cin = 1'b0;  
    #10 i_fa4_a = 4'b0010; i_fa4_b = 4'b0011; i_fa4_cin = 1'b0;  
    #10 i_fa4_a = 4'b0101; i_fa4_b = 4'b0011; i_fa4_cin = 1'b1;  
    #10 i_fa4_a = 4'b1111; i_fa4_b = 4'b0001; i_fa4_cin = 1'b0;  
    #10 i_fa4_a = 4'b1111; i_fa4_b = 4'b1111; i_fa4_cin = 1'b1;  
    #10 i_fa4_a = 4'b1001; i_fa4_b = 4'b0110; i_fa4_cin = 1'b0;  
    #10 i_fa4_a = 4'b0011; i_fa4_b = 4'b1100; i_fa4_cin = 1'b1;  
    #10 i_fa4_a = 4'b1010; i_fa4_b = 4'b1010; i_fa4_cin = 1'b0;  
    #10 i_fa4_a = 4'b0100; i_fa4_b = 4'b1001; i_fa4_cin = 1'b1;  
    #10 i_fa4_a = 4'b1111; i_fa4_b = 4'b1111; i_fa4_cin = 1'b1;  

    #10 $finish;  // End of simulation
end 


endmodule

ra_mi