🚩 추상화 (Abstract) ↔ 구체화 
- 추상화 : 해당 기능에서 필요한 것만 보여주는 형태 

 

 

FND
  • gpio port 

위 회로도를 봤을때 fnd가 bjt(AN n)에 의해  w4, v4, u4, u2 pin에 의해 제어되고, 이때 pin에 low 신호 (0)을 주어야 해당 fnd가 선택됨을 알 수 있다 (자세한 것은 push-pull/open-drain 포스팅 참고) 

 

이 FND를 제어할 수 있는 시스템을 설계해보자 

  • Block Diagram 

 

 

🚩 always@() begin ~ end 
항상 () 내부의 port를 감시하겠다 -> ()내부 port의 값이 변화할 때 아래 내용을 실행한다. 

- () 내부 port : 감시대상 (sensitivity list)
- () 안에 *가 들어가면 input port 전부 감시

- always 문 내부에서 값을 넘겨줄려면 우측 변수가 reg 타입으로 지정되어야 한다.
- always 문 외부에서 값을 넘겨줄려면 우측 변수가 wire 타입으로 지정되어야 한다. 

 

 

🛠️ sliding switch를 이용한 4bit 계산기 
  • Block diagram 

 

  • adder.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(1'b0),
    .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

// 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(i_cin),
    .ha_sum_o(fa_sum_o),
    .ha_carry_o(carry2)
); 

assign fa_carry_o = carry1 | carry2;

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
  • fnd_controller.v
`timescale 1ns / 10ps

module fnd_controller(
    input wire [1:0] i_con_fndSel,
    input wire [3:0] i_con_bcdData, 
    output wire [3:0] con_fndCom_o,
    output wire [7:0] con_segData_o
);

BCDtoseg_o_decoder U_BCDtoSEG(
    .i_bcd(i_con_bcdData),
    .seg_o(con_segData_o)
);

decoder_2to4 U_2to4(
    .i_dec_sel(i_con_fndSel),
    .dec_fndCom_o(con_fndCom_o)
); 

endmodule


// BCDtoseg_o_decoder
module BCDtoseg_o_decoder(
    input wire [3:0] i_bcd,
    output reg [7:0] seg_o
);

always@(i_bcd) begin
    case (i_bcd) 
        4'h0 : seg_o = 8'hc0; 
        4'h1 : seg_o = 8'hf9;
        4'h2 : seg_o = 8'ha4;
        4'h3 : seg_o = 8'hb0;
        4'h4 : seg_o = 8'h99;
        4'h5 : seg_o = 8'h92;
        4'h6 : seg_o = 8'h82;
        4'h7 : seg_o = 8'hf8;
        4'h8 : seg_o = 8'h80;
        4'h9 : seg_o = 8'h90;
        4'ha : seg_o = 8'h88;
        4'hb : seg_o = 8'h83;
        4'hc : seg_o = 8'hc6;
        4'hd : seg_o = 8'ha1;
        4'he : seg_o = 8'h86; 
        4'hf : seg_o = 8'h8e;  
        default : seg_o = 8'hff; 
    endcase 
end     
endmodule

// decoder_2to4
module decoder_2to4(
    input [1:0] i_dec_sel,
    output reg [3:0] dec_fndCom_o 
);

always@(i_dec_sel) begin
    case (i_dec_sel) 
        2'b00 : dec_fndCom_o = 4'b1110; 
        2'b01 : dec_fndCom_o = 4'b1101; 
        2'b10 : dec_fndCom_o = 4'b1011; 
        2'b11 : dec_fndCom_o = 4'b0111; 
        default : dec_fndCom_o = 4'b1111; 
    endcase 
end    

endmodule
  • calculator.v ( = top.v) 
`timescale 1ns / 10ps

module caculator(
    input wire [1:0] i_ca_sel, 
    input wire [3:0] i_ca_a, 
    input wire [3:0] i_ca_b,
    output [3:0] ca_fndCom_o,
    output [7:0] ca_fndFont_o,
    output ca_carry_o 
);

wire [3:0] w_sum; 

// assign ca_fndCom_o = 4'b1110; 

fullAdder_4bit U_4bit_adder(
    .i_fa4_a(i_ca_a),
    .i_fa4_b(i_ca_b),
    .fa4_sum_o(w_sum),
    .fa4_carry_o(ca_carry_o) 
); 

fnd_controller U_FND_con(
    .i_con_fndSel(i_ca_sel),
    .i_con_bcdData(w_sum),
    .con_fndCom_o(ca_fndCom_o),
    .con_segData_o(ca_fndFont_o)
); 

endmodule

 

  • RTL Analysis 

 

 

그런데 해당 시스템은 덧셈을 수행하기는 하지만 각 비트에 따라서만 출력할 뿐 전체 숫자를 fnd에 나타내지는 못한다

따라서 전체 덧셈 결과 (sum)을 각 4자리의 fnd에 각 숫자가 맞게 들어가도록 하려면 전체 숫자에서 한자리씩 나누어줘야 한다. 

 

🛠️ 4FND에 십진수 자리수에 맞추어 출력하도록 설계

 

Q. 10진수 자리수를 어떻게 분리할 것인가?

A. digit splitter  & 4*1 MUX !! 

