362 lines
7.5 KiB
Verilog
362 lines
7.5 KiB
Verilog
/*
|
|
* misc.v
|
|
*
|
|
* vim: ts=4 sw=4
|
|
*
|
|
* Misc peripheral functions
|
|
*
|
|
* Copyright (C) 2019-2020 Sylvain Munaut <tnt@246tNt.com>
|
|
* 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
|