// part of NeoGS project
//
// (c) NedoPC 2007-2013
//
// SD-card dma controller
/*
supports yet:
1. only read of SD card (512 bytes at once)
2. only full bursing writeback of read data to memory
SD read algo:
send FFs always. Check replies.
After first non-FF reply receive 512 bytes into FPGA mem then into RAM
*/
module dma_sd(
input wire clk,
input wire rst_n,
// control to spi module of SD-card
//
output wire sd_start,
input wire sd_rdy,
input wire [7:0] sd_recvdata,
// signals for ports.v
//
input wire [7:0] din, // input and output from ports.v
output reg [7:0] dout,
//
input wire module_select, // =1 - module selected for read-write operations from ports.v
input wire write_strobe, // one-cycle positive write strobe - writes to the selected registers from din
//
input wire [1:0] regsel, // 2'b00 - high address, 2'b01 - middle address, 2'b10 - low address, 2'b11 - control register
// signals for DMA controller/DMA sequencer
//
output reg [21:0] dma_addr,
output wire [7:0] dma_wd, // data written to DMA
output wire dma_rnw,
//
output wire dma_req,
input wire dma_ack,
input wire dma_end
);
reg dma_on;
reg [21:0] dma_addr;
wire dma_finish;
reg [3:0] state, next_state;
localparam _HAD = 2'b00; // high address
localparam _MAD = 2'b01; // mid address
localparam _LAD = 2'b10; // low address
localparam _CST = 2'b11; // control and status
// only dma writes
assign dma_rnw = 1'b0;
// control dout bus
always @*
case( regsel[1:0] )
_HAD: dout = { 2'b00, dma_addr[21:16] };
_MAD: dout = dma_addr[15:8];
_LAD: dout = dma_addr[7:0];
_CST: dout = { dma_on, 7'bXXX_XXXX };
endcase
// dma_on control
always @(posedge clk, negedge rst_n)
if( !rst_n )
dma_on <= 1'b0;
else if( dma_finish )
dma_on <= 1'b0;
else if( module_select && write_strobe && (regsel==_CST) )
dma_on <= din[7];
// dma_addr control
always @(posedge clk)
if( dma_ack && dma_on )
dma_addr <= dma_addr + 22'd1; // increment on successfull DMA transfer
else if( module_select && write_strobe )
begin
if( regsel==_HAD )
dma_addr[21:16] <= din[5:0];
else if( regsel==_MAD )
dma_addr[15:8] <= din[7:0];
else if( regsel==_LAD )
dma_addr[7:0] <= din[7:0];
end
// controlling FSM
localparam _IDLE = 4'd0;
localparam _WRDY1 = 4'd1; // send start to SPI
localparam _WRDY2 = 4'd2; //
always @(posedge clk, negedge dma_on)
if( !dma_on )
sd_state = _IDLE;
else // posedge clk
state <= next_state;
always @*
case( sd_state )
_IDLE: next_state = _WRDY1;
_WRDY1:begin
next_state = _WRDY2;
end
_WRDY2:begin
if( !sd_rdy )
next_state = _WRDY2;
else if( sd_recvdata==8'hFF )
next_state = _WRDY1;
else if( sd_recvdata==8'hFE )
next_state = _RECV;
else
next_state = _STOP;
end
_STOP:begin
next_state = _STOP; // rely on dma_on going to 0 and resetting everything
end
endcase
// sd_start
assign sd_start = ( state==_WRDY1 || );
// dma_finish
assign dma_finish = ( state==_STOP );
always @(posedge clk, negedge rst_n)
begin
if( !rst_n )
begin
sd_wr_stb = 1'b0;
sd_rd_stb = 1'b0;
sd_start = 1'b0;
sd_override = 1'b0;
sd_idle = 1'b0;
end
else // posedge clk
begin
case( sd_next_state )
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SD_IDLE:begin
sd_wr_stb <= 1'b0;
sd_rd_stb <= 1'b0;
sd_start <= 1'b0;
sd_override <= 1'b0;
sd_idle <= 1'b1;
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SD_READ1:begin
sd_override <= 1'b1; // takeover SD card SPI iface
sd_start <= 1'b0;
sd_wr_stb <= 1'b0;
sd_idle <= 1'b0;
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SD_READ2:begin
sd_start <= 1'b1; // trigger new SPI exchange
sd_wr_stb <= 1'b1; // trigger FIFO write
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SD_WRITE1:begin
sd_override <= 1'b1;
sd_start <= 1'b0;
sd_rd_str <= 1'b0;
sd_idle <= 1'b0;
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
SD_WRITE2:begin
sd_start <= 1'b1;
sd_rd_stb <= 1'b1;
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
endcase
end
end
// DMA-controlling FSM
reg [3:0] dma_state, dma_next_state
localparam DMA_IDLE
localparam DMA_PUT_WAIT
localparam DMA_PUT_RUN
always @(posedge clk, negedge rst_n)
begin
if( !rst_n )
begin
dma_state = DMA_IDLE;
end
else // posedge clk
begin
dma_state <= dma_next_state;
end
end
always @*
begin
case( dma_state )
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DMA_IDLE:begin
if( dma_go )
begin
if( dma_snr )
begin
........dma_state = DMA_GET_WAIT;
end
else // !dma_snr
begin
dma_next_state = DMA_PUT_WAIT;
end
end
else
begin
dma_next_state = DMA_IDLE;
end
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DMA_PUT_WAIT:begin
if( rdone )
begin
dma_next_state = DMA_IDLE;
end
else // !rdone
begin
if( !empty ) // fifo is not empty
begin
dma_next_state = DMA_PUT_RUN;
end
else // fifo empty
begin
dma_next_state = DMA_PUT_WAIT;
end
end
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
DMA_PUT_RUN:begin
if( rdone )
begin
dma_next_state = DMA_IDLE;
end
else
begin
if( empty )
begin
dma_next_state = DMA_PUT_WAIT;
end
else // !empty
begin
dma_next_state = DMA_PUT_RUN;
end
end
end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
endcase
end
always @(posedge clk, negedge rst_n)
begin
if( !rst_n )
begin
end
else // posedge clk
begin
case( dma_next_state )
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
endcase
end
end
endmodule