系统寄存器文件刚刚写完,uart_ctrl应该没问题

This commit is contained in:
yangshenbo 2026-04-03 22:02:13 +08:00
parent 281ede8487
commit 9be3e4a483
12 changed files with 1375 additions and 1 deletions

View File

@ -1,7 +1,7 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Engineer: Yangshenbo
//
// version:V1.0
// Create Date: 2026/03/22
//////////////////////////////////////////////////////////////////////////////////

26
rtl/digital_top.v Normal file
View File

@ -0,0 +1,26 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2026/04/03 22:01:15
// Design Name:
// Module Name: digital_top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module digital_top(
);
endmodule

View File

@ -0,0 +1,102 @@
//+FHDR--------------------------------------------------------------------------------------------------------
// 增加一个新寄存器
// SECTION A: 添加 localparam ADDR_NEW = 16'hXX;
// SECTION B: 声明 wire sel_new, we_new, [31:0] reg_new;
// SECTION C: 增加译码逻辑assign sel_new = (reg_idx == ADDR_NEW >> 2);
// SECTION D: 调用底层库例如 sirv_gnrl_dfflr #(32) new_dff (we_new, wrdata, reg_new, clk, rst_n);
// SECTION F: always 块中加入 else if (sel_new) rddata_reg = reg_new;
// SECTION G: reg_new 映射给模块的输出端口
//-FHDR--------------------------------------------------------------------------------------------------------
module system_regfile # (
parameter CHIPCODE = 32'hDA400801,
parameter MFDATE = 32'h20260510
)(
// [BLOCK 0] 系统与总线接口
input clk, // 时钟
input rst_n, // 异步复位 (低有效)
input [31:0] wrdata, // 总线写数据
input wren, // 写使能
input [24:0] rwaddr, // 地址 (Byte Address)
input rden, // 读使能
output [31:0] rddata // 总线读数据
);
// =============================================================================
// [SECTION A] 地址偏移定义 (Localparams)
// =============================================================================
localparam TESTR = 16'h00, DATER = 16'h04;
// =============================================================================
// [SECTION B] 内部连线声明 (Wires)
// =============================================================================
// 寄存器选择信号 (Enable Wires)
wire sel_testr, sel_dater;
// 写使能信号 (Write Enable Wires)
wire we_testr, we_dater;
// 寄存器存储连线 (Storage Wires)
wire [31:0] testr, dater;
// =============================================================================
// [SECTION C] 译码逻辑 (Decoding)
// =============================================================================
assign sel_testr = (rwaddr[15:0] == TESTR );
assign sel_dater = (rwaddr[15:0] == DATER );
// 写使能分配
assign we_testr = sel_testr & wren;
assign we_dater = sel_dater & wren;
// =============================================================================
// [SECTION D] 寄存器实例化 (Storage Implementation)
// =============================================================================
// --- 通用与测试寄存器 ---
sirv_gnrl_dfflrd #(32) testr_dff (32'h01234567, we_testr, wrdata[31:0], testr, clk, rst_n);
sirv_gnrl_dfflrd #(32) sfrtr_dff (32'd20270403, we_dater, wrdata[31:0], dater, clk, rst_n);
// =============================================================================
// [SECTION E] 特殊业务逻辑 (Business Logic)
// =============================================================================
// LVDS 实时状态寄存器
// sirv_gnrl_dffr #(8) lvdssr_inst ({link_down, train_ready, crc_error_r, phase_adj_req_r, phase_tap[2:0], prefilling}, lvdssr, clk, rst_n);
// =============================================================================
// [SECTION F] 读回逻辑 (Readback Mux)
// =============================================================================
reg [31:0] rddata_reg;
always @(*) begin
rddata_reg = 32'b0;
if (sel_testr) rddata_reg = testr;
else if (sel_dater) rddata_reg = dater;
end
sirv_gnrl_dfflr #(32) rddata_out_dff (rden, rddata_reg, rddata, clk, rst_n);
// =============================================================================
// [SECTION G] 输出映射 (Output Assignments)
// =============================================================================
// assign sys_soft_rstn = sys_soft_rstn_r;
// assign sync_oen = syncr[18];
// assign nco_clr = ncoctrlr[2];
// assign nco_en = ncoctrlr[1] & doselr[2];
// assign p2a_en = ncoctrlr[0] & doselr[2];
endmodule

View File

