*

write_fat.vhd


--------------------------------------------------------------------------

-- FILENAME : write_fat.vhd
--
-- Writes a new 12 bit entry to the File Allocation Table of a FAT12 disk.
--
-- Both FAT tables are written.
--
-- The document FATGEN103.doc written by Microsoft gives a complete
-- description of how to add new entries to the FAT. The examples from
-- that document are written in C. The VHDL in this module is based on
-- those C examples.
--
-- The final project report also gives a more detailed description of how
-- this module is implemented.
--
-- FAT_VALUE is the new 12 bit value to write and ENTRY is the location
-- to write it (ENTRY is equal to N in the FATGEN103.doc document).
--
-- AUTHOR : Craig Dunn
-- DATE STARTED : 1 April 2004
-- TAB SETTING : 4
-- RESET : Sync (controller ready)
-- CLOCK : 32Mhz
-- KNOWN BUGS : None
-- VERSION : 1.0
--
-- All of the design and code in this module is my own work. No design or
-- code has been borrowed or copied from any source.
--------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;

entity write_fat is
port ( EN : in std_logic;
MCLK : in std_logic;
WR : in std_logic;
RW_BSY : in std_logic;
DATA_IN : in std_logic_vector(7 downto 0);
ENTRY : in std_logic_vector(11 downto 0);
FAT_VALUE : in std_logic_vector(11 downto 0);

RD_BYTE : out std_logic;
WR_BYTE : out std_logic;
SIDE : out std_logic;
BSY : out std_logic;
SECTOR : out std_logic_vector(4 downto 0);
TRACK : out std_logic_vector(7 downto 0);
DATA_OUT : out std_logic_vector(7 downto 0);
RAM_ADDR : out std_logic_vector(8 downto 0)
);
end write_fat;

architecture write_fat_arch of write_fat is

type state_type is ( IDLE, READ_BYTE, WAIT_FOR_READ, WRITE_BYTE,
WAIT_FOR_WRITE, CALC_LOCATION );
type byte_type is ( FAT1_HI, FAT1_LO, FAT2_HI, FAT2_LO);

signal state : state_type;
signal current_byte : byte_type;

signal lo_sector : std_logic_vector(4 downto 0);
signal hi_sector : std_logic_vector(4 downto 0);
signal lo_address : std_logic_vector(8 downto 0);
signal hi_address : std_logic_vector(8 downto 0);
signal fat_offset : std_logic_vector(12 downto 0);
signal sig_data_in : std_logic_vector(7 downto 0);

constant FAT1_OFFSET : std_logic_vector(4 downto 0) := "00010";
constant FAT2_OFFSET : std_logic_vector(4 downto 0) := "01011";
constant SECS_PER_TRACK : std_logic_vector(4 downto 0) := "10010";

begin

-- The last sector of the second FAT is on the side one (SIDE = 0). All other
-- sectors are on side zero (SIDE = 1).
SIDE <= '0' when (current_byte = FAT2_HI and ((hi_sector + FAT2_OFFSET) > SECS_PER_TRACK)) or
(current_byte = FAT2_LO and ((lo_sector + FAT2_OFFSET) > SECS_PER_TRACK)) else '1';

TRACK <= (others => '0');

SECTOR <= (hi_sector + FAT1_OFFSET) when current_byte = FAT1_HI else
(hi_sector + FAT2_OFFSET) when (current_byte = FAT2_HI and ((hi_sector + FAT2_OFFSET) <= SECS_PER_TRACK)) else
(hi_sector + FAT2_OFFSET SECS_PER_TRACK) when (current_byte = FAT2_HI and ((hi_sector + FAT2_OFFSET) > SECS_PER_TRACK)) else
(lo_sector + FAT1_OFFSET) when current_byte = FAT1_LO else
(lo_sector + FAT2_OFFSET) when (current_byte = FAT2_LO and ((lo_sector + FAT2_OFFSET) <= SECS_PER_TRACK)) else
(lo_sector + FAT2_OFFSET SECS_PER_TRACK);

RAM_ADDR <= hi_address when (current_byte = FAT1_HI or current_byte = FAT2_HI) else lo_address;

DATA_OUT <= FAT_VALUE(7 downto 0) when (current_byte = FAT1_HI or current_byte = FAT2_HI) and ENTRY(0) = '0' else
FAT_VALUE(3 downto 0) & sig_data_in(3 downto 0) when (current_byte = FAT1_HI or current_byte = FAT2_HI) and ENTRY(0) = '1' else
sig_data_in(7 downto 4) & FAT_VALUE(11 downto 8) when (current_byte = FAT1_LO or current_byte = FAT2_LO) and ENTRY(0) = '0' else
FAT_VALUE(11 downto 4);


main : process(MCLK)
begin
if rising_edge(MCLK) then
if EN = '0' then
RD_BYTE <= '0';
WR_BYTE <= '0';
state <= IDLE;
else
case state is


-- Stay in this state until the external input of WR
-- goes high. When it does start writing the new
-- FAT entry.
------------------------------------------------------------
when IDLE =>
RD_BYTE <= '0';
WR_BYTE <= '0';
current_byte <= FAT1_HI;

if WR = '1' then
fat_offset <= ('0' & ENTRY) + ("00" & ENTRY(11 downto 1));
state <= CALC_LOCATION;
BSY <= '1';
else
state <= IDLE;
BSY <= '0';
end if;


-- Calculate the location of both the high and low FAT entry
-- bytes in both FAT tables.
------------------------------------------------------------
when CALC_LOCATION =>
hi_address <= fat_offset(8 downto 0);
hi_sector <= '0' & fat_offset(12 downto 9);

-- Check if the FAT entry is located in two sectors.
if ENTRY(8 downto 0) = "101010101" then
-- The low part of the entry is in a different sector.
lo_address <= (others => '0');
lo_sector <= ('0' & fat_offset(12 downto 9)) + '1';
else
lo_address <= fat_offset(8 downto 0) + '1';
lo_sector <= '0' & fat_offset(12 downto 9);
end if;

state <= READ_BYTE;


-- Read a byte from the FAT.
------------------------------------------------------------
when READ_BYTE =>
RD_BYTE <= '1';
if RW_BSY = '1' then
state <= WAIT_FOR_READ;
end if;


-- Wait for the read to finish.
------------------------------------------------------------
when WAIT_FOR_READ =>
RD_BYTE <= '0';
if RW_BSY = '0' then
sig_data_in <= DATA_IN;
state <= WRITE_BYTE;
end if;


-- Write the new byte back to the FAT. The byte is changed
-- in the WHEN clauses at the top of this module.
------------------------------------------------------------
when WRITE_BYTE =>
WR_BYTE <= '1';
if RW_BSY = '1' then
state <= WAIT_FOR_WRITE;
end if;


-- Wait here until the write is complete. When it is
-- complete either read the next byte or finish.
------------------------------------------------------------
when WAIT_FOR_WRITE =>
WR_BYTE <= '0';

if RW_BSY = '0' then
case current_byte is
when FAT1_HI => current_byte <= FAT1_LO;
state <= READ_BYTE;
when FAT1_LO => current_byte <= FAT2_HI;
state <= READ_BYTE;
when FAT2_HI => current_byte <= FAT2_LO;
state <= READ_BYTE;
when FAT2_LO => state <= IDLE;
when others => null;
end case;
end if;


when others =>
null;

end case;
end if;
end if;
end process main;


end write_fat_arch;


BackHome