OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [rtl/] [src_peripheral/] [DMA/] [dma_multi_channel_wb.v] - Rev 48

Compare with Previous | Blame | View Log

/**********************************************************************
**	File:  dma.v
**	Date:2017-05-14   
**    
**	Copyright (C) 2014-2017  Alireza Monemi
**    
**	This file is part of ProNoC 
**
**	ProNoC ( stands for Prototype Network-on-chip)  is free software: 
**	you can redistribute it and/or modify it under the terms of the GNU
**	Lesser General Public License as published by the Free Software Foundation,
**	either version 2 of the License, or (at your option) any later version.
**
** 	ProNoC is distributed in the hope that it will be useful, but WITHOUT
** 	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
** 	or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General
** 	Public License for more details.
**
** 	You should have received a copy of the GNU Lesser General Public
** 	License along with ProNoC. If not, see <http:**www.gnu.org/licenses/>.
**
**
**	Description: 
**	weighted round robin arbiter	
**	A multi chanel wishbone based DMA  and with support burst data transaction 
**	(Dose not support byte enable yet). 
***************************************/
 
// synthesis translate_off
`timescale 1ns / 1ps
// synthesis translate_on
 
 
 
 
 
 module dma_multi_chan_wb #(
    parameter chanel=4,
    parameter MAX_TRANSACTION_WIDTH=10, // Maximum transaction size will be 2 power of MAX_DMA_TRANSACTION_WIDTH words 
    parameter MAX_BURST_SIZE =256, // in words
    parameter FIFO_B = 4,
    parameter DEBUG_EN = 1,
    //wishbone port parameters
    parameter Dw            =   32,
    parameter S_Aw          =   7,
    parameter M_Aw          =   32,
    parameter TAGw          =   3,
    parameter SELw          =   4
 
 
)
(
     // 
    reset,
    clk,
 
     //wishbone slave interface signals
    s_dat_i,
    s_sel_i,
    s_addr_i,  
    s_cti_i,
    s_stb_i,
    s_cyc_i,
    s_we_i,    
    s_dat_o,
    s_ack_o,
 
 
 
    //wishbone master rd interface signals
    m_rd_sel_o,
    m_rd_addr_o,
    m_rd_cti_o,
    m_rd_stb_o,
    m_rd_cyc_o,
    m_rd_we_o,
    m_rd_dat_i,
    m_rd_ack_i,    
 
 
     //wishbone master wr interface signals
 
    m_wr_sel_o,
    m_wr_dat_o,
    m_wr_addr_o,
    m_wr_cti_o,
    m_wr_stb_o,
    m_wr_cyc_o,
    m_wr_we_o,
    m_wr_ack_i,   
 
 
    //intruupt interface
    irq
 
);
 
    input reset,clk;
 
   //wishbone slave interface signals
    input   [Dw-1       :   0]      s_dat_i;
    input   [SELw-1     :   0]      s_sel_i;
    input   [S_Aw-1     :   0]      s_addr_i;  
    input   [TAGw-1     :   0]      s_cti_i;
    input                           s_stb_i;
    input                           s_cyc_i;
    input                           s_we_i;
 
    output      [Dw-1       :   0]  s_dat_o;
    output  reg                     s_ack_o;
 
 
 
    //wishbone read master interface signals
    output  [SELw-1          :   0] m_rd_sel_o;
    output  [M_Aw-1          :   0] m_rd_addr_o;
    output  [TAGw-1          :   0] m_rd_cti_o;
    output                          m_rd_stb_o;
    output                          m_rd_cyc_o;
    output                          m_rd_we_o;
    input   [Dw-1           :  0]   m_rd_dat_i;
    input                           m_rd_ack_i;    
 
     //wishbone write master interface signals
    output  [SELw-1          :   0] m_wr_sel_o;
    output  [Dw-1            :   0] m_wr_dat_o;
    output  [M_Aw-1          :   0] m_wr_addr_o;
    output  [TAGw-1          :   0] m_wr_cti_o;
    output                          m_wr_stb_o;
    output                          m_wr_cyc_o;
    output                          m_wr_we_o;
    input                           m_wr_ack_i;   
 
    output irq;
 
    wire                            s_ack_o_next;
 
 
     function integer log2;
      input integer number; begin   
         log2=(number <=1) ? 1: 0;    
         while(2**log2<number) begin    
            log2=log2+1;    
         end       
      end   
    endfunction // log2 
 
 
    localparam 
        CHw=log2(chanel),
        BURST_SIZE_w= log2(MAX_BURST_SIZE);
 
     /*   wishbone slave adderess :
 
    [2:0]  
            0   :   DMA_STATUS_WB_ADDR
            1   :   BURST_SIZE_WB_ADDR  // The busrt size in words 
            2   :   DATA_SIZE_WB_ADDR,  // The transfer data size in byte  
            3   :   RD_STRT_WB_ADDR3,  // The source start address in byte       
            4   :   WR_STRT_WB_ADDR   // The destination start address in byte
 
    [3+CHw:3]
                chanel num       
 
    */
 
    wire [CHw-1 :   0] chanel_addr = s_addr_i [3+CHw:3];
    wire [2     :   0] chanel_s_addr_i = s_addr_i [2: 0];
 
 
 
     localparam [2  :   0]
        DMA_STATUS_WB_ADDR =3'd0, 
        BURST_SIZE_WB_ADDR =3'd1; // The busrt size in words
 
 
 
 
 
    reg [BURST_SIZE_w-1  :   0] burst_size, burst_size_next,burst_counter,burst_counter_next;
 
 
    wire [chanel-1 :   0] chanel_wr_is_busy, chanel_rd_is_busy;
    wire [chanel-1 :   0] chanel_wr_enable,chanel_rd_enable,chanel_state_reg_enable;
    wire [chanel-1 :   0] chanel_burst_counter_ld, chanel_burst_counter_dec;
    wire [chanel-1 :   0] chanel_fifo_wr, chanel_fifo_rd;
    wire [chanel-1 :   0] chanel_fifo_full, chanel_fifo_nearly_full, chanel_fifo_empty;
    wire [chanel-1 :   0] chanel_rd_is_active,chanel_wr_is_active;
    wire [CHw-1     :   0] rd_enable_binary,wr_enable_binary;
 
 
 
   wire  [SELw-1    :   0] chanel_m_rd_sel_o  [chanel-1 :   0];
   wire  [M_Aw-1    :   0] chanel_m_rd_addr_o [chanel-1 :   0];
   wire  [TAGw-1    :   0] chanel_m_rd_cti_o  [chanel-1 :   0];
   wire  [chanel-1 :   0] chanel_m_rd_stb_o; 
   wire  [chanel-1 :   0] chanel_m_rd_cyc_o; 
   wire  [chanel-1 :   0] chanel_m_rd_we_o; 
 
 
   wire  [SELw-1    :   0] chanel_m_wr_sel_o  [chanel-1 :   0];
   wire  [M_Aw-1    :   0] chanel_m_wr_addr_o [chanel-1 :   0];
   wire  [TAGw-1    :   0] chanel_m_wr_cti_o  [chanel-1 :   0];
   wire  [chanel-1 :   0] chanel_m_wr_stb_o; 
   wire  [chanel-1 :   0] chanel_m_wr_cyc_o; 
   wire  [chanel-1 :   0] chanel_m_wr_we_o; 
 
 
 
 
 
 
 
 
 
    wire burst_counter_ld = | chanel_burst_counter_ld; 
    wire burst_counter_dec= | chanel_burst_counter_dec;
    wire fifo_wr =  | chanel_fifo_wr; 
    wire fifo_rd =  | chanel_fifo_rd;
 
    wire last_burst = (burst_counter == 1);
    wire burst_is_set =  (burst_size>0);
 
    localparam STATUSw= 2 * CHw + 3 * chanel;
    wire  [STATUSw-1  :0] status;  
    wire [chanel-1 :   0] chanel_is_active = chanel_rd_is_busy|chanel_wr_is_busy;
    assign status= {rd_enable_binary,wr_enable_binary,chanel_rd_is_busy,chanel_wr_is_busy,chanel_is_active};
    assign s_dat_o={{(Dw-STATUSw){1'b0}}, status};
 
 
 
   bin_to_one_hot #(
   	.BIN_WIDTH(CHw),
   	.ONE_HOT_WIDTH(chanel)
   )
   convert(
   	.bin_code(chanel_addr),
   	.one_hot_code(chanel_state_reg_enable)
   );
 
 
 
 
    assign s_ack_o_next    =   s_stb_i & (~s_ack_o);
 
 
    always @ (*)begin 
        burst_counter_next=burst_counter;
        burst_size_next= burst_size;
        if(burst_counter_ld)    burst_counter_next = burst_size;
        if(burst_counter_dec)   burst_counter_next= burst_counter- 1'b1;
 
        if(s_stb_i  &    s_we_i )   begin 
            if (chanel_wr_is_busy == {chanel{1'b0}})  begin   
                case(chanel_s_addr_i)
                    BURST_SIZE_WB_ADDR: begin 
                        burst_size_next=s_dat_i [BURST_SIZE_w-1 : 0];    
                    end //BURST_SIZE_WB_ADDR
                endcase
            end      
        end
 
    end 
 
 
`ifdef SYNC_RESET_MODE 
    always @ (posedge clk )begin 
