⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nand_flash_ctl.v

📁 nand flash control logic
💻 V
📖 第 1 页 / 共 2 页
字号:
/*
clk is 125~250MHz
operation:
0~128KB is used as eprom for MCU, space greater than 128K is functioned 
  as a ATA PIO disk
1 read blk0:  when a new efm_r cmd is issued, if efm_addr[31:17] is "0",
  state machine will handle read sequence (read cmd, read data from buffer,
  buffer is 512 bytes, so if addr[16:9] "hit" bufferred (cache_adr), get data
  from buffer, otherwise from nand, then change cache_adr.

  blk0 give mcu initial 128KB code, then all other blocks will be accessed 
  (read and write) by mcu as below (similar as ATA PIO operation)
2. mcu w: fff5_0000, written data is cmd (data[7:0]), cle
       w: fff5_0004, addr (data[7:0]), ale
       w/r: fff5_0008, data (data[31:0]), no ale, no cle
       w: fff5_0010 [3:0]cmd pulse width
       r: fff5_0014 status (ecc and busy)
3. program: mcu w 512B into fff5_1000~fff5_11ff, the last write start program
   operation on NAND

port_adr map:

key factors:
blk0 can min write 1k times.
it contains 
 basic code which normally is not changed, and also include
 blk_map address, this address is also not changed normally, until that block 
 is written failed.
 by this way, the number of write on blk0 is minimized

1. each flash chip is logic block (64*512B) mapped physical blocks
   the 64 page in a block has a valid bit: 0: not written, 1 written
2. 3.125% (512 blocks) are assigned as spare blocks

flash read flow:
^^^^^^^^^^^^
error management
   move flash block
3. nand mechanism **********
2007-10-19 since eprom may have max 4MB space, it need 32 nand blocks (128K each)
while only block zero is guaranteed to be good, we use blk0 as a mapping table between a logic block and a physical block
operation steps:
3.1 use external board (e.g. a 8051 board) to establish a logic mapping table on block0, and program mcu codes etc to those
  good blocks.
3.2 put (soldering of use socket) nand on merced board
3.3 power-on, p0_flash has a state machine (init_sm) and a map ram (32*8),  which will read  block0 into map and cfg
3.4 convert normal efm cycles to coresponding nand cycles
3.5 mcu use the 4MB code to load 4M~1G space to ddr, then enable shadow, after that, mcu excute code from ddr.
3.6 reprogram: new code in ddr, mcu use software engine to program nand.
3.7 repeated power-on by step 3.3~3.6
*/     
`timescale 100ps/100ps
module p0_flash (
	clk,reset,
	in_efm_r,in_efm_w,data1efm,efm_addr,data2efm,efm_ack,
	mcu_r,mcu_w,mcu_adr,mcu_di,mcu_do,mcu_ack,
	ale, cle,re_,we_,
	data0, t_data,
	rb_, ce0_,ce1_,out_en,f_en
);
input clk,reset;
input in_efm_r,in_efm_w;
output efm_ack;
input [31:0] data1efm;
input [31:2] efm_addr;
output [31:0] data2efm;
input mcu_r,mcu_w; //mcu_if
output mcu_ack;
input [31:2] mcu_adr;
input [31:0] mcu_do;
output [31:0] mcu_di;
output ale; //flash group1 ------- pins: 41 per group
output cle,re_,we_;
input rb_; //rdy/busy_: may tie two together
output ce0_,ce1_,out_en,f_en;
input [7:0] data0;
output [7:0] t_data;
wire i_reset = reset;
wire req_len = 'h80; //dword
wire [7:0] ecc_data0,ecc_data1,ecc_data2,ecc_data3;
reg bf2ddr; //after read flash to bf, copy bf to ddr
wire ecc_done;
wire [7:0] data0_o,data0t;
reg w_cmd,q_w_cmd,r_cmd;
reg [3:0] q_cmd_width,pulse_cnt; 
reg [8:0] f_adr,d_f_adr;//512 adr
wire [9:0] ram_adr0,q_ram_adr;//q_ram_adr is common
wire end_w_cmd = !w_cmd & q_w_cmd;
reg [3:0] q_ctl_st,d_ctl_st;
always @(posedge clk or posedge reset)
    if (reset) q_cmd_width <=3;
    else if (mcu_w & {mcu_adr,2'b0}=='hfff5_0010) q_cmd_width <= mcu_do[3:0];
wire [3:0] cmd_width = (q_ctl_st==14)? q_cmd_width : q_cmd_width+4;
reg [31:0]  data2efm,d_data2efm;
reg efm_ack,d_efm_ack;
always @(posedge clk) efm_ack<=d_efm_ack;
always @(posedge clk) data2efm<=d_data2efm;

reg [7:0] d_data;
reg [2:0] q_mctl_st,d_mctl_st;
always @(posedge clk or posedge reset)
    if (reset) q_mctl_st<=0;
    else q_mctl_st<=d_mctl_st;   //tzt:  for mcu_w

always @(posedge clk or posedge reset)
    if (reset) w_cmd <=0; 
    else if (pulse_cnt==cmd_width) begin
       if (w_cmd)  w_cmd <=0;
       else if (q_mctl_st==1 | q_mctl_st==2 | q_mctl_st==3 |
//       else if (mcu_w & {mcu_adr,2'b0}=='hfff5_0008 |
	     q_ctl_st==1 | q_ctl_st==8 | q_ctl_st==9 | q_ctl_st==10 |
	     q_ctl_st==11 | q_ctl_st==12 | q_ctl_st==13 
	    ) w_cmd <=1; 
    end
always @(posedge clk or posedge reset)
    if (reset) q_w_cmd<=0;
    else if (w_cmd) q_w_cmd<=1; 
    else if (w_cmd==0) q_w_cmd <=0;
/*
 0: idle
 1: issue mcu cmd
 2: issue mcu adr
 3: mcu_wt_nand
 4: mcu_rd_nand
*/
always @(q_mctl_st or mcu_r or mcu_w or mcu_adr or mcu_do or pulse_cnt or cmd_width) begin
    d_mctl_st=q_mctl_st;
    case (q_mctl_st)
    0: if (mcu_adr[31:4]=='hfff5_000) begin
         d_data<=mcu_do[7:0];
	if (mcu_w)
	 case (mcu_adr[3:2])
	 0:	d_mctl_st=1; //issue cle
	 1:	d_mctl_st=2; //issue ale
	 2:	d_mctl_st=3; //wt data 
	 default:	d_mctl_st=0; //spare
         endcase
	// if (mcu_r & mcu_adr[3:2]==2'b10) d_mctl_st=4;
       end
    1: begin         //issue cle
//         if (pulse_cnt==cmd_width) d_mctl_st=0;
	 if (end_w_cmd) d_mctl_st=0;
       end
    2: begin         //issue ale
//         if (pulse_cnt==cmd_width) d_mctl_st=0;
	if (end_w_cmd) d_mctl_st=0;
       end
    3: begin         //issue wt_data
//         if (pulse_cnt==cmd_width) d_mctl_st=0;
	if (end_w_cmd) d_mctl_st=0;
       end
    4: begin         //read data
       end
    endcase
end
//wire end_512B=ram_adr0[8:0]=='h1ff;
wire end_512B=ram_adr0[9:0]=='h20f;
reg q_end_512B;
reg [1:0] bf_h; //bf_h sel 4*512B blocks 
always @(posedge clk or posedge reset)
    if (reset) q_end_512B<=0;
    else if (ecc_done) q_end_512B<=0;
    else if (end_512B) q_end_512B<=1;
/*
 0: idle, 
 1: rd efm, linefill 512B from nand
 2: efm rd within 512B
 3: pio rd, linefill 512B from nand
 4: pio wt, write to nand 
 5,6,7: spare
 8: issue 1st adr
 9: issue 2nd adr
 10: issue 3rd adr
 11: issue 4th adr
 12: issue 5th adr
 13: issue 2nd cmd "30"
 14,15: spare
*/
reg [7:0] blk0_quarter_page_num;
reg quarter_page_vld;
always @(posedge clk or posedge reset)
   if (reset) quarter_page_vld<=0;
   else if (q_ctl_st==15 & ecc_done) quarter_page_vld<=1;
/*
always @(posedge clk or posedge reset)
   if (reset) blk0_quarter_page_num<=0; //bf is 512B, need 0.25 page num
   else if (q_ctl_st==15 & ecc_done) blk0_quarter_page_num<=efm_addr[17:10]; 
wire quarter_hit = quarter_page_vld & efm_addr[17:10]==blk0_quarter_page_num;
wire page_hit = quarter_page_vld & efm_addr[17:12]==blk0_quarter_page_num[7:2];
wire [1:0] page_quarter=efm_addr[11:10];
*/
always @(posedge clk or posedge reset)
   if (reset) blk0_quarter_page_num<=0; //bf is 512B, need 0.25 page num
   else if (q_ctl_st==15 & ecc_done) blk0_quarter_page_num<={efm_addr[18:17],efm_addr[14:9]}; 
   else if (q_mctl_st!=0) blk0_quarter_page_num<=8'h1;  //tzt: 
wire quarter_hit = quarter_page_vld & {efm_addr[18:17],efm_addr[14:9]}==blk0_quarter_page_num;
wire page_hit = quarter_page_vld & {efm_addr[18:17],efm_addr[14:11]}==blk0_quarter_page_num[7:2];
wire [1:0] page_quarter=efm_addr[10:9];
wire pulse_change = pulse_cnt==cmd_width;
reg [7:0] cmd_adr,d_cmd_adr;
reg sel_cmd, h2f;
always @(posedge clk) cmd_adr<=d_cmd_adr;
always @(posedge clk or posedge reset)
    if (reset) q_ctl_st<=0;
    else  q_ctl_st<=d_ctl_st;
reg [1:0] access_cnt;
wire [1:0] page_quarter_plus1 = page_quarter+1;
always @(posedge clk or posedge reset)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -