*

FDDController.vhd


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

-- FILENAME : FDDController.vhd
--
-- The main implementation of the floppy disk drive controller.
--
-- AUTHOR : Craig Dunn
-- DATE STARTED : 20 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 FDDController is
port ( RST : in std_logic; -- async reset
MCLK : in std_logic; -- master clock (32MHz)

-- floppy disk drive signals
TRACK_00 : in std_logic;
INDEX : in std_logic;
READ_DATA : in std_logic;
WRITE_PROTECT : in std_logic;
DISK_CHANGE : in std_logic;
DRIVE_SELECT : out std_logic;
MOTOR_ON : out std_logic;
DIRECTION_SELECT : out std_logic;
STEP : out std_logic;
WRITE_GATE : out std_logic;
WRITE_DATA : out std_logic;
SIDE_ONE_SELECT : out std_logic;

-- control signals
RD_SECT : in std_logic;
WR_SECT : in std_logic;
MEM_CLK : in std_logic;
MEM_WE : in std_logic;
SECTOR : in std_logic_vector(4 downto 0);
TRACK : in std_logic_vector(7 downto 0);
SIDE : in std_logic;
DATA_IN : in std_logic_vector(7 downto 0);
ADDR : in std_logic_vector(8 downto 0);
RDY : out std_logic;
BSY : out std_logic;
CRC_ERROR : out std_logic;
SEEK_ERROR : out std_logic;
WP_ERROR : out std_logic;
DATA_OUT : out std_logic_vector(7 downto 0)
);
end FDDController;

architecture FDDController_arch of FDDController is

component ramb4_s8
port(
WE : in std_logic;
EN : in std_logic;
RST : in std_logic;
CLK : in std_logic;
ADDR : in std_logic_vector(8 downto 0);
DI : in std_logic_vector(7 downto 0);
DO : out std_logic_vector(7 downto 0)
);
end component;

attribute box_type : string;
attribute box_type of ramb4_s8 : component is "black_box";

component synchronizer
port(
CLK : in std_logic;
CLR : in std_logic;
UNSYNC_IN : in std_logic;
SYNC_OUT : out std_logic
);
end component;

component dpll
port(
RST : in std_logic;
CLK_4MHZ : in std_logic;
BASIC_MFM : in std_logic;
DPLL_CLK : out std_logic
);
end component;

component mfm_encoder
port(
EN : in std_logic;
MCLK : in std_logic;
RAM_DO : in std_logic_vector(7 downto 0);
CRC_OUT : in std_logic_vector(15 downto 0);
CRC_DATA : out std_logic_vector(7 downto 0);
CRC_IN : out std_logic_vector(15 downto 0);
RAM_CLK : out std_logic;
RAM_ADDR : out std_logic_vector(8 downto 0);
BSY : out std_logic;
MFM_OUT : out std_logic
);
end component;

component index_counter
port(
INDEX : in std_logic;
COUNT : out std_logic_vector(3 downto 0)
);
end component;

component mfm_to_basic
port(
RST : in std_logic;
MFM_IN : in std_logic;
BASIC_OUT : out std_logic
);
end component;

component clock_divider
port(
RST : in std_logic;
MCLK : in std_logic;
CLK_4MHZ : out std_logic
);
end component;

component shift_32
port(
RST : in std_logic;
CLK : in std_logic;
D : in std_logic;
Q : out std_logic_vector(31 downto 0)
);
end component;

component init_controller
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 component;

component step_controller
port(
RST : in std_logic;
MCLK : in std_logic;
EN : in std_logic;
TRACK : in std_logic_vector(7 downto 0);
BSY : out std_logic;
STEP : out std_logic;
DIRECTION : out std_logic
);
end component;

component read_address_field
port(
MCLK : in std_logic;
EN : in std_logic;
DATA_IN : in std_logic_vector(7 downto 0);
BYTE_COUNT : in std_logic_vector(9 downto 0);
CRC_OUT : in std_logic_vector(15 downto 0);
CRC_IN : out std_logic_vector(15 downto 0);
CRC_DATA : out std_logic_vector(7 downto 0);
SECTOR : out std_logic_vector(4 downto 0)
);
end component;

