基于AHB_BUS的eFlash控制器的微架构设计
eFlash微架构设计
1.回顾架构设计
2.Flash时序仿真
2.1 ahb_flashc项目目录
- docs
- rtl
- sim
- tb
- model
2.2 docs
- 架构设计文档
- 微架构设计文档
- 集成需求文档
- DataSheet
2.3 model
model文件夹下放的是一些仿真模型(Flash的rtl代码)和一些文档,这里存放的模型是不可综合的,只用于仿真的模型
- tc -- typical case,典型场景
- wc -- worse case,较差的场景
- 不同场景之间,主要影响的是读延迟时间,写和擦除操作的延时时间相差不大
// 查看pdf文件
firefox xxxx.pdf&
-
配置读取时间的时候,需要按照worse case文档中的时间进行配置。
-
拿到model之后,可以查看其中的接口信号和参数
2.4 sim
sim路径下存放的是仿真的文件,Makefile等,主要执行的是run_rtl命令、
仿真了三个filelist
- model.list
- rtl.list
- tb.list
2.5 tb
在拿到Flash之后,可以搭建tb进行一些读写擦操作,更加深入的理解Flash的时序。
// flash_tb
`timescale 1ns/10ps
module flash_tb;
reg [9:0] XADR;
reg [4:0] YADR;
reg [31:0] DIN;
reg XE;
reg YE;
reg SE;
reg ERASE;
reg MAS1;
reg PROG;
reg NVSTR;
wire [31:0] DOUT;
reg [31:0] rdata;
initial begin
$vcdpluson();
end
initial begin
// 先将信号初始化
XADR = 10'b0;
YADR = 5'b0;
DIN = 32'b0;
XE = 1'b0;
YE = 2'b0;
SE = 1'b0;
ERASE = 1'b0;
MAS1 = 1'b0;
PROG = 1'b0;
NVSTR = 1'b0;
// 延迟100个时间单位
#100;
// 调用任务
page_erase(8'b0);
prog_word(10'h0,5'h0,32'h12345678);
read_word(10'h0,rdata);
// prog_word(10'b0,5'h0,32'haabbccdd);
// read_word(10'h0,5'h1,rdata);
// 延迟100个时间单位
#100;
// 结束仿真
$finish;
end
// 例化flash
// .表示rtl中的变量,()表示输入给rtl的变量,也就是在tb中定义的变量
SFD32KX32M32P4C_HE_LMC U_flash(
.XADR (XADR ),
.YADR (YADR ),
.DIN (DIN ),
.XE (XE ),
.YE (YE ),
.SE (SE ),
.ERASE (ERASE ),
.MAS1 (MAS1 ),
.PROG (PROG ),
.NVSTR (NVSTR ),
.IFREN (1'b0 ),
.TMR (1'b1 ),
.VPP () ,
.TM ()
);
task page_erase(input [7:0] page_num);
begin
#1234;
XADR = {page_num,2'b0}; // 1024行,256页,页数8位,再补两bit
XE = 1'b1;
ERASE = 1'b1;
#5000;
NVSTR = 1'b1;
#20000000;
ERASE = 1'b0;
#5000;
XE = 1'b0;
NVSTR = 1'b0;
#10000
end
endtask
task prog_word(input [9:0] xadr,input [4:0] yadr,input [31:0] wdata);
begin
#1234;
XADR = xadr;
YADR = yadr;
XE = 1'b1;
PROG = 1'b1;
#5000;
NVSTR = 1'b1;
#10000;
YE = 1'b1;
#20000;
YE = 1'b0;
#20;
PROG = 1'b0;
#5000;
XE = 1'b0;
NVSTR = 1'b0;
#10000;
end
endtask
task read_word(input [9:0] xadr,input [4:0] yadr,output [31:0] rdata);
begin
#1234;
XADR = xadr;
YADR = yadr;
XE = 1'b1;
YE = 1'b1;
SE = 1'b1;
#50;
rdata = DOUT;
XE = 1'b0;
YE = 1'b0;
SE = 1'b0;
end
endtask
endmodule
3.微架构呀设计思路
主要在架构设计文档的基础上进行信号补全
3.1 AHB_slave_if信号扩展
- 首选将AHB的两个phaze进行对齐
- 三种寄存器:配置寄存器,中断使能寄存器,状态寄存器需要明确
// 1.config寄存器
// 时间配置
// 写时间配置寄存器,可以根据读写擦时序图进行书写
1. read_access time
2. nvstore setup // 擦除操作的NVSore可以和prog共用,因为不能同时进行erase和prog
3. nvstore hold // 后面prog就没有必要再设置一套nvstore寄存器了
4. erase time
5. mass erase time
6. recover time
7. program setup time
8. program holdup time
9. program time
10. addr setup time
11. addr hold time
// 对于读操作,AHB总线会发送过来读地址,所以直接使用AHB总线发的地址进行读取
// 对于擦除操作,需要确定是哪一个page,所以要配置page num
12. page num
13. erase information or main block // 需要判断擦除的是Flash中的哪一部分
14. erase mass/page // 表示擦除mass还是page之后
// 确定上述信号之后,可以通知Flash_ctrl模块进行操作
15. erase_en
// 对于program操作
16. program wdata //配置写数据
17. program addr // 配置写地址
18. program information/main // 配置写Flash中的哪一块
// 配置完前面的寄存器之后,可以发送信号给Flash_ctrl进行操作
19.program_en
// 2. 配置状态寄存器,表示当前操作的状态,读完,写完....
1. prog_finish // 写完
2. erase_finish // 擦完,这个寄存器可以和上prog_finish共用
3. read_finish
4. boot_pe_error // boot期间出现了写操作的错误
// 3.中断使能寄存器
1.int_en
3.2 Flash_ctrl
Flash_ctrl接收的是寄存器的配置,描述状态机
* 方式一:针对于每一种操作,写一种状态机,相应信号来了之后就开启相应操作的状态机
* 方式二:可以将对于所有操作的状态机都集成到一个状态机中
3.2.1 prog状态机
- 初始的时候是IDLE
- 接收到写操作信号(prog_en)的时候,进入Tnvs状态,在这之前关于写操作的寄存器都要配置完成,在这个状态中设置一个计数器,如果计满当前的状态,就进入下一个状态,没有计满时间就在当前状态进行循环
- 在Tnvs之后,进入Tpgs(从NVSTR拉高到YE拉高)
- Tpgs之后进入Tads(地址准备好到YE拉高)
- Tprog
- Tadh
- Tpgh
- Tnvh
- Trcv
- 转到IDLE
3.2.2 erase状态机
合并状态机
- 红色状态表示两个状态机中所共有的状态,可以将红色状态进行合并
3.2.3 read状态机合并
read时序简单,只需要等待几个cycle进行返回读数据
3.2.4 Flash_ctrl内部信号设计
要对Flash_ctrl进行考虑DFT mode下,需要将两块Flash信号bypass
- 正常工作模式下,状态机分别向两块Flash发出控制信号,Flash0和Flash1都需要返回rdata
- DFT的时候Flash0和Flash1相当于是黑盒子,控制比较复杂,DFT是做扫描链测试,不断打入激励,扫描出结果
- DFT模式下, 引入一个异或逻辑,将状态机将要输出的逻辑转到异或逻辑中
- 通过一个mux,在dft使能(dft_en)的条件下,选择输出;dft_en拉高,表示当前是dft模式,就将Flash0和Flash1跳过,输出dft测试的结果;dft_en拉低表示当前是正常工作模式,将Flash0或者Flash1的输出作为输出的rdata
4.总结
- 微架构设计文档的输入是架构设计文档
- 分各个模块进行信号分析,细化AHB_slave_if中的信号和寄存器,绘制Flash_ctrl中的状态机
- 考虑DFT mode的测试路径
5.微架构设计文档
5.1 eFlash控制器模块框图
5.2 AHB_slave接口
5.3 信号功能说明表
- 一个地址对应一个byte,256kbyte需要18bit地址,上面表格中的地址位数是错误的
- eflash_wp_n -- 擦写flash的外部保护信号,在进行基台测试的时候,已经将程序烧录到flash中了,这些程序是不希望被修改的,所以要这个信号进行控制对flash的擦写
- boot_en -- 表示当前处于初始化状态,整个系统初始化,在初始化的时候需要保护boot区间,在boot区间之内,不能进行擦除和写的操作
- CPU过来的地址需要加一个偏移量offset,偏移到boot程序存放的地址?一般而言,boot区间通常分配在eflash比较后面的地址,不在eflash初始的位置;CPU在上电之后,CPU需要通过I-cache访问存储器,第一种情况,从存储器的0地址开始进行访问,初始的访问地址是0,如果此时boot区间不是0地址,所以在操作的时候,将boot区间做一个偏移,偏移到0地址;eflash根据是不是处于boot状态,如果处于boot状态,就将CPU发送过来的地址加一个offset(haddr+offset),否则就使用haddr;第二种情况,CPU中存在寄存器,CPU刚上电之后,寄存器的复位值就是boot区间的起始地址(start_addr),CPU在上电复位之后,可以直接拿start_addr进行寻址,不用将地址offset
- addr_offset--不是以byte为单位的,addr_offset通常都是1k,2k,,,,整数倍
- flash_busy -- 表示当前进行写擦操作
- flash_wr_done/flash_pe_done -- 表示擦写完成
- hready_flag -- 表示读操作的时候需要总线延迟
- flash_rdata -- 两块flash经过片选之后得到哪一块flash输出数据
- hready_resp -- 返回给AHB总线的数据,
- hresp -- AHB总线状态(okay,error,retry,split),如果没有error的状态就将其设置为1
- flash_pe_en -- 在配置好相关的寄存器之后,就可以产生擦除使能,可以是脉冲,也可以是电平
- rd_infr0_sel -- 表示读infr0 area片选信号,这几个片选信号使用的是独热码,最多只有1bit有效