OpenCores
URL https://opencores.org/ocsvn/nand_controller/nand_controller/trunk

Subversion Repositories nand_controller

Compare Revisions

  • This comparison shows the changes necessary to convert path
    /nand_controller/trunk
    from Rev 8 to Rev 9
    Reverse comparison

Rev 8 → Rev 9

/VHDL/nand_stuff.vhd File deleted \ No newline at end of file
/VHDL/nand_ctrl.vhd File deleted \ No newline at end of file
/VHDL/nand_interface.vhd File deleted \ No newline at end of file
/VHDL/io_unit.vhd
0,0 → 1,95
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
-- Title : ONFI compliant NAND interface
-- File : io_unit.vhd
-- Author : Alexey Lyashko <pradd@opencores.org>
-- License : LGPL
-------------------------------------------------------------------------------------------------
-- Description:
-- This file implements data IO unit of the controller.
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
 
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.onfi.all;
 
entity io_unit is
generic (io_type : io_t);
port
(
clk : in std_logic;
activate : in std_logic;
data_in : in std_logic_vector(15 downto 0);
io_ctrl : out std_logic := '1';
data_out : out std_logic_vector(15 downto 0);
busy : out std_logic
);
end io_unit;
 
 
 
architecture action of io_unit is
type io_state_t is (IO_IDLE, IO_HOLD, IO_DELAY);
signal state : io_state_t := IO_IDLE;
signal n_state : io_state_t := IO_IDLE;
signal delay : integer := 0;
signal data_reg : std_logic_vector(15 downto 0);
begin
 
busy <= '1' when state /= IO_IDLE else
'0';
data_out <= data_reg when (io_type = IO_WRITE and state /= IO_IDLE) or
io_type = IO_READ else
x"0000";
io_ctrl <= '0' when state = IO_DELAY and n_state = IO_HOLD else
'1';
 
IO: process(clk, activate)
begin
if(rising_edge(clk))then
case state is
when IO_IDLE =>
if(io_type = IO_WRITE)then
data_reg <= data_in;
end if;
if(activate = '1')then
if(io_type = IO_WRITE)then
delay <= t_wp;
else
delay <= t_rea;
end if;
n_state <= IO_HOLD;
state <= IO_DELAY;
end if;
when IO_HOLD =>
if(io_type = IO_WRITE)then
delay <= t_wh;
else
delay <= t_reh;
end if;
n_state <= IO_IDLE;
state <= IO_DELAY;
when IO_DELAY =>
if(delay > 1)then
delay <= delay - 1;
else
if(io_type = IO_READ and n_state = IO_IDLE)then
data_reg <= data_in; -- This thing needs to be checked with read hardware. Assignment may be needed somewhat earlier.
end if;
state <= n_state;
end if;
when others =>
state <= IO_IDLE;
end case;
end if;
end process;
end action;
/VHDL/onfi_package.vhd
0,0 → 1,104
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
-- Title : ONFI compliant NAND interface
-- File : onfi_package.vhd
-- Author : Alexey Lyashko <pradd@opencores.org>
-- License : LGPL
-------------------------------------------------------------------------------------------------
-- Description:
-- This file contains clock cycle duration definition, delay timing constants as well as
-- definition of FSM states and types used in the module.
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
 
library ieee;
use ieee.std_logic_1164.all;
 
package onfi is
-- Clock cycle length in ns
-- IMPORTANT!!! The 'clock_cycle' is configured for 400MHz, change it appropriately!
constant clock_cycle : real := 2.5;
 