component read_data_field
port(
MCLK : in std_logic;
EN : in std_logic;
DATA_IN : in std_logic_vector(7 downto 0);
NEW_DATA : in std_logic;
RD_SECT : in std_logic;
INDEX_COUNT : in std_logic_vector(3 downto 0);
READ_SECTOR : in std_logic_vector(4 downto 0);
CURRENT_SECTOR : in std_logic_vector(4 downto 0);
BYTE_COUNT : in std_logic_vector(9 downto 0);
DATA_FIELD : in std_logic;
CRC_OUT : in std_logic_vector(15 downto 0);
CRC_IN : out std_logic_vector(15 downto 0);
CRC_DATA : out std_logic_vector(7 downto 0);
CRC_EN : out std_logic;
BSY : out std_logic;
RAM_CLK : out std_logic;
RAM_ADDR : out std_logic_vector(8 downto 0);
CRC_ERROR : out std_logic;
SEEK_ERROR : out std_logic
);
end component;

component write_data_field
port(
MCLK : in std_logic;
EN : in std_logic;
WR_SECT : in std_logic;
ADDRESS_FIELD : in std_logic;
WRITE_PROTECT : in std_logic;
ENCODER_BSY : in std_logic;
INDEX_COUNT : in std_logic_vector(3 downto 0);
CURRENT_SECTOR : in std_logic_vector(4 downto 0);
WRITE_SECTOR : in std_logic_vector(4 downto 0);
BYTE_COUNT : in std_logic_vector(9 downto 0);
BSY : out std_logic;
SEEK_ERROR : out std_logic;
WP_ERROR : out std_logic;
ENCODER_EN : out std_logic
);
end component;

component byte_counter
port(
RST : in std_logic;
DPLL_CLK : in std_logic;
AF_AM : in std_logic;
DF_AM : in std_logic;
NEW_BYTE : out std_logic;
COUNT : out std_logic_vector(9 downto 0)
);
end component;

component crc
port(
DATA_IN : in std_logic_vector(7 downto 0);
CRC_IN : in std_logic_vector(15 downto 0);
CRC_OUT : out std_logic_vector(15 downto 0)
);
end component;


type field_type is ( ADDRESS_FIELD, DATA_FIELD );

signal current_field : field_type;
signal synced_index : std_logic;
signal synced_mfm : std_logic;
signal basic_mfm : std_logic;
signal clk_4mhz : std_logic;
signal address_field_am : std_logic;
signal data_field_am : std_logic;
signal sig_newbyte : std_logic;
signal controller_rdy : std_logic;
signal ram_we : std_logic;
signal ram_en : std_logic;
signal ram_rst : std_logic;
signal ram_clk : std_logic;
signal read_bsy : std_logic;
signal ram_clk_rd : std_logic;
signal controller_bsy : std_logic;
signal dpll_clk : std_logic;
signal mfm_ram_clk : std_logic;
signal mfm_out : std_logic;
signal write_bsy : std_logic;
signal df_crc_en : std_logic;
signal read_seek_err : std_logic;
signal write_seek_err : std_logic;
signal init_direction : std_logic;
signal init_step : std_logic;
signal stepper_bsy : std_logic;
signal stepper_step : std_logic;
signal stepper_direction : std_logic;
signal read_af_en : std_logic;
signal sig_data_field : std_logic;
signal sig_address_field : std_logic;
signal encoder_en : std_logic;
signal encoder_bsy : std_logic;
signal index_count : std_logic_vector(3 downto 0);
signal sector_reg : std_logic_vector(4 downto 0);
signal ram_di : std_logic_vector(7 downto 0);
signal ram_do : std_logic_vector(7 downto 0);
signal byte_reg : std_logic_vector(7 downto 0);
signal df_crc_data : std_logic_vector(7 downto 0);
signal af_crc_data : std_logic_vector(7 downto 0);
signal crc_data : std_logic_vector(7 downto 0);
signal mfm_crc_data : std_logic_vector(7 downto 0);
signal mfm_ram_addr : std_logic_vector(8 downto 0);
signal ram_addr : std_logic_vector(8 downto 0);
signal ram_addr_rd : std_logic_vector(8 downto 0);
signal sig_byte_count : std_logic_vector(9 downto 0);
signal crc_out : std_logic_vector(15 downto 0);
signal crc_in : std_logic_vector(15 downto 0);
signal mfm_crc_in : std_logic_vector(15 downto 0);
signal af_crc_in : std_logic_vector(15 downto 0);
signal df_crc_in : std_logic_vector(15 downto 0);
signal mfm_seq_32 : std_logic_vector(31 downto 0);

