122 lines
4.7 KiB
Systemverilog
122 lines
4.7 KiB
Systemverilog
`timescale 1ns/1ps
|
|
// Trigger decision is combinational for the currently accepted sample; the
|
|
// acquisition buffer can write that same sample as its trigger record.
|
|
module trigger_engine (
|
|
input wire clk,
|
|
input wire rst,
|
|
input wire arm,
|
|
input wire stop,
|
|
input wire session_fault,
|
|
input wire [2:0] cfg_source,
|
|
input wire [1:0] cfg_mode,
|
|
input wire cfg_falling,
|
|
input wire [9:0] cfg_level,
|
|
input wire [9:0] cfg_hysteresis,
|
|
input wire [31:0] cfg_auto_timeout,
|
|
input wire [63:0] sample_data,
|
|
input wire [63:0] sample_index,
|
|
input wire sample_valid,
|
|
input wire ext_level,
|
|
input wire eligible,
|
|
output wire trigger_hit,
|
|
output wire auto_hit,
|
|
output reg armed,
|
|
output reg [63:0] trigger_index,
|
|
output reg config_error
|
|
);
|
|
reg [2:0] active_source;
|
|
reg [1:0] active_mode;
|
|
reg active_falling;
|
|
reg [9:0] active_level, active_hysteresis;
|
|
reg [31:0] active_timeout, accepted_count;
|
|
reg crossing_armed;
|
|
reg ext_seen, ext_previous;
|
|
reg [9:0] selected_sample;
|
|
wire [10:0] high_sum = {1'b0, active_level} + {1'b0, active_hysteresis};
|
|
wire [9:0] high_threshold = high_sum > 11'd1023 ? 10'd1023 : high_sum[9:0];
|
|
wire [9:0] low_threshold = active_level > active_hysteresis ?
|
|
active_level - active_hysteresis : 10'd0;
|
|
|
|
always @* begin
|
|
case (active_source)
|
|
3'd0: selected_sample = sample_data[9:0];
|
|
3'd1: selected_sample = sample_data[25:16];
|
|
3'd2: selected_sample = sample_data[41:32];
|
|
3'd3: selected_sample = sample_data[57:48];
|
|
default: selected_sample = 10'd0;
|
|
endcase
|
|
end
|
|
|
|
wire analog_arm_condition = active_falling ?
|
|
(active_hysteresis == 0 ? selected_sample > active_level : selected_sample >= high_threshold) :
|
|
(active_hysteresis == 0 ? selected_sample < active_level : selected_sample <= low_threshold);
|
|
wire analog_cross_condition = active_falling ?
|
|
selected_sample <= low_threshold : selected_sample >= high_threshold;
|
|
wire analog_event = crossing_armed && analog_cross_condition;
|
|
wire external_event = ext_seen && (active_falling ?
|
|
(ext_previous && !ext_level) : (!ext_previous && ext_level));
|
|
wire edge_event = active_source == 3'd4 ? external_event : analog_event;
|
|
// Counter describes preceding accepted samples. N expires on sample N;
|
|
// zero expires immediately, but fallback still waits for eligibility.
|
|
wire auto_expired = active_timeout == 0 || accepted_count >= active_timeout - 1'b1;
|
|
wire auto_event = active_mode == 2'd0 && auto_expired;
|
|
assign trigger_hit = !rst && !arm && !stop && !session_fault && armed &&
|
|
sample_valid && eligible && (edge_event || auto_event);
|
|
assign auto_hit = trigger_hit && !edge_event && auto_event;
|
|
|
|
always @(posedge clk) begin
|
|
if (rst) begin
|
|
armed <= 0;
|
|
trigger_index <= 0;
|
|
config_error <= 0;
|
|
active_source <= 0;
|
|
active_mode <= 0;
|
|
active_falling <= 0;
|
|
active_level <= 0;
|
|
active_hysteresis <= 0;
|
|
active_timeout <= 0;
|
|
accepted_count <= 0;
|
|
crossing_armed <= 0;
|
|
ext_seen <= 0;
|
|
ext_previous <= 0;
|
|
end else if (stop || session_fault) begin
|
|
armed <= 0;
|
|
accepted_count <= 0;
|
|
crossing_armed <= 0;
|
|
ext_seen <= 0;
|
|
end else if (arm) begin
|
|
active_source <= cfg_source;
|
|
active_mode <= cfg_mode;
|
|
active_falling <= cfg_falling;
|
|
active_level <= cfg_level;
|
|
active_hysteresis <= cfg_hysteresis;
|
|
active_timeout <= cfg_auto_timeout;
|
|
armed <= (cfg_source <= 3'd4) && (cfg_mode <= 2'd2);
|
|
if (cfg_source > 3'd4 || cfg_mode > 2'd2)
|
|
config_error <= 1'b1;
|
|
trigger_index <= 0;
|
|
accepted_count <= 0;
|
|
crossing_armed <= 0;
|
|
ext_seen <= 0;
|
|
ext_previous <= 0;
|
|
end else if (armed && sample_valid) begin
|
|
if (accepted_count != 32'hffffffff)
|
|
accepted_count <= accepted_count + 1'b1;
|
|
if (active_source == 3'd4) begin
|
|
ext_previous <= ext_level;
|
|
ext_seen <= 1'b1;
|
|
end else if (analog_event) begin
|
|
// Consume the crossing even before sufficient prehistory;
|
|
// eligibility becoming true later must not replay this edge.
|
|
crossing_armed <= 1'b0;
|
|
end else if (analog_arm_condition) begin
|
|
crossing_armed <= 1'b1;
|
|
end
|
|
if (trigger_hit) begin
|
|
armed <= 1'b0;
|
|
trigger_index <= sample_index;
|
|
end
|
|
end
|
|
end
|
|
endmodule
|