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/VHDL
- from Rev 8 to Rev 9
- ↔ Reverse comparison
Rev 8 → Rev 9
/nand_stuff.vhd
File deleted
\ No newline at end of file
/nand_ctrl.vhd
File deleted
\ No newline at end of file
/nand_interface.vhd
File deleted
\ No newline at end of file
/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; |
/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; |
/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; |
/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"¤t_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"¤t_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; |
|