forked from SJTU-YONGFU-RESEARCH-GRP/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlogic_analyzer.v
More file actions
executable file
·256 lines (234 loc) · 9.81 KB
/
logic_analyzer.v
File metadata and controls
executable file
·256 lines (234 loc) · 9.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
/**
* Logic Analyzer
*
* This module implements a logic analyzer that captures digital signals
* based on configurable trigger conditions. It provides pre-trigger and
* post-trigger capture capabilities for debugging digital systems.
*
* Key Features:
* - Multi-channel capture: Up to CHANNEL_COUNT channels
* - Configurable triggers: Equal, not equal, rising edge, falling edge
* - Pre-trigger capture: Captures samples before trigger
* - Post-trigger capture: Captures samples after trigger
* - Circular buffer: Continuous capture with overwrite
* - Channel masking: Select which channels to monitor
*
* Trigger Modes:
* - Equal (0): Trigger when masked value equals trigger_value
* - Not Equal (1): Trigger when masked value does not equal trigger_value
* - Rising Edge (2): Trigger on rising edge of masked value
* - Falling Edge (3): Trigger on falling edge of masked value
*
* Operation:
* - ARM: Arms the trigger, starts pre-trigger capture
* - ARMED: Waiting for trigger condition, capturing pre-trigger samples
* - CAPTURE: Trigger detected, capturing post-trigger samples
* - COMPLETE: Capture complete, buffer full
*
* Buffer Management:
* - Circular buffer: Wraps around when full
* - Pre-trigger: Stores samples before trigger in circular buffer
* - Post-trigger: Continues capture after trigger
* - Readback: Can read captured samples via read interface
*
* Use Cases:
* - Digital signal debugging
* - Protocol analysis
* - Timing verification
* - System debugging
*
* @param CHANNEL_COUNT Number of channels (default: 32)
* @param SAMPLE_DEPTH Depth of capture buffer (default: 1024 samples)
* @param SAMPLE_WIDTH Bits per channel (default: 1 bit)
* @param TRIGGER_WIDTH Width of trigger value (default: 8 bits)
*
* @input clk Clock signal
* @input rst_n Active-low reset signal
*
* Probe Inputs:
* @input probe_in[CHANNEL_COUNT-1:0][SAMPLE_WIDTH-1:0] Probe input signals
*
* Control Interface:
* @input arm Arm the trigger
* @input force_trigger Force a trigger event
* @input channel_mask[CHANNEL_COUNT-1:0] Channels to monitor
* @input trigger_value[TRIGGER_WIDTH-1:0] Value to trigger on
* @input trigger_mask[TRIGGER_WIDTH-1:0] Bits to check for trigger
* @input trigger_mode[1:0] Trigger mode: 0=equal, 1=not equal, 2=rising, 3=falling
* @input trigger_channel[CHANNEL_COUNT-1:0] Channel(s) to trigger on
*
* Status:
* @output triggered Trigger detected
* @output capturing Actively capturing
* @output buffer_full Capture buffer is full
*
* Readback Interface:
* @input read_en Read enable
* @input read_addr[$clog2(SAMPLE_DEPTH)-1:0] Read address
* @output read_data[CHANNEL_COUNT-1:0][SAMPLE_WIDTH-1:0] Read data
*/
module logic_analyzer #(
parameter CHANNEL_COUNT = 32,
parameter SAMPLE_DEPTH = 1024,
parameter SAMPLE_WIDTH = 1, // Bits per channel
parameter TRIGGER_WIDTH = 8
)(
// Global signals
input wire clk,
input wire rst_n,
// Probe inputs
input wire [CHANNEL_COUNT-1:0][SAMPLE_WIDTH-1:0] probe_in,
// Control interface
input wire arm, // Arm the trigger
input wire force_trigger, // Force a trigger event
input wire [CHANNEL_COUNT-1:0] channel_mask, // Channels to monitor
input wire [TRIGGER_WIDTH-1:0] trigger_value, // Value to trigger on
input wire [TRIGGER_WIDTH-1:0] trigger_mask, // Bits to check for trigger
input wire [1:0] trigger_mode, // 0=equal, 1=not equal, 2=rising, 3=falling
input wire [CHANNEL_COUNT-1:0] trigger_channel,// Channel(s) to trigger on
// Status signals
output reg triggered, // Trigger detected
output reg capturing, // Actively capturing
output reg buffer_full, // Capture buffer is full
// Readback interface
input wire read_en,
input wire [$clog2(SAMPLE_DEPTH)-1:0] read_addr,
output reg [CHANNEL_COUNT-1:0][SAMPLE_WIDTH-1:0] read_data
);
// Internal signals
reg [CHANNEL_COUNT-1:0][SAMPLE_WIDTH-1:0] sample_buffer [0:SAMPLE_DEPTH-1];
reg [$clog2(SAMPLE_DEPTH)-1:0] write_ptr;
reg [CHANNEL_COUNT-1:0][SAMPLE_WIDTH-1:0] probe_in_prev; // Previous sample for edge detection
// State definitions
localparam IDLE = 2'b00;
localparam ARMED = 2'b01;
localparam CAPTURE = 2'b10;
localparam COMPLETE = 2'b11;
reg [1:0] state;
// Trigger logic
reg [TRIGGER_WIDTH-1:0] masked_probe;
reg [TRIGGER_WIDTH-1:0] prev_masked_probe;
reg trigger_match;
reg trigger_occurred;
// Extract the trigger bits from the masked channel
// This extracts bits safely, ensures we don't try to extract more bits than available
integer i;
always @(*) begin
masked_probe = {TRIGGER_WIDTH{1'b0}};
for (i = 0; i < CHANNEL_COUNT; i = i + 1) begin
if (trigger_channel[i] && channel_mask[i]) begin
// Only extract as many bits as available, pad with zeros if needed
if (SAMPLE_WIDTH >= TRIGGER_WIDTH) begin
/* verilator lint_off SELRANGE */
masked_probe = probe_in[i][TRIGGER_WIDTH-1:0];
/* verilator lint_on SELRANGE */
end else begin
masked_probe[SAMPLE_WIDTH-1:0] = probe_in[i];
end
end
end
end
// Extract previous value of trigger channel
always @(*) begin
prev_masked_probe = {TRIGGER_WIDTH{1'b0}};
for (i = 0; i < CHANNEL_COUNT; i = i + 1) begin
if (trigger_channel[i] && channel_mask[i]) begin
// Only extract as many bits as available, pad with zeros if needed
if (SAMPLE_WIDTH >= TRIGGER_WIDTH) begin
/* verilator lint_off SELRANGE */
prev_masked_probe = probe_in_prev[i][TRIGGER_WIDTH-1:0];
/* verilator lint_on SELRANGE */
end else begin
prev_masked_probe[SAMPLE_WIDTH-1:0] = probe_in_prev[i];
end
end
end
end
// Trigger condition detection
wire equal_match = ((masked_probe & trigger_mask) == (trigger_value & trigger_mask));
wire rising_edge = ((masked_probe & trigger_mask) > (prev_masked_probe & trigger_mask));
wire falling_edge = ((masked_probe & trigger_mask) < (prev_masked_probe & trigger_mask));
// Trigger condition based on mode
always @(*) begin
case (trigger_mode)
2'b00: trigger_match = equal_match; // Equal
2'b01: trigger_match = !equal_match; // Not Equal
2'b10: trigger_match = rising_edge; // Rising edge
2'b11: trigger_match = falling_edge; // Falling edge
default: trigger_match = 1'b0;
endcase
end
// Main state machine
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
state <= IDLE;
triggered <= 1'b0;
capturing <= 1'b0;
buffer_full <= 1'b0;
write_ptr <= 0;
trigger_occurred <= 1'b0;
for (i = 0; i < CHANNEL_COUNT; i = i + 1) begin
probe_in_prev[i] <= 0;
end
end else begin
// Store previous sample for edge detection
probe_in_prev <= probe_in;
case (state)
IDLE: begin
if (arm) begin
state <= ARMED;
capturing <= 1'b0;
triggered <= 1'b0;
buffer_full <= 1'b0;
write_ptr <= 0;
trigger_occurred <= 1'b0;
end
end
ARMED: begin
capturing <= 1'b1;
// Check for trigger condition
if (trigger_match || force_trigger) begin
triggered <= 1'b1;
trigger_occurred <= 1'b1;
state <= CAPTURE;
end else begin
// Store pre-trigger samples
sample_buffer[write_ptr] <= probe_in;
write_ptr <= write_ptr + 1;
if (write_ptr == SAMPLE_DEPTH - 1) begin
write_ptr <= 0; // Circular buffer
end
end
end
CAPTURE: begin
// Continue capturing post-trigger
sample_buffer[write_ptr] <= probe_in;
write_ptr <= write_ptr + 1;
if (write_ptr == SAMPLE_DEPTH - 1) begin
state <= COMPLETE;
capturing <= 1'b0;
buffer_full <= 1'b1;
end
end
COMPLETE: begin
// Stay in this state until rearmed
if (arm) begin
state <= ARMED;
capturing <= 1'b0;
triggered <= 1'b0;
buffer_full <= 1'b0;
write_ptr <= 0;
trigger_occurred <= 1'b0;
end
end
default: state <= IDLE;
endcase
end
end
// Read interface
always @(posedge clk) begin
if (read_en) begin
read_data <= sample_buffer[read_addr];
end
end
endmodule