thermometer_digital/spi_thermometer_digital/sim/therm_chip_top/TB.sv

230 lines
7.6 KiB
Systemverilog

`timescale 1ns / 1ps
module TB();
// ==========================================
// Parameters & Signal Definitions
// ==========================================
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;
// Clock Generation
initial clk = 0;
always #(CLK_PERIOD/2) clk = ~clk;
// initial begin
// $fsdbDumpfile("wave.fsdb");
// $fsdbDumpvars();
// end
// ==========================================
// DUT Instantiation
// ==========================================
digital_top u_digital_top(
.clk (clk),
.rst_n (rst_n),
.uart_rx (uart_rx),
.uart_tx (uart_tx),
.sig_in (sig_in)
);
// // ==========================================
// // TX Driver: Read from case.txt
// // ==========================================
// initial begin
// int file_h;
// int status;
// logic [63:0] val;
// // Initialize signals
// 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
// // Read hex data per line
// 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); // Frame gap
// }
// end
// $fclose(file_h);
// $display("[TX] All cases sent.");
// // Wait for RX return data
// #(BIT_TIME * 500);
// $display("[SIM] Simulation finished.");
// $finish;
// end
// ==========================================
// RX Monitor: Save to 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-bit data packet
logic [7:0] rx_byte;
// Collect 4 bytes to form 32-bit data
for (int byte_idx = 0; byte_idx < 4; byte_idx++) begin
// 1. Wait for start bit (falling edge)
@(negedge uart_tx);
// 2. Skip start bit, sample at center point
#(BIT_TIME / 2);
#(BIT_TIME);
// Read 8 data bits
for (int i = 0; i < 8; i++) begin
rx_byte[i] = uart_tx;
#(BIT_TIME);
end
// Combine to 32-bit (little-endian)
packet_word[24 - 8*byte_idx +: 8] = rx_byte;
// $display("[%t] Byte %0d: 0x%h", $time, byte_idx, rx_byte);
// Wait for end of stop bit
if (byte_idx < 3) begin
#(BIT_TIME / 2);
end
end
// Write to file (one 32-bit data per line)
$fdisplay(rx_file_h, "%08h", packet_word);
$display("[%0t] Packet (32-bit): 0x%08h", $time, packet_word);
// Wait for end of last stop bit
#(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
// ==========================================
// Task: Send one byte (Serial TX)
// ==========================================
task automatic send_byte(input [7:0] data);
begin
uart_rx = 0; // Start bit
#(BIT_TIME);
for (int i = 0; i < 8; i++) begin
uart_rx = data[i]; // LSB First
#(BIT_TIME);
end
uart_rx = 1; // Stop bit
#(BIT_TIME);
end
endtask
// Task: Send 32/64 bit data
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 from highest byte
send_byte(data[i*8 +: 8]);
end
endtask
initial begin
// 1. Initialization
rst_n = 0; uart_rx = 1; sig_in = 0;
#(CLK_PERIOD * 20);
rst_n = 1;
#(CLK_PERIOD * 100);
$display("------- Step 1: read Thermometer Regs -------");
send_data(64'h80000004_00000004,64);
send_data(64'h80000008_00000004,64); //mode[25:24] + win
send_data(64'h8000000c_00000004,64); //calibration H / L
send_data(64'h80000010_00000004,64); //rep[31] +rep_gap[23:0]
send_data(64'h80000014_00000004,64); //result [23:0]
$display("------- Step 2: Running Concurrent Tasks -------");
fork
// Process A: Generate input pulses (simulate temperature change)
begin
gen_pulses(200, 10); // 100kHz for 10ms
gen_pulses(300, 20);
gen_pulses(400, 30);
end
// Process B: Insert read command during reporting
begin
#(6ms); // Wait for first report packet
send_data(64'h80000014_00000004,64); $display("[%0t] == Sending Read Request ==", $time);
send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32); $display("[%0t] == open report_en==",$time);
send_data(64'h0000008_00000004,64);send_data(32'h0100_03e8,32); $display("[%0t] == mode = 1 ==",$time);
#15ms;
send_data(64'h00000010_00000004,64);send_data(32'h0000_06e8,32);$display("[%0t] == cloese report_en==",$time);
//send_data(64'h00000010_00000004,64);send_data(32'h8000_06e8,32); $display("[%0t] == open report_en==",$time);
//send_data(64'h00000010_00000004,64);send_data(32'h0000_06e8,32);$display("[%0t] == cloese report_en==",$time);
#30000;
send_data(64'h80000014_00000004,64);
end
join
#(BIT_TIME * 500);
$display("Test Done.");
$finish;
end
endmodule