/ 9_Firmware / 9_2_FPGA / usb_data_interface.v
usb_data_interface.v
  1  module usb_data_interface (
  2      input wire clk,              // Main clock (100MHz recommended)
  3      input wire reset_n,
  4      input wire ft601_reset_n,    // FT601-domain synchronized reset
  5      
  6      // Radar data inputs
  7      input wire [31:0] range_profile,
  8      input wire range_valid,
  9      input wire [15:0] doppler_real,
 10      input wire [15:0] doppler_imag,
 11      input wire doppler_valid,
 12      input wire cfar_detection,
 13      input wire cfar_valid,
 14      
 15      // FT601 Interface (Slave FIFO mode)
 16      // Data bus
 17      inout wire [31:0] ft601_data,    // 32-bit bidirectional data bus
 18      output reg [3:0] ft601_be,       // Byte enable (4 lanes for 32-bit mode)
 19      
 20      // Control signals
 21      output reg ft601_txe_n,          // Transmit enable (active low)
 22      output reg ft601_rxf_n,          // Receive enable (active low)
 23      input wire ft601_txe,             // Transmit FIFO empty
 24      input wire ft601_rxf,             // Receive FIFO full
 25      output reg ft601_wr_n,            // Write strobe (active low)
 26      output reg ft601_rd_n,            // Read strobe (active low)
 27      output reg ft601_oe_n,            // Output enable (active low)
 28      output reg ft601_siwu_n,          // Send immediate / Wakeup
 29      
 30      // FIFO flags
 31      input wire [1:0] ft601_srb,       // Selected read buffer
 32      input wire [1:0] ft601_swb,       // Selected write buffer
 33      
 34      // Clock
 35      output wire ft601_clk_out,        // Output clock to FT601 (forwarded via ODDR)
 36      input wire ft601_clk_in,          // Clock from FT601 (60/100MHz)
 37      
 38      // ========== HOST COMMAND OUTPUTS (Gap 4: USB Read Path) ==========
 39      // These outputs are registered in the ft601_clk domain and must be
 40      // CDC-synchronized by the consumer (radar_system_top.v) before use
 41      // in the clk_100m domain.
 42      //
 43      // Command word format: {opcode[7:0], addr[7:0], value[15:0]}
 44      //   0x01 = Set radar mode (value[1:0] -> mode_controller mode)
 45      //   0x02 = Single chirp trigger (value ignored, pulse cmd_valid)
 46      //   0x03 = Set CFAR threshold (value[15:0] -> threshold)
 47      //   0x04 = Set stream control (value[2:0] -> enable range/doppler/cfar)
 48      //   0x10-0x15 = Chirp timing configuration (Gap 2)
 49      //   0xFF = Status request (triggers status response packet)
 50      output reg [31:0] cmd_data,      // Last received command word
 51      output reg cmd_valid,            // Pulse: new command received (ft601_clk domain)
 52      output reg [7:0] cmd_opcode,     // Decoded opcode for convenience
 53      output reg [7:0] cmd_addr,       // Decoded register address
 54      output reg [15:0] cmd_value,     // Decoded value
 55  
 56      // Gap 2: Stream control input (clk_100m domain, CDC'd internally)
 57      // Bit 0 = range stream enable
 58      // Bit 1 = doppler stream enable
 59      // Bit 2 = cfar/detection stream enable
 60      input wire [2:0] stream_control,
 61  
 62      // Gap 2: Status readback inputs (clk_100m domain, CDC'd internally)
 63      // When status_request pulses, the write FSM sends a status response
 64      // packet containing the current register values.
 65      input wire status_request,                 // 1-cycle pulse in clk_100m when 0xFF received
 66      input wire [15:0] status_cfar_threshold,   // Current CFAR threshold
 67      input wire [2:0]  status_stream_ctrl,      // Current stream control
 68      input wire [1:0]  status_radar_mode,       // Current radar mode
 69      input wire [15:0] status_long_chirp,       // Current long chirp cycles
 70      input wire [15:0] status_long_listen,      // Current long listen cycles
 71      input wire [15:0] status_guard,            // Current guard cycles
 72      input wire [15:0] status_short_chirp,      // Current short chirp cycles
 73      input wire [15:0] status_short_listen,     // Current short listen cycles
 74      input wire [5:0]  status_chirps_per_elev,  // Current chirps per elevation
 75      input wire [1:0]  status_range_mode,       // Fix 7: Current range mode (0x20)
 76  
 77      // Self-test status readback (opcode 0x31 / included in 0xFF status packet)
 78      input wire [4:0]  status_self_test_flags,  // Per-test PASS(1)/FAIL(0) latched
 79      input wire [7:0]  status_self_test_detail, // Diagnostic detail byte latched
 80      input wire        status_self_test_busy    // Self-test FSM still running
 81  );
 82  
 83  // USB packet structure (same as before)
 84  localparam HEADER = 8'hAA;
 85  localparam FOOTER = 8'h55;
 86  
 87  // FT601 configuration
 88  localparam FT601_DATA_WIDTH = 32;
 89  localparam FT601_BURST_SIZE = 512;    // Max burst size in bytes
 90  
 91  // ============================================================================
 92  // WRITE FSM State definitions (Verilog-2001 compatible)
 93  // ============================================================================
 94  localparam [2:0] IDLE                = 3'd0,
 95                   SEND_HEADER         = 3'd1,
 96                   SEND_RANGE_DATA     = 3'd2,
 97                   SEND_DOPPLER_DATA   = 3'd3,
 98                   SEND_DETECTION_DATA = 3'd4,
 99                   SEND_FOOTER         = 3'd5,
