Attention

This documentation is a work in progress. Expect to see errors and unfinished things.

complex_freq Source File

  1`timescale 1ns / 1ns
  2
  3module complex_freq #(
  4     parameter refcnt_w = 17
  5) (
  6     input clk,  // single clock domain
  7     input signed [17:0] sdata,
  8     input sgate,  // high for two cycles representing I and Q
  9     output signed [refcnt_w-1:0] freq,
 10     output freq_valid, // Asserted when freq output is valid
 11     output [16:0] amp_max,
 12     output [16:0] amp_min,
 13     output updated, // Asserted when amp_{max,min} are updated
 14     output timing_err, // New data received while calculation is ongoing
 15     //
 16     // Additional output giving magnitude-squared, meant to
 17     // support average power calculations; can be ignored.
 18     output [23:0] square_sum_out,
 19     output square_sum_valid
 20);
 21
 22// One multiplier to square the inputs
 23reg signed [35:0] square, square_d;
 24reg signed [36:0] square_sum;
 25always @(posedge clk) begin
 26     square <= sdata*sdata;
 27     square_d <= square;
 28     square_sum <= square + square_d;
 29end
 30wire [33:0] square_sum_cut = square_sum[33:0];
 31
 32// Find cycle of valid sum
 33reg sgate1, sgate2, sum_valid;
 34always @(posedge clk) begin
 35     sgate1 <= sgate;
 36     sgate2 <= sgate1;
 37     sum_valid <= sgate1 & sgate2;
 38end
 39
 40assign square_sum_out = square_sum_cut[33:10];
 41assign square_sum_valid = sum_valid;
 42
 43// Sqrt for convenience and to keep the word width down
 44wire [16:0] sqrt_val;
 45wire sqrt_valid;
 46isqrt #(.X_WIDTH(34)) sqrt(.clk(clk), .x(square_sum_cut), .en(sum_valid),
 47     .y(sqrt_val), .dav(sqrt_valid));
 48
 49// Catch obvious errors; leave latching to the upper layers
 50reg busy=0, timing_err_r=0;
 51always @(posedge clk) begin
 52     if (sum_valid) busy <= 1;
 53     if (sqrt_valid) busy <= 0;
 54     timing_err_r <= busy & sgate;
 55end
 56assign timing_err = timing_err_r;
 57
 58// Find min and max
 59wire rollover;
 60reg [16:0] amp_max_x, amp_min_x;  // developing values
 61reg [16:0] amp_max_r, amp_min_r;  // frozen values reported to caller
 62wire cmp_gt = sqrt_val > amp_max_x;
 63wire cmp_lt = sqrt_val < amp_min_x;
 64always @(posedge clk) begin
 65     if (sqrt_valid && (cmp_gt || rollover)) amp_max_x <= sqrt_val;
 66     if (sqrt_valid && (cmp_lt || rollover)) amp_min_x <= sqrt_val;
 67     if (sqrt_valid && rollover) begin
 68             amp_max_r <= amp_max_x;
 69             amp_min_r <= amp_min_x;
 70     end
 71end
 72assign amp_max = amp_max_r;
 73assign amp_min = amp_min_r;
 74
 75// Reference counter
 76reg [refcnt_w-1:0] refcnt=1;
 77reg rollover_r=0;
 78always @(posedge clk) begin
 79     if (sqrt_valid) refcnt <= refcnt-1;
 80     rollover_r <= &refcnt;
 81end
 82assign rollover = rollover_r;
 83
 84// Frequency counter
 85reg [refcnt_w:0] quad_cnt, freq_r;
 86reg [1:0] quad, oldquad;
 87wire [1:0] transition = quad - oldquad;
 88reg invalid=0, freq_valid_r=0;
 89wire newbit = sdata[17] ^ (sgate1 & quad[0]);
 90reg updated_r=0;
 91always @(posedge clk) begin
 92     if (sgate) quad <= {quad[0], newbit};
 93     if (sum_valid) begin
 94             oldquad <= quad;
 95             case (transition)
 96             0: quad_cnt <= quad_cnt;
 97             1: quad_cnt <= quad_cnt-1;
 98             2: invalid <= 1;
 99             3: quad_cnt <= quad_cnt+1;
100             endcase
101     end
102     if (sqrt_valid && rollover) begin
103             freq_r <= quad_cnt;
104             freq_valid_r <= ~invalid;
105             quad_cnt <= 0;
106             invalid <= 0;
107     end
108     updated_r <= sqrt_valid && rollover;
109end
110assign freq = freq_r[refcnt_w:1];
111assign freq_valid = freq_valid_r;
112assign updated = updated_r;
113
114endmodule