dmac学习之基于shadow register的multi block transfer

基于DW_axi_dmac_databook,对multi block transfer进行了验证。

Programming Flow for LLI-Based Multi-Block Transfer
ARC StatusSoftware Sequencepostscript
initial1)配置DMAC_CFGREG[1:0]2'b11,对DMA进行使能;
2)配置CHx_CFG2[3:0]4'b1111,表明是基于LLImulti block传输;
3)基于传输类型(M2M/M2P/P2M/P2P)配置CHx_CFG2[34:32]
LLI configuration1)配置CHx_SARCHx_DAR的地址;
2)配置CHx_BLOCK_TS来指定一个block包含位宽为SRC_TR_WIDTH数据的个数;
3)配置CHx_CTL[10:8].SRC_TR_WIDTH来表明每个数据的位宽;
4)配置CHx_CTL[47].AWLEN_EN,对AWLEN进行使能;
5)配置CHx_CTL[55:48].AWLEN,用于指定每个burst transaction中的数据个数(用于匹配destination的位宽);
6)配置CHx_CTL[58].IOC_BlkTfr1,支持输出block传输结束的中断信号;
7)配置CHx_CTL[63].ShadowReg_Or_LLI_Valid1,表明可以将有关寄存器的值写入shadowreg
8)配置CHENREG2,拉高用于传输的通道使能和写使能,开始传输数据;
9)对CHx_CTL[63].ShadowReg_Or_LLI_Valid进行轮询,直到该bit值为0
CHx_CTL必须是最后一个配置的寄存器
remaining block1)配置CHx_SAR/CHx_DAR/CHx_BLOCK_TS/CHx_CTL寄存器;
2)开始数据传输;
CHx_CTL必须是最后一个配置的寄存器
last block1)配置CHx_SAR/CHx_DAR/CHx_BLOCK_TS/CHx_CTL寄存器,并将CHx_CTL[62].SHADOWREG_OR_LLI_LAST信号拉高,表明这是最后一个block
2)轮询CHx_INTSTATUS[1].DMA_TFR_DONE_IntStat的值直到该bit1
3)结束传输。

Programming Flow for Shadow-Register-Based Multi-Block Transfer
ARC StatusSoftware Sequencepostscript
initial1) Software reads the DMAC channel enable register (DMAC_ChEnReg) to select an available (unused) channel.
2) Software programs the CHx_CFG register with appropriate values for the DMA transfer.
1) The SRC_MLTBLK_TYPE and/or DST_MLTBLK_TYPE bits must be set to 2’b10.
2)
 The CHx_CFG register must be programmed before programming the CHx_SAR, CHx_DAR, CHx_BLOCK_TS, or CHx_CTL registers.
3) If the slave interface data bus width or transfer size is less than 64 bits, CHx_CFG[7:0] should be updated in the first write to the CHx_CFG register.
first block1) Software programs the CHx_SAR and/or CHx_DAR, CHx_BLOCK_TS, and CHx_CTL registers with appropriate values for the first block. DW_axi_dmac loads the corresponding shadow registers with these values.
2) Software enables the channel by writing 1 to the appropriate bit location in the DMAC_ChEnReg register.
3) DW_axi_dmac initiates the DMA block transfer operation based on the settings for the block transfer.
4) Software polls the ShadowReg_Or_LLI_Valid bit in the CHx_CTL register(
VALID2) till it is 0.
1) The CHx_CTL register must be the last register to be programmed with the ShadowReg_Or_LLI_Valid bit set to 1 to indicate that the shadow register contents are valid. If the slave interface data bus width or transfer size is less than 64 bits, CHx_CTL[63:56] must be updated last.
2)The block transfer might start immediately or after the hardware or software handshaking request, depending on the value of the TT_FC field in the CHx_CFG register.
3) If 
VALID1 is seen as '0', DW_axi_dmac waits till software writes (any value) to CHx_BLK_TFR_ResumeReqReg to indicate valid LLI availability, before attempting another Shadow Register fetch operation. DW_axi_dmac might generate 'ShadowReg_Or_LLI_Invalid_ERR' Interrupt in this case.
4) Else if
 VALID1 is seen as '1', DW_axi_dmac copies the shadow register contents to the registers used for executing the DMA block transfer (CHx_SAR and/or CHx_DAR, CHx_BLOCK_TS and CHx_CTL registers) and clears the VALID1&VALID2 to 0.
