OpenCores
URL https://opencores.org/ocsvn/astron_mm/astron_mm/trunk

Subversion Repositories astron_mm

[/] [astron_mm/] [trunk/] [common_reg_cross_domain.vhd] - Blame information for rev 2

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 2 danv
-------------------------------------------------------------------------------
2
--
3
-- Copyright (C) 2010
4
-- ASTRON (Netherlands Institute for Radio Astronomy) <http://www.astron.nl/>
5
-- JIVE (Joint Institute for VLBI in Europe) <http://www.jive.nl/>
6
-- P.O.Box 2, 7990 AA Dwingeloo, The Netherlands
7
--
8
-- This program is free software: you can redistribute it and/or modify
9
-- it under the terms of the GNU General Public License as published by
10
-- the Free Software Foundation, either version 3 of the License, or
11
-- (at your option) any later version.
12
--
13
-- This program is distributed in the hope that it will be useful,
14
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
15
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
-- GNU General Public License for more details.
17
--
18
-- You should have received a copy of the GNU General Public License
19
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
20
--
21
-------------------------------------------------------------------------------
22
 
23
LIBRARY IEEE, common_pkg_lib, common_components_lib, common_ram_lib;
24
USE IEEE.std_logic_1164.ALL;
25
USE IEEE.numeric_std.ALL;
26
USE common_pkg_lib.common_pkg.ALL;
27
USE common_ram_lib.common_ram_pkg.ALL;
28
 
29
-- Purpose: Get in_dat from in_clk to out_clk domain when in_new is asserted.
30
-- Remarks:
31
-- . If in_new is a pulse, then new in_dat is available after g_in_new_latency.
32
-- . It is also allowed to hold in_new high, then out_new will pulse once for
33
--   every 24 out_clk cycles.
34
-- . Use in_done to be sure that in_dat due to in_new has crossed the clock
35
--   domain, in case of multiple in_new pulses in a row the in_done will only
36
--   pulse when this state remains s_idle, so after the last in_new.
37
-- . If the in_dat remains unchanged during the crossing of in_new to out_en
38
--   then g_input_buf=FALSE may be used to save some flipflops
39
 
40
ENTITY common_reg_cross_domain IS
41
  GENERIC (
42
    g_input_buf      : BOOLEAN := TRUE;
43
    g_in_new_latency : NATURAL := 0;  -- >= 0
44
    g_out_dat_init   : STD_LOGIC_VECTOR(c_mem_reg_init_w-1 DOWNTO 0) := (OTHERS => '0')
45
  );
46
  PORT (
47
    in_rst      : IN  STD_LOGIC;
48
    in_clk      : IN  STD_LOGIC;
49
    in_new      : IN  STD_LOGIC := '1';  -- when '1' then new in_dat is available after g_in_new_latency
50
    in_dat      : IN  STD_LOGIC_VECTOR;
51
    in_done     : OUT STD_LOGIC;         -- pulses when no more pending in_new
52
    out_rst     : IN  STD_LOGIC;
53
    out_clk     : IN  STD_LOGIC;
54
    out_dat     : OUT STD_LOGIC_VECTOR;
55
    out_new     : OUT STD_LOGIC          -- when '1' then the out_dat was updated with in_dat due to in_new
56
  );
57
END common_reg_cross_domain;
58
 
59
 
60
ARCHITECTURE rtl OF common_reg_cross_domain IS
61
 
62
  CONSTANT c_dat : STD_LOGIC_VECTOR(in_dat'RANGE) := g_out_dat_init(in_dat'RANGE);
63
 
64
  ------------------------------------------------------------------------------
65
  -- in_clk domain
66
  ------------------------------------------------------------------------------
67
  SIGNAL reg_new          : STD_LOGIC_VECTOR(0 TO g_in_new_latency) := (OTHERS=>'0');
