| init_controller.vhd
--------------------------------------------------------------------------
-- FILENAME : init_controller.vhd
--
-- This component is the first component to become active after a reset
-- and takes total control of the controller. While in control it will
-- check if a disk is in the disk drive and then move the read / write
-- head to track zero. Control is then passed to the other controller
-- components. If at any point the control is reset or a disk is removed
-- this component takes over control again (the other components can't
-- really do much unless a disk is in the drive).
--
-- The RDY output is used as synchronus reset to many of the components.
-- This isn't a problem as those components are clocked by MCLK and this
-- component will take many MCLK pulses to do it's stuff, therefore
-- guaranteeing that the other components will synchronusly reset.
--
-- I have found that if the power to disk drive is toggled the
-- read / write head can move very slightly of the current track. When
-- this happens the data from the drive is corrupt and the TRACK_00
-- signal from the disk drive can indicate that it is on track zero. To
-- overcome this I move the read / write head to track 80 and then back
-- to track zero. This effectivly realligns the read / write head and
-- generates a valid TRACK_00 signal.
--
-- The DISK_CHANGE signal only signals that a disk is present after
-- performing a step.
--
-- AUTHOR : Craig Dunn
-- DATE STARTED : 30 December 2003
-- TAB SETTING : 4
-- RESET : Async (active low)
-- CLOCK : 32MHz (clock dependent)
-- 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 init_controller is
Port ( RST : in std_logic;
MCLK : in std_logic;
DISK_CHANGE : in std_logic;
TRACK_00 : in std_logic;
RDY : out std_logic;
STEP : out std_logic;
DIRECTION : out std_logic
);
end init_controller;
architecture init_controller_arch of init_controller is
type state_type is ( RESET, IDLE, CHECK_FOR_DISK, MOVE_TO_TRACK80, MOVE_TO_TRACK00,
DELAY_20MS, PERFORM_STEP_IN, PERFORM_STEP_OUT );
signal state : state_type;
signal step_dly : integer range 0 to 200000;
signal track_count : integer range 0 to 200;
signal delay_count : integer range 0 to 640000;
constant DURATION_4MS : integer := 128000;
constant DURATION_5MS : integer := 160000;
constant DURATION_20MS : integer := 640000;
begin
STEP <= '1' when step_dly < DURATION_4MS else '0';
main : process (RST, MCLK)
begin
if RST = '0' then
RDY <= '0';
state <= RESET;
step_dly <= 0;
DIRECTION <= '0';
elsif rising_edge(MCLK) then
case state is
when RESET =>
DIRECTION <= '0'; -- move towards track 00
step_dly <= 0;
state <= CHECK_FOR_DISK;
-- Enter this state directly after a reset or once a disk
-- has been found and the read / write head has been moved
-- to track zero. While in this state it keeps checking
-- that a disk is in the drive.
------------------------------------------------------------
when IDLE =>
-- If ever a disk is removed DISK_CHANGE will go low.
if DISK_CHANGE = '0' then
RDY <= '0';
DIRECTION <= '0'; -- move towards track 00
step_dly <= 0;
state <= CHECK_FOR_DISK;
end if;
-- Keep incrementing step_dly for 5ms. In this time a step
-- pulse will generated (see STEP) which will make the
-- DISK_CHANGE signal valid.
------------------------------------------------------------
when CHECK_FOR_DISK =>
if step_dly = DURATION_5MS then
if DISK_CHANGE = '1' then
-- A disk is present so move the read / write to
-- track 80 and then back to track zero (reallign
-- the head).
step_dly <= 0;
track_count <= 0;
state <= MOVE_TO_TRACK80;
else
state <= IDLE;
end if;
else
step_dly <= step_dly + 1;
state <= CHECK_FOR_DISK;
end if;
-- Generated 80 STEP pulses to make sure we are on track
-- 80 and then move back to track zero. As we don't know
-- what track we are on the safest thing to do is assume
-- we are on track zero.
------------------------------------------------------------
when MOVE_TO_TRACK80 =>
DIRECTION <= '0'; -- move towards track 80
if track_count = 80 then
state <= MOVE_TO_TRACK00;
else
track_count <= track_count + 1;
state <= PERFORM_STEP_OUT;
end if;
-- When we enter this state we are on track 80 so keep
-- stepping the read / write head inwards until the
-- TRACK_00 signal from the disk drive indicates that we
-- are definatly on track zero. This is more reliable than
-- simply counting the STEP pulses.
------------------------------------------------------------
when MOVE_TO_TRACK00 =>
DIRECTION <= '1'; -- move towards track zero
if TRACK_00 = '1' then
track_count <= 0;
state <= PERFORM_STEP_IN;
else
-- We are now on track zero so the controller
-- is ready to be used. A floppy disk specification
-- recommends a 20ms gap between a STEP and a WRITE
-- so generate that delay here.
delay_count <= 0;
state <= DELAY_20MS;
end if;
-- Generate a 20ms delay after the final STEP just in case
-- a WRITE is performed straight away. When this delay
-- is complete the controller is ready to be used.
------------------------------------------------------------
when DELAY_20MS =>
if delay_count = DURATION_20MS then
RDY <= '1';
state <= IDLE;
else
delay_count <= delay_count + 1;
state <= DELAY_20MS;
end if;
-- Perform a STEP. See the STEP signal to see how this
-- works.
------------------------------------------------------------
when PERFORM_STEP_IN =>
if step_dly = DURATION_5MS then
step_dly <= 0;
state <= MOVE_TO_TRACK00;
else
step_dly <= step_dly + 1;
state <= PERFORM_STEP_IN;
end if;
-- Perform a STEP. See the STEP signal to see how this
-- works.
------------------------------------------------------------
when PERFORM_STEP_OUT =>
if step_dly = DURATION_5MS then
step_dly <= 0;
state <= MOVE_TO_TRACK80;
else
step_dly <= step_dly + 1;
state <= PERFORM_STEP_OUT;
end if;
when others =>
null;
end case;
end if;
end process main;
end init_controller_arch;
|