This commit is contained in:
aschi54
2010-12-27 13:20:36 +00:00
commit 92c2ab95fc
427 changed files with 91737 additions and 0 deletions

View File

@@ -0,0 +1,253 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- Address mark detector file. This part detects the address ----
---- mark in the incoming data stream in FM and also in MFM mode ----
---- and provides therewith synchronisation information for the ----
---- control state machine and for the data separator in the ----
---- transceiver unit. ----
---- ----
------------------------------- Some theory -------------------------------------
---- Frequency modulation FM: ----
---- The frequency modulation works as follows: ----
---- 1. every first pulse of the clock and data line is a clock. ----
---- 2. every second pulse is a data. ----
---- 3. a logic 1 is represented by two consecutive pulses (clock and data). ----
---- 4. a logic 0 is represented by one clock pulse and no data pulse. ----
---- 5. Hence there are a maximum of two pulses per data bit. ----
---- 6. one clock and one data pulse come together in one bit cell. ----
---- 7. the duration of a bit cell in FM is 4 microseconds. ----
---- 8. an ID address mark is represented as data FE with clock C7. ----
---- 9. a DATA address mark is represented as data FB with clock C7. ----
---- Examples: ----
---- Binary data 1 1 0 0 1 0 1 1 is represented in FM as follows: ----
---- 1111101011101111 ----
---- the FE data 1 1 1 1 1 1 1 0 is represented as follows: ----
---- 1111111111111110 ----
---- with C7 clock mask 1 1 0 0 0 1 1 1 which masks the clock pulses there ----
---- results: 1111010101111110 this is the ID address mark. ----
---- the FB data 1 1 1 1 1 0 1 1 is represented as follows: ----
---- 1111111111101111 ----
---- with C7 clock mask 1 1 0 0 0 1 1 1 which masks the clock pulses there ----
---- results: 1111010101101111 this is the DATA address mark. ----
---- the F8 data 1 1 1 1 1 0 0 0 is represented as follows: ----
---- 1111111111101010 ----
---- with C7 clock mask 1 1 0 0 0 1 1 1 which masks the clock pulses there ----
---- results: 1111010101101010 this is the deleted DATA mark. ----
---- ----
---- ----
---- Modified frequency modulation MFM: ----
---- The modified frequency modulation works as follows: ----
---- 1. every first pulse of the clock and data line is a clock. ----
---- 2. every second pulse is a data. ----
---- 3. a logic 1 is represented by no clock but a data pulse. ----
---- 4. a logic 0 is represented by a clock pulse and no data pulse if ----
---- following a 0. ----
---- 5. a logic 0 is represented by no pulse if following a 1. ----
---- 6. Hence there are a maximum of one pulse per data bit. ----
---- 7. one clock and one data pulse form together one bit cell. ----
---- 8. the duration of a bit cell in MFM is 2 microseconds. ----
---- 9. an address mark sync is represented as data A1 with missing clock ----
---- pulse between bit 4 and 5. ----
---- Examples: ----
---- Binary data FE 1 1 1 1 1 1 1 0 is represented in MFM as follows: ----
---- 0101010101010100 this is the ID address mark. ----
---- Binary data FB 1 1 1 1 1 0 1 1 is represented in MFM as follows: ----
---- 0101010101000101 this is the DATA address mark. ----
---- Binary data F8 1 1 1 1 1 0 0 0 is represented in MFM as follows: ----
---- 0101010101001010 this is the deleted DATA address mark. ----
---- the A1 data 1 0 1 0 0 0 0 1 is represented as follows: ----
---- 0100010010101001 ----
---- with the missing clock pulse between bits 4 and 5 there results: ----
---- results: 0100010010001001 this is the address mark sync. ----
---- ----
---- Both MFM and FM are during read and write shifted with most significant ----
---- bit (MSB) first. During the FM address marks are written without a ----
---- SYNC pulse the MFM coded data requires a synchronisation (A1 with ----
---- missing clock pulse because at the beginning of the data stream it is ----
---- not defined wether a clock pulse or a data pulse appears first. In FM ----
---- coding the first pulse is in any case a clock pulse. ----
---------------------------------------------------------------------------------
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 - 2008 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Revision 2K8A 2008/07/14 WF
-- Minor changes.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF1772IP_AM_DETECTOR is
port(
-- System control
CLK : in bit;
RESETn : in bit;
-- Controls:
DDEn : in bit;
-- Serial data and clock:
DATA : in bit;
DATA_STRB : in bit;
-- Address mark detector:
ID_AM : out bit; -- ID address mark strobe.
DATA_AM : out bit; -- Data address mark strobe.
DDATA_AM : out bit -- Deleted data address mark strobe.
);
end WF1772IP_AM_DETECTOR;
architecture BEHAVIOR of WF1772IP_AM_DETECTOR is
signal SHIFT : bit_vector(15 downto 0);
signal SYNC : boolean;
signal ID_AM_I : bit;
signal DATA_AM_I : bit;
signal DDATA_AM_I : bit;
begin
SHIFTREG: process(RESETn, CLK)
begin
if RESETn = '0' then
SHIFT <= (others => '0');
elsif CLK = '1' and CLK' event then
if DATA_STRB = '1' then
-- MSB first leads to a shift left operation.
SHIFT <= SHIFT(14 downto 0) & DATA;
elsif DDEn = '0' and SHIFT = "0100010010001001" then -- This is the synchronisation in MFM.
SHIFT <= (others => '0');
end if;
end if;
end process SHIFTREG;
MFM_SYNCLOCK: process(RESETn, CLK)
-- The SYNC pulse is generated in MFM mode only when the sync character
-- appears in the shift register (A1 sync mark, see file header).
-- After the sync character is detected, the sync time counter is loaded
-- with a value of 17. During counting the following 17 read clock pulses
-- down, the SYNC is true. After exactly 16 pulses the address mark is
-- detected if the pattern in the shift register fits one of the address
-- marks. The address mark pulses are valid for one read clock cycle until
-- SYNC goes low again. This mechanism is used to detect the correct address
-- marks in the MFM data stream during the type III read track command.
-- This is an improvement over the original WD1772 chip.
variable TMP : std_logic_vector(4 downto 0);
begin
if RESETn = '0' then
TMP := "00000";
elsif CLK = '1' and CLK' event then
if SHIFT = "0100010010001001" and DDEn = '0' then
TMP := "10001"; -- Load sync time counter.
elsif DATA_STRB = '1' and TMP > "00000" then
TMP := TMP - '1';
end if;
end if;
case TMP is
when "00000" => SYNC <= false;
when others => SYNC <= true;
end case;
end process MFM_SYNCLOCK;
-- The addressmark is nominally valid for one data pulse cycle (1us, 2us, 4us).
-- The pulse is shorter due to the fact that the detected address marks change the
-- state of the control state machine and so clear the address mark shift register...
ID_AM_I <= '1' when DDEn = '1' and SHIFT = "1111010101111110" else
'1' when DDEn = '0' and SHIFT = "0101010101010100" and SYNC = true else '0';
DATA_AM_I <= '1' when DDEn = '1' and SHIFT = "1111010101101111" else
-- Normal data address mark...
'1' when DDEn = '0' and SHIFT = "0101010101000101" and SYNC = true else '0';
DDATA_AM_I <= '1' when DDEn = '1' and SHIFT = "1111010101101010" else
-- ... and deleted address mark in MFM mode:
'1' when DDEn = '0' and SHIFT = "0101010101001010" and SYNC = true else '0';
ADRMARK_STROBES: process(RESETn, CLK)
-- ... nevertheless The controller and the transceiver require ID address mark strobes
-- and DATA address mark strobes. Therefore this process provides these strobe
-- signals independant of any 'feedbacks' like pulse shortening by the controller
-- state machine itself.
variable ID_AM_LOCK, DATA_AM_LOCK, DDATA_AM_LOCK : boolean;
begin
if RESETn = '0' then
ID_AM_LOCK := false;
DATA_AM_LOCK := false;
ID_AM <= '0';
DATA_AM <= '0';
elsif CLK = '1' and CLK' event then
-- ID address mark:
if ID_AM_I = '1' and ID_AM_LOCK = false then
ID_AM <= '1';
ID_AM_LOCK := true;
elsif ID_AM_I = '0' then
ID_AM <= '0';
ID_AM_LOCK := false;
else
ID_AM <= '0';
end if;
-- Data address mark:
if DATA_AM_I = '1' and DATA_AM_LOCK = false then
DATA_AM <= '1';
DATA_AM_LOCK := true;
elsif DATA_AM_I = '0' then
DATA_AM <= '0';
DATA_AM_LOCK := false;
else
DATA_AM <= '0';
end if;
-- Deleted data address mark:
if DDATA_AM_I = '1' and DDATA_AM_LOCK = false then
DDATA_AM <= '1';
DDATA_AM_LOCK := true;
elsif DDATA_AM_I = '0' then
DDATA_AM <= '0';
DDATA_AM_LOCK := false;
else
DDATA_AM <= '0';
end if;
end if;
end process ADRMARK_STROBES;
end architecture BEHAVIOR;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,162 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- The CRC cyclic redundancy checker unit. Further description ----
---- see below. ----
---- ----
---- Working principle of the CRC generator and verify unit: ----
---- During read operation: ----
---- The CRC generator is switched on via after the detection of ----
---- the address ID of the data ID mark. The CRC generation last ----
---- in case of the address ID until the lenght byte is read. ----
---- In case of generation after the data address mark the CRC ----
---- generator is activated until the last data byte is read. ----
---- The number of data bytes to be read depends on the LENGHT ----
---- information in the header file. After generation of the CRC ----
---- the CRC_GEN is switched off and the VERIFY procedure begins ----
---- by activating CRC_VERIFY. The previously generated CRC is ----
---- then compared (serially) with the two consecutive read CRC ----
---- bytes. The CRC error appeas, when the comparision fails. ----
---- During write operation: ----
---- The CRC generator is switched on via after the detection of ----
---- the address ID of the data ID mark. The CRC generation last ----
---- in case of the address ID until the lenght byte is read. ----
---- In case of generation after the data address mark the CRC ----
---- generator is activated until the last data byte is read. ----
---- The number of data bytes to be read depends on the LENGHT ----
---- information in the header file. After the generation of the ----
---- two CRC bytes, the write out process begins by activating ----
---- CRC_SHFTOUT. The CRC data appears in this case serially on ----
---- the CRC_SDOUT. ----
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 - 2008 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Revision 2K8A 2008/07/14 WF
-- Minor changes.
-- Revision 2K9A 2009/06/20 WF
-- CRC_SHIFT has now synchronous reset to meeet preset behaviour.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF1772IP_CRC_LOGIC is
port(
-- System control
CLK : in bit;
RESETn : in bit;
DISK_RWn : in bit;
-- Preset controls:
DDEn : in bit;
ID_AM : in bit;
DATA_AM : in Bit;
DDATA_AM : in Bit;
-- CRC unit:
SD : in bit; -- Serial data input.
CRC_STRB : in bit; -- Data strobe.
CRC_2_DISK : in bit; -- Forces the unit to flush the CRC remainder.
CRC_PRES : in bit; -- Presets the CRC unit during write to disk.
CRC_SDOUT : out bit; -- Serial data output.
CRC_ERR : out bit -- Indicates CRC error.
);
end WF1772IP_CRC_LOGIC;
architecture BEHAVIOR of WF1772IP_CRC_LOGIC is
signal CRC_SHIFT : bit_vector(15 downto 0);
begin
P_CRC: process
-- The shift register is initialised with appropriate values in HD or DD mode.
-- In theory the shift register should be preset to ones. Due to a latency of one byte
-- in FM mode or 4 bytes in MFM mode it is necessary to preset the shift register with
-- the CRC values of this ID address mark, data address mark and the A1 sync bytes. The
-- latency is caused by the addressmark detector which needs one or 4 byte time(s) for
-- detection. The CRC unit therefore starts with every detection of an address mark and
-- ends if the CRC unit is flushed.
begin
wait until CLK = '1' and CLK' event;
if RESETn = '0' then
CRC_SHIFT <= (others => '1');
elsif CRC_2_DISK = '1' then
if CRC_STRB = '1' then
CRC_SHIFT <= CRC_SHIFT(14 downto 0) & '0';
end if;
elsif CRC_PRES = '1' then -- Preset during write sector or write track command.
CRC_SHIFT <= x"FFFF";
elsif DDEn = '1' and ID_AM = '1' then -- DD mode and ID address mark detected.
CRC_SHIFT <= x"EF21"; -- The CRC-CCITT for data x"FE" is x"EF21"
elsif DDEn = '1' and DATA_AM = '1' then -- DD mode and data address mark detected.
CRC_SHIFT <= x"BF84"; -- The CRC-CCITT for data x"FB" is x"BF84"
elsif DDEn = '1' and DDATA_AM = '1' then -- DD mode and deleted data address mark detected.
CRC_SHIFT <= x"8FE7"; -- The CRC-CCITT for data x"F8" is x"8FE7"
elsif DDEn = '0' and ID_AM = '1' then -- HD mode and ID address mark detected.
CRC_SHIFT <= x"B230"; -- The CRC-CCITT for data x"A1A1A1FE" is x"B230"
elsif DDEn = '0' and DATA_AM = '1' then -- HD mode and data address mark detected.
CRC_SHIFT <= x"E295"; -- The CRC-CCITT for data x"A1A1A1FB" is x"E295"
elsif DDEn = '0' and DDATA_AM = '1' then -- HD mode and deleted data address mark detected.
CRC_SHIFT <= x"D2F6"; -- The CRC-CCITT for data x"A1A1A1F8" is x"D2F6"
elsif CRC_STRB = '1' then
-- CRC-CCITT (xFFFF):
-- the polynomial is G(x) = x^16 + x^12 + x^5 + 1
-- In this mode the CRC is encoded. In read from disk mode, the encoding works as CRC
-- verification. In this operating condition the ID or the data field is compared
-- against the CRC checksum. if there are no errors, the shift register's value is
-- x"0000" after the last bit of the checksum is shifted in. In write to disk mode the
-- CRC linear feedback shift register (lfsr) works to generate the CRC remainder of the
-- ID or data field.
CRC_SHIFT <= CRC_SHIFT(14 downto 12) & (CRC_SHIFT(15) xor CRC_SHIFT(11) xor SD) &
CRC_SHIFT(10 downto 5) & (CRC_SHIFT(15) xor CRC_SHIFT(4) xor SD) &
CRC_SHIFT(3 downto 0) & (CRC_SHIFT(15) xor SD);
end if;
end process P_CRC;
CRC_SDOUT <= CRC_SHIFT(15);
CRC_ERR <= '0' when CRC_SHIFT = x"0000" else '1';
end architecture BEHAVIOR;

View File

@@ -0,0 +1,426 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- The digital PLL is responsible to detect the incoming serial ----
---- data stream and provide a system clock synchronous signal ----
---- containing the data and clock information. ----
---- To understand how the code works in detail refer to the free ----
---- US patent no. 4,780,844. ----
---- ----
---- Attention: The settings for TOP and BOTTOM, which control ----
---- the PLL frequency and for PHASE_CORR which control the PLL ----
---- phase are rather critical for a good read condition! To test ----
---- the PLL in the WD1772 compatible core do the following: ----
---- Sample on an oscilloscope on one channel the falling edge of ----
---- the RDn pulse and on the other channel the PLL_DSTRB. The ----
---- RDn must be located exactly between the PLL_DSTRB pulses. ----
---- Otherwise, the parameters TOP, BOTTOM and PHASE_CORR have to ----
---- be optimized. ----
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 - 2008 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release: the MFM portion for HD and DD floppies is tested.
-- The FM mode (DDEn = '1') is not completely tested due to lack of FM
-- drives.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Revision 2K7B 2006/12/29 WF
-- Introduced several improvements based on a very good examination
-- of the pll code by Jean Louis-Guerin.
-- Revision 2K8A 2008/07/14 WF
-- Minor changes.
-- Revision 2K8B 2008/12/24 WF
-- Improvement of the INPORT process.
-- Bugfix of the FREQ_AMOUNT counter: now stops if its value is zero.
-- Several changes concerning the PLL parameters to improve the
-- stability of the PLL.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF1772IP_DIGITAL_PLL is
generic(
-- The valid range of the period counter of the PLL is given by the TOP and BOTTOM
-- limits. The counter range is therefore BOTTOM <= counter value <= TOP.
-- The generic PHASE_CORR is responsible fo the center setting of PLL_DSTRB concerning
-- the RDn period.
-- The nominal frequency setting is 128. So it is recommended to use TOP and BOTTOM
-- settings symmetrically around 128. If TOP = BOTTOM = 128, the frequency control
-- is disabled. TOP + PHASE_CORR may not exceed a value of 255. BOTTOM - PHASE_CORR
-- may not drop below zero.
TOP : integer range 0 to 255 := 152; -- +18.0%
BOTTOM : integer range 0 to 255 := 104; -- -18.0%
PHASE_CORR : integer range 0 to 128 := 75
);
port(
-- System control
CLK : in bit; -- 16MHz clock.
RESETn : in bit;
-- Controls
DDEn : in bit; -- Double density enable.
HDTYPE : in bit; -- This control is '1' when HD disks are inserted.
DISK_RWn : in bit; -- Read write control.
-- Data and clock lines
RDn : in bit; -- Read signal from the disk.
PLL_D : out bit; -- Synchronous read signal.
PLL_DSTRB : out bit -- Read strobe.
);
end WF1772IP_DIGITAL_PLL;
architecture BEHAVIOR of WF1772IP_DIGITAL_PLL is
signal RD_In : bit;
signal UP, DOWN : bit;
signal PHASE_DECREASE : bit;
signal PHASE_INCREASE : bit;
signal HI_STOP, LOW_STOP : bit;
signal PER_CNT : std_logic_vector(7 downto 0);
signal ADDER_IN : std_logic_vector(7 downto 0);
signal ADDER_MSBs : bit_vector(2 downto 0);
signal RD_PULSE : bit;
signal ROLL_OVER : bit;
signal HISTORY_REG : bit_vector(1 downto 0);
signal ERROR_HISTORY : integer range 0 to 2;
begin
INPORT: process
-- This process is necessary due to the poor quality of the rising
-- edge of RDn. Let it work on the negative clock edge.
begin
wait until CLK = '0' and CLK' event;
RD_In <= RDn;
end process INPORT;
EDGEDETECT: process(RESETn, CLK)
-- This process forms a falling edge detector for the incoming
-- data read port. The output (RD_PULSE) goes high for exactly
-- one clock period after the RDn is low and the positive
-- clock edge is detected.
variable LOCK : boolean;
begin
if RESETn = '0' then
RD_PULSE <= '0';
LOCK := false;
elsif CLK = '1' and CLK' event then
if DISK_RWn = '0' then -- Disable detector in write mode.
RD_PULSE <= '0';
elsif RD_In = '0' and LOCK = false then
RD_PULSE <= '1'; -- READ_PULSE is inverted against RDn
LOCK := true;
elsif RD_In = '1' then
LOCK := false;
RD_PULSE <= '0';
else
RD_PULSE <= '0';
end if;
end if;
end process EDGEDETECT;
PERIOD_CNT: process(RESETn, CLK)
-- This process provides the nominal variable added to the adder. To achieve a good
-- settling time of the PLL in all cases, the period counter is controlled via the DDEn
-- and HDTYPE flags respective to its added value. Be aware, that in case of adding "10"
-- or "11", the TOP value may be exceeded or the period counter may drop below the BOTTOM
-- value. The higher the value added, the faster will be the settling time of phase locked
-- loop .
begin
if RESETn = '0' then
PER_CNT <= "10000000"; -- Initial value is 128.
elsif CLK = '1' and CLK' event then
if UP = '1' then
PER_CNT <= PER_CNT + '1';
elsif DOWN = '1' then
PER_CNT <= PER_CNT - '1';
end if;
end if;
end process PERIOD_CNT;
HI_STOP <= '1' when PER_CNT >= TOP else '0';
LOW_STOP <= '1' when PER_CNT <= BOTTOM else '0';
ADDER_IN <= -- This DISK_RWn = '0' implementation keeps the last phase information
-- of the PLL in read from disk mode. It should be a good solution concer-
-- ning alternative read write cycles.
"10000000" when DISK_RWn = '0' else -- Nominal value for write to disk.
PER_CNT + PHASE_CORR when PHASE_INCREASE = '1' else -- Phase lags.
PER_CNT - PHASE_CORR when PHASE_DECREASE = '1' else -- Phase leeds.
PER_CNT; -- No phase correction;
ADDER: process(RESETn, CLK, DDEn, HDTYPE)
-- Clock adjustment: The clock cycle is 62.5ns for the 16MHz system clock.
-- The offset (LSBs) of the adder input is chosen to be conform with the required
-- rollover period in the different DDEn and HDTYPE modi as follows:
-- With a nominal adder input term of 128:
-- The adder rolls over every 4us for DDEn = 1 and HDTYPE = 0.
-- The adder rolls over every 2us for DDEn = 1 and HDTYPE = 1.
-- The adder rolls over every 2us for DDEn = 0 and HDTYPE = 0.
-- The adder rolls over every 1us for DDEn = 0 and HDTYPE = 1.
-- The given times are the half of a data period time in MFM or FM.
variable ADDER_DATA : std_logic_vector(12 downto 0);
begin
if RESETn = '0' then
ADDER_DATA := (others => '0');
elsif CLK = '1' and CLK' event then
ADDER_DATA := ADDER_DATA + ADDER_IN;
end if;
--
case DDEn & HDTYPE is
when "01" => -- MFM mode using HD disks, results in 1us inspection period:
ADDER_MSBs <= To_BitVector(ADDER_DATA(10 downto 8));
when "00" => -- MFM mode using DD disks, results in 2us inspection period:
ADDER_MSBs <= To_BitVector(ADDER_DATA(11 downto 9));
when "11" => -- FM mode using HD disks, results in 2us inspection period:
ADDER_MSBs <= To_BitVector(ADDER_DATA(11 downto 9));
when "10" => -- FM mode using DD disks, results in 4us inspection period:
ADDER_MSBs <= To_BitVector(ADDER_DATA(12 downto 10));
end case;
end process ADDER;
ROLLOVER: process(RESETn, CLK)
-- This process forms a falling edge detector for the detection
-- of the adder's rollover time. The output goes low for exactly
-- one clock period after the rollover is detected and the positive
-- clock edge appears.
variable LOCK : boolean;
begin
if RESETn = '0' then
ROLL_OVER <= '0';
LOCK := false;
elsif CLK = '1' and CLK' event then
if ADDER_MSBs /= "111" and LOCK = false then
ROLL_OVER <= '1';
LOCK := true;
elsif ADDER_MSBs = "111" then
LOCK := false;
ROLL_OVER <= '0';
else
ROLL_OVER <= '0';
end if;
end if;
end process ROLLOVER;
PLL_DSTRB <= ROLL_OVER;
DATA_FLIP_FLOP: process(RESETn, CLK, RD_PULSE)
-- This flip-flop is responsible for 'catching' the read pulses of the
-- serial data input.
begin
if RESETn = '0' then
PLL_D <= '0'; -- Asynchronous reset.
elsif CLK = '1' and CLK' event then
if RD_PULSE = '1' then
PLL_D <= '1'; -- Read pulse detected.
elsif ROLL_OVER = '1' then
PLL_D <= '0';
end if;
end if;
end process DATA_FLIP_FLOP;
WIN_HISTORY: process(RESETn, CLK)
begin
if RESETn = '0' then
HISTORY_REG <= "00";
elsif CLK = '1' and CLK' event then
if RD_PULSE = '1' then
HISTORY_REG <= ADDER_MSBs(2) & HISTORY_REG(1);
end if;
end if;
end process WIN_HISTORY;
-- Error history:
-- This signal indicates the number of consequtive levels of the adder's
-- MSB and the history register as shown in the following table. The default
-- setting of 0 was added to compile with the Xilinx ISE.
ERROR_HISTORY <= 2 when ADDER_MSBs(2) = '0' and HISTORY_REG = "00" else -- Speed strongly up.
1 when ADDER_MSBs(2) = '0' and HISTORY_REG = "01" else -- Speed up.
0 when ADDER_MSBs(2) = '0' and HISTORY_REG = "10" else -- o.k.
0 when ADDER_MSBs(2) = '0' and HISTORY_REG = "11" else -- Now adjusted.
0 when ADDER_MSBs(2) = '1' and HISTORY_REG = "00" else -- Now adjusted.
0 when ADDER_MSBs(2) = '1' and HISTORY_REG = "01" else -- o.k.
1 when ADDER_MSBs(2) = '1' and HISTORY_REG = "10" else -- Slow down.
2 when ADDER_MSBs(2) = '1' and HISTORY_REG = "11" else 0; -- Slow strongly down.
FREQUENCY_DECODER: process(RESETn, CLK, HI_STOP, LOW_STOP)
-- The frequency decoder controls the period of the data inspection window respective to the
-- ERROR_HISTORY for the 11 bit adder is as follows:
-- ERROR_HISTORY = 0:
-- -> no correction necessary <-
-- ERROR_HISTORY = 1:
-- MSBs input: 7 6 5 4 3 2 1 0
-- Correction output: -3 -2 -1 0 0 +1 +2 +3
-- ERROR_HISTORY = 2:
-- MSBs input: 7 6 5 4 3 2 1 0
-- Correction output: -4 -3 -2 -1 +1 +2 +3 +4
-- The most significant bit of the FREQ_AMOUNT controls incrementation or decrementation
-- of the adder (0 is up).
variable FREQ_AMOUNT: std_logic_vector(3 downto 0);
begin
if RESETn = '0' then
FREQ_AMOUNT := "0000";
elsif CLK = '1' and CLK' event then
if RD_PULSE = '1' then -- Load the frequency amount register.
case ERROR_HISTORY is
when 2 =>
case ADDER_MSBs is
when "000" => FREQ_AMOUNT := "0100";
when "001" => FREQ_AMOUNT := "0011";
when "010" => FREQ_AMOUNT := "0010";
when "011" => FREQ_AMOUNT := "0001";
when "100" => FREQ_AMOUNT := "1001";
when "101" => FREQ_AMOUNT := "1010";
when "110" => FREQ_AMOUNT := "1011";
when "111" => FREQ_AMOUNT := "1100";
end case;
when 1 =>
case ADDER_MSBs is
when "000" => FREQ_AMOUNT := "0011";
when "001" => FREQ_AMOUNT := "0010";
when "010" => FREQ_AMOUNT := "0001";
when "011" => FREQ_AMOUNT := "0000";
when "100" => FREQ_AMOUNT := "1000";
when "101" => FREQ_AMOUNT := "1001";
when "110" => FREQ_AMOUNT := "1010";
when "111" => FREQ_AMOUNT := "1011";
end case;
when others =>
FREQ_AMOUNT := "0000";
end case;
elsif FREQ_AMOUNT(2 downto 0) > "000" then
FREQ_AMOUNT := FREQ_AMOUNT - '1'; -- Modify the frequency amount register.
end if;
end if;
--
if FREQ_AMOUNT(3) = '0' and FREQ_AMOUNT(2 downto 0) /= "000" and HI_STOP = '0' then
-- FREQ_AMOUNT(3) = '0' means Frequency is too low. Count up when counter is not at HI_STOP.
UP <= '1';
DOWN <= '0';
elsif FREQ_AMOUNT(3) = '1' and FREQ_AMOUNT (2 downto 0) /= "000" and LOW_STOP = '0' then
-- FREQ_AMOUNT(3) = '1' means Frequency is too high. Count down when counter is not at LOW_STOP.
UP <= '0';
DOWN <= '1';
else
UP <= '0';
DOWN <= '0';
end if;
end process FREQUENCY_DECODER;
PHASE_DECODER: process(RESETn, CLK)
-- The phase decoder depends on the value of ADDER_MSBs. If the phase leeds, the most significant bit
-- of PHASE_AMOUNT indicates with a '0', that the next rollover should appear earlier. In case of a
-- phase lag, the next rollover should come later (indicated by a '1' of the most significant bit of
-- PHASE_AMOUNT).
-- This implementation gives the freedom to adjust the phase amount individually for every mode
-- depending on DDEn and HDTYPE.
variable PHASE_AMOUNT: std_logic_vector(5 downto 0);
begin
if RESETn = '0' then
PHASE_AMOUNT := "000000";
elsif CLK = '1' and CLK' event then
if RD_PULSE = '1' and DDEn = '1' and HDTYPE = '0' then -- FM mode, single density.
case ADDER_MSBs is -- Multiplier: 4.
when "000" => PHASE_AMOUNT := "010000";
when "001" => PHASE_AMOUNT := "001101";
when "010" => PHASE_AMOUNT := "001000";
when "011" => PHASE_AMOUNT := "000100";
when "100" => PHASE_AMOUNT := "100100";
when "101" => PHASE_AMOUNT := "101000";
when "110" => PHASE_AMOUNT := "101100";
when "111" => PHASE_AMOUNT := "110000";
end case;
elsif RD_PULSE = '1' and DDEn = '1' and HDTYPE = '1' then -- FM mode, double density
case ADDER_MSBs is -- Multiplier: 2.
when "000" => PHASE_AMOUNT := "001000";
when "001" => PHASE_AMOUNT := "000110";
when "010" => PHASE_AMOUNT := "000100";
when "011" => PHASE_AMOUNT := "000010";
when "100" => PHASE_AMOUNT := "100010";
when "101" => PHASE_AMOUNT := "100100";
when "110" => PHASE_AMOUNT := "100110";
when "111" => PHASE_AMOUNT := "101000";
end case;
elsif RD_PULSE = '1' and DDEn = '0' and HDTYPE = '0' then -- MFM mode, single density
case ADDER_MSBs is -- Multiplier: 2.
when "000" => PHASE_AMOUNT := "000110";
when "001" => PHASE_AMOUNT := "000100";
when "010" => PHASE_AMOUNT := "000011";
when "011" => PHASE_AMOUNT := "000010";
when "100" => PHASE_AMOUNT := "100010";
when "101" => PHASE_AMOUNT := "100011";
when "110" => PHASE_AMOUNT := "100100";
when "111" => PHASE_AMOUNT := "100110";
end case;
elsif RD_PULSE = '1' and DDEn = '0' and HDTYPE = '1' then -- MFM mode, double density.
case ADDER_MSBs is -- Multiplier: 1.
when "000" => PHASE_AMOUNT := "000100";
when "001" => PHASE_AMOUNT := "000011";
when "010" => PHASE_AMOUNT := "000010";
when "011" => PHASE_AMOUNT := "000001";
when "100" => PHASE_AMOUNT := "100001";
when "101" => PHASE_AMOUNT := "100010";
when "110" => PHASE_AMOUNT := "100011";
when "111" => PHASE_AMOUNT := "100100";
end case;
else -- Modify phase amount register:
if PHASE_AMOUNT(4 downto 0) > x"0" then
PHASE_AMOUNT := PHASE_AMOUNT - 1;
end if;
end if;
end if;
--
if PHASE_AMOUNT(5) = '0' and PHASE_AMOUNT(4 downto 0) > x"0" then
-- PHASE_AMOUNT(5) = '0' means, that the phase leeds.
PHASE_INCREASE <= '1'; -- Speed phase up, accelerate next rollover.
PHASE_DECREASE <= '0';
elsif PHASE_AMOUNT(5) = '1' and PHASE_AMOUNT(4 downto 0) > x"0" then
-- PHASE_AMOUNT(5) = '1' means, that the phase lags.
PHASE_INCREASE <= '0';
PHASE_DECREASE <= '1'; -- Speed phase down, delay of next rollover.
else
PHASE_INCREASE <= '0';
PHASE_DECREASE <= '0';
end if;
end process PHASE_DECODER;
end architecture BEHAVIOR;

View File

@@ -0,0 +1,232 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- This is the package file containing the component ----
---- declarations. ----
---- ----
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 - 2008 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Revision 2K8A 2008/07/14 WF
-- Minor changes.
-- Removed CRC_BUSY.
library ieee;
use ieee.std_logic_1164.all;
package WF1772IP_PKG is
-- component declarations:
component WF1772IP_AM_DETECTOR
port(
CLK : in bit;
RESETn : in bit;
DDEn : in bit;
DATA : in bit;
DATA_STRB : in bit;
ID_AM : out bit;
DATA_AM : out bit;
DDATA_AM : out bit
);
end component;
component WF1772IP_CONTROL
port(
CLK : in bit;
RESETn : in bit;
A1, A0 : in bit;
RWn : in bit;
CSn : in bit;
DDEn : in bit;
DR : in bit_vector(7 downto 0);
CMD : in std_logic_vector(7 downto 0);
DSR : in std_logic_vector(7 downto 0);
TR : in std_logic_vector(7 downto 0);
SR : in std_logic_vector(7 downto 0);
MO : out bit;
WR_PR : out bit;
SPINUP_RECTYPE : out bit;
SEEK_RNF : out bit;
CRC_ERRFLAG : out bit;
LOST_DATA_TR00 : out bit;
DRQ : out bit;
DRQ_IPn : out bit;
BUSY : out bit;
AM_2_DISK : out bit;
ID_AM : in bit;
DATA_AM : in bit;
DDATA_AM : in bit;
CRC_ERR : in bit;
CRC_PRES : out bit;
TR_PRES : out bit;
TR_CLR : out bit;
TR_INC : out bit;
TR_DEC : out bit;
SR_LOAD : out bit;
SR_INC : out bit;
TRACK_NR : out std_logic_vector(7 downto 0);
DR_CLR : out bit;
DR_LOAD : out bit;
SHFT_LOAD_SD : out bit;
SHFT_LOAD_ND : out bit;
CRC_2_DISK : out bit;
DSR_2_DISK : out bit;
FF_2_DISK : out bit;
PRECOMP_EN : out bit;
DATA_STRB : in bit;
DISK_RWn : out bit;
WPRTn : in bit;
TRACK00n : in bit;
IPn : in bit;
DIRC : out bit;
STEP : out bit;
WG : out bit;
INTRQ : out bit
);
end component;
component WF1772IP_CRC_LOGIC
port(
CLK : in bit;
RESETn : in bit;
DDEn : in bit;
DISK_RWn : in bit;
ID_AM : in bit;
DATA_AM : in bit;
DDATA_AM : in bit;
SD : in bit;
CRC_STRB : in bit;
CRC_2_DISK : in bit;
CRC_PRES : in bit;
CRC_SDOUT : out bit;
CRC_ERR : out bit
);
end component;
component WF1772IP_DIGITAL_PLL
port(
CLK : in bit;
RESETn : in bit;
DDEn : in bit;
HDTYPE : in bit;
DISK_RWn : in bit;
RDn : in bit;
PLL_D : out bit;
PLL_DSTRB : out bit
);
end component;
component WF1772IP_REGISTERS
port(
CLK : in bit;
RESETn : in bit;
CSn : in bit;
ADR : in bit_vector(1 downto 0);
RWn : in bit;
DATA_IN : in std_logic_vector (7 downto 0);
DATA_OUT : out std_logic_vector (7 downto 0);
DATA_EN : out bit;
CMD : out std_logic_vector(7 downto 0);
SR : out std_logic_vector(7 downto 0);
TR : out std_logic_vector(7 downto 0);
DSR : out std_logic_vector(7 downto 0);
DR : out bit_vector(7 downto 0);
SD_R : in bit;
DATA_STRB : in bit;
DR_CLR : in bit;
DR_LOAD : in bit;
TR_PRES : in bit;
TR_CLR : in bit;
TR_INC : in bit;
TR_DEC : in bit;
TRACK_NR : in std_logic_vector(7 downto 0);
SR_LOAD : in bit;
SR_INC : in bit;
SHFT_LOAD_SD : in bit;
SHFT_LOAD_ND : in bit;
MOTOR_ON : in bit;
WRITE_PROTECT : in bit;
SPINUP_RECTYPE : in bit;
SEEK_RNF : in bit;
CRC_ERRFLAG : in bit;
LOST_DATA_TR00 : in bit;
DRQ : in bit;
DRQ_IPn : in bit;
BUSY : in bit;
DDEn : in bit
);
end component;
component WF1772IP_TRANSCEIVER
port(
CLK : in bit;
RESETn : in bit;
DDEn : in bit;
HDTYPE : in bit;
ID_AM : in bit;
DATA_AM : in bit;
DDATA_AM : in bit;
SHFT_LOAD_SD : in bit;
DR : in bit_vector(7 downto 0);
PRECOMP_EN : in bit;
AM_TYPE : in bit;
AM_2_DISK : in bit;
CRC_2_DISK : in bit;
DSR_2_DISK : in bit;
FF_2_DISK : in bit;
SR_SDOUT : in std_logic;
CRC_SDOUT : in bit;
WRn : out bit;
PLL_DSTRB : in bit;
PLL_D : in bit;
WDATA : out bit;
DATA_STRB : out bit;
SD_R : out bit
);
end component;
end WF1772IP_PKG;

View File

@@ -0,0 +1,264 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- This file models all the five WD1772 registers: DATA-, ----
---- COMMAND-, SECTOR-, TRACK- and STATUS register as also the ----
---- shift register. ----
---- ----
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 - 2008 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Revision 2K8A 2008/07/14 WF
-- Minor changes.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF1772IP_REGISTERS is
port(
-- System control:
CLK : in bit;
RESETn : in bit;
-- Bus interface:
CSn : in bit;
ADR : in bit_vector(1 downto 0);
RWn : in bit;
DATA_IN : in std_logic_vector (7 downto 0);
DATA_OUT : out std_logic_vector (7 downto 0);
DATA_EN : out bit;
-- FDC data:
CMD : out std_logic_vector(7 downto 0); -- Command register.
SR : out std_logic_vector(7 downto 0); -- Sector register.
TR : out std_logic_vector(7 downto 0); -- Track register.
DSR : out std_logic_vector(7 downto 0); -- Data shift register.
DR : out bit_vector(7 downto 0); -- Data register.
-- Serial data and clock strobes (in and out):
DATA_STRB : in bit; -- Strobe for the incoming data.
SD_R : in bit; -- Serial data input.
-- DATA register control:
DR_CLR : in bit; -- Clear.
DR_LOAD : in bit; -- LOAD.
-- Track register controls:
TR_PRES : in bit; -- Set x"FF".
TR_CLR : in bit; -- Clear.
TR_INC : in bit; -- Increment.
TR_DEC : in bit; -- Decrement.
-- Sector register control:
TRACK_NR : in std_logic_vector(7 downto 0);
SR_LOAD : in bit; -- Load.
SR_INC : in bit; -- Increment.
-- Shift register control:
SHFT_LOAD_SD : in bit;
SHFT_LOAD_ND : in bit;
-- Status register stuff
MOTOR_ON : in bit;
WRITE_PROTECT : in bit;
SPINUP_RECTYPE : in bit; -- Disk is on speed / data mark status.
SEEK_RNF : in bit; -- Seek error / record not found status flag.
CRC_ERRFLAG : in bit; -- CRC status flag.
LOST_DATA_TR00 : in bit;
DRQ : in bit;
DRQ_IPn : in bit;
BUSY : in bit;
-- Others:
DDEn : in bit
);
end WF1772IP_REGISTERS;
architecture BEHAVIOR of WF1772IP_REGISTERS is
-- Remark: In the original data sheet 'WD17X-00' there is the following statement:
-- "After any register is written to, the same register cannot be read from until
-- 16us in MFM or 32us in FMMM have elapsed." If this is a hint for a hardware read
-- lock ... this lock is not implemented in this code.
signal SHIFT_REG : std_logic_vector(7 downto 0);
signal DATA_REG : std_logic_vector(7 downto 0);
signal COMMAND_REG : std_logic_vector(7 downto 0);
signal SECTOR_REG : std_logic_vector(7 downto 0);
signal TRACK_REG : std_logic_vector(7 downto 0);
signal STATUS_REG : bit_vector(7 downto 0);
signal SD_R_I : std_logic;
begin
-- Type conversion To_Std_Logic:
SD_R_I <= '1' when SD_R = '1' else '0';
P_SHIFTREG: process(RESETn, CLK)
begin
if RESETn = '0' then
SHIFT_REG <= x"00";
elsif CLK = '1' and CLK' event then
if SHFT_LOAD_ND = '1' then
SHIFT_REG <= DATA_REG; -- Load data register stuff.
elsif SHFT_LOAD_SD = '1' and DDEn = '1' then
SHIFT_REG <= DATA_REG; -- Normal data in FM mode.
elsif SHFT_LOAD_SD = '1' and DDEn = '0' then -- MFM mode:
case DATA_REG is
when x"F5" => SHIFT_REG <= x"A1"; -- Special character.
when x"F6" => SHIFT_REG <= x"C2"; -- Special character.
when others => SHIFT_REG <= DATA_REG; -- Normal MFM data.
end case;
elsif DATA_STRB = '1' then -- Shift left during read from disk or write to disk.
SHIFT_REG <= SHIFT_REG(6 downto 0) & SD_R_I; -- for write operation SD_R_I is a dummy.
end if;
end if;
end process P_SHIFTREG;
DSR <= SHIFT_REG;
DATAREG: process(RESETn, CLK)
begin
if RESETn = '0' then
DATA_REG <= x"00";
elsif CLK = '1' and CLK' event then
if CSn = '0' and ADR = "11" and RWn = '0' then
DATA_REG <= DATA_IN; -- Write bus data to register
elsif DR_LOAD = '1' and DRQ = '0' then
DATA_REG <= SHIFT_REG; -- Correct data loaded to shift register.
elsif DR_LOAD = '1' and DRQ = '1' then
DATA_REG <= x"00"; -- Dummy byte due to lost data loaded to shift register.
elsif DR_CLR = '1' then
DATA_REG <= (others => '0');
end if;
end if;
end process DATAREG;
-- Data register buffered for further data processing.
DR <= To_BitVector(DATA_REG);
SECTORREG: process(RESETn, CLK)
begin
if RESETn = '0' then
SECTOR_REG <= x"00";
elsif CLK = '1' and CLK' event then
if CSn = '0' and ADR = "10" and RWn = '0' and BUSY = '0' then
SECTOR_REG <= DATA_IN; -- Write to register when device is not busy.
elsif SR_LOAD = '1' then
-- Load the track number to the sector register in the type III command
-- 'Read Address'.
SECTOR_REG <= TRACK_NR;
elsif SR_INC = '1' then
SECTOR_REG <= SECTOR_REG + '1';
end if;
end if;
end process SECTORREG;
SR <= SECTOR_REG;
TRACKREG: process(RESETn, CLK)
begin
if RESETn = '0' then
TRACK_REG <= x"00";
elsif CLK = '1' and CLK' event then
if CSn = '0' and ADR = "01" and RWn = '0' and BUSY = '0' then
TRACK_REG <= DATA_IN; -- Write to register when device is busy.
elsif TR_PRES = '1' then
TRACK_REG <= (others => '1'); -- Preset the track register.
elsif TR_CLR = '1' then
TRACK_REG <= (others => '0'); -- Reset the track register.
elsif TR_INC = '1' then
TRACK_REG <= TRACK_REG + '1'; -- Increment register contents.
elsif TR_DEC = '1' then
TRACK_REG <= TRACK_REG - '1'; -- Decrement register contents.
end if;
end if;
end process TRACKREG;
TR <= TRACK_REG;
COMMANDREG: process(RESETn, CLK)
-- The command register is write only.
begin
if RESETn = '0' then
COMMAND_REG <= x"00";
elsif CLK = '1' and CLK' event then
if CSn = '0' and ADR = "00" and RWn = '0' and BUSY = '0' then
COMMAND_REG <= DATA_IN; -- Write to register when device is not busy.
-- Write 'force interrupt' to register even when device is busy:
elsif CSn = '0' and ADR = "00" and RWn = '0' and DATA_IN(7 downto 4) = x"D" then
COMMAND_REG <= DATA_IN;
end if;
end if;
end process COMMANDREG;
CMD <= COMMAND_REG;
STATUSREG: process(RESETn, CLK)
-- The status register is read only to the data bus.
begin
-- Status register wiring:
if RESETn = '0' then
STATUS_REG <= x"00";
elsif CLK = '1' and CLK' event then
STATUS_REG(7) <= MOTOR_ON;
STATUS_REG(6) <= WRITE_PROTECT;
STATUS_REG(5) <= SPINUP_RECTYPE;
STATUS_REG(4) <= SEEK_RNF;
STATUS_REG(3) <= CRC_ERRFLAG;
STATUS_REG(2) <= LOST_DATA_TR00;
STATUS_REG(1) <= DRQ_IPn;
STATUS_REG(0) <= BUSY;
end if;
end process STATUSREG;
-- Read from track, sector or data register:
-- The register data after writing to the track register is valid at least
-- after 32us in FM mode and after 16us in MFM mode.
-- Read from status register. This register is read only:
-- Be aware, that the status register data bits 7 to 1 after writing
-- the command regsiter are valid at least after 64us in FM mode or 32us in MFM mode and
-- the bit 0 (BUSY) is valid after 48us in FM mode or 24us in MFM mode.
DATA_OUT <= TRACK_REG when CSn = '0' and ADR = "01" and RWn = '1' else
SECTOR_REG when CSn = '0' and ADR = "10" and RWn = '1' else
DATA_REG when CSn = '0' and ADR = "11" and RWn = '1' else
To_StdLogicVector(STATUS_REG) when CSn = '0' and ADR = "00" and RWn = '1' else (others => '0');
DATA_EN <= '1' when CSn = '0' and RWn = '1' else '0';
end architecture BEHAVIOR;

View File

@@ -0,0 +1,154 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- This is the top level file. ----
---- ----
---- ----
---- To Do: ----
---- - Test of the FM portion of the code (if there is any need). ----
---- - Test of the read track command. ----
---- - Test of the read address command. ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release: the MFM portion for HD and DD floppies is tested.
-- The FM mode (DDEn = '1') is not completely tested due to the lack
-- of FM drives.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Fixed the polarity of the precompensation flag.
-- The flag is no active '0'. Thanks to Jorma
-- Oksanen for the information.
-- Revision 2K7B 2006/12/29 WF
-- Introduced several improvements based on a very good examination
-- of the pll code by Jean Louis-Guerin.
-- Revision 2K8B 2008/12/24 WF
-- Rewritten this top level file as a wrapper for the top_soc file.
library work;
use work.WF1772IP_PKG.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF1772IP_TOP is
port (
CLK : in bit; -- 16MHz clock!
MRn : in bit;
CSn : in bit;
RWn : in bit;
A1, A0 : in bit;
DATA : inout std_logic_vector(7 downto 0);
RDn : in bit;
TR00n : in bit;
IPn : in bit;
WPRTn : in bit;
DDEn : in bit;
HDTYPE : in bit; -- '0' = DD disks, '1' = HD disks.
MO : out bit;
WG : out bit;
WD : out bit;
STEP : out bit;
DIRC : out bit;
DRQ : out bit;
INTRQ : out bit
);
end entity WF1772IP_TOP;
architecture STRUCTURE of WF1772IP_TOP is
component WF1772IP_TOP_SOC
port (
CLK : in bit;
RESETn : in bit;
CSn : in bit;
RWn : in bit;
A1, A0 : in bit;
DATA_IN : in std_logic_vector(7 downto 0);
DATA_OUT : out std_logic_vector(7 downto 0);
DATA_EN : out bit;
RDn : in bit;
TR00n : in bit;
IPn : in bit;
WPRTn : in bit;
DDEn : in bit;
HDTYPE : in bit;
MO : out bit;
WG : out bit;
WD : out bit;
STEP : out bit;
DIRC : out bit;
DRQ : out bit;
INTRQ : out bit
);
end component;
signal DATA_OUT : std_logic_vector(7 downto 0);
signal DATA_EN : bit;
begin
DATA <= DATA_OUT when DATA_EN = '1' else (others => 'Z');
I_1772: WF1772IP_TOP_SOC
port map(
CLK => CLK,
RESETn => MRn,
CSn => CSn,
RWn => RWn,
A1 => A1,
A0 => A0,
DATA_IN => DATA,
DATA_OUT => DATA_OUT,
DATA_EN => DATA_EN,
RDn => RDn,
TR00n => TR00n,
IPn => IPn,
WPRTn => WPRTn,
DDEn => DDEn,
HDTYPE => HDTYPE,
MO => MO,
WG => WG,
WD => WD,
STEP => STEP,
DIRC => DIRC,
DRQ => DRQ,
INTRQ => INTRQ
);
end architecture STRUCTURE;

View File

@@ -0,0 +1,333 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- Top level file for use in systems on programmable chips. ----
---- ----
---- ----
---- To Do: ----
---- - Test of the FM portion of the code (if there is any need). ----
---- - Test of the read track command. ----
---- - Test of the read address command. ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 - 2008 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release: the MFM portion for HD and DD floppies is tested.
-- The FM mode (DDEn = '1') is not completely tested due to the lack
-- of FM drives.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Fixed the polarity of the precompensation flag.
-- The flag is no active '0'. Thanks to Jorma Oksanen for the information.
-- Top level file provided for SOC (systems on programmable chips).
-- Revision 2K7B 2006/12/29 WF
-- Introduced several improvements based on a very good examination
-- of the pll code by Jean Louis-Guerin.
-- Revision 2K8A 2008/07/14 WF
-- Minor changes.
-- Revision 2K8B 2008/12/24 WF
-- Bugfixes in the controller due to hanging state machine.
-- Removed CRC_BUSY.
--
library work;
use work.WF1772IP_PKG.all;
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF1772IP_TOP_SOC is
port (
CLK : in bit; -- 16MHz clock!
RESETn : in bit;
CSn : in bit;
RWn : in bit;
A1, A0 : in bit;
DATA_IN : in std_logic_vector(7 downto 0);
DATA_OUT : out std_logic_vector(7 downto 0);
DATA_EN : out bit;
RDn : in bit;
TR00n : in bit;
IPn : in bit;
WPRTn : in bit;
DDEn : in bit;
HDTYPE : in bit; -- '0' = DD disks, '1' = HD disks.
MO : out bit;
WG : out bit;
WD : out bit;
STEP : out bit;
DIRC : out bit;
DRQ : out bit;
INTRQ : out bit
);
end entity WF1772IP_TOP_SOC;
architecture STRUCTURE of WF1772IP_TOP_SOC is
signal DATA_OUT_REG : std_logic_vector(7 downto 0);
signal DATA_EN_REG : bit;
signal CMD_I : std_logic_vector(7 downto 0);
signal DR_I : bit_vector(7 downto 0);
signal DSR_I : std_logic_vector(7 downto 0);
signal TR_I : std_logic_vector(7 downto 0);
signal SR_I : std_logic_vector(7 downto 0);
signal ID_AM_I : bit;
signal DATA_AM_I : bit;
signal DDATA_AM_I : bit;
signal AM_TYPE_I : bit;
signal AM_2_DISK_I : bit;
signal DATA_STRB_I : bit;
signal BUSY_I : bit;
signal DRQ_I : bit;
signal DRQ_IPn_I : bit;
signal LD_TR00_I : bit;
signal SP_RT_I : bit;
signal SEEK_RNF_I : bit;
signal WR_PR_I : bit;
signal MO_I : bit;
signal PLL_DSTRB_I : bit;
signal PLL_D_I : bit;
signal CRC_SD_I : bit;
signal CRC_ERR_I : bit;
signal CRC_PRES_I : bit;
signal CRC_ERRFLAG_I : bit;
signal SD_R_I : bit;
signal CRC_SDOUT_I : bit;
signal SHFT_LOAD_SD_I : bit;
signal SHFT_LOAD_ND_I : bit;
signal WR_In : bit;
signal TR_PRES_I : bit;
signal TR_CLR_I : bit;
signal TR_INC_I : bit;
signal TR_DEC_I : bit;
signal SR_LOAD_I : bit;
signal SR_INC_I : bit;
signal DR_CLR_I : bit;
signal DR_LOAD_I : bit;
signal TRACK_NR_I : std_logic_vector(7 downto 0);
signal CRC_2_DISK_I : bit;
signal DSR_2_DISK_I : bit;
signal FF_2_DISK_I : bit;
signal PRECOMP_EN_I : bit;
signal DISK_RWn_I : bit;
signal WDATA_I : bit;
begin
-- Three state data bus:
DATA_OUT <= DATA_OUT_REG when DATA_EN_REG = '1' else (others => '0');
DATA_EN <= DATA_EN_REG;
-- Some signals copied to the outputs:
WD <= not WR_In;
MO <= MO_I;
DRQ <= DRQ_I;
-- Write deleted data address mark in MFM mode in 'Write Sector' command in
-- case of asserted command bit 0.
AM_TYPE_I <= '0' when CMD_I(7 downto 5) = "101" and CMD_I(0) = '1' else '1';
-- The CRC unit is used during read from disk and write to disk.
-- This is the data multiplexer for the data stream to encode.
CRC_SD_I <= SD_R_I when DISK_RWn_I = '1' else WDATA_I;
I_CONTROL: WF1772IP_CONTROL
port map(
CLK => CLK,
RESETn => RESETn,
A1 => A0,
A0 => A1,
RWn => RWn,
CSn => CSn,
DDEn => DDEn,
DR => DR_I,
CMD => CMD_I,
DSR => DSR_I,
TR => TR_I,
SR => SR_I,
MO => MO_I,
WR_PR => WR_PR_I,
SPINUP_RECTYPE => SP_RT_I,
SEEK_RNF => SEEK_RNF_I,
CRC_ERRFLAG => CRC_ERRFLAG_I,
LOST_DATA_TR00 => LD_TR00_I,
DRQ => DRQ_I,
DRQ_IPn => DRQ_IPn_I,
BUSY => BUSY_I,
AM_2_DISK => AM_2_DISK_I,
ID_AM => ID_AM_I,
DATA_AM => DATA_AM_I,
DDATA_AM => DDATA_AM_I,
CRC_ERR => CRC_ERR_I,
CRC_PRES => CRC_PRES_I,
TR_PRES => TR_PRES_I,
TR_CLR => TR_CLR_I,
TR_INC => TR_INC_I,
TR_DEC => TR_DEC_I,
SR_LOAD => SR_LOAD_I,
SR_INC => SR_INC_I,
TRACK_NR => TRACK_NR_I,
DR_CLR => DR_CLR_I,
DR_LOAD => DR_LOAD_I,
SHFT_LOAD_SD => SHFT_LOAD_SD_I,
SHFT_LOAD_ND => SHFT_LOAD_ND_I,
CRC_2_DISK => CRC_2_DISK_I,
DSR_2_DISK => DSR_2_DISK_I,
FF_2_DISK => FF_2_DISK_I,
PRECOMP_EN => PRECOMP_EN_I,
DATA_STRB => DATA_STRB_I,
DISK_RWn => DISK_RWn_I,
WPRTn => WPRTn,
TRACK00n => TR00n,
IPn => IPn,
DIRC => DIRC,
STEP => STEP,
WG => WG,
INTRQ => INTRQ
);
I_REGISTERS: WF1772IP_REGISTERS
port map(
CLK => CLK,
RESETn => RESETn,
CSn => CSn,
ADR(1) => A1,
ADR(0) => A0,
RWn => RWn,
DATA_IN => DATA_IN,
DATA_OUT => DATA_OUT_REG,
DATA_EN => DATA_EN_REG,
CMD => CMD_I,
TR => TR_I,
SR => SR_I,
DSR => DSR_I,
DR => DR_I,
SD_R => SD_R_I,
DATA_STRB => DATA_STRB_I,
DR_CLR => DR_CLR_I,
DR_LOAD => DR_LOAD_I,
TR_PRES => TR_PRES_I,
TR_CLR => TR_CLR_I,
TR_INC => TR_INC_I,
TR_DEC => TR_DEC_I,
TRACK_NR => TRACK_NR_I,
SR_LOAD => SR_LOAD_I,
SR_INC => SR_INC_I,
SHFT_LOAD_SD => SHFT_LOAD_SD_I,
SHFT_LOAD_ND => SHFT_LOAD_ND_I,
MOTOR_ON => MO_I,
WRITE_PROTECT => WR_PR_I,
SPINUP_RECTYPE => SP_RT_I,
SEEK_RNF => SEEK_RNF_I,
CRC_ERRFLAG => CRC_ERRFLAG_I,
LOST_DATA_TR00 => LD_TR00_I,
DRQ => DRQ_I,
DRQ_IPn => DRQ_IPn_I,
BUSY => BUSY_I,
DDEn => DDEn
);
I_DIGITAL_PLL: WF1772IP_DIGITAL_PLL
port map(
CLK => CLK,
RESETn => RESETn,
DDEn => DDEn,
HDTYPE => HDTYPE,
DISK_RWn => DISK_RWn_I,
RDn => RDn,
PLL_D => PLL_D_I,
PLL_DSTRB => PLL_DSTRB_I
);
I_AM_DETECTOR: WF1772IP_AM_DETECTOR
port map(
CLK => CLK,
RESETn => RESETn,
DDEn => DDEn,
DATA => PLL_D_I,
DATA_STRB => PLL_DSTRB_I,
ID_AM => ID_AM_I,
DATA_AM => DATA_AM_I,
DDATA_AM => DDATA_AM_I
);
I_CRC_LOGIC: WF1772IP_CRC_LOGIC
port map(
CLK => CLK,
RESETn => RESETn,
DDEn => DDEn,
DISK_RWn => DISK_RWn_I,
ID_AM => ID_AM_I,
DATA_AM => DATA_AM_I,
DDATA_AM => DDATA_AM_I,
SD => CRC_SD_I,
CRC_STRB => DATA_STRB_I,
CRC_2_DISK => CRC_2_DISK_I,
CRC_PRES => CRC_PRES_I,
CRC_SDOUT => CRC_SDOUT_I,
CRC_ERR => CRC_ERR_I
);
I_TRANSCEIVER: WF1772IP_TRANSCEIVER
port map(
CLK => CLK,
RESETn => RESETn,
DDEn => DDEn,
HDTYPE => HDTYPE,
ID_AM => ID_AM_I,
DATA_AM => DATA_AM_I,
DDATA_AM => DDATA_AM_I,
SHFT_LOAD_SD => SHFT_LOAD_SD_I,
DR => DR_I,
PRECOMP_EN => PRECOMP_EN_I,
AM_TYPE => AM_TYPE_I,
AM_2_DISK => AM_2_DISK_I,
CRC_2_DISK => CRC_2_DISK_I,
DSR_2_DISK => DSR_2_DISK_I,
FF_2_DISK => FF_2_DISK_I,
SR_SDOUT => DSR_I(7),
CRC_SDOUT => CRC_SDOUT_I,
WRn => WR_In,
WDATA => WDATA_I,
PLL_DSTRB => PLL_DSTRB_I,
PLL_D => PLL_D_I,
DATA_STRB => DATA_STRB_I,
SD_R => SD_R_I
);
end architecture STRUCTURE;

View File

@@ -0,0 +1,517 @@
----------------------------------------------------------------------
---- ----
---- WD1772 compatible floppy disk controller IP Core. ----
---- ----
---- This file is part of the SUSKA ATARI clone project. ----
---- http://www.experiment-s.de ----
---- ----
---- Description: ----
---- Floppy disk controller with all features of the Western ----
---- Digital WD1772-02 controller. ----
---- ----
---- The transceiver unit contains on the one hand the receiver ----
---- part which strips off the clock signal from the data stream ----
---- and on the other hand the transmitter unit which provides in ----
---- the different modes (FM and MFM) all functions which are ----
---- necessary to send data, CRC bytes, 'FF', '00' or the address ----
---- marks. ----
---- ----
---- ----
---- To Do: ----
---- - ----
---- ----
---- Author(s): ----
---- - Wolfgang Foerster, wf@experiment-s.de; wf@inventronik.de ----
---- ----
----------------------------------------------------------------------
---- ----
---- Copyright (C) 2006 - 2008 Wolfgang Foerster ----
---- ----
---- This source file may be used and distributed without ----
---- restriction provided that this copyright statement is not ----
---- removed from the file and that any derivative work contains ----
---- the original copyright notice and the associated disclaimer. ----
---- ----
---- This source file is free software; you can redistribute it ----
---- and/or modify it under the terms of the GNU Lesser General ----
---- Public License as published by the Free Software Foundation; ----
---- either version 2.1 of the License, or (at your option) any ----
---- later version. ----
---- ----
---- This source is distributed in the hope that it will be ----
---- useful, but WITHOUT ANY WARRANTY; without even the implied ----
---- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR ----
---- PURPOSE. See the GNU Lesser General Public License for more ----
---- details. ----
---- ----
---- You should have received a copy of the GNU Lesser General ----
---- Public License along with this source; if not, download it ----
---- from http://www.gnu.org/licenses/lgpl.html ----
---- ----
----------------------------------------------------------------------
--
-- Revision History
--
-- Revision 2006A 2006/06/03 WF
-- Initial Release.
-- Revision 2K6B 2006/11/05 WF
-- Modified Source to compile with the Xilinx ISE.
-- Revision 2K8A 2008/07/14 WF
-- Minor changes.
-- Revision 2K9A 2009/06/20 WF
-- MFM_In and MASK_SHFT have now synchronous reset to meet preset requirement.
--
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity WF1772IP_TRANSCEIVER is
port(
-- System control
CLK : in bit; -- must be 16MHz
RESETn : in bit;
-- Data and Control:
HDTYPE : in bit; -- Floppy type HD or DD.
DDEn : in bit; -- Double density select (FM or MFM).
ID_AM : in bit; -- ID addressmark strobe.
DATA_AM : in Bit; -- Data addressmark strobe.
DDATA_AM : in Bit; -- Deleted data addressmark strobe.
SHFT_LOAD_SD : in bit; -- Indication for shift register load time.
DR : in bit_vector(7 downto 0); -- Content of the data register.
-- Data strobes:
PLL_DSTRB : in bit; -- Clock strobe for RD serial data input.
DATA_STRB : buffer bit;
-- Data strobe and data for the CRC during write operation:
WDATA : buffer bit;
-- Encoder (logic to disk):
PRECOMP_EN : in bit; -- control signal for MFM write precompensation.
AM_TYPE : in bit; -- Write deleted address mark in MFM mode when 0.
AM_2_DISK : in bit;
DSR_2_DISK : in bit;
FF_2_DISK : in bit;
CRC_2_DISK : in bit;
SR_SDOUT : in std_logic; -- encoder's data input from the shift register (serial).
CRC_SDOUT : in bit; -- encoder's data input from the CRC unit (serial).
WRn : out bit; -- write output for the MFM drive containing clock and data.
-- Decoder (disk to logic):
PLL_D : in bit; -- Serial data input.
SD_R : out bit -- Serial (decoded) data output.
);
end WF1772IP_TRANSCEIVER;
architecture BEHAVIOR of WF1772IP_TRANSCEIVER is
type MFM_STATES is (A_00, B_01, C_10);
type PRECOMP_VALUES is (EARLY, NOMINAL, LATE);
type DEC_STATES is (CLK_PHASE, DATA_PHASE);
signal MFM_STATE : MFM_STATES;
signal NEXT_MFM_STATE : MFM_STATES;
signal PRECOMP : PRECOMP_VALUES;
signal DEC_STATE : DEC_STATES;
signal NEXT_DEC_STATE : DEC_STATES;
signal FM_In : bit;
signal CLKMASK : bit; -- Control for suppression of FM clock transitions.
signal MFM_10_STRB : bit;
signal MFM_01_STRB : bit;
signal WR_CNT : std_logic_vector(3 downto 0);
signal MFM_In : bit;
signal AM_SHFT : bit_vector(31 downto 0);
begin
-- ####################### encoder stuff ###########################
ADRMARK: process(RESETn, CLK)
-- This process provides the address mark data for both FM and MFM in
-- write to disk mode. In FM only one byte is written where in MFM
-- 3 sync bytes x"A1" and one data address mark is written.
-- In this process only the data address mark is provided. The only way
-- writing the ID address mark is the write track command.
begin
if RESETn = '0' then
AM_SHFT <= (others => '0');
elsif CLK = '1' and CLK' event then
if AM_2_DISK = '1' and DATA_STRB = '1' then
AM_SHFT <= AM_SHFT (30 downto 0) & '0'; -- Shift out.
elsif AM_2_DISK = '0' and DDEn = '1' and AM_TYPE = '0' then -- FM mode.
AM_SHFT <= x"F8000000"; -- Load deleted FM address mark.
elsif AM_2_DISK = '0' and DDEn = '1' and AM_TYPE = '1' then -- FM mode.
AM_SHFT <= x"FB000000"; -- Load normal FM address mark.
elsif AM_2_DISK = '0' and DDEn = '0' and AM_TYPE = '0' then -- MFM mode deleted data mark.
AM_SHFT <= x"A1A1A1F8"; -- Load MFM syncs and address mark.
elsif AM_2_DISK = '0' and DDEn = '0' and AM_TYPE = '1' then -- Default: MFM mode normal data mark.
AM_SHFT <= x"A1A1A1FB"; -- Load MFM syncs and address mark.
end if;
end if;
end process ADRMARK;
-- Input multiplexer:
WDATA <= AM_SHFT(31) when AM_2_DISK = '1' else -- Address mark data data.
To_Bit(SR_SDOUT) when DSR_2_DISK = '1' else -- Shift register data.
CRC_SDOUT when CRC_2_DISK = '1' else -- CRC data.
'1' when FF_2_DISK = '1' else '0'; -- Write zeros is default.
-- Output multiplexer:
WRn <= '0' when FM_In = '0' and DDEn = '1' else -- FM portion.
'0' when MFM_In = '0' and DDEn = '0' else '1'; -- MFM portion and default.
CLK_MASK: process(CLK)
-- This part of software controls the suppression of the clock pulses
-- during transmission of several FM special characters. During writing
-- 'normal' data to the disk, only 8 mask bits of the shift register are
-- used. During writing MFM sync and address mark bits, the register is
-- used with 32 mask bits.
variable MASK_SHFT : bit_vector(23 downto 0);
variable LOCK : boolean;
begin
if CLK = '1' and CLK' event then
if RESETn = '0' then
MASK_SHFT := (others => '1');
LOCK := false;
-- Load the mask shift register just in time when the shift register is
-- loaded with valid data from the data register.
elsif SHFT_LOAD_SD = '1' and DDEn = '1' then -- FM mode.
case DR is
when x"F8" | x"F9" | x"FA" | x"FB" | x"FE" => MASK_SHFT := x"C7FFFF";
when x"FC" => MASK_SHFT := x"D7FFFF";
when x"F5" | x"F6" => MASK_SHFT := (others => '0'); -- Not allowed.
when others => MASK_SHFT := x"FFFFFF"; -- Normal data.
end case;
elsif SHFT_LOAD_SD = '1' and DDEn = '0' then -- MFM mode.
case DR is
when x"F5" => MASK_SHFT := x"FBFFFF"; -- Suppress clock pulse between bits 4 and 5.
when x"F6" => MASK_SHFT := x"F7FFFF"; -- Suppress clock pulse between bits 3 and 4.
when others => MASK_SHFT := x"FFFFFF"; -- Normal data.
end case;
elsif AM_2_DISK = '1' and DDEn = '1' and LOCK = false then -- FM mode.
MASK_SHFT := x"C7FFFF"; -- Load just once per AM_2_DISK rising edge.
LOCK := true;
elsif AM_2_DISK = '1' and DDEn = '0' and LOCK = false then -- MFM mode.
MASK_SHFT := x"FBFBFB"; -- Three syncs with suppressed clock pulse then transparent mask.
LOCK := true;
elsif DATA_STRB = '1' then -- shift as long as transmission is active
-- The Shift register is shifted left. After shifting the clockmasks out it is
-- transparent due to the '1's filled up from the left.
MASK_SHFT := MASK_SHFT(22 downto 0) & '1'; -- Shift left.
elsif AM_2_DISK = '0' then
LOCK := false; -- Release the lock after address mark has been written.
end if;
end if;
CLKMASK <= MASK_SHFT(23);
end process CLK_MASK;
FM_ENCODER: process (RESETn, DATA_STRB, CLK)
-- For DD type floppies the data rate is 125kBps. Therefore there are 128 16-MHz clocks cycles
-- per FM bit.
-- For HD type floppies the data rate is 250kBps. Therefore there are 64 16-MHz clocks cycles
-- per FM bit.
-- The FM write pulse width is 1.375us for DD and 0.750us HD type floppies.
-- This process provides the FM encoded signal. The first pulse is in any case the clock
-- pulse and the second pulse is due to data. The FM encoding is very simple and therefore
-- self explaining.
variable CNT : std_logic_vector(7 downto 0);
begin
if RESETn = '0' then
FM_In <= '1';
CNT := x"00";
elsif CLK = '1' and CLK' event then
-- In case of HD type floppies the counter reaches a value of b"0100000"
-- In case of DD type floppies the counter reaches a value of b"1000000"
if DATA_STRB = '1' then
CNT := x"00";
else
CNT := CNT + '1';
end if;
-- The flux reversal pulses are centered between the DATA_STRB pulses.
-- In detail: the clock pulse appears in the middle of the first half
-- of the DATA_STRB period and the data pulse appears in the middle of
-- the second half.
case HDTYPE is
when '0' => -- DD type floppies:
if CNT > "00010101" and CNT <= "00101011" then
FM_In <= not CLKMASK; -- FM clock.
elsif CNT > "01010101" and CNT <= "01101011" then
FM_In <= not WDATA; -- FM data.
else
FM_In <= '1';
end if;
when '1' => -- HD type floppies:
if CNT > "00001010" and CNT <= "00010110" then
FM_In <= not CLKMASK; -- FM clock.
elsif CNT > "00101010" and CNT <= "00110110" then
FM_In <= not WDATA; -- FM data.
else
FM_In <= '1';
end if;
end case;
end if;
end process FM_ENCODER;
MFM_ENCODE_REG: process(RESETn, CLK)
-- This process is the first portion of the more complicated MFM encoder. It can be interpreted
-- as a Moore machine. This part is the current state register.
begin
if RESETn = '0' then
MFM_STATE <= A_00;
elsif CLK = '1' and CLK' event then
MFM_STATE <= NEXT_MFM_STATE;
end if;
end process MFM_ENCODE_REG;
MFM_ENCODE_LOGIC: process(MFM_STATE, WDATA, DATA_STRB)
-- Rules for Encoding:
-- transitions are never located at the mid point of a 'zero'.
-- transistions are always located at the mid point of a '1'.
-- no transitions at the borders of a '1'.
-- transitions appear between two adjacent 'zeros'.
-- states are as follows:
-- A_00: idle state, no transition.
-- B_01: transistion between the MFM clock edges.
-- C_10: transition on the leading MFM clock edges.
-- The timing of the MFM output is done in the process MFM_WR_OUT.
begin
case MFM_STATE is
when A_00 =>
if WDATA = '0' and DATA_STRB = '1' then
NEXT_MFM_STATE <= C_10;
elsif WDATA = '1' and DATA_STRB = '1' then
NEXT_MFM_STATE <= B_01;
else
NEXT_MFM_STATE <= A_00; -- Stay, if there is no strobe.
end if;
when C_10 =>
if WDATA = '0' and DATA_STRB = '1' then
NEXT_MFM_STATE <= C_10;
elsif WDATA = '1' and DATA_STRB = '1' then
NEXT_MFM_STATE <= B_01;
else
NEXT_MFM_STATE <= C_10; -- Stay, if there is no strobe.
end if;
when B_01 =>
if WDATA = '0' and DATA_STRB = '1' then
NEXT_MFM_STATE <= A_00;
elsif WDATA = '1' and DATA_STRB = '1' then
NEXT_MFM_STATE <= B_01;
else
NEXT_MFM_STATE <= B_01; -- Stay, if there is no strobe.
end if;
end case;
end process MFM_ENCODE_LOGIC;
MFM_PRECOMPENSATION: process(RESETn, CLK)
-- The write pattern is adjusted in the MFM write timing process as follows:
-- after DATA_STRB (the duty cycle of this strobe is exactly one CLK) the
-- incoming data is bufferd in WRITEPATTERN. After the following DATA_STRB
-- the WDATA is shifted through WRITEPATTERN. After further DATA_STRBs the
-- WRITEPATTERN consists of previous, current and next WDATA like this:
-- WRITEPATTERN(3) is the second previous WDATA.
-- WRITEPATTERN(2) is the previous WDATA.
-- WRITEPATTERN(1) is the current WDATA to be sent.
-- WRITEPATTERN(0) is the next WDATA to be sent.
variable WRITEPATTERN : bit_vector(3 downto 0);
begin
if RESETn = '0' then
PRECOMP <= NOMINAL;
WRITEPATTERN := "0000";
elsif CLK = '1' and CLK' event then
if DATA_STRB = '1' then
WRITEPATTERN := WRITEPATTERN(2 downto 0) & WDATA; -- shift left
end if;
if PRECOMP_EN = '0' then
PRECOMP <= NOMINAL; -- no precompensation
else
case WRITEPATTERN is
when "1110" | "0110" => PRECOMP <= EARLY;
when "1011" | "0011" => PRECOMP <= LATE;
when "0001" => PRECOMP <= EARLY;
when "1000" => PRECOMP <= LATE;
when others => PRECOMP <= NOMINAL;
end case;
end if;
end if;
end process MFM_PRECOMPENSATION;
MFM_STROBES: process (RESETn, DATA_STRB, CLK)
-- For the MFM frequency is 250 kBps for DD type floppies, there are 64
-- 16 MHz clock cycles per MFM bit and for HD type floppies, which have
-- 500 kBps there are 32 16MHz clock pulses for one MFM bit.
-- The MFM state machine (Moore) switches on the DATA_STRB.
-- During one cycle there are the two further strobes MFM_10_STRB and
-- MFM_01_STRB which control the MFM output in the process MFM_WR_OUT.
-- The strobes are centered in the middle of the first half and in the
-- middle of the second half of the DATA_STRB cycle.
variable CNT : std_logic_vector(5 downto 0);
begin
if RESETn = '0' then
CNT := "000000";
elsif CLK = '1' and CLK' event then
if DATA_STRB = '1' then
CNT := (others => '0');
else
CNT := CNT + '1';
end if;
if HDTYPE = '1' then
case CNT is
-- encoder timing for MFM and HD type floppies.
when "000100" => MFM_10_STRB <= '1'; MFM_01_STRB <= '0'; -- Pulse centered in the first half.
when "010100" => MFM_10_STRB <= '0'; MFM_01_STRB <= '1'; -- Pulse centered in the second half.
when others => MFM_10_STRB <= '0'; MFM_01_STRB <= '0';
end case;
else
case CNT is
-- encoder timing for MFM and DD type floppies.
when "001010" => MFM_10_STRB <= '1'; MFM_01_STRB <= '0'; -- Pulse centered in the first half.
when "101000" => MFM_10_STRB <= '0'; MFM_01_STRB <= '1'; -- Pulse centered in the second half.
when others => MFM_10_STRB <= '0'; MFM_01_STRB <= '0';
end case;
end if;
end if;
end process MFM_STROBES;
-- MFM_WR_TIMING generates the timing for the write pulses which are
-- required by a MFM device like floppy disk drive. The pulse timing
-- meets the timing of the MFM data with pulse width of 700ns +/- 100ns
-- depending on write precompensation.
-- The original WD1772 (CLK = 8MHz) data timing was as follows:
-- The output is asserted as long as CNT is active; in detail
-- this are 4,5; 5,5 or 6,5 CLK cycles depending on the write
-- precompensation.
-- The new design which works with a 16MHz clock requires the following
-- timing: 9; 11 or 13 CLK cycles depending on the writeprecompensation
-- for DD floppies and 5; 6 or 7 CLK cycles depending on the write
-- precompensation for HD floppies.
-- To meet the timing requirements of half clocks
-- the WRn is controlled by the following three processes where the one
-- syncs on the positive clock edge and the other on the negative.
-- For more information on the WTn timing see the datasheet of the
-- WD177x floppy disc controller.
MFM_WR_TIMING: process(RESETn, CLK)
variable CLKMASK_MFM : bit;
begin
if RESETn = '0' then
WR_CNT <= x"F";
elsif CLK = '1' and CLK' event then
if DATA_STRB = '1' then
-- The CLKMASK_MFM is synchronised to DATA_STRB. This brings one strobe latency.
-- The timing in connection with the data is correct because the MFM encoder state machine
-- causes the data to be 1 DATA_STRB late too.
CLKMASK_MFM := CLKMASK;
end if;
if MFM_STATE = C_10 and MFM_10_STRB = '1' and CLKMASK_MFM = '1' then
WR_CNT <= x"0";
elsif MFM_STATE = B_01 and MFM_01_STRB = '1' then
WR_CNT <= x"0";
elsif WR_CNT < x"F" then
WR_CNT <= WR_CNT + '1';
end if;
end if;
end process MFM_WR_TIMING;
MFM_WR_OUT: process
begin
wait until CLK = '1' and CLK' event;
if RESETn = '0' then
MFM_In <= '1';
else
case HDTYPE is
when '1' => -- HD type.
if PRECOMP = EARLY and WR_CNT > x"0" and WR_CNT <= x"9" then
MFM_In <= '0'; -- 9,0 clock cycles for WRn --> early timing
elsif PRECOMP = NOMINAL and WR_CNT > x"0" and WR_CNT <= x"8" then
MFM_In <= '0'; -- 8,0 clock cycles for WRn --> nominal timing
elsif PRECOMP = LATE and WR_CNT > x"0" and WR_CNT <= x"7" then
MFM_In <= '0'; -- 7,0 clock cycles for WRn --> late timing
else
MFM_In <= '1';
end if;
when '0' => -- DD type.
if PRECOMP = EARLY and WR_CNT > x"0" and WR_CNT <= x"D" then
MFM_In <= '0'; -- 13,0 clock cycles for WRn --> early timing
elsif PRECOMP = NOMINAL and WR_CNT > x"0" and WR_CNT <= x"B" then
MFM_In <= '0'; -- 11,0 clock cycles for WRn --> nominal timing
elsif PRECOMP = LATE and WR_CNT > x"0" and WR_CNT <= x"9" then
MFM_In <= '0'; -- 9,0 clock cycles for WRn --> late timing
else
MFM_In <= '1';
end if;
end case;
end if;
end process MFM_WR_OUT;
-- ####################### Decoder stuff ###########################
-- The decoding of the serial FM or MFM encoded data stream
-- is done in the following two processes (Moore machine).
-- The decoder works in principle like a simple toggle Flip-Flop.
-- It is important to synchronise it in a way, that the clock
-- pulses are separated from the data pulses. The principle
-- works for both FM and MFM data due to the digital phase
-- locked loop, which delivers the serial data and the clock
-- strobe. In general this decoder can be understood as the
-- data separator where the digital phase locked loop provides
-- the FM or the MFM decoding. The data separation lives from
-- the fact, that FM and also MFM encoded signals consist of a
-- mixture of alternating data and clock pulses.
-- FM works as follows:
-- every first pulse of the FM signal is a clock pulse and every
-- second pulse is a logic '1' of the data. A missing second
-- pulse represents a logic '0' of the data.
-- MFM works as follows:
-- every first pulse of the MFM signal is a clock pulse. The coding
-- principle causes clock pulses to be absent in some conditions.
-- Every second pulse is a logic '1' of the data. A missing second
-- pulse represents a logic '0' of the data.
-- So FM and MFM compared, the data is represented directly by the
-- second pulses and the data separator has to look only for these.
-- The missing MFM clock pulses do not cause a problem because the
-- digital PLL used in conjunction with this data separator fills
-- up the clock pulses and delivers a PLL_DSTRB containing aequidistant
-- clock strobes and data strobes.
DEC_REG: process(RESETn, CLK)
begin
if RESETn = '0' then
DEC_STATE <= CLK_PHASE;
elsif CLK = '1' and CLK' event then
DEC_STATE <= NEXT_DEC_STATE;
end if;
end process DEC_REG;
DEC_LOGIC: process(DEC_STATE, ID_AM, DATA_AM, DDATA_AM, PLL_DSTRB, PLL_D)
begin
case DEC_STATE is
when CLK_PHASE =>
if PLL_DSTRB = '1' then
NEXT_DEC_STATE <= DATA_PHASE;
else
NEXT_DEC_STATE <= CLK_PHASE;
end if;
DATA_STRB <= '0'; -- Inactive during clock pulse time.
SD_R <= '0'; -- Inactive during clock pulse time.
when DATA_PHASE =>
if ID_AM = '1' or DATA_AM = '1' or DDATA_AM = '1' then
-- Here the state machine is synchronised
-- to separate data and clock pulses correctly.
NEXT_DEC_STATE <= CLK_PHASE;
elsif PLL_DSTRB = '1' then
NEXT_DEC_STATE <= CLK_PHASE;
else
NEXT_DEC_STATE <= DATA_PHASE;
end if;
-- During the data phase valid data appears at SD.
-- The data is valid during DATA_STRB.
DATA_STRB <= PLL_DSTRB;
SD_R <= PLL_D;
end case;
end process DEC_LOGIC;
end architecture BEHAVIOR;