constant AF_AM : std_logic_vector(31 downto 0) :=
"10000111000011100110011001100111";
constant DF_AM : std_logic_vector(31 downto 0) :=
"10000111000011100110011001111001";

begin

RDY <= controller_rdy;
BSY <= controller_bsy;
SEEK_ERROR <= read_seek_err or write_seek_err;
controller_bsy <= stepper_bsy or read_bsy or write_bsy or (not controller_rdy);

crc_data <= df_crc_data when df_crc_en = '1' else mfm_crc_data when encoder_en = '1' else af_crc_data;
crc_in <= df_crc_in when df_crc_en = '1' else mfm_crc_in when encoder_en = '1' else af_crc_in;

mfm_crc : crc port map(
DATA_IN => crc_data,
CRC_IN => crc_in,
CRC_OUT => crc_out
);


c1 : synchronizer port map(
CLK => MCLK,
CLR => RST,
UNSYNC_in => READ_DATA,
SYNC_out => synced_mfm
);

c2 : synchronizer port map (
CLK => MCLK,
CLR => RST,
UNSYNC_in => inDEX,
SYNC_out => synced_index
);

c4 : dpll port map (
RST => RST,
CLK_4MHZ => clk_4mhz,
BASIC_MFM => basic_mfm,
DPLL_CLK => dpll_clk
);

c5 : index_counter port map (
inDEX => synced_index,
COUNT => index_count
);

c6 : mfm_encoder port map(
EN => encoder_en,
MCLK => MCLK,
RAM_DO => ram_do,
RAM_CLK => mfm_ram_clk,
RAM_ADDR => mfm_ram_addr,
BSY => encoder_bsy,
MFM_OUT => mfm_out,
CRC_DATA => mfm_crc_data,
CRC_IN => mfm_crc_in,
CRC_OUT => crc_out
);

c7 : mfm_to_basic port map(
RST => RST,
MFM_in => synced_mfm,
BASIC_out => basic_mfm
);

c8 : clock_divider port map(
RST => RST,
MCLK => MCLK,
CLK_4MHZ => clk_4mhz
);

c9 : shift_32 port map(
RST => RST,
CLK => dpll_clk,
D => basic_mfm,
Q => mfm_seq_32
);

c10 : init_controller port map(
RST => RST,
MCLK => MCLK,
DISK_CHANGE => DISK_CHANGE,
TRACK_00 => TRACK_00,
RDY => controller_rdy,
STEP => init_step,
DIRECTION => init_direction
);

c11 : step_controller port map(
RST => RST,
MCLK => MCLK,
EN => controller_rdy,
TRACK => TRACK,
BSY => stepper_bsy,
STEP => stepper_step,
DIRECTION => stepper_direction
);

ram_en <= '1';
ram_rst <= not RST;
ram_we <= MEM_WE when controller_bsy = '0' else
'1' when (read_bsy = '1' and current_field = DATA_FIELD) else
'0';
ram_clk <= MEM_CLK when controller_bsy = '0' else
ram_clk_rd when read_bsy = '1' else
mfm_ram_clk when encoder_en = '1' else
'0';
ram_addr <= ADDR when controller_bsy = '0' else
ram_addr_rd when read_bsy = '1' else
mfm_ram_addr when encoder_en = '1' else
(others => '0');
ram_di <= DATA_in when controller_bsy = '0' else
byte_reg when read_bsy = '1' else
(others => '0');
DATA_out <= ram_do;

c12 : ramb4_s8 port map(
WE => ram_we,
EN => ram_en,
RST => ram_rst,
CLK => ram_clk,
ADDR => ram_addr,
DI => ram_di,
DO => ram_do
);

read_af_en <= '1' when current_field = ADDRESS_FIELD and controller_bsy = '1' else '0';

c13 : read_address_field port map(
MCLK => MCLK,
EN => read_af_en,
DATA_IN => byte_reg,
BYTE_COUNT => sig_byte_count,
SECTOR => sector_reg,
CRC_OUT => crc_out,
CRC_IN => af_crc_in,
CRC_DATA => af_crc_data
);

sig_data_field <= '1' when current_field = DATA_FIELD else '0';

