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 顶层接口信号描述:

SignalsI/OWidthformtoDeclaration
hclkinput1clock 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_int,output1Flashfalsh 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)

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 信号描述

SignalsI/OWidthformtoDeclaration
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_ctrlflash is busy
eflash_wp_n,input1Masterefalsh write protect enable
addr_offsetinput [4:0]Masterboot area address offset
boot_eninput1Masterboot area enable
hready_flaginput1flash_ctrlslave has finished transfer,transfer to hready_out
hready_outoutput1Masterthis slave to BUS siganl
hrespoutput[1:0]MasterOK 、ERROR、SPLIT、RETRY
hrdataoutput[31:0]Masterflash read data or register value
flash_prog_enoutput1flash_ctrlflash program enable
flash_pe_enoutput1flash_ctrlflash page erase enable
flash_rd_enoutput1flash_ctrlflash read enable
rd_inf0_seloutput1flash_ctrlinformation0 area read select
rd_inf1_seloutput1flash_ctrlinformation1 area read select
rd_main0_seloutput1flash_ctrlmain0 area read select
rd_main1_seloutput1flash_ctrlmain1 area read select
flash0_rd_csoutput1flash_ctrlflash0 read selcet
flash1_rd_csoutput1flash_ctrlflash0 read selcet
prog_infrarea0_seloutput1flash_ctrlinformation0 area program select
prog_infrarea1_seloutput1flash_ctrlinformation1 area program select
prog_mainarea0_seloutput1flash_ctrlmain0 area program select
prog_mainarea1_seloutput1flash_ctrlmain1 area program select
pe_num,output[8:0]flash_ctrlpage number
pe_main_infr_seloutput1flash_ctrlpage erase main or infromation area
flash_addr_out,output[14:0]flash_ctrlflash address
flash_wdata,output[31:0]flash_ctrlflash write data
flash_ctrl_int,output1flash_ctrlflash interrupt enable
t_nvstr_setupoutput[11:0]flash_ctrlPROG/ERASE to NVSTR set up time >5us
t_nvstr_holdoutput[11:0]flash_ctrlNVSTR hold time >5us
t_rcvoutput[7:0]flash_ctrlRecover time >1us
t_prog_setupoutput[15:0]flash_ctrlNVSTR to program set up time
t_prog_holdoutput[3:0]flash_ctrlProgram hold time (20~40us)
t_addr_setupoutput[3:0]flash_ctrlAdress/data set up time
t_addr_holdoutput[3:0]flash_ctrlAdress/data hold time
t_prog_procoutput[15:0]flash_ctrlprogram time
t_addr_acesoutput[7:0]flash_ctrlAccess time of read cycle
t_page_eraseoutput[23:0]flash_ctrlpage erase time >20ms

2.1.2 寄存器地址及功能描述

base address :0x0006_0000

timing相关寄存器的复位初始值按悲观情况120MHz计算(正常在100MHz),保证默认情况下的flash读写操作可以正常进行。

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每次写操作完成的时间
rd_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 操作出错标记寄存器

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 信号描述

SignalsI/OWidthformtoDeclaration
flash_clk,input1clock 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_enoutput1flash0falsh0 xaddress enable(XE)
flash0_yaddr_enoutput1flash0falsh0 yaddress enable(YE)
flash0_se_enoutput1flash0falsh0 SA enable(SE)
flash0_prog_enoutput1flash0falsh0 progaram enable(PROG)
flash0_nvstr_enoutput1flash0falsh0 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_enoutput 1flash1falsh1 xaddress enable(XE)
flash1_yaddr_enoutput 1flash1falsh1 yaddress enable(YE)
flash1_se_enoutput 1flash1falsh1 SA enable(SE)
flash1_prog_enoutput 1flash1falsh1 progaram enable(PROG)
flash1_nvstr_enoutput 1flash1falsh1 non-volatile store cycle enable(NVSTR)
flash1_erase_enoutput 1flash1flash1 erase enable(ERASE)
flash1_mass_enoutput 1flash1flash1 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)

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

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值