/ 9_Firmware / 9_2_FPGA / ddc_input_interface.v
ddc_input_interface.v
 1  `timescale 1ns / 1ps
 2  // ddc_input_interface.v
 3  module ddc_input_interface (
 4      input wire clk,           // 100MHz
 5      input wire reset_n,
 6      
 7      // DDC Input (18-bit)
 8      input wire signed [17:0] ddc_i,
 9      input wire signed [17:0] ddc_q,
10      input wire valid_i,
11      input wire valid_q,
12      
13      // Scaled output (16-bit)
14      output reg signed [15:0] adc_i,
15      output reg signed [15:0] adc_q,
16      output reg adc_valid,
17      
18      // Status
19      output wire data_sync_error
20  );
21  
22  // Synchronize valid signals
23  reg valid_i_reg, valid_q_reg;
24  reg valid_sync;
25  
26  always @(posedge clk or negedge reset_n) begin
27      if (!reset_n) begin
28          valid_i_reg <= 1'b0;
29          valid_q_reg <= 1'b0;
30          valid_sync <= 1'b0;
31          adc_valid <= 1'b0;
32      end else begin
33          valid_i_reg <= valid_i;
34          valid_q_reg <= valid_q;
35          
36          // Require both I and Q valid simultaneously
37          valid_sync <= valid_i_reg && valid_q_reg;
38          adc_valid <= valid_sync;
39      end
40  end
41  
42  // Scale 18-bit to 16-bit with convergent rounding + saturation
43  // ddc_i[17:2] extracts the upper 16 bits; ddc_i[1] is the rounding bit.
44  // Without saturation, 0x7FFF + 1 = 0x8000 (sign flip at positive full scale).
45  // Fix: saturate to 0x7FFF when rounding would overflow a positive value.
46  // Negative values cannot overflow: the most negative 18-bit value (-131072)
47  // truncates to -8192 (0x8000 as 16-bit) and rounding only moves toward zero.
48  wire [15:0] trunc_i = ddc_i[17:2];
49  wire [15:0] trunc_q = ddc_q[17:2];
50  wire        round_i = ddc_i[1];
51  wire        round_q = ddc_q[1];
52  
53  // Overflow occurs only when truncated value is max positive AND round bit set
54  wire        sat_i = (trunc_i == 16'h7FFF) & round_i;
55  wire        sat_q = (trunc_q == 16'h7FFF) & round_q;
56  
57  always @(posedge clk) begin
58      if (valid_sync) begin
59          adc_i <= sat_i ? 16'sh7FFF : (trunc_i + {15'b0, round_i});
60          adc_q <= sat_q ? 16'sh7FFF : (trunc_q + {15'b0, round_q});
61      end
62  end
63  
64  // Error detection
65  assign data_sync_error = (valid_i_reg ^ valid_q_reg);
66  
67  endmodule