5) When CHx_CTL.ShadowReg_Or_LLI_Last is asserted, it means that the current block is the final block in the transfer.Otherwise it indicates that there are one or more blocks to be transferred and checks 
VALID1 bit again at the end of current block transfer.
6) DW_axi_dmac clears 
VALID2 to 0 only after copying the shadow register contents to the registers used for executing the DMA block transfer.
7) Software must program the shadow registers with a new set of values only after the 
VALID2 is set to 0.
8) If software tries to programs the shadow registers when the 
VALID2 is set to 1, DW_axi_dmac ignores this write operation, sets the SLVIF_ShadowReg_WrOnValid_ERR bit of the CHx_IntStatusReg register to 1, and generates an interrupt (if the corresponding interrupt generation is not masked off).
remaining block1) Software programs the CHx_SAR and/or CHx_DAR, CHx_BLOCK_TS, and CHx_CTL registers with appropriate values for the next block.
2) DW_axi_dmac initiates the DMA block transfer operation based on the settings for the block transfer.
3) Software waits for the block transfer completion interrupt or polls the block transfer completion indication bit (BLOCK_TFR_DONE) of the CHx_IntStatusReg register until it is set to 1.
4) If there are one or more blocks to be transferred, software polls CHx_CTL.ShadowReg_Or_LLI_Valid(
VALID2) bit until it is seen as 0 and go to step 1.
1) The DMA block transfer corresponding to the previous shadow register contents may be in progress when software is programming these registers.
2) One read operation is enough as DW_axi_dmac should have already copied the shadow register contents and cleared 
VALID2 to 0.
`ifndef NPC_RSU_XDMA_TCM2L3_SINGLE_BLOCK_TEST__SV
`define NPC_RSU_XDMA_TCM2L3_SINGLE_BLOCK_TEST__SV


