gateware/icE1usb-proto: Initial import

This is the project specific to the PMOD based early prototype.
It was used either with the icebreaker or the icebreaker-bitsy
board as host. Set BOARD variable appropriately during build.

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/gateware/icE1usb-proto/rtl/misc.v b/gateware/icE1usb-proto/rtl/misc.v
new file mode 100644
index 0000000..e7a2854
--- /dev/null
+++ b/gateware/icE1usb-proto/rtl/misc.v
@@ -0,0 +1,217 @@
+/*
+ * 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 e1_vref_ct_pdm,
+	output wire e1_vref_p_pdm,
+	output wire e1_vref_n_pdm,
+
+	output wire clk_tune_hi,
+	output wire clk_tune_lo,
+
+	// Button
+	input  wire btn,
+
+	// Ticks
+	input  wire tick_e1_rx,
+	input  wire 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
+	// -------
+
+	// Bus
+	wire        bus_clr;
+	reg         bus_we_boot;
+	reg  [ 1:0] bus_we_pdm_clk;
+	reg  [ 2:0] bus_we_pdm_e1;
+
+	// Counters
+	reg  [15:0] cnt_e1_rx;
+	reg  [15:0] cap_e1_rx;
+	reg  [15:0] cnt_e1_tx;
+	reg  [15:0] cap_e1_tx;
+	reg  [31:0] cnt_time;
+
+	// PDM
+	reg  [12:0] pdm_clk[0:1];
+	reg  [ 8:0] pdm_e1[0:2];
+
+	// 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_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;
+			bus_we_pdm_e1[2]  <= 1'b0;
+		end else begin
+			bus_we_boot       <= wb_addr == 4'h0;
+			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;
+			bus_we_pdm_e1[2]  <= wb_addr == 4'hc;
+		end
+
+	// Read mux
+	always @(posedge clk)
+		if (bus_clr)
+			wb_rdata <= 32'h00000000;
+		else
+			case (wb_addr[3:0])
+				4'h4:    wb_rdata <= { cap_e1_rx, cap_e1_tx };
+				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] };
+				4'hc:    wb_rdata <= {  pdm_e1[2][8], 23'h000000,  pdm_e1[2][ 7:0] };
+				default: wb_rdata <= 32'hxxxxxxxx;
+			endcase
+
+
+	// Counters
+	// --------
+
+	// E1 ticks
+	always @(posedge clk or posedge rst)
+		if (rst)
+			cnt_e1_rx <= 16'h0000;
+		else if (tick_e1_rx)
+			cnt_e1_rx <= cnt_e1_rx + 1;
+
+	always @(posedge clk or posedge rst)
+		if (rst)
+			cnt_e1_tx <= 16'h0000;
+		else if (tick_e1_tx)
+			cnt_e1_tx <= cnt_e1_tx + 1;
+
+	always @(posedge clk)
+		if (tick_usb_sof) begin
+			cap_e1_rx <= cnt_e1_rx;
+			cap_e1_tx <= cnt_e1_tx;
+		end
+
+	// 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;
+			pdm_e1[2]  <= 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] };
+			if (bus_we_pdm_e1[2])   pdm_e1[2]  <= { 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[2:0] (
+		.pdm    ({ e1_vref_ct_pdm, e1_vref_p_pdm,  e1_vref_n_pdm  }),
+		.cfg_val({ pdm_e1[2][7:0], pdm_e1[1][7:0], pdm_e1[0][7:0] }),
+		.cfg_oe ({ pdm_e1[2][8],   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(3),
+		.DFU_MODE(0)
+	) dfu_I (
+		.boot_sel(boot_sel),
+		.boot_now(boot_now),
+		.btn_pad (btn),
+		.btn_val (),
+		.rst_req (rst_req),
+		.clk     (clk),
+		.rst     (rst)
+	);
+
+endmodule // misc