Compare commits
2 Commits
281ede8487
...
be7c6d5c78
| Author | SHA1 | Date |
|---|---|---|
|
|
be7c6d5c78 | |
|
|
9be3e4a483 |
|
|
@ -1,7 +1,7 @@
|
|||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Engineer: Yangshenbo
|
||||
//
|
||||
// version:V1.0
|
||||
// Create Date: 2026/03/22
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
`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(
|
||||
input clk,
|
||||
input rst_n,
|
||||
input uart_rx,
|
||||
output uart_tx
|
||||
);
|
||||
|
||||
wire [31:0] w_wrdata; // DUT -> SRAM 写数据
|
||||
wire [24:0] w_addr; // DUT -> SRAM 地址
|
||||
wire w_wren; // 写使能
|
||||
wire w_rden; // 读使能
|
||||
wire [31:0] w_rddata; // SRAM -> DUT 读数据
|
||||
|
||||
|
||||
// 例化待测模块 (DUT)
|
||||
uart_ctrl_sysreg #(
|
||||
.BAUD (115200),
|
||||
.CLOCK_FREQ (50_000_000)
|
||||
) u_uart_ctrl (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.uart_rx (uart_rx),
|
||||
.uart_tx (uart_tx),
|
||||
.o_wrdata (w_wrdata),
|
||||
.o_addr (w_addr),
|
||||
.o_wren (w_wren),
|
||||
.o_rden (w_rden),
|
||||
.i_rddata (w_rddata)
|
||||
);
|
||||
|
||||
system_regfile u_system_regfile (
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.wrdata (w_wrdata),
|
||||
.wren (w_wren),
|
||||
.rwaddr (w_addr),
|
||||
.rden (w_rden),
|
||||
.rddata (w_rddata)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,125 @@
|
|||
`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_WAIT_RD = 3'd3,
|
||||
S_RD_DATA = 3'd4,
|
||||
S_WR_DATA = 3'd5;
|
||||
|
||||
|
||||
|
||||
|
||||
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_WAIT_RD;
|
||||
end
|
||||
else begin //写指令
|
||||
state <= S_WR_DATA;
|
||||
end
|
||||
end
|
||||
S_WAIT_RD : begin //3
|
||||
o_rden <= 1'b0;
|
||||
state <= S_RD_DATA;
|
||||
end
|
||||
S_RD_DATA :begin //4
|
||||
uart_tx_data <= i_rddata;
|
||||
uart_tx_go <= 1'b1;
|
||||
state <= S_IDLE;
|
||||
end
|
||||
S_WR_DATA : begin //5
|
||||
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
|
||||
|
|
@ -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
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
`timescale 1ns / 1ps
|
||||
|
||||
module TB_top();
|
||||
|
||||
// ==========================================
|
||||
// 参数与信号定义
|
||||
// ==========================================
|
||||
parameter CLK_PERIOD = 20; // 50MHz
|
||||
parameter BAUD = 115200;
|
||||
localparam BIT_TIME = 1_000_000_000 / BAUD;
|
||||
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
reg uart_rx; // 对应 DUT 的 RX
|
||||
wire uart_tx; // 对应 DUT 的 TX
|
||||
|
||||
// 时钟生成
|
||||
initial clk = 0;
|
||||
always #(CLK_PERIOD/2) clk = ~clk;
|
||||
|
||||
// ==========================================
|
||||
// 实例化被测设计 (DUT)
|
||||
// ==========================================
|
||||
digital_top u_digital_top(
|
||||
.clk (clk),
|
||||
.rst_n (rst_n),
|
||||
.uart_rx (uart_rx),
|
||||
.uart_tx (uart_tx)
|
||||
);
|
||||
|
||||
// ==========================================
|
||||
// 任务:发送一个字节 (Serial TX)
|
||||
// ==========================================
|
||||
task automatic send_byte(input [7:0] data);
|
||||
begin
|
||||
uart_rx = 0; // 起始位
|
||||
#(BIT_TIME);
|
||||
for (int i = 0; i < 8; i++) begin
|
||||
uart_rx = data[i]; // LSB First
|
||||
#(BIT_TIME);
|
||||
end
|
||||
uart_rx = 1; // 停止位
|
||||
#(BIT_TIME);
|
||||
end
|
||||
endtask
|
||||
|
||||
// 任务:发送 32/64 位数据
|
||||
task automatic send_data(input [63:0] data, input int len_bits);
|
||||
int bytes = len_bits / 8;
|
||||
for (int i = 0; i < bytes; i++) begin
|
||||
// 默认小端发送:低字节在前
|
||||
send_byte(data[i*8 +: 8]);
|
||||
end
|
||||
endtask
|
||||
|
||||
// ==========================================
|
||||
// 流程控制:TX 驱动 (从 case.txt 读取)
|
||||
// ==========================================
|
||||
initial begin
|
||||
int file_h;
|
||||
int status;
|
||||
logic [63:0] val;
|
||||
|
||||
// 初始化信号
|
||||
rst_n = 0;
|
||||
uart_rx = 1;
|
||||
#(CLK_PERIOD * 10);
|
||||
rst_n = 1;
|
||||
file_h = $fopen("case.txt", "r");
|
||||
if (!file_h) begin
|
||||
$display("[TX ERROR] Cannot open case.txt");
|
||||
$finish;
|
||||
end
|
||||
|
||||
$display("[TX] Starting transmission...");
|
||||
|
||||
while (!$feof(file_h)) begin
|
||||
// 假设文件中每行是一个 hex 数据
|
||||
status = $fscanf(file_h, "%h\n", val);
|
||||
if (status == 1) begin
|
||||
if (val > 64'hFFFF_FFFF) begin
|
||||
$display("[%t] TX CMD: %h", $time, val);
|
||||
send_data(val, 64);
|
||||
end else begin
|
||||
$display("[%t] TX DATA: %h", $time, val[31:0]);
|
||||
send_data(val[31:0], 32);
|
||||
end
|
||||
#(BIT_TIME * 5); // 帧间隙
|
||||
end
|
||||
end
|
||||
|
||||
$fclose(file_h);
|
||||
$display("[TX] All cases sent.");
|
||||
|
||||
// 等待一段时间观察 RX 是否还有回传,然后结束
|
||||
#(BIT_TIME * 500);
|
||||
$display("[SIM] Simulation finished.");
|
||||
$finish;
|
||||
end
|
||||
|
||||
// ==========================================
|
||||
// 流程控制:RX 监听 (保存到 rx_data.txt)
|
||||
// ==========================================
|
||||
int rx_file_h;
|
||||
initial begin
|
||||
|
||||
logic [7:0] rx_byte;
|
||||
|
||||
rx_file_h = $fopen("rx_data.txt", "w");
|
||||
if (!rx_file_h) begin
|
||||
$display("[RX ERROR] Cannot create rx_data.txt");
|
||||
$finish;
|
||||
end
|
||||
|
||||
forever begin
|
||||
logic [31:0] packet_word; // 32位数据包
|
||||
logic [7:0] rx_byte;
|
||||
// 收集4个字节并组合成32位数据
|
||||
for (int byte_idx = 0; byte_idx < 4; byte_idx++) begin
|
||||
// 1. 等待起始位 (下降沿)
|
||||
@(negedge uart_tx);
|
||||
// 2. 跳过起始位,采样数据中心点
|
||||
#(BIT_TIME / 2);
|
||||
#(BIT_TIME);
|
||||
// 读取8个数据位
|
||||
for (int i = 0; i < 8; i++) begin
|
||||
rx_byte[i] = uart_tx;
|
||||
#(BIT_TIME);
|
||||
end
|
||||
// 组合成32位数据(小端序:先收到的在低位)
|
||||
packet_word[8*byte_idx +: 8] = rx_byte;
|
||||
$display("[%t] Byte %0d: 0x%h", $time, byte_idx, rx_byte);
|
||||
// 等待停止位结束
|
||||
if (byte_idx < 3) begin
|
||||
#(BIT_TIME / 2);
|
||||
end
|
||||
end
|
||||
|
||||
// 写入文件(一行一个32位数据)
|
||||
$fdisplay(rx_file_h, "%08h", packet_word);
|
||||
$display("[%t] Packet (32-bit): 0x%08h", $time, packet_word);
|
||||
|
||||
// 等待最后一个字节的停止位结束
|
||||
#(BIT_TIME / 2);
|
||||
end
|
||||
end
|
||||
|
||||
final begin
|
||||
if (rx_file_h) begin
|
||||
$fclose(rx_file_h);
|
||||
$display("[RX] File closed at %t",$time);
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,123 @@
|
|||
`timescale 1ns / 1ps
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Company:
|
||||
// Engineer:
|
||||
//
|
||||
// Create Date: 2026/04/03 22:09:36
|
||||
// Design Name:
|
||||
// Module Name: tb_diginal_top
|
||||
// Project Name:
|
||||
// Target Devices:
|
||||
// Tool Versions:
|
||||
// Description:
|
||||
//
|
||||
// Dependencies:
|
||||
//
|
||||
// Revision:
|
||||
// Revision 0.01 - File Created
|
||||
// Additional Comments:
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
module tb_diginal_top();
|
||||
|
||||
reg clk;
|
||||
reg rst_n;
|
||||
wire uart_tx;
|
||||
reg uart_rx;
|
||||
|
||||
parameter CLK_PERIOD = 20; // 50MHz
|
||||
parameter BAUD = 115200; // 提高波特率加快仿真
|
||||
localparam BIT_TIME = 1_000_000_000 / BAUD; // 计算1比特持续的ns数
|
||||
|
||||
initial clk = 0;
|
||||
always #(CLK_PERIOD/2) clk = ~clk;
|
||||
|
||||
digital_top u_digital_top(
|
||||
.clk(clk),
|
||||
.rst_n(rst_n),
|
||||
.uart_rx(uart_rx),
|
||||
.uart_tx(uart_tx)
|
||||
);
|
||||
|
||||
// ============================================================
|
||||
// 模拟上位机:字节发送任务 (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
|
||||
endmodule
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue