片上系统设计思想与源代码分析
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.5 NandFlash控制器源代码分析

这是一个基本的NandFlash控制器,设计目标为硬件简化,完成基本的控制功能,而其他功能由软件完成,包括前向纠错。

4.5.1 输入输出信号

该NandFlash控制器兼容标准WISHBONE Slave接口标准和K9F2G08U0M NandFlash接口,输入输出信号如下:

module nfc_top(
//WISHBONE从设备接口
clk_i,rst_i,adr_i,dat_o,dat_i,cyc_i,stb_i,sel_i,we_i,ack_o,rty_o,err_o,
//nandflash side
nf_data_io, //NandFlash数据输入输出,8比特
nf_cen, //NandFlash片选
nf_ale, //NandFlash地址锁定使能
nf_cle, //NandFlash命令锁定使能
nf_ren, //NandFlash读使能
nf_wen, //NandFlash写使能
nf_rb); //NandFlash准备好/忙

4.5.2 寄存器定义

NandFlash中各寄存器的定义及说明如表4-4~表4-8所示。

表4-4 NandFlash命令寄存器

表4-8 NandFlash状态寄存器

表4-5 NandFlash操作地址寄存器

表4-6 NandFlash数据寄存器

表4-7 NandFlash状态寄存器

4.5.3 源代码分析

设计文件列表如表4-9所示。

表4-9 设计文件列表

nfc_defines.v定义了基本命令,具体如下