`else 
    always @ (posedge clk or posedge reset)begin 
`endif   
        if(reset) begin 
            burst_counter <= {BURST_SIZE_w{1'b0}};
            burst_size <= {BURST_SIZE_w{1'b1}};
            s_ack_o <= 1'b0;   
        end else begin 
            burst_counter<= burst_counter_next; 
            burst_size <= burst_size_next; 
            s_ack_o <= s_ack_o_next;           
        end 
    end 
 
 
 
 
 
 
    genvar i;
    generate
    for (i=0;i<chanel; i=i+1) begin : chanel_
        dma_single_wb #(
        	.MAX_TRANSACTION_WIDTH(MAX_TRANSACTION_WIDTH),
        	.Dw(Dw),
        	.S_Aw(3),
        	.M_Aw(M_Aw),
        	.TAGw(TAGw),
        	.SELw(SELw)
        )
        chanel_dma
        (
        	.reset(reset),
        	.clk(clk),
        	.status(),
 
        	//active-enable signals
        	.rd_enable(chanel_rd_enable[i]),
        	.wr_enable(chanel_wr_enable[i]),
        	.state_reg_enable(chanel_state_reg_enable[i]),
        	.rd_is_busy(chanel_rd_is_busy[i]),
        	.wr_is_busy(chanel_wr_is_busy[i]),
        	.rd_is_active(chanel_rd_is_active[i]),
        	.wr_is_active(chanel_wr_is_active[i]),
        	.burst_counter_ld(chanel_burst_counter_ld[i]),
        	.burst_counter_dec(chanel_burst_counter_dec[i]),
        	.burst_size_is_set(burst_is_set),
        	.last_burst(last_burst),
 
        	//fifo
        	.fifo_wr(chanel_fifo_wr[i]), 
            .fifo_rd(chanel_fifo_rd[i]), 
            .fifo_full(chanel_fifo_full[i]),
            .fifo_nearly_full(chanel_fifo_nearly_full[i]),
            .fifo_empty(chanel_fifo_empty[i]),
 
        	//wb salve
        	.s_dat_i(s_dat_i),
        	.s_sel_i(s_sel_i),
        	.s_addr_i(chanel_s_addr_i),
        	.s_cti_i(s_cti_i),
        	.s_stb_i(s_stb_i),
        	.s_cyc_i(s_cyc_i),
        	.s_we_i(s_we_i),
        	//.s_dat_o(s_dat_o),
        	//.s_ack_o(s_ack_o),
 
        	//
        	.m_rd_sel_o(chanel_m_rd_sel_o[i]),
        	.m_rd_addr_o(chanel_m_rd_addr_o[i]),
        	.m_rd_cti_o(chanel_m_rd_cti_o[i]),
        	.m_rd_stb_o(chanel_m_rd_stb_o[i]),
        	.m_rd_cyc_o(chanel_m_rd_cyc_o[i]),
        	.m_rd_we_o(chanel_m_rd_we_o[i]),
        //	.m_rd_dat_i(m_rd_dat_i),
        	.m_rd_ack_i(m_rd_ack_i),
 
 
        	.m_wr_sel_o(chanel_m_wr_sel_o[i]),
        //	.m_wr_dat_o(chanel_m_wr_dat_o[i]),
        	.m_wr_addr_o(chanel_m_wr_addr_o[i]),
        	.m_wr_cti_o(chanel_m_wr_cti_o[i]),
        	.m_wr_stb_o(chanel_m_wr_stb_o[i]),
        	.m_wr_cyc_o(chanel_m_wr_cyc_o[i]),
        	.m_wr_we_o(chanel_m_wr_we_o[i]),
        	.m_wr_ack_i(m_wr_ack_i)
        );
 
    end  // for loop for chanel
 
 
    if(chanel> 1) begin : multi_chanel
 
        // round roubin arbiter
        bus_arbiter # (
            .M (chanel)
        )
        wr_arbiter
        (
            .request (chanel_wr_is_active ),
            .grant  (chanel_wr_enable),
            .clk (clk),
            .reset (reset)
        );
 
 
 
 
        bus_arbiter # (
            .M (chanel)
        )
        rd_arbiter
        (
            .request (chanel_rd_is_active),
            .grant  (chanel_rd_enable),
            .clk (clk),
            .reset (reset)
        );
 
 
        one_hot_to_bin #(
            .ONE_HOT_WIDTH(chanel),
            .BIN_WIDTH(CHw)
        )
        rd_en_conv
        (
            .one_hot_code(chanel_rd_enable),
            .bin_code(rd_enable_binary)
        );
 
 
         one_hot_to_bin #(
            .ONE_HOT_WIDTH(chanel),
            .BIN_WIDTH(CHw)
        )
        wr_en_conv
        (
            .one_hot_code(chanel_wr_enable),
            .bin_code(wr_enable_binary)
        );
 
 
    end else begin : single_chanel // if we have just one chanel there is no needs for arbitration
        assign chanel_wr_enable =  chanel_wr_is_busy;
        assign chanel_rd_enable =  chanel_rd_is_busy;
        assign rd_enable_binary = 1'b0;
        assign wr_enable_binary = 1'b0;
    end
    endgenerate  
 
 
    //wb multiplexors
 
    assign m_rd_sel_o  = chanel_m_rd_sel_o[rd_enable_binary];
    assign m_rd_addr_o = chanel_m_rd_addr_o[rd_enable_binary];
    assign m_rd_cti_o  = chanel_m_rd_cti_o[rd_enable_binary];
    assign m_rd_stb_o  = chanel_m_rd_stb_o[rd_enable_binary];
    assign m_rd_cyc_o  = chanel_m_rd_cyc_o[rd_enable_binary];
    assign m_rd_we_o   = chanel_m_rd_we_o[rd_enable_binary];
 
 
 
    assign m_wr_sel_o = chanel_m_wr_sel_o[wr_enable_binary];
    assign m_wr_addr_o= chanel_m_wr_addr_o[wr_enable_binary];
    assign m_wr_cti_o = chanel_m_wr_cti_o[wr_enable_binary];
    assign m_wr_stb_o = chanel_m_wr_stb_o[wr_enable_binary];
    assign m_wr_cyc_o = chanel_m_wr_cyc_o[wr_enable_binary];
    assign m_wr_we_o  = chanel_m_wr_we_o[wr_enable_binary];
 
 
 
 
 
 
 
 
  shared_mem_fifos #(
  	.NUM(chanel),
  	.B(FIFO_B),
  	.Dw(Dw),
  	.DEBUG_EN(DEBUG_EN)
  )
  the_shared_mem_fifos
  (
  	.din(m_rd_dat_i),
  	.fifo_num_wr(chanel_rd_enable ), // when chnnel is in read mode it start writing on fifo
  	.fifo_num_rd(chanel_wr_enable),
  	.wr_en(fifo_wr),
  	.rd_en(fifo_rd),
  	.dout(m_wr_dat_o),
  	.full(chanel_fifo_full),
  	.nearly_full(chanel_fifo_nearly_full),
  	.empty(chanel_fifo_empty),  
  	.reset(reset),
  	.clk(clk)
  );
 
 
 
 
 
 
 
 endmodule
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
module dma_single_wb #(
 
    parameter MAX_TRANSACTION_WIDTH=10, // MAximum transaction size will be 2 power of MAX_DMA_TRANSACTION_WIDTH words 
    //wishbone port parameters
    parameter Dw            =   32,
    parameter S_Aw          =   7,
    parameter M_Aw          =   32,
    parameter TAGw          =   3,
    parameter SELw          =   4
 
 
)
(
     // 
    reset,
    clk,
 
    //ctrl signals
    rd_enable,
    wr_enable,
    state_reg_enable,
    rd_is_busy,
    wr_is_busy,
    rd_is_active,
    wr_is_active,
    last_burst,
    status,
 
    //fifo signals
    fifo_wr, 
    fifo_rd, 
    fifo_full,
    fifo_nearly_full,
    fifo_empty,
 
    //busrdt counter control signals
    burst_counter_ld,
    burst_counter_dec,
    burst_size_is_set,
 
     //wishbone slave interface signals
    s_dat_i,
    s_sel_i,
    s_addr_i,  
    s_cti_i,
    s_stb_i,
    s_cyc_i,
    s_we_i,    
   // s_dat_o,
   // s_ack_o,
 
 
 
    //wishbone master rd interface signals
    m_rd_sel_o,
    m_rd_addr_o,
    m_rd_cti_o,
    m_rd_stb_o,
    m_rd_cyc_o,
    m_rd_we_o,
  //  m_rd_dat_i,
    m_rd_ack_i,    
 
 
     //wishbone master wr interface signals
 
    m_wr_sel_o,
   // m_wr_dat_o,
    m_wr_addr_o,
    m_wr_cti_o,
    m_wr_stb_o,
    m_wr_cyc_o,
    m_wr_we_o,
    m_wr_ack_i  
 
 
 
 
);
 
 
    function integer log2;
      input integer number; begin   
         log2=(number <=1) ? 1: 0;    
         while(2**log2<number) begin    
            log2=log2+1;    
         end       
      end   
    endfunction // log2 
 
    localparam
        WORLD_SIZE = Dw/8,
        OFFSET_w= log2(WORLD_SIZE);
 
 
 
 
 
    //state machine registers/parameters
    localparam
        RD_ST_NUM=3,
        WR_ST_NUM=3;
    localparam [RD_ST_NUM-1 :   0]
        RD_IDEAL = 1,
        RD_ACTIVE =2,
        RD_RELEASE_WB=4;    
 
 
    localparam [WR_ST_NUM-1:0]
        WR_IDEAL = 1,
        WR_READ_FIFO=2,
        WR_ACTIVE =4;
 
 
    localparam [2 : 0]
        CLASSIC = 3'b000,
        CONST_ADDR_BURST = 3'b010,
        INCREMENT_BURST = 3'b011,
        END_OF_BURST = 3'b111;
 
 
      //control Registers/ parameters 
 
    localparam [S_Aw-1  :   0]
        DMA_STATUS_WB_ADDR =0, 
        BURST_SIZE_WB_ADDR =1, // The busrt size in words
        DATA_SIZE_WB_ADDR =2,  // The transfer data size in byte
        RD_STRT_WB_ADDR =   3, // The source start address in byte       
        WR_STRT_WB_ADDR=4; // the destination start address in byte   
 
 
    localparam STATUSw=RD_ST_NUM+WR_ST_NUM+1;
 
    output  [STATUSw-1  :0] status;  
 
 
    input reset,clk,rd_enable,wr_enable, state_reg_enable;
    output reg rd_is_busy, wr_is_busy;
    output reg burst_counter_ld,    burst_counter_dec;
    input burst_size_is_set;
    input last_burst;
    output reg rd_is_active, wr_is_active;
 
 
    //fifo
    output reg  fifo_wr, fifo_rd;
    input       fifo_full, fifo_nearly_full, fifo_empty;
 
 
     //wishbone slave interface signals
    input   [Dw-1       :   0]      s_dat_i;
    input   [SELw-1     :   0]      s_sel_i;
    input   [S_Aw-1     :   0]      s_addr_i;  
    input   [TAGw-1     :   0]      s_cti_i;
    input                           s_stb_i;
    input                           s_cyc_i;
    input                           s_we_i;
 
  //  output      [Dw-1       :   0]  s_dat_o;
  //  output  reg                     s_ack_o;
 
 
 
    //wishbone read master interface signals
    output  [SELw-1          :   0] m_rd_sel_o;
    output  [M_Aw-1          :   0] m_rd_addr_o;
    output reg [TAGw-1       :   0] m_rd_cti_o;
    output                          m_rd_stb_o;
    output   reg                    m_rd_cyc_o;
    output                          m_rd_we_o;
   // input   [Dw-1           :  0]   m_rd_dat_i;
    input                           m_rd_ack_i;    
 
     //wishbone write master interface signals
    output  [SELw-1          :   0] m_wr_sel_o;
  //  output  [Dw-1            :   0] m_wr_dat_o;
    output  [M_Aw-1          :   0] m_wr_addr_o;
    output  reg [TAGw-1      :   0] m_wr_cti_o;
    output                          m_wr_stb_o;
    output  reg                     m_wr_cyc_o;
    output                          m_wr_we_o;
    input                           m_wr_ack_i;   
 
 
 
 
     wire dma_busy;
 
 
 
 
 
    wire [S_Aw-1    :   0] wb_wr_rd_addr;
    assign wb_wr_rd_addr =   s_addr_i [S_Aw-1 :   0];
 
 
    reg [Dw-1   :   0] rd_start_addr,rd_start_addr_next; 
    reg [Dw-1   :   0] wr_start_addr,wr_start_addr_next;
 
    reg [MAX_TRANSACTION_WIDTH-1    :   0] data_size, data_size_next;
    reg [MAX_TRANSACTION_WIDTH-1    :   0] rd_counter, rd_counter_next;
    reg [MAX_TRANSACTION_WIDTH-1    :   0] wr_counter, wr_counter_next;
 
 
 
 
 
 
 
    reg  rd_start, rd_done,wr_done;  
 
    wire last_data = (rd_counter == data_size-1'b1);
 
 
 
 
 
    reg [RD_ST_NUM-1    :0] rd_ps,rd_ns; // read  peresent state, read next sate 
    reg [WR_ST_NUM-1    :0] wr_ps,wr_ns; // read  peresent state, read next sate
 
    reg wr_is_busy_next, rd_is_busy_next;
 
 
    assign status= {wr_ps,rd_ps,dma_busy};
   // assign s_dat_o={{(Dw-STATUSw){1'b0}}, status};
 
 
 
 
    assign dma_busy = (rd_ps!= RD_IDEAL) | (wr_ps!= WR_IDEAL);
 
 
    assign m_rd_addr_o =  rd_start_addr + rd_counter;
    assign m_wr_addr_o =  wr_start_addr + wr_counter;
    assign m_rd_stb_o =  m_rd_cyc_o;
    assign m_wr_stb_o =  m_wr_cyc_o;
    assign m_wr_we_o = 1'b1;
    assign m_rd_we_o = 1'b0;
    //assign m_rd_cti_o = ( rd_data_end | burst_data_end | fifo_nearly_full) ? END_OF_BURST : CONST_ADDR_BURST;
    //assign m_wr_cti_o = (fifo_has_one_word & ~fifo_wr) ? END_OF_BURST : CONST_ADDR_BURST;
    assign m_wr_sel_o = 4'b1111;
    assign m_rd_sel_o = 4'b1111;
 
 //  assign  rd_is_busy = (rd_ps == RD_ACTIVE);
 //   assign  wr_is_busy = (wr_ps == WR_ACTIVE);
 
 
 
    //read state machine
    always @ (*) begin 
        // default values 
        rd_ns = rd_ps;
        rd_counter_next=rd_counter;
        burst_counter_ld=1'b0;
        burst_counter_dec=1'b0;
        m_rd_cti_o =  CONST_ADDR_BURST;
        m_rd_cyc_o=1'b0;
        fifo_wr=1'b0;
        rd_done = 1'b0;
        rd_is_active =1'b0;
 
            case(rd_ps)
                RD_IDEAL: begin 
                   if(rd_start) begin 
                        if (burst_size_is_set && (data_size>0)) begin 
                            rd_counter_next= {MAX_TRANSACTION_WIDTH{1'b0}};
                            burst_counter_ld=1'b1;
                            rd_ns = RD_ACTIVE;
                        end else begin // sett error reg
 
                       end
                   end
                end // RD_IDEAL
                RD_ACTIVE: begin 
                    rd_is_active =1'b1; // this signal sends request to the rd_arbiter, the granted signal is rd_enable
                    if(rd_enable) begin 
                        m_rd_cyc_o=1'b1; 
                        if(last_data |  last_burst | (fifo_nearly_full & !fifo_rd))  m_rd_cti_o= END_OF_BURST;  
                        if(fifo_nearly_full & !fifo_rd)  rd_ns = RD_RELEASE_WB;
 
 
                        if (m_rd_ack_i) begin 
                                fifo_wr=1'b1;
                                rd_counter_next=rd_counter +1'b1;
                                burst_counter_dec=1'b1;
 
                                if(last_data) begin 
                                  rd_ns = RD_IDEAL;
                                  rd_done = 1'b1;
 
                                end else if (last_burst | (fifo_nearly_full & !fifo_rd)) begin 
                                  rd_ns = RD_RELEASE_WB;
 
                                end 
                        end 
                    end
 
                end // RD_ACTIVE
                RD_RELEASE_WB: begin 
                    //burst_counter_next = burst_size;
 
                      burst_counter_ld=1'b1;
                    if(!fifo_full) begin 
                        rd_ns = RD_ACTIVE;
                    end
 
                end //RD_RELEASE_WB
                    default: begin
 
 
                    end
            endcase      
    end//alays
 
 
 
 
 //write state machine    
    always @ (*) begin 
        // default values 
        wr_ns = wr_ps;
        wr_counter_next=wr_counter;
        m_wr_cyc_o=1'b0;
        m_wr_cti_o= CONST_ADDR_BURST;
        fifo_rd=1'b0;
        wr_done=1'b0;
        wr_is_active =1'b0;
        if (rd_start ) wr_counter_next = {MAX_TRANSACTION_WIDTH{1'b0}}; 
 
 
            case(wr_ps)
                WR_IDEAL: begin                   
                    if(!fifo_empty)begin 
                        wr_ns = WR_READ_FIFO;                         
                    end 
 
                end // WR_IDEAL
                WR_READ_FIFO: begin 
                     wr_is_active =1'b1; // this signal sends request to the wr_arbiter, the granted signal is wr_enable
                     if(wr_enable) begin 
                          wr_ns = WR_ACTIVE; 
                          fifo_rd=1'b1;
                    end
                end
 
 
                WR_ACTIVE: begin 
                     wr_is_active =1'b1; // this signal sends request to the wr_arbiter, the granted signal is wr_enable
                     if(wr_enable) begin 
                            m_wr_cyc_o=1'b1; 
                            if (fifo_empty) begin 
                                m_wr_cti_o= END_OF_BURST;                             
                            end
                            if (m_wr_ack_i) begin 
                                wr_counter_next=wr_counter +1'b1;   
                                if (fifo_empty) begin 
                                    wr_ns = WR_IDEAL; 
                                    wr_done=1'b1;
                                end else begin 
                                    fifo_rd=1'b1;
                                end                 
                            end 
                     end               
                end // WR_ACTIVE
                default: begin
 
 
                    end
            endcase
 
    end//alays
 
 
 
 
 
    // update control registers
    always @ (*) begin 
        //default values
        rd_start_addr_next= rd_start_addr;
        wr_start_addr_next=wr_start_addr;
        data_size_next= data_size;
      //  burst_size_next= burst_size;
        rd_start = 1'b0;
        if(s_stb_i  &    s_we_i & state_reg_enable)   begin 
            if (!dma_busy)  begin   
                case(wb_wr_rd_addr)
                    RD_STRT_WB_ADDR: begin                    
                        rd_start_addr_next={{OFFSET_w{1'b0}},s_dat_i [Dw-1    : OFFSET_w]};
                    end //RD_STRT_WB_ADDR
                    DATA_SIZE_WB_ADDR: begin 
                        data_size_next=s_dat_i [MAX_TRANSACTION_WIDTH+OFFSET_w-1 :   OFFSET_w]; 
                    end //DATA_SIZE_WB_ADDR
                    BURST_SIZE_WB_ADDR: begin 
              //          burst_size_next=s_dat_i [BURST_SIZE_w-1 : 0];    
                    end //BURST_SIZE_WB_ADDR
                    WR_STRT_WB_ADDR: begin 
                        wr_start_addr_next= {{OFFSET_w{1'b0}},s_dat_i [Dw-1 :   OFFSET_w]};
                        rd_start = 1'b1;
                    end //WR_STRT_WB_ADDR
                          default :begin 
 
 
                          end                         
                 endcase//wb_wr_rd_addr
            end//if
        end//if
   end// always
 
 
 
    always @(*)begin 
        rd_is_busy_next= rd_is_busy;
        if(rd_start) rd_is_busy_next =1'b1;
        else if(rd_done) rd_is_busy_next=1'b0;
    end
 
    wire wr_start = ~fifo_empty;
     always @(*)begin 
        wr_is_busy_next= wr_is_busy;
        if(wr_done) wr_is_busy_next =1'b0;
        else if(wr_start) wr_is_busy_next=1'b1;
    end
 
 
 
 
    //registers assigmnet
 
`ifdef SYNC_RESET_MODE 
    always @ (posedge clk )begin 
`else 
    always @ (posedge clk or posedge reset)begin 
`endif   
        if(reset) begin 
            rd_ps <= RD_IDEAL;
            wr_ps <= WR_IDEAL;
         //   s_ack_o <= 1'b0;
            rd_start_addr <= {Dw{1'b0}};
            wr_start_addr <= {Dw{1'b0}};
            data_size <= {MAX_TRANSACTION_WIDTH{1'b0}};
          //  burst_size <= {BURST_SIZE_w{1'b0}};   
            rd_counter <=  {MAX_TRANSACTION_WIDTH{1'b0}};
            wr_counter <=   {MAX_TRANSACTION_WIDTH{1'b0}}; 
            rd_is_busy<= 1'b0;
            wr_is_busy<= 1'b0;
       //     burst_counter <= {BURST_SIZE_w{1'b0}};
 
        end else begin 
            rd_ps <= rd_ns;
            wr_ps <= wr_ns;
            rd_start_addr <= rd_start_addr_next;
            wr_start_addr <= wr_start_addr_next;
            data_size <= data_size_next;
   //         burst_size <= burst_size_next;  
            rd_counter <=  rd_counter_next;
            wr_counter <=  wr_counter_next; 
            rd_is_busy <=rd_is_busy_next;
            wr_is_busy <=wr_is_busy_next;
       //     burst_counter<= burst_counter_next;            
       //     s_ack_o<=s_ack_o_next;
        end 
    end 
 
 
 
 
/*
    dma_fifo  #(
         .Dw(Dw),//data_width
         .B(FIFO_B) // buffer num
    ) 
    the_fifo
    (
         .din(m_rd_dat_i),   
         .wr_en(fifo_wr), 
         .rd_en(fifo_rd), 
         .dout(m_wr_dat_o),  
         .full(fifo_full),
         .nearly_full(fifo_nearly_full),
         .empty(fifo_empty),
         .reset(reset),
         .clk(clk)
    );
*/
 
 
 
 
 
 
endmodule
 
 
 
 
/**************
*   shared memory multi chanel fifo  
*
****************/ 
 
module shared_mem_fifos #(
    parameter NUM      =   4,
    parameter B        =   4,   // buffer space :flit per VC 
    parameter Dw     =   32,
    parameter DEBUG_EN =   1
 
    )   
    (
        din,     // Data in
        fifo_num_wr,//write vertual chanel   
        fifo_num_rd,//read vertual chanel    
        wr_en,   // Write enable
        rd_en,   // Read the next word
        dout,    // Data out
        full,
        nearly_full,
        empty,
        reset,
        clk
 
    );
 
 
 
    function integer log2;
      input integer number; begin   
         log2=(number <=1) ? 1: 0;    
         while(2**log2<number) begin    
            log2=log2+1;    
         end       
      end   
    endfunction // log2 
 
    localparam      V       =   NUM,
                    Fw      =   Dw,   //flit width
                    BV      =   B   *   V;
 
 
    input  [Fw-1      :0]   din;     // Data in
    input  [V-1       :0]   fifo_num_wr;//write vertual chanel   
    input  [V-1       :0]   fifo_num_rd;//read vertual chanel    
    input                   wr_en;   // Write enable
    input                   rd_en;   // Read the next word
    output [Fw-1       :0]  dout;    // Data out
 
    output [V-1 :   0] full;
    output [V-1 :   0] nearly_full;
    output [V-1 :   0] empty;
 
 
 
 
    input                   reset;
    input                   clk;
 
 
    localparam BVw              =   log2(BV),
               Bw               =   (B==1)? 1 : log2(B),
               Vw               =  (V==1)? 1 : log2(V),
               DEPTHw           =   Bw+1,
               BwV              =   Bw * V,
               BVwV             =   BVw * V,
               RAM_DATA_WIDTH   =   Fw ;
 
 
 
    wire  [RAM_DATA_WIDTH-1     :   0] fifo_ram_din;
    wire  [RAM_DATA_WIDTH-1     :   0] fifo_ram_dout;
    wire  [V-1                  :   0] wr;
    wire  [V-1                  :   0] rd;
    reg   [DEPTHw-1             :   0] depth    [V-1            :0];
 
 
    assign fifo_ram_din = din;
    assign dout = fifo_ram_dout;    
    assign  wr  =   (wr_en)?  fifo_num_wr : {V{1'b0}};
    assign  rd  =   (rd_en)?  fifo_num_rd : {V{1'b0}};
 
 
    //assign dout = queue[rd_ptr];
 
 
 
 
genvar i;
 
generate 
    if((2**Bw)==B)begin :pow2
        /*****************      
          Buffer width is power of 2
        ******************/
    reg [Bw- 1      :   0] rd_ptr [V-1          :0];
    reg [Bw- 1      :   0] wr_ptr [V-1          :0];
 
 
 
 
    wire [BwV-1    :    0]  rd_ptr_array;
    wire [BwV-1    :    0]  wr_ptr_array;
    wire [Bw-1     :    0]  vc_wr_addr;
    wire [Bw-1     :    0]  vc_rd_addr; 
    wire [Vw-1     :    0]  wr_select_addr;
    wire [Vw-1     :    0]  rd_select_addr; 
    wire [Bw+Vw-1  :    0]  wr_addr;
    wire [Bw+Vw-1  :    0]  rd_addr;
 
 
 
 
    assign  wr_addr =   {wr_select_addr,vc_wr_addr};
    assign  rd_addr =   {rd_select_addr,vc_rd_addr};
 
 
 
    one_hot_mux #(
        .IN_WIDTH       (BwV),
        .SEL_WIDTH      (V) 
    )
    wr_ptr_mux
    (
        .mux_in         (wr_ptr_array),
        .mux_out            (vc_wr_addr),
        .sel                (fifo_num_wr)
    );
 
 
 
    one_hot_mux #(
        .IN_WIDTH       (BwV),
        .SEL_WIDTH      (V) 
    )
    rd_ptr_mux
    (
        .mux_in         (rd_ptr_array),
        .mux_out            (vc_rd_addr),
        .sel                (fifo_num_rd)
    );
 
 
 
    one_hot_to_bin #(
    .ONE_HOT_WIDTH  (V)
 
    )
    wr_vc_start_addr
    (
    .one_hot_code   (fifo_num_wr),
    .bin_code       (wr_select_addr)
 
    );
 
    one_hot_to_bin #(
    .ONE_HOT_WIDTH  (V)
 
    )
    rd_vc_start_addr
    (
    .one_hot_code   (fifo_num_rd),
    .bin_code       (rd_select_addr)
 
    );
 
    dma_fifo_ram    #(
        .DATA_WIDTH (RAM_DATA_WIDTH),
        .ADDR_WIDTH (BVw )
    )
    the_queue
    (
        .wr_data        (fifo_ram_din), 
        .wr_addr        (wr_addr[BVw-1  :   0]),
        .rd_addr        (rd_addr[BVw-1  :   0]),
        .wr_en          (wr_en),
        .rd_en          (rd_en),
        .clk            (clk),
        .rd_data        (fifo_ram_dout)
    );  
 
    for(i=0;i<V;i=i+1) begin :loop0
 
        assign full[i] = (depth [i] == B);
        assign nearly_full[i] = depth[i] >= B-1;
        assign empty[i] = depth[i] == {DEPTHw{1'b0}};
 
 
        assign  wr_ptr_array[(i+1)*Bw- 1        :   i*Bw]   =       wr_ptr[i];
        assign  rd_ptr_array[(i+1)*Bw- 1        :   i*Bw]   =       rd_ptr[i];
        //assign    vc_nearly_full[i] = (depth[i] >= B-1);
 
 
 
`ifdef SYNC_RESET_MODE 
    always @ (posedge clk )begin 
`else 
    always @ (posedge clk or posedge reset)begin 
`endif  
            if (reset) begin
                rd_ptr  [i] <= {Bw{1'b0}};
                wr_ptr  [i] <= {Bw{1'b0}};
                depth   [i] <= {DEPTHw{1'b0}};
            end
            else begin
                if (wr[i] ) wr_ptr[i] <= wr_ptr [i]+ 1'h1;
                if (rd[i] ) rd_ptr [i]<= rd_ptr [i]+ 1'h1;
                if (wr[i] & ~rd[i]) depth [i]<=
//synthesis translate_off
//synopsys  translate_off
                   #1
//synopsys  translate_on
//synthesis translate_on
                   depth[i] + 1'h1;
                else if (~wr[i] & rd[i]) depth [i]<=
//synthesis translate_off
//synopsys  translate_off
                   #1
//synopsys  translate_on
//synthesis translate_on
                   depth[i] - 1'h1;
            end//else
        end//always
 
 
//synthesis translate_off
//synopsys  translate_off
 
        always @(posedge clk) begin
            if(~reset)begin
                if (wr[i] && (depth[i] == B) && !rd[i])
                    $display("%t: ERROR: Attempt to write to full FIFO: %m",$time);
                if (rd[i] && (depth[i] == {DEPTHw{1'b0}}   ))
                    $display("%t: ERROR: Attempt to read an empty FIFO: %m",$time);
 
          end//~reset      
        //if (wr_en)       $display($time, " %h is written on fifo ",din);
        end//always
//synopsys  translate_on
//synthesis translate_on
    end//for
 
 
 
    end  else begin :no_pow2    //pow2
 
 
 
 
 
    /*****************      
        Buffer width is not power of 2
     ******************/
 
 
 
 
 
    //pointers
    reg [BVw- 1     :   0] rd_ptr [V-1          :0];
    reg [BVw- 1     :   0] wr_ptr [V-1          :0];
 
    // memory address
    wire [BVw- 1    :   0]  wr_addr;
    wire [BVw- 1    :   0]  rd_addr;
 
    //pointer array      
    wire [BVwV- 1   :   0]  wr_addr_all;
    wire [BVwV- 1   :   0]  rd_addr_all;
 
    for(i=0;i<V;i=i+1) begin :loop0
 
        assign  wr_addr_all[(i+1)*BVw- 1        :   i*BVw]   =       wr_ptr[i];
        assign  rd_addr_all[(i+1)*BVw- 1        :   i*BVw]   =       rd_ptr[i];       
        assign full[i] = (depth [i] == B);
        assign nearly_full[i] = depth[i] >= B-1;
        assign empty[i] = depth[i] == {DEPTHw{1'b0}};
 
 
`ifdef SYNC_RESET_MODE 
    always @ (posedge clk )begin 
`else 
    always @ (posedge clk or posedge reset)begin 
`endif  
            if (reset) begin
                rd_ptr  [i] <= (B*i);
                wr_ptr  [i] <= (B*i);
                depth   [i] <= {DEPTHw{1'b0}};
            end
            else begin
                if (wr[i] ) wr_ptr[i] <=(wr_ptr[i]==(B*(i+1))-1)? (B*i) : wr_ptr [i]+ 1'h1;
                if (rd[i] ) rd_ptr[i] <=(rd_ptr[i]==(B*(i+1))-1)? (B*i) : rd_ptr [i]+ 1'h1;
                if (wr[i] & ~rd[i]) depth [i]<=
//synthesis translate_off
//synopsys  translate_off
                   #1
//synopsys  translate_on
//synthesis translate_on
                   depth[i] + 1'h1;
                else if (~wr[i] & rd[i]) depth [i]<=
//synthesis translate_off
//synopsys  translate_off
                   #1          
//synopsys  translate_on
//synthesis translate_on
                   depth[i] - 1'h1;
            end//else
        end//always  
 
 
//synthesis translate_off
//synopsys  translate_off
 
        always @(posedge clk) begin
            if(~reset)begin
                if (wr[i] && (depth[i] == B) && !rd[i])
                    $display("%t: ERROR: Attempt to write to full FIFO: %m",$time);
                if (rd[i] && (depth[i] == {DEPTHw{1'b0}}   ))
                    $display("%t: ERROR: Attempt to read an empty FIFO: %m",$time);
 
 
        //if (wr_en)       $display($time, " %h is written on fifo ",din);
            end//~reset
        end//always
 
//synopsys  translate_on
//synthesis translate_on
 
 
 
    end//FOR
 
 
    one_hot_mux #(
        .IN_WIDTH(BVwV),
        .SEL_WIDTH(V),
        .OUT_WIDTH(BVw)
    )
    wr_mux
    (
        .mux_in(wr_addr_all),
        .mux_out(wr_addr),
        .sel(fifo_num_wr)
    );
 
    one_hot_mux #(
        .IN_WIDTH(BVwV),
        .SEL_WIDTH(V),
        .OUT_WIDTH(BVw)
    )
    rd_mux
    (
        .mux_in(rd_addr_all),
        .mux_out(rd_addr),
        .sel(fifo_num_rd)
    );
 
    dma_fifo_ram_mem_size  #(
       .DATA_WIDTH (RAM_DATA_WIDTH),
       .MEM_SIZE (BV ) 
    )
    the_queue
    (
        .wr_data        (fifo_ram_din), 
        .wr_addr        (wr_addr),
        .rd_addr        (rd_addr),
        .wr_en          (wr_en),
        .rd_en          (rd_en),
        .clk            (clk),
        .rd_data        (fifo_ram_dout)
    );  
 
 
 
 
 
 
    end
    endgenerate
 
 
 
 
 
 
//synthesis translate_off
//synopsys  translate_off
generate
if(DEBUG_EN) begin :dbg 
    always @(posedge clk) begin
        if(~reset)begin
            if(wr_en && fifo_num_wr == {V{1'b0}})
                    $display("%t: ERROR: Attempt to write when no wr chanel is asserted: %m",$time);
            if(rd_en && fifo_num_rd == {V{1'b0}})
                    $display("%t: ERROR: Attempt to read when no rd chanel  is asserted: %m",$time);
        end
    end
end 
endgenerate 
//synopsys  translate_on
//synthesis translate_on    
 
endmodule
 
 
 
 
/****************************
 
     fifo_ram
 
*****************************/
 
 
 
module dma_fifo_ram     #(
    parameter DATA_WIDTH    = 32,
    parameter ADDR_WIDTH    = 8       
    )
    (
        input [DATA_WIDTH-1         :       0]  wr_data,        
        input [ADDR_WIDTH-1         :       0]      wr_addr,
        input [ADDR_WIDTH-1         :       0]      rd_addr,
        input                                               wr_en,
        input                                               rd_en,
        input                                           clk,
        output [DATA_WIDTH-1   :       0]      rd_data
    );  
 
	reg [DATA_WIDTH-1:0] memory_rd_data; 
   // memory
	reg [DATA_WIDTH-1:0] queue [2**ADDR_WIDTH-1:0] /* synthesis ramstyle = "no_rw_check , M9K" */;
	always @(posedge clk ) begin
			if (wr_en)
				 queue[wr_addr] <= wr_data;
			if (rd_en)
				 memory_rd_data <= queue[rd_addr];
	end
 
    assign rd_data =  memory_rd_data;
 
endmodule
 
 
 
module dma_fifo_ram_mem_size     #(
    parameter DATA_WIDTH  = 32,
    parameter MEM_SIZE    = 200   
    )
    (
       wr_data,        
       wr_addr,
       rd_addr,
       wr_en,
       rd_en,
       clk,
       rd_data
    ); 
 
 
    function integer log2;
      input integer number; begin   
         log2=(number <=1) ? 1: 0;    
         while(2**log2<number) begin    
            log2=log2+1;    
         end 	   
      end   
    endfunction // log2 
 
    localparam ADDR_WIDTH=log2(MEM_SIZE);
 
    input [DATA_WIDTH-1         :       0]  wr_data;       
    input [ADDR_WIDTH-1         :       0]  wr_addr;
    input [ADDR_WIDTH-1         :       0]  rd_addr;
    input                                   wr_en;
    input                                   rd_en;
    input                                   clk;
    output reg  [DATA_WIDTH-1   :       0]  rd_data;
 
 
 
    reg [DATA_WIDTH-1:0] queue [MEM_SIZE-1:0] /* synthesis ramstyle = "no_rw_check , M9K" */;
 
    always @(posedge clk ) begin
         if (wr_en)   queue[wr_addr] <= wr_data;
         if (rd_en)   rd_data <= queue[rd_addr];
    end
 
 
endmodule
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.