Top secrets sources NedoPC ngs

Rev

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

// part of NeoGS project (c) 2008-2013 NedoPC

// dma sequencer

/*

input interface of every DMA end-user

clocks: ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^  ^
reqN    _______/```````````\______________/`````````````````\______________/``````````````````
ackN    ________________/``\_____________________________/``\____________________/``\__/``\__/
doneN   _________________________/``\_____________________________/``\______________/``\__/``\
rnwN    -------/```````````\--------------\_________________/--------------/````````\_____/```
adrwdN  -------< read addr >--------------< write addr&data >--------------< rdaddr X wra X rd
rdN     -------------------------<dd>-----------------------------------------------<dd>------


sequencing algorithm is round-robin with fixed initial prioritizing when multiple requests appear simultaneously while
everything was idle

*/



module dma_sequencer(

        input wire clk,
        input wire rst_n,

        // dma requests connection
        //
        input wire req0,
        input wire req1,
        input wire req2,
        input wire req3,

        input wire [21:0] addr0,
        input wire [21:0] addr1,
        input wire [21:0] addr2,
        input wire [21:0] addr3,

        input wire rnw0,
        input wire rnw1,
        input wire rnw2,
        input wire rnw3,

        input wire [7:0] wd0,
        input wire [7:0] wd1,
        input wire [7:0] wd2,
        input wire [7:0] wd3,


        output wire ack0,
        output wire ack1,
        output wire ack2,
        output wire ack3,

        output wire end0,
        output wire end1,
        output wire end2,
        output wire end3,

//      dma controller connection
        output wire        dma_req,
        output wire [21:0] dma_addr,
        output wire        dma_rnw,
        output wire  [7:0] dma_wd,

        input  wire        dma_ack,
        input  wire        dma_end
);
        localparam DEVNUM = 4;



        wire [DEVNUM-1:0] reqs;
        wire       [21:0] addrs [0:DEVNUM-1];
        wire [DEVNUM-1:0] rnws;
        wire        [7:0] wds   [0:DEVNUM-1];
        wire [DEVNUM-1:0] acks;
        wire [DEVNUM-1:0] ends;


        // aggregate signals for brewity
        assign reqs[DEVNUM-1:0] = {req3,req2,req1,req0};
        assign addrs[0] = addr0;
        assign addrs[1] = addr1;
        assign addrs[2] = addr2;
        assign addrs[3] = addr3;
        assign rnws[DEVNUM-1:0] = {rnw3,rnw2,rnw1,rnw0};
        assign wds[0] = wd0;
        assign wds[1] = wd1;
        assign wds[2] = wd2;
        assign wds[3] = wd3;
        assign {ack3,ack2,ack1,ack0} = acks[DEVNUM-1:0];
        assign {end3,end2,end1,end0} = ends[DEVNUM-1:0];





        reg  [DEVNUM-1:0] cur_input_mux;  // which current input is muxed to the DMA  (input=req,ack,addr,wd)
        reg  [DEVNUM-1:0] cur_output_mux; // which current output is muxed to the DMA (output=end)

        wire [DEVNUM-1:0] next_input_mux;

        reg busy;


        always @(posedge clk, negedge rst_n)
        begin
                if( !rst_n )
                        busy = 1'b0;
                else // posedge clk
                begin
                        if( !busy )
                                busy <= |reqs;
                        else // busy
                                busy <= dma_req;
                end
        end


        always @(posedge clk, negedge rst_n)
        begin
                if( !rst_n )
                begin
                        cur_input_mux  = {DEVNUM{1'b0}}; // to remove static priority selection after idle -- have here 'd1!
                end
                else // posedge clk
                begin
                        if( (!busy) || dma_ack ) // idle or dma acknoledges data receive
                        begin
                                cur_input_mux <= next_input_mux;
                        end
                end
        end

        rr_arbiter #( .DEVNUM(DEVNUM) ) rr_arbiter(
                .reqs(reqs),
                .prev( cur_input_mux),
                .next(next_input_mux)
        );



        // output mux should follow input after dma_ack
        //
        always @(posedge clk, negedge rst_n)
        begin
                if( !rst_n )
                begin
                        cur_output_mux = {DEVNUM{1'b0}};
                end
                else // posedge clk
                begin
                        if( dma_ack )
                                cur_output_mux <= cur_input_mux;
                end
        end





        // actual muxing of input data
        //
        wor         int_dma_req;  // wor is to do easily decoded AND-OR muxes
        wor  [20:0] int_dma_addr; //
        wand        int_dma_rnw;  // this is WAND to have it 1 in idle
        wor   [7:0] int_dma_wd;   //
        //
        genvar i;
        generate
                for(i=0;i<DEVNUM;i=i+1)
                begin : mux_dma_inputs

                        assign int_dma_req  =     cur_input_mux[i]   &  reqs[i]; // wired OR happens!
                        assign int_dma_addr = {21{cur_input_mux[i]}} & addrs[i]; //
                        assign int_dma_rnw  =   (~cur_input_mux[i])  |  rnws[i]; // wired AND...
                        assign int_dma_wd   =  {8{cur_input_mux[i]}} &   wds[i]; //
                end
        endgenerate
        //
        // output data to dma controller
        //
        assign dma_req  = int_dma_req;
        assign dma_addr = int_dma_addr;
        assign dma_rnw  = int_dma_rnw;
        assign dma_wd   = int_dma_wd;

        // actual de-muxing of output data from dma controller
        //
        assign acks = cur_input_mux  & {DEVNUM{dma_ack}};
        assign ends = cur_output_mux & {DEVNUM{dma_end}};

endmodule






// round-robin arbiter
module rr_arbiter(
        /*input  wire [DEVNUM-1:0]*/ reqs,
        /*input  wire [DEVNUM-1:0]*/ prev,

        /*output wire [DEVNUM-1:0]*/ next
);
        parameter DEVNUM=4;


        input  wire [DEVNUM-1:0] reqs;
        input  wire [DEVNUM-1:0] prev;

        output wire [DEVNUM-1:0] next;



        genvar i;



        // arbitration if there was previous actives
        //
        wire [DEVNUM-1:0] loop;
        wire [DEVNUM-1:0] next_arb;

        generate
                for(i=0;i<DEVNUM;i=i+1)
                begin : gen_forwarders

                        if( i==0 )
                                rr_fwd forwarder( .prev(prev[i]),
                                                  .req(reqs[i]),
                                                  .next(next_arb[i]),
                                                  .loop_in(loop[DEVNUM-1]),
                                                  .loop_out(loop[i]) );
                        else
                                rr_fwd forwarder( .prev(prev[i]),
                                                  .req(reqs[i]),
                                                  .next(next_arb[i]),
                                                  .loop_in(loop[i-1]),
                                                  .loop_out(loop[i]) );
                end
        endgenerate


        // arbitration if there was no actives prior to requests
        //
        wire  [DEVNUM-1:0] next_empty;

        generate
                for(i=0;i<DEVNUM;i=i+1)
                begin : pri_enc
                        if( i==0 )
                        begin : pri_zero
                                assign next_empty[0] = reqs[0];
                        end
                        else
                        begin : pri_nonzero
                                assign next_empty[i] = reqs[i] & ( ~|reqs[i-1:0] );
                        end
                end
        endgenerate


        // select between prev-busy and prev-free cases
        assign next = ( prev ) ? next_arb : next_empty;

endmodule


// round-robin request forwarder (1 bit)
module rr_fwd(
        input  wire prev,  // who was arbitrated last time (one-hot)
        input  wire req,   // who are requesting
        output reg  next, // who will be next

        input  wire loop_in, // for internal arbitration
        output reg  loop_out //
);

        always @*
        begin
                if( prev )
                begin
                        loop_out = 1'b1;
                end
                else //!prev
                begin
                        loop_out = req ? 1'b0 : loop_in;
                end
        end

        always @*
        begin
                next = req ? loop_in : 1'b0;
        end

endmodule