→ 전체 4자리 천단위 숫자를 나누고 %연산자를 이용해 자리수만 추출한다. 

→ 4*1 mux를 이용해 fnd 자리수를 선택

  • 전체 Block Diagram

  • RTL Analysis 

 

  • (top) calculator.v
`timescale 1ns / 10ps

module caculator (
    input wire [1:0] i_ca_sel,
    input wire [3:0] i_ca_a,
    input wire [3:0] i_ca_b,
    output [3:0] ca_fndCom_o,
    output [7:0] ca_fndFont_o
);

    wire [3:0] w_sum;
    wire w_carry; 

    // assign ca_fndCom_o = 4'b1110; 

    fullAdder_4bit U_4bit_adder (
        .i_fa4_a(i_ca_a),
        .i_fa4_b(i_ca_b),
        .fa4_sum_o(w_sum),
        .fa4_carry_o(w_carry)
    );

    fnd_controller U_FND_con (
        .i_con_fndSel (i_ca_sel),
        .i_con_bcdData({w_carry, w_sum}),
        .con_fndCom_o (ca_fndCom_o),
        .con_segData_o(ca_fndFont_o)
    );

endmodule

 

  • fnd_controller.v
`timescale 1ns / 10ps

module fnd_controller (
    input  wire [1:0] i_con_fndSel,
    input  wire [4:0] i_con_bcdData,
    output wire [3:0] con_fndCom_o,
    output wire [7:0] con_segData_o
);

    wire [3:0] w_dig1, w_dig10, w_dig100, w_dig1000, w_bcdData; 

    decoder_2to4 U_2to4 (
        .i_dec_x(i_con_fndSel),
        .dec_y_o(con_fndCom_o)
    );

    digit_splitter U_dig_splitter(
        .i_dig_dig(i_con_bcdData),
        .dig_dig1_o(w_dig1),
        .dig_dig10_o(w_dig10),
        .dig_dig100_o(w_dig100),
        .dig_dig1000_o(w_dig1000)
    );

    mux_41 U_mux_41 (
        .i_mul_sel(i_con_fndSel),
        .i_mul_x0(w_dig1),
        .i_mul_x1(w_dig10),
        .i_mul_x2(w_dig100),
        .i_mul_x3(w_dig1000),
        .mul_y_o(w_bcdData)
    );

    BCDtoseg_o_decoder U_BCDtoSEG (
        .i_bcd(w_bcdData),
        .seg_o(con_segData_o)
    );

endmodule


// BCDtoseg_o_decoder
module BCDtoseg_o_decoder (
    input  wire [3:0] i_bcd,
    output reg  [7:0] seg_o
);

    always @(i_bcd) begin
        case (i_bcd)
            4'h0: seg_o = 8'hc0;
            4'h1: seg_o = 8'hf9;
            4'h2: seg_o = 8'ha4;
            4'h3: seg_o = 8'hb0;
            4'h4: seg_o = 8'h99;
            4'h5: seg_o = 8'h92;
            4'h6: seg_o = 8'h82;
            4'h7: seg_o = 8'hf8;
            4'h8: seg_o = 8'h80;
            4'h9: seg_o = 8'h90;
            4'ha: seg_o = 8'h88;
            4'hb: seg_o = 8'h83;
            4'hc: seg_o = 8'hc6;
            4'hd: seg_o = 8'ha1;
            4'he: seg_o = 8'h86;
            4'hf: seg_o = 8'h8e;
            default: seg_o = 8'hff;
        endcase
    end
endmodule

// decoder_2to4
module decoder_2to4 (
    input [1:0] i_dec_x,
    output reg [3:0] dec_y_o
);

    always @(i_dec_x) begin
        case (i_dec_x)
            2'b00:   dec_y_o = 4'b1110;
            2'b01:   dec_y_o = 4'b1101;
            2'b10:   dec_y_o = 4'b1011;
            2'b11:   dec_y_o = 4'b0111;
            default: dec_y_o = 4'b1111;
        endcase
    end

endmodule

module digit_splitter (
    input wire [4:0] i_dig_dig,
    output [3:0] dig_dig1_o,
    output [3:0] dig_dig10_o,
    output [3:0] dig_dig100_o,
    output [3:0] dig_dig1000_o
);

    assign dig_dig1_o = i_dig_dig % 10;
    assign dig_dig10_o = (i_dig_dig / 10) % 10;
    assign dig_dig100_o = (i_dig_dig / 100) % 10;
    assign dig_dig1000_o = (i_dig_dig / 1000) % 10;

endmodule

module mux_41 (
    input  wire [1:0] i_mul_sel,
    input  wire [3:0] i_mul_x0,
    input  wire [3:0] i_mul_x1,
    input  wire [3:0] i_mul_x2,
    input  wire [3:0] i_mul_x3,
    output reg  [3:0] mul_y_o
);

    always @(*) begin
        case (i_mul_sel)
            2'b00:   mul_y_o = i_mul_x0;
            2'b01:   mul_y_o = i_mul_x1;
            2'b10:   mul_y_o = i_mul_x2;
            2'b11:   mul_y_o = i_mul_x3;
            default: mul_y_o = 4'bx;
        endcase
    end

endmodule
ra_mi