`include"../simple_uart_tx/simple_uart_tx.v"
module simple_uart_rx (
input clk,
input reset_n,
input rx,
output [7:0] rx_data
);
localparam IDLE = 0;
localparam START = 1;
localparam MID = 2;
localparam D0 = 3;
localparam D1 = 4;
localparam D2 = 5;
localparam D3 = 6;
localparam D4 = 7;
localparam D5 = 8;
localparam D6 = 9;
localparam D7 = 10;
localparam STOP = 11;
localparam STOP_1 = 12;
reg rx_delay1;
reg rx_delay2;
reg [3:0] cst;
reg [3:0] nst;
reg [8:0] clk_count;
reg [7:0] rRxdata;
// falling edge detection : initiate 'start' or CDC, Metastability
always @(posedge clk, negedge reset_n) begin
if(!reset_n) begin
rx_delay1 <= 1'b0;
rx_delay2 <= 1'b0;
end
else begin
rx_delay1 <= rx;
rx_delay2 <= rx_delay1;
end
end
wire f_edge_det = !rx_delay1 & rx_delay2;
wire bit_clr_st = f_edge_det & (cst == IDLE);
wire bit_clr_ha = (clk_count == 216) && (cst == START);
wire bit_clr = (clk_count == 433);
//counter
always @(posedge clk, negedge reset_n) begin
if(!reset_n)
clk_count <= 0;
else if (bit_clr_st)
clk_count <= 0;
else if (bit_clr_ha)
clk_count <= 0;
else if (bit_clr)
clk_count <= 0;
else
clk_count <= clk_count + 1;
end
//seq
always @(posedge clk, negedge reset_n) begin
if(!reset_n) begin
cst <= IDLE;
end else
cst <= nst;
end
//comb
always @(*) begin
case (cst)
IDLE : if (f_edge_det) nst = START;
START : if (bit_clr_ha) nst = D0;
D0 : if (bit_clr) nst = D1;
D1 : if (bit_clr) nst = D2;
D2 : if (bit_clr) nst = D3;
D3 : if (bit_clr) nst = D4;
D4 : if (bit_clr) nst = D5;
D5 : if (bit_clr) nst = D6;
D6 : if (bit_clr) nst = D7;
D7 : if (bit_clr) nst = STOP;
STOP : if (bit_clr) nst = IDLE;
default : nst = IDLE;
endcase
end
//output
always @(posedge clk, negedge reset_n) begin
if(!reset_n)
rRxdata <= 0;
else begin
case (cst)
D0 : if (bit_clr) rRxdata[0] = rx;
D1 : if (bit_clr) rRxdata[1] = rx;
D2 : if (bit_clr) rRxdata[2] = rx;
D3 : if (bit_clr) rRxdata[3] = rx;
D4 : if (bit_clr) rRxdata[4] = rx;
D5 : if (bit_clr) rRxdata[5] = rx;
D6 : if (bit_clr) rRxdata[6] = rx;
D7 : if (bit_clr) rRxdata[7] = rx;
//STOP :
endcase
end
end
assign rx_data = rRxdata;
endmodule
//testbench
`timescale 1 ns / 1 ns
module tb_simple_uart_rx ();
reg clk; // design arbitrary pattern
reg reset_n; // design arbitrary pattern
wire tx;
wire [7:0] rx_data;
simple_uart_tx uSimple_uart_tx_0 (
.clk(clk),
.reset_n(reset_n),
.tx(tx)
);
simple_uart_rx uSimple_uart_rx_0 (
.clk(clk),
.reset_n(reset_n),
.rx(tx),
.rx_data(rx_data)
);
// clock gen : design arbitrary pattern
initial begin
clk = 1'b0;
forever #10 clk = ~ clk;
end
// always #10 clk = ~ clk;
// reset_n gen : design arbitrary pattern
initial begin
reset_n = 1'b1;
@(negedge clk);
@(negedge clk);
reset_n = 1'b0;
@(negedge clk);
@(negedge clk);
@(negedge clk);
reset_n = 1'b1;
end
endmodule
// tcl file
vlib work
vlog simple_uart_tx.v simple_uart_rx.v tb_simple_uart_rx.v
vsim work.tb_simple_uart_rx
view wave
add wave -radix unsigned /clk
add wave -radix unsigned /reset_n
add wave -radix unsigned /rx
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/rx
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/rx_delay1
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/rx_delay2
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/f_edge_det
//add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/clk_count
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/bit_clr_st
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/bit_clr_ha
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/cst
add wave -radix unsigned /tb_simple_uart_rx/uSimple_uart_rx_0/nst
run 300 us
Simulation waveform ASCII 'X', 01011000.
상태 변화(STOP, 11 → IDLE, 0) 이후에도 rx_data 값 유지.
simple_uart_tx module 의 ASCII 'X' 가 simple_uart_rx module 내부로 instantiation. Simulation 을 통해 [7:0] rx_data (0101 1000) 를 확인했고, DE1-SoC Board 에 연결하여 7-segment 동작을 확인한다.
//instantiation, 7segment
seven_segment_cntrl uSeven_segment_cntrl_hex1 (
.inp(rRxdata[7:4]),
.seg_a(seg_a),
.seg_b(seg_b),
.seg_c(seg_c),
.seg_d(seg_d),
.seg_e(seg_e),
.seg_f(seg_f),
.seg_g(seg_g)
);
seven_segment_cntrl uSeven_segment_cntrl_hex0 (
.inp(rRxdata[3:0]),
.seg_a(seg_h),
.seg_b(seg_i),
.seg_c(seg_j),
.seg_d(seg_k),
.seg_e(seg_l),
.seg_f(seg_m),
.seg_g(seg_n)
);
simple_uart_tx module 에서 지정한 ASCII 'X' 가 아닌, 임의의 입력에 대한 7segment 출력을 확인하고자 한다.
//`include"../simple_uart_tx/simple_uart_tx.v"
`include"../lab3_2/seven_segment_cntrl.v"
module simple_uart_rx (
input clk,
input reset_n,
input rx,
//output [7:0] rx_data
output seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g,
output seg_h, seg_i, seg_j, seg_k, seg_l, seg_m, seg_n
);
localparam IDLE = 0;
localparam START = 1;
localparam MID = 2;
localparam D0 = 3;
localparam D1 = 4;
localparam D2 = 5;
localparam D3 = 6;
localparam D4 = 7;
localparam D5 = 8;
localparam D6 = 9;
localparam D7 = 10;
localparam STOP = 11;
localparam STOP_1 = 12;
reg rx_delay1;
reg rx_delay2;
reg [3:0] cst = 0;
reg [3:0] nst;
reg [8:0] clk_count = 0;
reg [7:0] rRxdata;
// falling edge detection : initiate 'start' or CDC, Metastability
always @(posedge clk, negedge reset_n) begin
if(!reset_n) begin
rx_delay1 <= 1'b0;
rx_delay2 <= 1'b0;
end
else begin
rx_delay1 <= rx;
rx_delay2 <= rx_delay1;
end
end
wire f_edge_det = !rx_delay1 & rx_delay2;
wire bit_clr_st = f_edge_det & (cst == IDLE);
wire bit_clr_ha = (clk_count == 216) && (cst == START);
wire bit_clr = (clk_count == 433);
//counter
always @(posedge clk, negedge reset_n) begin
if(!reset_n)
clk_count <= 0;
else if (bit_clr_st)
clk_count <= 0;
else if (bit_clr_ha)
clk_count <= 0;
else if (bit_clr)
clk_count <= 0;
else
clk_count <= clk_count + 1;
end
//seq
always @(posedge clk, negedge reset_n) begin
if(!reset_n) begin
cst <= IDLE;
end else
cst <= nst;
end
//comb
always @(*) begin
case (cst)
IDLE : if (f_edge_det) nst = START;
START : if (bit_clr_ha) nst = D0;
D0 : if (bit_clr) nst = D1;
D1 : if (bit_clr) nst = D2;
D2 : if (bit_clr) nst = D3;
D3 : if (bit_clr) nst = D4;
D4 : if (bit_clr) nst = D5;
D5 : if (bit_clr) nst = D6;
D6 : if (bit_clr) nst = D7;
D7 : if (bit_clr) nst = STOP;
STOP : if (bit_clr) nst = IDLE;
default : nst = IDLE;
endcase
end
always @(posedge clk, negedge reset_n) begin
if(!reset_n)
rRxdata <= 0;
else begin
case (cst)
D0 : if (bit_clr) rRxdata[0] <= rx;
D1 : if (bit_clr) rRxdata[1] <= rx;
D2 : if (bit_clr) rRxdata[2] <= rx;
D3 : if (bit_clr) rRxdata[3] <= rx;
D4 : if (bit_clr) rRxdata[4] <= rx;
D5 : if (bit_clr) rRxdata[5] <= rx;
D6 : if (bit_clr) rRxdata[6] <= rx;
D7 : if (bit_clr) rRxdata[7] <= rx;
endcase
end
end
//assign rx_data = rRxdata;
seven_segment_cntrl uSeven_segment_cntrl_hex1 (
.inp(rRxdata[7:4]),
.seg_a(seg_a),
.seg_b(seg_b),
.seg_c(seg_c),
.seg_d(seg_d),
.seg_e(seg_e),
.seg_f(seg_f),
.seg_g(seg_g)
);
seven_segment_cntrl uSeven_segment_cntrl_hex0 (
.inp(rRxdata[3:0]),
.seg_a(seg_h),
.seg_b(seg_i),
.seg_c(seg_j),
.seg_d(seg_k),
.seg_e(seg_l),
.seg_f(seg_m),
.seg_g(seg_n)
);
endmodule
일단 보드 연결하기 전에 simulation 맛보기 Test-bench.
`timescale 1 ns / 1 ns
module simple_uart_rx_tb ();
reg clk;
reg reset_n;
reg rx;
wire seg_a, seg_b, seg_c, seg_d, seg_e, seg_f, seg_g;
wire seg_h, seg_i, seg_j, seg_k, seg_l, seg_m, seg_n;
simple_uart_rx uSimple_uart_rx (
.clk(clk),
.reset_n(reset_n),
.rx(rx),
.seg_a(seg_a),
.seg_b(seg_b),
.seg_c(seg_c),
.seg_d(seg_d),
.seg_e(seg_e),
.seg_f(seg_f),
.seg_g(seg_g),
.seg_h(seg_h),
.seg_i(seg_i),
.seg_j(seg_j),
.seg_k(seg_k),
.seg_l(seg_l),
.seg_m(seg_m),
.seg_n(seg_n)
);
initial begin
clk = 1'b1;
forever #10 clk = ~ clk;
end
initial begin
reset_n = 1'b1;
end
initial begin
rx = 1'b1;
#20000 rx = 1'b0;
#4340 rx = 1'b0;
#8680 rx = 1'b0;
#8680 rx = 1'b0;
#8680 rx = 1'b0;
#8680 rx = 1'b1;
#8680 rx = 1'b1;
#8680 rx = 1'b0;
#8680 rx = 1'b1;
#8680 rx = 1'b0;//ASCII 'X'
#8680 rx = 1'b1;
#8680 rx = 1'b1;//STOP
#8680 rx = 1'b1;
#8680 rx = 1'b0;
#4340 rx = 1'b0;
#8680 rx = 1'b1;
#8680 rx = 1'b0;
#8680 rx = 1'b0;
#8680 rx = 1'b0;
#8680 rx = 1'b0;
#8680 rx = 1'b0;
#8680 rx = 1'b1;
#8680 rx = 1'b0;//ASCII 'A'
#8680 rx = 1'b1;
#8680 rx = 1'b1;//STOP
end
endmodule
ASCII code 출력 확인.
7segment 출력 확인.
rx_data[0] 을 시작으로 rx_data[3] 까지 채워지면 hex0 값(seg_h ~ seg_n) 출력. 이후에 rx_data[7] 까지 모두 채워지면 hex1 값(seg_a ~ seg_g) 까지도 출력.
Board 연결 : Pin Planner, Programmer. (DE1-SoC spec 참고)
띠요옹? 이상한 값이 나와버렸다.
RTL Viewer 를 확인하면 cst 앞에 Latch 가 발생했다.
Latch 들은 Synthesis Tool 에서 자동으로 생성되며, verilog HDL code 내에 지정되어야 하는 모든 조건들 중 일부가 정의되지 않았기 때문에 발생한다.
always @(*) begin
case (cst)
IDLE : if (f_edge_det) nst = START;
START : if (bit_clr_ha) nst = D0;
D0 : if (bit_clr) nst = D1;
D1 : if (bit_clr) nst = D2;
D2 : if (bit_clr) nst = D3;
D3 : if (bit_clr) nst = D4;
D4 : if (bit_clr) nst = D5;
D5 : if (bit_clr) nst = D6;
D6 : if (bit_clr) nst = D7;
D7 : if (bit_clr) nst = STOP;
STOP : if (bit_clr) nst = IDLE;
default : nst = IDLE;
endcase
end
위와 같은 IF 문에서 가능한 조건들에 대하여 모두 동작정의가 되어 있지 않으면 nst 에 이전 값을 저장하는 Latch 가 자동으로 합성된다. Latch 는 Clock Edge 기반의 Synchronous 동작이 아닌 level sensitive, Asynchronous 동작이다. 따라서, Timing 관점에서 문제가 발생한다.
always @(*) begin
case (cst)
IDLE : if (f_edge_det) nst = START; else nst = IDLE;
START : if (bit_clr_ha) nst = D0; else nst = START;
D0 : if (bit_clr) nst = D1; else nst = D0;
D1 : if (bit_clr) nst = D2; else nst = D1;
D2 : if (bit_clr) nst = D3; else nst = D2;
D3 : if (bit_clr) nst = D4; else nst = D3;
D4 : if (bit_clr) nst = D5; else nst = D4;
D5 : if (bit_clr) nst = D6; else nst = D5;
D6 : if (bit_clr) nst = D7; else nst = D6;
D7 : if (bit_clr) nst = STOP; else nst = D7;
STOP : if (bit_clr) nst = IDLE; else nst = STOP;
default : nst = IDLE;
endcase
end
뾰로롱~
RTL Viewer 도 깔끔하게 나왔다.
//Latch generation
always @(*) begin
if(!reset_n)
rRxdata = 0;
else begin
case (cst)
D0 : if (bit_clr) rRxdata[0] = rx;
D1 : if (bit_clr) rRxdata[1] = rx;
D2 : if (bit_clr) rRxdata[2] = rx;
D3 : if (bit_clr) rRxdata[3] = rx;
D4 : if (bit_clr) rRxdata[4] = rx;
D5 : if (bit_clr) rRxdata[5] = rx;
D6 : if (bit_clr) rRxdata[6] = rx;
D7 : if (bit_clr) rRxdata[7] = rx;
endcase
end
end
always @(posedge clk, negedge reset_n) begin
if(!reset_n)
rRxdata <= 0;
else begin
case (cst)
D0 : if (bit_clr) rRxdata[0] <= rx;
D1 : if (bit_clr) rRxdata[1] <= rx;
D2 : if (bit_clr) rRxdata[2] <= rx;
D3 : if (bit_clr) rRxdata[3] <= rx;
D4 : if (bit_clr) rRxdata[4] <= rx;
D5 : if (bit_clr) rRxdata[5] <= rx;
D6 : if (bit_clr) rRxdata[6] <= rx;
D7 : if (bit_clr) rRxdata[7] <= rx;
endcase
end
end
위와 같이 always @( ) block 내에서 clk 와 같은 동기화 신호를 Sensitivity list 에 포함시키는 경우, 해당 block 내의 register 나 logic circuit 는 클럭 신호에 의해 동작하는 순차 회로(Sequential Circuit)로 간주된다. 따라서, else 문을 사용하지 않아도 latch 를 생성하지 않는다. 이미 클럭에 의해 트리거(Edge-triggered)되는 순간, 순차 논리에서 if 문이 아닌 모든 조건에 대해 해당 상태가 이전 클럭 사이클에서 저장된 상태를 유지하기 때문이다.
'[Harman] 반도체 설계 > Quartus' 카테고리의 다른 글
Quartus II project - Avalon pwm. (0) | 2023.09.09 |
---|---|
Quartus II project - Verilog HDL Design pptx. (3) | 2023.08.27 |
Quartus II project - Uart Rx Segment [1]. (0) | 2023.08.17 |
Quartus II project - Simple Uart Rx. (0) | 2023.08.16 |
Quartus II Project - Falling Edge Detection. (0) | 2023.08.15 |