/* * misc.v * * vim: ts=4 sw=4 * * Misc peripheral functions * * Copyright (C) 2019-2020 Sylvain Munaut * SPDX-License-Identifier: CERN-OHL-S-2.0 */ `default_nettype none // `define WITH_PDM_READBACK module misc ( // PDM outputs output wire [1:0] e1_rx_bias, output wire clk_tune_hi, output wire clk_tune_lo, // GPS output wire gps_reset_n, input wire gps_pps, // GPIO inout wire [ 2:0] gpio, // E1 led status output wire [ 7:0] e1_led_state, output wire e1_led_run, input wire e1_led_active, // Button input wire btn_val, input wire btn_stb, // Ticks input wire [ 1:0] tick_e1_rx, input wire [ 1:0] tick_e1_tx, input wire tick_usb_sof, // Reset request output wire rst_req, // Aux UART output wire aux_uart_rx, input wire aux_uart_tx, // Wishbone input wire [ 7:0] wb_addr, output reg [31:0] wb_rdata, input wire [31:0] wb_wdata, input wire wb_we, input wire wb_cyc, output reg wb_ack, // Clock / Reset input wire clk, input wire rst ); // Signals // ------- genvar i; // Bus wire bus_clr; reg bus_we_boot; reg bus_we_gpio; reg bus_we_led; reg [ 1:0] bus_we_pdm_clk; reg [ 1:0] bus_we_pdm_e1; // GPIO reg [3:0] gpio_fn; reg [3:0] gpio_oe; wire [3:0] gpio_oe_io; reg [3:0] gpio_out; wire [3:0] gpio_out_io; wire [3:0] gpio_in; // LED reg [ 8:0] e1_led; // PPS sync wire gps_pps_iob; wire aux_pps_iob; reg pps_in; wire pps_rise; // Counters wire [15:0] cap_e1_rx[0:1]; wire [15:0] cap_e1_tx[0:1]; wire [31:0] cap_pps; wire [31:0] cnt_time; // PDM reg [12:0] pdm_clk[0:1]; reg [ 8:0] pdm_e1[0:1]; // Boot reg [1:0] boot_sel; reg boot_now; // Bus interface // ------------- // Ack always @(posedge clk) wb_ack <= wb_cyc & ~wb_ack; assign bus_clr = ~wb_cyc | wb_ack; // Write enables always @(posedge clk) if (bus_clr | ~wb_we) begin bus_we_boot <= 1'b0; bus_we_gpio <= 1'b0; bus_we_led <= 1'b0; bus_we_pdm_clk[0] <= 1'b0; bus_we_pdm_clk[1] <= 1'b0; bus_we_pdm_e1[0] <= 1'b0; bus_we_pdm_e1[1] <= 1'b0; end else begin bus_we_boot <= wb_addr == 4'h0; bus_we_gpio <= wb_addr == 4'h1; bus_we_led <= wb_addr == 4'h2; bus_we_pdm_clk[0] <= wb_addr == 4'h8; bus_we_pdm_clk[1] <= wb_addr == 4'h9; bus_we_pdm_e1[0] <= wb_addr == 4'ha; bus_we_pdm_e1[1] <= wb_addr == 4'hb; end // Read mux always @(posedge clk) if (bus_clr) wb_rdata <= 32'h00000000; else case (wb_addr[3:0]) 4'h1: wb_rdata <= { 4'h0, gpio_fn, 4'h0, gpio_in, 4'h0, gpio_oe, 4'h0, gpio_out }; 4'h2: wb_rdata <= { 22'h000000, e1_led_active, e1_led }; 4'h4: wb_rdata <= { cap_e1_tx[0], cap_e1_rx[0] }; 4'h5: wb_rdata <= { cap_e1_tx[1], cap_e1_rx[1] }; 4'h6: wb_rdata <= cap_pps; 4'h7: wb_rdata <= cnt_time; `ifdef WITH_PDM_READBACK 4'h8: wb_rdata <= { pdm_clk[0][12], 19'h00000, pdm_clk[0][11:0] }; 4'h9: wb_rdata <= { pdm_clk[1][12], 19'h00000, pdm_clk[1][11:0] }; 4'ha: wb_rdata <= { pdm_e1[0][8], 23'h000000, pdm_e1[0][ 7:0] }; 4'hb: wb_rdata <= { pdm_e1[1][8], 23'h000000, pdm_e1[1][ 7:0] }; `endif default: wb_rdata <= 32'hxxxxxxxx; endcase // GPIO (incl gps reset) // ---- // IOB SB_IO #( .PIN_TYPE(6'b110100), // Reg in/out/oe .PULLUP(1'b1), .IO_STANDARD("SB_LVCMOS") ) gpio_iob_I[3:0] ( .PACKAGE_PIN ({gps_reset_n, gpio}), .CLOCK_ENABLE (1'b1), .INPUT_CLK (clk), .OUTPUT_CLK (clk), .OUTPUT_ENABLE(gpio_oe_io), .D_OUT_0 (gpio_out_io), .D_IN_0 (gpio_in) ); // Alt function // gpio[0]: aux_uart_rx assign gpio_out_io[0] = gpio_fn[0] ? 1'b0 : gpio_out[0]; assign gpio_oe_io[0] = gpio_fn[0] ? 1'b0 : gpio_oe[0]; assign aux_uart_rx = gpio_fn[0] ? gpio_in[0] : 1'b1; // gpio[1]: aux_uart_tx assign gpio_out_io[1] = gpio_fn[1] ? aux_uart_tx : gpio_out[1]; assign gpio_oe_io[1] = gpio_fn[1] ? 1'b1 : gpio_oe[1]; // gpio[2]: aux pps assign gpio_out_io[2] = gpio_fn[2] ? gps_pps_iob : gpio_out[2]; assign gpio_oe_io[2] = gpio_oe[2]; assign aux_pps_iob = gpio_in[2]; // gpio[3]: Always gps_reset_n assign gpio_out_io[3] = gpio_out[3]; assign gpio_oe_io[3] = gpio_oe[3]; // Bus always @(posedge clk or posedge rst) if (rst) begin gpio_fn <= 4'h0; gpio_oe <= 4'h0; gpio_out <= 4'h0; end else if (bus_we_gpio) begin gpio_fn <= wb_wdata[27:24]; gpio_oe <= wb_wdata[11:8]; gpio_out <= wb_wdata[ 3:0]; end // E1 led status // ------------- always @(posedge clk or posedge rst) if (rst) e1_led <= 9'h00; else if (bus_we_led) e1_led <= wb_wdata[8:0]; assign e1_led_state = e1_led[7:0]; assign e1_led_run = e1_led[8]; // PPS input // --------- // IO reg SB_IO #( .PIN_TYPE(6'b000000), // Reg input, no output .PULLUP(1'b0), .IO_STANDARD("SB_LVCMOS") ) pps_iob_I ( .PACKAGE_PIN(gps_pps), .INPUT_CLK (clk), .D_IN_0 (gps_pps_iob) ); // Mux with aux always @(posedge clk) pps_in <= (gpio_fn[2] & ~gpio_oe[2]) ? aux_pps_iob : gps_pps_iob; // Deglitch glitch_filter #( .L(2), .RST_VAL(1'b0), .WITH_SYNCHRONIZER(0) ) pps_flt_I ( .in (pps_in), .val (), .rise (pps_rise), .fall (), .clk (clk), `ifdef SIM .rst (rst) `else // Don't reset so we let the filter settle before // the rest of the logic engages .rst (1'b0) `endif ); // Counters // -------- // E1 ticks capcnt #( .W(16) ) e1_cnt_I[3:0] ( .cnt_cur (), .cnt_cap ({cap_e1_tx[1], cap_e1_rx[1], cap_e1_tx[0], cap_e1_rx[0] }), .inc ({tick_e1_tx[1], tick_e1_rx[1], tick_e1_tx[0], tick_e1_rx[0]}), .cap (tick_usb_sof), .clk (clk), .rst (rst) ); // Time / PPS capcnt #( .W(32) ) time_cnt_I ( .cnt_cur (cnt_time), .cnt_cap (cap_pps), .inc (1'b1), .cap (pps_rise), .clk (clk), .rst (rst) ); // PDM outputs // ----------- // Registers always @(posedge clk or posedge rst) if (rst) begin pdm_clk[0] <= 0; // 13'h1800; pdm_clk[1] <= 0; // 13'h1800; pdm_e1[0] <= 0; // 9'h190; pdm_e1[1] <= 0; // 9'h190; end else begin if (bus_we_pdm_clk[0]) pdm_clk[0] <= { wb_wdata[31], wb_wdata[11:0] }; if (bus_we_pdm_clk[1]) pdm_clk[1] <= { wb_wdata[31], wb_wdata[11:0] }; if (bus_we_pdm_e1[0]) pdm_e1[0] <= { wb_wdata[31], wb_wdata[ 7:0] }; if (bus_we_pdm_e1[1]) pdm_e1[1] <= { wb_wdata[31], wb_wdata[ 7:0] }; end // PDM cores pdm #( .WIDTH(12), .PHY("ICE40"), .DITHER("YES") ) pdm_clk_I[1:0] ( .pdm ({ clk_tune_hi, clk_tune_lo }), .cfg_val({ pdm_clk[1][11:0], pdm_clk[0][11:0] }), .cfg_oe ({ pdm_clk[1][12], pdm_clk[0][12] }), .clk (clk), .rst (rst) ); pdm #( .WIDTH(8), .PHY("ICE40"), .DITHER("NO") ) pdm_e1_I[1:0] ( .pdm ({ e1_rx_bias[1], e1_rx_bias[0] }), .cfg_val({ pdm_e1[1][7:0], pdm_e1[0][7:0] }), .cfg_oe ({ pdm_e1[1][8], pdm_e1[0][8] }), .clk (clk), .rst (rst) ); // DFU / Reboot // ------------ always @(posedge clk or posedge rst) if (rst) begin boot_now <= 1'b0; boot_sel <= 2'b00; end else if (bus_we_boot) begin boot_now <= wb_wdata[2]; boot_sel <= wb_wdata[1:0]; end dfu_helper #( .TIMER_WIDTH(26), .BTN_MODE(0), .DFU_MODE(0) ) dfu_I ( .boot_sel(boot_sel), .boot_now(boot_now), .btn_pad (btn_val), .btn_tick(btn_stb), .btn_val (), .rst_req (rst_req), .clk (clk), .rst (rst) ); endmodule // misc