vcs仿真flash模型时,flash一直为忙的分析

flash模型

  • MT25QU01GBBB8E0_VG13
    该模型从Micron官方网站下载,搜索地址Micron仿真模型搜索 进入Micron官网,在搜索框输入‘sim-model’,搜索结果列表中会出现很多可以使用的模型。
    仿真环境建立过程不谈。
  • 准备软件
    软件中实现spi-flash的各种操作,readid,读擦写等,编译成vcs需要的格式

执行流程

  • read ID
[312777.000 ns ns] COMMAND DECODED: Read ID , withAddr=00000000, with2Addr=00000000, with4Addr=00000000, cmdcode=9f 
[312777.000 ns ns] COMMAND RECOGNIZED: Read ID.
  [312785.000 ns ns] Data are going to be output: 20. [Read ID, byte 0] 0 0
  [312937.000 ns ns] Data are going to be output: ba. [Read ID, byte 1] 0 0
  [313129.000 ns ns] Data are going to be output: 20. [Read ID, byte 2] 0 0
  [313321.000 ns ns] Data are going to be output: 10. [Read ID, byte 3] 0 0
jedec: 0x20ba20

模型中识别spi送进来的指令,然后返回当前使用的flash型号。

  • erase
[327733.000 ns ns] COMMAND DECODED: Write Enable , withAddr=00000000, with2Addr=00000000, with4Addr=00000000, cmdcode=06 
[327733.000 ns ns] COMMAND RECOGNIZED: Write Enable.
  [327813.000 ns ns] Command execution completed: WEL bit set.
[327973.000 ns ns] COMMAND DECODED: Subsector Erase , withAddr=00000001, with2Addr=00000000, with4Addr=00000000, cmdcode=20 
[327973.000 ns ns] 1.COMMAND RECOGNIZED: Subsector Erase. Address expected ...  
  [328545.000 ns ns] Address latched: 0000000 (byte 0 of page 0, sector 0)
  [328609.000 ns ns] Command execution begins: Subsector Erase 
  [328609.000 ns ns] isProtected_by_SR: 0 sectAddr: 000 
  [328609.000 ns ns] isProtected_by_lockReg: 0 sectAddr: 000 
  [328609.000 ns ns] isProtected_by_PPBReg: 1 sectAddr: 000
  [328609.000 ns ns] isProtected_by_lockReg4Kb: 0 subsecAddr: 0000 
  [328767.000 ns ns] COMMAND DECODED: Read SR , withAddr=00000000, with2Addr=00000000, with4Addr=00000000, cmdcode=05 
[328767.000 ns ns] COMMAND RECOGNIZED: Read SR.
  [328775.000 ns ns] Data are going to be output: 00000011. [Read Status Register] 0 0

