gateware/icE1usb: Initial import of production hardware gateware

Current version has second E1 channel disabled to allow the
build to works. Works is in progress to optimize the gateware and
the fpga toolchain to allow full featured build.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/gateware/icE1usb/rtl/misc.v b/gateware/icE1usb/rtl/misc.v
new file mode 100644
index 0000000..a1d1a9c
--- /dev/null
+++ b/gateware/icE1usb/rtl/misc.v
@@ -0,0 +1,337 @@
+/*
+ * 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
+
+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,
+
+	// 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_oe;
+	reg  [3:0] gpio_out;
+	wire [3:0] gpio_in;
+
+	// LED
+	reg  [ 8:0] e1_led;
+
+	// PPS sync
+	wire gps_pps_iob;
+	wire gps_pps_r;
+
+	// Counters
+	reg  [15:0] cnt_e1_rx[0:1];
+	reg  [15:0] cap_e1_rx[0:1];
+	reg  [15:0] cnt_e1_tx[0:1];
+	reg  [15:0] cap_e1_tx[0:1];
+	reg  [31:0] cap_gps;
+	reg  [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 <= { 12'h000, gpio_in, 4'h0, gpio_oe, 4'h0, gpio_out };
+				4'h2:    wb_rdata <= { 22'h000000, e1_led_active, e1_led_run, 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_gps;
+				4'h7:    wb_rdata <= cnt_time;
+				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] };
+				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),
+		.D_OUT_0      (gpio_out),
+		.D_IN_0       (gpio_in)
+	);
+
+	// Bus
+	always @(posedge clk or posedge rst)
+		if (rst) begin
+			gpio_oe  <= 4'h0;
+			gpio_out <= 4'h0;
+		end else if (bus_we_gpio) begin
+			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")
+	) btn_iob_I (
+		.PACKAGE_PIN(gps_pps),
+		.INPUT_CLK  (clk),
+		.D_IN_0     (gps_pps_iob)
+	);
+
+	// Deglitch
+	glitch_filter #(
+		.L(2),
+		.RST_VAL(1'b0),
+		.WITH_SYNCHRONIZER(1)
+	) btn_flt_I (
+		.in       (gps_pps_iob),
+		.val      (),
+		.rise     (gps_pps_r),
+		.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
+	for (i=0; i<2; i=i+1) begin
+
+		always @(posedge clk or posedge rst)
+			if (rst)
+				cnt_e1_rx[i] <= 16'h0000;
+			else if (tick_e1_rx[i])
+				cnt_e1_rx[i] <= cnt_e1_rx[i] + 1;
+
+		always @(posedge clk or posedge rst)
+			if (rst)
+				cnt_e1_tx[i] <= 16'h0000;
+			else if (tick_e1_tx[i])
+				cnt_e1_tx[i] <= cnt_e1_tx[i] + 1;
+
+		always @(posedge clk)
+			if (tick_usb_sof) begin
+				cap_e1_rx[i] <= cnt_e1_rx[i];
+				cap_e1_tx[i] <= cnt_e1_tx[i];
+			end
+
+	end
+
+	// GPS
+	always @(posedge clk or posedge rst)
+		if (rst)
+			cap_gps <= 32'h00000000;
+		else if (gps_pps_r)
+			cap_gps <= cnt_time;
+
+	// Time counter
+	always @(posedge clk)
+		if (rst)
+			cnt_time <= 32'h00000000;
+		else
+			cnt_time <= cnt_time + 1;
+
+
+	// 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