thermometer_digital/spi_thermometer_digital/tb/tb_diginal_top.sv

159 lines
4.7 KiB
Systemverilog
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

`timescale 1ns / 1ps
module tb_digital_top();
// 参数定义
parameter CLK_PERIOD = 20; // 100MHz 系统时钟
parameter SCLK_PERIOD = 200; // 10MHz SPI时钟 (必须比系统时钟慢)
// 信号声明
logic clk;
logic rst_n;
logic [4:0] cfgid;
logic sclk;
logic csn;
logic mosi;
logic miso;
logic oen;
logic sig_in;
// 实例化 DUT
digital_top u_digital_top (
.clk (clk ),
.rst_n (rst_n ),
.cfgid (cfgid ),
.sclk (sclk ),
.csn (csn ),
.mosi (mosi ),
.miso (miso ),
.oen (oen ),
.sig_in ( sig_in )
);
// 系统时钟产生
initial begin
clk = 0;
forever #(CLK_PERIOD/2) clk = ~clk;
end
// 初始复位与赋值
initial begin
rst_n = 0;
sclk = 0;
csn = 1;
mosi = 0;
cfgid = 5'h00; // 设定芯片ID为 10
#(CLK_PERIOD * 10);
rst_n = 1;
#(CLK_PERIOD * 10);
fork
begin // --- 开始测试 ---
#2ms;
spi_read(25'h08, 5'h00);
#(CLK_PERIOD * 10);
spi_read(25'h0c, 5'h00);
#(CLK_PERIOD * 10);
spi_write(25'h08, 5'h00, 32'h2);
end
begin
gen_pulses(1000,5);
end
join
// spi_read(25'h04, 5'h00);
//aa
// spi_read(25'h00, 5'h0A);
// #(SCLK_PERIOD * 5);
// spi_read(25'h00, 5'h0A);
// // 1. 测试写操作: 写入 0x12345678 到 地址 0x100
// spi_write(25'h00, 5'h0A, 32'h12345678);
// #(SCLK_PERIOD * 5);
// // 2. 测试读操作: 从地址 0x100 读取 (验证读使能和地址)
// spi_read(25'h00, 5'h0A);
#(SCLK_PERIOD * 20);
$display("Test Bench Finished.");
$finish;
end
// ---------------------------------------------------------
// Task: SPI 发送/接收 32位数据
// ---------------------------------------------------------
task spi_xfer_32(input [31:0] data_in, output [31:0] data_out);
for (int i = 31; i >= 0; i--) begin
mosi = data_in[i]; // MSB First ,psclk前给数据 psclk让人采样. 自己什么时候采?要看别人什么时候给数据
#(SCLK_PERIOD/2);
sclk = 1; // 上升沿DUT采样
data_out[i] = miso;
// 采样从机发回的数据
#(SCLK_PERIOD/2);
sclk = 0;
end
endtask
// ---------------------------------------------------------
// Task: 写操作 (wnr=0)
// ---------------------------------------------------------
task spi_write(input [24:0] target_addr, input [4:0] id, input [31:0] data);
logic [31:0] header;
logic [31:0] dummy;
header = {1'b0, target_addr, id, 1'b0}; // 构造命令帧
$display("[WRITE] Addr: %h, Data: %h", target_addr, data);
csn = 0;
spi_xfer_32(header, dummy); // 发送命令
spi_xfer_32(data, dummy); // 发送数据
csn = 1;
mosi = 0;
endtask
// ---------------------------------------------------------
// Task: 读操作 (wnr=1)
// ---------------------------------------------------------
task spi_read(input [24:0] target_addr, input [4:0] id);
logic [31:0] header;
logic [31:0] read_val;
header = {1'b1, target_addr, id, 1'b0}; // 构造命令帧 (wnr=1)
$display("[READ] Addr: %h", target_addr);
csn = 0;
spi_xfer_32(header, read_val); // 发送命令帧,此时读回的可能是无用数据
spi_xfer_32(32'h0, read_val); // 发送Dummy接收真正的读数据
csn = 1;
mosi = 0;
$display("[READ] Result: %h", read_val);
endtask
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
endmodule