@ -0,0 +1,342 @@
/*
Copyright 2018-2020 Nuclei System Technology, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
//=====================================================================
//
// Designer : Bob Hu
//
// Description:
// All of the general DFF and Latch modules
//
// ====================================================================
//
//
// ===========================================================================
//
// Description:
// Verilog module sirv_gnrl DFF with Load-enable and Reset
// Default reset value is 1
//
// ===========================================================================
`define DISABLE_SV_ASSERTION
`define dly #0.2
module sirv_gnrl_dfflrs # (
parameter DW = 32
) (
input lden,
input [DW-1:0] dnxt,
output [DW-1:0] qout,
input clk,
input rst_n
);
reg [DW-1:0] qout_r;
always @(posedge clk or negedge rst_n)
begin : DFFLRS_PROC
if (rst_n == 1'b0)
qout_r <= {DW{1'b1}};
else if (lden == 1'b1)
qout_r <= `dly dnxt;
end
assign qout = qout_r;
`ifndef FPGA_SOURCE//{
`ifndef DISABLE_SV_ASSERTION//{
//synopsys translate_off
sirv_gnrl_xchecker # (
.DW(1)
) sirv_gnrl_xchecker(
.i_dat(lden),
.clk (clk)
);
//synopsys translate_on
`endif//}
`endif//}
endmodule
// ===========================================================================
//
// Description:
// Verilog module sirv_gnrl DFF with Load-enable and Reset
// Default reset value is 0
//
// ===========================================================================
module sirv_gnrl_dfflr # (
parameter DW = 32
) (
input lden,
input [DW-1:0] dnxt,
output [DW-1:0] qout,
input clk,
input rst_n
);
reg [DW-1:0] qout_r;
always @(posedge clk or negedge rst_n)
begin : DFFLR_PROC
if (rst_n == 1'b0)
qout_r <= {DW{1'b0}};
else if (lden == 1'b1)
qout_r <= `dly dnxt;
end
assign qout = qout_r;
`ifndef FPGA_SOURCE//{
`ifndef DISABLE_SV_ASSERTION//{
//synopsys translate_off
sirv_gnrl_xchecker # (
.DW(1)
) sirv_gnrl_xchecker(
.i_dat(lden),
.clk (clk)
);
//synopsys translate_on
`endif//}
`endif//}
endmodule
// ===========================================================================
//
// Description:
// Verilog module sirv_gnrl DFF with Load-enable and Reset
// Default reset value is input
//
// ===========================================================================
module sirv_gnrl_dfflrd # (
parameter DW = 32
) (
input [DW-1:0] init,
input lden,
input [DW-1:0] dnxt,
output [DW-1:0] qout,
input clk,
input rst_n
);
reg [DW-1:0] qout_r;
always @(posedge clk or negedge rst_n)
begin : DFFLR_PROC
if (rst_n == 1'b0)
qout_r <= init;
else if (lden == 1'b1)
qout_r <= `dly dnxt;
end
assign qout = qout_r;
`ifndef FPGA_SOURCE//{
`ifndef DISABLE_SV_ASSERTION//{
//synopsys translate_off
sirv_gnrl_xchecker # (
.DW(1)
) sirv_gnrl_xchecker(
.i_dat(lden),
.clk (clk)
);
//synopsys translate_on
`endif//}
`endif//}
endmodule
// ===========================================================================
//
// Description:
// Verilog module sirv_gnrl DFF with Load-enable, no reset
//
// ===========================================================================
module sirv_gnrl_dffl # (
parameter DW = 32
) (
input lden,
input [DW-1:0] dnxt,
output [DW-1:0] qout,
input clk
);
reg [DW-1:0] qout_r;
always @(posedge clk)
begin : DFFL_PROC
if (lden == 1'b1)
qout_r <= `dly dnxt;
end
assign qout = qout_r;
`ifndef FPGA_SOURCE//{
`ifndef DISABLE_SV_ASSERTION//{
//synopsys translate_off
sirv_gnrl_xchecker # (
.DW(1)
) sirv_gnrl_xchecker(
.i_dat(lden),
.clk (clk)
);
//synopsys translate_on
`endif//}
`endif//}
endmodule
// ===========================================================================
//
// Description:
// Verilog module sirv_gnrl DFF with Reset, no load-enable
// Default reset value is 1
//
// ===========================================================================
module sirv_gnrl_dffrs # (
parameter DW = 32
) (
input [DW-1:0] dnxt,
output [DW-1:0] qout,
input clk,
input rst_n
);
reg [DW-1:0] qout_r;
always @(posedge clk or negedge rst_n)
begin : DFFRS_PROC
if (rst_n == 1'b0)
qout_r <= {DW{1'b1}};
else
qout_r <= `dly dnxt;
end
assign qout = qout_r;
endmodule
// ===========================================================================
//
// Description:
// Verilog module sirv_gnrl DFF with Reset, no load-enable
// Default reset value is 0
//
// ===========================================================================
module sirv_gnrl_dffr # (
parameter DW = 32
) (
input [DW-1:0] dnxt,
output [DW-1:0] qout,
input clk,
input rst_n
);
reg [DW-1:0] qout_r;
always @(posedge clk or negedge rst_n)
begin : DFFR_PROC
if (rst_n == 1'b0)
qout_r <= {DW{1'b0}};
else
qout_r <= `dly dnxt;
end
assign qout = qout_r;
endmodule
// ===========================================================================
//
// Description:
// Verilog module for general latch
//
// ===========================================================================
module sirv_gnrl_ltch # (
parameter DW = 32
) (
//input test_mode,
input lden,
input [DW-1:0] dnxt,
output [DW-1:0] qout
);
reg [DW-1:0] qout_r;
always @ *
begin : LTCH_PROC
if (lden == 1'b1)
qout_r <= dnxt;
end
//assign qout = test_mode ? dnxt : qout_r;
assign qout = qout_r;
`ifndef FPGA_SOURCE//{
`ifndef DISABLE_SV_ASSERTION//{
//synopsys translate_off
always_comb
begin
CHECK_THE_X_VALUE:
assert (lden !== 1'bx)
else $fatal ("\n Error: Oops, detected a X value!!! This should never happen. \n");
end
//synopsys translate_on
`endif//}
`endif//}
endmodule
// module sirv_gnrl_edffr #(parameter type T = logic) (
// input T dnxt,
// output T qout,
// input clk, rst_n
// );
// T qout_r;
// always_ff @(posedge clk or negedge rst_n) begin
// if (!rst_n) qout_r <= T'('0);
// else qout_r <= `dly dnxt;
// end
// assign qout = qout_r;
// endmodule

111
rtl/uart_byte_rx.v Normal file
View File

@ -0,0 +1,111 @@
module uart_byte_rx #(
parameter CLOCK_FREQ = 50_000_000,
parameter BAUD = 9600
)
(
Clk,
Reset_n,
uart_rx,
Rx_Done,
Rx_Data
);
input Clk;
input Reset_n;
input uart_rx;
output reg Rx_Done;
output reg[7:0]Rx_Data;
parameter MCNT_BAUD = CLOCK_FREQ / BAUD - 1;
reg [7:0]r_Rx_Data;
reg [29:0]baud_div_cnt;
reg en_baud_cnt;
reg [3:0]bit_cnt;
wire w_Rx_Done;
wire nedge_uart_rx;
reg r_uart_rx;
reg dff0_uart_rx,dff1_uart_rx;
//波特率计数器逻辑
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
baud_div_cnt <= 0;
else if(en_baud_cnt)begin
if(baud_div_cnt == MCNT_BAUD)
baud_div_cnt <= 0;
else
baud_div_cnt <= baud_div_cnt + 1'd1;
end
else
baud_div_cnt <= 0;
//UART 信号边沿检测逻辑
always@(posedge Clk)
dff0_uart_rx <= uart_rx;
always@(posedge Clk)
dff1_uart_rx <= dff0_uart_rx;
always@(posedge Clk)
r_uart_rx <= dff1_uart_rx;
assign nedge_uart_rx = (dff1_uart_rx == 0) && (r_uart_rx == 1);
//波特率计数器使能逻辑
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
en_baud_cnt <= 0;
else if(nedge_uart_rx)
en_baud_cnt <= 1;
else if((baud_div_cnt == MCNT_BAUD/2) && (bit_cnt == 0) && (dff1_uart_rx == 1))
en_baud_cnt <= 0;
else if((baud_div_cnt == MCNT_BAUD/2) && (bit_cnt == 9))
en_baud_cnt <= 0;
//位计数器逻辑
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bit_cnt <= 0;
else if((bit_cnt == 9) && (baud_div_cnt == MCNT_BAUD/2))
bit_cnt <= 0;
else if(baud_div_cnt == MCNT_BAUD)
bit_cnt <= bit_cnt + 1'd1;
//位接收逻辑
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
r_Rx_Data <= 8'd0;
else if(baud_div_cnt == MCNT_BAUD/2)begin
case(bit_cnt)
1:r_Rx_Data[0] <= dff1_uart_rx;
2:r_Rx_Data[1] <= dff1_uart_rx;
3:r_Rx_Data[2] <= dff1_uart_rx;
4:r_Rx_Data[3] <= dff1_uart_rx;
5:r_Rx_Data[4] <= dff1_uart_rx;
6:r_Rx_Data[5] <= dff1_uart_rx;
7:r_Rx_Data[6] <= dff1_uart_rx;
8:r_Rx_Data[7] <= dff1_uart_rx;
default: r_Rx_Data <= r_Rx_Data;
endcase
end
//接收完成标志信号
assign w_Rx_Done = (baud_div_cnt == MCNT_BAUD/2) && (bit_cnt == 9);
always@(posedge Clk)
Rx_Done <= w_Rx_Done;
always@(posedge Clk)
if(w_Rx_Done)
Rx_Data <= r_Rx_Data;
endmodule

110
rtl/uart_byte_tx.v Normal file
View File

@ -0,0 +1,110 @@
module uart_byte_tx #(
parameter BAUD = 9600,
parameter CLOCK_FREQ = 50_000_000
)
(
Clk,
Reset_n,
Send_Go,
Data,
uart_tx,
Tx_Done
);
//
input Clk;
input Reset_n;
input Send_Go;
input [7:0]Data;
output reg uart_tx;
output reg Tx_Done;
parameter MCNT_BAUD = CLOCK_FREQ / BAUD - 1;
parameter MCNT_BIT = 10-1;
reg [29:0]baud_div_cnt;
reg en_baud_cnt;
reg [3:0]bit_cnt;
reg [7:0]r_Data;
wire w_Tx_Done;
//波特率计数器 1/9600 *1000000000 / 20 - 1
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
baud_div_cnt <= 0;
else if(en_baud_cnt)begin
if(baud_div_cnt == MCNT_BAUD)
baud_div_cnt <= 0;
else
baud_div_cnt <= baud_div_cnt + 1'd1;
end
else
baud_div_cnt <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
en_baud_cnt <= 0;
else if(Send_Go)
en_baud_cnt <= 1;
else if(w_Tx_Done)
en_baud_cnt <= 0;
//位计数器
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bit_cnt <= 0;
else if(baud_div_cnt == MCNT_BAUD)begin
if(bit_cnt == MCNT_BIT)
bit_cnt <= 0;
else
bit_cnt <= bit_cnt + 1'd1;
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
r_Data <= 0;
else if(Send_Go)
r_Data <= Data;
else
r_Data <= r_Data;
// always@(posedge Clk)
// if(Send_Go)
// r_Data <= Data;
//位发送逻辑
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
uart_tx <= 1'd1;
else if(en_baud_cnt == 0)
uart_tx <= 1'd1;
else begin
case(bit_cnt)
0:uart_tx <= 1'd0;
1:uart_tx <= r_Data[0];
2:uart_tx <= r_Data[1];
3:uart_tx <= r_Data[2];
4:uart_tx <= r_Data[3];
5:uart_tx <= r_Data[4];
6:uart_tx <= r_Data[5];
7:uart_tx <= r_Data[6];
8:uart_tx <= r_Data[7];
9:uart_tx <= 1'd1;
default:uart_tx <= uart_tx;
endcase
end
assign w_Tx_Done = ((bit_cnt == 9) && (baud_div_cnt == MCNT_BAUD));
always@(posedge Clk)
Tx_Done <= w_Tx_Done;
endmodule

121
rtl/uart_ctrl_sysreg.v Normal file
View File

@ -0,0 +1,121 @@
`timescale 1ns / 1ps
module uart_ctrl_sysreg #(
parameter BAUD = 115200,
parameter CLOCK_FREQ = 50_000_000
)(
input clk
,input rst_n
// 串口接口
,input uart_rx
,output uart_tx
//5口
,output reg [31:0] o_wrdata //write data to sram
,output reg [24:0] o_addr //sram address
,output reg o_wren //write enable sram
,output reg o_rden //rden enable sram
,input [31:0] i_rddata //read data from sram
);
// --- uart_top ---
wire [31:0] uart_rx_data;
wire uart_rx_done;
reg [31:0] uart_tx_data;
reg uart_tx_go;
wire uart_tx_done;
uart_top_32bit #(
.BAUD(BAUD),
.CLOCK_FREQ(CLOCK_FREQ)
) uart_32bit_inst (
.Clk(clk), .Reset_n(rst_n),
.Send_Go32(uart_tx_go), .Tx_Data32(uart_tx_data), .Tx_Done32(uart_tx_done),
.uart_tx(uart_tx), .uart_rx(uart_rx),
.Rx_Done32(uart_rx_done), .Rx_Data32(uart_rx_data)
);
// 协议解析寄存器
reg [63:0] cmd_reg;
reg [31:0]wr_data_buff;
reg [19:0] data_bytes_len;
// 状态机定义
reg [2:0] state;
localparam S_IDLE = 3'd0,
S_RX_CMD_L = 3'd1,
S_PARSE = 3'd2,
S_RD_DATA = 3'd3,
S_WR_DATA = 3'd4;
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
state <= 0;
cmd_reg <= 0;
o_wrdata <= 0;
o_wren <= 0;
o_rden <= 0;
uart_tx_go <= 1'b0;
uart_tx_data <= 1'b0;
end
else begin
case(state)
S_IDLE : begin //0
uart_tx_go <= 1'b0;
if(uart_rx_done) begin
cmd_reg[63:32] <= uart_rx_data;
state <= S_RX_CMD_L;
end
end
S_RX_CMD_L : begin //1
if(uart_rx_done)begin
cmd_reg[31:0] <= uart_rx_data;
state <= S_PARSE;
end
end
S_PARSE : begin //2
o_addr <= cmd_reg[56:32];
data_bytes_len <= cmd_reg[19:0];
if(cmd_reg[63] == 1'b1) begin //读指令
o_rden <= 1'b1;
state <= S_RD_DATA;
end
else begin //写指令
state <= S_WR_DATA;
end
end
S_RD_DATA :begin //3
o_rden <= 1'b0;
uart_tx_data <= i_rddata;
uart_tx_go <= 1'b1;
state <= S_IDLE;
end
S_WR_DATA : begin //4
o_wren <= 1'b0;
if(data_bytes_len != 0)begin
if(uart_rx_done) begin
o_wrdata <= uart_rx_data;
o_wren <= 1'b1;
data_bytes_len <= data_bytes_len - 20'd4;
end
end
else begin
state <= S_IDLE;
end
end
endcase
end
end
endmodule

163
rtl/uart_top_32bit.v Normal file
View File

@ -0,0 +1,163 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer: yangshenbo
//
// Create Date: 2026/03/31 10:53:24
// Design Name:
// Module Name: uart_top_32bit
//
//////////////////////////////////////////////////////////////////////////////////
module uart_top_32bit #(
parameter BAUD = 9600,
parameter CLOCK_FREQ = 50_000_000
)
(
input Clk,
input Reset_n,
// 32位发送接口
input Send_Go32, // 32位发送启动脉冲
input [31:0] Tx_Data32, // 待发送的32位数据
output Tx_Done32, // 32位发送完成标志
output uart_tx, // 物理引脚TX
// 32位接收接口
input uart_rx, // 物理引脚RX
output reg Rx_Done32, // 32位接收完成标志
output reg [31:0] Rx_Data32 // 接收到的32位数据
);
// --- 内部连线 ---
wire byte_tx_go;
wire [7:0] byte_tx_data;
wire byte_tx_done;
wire byte_rx_done;
wire [7:0] byte_rx_data;
// ============================================================
// 1. 发送逻辑控制 (32-bit to 4x8-bit)
// ============================================================
reg [3:0] tx_state;
reg [31:0] tx_data_buffer;
reg byte_tx_go_reg;
reg [7:0] byte_tx_data_reg;
assign byte_tx_go = byte_tx_go_reg;
assign byte_tx_data = byte_tx_data_reg;
always @(posedge Clk or negedge Reset_n) begin
if (!Reset_n) begin
tx_state <= 0;
byte_tx_go_reg <= 0;
tx_data_buffer <= 0;
end else begin
case (tx_state)
0: begin // 等待发送触发
if (Send_Go32) begin
tx_data_buffer <= Tx_Data32;
tx_state <= 1;
end
end
1, 2, 3, 4: begin // 依次发送字节0, 1, 2, 3
byte_tx_data_reg <= tx_data_buffer[7:0]; // 优先发低位(小端)
byte_tx_go_reg <= 1;
tx_state <= tx_state + 4; // 跳转到等待状态 (利用加法偏移)
end
// 状态 5, 6, 7, 8 用于等待 byte_tx_done
5, 6, 7, 8: begin
byte_tx_go_reg <= 0;
if (byte_tx_done) begin
tx_data_buffer <= tx_data_buffer >> 8; // 移位准备下一字节
if (tx_state == 8) tx_state <= 0; // 发完4个
else tx_state <= tx_state - 3; // 回到下一个发送状态
end
end
endcase
end
end
assign Tx_Done32 = (tx_state == 8 && byte_tx_done);
// ============================================================
// 2. 接收逻辑控制 (4x8-bit to 32-bit)
// ============================================================
reg [1:0] rx_cnt;
reg [31:0] rx_data_buffer;
reg rx_done32_reg;
always @(posedge Clk or negedge Reset_n) begin
if (!Reset_n) begin
rx_cnt <= 0;
rx_data_buffer <= 0;
rx_done32_reg <= 0;
end else begin
rx_done32_reg <= 0;
if (byte_rx_done) begin
// 拼接数据 (小端模式)
case(rx_cnt)
0: rx_data_buffer[7:0] <= byte_rx_data;
1: rx_data_buffer[15:8] <= byte_rx_data;
2: rx_data_buffer[23:16] <= byte_rx_data;
3: rx_data_buffer[31:24] <= byte_rx_data;
endcase
if (rx_cnt == 3) begin
rx_cnt <= 0;
rx_done32_reg <= 1;
end else begin
rx_cnt <= rx_cnt + 1;
end
end
end
end
always @(posedge Clk or Reset_n) begin
if(!Reset_n) begin
Rx_Data32 <= 1'b0;
Rx_Done32 <= 1'b0;
end
else if(rx_done32_reg)begin
Rx_Data32 <= rx_data_buffer;
Rx_Done32 <= rx_done32_reg;
end
else begin
Rx_Data32 <= Rx_Data32;
Rx_Done32 <= 0;
end
end
// ============================================================
// 3. 模块实例化
// ============================================================
// 实例化发送字节模块
uart_byte_tx #(
.BAUD(BAUD),
.CLOCK_FREQ(CLOCK_FREQ)
) u_uart_byte_tx (
.Clk(Clk),
.Reset_n(Reset_n),
.Send_Go(byte_tx_go),
.Data(byte_tx_data),
.uart_tx(uart_tx),
.Tx_Done(byte_tx_done)
);
// 实例化接收字节模块
uart_byte_rx #(
.BAUD(BAUD),
.CLOCK_FREQ(CLOCK_FREQ)
) u_uart_byte_rx (
.Clk(Clk),
.Reset_n(Reset_n),
.uart_rx(uart_rx),
.Rx_Done(byte_rx_done),
.Rx_Data(byte_rx_data)
);
endmodule

153
tb/tb_uart_ctrl_sysreg.v Normal file
View File

@ -0,0 +1,153 @@
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2026/03/31 13:01:26
// Design Name:
// Module Name: tb_uart_ctrl_sysreg
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
`timescale 1ns / 1ps
module tb_uart_ctrl_sysreg();
// --- 参数与信号 ---
parameter CLK_PERIOD = 20; // 50MHz
parameter BAUD = 115200; // 提高波特率加快仿真
localparam BIT_TIME = 1_000_000_000 / BAUD; // 计算1比特持续的ns数
// 端口信号
reg clk;
reg rst_n;
reg uart_rx; // 发给 DUT UART 数据
wire uart_tx; // DUT 回发数据
wire [31:0] o_wrdata; // DUT -> SRAM 写数据
wire [24:0] o_addr; // DUT -> SRAM 地址
wire o_wren; // 写使能
wire o_rden; // 读使能
reg [31:0] i_rddata; // SRAM -> DUT 读数据
// 例化待测模块 (DUT)
uart_ctrl_sysreg #(
.BAUD (BAUD),
.CLOCK_FREQ (50_000_000)
) u_dut (
.clk (clk),
.rst_n (rst_n),
.uart_rx (uart_rx),
.uart_tx (uart_tx),
.o_wrdata (o_wrdata),
.o_addr (o_addr),
.o_wren (o_wren),
.o_rden (o_rden),
.i_rddata (i_rddata)
);
// --- 时钟产生 ---
initial clk = 0;
always #(CLK_PERIOD/2) clk = ~clk;
// ============================================================
// 模拟上位机字节发送任务 (Serial UART TX)
// ============================================================
task send_byte;
input [7:0] data;
integer i;
begin
uart_rx = 0; // 起始位
#(BIT_TIME);
for (i = 0; i < 8; i = i + 1) begin
uart_rx = data[i]; // 数据位 (LSB first)
#(BIT_TIME);
end
uart_rx = 1; // 停止位
#(BIT_TIME);
#(BIT_TIME); // 字节间隙
end
endtask
// 发送 32 位数据 (拆分为 4 个字节)
task send_32bit;
input [31:0] data;
begin
// 注意这里发送顺序要和你的串口接收模块端序一致
// 假设小端发送先发 [7:0]
send_byte(data[7:0]);
send_byte(data[15:8]);
send_byte(data[23:16]);
send_byte(data[31:24]);
end
endtask
// ============================================================
// 主测试流程
// ============================================================
integer file_ptr;
integer status;
reg [63:0] temp_cmd;
reg [31:0] temp_data;
initial begin
// 初始化
rst_n = 0;
uart_rx = 1;
#(CLK_PERIOD * 10);
rst_n = 1;
#(CLK_PERIOD * 100);
// 打开测试文件
file_ptr = $fopen("D:/shortname/thermometer/try/test_cases.txt", "r");
if (file_ptr == 0) begin
$display("====Error: can not open test_cases.txt file!===");
$finish;
end
$display("======= Begin Send Case =======");
while (!$feof(file_ptr)) begin
// 尝试读取一行先尝试按 64 CMD 读取
status = $fscanf(file_ptr, "%h\n", temp_cmd);
if (status == 1) begin
if (temp_cmd > 64'hFFFF_FFFF) begin
// 如果读到的是 64 认为是 CMD
$display("[%t] Send command frame: 0x%h", $time, temp_cmd);
send_32bit(temp_cmd[63:32]); // 先发高32位
send_32bit(temp_cmd[31:0]); // 再发低32位
end else begin
// 如果读到的是 32 认为是 DATA
$display("[%t] Send data stream: 0x%h", $time, temp_cmd[31:0]);
send_32bit(temp_cmd[31:0]);
end
end
#(BIT_TIME * 20); // 指令/数据组之间的间隔
end
$display("======= All Cases Sent =======");
$fclose(file_ptr);
#(BIT_TIME * 200);
$stop;
end
// ============================================================
// 监听回传捕捉 FPGA 返回的读数据
// ============================================================
// 简单起见这里直接观察波形或者你可以写一个串口接收任务
initial begin
$display("[%t] 监听器已启动...", $time);
end
endmodule

113
tb/tb_uart_top_32bit.v Normal file
View File

@ -0,0 +1,113 @@
`timescale 1ns / 1ps
module tb_uart_top_32bit();
// --- 参数定义 ---
parameter CLK_PERIOD = 20;
parameter BAUD = 115200; // 提高波特率可以加快仿真速度
parameter CLOCK_FREQ = 50_000_000;
// --- 信号声明 ---
reg Clk;
reg Reset_n;
reg Send_Go32;
reg [31:0] Tx_Data32;
wire uart_tx;
wire uart_rx;
wire Tx_Done32;
wire Rx_Done32;
wire [31:0] Rx_Data32;
// --- 实例化 DUT ---
uart_top_32bit #(
.BAUD(BAUD),
.CLOCK_FREQ(CLOCK_FREQ)
) dut (
.Clk(Clk),
.Reset_n(Reset_n),
.Send_Go32(Send_Go32),
.Tx_Data32(Tx_Data32),
.Tx_Done32(Tx_Done32),
.uart_tx(uart_tx),
.uart_rx(uart_rx),
.Rx_Done32(Rx_Done32),
.Rx_Data32(Rx_Data32)
);
// 构造回环
assign uart_rx = uart_tx;
// 时钟产生
initial Clk = 0;
always #(CLK_PERIOD/2) Clk = ~Clk;
// ============================================================
// 发送并校验的任务 (Task)
// ============================================================
task send_and_check;
input [31:0] data;
begin
Tx_Data32 = data;
Send_Go32 = 1;
#(CLK_PERIOD);
Send_Go32 = 0;
// 等待发送和接收全部完成
fork
wait(Rx_Done32);
wait(Tx_Done32);
join
#(CLK_PERIOD * 10); // 留一点余量
if (Rx_Data32 === data)
$display("[PASS] 发送: 0x%h | 接收: 0x%h", data, Rx_Data32);
else
$display("[FAIL] 发送: 0x%h | 接收: 0x%h !!! 错误 !!!", data, Rx_Data32);
#(CLK_PERIOD * 100); // 两次发送间的间隔
end
endtask
// ============================================================
// 测试流程
// ============================================================
integer i;
initial begin
// 初始化
Reset_n = 0;
Send_Go32 = 0;
Tx_Data32 = 0;
// 复位
#(CLK_PERIOD * 10);
Reset_n = 1;
#(CLK_PERIOD * 10);
$display("======= 开始 32位串口回环测试 =======");
// 1. 基础边界测试
send_and_check(32'h0000_0000);
send_and_check(32'hFFFF_FFFF);
// 2. 经典交替位测试 (检查串扰和采样)
send_and_check(32'hAAAA_AAAA);
send_and_check(32'h5555_5555);
// 3. 随机/特殊数据测试
send_and_check(32'h1234_5678);
send_and_check(32'h8765_4321);
send_and_check(32'hDEAD_BEEF);
// 4. 循环自动测试 (测试 5 组递增数据)
for (i = 0; i < 5; i = i + 1) begin
send_and_check(32'h2024_0000 + i);
end
$display("======= 所有测试用例执行完毕 =======");
#(CLK_PERIOD * 200);
$stop;
end
endmodule

89
tb/uart_byte_rx_tb.v Normal file
View File

@ -0,0 +1,89 @@
`timescale 1ns / 1ps
module uart_byte_rx_tb();
reg Clk;
reg Reset_n;
reg uart_rx;
wire Rx_Done;
wire [7:0]Rx_Data;
uart_byte_rx uart_byte_rx(
.Clk(Clk),
.Reset_n(Reset_n),
.uart_rx(uart_rx),
.Rx_Done(Rx_Done),
.Rx_Data(Rx_Data)
);
initial Clk = 1;
always #10 Clk= ~Clk;
initial begin
Reset_n = 0;
uart_rx = 1;
#201;
Reset_n = 1;
#200;
//8'b0101_0101
uart_rx = 0; #(5208*20); //Æðʼλ
uart_rx = 1; #(5208*20); //bit0
uart_rx = 0; #(5208*20); //bit1
uart_rx = 1; #(5208*20); //bit2
uart_rx = 0; #(5208*20); //bit3
uart_rx = 1; #(5208*20); //bit4
uart_rx = 0; #(5208*20); //bit5
uart_rx = 1; #(5208*20); //bit6
uart_rx = 0; #(5208*20); //bit7
uart_rx = 1; #(5208*20); //ֹͣλ
#(5208*20*10);
//8'b1010_1010
uart_rx = 0; #(5208*20); //Æðʼλ
uart_rx = 0; #(5208*20); //bit0
uart_rx = 1; #(5208*20); //bit1
uart_rx = 0; #(5208*20); //bit2
uart_rx = 1; #(5208*20); //bit3
uart_rx = 0; #(5208*20); //bit4
uart_rx = 1; #(5208*20); //bit5
uart_rx = 0; #(5208*20); //bit6
uart_rx = 1; #(5208*20); //bit7
uart_rx = 1; #(5208*20); //ֹͣλ
#(5208*20*10);
//8'b1111_0000
uart_rx = 0; #(5208*20); //Æðʼλ
uart_rx = 0; #(5208*20); //bit0
uart_rx = 0; #(5208*20); //bit1
uart_rx = 0; #(5208*20); //bit2
uart_rx = 0; #(5208*20); //bit3
uart_rx = 1; #(5208*20); //bit4
uart_rx = 1; #(5208*20); //bit5
uart_rx = 1; #(5208*20); //bit6
uart_rx = 1; #(5208*20); //bit7
uart_rx = 1; #(5208*20); //ֹͣλ
#(5208*20*10);
//8'b0000_1111
uart_rx = 0; #(5208*20); //Æðʼλ
uart_rx = 1; #(5208*20); //bit0
uart_rx = 1; #(5208*20); //bit1
uart_rx = 1; #(5208*20); //bit2
uart_rx = 1; #(5208*20); //bit3
uart_rx = 0; #(5208*20); //bit4
uart_rx = 0; #(5208*20); //bit5
uart_rx = 0; #(5208*20); //bit6
uart_rx = 0; #(5208*20); //bit7
uart_rx = 1; #(5208*20); //ֹͣλ
#(5208*20*10);
$stop;
end
endmodule

44
tb/uart_byte_tx_tb.v Normal file
View File

@ -0,0 +1,44 @@
`timescale 1ns / 1ps
module uart_byte_tx_tb();
reg Clk;
reg Reset_n;
reg [7:0]Data;
reg Send_Go;
wire uart_tx;
wire Tx_Done;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.uart_tx(uart_tx),
.Send_Go(Send_Go),
.Tx_Done(Tx_Done)
);
// defparam uart_byte_tx.MCNT_DLY = 50_000_0 - 1;
initial Clk = 1;
always #10 Clk = ~Clk;
initial begin
Reset_n = 0;
#200;
Reset_n = 1;
Data = 8'b0101_0101;
Send_Go = 1 ;
#20;
Send_Go = 0;
#20;
#30000000;
Data = 8'b1010_1010;
Send_Go = 1 ;
#20;
Send_Go = 0;
#20;
#30000000;
$stop;
end
endmodule