|
|
/*********************************************************/
// 모듈: 고속 uart
// 파일이름:uart.v
// 버젼 : 1.0
// 날짜 : 2026.05.26
// 저자 : 탁 형옥
// 코딩 언어 : verilog
// 문제 내용 (해결해야 할 목표):
클럭 주파수를 변경하면 회로에 반영되어 송신 속도가 개선됨을 확인한다.
// 요구되는 언어 기술 (어려운 점):
첫 데이터가 Parity 오류로 Invalid하고 그 이후는 valid 함. 200 MHz 클럭 공급에 대해서 유아트 100Mbps 동작 속도를 갖음.
오류 패턴을 이후에 송신에 정상적으로 송신 확인 (1st 데이터 오류는 동기가 이루어지지 않은 상황에서 송신시도함으로 수신오류가
생기는 것으로 여겨진다.)
// 목표와 기술을 도달하기 위한 알아야 할 기술(문법), 어려운 점, 문제점 극복 과정:
FPGA의 송수신 드라이버 칩이 동작 속도를 지원해야 하며 데이터의 빠른 쓰기 및 읽기에 대한 메모리 읽기 쓰기 시간을 보장해주어야 한다.
// 결과 도출:
400MHz 클럭 공급에 의해 Uart 전송속도 160Mbpps펄스폭 타이밍시뮬레이션 okay
// 기본 목표 과제를 한층 더 깊이 있게 하기 위한 생각:
// 이용 가능한 분야:
// 기술과 트렌드:
// 설명 :
//
/*********************************************************/
`timescale 1ns/100ps
module uart_top(
input clk,
input rstn,
input [7:0] data_in,
input send,
output tx,
output busy,
input rx,
output [7:0] data_out,
output valid
);
parameter CLK_FREQ = 200_000_000;
// localparam BAUD_RATE = 115200;
parameter BAUD_RATE = 100_000_000;
parameter BAUD_DIV = CLK_FREQ / BAUD_RATE;
parameter HALF_BAUD_RATE = BAUD_DIV / 2;
wire clk_o1,clk_o2;
clk_wiz_0 clock
(
.clk_out1(clk_o1),
.clk_out2(clk_o2),
.reset(reset),
.locked(locked),
// Clock in ports
.clk_in1(clk)
);
wire clk_o;
assign clk_o = clk_o2;
uart_tx #(.CLK_FREQ(CLK_FREQ),
.BAUD_RATE(BAUD_RATE)) TX
(
.clk(clk_o),
.rstn(rstn),
.data_in(data_in),
.send(send),
.tx(tx),
.busy(busy)
);
uart_rx2
#(
.CLK_FREQ (CLK_FREQ),
.BAUD_RATE (BAUD_RATE)
) RX
(
.clk(clk_o),
.rstn(rstn),
.rx(rx),
.data_out(data_out),
.valid(valid)
);
endmodule
module uart_tx
#(
parameter CLK_FREQ = 100_000_000,
parameter BAUD_RATE = 115200
)
(
input wire clk,
input wire rstn,
input wire [7:0] data_in,
input wire send,
output reg tx,
output reg busy
);
localparam BAUD_DIV = CLK_FREQ / BAUD_RATE;
localparam SEND=1'b1, IDLE=1'b0;
reg [11:0] cnt;
reg [10:0] s_r;
reg parity;
reg ST;
wire [0:7] rdata ={data_in[0],data_in[1],data_in[2],data_in[3],data_in[4],data_in[5],data_in[6],data_in[7]};
wire clk_en;
assign clk_en = (cnt==(BAUD_DIV-1)) ?1'b1 :1'b0;
always @(posedge clk)
begin
if(rstn==1'b0)
begin
cnt<=0;
end
else if(cnt<(BAUD_DIV-1))
cnt<=cnt+1'b1;
else
begin
cnt<=0;
// fabric_generated clock clk_b <=~clk_b; not to be recomend
end
end
reg [4:0] scnt;
always @(posedge clk or negedge rstn)
begin
if(rstn==1'b0)
begin
ST<=IDLE;
busy<=1'b0;
end
else if(clk_en==1'b1)
begin
case(ST)
IDLE:
begin
if(send)
begin
parity = ^data_in;
s_r<={1'b0,rdata[0:7],parity,1'b0};
ST<=SEND;
tx<=1'b1;
scnt<=0;
end
else
begin
ST<=IDLE;
tx<=1'b1;
end
busy<=1'b0;
end
SEND:
begin
{tx,s_r}<={s_r,1'b1};
if(scnt<10)
scnt<=scnt+1'b1;
else
ST<=IDLE;
busy<=1'b1;
end
endcase
end
end
endmodule
module uart_rx2
#(
parameter CLK_FREQ = 100_000_000,
parameter BAUD_RATE = 115200
)
(
input wire clk,
input wire rstn,
input wire rx,
output reg [7:0] data_out,
output reg valid
);
localparam BAUD_DIV = CLK_FREQ / BAUD_RATE ;
localparam HALF_BAUD_DIV = BAUD_DIV / 2;
parameter IDLE=3'b000, START=3'b001, DATA=3'b010, STOP=3'b011, DONE=3'b100, CHECK=3'b101;
reg [2:0] st,nstate;
reg [9:0] cnt;
reg [3:0] rcnt;
wire h_bclk_en;
assign h_bclk_en= (cnt==HALF_BAUD_DIV) || (pcnt==HALF_BAUD_DIV);
always @(posedge clk)
begin
if(rstn==1'b0)
st<=IDLE;
else if(h_bclk_en==1'b1)
st<=nstate;
end
always @(posedge clk)
begin
if(rx==1'b0)
cnt<=0;
else if(cnt<(BAUD_DIV-1))
cnt<=cnt+1'b1;
else
cnt<=0;
end
reg [10:0] pcnt;
reg rParity;
always @(posedge clk)
begin
if(rx==1'b1)
pcnt<=0;
else if(pcnt<(BAUD_DIV-1))
pcnt<=pcnt+1'b1;
else
pcnt<=0;
end
always @*
begin
case(st)
IDLE: begin
if(rx==1'b0)
nstate<=START;
else
nstate<=IDLE;
end
START:begin
nstate<=DATA;
end
DATA: begin
if(rcnt<8)
nstate<=DATA;
else
nstate<=CHECK;
end
CHECK: begin
nstate<=STOP;
end
STOP: begin
nstate<=DONE;
end
DONE: begin
nstate<=IDLE;
end
default: begin nstate<= IDLE; end
endcase
end
reg [7:0] rdata_out;
always @*
begin
data_out={rdata_out[0],rdata_out[1],rdata_out[2],rdata_out[3],rdata_out[4],rdata_out[5],rdata_out[6],rdata_out[7]};
end
always @(posedge clk)
begin
if(rstn==1'b0)
rcnt<=0;
else if(h_bclk_en==1'b1 && ((st==DATA)|| (st==START)))
begin
rcnt<=rcnt+1'b1;
end
// else if(h_bclk_en==1'b1 && (st==CHECK))
else if(h_bclk_en==1'b1 && (st==DONE))
begin
valid <= !(^rdata_out ^ rParity);
// valid <=1'b0;
rcnt<=0;
end
else
valid <= 1'b0;
end
always @(posedge clk)
begin
if(rstn==1'b0)
rdata_out <= 8'hff;
else if(h_bclk_en==1'b1 && ((st==DATA)|| (st==START)))
begin
if(rcnt<8)
rdata_out <= {rdata_out[6:0],rx};
end
if(rcnt==8)
rParity<=rx;
end
endmodule
`timescale 1ns/100ps
module tb_uart_top2;
parameter CLK_FREQ = 200_000_000;
// localparam BAUD_RATE = 115200;
parameter BAUD_RATE = 100_000_000;
parameter HALF_BAUD_RATE = CLK_FREQ / BAUD_RATE /2;
reg clk;
reg rstn;
reg [7:0] data_in;
reg send;
wire tx;
wire busy;
reg rx;
wire [7:0] data_out;
wire valid;
uart_top #(.CLK_FREQ(CLK_FREQ),
.BAUD_RATE(BAUD_RATE)) UART
(
.clk(clk),
.rstn(rstn),
.data_in(data_in),
.send(send),
.tx(tx),
.busy(busy),
.rx(rx),
.data_out(data_out),
.valid(valid)
);
assign rx=tx;
//reg [HALF_BAUD_RATE:0] delay;
/*
reg [7:0] delay;
always @(posedge clk)
begin
{rx,delay}={delay,tx};
end
*/
always #5 clk=~clk;
initial
begin
clk=1'b0; rstn=1'b1;
#500; rstn=1'b0;
#100 rstn=1'b1; data_in=8'hA1;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
repeat (3) @(posedge clk);
data_in=8'hA2;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
repeat (3) @(posedge clk);
data_in=8'hA5;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
repeat (3) @(posedge clk);
data_in=8'hA4;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
repeat (3) @(posedge clk);
data_in=8'hFF;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
data_in=8'hFF;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
data_in=8'h0;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
data_in=8'h0;
repeat (2) @(posedge clk); send=1'b1;
repeat (2) @(posedge clk); send=1'b0;
@(negedge busy);
end
endmodule
1) 100MHz clock
1) 200MHz clock
1) 400MHz clock
|
|
