AHB2eflash 控制器设计笔记

一、flash工艺

1.1 Logic vs Flash

数据掉电后消失(PC / phone / server : CPU +)

① SRAM

② DRAM

数据非易失

① NOR FLASH

② NAND FLASH

③ SSD

④ SATA

⑤ U 盘

⑥ 移动硬盘

⑦ 机械磁盘

数据掉电后保存(MCU , 单芯片方案)

eflash

1.2 设计需求

Eflash 控制器

① 作为系统程序的存储空间;

② flash存储体IP由代工厂提供;

③ 项目完成 flash 控制器的设计

④ eflash 作为 ahb slave 的形式存在

特性:

① 支持 32位 的 ahb slave interface (不支持该总线 busy 传输类型)

② 支持eflash 的多周期的读、写、页擦操作(2块独立的 eflash 串联封装)

③ eflash 操作可配置(时序、功能)(flash 的异步操作)

④ 支持 eflash 中的 boot 区空间的擦写保护;

知识点

① amba 总线

② 阅读 flash datasheet 写控制器的能力

③ 如何利用行为级模型进行仿真

④ 关于 boot 的概念

⑤ DFT 的概念

⑥ 文档体系(设计文档体系、验证文档体系)

⑦ 底层驱动的概念

flash

① 由代工厂提供;

② 提供各种文件(仿真、时序),一般不提供 GDS ,需要在工厂做 merge;

③ 32K * 32 bit(32 K * 8 byte = 128 Kbyte) 256 page(512 bytes / page)

④ 两片 flash 串联(共 256 KBytes)

面积

1121.58 um * 1766.075 um ≈ 2 ㎜²

功耗:

注意:没有clk,所以时钟需要自己生成

二 、 flash spec 【读相关文档得到】

2.1 信号

名称I/O描述
XADR[9:0]I寻址的是行,10bit,低两位表示page中的哪一行,[9:2] 表示选择的page ,[1:0] 表示选择page 中的哪一行;
YADR[4:0]I一行中有32个dw ,所以使用 5 bit【dw : double word】
DIN[31:0]I写数据
DOUT[31:0]O输出数据(读数据)
XEIx 地址有效,当XE = 1 时,XADR是有效的
YEIy 地址有效,当 YE =1 时,YADR 是有效的
SEI灵敏放大器的使能信号,读数据的时候,读某行某列中存储单元的数据,存储在晶体管中,驱动能力不够,需要灵敏放大器,将信号读到的数据送到输出端
IFRENI1:表示访问 information block ;0:表示访问 main block;通常设置为1
ERASEI按页擦除
MAS1I按块擦除
PROGI数据写入,程序烧录
NVSTRI非易失性操作
VDDI电源
VSSI

一片 flash :32K * 32 bits = 1024 Kbits = 128K Bytes;

每页 512 byte ,一共是256 页

每页 4 行,一共1K 行, XADR 需要 10 bits

每行 32 列 , 一行是 128 bytes

地址映射:

首先将memory分成page,page分成row,row分成double word

2.2 测试信号

2.3 电流、电压

img

① Standby的时候,电流以微安形式存在,在工作状态下的时候,电流以毫安形式存在,在不同的模式下,电流相差一个数量级。不同情况下,电流不同,功耗不同

② SRAM是一维的寻址,eFlash是二维地址

③ Word是多少位的(32位或者是16位),是根据不同的系统确定的

2.4 读写擦信号

真值表:

MODEXEYESEPROGERASEMAS1NVSTR
StandbyLLLLLLL
ReadHHHLLLL
ProgramHHLHLLH
Page EraseHLLLHLH
Mass EraseHLLLHHH

IFREN 真值表

ModeIFREN = 1IFREN = 0
Read读取 information block读取main block
ProgramProgram information blockProgram main block
Page erase对 information block 进行页擦对 main block进行页擦
Mass erase全擦除 【所有 block】擦除 main block

test mode

ModePROGERASEYEXEIFRENMAS1
Test mode 1LLHLLH
Test mode 2LLHLHL
Test mode 3LHHHLL

【Test mode信号主要通过基台进行测试,不需要进行内建自测试】

2.5 时序参数

参数symbolminmaxUnit
Access time of read cycleTacc-24ns
读时序的数据保持时间Tdh0-ns
PROG/ERASE to NVSTR 的建立时间Tnvs5-us
NVSTR 的保持时间Tnvh5-us
NVSTR 的保持时间( 在块擦除的时候)Tnvh1100-us
NVSTR to program 的建立时间Tpgs10-us
program 的保持时间Tpgh20-ns
Program 的时间Tprog2040us
address / data 建立时间Tads20-ns
address / data 保持时间Tadh20-ns
保留时间Trcv1-us
Cumulative program HV period (1)Thv-4ms
擦除时间Terase2040ms
块擦除时间Tme2040ms

2.6 时序图

1)页擦除时序图
页擦状态过程描述:

① IFREN = 0 表示对 main block进行页擦,IFREN = 1 表示对 information block 进行页擦;

② XADR 进行配置;并将 XE、ERASE 信号拉高 ;

③ YE , SE , MAS1 信号始终为低;

④ 在ERASE 信号保持 Tnvs = 5 us (至少)之后,将NVSTR 信号拉高;

⑤ 保持各自的状态 持续 Terase = 20 ~ 40 ms 的时间,将 ERASE 信号拉低

⑥ ERASE 信号拉低后,保持 Tnvh = 5 us (至少)之后,XADR 信号进行一次变换;同时将NVSTR , XE ,信号拉低,并维持Trcv = 1 us(至少) 的时间。

2)块擦除时序图

块擦除状态过程描述:

① IFREN = 0 表示对 main block进行块擦,IFREN = 1 表示对全部 block 进行块擦;

② XADR 进行配置;并将 XE、ERASE 、MAS1 信号拉高 ;

③ YE , SE 信号始终为低;

④ 在ERASE 信号保持 Tnvs = 5 us (至少)之后,将NVSTR 信号拉高;

⑤ 保持各自的状态 持续 Tme = 20 ~ 40 ms 的时间,将 ERASE 信号拉低;

⑥ ERASE 信号拉低后,保持 Tnvh1 = 100 us (至少)之后,XADR 信号进行一次变换;同时将NVSTR , XE , MAS1 信号拉低,并维持Trcv = 1 us(至少) 的时间后,进入下一个状态;

3)写时序图

写状态过程描述:

① IFREN = 0 表示对 main block进行写操作,IFREN = 1 表示对information block 进行写操作;

② XADR 进行配置;并将 XE 、PROG 信号拉高 ,YE 信号拉低 ;

③ 在PROG 信号保持 Tnvs = 5 us (至少)之后,将NVSTR 信号拉高;

④ 在 NVSTR 信号拉高 Tpgs = 10 us (至少)之后,将 YE 信号拉高;

⑤ 将YE 信号拉高 Tprog = 20 ~ 40 us 的时间后,将 YE 信号拉低;

⑥ 在 YE 信号拉高之前,需要将 YADR 信号和 DIN 信号至少保持 Tads = 20ns (至少)的时间,【为了满足建立时间】;

在YE 信号拉低之后,需要将 YADR 信号和 DIN 信号至少保持 Tadh = 20 ns (至少)的时间,【为了满足保持时间】。

⑦ 每次写入一笔数据都需要将 YE 信号拉高一次,并保持 Tprog = 20 ~ 40 us ;【图中 DIN 连续写入了三笔数据 】

⑧ 在写入最后一笔数据之后,YE 信号拉低,并保持 Tpgh = 20 ns (至少)的时间后,将 PROG 信号拉低;

⑨ 在 PROG 信号拉低之后,保持 Tnvh = 5us (至少)的时间后,将 NVSTR 信号和 XE 信号拉低,将IFREN 信号和 XADR 信号进行一次变换。

⑩ 在所有信号维持上述状态 Trcv = 1 us(至少) 的时间后,进入下一个状态;

【注意,写操作时,XE 信号拉高的时间 Thv = 4ms (最多)】

4)读时序图

读状态过程描述:

① IFREN = 0 表示对 main block进行写操作,IFREN = 1 表示对information block 进行写操作;

② XADR 、YADR 进行配置;并将 XE 、SE 、YE 信号拉高 ;

③ 当 XE 信号拉高之后,保持 Txa = Tacc = 24 ns (最多)的时间之后,读取 DOUT 中的数据;【读时序的保持时间 Tdh = 0 ns (至少,最大值未规定)】

④ 每次读取数据, 需要将 SE 信号变化一次。

三 、eflash 控制器的架构设计

3.1 整体框图

3.2 eflash 功能列表

① 支持32 位的 AHB slave interface;

② 支持 eflash 多周期的读、写、页擦操作(两块独立的eflash 串联封装,256KByte);

③ eflash 操作可配置(时序、功能);

④ 支持 eflash 中的 boot 区空间的擦写保护;

⑤ 支持 DFT 功能;

3.3 eflash 控制器软硬件模块划分

软件部分:

① eflash 控制器的驱动;

② 对读写擦的时序进行配置;

硬件部分:

① 实现 amba 2.0 接口;

② 实现 eflash 控制器接口时序;

3.4 各个模块分析

3.4.1 顶层模块

顶层模块包含两部分内容,一部分是ahb_flash_if 模块,另一部分是flash_ctrl 模块;

① ahb_flash_if 模块:接收AHB总线控制信号,地址信号和数据信号;将地址译码转化成flash地址;配置控制寄存器以配合flash_ctrl模块的控制操作;并且储存flash工作状态到状态寄存器供软件可查。

② flash_ctrl 模块:接收总线地址和命令,完成Flsh的读、写、和擦除操作。

img

信号描述:
信号I/Owidthfromto描述
hclkI1clock sourceAHB BUS clock
hresetninput1reset controllerAHB bus reset signal
hselinput1decoderslave selected signal
hready_ininput1other slavehigh:bus is ready to use
hwriteinput1MasterHigh:wrte; Low:read
hsizeinput[2:0]Mastertransfer size: 8/16/32 Max:1024
htransinput[2:0]Master传输类型:NONSEQ、SEQ、IDLE、BUSY
hburstinput[1:0]Master8种 singal incr beat4/8/16 ,wrap4/8/16
hwdatainput[31:0]Masterwrite data
haddrinput[31:0]MasterAHB bus address
eflash_wp_ninput1efalsh write protect enable
dft_eninput1DFT enable
boot_eninput1boot area enable
addr_offsetinput[4:0]address offset
flash0_dout_ininput[31:0]flash0 read data out
flash1_dout_ininput[31:0]flash1 read data out
hready_outoutput1Masterslave has finished transfer
hrespoutput[1:0]MasterOKEY、ERROR、RETRY、SPLIT
hrdataoutput[31:0]MasterAHB bus read data
flash_ctrl_intoutput1Flashfalsh control interrupt signal when program done or pe done
flash0_infr_enoutput1Flashflash0 infromation block enable(IFREN)
flash0_xaddr_enoutput1Flashfalsh0 xaddress enable(XE)
flash0_yaddr_enoutput1Flashfalsh0 yaddress enable(YE)
flash0_se_enoutput1Flashfalsh0 SA enable(SE)
flash0_prog_enoutput1Flashfalsh0 progaram enable(PROG)
flash0_nvstr_enoutput1Flashfalsh0 non-volatile store cycle enable(NVSTR)
flash0_erase_enoutput1Flashflash0 erase enable(ERASE)
flash0_mass_enoutput1Flashflash0 mass erase enable(MAS1)
flash0_xaddroutput[9:0]Flashflash0 x address(XADR)
flash0_yaddroutput[4:0]Flashflash0 y address(YADR)
flash0_wdataoutput[31:0]Flashflash0 write data(DIN)
flash1_infr_enoutput1Flashflash1 infromation block enable(IFREN)
flash1_xaddr_enoutput1Flashfalsh1 xaddress enable(XE)
flash1_yaddr_enoutput1Flashfalsh1 yaddress enable(YE)
flash1_se_enoutput1Flashfalsh1 SA enable(SE)
flash1_prog_enoutput1Flashfalsh1 progaram enable(PROG)
flash1_nvstr_enoutput1Flashfalsh1 non-volatile store cycle enable(NVSTR)
flash0_erase_enoutput1Flashflash1 erase enable(ERASE)
flash1_mass_enoutput1Flashflash1 mass erase enable(MAS1)
flash1_xaddroutput[9:0]Flashflash1 x address(XADR)
flash1_yaddroutput[4:0]Flashflash1 y address(YADR)
flash1_wdataoutput[31:0]Flashflash1 write data(DIN)

3.4.2 ahb_flash_if 模块

img

信号描述
信号I/Owidth描述
hclk,input1clock source AHB bus clock
hresetn,input1reset controller AHB bus reset signal
hsel,input1decoder slave selected signal
hready_in,input1other slave high:bus is ready to use
hwrite,input1Master High:wrte; Low:read
hsize,input[2:0]Master transfer size: 8/16/32 Max:1024
htrans,input[2:0]Master 传输类型:NONSEQ、SEQ、IDLE、BUSY
hburst,input[1:0]Master 8种 singal incr beat4/8/16 ,wrap4/8/16
hwdata,input[31:0]Master write data
haddrinput[31:0]Master AHB bus address
flash_rdatainput[31:0]flash_ctrl flash read out data
flash_prog_doneinput1flash_ctrl flash program has finished
flash_busyinput1flash is busy
eflash_wp_n,input1efalsh write protect enable
addr_offsetinput[4:0]boot area address offset
boot_eninput1boot area enable
hready_flaginput1slave has finished transfer,transfer to hready_out
hready_outoutput1this slave to BUS siganl
hrespoutput[1:0]OK 、ERROR、SPLIT、RETRY
hrdataoutput[31:0]flash read data or register value
flash_prog_enoutput1flash program enable
flash_pe_enoutput1flash page erase enable
flash_rd_enoutput1flash read enable
rd_inf0_seloutput1information0 area read select
rd_inf1_seloutput1information1 area read select
rd_main0_seloutput1main0 area read select
rd_main1_seloutput1main1 area read select
flash0_rd_csoutput1flash0 read selcet
flash1_rd_csoutput1flash0 read selcet
prog_infrarea0_seloutput1information0 area program select
prog_infrarea1_seloutput1information1 area program select
prog_mainarea0_seloutput1main0 area program select
prog_mainarea1_seloutput1main1 area program select
pe_num,output[8:0]page number
pe_main_infr_seloutput1page erase main or infromation area
flash_addr_out,output[14:0]flash address
flash_wdata,output[31:0]flash write data
flash_ctrl_int,output1flash interrupt enable
t_nvstr_setupoutput[11:0]PROG/ERASE to NVSTR set up time >5us
t_nvstr_holdoutput[11:0]NVSTR hold time >5us
t_rcvoutput[7:0]Recover time >1us
t_prog_setupoutput[15:0]NVSTR to program set up time
t_prog_holdoutput[3:0]Program hold time (20~40us)
t_addr_setupoutput[3:0]Adress/data set up time
t_addr_holdoutput[3:0]Adress/data hold time
t_prog_procoutput[15:0]program time
t_addr_acesoutput[7:0]Access time of read cycle
t_page_eraseoutput[23:0]page erase time >20ms
寄存器地址及功能描述:
namebitsAddress OffsetReset valueDefinition
nvstr_setup_timing[31:0]0x0032‘h259写/擦操到NVSTR的建立时间
nvstr_hold_timing[31:0]0x0432‘h259写/擦操到NVSTR的保持时间
prog_setup_timing[31:0]0x0832‘h4b1写操作建立时间
progaddr_sethold_timing[31:0]0x0c32‘h333写操作地址建立、保持时间及写完成后的保持时间
prog_proc_timing[31:0]0x1032‘h962每次写操作完成的时间
read_aces_timing[31:0]0x1432‘h5读操作所需要的时间
pe_timing[31:0]0x1832‘h0页擦除所需要的时间(需配置)
rcv_timing[31:0]0x1c32‘h79恢复时间
wr_en_r[31:0]0x2032‘h0Flash program使能
pe_en_r[31:0]0x2432‘h0Flash 页擦使能
pe_num_r[31:0]0x289‘h1df页擦的数量
pe_main_infr_sel_r[31:0]0x2c32‘h0页擦main区还是information区选择
prog_addr_r[31:0]0x3032‘h0program 地址
prog_data_r[31:0]0x3432‘h0program 数据
int_en_r[31:0]0x38-中断使能
flash_status_r[31:0]0x3c-flash 状态寄存器
boot_error_r[31:0]0x40-boot 操作出错标记寄存器