-- NAND interface delays.
-- Delays of 7.5ns may need to be fixed to 7.0.
constant t_cls : integer := integer(10.0 / clock_cycle);
constant t_clh : integer := integer(5.0 / clock_cycle);
constant t_wp : integer := integer(10.0 / clock_cycle);
constant t_wh : integer := integer(7.5 / clock_cycle);
constant t_wc : integer := integer(20.0 / clock_cycle);
constant t_ds : integer := integer(7.5 / clock_cycle);
constant t_dh : integer := integer(5.0 / clock_cycle);
constant t_als : integer := integer(10.0 / clock_cycle);
constant t_alh : integer := integer(5.0 / clock_cycle);
constant t_rr : integer := integer(20.0 / clock_cycle);
constant t_rea : integer := integer(16.0 / clock_cycle);
constant t_rp : integer := integer(10.0 / clock_cycle);
constant t_reh : integer := integer(7.5 / clock_cycle);
constant t_wb : integer := integer(100.0 / clock_cycle);
constant t_rst : integer := integer(5000.0 / clock_cycle);
constant t_bers : integer := integer(700000.0 / clock_cycle);
constant t_whr : integer := integer(80.0 / clock_cycle);
constant t_prog : integer := integer(600000000.0 / clock_cycle);
constant t_adl : integer := integer(70.0 / clock_cycle);
type latch_t is (LATCH_CMD, LATCH_ADDR);
type io_t is (IO_READ, IO_WRITE);
type master_state_t is
(
M_IDLE, -- NAND Master is in idle state - awaits commands.
M_RESET, -- NAND Master is being reset.
M_WAIT, -- NAND Master waits for current operation to complete.
M_DELAY, -- Execute timed delay.
M_NAND_RESET, -- NAND Master executes NAND 'reset' command.
M_NAND_READ_PARAM_PAGE, -- Read ONFI parameter page.
M_NAND_READ_ID, -- Read the JEDEC ID of the chip.
M_NAND_BLOCK_ERASE, -- Erase block specified by address in current_address.
M_NAND_READ_STATUS, -- Read status byte.
M_NAND_READ, -- Reads page into the buffer.
M_NAND_READ_8,
M_NAND_READ_16,
M_NAND_PAGE_PROGRAM, -- Program one page.
-- interface commands
MI_GET_STATUS, -- Returns the status byte.
MI_CHIP_ENABLE, -- Sets CE# to 0.
MI_CHIP_DISABLE, -- Sets CE# to 1.
MI_WRITE_PROTECT, -- Sets WP# to 0.
MI_WRITE_ENABLE, -- Sets WP# to 1.
MI_RESET_INDEX, -- Resets page_idx (used as indes into arrays) to 0.
-- The following states depend on 'page_idx' pointer. If its value goes beyond the limits
-- of the array, it is then reset to 0.
MI_GET_ID_BYTE, -- Gets chip_id(page_idx) byte.
MI_GET_PARAM_PAGE_BYTE, -- Gets page_param(page_idx) byte.
MI_GET_DATA_PAGE_BYTE, -- Gets page_data(page_idx) byte.
MI_SET_DATA_PAGE_BYTE, -- Sets value at page_data(page_idx).
MI_GET_CURRENT_ADDRESS_BYTE, -- Gets current_address(page_idx) byte.
MI_SET_CURRENT_ADDRESS_BYTE -- Sets value at current_address(page_idx).
);
type master_substate_t is
(
MS_BEGIN,
MS_SUBMIT_COMMAND,
MS_SUBMIT_COMMAND1,
MS_SUBMIT_ADDRESS,
MS_WRITE_DATA0,
MS_WRITE_DATA1,
MS_WRITE_DATA2,
MS_WRITE_DATA3,
MS_READ_DATA0,
MS_READ_DATA1,
MS_READ_DATA2,
MS_DELAY,
MS_WAIT,
MS_END
);
type page_t is array (0 to 8628) of std_logic_vector(7 downto 0);
type param_page_t is array (0 to 255) of std_logic_vector(7 downto 0);
type nand_id_t is array (0 to 4) of std_logic_vector(7 downto 0);
type nand_address_t is array (0 to 4) of std_logic_vector(7 downto 0);
type states_t is array (0 to 255) of master_state_t;
constant max_page_idx : integer := 8626;
end onfi;
/VHDL/latch_unit.vhd
0,0 → 1,104
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
-- Title : ONFI compliant NAND interface
-- File : latch_unit.vhd
-- Author : Alexey Lyashko <pradd@opencores.org>
-- License : LGPL
-------------------------------------------------------------------------------------------------
-- Description:
-- This file implements command/address latch component of the NAND controller, which takes
-- care of dispatching commands to a NAND chip.
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
 
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.onfi.all;
 
 
entity latch_unit is
generic (latch_type : latch_t);
port
(
clk : in std_logic;
activate : in std_logic;
data_in : in std_logic_vector(15 downto 0);
latch_ctrl : out std_logic := '0';
write_enable : out std_logic := '1';
busy : out std_logic := '0';
data_out : out std_logic_vector(15 downto 0)
);
 
end latch_unit;
 
 
architecture action of latch_unit is
type latch_state_t is (LATCH_IDLE, LATCH_HOLD, LATCH_WAIT, LATCH_DELAY);
signal state : latch_state_t := LATCH_IDLE;
signal n_state : latch_state_t := LATCH_IDLE;
signal delay : integer := 0;
begin
 
