eFlash控制器设计
一、功能概述:
eFlash(embedded Flash)控制器控制eFlash的存储操作(读/写/擦除),其中eFlash一般为NOR Flash,其最大点是芯片内执行,采用了随机访问技术,与常见的SRAM相同。这样应用程序可以直接在Flash内运行,不必再把代码读取到系统主存中[1]。多用于存储bootloader等系统启动程序。存储体一般由代工厂提供。
功能特性:
- 支持32位的AHB slave interface(不支持该总线busy传输类型);
- 支持eFlash的多周期读、写、页擦操作(2块独立的eFlash串联封装);
- eFlash操作可配置(时序、功能)(flash的异步操作);
- 支持eFlash中的boot区空间的擦写保护。
1.1 功能框图
eFlash控制器由以下模块组成:
- flash与AHB总线的接口模块(flash_ahb_if):接收AHB总线控制信号,地址信号和数据信号;将地址译码转化成flash地址;配置控制寄存器以配合flash_ctrl模块的控制操作;并且储存flash工作状态到状态寄存器供软件可查。
- flash控制模块(falsh_ctrl):接收总线地址和命令,完成Flsh的读、写、和擦除操作;
1.2 顶层接口信号描述:
Signals | I/O | Width | form | to | Declaration |
---|---|---|---|---|---|
hclk | input | 1 | clock source | AHB bus clock | |
hresetn | input | 1 | reset controller | AHB bus reset signal | |
hsel | input | 1 | decoder | slave selected signal | |
hready_in | input | 1 | other slave | high:bus is ready to use | |
hwrite | input | 1 | Master | 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 | |
haddr | input | [31:0] | Master | AHB bus address | |
eflash_wp_n | input | 1 | efalsh write protect enable | ||
dft_en | input | 1 | DFT enable | ||
boot_en | input | 1 | boot area enable | ||
addr_offset | input | [4:0] | address offset | ||
flash0_dout_in | input | [31:0] | flash0 read data out | ||
flash1_dout_in | input | [31:0] | flash1 read data out | ||
hready_out | output | 1 | Master | slave has finished transfer | |
hresp | output | [1:0] | Master | OKEY、ERROR、RETRY、SPLIT | |
hrdata | output | [31:0] | Master | AHB bus read data | |
flash_ctrl_int, | output | 1 | Flash | falsh control interrupt signal when program done or pe done | |
flash0_infr_en | output | 1 | Flash | flash0 infromation block enable(IFREN) | |
flash0_xaddr_en | output | 1 | Flash | falsh0 xaddress enable(XE) | |
flash0_yaddr_en | output | 1 | Flash | falsh0 yaddress enable(YE) | |
flash0_se_en | output | 1 | Flash | falsh0 SA enable(SE) | |
flash0_prog_en | output | 1 | Flash | falsh0 progaram enable(PROG) | |
flash0_nvstr_en | output | 1 | Flash | falsh0 non-volatile store cycle enable(NVSTR) | |
flash0_erase_en | output | 1 | Flash | flash0 erase enable(ERASE) | |
flash0_mass_en | output | 1 | Flash | flash0 mass erase enable(MAS1) | |
flash0_xaddr | output | [9:0] | Flash | flash0 x address(XADR) | |
flash0_yaddr | output | [4:0] | Flash | flash0 y address(YADR) | |
flash0_wdata | output | [31:0] | Flash | flash0 write data(DIN) | |
flash1_infr_en | output | 1 | Flash | flash1 infromation block enable(IFREN) | |
flash1_xaddr_en | output | 1 | Flash | falsh1 xaddress enable(XE) | |
flash1_yaddr_en | output | 1 | Flash | falsh1 yaddress enable(YE) | |
flash1_se_en | output | 1 | Flash | falsh1 SA enable(SE) | |
flash1_prog_en | output | 1 | Flash | falsh1 progaram enable(PROG) | |
flash1_nvstr_en | output | 1 | Flash | falsh1 non-volatile store cycle enable(NVSTR) | |
flash0_erase_en | output | 1 | Flash | flash1 erase enable(ERASE) | |
flash1_mass_en | output | 1 | Flash | flash1 mass erase enable(MAS1) | |
flash1_xaddr | output | [9:0] | Flash | flash1 x address(XADR) | |
flash1_yaddr | output | [4:0] | Flash | flash1 y address(YADR) | |
flash1_wdata | output | [31:0] | Flash | flash1 write data(DIN) |
1.3 顶层Veilog实现
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
二、各模块详细描述
eFlash控制器由以下模块组成:
- flash与AHB总线的接口模块(flash_ahb_if):接收AHB总线控制信号,地址信号和数据信号;将地址译码转化成flash地址;配置控制寄存器以配合flash_ctrl模块的控制操作;并且储存flash工作状态到状态寄存器供软件可查。
- flash控制模块(falsh_ctrl): 产生flash操作所需要的操作命令与时序,驱动Flash异步工作。
2.1 Flash AHB 接口模块
flash_ahb_slave_if模块是flash控制器的AHB 总线接口模块。其具有以下几个作用:
1、将地址和数据传递给flash控制模块,用于对flash的读/写/页擦操作。
- 对于写Flash的过程,要将操作的地址和数据配置到相应配置寄存器;
- 对于读/页擦,地址通过译码传送给flash控制模块。
2、配置控制寄存器,对控制器的操作进行一个配置,包括写数据和写地址的配置,一些操作的使能,时序寄存器的配置等。以及配置状态寄存器,使Flash的工作状态可查。
2.1.1 信号描述
Signals | I/O | Width | form | to | Declaration |
---|---|---|---|---|---|
hclk, | input | 1 | clock source AHB bus clock | ||
hresetn, | input | 1 | reset controller AHB bus reset signal | ||
hsel, | input | 1 | decoder slave selected signal | ||
hready_in, | input | 1 | other slave high:bus is ready to use | ||
hwrite, | input | 1 | Master 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 | ||
haddr | input | [31:0] | Master AHB bus address | ||
flash_rdata | input | [31:0] | flash_ctrl flash read out data | ||
flash_prog_done | input | 1 | flash_ctrl flash program has finished | ||
flash_busy | input | 1 | flash_ctrl | flash is busy | |
eflash_wp_n, | input | 1 | Master | efalsh write protect enable | |
addr_offset | input [4:0] | Master | boot area address offset | ||
boot_en | input | 1 | Master | boot area enable | |
hready_flag | input | 1 | flash_ctrl | slave has finished transfer,transfer to hready_out | |
hready_out | output | 1 | Master | this slave to BUS siganl | |
hresp | output | [1:0] | Master | OK 、ERROR、SPLIT、RETRY | |
hrdata | output | [31:0] | Master | flash read data or register value | |
flash_prog_en | output | 1 | flash_ctrl | flash program enable | |
flash_pe_en | output | 1 | flash_ctrl | flash page erase enable | |
flash_rd_en | output | 1 | flash_ctrl | flash read enable | |
rd_inf0_sel | output | 1 | flash_ctrl | information0 area read select | |
rd_inf1_sel | output | 1 | flash_ctrl | information1 area read select | |
rd_main0_sel | output | 1 | flash_ctrl | main0 area read select | |
rd_main1_sel | output | 1 | flash_ctrl | main1 area read select | |
flash0_rd_cs | output | 1 | flash_ctrl | flash0 read selcet | |
flash1_rd_cs | output | 1 | flash_ctrl | flash0 read selcet | |
prog_infrarea0_sel | output | 1 | flash_ctrl | information0 area program select | |
prog_infrarea1_sel | output | 1 | flash_ctrl | information1 area program select | |
prog_mainarea0_sel | output | 1 | flash_ctrl | main0 area program select | |
prog_mainarea1_sel | output | 1 | flash_ctrl | main1 area program select | |
pe_num, | output | [8:0] | flash_ctrl | page number | |
pe_main_infr_sel | output | 1 | flash_ctrl | page erase main or infromation area | |
flash_addr_out, | output | [14:0] | flash_ctrl | flash address | |
flash_wdata, | output | [31:0] | flash_ctrl | flash write data | |
flash_ctrl_int, | output | 1 | flash_ctrl | flash interrupt enable | |
t_nvstr_setup | output | [11:0] | flash_ctrl | PROG/ERASE to NVSTR set up time >5us | |
t_nvstr_hold | output | [11:0] | flash_ctrl | NVSTR hold time >5us | |
t_rcv | output | [7:0] | flash_ctrl | Recover time >1us | |
t_prog_setup | output | [15:0] | flash_ctrl | NVSTR to program set up time | |
t_prog_hold | output | [3:0] | flash_ctrl | Program hold time (20~40us) | |
t_addr_setup | output | [3:0] | flash_ctrl | Adress/data set up time | |
t_addr_hold | output | [3:0] | flash_ctrl | Adress/data hold time | |
t_prog_proc | output | [15:0] | flash_ctrl | program time | |
t_addr_aces | output | [7:0] | flash_ctrl | Access time of read cycle | |
t_page_erase | output | [23:0] | flash_ctrl | page erase time >20ms |
2.1.2 寄存器地址及功能描述
base address :0x0006_0000
timing相关寄存器的复位初始值按悲观情况120MHz计算(正常在100MHz),保证默认情况下的flash读写操作可以正常进行。
name | bits | Address Offset | Reset value | Definition |
---|---|---|---|---|
nvstr_setup_timing | [31:0] | 0x00 | 32‘h259 | 写/擦操到NVSTR的建立时间 |
nvstr_hold_timing | [31:0] | 0x04 | 32‘h259 | 写/擦操到NVSTR的保持时间 |
prog_setup_timing | [31:0] | 0x08 | 32‘h4b1 | 写操作建立时间 |
progaddr_sethold_timing | [31:0] | 0x0c | 32‘h333 | 写操作地址建立、保持时间及写完成后的保持时间 |
prog_proc_timing | [31:0] | 0x10 | 32‘h962 | 每次写操作完成的时间 |
rd_aces_timing | [31:0] | 0x14 | 32‘h5 | 读操作所需要的时间 |
pe_timing | [31:0] | 0x18 | 32‘h0 | 页擦除所需要的时间(需配置) |
rcv_timing | [31:0] | 0x1c | 32‘h79 | 恢复时间 |
wr_en_r | [31:0] | 0x20 | 32‘h0 | Flash program使能 |
pe_en_r | [31:0] | 0x24 | 32‘h0 | Flash 页擦使能 |
pe_num_r | [31:0] | 0x28 | 9‘h1df | 页擦的数量 |
pe_main_infr_sel_r | [31:0] | 0x2c | 32‘h0 | 页擦main区还是information区选择 |
prog_addr_r | [31:0] | 0x30 | 32‘h0 | program 地址 |
prog_data_r | [31:0] | 0x34 | 32‘h0 | program 数据 |
int_en_r | [31:0] | 0x38 | - | 中断使能 |
flash_status_r | [31:0] | 0x3c | - | flash 状态寄存器 |
boot_error_r | [31:0] | 0x40 | - | boot 操作出错标记寄存器 |
2.1.3 Verilog 实现
module flash_ahb_slave_if (
//input signals
hclk,
hresetn,
hsel,
hready_in,
hwrite,
hsize,
htrans,
hburst,
hwdata,
haddr,
flash_rdata,
flash_prog_done,
flash_pe_done,
flash_busy,
eflash_wp_n,
addr_offset,//used for boot area
boot_en,
hready_flag,
//output signals
hready_out,
hresp,
hrdata,
flash_prog_en, //program enable
flash_pe_en, //page erase enable
flash_rd_en, //read enable
rd_inf0_sel,
rd_inf1_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,
flash_addr_out,
flash_wdata,
flash_ctrl_int, //use for interupt controller
//flash operation configuration for timing
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
);
input hclk;
input hsel;
//总线上其它slave是否全部IDLE(全IDLE才可以工作),
//其它slave有hready为低,则总线在满,这个hready_in也为低
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;
//从flash读出的地址,传输到AHB Bus
//(如果不在配置寄存器则直接赋值给hrdata输出到总线)
input [31:0] flash_rdata;
input flash_prog_done;
input flash_pe_done;
input flash_busy;
input eflash_wp_n;
input boot_en;
input [4:0] addr_offset;
input hready_flag;
//output signals
output hready_out;
output [1:0] hresp;
//------------------------------------------------------//
//AHB read data output.
//hrdata = if(status_sel) flash_status_r
// else (flash_cs) flash_rdata
//读配置寄存器,或者flash
//------------------------------------------------------//
output [31:0] hrdata;
output flash_prog_en;
output flash_pe_en;
output flash_rd_en;
output rd_inf0_sel;
output rd_inf1_sel;
output rd_main0_sel;
output rd_main1_sel;
output flash0_rd_cs;
output flash1_rd_cs;
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;
//给Flash的地址一共15bit
output [14:0] flash_addr_out;
output [31:0] flash_wdata;
output flash_ctrl_int; //use for interrupt controller
//flash operation configuration for timing
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;
//----------------------------------------------//
// register used for temp the ahb input signas
reg hwrite_r ;
reg [2:0] hsize_r ;
reg [1:0] htrans_r ;
reg [2:0] hburst_r ;
reg [31:0] haddr_r ;
//flash operation config register
//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] progaddr_sethold_timing;
reg [31:0] prog_proc_timing;
//read timing
reg [31:0] rd_aces_timing;
//page erase timing
reg [31:0] pe_timing;
//Address register and progam 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] prog_data1_r;
reg [31:0] prog_data2_r;
reg [31:0] prog_data3_r;
reg [31:0] invalid_data_r;
//falsh program/page erase operation control registers
//and main/info mem selected mark
//wr_en_r[0]:flash prog enable
//pe_en_r[0]:flash page erase enable
reg wr_en_r;
reg pe_en_r;
reg main_infr_sel;
//AHN Bus transactions
parameter IDLE = 2'b00;
parameter BUSY = 2'b01;
parameter NONSEQ = 2'b10;
parameter SEQ = 2'b11;
//Soc总线地址分配使用到 0x0028_1FFF ,所以识别控制寄存器地址
//以及MAIN INFR 地址判断到24位[23:0]
// REG : 0x0006_0000~0x0006_0fff :haddr[23:12] = 12'h060
// INFR : 0x0006_1000~0x0006_7fff :
// INFR : 0x0006_1000~0x0006_13ff 0110_0001_0000_0000
// INFR : 0x0006_1400~0x0006_17ff 0110_0100_0000_0000
parameter REG_ADDR = 12'h060;
parameter INFR_ADDR = 12'h061;
parameter INFR0_ADDR = 1'h0;
parameter INFR1_ADDR = 2'h1;
// MAIN : 0000_0000 ~ 0003_ffff :haddr[23:15] = 6'h00
// MIAN0: 0000_0000 ~ 0001_ffff :haddr[17:16] = 0-
// MIAN1: 0002_0000 ~ 0003_ffff: haddr[17:16] = 1-
parameter MAIN_ADDR = 6'h0;
parameter MAIN0_ADDR = 1'b0;
parameter MAIN1_ADDR = 1'b1;
//时序控制寄存器的地址偏移,在在控制寄存器初始地址
//加上偏移地址就是相应控制寄存器的地址
//timing configuration register address
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_MIANINFR_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,
PROG_DATA1_ADDR = 8'h44,
PROG_DATA2_ADDR = 8'h48,
PROG_DATA3_ADDR = 8'h50,
PROG_NUM_ADDR = 8'h54;
//-----------------------------------------------------//
//Generate AHB slave output signals:hready_out & hresp //
//flash prog : hready_out = 1; //
//flash pe : hready_out = 1; //
//flash read : if(reg_operation) hready_out = 1; //
// else hready_out =flash_rd_ready //
//-----------------------------------------------------//
//hready_flag 是控制器那边给的接口模块的,然后AHB总线判断
//ready了,就可以进行读取数据了
//hresp这里直接赋值00,表示response只有OK这种状态,其它不考虑
assign hready_out = hready_flag;
assign hresp = 2'b00;
//---------------------------------------------//
//Generate AHB write and read enable signals //
//ahb_wr_en : htrasn_r and hwrite_r //
//ahb_rd_en : htrasn_r and hwrite_r //
//---------------------------------------------//
//ahb_wr_en 当写信号有效、flash不处在busy状态、
//并且htrans不为IDLE或者BUSY,则有效
//ahb_wr_en 不用判断flash_busy 因为在读的时候有hready信号判断
assign ahb_wr_en = ((htrans == NONSEQ)||(htrans == SEQ)) && hwrite_r && (!flash_busy);
assign ahb_rd_en = ((htrans == NONSEQ)||(htrans == SEQ)) && (!hwrite_r);
//---------------------------------------------//
//flash input data and address.
//flash_addr : haddr_r[17:0] => 64KBytes row address
//flash_addr_out : haddr_r[17:2] => double word (32bits) align
//flash_wdata : when prog,prog_data_r
//
// NOTE:haddr_r will be XOR with addr_offser, <=> haddr_r+addr_offset
// why use the xor logic,not use the + ?
//----------------------------------------------------//
//flash_addr 是一个byte的地址(AHB那边),要给FLash一个32bit地址(4byte),flash_addr_out要去掉地址低2位
//???这里flash_addr 有问题
//??不确定:prog_addr_r寄存器18bit有效?每一片是15bit,最高bit片选;一个byte的地址,最低2位没用。高16位有用,最高位选哪一个flash,中间15位位XYADR
// 如果是写FLash那么地址等于prog_addr,这个地址被配置在PROG_ADDR 寄存器中;
// 如果
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;
assign flash_addr_out = flash_addr[16:2];
//flash_wdata 通过AHB写寄存器得到
assign flash_wdata = prog_data_r;
//------------------------------------------//
//config the flash configure register
//timing 都是通过hwdata写进来的
//-------------------------------------------//
//common configuration except for read operation
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 = progaddr_sethold_timing[15:0];
//read configuration
assign t_addr_aces = rd_aces_timing[7:0];
//page erase timing
assign t_page_erase = pe_timing[23:0];
//---------------------------------------------------//
//Generate flash reg_sel;infr_mem and main_mem sel when
//flash read operation
//main mem addr :0x0000_0000~0x0003_ffff
//infr mem addr :0x0006_1000~0x0006_7fff
//reg confige addr :0x0006_0000~0x0006_0fff
//Soc总线地址分配使用到 0x0028_1FFF ,所以识别控制寄存器地址
//以及MAIN INFR 地址判断到24位[23:0]
// REG : 0x0006_0000~0x0006_0fff :haddr[23:12] = 12'h060
// INFR : 0x0006_1000~0x0006_7fff :
// INFR : 0x0006_1000~0x0006_13ff 0110_0001_0000_0000
// INFR : 0x0006_1400~0x0006_17ff 0110_0100_0000_0000
//parameter REG_ADDR = 12'h060;
//parameter INFR_ADDR = 12'h061; ❓
//用地址的 haddr[11]判断INFR0,INFR1
//parameter INFR0_ADDR = 1'h0;
//parameter INFR1_ADDR = 2'h1;
// MAIN : 0000_0000 ~ 0003_ffff :haddr[23:15] = 6'h00
// MIAN0: 0000_0000 ~ 0001_ffff :haddr[17:16] = 0-
// MIAN1: 0002_0000 ~ 0003_ffff :haddr[17:16] = 1-
//parameter MAIN_ADDR = 6'h0;
//用地址的 haddr[17]判断main0,main1
//parameter MAIN0_ADDR = 1'b0;
//parameter MAIN0_ADDR = 1'b1;
//---------------------------------------------------//
assign reg_sel = (haddr_r[23:12] == REG_ADDR);
//area selected when in flash operation
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);
assign rd_main_sel = (haddr[23:18] == MAIN_ADDR);
assign rd_main0_sel = rd_mian_sel && (flash_addr[17] == MAIN0_ADDR);
assign rd_main1_sel = rd_mian_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_en作区分;
//读中断寄存器还是读存储器有区分,读存储器要等ready
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
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 bytes));
// 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(8K bytes));
// 3e000--> prog_addr_r[17:13] = 5'h11111;
// 16K bytes:
// 3c000--> prog_addr_r[17:14] = 4'h1111;
//-------------------------------------------------------------//
//一页4行,1行128byte,一页512byte;3c000-->page 480;3e000-->page 496
//写/页擦的地址刚好是boot区地址的话,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) ? (pe_num_r[8:4] == 5'b11111 ):
(addr_offset_r == 5'b11110) ? (pe_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
//boot区没写,没页擦,boot区地址没有选中
assign non_boot_addr_correct = !(boot_wr_sel || boot_pe_sel);
//the adress is always right when boot protect turn off in flash
//operation or is part of right when address is not boot adress
//when boot prot turn on
//判断地址是否正确:启用了boot保护的话,non_boot_addr_correct要为1才正确
//即没有boot wr和pe;没启用boot保护,那么地址正确
assign flash_addr_correct = boot_protect_n ? 1'b1 : non_boot_addr_correct;
//generate one of conditions of flash program and page erase enable
//若地址不正确则不能进行写和页擦
assign wr_en = wr_en_r && flash_addr_correct;
assign pe_en = pe_en_r && flash_addr_correct;
//--------------------------------------------------//
//Generate flash control logic
//flash_prog_en :flash_wp_n = 1 && wr_en_r[0] = 1;
//flash_pe_en :flash_wp_n = 1 && pe_en_r[0] = 1;
//--------------------------------------------------//
//flash program operation enable
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_pe_en = eflash_wp_n && (pe_en == 1'b1);
//pe_num_r和pe_main_infr_sel_r :配置寄存器,写入配置
assign pe_num = pe_num_r;
assign pe_main_infr_sel = pe_main_infr_sel_r;
//写状态寄存器有效:ahb写使能,配置寄存器选中,地址为状态寄存器地址
assign wr_status_valid = ahb_wr_en && reg_sel && (haddr_r[7:0] == FLASH_STATUS_ADDR);
//--------------------------------------------------------------//
//Generate interupt signal.
//when int_en_r[1] enable,flash_ctrl_int[i] output enable
//-------------------------------------------------------------//
assign flash_ctrl_int = (flash_status_r[0] && int_en_r[0] ||(flash_status_r[1]&&int_en_r[1])
//------------------------------------------------------//
//AHB read data output. ✔
//hrdata = if(status_sel) flash_status_r
// else (flash_cs) flash_rdata
//------------------------------------------------------//
//AHB读数据,当配置寄存器选中,读配置寄存器中内容,否则读flash读出的数据;
always@(*) begin
if(ahb_rd_en && reg_sel)
begin
case(haddr_r[7:0])
NVSTR_SETUP_ADDR : hrdata = nvstr_setup_timing ;
NVSTR_HOLD_ADDR : hrdata = nvstr_hold_timing ;
RCV_ADDR : hrdata = rcv_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 ;
PE_ADDR : hrdata = pe_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_MIANINFR_SEL_ADDR : hrdata = {31'h0,pe_main_infr_sel_r};
PROG_ADDR_ADDR : hrdata = prog_addr_r ;
PROG_DATA_ADDR : hrdata = prog_data_r ;
PROG_DATA1_ADDR : hrdata = prog_data1_r ;
PROG_DATA2_ADDR : hrdata = prog_data2_r ;
PROG_DATA3_ADDR : hrdata = prog_data3_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 AHB addr and control signals ✔
//--------------------------------------------------//
always@(posedge hclk or negedge hresetn) begin
if(!hresetn)
begin
hsize_r <= 1'b0 ;
htrans_r <= 3'b0 ;
hburst_r <= 3'b0 ;
hwdata_r <= 2'b0 ;
haddr_r <= 32'b0;
end
else if (hsel && hready_in)
begin
hsize_r <= hsize ;
htrans_r <= htrans ;
hburst_r <= hburst ;
hwdata_r <= hwdata ;
haddr_r <= haddr ;
end
else
begin
hsize_r <= 1'b0 ;
htrans_r <= 3'b0 ;
hburst_r <= 3'b0 ;
hwdata_r <= 2'b0 ;
haddr_r <= 32'b0;
end
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 ✔
//用于硬件清零,done 信号只保持一个周期
//----------------------------------------------------------//
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
begin
boot_pe_done <= 1'b0;
boot_wr_done <= 1'b0;
end
else if(boot_protect_n)
begin
boot_pe_done <= 1'b0;
boot_wr_done <= 1'b0;
end
else
begin
if (wr_en_r && boot_wr_sel)
boot_wr_done <= 1'b1;
else if (pe_en_r && boot_pe_sel)
boot_pe_done <= 1'b1;
else if (boot_wr_done || boot_pe_done)
begin
boot_pe_done <= 1'b0;
boot_wr_done <= 1'b0;
end
end
end
//-------------------------------------------------///
//AHB write registers.
//when ahb_wr_en,hdata 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 <= 2'h962 ;
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;
RCV_ADDR : rcv_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;
PE_ADDR : pe_timing <= hwdata;
WR_EN_ADDR : wr_en_r <= hwdata[0]; //software set
PE_CONFIG_ADDR : pe_en_r <= hwdata[0];
//最高位判断是flash0,还是flash1
PE_NUM_ADDR : pe_num_r <= hwdata[8:0];
PE_MIANINFR_SEL_ADDR : pe_main_infr_sel_r <= hwdata[0];
PROG_ADDR_ADDR : prog_addr_r <= hwdata;
PROG_DATA_ADDR : prog_data_r <= hwdata;
PROG_DATA1_ADDR : prog_data1_r <= hwdata;
PROG_DATA2_ADDR : prog_data2_r <= hwdata;
PROG_DATA3_ADDR : prog_data3_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
wr_en_r <= 1'b0; //hardware reset,
prog_addr_r <= 32'h3bfff;
end
else if (flash_pe_done || boot_pe_done)
begin
pe_en_r <= 1'b0;
pe_num_r <= 9'h1df;
end
end
//----------------------------------------------------------------//
//Flash operation status and boot operation status
//flash_status_r:页擦写操作完成信号 ✔
//----------------------------------------------------------------//
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
flash_status_r[0] <= 1'b0;
else if (wr_status_valid && hwdata[0]) //software :wite operation to reset;write 1 to reset
flash_status_r[0] <= 1'b0;
else if (flash_prog_done || boot_wr_done)
flash_status_r[0] <= 1'b1; //hardware set,when to reset? -->status
end
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
flash_status_r[1] <= 1'b0;
else if (wr_status_valid && hwdata[1]) //software :wite operation to reset;write 1 to reset
flash_status_r[1] <= 1'b0;
else if (flash_pe_done || boot_pe_done)
flash_status_r[1] <= 1'b1; //hardware set,when to reset? -->status
end
//----------------------------------------------------------------//
//Flash operation status and boot operation status
//boot_pe_wr_error_r:boot区非法操作
//启动了boot区保护boot_pe_sel/boot_wr_sel确有效 ✔
always@(posedge hclk or negedge hresetn)
begin
if (!hresetn)
boot_pe_wr_error_r <= 1'b0;
else if (boot_protect_n)
boot_pe_wr_error_r <= 1'b0;
else if (wr_status_valid && (hwdata[0]||hwdata[1]))
boot_pe_wr_error_r <= 1'b0;
else if (boot_pe_sel || boot_wr_sel)
boot_pe_wr_error_r <= 1'b1;
end
endmodule
2.2 Flash 控制模块
Flash 控制模块(flash_ctrl)接收flash_ahb_slave_if的地址、数据、控制信号(写/读/页擦使能、flash0 or flash1/Main or information area select 等选择信号、时序控制信号等)。通过状flash_ctrl态机对Flash的进行操作控制,这里状态机主要通过计数,实现载满足操作所需要的时序条件下,输出相关控制信号给FLash。电路框图如下图所示,状态转换图及状态描述见2.2.2节。
2.2.1 FLash操作时序
Flash是异步工作的,本设计中Flash的操作需要满足下述时序。
下图是一些时序参数,具体操作时序图在后面
a.读操作时序
b.写操作时序:
c.页擦操作时序:
d.块擦除操作时序:
2.2.2 状态转换图及状态描述
软件置位:Master通过配置寄存器,控制状态的开始。
硬件清零:(做完由硬件控制回到IDLE状态),因为软件不知道硬件什么时候做完。而且硬件直接处理速度更快。
FLASH_IDLE:初始空闲状态,等待Flash操作,根据控制命令跳转到后续相关操作状态;
READ_ACCESS:读操作状态,等待读完成返回IDLE状态。这里读时间由配置寄存器控制,通过计数器计时,判断读是否完成;在XADDR,YADDR,XE,YE,SE配置好后等读结束;
FLASH_TNVS:在写和页擦操作之前Flash控制信号NVSTR要变为高电平,这里是在其它信号配置好后经过Tnvs使其有效。根据使写使能还是页擦使能进入相应状态。
PE_ERASE:进行页擦操作,页擦的时间为Terase。页擦后,NVSTR信号需要再保持Tnvh时间后再拉低,所以进入FLASH_TNVH状态;
FLASH_TNVH:计数保持Tnvh后,将NVSTR信号拉低。之后还需要一段recover time,于是进入FLASH_REC状态;
FLASH_REC:计数保持Trec时间后,重新回到FLASH_IDLE状态;
PROG_SETUP:program的建立时间控制,在NVSTR有效后,需要满足此建立时间,才能进行后续的操作;
ADDR_SETUP:数据和地址的建立时间控制,计数到满足地址信号的建立时间后拉高YE(yaddress enable);
PROG_PROC:写过程时间控制;
ADDR_HOLD:数据和地址的地址保持时间控制;
PROG_HOLD:写保持时间控制。
2.2.3 信号描述
Signals | I/O | Width | form | to | Declaration |
---|---|---|---|---|---|
flash_clk, | input | 1 | clock source | AHB bus clock | |
flash_rst_n | input | 1 | reset controller | AHB bus reset signal | |
prog_en | input | 1 | flash_ahb_slave_if | flash program enable | |
pe_en | input | 1 | flash_ahb_slave_if | flash page erase enable | |
read_en | input | 1 | flash_ahb_slave_if | flash read enable | |
rd_inf0_sel | input | 1 | flash_ahb_slave_if | information0 area read select | |
rd_inf1_sel | input | 1 | flash_ahb_slave_if | information1 area read select | |
rd_main0_sel | input | 1 | flash_ahb_slave_if | main0 area read select | |
rd_main1_sel | input | 1 | flash_ahb_slave_if | main1 area read select | |
flash0_rd_cs | input | 1 | flash_ahb_slave_if | flash0 read selcet | |
flash1_rd_cs | input | 1 | flash_ahb_slave_if | flash0 read selcet | |
prog_infrarea0_sel | input | 1 | flash_ahb_slave_if | information0 area program select | |
prog_infrarea1_sel | input | 1 | flash_ahb_slave_if | information1 area program select | |
prog_mainarea0_sel | input | 1 | flash_ahb_slave_if | main0 area program select | |
prog_mainarea1_sel | input | 1 | flash_ahb_slave_if | main1 area program select | |
pe_num, | input | [8:0] | flash_ahb_slave_if | page number | |
pe_main_infr_sel | input | 1 | flash_ahb_slave_if | page erase main or infromation area | |
flash_addr | input | [14:0] | flash_ahb_slave_if | flash address | |
flash_data_in | input | [31:0] | flash_ahb_slave_if | flash write data | |
flash0_rdata | input | [31:0] | flash_ahb_slave_if | flash0 read data | |
flash1_rdata | input | [31:0] | flash_ahb_slave_if | flash1 read data | |
flash_ctrl_int, | input | 1 | flash_ahb_slave_if | flash interrupt signal(op finish) | |
nvstr_set_timing | input | [11:0] | flash_ahb_slave_if | PROG/ERASE to NVSTR set up time >5us | |
nvstr_hold_timing | input | [11:0] | flash_ahb_slave_if | ||
rcv_timing | input | [7:0] | flash_ahb_slave_if | Recover time >1us | |
prog_set_timing | input | [15:0] | flash_ahb_slave_if | NVSTR to program set up time | |
prog_hold_timing | input | [3:0] | flash_ahb_slave_if | Program hold time (20~40us) | |
addr_set_timing | input | [3:0] | flash_ahb_slave_if | Adress/data set up time | |
addr_hold_timing | input | [3:0] | flash_ahb_slave_if | Adress/data hold time | |
prog_proc_timing | input | [15:0] | flash_ahb_slave_if | program time | |
addr_aces_timing | input | [7:0] | flash_ahb_slave_if | Access time of read cycle | |
page_erase_timing | input | [23:0] | flash_ahb_slave_if | page erase time >20ms | |
flash0_infr_en | output | 1 | flash0 | flash0 infromation block enable(IFREN) | |
flash0_xaddr_en | output | 1 | flash0 | falsh0 xaddress enable(XE) | |
flash0_yaddr_en | output | 1 | flash0 | falsh0 yaddress enable(YE) | |
flash0_se_en | output | 1 | flash0 | falsh0 SA enable(SE) | |
flash0_prog_en | output | 1 | flash0 | falsh0 progaram enable(PROG) | |
flash0_nvstr_en | output | 1 | flash0 | falsh0 non-volatile store cycle enable(NVSTR) | |
flash0_erase_en | output | 1 | flash0 | flash0 erase enable(ERASE) | |
flash0_mass_en | output | 1 | flash0 | flash0 mass erase enable(MAS1) | |
flash0_xaddr | output | [9:0] | flash0 | flash0 x address(XADR) | |
flash0_yaddr | output | [4:0] | flash0 | flash0 y address(YADR) | |
flash0_wdata | output | [31:0] | flash0 | flash0 write data(DIN) | |
flash1_infr_en | output | 1 | flash1 | flash1 infromation block enable(IFREN) | |
flash1_xaddr_en | output 1 | flash1 | falsh1 xaddress enable(XE) | ||
flash1_yaddr_en | output 1 | flash1 | falsh1 yaddress enable(YE) | ||
flash1_se_en | output 1 | flash1 | falsh1 SA enable(SE) | ||
flash1_prog_en | output 1 | flash1 | falsh1 progaram enable(PROG) | ||
flash1_nvstr_en | output 1 | flash1 | falsh1 non-volatile store cycle enable(NVSTR) | ||
flash1_erase_en | output 1 | flash1 | flash1 erase enable(ERASE) | ||
flash1_mass_en | output 1 | flash1 | flash1 mass erase enable(MAS1) | ||
flash1_xaddr | output [9:0] | flash1 | flash1 x address(XADR) | ||
flash1_yaddr | output [4:0] | flash1 | flash1 y address(YADR) | ||
flash1_wdata | output [31:0] | flash1 | flash1 write data(DIN) |
2.2.4 Verilog实现
module flash_ctrl.v(
//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 flash_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 flash_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_nexy;
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 = 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
hread = 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'b01;
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'1b;
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