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