SummerCart64/fw/rtl/sd/sd_regs.v
2021-02-19 01:36:57 +01:00

247 lines
7.8 KiB
Verilog

module sd_regs (
input i_clk,
input i_reset,
output reg [1:0] o_sd_clk_config,
output reg [5:0] o_command_index,
output reg [31:0] o_command_argument,
output reg o_command_long_response,
output reg o_command_skip_response,
input [5:0] i_command_index,
input [31:0] i_command_response,
output reg o_command_start,
input i_command_busy,
input i_command_timeout,
input i_command_response_crc_error,
output reg o_dat_width,
output reg o_dat_direction,
output reg [6:0] o_dat_block_size,
output reg [7:0] o_dat_num_blocks,
output reg o_dat_start,
output reg o_dat_stop,
input i_dat_busy,
input i_dat_write_busy,
input i_dat_crc_error,
input i_dat_write_error,
input i_dat_write_ok,
output reg o_rx_fifo_flush,
output reg o_rx_fifo_pop,
input i_rx_fifo_empty,
input i_rx_fifo_full,
input i_rx_fifo_overrun,
input [8:0] i_rx_fifo_items,
input [31:0] i_rx_fifo_data,
output reg o_tx_fifo_flush,
output o_tx_fifo_push,
input i_tx_fifo_empty,
input i_tx_fifo_full,
input i_tx_fifo_underrun,
input [8:0] i_tx_fifo_items,
output [31:0] o_tx_fifo_data,
output [3:0] o_dma_bank,
output [23:0] o_dma_address,
output [14:0] o_dma_length,
input [3:0] i_dma_bank,
input [23:0] i_dma_address,
input [14:0] i_dma_left,
output o_dma_load_bank_address,
output o_dma_load_length,
output reg o_dma_direction,
output reg o_dma_start,
output reg o_dma_stop,
input i_dma_busy,
input i_request,
input i_write,
output o_busy,
output reg o_ack,
input [3:0] i_address,
output reg [31:0] o_data,
input [31:0] i_data
);
localparam [2:0] SD_REG_SCR = 3'd0;
localparam [2:0] SD_REG_ARG = 3'd1;
localparam [2:0] SD_REG_CMD = 3'd2;
localparam [2:0] SD_REG_RSP = 3'd3;
localparam [2:0] SD_REG_DAT = 3'd4;
localparam [2:0] SD_REG_DMA_SCR = 3'd5;
localparam [2:0] SD_REG_DMA_ADDR = 3'd6;
localparam [2:0] SD_REG_DMA_LEN = 3'd7;
wire w_write_request = i_request && i_write && !o_busy;
wire w_read_request = i_request && !i_write && !o_busy;
always @(*) begin
o_dma_bank = i_data[31:28];
o_dma_address = i_data[25:2];
o_dma_length = i_data[14:0];
o_dma_load_bank_address = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_ADDR);
o_dma_load_length = w_write_request && !i_address[3] && (i_address[2:0] == SD_REG_DMA_LEN);
o_tx_fifo_data = i_data;
o_tx_fifo_push = w_write_request && i_address[3] && !i_tx_fifo_full && !i_dma_busy;
o_busy = 1'b0;
end
always @(posedge i_clk) begin
o_command_start <= 1'b0;
o_dat_start <= 1'b0;
o_rx_fifo_flush <= 1'b0;
o_tx_fifo_flush <= 1'b0;
o_dma_start <= 1'b0;
o_dat_stop <= 1'b0;
o_dma_stop <= 1'b0;
if (i_reset) begin
o_sd_clk_config <= 2'd0;
o_dat_width <= 1'b0;
o_dat_direction <= 1'b0;
o_dat_block_size <= 7'd0;
o_dat_num_blocks <= 8'd0;
o_dma_direction <= 1'b0;
end else if (w_write_request) begin
if (!i_address[3]) begin
case (i_address[2:0])
SD_REG_SCR: begin
if (!i_command_busy && !i_dat_busy) begin
o_sd_clk_config <= i_data[1:0];
end
if (!i_dat_busy) begin
o_dat_width <= i_data[2];
end
end
SD_REG_ARG: begin
if (!i_command_busy) begin
o_command_argument <= i_data;
end
end
SD_REG_CMD: begin
if (!i_command_busy) begin
{
o_command_skip_response,
o_command_long_response,
o_command_start,
o_command_index
} <= i_data[8:0];
end
end
SD_REG_RSP: begin
end
SD_REG_DAT: begin
if (!i_dat_busy || i_data[1]) begin
{
o_tx_fifo_flush,
o_rx_fifo_flush,
o_dat_num_blocks,
o_dat_block_size,
o_dat_direction,
o_dat_stop,
o_dat_start
} <= i_data[19:0];
end
end
SD_REG_DMA_SCR: begin
if (!i_dma_busy || i_data[1]) begin
{
o_dma_direction,
o_dma_stop,
o_dma_start
} <= i_data[2:0];
end
end
SD_REG_DMA_ADDR: begin
end
SD_REG_DMA_LEN: begin
end
endcase
end
end
end
always @(posedge i_clk) begin
o_rx_fifo_pop <= 1'b0;
o_ack <= 1'b0;
if (i_reset) begin
o_data <= 32'h0000_0000;
end else if (w_read_request) begin
o_ack <= 1'b1;
if (!i_address[3]) begin
case (i_address[2:0])
SD_REG_SCR: begin
o_data <= {29'd0, o_dat_width, o_sd_clk_config};
end
SD_REG_ARG: begin
o_data <= o_command_argument;
end
SD_REG_CMD: begin
o_data <= {
23'd0,
i_command_response_crc_error,
i_command_timeout,
i_command_busy,
i_command_index
};
end
SD_REG_RSP: begin
o_data <= i_command_response;
end
SD_REG_DAT: begin
o_data <= {
3'd0,
i_dat_write_ok,
i_dat_write_error,
i_dat_write_busy,
i_tx_fifo_items,
i_tx_fifo_full,
i_tx_fifo_empty,
i_tx_fifo_underrun,
i_rx_fifo_items,
i_rx_fifo_full,
i_rx_fifo_empty,
i_rx_fifo_overrun,
i_dat_crc_error,
i_dat_busy
};
end
SD_REG_DMA_SCR: begin
o_data <= {29'd0, o_dma_direction, 1'b0, i_dma_busy};
end
SD_REG_DMA_ADDR: begin
o_data <= {i_dma_bank, 2'd0, i_dma_address, 2'b00};
end
SD_REG_DMA_LEN: begin
o_data <= {17'd0, i_dma_left};
end
endcase
end else begin
if (!i_rx_fifo_empty && !i_dma_busy) begin
o_rx_fifo_pop <= 1'b1;
end
o_data <= i_rx_fifo_data;
end
end
end
endmodule