Top secrets sources NedoPC ngs

Rev

Rev 98 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

// 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,

        output wire        int_req
);

        reg dma_on;

        wire dma_finish;

        reg [3:0] state, next_state;

        wire wdone,rdone;
       
        reg int_dma_req;



        assign int_req = dma_finish;



        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



        // 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_req && 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;
        localparam _WRDY2  = 4'd2;
        localparam _RECV1  = 4'd3;
        localparam _RECV2  = 4'd4;
        localparam _CRC1   = 4'd5;
        localparam _CRC2   = 4'd6;
        localparam _DMAWR  = 4'd7;
        localparam _STOP   = 4'd8;


        always @(posedge clk, negedge dma_on)
        if( !dma_on )
                state = _IDLE;
        else // posedge clk
                state <= next_state;

        always @*
        case( 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 = _RECV1;
                else   
                            next_state = _STOP;
        end        
                       
        _RECV1:begin   
                if( !wdone )
                        next_state = _RECV2;
                else
                        next_state = _CRC1;
        end

        _RECV2:begin
                if( !sd_rdy )
                        next_state = _RECV2;
                else
                        next_state = _RECV1;
        end

        _CRC1:begin // 1st CRC byte is already started in last _RECV1 state
                if( !sd_rdy )
                        next_state = _CRC1;
                else
                        next_state = _CRC2;
        end

        _CRC2:begin // here just start 2nd CRC byte receive
                next_state = _DMAWR;
        end

        _DMAWR:begin
                if( int_dma_req )
                        next_state = _DMAWR;
                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 || state==_RECV1 || state==_CRC2 );

       
        // dma_finish
        assign dma_finish = ( state==_STOP );

       
       

       

        // only dma writes
        assign dma_rnw = 1'b0;

        assign dma_req = int_dma_req;

        always @(posedge clk, negedge dma_on)
        if( !dma_on )
                int_dma_req <= 1'b0;
        else if( state==_CRC2 )
                int_dma_req <= 1'b1;
        else if( rdone && dma_ack )
                int_dma_req <= 1'b0;



        // fifo
        dma_fifo_oneshot dma_fifo_oneshot
        (
                .clk  (clk   ),
                .rst_n(dma_on),
       
                .wr_stb( state==_RECV2 && sd_rdy ),
                .rd_stb( (dma_req && dma_ack) || state==_CRC2 ),
       
                .wdone(wdone),
                .rdone(rdone),
                .empty(     ),
                .w511 (     ),
       
                .wd(sd_recvdata),
                .rd(dma_wd     )
        );
       
       

endmodule