🚩 추상화 (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
'하만 세미콘 아카데미 8기 > verilog 설계' 카테고리의 다른 글
241206 cpu 설계 기초 2 (0) | 2024.12.07 |
---|---|
241205 cpu 설계 기초 (0) | 2024.12.06 |
241106 - verilog 기초 3 (+Counter) (0) | 2024.11.07 |
241104 verilog 기초 1 (+gate, adder) (0) | 2024.11.07 |