busy <= '1' when state /= LATCH_IDLE else '0';
latch_ctrl <= '1' when state = LATCH_HOLD or
(state = LATCH_DELAY and
(n_state = LATCH_HOLD or
n_state = LATCH_WAIT)) else
'0';
write_enable <= '0' when (state = LATCH_DELAY and n_state = LATCH_HOLD) else
'1' when state /= LATCH_IDLE else
'H';
data_out <= data_in when (state /= LATCH_IDLE and state /= LATCH_WAIT and n_state /= LATCH_IDLE) else
"LLLLLLLLLLLLLLLL";
 
LATCH:process(clk, activate)
begin
if(rising_edge(clk))then
case state is
when LATCH_IDLE =>
if(activate = '1')then
n_state <= LATCH_HOLD;
state <= LATCH_DELAY;
delay <= t_wp;
end if;
when LATCH_HOLD =>
if(latch_type = LATCH_CMD)then
delay <= t_clh;
else
delay <= t_wh;
end if;
n_state <= LATCH_WAIT;
state <= LATCH_DELAY;
when LATCH_WAIT =>
if(latch_type = LATCH_CMD)then
-- Delay has been commented out. It is component's responsibility to
-- execute proper delay on command submission.
-- state <= LATCH_DELAY;
state <= LATCH_IDLE;
n_state <= LATCH_IDLE;
-- delay <= t_wb;
else
state <= LATCH_IDLE;
end if;
when LATCH_DELAY =>
if(delay > 1)then
delay <= delay - 1;
else
state <= n_state;
end if;
when others =>
state <= LATCH_IDLE;
end case;
end if;
end process;
end action;
/VHDL/nand_master.vhd
0,0 → 1,758
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
-- Title : ONFI compliant NAND interface
-- File : nand_master.vhd
-- Author : Alexey Lyashko <pradd@opencores.org>
-- License : LGPL
-------------------------------------------------------------------------------------------------
-- Description:
-- The nand_master entity is the topmost entity of this ONFi (Open NAND Flash interface <http://www.onfi.org>)
-- compliant NAND flash controller. It provides very simple interface and short and easy to use
-- set of commands.
-- It is important to mention, that the controller takes care of delays and proper NAND command
-- sequences. See documentation for further details.
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
 
 
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use work.onfi.all;
 
entity nand_master is
port
(
-- System clock
clk : in std_logic;
-- NAND chip control hardware interface. These signals should be bound to physical pins.
nand_cle : out std_logic := '0';
nand_ale : out std_logic := '0';
nand_nwe : out std_logic := '1';
nand_nwp : out std_logic := '0';
nand_nce : out std_logic := '1';
nand_nre : out std_logic := '1';
nand_rnb : in std_logic;
-- NAND chip data hardware interface. These signals should be boiund to physical pins.
nand_data : inout std_logic_vector(15 downto 0);
-- Component interface
nreset : in std_logic;
data_out : out std_logic_vector(7 downto 0);
data_in : in std_logic_vector(7 downto 0);
busy : out std_logic := '0';
activate : in std_logic;
cmd_in : in std_logic_vector(7 downto 0)
);
end nand_master;
 
-- Structural architecture of the NAND_MASTER component.
architecture struct of nand_master is
-- Latch Unit.
-- This component implements NAND's address and command latch interfaces.
component latch_unit
generic(latch_type : latch_t);
port(
activate,
clk : in std_logic;
data_in : in std_logic_vector(15 downto 0);
latch_ctrl,
write_enable,
busy : out std_logic;
data_out : out std_logic_vector(15 downto 0)
);
end component;
-- Latch unit related signals
signal cle_activate : std_logic;
signal cle_latch_ctrl : std_logic;
signal cle_write_enable : std_logic;
signal cle_busy : std_logic;
signal cle_data_in : std_logic_vector(15 downto 0);
signal cle_data_out : std_logic_vector(15 downto 0);
signal ale_activate : std_logic;
signal ale_latch_ctrl : std_logic;
signal ale_write_enable : std_logic;
signal ale_busy : std_logic;
signal ale_data_in : std_logic_vector(15 downto 0);
signal ale_data_out : std_logic_vector(15 downto 0);
 
-- IO Unit.
-- This component implements NAND's read/write interfaces.
component io_unit
generic (io_type : io_t);
port(
activate,
clk : in std_logic;
data_in : in std_logic_vector(15 downto 0);
io_ctrl,
busy : out std_logic;
data_out : out std_logic_vector(15 downto 0)
);
end component;
-- IO Unit related signals
signal io_rd_activate : std_logic;
signal io_rd_io_ctrl : std_logic;
signal io_rd_busy : std_logic;
signal io_rd_data_in : std_logic_vector(15 downto 0);
signal io_rd_data_out : std_logic_vector(15 downto 0);
signal io_wr_activate : std_logic;
signal io_wr_io_ctrl : std_logic;
signal io_wr_busy : std_logic;
signal io_wr_data_in : std_logic_vector(15 downto 0);
signal io_wr_data_out : std_logic_vector(15 downto 0);
-- FSM
signal state : master_state_t := M_RESET;
signal n_state : master_state_t := M_RESET;
signal substate : master_substate_t := MS_BEGIN;
signal n_substate : master_substate_t := MS_BEGIN;
signal delay : integer := 0;
signal byte_count : integer := 0;
signal page_idx : integer := 0;
signal page_data : page_t;
signal page_param : param_page_t;
signal chip_id : nand_id_t;
signal current_address : nand_address_t;
signal data_bytes_per_page : integer;
signal oob_bytes_per_page : integer;
signal addr_cycles : integer;
signal state_switch : states_t :=
(
0 => M_RESET,
1 => M_NAND_RESET,
2 => M_NAND_READ_PARAM_PAGE,
3 => M_NAND_READ_ID,
4 => M_NAND_BLOCK_ERASE,
5 => M_NAND_READ_STATUS,
6 => M_NAND_READ,
7 => M_NAND_PAGE_PROGRAM,
8 => MI_GET_STATUS,
9 => MI_CHIP_ENABLE,
10 => MI_CHIP_DISABLE,
11 => MI_WRITE_PROTECT,
12 => MI_WRITE_ENABLE,
13 => MI_RESET_INDEX,
14 => MI_GET_ID_BYTE,
15 => MI_GET_PARAM_PAGE_BYTE,
16 => MI_GET_DATA_PAGE_BYTE,
17 => MI_SET_DATA_PAGE_BYTE,
18 => MI_GET_CURRENT_ADDRESS_BYTE,
19 => MI_SET_CURRENT_ADDRESS_BYTE,
others => M_IDLE
);
-- The following is a sort of a status register. Bit set to 1 means TRUE, bit set to 0 means FALSE:
-- 0 - is ONFI compliant
-- 1 - bus width (0 - x8 / 1 - x16)
-- 2 - is chip enabled
-- 3 - is chip write protected
-- 4 - array pointer out of bounds
-- 5 -
-- 6 -
-- 7 -
signal status : std_logic_vector(7 downto 0) := x"00";
begin
 
-- Asynchronous command latch interface.
ACL: latch_unit
generic map (latch_type => LATCH_CMD)
port map
(
activate => cle_activate,
latch_ctrl => cle_latch_ctrl,
write_enable => cle_write_enable,
busy => cle_busy,
clk => clk,
data_in => cle_data_in,
data_out => cle_data_out
);
-- Asynchronous address latch interface.
AAL: latch_unit
generic map (latch_type => LATCH_ADDR)
port map
(
activate => ale_activate,
latch_ctrl => ale_latch_ctrl,
write_enable => ale_write_enable,
busy => ale_busy,
clk => clk,
data_in => ale_data_in,
data_out => ale_data_out
);
-- Output to NAND
IO_WR: io_unit
generic map (io_type => IO_WRITE)
port map
(
clk => clk,
activate => io_wr_activate,
data_in => io_wr_data_in,
data_out => io_wr_data_out,
io_ctrl => io_wr_io_ctrl,
busy => io_wr_busy
);
-- Input from NAND
IO_RD: io_unit
generic map (io_type => IO_READ)
port map
(
clk => clk,
activate => io_rd_activate,
data_in => io_rd_data_in,
data_out => io_rd_data_out,
io_ctrl => io_rd_io_ctrl,
busy => io_rd_busy
);
-- Busy indicator
busy <= '0' when state = M_IDLE else
'1';
-- Bidirection NAND data interface.
--nand_data <= (cle_data_out or ale_data_out or io_wr_data_out) when (cle_busy or ale_busy or io_wr_busy) = '1' else x"ZZZZ";
nand_data <= cle_data_out when cle_busy = '1' else
ale_data_out when ale_busy = '1' else
io_wr_data_out when io_wr_busy = '1' else
"ZZZZZZZZZZZZZZZZ";
io_rd_data_in <= nand_data;
-- Command Latch Enable
nand_cle <= cle_latch_ctrl;
-- Address Latch Enable
nand_ale <= ale_latch_ctrl;
-- Write Enable
nand_nwe <= cle_write_enable and ale_write_enable and io_wr_io_ctrl;
-- Read Enable
nand_nre <= io_rd_io_ctrl;
-- Activation of command latch unit
cle_activate <= '1' when state = M_NAND_RESET or -- initiate submission of RESET command
(state = M_NAND_READ_PARAM_PAGE and substate = MS_BEGIN) or -- initiate submission of READ PARAMETER PAGE command
(state = M_NAND_BLOCK_ERASE and substate = MS_BEGIN) or -- initiate submission of BLOCK ERASE command
(state = M_NAND_BLOCK_ERASE and substate = MS_SUBMIT_COMMAND1) or -- initiate submission of BLOCK ERASE 2 command
(state = M_NAND_READ_STATUS and substate = MS_BEGIN) or -- initiate submission of READ STATUS command
(state = M_NAND_READ and substate = MS_BEGIN) or -- initiate read mode for READ command
(state = M_NAND_READ and substate = MS_SUBMIT_COMMAND1) or -- initiate submission of READ command
(state = M_NAND_PAGE_PROGRAM and substate = MS_BEGIN) or -- initiate write mode for PAGE PROGRAM command
(state = M_NAND_PAGE_PROGRAM and substate = MS_SUBMIT_COMMAND1) or -- initiate submission for PAGE PROGRAM command
(state = M_NAND_READ_ID and substate = MS_BEGIN) else -- initiate submission of READ ID command
'0';
-- Activation of address latch unit
ale_activate <= '1' when (state = M_NAND_READ_PARAM_PAGE and substate = MS_SUBMIT_COMMAND) or -- initiate address submission for READ PARAMETER PAGE command
(state = M_NAND_BLOCK_ERASE and substate = MS_SUBMIT_COMMAND) or -- initiate address submission for BLOCK ERASE command
(state = M_NAND_READ and substate = MS_SUBMIT_COMMAND) or -- initiate address submission for READ command
(state = M_NAND_PAGE_PROGRAM and substate = MS_SUBMIT_ADDRESS) or -- initiate address submission for PAGE PROGRAM command
(state = M_NAND_READ_ID and substate = MS_SUBMIT_COMMAND) else -- initiate address submission for READ ID command
'0';
-- Activation of read byte mechanism
io_rd_activate <= '1' when (state = M_NAND_READ_PARAM_PAGE and substate = MS_READ_DATA0) or -- initiate byte read for READ PARAMETER PAGE command
(state = M_NAND_READ_STATUS and substate = MS_READ_DATA0) or -- initiate byte read for READ STATUS command
(state = M_NAND_READ and substate = MS_READ_DATA0) or -- initiate byte read for READ command
(state = M_NAND_READ_ID and substate = MS_READ_DATA0) else -- initiate byte read for READ ID command
'0';
-- Activation of write byte mechanism
io_wr_activate <= '1' when (state = M_NAND_PAGE_PROGRAM and substate = MS_WRITE_DATA3) else -- initiate byte write for PAGE_PROGRAM command
'0';
MASTER: process(clk, nreset, activate, cmd_in, data_in, state_switch)
variable tmp_int : std_logic_vector(31 downto 0);
variable tmp : integer;
begin
if(nreset = '0')then
state <= M_RESET;
-- elsif(activate = '1')then
-- state <= state_switch(to_integer(unsigned(cmd_in)));
elsif(rising_edge(clk))then
case state is
-- RESET state. Speaks for itself
when M_RESET =>
state <= M_IDLE;
substate <= MS_BEGIN;
delay <= 0;
byte_count <= 0;
page_idx <= 0;
current_address(0)<= x"00";
current_address(1)<= x"00";
current_address(2)<= x"00";
current_address(3)<= x"00";
current_address(4)<= x"00";
data_bytes_per_page <= 0;
oob_bytes_per_page <= 0;
addr_cycles <= 0;
status <= x"08"; -- We start write protected!
nand_nce <= '1';
nand_nwp <= '0';
-- This is in fact a command interpreter
when M_IDLE =>
if(activate = '1')then
state <= state_switch(to_integer(unsigned(cmd_in)));
end if;
-- Reset the NAND chip
when M_NAND_RESET =>
cle_data_in <= x"00ff";
state <= M_WAIT;
n_state <= M_IDLE;
when MI_GET_STATUS =>
data_out <= status;
state <= M_IDLE;
when MI_CHIP_ENABLE =>
nand_nce <= '0';
state <= M_IDLE;
status(2) <= '1';
when MI_CHIP_DISABLE =>
nand_nce <= '1';
state <= M_IDLE;
status(2) <= '0';
when MI_WRITE_PROTECT =>
nand_nwp <= '0';
status(3) <= '1';
state <= M_IDLE;
when MI_WRITE_ENABLE =>
nand_nwp <= '1';
status(3) <= '0';
state <= M_IDLE;
when MI_RESET_INDEX =>
page_idx <= 0;
state <= M_IDLE;
when MI_GET_ID_BYTE =>
if(page_idx < 5)then
data_out <= chip_id(page_idx);
page_idx <= page_idx + 1;
status(4) <= '0';
else
data_out <= x"00";
page_idx <= 0;
status(4) <= '1';
end if;
state <= M_IDLE;
when MI_GET_PARAM_PAGE_BYTE =>
if(page_idx < 256)then
data_out <= page_param(page_idx);
page_idx <= page_idx + 1;
status(4) <= '0';
else
data_out <= x"00";
page_idx <= 0;
status(4) <= '1';
end if;
state <= M_IDLE;
when MI_GET_DATA_PAGE_BYTE =>
if(page_idx < data_bytes_per_page + oob_bytes_per_page)then
data_out <= page_data(page_idx);
page_idx <= page_idx + 1;
status(4) <= '0';
else
data_out <= x"00";
page_idx <= 0;
status(4) <= '1';
end if;
state <= M_IDLE;
when MI_SET_DATA_PAGE_BYTE =>
if(page_idx < data_bytes_per_page + oob_bytes_per_page)then
page_data(page_idx) <= data_in;
page_idx <= page_idx + 1;
status(4) <= '0';
else
page_idx <= 0;
status(4) <= '1';
end if;
state <= M_IDLE;
when MI_GET_CURRENT_ADDRESS_BYTE =>
if(page_idx < addr_cycles)then
data_out <= current_address(page_idx);
page_idx <= page_idx + 1;
status(4) <= '0';
else
page_idx <= 0;
status(4) <= '1';
end if;
state <= M_IDLE;
when MI_SET_CURRENT_ADDRESS_BYTE =>
if(page_idx < addr_cycles)then
current_address(page_idx) <= data_in;
page_idx <= page_idx + 1;
status(4) <= '0';
else
page_idx <= 0;
status(4) <= '1';
end if;
state <= M_IDLE;
-- Program one page.
when M_NAND_PAGE_PROGRAM =>
if(substate = MS_BEGIN)then
cle_data_in <= x"0080";
substate <= MS_SUBMIT_COMMAND;
state <= M_WAIT;
n_state <= M_NAND_PAGE_PROGRAM;
byte_count <= 0;
elsif(substate = MS_SUBMIT_COMMAND)then
byte_count <= byte_count + 1;
ale_data_in <= x"00"&current_address(byte_count);
substate <= MS_SUBMIT_ADDRESS;
elsif(substate = MS_SUBMIT_ADDRESS)then
if(byte_count < addr_cycles)then
substate <= MS_SUBMIT_COMMAND;
else
substate <= MS_WRITE_DATA0;
end if;
state <= M_WAIT;
n_state <= M_NAND_PAGE_PROGRAM;
elsif(substate = MS_WRITE_DATA0)then
delay <= t_adl;
state <= M_DELAY;
n_state <= M_NAND_PAGE_PROGRAM;
substate <= MS_WRITE_DATA1;
page_idx <= 0;
byte_count <= 0;
 
elsif(substate = MS_WRITE_DATA1)then
byte_count <= byte_count + 1;
page_idx <= page_idx + 1;
io_wr_data_in <= x"00"&page_data(page_idx);
if(status(1) = '0')then
substate <= MS_WRITE_DATA3;
else
substate <= MS_WRITE_DATA2;
end if;
elsif(substate = MS_WRITE_DATA2)then
page_idx <= page_idx + 1;
io_wr_data_in(15 downto 8) <= page_data(page_idx);
substate <= MS_WRITE_DATA3;
elsif(substate = MS_WRITE_DATA3)then
if(byte_count < data_bytes_per_page + oob_bytes_per_page)then
substate <= MS_WRITE_DATA1;
else
substate <= MS_SUBMIT_COMMAND1;
end if;
n_state <= M_NAND_PAGE_PROGRAM;
state <= M_WAIT;
elsif(substate = MS_SUBMIT_COMMAND1)then
cle_data_in <= x"0010";
n_state <= M_NAND_PAGE_PROGRAM;
state <= M_WAIT;
substate <= MS_WAIT;
elsif(substate = MS_WAIT)then
delay <= t_wb + t_prog;
state <= M_DELAY;
n_state <= M_NAND_PAGE_PROGRAM;
substate <= MS_END;
byte_count <= 0;
page_idx <= 0;
elsif(substate = MS_END)then
state <= M_WAIT;
n_state <= M_IDLE;
substate <= MS_BEGIN;
end if;
-- Reads single page into the buffer.
when M_NAND_READ =>
if(substate = MS_BEGIN)then
cle_data_in <= x"0000";
substate <= MS_SUBMIT_COMMAND;
state <= M_WAIT;
n_state <= M_NAND_READ;
byte_count <= 0;
elsif(substate = MS_SUBMIT_COMMAND)then
byte_count <= byte_count + 1;
ale_data_in <= x"00"&current_address(byte_count);
substate <= MS_SUBMIT_ADDRESS;
elsif(substate = MS_SUBMIT_ADDRESS)then
if(byte_count < addr_cycles)then
substate <= MS_SUBMIT_COMMAND;
else
substate <= MS_SUBMIT_COMMAND1;
end if;
state <= M_WAIT;
n_state <= M_NAND_READ;
elsif(substate = MS_SUBMIT_COMMAND1)then
cle_data_in <= x"0030";
substate <= MS_DELAY;
state <= M_WAIT;
n_state <= M_NAND_READ;
elsif(substate = MS_DELAY)then
delay <= t_wb;
substate <= MS_READ_DATA0;
state <= M_DELAY;
n_state <= M_NAND_READ;
byte_count <= 0;
page_idx <= 0;
elsif(substate = MS_READ_DATA0)then
byte_count <= byte_count + 1;
n_state <= M_NAND_READ;
state <= M_WAIT;
substate <= MS_READ_DATA1;
elsif(substate = MS_READ_DATA1)then
page_data(page_idx) <= io_rd_data_out(7 downto 0);
page_idx <= page_idx + 1;
if(byte_count = data_bytes_per_page + oob_bytes_per_page and status(1) = '0')then
substate <= MS_END;
else
if(status(1) = '0')then
substate <= MS_READ_DATA0;
else
substate <= MS_READ_DATA2;
end if;
end if;
elsif(substate = MS_READ_DATA2)then
page_idx <= page_idx + 1;
page_data(page_idx) <= io_rd_data_out(15 downto 8);
if(byte_count = data_bytes_per_page + oob_bytes_per_page)then
substate <= MS_END;
else
substate <= MS_READ_DATA0;
end if;
elsif(substate = MS_END)then
substate <= MS_BEGIN;
state <= M_IDLE;
byte_count <= 0;
end if;
-- Read status byte
when M_NAND_READ_STATUS =>
if(substate = MS_BEGIN)then
cle_data_in <= x"0070";
substate <= MS_SUBMIT_COMMAND;
state <= M_WAIT;
n_state <= M_NAND_READ_STATUS;
elsif(substate = MS_SUBMIT_COMMAND)then
delay <= t_whr;
substate <= MS_READ_DATA0;
state <= M_DELAY;
n_state <= M_NAND_READ_STATUS;
elsif(substate = MS_READ_DATA0)then
substate <= MS_READ_DATA1;
state <= M_WAIT;
n_state <= M_NAND_READ_STATUS;
elsif(substate = MS_READ_DATA1)then -- This is to make sure 'data_out' has valid data before 'busy' goes low.
data_out <= io_rd_data_out(7 downto 0);
state <= M_NAND_READ_STATUS;
substate <= MS_END;
elsif(substate = MS_END)then
substate <= MS_BEGIN;
state <= M_IDLE;
end if;
-- Erase block specified by current_address
when M_NAND_BLOCK_ERASE =>
if(substate = MS_BEGIN)then
cle_data_in <= x"0060";
substate <= MS_SUBMIT_COMMAND;
state <= M_WAIT;
n_state <= M_NAND_BLOCK_ERASE;
byte_count <= 3; -- number of address bytes to submit
elsif(substate = MS_SUBMIT_COMMAND)then
byte_count <= byte_count - 1;
ale_data_in(15 downto 8) <= x"00";
ale_data_in(7 downto 0) <= current_address(5 - byte_count);
substate <= MS_SUBMIT_ADDRESS;
state <= M_WAIT;
n_state <= M_NAND_BLOCK_ERASE;
elsif(substate = MS_SUBMIT_ADDRESS)then
if(0 < byte_count)then
substate <= MS_SUBMIT_COMMAND;
else
substate <= MS_SUBMIT_COMMAND1;
end if;
elsif(substate = MS_SUBMIT_COMMAND1)then
cle_data_in <= x"00d0";
substate <= MS_END;
state <= M_WAIT;
n_state <= M_NAND_BLOCK_ERASE;
elsif(substate = MS_END)then
n_state <= M_IDLE;
delay <= t_wb + t_bers;
state <= M_DELAY;
substate <= MS_BEGIN;
byte_count <= 0;
end if;
-- Read NAND chip JEDEC ID
when M_NAND_READ_ID =>
if(substate = MS_BEGIN)then
cle_data_in <= x"0090";
substate <= MS_SUBMIT_COMMAND;
state <= M_WAIT;
n_state <= M_NAND_READ_ID;
elsif(substate = MS_SUBMIT_COMMAND)then
ale_data_in <= X"0000";
substate <= MS_SUBMIT_ADDRESS;
state <= M_WAIT;
n_state <= M_NAND_READ_ID;
elsif(substate = MS_SUBMIT_ADDRESS)then
delay <= t_wb;
state <= M_DELAY;
n_state <= M_NAND_READ_ID;
substate <= MS_READ_DATA0;
byte_count <= 5;
page_idx <= 0;
elsif(substate = MS_READ_DATA0)then
byte_count <= byte_count - 1;
state <= M_WAIT;
n_state <= M_NAND_READ_ID;
substate <= MS_READ_DATA1;
elsif(substate = MS_READ_DATA1)then
chip_id(page_idx) <= io_rd_data_out(7 downto 0);
if(0 < byte_count)then
page_idx <= page_idx + 1;
substate <= MS_READ_DATA0;
else
substate <= MS_END;
end if;
elsif(substate = MS_END)then
byte_count <= 0;
page_idx <= 0;
substate <= MS_BEGIN;
state <= M_IDLE;
end if;
-- *data_in is assigned one clock cycle after *_activate is triggered!!!!
-- According to ONFI's timing diagrams this should be normal, but who knows...
when M_NAND_READ_PARAM_PAGE =>
if(substate = MS_BEGIN)then
cle_data_in <= x"00ec";
substate <= MS_SUBMIT_COMMAND;
state <= M_WAIT;
n_state <= M_NAND_READ_PARAM_PAGE;
elsif(substate = MS_SUBMIT_COMMAND)then
ale_data_in <= X"0000";
substate <= MS_SUBMIT_ADDRESS;
state <= M_WAIT;
n_state <= M_NAND_READ_PARAM_PAGE;
elsif(substate = MS_SUBMIT_ADDRESS)then
delay <= t_wb;
state <= M_DELAY;
n_state <= M_NAND_READ_PARAM_PAGE;
substate <= MS_READ_DATA0;
byte_count <= 256;
page_idx <= 0;
elsif(substate = MS_READ_DATA0)then
byte_count <= byte_count - 1;
state <= M_WAIT;
n_state <= M_NAND_READ_PARAM_PAGE;
substate <= MS_READ_DATA1;
elsif(substate = MS_READ_DATA1)then
page_param(page_idx) <= io_rd_data_out(7 downto 0);
if(0 < byte_count)then
page_idx <= page_idx + 1;
substate <= MS_READ_DATA0;
else
substate <= MS_END;
end if;
elsif(substate = MS_END)then
byte_count <= 0;
page_idx <= 0;
substate <= MS_BEGIN;
state <= M_IDLE;
-- Check the chip for being ONFI compliant
if(page_param(0) = x"4f" and page_param(1) = x"4e" and page_param(2) = x"46" and page_param(3) = x"49")then
-- Set status bit 0
status(0) <= '1';
-- Bus width
status(1) <= page_param(6)(0);
-- Setup counters:
-- Number of bytes per page
tmp_int := page_param(83)&page_param(82)&page_param(81)&page_param(80);
data_bytes_per_page <= to_integer(unsigned(tmp_int));
-- Number of spare bytes per page (OOB)
tmp_int := "0000000000000000" & page_param(85) & page_param(84);
oob_bytes_per_page <= to_integer(unsigned(tmp_int));
-- Number of address cycles
addr_cycles <= to_integer(unsigned(page_param(101)(3 downto 0))) + to_integer(unsigned(page_param(101)(7 downto 4)));
end if;
end if;
-- Wait for latch and IO modules to become ready as well as for NAND's R/B# to be '1'
when M_WAIT =>
if('0' = (cle_busy or ale_busy or io_rd_busy or io_wr_busy or (not nand_rnb)))then
state <= n_state;
end if;
-- Simple delay mechanism
when M_DELAY =>
if(delay > 1)then
delay <= delay - 1;
else
state <= n_state;
end if;
-- For just in case ("Shit happens..." (C) Forrest Gump)
when others =>
state <= M_RESET;
end case;
end if;
end process;
end struct;
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.