c14 : read_data_field port map(
MCLK => MCLK,
EN => controller_rdy,
DATA_in => byte_reg,
NEW_DATA => sig_newbyte,
RD_SECT => RD_SECT,
INDEX_COUNT => index_count,
READ_SECTOR => SECTOR,
CURRENT_SECTOR => sector_reg,
BYTE_COUNT => sig_byte_count,
DATA_FIELD => sig_data_field,
BSY => read_bsy,
RAM_CLK => ram_clk_rd,
RAM_ADDR => ram_addr_rd,
CRC_ERROR => CRC_ERROR,
SEEK_ERROR => read_seek_err,
CRC_OUT => crc_out,
CRC_IN => df_crc_in,
CRC_DATA => df_crc_data,
CRC_EN => df_crc_en
);

sig_address_field <= '1' when current_field = ADDRESS_FIELD else '0';

c15 : write_data_field port map(
MCLK => MCLK,
EN => controller_rdy,
WR_SECT => WR_SECT,
ADDRESS_FIELD => sig_address_field,
WRITE_PROTECT => WRITE_PROTECT,
ENCODER_BSY => encoder_bsy,
INDEX_COUNT => index_count,
CURRENT_SECTOR => sector_reg,
WRITE_SECTOR => SECTOR,
BYTE_COUNT => sig_byte_count,
BSY => write_bsy,
SEEK_ERROR => write_seek_err,
WP_ERROR => WP_ERROR,
ENCODER_EN => encoder_en
);

c16 : byte_counter port map(
RST => RST,
DPLL_CLK => dpll_clk,
AF_AM => address_field_am,
DF_AM => data_field_am,
NEW_BYTE => sig_newbyte,
COUNT => sig_byte_count
);


address_field_am <= '1' when mfm_seq_32 = AF_AM or
mfm_seq_32 = (not AF_AM) else '0';

data_field_am <= '1' when mfm_seq_32 = DF_AM or
mfm_seq_32 = (not DF_AM) else '0';

field_detector : process(MCLK)
begin
if rising_edge(MCLK) then
-- The controller is not ready either on a system reset or
-- when a disk is removed.
if controller_rdy = '0' then
current_field <= DATA_FIELD;
else
-- The address_field_am and data_field_am signals only
-- indicate when we are at the start of the address mark
-- so current_field is used to indicate when we are
-- in the field.
if address_field_am = '1' then
current_field <= ADDRESS_FIELD;
elsif data_field_am = '1' then
current_field <= DATA_FIELD;
end if;
end if;
end if;
end process field_detector;

--------------------------------------------------------------------------
-- SIGNAL : byte_reg
--
-- When a new byte is read from the disk it is put in this signal. Any
-- value in this signal is valid and remains valid until a complete
-- new byte arrives. The byte_count signal can be used as an indicator
-- to read this signal.
--------------------------------------------------------------------------

byte_reg(0) <= '1' when mfm_seq_32(0) /= mfm_seq_32(1) and sig_newbyte = '1' else '0';
byte_reg(1) <= '1' when mfm_seq_32(2) /= mfm_seq_32(3) and sig_newbyte = '1' else '0';
byte_reg(2) <= '1' when mfm_seq_32(4) /= mfm_seq_32(5) and sig_newbyte = '1' else '0';
byte_reg(3) <= '1' when mfm_seq_32(6) /= mfm_seq_32(7) and sig_newbyte = '1' else '0';
byte_reg(4) <= '1' when mfm_seq_32(8) /= mfm_seq_32(9) and sig_newbyte = '1' else '0';
byte_reg(5) <= '1' when mfm_seq_32(10) /= mfm_seq_32(11) and sig_newbyte = '1' else '0';
byte_reg(6) <= '1' when mfm_seq_32(12) /= mfm_seq_32(13) and sig_newbyte = '1' else '0';
byte_reg(7) <= '1' when mfm_seq_32(14) /= mfm_seq_32(15) and sig_newbyte = '1' else '0';


--------------------------------------------------------------------------
-- SIGNALS : floppy disk drive signals
--
-- All the outputs to the floppy disk drive.
--------------------------------------------------------------------------

SIDE_ONE_SELECT <= SIDE;
DRIVE_SELECT <= '0';
MOTOR_ON <= '0' when read_bsy = '1' or write_bsy = '1' else '1';
STEP <= init_step and stepper_step when RST = '1' else '1';
DIRECTION_SELECT <= init_direction when controller_rdy = '0' else stepper_direction;
WRITE_DATA <= mfm_out;
WRITE_GATE <= '0' when RST = '1' and encoder_en = '1' else '1';


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

end FDDController_arch;


BackHome