219 lines
7.0 KiB
Systemverilog
219 lines
7.0 KiB
Systemverilog
`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
|
||
reg sig_in;
|
||
|
||
// 时钟生成
|
||
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),
|
||
.sig_in (sig_in)
|
||
);
|
||
|
||
|
||
|
||
// // ==========================================
|
||
// // 流程控制: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
|
||
|
||
initial begin
|
||
// 1. 初始化
|
||
rst_n = 0; uart_rx = 1; sig_in = 0;
|
||
#(CLK_PERIOD * 20);
|
||
rst_n = 1;
|
||
#(CLK_PERIOD * 100);
|
||
|
||
$display("------- Step 1: Configure Thermometer Regs -------");
|
||
send_data(64'h80000004_00000004,64);
|
||
send_data(64'h80000008_00000004,64);
|
||
send_data(64'h8000000c_00000004,64);
|
||
send_data(64'h80000010_00000004,64);
|
||
send_data(64'h80000014_00000004,64);
|
||
|
||
|
||
$display("------- Step 2: Running Concurrent Tasks -------");
|
||
fork
|
||
// 进程 A: 模拟输入脉冲 (代表温度变化)
|
||
begin
|
||
gen_pulses(400, 10); // 100kHz 持续 10ms
|
||
end
|
||
|
||
// 进程 B: 在上报期间,强行插口读取指令
|
||
begin
|
||
#(2_000000); // 等待第一个上报包可能发出
|
||
$display("[%t] TX: Sending Read Request during active reporting...", $time);
|
||
send_data(64'h80000014_00000004,64);
|
||
send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32);
|
||
send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32);
|
||
end
|
||
join
|
||
|
||
#(BIT_TIME * 500);
|
||
$display("Test Done.");
|
||
$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[24 - 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
|
||
|
||
// --- Pulse Generation Task ---
|
||
// freq_khz: Target frequency (kHz)
|
||
// duration_ms: Test duration (ms)
|
||
task automatic gen_pulses(input int freq_khz, input int duration_ms);
|
||
int half_period_ns;
|
||
longint end_time_ns;
|
||
begin
|
||
if (freq_khz <= 0) begin
|
||
sig_in = 0;
|
||
#(duration_ms * 1000000);
|
||
end else begin
|
||
half_period_ns = 500000 / freq_khz;
|
||
end_time_ns = $time + (longint'(duration_ms) * 1000000);
|
||
|
||
$display("[%0t] Start generating signal: %0d kHz", $time, freq_khz);
|
||
while ($time < end_time_ns) begin
|
||
sig_in = 1;
|
||
#(half_period_ns);
|
||
sig_in = 0;
|
||
#(half_period_ns);
|
||
end
|
||
end
|
||
end
|
||
endtask
|
||
|
||
// ==========================================
|
||
// 任务:发送一个字节 (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 = bytes - 1; i >= 0; i--) begin // 从最高字节往下发
|
||
send_byte(data[i*8 +: 8]);
|
||
end
|
||
endtask
|
||
|
||
endmodule |