gateware: Initial import of all common parts

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/gateware/common/rtl/wb_arbiter.v b/gateware/common/rtl/wb_arbiter.v
new file mode 100644
index 0000000..e924eee
--- /dev/null
+++ b/gateware/common/rtl/wb_arbiter.v
@@ -0,0 +1,127 @@
+/*
+ * wb_arbiter.v
+ *
+ * vim: ts=4 sw=4
+ *
+ * Copyright (C) 2020  Sylvain Munaut <tnt@246tNt.com>
+ * SPDX-License-Identifier: CERN-OHL-P-2.0
+ */
+
+`default_nettype none
+
+module wb_arbiter #(
+	parameter integer N = 3,
+	parameter integer DW = 32,
+	parameter integer AW = 16,
+	parameter integer MW = DW / 8
+)(
+	/* Slave buses */
+	input  wire [(N*AW)-1:0] s_addr,
+	output wire [(N*DW)-1:0] s_rdata,
+	input  wire [(N*DW)-1:0] s_wdata,
+	input  wire [(N*MW)-1:0] s_wmsk,
+	input  wire [ N    -1:0] s_we,
+	input  wire [ N    -1:0] s_cyc,
+	output wire [ N    -1:0] s_ack,
+
+	/* Master bus */
+	output reg  [AW-1:0] m_addr,
+	input  wire [DW-1:0] m_rdata,
+	output reg  [DW-1:0] m_wdata,
+	output reg  [MW-1:0] m_wmsk,
+	output reg           m_we,
+	output wire          m_cyc,
+	input  wire          m_ack,
+
+	/* Clock / Reset */
+	input  wire clk,
+	input  wire rst
+);
+
+	// Signals
+	// -------
+
+	genvar i;
+
+	reg  [AW-1:0] mux_addr;
+	reg  [DW-1:0] mux_wdata;
+	reg  [MW-1:0] mux_wmsk;
+
+	reg  [N-1:0] sel_nxt;
+	reg  [N-1:0] sel;
+	reg  busy;
+	wire reselect;
+
+
+	// Muxing
+	// ------
+
+	for (i=0; i<N; i=i+1)
+	begin
+		assign s_rdata[DW*i+:DW] = sel[i] ? m_rdata : { DW{1'b0} };
+		assign s_ack[i] = sel[i] ? m_ack : 1'b0;
+	end
+
+	always @(*)
+	begin : mux
+		integer i;
+
+		mux_addr  = { AW{1'b0} };
+		mux_wdata = { DW{1'b0} };
+		mux_wmsk  = { MW{1'b0} };
+
+		for (i=N-1; i>=0; i=i-1) begin
+			mux_addr  = mux_addr  | (sel_nxt[i] ? s_addr[AW*i+:AW]  : { AW{1'b0} });
+			mux_wdata = mux_wdata | (sel_nxt[i] ? s_wdata[DW*i+:DW] : { DW{1'b0} });
+			mux_wmsk  = mux_wmsk  | (sel_nxt[i] ? s_wmsk[MW*i+:MW]  : { MW{1'b0} });
+		end
+	end
+
+	always @(posedge clk or posedge rst)
+	begin
+		if (rst) begin
+			m_addr  <= { AW{1'b0} };
+			m_wdata <= { DW{1'b0} };
+			m_wmsk  <= { MW{1'b0} };
+			m_we    <= 1'b0;
+		end else if (reselect) begin
+			m_addr  <= mux_addr;
+			m_wdata <= mux_wdata;
+			m_wmsk  <= mux_wmsk;
+			m_we    <= |(s_we & sel_nxt);
+		end
+	end
+
+
+	// Arbitration
+	// -----------
+
+	// Priority encoder for the next master
+	always @(*)
+	begin : prio
+		integer i;
+
+		sel_nxt <= 0;
+		for (i=N-1; i>=0; i=i-1)
+			if (s_cyc[i] & ~sel[i]) begin
+				sel_nxt    <= 0;
+				sel_nxt[i] <= 1'b1;
+			end
+	end
+
+	// When to reselect
+	assign reselect = m_ack | ~busy;
+
+	// Register current master (if any)
+	always @(posedge clk or posedge rst)
+		if (rst) begin
+			busy <= 1'b0;
+			sel  <= 0;
+		end else if (reselect) begin
+			busy <= |(s_cyc & ~sel);
+			sel  <= sel_nxt;
+		end
+
+	assign m_cyc = busy;
+
+endmodule // wb_arbiter