文件位置:uart_fiber.srcs/sources_1/new/aurora_top.v
module aurora_top(
input init_clk, // 初始化时钟(通常为50MHz)
output user_clk_i, // Aurora用户时钟输出
output CHANNEL_UP, // Aurora通道建立状态
input RESET, // 复位信号
input GT_RESET_IN, // GTX收发器复位信号
input [15:0] uart_rx, // 16路串口接收数据
output [15:0] uart_tx, // 16路串口发送数据
input GTPQ0_P, // 光纤时钟正端
input GTPQ0_N, // 光纤时钟负端
input RXP, // 光纤接收正端
input RXN, // 光纤接收负端
output TXP, // 光纤发送正端
output TXN // 光纤发送负端
);
input
/output
:定义模块的输入输出端口。[15:0]
:16位总线,表示16路数据。// Aurora AXI-Stream发送接口信号
wire [15:0] tx_tdata_i; // 发送数据
wire tx_tvalid_i; // 发送数据有效
wire tx_tready_i; // 发送数据就绪
wire [1:0] tx_tkeep_i; // 发送数据保持
wire tx_tlast_i; // 发送数据最后
// Aurora AXI-Stream接收接口信号
wire [15:0] rx_tdata_i; // 接收数据
wire rx_tvalid_i; // 接收数据有效
wire [1:0] rx_tkeep_i; // 接收数据保持
wire rx_tlast_i; // 接收数据最后
wire
:声明连线信号,适用于组合逻辑。[15:0]
:16位宽度,适合并行数据。// Aurora 8B/10B IP核实例化
// 该IP核负责底层光纤协议的收发和时钟管理
// 只需连接好接口信号即可,无需关心内部实现
aurora_8b10b_0_exdes inst_aurora_8b10b_0_exdes (
.clk_50m(init_clk), // 50MHz时钟输入
.RESET(RESET), // 复位信号
.GT_RESET_IN(GT_RESET_IN), // GTX收发器复位
.CHANNEL_UP(CHANNEL_UP), // 通道建立状态输出
.GTPQ0_P(GTPQ0_P), // 光纤时钟正端
.GTPQ0_N(GTPQ0_N), // 光纤时钟负端
.RXP(RXP), // 光纤接收正端
.RXN(RXN), // 光纤接收负端
.TXP(TXP), // 光纤发送正端
.TXN(TXN), // 光纤发送负端
.user_clk_i(user_clk_i), // Aurora用户时钟输出
.tx_tdata_i(tx_tdata_i), // 发送数据
.tx_tvalid_i(tx_tvalid_i), // 发送数据有效
.tx_tready_i(tx_tready_i), // 发送数据就绪
.tx_tkeep_i(tx_tkeep_i), // 发送数据保持
.tx_tlast_i(tx_tlast_i), // 发送数据最后
.rx_tdata_i(rx_tdata_i), // 接收数据
.rx_tvalid_i(rx_tvalid_i), // 接收数据有效
.rx_tkeep_i(rx_tkeep_i), // 接收数据保持
.rx_tlast_i(rx_tlast_i) // 接收数据最后
);
inst_aurora_8b10b_0_exdes
:IP核实例名。.端口名(信号名)
:将模块端口与外部信号连接。// Aurora控制模块实例化
// 负责数据缓存、状态机、FIFO、协议转换等核心控制逻辑
aurora_ctrl_mod inst_aurora_ctrl_mod (
.proc_clk(init_clk), // 处理时钟
.user_clk_i(user_clk_i), // Aurora用户时钟
.rst(RESET), // 复位信号
.CHANNEL_UP(CHANNEL_UP), // 通道建立状态
.uart_rx(uart_rx), // 16路串口接收
.uart_tx(uart_tx), // 16路串口发送
.tx_tdata_i(tx_tdata_i), // 发送数据
.tx_tvalid_i(tx_tvalid_i), // 发送数据有效
.tx_tkeep_i(tx_tkeep_i), // 发送数据保持
.tx_tlast_i(tx_tlast_i), // 发送数据最后
.tx_tready_i(tx_tready_i), // 发送数据就绪
.rx_tdata_i(rx_tdata_i), // 接收数据
.rx_tvalid_i(rx_tvalid_i), // 接收数据有效
.rx_tkeep_i(rx_tkeep_i), // 接收数据保持
.rx_tlast_i(rx_tlast_i) // 接收数据最后
);
文件位置:uart_fiber.srcs/sources_1/new/aurora_ctrl_mod.v
module aurora_ctrl_mod #(
parameter D_WIDTH = 16 // 数据宽度参数,默认16位
) (
// 系统接口
input proc_clk, // 处理时钟(如50MHz)
input user_clk_i, // Aurora用户时钟
input CHANNEL_UP, // 通道建立状态
input rst, // 复位信号
// 串口接口
input [15:0] uart_rx, // 16路串口接收
output reg [15:0] uart_tx, // 16路串口发送
// Aurora发送接口
output [D_WIDTH-1:0] tx_tdata_i, // 发送数据
output tx_tvalid_i, // 发送数据有效
output [1:0] tx_tkeep_i, // 发送数据保持
output tx_tlast_i, // 发送数据最后
input tx_tready_i, // 发送数据就绪
// Aurora接收接口
input [D_WIDTH-1:0] rx_tdata_i, // 接收数据
input rx_tvalid_i, // 接收数据有效
input [1:0] rx_tkeep_i, // 接收数据保持
input rx_tlast_i // 接收数据最后
);
parameter
:参数化模块,便于扩展。output reg
:可赋值的输出端口。// 串口接收数据寄存器
reg [15:0] uart_rx_reg;
always@(posedge proc_clk) begin
uart_rx_reg <= uart_rx; // 将输入串口数据寄存,防止亚稳态
end
// 通道状态时钟域同步FIFO
wire channel_up_reg;
fifo_onebit inst_fifo_channelup (
.wr_clk(user_clk_i), // 写时钟(Aurora时钟域)
.rd_clk(proc_clk), // 读时钟(处理时钟域)
.din(CHANNEL_UP), // 通道状态数据
.wr_en(1'b1), // 写使能,始终有效
.rd_en(1'b1), // 读使能,始终有效
.dout(channel_up_reg), // 同步后的通道状态
.full(), // 未用
.empty() // 未用
);
always@(posedge clk)
:时序逻辑,时钟上升沿触发。fifo_onebit
:单比特FIFO,用于跨时钟域同步。reg [15:0] proc_wr_cnt;
always@(posedge proc_clk or posedge rst) begin
if(rst)
proc_wr_cnt <= 'b0; // 复位时清零
else if(channel_up_reg) begin
if(proc_wr_cnt == 16'hffff)
proc_wr_cnt <= proc_wr_cnt; // 保持最大值
else
proc_wr_cnt <= proc_wr_cnt + 1'b1; // 递增
end else
proc_wr_cnt <= 'b0; // 通道未建立时清零
end
assign rs422_in_valid = (proc_wr_cnt == 16'hffff) ? 1'b1 : 1'b0; // 计数器满时产生数据有效信号
assign
:组合逻辑赋值。16'hffff
:16位全1,最大值。// 发送FIFO用于缓存串口数据,实现跨时钟域传输
aurora_tx_rs422_fifo inst_rs422_fifo (
.rst(rst),
.wr_clk(proc_clk),
.rd_clk(user_clk_i),
.din(uart_rx_reg),
.wr_en(rs422_in_valid),
.rd_en(rs422_tx_fifo_rden),
.dout(rs422_tx_fifo_dout),
.full(rs422_tx_fifo_full),
.empty(rs422_tx_fifo_empty),
.prog_empty(rs422_tx_fifo_prog_empty)
);
.wr_clk
/.rd_clk
:写/读时钟,实现跨时钟域。.din
/.dout
:数据输入/输出。.wr_en
/.rd_en
:写/读使能。reg [1:0] state; // 状态机状态
reg [15:0] rd_count; // 读计数器
reg rd_valid_enable; // 读有效使能
always @ (posedge user_clk_i or posedge rst) begin
if(rst) begin
state <= 'b0;
rd_valid_enable <= 'b0;
rd_count <= 2'd0;
end else if(CHANNEL_UP) begin
case(state)
2'd0 : begin // 等待FIFO有数据
if((!rs422_tx_fifo_prog_empty)) begin
state <= 2'd1;
rd_valid_enable <= 1'b0;
rd_count <= 'b0;
end else begin
state <= 'b0;
rd_valid_enable <= 1'b0;
rd_count <= 'b0;
end
end
2'd1 : begin // 发送数据
if(rs422_tx_fifo_rden) begin
if(rd_count == 16'd511) begin
state <= 2'd0;
rd_valid_enable <= 1'b0;
rd_count <= 'b0;
end else begin
state <= 2'd1;
rd_valid_enable <= 1'b1;
rd_count <= rd_count + rs422_tx_fifo_rden;
end
end else begin
state <= 2'd1;
rd_valid_enable <= 1'b1;
rd_count <= rd_count + rs422_tx_fifo_rden;
end
end
endcase
end else begin
state <= 'b0;
rd_valid_enable <= 'b0;
rd_count <= 2'd0;
end
end
case
:多路分支,状态机常用。2'd0
/2'd1
:2位二进制数。rd_valid_enable
:控制FIFO读使能。assign tx_tlast_i = ((rs422_tx_fifo_rden && rd_count == 511) ? 1 : 0); // 最后一个数据包标志
assign rs422_tx_fifo_rden = tx_tready_i && (!rs422_tx_fifo_empty) && rd_valid_enable; // FIFO读使能条件
assign tx_tvalid_i = rs422_tx_fifo_rden; // 发送数据有效信号
assign tx_tdata_i = rs422_tx_fifo_dout; // 发送数据
assign tx_tkeep_i = 2'h3; // 发送数据保持信号(全有效)
tx_tlast_i
:AXI-Stream协议最后数据包标志。tx_tkeep_i
:数据字节有效掩码,2位全1表示16位全有效。请查看“项目实现指南-第二部分-下.md”继续阅读:包括数据接收控制、调试功能、项目总结与技术亮点。