class npc_rsu_xdma_tcm2l3_single_block_test extends npc_base_test;

    `uvm_component_utils_begin(npc_rsu_xdma_tcm2l3_single_block_test)
    `uvm_component_utils_end

    function new(string name, uvm_component parent);
        super.new(name,parent);
    endfunction : new

    // build_phase
    virtual function void build_phase(uvm_phase phase);
        super.build_phase(phase);

        uvm_config_db#(uvm_object_wrapper)::set(this, "npc_sys_env_h.npc_env_h.npc_noc_env_h.axi_env.slave[36].sequencer.run_phase", "default_sequence", axi_slave_mem_response_sequence::type_id::get());     
        uvm_config_db#(uvm_object_wrapper)::set(this, "npc_sys_env_h.npc_env_h.npc_noc_env_h.axi_env.slave[37].sequencer.run_phase", "default_sequence", axi_slave_mem_response_sequence::type_id::get());

    endfunction : build_phase
    


    task main_phase(uvm_phase phase);
        bit [2047:0]            l3_data_tmp;
        bit [127:0]             tcm_data_tmp;
        bit [127:0]             tcm_data_tmp1;
        bit [127:0]             tcm_data_q[$];
        bit [63:0]              rdata;
        bit [63:0]              wdata;
        response_status_type    rsp_status;
        super.main_phase(phase);
        `uvm_info("[NPC_BASE_TEST]: ","entering main_phase...", UVM_LOW)
        phase.raise_objection(this);
        `uvm_info(get_full_name(),$sformatf("debug info, round 1, now update l3 mem"), UVM_LOW)
        tcm_data_q.delete();
        // Fill 256Byte
        for(int i=0; i<256; i++)begin
            l3_data_tmp[8*i+:8] = i;
        end
        npc_sys_env_h.npc_env_h.npc_noc_env_h.axi_env.slave[36].axi_slave_mem.write(32'h4000_0000, l3_data_tmp[1023:0]);
        npc_sys_env_h.npc_env_h.npc_noc_env_h.axi_env.slave[36].axi_slave_mem.write(32'h4000_0080, l3_data_tmp[2047:1024]);
        for(int j=0; j<16; j++)begin
            tcm_data_tmp = '0;
            tcm_data_tmp = l3_data_tmp[j*128+:128];
            tcm_data_q.push_back(tcm_data_tmp);
        end
        //for(int i=0; i<(1024*4/128); i++)begin
        //    std::randomize(l3_data_tmp) with{l3_data_tmp dist{ 0:/5, [1:'1-1]:/90,'1:/5};};
        //    npc_sys_env_h.npc_env_h.npc_noc_env_h.axi_env.slave[36].axi_slave_mem.write(32'h4000_0000+i*128,l3_data_tmp);
        //    for(int j=0; j<8; j++)begin
        //        tcm_data_tmp = '0;
        //        npc_sys_env_h.npc_env_h.npc_noc_env_h.axi_env.slave[47].axi_slave_mem.write(i*128+j*16,tcm_data_tmp);
        //        tcm_data_tmp = l3_data_tmp[j*128+:128];
        //        tcm_data_q.push_back(tcm_data_tmp);
        //    end
        //end
        `uvm_info(get_full_name(),$sformatf("debug info, round 2, now config rsu.xdma"), UVM_LOW)
        m_reg_seq.reg_base_seq.get_handle();
        
        m_reg_seq.reg_write_obj(`RSU_RAL.ss_rstnctrl, 32'hffff_ffff, DV_FRONTDOOR, rsp_status);
        m_reg_seq.reg_read_obj(`RSU_DMAC_COMMON_REG.DMAC_IDREG, rdata, DV_FRONTDOOR, rsp_status);
        `uvm_info(get_full_name(),$sformatf("debug info, dmac id  is 'h%0h", rdata), UVM_LOW)
        m_reg_seq.reg_read_obj(`RSU_DMAC_COMMON_REG.DMAC_CFGREG, rdata, DV_FRONTDOOR, rsp_status);
        wdata   = rdata;
        // Enable INT and DMAC
        wdata[1:0] = 2'b11;
        m_reg_seq.reg_write_obj(`RSU_DMAC_COMMON_REG.DMAC_CFGREG, wdata, DV_FRONTDOOR, rsp_status);
        m_reg_seq.reg_read_obj(`RSU_DMAC_COMMON_REG.DMAC_CFGREG, rdata, DV_FRONTDOOR, rsp_status);
        m_reg_seq.reg_read_obj(`RSU_DMAC_COMMON_REG.DMAC_CHENREG2, rdata, DV_FRONTDOOR, rsp_status);
        if(rdata[1] != 0) begin
            `uvm_error(get_full_name(),$sformatf("debug info, ch2 is not free"))
        end
        else begin
            
            /*
             * CFG2
             */
            `uvm_info(get_full_name(),$sformatf("debug info, ch2 is free, we will use it"), UVM_LOW)
            m_reg_seq.reg_read_obj(`RSU_DMAC_CHANNEL2_REG.CH2_CFG2, rdata, DV_FRONTDOOR, rsp_status);
            wdata           = rdata;
            // SRC_MULTBLK_TYPE
            wdata[1:0]      = 2'b10;
            // DST_MULTBLK_TYPE
            wdata[3:2]      = 2'b10;
            // TT_FC
            wdata[34:32]    = 3'h0;
            // LOCK_CH_L
            wdata[54:53]    = 2'b01;
            m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_CFG2, wdata, DV_FRONTDOOR, rsp_status);

            /*
             * For first block
             */
            // SAR - DDR
            wdata = 64'h4000_0000;
            m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_SAR, wdata, DV_FRONTDOOR, rsp_status);
            m_reg_seq.reg_read_obj(`RSU_DMAC_CHANNEL2_REG.CH2_SAR, rdata, DV_FRONTDOOR, rsp_status);
            `uvm_info(get_full_name(),$sformatf("debug info, ch2 sar is 'h%0h", rdata), UVM_LOW)

            // DAR - TCM
            wdata = 64'h0;
            m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_DAR, wdata, DV_FRONTDOOR, rsp_status);

            // BLOCK_TS
            wdata = 31; // BLOCK_TS
            m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_BLOCK_TS, wdata, DV_FRONTDOOR, rsp_status);

            // CH2_CTL
            m_reg_seq.reg_read_obj(`RSU_DMAC_CHANNEL2_REG.CH2_CTL, rdata, DV_FRONTDOOR, rsp_status);
            wdata           = rdata;
            
            // SHADOWREG_OR_LLI_VALID
            wdata[63]       = 1'b1;
            // IOC_BlkTfr
            wdata[58]       = 1'b1;       
            // AWLEN
            wdata[55:48]    = 8'h3;
            // AWLEN_EN
            wdata[47]       = 1'b1;
            // SRC_TR_WIDTH
            wdata[10:8]     = 3'h2;
            `uvm_info(get_full_name(),$sformatf("debug info, round 4, now config ch2_cfg register, wdata is 'h%0h",wdata), UVM_LOW)
            m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_CTL, wdata, DV_FRONTDOOR, rsp_status);
            
            // CHENREG2
            m_reg_seq.reg_read_obj(`RSU_DMAC_COMMON_REG.DMAC_CHENREG2, rdata, DV_FRONTDOOR, rsp_status);
            wdata           = rdata;
            // CH2_EN
            wdata[1]        = 1'b1;
            // CH2_WE
            wdata[17]       = 1'b1;
            m_reg_seq.reg_write_obj(`RSU_DMAC_COMMON_REG.DMAC_CHENREG2, wdata, DV_FRONTDOOR, rsp_status);
            `uvm_info(get_full_name(),$sformatf("debug info, round 4, now read chenreg2, rdata is 'h%0h",rdata), UVM_LOW)
        end

        /*
         * Polling shadow register valid
         */
        `uvm_info(get_full_name(),$sformatf("debug info, round 4, now poll rsu.xdma shadowreg valid"), UVM_LOW)
        rdata[63] = 1;
        while (rdata[63] == 1'b1) begin
            m_reg_seq.reg_read_obj(`RSU_DMAC_CHANNEL2_REG.CH2_CTL, rdata, DV_FRONTDOOR, rsp_status);
            `uvm_info(get_full_name(),$sformatf("debug info, round 4, now read ch2_ctl, rdata is 'h%0h", rdata), UVM_LOW)
            #100ns;
        end

        /*
         * For second block (last)
         */
        // SAR - DDR
        wdata = 64'h4000_0080;
        m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_SAR, wdata, DV_FRONTDOOR, rsp_status);
        m_reg_seq.reg_read_obj(`RSU_DMAC_CHANNEL2_REG.CH2_SAR, rdata, DV_FRONTDOOR, rsp_status);
        `uvm_info(get_full_name(),$sformatf("debug info, ch2 sar is 'h%0h", rdata), UVM_LOW)

        // DAR - TCM
        wdata = 64'h80;
        m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_DAR, wdata, DV_FRONTDOOR, rsp_status);
        // CH2_CTL
        m_reg_seq.reg_read_obj(`RSU_DMAC_CHANNEL2_REG.CH2_CTL, rdata, DV_FRONTDOOR, rsp_status);
        wdata           = rdata;
        // SHADOWREG_OR_LLI_VALID 
        wdata[63]       = 1'b1;
        // SHADOWREG_OR_LLI_LAST
        wdata[62]       = 1'b1;
        m_reg_seq.reg_write_obj(`RSU_DMAC_CHANNEL2_REG.CH2_CTL, wdata, DV_FRONTDOOR, rsp_status);
        `uvm_info(get_full_name(),$sformatf("debug info, round 4, write CH2 shadowreg"), UVM_LOW)

        rdata = 0;
        while(!rdata[1])begin
            m_reg_seq.reg_read_obj(`RSU_DMAC_CHANNEL2_REG.CH2_INTSTATUS, rdata, DV_FRONTDOOR, rsp_status );
            `uvm_info(get_full_name(),$sformatf("debug info, round 4, now read ch2_intstatus, rdata is 'h%0h", rdata), UVM_LOW)
            #100ns;
        end

        `uvm_info(get_full_name(),$sformatf("debug info, round 4, now check data l3 vs tcm"), UVM_LOW)
        for(int i=0; i<16 ; i++)begin
            tcm_data_tmp    = npc_sys_env_h.npc_env_h.npc_noc_env_h.axi_env.slave[47].axi_slave_mem.read(i*16);
            tcm_data_tmp1   = tcm_data_q.pop_front();
            if( tcm_data_tmp == tcm_data_tmp1 )
                `uvm_info(get_full_name(),$sformatf("debug info, tcm data check ok , addr is %0d", i*16), UVM_LOW)
            else
                `uvm_error(get_full_name(),$sformatf("debug info, tcm data check fail , addr is %0d", i*16))
        end

      `uvm_info(get_full_name(),$sformatf("debug info, rsu xdma single bolck transfer test end"), UVM_LOW)

      phase.drop_objection(this);
      `uvm_info("[NPC_BASE_TEST]: ","exiting main_phase...", UVM_LOW)
    endtask : main_phase


endclass : npc_rsu_xdma_tcm2l3_single_block_test 

`endif

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值