Top secrets sources NedoPC ngs

Rev

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

// part of NeoGS project
//
// (c) NedoPC 2007-2008
//
// modelling is in tb_dma1.*
// look also at dma_access.png

module dma_access(

        input            clk,

        input            rst_n,


        input            dma_req,  // DMA request
        input     [21:0] dma_addr, // DMA address (2mb)
        input            dma_rnw,  // DMA READ/nWRITE
        input      [7:0] dma_wd,   // DMA data to write
        output reg [7:0] dma_rd,   // DMA data just read

        output reg       dma_busynready, // DMA BUSY/nREADY
        output reg       dma_ack, // positive pulse as dma_busynready goes high
        output reg       dma_end, // positive pulse as dma_busynready goes low

        output wire        mem_dma_bus,  // DMA taking over the bus
        output wire [21:0] mem_dma_addr, // DMA address going to the bus
        output wire  [7:0] mem_dma_wd,   // DMA data going to the bus
        input        [7:0] mem_dma_rd,   // DMA data going from the bus
        output wire        mem_dma_rnw,  // DMA bus direction (1=read, 0=write)
        output reg         mem_dma_oe,   // DMA read strobe going to the bus
        output reg         mem_dma_we,   // DMA write pulse going to the bus


        output reg       busrq_n, // CPU       signals
        input            busak_n  //    control
);

        reg dma_bus;

        reg [21:0] int_dma_addr;
        reg        int_dma_rnw;
        reg  [7:0] int_dma_wd;
        wire [7:0] int_dma_rd;

        assign mem_dma_bus  = dma_bus;
        assign mem_dma_addr = int_dma_addr;
        assign mem_dma_wd   = int_dma_wd;
        assign mem_dma_rnw  = int_dma_rnw;
        assign int_dma_rd   = mem_dma_rd;



        localparam IDLE     = 0;
        localparam START    = 1;
        localparam WACK     = 2;
        localparam READ1    = 3;
        localparam READ2    = 4;
        localparam WRITE1   = 5;
        localparam WRITE2   = 6;


        reg [3:0] state;
        reg [3:0] next_state;




        // for simulation purposes
        initial
        begin
                state       <= IDLE;
                busrq_n     <= 1'b1;
                mem_dma_oe  <= 1'b1;
                mem_dma_we  <= 1'b1;
        end


// FSM
        always @(posedge clk, negedge rst_n)
        begin
                if( !rst_n )
                        state <= IDLE;
                else
                        state <= next_state;
        end


        always @*
        begin
                case( state )
//////////////////////////////////////////////////////////////////////////////////////////
                IDLE:
                begin
                        if( dma_req==1'b1 )
                                next_state <= START;
                        else
                                next_state <= IDLE;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                START:
                begin
                        next_state <= WACK;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                WACK:
                begin
                        if( busak_n == 1'b1 ) ///// ACHTUNG WARNING!!! probably use here registered busak?
                                next_state <= WACK;
                        else // busak_n == 1'b0
                        begin
                                if( int_dma_rnw == 1'b1 ) // read
                                        next_state <= READ1;
                                else // int_dma_rnw == 1'b0 - write
                                        next_state <= WRITE1;
                        end
                end
//////////////////////////////////////////////////////////////////////////////////////////
                READ1:
                begin
                        next_state <= READ2;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                READ2:
                begin
                        if( dma_req == 1'b0 )
                                next_state <= IDLE;
                        else // dma_req == 1'b1
                        begin
                                if( dma_rnw == 1'b1 ) // next is read
                                        next_state <= READ1;
                                else // dma_rnw == 1'b0 - next is write
                                        next_state <= WRITE1;
                        end
                end
//////////////////////////////////////////////////////////////////////////////////////////
                WRITE1:
                begin
                        next_state <= WRITE2;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                WRITE2:
                begin
                        if( dma_req == 1'b0 )
                                next_state <= IDLE;
                        else // dma_req == 1'b1
                        begin
                                if( dma_rnw == 1'b1 ) // next is read
                                        next_state <= READ1;
                                else // dma_rnw == 1'b0 - next is write
                                        next_state <= WRITE1;
                        end
                end
//////////////////////////////////////////////////////////////////////////////////////////
                endcase
        end


        always @(posedge clk, negedge rst_n)
        begin
                if( !rst_n )
                begin
                        busrq_n        <= 1'b1;
                        dma_busynready <= 1'b0;
                        dma_ack        <= 1'b0;
                        dma_end        <= 1'b0;
                        dma_bus        <= 1'b0;
                        mem_dma_oe     <= 1'b1;
                end
                else case( next_state )
//////////////////////////////////////////////////////////////////////////////////////////
                IDLE:
                begin
                        dma_end        <= 1'b0;

                        busrq_n        <= 1'b1;
                        dma_bus        <= 1'b0;
                        mem_dma_oe     <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                START:
                begin
//                      dma_bus        <= 1'b0; // if rst=0>1 and dma_ack=1 --> ??? is this really needed?


                        busrq_n        <= 1'b0;

                        dma_busynready <= 1'b1;
                        dma_ack        <= 1'b1;

                        int_dma_rnw    <= dma_rnw;
                        int_dma_addr   <= dma_addr;
                        int_dma_wd     <= dma_wd;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                WACK:
                begin
                        dma_ack <= 1'b0;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                READ1:
                begin
                        dma_bus    <= 1'b1; // take over the bus
                        mem_dma_oe <= 1'b0;
                        if( dma_busynready == 1'b0 ) // if we are here from READ2 or WRITE2
                        begin
                                dma_busynready <= 1'b1;
                                dma_ack        <= 1'b1;
                                dma_end        <= 1'b0;
                                int_dma_rnw    <= 1'b1;
                                int_dma_addr   <= dma_addr;
                        end
                end
//////////////////////////////////////////////////////////////////////////////////////////
                READ2:
                begin
                        dma_busynready <= 1'b0;
                        dma_ack        <= 1'b0;
                        dma_end        <= 1'b1;
                        dma_rd <= int_dma_rd;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                WRITE1:
                begin
                        dma_bus    <= 1'b1; // take over the bus
                        mem_dma_oe <= 1'b1;

                        if( dma_busynready == 1'b0 ) // from READ2 or WRITE2
                        begin
                                dma_busynready <= 1'b1;
                                dma_ack        <= 1'b1;
                                dma_end        <= 1'b0;
                                int_dma_rnw    <= 1'b0;
                                int_dma_addr   <= dma_addr;
                                int_dma_wd     <= dma_wd;
                        end
                end
//////////////////////////////////////////////////////////////////////////////////////////
                WRITE2:
                begin
                        dma_busynready <= 1'b0;
                        dma_ack        <= 1'b0;
                        dma_end        <= 1'b1;
                end
//////////////////////////////////////////////////////////////////////////////////////////
                endcase
        end




// mem_dma_we generator

        always @(negedge clk,negedge rst_n)
        begin
                if( !rst_n )
                        mem_dma_we <= 1'b1;
                else
                begin
                        if( dma_bus )
                        begin
                                if( !int_dma_rnw )
                                        mem_dma_we <= ~mem_dma_we;
                        end
                        else
                                mem_dma_we <= 1'b1;
                end
        end


endmodule