Files
templates/hdl/logic-analyzer/rtl/la_trigger_buffer.v
T

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