flash擦除过程中,先发送06命令解锁flash
然后执行20命令,对解锁的flash进行擦除。
当程序运行到这里,剩下的时间就是漫长的等待,以至于认为擦除操作失败。实际上只是delay的时间比较长,需要等待的时间比较久而已。以下通过代码分析其中的原因。
首先找到flash擦除的执行代码

  //--------------
    // Erase
    //--------------

    always @N25Qxxx.seqRecognized 
    
    if ((N25Qxxx.cmdRecName==="Sector Erase" || N25Qxxx.cmdRecName==="Subsector Erase" || N25Qxxx.cmdRecName==="Subsector Erase 32K" ||N25Qxxx.cmdRecName==="Subsector Erase 32K 4Byte" ||
        N25Qxxx.cmdRecName==="Bulk Erase" || N25Qxxx.cmdRecName==="Die Erase") && (N25Qxxx.die_active == 1))begin : erase_operations
    
          .......
          
        `endif      
        end else      
        fork : erase_ops

        begin : exe
        
           @(posedge N25Qxxx.S);

            disable reset;

            operation = N25Qxxx.cmdRecName;
            destAddr = N25Qxxx.addr;
            if(Suspended == 0) destAddrSusp1 = destAddr;
            N25Qxxx.latchingMode="N";
            N25Qxxx.busy = 1;
            startTime = $time;
            $display("  [%0t ns] Command execution begins: %0s for3.", $time, operation);
            if (operation=="Sector Erase") delay=erase_delay;
            `ifdef Stack512Mb
              else if (operation=="Die Erase") delay=erase_die_delay;
           ......
           
            `ifdef SubSect
              else if (operation=="Subsector Erase")  
              begin
              delay=erase_ss_delay; 
              $display("  [%0t ns] Command execution begins: %0s for7.", $time, operation);
              end
      		......
            `endif  
            
            -> errorCheck;

            @(noError) 
                begin
                    
                    ......
                    
                    `ifdef SubSect
                      else if (operation=="Subsector Erase")  
                      begin
                      mem.eraseSubsector(destAddr);
                       $display("  [%0t ns] Command execution begins: Subsector Erase %d.", $time,destAddr);
                      end
                      
                    ......
        end


        begin : reset
        
          @N25Qxxx.resetEvent;
            operation = "None";
            disable exe;    
        end  
    join
end

删除大部分代码,保留关键部分。
以下是主要的流程:
着重看 fork : erase_ops 函数,首先判断operation,执行什么操作,通过log日志,可以看出已经准确

  • 识别了Subsector Erase操作,
  • 该操作下给delay参数赋值为erase_ss_delay
  • 并且将flash状态设置为busy。
  • 接着触发errorCheck事件,该事件中主要判断将要操作的命令,以及flash是否解锁准备好执行该命令,
  • 然后等待捕捉@(noError)事件,执行真正的擦除动作。
errorCheck中的实现
 //------------------------
    //  Error check
    //------------------------
    // This process also models  
    // the operation delays
    
    always @(errorCheck) fork : errorCheck_ops
    
    ......
    
     if ( (operation=="Page Program" || operation=="Dual Program" || operation=="Dual Extended Program" || 
                           operation=="Quad Extended Program" || operation=="Quad Program" || operation=="Dual Command Page Program" || operation=="Quad Command Page Program" ||
                           operation=="Sector Erase" ||  operation=="Subsector Erase" || operation=="Subsector Erase 32K" || operation=="Subsector Erase 32K 4Byte")

                                                        &&
                          `ifdef Stack512Mb
                            //(isProtected_by_SR_stack(destAddr)!==0 || lock.isProtected_by_lockReg(destAddr)!==0) ) begin
                            (lock.isProtected_by_SR(destAddr)!==0 || lock.isProtected_by_lockReg(destAddr)!==0) ) begin
                          `else
                            `ifdef MEDT_PPB  
                            ((lock.isProtected_by_SR(destAddr)!==0 || lock.isProtected_by_lockReg(destAddr)!==0) || ppb.isProtected_by_PPBReg(destAddr)!==1 || lock4kb.isProtected_by_lockReg(destAddr)!==0)) 
                            begin
	
	-> error;
						.......
			
    
        fork : dynamicCheck
			
				......
       
            // #delay begin 
           
            begin : main_ops
             $display(" **INFO** start delay!");
              #delay;
            $display(" **INFO** delay over!");
            N25Qxxx.busy=0;
            
                if(!Suspended || !prog.prog_susp) -> stat.WEL_reset;
                -> noError;
                #1; 
                -> noError2;
                disable dynamicCheck;
                disable errorCheck_ops;
            end
        join

在errorCheck中,如果出现错误则会释放error的事件,如果没有错,则会执行main_ops。
这里开始delay,这个delay就是上面的 erase_ss_delay

若果这个值设置太大,会出现上文提到的仿真的等待的时间过长。

然后清除flash的busy状态,释放noError事件,flash接着执行正真的擦除动作。
通过查看时间配置参数,在TImingData.h中,找到参数配置

 `ifdef SubSect 
   parameter time erase_ss_delay = tSSE;
`endif

parameter time tSSE = 3e9; 

由此可见,等待的时间是过长了。
对应的flash手册中指出,flash页擦除的时间大概为300ms,所以官方的配置为3e9,此处为了减少仿真等待的时间,可以将此值改成一个合理的数值比如30.则会大大提高仿真的速率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值