blob: a1d1a9cbfcf95ad434b562ef151544dda09ce1ca [file] [log] [blame]
Sylvain Munautbd83e532020-09-15 22:11:29 +02001/*
2 * misc.v
3 *
4 * vim: ts=4 sw=4
5 *
6 * Misc peripheral functions
7 *
8 * Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
9 * SPDX-License-Identifier: CERN-OHL-S-2.0
10 */
11
12`default_nettype none
13
14module misc (
15 // PDM outputs
16 output wire [1:0] e1_rx_bias,
17
18 output wire clk_tune_hi,
19 output wire clk_tune_lo,
20
21 // GPS
22 output wire gps_reset_n,
23 input wire gps_pps,
24
25 // GPIO
26 inout wire [ 2:0] gpio,
27
28 // E1 led status
29 output wire [ 7:0] e1_led_state,
30 output wire e1_led_run,
31 input wire e1_led_active,
32
33 // Button
34 input wire btn_val,
35 input wire btn_stb,
36
37 // Ticks
38 input wire [ 1:0] tick_e1_rx,
39 input wire [ 1:0] tick_e1_tx,
40 input wire tick_usb_sof,
41
42 // Reset request
43 output wire rst_req,
44
45 // Wishbone
46 input wire [ 7:0] wb_addr,
47 output reg [31:0] wb_rdata,
48 input wire [31:0] wb_wdata,
49 input wire wb_we,
50 input wire wb_cyc,
51 output reg wb_ack,
52
53 // Clock / Reset
54 input wire clk,
55 input wire rst
56);
57
58 // Signals
59 // -------
60
61 genvar i;
62
63 // Bus
64 wire bus_clr;
65 reg bus_we_boot;
66 reg bus_we_gpio;
67 reg bus_we_led;
68 reg [ 1:0] bus_we_pdm_clk;
69 reg [ 1:0] bus_we_pdm_e1;
70
71 // GPIO
72 reg [3:0] gpio_oe;
73 reg [3:0] gpio_out;
74 wire [3:0] gpio_in;
75
76 // LED
77 reg [ 8:0] e1_led;
78
79 // PPS sync
80 wire gps_pps_iob;
81 wire gps_pps_r;
82
83 // Counters
84 reg [15:0] cnt_e1_rx[0:1];
85 reg [15:0] cap_e1_rx[0:1];
86 reg [15:0] cnt_e1_tx[0:1];
87 reg [15:0] cap_e1_tx[0:1];
88 reg [31:0] cap_gps;
89 reg [31:0] cnt_time;
90
91 // PDM
92 reg [12:0] pdm_clk[0:1];
93 reg [ 8:0] pdm_e1[0:1];
94
95 // Boot
96 reg [1:0] boot_sel;
97 reg boot_now;
98
99
100 // Bus interface
101 // -------------
102
103 // Ack
104 always @(posedge clk)
105 wb_ack <= wb_cyc & ~wb_ack;
106
107 assign bus_clr = ~wb_cyc | wb_ack;
108
109 // Write enables
110 always @(posedge clk)
111 if (bus_clr | ~wb_we) begin
112 bus_we_boot <= 1'b0;
113 bus_we_gpio <= 1'b0;
114 bus_we_led <= 1'b0;
115 bus_we_pdm_clk[0] <= 1'b0;
116 bus_we_pdm_clk[1] <= 1'b0;
117 bus_we_pdm_e1[0] <= 1'b0;
118 bus_we_pdm_e1[1] <= 1'b0;
119 end else begin
120 bus_we_boot <= wb_addr == 4'h0;
121 bus_we_gpio <= wb_addr == 4'h1;
122 bus_we_led <= wb_addr == 4'h2;
123 bus_we_pdm_clk[0] <= wb_addr == 4'h8;
124 bus_we_pdm_clk[1] <= wb_addr == 4'h9;
125 bus_we_pdm_e1[0] <= wb_addr == 4'ha;
126 bus_we_pdm_e1[1] <= wb_addr == 4'hb;
127 end
128
129 // Read mux
130 always @(posedge clk)
131 if (bus_clr)
132 wb_rdata <= 32'h00000000;
133 else
134 case (wb_addr[3:0])
135 4'h1: wb_rdata <= { 12'h000, gpio_in, 4'h0, gpio_oe, 4'h0, gpio_out };
136 4'h2: wb_rdata <= { 22'h000000, e1_led_active, e1_led_run, e1_led };
137 4'h4: wb_rdata <= { cap_e1_tx[0], cap_e1_rx[0] };
138 4'h5: wb_rdata <= { cap_e1_tx[1], cap_e1_rx[1] };
139 4'h6: wb_rdata <= cap_gps;
140 4'h7: wb_rdata <= cnt_time;
141 4'h8: wb_rdata <= { pdm_clk[0][12], 19'h00000, pdm_clk[0][11:0] };
142 4'h9: wb_rdata <= { pdm_clk[1][12], 19'h00000, pdm_clk[1][11:0] };
143 4'ha: wb_rdata <= { pdm_e1[0][8], 23'h000000, pdm_e1[0][ 7:0] };
144 4'hb: wb_rdata <= { pdm_e1[1][8], 23'h000000, pdm_e1[1][ 7:0] };
145 default: wb_rdata <= 32'hxxxxxxxx;
146 endcase
147
148
149 // GPIO (incl gps reset)
150 // ----
151
152 // IOB
153 SB_IO #(
154 .PIN_TYPE(6'b110100), // Reg in/out/oe
155 .PULLUP(1'b1),
156 .IO_STANDARD("SB_LVCMOS")
157 ) gpio_iob_I[3:0] (
158 .PACKAGE_PIN ({gps_reset_n, gpio}),
159 .CLOCK_ENABLE (1'b1),
160 .INPUT_CLK (clk),
161 .OUTPUT_CLK (clk),
162 .OUTPUT_ENABLE(gpio_oe),
163 .D_OUT_0 (gpio_out),
164 .D_IN_0 (gpio_in)
165 );
166
167 // Bus
168 always @(posedge clk or posedge rst)
169 if (rst) begin
170 gpio_oe <= 4'h0;
171 gpio_out <= 4'h0;
172 end else if (bus_we_gpio) begin
173 gpio_oe <= wb_wdata[11:8];
174 gpio_out <= wb_wdata[ 3:0];
175 end
176
177
178 // E1 led status
179 // -------------
180
181 always @(posedge clk or posedge rst)
182 if (rst)
183 e1_led <= 9'h00;
184 else if (bus_we_led)
185 e1_led <= wb_wdata[8:0];
186
187 assign e1_led_state = e1_led[7:0];
188 assign e1_led_run = e1_led[8];
189
190
191 // PPS input
192 // ---------
193
194 // IO reg
195 SB_IO #(
196 .PIN_TYPE(6'b000000), // Reg input, no output
197 .PULLUP(1'b0),
198 .IO_STANDARD("SB_LVCMOS")
199 ) btn_iob_I (
200 .PACKAGE_PIN(gps_pps),
201 .INPUT_CLK (clk),
202 .D_IN_0 (gps_pps_iob)
203 );
204
205 // Deglitch
206 glitch_filter #(
207 .L(2),
208 .RST_VAL(1'b0),
209 .WITH_SYNCHRONIZER(1)
210 ) btn_flt_I (
211 .in (gps_pps_iob),
212 .val (),
213 .rise (gps_pps_r),
214 .fall (),
215 .clk (clk),
216`ifdef SIM
217 .rst (rst)
218`else
219 // Don't reset so we let the filter settle before
220 // the rest of the logic engages
221 .rst (1'b0)
222`endif
223 );
224
225
226 // Counters
227 // --------
228
229 // E1 ticks
230 for (i=0; i<2; i=i+1) begin
231
232 always @(posedge clk or posedge rst)
233 if (rst)
234 cnt_e1_rx[i] <= 16'h0000;
235 else if (tick_e1_rx[i])
236 cnt_e1_rx[i] <= cnt_e1_rx[i] + 1;
237
238 always @(posedge clk or posedge rst)
239 if (rst)
240 cnt_e1_tx[i] <= 16'h0000;
241 else if (tick_e1_tx[i])
242 cnt_e1_tx[i] <= cnt_e1_tx[i] + 1;
243
244 always @(posedge clk)
245 if (tick_usb_sof) begin
246 cap_e1_rx[i] <= cnt_e1_rx[i];
247 cap_e1_tx[i] <= cnt_e1_tx[i];
248 end
249
250 end
251
252 // GPS
253 always @(posedge clk or posedge rst)
254 if (rst)
255 cap_gps <= 32'h00000000;
256 else if (gps_pps_r)
257 cap_gps <= cnt_time;
258
259 // Time counter
260 always @(posedge clk)
261 if (rst)
262 cnt_time <= 32'h00000000;
263 else
264 cnt_time <= cnt_time + 1;
265
266
267 // PDM outputs
268 // -----------
269
270 // Registers
271 always @(posedge clk or posedge rst)
272 if (rst) begin
273 pdm_clk[0] <= 0; // 13'h1800;
274 pdm_clk[1] <= 0; // 13'h1800;
275 pdm_e1[0] <= 0; // 9'h190;
276 pdm_e1[1] <= 0; // 9'h190;
277 end else begin
278 if (bus_we_pdm_clk[0]) pdm_clk[0] <= { wb_wdata[31], wb_wdata[11:0] };
279 if (bus_we_pdm_clk[1]) pdm_clk[1] <= { wb_wdata[31], wb_wdata[11:0] };
280 if (bus_we_pdm_e1[0]) pdm_e1[0] <= { wb_wdata[31], wb_wdata[ 7:0] };
281 if (bus_we_pdm_e1[1]) pdm_e1[1] <= { wb_wdata[31], wb_wdata[ 7:0] };
282 end
283
284 // PDM cores
285 pdm #(
286 .WIDTH(12),
287 .PHY("ICE40"),
288 .DITHER("YES")
289 ) pdm_clk_I[1:0] (
290 .pdm ({ clk_tune_hi, clk_tune_lo }),
291 .cfg_val({ pdm_clk[1][11:0], pdm_clk[0][11:0] }),
292 .cfg_oe ({ pdm_clk[1][12], pdm_clk[0][12] }),
293 .clk (clk),
294 .rst (rst)
295 );
296
297 pdm #(
298 .WIDTH(8),
299 .PHY("ICE40"),
300 .DITHER("NO")
301 ) pdm_e1_I[1:0] (
302 .pdm ({ e1_rx_bias[1], e1_rx_bias[0] }),
303 .cfg_val({ pdm_e1[1][7:0], pdm_e1[0][7:0] }),
304 .cfg_oe ({ pdm_e1[1][8], pdm_e1[0][8] }),
305 .clk (clk),
306 .rst (rst)
307 );
308
309
310 // DFU / Reboot
311 // ------------
312
313 always @(posedge clk or posedge rst)
314 if (rst) begin
315 boot_now <= 1'b0;
316 boot_sel <= 2'b00;
317 end else if (bus_we_boot) begin
318 boot_now <= wb_wdata[2];
319 boot_sel <= wb_wdata[1:0];
320 end
321
322 dfu_helper #(
323 .TIMER_WIDTH(26),
324 .BTN_MODE(0),
325 .DFU_MODE(0)
326 ) dfu_I (
327 .boot_sel(boot_sel),
328 .boot_now(boot_now),
329 .btn_pad (btn_val),
330 .btn_tick(btn_stb),
331 .btn_val (),
332 .rst_req (rst_req),
333 .clk (clk),
334 .rst (rst)
335 );
336
337endmodule // misc