`timescale 1ns / 1ps module tb; // ======================== 参数 ======================== localparam CLK_PERIOD = 9.615; // 104MHz localparam ADC_PERIOD = 1000; // 1MHz -> 1000ns // ======================== 信号 ======================== reg pclk; reg presetn; reg [11:0] paddr; reg pwrite; reg [31:0] pwdata; wire [31:0] prdata; reg psel; reg penable; reg [11:0] trig_threshold; reg [15:0] trig_pulse_width; reg [1:0] trig_edge; reg [1:0] trig_mode; reg [4:0] trig_time_slot; reg [15:0] trig_auto_timeout; reg adc_en; reg adc_run; reg adc_restart; reg adc_eoc; reg [11:0] adc_data; wire ram_wren_b; wire [9:0] ram_wr_addr; wire [15:0] ram_wr_data_b; wire trig_done; wire [9:0] trigger_ptr; // 辅助变量(必须在模块顶部声明) real triangle_phase; real triangle_step; real tri_val; real volt; integer code; reg [11:0] adc_data_next=0; reg adc_eoc_dly; integer trigger_count; // ======================== DUT 实例 ======================== trig_ctrl uut ( .pclk (pclk), .presetn (presetn), .paddr (paddr), .pwrite (pwrite), .pwdata (pwdata), .prdata (prdata), .psel (psel), .penable (penable), .trig_threshold (trig_threshold), .trig_pulse_width(trig_pulse_width), .trig_edge (trig_edge), .trig_mode (trig_mode), .trig_time_slot (trig_time_slot), .trig_auto_timeout(trig_auto_timeout), .adc_en (adc_en), .adc_run (adc_run), .adc_restart (adc_restart), .adc_eoc (adc_eoc), .adc_data (adc_data), .ram_wren_b (ram_wren_b), .ram_wr_addr (ram_wr_addr), .ram_wr_data_b (ram_wr_data_b), .trig_done (trig_done), .trigger_ptr (trigger_ptr) ); // ======================== 时钟与复位 ======================== initial begin pclk = 0; forever #(CLK_PERIOD/2) pclk = ~pclk; end initial begin presetn = 0; #200; presetn = 1; end // ======================== 三角波生成 ======================== initial begin triangle_phase = 0.0; triangle_step = (2.0 * 50000) / 1000000; // 50kHz / 1MHz end always #(ADC_PERIOD) begin // 更新相位 triangle_phase = triangle_phase + triangle_step; if (triangle_phase > 1.0) triangle_phase = triangle_phase - 2.0; // 三角波值 (-1.0 ~ 1.0) if (triangle_phase >= 0) tri_val = 1.0 - 2.0 * triangle_phase; else tri_val = 1.0 + 2.0 * triangle_phase; // 映射到电压:中心1.65V,幅度1.5V -> 0.15V~3.15V volt = 1.65 + 1.5 * tri_val; // 转换为12位ADC码值 code = (volt / 3.3) * 4095.0; if (code > 4095) code = 4095; if (code < 0) code = 0; adc_data_next = code[11:0]; end // ======================== ADC EOC 脉冲 ======================== always @(posedge pclk or negedge presetn) begin if (!presetn) begin adc_eoc <= 1'b0; adc_data <= 12'd0; adc_eoc_dly <= 1'b0; end else begin adc_eoc <= 1'b0; if (adc_eoc_dly) begin adc_eoc <= 1'b1; adc_data <= adc_data_next; end end end initial begin adc_eoc_dly = 1'b0; forever begin #(ADC_PERIOD - 10); adc_eoc_dly = 1'b1; #10; adc_eoc_dly = 1'b0; end end // ======================== 测试主流程(自动模式) ======================== initial begin // 初始化 paddr = 12'd0; pwdata = 32'd0; pwrite = 1'b0; psel = 1'b0; penable= 1'b0; trig_threshold = 12'd2048; // 1.65V trig_pulse_width = 16'd0; trig_edge = 2'b00; trig_mode = 2'b00; // 自动模式 trig_time_slot = 5'd0; trig_auto_timeout = 16'd200; // 超时值 adc_en = 1'b0; adc_run = 1'b0; adc_restart = 1'b0; trigger_count = 0; wait(presetn == 1'b1); repeat(50) @(posedge pclk); $display("========================================"); $display(" Auto Mode Test - Waiting for triggers"); $display("========================================"); // 启动采集 adc_en = 1'b1; adc_run = 1'b1; // 等待至少两次触发完成 while (trigger_count < 5) begin @(posedge pclk); if (trig_done) begin trigger_count = trigger_count + 1; $display("[%0t] *** Trigger #%0d occurred! trigger_ptr = %d, ram_wr_addr = %d", $time, trigger_count, trigger_ptr, ram_wr_addr); // 模拟上位机读取后重启 repeat(100) @(posedge pclk); adc_restart <= 1'b1; repeat(20) @(posedge pclk); // 给20个时钟宽脉冲 adc_restart <= 1'b0; $display("[%0t] Restart issued, waiting for next trigger...", $time); end end $display("[%0t] Two triggers observed. Test finished.", $time); #10000; $stop; end // ======================== 波形记录 ======================== initial begin $dumpfile("tb_auto.vcd"); $dumpvars(0, tb); $dumpvars(1, uut.curr_state); $dumpvars(1, uut.trig_hit_comb); $dumpvars(1, uut.trig_hit_comb_reg); end endmodule