100                   WAIT_ACK            = 3'd6,
101                   SEND_STATUS         = 3'd7;  // Gap 2: status readback
102  
103  reg [2:0] current_state;
104  reg [7:0] byte_counter;
105  reg [31:0] data_buffer;
106  reg [31:0] ft601_data_out;
107  reg ft601_data_oe;  // Output enable for bidirectional data bus
108  
109  // ============================================================================
110  // READ FSM State definitions (Gap 4: USB Read Path)
111  // ============================================================================
112  // FT601 245 synchronous FIFO read protocol:
113  //   1. Host has data available: RXF_N = 0 (active low)
114  //   2. FPGA asserts OE_N = 0 (bus turnaround: FT601 starts driving data bus)
115  //   3. Wait 1 cycle for bus turnaround settling
116  //   4. FPGA asserts RD_N = 0 (start reading: data valid on each posedge)
117  //   5. Sample ft601_data[31:0] while RD_N = 0 and RXF_N = 0
118  //   6. Deassert RD_N = 1, then OE_N = 1
119  //
120  // The read FSM only activates when the write FSM is IDLE and RXF indicates
121  // data is available. This prevents bus contention between TX and RX.
122  localparam [2:0] RD_IDLE      = 3'd0,  // Waiting for RXF
123                   RD_OE_ASSERT = 3'd1,  // Assert OE_N=0, wait turnaround
124                   RD_READING   = 3'd2,  // Assert RD_N=0, sample data
125                   RD_DEASSERT  = 3'd3,  // Deassert RD_N, then OE_N
126                   RD_PROCESS   = 3'd4;  // Process received command word
127  
128  reg [2:0] read_state;
129  reg [31:0] rx_data_captured;  // Data word read from host
130  
131  // ========== CDC INPUT SYNCHRONIZERS (clk domain -> ft601_clk_in domain) ==========
132  // The valid signals arrive from clk_100m but the state machine runs on ft601_clk_in.
133  // Even though both are 100 MHz, they are asynchronous clocks and need synchronization.
134  
135  // 2-stage synchronizers for valid signals
136  (* ASYNC_REG = "TRUE" *) reg [1:0] range_valid_sync;
137  (* ASYNC_REG = "TRUE" *) reg [1:0] doppler_valid_sync;
138  (* ASYNC_REG = "TRUE" *) reg [1:0] cfar_valid_sync;
139  
140  // Delayed versions of sync[1] for proper edge detection
141  reg range_valid_sync_d;
142  reg doppler_valid_sync_d;
143  reg cfar_valid_sync_d;
144  
145  // Holding registers: data captured in SOURCE domain (clk_100m) when valid
146  // asserts, then read by ft601 domain after synchronized valid edge.
147  // This is safe because the data is stable for the entire time the valid
148  // pulse is being synchronized (2+ ft601_clk cycles).
149  reg [31:0] range_profile_hold;
150  reg [15:0] doppler_real_hold;
151  reg [15:0] doppler_imag_hold;
152  reg cfar_detection_hold;
153  
154  // Gap 2: Status request toggle register (clk_100m domain).
155  // Declared here (before the always block) to satisfy iverilog forward-ref rules.
156  reg status_req_toggle_100m;
157  
158  // Source-domain holding registers (clk domain)
159  always @(posedge clk or negedge reset_n) begin
160      if (!reset_n) begin
161          range_profile_hold <= 32'd0;
162          doppler_real_hold  <= 16'd0;
163          doppler_imag_hold  <= 16'd0;
164          cfar_detection_hold <= 1'b0;
165          status_req_toggle_100m <= 1'b0;
166      end else begin
167          if (range_valid)
168              range_profile_hold <= range_profile;
169          if (doppler_valid) begin
170              doppler_real_hold <= doppler_real;
171              doppler_imag_hold <= doppler_imag;
172          end
173          if (cfar_valid)
174              cfar_detection_hold <= cfar_detection;
175          // Gap 2: Toggle on status request pulse (CDC to ft601_clk)
176          if (status_request)
177              status_req_toggle_100m <= ~status_req_toggle_100m;
178      end
179  end
180  
181  // FT601-domain captured data (sampled from holding regs on sync'd edge)
182  reg [31:0] range_profile_cap;
183  reg [15:0] doppler_real_cap;
184  reg [15:0] doppler_imag_cap;
185  reg cfar_detection_cap;
186  
187  // Data-pending flags (ft601_clk domain).
188  // Set when a valid edge is detected, cleared when the write FSM consumes
189  // or skips the data. Prevents the write FSM from blocking forever when
190  // a stream's valid hasn't fired yet (e.g., Doppler needs 32 chirps).
191  reg doppler_data_pending;
192  reg cfar_data_pending;
193  
194  // Gap 2: CDC for stream_control (clk_100m -> ft601_clk_in)
195  // stream_control changes infrequently (only on host USB command), so
196  // per-bit 2-stage synchronizers are sufficient. No Gray coding needed
197  // because the bits are independent enables.
198  // Fix #5: Default to range-only (3'b001) on reset to prevent write FSM
199  // deadlock before host configures streams. With all streams enabled on
200  // reset, the first range_valid triggers the write FSM which then blocks
201  // forever on SEND_DOPPLER_DATA (Doppler hasn't produced data yet).
202  (* ASYNC_REG = "TRUE" *) reg [2:0] stream_ctrl_sync_0;
203  (* ASYNC_REG = "TRUE" *) reg [2:0] stream_ctrl_sync_1;
204  wire stream_range_en   = stream_ctrl_sync_1[0];
205  wire stream_doppler_en = stream_ctrl_sync_1[1];
206  wire stream_cfar_en    = stream_ctrl_sync_1[2];
207  
208  // Gap 2: Status request CDC (toggle CDC, same pattern as cmd_valid)
209  // status_request is a 1-cycle pulse in clk_100m. Toggle→sync→edge-detect.
210  // NOTE: status_req_toggle_100m declared above (before source-domain always block)
211  (* ASYNC_REG = "TRUE" *) reg [1:0] status_req_sync;
212  reg status_req_sync_prev;
213  wire status_req_ft601 = status_req_sync[1] ^ status_req_sync_prev;
214  
215  // Status snapshot: captured in ft601_clk domain when status request arrives.
216  // The clk_100m-domain status inputs are stable for many cycles after the
217  // command decode, so sampling them a few ft601_clk cycles later is safe.
218  reg [31:0] status_words [0:5];  // 6 status words (word 5 = self-test)
219  reg [2:0] status_word_idx;
220  
221  wire range_valid_ft;
222  wire doppler_valid_ft;
223  wire cfar_valid_ft;
224  
225  always @(posedge ft601_clk_in or negedge ft601_reset_n) begin
226      if (!ft601_reset_n) begin
227          range_valid_sync   <= 2'b00;
228          doppler_valid_sync <= 2'b00;
229          cfar_valid_sync    <= 2'b00;
230          range_valid_sync_d   <= 1'b0;
231          doppler_valid_sync_d <= 1'b0;
232          cfar_valid_sync_d    <= 1'b0;
233          range_profile_cap  <= 32'd0;
234          doppler_real_cap   <= 16'd0;
235          doppler_imag_cap   <= 16'd0;
236          cfar_detection_cap <= 1'b0;
237          // Fix #5: Default to range-only on reset (prevents write FSM deadlock)
238          stream_ctrl_sync_0 <= 3'b001;
239          stream_ctrl_sync_1 <= 3'b001;
240          // Gap 2: status request CDC reset
241          status_req_sync <= 2'b00;
242          status_req_sync_prev <= 1'b0;
243          status_word_idx <= 3'd0;
244      end else begin
245          // Synchronize valid strobes (2-stage sync chain)
246          range_valid_sync   <= {range_valid_sync[0],   range_valid};
247          doppler_valid_sync <= {doppler_valid_sync[0], doppler_valid};
248          cfar_valid_sync    <= {cfar_valid_sync[0],    cfar_valid};
249  
250          // Gap 2: stream control CDC (2-stage)
251          stream_ctrl_sync_0 <= stream_control;
252          stream_ctrl_sync_1 <= stream_ctrl_sync_0;
253  
254          // Gap 2: status request CDC (toggle sync + edge detect)
255          status_req_sync <= {status_req_sync[0], status_req_toggle_100m};
256          status_req_sync_prev <= status_req_sync[1];
257  
258          // Gap 2: Capture status snapshot when request arrives in ft601 domain
259          if (status_req_ft601) begin
260              // Pack register values into 5x 32-bit status words
261              // Word 0: {0xFF, mode[1:0], stream_ctrl[2:0], cfar_threshold[15:0]}
262              status_words[0] <= {8'hFF, 3'b000, status_radar_mode,
263                                  5'b00000, status_stream_ctrl,
264                                  status_cfar_threshold};
265              // Word 1: {long_chirp_cycles[15:0], long_listen_cycles[15:0]}
266              status_words[1] <= {status_long_chirp, status_long_listen};
267              // Word 2: {guard_cycles[15:0], short_chirp_cycles[15:0]}
268              status_words[2] <= {status_guard, status_short_chirp};
269              // Word 3: {short_listen_cycles[15:0], chirps_per_elev[5:0], 10'b0}
270              status_words[3] <= {status_short_listen, 10'd0, status_chirps_per_elev};
271              // Word 4: Fix 7 — range_mode in bits [1:0], rest reserved
272              status_words[4] <= {30'd0, status_range_mode};
273              // Word 5: Self-test results {reserved[6:0], busy, reserved[7:0], detail[7:0], reserved[2:0], flags[4:0]}
274              status_words[5] <= {7'd0, status_self_test_busy,
275                                  8'd0, status_self_test_detail,
276                                  3'd0, status_self_test_flags};
277          end
278  
279          // Delayed version of sync[1] for edge detection
280          range_valid_sync_d   <= range_valid_sync[1];
281          doppler_valid_sync_d <= doppler_valid_sync[1];
282          cfar_valid_sync_d    <= cfar_valid_sync[1];
283  
284          // Capture data on rising edge of FULLY SYNCHRONIZED valid (sync[1])
285          // Data in holding regs is stable by the time sync[1] rises (2+ cycles)
286          if (range_valid_sync[1] && !range_valid_sync_d)
287              range_profile_cap <= range_profile_hold;
288          if (doppler_valid_sync[1] && !doppler_valid_sync_d) begin
289              doppler_real_cap <= doppler_real_hold;
290              doppler_imag_cap <= doppler_imag_hold;
291          end
292          if (cfar_valid_sync[1] && !cfar_valid_sync_d) begin
293              cfar_detection_cap <= cfar_detection_hold;
294          end
295      end
296  end
297  
298  // Rising-edge detect on FULLY SYNCHRONIZED valid (sync[1], not sync[0])
299  // This provides full 2-stage metastability protection before use.
300  assign range_valid_ft   = range_valid_sync[1]   && !range_valid_sync_d;
301  assign doppler_valid_ft = doppler_valid_sync[1]  && !doppler_valid_sync_d;
302  assign cfar_valid_ft    = cfar_valid_sync[1]     && !cfar_valid_sync_d;
303  
304  // FT601 data bus direction control
305  assign ft601_data = ft601_data_oe ? ft601_data_out : 32'hzzzz_zzzz;
306  
307  always @(posedge ft601_clk_in or negedge ft601_reset_n) begin
308      if (!ft601_reset_n) begin
309          current_state <= IDLE;
310          read_state <= RD_IDLE;
311          byte_counter <= 0;
312          ft601_data_out <= 0;
313          ft601_data_oe <= 0;
314          ft601_be <= 4'b1111;  // All bytes enabled for 32-bit mode
315          ft601_txe_n <= 1;
316          ft601_rxf_n <= 1;
317          ft601_wr_n <= 1;
318          ft601_rd_n <= 1;
319          ft601_oe_n <= 1;
320          ft601_siwu_n <= 1;
321          rx_data_captured <= 32'd0;
322          cmd_data <= 32'd0;
323          cmd_valid <= 1'b0;
324          cmd_opcode <= 8'd0;
325          cmd_addr <= 8'd0;
326          cmd_value <= 16'd0;
327          doppler_data_pending <= 1'b0;
328          cfar_data_pending <= 1'b0;
329          // NOTE: ft601_clk_out is driven by the clk-domain always block below.
330          // Do NOT assign it here (ft601_clk_in domain) — causes multi-driven net.
331      end else begin
332          // Default: clear one-shot signals
333          cmd_valid <= 1'b0;
334  
335          // Data-pending flag management: set on valid edge, cleared when
336          // consumed or skipped by write FSM. Must be in this always block
337          // (not the CDC sync block) to avoid Vivado multiple-driver DRC error.
338          if (doppler_valid_ft)
339              doppler_data_pending <= 1'b1;
340          if (cfar_valid_ft)
341              cfar_data_pending <= 1'b1;
342  
343          // ================================================================
344          // READ FSM — host-to-FPGA command path (Gap 4)
345          //
346          // The read FSM takes priority over write when both could activate.
347          // It only starts when the write FSM is IDLE and ft601_rxf
348          // indicates data from host is available.
349          // ================================================================
350          case (read_state)
351              RD_IDLE: begin
352                  // Only start reading if write FSM is idle and host has data.
353                  // ft601_rxf active-low: 0 means data available from host.
354                  if (current_state == IDLE && !ft601_rxf) begin
355                      ft601_oe_n <= 1'b0;     // Assert OE: tell FT601 to drive bus
356                      ft601_data_oe <= 1'b0;  // FPGA releases bus (FT601 drives)
357                      read_state <= RD_OE_ASSERT;
358                  end
359              end
360  
361              RD_OE_ASSERT: begin
362                  // 1-cycle turnaround: OE_N asserted, bus settling.
363                  // FT601 spec requires 1 clock of OE_N before RD_N assertion.
364                  if (!ft601_rxf) begin
365                      ft601_rd_n <= 1'b0;     // Assert RD: start reading
366                      read_state <= RD_READING;
367                  end else begin
368                      // Host withdrew data — abort
369                      ft601_oe_n <= 1'b1;
370                      read_state <= RD_IDLE;
371                  end
372              end
373  
374              RD_READING: begin
375                  // Data is valid on ft601_data. Sample it.
376                  // For now we read a single 32-bit command word per transaction.
377                  rx_data_captured <= ft601_data;
378                  ft601_rd_n <= 1'b1;         // Deassert RD
379                  read_state <= RD_DEASSERT;
380              end
381  
382              RD_DEASSERT: begin
383                  // Deassert OE_N (1 cycle after RD_N deasserted)
384                  ft601_oe_n <= 1'b1;
385                  read_state <= RD_PROCESS;
386              end
387  
388              RD_PROCESS: begin
389                  // Decode the received command word and pulse cmd_valid.
390                  // Format: {opcode[31:24], addr[23:16], value[15:0]}
391                  cmd_data   <= rx_data_captured;
392                  cmd_opcode <= rx_data_captured[31:24];
393                  cmd_addr   <= rx_data_captured[23:16];
394                  cmd_value  <= rx_data_captured[15:0];
395                  cmd_valid  <= 1'b1;
396                  read_state <= RD_IDLE;
397              end
398  
399              default: read_state <= RD_IDLE;
400          endcase
401  
402          // ================================================================
403          // WRITE FSM — FPGA-to-host data streaming (existing)
404          //
405          // Only operates when read FSM is idle (no bus contention).
406          // ================================================================
407          if (read_state == RD_IDLE) begin
408              case (current_state)
409                  IDLE: begin
410                      ft601_wr_n <= 1;
411                      ft601_data_oe <= 0;  // Release data bus
412                      // Gap 2: Status readback takes priority
413                      if (status_req_ft601 && ft601_rxf) begin
414                          current_state <= SEND_STATUS;
415                          status_word_idx <= 3'd0;
416                      end
417                      // Trigger write FSM on range_valid edge (primary data source).
418                      // Doppler/cfar data_pending flags are checked inside
419                      // SEND_DOPPLER_DATA and SEND_DETECTION_DATA to skip or send.
420                      // Do NOT trigger on pending flags alone — they're sticky and
421                      // would cause repeated packet starts without new range data.
422                      else if (range_valid_ft && stream_range_en) begin
423                          // Don't start write if a read is about to begin
424                          if (ft601_rxf) begin  // rxf=1 means no host data pending
425                              current_state <= SEND_HEADER;
426                              byte_counter <= 0;
427                          end
428                      end
429                  end
430                  
431                  SEND_HEADER: begin
432                      if (!ft601_txe) begin  // FT601 TX FIFO not empty
433                          ft601_data_oe <= 1;
434                          ft601_data_out <= {24'b0, HEADER};
435                          ft601_be <= 4'b0001;  // Only lower byte valid
436                          ft601_wr_n <= 0;     // Assert write strobe
437                          // Gap 2: skip to first enabled stream
438                          if (stream_range_en)
439                              current_state <= SEND_RANGE_DATA;
440                          else if (stream_doppler_en)
441                              current_state <= SEND_DOPPLER_DATA;
442                          else if (stream_cfar_en)
443                              current_state <= SEND_DETECTION_DATA;
444                          else
445                              current_state <= SEND_FOOTER;  // No streams — send footer only
446                      end
447                  end
448                  
449                  SEND_RANGE_DATA: begin
450                      if (!ft601_txe) begin
451                          ft601_data_oe <= 1;
452                          ft601_be <= 4'b1111;  // All bytes valid for 32-bit word
453                          
454                          case (byte_counter)
455                              0: ft601_data_out <= range_profile_cap;
456                              1: ft601_data_out <= {range_profile_cap[23:0], 8'h00};
457                              2: ft601_data_out <= {range_profile_cap[15:0], 16'h0000};
458                              3: ft601_data_out <= {range_profile_cap[7:0], 24'h000000};
459                          endcase
460                          
461                          ft601_wr_n <= 0;
462                          
463                          if (byte_counter == 3) begin
464                              byte_counter <= 0;
465                              // Gap 2: skip disabled streams
466                              if (stream_doppler_en)
467                                  current_state <= SEND_DOPPLER_DATA;
468                              else if (stream_cfar_en)
469                                  current_state <= SEND_DETECTION_DATA;
470                              else
471                                  current_state <= SEND_FOOTER;
472                          end else begin
473                              byte_counter <= byte_counter + 1;
474                          end
475                      end
476                  end
477                  
478                  SEND_DOPPLER_DATA: begin
479                      if (!ft601_txe && doppler_data_pending) begin
480                          ft601_data_oe <= 1;
481                          ft601_be <= 4'b1111;
482                          
483                          case (byte_counter)
484                              0: ft601_data_out <= {doppler_real_cap, doppler_imag_cap};
485                              1: ft601_data_out <= {doppler_imag_cap, doppler_real_cap[15:8], 8'h00};
486                              2: ft601_data_out <= {doppler_real_cap[7:0], doppler_imag_cap[15:8], 16'h0000};
487                              3: ft601_data_out <= {doppler_imag_cap[7:0], 24'h000000};
488                          endcase
489                          
490                          ft601_wr_n <= 0;
491                          
492                          if (byte_counter == 3) begin
493                              byte_counter <= 0;
494                              doppler_data_pending <= 1'b0;
495                              if (stream_cfar_en)
496                                  current_state <= SEND_DETECTION_DATA;
497                              else
498                                  current_state <= SEND_FOOTER;
499                          end else begin
500                              byte_counter <= byte_counter + 1;
501                          end
502                      end else if (!doppler_data_pending) begin
503                          // No doppler data available yet — skip to next stream
504                          byte_counter <= 0;
505                          if (stream_cfar_en)
506                              current_state <= SEND_DETECTION_DATA;
507                          else
508                              current_state <= SEND_FOOTER;
509                      end
510                  end
511                  
512                  SEND_DETECTION_DATA: begin
513                      if (!ft601_txe && cfar_data_pending) begin
514                          ft601_data_oe <= 1;
515                          ft601_be <= 4'b0001;
516                          ft601_data_out <= {24'b0, 7'b0, cfar_detection_cap};
517                          ft601_wr_n <= 0;
518                          cfar_data_pending <= 1'b0;
519                          current_state <= SEND_FOOTER;
520                      end else if (!cfar_data_pending) begin
521                          // No CFAR data available yet — skip to footer
522                          current_state <= SEND_FOOTER;
523                      end
524                  end
525                  
526                  SEND_FOOTER: begin
527                      if (!ft601_txe) begin
528                          ft601_data_oe <= 1;
529                          ft601_be <= 4'b0001;
530                          ft601_data_out <= {24'b0, FOOTER};
531                          ft601_wr_n <= 0;
532                          current_state <= WAIT_ACK;
533                      end
534                  end
535  
536                  // Gap 2: Status readback — send 6 x 32-bit status words
537                  // Format: HEADER, status_words[0..5], FOOTER
538                  SEND_STATUS: begin
539                      if (!ft601_txe) begin
540                          ft601_data_oe <= 1;
541                          ft601_be <= 4'b1111;
542                          case (status_word_idx)
543                              3'd0: begin
544                                  // Send status header marker (0xBB = status response)
545                                  ft601_data_out <= {24'b0, 8'hBB};
546                                  ft601_be <= 4'b0001;
547                              end
548                              3'd1: ft601_data_out <= status_words[0];
549                              3'd2: ft601_data_out <= status_words[1];
550                              3'd3: ft601_data_out <= status_words[2];
551                              3'd4: ft601_data_out <= status_words[3];
552                              3'd5: ft601_data_out <= status_words[4];
553                              3'd6: ft601_data_out <= status_words[5];
554                              3'd7: begin
555                                  // Send status footer
556                                  ft601_data_out <= {24'b0, FOOTER};
557                                  ft601_be <= 4'b0001;
558                              end
559                              default: ;
560                          endcase
561                          ft601_wr_n <= 0;
562                          if (status_word_idx == 3'd7) begin
563                              status_word_idx <= 3'd0;
564                              current_state <= WAIT_ACK;
565                          end else begin
566                              status_word_idx <= status_word_idx + 1;
567                          end
568                      end
569                  end
570                  
571                  WAIT_ACK: begin
572                      ft601_wr_n <= 1;
573                      ft601_data_oe <= 0;  // Release data bus
574                      current_state <= IDLE;
575                  end
576              endcase
577          end
578      end
579  end
580  
581  // ============================================================================
582  // FT601 clock output forwarding
583  // ============================================================================
584  // Forward ft601_clk_in back out via ODDR so that the forwarded clock at the
585  // pin has the same insertion delay as the data outputs (both go through the
586  // same BUFG). This makes the output delay analysis relative to the generated
587  // clock at the pin, where insertion delays cancel.
588  
589  `ifndef SIMULATION
590  ODDR #(
591      .DDR_CLK_EDGE("OPPOSITE_EDGE"),
592      .INIT(1'b0),
593      .SRTYPE("SYNC")
594  ) oddr_ft601_clk (
595      .Q(ft601_clk_out),
596      .C(ft601_clk_in),
597      .CE(1'b1),
598      .D1(1'b1),
599      .D2(1'b0),
600      .R(1'b0),
601      .S(1'b0)
602  );
603  `else
604  // Simulation: behavioral clock forwarding
605  reg ft601_clk_out_sim;
606  always @(posedge ft601_clk_in or negedge ft601_reset_n) begin
607      if (!ft601_reset_n)
608          ft601_clk_out_sim <= 1'b0;
609      else
610          ft601_clk_out_sim <= 1'b1;
611  end
612  // In simulation, just pass the clock through
613  assign ft601_clk_out = ft601_clk_in;
614  `endif
615  
616  endmodule