aboutsummaryrefslogtreecommitdiffstats
path: root/fpga/usrp3/lib/rfnoc/fosphor/f15_wf_agg.v
blob: 7b12bc4d5fc66a7f41de068ea837e449619a7a7c (plain)
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
/*
 * f15_wf_agg.v
 *
 * Watefall Aggregation
 *
 * Copyright (C) 2016  Ettus Corporation LLC
 *
 * vim: ts=4 sw=4
 */

`ifdef SIM
`default_nettype none
`endif

module f15_wf_agg #(
	parameter integer Y_WIDTH = 12,
	parameter integer X_WIDTH = 16,
	parameter integer DECIM_WIDTH = 8
)(
	input wire [Y_WIDTH-1:0] yin_0,
	input wire [X_WIDTH-1:0] x_0,
	input wire valid_0,
	input wire last_0,
	input wire [15:0] rng_0,

	output wire [Y_WIDTH-1:0] yout_3,
	output wire [7:0] zout_3,
	output wire zvalid_3,

	input wire [1:0] cfg_div,
	input wire cfg_mode,		// 0=MaxHold, 1=Average
	input wire [DECIM_WIDTH-1:0] cfg_decim,
	input wire cfg_decim_changed,

	input wire clk,
	input wire rst
);

	localparam integer R_WIDTH = X_WIDTH + 9;

	// Signals
		// Data pah
	reg [R_WIDTH-1:0] xe_1;
	reg [R_WIDTH-1:0] ye_1;

	wire over_2;
	reg [R_WIDTH-1:0] r_2;
	reg [Y_WIDTH-1:0] x_2;
	reg [Y_WIDTH-1:0] y_2;

	reg [Y_WIDTH-1:0] y_3;

		// Control
	reg [DECIM_WIDTH:0] decim_cnt;
	reg init_0;
	wire init_2;
	reg init_force_0;
	reg flush_0;
	reg zvalid_1;


	// Datapath
	// --------

	// X predivision mux
	always @(posedge clk)
	begin
		case (cfg_div)
			2'b00:
				xe_1 <= { 1'd0, x_0, 8'd0 };	// 1:1

			2'b01:
				xe_1 <= { 4'd0, x_0, 5'd0 };	// 1:8

			2'b10:
				xe_1 <= { 7'd0, x_0, 2'd0 };	// 1:64

			2'b11:
				xe_1 <= { 9'd0, x_0 };			// 1:256
		endcase
	end

	// Y register
	always @(posedge clk)
	begin
		if (cfg_mode)
			// Average
			ye_1 <= { 1'b0, yin_0, rng_0[R_WIDTH-Y_WIDTH-2:0] };
		else
			// Max Hold
			ye_1 <= { 1'b0, yin_0, {(R_WIDTH-Y_WIDTH-1){1'b0}} };
	end

	// Adder / Substractor
	always @(posedge clk)
	begin
		if (cfg_mode)
			// Average
			r_2 <= ye_1 + xe_1;
		else
			// Max-Hold
			r_2 <= ye_1 - xe_1;
	end

	assign over_2 = r_2[R_WIDTH-1];

	// Registers for the two branches.
	always @(posedge clk)
	begin
		x_2 <= xe_1[R_WIDTH-2:R_WIDTH-Y_WIDTH-1];
		y_2 <= ye_1[R_WIDTH-2:R_WIDTH-Y_WIDTH-1];
	end

	// Output mux
	always @(posedge clk)
	begin
		// If first : take x_2
		// If average :
		//  - If overflow = 0 -> take r_2
		//  - If overflow = 1 -> sature to all 1's
		// If max-hold
		//  - If overflow = 0 -> take y_2
		//  - If overflow = 1 -> take x_2
		if (init_2)
			y_3 <= x_2;
		else if (cfg_mode)
			y_3 <= over_2 ? { (Y_WIDTH){1'b1} } : r_2[R_WIDTH-2:R_WIDTH-Y_WIDTH-1];
		else
			y_3 <= over_2 ? x_2 : y_2;
	end

	assign yout_3 = y_3;
	assign zout_3 = y_3[Y_WIDTH-1:Y_WIDTH-8];


	// Control
	// -------

	// 1-in-N decimation counter
	always @(posedge clk)
	begin
		if (rst)
			decim_cnt <= 0;
		else if (cfg_decim_changed)
			// Force Reload
			decim_cnt <= { 1'b0, cfg_decim };
		else if (valid_0 & last_0)
			if (decim_cnt[DECIM_WIDTH])
				// Reload
				decim_cnt <= { 1'b0, cfg_decim };
			else
				// Just decrement
				decim_cnt <= decim_cnt - 1;
	end

	// Decimation flush & init states
	always @(posedge clk)
	begin
		if (rst) begin
			// Initial state
			flush_0 <= 1'b0;
			init_0  <= 1'b1;
			init_force_0 <= 1'b0;
		end else begin
			if (valid_0 & last_0) begin
				// Flushing
				flush_0 <= decim_cnt[DECIM_WIDTH];

				// Init after flush or if forced
				init_0 <= flush_0 | init_force_0;
			end

			// Init forcing after a decim change
			if (cfg_decim_changed)
				init_force_0 <= 1'b1;
			else if (valid_0 & last_0)
				init_force_0 <= 1'b0;
		end
	end

	delay_bit #(2) dl_init(init_0, init_2, clk);

	// Z-output valid
	always @(posedge clk)
		zvalid_1 <= valid_0 & flush_0;

	delay_bit #(2) dl_zvalid(zvalid_1, zvalid_3, clk);

endmodule // f15_wf_agg