[VerilogHDL] C&Verilog차이, SystemVerilog 기본, 8bit Adder FND, 만진 카운터VerilogHDL/Study2024. 5. 16. 02:20
Table of Contents
1. C언어 vs Verilog
1. C언어 : Sequential(잇달아)
→ Polling 방식으로 위에서부터 아래로 차례대로 실행
2. Verilog : Concurrency(동시성)
→ 동시 실행
2. 8bit Adder FND
2-1. 8bit Adder 만들기
더보기
`timescale 1ns / 1ps
module Adder_8bit (
input [7:0] a,
input [7:0] b,
input cin,
output [7:0] sum,
output co
);
wire w_carry0;
Adder_4bit U_4bitAdder0 (
.a (a[3:0]),
.b (b[3:0]),
.cin(cin),
.sum(sum[3:0]),
.co (w_carry0)
);
Adder_4bit U_4bitAdder1 (
.a (a[7:4]),
.b (b[7:4]),
.cin(w_carry0),
.sum(sum[7:4]),
.co (co)
);
endmodule
module Adder_4bit (
input [3:0] a,
input [3:0] b,
input cin,
output [3:0] sum,
output co
);
wire [2:0] w_carry;
fullAdder U_FA0 (
.a (a[0]),
.b (b[0]),
.cin(cin),
.sum(sum[0]),
.co (w_carry[0])
);
fullAdder U_FA1 (
.a (a[1]),
.b (b[1]),
.cin(w_carry[0]),
.sum(sum[1]),
.co (w_carry[1])
);
fullAdder U_FA2 (
.a (a[2]),
.b (b[2]),
.cin(w_carry[1]),
.sum(sum[2]),
.co (w_carry[2])
);
fullAdder U_FA3 (
.a (a[3]),
.b (b[3]),
.cin(w_carry[2]),
.sum(sum[3]),
.co (co)
);
endmodule
module halfAdder (
input a,
input b,
output sum,
output carry
);
assign sum = a ^ b;
assign carry = a & b;
endmodule
module fullAdder (
input a,
input b,
input cin,
output sum,
output co
);
wire w_sum1, w_carry1, w_carry2;
halfAdder U_HA1 (
.a(a),
.b(b),
.sum (w_sum1),
.carry(w_carry1)
);
halfAdder U_HA2 (
.a(w_sum1),
.b(cin),
.sum (sum),
.carry(w_carry2)
);
assign co = w_carry1 | w_carry2;
endmodule
2-2. 8bit Adder 검증(System Verilog)
[System Verilog 검증]
`timescale 1ns / 1ps
class transaction;
rand logic [7:0] a;
rand logic [7:0] b;
endclass // transaction
module tb_adder ();
transaction trans;
logic [7:0] a, b, sum;
logic co;
Adder_8bit dut (
.a (a),
.b (b),
.cin(1'b0),
.sum(sum),
.co (co)
);
initial begin
trans = new();
repeat (100) begin
trans.randomize();
a = trans.a;
b = trans.b;
#10;
$display("%t : a(%d) + b(%d) = sum(%d)", $time, trans.a, trans.b, {co, sum}); // 비트 결합 연산자
if ((trans.a + trans.b) == {co, sum}) $display("plssed!");
else $display("failed!");
end
end
endmodule
위와 같이 8bit Adder가 정상 동작하는 것을 확인할 수 있음.
2-3. 8bit Adder FND 출력
더보기
`timescale 1ns / 1ps
module fndContorller (
input clk,
input [13:0] digit,
input [1:0] fndSel,
output [7:0] fndFont,
output [3:0] fndCom
);
wire [3:0] w_digit_1, w_digit_10, w_digit_100, w_digit_1000;
wire [3:0] w_digit;
wire [1:0] w_count;
counter U_Counter_2bit (
.clk (clk),
.count(w_count)
);
Adder_Decoder U_Decoder_2x4 (
.fndSel(w_count),
.fndCom(fndCom)
);
digitSplitter U_DigitSplitter (
.i_digit(digit),
.o_digit_1(w_digit_1),
.o_digit_10(w_digit_10),
.o_digit_100(w_digit_100),
.o_digit_1000(w_digit_1000)
);
mux U_Mux_4x1 (
.sel(w_count),
.x0 (w_digit_1),
.x1 (w_digit_10),
.x2 (w_digit_100),
.x3 (w_digit_1000),
.y(w_digit)
);
BDCtoSEG U_BcdToSeg (
.bcd(w_digit),
.seg(fndFont)
);
endmodule
module digitSplitter (
input [13:0] i_digit,
output [3:0] o_digit_1,
output [3:0] o_digit_10,
output [3:0] o_digit_100,
output [3:0] o_digit_1000
);
assign o_digit_1 = i_digit % 10;
assign o_digit_10 = i_digit / 10 % 10;
assign o_digit_100 = i_digit / 100 % 10;
assign o_digit_1000 = i_digit / 1000 % 10;
endmodule
module mux (
input [1:0] sel,
input [3:0] x0,
input [3:0] x1,
input [3:0] x2,
input [3:0] x3,
output reg [3:0] y
);
always @(*) begin // * : 모든 변수 감시
case (sel)
2'b00: y = x0;
2'b01: y = x1;
2'b10: y = x2;
2'b11: y = x3;
default: y = x0;
endcase
end
endmodule
module BDCtoSEG (
input [3:0] bcd,
output reg [7:0] seg
);
always @(bcd) begin
case (bcd)
4'h0: seg = 8'hc0;
4'h1: seg = 8'hf9;
4'h2: seg = 8'ha4;
4'h3: seg = 8'hb0;
4'h4: seg = 8'h99;
4'h5: seg = 8'h92;
4'h6: seg = 8'h82;
4'h7: seg = 8'hf8;
4'h8: seg = 8'h80;
4'h9: seg = 8'h90;
4'ha: seg = 8'h88;
4'hb: seg = 8'h83;
4'hc: seg = 8'hc6;
4'hd: seg = 8'ha1;
4'he: seg = 8'h86;
4'hf: seg = 8'h8e;
default: seg = 8'hff;
endcase
end
endmodule
module Adder_Decoder (
input [1:0] fndSel,
output reg [3:0] fndCom
);
always @(fndSel) begin
case (fndSel)
2'b00: fndCom = 4'b1110;
2'b01: fndCom = 4'b1101;
2'b10: fndCom = 4'b1011;
2'b11: fndCom = 4'b0111;
default: fndCom = 4'b1111;
endcase
end
endmodule
module counter (
input clk,
output [1:0] count
);
reg [1:0] counter = 0;
assign count = counter;
always @(posedge clk) begin
if (counter == 3) begin
counter <= 0;
end else begin
counter <= counter + 1;
end
end
endmodule
[Adder8bit_FND]
`timescale 1ns / 1ps
module Adder_fnd (
input clk,
input [7:0] a,
input [7:0] b,
output [3:0] fndCom,
output [7:0] fndFont
);
wire [7:0] w_sum;
wire w_carry;
Adder_8bit U_Adder (
.a (a),
.b (b),
.cin(1'b0),
.sum(w_sum),
.co (w_carry)
);
fndContorller U_FndController (
.clk(clk),
.fndSel(fndSel),
.digit ({5'b0, w_carry, w_sum}),
.fndFont(fndFont),
.fndCom (fndCom)
);
endmodule
결과
3. FND 계속 출력되도록 설계
3-1. counter 설계
- 매 clk마다 다른 FND 출력 → FND Select 버튼 대신 clk을 FND Select로 사용 → FND가 꺼지지 않고 계속 출력됨
구현
[Counter]
module counter #(
parameter MAX_COUNT = 4 // define
) (
input clk,
output [1:0] count
);
reg [1:0] counter = 0;
assign count = counter;
always @(posedge clk) begin // posedge : rising edge
if (counter == (MAX_COUNT - 1)) begin
counter <= 0;
end else begin
counter <= counter + 1;
end
end
endmodule
- `<=` : Non-blocking 방식의 등호라고 생각하면 된다.
- Verilog의 특징인 동시성때문에 `=` 의 blocking 방식을 사용하면 a=1, b=a 일 때 b=x가 된다.
- (두개 식이 동시에 진행되기 때문에 a의 값이 아직 결정되지 않았기 때문)
더보기
`timescale 1ns / 1ps
module fndContorller (
input clk,
input [13:0] digit,
output [7:0] fndFont,
output [3:0] fndCom
);
wire [3:0] w_digit_1, w_digit_10, w_digit_100, w_digit_1000;
wire [3:0] w_digit;
wire [1:0] w_count;
counter #(.MAX_COUNT(4)) U_Counter_2bit (
.clk (w_clk_1khz),
.count(w_count)
);
Adder_Decoder U_Decoder_2x4 (
.fndSel(w_count),
.fndCom(fndCom)
);
digitSplitter U_DigitSplitter (
.i_digit(digit),
.o_digit_1(w_digit_1),
.o_digit_10(w_digit_10),
.o_digit_100(w_digit_100),
.o_digit_1000(w_digit_1000)
);
mux U_Mux_4x1 (
.sel(w_count),
.x0 (w_digit_1),
.x1 (w_digit_10),
.x2 (w_digit_100),
.x3 (w_digit_1000),
.y(w_digit)
);
BDCtoSEG U_BcdToSeg (
.bcd(w_digit),
.seg(fndFont)
);
endmodule
module digitSplitter (
input [13:0] i_digit,
output [3:0] o_digit_1,
output [3:0] o_digit_10,
output [3:0] o_digit_100,
output [3:0] o_digit_1000
);
assign o_digit_1 = i_digit % 10;
assign o_digit_10 = i_digit / 10 % 10;
assign o_digit_100 = i_digit / 100 % 10;
assign o_digit_1000 = i_digit / 1000 % 10;
endmodule
module mux (
input [1:0] sel,
input [3:0] x0,
input [3:0] x1,
input [3:0] x2,
input [3:0] x3,
output reg [3:0] y
);
always @(*) begin // * : 모든 변수 감시
case (sel)
2'b00: y = x0;
2'b01: y = x1;
2'b10: y = x2;
2'b11: y = x3;
default: y = x0;
endcase
end
endmodule
module BDCtoSEG (
input [3:0] bcd,
output reg [7:0] seg
);
always @(bcd) begin
case (bcd)
4'h0: seg = 8'hc0;
4'h1: seg = 8'hf9;
4'h2: seg = 8'ha4;
4'h3: seg = 8'hb0;
4'h4: seg = 8'h99;
4'h5: seg = 8'h92;
4'h6: seg = 8'h82;
4'h7: seg = 8'hf8;
4'h8: seg = 8'h80;
4'h9: seg = 8'h90;
4'ha: seg = 8'h88;
4'hb: seg = 8'h83;
4'hc: seg = 8'hc6;
4'hd: seg = 8'ha1;
4'he: seg = 8'h86;
4'hf: seg = 8'h8e;
default: seg = 8'hff;
endcase
end
endmodule
module Adder_Decoder (
input [1:0] fndSel,
output reg [3:0] fndCom
);
always @(fndSel) begin
case (fndSel)
2'b00: fndCom = 4'b1110;
2'b01: fndCom = 4'b1101;
2'b10: fndCom = 4'b1011;
2'b11: fndCom = 4'b0111;
default: fndCom = 4'b1111;
endcase
end
endmodule
module counter (
input clk,
output [1:0] count
);
reg [1:0] counter = 0;
assign count = counter;
always @(posedge clk) begin
if (counter == 3) begin
counter <= 0;
end else begin
counter <= counter + 1;
end
end
endmodule
더보기
`timescale 1ns / 1ps
module Adder_fnd (
input clk,
input [7:0] a,
input [7:0] b,
output [3:0] fndCom,
output [7:0] fndFont
);
wire [7:0] w_sum;
wire w_carry;
Adder_8bit U_Adder (
.a (a),
.b (b),
.cin(1'b0),
.sum(w_sum),
.co (w_carry)
);
fndContorller U_FndController (
.clk(clk),
.fndSel(fndSel),
.digit ({5'b0, w_carry, w_sum}),
.fndFont(fndFont),
.fndCom (fndCom)
);
endmodule
결과
⇒ 너무 clk이 빨라서(100MHz) 제대로 안보임
→ Prescaler 만들어 클럭의 속도를 조절해보자!
3-2. Prescaler 설계
- 100MHz의 clk을 1kHz로 만들기
구현
[Prescaler]
module clkDiv #(
parameter MAX_COUNT = 100_000
) (
input clk,
output o_clk
);
reg [$clog2(MAX_COUNT)-1:0] counter = 0; // 17bit <- clog : 2의 n승 : 100000, n : 17(0부터 시작이므로 17-1)
reg r_tick = 0;
assign o_clk = r_tick;
always @(posedge clk) begin // 1kHz, posedge : rising edge
if (counter == (MAX_COUNT - 1)) begin
counter <= 0;
r_tick <= 1'b1; // clk이 100 000 000 일때 1, 나머지는 0
end else begin
counter <= counter + 1;
r_tick <= 1'b0;
end
end
endmodule
더보기
`timescale 1ns / 1ps
module fndContorller (
input clk,
input [13:0] digit,
output [7:0] fndFont,
output [3:0] fndCom
);
wire [3:0] w_digit_1, w_digit_10, w_digit_100, w_digit_1000;
wire [3:0] w_digit;
wire [1:0] w_count;
wire w_clk_1khz;
clkDiv #(.MAX_COUNT(100_000)) U_ClkDiv (
.clk(clk),
.o_clk(w_clk_1khz)
);
counter #(.MAX_COUNT(4)) U_Counter_2bit (
.clk (w_clk_1khz),
.count(w_count)
);
Adder_Decoder U_Decoder_2x4 (
.fndSel(w_count),
.fndCom(fndCom)
);
digitSplitter U_DigitSplitter (
.i_digit(digit),
.o_digit_1(w_digit_1),
.o_digit_10(w_digit_10),
.o_digit_100(w_digit_100),
.o_digit_1000(w_digit_1000)
);
mux U_Mux_4x1 (
.sel(w_count),
.x0 (w_digit_1),
.x1 (w_digit_10),
.x2 (w_digit_100),
.x3 (w_digit_1000),
.y(w_digit)
);
BDCtoSEG U_BcdToSeg (
.bcd(w_digit),
.seg(fndFont)
);
endmodule
module digitSplitter (
input [13:0] i_digit,
output [3:0] o_digit_1,
output [3:0] o_digit_10,
output [3:0] o_digit_100,
output [3:0] o_digit_1000
);
assign o_digit_1 = i_digit % 10;
assign o_digit_10 = i_digit / 10 % 10;
assign o_digit_100 = i_digit / 100 % 10;
assign o_digit_1000 = i_digit / 1000 % 10;
endmodule
module mux (
input [1:0] sel,
input [3:0] x0,
input [3:0] x1,
input [3:0] x2,
input [3:0] x3,
output reg [3:0] y
);
always @(*) begin // * : 모든 변수 감시
case (sel)
2'b00: y = x0;
2'b01: y = x1;
2'b10: y = x2;
2'b11: y = x3;
default: y = x0;
endcase
end
endmodule
module BDCtoSEG (
input [3:0] bcd,
output reg [7:0] seg
);
always @(bcd) begin
case (bcd)
4'h0: seg = 8'hc0;
4'h1: seg = 8'hf9;
4'h2: seg = 8'ha4;
4'h3: seg = 8'hb0;
4'h4: seg = 8'h99;
4'h5: seg = 8'h92;
4'h6: seg = 8'h82;
4'h7: seg = 8'hf8;
4'h8: seg = 8'h80;
4'h9: seg = 8'h90;
4'ha: seg = 8'h88;
4'hb: seg = 8'h83;
4'hc: seg = 8'hc6;
4'hd: seg = 8'ha1;
4'he: seg = 8'h86;
4'hf: seg = 8'h8e;
default: seg = 8'hff;
endcase
end
endmodule
module Adder_Decoder (
input [1:0] fndSel,
output reg [3:0] fndCom
);
always @(fndSel) begin
case (fndSel)
2'b00: fndCom = 4'b1110;
2'b01: fndCom = 4'b1101;
2'b10: fndCom = 4'b1011;
2'b11: fndCom = 4'b0111;
default: fndCom = 4'b1111;
endcase
end
endmodule
module counter #(
parameter MAX_COUNT = 4 // define
) (
input clk,
output [1:0] count
);
reg [1:0] counter = 0;
assign count = counter;
always @(posedge clk) begin
if (counter == MAX_COUNT - 1) begin
counter <= 0;
end else begin
counter <= counter + 1;
end
end
endmodule
module clkDiv #(
parameter MAX_COUNT = 100
) (
input clk,
output o_clk
);
reg [$clog2(MAX_COUNT)-1:0] counter = 0; // 17bit <- clog : 2의 n승 : 100000, n : 17(0부터 시작이므로 17-1)
reg r_tick = 0;
always @(posedge clk) begin // 1kHz
if (counter == (MAX_COUNT - 1)) begin
counter <= 0;
r_tick <= 1'b1; // clk이 100 000 000 일때 1, 나머지는 0
end else begin
counter <= counter + 1;
r_tick <= 1'b0;
end
end
endmodule
더보기
`timescale 1ns / 1ps
module Adder_fnd (
input clk,
input [7:0] a,
input [7:0] b,
output [3:0] fndCom,
output [7:0] fndFont
);
wire [7:0] w_sum;
wire w_carry;
Adder_8bit U_Adder (
.a (a),
.b (b),
.cin(1'b0),
.sum(w_sum),
.co (w_carry)
);
fndContorller U_FndController (
.clk(clk),
.fndSel(fndSel),
.digit ({5'b0, w_carry, w_sum}),
.fndFont(fndFont),
.fndCom (fndCom)
);
endmodule
결과
4. 만진 카운터
구현
[FND Controller : module counter 수정]
module counter #(
parameter MAX_COUNT = 4 // define
) (
input clk,
output [$clog2(MAX_COUNT)-1:0] count
);
reg [$clog2(MAX_COUNT)-1:0] counter = 0;
assign count = counter;
always @(posedge clk) begin
if (counter == MAX_COUNT - 1) begin
counter <= 0;
end else begin
counter <= counter + 1;
end
end
endmodule
→ output 크기를 늘림
[UpConter_10k]
`timescale 1ns / 1ps
module UpCounter_10k #(
parameter MAX_COUNT = 9999
) (
input clk,
output [3:0] fndCom,
output [7:0] fndFont
);
wire w_clk_10hz;
wire [13:0] w_count_10k;
clkDiv #(
.MAX_COUNT(100_000_00) // 10Hz, 0.1s
) U_ClkDiv_10Hz (
.clk(clk),
.o_clk(w_clk_10hz)
);
counter #(
.MAX_COUNT(10_000) // 10k count
) U_Counter_2bit_10Hz (
.clk (w_clk_10hz),
.count(w_count_10k)
);
fndContorller U_FndController (
.clk (clk),
.digit(w_count_10k),
.fndFont(fndFont),
.fndCom (fndCom)
);
endmodule
결과
4-1. Reset 추가
- 가운데 버튼 reset 기능 추가
구현
더보기
module fndContorller (
input reset,
input clk,
input [13:0] digit,
input [1:0] fndSel,
output [7:0] fndFont,
output [3:0] fndCom
);
wire [3:0] w_digit_1, w_digit_10, w_digit_100, w_digit_1000;
wire [3:0] w_digit;
wire [1:0] w_count;
wire w_clk_1khz;
clkDiv #(
.MAX_COUNT(100_000)
) U_ClkDiv (
.reset(reset),
.clk(clk),
.o_clk(w_clk_1khz)
);
counter #(
.MAX_COUNT(4)
) U_Counter_2bit (
.reset(reset),
.clk (w_clk_1khz),
.count(w_count)
);
...
module counter #(
parameter MAX_COUNT = 4 // define
) (
input clk,
input reset,
output [$clog2(MAX_COUNT)-1:0] count
);
reg [$clog2(MAX_COUNT)-1:0] counter = 0;
assign count = counter;
always @(posedge clk, posedge reset) begin // 리셋 버튼 누르면?
if (reset == 1'b1) begin
counter <= 0;
end else begin
if (counter == MAX_COUNT - 1) begin
counter <= 0;
end else begin
counter <= counter + 1;
end
end
end
endmodule
module clkDiv #(
parameter MAX_COUNT = 100
) (
input clk,
input reset,
output o_clk
);
reg [$clog2(
MAX_COUNT
)-1:0] counter = 0; // 17bit <- clog : 2의 n승 : 100000, n : 17(0부터 시작이므로 17-1)
reg r_tick = 0;
assign o_clk = r_tick;
always @(posedge clk, posedge reset) begin // 리셋 버튼 누르면?
if (reset == 1'b1) begin
counter <= 0;
end else begin
if (counter == (MAX_COUNT - 1)) begin
counter <= 0;
r_tick <= 1'b1; // clk이 100 000 000 일때 1, 나머지는 0
end else begin
counter <= counter + 1;
r_tick <= 1'b0;
end
end
end
endmodule
더보기
`timescale 1ns / 1ps
module UpCounter_10k #(
parameter MAX_COUNT = 9999
) (
input clk,
input reset,
output [3:0] fndCom,
output [7:0] fndFont
);
wire w_clk_10hz;
wire [13:0] w_count_10k;
clkDiv #(
.MAX_COUNT(100_000_00) // 10Hz, 0.1s
) U_ClkDiv_10Hz (
.reset(reset),
.clk(clk),
.o_clk(w_clk_10hz)
);
counter #(
.MAX_COUNT(10_000) // 10k count
) U_Counter_2bit_10Hz (
.reset(reset),
.clk (w_clk_10hz),
.count(w_count_10k)
);
fndContorller U_FndController (
.reset(reset),
.clk (clk),
.digit(w_count_10k),
.fndFont(fndFont),
.fndCom (fndCom)
);
endmodule
결과
→ 리셋 버튼 눌렀을 때(rising edge) 모듈 count 초기화
Made By Minseok KIM
'VerilogHDL > Study' 카테고리의 다른 글
[VerilogHDL] FSM 코딩(Moore, Mealy) - 버튼, UpCounter (0) | 2024.05.19 |
---|---|
[VerilogHDL] 조합 논리 회로 & 순차 논리 회로, Latch & FlipFlop (0) | 2024.05.19 |
[VerilogHDL] System Verilog, 4bit Adder FND 출력 (0) | 2024.05.16 |
[VerilogHDL] HalfAdder, FullAdder, 4bit Adder (0) | 2024.05.09 |
[VerilogHDL] 반도체 칩 설계과정, Vivado 시작하기, 시뮬레이션, Logic Gates (0) | 2024.05.09 |
@민바Minba :: Minba's blog
Let's Be Happy!
도움이 되었으면 좋겠어요 :)