1
0
mirror of https://github.com/ibm2030/IBM2030.git synced 2026-01-11 23:52:47 +00:00
ibm2030.IBM2030/FMD2030_5-08A1.vhd
2015-11-25 09:59:27 +01:00

197 lines
7.7 KiB
VHDL

---------------------------------------------------------------------------
-- Copyright 2010 Lawrence Wilkinson lawrence@ljw.me.uk
--
-- This file is part of LJW2030, a VHDL implementation of the IBM
-- System/360 Model 30.
--
-- LJW2030 is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- LJW2030 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 General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with LJW2030 . If not, see <http://www.gnu.org/licenses/>.
--
---------------------------------------------------------------------------
--
-- File: FMD2030_5-08A1.vhd
-- Creation Date: 22:26:31 18/04/05
-- Description:
-- Clock generator - 4 phase (T1,T2,T3,T4 and P1,P2,P3,P4)
-- Page references like "5-01A" refer to the IBM Maintenance Diagram Manual (MDM)
-- for the 360/30 R25-5103-1
-- References like "02AE6" refer to coordinate "E6" on page "5-02A"
-- Logic references like "AB3D5" refer to card "D5" in board "B3" in gate "A"
-- Gate A is the main logic gate, B is the second (optional) logic gate,
-- C is the core storage and X is the CCROS unit
--
-- Revision History:
-- Revision 1.0 2010-07-13
-- Initial Release
-- Revision 1.1 2012-04-07
-- Add registers to all clock outputs and delay rising edge of Px and Tx clocks
---------------------------------------------------------------------------
library IEEE;
Library UNISIM;
use UNISIM.vcomponents.all;
use IEEE.STD_LOGIC_1164.ALL;
-- use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.Gates_package.all;
use work.all;
entity Clock is Port (
-- Clock stuff
CLOCK_IN : in std_logic;
T1,T2,T3,T4 : out std_logic;
P1,P2,P3,P4 : out std_logic;
OSC_T_LINE : out std_logic; -- 12A
M_CONV_OSC : out std_logic; -- 03C
P_CONV_OSC : out std_logic; -- 03D,03C
M_CONV_OSC_2 : out std_logic; -- 03C
CLOCK_ON : out std_logic; -- 03D,04A,03C,13B,12A,11B
CLOCK_OFF : out std_logic; -- 04B,06C,09B,03D
CLOCK_START : in std_logic; -- 03C
MACH_RST_3 : in std_logic; -- 03D
Sw_Slow : in std_logic -- '1' to run slow
);
end Clock;
architecture FMD of Clock is
-- Following 2 lines to run clock at 5.33MHz (standard)
-- subtype DividerSize is STD_LOGIC_VECTOR(5 downto 0);
subtype DividerSize is STD_LOGIC_VECTOR(25 downto 0);
constant RATIOFast : DividerSize := "00000000000000000000001000"; -- 5 gives 10MHz => 720ns cycle
-- Following 2 lines to run clock at 5Hz
constant RATIOSlow : DividerSize := "00100010010101010001000000"; -- 5M gives 10Hz => 720ms cycle
constant ZERO : DividerSize := (others=>'0');
constant ONE : DividerSize := (0=>'1',others=>'0');
signal DIVIDER : DividerSize := (others=>'0');
signal DIVIDER_MAX : DividerSize;
signal OSC2,OSC,M_DLYD_OSC,DLYN_OSC,T1A,T2A,T3A,T4A,OSC2_DLYD : STD_LOGIC := '0';
-- signal SETS,RSTS : STD_LOGIC_VECTOR(1 to 4);
signal CLK : STD_LOGIC_VECTOR(1 to 4) := "0001";
signal P1D,P2D,P3D,P4D : STD_LOGIC;
signal OSC_T_LINEA, CLOCK_ONA, CLOCK_OFFA, P_CONV_OSCA,M_CONV_OSC_2A, N_OSC : STD_LOGIC;
begin
-- Divide the 50MHz FPGA clock down
-- 1.5us storage cycle means T1-4 takes 750ns, or 1.33MHz
-- The clock to generate the four phases is therefore 2.66MHz
-- OSC2 is actually double the original oscillator (5.33MHz) as only one edge is used
DIVIDER_MAX <= RatioSlow when Sw_Slow='1' else RATIOFast;
OSC2 <= '1' when DIVIDER > '0' & DIVIDER_MAX(DIVIDER_MAX'left downto 1) else '0';
N_OSC <= not OSC;
process (CLOCK_IN)
begin
if CLOCK_IN'event and CLOCK_IN='1' then
if DIVIDER>=DIVIDER_MAX then
DIVIDER <= ZERO;
else
DIVIDER <= DIVIDER + ONE;
end if;
end if;
end process;
-- AC1K6,AC1C6 Probably have to re-do this lot to get it work
--SETS(1) <= not DLYD_OSC and CLOCK_START and not CLK(3) and CLK(4);
--SETS(2) <= DLYD_OSC not CLK(4) and CLK(1);
--SETS(3) <= not DLYD_OSC and not CLK(1) and CLK(2);
--SETS(4) <= (DLYD_OSC and not CLK(2) and CLK(3)) or MACH_RST_3='1';
--RSTS(1) <= (not DLYD_OSC and CLK(2)) or MACH_RST_3='1';
--RSTS(2) <= (OSC and CLK(3)) or MACH_RST_3='1';
--RSTS(3) <= (not DLYD_OSC and CLK(4)) or MACH_RST_3='1';
--RSTS(4) <= OSC and CLK(1);
--FLV(SETS,RSTS,CLK); -- AC1C6
-- The following process forms a ring counter
-- MACH_RST_3 forces the counter to 0001
-- If CLOCK_START is false, the counter stays at 0001
-- When CLOCK_START goes true, the counter cycles through
-- 0001 0001 0001 1001 1100 0110 0011 1001 1100 ....
-- When CLOCK_START subsequently goes false, the sequence continues
-- until reaching 0011, after which it stays at 0001
-- ... 1001 1100 0110 0011 0001 0001 0001 ...
-- The original counter used a level-triggered implementation, driven by
-- both levels of the OSC signal. Here it is easier to make it edge triggered
-- which requires a clock of twice the frequency, hence OSC2
process (OSC2, MACH_RST_3, CLOCK_START)
begin
if OSC2'event and OSC2='1' then
if OSC='0' then -- OSC Rising edge: +P1 (P4=1 & START) -P3 (P4=1) or -P1 +P3 (P2=1)
OSC <= '1';
if CLK(2)='1' or MACH_RST_3='1' then
CLK(1) <= '0';
elsif CLOCK_START='1' and CLK(4)='1' then
CLK(1) <= '1';
end if;
if CLK(4)='1' or MACH_RST_3='1' then
CLK(3) <= '0';
elsif CLK(2)='1' then
CLK(3) <= '1';
end if;
else -- OSC Falling edge: +P2 -P4 (P1=1) or -P2 +P4 (P3=1)
OSC <= '0';
if CLK(3)='1' or MACH_RST_3='1' then
CLK(2) <= '0';
elsif CLK(1)='1' then
CLK(2) <= '1';
end if;
if CLK(3)='1' or MACH_RST_3='1' then
CLK(4) <= '1';
elsif CLK(1)='1' then
CLK(4) <= '0';
end if;
end if;
end if;
end process;
OSC_T_LINEA <= OSC; -- AC1B6
OSC_T_LINED : FDCE port map(D=>OSC_T_LINEA,Q=>OSC_T_LINE,CE=>'1',C=>CLOCK_IN,CLR=>'0');
M_CONV_OSCD : FDCE port map(D=>N_OSC,Q=>M_CONV_OSC,CE=>'1',C=>CLOCK_IN,CLR=>'0'); -- AC1C6
M_DLYD_OSC <= not OSC; -- AC1C6
DLYN_OSC <= OSC; -- AC1C6
-- P1 <= CLK(1);
-- P2 <= CLK(2);
-- P3 <= CLK(3);
-- P4 <= CLK(4);
-- Delay the rising edge of each P pulse to ensure that the T pulses never overlap
P1DLY: entity DelayRisingEdgeX port map (D=>CLK(1),CLK=>CLOCK_IN,Q=>P1D);
P2DLY: entity DelayRisingEdgeX port map (D=>CLK(2),CLK=>CLOCK_IN,Q=>P2D);
P3DLY: entity DelayRisingEdgeX port map (D=>CLK(3),CLK=>CLOCK_IN,Q=>P3D);
P4DLY: entity DelayRisingEdgeX port map (D=>CLK(4),CLK=>CLOCK_IN,Q=>P4D);
T1A <= P4D and P1D;
T2A <= P1D and P2D;
T3A <= P2D and P3D;
T4A <= P3D and P4D;
T1D : FDCE port map(D=>T1A,Q=>T1,CE=>'1',C=>CLOCK_IN,CLR=>'0');
T2D : FDCE port map(D=>T2A,Q=>T2,CE=>'1',C=>CLOCK_IN,CLR=>'0');
T3D : FDCE port map(D=>T3A,Q=>T3,CE=>'1',C=>CLOCK_IN,CLR=>'0');
T4D : FDCE port map(D=>T4A,Q=>T4,CE=>'1',C=>CLOCK_IN,CLR=>'0');
P1C : FDCE port map(D=>P1D,Q=>P1,CE=>'1',C=>CLOCK_IN,CLR=>'0');
P2C : FDCE port map(D=>P2D,Q=>P2,CE=>'1',C=>CLOCK_IN,CLR=>'0');
P3C : FDCE port map(D=>P3D,Q=>P3,CE=>'1',C=>CLOCK_IN,CLR=>'0');
P4C : FDCE port map(D=>P4D,Q=>P4,CE=>'1',C=>CLOCK_IN,CLR=>'0');
CLOCK_ONA <= CLK(1) or CLK(2) or CLK(3);
CLOCK_OND : FDCE port map(D=>CLOCK_ONA,Q=>CLOCK_ON,CE=>'1',C=>CLOCK_IN,CLR=>'0');
CLOCK_OFFA <= not CLOCK_ONA;
CLOCK_OFFD : FDCE port map(D=>CLOCK_OFFA,Q=>CLOCK_OFF,CE=>'1',C=>CLOCK_IN,CLR=>'0');
P_CONV_OSCA <= OSC and CLOCK_OFFA;
P_CONV_OSCD : FDCE port map(D=>P_CONV_OSCA,Q=>P_CONV_OSC,CE=>'1',C=>CLOCK_IN,CLR=>'0');
M_CONV_OSC_2A <= not(P_CONV_OSCA);
M_CONV_OSC_2D : FDCE port map(D=>M_CONV_OSC_2A,Q=>M_CONV_OSC_2,CE=>'1',C=>CLOCK_IN,CLR=>'0');
end FMD;