gateware: Initial import of all common parts

Signed-off-by: Sylvain Munaut <tnt@246tNt.com>
diff --git a/gateware/common/rtl/wb_dma.v b/gateware/common/rtl/wb_dma.v
new file mode 100644
index 0000000..c3af029
--- /dev/null
+++ b/gateware/common/rtl/wb_dma.v
@@ -0,0 +1,208 @@
+/*
+ * wb_dma.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_dma #(
+	parameter integer A0W = 9,
+	parameter integer A1W = 9,
+	parameter integer DW = 32
+)(
+	// Master 0
+	output wire [A0W-1:0] m0_addr,
+	input  wire [ DW-1:0] m0_rdata,
+	output wire [ DW-1:0] m0_wdata,
+	output wire           m0_we,
+	output wire           m0_cyc,
+	input  wire           m0_ack,
+
+	// Master 1
+	output wire [A1W-1:0] m1_addr,
+	input  wire [ DW-1:0] m1_rdata,
+	output wire [ DW-1:0] m1_wdata,
+	output wire           m1_we,
+	output wire           m1_cyc,
+	input  wire           m1_ack,
+
+	// Slave (control)
+	input  wire [   1:0] ctl_addr,
+	output wire [DW-1:0] ctl_rdata,
+	input  wire [DW-1:0] ctl_wdata,
+	input  wire          ctl_we,
+	input  wire          ctl_cyc,
+	output wire          ctl_ack,
+
+	// Clock / Reset
+	input  wire clk,
+	input  wire rst
+);
+
+	// Signals
+	// -------
+
+	// Control
+	reg [1:0] state;	// [1] = busy [0] = phase 0(read) 1(write)
+	reg [1:0] state_nxt;
+	reg dir;			// 0 = M0->M1, 1 = M1->M0
+	reg go;
+
+	wire ack_rd;
+	wire ack_wr;
+
+	// Data register
+	wire data_ce;
+	reg  [DW-1:0] data_reg;
+
+	// Address counters
+	wire m0_addr_ce;
+	wire m0_addr_ld;
+	reg  [A0W-1:0] m0_addr_i;
+
+	wire m1_addr_ce;
+	wire m1_addr_ld;
+	reg  [A1W-1:0] m1_addr_i;
+
+	// Length counter
+	wire len_ce;
+	wire len_ld;
+	reg  [12:0] len;
+	wire len_last;
+
+	// Control IF
+	reg  ctl_do_write;
+	reg  ctl_do_read;
+	reg  ctl_ack_i;
+
+
+	// Control
+	// -------
+
+	always @(posedge clk or posedge rst)
+		if (rst)
+			go <= 1'b0;
+		else
+			go <= ctl_do_write & (ctl_addr[1:0] == 2'b00) & ctl_wdata[15];
+
+	always @(posedge clk or posedge rst)
+		if (rst)
+			state <= 2'b00;
+		else
+			state <= state_nxt;
+
+	always @(*)
+	begin
+		state_nxt <= state;
+
+		case (state)
+			2'b00: begin
+				if (go)
+					state_nxt <= 2'b10;
+			end
+
+			2'b10: begin
+				if (ack_rd)
+					state_nxt <= 2'b11;
+			end
+
+			2'b11: begin
+				if (ack_wr)
+					state_nxt <= len_last ? 2'b00 : 2'b10;
+			end
+
+			default:
+				state_nxt <= 2'b00;
+		endcase
+	end
+
+	assign ack_rd = (m0_ack & ~dir) | (m1_ack &  dir);
+	assign ack_wr = (m0_ack &  dir) | (m1_ack & ~dir);
+
+
+	// WB transaction
+	// --------------
+
+	assign m0_cyc = state[1] & ~(state[0] ^ dir);
+	assign m1_cyc = state[1] &  (state[0] ^ dir);
+
+	assign m0_we  =  dir;
+	assign m1_we  = ~dir;
+
+
+	// Data register
+	// -------------
+
+	assign data_ce = ack_rd;
+
+	always @(posedge clk)
+		if (data_ce)
+			data_reg <= dir ? m1_rdata : m0_rdata;
+
+	assign m0_wdata = data_reg;
+	assign m1_wdata = data_reg;
+
+
+	// Address counters
+	// ----------------
+
+	always @(posedge clk)
+		if (m0_addr_ce)
+			m0_addr_i <= m0_addr_ld ? ctl_wdata[A0W-1:0] : (m0_addr_i + 1);
+
+	always @(posedge clk)
+		if (m1_addr_ce)
+			m1_addr_i <= m1_addr_ld ? ctl_wdata[A1W-1:0] : (m1_addr_i + 1);
+
+	assign m0_addr_ce = m0_addr_ld | ack_wr;
+	assign m1_addr_ce = m1_addr_ld | ack_wr;
+
+	assign m0_addr_ld = ctl_do_write & (ctl_addr[1:0] == 2'b10);
+	assign m1_addr_ld = ctl_do_write & (ctl_addr[1:0] == 2'b11);
+
+	assign m0_addr = m0_addr_i;
+	assign m1_addr = m1_addr_i;
+
+
+	// Length counter
+	// --------------
+
+	always @(posedge clk)
+		if (len_ce)
+			len <= len_ld ? { 1'b0, ctl_wdata[11:0] } : (len - 1);
+
+	always @(posedge clk)
+		if (len_ld)
+			dir <= ctl_wdata[14];
+
+	assign len_ce   = len_ld | ack_wr;
+	assign len_ld   = ctl_do_write & (ctl_addr[1:0] == 2'b00);
+	assign len_last = len[12];
+
+
+	// Control IF
+	// ----------
+
+	always @(posedge clk or posedge rst)
+		if (rst) begin
+			ctl_do_write <= 1'b0;
+			ctl_do_read  <= 1'b0;
+			ctl_ack_i    <= 1'b0;
+		end else begin
+			ctl_do_write <= ~ctl_ack_i & ctl_cyc &  ctl_we;
+			ctl_do_read  <= ~ctl_ack_i & ctl_cyc & ~ctl_we & (ctl_addr[1:0] == 2'b00);
+			ctl_ack_i    <= ~ctl_ack_i & ctl_cyc;
+		end
+
+	assign ctl_ack = ctl_ack_i;
+
+	assign ctl_rdata = {
+		{(DW-16){1'b0}},
+		(ctl_do_read ? { state[1], dir, 1'b0, len } : 16'h0000)
+	};
+
+endmodule // wb_dma