/* * ut_dma_rd.v * * DMA Read (Mem -> USB) * * vim: ts=4 sw=4 * * Copyright (C) 2022 Sylvain Munaut * SPDX-License-Identifier: CERN-OHL-P-2.0 */ `default_nettype none module ut_dma_rd ( // Bus interface output wire [31:0] bus_rdata, input wire [31:0] bus_wdata, input wire bus_we_cmd_lo, input wire bus_we_cmd_hi, // Memory interface output reg [23:0] mi_addr, output reg [ 6:0] mi_len, output wire mi_valid, input wire mi_ready, input wire [7:0] mi_rdata, input wire mi_rstb, input wire mi_rlast, // DMA access to USB EP output wire dma_req, input wire dma_gnt, output reg [15:0] dma_addr, output wire [31:0] dma_data, output wire dma_we, // Clock / Reset input wire clk, input wire rst ); // Signals // ------- // FSM localparam [1:0] ST_IDLE = 0, ST_WAIT_GNT = 1, ST_SUBMIT = 2, ST_DATA = 3; reg [1:0] state; reg [1:0] state_nxt; // DMA interface reg [23:0] data_shift; reg [1:0] data_cnt; // Bus interface // ------------- assign bus_rdata = { 31'd0, (state != ST_IDLE) }; // FSM // --- // State register always @(posedge clk) if (rst) state <= ST_IDLE; else state <= state_nxt; // Next state always @(*) begin // Default state_nxt = state; // Transitions case (state) ST_IDLE: if (bus_we_cmd_lo) state_nxt = ST_WAIT_GNT; ST_WAIT_GNT: if (dma_gnt) state_nxt = ST_SUBMIT; ST_SUBMIT: if (mi_ready) state_nxt = ST_DATA; ST_DATA: if (mi_rstb & mi_rlast) state_nxt = ST_IDLE; endcase end // Memory interface // ---------------- // Address always @(posedge clk) if (bus_we_cmd_hi) mi_addr <= bus_wdata[23:0]; // Length always @(posedge clk) if (bus_we_cmd_lo) mi_len <= { bus_wdata[20:16], 2'b11 }; // Valid assign mi_valid = (state == ST_SUBMIT); // DMA interface // ------------- // Request assign dma_req = (state != ST_IDLE); // Address always @(posedge clk) dma_addr <= bus_we_cmd_lo ? bus_wdata[15:0] : (dma_addr + {16{bus_we_cmd_lo}} + dma_we); /* if (bus_we_cmd_lo) dma_addr <= bus_wdata[15:0]; else dma_addr <= dma_addr + {15'd0, dma_we}; */ // Data write adapter always @(posedge clk) if (state != ST_DATA) data_cnt <= 2'b00; else data_cnt <= data_cnt + mi_rstb; always @(posedge clk) if (mi_rstb) data_shift <= { mi_rdata, data_shift[23:8] }; assign dma_data = { mi_rdata, data_shift }; assign dma_we = mi_rstb & (data_cnt == 2'b11); endmodule // ut_dma_rd