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