|
|
/*********************************************************/
// 모듈: 링크 송수신 로직 블럭
// 파일이름:.v
// 버젼 : 1.0
// 날짜 : 2026.06.26
// 저자 : 탁 형옥
// 코딩 언어 : verilog
// 문제 내용 (해결해야 할 목표):
SOF+LEN+DATA+CRC+EOF 프레임 구조를 갖는 패킷의 송신 및 수신
// 요구되는 언어 기술 (어려운 점):
직렬화 패킷을 수신하여 수신 Fifo 에 정렬하여 쓰기
tx 를 가변 시간 만큼 지연을 주어서 rx 에 연결시에도 정상 동작함을 확인한다.
수신데이터 정렬을 정확히 하기 위한 방법을 생각해본다.
// 목표와 기술을 도달하기 위한 알아야 할 기술(문법), 어려운 점, 문제점 극복 과정:
시스템베릴로그 자료형을 이용하여 상태 표현 , 카나나 도움 받음
// 결과 도출:
LEN이 3인 패킷의 12,34,56을 수신 메모리에 저장됨을 확인함.
// 기본 목표 과제를 한층 더 깊이 있게 하기 위한 생각:
640Mbps 속도로 직렬화 하여 보냄 사용자가 80MB/s의 속도로 송신 : 타이밍 바이얼레이션 발생
100 Mbps 속도로 직렬화 보냄 사용자가 12.5MB/s 의 속도로 송신 : 타이밍 만족함.
// 이용 가능한 분야:
사용자 프로토콜 설계에 의한 100Mbps 의 데이터 링크
// 기술과 트렌드:
// 설명 :
//
/*********************************************************/
module uart_packet_tx (
input wire clk,
output wire clk1,
output wire clk2,
input wire rst_n,
input wire data_valid,
input wire [7:0] data_in,
input wire [7:0] data_len, // 전체 데이터 길이
output reg frame_valid,
output reg [7:0] frame_out,
output reg tx
);
localparam IDLE = 3'd0,
SOF = 3'd1,
LEN = 3'd2,
DATA = 3'd3,
CRC = 3'd4,
EOF = 3'd5;
reg [2:0] state, next_state;
reg [7:0] data_cnt;
reg [7:0] data_buf[255:0];
integer i;
wire clk_640MHz, clk_80MHz,clk_99_8MHz;
wire clk2;
reg clk2_r;
clk_wiz_0 CLOCK
(
// Clock out ports
.clk_out1(clk_640MHz),
.clk_out2(clk_80MHz),
.clk_out3(clk_99_8MHz),
// Status and control signals
.reset(reset),
.locked(locked),
// Clock in ports
.clk_in1(clk)
);
assign clk1=clk_640MHz;
assign clk2=clk_80MHz;
always @(negedge clk1)
clk2_r<=~clk2;
// 데이터 버퍼에 저장
always @(posedge clk1 or negedge rst_n) begin
if (!rst_n) begin
for (i = 0; i < 256; i = i + 1)
data_buf[i] <= 8'd0;
data_cnt <= 8'd0;
end else if (data_valid && data_cnt < data_len) begin
data_buf[data_cnt] <= data_in;
// if((clk2_r==1'b0)&&(clk2==1'b1))
data_cnt <= data_cnt + 1;
end
end
// 상태 전이
always @(posedge clk2 or negedge rst_n) begin
if (!rst_n) state <= IDLE;
else state <= next_state;
end
// 상태 결정
always @(*) begin
case (state)
IDLE: next_state = (data_cnt == data_len) ? SOF : IDLE;
SOF: next_state = LEN;
LEN: next_state = DATA;
DATA: next_state = (data_cnt == 0) ? CRC : DATA;
CRC: next_state = EOF;
EOF: next_state = IDLE;
default: next_state = IDLE;
endcase
end
// 출력 제어
reg [7:0] out_cnt;
reg [7:0] frame;
reg [7:0] crc_check;
reg [2:0] bcnt;
always @(posedge clk1)
begin
if (!rst_n)
bcnt<=0;
else if(state==IDLE)
begin
bcnt<=0;
crc_check<=0;
end
else
bcnt<=bcnt+1'b1;
if(!rst_n)
tx<=1'b0;
else if(bcnt==3'b000)
begin
frame<=frame_out;
crc_check^=frame_out;
tx<=frame_out[7];
end
else
{tx,frame[6:1]}<=frame[7:0];
end
always @(posedge clk2 or negedge rst_n) begin
if (!rst_n) begin
frame_valid <= 1'b0;
frame_out <= 8'd0;
out_cnt <= 8'd0;
end else begin
case (state)
SOF: begin
frame_valid <= 1'b1;
frame_out <= 8'h55;
end
LEN: begin
frame_valid <= 1'b1;
frame_out <= data_len;
out_cnt <= 8'd0;
end
DATA: begin
if (out_cnt < data_len) begin
frame_valid <= 1'b1;
frame_out <= data_buf[out_cnt];
out_cnt <= out_cnt + 1;
data_cnt <= data_cnt - 1;
end else begin
// frame_valid <= 1'b0;
frame_out <= crc_check;
frame_valid <=1'b1;
end
end
CRC: begin
frame_valid <= 1'b1;
//frame_out <= crc_check;
frame_out <= 8'hAA;
end
EOF: begin
frame_valid <= 1'b1;
frame_out <= 8'h00;
end
default: begin
frame_valid <= 1'b0;
frame_out <= 8'd0;
end
endcase
end
end
endmodule
`timescale 1ns/100ps
module tb_uart_packet;
reg clk, rst_n;
reg data_valid;
reg [7:0] data_in;
reg [7:0] data_len;
wire frame_valid;
wire [7:0] frame_out;
wire [7:0] fifo_dout;
wire rx;
wire fifo_empty;
reg fifo_rd_en;
wire packet_valid;
uart_packet_tx Tx_dut (
.clk(clk),
.clk1(clk1),
.clk2(clk2),
.rst_n(rst_n),
.data_valid(data_valid),
.data_in(data_in),
.data_len(data_len),
.frame_valid(frame_valid),
.frame_out(frame_out),
.tx(tx)
);
assign rx = tx;
uart_packet_rx2 Rx_dut (
.clk(clk1),
.clk2(clk2),
.rst_n(rst_n),
.rx(rx), // 직렬 입력
.fifo_dout(fifo_dout), // FIFO 데이터 출력
.fifo_empty(fifo_empty), // FIFO 비어있음 플래그
.fifo_rd_en(fifo_rd_en), // 사용자 읽기 요청
.packet_valid(packet_valid) // 유효 패킷 수신 완료 플래그
);
// 클록 생성
initial clk = 0;
always #5 clk = ~clk;
initial begin
rst_n = 0; data_valid = 0; data_in = 0; data_len = 0;
fifo_rd_en =1'b0;
#600;
rst_n = 1;
// 데이터 입력 예시: 3바이트 (0x12, 0x34, 0x56)
data_len = 8'd3;
repeat(2) @(posedge clk1);
data_in = 8'h12; data_valid = 1;
@(posedge clk1);
data_in = 8'h34;
@(posedge clk1);
data_in = 8'h56;
@(posedge clk1);
data_valid = 0;
// 프레임 출력 대기
#200;
fifo_rd_en =1'b1;
#10 fifo_rd_en =1'b0;
fifo_rd_en =1'b1;
#10 fifo_rd_en =1'b0;
// $finish;
end
// 출력 모니터링
always @(posedge clk) begin
if (frame_valid)
$display("Time %0t: frame_out = 0x%02X", $time, frame_out);
end
endmodule
|
|
