-
Notifications
You must be signed in to change notification settings - Fork 103
/
Copy pathgearbox_up_dc.vhdl
155 lines (134 loc) · 6.11 KB
/
gearbox_up_dc.vhdl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
-- EMACS settings: -*- tab-width: 2; indent-tabs-mode: t -*-
-- vim: tabstop=2:shiftwidth=2:noexpandtab
-- kate: tab-width 2; replace-tabs off; indent-width 2;
-- =============================================================================
-- Authors: Patrick Lehmann
--
-- Entity: An upscaling gearbox module with a dependent clock (dc) interface.
--
-- Description:
-- -------------------------------------
-- This module provides a upscaling gearbox with a dependent clock (dc)
-- interface. It perfoems a 'byte' to 'word' collection. The default order is
-- LITTLE_ENDIAN (starting at byte(0)). Input "In_Data" is of clock domain
-- "Clock1"; output "Out_Data" is of clock domain "Clock2". The "In_Align"
-- is required to mark the starting byte in the word. An optional input
-- register can be added by enabling (ADD_INPUT_REGISTERS = TRUE).
--
-- Assertions:
-- ===========
-- - Clock periods of Clock1 and Clock2 MUST be multiples of each other.
-- - Clock1 and Clock2 MUST be phase aligned (related) to each other.
--
-- License:
-- =============================================================================
-- Copyright 2007-2016 Technische Universitaet Dresden - Germany
-- Chair of VLSI-Design, Diagnostics and Architecture
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
-- http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.
-- =============================================================================
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.NUMERIC_STD.all;
library PoC;
use PoC.utils.all;
use PoC.components.all;
entity gearbox_up_dc is
generic (
INPUT_BITS : positive := 8; -- input bit width
INPUT_ORDER : T_BIT_ORDER := LSB_FIRST; -- LSB_FIRST: start at byte(0), MSB_FIRST: start at byte(n-1)
OUTPUT_BITS : positive := 32; -- output bit width
ADD_INPUT_REGISTERS : boolean := FALSE -- add input register @Clock1
);
port (
Clock1 : in std_logic; -- input clock domain
Clock2 : in std_logic; -- output clock domain
In_Align : in std_logic; -- align word (one cycle high impulse)
In_Data : in std_logic_vector(INPUT_BITS - 1 downto 0); -- input word
Out_Data : out std_logic_vector(OUTPUT_BITS - 1 downto 0); -- output word
Out_Valid : out std_logic -- output is valid
);
end entity;
architecture rtl of gearbox_up_dc is
constant BIT_RATIO : REAL := real(OUTPUT_BITS) / real(INPUT_BITS);
constant INPUT_CHUNKS : positive := integer(BIT_RATIO);
constant BITS_PER_CHUNK : positive := INPUT_BITS;
constant COUNTER_MAX : positive := INPUT_CHUNKS - 1;
constant COUNTER_BITS : positive := log2ceil(COUNTER_MAX + 1);
subtype T_CHUNK is std_logic_vector(BITS_PER_CHUNK - 1 downto 0);
type T_CHUNK_VECTOR is array(natural range <>) of T_CHUNK;
-- convert chunk-vector to flatten vector
function to_slv(slvv : T_CHUNK_VECTOR) return std_logic_vector is
variable slv : std_logic_vector((slvv'length * BITS_PER_CHUNK) - 1 downto 0);
begin
for i in slvv'range loop
slv(((i + 1) * BITS_PER_CHUNK) - 1 downto i * BITS_PER_CHUNK) := slvv(i);
end loop;
return slv;
end function;
signal Counter_us : unsigned(COUNTER_BITS - 1 downto 0) := (others => '0');
signal Select_us : unsigned(COUNTER_BITS - 1 downto 0);
signal In_Data_d : std_logic_vector(INPUT_BITS - 1 downto 0) := (others => '0');
signal In_Align_d : std_logic;
signal Data_d : T_CHUNK_VECTOR(INPUT_CHUNKS - 2 downto 0) := (others => (others => '0'));
signal Collected : std_logic_vector(OUTPUT_BITS - 1 downto 0);
signal Collected_swapped : std_logic_vector(OUTPUT_BITS - 1 downto 0);
signal Collected_en : std_logic;
signal Collected_d : std_logic_vector(OUTPUT_BITS - 1 downto 0) := (others => '0');
signal DataOut_d : std_logic_vector(OUTPUT_BITS - 1 downto 0) := (others => '0');
signal Valid_r : std_logic := '0';
signal Valid_d : std_logic := '0';
begin
assert (INPUT_BITS < OUTPUT_BITS) report "INPUT_BITS must be less than OUTPUT_BITS, otherwise it's no up-sizing gearbox." severity FAILURE;
-- input register @Clock1
In_Align_d <= In_Align when registered(Clock1, ADD_INPUT_REGISTERS);
In_Data_d <= In_Data when registered(Clock1, ADD_INPUT_REGISTERS);
-- byte alignment counter @Clock1
process(Clock1)
begin
if rising_edge(Clock1) then
if (In_Align_d = '1') then
Counter_us <= to_unsigned(1, Counter_us'length);
Valid_r <= '0';
elsif (upcounter_equal(cnt => Counter_us, value => COUNTER_MAX) = '1') then
Counter_us <= to_unsigned(0, Counter_us'length);
Valid_r <= '1';
else
Counter_us <= Counter_us + 1;
end if;
end if;
end process;
Select_us <= mux(In_Align_d, Counter_us, (Counter_us'range => '0'));
-- delay registers @Clock1
process(Clock1)
begin
if rising_edge(Clock1) then
for j in 0 to INPUT_CHUNKS - 2 loop
if j = to_index(Select_us, COUNTER_MAX) then -- D-FF enable
Data_d(j) <= In_Data_d;
end if;
end loop;
end if;
end process;
-- compose output word
Collected <= In_Data_d & to_slv(Data_d);
Collected_swapped <= ite((INPUT_ORDER = LSB_FIRST), Collected, swap(Collected, INPUT_BITS));
-- register collected signals again @Clock1
Collected_en <= upcounter_equal(cnt => Select_us, value => COUNTER_MAX);
Collected_d <= ffdre(q => Collected_d, d => Collected_swapped, en => Collected_en) when rising_edge(Clock1);
-- add output register @Clock2
DataOut_d <= Collected_d when rising_edge(Clock2);
Valid_d <= Valid_r when rising_edge(Clock2);
Out_Data <= DataOut_d;
Out_Valid <= Valid_d;
end architecture;