//1.command define
`define     READ_FST      8'h00
`define     READ_SEC      8'h30////wait Ttr
`define     READ_ID      8'h90
`define     RESET         8'hff
`define     PPRAM_FST     8'h80
`define     PPRAM_SEC     8'h10
`define     BERASE_FST    8'h60
`define     BERASE_SEC    8'hd0
//2.register address define
`define     NFCMD_ADR     16'h_0004
`define     NFADDR_ADR    16'h0008
`define     NFDATA_ADR    16'h000C
`define     NFSTAT_ADR    16'h0010
`define     NFENDADDR_ADR  16'h0014

nfc_top.v是对NandFlash进行操作的状态机。其源代码如下:

`include "timescale.v"
`include "nfc_defines.v"
module nfc_top(
//wishbone side
clk_i,rst_i,adr_i,dat_o,dat_i,cyc_i,stb_i,sel_i,we_i,ack_o,rty_o,err_o,
//NandFlash side
nf_data_io,nf_cen,nf_ale,nf_cle,nf_ren,nf_wen,nf_rb);
……//此处省略了输入输出信号和部分内部信号定义
assign rty_o=1'b0;
assign err_o=1'b0;
wire access=cyc_i&stb_i&(!ack_o);
wire cmd_write=(adr_i==`NFCMD_ADR)&we_i&access;
wire addr_write=(adr_i==`NFADDR_ADR)&we_i&access;
wire status_read=(adr_i==`NFSTAT_ADR)&(!we_i)&access;
wire data_read=(adr_i==`NFDATA_ADR)& (!we_i)&access;
wire data_write=(adr_i==`NFDATA_ADR)& (we_i)&access;
wire end_addr=(adr_i==`NFENDADDR_ADR)&we_i&access;
reg drive_data;
reg [7:0] data_out;
assign nf_data_io=drive_data?data_out:8'bzzzz_zzzz;
//为简化代码行数而定义的宏
`define NFSIGNAL {nf_cen,nf_cle,nf_ale,nf_ren,nf_wen}
`define NFSIGNAL_IDLE 5'b00011
`define NFSIGNAL_CMDWR  5'b01010
`define NFSIGNAL_CMDHOLD 5'b01011
`define NFSIGNAL_ADDR_IDLE 5'b00111
`define NFSIGNAL_ADDR_WR 5'b00110
`define NFSIGNAL_DATAWR 5'b00010
`define NFSIGNAL_DATARD 5'b00001
reg [3:0] wait_cnt;
reg block_erase,read_id;
reg [5:0] state;//主状态
parameter   NF_IDLE=1,NF_CMD=2,NF_CMD_HOLD=3,NF_WAIT_ADDR=4,NF_ADDR1=5,NF_ADDR2=6,
            NF_ADDR3=7, NF_ADDR4=8, NF_ADDR5=9, NF_ADDR6=10, NF_ADDR7=11, NF_ADDR8=12,
            NF_ADDR9=13, NF_ADDR10=14,NF_END_ADDR=15, NF_STATUS=16,NF_WRITE_DATA1=17,
            NF_WRITE_DATA2=18,NF_WRITE_DATA3=19,NF_WRITE_DATA4=20, NF_WRITE_DATA5=21,
NF_WRITE_DATA6=22,NF_WRITE_DATA7=23,NF_WRITE_DATA8=24,NF_READ_DATA1=25,
NF_READ_DATA2=26,NF_READ_DATA3=27,NF_READ_DATA4=28,NF_READ_DATA5=29,
NF_READ_DATA6=30,NF_READ_DATA7=31,NF_READ_DATA8=32,NF_TWR=33;always @(posedge clk_i or
posedge rst) begin
    if(rst) begin      state<=NF_IDLE;data_out<=8'b0; drive_data<=1'b0;
      `NFSIGNAL<=`NFSIGNAL_IDLE;
      wait_cnt<=0; ack_o<=0; length<=0; fast_mode<=0;
      {block_erase,read_id}<=2'b00;
    end
    else begin
      case(state)
        NF_IDLE:begin
{nf_cen,nf_cle,nf_ren,nf_wen}<=4'b0011;
//NandFlash的工作速度较慢,插入等待周期
wait_cnt<=2; drive_data<=1'b0;
//根据不同的命令产生不同的状态。
            if(cmd_write & (nf_rb)) begin
                state<=NF_CMD;
            end
            else if(addr_write &(nf_rb)) begin  state<=NF_WAIT_ADDR; end
            else if(end_addr &(nf_rb)) begin  state<=NF_END_ADDR; end
            else if(data_write &(nf_rb)) begin  state<=NF_WRITE_DATA1;  end
            else if(data_read&(nf_rb)) begin state<=NF_READ_DATA1; end
            else if (status_read&(nf_rb)) begin state<=NF_STATUS; end
          //对于来自主设备的错误请求,给出ack应答,避免造成总线死锁,给出err应答在一些场合更恰当。
            else if(access) begin ack_o<=1'b1; end
            else ack_o<=1'b0;
        end
        NF_CMD:begin           `NFSIGNAL<=`NFSIGNAL_CMDWR;
            drive_data<=1'b1;  data_out<=dat_i[7:0];
fast_mode<=dat_i[8];//在该模式下,主设备可一次写入32位的地址
            if(wait_cnt==0) begin  wait_cnt<=2; state<=NF_CMD_HOLD;  end
            else begin  wait_cnt<=wait_cnt-1; end
        end
        NF_CMD_HOLD: begin
            `NFSIGNAL<=`NFSIGNAL_CMDHOLD;
            if(wait_cnt==0) begin wait_cnt<=2; state<=NF_IDLE;
              ack_o<=1; drive_data<=1'b0;
            end
            else begin wait_cnt<=wait_cnt-1; end
          end
          NF_WAIT_ADDR: begin
            `NFSIGNAL<=`NFSIGNAL_ADDR_IDLE;
            if(wait_cnt==0) begin wait_cnt<=2; state<=NF_ADDR1; drive_data<=1'b0; end
            else begin wait_cnt<=wait_cnt-1; end
          end
          NF_ADDR1:begin //写入地址的最低8位,即列地址1
           `NFSIGNAL<=`NFSIGNAL_ADDR_WR;
           drive_data<=1'b1;  data_out<=dat_i[7:0];
           if(wait_cnt==0) begin wait_cnt<=2; state<=NF_ADDR2;  end
           else begin wait_cnt<=wait_cnt-1; end
          end
          NF_ADDR2:begin //相邻写操作之间的空闲
           `NFSIGNAL<=`NFSIGNAL_ADDR_IDLE;
            if(wait_cnt==0) begin wait_cnt<=2;
//在快速模式下,连续分5次将地址写入NandFlash。
if(fast_mode) state<=NF_ADDR3;
else begin state<=NF_IDLE;ack_o<=1'b1;end  end
            else begin wait_cnt<=wait_cnt-1; end
          end
          NF_ADDR3:begin
            `NFSIGNAL<=`NFSIGNAL_ADDR_WR;
            drive_data<=1'b1; data_out<={4'b0,dat_i[11:8]};
             if(wait_cnt==0) begin
                wait_cnt<=2;  state<=NF_ADDR4;
             end
             else begin  wait_cnt<=wait_cnt-1; end
          end
          NF_ADDR4:begin … end//写入列地址2
          NF_ADDR5:begin … end//相邻地址操作之间的空闲
          NF_ADDR6:begin … end//写入行地址1
          NF_ADDR7:begin … end//相邻地址操作之间的空闲
          NF_ADDR8:begin … end//写入行地址2
          NF_ADDR9:begin … end//相邻地址操作之间的空闲
          NF_ADDR10:begin//写入行地址3
            `NFSIGNAL<=`NFSIGNAL_ADDR_IDLE;
             if(wait_cnt==0) begin
  wait_cnt<=2; ack_o<=1'b0; state<=NF_END_ADDR;
            end
             else begin  wait_cnt<=wait_cnt-1; end
          end
          NF_END_ADDR:begin//地址写为完成
             `NFSIGNAL<=`NFSIGNAL_IDLE; state<=NF_IDLE;
             ack_o<=1; drive_data<=1'b0; wait_cnt<=2;
          end
          NF_WRITE_DATA8:begin第4次数据写之后的空闲,回到NF_IDLE状态
              `NFSIGNAL<=`NFSIGNAL_IDLE; drive_data<=1'b1;
              if(wait_cnt==0) begin
                wait_cnt<=2; state<=NF_IDLE; ack_o<=1'b1;
              end
              else begin wait_cnt<=wait_cnt-1; end
           end
           NF_READ_DATA1:begin //第一次读数据
              `NFSIGNAL<=`NFSIGNAL_DATARD; drive_data<=1'b0;
              if(wait_cnt==0) begin
                wait_cnt<=2; state<=NF_READ_DATA2; dat_o<={24'b0,nf_data_io};
  end
              else begin wait_cnt<=wait_cnt-1; end
           end
           NF_READ_DATA2:begin //相邻读数据之间的空隙
              `NFSIGNAL<=`NFSIGNAL_IDLE;
              if(wait_cnt==0) begin
                wait_cnt<=2;
                if(fast_mode) state<=NF_READ_DATA3;
                else begin state<=NF_IDLE; ack_o<=1'b1; end
              end
              else begin wait_cnt<=wait_cnt-1; end
           end
            NF_READ_DATA3:begin……end //第2、3、4次数据读
            ……//
          NF_TWR:begin //等待周期
              `NFSIGNAL<=`NFSIGNAL_IDLE; ack_o<=0;
              if(wait_cnt==0) begin  wait_cnt<=2; state<=NF_IDLE; end
              else begin wait_cnt<=wait_cnt-1; end
              end
          NF_WRITE_DATA1:begin //第一次写入数据
              `NFSIGNAL<=`NFSIGNAL_DATAWR;
            drive_data<=1'b1; data_out<=dat_i[7:0];
              if(wait_cnt==0) begin
                wait_cnt<=2; state<=NF_WRITE_DATA2;
              end
              else begin wait_cnt<=wait_cnt-1; end
          end
          NF_WRITE_DATA2:begin //写数据完成后的空闲
            `NFSIGNAL<=`NFSIGNAL_IDLE; drive_data<=1'b1;
              if(wait_cnt==0) begin
                wait_cnt<=2; //快速模式下主机写1次,状态机写NandFlash 4 次
                if(fast_mode) state<= NF_WRITE_DATA3;
                else begin state<=NF_IDLE; ack_o<=1'b1; end
              end
              else begin wait_cnt<=wait_cnt-1; end
          end
         NF_WRITE_DATA3:begin…end //第2、3、4次数据写
         ……//
            NF_READ_DATA8:begin //第4次数据读之后的空闲
              `NFSIGNAL<=`NFSIGNAL_IDLE;
              if(wait_cnt==0) begin
                wait_cnt<=2; state<=NF_IDLE; ack_o<=1'b1;
              end
              else begin wait_cnt<=wait_cnt-1; end
           end
           NF——STATUS:begin //读状态
              dat_o<={1'b0,nf_cen,nf_cle,nf_ale,nf_ren,nf_wen,nf_rb};ack_o<=1'b1;
              state<=NF_IDLE;
           end
           default: begin state<=NF_IDLE; end
        endcase
      end
    end
    endmodule