3.4.3 flash_ctrl 模块

img

信号描述
SignalsI/OWidthformto描述
flash_clkinput1clock sourceAHB bus clock
flash_rst_ninput1reset controllerAHB bus reset signal
prog_eninput1flash_ahb_slave_ifflash program enable
pe_eninput1flash_ahb_slave_ifflash page erase enable
read_eninput1flash_ahb_slave_ifflash read enable
rd_inf0_selinput1flash_ahb_slave_ifinformation0 area read select
rd_inf1_selinput1flash_ahb_slave_ifinformation1 area read select
rd_main0_selinput1flash_ahb_slave_ifmain0 area read select
rd_main1_selinput1flash_ahb_slave_ifmain1 area read select
flash0_rd_csinput1flash_ahb_slave_ifflash0 read selcet
flash1_rd_csinput1flash_ahb_slave_ifflash0 read selcet
prog_infrarea0_selinput1flash_ahb_slave_ifinformation0 area program select
prog_infrarea1_selinput1flash_ahb_slave_ifinformation1 area program select
prog_mainarea0_selinput1flash_ahb_slave_ifmain0 area program select
prog_mainarea1_selinput1flash_ahb_slave_ifmain1 area program select
pe_num,input[8:0]flash_ahb_slave_ifpage number
pe_main_infr_selinput1flash_ahb_slave_ifpage erase main or infromation area
flash_addrinput[14:0]flash_ahb_slave_ifflash address
flash_data_ininput[31:0]flash_ahb_slave_ifflash write data
flash0_rdatainput[31:0]flash_ahb_slave_ifflash0 read data
flash1_rdatainput[31:0]flash_ahb_slave_ifflash1 read data
flash_ctrl_int,input1flash_ahb_slave_ifflash interrupt signal(op finish)
nvstr_set_timinginput[11:0]flash_ahb_slave_ifPROG/ERASE to NVSTR set up time >5us
nvstr_hold_timinginput[11:0]flash_ahb_slave_if
rcv_timinginput[7:0]flash_ahb_slave_ifRecover time >1us
prog_set_timinginput[15:0]flash_ahb_slave_ifNVSTR to program set up time
prog_hold_timinginput[3:0]flash_ahb_slave_ifProgram hold time (20~40us)
addr_set_timinginput[3:0]flash_ahb_slave_ifAdress/data set up time
addr_hold_timinginput[3:0]flash_ahb_slave_ifAdress/data hold time
prog_proc_timinginput[15:0]flash_ahb_slave_ifprogram time
addr_aces_timinginput[7:0]flash_ahb_slave_ifAccess time of read cycle
page_erase_timinginput[23:0]flash_ahb_slave_ifpage erase time >20ms
flash0_infr_enoutput1flash0flash0 infromation block enable(IFREN)
flash0_xaddr_enoutput1flash0flash0 xaddress enable(XE)
lash0_yaddr_enoutput1flash0flash0 yaddress enable(YE)
flash0_se_enoutput1flash0flash0 SA enable(SE)
flash0_prog_enoutput1flash0flash0 progaram enable(PROG)
flash0_nvstr_enoutput1flash0flash0 non-volatile store cycle enable(NVSTR)
flash0_erase_enoutput1flash0flash0 erase enable(ERASE)
flash0_mass_enoutput1flash0flash0 mass erase enable(MAS1)
flash0_xaddroutput[9:0]flash0flash0 x address(XADR)
flash0_yaddroutput[4:0]flash0flash0 y address(YADR)
flash0_wdataoutput[31:0]flash0flash0 write data(DIN)
flash1_infr_enoutput1flash1flash1 infromation block enable(IFREN)
flash1_xaddr_enoutput1flash1flash1 xaddress enable(XE)
flash1_yaddr_enoutput1flash1flash1 yaddress enable(YE)
flash1_se_enoutput1flash1flash1 SA enable(SE)
flash1_prog_enoutput1flash1flash1 progaram enable(PROG)
flash1_nvstr_enoutput1flash1flash1 non-volatile store cycle enable(NVSTR)
flash1_erase_enoutput1flash1flash1 erase enable(ERASE)
flash1_mass_enoutput1flash1flash1 mass erase enable(MAS1)
flash1_xaddroutput[9:0]flash1flash1 x address(XADR)
flash1_yaddroutput[4:0]flash1flash1 y address(YADR)
flash1_wdataoutput[31:0]flash1flash1 write data(DIN)

状态机:软件置位,硬件清零

3.5 用户模式

系统复位后,eflash 默认工作在读 main memory 区域,其他工作方式通过相关寄存器的配置和使能信号使能工作。 eflash 工作在main memory area / information memory area / reg config area 需要 AHB 接口的地址译码逻辑块产生相应的片选。

1)eflash 控制器工作需要配置的寄存器
① 读操作 工作流程

首先读操作是系统的默认操作,同时相关工作配置寄存器也有默认的值,如果想改变读的速度,可以对以下寄存器进行配置:

read_aces_timing

然后通过 AHB 接口的地址译码逻辑确定是工作在哪一个 area ,无论是工作在 main memory area 还是工作在 information memory area ,其工作时序是一样的,配置寄存器的方式是相同的。

② 写操作工作流程

首先需要配置如下的时序寄存器

nvstr_setup_timing

nvstr_hold_timing

rcv_timing

prog_setup_timing

progaddr_sethold_timing

prog_proc_timing

int_en_r (可选)

prog_addr_r

prog_data_r

最后配置写操作寄存器 wr_r [31:0] = 32'h01 ; (此时为对 main memory 进行写操作)。

然后通过 AHB 接口的地址译码逻辑确定是工作在哪个 area ,无论是工作在 main memory area 还是工作在 information memory area ,其工作的时序都是一样的。写操作完成之后,状态寄存器 flash_status_r[0] 为高, 此时需要清楚该状态才能进入下一步操作 (清中断)。

③ 页擦操作工作流程

首先配置时序寄存器

nvstr_setup_timing

nvstr_hold_timing

rcv_timing

pe_timing

int_en_r (可选)

pe_num_r

pe_main_infr_sel_r

最后配置写 寄存器 pe_r[31:0] = 32'h01 (此时对 main memory 进行页擦操作);

然后通过 AHB 接口的地址译码逻辑确定是工作在哪个 area ,无论是工作在 main memory area 还是工作在 information memory area ,其工作的时序都是一样的。页擦操作完成之后,状态寄存器 flash_status_r[0] 为高, 此时需要清楚该状态才能进入下一步操作 (清中断)。

2) timing 寄存器配置计算方法

以时钟频率 120 MHz (8.33 ns )为例,计算timing 寄存器的配置值。

timing寄存器datasheet 值需要配置的值(16进制)
read_aces_timing35 ns35 / 8.33 ≈ 5
nvstr_setup_timing5000 ns (min)5000 / 8.33 ≈ 259 (min)
nvstr_hold_timing5000 ns (min)5000 / 8.33 ≈ 259 (min)
rcv_timing1000 ns (min)1000 / 8.33 ≈ 79 (min)
prog_setup_timing10000 ns (min)10000 / 8.33 ≈ 4b1 (min)
progaddr_sethold_timing[3:0]20 ns (min)20 / 8.33 ≈ 3 (min)
progaddr_sethold_timing[7:4]20 ns (min)20 / 8.33 ≈ 3 (min)
progaddr_sethold_timing[11:8]20 ns (min)20 / 8.33 ≈ 3 (min)
prog_proc_timing20 ~ 40 us20_000 / 8.33 ≈ 962 (min)
pe_timing20 ~ 40 ms20_000_000 / 8.33 ≈ 24a2c1 (min)

3)关于 boot 区的操作说明

关于 boot 区,默认情况下软件时不能擦写 (读操作任何时候都可以)此地址空间的 (boot 区被保护了),此时如果软件对此空间进行擦写操作,那么一方面会从硬件的 flash_status_r 中读到相应的完成信号;另一方面,会读到关于 boot 区 有无误操作信号,寄存器名称为 boot_pe_wr_error_r 的值,此时值为 “1” ,表示了软件的非法操作。当然,如果软件确实需要对 boot 区进行擦写操作,(擦写操作流程参考前面已经提出的说明),那么需要将 boot 区保护功能禁止,此时就可以对该区进行正常的擦写读操作,同时会检测到 boot_pe_wr_error_r 的值为 “0”。

4)测试模式

通过 testmode 选中测试模式,在测试模式需要引入 eflash 的输入信号 ( test_in ),输出为 test_out 。

通过 top 层 dft_en 信号为高时,则进行 dft 测试,将flash_ctrl.v 中的输出信号进行 “异或” 操作,通过 dft_en 使能的 MUX 选择是 eflash 的数据输出还是 dft 使能数据输出。

【测试模式可以简略看就行】

三、eflash 控制器的 rtl 代码

3.1 flash_ctrl_top 模块

flash_ctrl_top (
        //  input signals
        hclk,
        hresetn,
        hsel,
        hready_in,
        hwrite,
        hsize,
        htrans,
        hburst,
        hwdata,
        haddr,
        
        eflash_wp_n,
        dft_en,
        boot_en,
        addr_offset,
        
        flash0_dout_in,
        flash1_dout_in,
        
        //  output signals
        hready_out,
        hresp,
        hrdata,
        
        flash_ctrl_int,
        
        flash0_infr_en,
        flash0_xaddr_en,
        flash0_yaddr_en,
        flash0_se_en,
        flash0_prog_en,
        flash0_nvstr_en,
        flash0_erase_en,
        flash0_mass_en,
        flash0_xaddr,
        flash0_yaddr,
        flash0_wdata,
        
        flash1_infr_en,
        flash1_xaddr_en,        
        flash1_yaddr_en,
        flash1_se_en,
        flash1_prog_en,
        flash1_nvstr_en,
        flash1_erase_en,
        flash1_mass_en,
        flash1_xaddr,
        flash1_yaddr,
        flash1_wdata
);
​
parameter   XADDR = 10;
parameter   XADDR_LOW = 6;
parameter   YADDR = 5;
​
//  AHB interface
input   hclk;
input   hresetn;
input   hsel;
input   hready_in;
input   hwrite;
input [2:0]     hsize;
input [2:0]     htrans;
input [1:0]     hburst;
input [31:0]    hwdata;
​
input   eflash_wp_n;
input   dft_en;
input   boot_en;
​
//  boot area offset
input [4:0]     addr_offset;
​
//flash data out
input [31:0]    flash0_dout_in;
input [31:0]    flash1_dout_in;
​
//  hrdata = flash_dout_in in  flash_ahb_slave_if module
output  hready_out;
output [1:0]    hresp;
output [31:0]   hrdata;
​
//  interrput enable
output  flash_ctrl_int;
​
//flash control siganls
output  flash0_infr_en;
output  flash0_xaddr_en;
output  flash0_yaddr_en;
output  flash0_se_en;
output  flash0_prog_en;
output  flash0_nvstr_en;
output  flash0_mass_en;
output [XADDR-1:0]  flash0_xaddr;
output [YADDR-1:0]  flash0_yaddr;
output [31:0]       flash0_wdata;
​
output  flash1_infr_en;
output  flash1_xaddr_en;        
output  flash1_yaddr_en;
output  flash1_se_en;
output  flash1_prog_en;
output  flash1_nvstr_en;
output  flash1_mass_en;
output [XADDR-1:0]  flash1_xaddr;
output [YADDR-1:0]  flash1_yaddr;
output [31:0]       flash1_wdata;
​
​
wire flash_wr_en;
wire flash_pe_en;
wire flash_prog_en;
wire flash_rd_en;
​
wire [11:0] t_nvstr_setup;
wire [11:0] t_nvstr_hold;
wire [7:0]  t_rcv;
wire [15:0] t_prog_setup;
wire [3:0]  t_prog_hold;
wire [15:0] t_addr_setup;
wire [7:0]  t_addr_hold;
wire [23:0] t_prog_proc;
wire [14:0] t_addr_aces;
wire [31:0] t_page_erase;
​
wire [14:0] flash_addr_out;
wire [31:0] flash_wdata;
wire flash_prog_done;
wire flash_pe_done;
wire flash_busy;
wire flash_ctrl_int;
wire rd_infr0_sel;
wire rd_infr1_sel;
wire rd_main0_sel;
wire rd_main1_sel;
wire flash0_rd_cs;
wire flash1_rd_cs;
wire prog_infrarea0_sel;
wire prog_infrarea1_sel;
wire prog_mainarea0_sel;
wire prog_mainarea1_sel;
wire [8:0] pe_num;
wire pe_main_infr_sel;
​
wire [31:0] flash_rdata;
​
wire hready_flag;
​
//  instance AHB slave interface
flash_ahb_slave_if  U_flash_ahb_slave_if (
    //input signals
        .hclk       (hclk),
        .hresetn    hresetn),
        .hsel       (hsel),
        .hready_in  (hready_in),
        .hwrite     (hwrite),
        .hsize      (hsize),
        .htrans     (htrans),
        .hburst     (hburst),
        .hwdata     (hwdata),
        .haddr      (haddr),
        
            .flash_rdata        (flash_rdata),
            .flash_prog_done    (flash_prog_done),
            .flash_pe_done      (flash_pe_done),
            .flash_busy         (flash_busy),
            
            .eflash_wp_n        (eflash_wp_n),
            .addr_offset        (addr_offset),      //used for boot area
            .boot_en            (boot_en),
            .hready_flag        (hready_flag),
​
    //output signals
            .hready_out         (hready_out),
            .hresp              (hresp),
            .hrdata             (hrdata),
        //  flash operation control
            .flash_prog_en      (flash_prog_en),    //program enable
            .flash_pe_en        (flash_pe_en),  //page erase enable
            .flash_rd_en        (flash_rd_en),  //read enable
            
            .rd_inf0_sel        (rd_inf0_sel),
            .rd_inf1_sel        (rd_inf1_sel),
            .rd_main0_sel       (rd_main0_sel),
            .rd_main1_sel       (rd_main1_sel),
            .flash0_rd_cs       (flash0_rd_cs),
            .flash1_rd_cs       (flash1_rd_cs),
            
            .prog_infrarea0_sel (prog_infrarea0_sel),
            .prog_infrarea1_sel (prog_infrarea1_sel),
            .prog_mainarea0_sel (prog_mainarea0_sel),
            .prog_mainarea1_sel (prog_mainarea1_sel),
​
            .pe_num             (pe_num),
            .pe_main_infr_sel   (pe_main_infr_sel),
            .flash_addr_out     (flash_addr_out),
            .flash_wdata        (flash_wdata),  
            .flash_ctrl_int     (flash_ctrl_int), //use for interupt controller
        
        
        //flash operation configuration for timing
            .t_nvstr_setup      (t_nvstr_setup),
            .t_nvstr_hold       (t_nvstr_hold),
            .t_rcv              (t_rcv),
            
            .t_prog_setup       (t_prog_setup),
            .t_prog_hold        (t_prog_hold),
            .t_addr_setup       (t_addr_setup),
            .t_addr_hold        (t_addr_hold),
            .t_prog_proc        (t_prog_proc),
            
            .t_addr_aces        (t_addr_aces),
            
            .t_page_erase       (t_page_erase)
​
);
​
flash_ctrl U_flash_ctrl (
        //input sginals
    .flash_clk      (hclk),
    .flash_rst_n    (hresetn),
    
    .prog_en        (flash_prog_en),
    .pe_en          (flash_pe_en),
    .read_en        (read_en),
    
    .rd_infr0_sel   (rd_infr0_sel),
    .rd_infr1_sel   (rd_infr1_sel),
    .rd_main0_sel   (rd_main0_sel),
    .rd_main1_sel   (rd_main1_sel),
    .flash0_rd_cs   (flash0_rd_cs),
    .flash1_rd_cs   (flash1_rd_cs),
    .prog_infrarea0_sel (prog_infrarea0_sel),
    .prog_infrarea1_sel (prog_infrarea1_sel),
    .prog_mainarea0_sel (prog_mainarea0_sel),
    .prog_mainarea1_sel (prog_mainarea1_sel),
    
    .pe_num             (pe_num),
    .pe_main_infr_sel   (pe_main_infr_sel),
    
    //.dft_en           (dft_en),
    
    .flash_addr     (flash_addr_out),
    .flash_data_in  (flash_wdata),
    
    .flash0_rdata   (flash0_dout_in),
    .flash1_rdata   (flash1_dout_in),
//timing control
    .//common timing
    .nvstr_set_timing   (t_nvstr_setup),
    .nvstr_hold_timing  (t_nvstr_hold),
    .rcv_timing         (t_rcv),
    
    //prog timing
    .prog_set_timing    (t_prog_setup),
    .prog_timing        (t_prog_proc),
    .prog_hold_timing   (t_prog_hold),
    .prog_addr_set_timing   (t_addr_setup),
    .prog_addr_hold_timing  (t_addr_hold),
    
    //read_timing
    .addr_acces_timing  (t_addr_aces),
    
    .//page erase timing
    .page_erase_timing  (t_page_erase),
    
//ou.tput signals
    .flash0_infr_en     (flash0_infr_en),
    .flash0_xaddr_en    (flash0_xaddr_en),
    .flash0_yaddr_en    (flash0_yaddr_en),
    .flash0_se_en       (flash0_se_en),
    .flash0_prog_en     (flash0_prog_en),
    .flash0_nvstr_en    (flash0_nvstr_en),
    .flash0_erase_en    (flash0_erase_en),
    .flash0_mass_en     (flash0_mass_en),
    
    .flash0_xaddr       (flash0_xaddr),
    .flash0_yaddr       (flash0_yaddr),
    .flash0_wdata       (flash0_wdata),
    
    .flash1_infr_en     (flash1_infr_en),
    .flash1_xaddr_en    (flash1_xaddr_en),
    .flash1_yaddr_en    (flash1_yaddr_en),
    .flash1_se_en       (flash1_se_en),
    .flash1_prog_en     (flash1_prog_en),
    .flash1_nvstr_en    (flash1_nvstr_en),
    .flash1_erase_en    (flash1_erase_en),
    .flash1_mass_en     (flash1_mass_en),
​
    .flash1_xaddr       (flash1_xaddr),
    .flash1_yaddr       (flash1_yaddr),
    .flash1_wdata       (flash1_wdata),
    
    .flash_prog_done(flash_prog_done),
    .flash_pe_done  (flash_pe_done),
    .flash_busy     (flash_busy),
    .hready_flag    (hready_flag),
    .flash_data_out (flash_rdata)
    
);
endmodule
 

3.2 flash_ahb_slave_if 模块

// flash_ahb_slave_if
​
module flash_ahb_slave_if(
    
    //********************************************************
    //                  input signals                       //
    //********************************************************
    
    // ahb signals
    hclk,
    hresetn,
    hsel,
    hready_in,
    hwrite,
    hsize,
    htrans,
    hburst,
    hwdata,
    haddr,
    
    
    // flash_ctrl input signals
    flash_rdata,
    flash_prog_done,
    flash_pe_done,
    flash_busy,
    
    // 外部输入的擦写保护信号
    eflash_wp_n,
    
    // boot 区间的初始地址,外部输入信号
    addr_offset, 
    
    // boot 使能信号
    boot_en,
    
    // read操作的时候通过hready拉低实现
    hready_flag,
    
    //********************************************************
    //                  output signals                      //
    //********************************************************
    
    // *************************输出读写擦使能信号*************************
    
    flash_prog_en,
    flash_pe_en,
    flash_rd_en,
    
    // *******************读写擦flash中哪部分对应的信号********************
    // flash片选信号
    // information or main block选择信号
​
    
    // 读flash0或者flash1
    flash0_rd_cs
    flash1_rd_cs
    
    // 读flash中的哪部分,代码有冗余
    rd_infr0_sel,
    rd_infr1_sel,
    rd_main0_sel,
    rd_main1_sel,
    
    // 写flash中的哪部分
    prog_infrarea0_sel,
    prog_infrarea1_sel,
    prog_mainarea0_sel,
    prog_mainarea1_sel,
    
    // 擦除的页数
    pe_num,
    
    // 擦除flash中的哪部分
    pe_main_infr_sel,
    
    // *******************读写地址和数据********************
    flash_addr_out,
    flash_wdata,
    
    
    
    
    // ******************时间寄存器配置信号*****************
    t_nvstr_setup,
    t_nvstr_hold,
    t_rcv,
    
    
    // 写操作寄存器
    t_prog_setup, 
    t_prog_hold,
    t_addr_setup,
    t_addr_hold,
    t_prog_proc,
    
    // 读操作用的寄存器
    t_addr_aces,
    
    // 擦除操作
    t_page_erase,
    
    
    // *****************中断信号****************************
    flash_ctrl_int
    
    
);
​
​
    input clk;
    input hresetn;
    input hsel;
    input hready_in;
    input hwrite;
    input [2:0] hsize;
    input [2:0] hburst;
    input [1:0] htrans;
    input [31:0] hwdata;
    input [31:0] haddr;
    
    input flash_prog_done;
    input flash_pe_done;
    input flash_busy;
    
    // 0的时候擦写保护,1的时候不保护
    input eflash_wp_n;
    input boot_en;
    input [4:0] addr_offset;
    input hready_flag;
    
    output flash_prog_en;
    output flash_pe_en;
    output flash_rd_en;
    
    output [11:0] t_nvstr_setup;
    output [11:0] t_nvstr_hold;
    output [7:0] t_rcv;
    
    output [15:0] t_prog_setup;
    output [3:0] t_prog_hold;
    output [3:0] t_addr_setup;
    output [3:0] t_addr_hold;
    output [15:0] t_prog_proc;
    
    output [7:0] t_addr_aces;
    
    output [23:0] t_page_erase;
    
    
    output flash0_rd_cs
    output flash1_rd_cs
​
    output rd_infr0_sel,
    output rd_infr1_sel,
    output rd_main0_sel,
    output rd_main1_sel,
​
    output prog_infrarea0_sel,
    output prog_infrarea1_sel,
    output prog_mainarea0_sel,
    output prog_mainarea1_sel,
    
    output [8:0] pe_num;
    output pe_main_infr_sel;
    output [14:0] flash_addr_out;
    output [31:0] flash_wdata;
​
​
​
    //********************************************************
    //                 internal register                    //
    //********************************************************
    
    // register used for temp the ahb input signals
    reg hwrite_r;
    reg [2:0] hsize_r;
    reg [2:] hburst_r;
    reg [1:0] htrans_r;
    reg [31:0] haddr_r;
    
    // flash operation config registers
    // common timing
    
    reg [31:0] nvstr_setup_timing;
    reg [31:0] nvstr_hold_timing;
    reg [31:0] rcv_timing;
    
    // program timing
    reg [31:0] prog_setup_timing;
    reg [31:0] prog_hold_timing;
    reg [31:0] prog_proc_timing;
    reg [31:0] progaddr_sethold_timing;
    
    // read timing 
    reg [31:0] rd_aces_timing;
    
    // erase timing
    reg [31:0] pe_timing;
    
    // Address register and program data register used for flash
    // program or page erase operation
    reg [31:0] prog_addr_r;
    reg [31:0] prog_data_r;
    reg [31:0] invalid_data_r;
    
    // flash program/page erase operation control registers and main  mem/info mem/info
    // selected mark
    // wr_en_r[0]:flash prog enable
    // pe_en_r[0]:flash pe enable
    reg wr_en_r;
    reg pe_en_r;
    reg pe_main_infr_sel_r;
    reg [8:0] pe_num_r;
    
    // int_en_r for enable interrupt and flash operation(prog/pe) status
    reg [31:0] int_en_r;
    reg [1:0] flash_status_r;
    
    // boot_pe_wr_error_r:boot area page erase or write finish forbidden when boot area protected
    reg boot_pe_wr_error_r;
    
    reg boot_pe_done; // This two signals show boot operation
    reg boot_wr_done; // finish when in boot area protect
    
    
    reg [4:0] addr_offset_r; // 16k bytes boot area
    reg [31:0] hrdata;
    
    
    wire ahb_wr_en;
    wire ahb_rd_en;
    wire trans_en;
    wire f_rd_en;
    wire wr_status_valid;
    wire rd_infr_sel;
    wire rd_main_sel;
    
    // flash operation area select
    wire reg_sel;
    wire rd_infrarea_sel;
    wire rd_mainarea_sel;
    wire prog_pe_infrarea_sel;
    wire prog_pe_mainarea_sel;
    wire infrarea_sel;
    wire flash_mem_rd;
    wire [31:0] flash_addr;
    
    // boot area operation enable signals
    
    wire boot_protect_n;
    wire boot_pe_sel;
    wire boot_wr_sel;
    wire non_boot_addr_correct;
    wire flash_addr_correct;
    wire wr_en;
    wire pe_en;
    
    
    // AHB Bus transactions
    parameter       IDLE    =   2'b00,
                    BUSY    =   2'b01,
                    NONSEQ  =   2'b10,
                    SEQ     =   2'b11;
                    
    
    // flash 中的 寄存器空间
    parameter       REG_ADDR    =   12'h060; // 60000 - 60fff
    parameter       INFR_ADDR   =   12'h061; // 61000 - 617ff
    parameter       INFR0_ADDR  =   1'b0;    // 61000 - 613ff
    parameter       INFR1_ADDR  =   2'h1;    // 61400 - 617ff
    parameter       MAIN_ADDR   =   6'h0;    // 0000_0000 - 0003_ffff
    parameter       MAIN0_ADDR  =   1'b0;    // 0000_0000 - 0001_ffff: haddr[17:16] = 0
    parameter       MAIN1_ADDR  =   1'b1;    // 0002_0000 - 0003_ffff: haddr[17;16] = 1
    
    
    
    
    parameter       NVSTR_SETUP_ADDR        =   8'h00,
                    NVSTR_HOLD_ADDR         =   8'h04,
                    PROG_SETUP_ADDR         =   8'h08,
                    PROGADDR_SETHOLD_ADDR   =   8'h0c,
                    PROG_PROC_ADDR          =   8'h10,
                    RD_ACES_ADDR            =   8'h14,
                    PE_ADDR                 =   8'h18,
                    RCV_ADDR                =   8'h1c,
                    WR_EN_ADDR              =   8'h20,
                    PE_CONFIG_ADDR          =   8'h24,
                    PE_NUM_ADDR             =   8'h28,
                    PE_MAININFR_SEL_ADDR    =   8'h2c,
                    PROG_ADDR_ADDR          =   8'h30,
                    PROG_DATA_ADDR          =   8'h34,
                    INT_EN_ADDR             =   8'h38,
                    FLASH_STATUS_ADDR       =   8'h3c,
                    BOOT_ERROR_ADDR         =   8'h40;
    
    
    
    //------------------------------------------------------------//
    // Generate AHB slave output signals : hready_out & hresp
    // flash pe : hready_out = 1
    // flash read : if(reg operation) hready_out = 1
    //              else hready_out = flash_rd_ready
    // -----------------------------------------------------------//
    
    assign hready_out = hready_flag;
    
    assign hresp = 2'b0;
    
    
    //--------------------------------------------//
    // Generate ahb wirte and read enable signals //
    // ahb_wr_en: htrans_r and hwrite_r
    // ahb_rd_en:htrans_r and hwrite_r
    
    assign ahb_wr_en = (htrans == NONSEQ || htrans == SEQ) && hwrite_r && (!flash_busy);
    
    // read的时候不用与上flash_busy,因为hready已经进行了判断