68
  SIGNAL nxt_reg_new      : STD_LOGIC_VECTOR(reg_new'RANGE);
69
 
70
  SIGNAL in_buf           : STD_LOGIC_VECTOR(c_dat'RANGE) := c_dat;
71
  SIGNAL in_buf_reg       : STD_LOGIC_VECTOR(c_dat'RANGE) := c_dat;
72
  SIGNAL nxt_in_buf_reg   : STD_LOGIC_VECTOR(c_dat'RANGE);
73
 
74
  -- Register access clock domain crossing
75
  TYPE t_state_enum IS (s_idle, s_busy);
76
 
77
  SIGNAL cross_req        : STD_LOGIC;
78
  SIGNAL cross_busy       : STD_LOGIC;
79
  SIGNAL nxt_in_done      : STD_LOGIC;
80
  SIGNAL state            : t_state_enum;
81
  SIGNAL nxt_state        : t_state_enum;
82
  SIGNAL prev_state       : t_state_enum;
83
  SIGNAL in_new_hold      : STD_LOGIC;
84
  SIGNAL nxt_in_new_hold  : STD_LOGIC;
85
 
86
  ------------------------------------------------------------------------------
87
  -- out_clk domain
88
  ------------------------------------------------------------------------------
89
  SIGNAL out_en           : STD_LOGIC;
90
  SIGNAL i_out_dat        : STD_LOGIC_VECTOR(c_dat'RANGE) := c_dat;  -- register init without physical reset
91
  SIGNAL nxt_out_dat      : STD_LOGIC_VECTOR(c_dat'RANGE);
92
 
93
BEGIN
94
 
95
  out_dat <= i_out_dat;
96
 
97
  ------------------------------------------------------------------------------
98
  -- in_clk domain
99
  ------------------------------------------------------------------------------
100
 
101
  reg_new(0) <= in_new;
102
 
103
  gen_latency : IF g_in_new_latency>0 GENERATE
104
    p_reg_new : PROCESS(in_rst, in_clk)
105
    BEGIN
106
      IF in_rst='1' THEN
107
        reg_new(1 TO g_in_new_latency) <= (OTHERS=>'0');
108
      ELSIF rising_edge(in_clk) THEN
109
        reg_new(1 TO g_in_new_latency) <= nxt_reg_new(1 TO g_in_new_latency);
110
      END IF;
111
    END PROCESS;
112
 
113
    nxt_reg_new(1 TO g_in_new_latency) <= reg_new(0 TO g_in_new_latency-1);
114
  END GENERATE;
115
 
116
  p_in_clk : PROCESS(in_rst, in_clk)
117
  BEGIN
118
    IF in_rst='1' THEN
119
      in_new_hold <= '0';
120
      in_done     <= '0';
121
      state       <= s_idle;
122
      prev_state  <= s_idle;
123
    ELSIF rising_edge(in_clk) THEN
124
      in_buf_reg  <= nxt_in_buf_reg;
125
      in_new_hold <= nxt_in_new_hold;
126
      in_done     <= nxt_in_done;
127
      state       <= nxt_state;
128
      prev_state  <= state;
129
    END IF;
130
  END PROCESS;
131
 
132
  -- capture the new register data
133
  no_in_buf : IF g_input_buf=FALSE GENERATE
134
    in_buf <= in_dat;  -- assumes that in_dat remains unchanged during the crossing of in_new to out_en
135
  END GENERATE;
136
 
137
  gen_in_buf : IF g_input_buf=TRUE GENERATE
138
    nxt_in_buf_reg <= in_dat WHEN cross_req='1' ELSE in_buf_reg;
139
    in_buf         <= in_buf_reg;
140
  END GENERATE;
141
 
142
 
143
  -- handshake control of the clock domain crossing by u_cross_req
144
  -- hold any subsequent in_new during cross domain busy to ensure that the out_dat will get the latest value of in_dat
145
  p_state : PROCESS(state, prev_state, reg_new, in_new_hold, cross_busy)
146
  BEGIN
147
    cross_req <= '0';
148
    nxt_in_done <= '0';
149
    nxt_in_new_hold <= in_new_hold;
150
    nxt_state <= state;
151
    CASE state IS
152
      WHEN s_idle =>
153
        nxt_in_new_hold <= '0';
154
        IF reg_new(g_in_new_latency)='1' OR in_new_hold='1' THEN
155
          cross_req <= '1';
156
          nxt_state <= s_busy;
157
        ELSIF UNSIGNED(reg_new)=0 AND prev_state=s_busy THEN
158
          nxt_in_done <= '1';  -- no pending in_new at input or in shift register and just left s_busy, so signal in_done
159
        END IF;
160
      WHEN OTHERS => -- s_busy
161
        IF reg_new(g_in_new_latency)='1' THEN
162
          nxt_in_new_hold <= '1';
163
        END IF;
164
        IF cross_busy='0' THEN
165
          nxt_state <= s_idle;
166
        END IF;
167
    END CASE;
168
  END PROCESS;
169
 
170
  ------------------------------------------------------------------------------
171
  -- cross clock domain
172
  ------------------------------------------------------------------------------
173
  u_cross_req : ENTITY common_components_lib.common_spulse
174
  PORT MAP (
175
    in_rst     => in_rst,
176
    in_clk     => in_clk,
177
    in_pulse   => cross_req,
178
    in_busy    => cross_busy,
179
    out_rst    => out_rst,
180
    out_clk    => out_clk,
181
    out_pulse  => out_en
182
  );
183
 
184
  ------------------------------------------------------------------------------
185
  -- out_clk domain
186
  ------------------------------------------------------------------------------
187
  p_out_clk : PROCESS(out_rst, out_clk)
188
  BEGIN
189
    IF out_rst='1' THEN
190
      out_new   <= '0';
191
    ELSIF rising_edge(out_clk) THEN
192
      i_out_dat <= nxt_out_dat;
193
      out_new   <= out_en;
194
    END IF;
195
  END PROCESS;
196
 
197
  -- some clock cycles after the cross_req the in_buf data is stable for sure
198
  nxt_out_dat <= in_buf WHEN out_en='1' ELSE i_out_dat;
199
 
200
END rtl;

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.