`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