93 lines
3.5 KiB
Verilog
93 lines
3.5 KiB
Verilog
`timescale 1ns / 1ps
|
|
// Triggered, lossless encoding of constant digital runs. Each run emits the
|
|
// sample byte followed by its duration minus one (1..256 sample ticks).
|
|
// The small queue absorbs clusters of edges. Overflow latches a fault
|
|
// instead of slowing the sampling clock or silently dropping edges.
|
|
module la_run_encoder (
|
|
input wire clk, reset, arm, stop, tick,
|
|
input wire [7:0] sample, channel_mask,
|
|
input wire [7:0] level_mask, level_value, edge_mask, edge_value, any_edge_mask,
|
|
output wire stored,
|
|
output reg overflow,
|
|
output wire valid,
|
|
output wire [7:0] data,
|
|
input wire ready
|
|
);
|
|
reg [7:0] channels, levels, values, directed, direction, edges;
|
|
reg [7:0] previous, run_sample, run_length, run_input;
|
|
reg previous_valid, triggered, run_tick, run_started;
|
|
wire [7:0] selected = sample & channels;
|
|
wire level_hit = (selected & levels) == values;
|
|
wire edge_hit = edges == 0 || (previous_valid &&
|
|
((selected ^ previous) & edges) == edges && (selected & directed) == direction);
|
|
assign stored = tick && !overflow && (triggered || (level_hit && edge_hit));
|
|
|
|
(* ram_style = "distributed" *) reg [15:0] runs [0:31];
|
|
reg [5:0] wr_ptr, rd_ptr;
|
|
reg [15:0] output_run;
|
|
reg output_valid, high_byte;
|
|
wire full = wr_ptr == {~rd_ptr[5], rd_ptr[4:0]};
|
|
wire emit = run_tick && !overflow && run_started &&
|
|
(run_input != run_sample || run_length == 255);
|
|
assign valid = output_valid && !overflow;
|
|
assign data = high_byte ? output_run[15:8] : output_run[7:0];
|
|
|
|
always @(posedge clk) begin
|
|
if (reset || stop || arm) begin
|
|
channels <= channel_mask;
|
|
levels <= level_mask & channel_mask;
|
|
values <= level_value & level_mask & channel_mask;
|
|
directed <= edge_mask & channel_mask;
|
|
direction <= edge_value & edge_mask & channel_mask;
|
|
edges <= (edge_mask | any_edge_mask) & channel_mask;
|
|
previous_valid <= 0;
|
|
triggered <= 0;
|
|
run_tick <= 0;
|
|
run_started <= 0;
|
|
overflow <= 0;
|
|
wr_ptr <= 0;
|
|
rd_ptr <= 0;
|
|
output_valid <= 0;
|
|
high_byte <= 0;
|
|
end else begin
|
|
// The trigger comparison and the run encoder each get a full cycle.
|
|
run_tick <= stored;
|
|
run_input <= selected;
|
|
if (tick) begin
|
|
previous <= selected;
|
|
previous_valid <= 1;
|
|
end
|
|
if (stored)
|
|
triggered <= 1;
|
|
if (run_tick && !overflow) begin
|
|
run_started <= 1;
|
|
if (!run_started || emit) begin
|
|
run_sample <= run_input;
|
|
run_length <= 0;
|
|
end else begin
|
|
run_length <= run_length + 1'b1;
|
|
end
|
|
end
|
|
if (emit) begin
|
|
if (full)
|
|
overflow <= 1;
|
|
else
|
|
wr_ptr <= wr_ptr + 1'b1;
|
|
end
|
|
if (!output_valid && rd_ptr != wr_ptr) begin
|
|
output_run <= runs[rd_ptr[4:0]];
|
|
rd_ptr <= rd_ptr + 1'b1;
|
|
output_valid <= 1;
|
|
end else if (valid && ready) begin
|
|
high_byte <= !high_byte;
|
|
if (high_byte)
|
|
output_valid <= 0;
|
|
end
|
|
end
|
|
end
|
|
|
|
always @(posedge clk)
|
|
if (!reset && !arm && !stop && emit && !full)
|
|
runs[wr_ptr[4:0]] <= {run_length, run_sample};
|
|
endmodule
|