From 1afb05d18ab986fff9e9401c4b0daf4f1b0e7236 Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Fri, 10 Oct 2008 21:25:58 +0000 Subject: [PATCH] Intital revision git-svn-id: http://moon:8086/svn/vhdl/trunk@41 cc03376c-175c-47c8-b038-4cd826a8556b --- lib/misc/async_port_wb.vhd | 259 ++++++++++++++++++++++++++++++++++ lib/misc/clockgen_virtex4.vhd | 236 +++++++++++++++++++++++++++++++ 2 files changed, 495 insertions(+) create mode 100644 lib/misc/async_port_wb.vhd create mode 100644 lib/misc/clockgen_virtex4.vhd diff --git a/lib/misc/async_port_wb.vhd b/lib/misc/async_port_wb.vhd new file mode 100644 index 0000000..4900565 --- /dev/null +++ b/lib/misc/async_port_wb.vhd @@ -0,0 +1,259 @@ +----------------------------------------------------------------------- +-- $Header: /tmp/cvsroot/VHDL/lib/misc/async_port_wb.vhd,v 1.1 2008-10-10 21:25:46 Jens Exp $ +----------------------------------------------------------------------- +library IEEE; +use IEEE.STD_LOGIC_1164.ALL; +use IEEE.NUMERIC_STD.ALL; +use work.sys_types.all; + + ------------------------------------------------------------------ +entity async_port_wb is + Generic + ( + addr_width : natural := 32; + data_width : natural := 32; + async_timespec : async_timespec_t + ); + Port + ( + CLK_I : in STD_LOGIC; + RST_I : in STD_LOGIC; + CYC_I : in STD_LOGIC; + STB_I : in STD_LOGIC; + WE_I : in STD_LOGIC; + ACK_O : out STD_LOGIC; + SRDY_O : out STD_LOGIC; + MRDY_I : in STD_LOGIC; + ADDR_I : in unsigned(31 downto 0); + DAT_I : in unsigned(31 downto 0); + DAT_O : out unsigned(31 downto 0); + async_a : out unsigned(addr_width-1 downto 0); + async_d : inout unsigned(data_width-1 downto 0); + async_cs : out std_logic; + async_wr : out std_logic; + async_rd : out std_logic; + async_rst : out std_logic + ); +end async_port_wb; + +architecture Behavioral of async_port_wb is + + type async_t is record + cs : std_logic; + wr : std_logic; + rd : std_logic; + rst : std_logic; + drive_d : std_logic; + end record; + + type async_state_t is (start, reset, rdy, leadin_rd, read, leadin_wr, write, leadout_rd, leadout_wr, release); + + signal s, sn : async_state_t; + signal as : async_t; + signal ack : std_logic; + signal cc_rst : std_logic; + signal cycle_cnt : natural range 0 to 15; + signal cycle_reload : natural range 0 to 15; + + ------------------------------------------------------------------ + begin + + proc_cycle_counter: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if cc_rst = '1' then + cycle_cnt <= cycle_reload; + elsif cycle_cnt /= 0 then + cycle_cnt <= cycle_cnt - 1; + end if; + end if; + end process; + + ------------------------------------------------------------------ + proc_state_next: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if RST_I = '1' then + s <= start; + else + s <= sn; + end if; + end if; + end process; + + proc_state: + process(s, cycle_cnt, STB_I, CYC_I, WE_I) + begin + + cycle_reload <= async_timespec.ncyc_pulse_rst; + cc_rst <= '0'; + as.rst <= '0'; + as.cs <= '0'; + as.wr <= '0'; + as.rd <= '0'; + as.drive_d <= '0'; + SRDY_O <= '0'; + ack <= '0'; + + sn <= s; + case s is + + when start => + cc_rst <= '1'; + sn <= reset; + when reset => + as.rst <= '1'; + if cycle_cnt = 0 then + sn <= rdy; + end if; + when rdy => + SRDY_O <= CYC_I; + if (STB_I and CYC_I) = '1' then + as.cs <= '1'; + cc_rst <= '1'; + cycle_reload <= async_timespec.ncyc_access-1; + if WE_I = '0' then + sn <= leadin_rd; + else + sn <= leadin_wr; + end if; + end if; + + when leadin_rd => + as.cs <= '1'; + if cycle_cnt = 0 then + cc_rst <= '1'; + cycle_reload <= async_timespec.ncyc_pulse_rd-1; + as.rd <= '1'; + sn <= read; + end if; + + when leadin_wr => + as.cs <= '1'; + if cycle_cnt = 0 then + cc_rst <= '1'; + cycle_reload <= async_timespec.ncyc_pulse_wr-1; + as.wr <= '1'; + as.drive_d <= '1'; + sn <= write; + end if; + + when read => + as.cs <= '1'; + as.rd <= '1'; + if cycle_cnt = 0 then + cc_rst <= '1'; + cycle_reload <= async_timespec.ncyc_cs_hold-1; +-- as.rd <= '0'; + sn <= leadout_rd; + ack <= '1'; + end if; + + when write => + as.drive_d <= '1'; + as.cs <= '1'; + as.wr <= '1'; + if cycle_cnt = 0 then + as.wr <= '0'; + cc_rst <= '1'; + cycle_reload <= async_timespec.ncyc_cs_hold-1; + sn <= leadout_wr; +-- ack <= '1'; + end if; + + when leadout_rd => + as.cs <= '1'; + if cycle_cnt = 0 then + cc_rst <= '1'; + cycle_reload <= async_timespec.ncyc_release-1; + sn <= release; + as.cs <= '0'; + end if; + + when leadout_wr => + as.cs <= '1'; + as.drive_d <= '1'; + if cycle_cnt = 0 then + cc_rst <= '1'; + cycle_reload <= async_timespec.ncyc_release-1; + sn <= release; + as.cs <= '0'; + end if; + + when release => + if cycle_cnt = 0 then + sn <= rdy; + end if; + + when others => + sn <= rdy; + + end case; + end process; + + ------------------------------------------------------------------ + output_ctrl: + process(CLK_I) + begin + if rising_edge(CLK_I) then + async_cs <= (not async_timespec.pol_cs) xor as.cs; + async_wr <= (not async_timespec.pol_we) xor as.wr; + async_rd <= (not async_timespec.pol_oe) xor as.rd; + async_rst <= (not async_timespec.pol_rst) xor as.rst; + end if; + end process; + + ------------------------------------------------------------------ + din_register: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if as.rd = '1' then + DAT_O(data_width-1 downto 0) <= async_d; + end if; + end if; + end process; + + ------------------------------------------------------------------ + output_addr: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if RST_I = '1' then + async_a <= (others => '0'); + elsif (STB_I and CYC_I) = '1' then + async_a <= ADDR_I(addr_width-1 downto 0); + end if; + end if; + end process; + + ------------------------------------------------------------------ + output_ACK: + process(CLK_I) + begin + if rising_edge(CLK_I) then + if RST_I = '1' then + ACK_O <= '0'; + else + ACK_O <= ack; + end if; + end if; + end process; + + ------------------------------------------------------------------ + output_data: + process(CLK_I) + begin + if rising_edge(CLK_I) then + async_d <= (others => 'Z'); + if as.drive_d = '1' then + async_d <= DAT_I(data_width-1 downto 0); + end if; + end if; + end process; + + ------------------------------------------------------------------ + +end Behavioral; diff --git a/lib/misc/clockgen_virtex4.vhd b/lib/misc/clockgen_virtex4.vhd new file mode 100644 index 0000000..a5cac9c --- /dev/null +++ b/lib/misc/clockgen_virtex4.vhd @@ -0,0 +1,236 @@ +------------------------------------------------------------------------- +-- Project: SDRAM controller +-- This file: Clock generator (Virtex-4 specific) +-- +-- Copyright (C) 2007 J. Ahrensfeld +-- +-- This program 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. +-- +-- This program 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 this program. If not, see . +-- +-- For questions and ideas, please contact the author at jens@jayfield.org +-- +-------------------------------------------------------------------------- + +library ieee, work; +USE IEEE.STD_LOGIC_1164.ALL; +USE IEEE.NUMERIC_STD.ALL; + +Library UNISIM; +use UNISIM.vcomponents.all; + +entity clockgen is + generic + ( + sys1_phaseshift : integer := 0; + frequency_hz : integer := 100E6 + ); + port + ( + -- Clocks and Reset + rst : in std_logic; -- external async reset, low active + clk_in : in std_logic; -- system clock (e.g. 100MHz), from board + clk_fb_in : in std_logic; -- feedback clock + sys1_clk0_out : out std_logic; -- System clock #1 (e.g. clock for DDR-SDRAM data capture), dcm#1 output 0° + sys1_clk270_out : out std_logic; -- System clock #1 (e.g. clock for DDR-SDRAM data capture), dcm#1 output 270° + sys0_clk0_out : out std_logic; -- System clock #0, dcm#0 output 0° + sys0_clk270_out : out std_logic; -- System clock #0, dcm#0 output 270° + locked_out : out std_logic; -- DCM locked status + error_out : out std_logic -- indicates DCM Errors + ); +end; + +architecture tech of clockgen is + + constant CLKIN_PER : real := real(1000E6/frequency_hz); + + signal locked : unsigned(1 downto 0); + signal dcm_rst : unsigned(1 downto 0); + signal sys1_clk0 : std_logic; + signal sys1_clk270 : std_logic; + signal sys1_clk0_bufg : std_logic; + signal sys1_clk270_bufg : std_logic; + signal sys0_clk0 : std_logic; + signal sys0_clk270 : std_logic; + signal sys0_clk0_bufg : std_logic; + signal sys0_clk270_bufg : std_logic; + signal dcm1_locked, dcm2_locked : unsigned(2 downto 0); + signal cnt_q : unsigned(4 downto 0); + + type STATE_TYPE is (s0, s1, s2, s3, s4); + signal state_q : STATE_TYPE; + +begin + + sys1_clk0_out <= sys1_clk0_bufg; + sys1_clk270_out <= sys1_clk270_bufg; + sys0_clk0_out <= sys0_clk0_bufg; + sys0_clk270_out <= sys0_clk270_bufg; + +bufg11: bufg + port map + ( + o => sys0_clk0_bufg, + i => sys0_clk0 + ); + +bufg12: bufg + port map ( + o => sys0_clk270_bufg, + i => sys0_clk270 + ); + +bufg13: bufg + port map + ( + o => sys1_clk0_bufg, + i => sys1_clk0 + ); + +bufg14: bufg + port map ( + o => sys1_clk270_bufg, + i => sys1_clk270 + ); + + ------------------------------------------------------------------------------------------------------- + -- Clock generation + ------------------------------------------------------------------------------------------------------- + +inst_DCM_BASE_0 : DCM_BASE + generic map ( + CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 + -- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 + CLKFX_DIVIDE => 1, -- Can be any interger from 1 to 32 + CLKFX_MULTIPLY => 4, -- Can be any integer from 2 to 32 + CLKIN_DIVIDE_BY_2 => FALSE, -- TRUE/FALSE to enable CLKIN divide by two feature + CLKIN_PERIOD => CLKIN_PER, -- Specify period of input clock in ns from 1.25 to 1000.00 + CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift mode of NONE or FIXED + CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE or 1X + DCM_AUTOCALIBRATION => TRUE, -- DCM calibrartion circuitry TRUE/FALSE + DCM_PERFORMANCE_MODE => "MAX_SPEED", -- Can be MAX_SPEED or MAX_RANGE + DESKEW_ADJUST => "SOURCE_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or + -- an integer from 0 to 15 + DFS_FREQUENCY_MODE => "LOW", -- LOW or HIGH frequency mode for frequency synthesis + DLL_FREQUENCY_MODE => "LOW", -- LOW, HIGH, or HIGH_SER frequency mode for DLL + DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE + FACTORY_JF => X"F0F0", -- FACTORY JF Values Suggested to be set to X"F0F0" + PHASE_SHIFT => 0, -- Amount of fixed phase shift from -255 to 1023 + STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE + port map ( + CLK0 => sys0_clk0, -- 0 degree DCM CLK ouptput + CLK180 => open, -- 180 degree DCM CLK output + CLK270 => sys0_clk270, -- 270 degree DCM CLK output + CLK2X => open, -- 2X DCM CLK output + CLK2X180 => open, -- 2X, 180 degree DCM CLK out + CLK90 => open, -- 90 degree DCM CLK output + CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE) + CLKFX => open, -- DCM CLK synthesis out (M/D) + CLKFX180 => open, -- 180 degree CLK synthesis out + LOCKED => locked(0), -- DCM LOCK status output + CLKFB => clk_fb_in, -- DCM clock feedback + CLKIN => clk_in, -- Clock input (from IBUFG, BUFG or DCM) + RST => dcm_rst(0) -- DCM asynchronous reset input + ); + + inst_DCM_BASE_1 : DCM_BASE + generic map ( + CLKDV_DIVIDE => 2.0, -- Divide by: 1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5,6.0,6.5 + -- 7.0,7.5,8.0,9.0,10.0,11.0,12.0,13.0,14.0,15.0 or 16.0 + CLKFX_DIVIDE => 1, -- Can be any interger from 1 to 32 + CLKFX_MULTIPLY => 4, -- Can be any integer from 2 to 32 + CLKIN_DIVIDE_BY_2 => FALSE, -- TRUE/FALSE to enable CLKIN divide by two feature + CLKIN_PERIOD => CLKIN_PER, -- Specify period of input clock in ns from 1.25 to 1000.00 + CLKOUT_PHASE_SHIFT => "FIXED", -- Specify phase shift mode of NONE or FIXED + CLK_FEEDBACK => "1X", -- Specify clock feedback of NONE or 1X + DCM_AUTOCALIBRATION => TRUE, -- DCM calibrartion circuitry TRUE/FALSE + DCM_PERFORMANCE_MODE => "MAX_SPEED", -- Can be MAX_SPEED or MAX_RANGE + DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS", -- SOURCE_SYNCHRONOUS, SYSTEM_SYNCHRONOUS or + -- an integer from 0 to 15 + DFS_FREQUENCY_MODE => "LOW", -- LOW or HIGH frequency mode for frequency synthesis + DLL_FREQUENCY_MODE => "LOW", -- LOW, HIGH, or HIGH_SER frequency mode for DLL + DUTY_CYCLE_CORRECTION => TRUE, -- Duty cycle correction, TRUE or FALSE + FACTORY_JF => X"F0F0", -- FACTORY JF Values Suggested to be set to X"F0F0" + PHASE_SHIFT => sys1_phaseshift, -- Amount of fixed phase shift from -255 to 1023 + STARTUP_WAIT => FALSE) -- Delay configuration DONE until DCM LOCK, TRUE/FALSE + port map ( + CLK0 => sys1_clk0, -- 0 degree DCM CLK ouptput + CLK180 => open, -- 180 degree DCM CLK output + CLK270 => sys1_clk270, -- 270 degree DCM CLK output + CLK2X => open, -- 2X DCM CLK output + CLK2X180 => open, -- 2X, 180 degree DCM CLK out + CLK90 => open, -- 90 degree DCM CLK output + CLKDV => open, -- Divided DCM CLK out (CLKDV_DIVIDE) + CLKFX => open, -- DCM CLK synthesis out (M/D) + CLKFX180 => open, -- 180 degree CLK synthesis out + LOCKED => locked(1), -- DCM LOCK status output + CLKFB => sys1_clk0_bufg, -- DCM clock feedback + CLKIN => clk_fb_in, -- Clock input (from IBUFG, BUFG or DCM) + RST => dcm_rst(1) -- DCM asynchronous reset input + ); + + dcm_rst(1) <= not locked(0); + +dcm_fsm: + process(rst, clk_in) + begin + if rst = '1' then + state_q <= s0; + dcm_rst(0) <= '0'; + cnt_q <= "11111"; + error_out <= '0'; + locked_out <= '0'; + dcm1_locked <= (others => '0'); + dcm2_locked <= (others => '0'); + elsif rising_edge(clk_in) then + case state_q is + when s0 => + state_q <= s1; + + when s1 => + cnt_q <= cnt_q - 1; + if cnt_q = 0 then + dcm_rst(0) <= '1'; + state_q <= s2; + end if; + + when s2 => + cnt_q <= cnt_q - 1; + if cnt_q = 0 then + dcm_rst(0) <= '0'; + state_q <= s3; + end if; + + when s3 => + if dcm1_locked(2)='1' and dcm2_locked(2)='1' then + state_q <= s4; + error_out <= '0'; + end if; + + when s4 => + if dcm1_locked(2)='1' and dcm2_locked(2)='1' then + locked_out <= '1'; + else + error_out <= '1'; + end if; + end case; + + -- synchronize 'dcm1_locked' + dcm1_locked <= dcm1_locked(1 downto 0) & locked(0); + dcm2_locked <= dcm2_locked(1 downto 0) & locked(1); + + end if; + end process; + +end architecture tech; + +