网上有很多文章写道,nand flash的读写操作是以page为单位,还有文章说些nand flash时必须按page0、page1、page2…的顺序写,必须先写完前面的page才能写后面的page。难道nandflash就不能随机读到某个字节吗?只能一次性读一页?为啥写要按顺序写?不就是选中某根字线的事吗?明明可以做到随机选中啊,大家在学习过程中是否有这些疑问,今天尝试解答一下。
先来回顾一下nand flash的阵列结构:
通常以32或64个存储单元组成一个漏源相接的存储串,每个串的两头各有一个源线SL和位线BL选通管。32或64根字线连接存储单元的控制栅。一组这样的存储串组成一个block,也就是说32或64根字线下挂的所有存储单元组成一个block,而一根字线下挂的所有存储单元组成一个page或多个page。通常情况下,对SLC来说,一个字线对应一个Page; MLC则对应2个Page,这两个Page是一对(Lower Page和UpperPage); TLC对应3个Page(Lower Page、UpperPage和Extra Page,不同闪存厂家叫法不一样)。一个Page有多大,那么字线上面就有多少个存储单元,就有多少个位线。还有将位线以奇偶划分的,此时的page数会翻倍。
一个 LUN(die)至少包含一个page寄存器和一个plane,也有一个LUN内含2个或4个plane。 每个plane对应一个page寄存器。通常,为了加快读写吞吐量,每个plane还会增加一个cache 寄存器,Cache读支持在传输前一个Page数据给主控的时候(Cache Register→主控),可以从闪存介质读取下一个主控需要读的Page的数据到Page Register(闪存介质→Page Register),这样数据在闪存总线传输的时间就可以隐藏在读闪存介质的时间里(或者相反,取决于哪个时间更长); Cache Program也是如此,它支持闪存写前一个Page数据的同时(Page Register→闪存介质),传输下一个要写的数据到CacheRegister(主控→Cache Register),这样数据在闪存总线传输可以隐藏在前一个Page的写时间里。当然,有两个Register的闪存也支持正常的读写模式,这时候,用户可以把Cache Register和Page Register看成是一个缓存。
再来回顾一下nandflash的寻址,ONFI协议规定了两种地址类型:列地址和行地址,列地址用来访问一个page中的字节和字。行地址用于寻址page,block或者LUN。看到这里大家就有疑问了,这不是有列地址可以访问一个page中的字节吗?如果是以page为基本读写操作单位,那要列地址干什么?
首先,nand flash的读写操作是以page为单位,这句话从nand阵列本身来说是没错的,我们分情况举例说明:
1、如果是操作一个连续存储的大文件,主机通过READ PAGE(00h–30h)命令,选中相应字线后,整个字线上的所有存储单元(就是一个page)的状态(管子是通还是断)就会呈现在各自的位线上,位线上的电平信息会全部传输到与page大小相同的cache寄存器中,这时并不关注列地址是多少,等到第一页全部传输到缓存寄存器后,再通过列地址寻址,在缓存寄存器中定位到列地址指示的字节,然后开始输出到IO,这个列地址之前的数据就不会输出了。之后可以继续发送READ PAGE(00h–30h)命令读接下来的页,接下来的列地址就都为0,就可以完成整页整页输出。为了加大吞吐量,可以使用cache操作,使用READ PAGE CACHE SEQUENTIAL (31h)命令,就可以在cache寄存器输出当前页的同时,将下一页的数据移动到page寄存器中,这里是自动寻址到下一页,不用每次再写地址,同时将IO传输时间段与阵列操作时间段重叠,可以有效提升吞吐量,读大文件通常用此命令。
2、如果是读一些分散的小文件,比如先读page0的第8个字节,然后再读page0的第1个字节。假设每次读都在阵列上做列寻址,那第一次用一个读命令,定位到第8个字节,将这个字节传输到cache寄存器中,然后通过IO输出这个字节,再读第1字节的时候,又要重复发命令、地址,最关键的是还要做一次阵列到cache寄存器的数据搬运,这个搬运的时间是比较长的,造成效率很低,显然开发者不会这么去设计一个存储器。再者,怎么做到从nand阵列里只移动某一个字节的数据出去也是个问题,我们知道ONFI规定的读命令里,只给了一个起始地址,并没有给要读多长的数据信息,读多少就看外部读使能信号RE或者时钟发多少周期,所以在nand flash芯片内部的地址解码,只能解出来page地址(也就是选中哪根字线)和列地址(缓存寄存器中的页内偏移),列地址并不是用来选中位线,因为列地址只是一个起始偏移,并不能告诉阵列是要选中这个偏移开始的8根位线,还是这个偏移开始之后的所有位线。所以综合来看,一定是先把一整页全部移动到cache寄存器中,然后再在寄存器里做页内偏移寻址,这样就在第一个读第8个字节的命令下,就把整页数据都移动到cache寄存器了,下一次读第1个字节就不用再访问阵列了,直接使用RANDOM DATA READ (05h-E0h)命令,改变缓存的列地址,就可以读第1个字节了。
所以综上所述,nand flash的读写操作是以page为单位,说的是nand阵列操作的确是以page为基本单位,同时nand flash也能随机访问到某个字节,操作原理是在cache寄存器中做偏移寻址。正是因为nand flash这种操作机制,他的小文件随机读写效率不高,要多次发命令、地址,数据在整个IO传输中的占比较低,不经济。但是它操作大文件很合适,效率很高。
接下来看nand flash时必须按page0、page1、page2…的顺序写吗?这句话也没错,但是得分情况,如果是MLC、TLC这些一个cell存放多个bit的情况,就需要按顺序写Page0、Page1、Page2…,原因是MLC一个存储单元包含两个bit,要先写Lower Page,再写UpperPage,这是工艺决定的,但是对于读操作就没有这个限制,同时,如果是SLC,也没有这个限制。
最后仍有一个疑问:既然阵列操作是整页进行的,用不着去选中位线,那位线上的位线选择器和源线选择器是干什么的?这个疑问求大佬赐教。