-- 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: A downscaling gearbox module with a dependent clock (dc) interface.
--
-- Description:
--
-- This module provides a downscaling gearbox with a dependent clock (dc)
-- interface. It perfoems a 'word' to 'byte' splitting. 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". Optional input and
-- output registers can be added by enabling (ADD_***PUT_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-2015 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 [docs]gearbox_down_dc is
generic (
INPUT_BITS : positive := 32; -- input bits ('words')
OUTPUT_BITS : positive := 8; -- output bits ('byte')
OUTPUT_ORDER : T_BIT_ORDER := LSB_FIRST; -- LSB_FIRST: start at byte(0), MSB_FIRST: start at byte(n-1)
ADD_INPUT_REGISTERS : boolean := FALSE; -- add input register @Clock1
ADD_OUTPUT_REGISTERS : boolean := FALSE -- add output register @Clock2
);
port (
Clock1 : in std_logic; -- input clock domain
Clock2 : in std_logic; -- output clock domain
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
);
end entity;
architecture [docs]rtl of gearbox_down_dc is
constant BIT_RATIO : REAL := real(INPUT_BITS) / real(OUTPUT_BITS);
constant COUNTER_BITS : positive := log2ceil(integer(BIT_RATIO));
type T_MUX_INPUT is array (natural range <>) of std_logic_vector(OUTPUT_BITS - 1 downto 0);
signal WordBoundary : std_logic := '0';
signal WordBoundary_d : std_logic := '0';
signal Align : std_logic;
signal Data_d : std_logic_vector(INPUT_BITS - 1 downto 0) := (others => '0');
signal DataIn : std_logic_vector(INPUT_BITS - 1 downto 0);
signal DataOut_d : std_logic_vector(OUTPUT_BITS - 1 downto 0) := (others => '0');
signal MuxInput : T_MUX_INPUT(2**COUNTER_BITS - 1 downto 0);
signal MuxOutput : std_logic_vector(OUTPUT_BITS - 1 downto 0);
signal MuxCounter_us : unsigned(COUNTER_BITS - 1 downto 0) := (others => '0');
signal MuxSelect_us : unsigned(COUNTER_BITS - 1 downto 0);
begin
assert (INPUT_BITS > OUTPUT_BITS) report "OUTPUT_BITS must be less than INPUT_BITS, otherwise it's no down-sizing gearbox." severity FAILURE;
-- input register @Clock1
Data_d <= In_Data when registered(Clock1, ADD_INPUT_REGISTERS);
-- switch byte order if neccessary
DataIn <= ite((OUTPUT_ORDER = LSB_FIRST), Data_d, swap(Data_d, OUTPUT_BITS));
-- selection multiplexer
genMuxInput : for j in 0 to (2 ** COUNTER_BITS) - 1 generate
MuxInput(j) <= DataIn(((j + 1) * OUTPUT_BITS) - 1 downto (j * OUTPUT_BITS));
end generate;
-- multiplexer control @Clock2
MuxCounter_us <= upcounter_next(cnt => MuxCounter_us, rst => Align, INIT => 1) when rising_edge(Clock2);
MuxSelect_us <= mux(Align, MuxCounter_us, (MuxCounter_us'range => '0'));
MuxOutput <= MuxInput(to_index(MuxSelect_us));
-- word boundary T-FF @Clock1 and D-FF @Clock2
WordBoundary <= not WordBoundary when rising_edge(Clock1);
WordBoundary_d <= WordBoundary when rising_edge(Clock2);
Align <= WordBoundary xor WordBoundary_d;
-- add output register @Clock2
DataOut_d <= MuxOutput when registered(Clock2, ADD_OUTPUT_REGISTERS);
Out_Data <= DataOut_d;
end architecture;