135 lines
5.0 KiB
Verilog
135 lines
5.0 KiB
Verilog
`timescale 1ns / 1ps
|
|
// Record a finite window from the first matching sample, then read it out.
|
|
// Input samples are already synchronized to clk. Only the readout can stall.
|
|
module la_trigger_buffer #(
|
|
parameter integer ADDR_WIDTH = 16,
|
|
parameter integer EXTERNAL_TRIGGER = 0
|
|
)(
|
|
input wire clk, reset, arm, stop,
|
|
input wire [7:0] sample,
|
|
input wire [16:0] divider,
|
|
input wire [ADDR_WIDTH-1:0] last_address,
|
|
input wire [ADDR_WIDTH-1:0] pretrigger,
|
|
input wire use_external, external_hit,
|
|
output wire trigger_tick,
|
|
input wire [7:0] level_mask, level_value, edge_mask, edge_value, any_edge_mask,
|
|
output reg capturing,
|
|
output wire stored,
|
|
output reg data_valid,
|
|
output reg [7:0] data,
|
|
input wire ready
|
|
);
|
|
reg [16:0] period, timer;
|
|
reg [ADDR_WIDTH-1:0] write_address, read_address, pre, history, post_left, read_left;
|
|
reg [7:0] levels, values, directed, direction, edges, previous;
|
|
reg previous_valid, triggered, external_mode;
|
|
reg [1:0] read_pending;
|
|
wire [7:0] memory_data;
|
|
wire sample_tick = capturing && timer == 0 && !reset && !stop && !arm;
|
|
wire match_level = (sample & levels) == values;
|
|
wire match_edge = edges == 0 || (previous_valid &&
|
|
((sample ^ previous) & edges) == edges && (sample & directed) == direction);
|
|
assign trigger_tick = sample_tick && !triggered && history == 0;
|
|
wire fire = trigger_tick && (external_mode ? external_hit : match_level && match_edge);
|
|
assign stored = sample_tick && (triggered || fire);
|
|
|
|
reg write_pending;
|
|
reg [ADDR_WIDTH-1:0] pending_address;
|
|
reg [7:0] pending_sample;
|
|
always @(posedge clk) begin
|
|
write_pending <= sample_tick && (pre != 0 || triggered || fire);
|
|
pending_address <= write_address;
|
|
pending_sample <= sample;
|
|
end
|
|
|
|
la_capture_buffer #(.SAMPLE_WIDTH(8), .ADDR_WIDTH(ADDR_WIDTH)) memory (
|
|
.wr_clk(clk), .wr_en(write_pending && !reset), .wr_addr(pending_address), .wr_data(pending_sample),
|
|
.rd_clk(clk), .rd_addr(read_address), .rd_data(memory_data)
|
|
);
|
|
|
|
always @(posedge clk) begin
|
|
if (reset || stop) begin
|
|
capturing <= 0;
|
|
data_valid <= 0;
|
|
read_pending <= 0;
|
|
period <= 0;
|
|
timer <= 0;
|
|
pre <= 0;
|
|
history <= 0;
|
|
post_left <= 0;
|
|
read_left <= 0;
|
|
write_address <= 0;
|
|
read_address <= 0;
|
|
levels <= 0;
|
|
values <= 0;
|
|
directed <= 0;
|
|
direction <= 0;
|
|
edges <= 0;
|
|
previous <= 0;
|
|
previous_valid <= 0;
|
|
triggered <= 0;
|
|
external_mode <= 0;
|
|
end else if (arm) begin
|
|
capturing <= 1;
|
|
data_valid <= 0;
|
|
read_pending <= 0;
|
|
period <= divider - 1'b1;
|
|
timer <= 0;
|
|
pre <= EXTERNAL_TRIGGER && use_external ? pretrigger : 0;
|
|
history <= EXTERNAL_TRIGGER && use_external ? pretrigger : 0;
|
|
post_left <= last_address - (EXTERNAL_TRIGGER && use_external ? pretrigger : 0);
|
|
read_left <= last_address;
|
|
write_address <= 0;
|
|
read_address <= 0;
|
|
levels <= level_mask;
|
|
values <= level_value & level_mask;
|
|
directed <= edge_mask;
|
|
direction <= edge_value & edge_mask;
|
|
edges <= edge_mask | any_edge_mask;
|
|
previous_valid <= 0;
|
|
triggered <= 0;
|
|
external_mode <= EXTERNAL_TRIGGER && use_external;
|
|
end else if (capturing) begin
|
|
if (sample_tick) begin
|
|
timer <= period;
|
|
previous <= sample;
|
|
previous_valid <= 1;
|
|
if (history != 0)
|
|
history <= history - 1'b1;
|
|
if (pre != 0 || triggered || fire)
|
|
write_address <= write_address + 1'b1;
|
|
if (fire) begin
|
|
triggered <= 1;
|
|
read_address <= write_address - pre;
|
|
if (post_left == 0) begin
|
|
capturing <= 0;
|
|
read_pending <= 3;
|
|
end
|
|
end else if (triggered) begin
|
|
post_left <= post_left - 1'b1;
|
|
if (post_left == 1) begin
|
|
capturing <= 0;
|
|
read_pending <= 3;
|
|
end
|
|
end
|
|
end else begin
|
|
timer <= timer - 1'b1;
|
|
end
|
|
end else if (read_pending != 0) begin
|
|
read_pending <= read_pending - 1'b1;
|
|
// Keep the BRAM read mux out of the downstream FIFO write path.
|
|
if (read_pending == 1) begin
|
|
data <= memory_data;
|
|
data_valid <= 1;
|
|
end
|
|
end else if (data_valid && ready) begin
|
|
data_valid <= 0;
|
|
if (read_left != 0) begin
|
|
read_left <= read_left - 1'b1;
|
|
read_address <= read_address + 1'b1;
|
|
read_pending <= 2;
|
|
end
|
|
end
|
|
end
|
|
endmodule
|