​
    
    //--------------------------------------------//
    // flash input data and address
    // flash_addr : haddr_r[17:2] => 64Kbytes row address
    // flash_addr_out : haddr_r[17:2] => double word (32bit) align
    // flash_wdata:when prog,prog_data_r
    // Note: haddr_r willbe xor with addr_offset <=> haddr_r + addr_offset
    // why use the xor logic,not use + ?
    //--------------------------------------------//
    
    assign flash_addr = (flash_prog_en) ? prog_addr_r:
                        (boot_en && rd_main_sel) ? {haddr[31:18],haddr[17:13]|addr_offset,haddr[12:0]}:haddr;
                        
    // flash_addr是以byte的地址,但是在prog和read的时候是以dw为单位的地址,所以进行转换,去掉低两bit
    // xaddr - 10bit
    // yaddr - 5bit
    // flash_addr_out => 15bit
    assign flash_addr_out = flash_addr[16:2];
    
    // ahb写寄存器得到寄存器的值
    assign flash_wdata = prog_data_r;
    
    //--------------------------------------------//
    //     Confige the flash configure registers  //
    //--------------------------------------------//
    // 将寄存器的值连出来
    assign t_nvstr_setup = nvstr_setup_timing[11:0];
    assign t_nvstr_hold = nvstr_hold_timing[11:0];
    assign t_rcv = rcv_timing[7:0];
    
    
    // program configuration
    assign t_prog_setup = prog_setup_timing[15:0];
    assign t_prog_hold = progaddr_sethold_timing[3:0];
    assign t_addr_setup = progaddr_sethold_timing[7:4];
    assign t_addr_hold = progaddr_sethold_timing[11:8];
    assign t_prog_proc = prog_proc_timing[15:0]
    
    // read configuration
    assign t_addr_aces = rd_aces_timing[7:0];
    
    // page erase configuration
    assign t_page_erase = pe_timing[23:0];
    
    //----------------------------------------------------------------------------//
    // Generate flash control logic
    // flash_prog_en :  eflash_wp_n = 1 && wr_en_r[0] = 1;
    // flash_pe_en :    eflash_wp_n = 1 && wr_en_r[0] = 1;
    // ---------------------------------------------------------------------------//
    
    //----------------------------------------------------------------------------//
    // Generate flash reg_sel : infr_mem and main_mem sel when flash read operation
    // main mem addr:    0x0000 0000 - 0x 0003 ffff (18bit - 256K)
    // infr mem addr:    0x0006 1000 - 0x 0006 7fff (15bit - 32K)
    // reg config addr   0x0006 0000 - 0x 0006 0fff (12bit - 4k)
    //----------------------------------------------------------------------------//
    
    // 寄存器空间4k
    // 0x0006 0000 - 0x 0006 0fff 
    // 只需要判断haddr[23:12]这个范围,就可以判断出访问的是哪个空间
    // 060 -- 0000 0110 0000 -- REG_ADDR
    assign reg_sel = haddr_r[23:12] == REG_ADDR;
    
    
    // area select when in flash read operation
    // information block 2 page -- 1k -- 10bit(0-9,用第11bit选择哪一个infr)
    // 2 information block 2k - 11bit
    // 0x0006 1000 - 0x0006 17ff
    // 061 -- 0000 0110 0001 -- INFR_ADDR
    assign rd_infr_sel = (haddr[23:12] == INFR_ADDR);
    assign rd_infr0_sel = rd_infr_sel && (haddr[10] == INFR0_ADDR);
    assign rd_infr1_sel = rd_infr_sel && (haddr[11:10] == INFR1_ADDR);
    
    // 低18bit为256Kflash的寻址,23-18bit用于寻址main block
    // 128K -- 17bit,可以用18bit选择哪个flash的main block
    assign rd_main_sel = (haddr[23:18] == MAIN_ADDR);
    assign rd_main0_sel = rd_main_sel && (flash_addr[17] == MAIN0_ADDR);
    assign rd_main1_sel = rd_main_sel && (flash_addr[17] == MAIN1_ADDR);
    
    
    assign flash0_rd_cs = (rd_infr0_sel || rd_main0_sel);
    assign flash1_rd_cs = (rd_infr1_sel || rd_main1_sel);
    
    // flash read operation enable
    // f_rd_en - 对于flash ctrl的读请求
    // flash_rd_en - 对于flash的读请求,只有当选择读取main block的时候才会产生对flash的读请求
    // flash_busy - 当前flash正处于读写擦状态,不能进行操作
    assign f_rd_en = hsel && (htrans == NONSEQ || htrans == SEQ) && (!hwrite);
    assign flash_rd_en = f_rd_en && (!flash_busy) && (flash0_rd_cs || flash1_rd_cs);
    
    // Generate boot protect signal,it actives "high" when boot begin and actives "low" when boot finish
    // boot_en为高的时候需要对于boot区间进行保护
    assign boot_protect_n = boot_en;
    
    // -------------------------------------------------------------------------//
    // Generate boot area operation(write and page erase operation) enable signals
    // When boot page erase (addr_offset_r == 5'h11111(8k byte));
    //                      3e000-->page 496 -->pe_num_r = 5'h11111;
    //                      16k bytes:
    //                      3c000-->page 480 -->pe_num_r = 4'h1111;
    // When boot write(addr_offset_r == 5'h11111(8 kbytes)):
    //                      3e000-->prog_addr_r[17:13] = 5'h111111;
    //                      16k bytes:
    //                      3c000-->prog_addr_r[17:14] = 4'h1111;
    // -------------------------------------------------------------------------//
    
    // boot区间有两种情况
    // 8k以3e000为offset
    // 16k 以3c000为offset
    // 根据addr_offset判断是3c000开始还是3e000开始
    // 3c000 - 3ffff -- 16k
    // 3e000 - 3ffff -- 8K
    
    // 3e000 -- 0011 1110 0000 0000 0000 - 低13bit表示boot区的粒度,高5bit表示offset地址
    // 3c000 -- 0011 1100 0000 0000 0000
    // 3ffff -- 0011 1111 1111 1111 1111
    
    // for program
    // addr_offset == ox3e000;
    // boot area :
    // first_addr:  0011 1111 0000 0000 0000 
    // last_addr:   0011 1111 1111 1111 1111
    
    // addr_offset == ox3c000;
    // boot area :
    // first_addr:  0011 1110 0000 0000 0000 
    // last_addr:   0011 1111 1111 1111 1111
    
    // for erase
    // page - 512byte -- 9bit表示
    // addr_offset == ox3e000;
    // boot area :
    // first_page:  0011 1111 000
    // last_addr:   0011 1111 111
    
    // addr_offset == ox3c000;
    // boot area :
    // first_page:  0011 1110 000
    // last_page:   0011 1111 111
    
    // 判断擦写是不是落在boot区间内
    assign boot_wr_sel = (addr_offset_r == 5'b11111) ? (prog_addr_r[17:13] == 5'b11111):
                            (addr_offset_r == 5'b11110) ? (prog_addr_r[17:14] == 4'b1111) : 1'b0;
    assign boot_pe_sel = (addr_offset_r == 5'b11111) ? (page_num_r[8:4] == 5'b11111):
                            (addr_offset_r == 5'b11110) ? (page_num_r[8:5] == 4'b1111) : 1'b0;
    
    
    // select the right address when boot protect enable in the flash  operation 
    // except the address of boot area
    // non_boot_addr_correct -- 表示当前不是非法操作
    assign non_boot_addr_correct = !(boot_wr_sel || boot_pe_sel);
    
    
    // The address is always right when boot protect  turn off in flash operation
    // or is part of right when the address is not boot Address when boot protect turn on
    assign flash_addr_correct = boot_protect_n ? 1'b1 : non_boot_addr_correct;
    
    // Generate one of condition of flash program and page erase enable
    // 擦写寄存器中的值为高并且flash地址选择正确,产生擦写信号
    assign wr_en = wr_en_r && flash_addr_correct;
    assign pe_en = pe_en_r && flash_addr_correct;
    
    // flash program operation enable
    // flash_prog_en - 给到状态机
    // eflash_wp_n 为0 ,写保护信号有效,flash_prog_n 永远为0,进行写保护
    // eflash_wp_n 为1,撤销写保护,wr_en == 1'b1,产生写使能给状态机
    assign flash_prog_en = eflash_wp_n && (wr_en == 1'b1);
    
    // area select when in flash page erase operation
    // flash page erase operation enable
    assign flash_page_erase = eflash_wp_n && (pe_en == 1'b1);
    assign pe_num = pe_num_r;
    assign pe_main_infr_sel = pe_main_infr_sel_r;
    
    
    //area select when in flash program operation
    assign prog_infrarea_sel = (prog_addr_r[23:12] == INFR_ADDR);
    assign prog_infrarea0_sel = prog_infrarea_sel && (prog_addr_r[10] == INFR0_ADDR);
    assign prog_infrarea1_sel = prog_infrarea_sel && (prog_addr_r[11:10] == INFR1_ADDR);
    
    // 低18bit为256Kflash的寻址,23-18bit用于寻址main block
    // 128K -- 17bit,可以用18bit选择哪个flash的main block
    assign prog_mainarea_sel = (prog_addr_r[23:18] == MAIN_ADDR);
    assign prog_mainarea0_sel = prog_mainarea_sel && (prog_addr_r[17] == MAIN0_ADDR);
    assign prog_mainarea1_sel = prog_mainarea_sel && (prog_addr_r[17] == MAIN1_ADDR);
    
    
    //--------------------------------------------------------------//
    // Generate interrupt signal.
    // When int_en_r[i] enable,flash_ctrl_int[i] output
    // enable
    //--------------------------------------------------------------//
    assign wr_status_valid = ahb_wr_en && reg_sel && (haddr_r[7:0] == FLASH_STATUS_ADDR);
    
    // flash_status_r[0]为高,表示有写操作完成
    // int_en_r[0] 为高表示写操作中断使能,可以发出中断
    // flash_status_r[1]为高,表示有pe操作完成
    // int_en_r[1] 为高表示pe操作中断使能,可以发出中断
    assign flash_ctrl_int = ((flash_status_r[0]) && int_en_r[0]) || (flash_status_r[1]) && int_en_r[1];
    
    //--------------------------------------------------------------//
    // Temp AHB addr and control signals
    //--------------------------------------------------------------//
    
    always @ (posedge hclk or negedge hresetn)
    begin
        if(!hresetn) begin
            hwrite_r <= 1'b0;
            hsize_r  <= 3'b0;
            htrans_r <= 2'b0;
            haddr_r  <= 32'b0;
            hburst_r <= 3'b0;
        else if(hsel && hready_in) begin
            hwrite_r <= hwrite;
            hsize_r  <= hsize ;
            htrans_r <= htrans;
            haddr_r  <= haddr ;
            hburst_r <= hburst;
        end
        else begin
            hwrite_r <= 1'b0;
            hsize_r <= 3'b0;
            htrans_r <= 2'b0;
            haddr_r <= 32'b0;
            hburst_r <= 3'b0;
        end
    end
    end
    
    
    // ---------------------------------------------------------------//
    // ahb read data output 
    // ahb总线读数据的产生
    always @ (*)
    begin
        if(ahb_rd_en && reg_sel)
        begin
            case(haddr[7:0])
                NVSTR_SETUP_ADDR        :   hrdata = nvstr_setup_timing;
                NVSTR_HOLD_ADDR         :   hrdata = hvstr_hold_timing;
                PROG_SETUP_ADDR         :   hrdata = prog_setup_timing;
                PROGADDR_SETHOLD_ADDR   :   hrdata = progaddr_sethold_timing;
                PROG_PROC_ADDR          :   hrdata = prog_proc_timing;
                RD_ACES_ADDR            :   hrdata = rd_aces_timing;
                RCV_ADDR                :   hrdata = rcv_timing;
                WR_EN_ADDR              :   hrdata = {31'h0,wr_en_r};
                PE_CONFIG_ADDR          :   hrdata = {31'h0,pe_en_r};
                PE_NUM_ADDR             :   hrdata = {23'h0,pe_num_r};
                PE_MAININFR_SEL_ADDR    :   hrdata = {31'h0,pe_main_infr_sel_r};
                PE_ADDR                 :   hrdata = pe_timing;
                PROG_ADDR_ADDR          :   hrdata = prog_addr_r;
                PROG_DATA_ADDR          :   hrdata = prog_data_r;
                INT_EN_ADDR             :   hrdata = int_en_r;
                FLASH_STATUS_ADDR       :   hrdata = {30'h0,flash_status_r};
                BOOT_ERROR_ADDR         :   hrdata = {31'h0,boot_pe_wr_error_r};
                default:                :   hrdata = 32'b0;
            endcase
        end
        else    
                hrdata = flash_rdata[31:0];
    end
    
    
    //-------------------------------------------------------------------------//
    //   Temp the value of addr_offset for boot area protect.
    //-------------------------------------------------------------------------//
    always@(posedge hclk or negedge hresetn) begin
        if(!hresetn)
            addr_offset_r <= 5'b0;
        else if(!boot_en)
            addr_offset_r <= addr_offset;
    end
    
    
    
    //-------------------------------------------------------------------------//
    //   When boot area protect,the program and page erase operation done
    // signal will active high when boot area select and active low in the next clock
    //-------------------------------------------------------------------------//
    
    // 擦写使能并且选择boot区间会将boot_wr/pe_done信号拉高
    // boot_wr/pe_done -- 信号拉高之后会写状态寄存器
    always @(posedge hclk or negedge hresetn)
    begin
        if(!hresetn) begin
            boot_wr_done <= 1'b0;
            boot_pe_done <= 1'b0;
        end
        else if(boot_protect_n) begin // boot_en失效的条件下
            boot_wr_done <= 1'b0;
            boot_pe_done <= 1'b0;
        end
        else if(wr_en && boot_wr_sel)
            boot_wr_done <= 1'b1;
        else if(pe_en && boot_pe_sel)
            boot_pe_done <= 1'b1;
        else if(boot_wr_done || boot_pe_done) begin 
            boot_wr_done <= 1'b0;
            boot_pe_done <= 1'b0;
        end
    end
    
    
    
    //-------------------------------------------------------------------------//
    // AHB write registers
    // When ahb_wr_en,hwdata write into reg address. 
    //-------------------------------------------------------------------------//
    // 复位信号来临将默认值写入寄存器
    always @(posedge hclk or negedge hresetn) begin
        if(!hresetn)
        begin
            nvstr_setup_timing      <=  32'h259;
            nvstr_hold_timing       <=  32'h259;
            rcv_timing              <=  32'h79;
            prog_setup_timing       <=  32'h4b1;
            progaddr_sethold_timing <=  32'h333;
            prog_proc_timing        <=  32'h962;
            rd_aces_timing          <=  32'h5;
            pe_timing               <=  32'h24a2c1;
            wr_en_r                 <=  1'b0;
            pe_en_r                 <=  1'b0;
            pe_num_r                <=  9'h1df;
            pe_main_infr_sel_r      <=  1'b0;
            prog_addr_r             <=  32'h0;
            prog_data_r             <=  32'h0;
            int_en_r                <=  32'h0;
            invalid_data_r          <=  32'h0;
        end
        else if(ahb_wr_en && reg_sel)
        begin
            case(haddr_r[7:0])
                NVSTR_SETUP_ADDR        :   nvstr_setup_timing      <=   hwdata;
                NVSTR_HOLD_ADDR         :   nvstr_hold_timing       <=   hwdata;
                PROG_SETUP_ADDR         :   prog_setup_timing       <=   hwdata;
                PROGADDR_SETHOLD_ADDR   :   progaddr_sethold_timing <=   hwdata;
                PROG_PROC_ADDR          :   prog_proc_timing        <=   hwdata;
                RD_ACES_ADDR            :   rd_aces_timing          <=   hwdata;
                RCV_ADDR                :   rcv_timing              <=   hwdata;
                WR_EN_ADDR              :   wr_en_r                 <=   hwdata[0];
                PE_CONFIG_ADDR          :   pe_en_r                 <=   hwdata[0];
                PE_NUM_ADDR             :   pe_num_r                <=   hwdata[8:0];
                PE_MAININFR_SEL_ADDR    :   pe_main_infr_sel_r      <=   hwdata[0];
                PE_ADDR                 :   pe_timing               <=   hwdata;
                PROG_ADDR_ADDR          :   prog_addr_r             <=   hwdata;
                PROG_DATA_ADDR          :   prog_data_r             <=   hwdata;
                INT_EN_ADDR             :   int_en_r                <=   hwdata;
                default:                :   invalid_data_r          <=   hwdata;
            endcase
        end
        else if(flash_prog_done || boot_wr_done) 
        begin
            // flash_prog_done - 是flash ctrl返回的信号
            // boot_wr_done - 是boot使能时,写boot区返回的信号
            wr_en_r <= 1'b0;
            prog_addr_r <= 32'h3bfff;
        end
        else if(flash_pe_done || boot_pe_done)
            pe_en_r <= 1'b0;
            pe_num_r <= 9'h1df;
        end
            
    end
    
    
    //-------------------------------------------------------------------------//
    // Flash operation status and boot operation status. 
    //-------------------------------------------------------------------------//
    always @ (posedge hclk or negedge hresetn)
    begin
        if(!hresetn) begin
            // 第一bit表示写状态
            flash_status_r[0] <= 1'b0;
        end 
        else if(wr_status_valid && hwdata[0]) begin  // 软件清0 - 写1清0
            flash_status_r[0] <= 1'b0;
        end
        else if(flash_prog_done || boot_wr_done)     // 硬件置位
            flash_status_r[0] <= 1'b1;
    end
    
    // flash_status_r 第一bit表示wr状态
    // 第二bit表示pe的状态-- 是否完成
    always @ (posedge hclk or negedge hresetn)
    begin
        if(!hresetn) begin
            // 第一bit表示写状态
            flash_status_r[1] <= 1'b0;
        end 
        else if(wr_status_valid && hwdata[1]) begin  // 软件清0 -- 写1清0(寄存器的值不一定为1)
            flash_status_r[1] <= 1'b0;
        end
        else if(flash_pe_done || boot_pe_done)     // 硬件置位
            flash_status_r[1] <= 1'b1;
    end
    
    always @ (posedge hclk or negedge hresetn)
    begin
        if(!hresetn) begin
            // 第一bit表示写状态
            boot_pe_wr_error_r <= 1'b0;
        end 
        else if(boot_protect_n) begin  
            boot_pe_wr_error_r <= 1'b0;
        end
        else if(wr_status_valid && (hwdata[1]||hwdata[0])) begin
            boot_pe_wr_error_r <= 1'b0;
        end
        else if(boot_pe_sel || boot_wr_sel)     
            boot_pe_wr_error_r <= 1'b1;
    end
    
endmodule

3.3 flash_ctrl 模块

module flash_ctrl(
        //input sginals
    flash_clk,
    flash_rst_n,
    
    prog_en,
    pe_en,
    read_en,
    
    rd_infr0_sel,
    rd_infr1_sel,
    rd_main0_sel,
    rd_main1_sel,
    flash0_rd_cs,
    flash1_rd_cs,
    prog_infrarea0_sel,
    prog_infrarea1_sel,
    prog_mainarea0_sel,
    prog_mainarea1_sel,
    
    pe_num,
    pe_main_infr_sel,
    
    //dft_en
    
    flash_addr,
    flash_data_in,
    
    flash0_rdata,
    flash1_rdata,
//timing control
    //common timing
    nvstr_set_timing,
    nvstr_hold_timing,
    rcv_timing,
    
    //prog timing
    prog_set_timing,
    prog_timing,
    prog_hold_timing,
    prog_addr_set_timing,
    prog_addr_hold_timing,
    
    //read_timing
    addr_acces_timing,
    
    //page erase timing
    page_erase_timing,
    
//output signals
    flash0_infr_en,
    flash0_xaddr_en,
    flash0_yaddr_en,
    flash0_se_en,
    flash0_prog_en,
    flash0_nvstr_en,
    flash0_erase_en,
    flash0_mass_en,
    
    flash0_xaddr,
    flash0_yaddr,
    flash0_wdata,
    
    flash1_infr_en  ,
    flash1_xaddr_en ,
    flash1_yaddr_en ,
    flash1_se_en    ,
    flash1_prog_en  ,
    flash1_nvstr_en ,
    flash1_erase_en ,
    flash1_mass_en  ,
            
    flash1_xaddr    ,
    flash1_yaddr    ,
    flash1_wdata    ,
    
    flash_prog_done,
    flash_pe_done,
    flash_busy,
    hready_flag,
    flash_data_out
    
);
//------------------------------------
//32K 可以用15bit表示    256 可以用8bit
//YADDR[4:0] ; XADDR [9:0] ;256 需要8bit表示即[7:0] YADDR[4:0] 加上XADDR[7:5] 
//   ==> XADDR[XADDR_LOW+1:XADDR_LOW-1]
parameter   XADDR = 10;         //main memory block : 32K X 32 bits;512 byte per page
            XADDR_LOW = 6;      //info memory block : 256 X 32 bits
            YADDR = 5;          //32 bytes per row
//flash_clk = hclk ; flash_rst_n = hreset_n
input   flash_clk;
input   flash_rst_n;
​
input   prog_en;
input   pe_en;
input   read_en;
input   rd_infr0_sel,
input   rd_infr1_sel,
input   rd_main0_sel,
input   rd_main1_sel,
input   flash0_rd_cs,
input   flash1_rd_cs,
input   prog_infrarea0_sel,
input   prog_infrarea1_sel,
input   prog_mainarea0_sel,
input   prog_mainarea1_sel,
//pe_num其实只需要8bit,这里给了9bit,最高位用来选择flash1还是flash0
input   [8:0] pe_num;
input   pe_main_infr_sel;
//input dft_en; 
//flash_addr 高10bitXADDR,低5位YADDR
input   [14:0] flash_addr;
input   [31:0] flash_data_in;
//存储体读出的数据先在ctrl然后再给到AHB
input   [31:0] flash0_rdata;
input   [31:0] flash1_rdata;
​
//--------------------------------------
//Config the flash's operation timing
//--------------------------------------
input   [11:0]  nvstr_set_timing;
input   [11:0]  nvstr_hold_timing;
input   [7:0]   rcv_timing;
​
//---------------------------------------
//program timing
input   [15:0]  prog_set_timing;
input   [15:0]  prog_timing;
input   [3:0]   prog_hold_timing;
input   [3:0]   prog_addr_set_timing;
input   [3:0]   prog_addr_hold_timing;
//----------------------------------------
​
//-----------------------
//read_timing
input   [7:0]   addr_acces_timing;
​
//------------------------
//page erase timing
input   [23:0]  page_erase_timing;
​
//output signals
//----2组信号分别给到存储器
output  flash0_infr_en;
output  flash0_xaddr_en;
output  flash0_yaddr_en;
output  flash0_se_en;
output  flash0_prog_en;
output  flash0_nvstr_en;
output  flash0_erase_en;
output  flash0_mass_en;
​
output  [XADDR-1:0] flash0_xaddr;
output  [YADDR-1:0] flash0_yaddr;
output  [31:0] flash0_wdata;
​
output  flash1_infr_en;
output  flash1_xaddr_en;
output  flash1_yaddr_en;
output  flash1_se_en;
output  flash1_prog_en;
output  flash1_nvstr_en;
output  flash1_erase_en;
output  flash1_mass_en;
     
output  [XADDR-1:0] flash1_xaddr;
output  [YADDR-1:0] flash1_yaddr;
output  [31:0] flash1_wdata;
​
//-----------------------------------
//Flash operation done marks
//-----------------------------------
//给到flash_ahb_slave_interface
output  flash_prog_done;
output  flash_pe_done;
output  flash_busy;
output  hready_flag;
output  [31:0] flash_data_out;
​
//---------------------------------------------------
//control registers used for flash operation  
//---------------------------------------------------
reg [XADDR-1:0] xaddr_r;    
reg [YADDR-1:0] yaddr_r;    
reg flash_infr_en       ;
reg xaddr_en_r          ;   
reg yaddr_en_r          ;   
reg prog_en_r           ;
reg se_r                ;   
reg nvstr_r             ;   
reg erase_r             ;
reg mass_r              ;   
reg hready_flag         ;
​
reg [31:0] flash_wdata_r;
​
//------------------------------------------
//Counters for flash operation timing
//All the timing counters use the same counter.
//the counter num uses the max value of flash timing--40ms
//-------------------------------------------------
    //common timing
reg [11:0]  nvstr_set_cnt;
reg [7:0]   rcv_cnt;
​
//write flash counters
reg [15:0]  prog_set_cnt;
reg [15:0]  prog_proc_cnt;
reg [3:0]   prog_end_hold_cnt;
reg [3:0]   prog_addr_set_cnt;
reg [3:0]   prog_addr_hold_cnt;
reg [19:0]  max_prog_cnt;
​
//page erase counter
reg [23:0]  flash_pe_cnt;   
reg [11:0]  nvstr_hold_cnt;
​
//read counter
reg [7:0]   addr_acces_cnt;
reg [7:0]   addr_acces_cnt_next;
​
//flash work state
reg [4:0] flash_current_st;
reg [4:0] flash_next_st;
reg [XADDR-1:0] flash0_xaddr_r_next;
reg [YADDR-1:0] flash0_yaddr_r_next;
reg [XADDR-1:0] flash1_xaddr_r_next;
reg [YADDR-1:0] flash1_yaddr_r_next;
reg [31:0] flash_wdata_r_next;
reg [XADDR-1:0] flash0_xaddr_r;
reg [YADDR-1:0] flash0_yaddr_r;
reg [XADDR-1:0] flash1_xaddr_r;
reg [YADDR-1:0] flash1_yaddr_r;
​
reg flash0_xe_r;
reg flash0_ye_r;
reg flash0_se_r;
reg flash0_infren_r;
reg flash0_erase_r;
reg flash0_mass_r;  
reg flash0_prog_r;
reg flash0_nvstr_r;
reg flash0_infren_r_next;
reg flash0_erase_r_next;
reg flash0_mass_r_next; 
reg flash0_prog_r_next;
reg flash0_nvstr_r_next;    
​
reg flash1_xe_r;
reg flash1_ye_r;
reg flash1_se_r;
reg flash1_infren_r;
reg flash1_erase_r;
reg flash1_mass_r;  
reg flash1_prog_r;
reg flash1_nvstr_r;
reg flash1_infren_r_next;
reg flash1_erase_r_next;
reg flash1_mass_r_next; 
reg flash1_prog_r_next;
reg flash1_nvstr_r_next;    
​
reg flash_busy_r;
reg flash_busy_r_next;
​
reg flash0_rd_en;
reg flash1_rd_en;
reg [XADDR-1:0] flash_infr_xaddr;
​
reg flash0_cs_r;
reg flash1_cs_r;
reg flash0_cs_r_next;
reg flash1_cs_r_next;
​
//register flash data output
reg [31:0] flash_rdata;
​
wire [31:0] rdata0;
wire [31:0] rdata1;
​
wire flash0_pe_prog_en;
wire flash1_pe_prog_en;
​
wire [31:0] flash0_comb_bit;
wire [31:0] flash1_comb_bit;
//wire [31:0] dft_data;
​
wire rcv_hold;
wire tnvs_hold;
wire tnvh_hold;
​
wire pe_hold;
​
wire prog_set_hold;
wire prog_addr_set_hold;
wire prog_proc_hold;
wire prog_end_hold;
wire prog_addr_hold;
​
wire rcv_finish;
wire tnvs_finish;
​
wire pe_finish;
​
wire rd_finish_pre;
​
wire prog_set_finish;
wire prog_addr_set_finish;
wire prog_proc_finish;
wire prog_addr_hold_finish;
wire prog_hold_finish;
​
wire tnvh_finish;
​
​
//parameter for flash FSM
//这里4bit就够了
parameter   FLASH_IDLE  = 5'h0,
            FLASH_TVNS  = 5'h1,
            
            PE_ERASE    = 5'h2,
            
            PROG_SETUP  = 5'h3,
            ADDR_SETUP  = 5'h4,
            PROG_PROC   = 5'h5,
            ADDR_HOLD   = 5'h6,
            PROG_HOLD   = 5'h7,                      
​
            READ_ACCESS = 5'h8,
            
            FLASH_TVNH  = 5'h9,
            RCV_TIME    = 5'ha;
​
//--------------------------------------------
//DFT operation
//--------------------------------------------
//the combination of the flash control signals but XADR
assign flash0_comb_bit = {9'b0,flash0_infr_en,flash0_xaddr_en,
                        flash0_yaddr_en,flash0_se_en,
                        flash0_prog_en,flash0_nvstr_en,
                        flash0_erase_en,flash0_mass_en,
                        flash0_xaddr,flash0_yaddr};
​
assign flash1_comb_bit = {9'b0,flash1_infr_en,flash1_xaddr_en,
                        flash1_yaddr_en,flash1_se_en,
                        flash1_prog_en,flash1_nvstr_en,
                        flash1_erase_en,flash1_mass_en,
                        flash1_xaddr,flash1_yaddr}; 
                        
assign dft_data = (flash0_wdata ^ flash0_comb_bit) ^ (flash1_wdata ^ flash1_comb_bit);
​
assign rdata0 = {dft_en} ? dft_data:flash0_rdata;
assign rdata1 = {dft_en} ? dft_data:flash1_rdata;
​
//flash data out
assign flash_data_out = flash_rdata;
​
//----------------------------------------------------------------
//Choose the right flash according to signal flash_cs,
//which generated from AHB inteface byte infromation area address.
//if flash_cs active high,means choosing the flash0,or choosing
//flash1 block
//----------------------------------------------------------------
//flssh0 operation signals
assign  flash0_xaddr        = flash0_xaddr_r;
assign  flash0_yaddr        = flash0_yaddr_r;
assign  flash0_xaddr_en     = flash0_xe_r;
assign  flash0_yaddr_en     = flash0_ye_r;
assign  flash0_se_en        = flash0_se_r;
assign  flash0_infr_en      = flash0_infren_r,
assign  flash0_erase_en     = flash0_erase_r;
assign  flash0_mass_en      = flash0_mass_r;
assign  flash0_prog_en      = flash0_prog_r;
assign  flash0_nvstr_en     = flash0_nvstr_r;
​
//flash1 operation signals
assign  flash1_xaddr        = flash1_xaddr_r;
assign  flash1_yaddr        = flash1_yaddr_r;
assign  flash1_xaddr_en     = flash1_xe_r;
assign  flash1_yaddr_en     = flash1_ye_r;
assign  flash1_se_en        = flash1_se_r;
assign  flash1_infr_en      = flash1_infren_r,
assign  flash1_erase_en     = flash1_erase_r;
assign  flash1_mass_en      = flash1_mass_r;
assign  flash1_prog_en      = flash1_prog_r;
assign  flash1_nvstr_en     = flash1_nvstr_r;
​
assign flash_busy = flash_busy_r;
​
//flsh write data
assign  flash0_wdata = flash0_wdata_r;
assign  flash1_wdata = flash1_wdata_r;
​
//-------------------------------------------------------------------
//control every counter working correspondingly in the current state
//--------------------------------------------------------------------
//每一个状态保持的信号,用于计数器计数,这里wire并不增加资源
assign rcv_hold     = (flash_current_st == RCV_TIME);
assign tnvs_hold    = (flash_current_st == FLASH_TVNS);
​
assign pe_hold      = (flash_current_st == PE_ERASE);
​
assign prog_set_hold    = (flash_current_st == PROG_SETUP);
assign prog_addr_set_hold   =  (flash_current_st == ADDR_SETUP);
assign prog_proc_hold   =  (flash_current_st == PROG_PROC);
assign prog_end_hold    = (flash_current_st == PROG_HOLD);
assign prog_addr_hold   = (flash_current_st == ADDR_HOLD);
​
assign tnvh_hold    = (flash_current_st == FLASH_TVNH);
​
​
//--------------------------------------------------------------------------
//Generate flash operation done in each of state.
//Ooce read operation finish,and the ready_out of AHB interface will
//be high in writing operation with this signal.Hready_out will always
//be high when in program operation
//---------------------------------------------------------------------------
assign flash_prog_done  = rcv_finish && prog_en;
assign flash_pe_done    = rcv_finish && pe_en;
​
//------------------------------------------------------------
//signals control flash FSM state jumping.
//----------------------------------------------------
//因为时间很长这里就没有-1了,-1要多个减法器
//读有-1,read要求高,不-1会浪费总线上一个周期(read会有等待)
assign rcv_finish       = (rcv_cnt == rcv_timing);
assign tnvs_finish      = (nvstr_set_cnt == nvstr_set_timing);
​
assign pe_finish        = (flash_pe_cnt == page_erase_timing);
​
assign rd_finish_pre    = (addr_access_cnt == addr_acces_timing - 1);
​
assign prog_set_finish          = (prog_set_cnt == prog_set_timing);
assign prog_addr_hold_finish    = (prog_addr_hold_cnt == prog_addr_hold_timing);
assign prog_proc_finish         = (prog_proc_cnt == prog_timing);   
assign prog_addr_set_finish     = (prog_addr_set_cnt == prog_addr_set_timing);
assign prog_hold_finish         = (prog_end_hold_cnt == prog_hold_timing);
​
assign tnvh_finish      = (nvstr_hold_cnt == nvstr_hold_timing);
​
​
//-----------------------------------
//      The Flash FSM
//--------------------------------------
//第一段时序逻辑  current_st 一定要这么做,其它的不一定
always@ (posedge flash_clk or negedge flash_rst_n ) begin
    if (!flash_rst_n)
    begin
        flash_current_st <= FLASH_IDLE;
        addr_acces_cnt  <= 0;
        flash0_xaddr_r  <= 0;
        flash0_yaddr_r  <= 0;
        flash1_xaddr_r  <= 0;
        flash1_yaddr_r  <= 0;
        flash_wdata_r   <= 0;
        
        flash0_xe_r     <= 0;
        flash0_ye_r     <= 0;
        flash0_se_r     <= 0;
        flash0_infren_r <= 0;
        flash0_erase_r  <= 0;
        flash0_mass_r   <= 0;
        flash0_prog_r   <= 0;
        flash0_nvstr_r  <= 0;
​
        flash1_xe_r     <= 0;
        flash1_ye_r     <= 0;
        flash1_se_r     <= 0;
        flash1_infren_r <= 0;
        flash1_erase_r  <= 0;
        flash1_mass_r   <= 0;
        flash1_prog_r   <= 0;
        flash1_nvstr_r  <= 0;
        
        flash_busy_r    <= 0;   
        flash0_cs_r     <= 0;
        flash1_cs_r     <= 0;
    end
    
    else begin
        flash_current_st <= flash_next_st;
        addr_acces_cnt  <= addr_acces_cnt_next;
        flash0_xaddr_r  <= flash0_xaddr_r_next  ;
        flash0_yaddr_r  <= flash0_yaddr_r_next  ;
        flash1_xaddr_r  <= flash1_xaddr_r_next  ;
        flash1_yaddr_r  <= flash1_yaddr_r_next  ;
        flash_wdata_r   <= flash_wdata_r_next   ;
        
        flash0_xe_r     <= flash0_xe_r_next;
        flash0_ye_r     <= flash0_ye_r_next;
        flash0_se_r     <= flash0_se_r_next;
        flash0_infren_r <= flash0_infren_r_next;
        flash0_erase_r  <= flash0_erase_r_next;
        flash0_mass_r   <= flash0_mass_r_next;  
        flash0_prog_r   <= flash0_prog_r_next;
        flash0_nvstr_r  <= flash0_nvstr_r_next;
​
        flash1_xe_r     <= flash1_xe_r_nexy;
        flash1_ye_r     <= flash1_ye_r_next;
        flash1_se_r     <= flash1_se_r_next;
        flash1_infren_r <= flash1_infren_r_next;
        flash1_erase_r  <= flash1_erase_r_next;
        flash1_mass_r   <= flash1_mass_r_next;  
        flash1_prog_r   <= flash1_prog_r_next;
        flash1_nvstr_r  <= flash1_nvstr_r_next;
        
        flash_busy_r    <= flash_busy_r_next;   
        
        flash0_cs_r     <= flash0_cs_r_next;
        flash1_cs_r     <= flash1_cs_r_next;
        
    end
end
    
​
//always@(flash_current_st or read_en or pe_en or prog_en or
//      tnvs_finish or pe_finish or prog_set_finish or prog_addr_set_finish     
//      or prog_proc_finish or prog_addr_hold_finish or prog_hold_finish
//      or tnvh_finish or rcv_finish or rd_finish_pre)
always@(*) begin
//初始化做一个保护,case flash_current_st 都不满足的话,next_st=current_st
//组合逻辑
    flash_next_st = flash_current_st;
    case (flash_current_st)
    FLASH_IDLE: 
    begin
        if (pe_en || prog_en)
            flash_next_st = FLASH_TNVS;
        else if (read_en)
            flash_current_st = READ_ACCESS;
        else
            flash_next_st = FLASH_IDLE;
    end
    
    READ_ACCESS: 
    //等待24ns,没有则保持这个状态
    begin
        if (!rd_finish_pre)
            flash_next_st = READ_ACCESS;
        else
            flash_next_st = FLASH_IDLE;
    end
    
    FLASH_TNVS:
    begin
        if(tnvs_finish)
        begin
            if(pe_en)
                flash_next_st = PE_ERASE;
            else if (prog_en)
                flash_next_st = PROG_SETUP;
            else
                flash_next_st = FLASH_IDLE;
        end
        else
            flash_next_st = FLASH_TNVS;
    end
    
    PE_ERASE:
    begin
        if(pe_finish)
            flash_next_st = FLASH_TVNH;
        else
            flash_next_st = PE_ERASE;
    end
    
    FLASH_TVNH:
    begin
        if(tnvh_finish)
            flash_next_st = RCV_TIME;
        else
            flash_next_st = FLASH_TVNH;
    end
    
    RCV_TIME:
    begin
        if(rcv_finish)
            flash_next_st = FLASH_IDLE;
        else
            flash_next_st = RCV_TIME;
    end
    
    PROG_SETUP:
    begin
        if(prog_set_finish)
            flash_next_st = ADDR_SETUP;
        else
            flash_next_st = PROG_SETUP;
    end
//------------------------------------------------
//ensure the prog_en is active;because prog_en can
//be negtive when the address is invaliue
//------------------------------------------------
//prog_en 做一个保护,比如状态机驱动了,发现地址写错了
//不能继续,prog_en 被收回,让设计可靠性更高
    ADDR_SETUP:
    begin
        if (prog_en)        
        begin
            if(prog_addr_hold_finish)
                flash_next_st = PROG_PROC;
            else
                flash_next_st = ADDR_SETUP;
        end
        else
            flash_next_st = FLASH_IDLE;
    end
​
    PROG_PROC:
    begin
        if(prog_en) 
        begin
            if (prog_proc_finish)
                flash_next_st = ADDR_HOLD;
            else 
                flash_next_st = PROG_PROC;
        end
        else
            flash_next_st = FLASH_IDLE;
    end
    
    ADDR_HOLD:
        begin
            if(prog_en)
            begin
                if(prog_addr_hold_finish)
                    flash_next_st = PROG_HOLD;
                else
                    flash_next_st = ADDR_HOLD;
            end
            else
                flash_next_st = FLASH_IDLE;
        end
    
    PROG_HOLD:
        begin:
            if(prog_en)
            begin
                if(prog_hold_finish)
                    flash_next_st = FLASH_TVNH;
                else
                    flash_next_st = PROG_HOLD;
            end
            else
                flash_next_st = FLASH_IDLE;
        end
​
    default : flash_next_st <= FLASH_IDLE;
    endcase
end
​
always@ (*) begin
//第三段组合逻辑,使用状态,产生信号
//这里r_next 保留信号做一个保护
    hready_flag = 1'b1;
    addr_acces_cnt_next = 0;
    flash0_xaddr_r_next = flash0_xaddr_r ;      
    flash0_yaddr_r_next = flash0_yaddr_r ;      
    flash1_xaddr_r_next = flash1_xaddr_r ;      
    flash1_yaddr_r_next = flash1_yaddr_r ;      
    flash_wdata_r_next  = flash_wdata_r  ;
    
    flash0_xe_r_next    = flash0_xe_r       ;       
    flash0_ye_r_next    = flash0_ye_r       ;
    flash0_se_r_next    = flash0_se_r       ;
    flash0_infren_r_next= flash0_infren_r   ;
    flash0_erase_r_next = flash0_erase_r    ;
    flash0_mass_r_next  = flash0_mass_r     ;
    flash0_prog_r_next  = flash0_prog_r     ;
    flash0_nvstr_r_next = flash0_nvstr_r    ;
​
    flash1_xe_r_next    = flash1_xe_r       ;       
    flash1_ye_r_next    = flash1_ye_r       ;
    flash1_se_r_next    = flash1_se_r       ;
    flash1_infren_r_next= flash1_infren_r   ;
    flash1_erase_r_next = flash1_erase_r    ;
    flash1_mass_r_next  = flash1_mass_r     ;
    flash1_prog_r_next  = flash1_prog_r     ;
    flash1_nvstr_r_next = flash1_nvstr_r    ;
    
    flash_busy_r_next   = flash_busy_r  ;
    
    flash0_cs_r_next    = flash0_cs_r   ;
    flash1_cs_r_next    = flash1_cs_r   ;
    
    case(flash_current_st)
    FLASH_IDLE:
    begin
        hready_flag = 1'b1;
        case(flash_next_st)
        READ_ACCESS:
        begin
            //xaddr :page address :512byte per page
            //xaddr :row address  :32byte per row [4:0]
            //flash_addr :haddr_r [17:0] 256KBytes
            //flash_addr [14:5] 1k row
            //如果是information则根据rd_infr_sel判断是哪个information;
            // INFR :   0x0006_1000~0x0006_13ff    0110_0001_0000_0000_0000
            // INFR :   0x0006_1400~0x0006_17ff    0110_0001_0100_0000_0000     
            //infromation的xaddr=flash_addr[9:5]
            //如果不是information则为main xaddr地址为flash_addr[14:5]=[10+6-2:6-1]
            //yaddr一直是flash_addr[4:0]
            flash0_xaddr_r_next = (rd_infr0_sel) ?{7'b0,flash_addr[XADDR-1:XADDR_LOW-1]} :
                                    flash_addr[XADDR+XADDR_LOW-2:XADDR_LOW-1];
            flash1_xaddr_r_next = (rd_infr1_sel) ?{7'b0,flash_addr[XADDR-1:XADDR_LOW-1]} :
                                    flash_addr[XADDR+XADDR_LOW-2:XADDR_LOW-1];
            //yaddr :bytes addr
            //flash_addr[4:0] 32bytes per row
            flash0_yaddr_r_next = flash_addr[YADDR-1:0];
            flash1_yaddr_r_next = flash_addr[YADDR-1:0];
            
            //这里read 可以在第一时间赋值号以下值,不用等
            flash0_xe_r_next    = (rd_main0_sel || rd_infr0_sel);       
            flash0_ye_r_next    = (rd_main0_sel || rd_infr0_sel);   
            flash0_se_r_next    = (rd_main0_sel || rd_infr0_sel);   
            flash0_infren_r_next= rd_infr0_sel   ;
            
            flash1_xe_r_next    = (rd_main1_sel || rd_infr1_sel);       
            flash1_ye_r_next    = (rd_main1_sel || rd_infr1_sel);   
            flash1_se_r_next    = (rd_main1_sel || rd_infr1_sel);   
            flash1_infren_r_next= rd_infr1_sel   ;
            
            flash_busy_r_next = 1'b1;
            
            flash0_cs_r_next = flash0_rd_cs;
            flash1_cs_r_next = flash1_rd_cs;
            
        end
        
        FLASH_TNVS
        begin   
            flash_busy_r_next = 1'b1;
            if(prog_en)
            begin
                flash0_xe_r_next    = (prog_infrarea0_sel || prog_mainarea0_sel);       
                flash0_infren_r_next= prog_infrarea0_sel;
                flash0_prog_r_next  = (prog_infrarea0_sel || prog_mainarea0_sel);
                
                flash1_xe_r_next    = (prog_infrarea1_sel || prog_mainarea1_sel);       
                flash1_infren_r_next= prog_infrarea1_sel;
                flash1_prog_r_next  = (prog_infrarea1_sel || prog_mainarea1_sel);
                
                flash0_xaddr_r_next = (prog_infrarea0_sel) ?{7'b0,flash_addr[XADDR_LOW+1 :XADDR_LOW-1]} :
                                    flash_addr[XADDR+XADDR_LOW-2:XADDR_LOW-1];
                flash0_xaddr_r_next = (prog_infrarea0_sel) ?{7'b0,flash_addr[XADDR_LOW+1 :XADDR_LOW-1]} :
                                    flash_addr[XADDR+XADDR_LOW-2:XADDR_LOW-1];
            end
            else if(pe_en)
            begin
                if(pe_main_infr_sel)//info select
                begin
                //infromation 只有2个page
                    if(pe_num[1] == 1'b0) //the first flash
                        begin
                            flash0_xe_r_next    = 1'b1;
                            flash0_ye_r_next    = 1'b1;
                            flash0_se_r_next    = 1'b1;
                            flash0_infren_r_next= {7'b0,pe_num[0],2'b0};
                        end
                        else 
                        begin
                            flash1_xe_r_next    = 1'b1;
                            flash1_ye_r_next    = 1'b1;
                            flash1_se_r_next    = 1'b1;
                            flash1_infren_r_next= {7'b0,pe_num[0],2'b0};
                        end
                end
                else  //main select
                begin
                //pe_num最高位判断flash0还是flash1
                    if(pe_num[8] == 1'b0) //the first flash
                        begin
                            flash0_xe_r_next    = 1'b1;
                            flash0_ye_r_next    = 1'b1;
                            flash0_se_r_next    = 1'b1;
                            flash0_infren_r_next= {pe_num[7:0],2'b0};
                        end
                        else 
                        begin
                            flash1_xe_r_next    = 1'b1;
                            flash1_ye_r_next    = 1'b1;
                            flash1_se_r_next    = 1'b1;
                            flash1_infren_r_next= {{pe_num[7:0],2'b0};
                        end
                end
            end
        end
        
        default :
        begin
            addr_acces_cnt_next = 0;
            flash0_xaddr_r_next = 0;
            flash0_yaddr_r_next = 0;
            flash1_xaddr_r_next = 0;
            flash1_yaddr_r_next = 0;
            flash_wdata_r_next  = 0;
​
            flash0_xe_r_next    = 0;
            flash0_ye_r_next    = 0;
            flash0_se_r_next    = 0;
            flash0_infren_r_next= 0;
            flash0_erase_r_next = 0;
            flash0_mass_r_next  = 0;
            flash0_prog_r_next  = 0;
            flash0_nvstr_r_next = 0;
​
            flash1_xe_r_next    = 0;
            flash1_ye_r_next    = 0;
            flash1_se_r_next    = 0;
            flash1_infren_r_next= 0;
            flash1_erase_r_next = 0;
            flash1_mass_r_next  = 0;
            flash1_prog_r_next  = 0;
            flash1_nvstr_r_next = 0;
​
            flash_busy_r_next   = 0;
​
            flash0_cs_r_next    = 0;
            flash1_cs_r_next    = 0;
        end
        endcase
    end
    
    READ_ACCESS:
    begin
        hready_flag = 1'b0;
        addr_acces_cnt_next = addr_acces_cnt + 1;
        if (flash_next_st == FLASH_IDLE)
        begin
            flash_busy_r_next = 1'b0;
            flash0_cs_r_next  = 1'b0;
            flash1_cs_r_next  = 1'b0; 
            
            flash0_xaddr_r_next = 0;
            flash0_yaddr_r_next = 0;
            flash1_xaddr_r_next = 0;
            flash1_yaddr_r_next = 0;
                
            flash0_xe_r_next    = 0;
            flash0_ye_r_next    = 0;
            flash0_se_r_next    = 0;
            flash0_infren_r_next= 0;
            
            flash1_xe_r_next    = 0;
            flash1_ye_r_next    = 0;
            flash1_se_r_next    = 0;
            flash1_infren_r_next= 0;
        end
        else
            flash_busy_r_next = 1'b1;
    end
    
    FLASH_TNVS:
    begin 
        if(flash_next_st == PROG_SETUP)
        begin
            flash0_nvstr_r_next = (prog_infrarea0_sel || prog_mainarea0_sel);
            flash1_nvstr_r_next = (prog_infrarea1_sel || prog_mainarea1_sel);
        end
        else if (flash_next_st == PE_ERASE)
        begin
            if(pe_main_infr_sel) //info select
            begin
                if(pe_num[1] == 1'b0) //the first flsh
                    flash0_nvstr_r_next = 1'b1;
                else
                    flash1_nvstr_r_next = 1'b1;
            end
            else //main select
            begin
                if(pe_num[8] == 1'b0 ) //the first flsh
                    flash0_nvstr_r_next = 1'b1;
                else
                    flash1_nvstr_r_next = 1'b1;
            end
        end
    end
    
    PE_ERASE:
    begin
        if(flash_next_st == FLASH_TVNH)
        begin
            flash0_erase_r_next = 1'b0;
            flash1_erase_r_next = 1'b0;
        end
    end
    
    PROG_SETUP:
    begin
        if(flash_next_st == ADDR_SETUP)
        begin
            flash0_yaddr_r_next = flash_yaddr[YADDR-1:0];
            flash1_yaddr_r_next = flash_yaddr[YADDR-1:0];
            flash_wdata_r_next  = flash_data_in;
        end
    end
    
    ADDR_SETUP:
    begin
        if(flash_next_st == PROG_PROC)
        begin
            flash0_ye_r_next    = (prog_infrarea0_sel || prog_mainarea0_sel);
            flash1_ye_r_next    = (prog_infrarea1_sel || prog_mainarea1_sel);
        end
    end
    
    PROG_PROC:
    begin
        if(flash_next_st == ADDR_HOLD)
        begin
            flash0_ye_r_next    = 1'b0;
            flash1_ye_r_next    = 1'b0;
        end
    end
    
    ADDR_HOLD:
    begin
        if(flash_next_st == PROG_HOLD)
        begin
            flash0_yaddr_r_next = 1'b0;
            flash1_yaddr_r_next = 1'b0;
        end
    end
    
    PROG_HOLD:
    begin
        if(flash_next_st == FLASH_TVNH)
        begin
            flash0_prog_r_next  = 1'b0;
            flash1_prog_r_next  = 1'b0;
        end
    end
    
    FLASH_TVNH:
    begin
        if(flash_next_st == RCV_TIME)
        begin
            flash0_xe_r_next    = 1'b0;
            flash1_xe_r_next    = 1'b0;
            flash0_nvstr_r_next = 1'b0;
            flash1_nvstr_r_next = 1'b0;
        end
    end
    
    RCV_TIME:
    begin
        if(flash_next_st == FLASH_IDLE)
            flash_busy_r_next = 1'b0;
        else
            flash_busy_r_next = 1'b1;
    end
    
    default : hready_flag = 1'b1;
    
    endcase
    end
end
​
​
//----------------------------------------------------- 
//Counter which generate control signals which control the FLASH_IDLE FSM
//--------------------------------------------------------------
​
//--------------------------------
//Recover hold time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        rcv_cnt <= 7'b0;
    else if((prog_en||pe_en) && rcv_hold)
        rcv_cnt <= rcv_cnt + 1'b1;
    else
        rcv_cnt <= 7'b0;
end
​
//----------------------------------
//NVSTR set time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        nvstr_set_cnt <= 12'b0;
    else if(tnvs_hold)
        nvstr_set_cnt <= nvstr_set_cnt + 1'b1;
    else
        nvstr_set_cnt <= 12'b0;
end
​
//----------------------------------
//NVSTR hold time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        nvstr_hold_cnt <= 12'b0;
    else if(tnvh_hold)
        nvstr_hold_cnt <= nvstr_hold_cnt + 1'b1;
    else
        nvstr_hold_cnt <= 12'b0;
end
​
//----------------------------------
// flash addr set time when prog
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        prog_addr_set_cnt <= 2'b0;
    else if(prog_addr_set_hold)
        prog_addr_set_cnt <= prog_addr_set_cnt + 1'b1;
    else
        prog_addr_set_cnt <= 2'b0;
end
​
//----------------------------------
// PROG set time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        prog_set_cnt <= 8'b0;
    else if(prog_set_hold)
        prog_set_cnt <= prog_set_cnt + 1'b1;
    else
        prog_set_cnt <= 8'b0;
end
​
//----------------------------------
// PROG time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        prog_proc_cnt <= 8'b0;
    else if(prog_proc_hold)
        prog_proc_cnt <= prog_proc_cnt + 1'b1;
    else
        prog_proc_cnt <= 8'b0;
end
​
//----------------------------------
// PROG address hold time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        prog_addr_hold_cnt <= 4'b0;
    else if(prog_addr_hold)
        prog_addr_hold_cnt <= prog_addr_hold_cnt + 1'b1;
    else
        prog_addr_hold_cnt <= 4'b0;
end
​
//----------------------------------
// PROG end hold time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        prog_end_hold_cnt <= 4'b0;
    else if(prog_end_hold)
        prog_end_hold_cnt <= prog_end_hold_cnt + 1'b1;
    else
        prog_end_hold_cnt <= 4'b0;
end
​
//----------------------------------
// PAGE ERASE hold time
​
always@(posedge flash_clk or negedge flash_rst_n) begin
    if(!flash_rst_n)
        flash_pe_cnt <= 24'b0;
    else if(pe_hold)
        flash_pe_cnt <= flash_pe_cnt + 1'b1;
    else
        flash_pe_cnt <= 24'b0;
end
​
//-------------------------------------
//register flash data output
//----------------------------------------
always@(posedge flash_clk or negedge flash_rst_n)
begin
    if(!flash_rst_n)
        flash_rdata <= 32'b0;
    else if (rd_finish_pre)
    // 用按位与 比MUX节省资源
        flash_rdata <= ({32{flash0_cs_r}} & rdata0) | ({32{flash1_cs_r}} & rdata1);
end
​
endmodule
​

3.4 flash_core 模块

module flash_core(
              //normal mode input signals
                flash0_infr_en,
                flash0_xaddr_en,
                flash0_yaddr_en,
                flash0_se_en,
                flash0_prog_en,
                flash0_nvstr_en,
                flash0_erase_en,
                flash0_mass_en,
                flash0_xaddr,
                flash0_yaddr,
                flash0_data_in,
                
                flash1_infr_en,
                flash1_xaddr_en,
                flash1_yaddr_en,
                flash1_se_en,
                flash1_prog_en,
                flash1_nvstr_en,
                flash1_erase_en,
                flash1_mass_en,
                flash1_xaddr,
                flash1_yaddr,
                flash1_data_in,
                
                tmr,
                vpp,
                tm,
                
                //test mode input signals
                test_infr_en,
                test_xaddr_en,
                test_yaddr_en,
                test_se_en,
                test_prog_en,
                test_nvstr_en,
                test_erase_en,
                test_mass_en,
                test_xaddr,
                test_yaddr,
                test_data_in,
                
                //test mode enable signal
                test_en,
                
                //power on protect signal
                in_pflash_por_wp,
                
                //data output 
                flash0_data_out,
                flash0_data_out
  );
  
  //----------------------------
  //declare the ports
  //----------------------------
  
  //flash0 control signals
  input              flash0_infr_en;
  input              flash0_xaddr_en;
  input              flash0_yaddr_en;
  input              flash0_se_en;
  input              flash0_prog_en;
  input              flash0_nvstr_en;
  input              flash0_erase_en;
  input              flash0_mass_en;
  input [9:0]        flash0_xaddr;
  input [4:0]        flash0_yaddr;
  input [31:0]       flash0_data_in;
  
  //flash1 control signals
  input              flash1_infr_en;
  input              flash1_xaddr_en;
  input              flash1_yaddr_en;
  input              flash1_se_en;
  input              flash1_prog_en;
  input              flash1_nvstr_en;
  input              flash1_erase_en;
  input              flash1_mass_en;
  input [9:0]        flash1_xaddr;
  input [4:0]        flash1_yaddr;
  input [31:0]       flash1_data_in;
  
  input              tmr;
  input              vpp;
  input [2:0]        tm;
  
  //test mode input signals
  input              test_infr_en;
  input              test_xaddr_en;
  input              test_yaddr_en;
  input              test_se_en;
  input              test_prog_en;
  input              test_nvstr_en;
  input              test_erase_en;
  input              test_mass_en;
  input              test_xaddr;
  input              test_yaddr;
  input              test_data_in;
  
  //test mode enable signal
  input              test_en;
  
  //power on protect signal
  input              in_pflash_por_wp;
  
  //data output signals
  output [31:0]      flash0_data_out;
  output [31:0]      flash1_data_out;
  
  //internal wire 
  wire tp_flash0_infr_en;
  wire tp_flash0_xaddr_en;
  wire tp_flash0_yaddr_en;
  wire tp_flash0_se_en;
  wire tp_flash0_prog_en;
  wire tp_flash0_nvstr_en;
  wire tp_flash0_erase_en;
  wire tp_flash0_mass_en;
  
  wire tp_flash1_infr_en;
  wire tp_flash1_xaddr_en;
  wire tp_flash1_yaddr_en;
  wire tp_flash1_se_en;
  wire tp_flash1_prog_en;
  wire tp_flash1_nvstr_en;
  wire tp_flash1_erase_en;
  wire tp_flash1_mass_en;
  
  wire flash0_ifren;
  wire flash0_xe;
  wire flash0_ye;
  wire flash0_se;
  wire flash0_prog;
  wire flash0_nvstr;
  wire flash0_erase;
  wire flash0_mas1;
  wire [9:0] flash0_xadr;
  wire [4:0] flash0_yadr;
  wire [31:0] flash0_din;
  
  wire flash1_ifren;
  wire flash1_xe;
  wire flash1_ye;
  wire flash1_se;
  wire flash1_prog;
  wire flash1_nvstr;
  wire flash1_erase;
  wire flash1_mas1;
  wire [9:0] flash1_xadr;
  wire [4:0] flash1_yadr;
  wire [31:0] flash1_din;
  
  
  //the mux logic
  //which choose the input into 
  //flash with the normal mode
  //or the test mode
  
  AND2X2 U_flash0_ifren_and (.Y(tp_flash0_infr_en  ),A(flash0_infr_en  ),B(1'b1));
  AND2X2 U_flash0_xe_and    (.Y(tp_flash0_xaddr_en ),A(flash0_xaddr_en ),B(1'b1));
  AND2X2 U_flash0_ye_and    (.Y(tp_flash0_yaddr_en ),A(flash0_yaddr_en ),B(1'b1));
  AND2X2 U_flash0_se_and    (.Y(tp_flash0_se_en    ),A(flash0_se_en    ),B(1'b1));
  AND2X2 U_flash0_prog_and  (.Y(tp_flash0_prog_en  ),A(flash0_prog_en  ),B(in_pflash_por_wp));
  AND2X2 U_flash0_nvstr_and (.Y(tp_flash0_nvstr_en ),A(flash0_nvstr_en ),B(in_pflash_por_wp));
  AND2X2 U_flash0_erase_and (.Y(tp_flash0_erase_en ),A(flash0_erase_en ),B(in_pflash_por_wp));
  AND2X2 U_flash0_mas1_and  (.Y(tp_flash0_mass_en  ),A(flash0_mass_en  ),B(in_pflash_por_wp));
  
  AND2X2 U_flash1_ifren_and (.Y(tp_flash1_infr_en  ),A(flash1_infr_en  ),B(1'b1));
  AND2X2 U_flash1_xe_and    (.Y(tp_flash1_xaddr_en ),A(flash1_xaddr_en ),B(1'b1));
  AND2X2 U_flash1_ye_and    (.Y(tp_flash1_yaddr_en ),A(flash1_yaddr_en ),B(1'b1));
  AND2X2 U_flash1_se_and    (.Y(tp_flash1_se_en    ),A(flash1_se_en    ),B(1'b1));
  AND2X2 U_flash1_prog_and  (.Y(tp_flash1_prog_en  ),A(flash1_prog_en  ),B(in_pflash_por_wp));
  AND2X2 U_flash1_nvstr_and (.Y(tp_flash1_nvstr_en ),A(flash1_nvstr_en ),B(in_pflash_por_wp));
  AND2X2 U_flash1_erase_and (.Y(tp_flash1_erase_en ),A(flash1_erase_en ),B(in_pflash_por_wp));
  AND2X2 U_flash1_mas1_and  (.Y(tp_flash1_mass_en  ),A(flash1_mass_en  ),B(in_pflash_por_wp));
  
  
  //flash0 input 
  assign flash0_ifren  = test_en ? test_infr_en  : tp_flash0_infr_en ;
  assign flash0_xe     = test_en ? test_xaddr_en : tp_flash0_xaddr_en;
  assign flash0_ye     = test_en ? test_yaddr_en : tp_flash0_yaddr_en;
  assign flash0_se     = test_en ? test_se_en    : tp_flash0_se_en   ;
  assign flash0_prog   = test_en ? test_prog_en  : tp_flash0_prog_en ;
  assign flash0_nvstr  = test_en ? test_nvstr_en : tp_flash0_nvstr_en;
  assign flash0_erase  = test_en ? test_erase_en : tp_flash0_erase_en;
  assign flash0_mas1   = test_en ? test_mass_en  : tp_flash0_mass_en ;
  assign flash0_xadr   = test_en ? test_xaddr    :    flash0_xaddr   ;
  assign flash0_yadr   = test_en ? test_yaddr    :    flash0_yaddr   ;
  assign flash0_din    = test_en ? test_data_in  :    flash0_data_in ;
  
  //flash1 input 
  assign flash1_ifren  = test_en ? test_infr_en  : tp_flash1_infr_en ;
  assign flash1_xe     = test_en ? test_xaddr_en : tp_flash1_xaddr_en;
  assign flash1_ye     = test_en ? test_yaddr_en : tp_flash1_yaddr_en;
  assign flash1_se     = test_en ? test_se_en    : tp_flash1_se_en   ;
  assign flash1_prog   = test_en ? test_prog_en  : tp_flash1_prog_en ;
  assign flash1_nvstr  = test_en ? test_nvstr_en : tp_flash1_nvstr_en;
  assign flash1_erase  = test_en ? test_erase_en : tp_flash1_erase_en;
  assign flash1_mas1   = test_en ? test_mass_en  : tp_flash1_mass_en ;
  assign flash1_xadr   = test_en ? test_xaddr    :    flash1_xaddr   ;
  assign flash1_yadr   = test_en ? test_yaddr    :    flash1_yaddr   ;
  assign flash1_din    = test_en ? test_data_in  :    flash1_data_in ;
  
  
  //instance the flash model
  SFD32KX32M32P4C_HE_LMC U_flash0_model(
           .XADR     (flash0_xadr),
           .YADR     (flash0_yadr),
           .DIN      (flash0_din),
           .DOUT     (flash0_data_out),
           .XE       (flash0_xe),
           .YE       (flash0_ye),
           .SE       (flash0_se),
           .ERASE    (flash0_erase),
           .MAS1     (flash0_mas1),
           .PROG     (flash0_prog),
           .NVSTR    (flash0_nvstr),
           .IFREN    (flash0_ifren),
           .TMR      (tmr),
           .VPP      (vpp),
           .TM       (tm)
  );
  
  SFD32KX32M32P4C_HE_LMC U_flash1_model(
           .XADR     (flash1_xadr    ),
           .YADR     (flash1_yadr    ),
           .DIN      (flash1_din     ),
           .DOUT     (flash1_data_out),
           .XE       (flash1_xe      ),
           .YE       (flash1_ye      ),
           .SE       (flash1_se      ),
           .ERASE    (flash1_erase   ),
           .MAS1     (flash1_mas1    ),
           .PROG     (flash1_prog    ),
           .NVSTR    (flash1_nvstr   ),
           .IFREN    (flash1_ifren   ),
           .TMR      (tmr            ),
           .VPP      (vpp            ),
           .TM       (tm             )
  );
  
  endmodule
 

3.5 flashc_top_sim 模块

 module flashc_top_sim(
                      //input signals
                      hclk,
                      hresetn,
                      hsel,
                      hready_in,
                      hwrite,
                      hsize,
                      htrans,
                      hburst,
                      hwdata,
                      haddr,
                      
                      eflash_wp_n,
                      dft_en,
                      boot_en,
                      addr_offset,
                      
                      //output signals
                      hready_out,
                      hresp,
                      hrdata,
                      flash_ctrl_int,
                      
                      tmr,
                      vpp,
                      tm,
                      
                      //test mode input signals
                      test_infr_en,
                      test_xaddr_en,
                      test_yaddr_en,
                      test_se_en,
                      test_prog_en,
                      test_nvstr_en,
                      test_erase_en,
                      test_mass_en,
                      test_xaddr,
                      test_yaddr,
                      test_data_in,
                      
                      //test mode enable signal
                      test_en,
                      
                      //power on protect signal
                      in_pflash_por_wp
  );
  
  parameter XADDR     = 10;
  parameter XADDR_LOW = 6;
  parameter YADDR     = 5; 
  
  
  input              hclk;
  input              hresetn;
  input              hsel;
  input              hready_in;
  input              hwrite;
  input [2:0]        hsize;
  input [2:0]        htrans;
  input [1:0]        hburst;
  input [31:0]       hwdata;
  input [31:0]       haddr;
  
  input              eflash_wp_n;
  input              dft_en;
  input              boot_en;
  //  boot area offset
  input [4:0]        addr_offset;
  
  input              tmr;
  input              vpp;
  input [2:0]        tm;
  
  //test mode input signals
  input              test_infr_en;
  input              test_xaddr_en;
  input              test_yaddr_en;
  input              test_se_en;
  input              test_prog_en;
  input              test_nvstr_en;
  input              test_erase_en;
  input              test_mass_en;
  input              test_xaddr;
  input              test_yaddr;
  input              test_data_in;
  
  //test mode enable signal
  input              test_en;
  
  //power on protect signal
  input              in_pflash_por_wp;
  
  //hrdata = flash_dout_in in  flash_ahb_slave_if module
  output hready_out;
  output [1:0] hresp;
  output [31:0] hrdata;
  
  //interrput enable
  output flash_ctrl_int;
  
  //flash control siganls
  wire               flash0_infr_en;
  wire               flash0_xaddr_en;
  wire               flash0_yaddr_en;
  wire               flash0_se_en;
  wire               flash0_prog_en;
  wire               flash0_nvstr_en;
  wire               flash0_mass_en;
  wire [XADDR-1:0]   flash0_xaddr;
  wire [YADDR-1:0]   flash0_yaddr;
  wire [31:0]        flash0_wdata;
  
  wire               flash1_infr_en;
  wire               flash1_xaddr_en;
  wire               flash1_yaddr_en;
  wire               flash1_se_en;
  wire               flash1_prog_en;
  wire               flash1_nvstr_en;
  wire               flash1_mass_en;
  wire [XADDR-1:0]   flash1_xaddr;
  wire [YADDR-1:0]   flash1_yaddr;
  wire [31:0]        flash1_wdata;
  
  flash_ctrl_top U_flash_ctrl_top(
                        .hclk            (hclk            ),
                        .hresetn         (hresetn         ),
                        .hsel            (hsel            ),
                        .hready_in       (hready_in       ),
                        .hwrite          (hwrite          ),
                        .hsize           (hsize           ),
                        .htrans          (htrans          ),
                        .hburst          (hburst          ),
                        .hwdata          (hwdata          ),
                        .haddr           (haddr           ),
                        
                        .eflash_wp_n     (eflash_wp_n     ),
                        .dft_en          (dft_en          ),
                        .boot_en         (boot_en         ),
                        .addr_offset     (addr_offset     ),
                        
                        .flash0_dout_in  (flash0_data2ahb ),
                        .flash1_dout_in, (flash1_data2ahb )
                        
                        //output signals
                        .hready_out      (hready_out      ),
                        .hresp           (hresp           ),
                        .hrdata          (hrdata          ),
                        
                        .flash_ctrl_int  (flash_ctrl_int  ),
                        
                        .flash0_infr_en  (flash0_infr_en  ),
                        .flash0_xaddr_en (flash0_xaddr_en ),
                        .flash0_yaddr_en (flash0_yaddr_en ),
                        .flash0_se_en    (flash0_se_en    ),
                        .flash0_prog_en  (flash0_prog_en  ),
                        .flash0_nvstr_en (flash0_nvstr_en ),
                        .flash0_erase_en (flash0_erase_en ),
                        .flash0_mass_en  (flash0_mass_en  ),
                        .flash0_xaddr    (flash0_xaddr    ),
                        .flash0_yaddr    (flash0_yaddr    ),
                        .flash0_wdata    (flash0_wdata    ),
                        
                        .flash1_infr_en  (flash1_infr_en  ),
                        .flash1_xaddr_en (flash1_xaddr_en ),
                        .flash1_yaddr_en (flash1_yaddr_en ),
                        .flash1_se_en    (flash1_se_en    ),
                        .flash1_prog_en  (flash1_prog_en  ),
                        .flash1_nvstr_en (flash1_nvstr_en ),
                        .flash1_erase_en (flash1_erase_en ),
                        .flash1_mass_en  (flash1_mass_en  ),
                        .flash1_xaddr    (flash1_xaddr    ),
                        .flash1_yaddr    (flash1_yaddr    ),
                        .flash1_wdata    (flash1_wdata    )
  );
  
  flash_core U_flash_core(
                        .flash0_infr_en   (flash0_infr_en   ),
                        .flash0_xaddr_en  (flash0_xaddr_en  ),
                        .flash0_yaddr_en  (flash0_yaddr_en  ),
                        .flash0_se_en     (flash0_se_en     ),
                        .flash0_prog_en   (flash0_prog_en   ),
                        .flash0_nvstr_en  (flash0_nvstr_en  ),
                        .flash0_erase_en  (flash0_erase_en  ),
                        .flash0_mass_en   (flash0_mass_en   ),
                        .flash0_xaddr     (flash0_xaddr     ),
                        .flash0_yaddr     (flash0_yaddr     ),
                        .flash0_data_in   (flash0_data_in   ),
                
                        .flash1_infr_en   (flash1_infr_en   ),
                        .flash1_xaddr_en  (flash1_xaddr_en  ),
                        .flash1_yaddr_en  (flash1_yaddr_en  ),
                        .flash1_se_en     (flash1_se_en     ),
                        .flash1_prog_en   (flash1_prog_en   ),
                        .flash1_nvstr_en  (flash1_nvstr_en  ),
                        .flash1_erase_en  (flash1_erase_en  ),
                        .flash1_mass_en   (flash1_mass_en   ),
                        .flash1_xaddr     (flash1_xaddr     ),
                        .flash1_yaddr     (flash1_yaddr     ),
                        .flash1_data_in   (flash1_data_in   ),
                
                        .tmr              (tmr              ),
                        .vpp              (vpp              ),
                        .tm               (tm               ),
                
                //test mode input signals
                        .test_infr_en     (test_infr_en     ),
                        .test_xaddr_en    (test_xaddr_en    ),
                        .test_yaddr_en    (test_yaddr_en    ),
                        .test_se_en       (test_se_en       ),
                        .test_prog_en     (test_prog_en     ),
                        .test_nvstr_en    (test_nvstr_en    ),
                        .test_erase_en    (test_erase_en    ),
                        .test_mass_en     (test_mass_en     ),
                        .test_xaddr       (test_xaddr       ),
                        .test_yaddr       (test_yaddr       ),
                        .test_data_in     (test_data_in     ),
                
                //test mode enable signal
                        .test_en          (test_en          ),
                
                //power on protect signal
                        .in_pflash_por_wp (in_pflash_por_wp ),
                
                //data output 
                        .flash0_data_out  (flash0_data_out  ),
                        .flash0_data_out  (flash0_data_out  )
                        
  );
  
  
  endmodule
 
 

四、 eflash 控制器的仿真

4.1 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

4.2 对整体的仿真  

`timescale 1ns / 1ps
/*--------------------------------------------------------------------------------
--  Module      :  flashc_top_sim_tb
--  Description :  
------------------------------------------------------------------------------*/
  module flashc_top_sim_tb;
  
  reg                          hclk;
  reg                          hresetn;
  reg                          hsel;
  reg                          hwrite;
  reg                          hready;
  reg [2:0]                    hsize;
  reg [2:0]                    hburst;
  reg [1:0]                    htrans;
  reg [31:0]                   hwdata;
  reg [31:0]                   haddr;
​
  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;
  reg                          test_en;
  
  wire                          hready_resp;
  wire [1:0]                    hresp;
  wire [31:0]                   hrdata;
  
  wire [31:0]                   DOUT;
  reg [31:0]                    rdata;
  
  //reg sim_ctrl;
  
  //clock generator
  initial
  begin
    hclk = 0;
  forever 
    begin
      #5 hclk = ~hclk;
    end
  end
  
  
  
  
  //dump waveform
  `ifdef VPD_ON
  initial begin
    $vcdpluson();
  end
  `endif
  
  parameter IDLE   = 2'b00;
  parameter BUSY   = 2'b01;
  parameter NONSEQ = 2'b10;
  parameter SEQ    = 2'b11;
//   // for test
//   initial begin
//     sim_ctrl = 1'b0;
//     test_en  = 1'b1;
//     XADR     = 10'b0;
//     YADR     = 5'b0;
//     DIN      = 32'b0;
//     XE       = 1'b0;
//     YE       = 1'b0;
//     SE       = 1'b0;
//     ERASE    = 1'b0;
//     MAS1     = 1'b0;
//     PROG     = 1'b0;
//     NVSTR    = 1'b0;
//     #100;
//     page_erase(8'b0);
//     prog_word(10'h0,5'h0,32'h12345678);
//     read_word(10'h0,5'h0,rdata);
//     prog_word(10'h0,5'h1,32'haabbccdd);
//     read_word(10'h0,5'h1,rdata);
//     #1000;
//     sim_ctrl = 1'b1;
//   end
  
  parameter NVSTR_SETUO_ADDR      = 8'h00;
  parameter NVSTR_HOLD_ADDR       = 8'h04;
  parameter PROG_SETUO_ADDR       = 8'h08;
  parameter PROGADDR_SETHOLD_ADDR = 8'h0c;
  parameter PROG_PROC_ADDR        = 8'h10;
  parameter RD_ACES_ADDR          = 8'h14;
  parameter PE_ADDR               = 8'h18;
  parameter RCV_ADDR              = 8'h1c;
  parameter WR_EN_ADDR            = 8'h20;
  parameter PE_CONFIG_ADDR        = 8'h24;
  parameter PE_NUM_ADDR           = 8'h28;
  parameter PE_MAININFR_SEL_ADDR  = 8'h2c;
  parameter PROG_ADDR_ADDR        = 8'h30;
  parameter PROG_DATA_ADDR        = 8'h34;
  parameter INT_EN_ADDR           = 8'h38;
  parameter FLASH_STATUS_ADDR     = 8'h3c;
  parameter BOOT_ERROR_ADDR       = 8'h40;
  
  //for function mode
  initial begin
    hresetn = 0;
    htrans  = IDLE;
    hsize   = 3'b0;
    hburst  = 3'b0;
    hwrite  = 0;
    hsel    = 0;
    hready  = 0;
    haddr   = 0;
    hwdata  = 0;
    #200;
    hresetn = 1;
    
//     wait(sim_ctrl);
    test_en = 1'b0;
    #100;
    
    //config the int_en
    ahb_write_32(32'h60038,32'h2);
    //config the maininfr_sel
    ahb_write_32(32'h6002c,32'h0);
    //config the pe_num
    ahb_write_32(32'h60028,32'h0);
    //config the pe_config
    ahb_write_32(32'h60024,32'h1);
    
    wait(flashc_top_sim_tb .U_flashc_top_sim.flash_ctrl_int);
    #100;
    //clear int
    ahb_write_32(32'h6003c,32'h2);
    //page erase finish
    #1000;
    //config the int en
    ahb_write_32(32'h60038,32'h1);
    //config the prog addr
    ahb_write_32(32'h60030,32'h0);
    //config the prog data
    ahb_write_32(32'h60034,32'h11223344);
    //config the prog config
    ahb_write_32(32'h60020,32'h1);
    wait(flashc_top_sim_tb .U_flashc_top_sim.flash_ctrl_int);
    #1000;
    //clear int
    ahb_write_32(32'h6003c,32'h1);
    
    //config the prog addr
    ahb_write_32(32'h60030,32'h4);
    //config the prog data
    ahb_write_32(32'h60034,32'haabbccdd);
    //config the prog config
    ahb_write_32(32'h60020,32'h1);
    wait(flashc_top_sim_tb .U_flashc_top_sim.flash_ctrl_int);
    #100;
    //clear int
    ahb_write_32(32'h60038,32'h1);
    #1000;
    ahb_read_32(32'h0,rdata);
    ahb_read_32(32'h4,rdata);
    
    #100;
    $finish
  end
  
  
  flashc_top_sim U_flashc_top_sim(
                        .hclk                  (hclk        ),
                        .hresetn               (hresetn     ),
                        .hsel                  (hsel        ),
                        .hready_in             (hready      ),
                        .hwrite                (hwrite      ),
                        .hsize                 (hsize       ),
                        .htrans                (htrans      ),
                        .hburst                (hburst      ),
                        .hwdata                (hwdata      ),
                        .haddr                 (haddr       ),
                        .eflash_wp_n           (1'b1        ),
                        .dft_en                (1'b0        ),
                        .boot_en               (1'b0        ),
                        .addr_offset           (5'b0        ),
                        .hready_out            (hready_resp ),
                        .hresp                 (            ),
                        .hrdata                (            ),
                        .flash_ctrl_int        (            ),
                        .tmr                   (1'b1        ),
                        .vpp                   (            ),
                        .tm                    (            ),
                        .test_infr_en          (1'b0        ),
                        .test_xaddr_en         (XE          ),
                        .test_yaddr_en         (YE          ),
                        .test_se_en            (SE          ),
                        .test_prog_en          (PROG        ),
                        .test_nvstr_en         (NVSTR       ),
                        .test_erase_en         (ERASE       ),
                        .test_mass_en          (MAS1        ),
                        .test_xaddr            (XADR        ),
                        .test_yaddr            (YADR        ),
                        .test_data_in          (DIN         ),
                        .test_en               (test_en     ),
                        .in_pflash_por_wp      (1'b1        )
  );
  
  
  
  task ahb_write_32(input [31:0] addr,input [31:0] wdata);
  begin
    @(posedge hclk);
    #1;
    hsize    = 3'b010;
    htrans   = NONSEQ;
    hwrite   = 1;
    hsel     = 1;
    hready   = 1;
    haddr    = addr;
    @(posedge hclk);
    #1;
    hsize    = 3'b000;
    htrans   = IDLE;
    hwrite   = 0;
    hsel     = 0;
    hwdata   = wdata;
    @(posedge hclk);
    #1;
    haddr    = 32'b0;
    @(posedge hclk);
    end
  endtask
    
  task ahb_read_32(input [31:0] addr,output [31:0] rdata);
  begin
    @(posedge hclk);
    #1;
    haddr    = addr;
    hsize    = 3'b010;
    htrans   = NONSEQ;
    hwrite   = 1;
    hsel     = 1;
    @(posedge hclk);
    #1;
    hsize    = 3'b000;
    htrans   = IDLE;
    hwrite   = 0;
    hsel     = 0;
    wait(hready_resp)
    @(posedge hclk);
    rdata    = hrdata;
    haddr    = 32'b0;
    @(posedge hclk);
    end
  endtask
  
  task page_erase(input [7:0] page_num);
  begin
    #1234;
    XADR  = {page_num, 2'b0};
    XE    = 1'b1;
    ERASE = 1'b1;
    #5000;
    NVSTR = 1'b1;
    #20_000_000;
    ERASE = 1'b0;
    #5000;
    XE    = 1'b0;
    NVSTR = 1'b0;
    #10_000;
  end
  endtask
  
  task prog_word(input [9:0] xadr,input [4:0] yadr,input [31:0] wdata);
  begin
    #1234;
    XADR  = xadr;
    YADR  = yadr;
    DIN   = wdata;
    XE    = 1'b1;
    PROG  = 1'b1;
    #5000;
    NVSTR = 1'b1;
    #10_000;
    YE    = 1'b1;
    #20_000;
    YE    = 1'b0;
    #20;
    PROG = 1'b0;
    #5000;
    XE    = 1'b0;
    NVSTR = 1'b0;
    #10_000;
  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

  • 21
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
随着计算机系统的发展,内存的速度成为了系统性能的瓶颈之一。为了解决这一问题,SRAM(静态随机存储器)成为了一种常用的内存类型,而AHB(高级高速总线)是一种快速的总线协议。基于AHB的SRAM控制器设计与优化可以显著提高系统性能。 SRAM控制器的任务是管理SRAM芯片的读写操作。基于AHB的SRAM控制器可以通过总线传输协议来与其他设备进行通信,从而实现高速数据传输。其中,读取操作需要首先将地址和请求发送到SRAM中,然后等待SRAM返回数据。在这个过程中,控制器需要使用适当的寻址算法来定位存储位置,并根据SRAM的工作原理优化读取周期。 在设计和优化基于AHB的SRAM控制器时,需要考虑以下几个关键因素: 第一,SRAM内部结构的特点。SRAM的读取速度非常快,但它的存储密度相对较低,且需要专用硬件实现。因此,控制器需要在寻址和数据访问方面操作SRAM的内部结构。 第二,总线带宽。为了充分利用AHB总线的高速性能,控制器应使用适当的调度算法和数据传输协议,以充分利用总线带宽。 第三,芯片时序。SRAM芯片的时序和时延对读写操作的速度有重要影响。控制器应根据SRAM芯片的特性和内部结构来优化时序和时延参数。 综上所述,基于AHB的SRAM控制器设计和优化是一项复杂且重要的任务,它需要结合SRAM芯片的特性、总线带宽和时序参数进行考虑,以充分利用系统性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

炎龙铠甲会合体

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值