Wojciech M. Zabołotny
2018-11-23 10:45:57 UTC
The sources below implement a simple clock domain crossing block,
allowing connection of master working in one "SLAVE" clock domain
with slaves located in the another "MASTER" clock domain.
Please note, that in synthesis this blok must be accompanied with
the appropriate constraints (please see sources).
The code is provided "AS IS" without warranty of any kind.
You use it on your own risk!
Regards,
Wojtek
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh28034
# Made on 2018-11-23 11:34 CET by <***@wzdell>.
# Source directory was '/tmp/wb_cdc'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 6058 -rw-r--r-- wb_cdc.vhd
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= wb_cdc.vhd ==============
if test -n "${keep_file}" && test -f 'wb_cdc.vhd'
then
${echo} "x - SKIPPING wb_cdc.vhd (file already exists)"
else
${echo} "x - extracting wb_cdc.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wb_cdc.vhd' &&
-------------------------------------------------------------------------------
-- Title : Wishbone CDC for classic single cycles
-- Project :
-------------------------------------------------------------------------------
-- File : wb_cdc.vhd
-- Author : Wojciech Zabolotny <***@gmail.com> or <***@ise.pw.edu.pl>
-- Company :
-- Created : 2018-03-11
-- Last update: 2018-11-23
-- Platform :
-- Standard : VHDL'93/02
-- License : PUBLIC DOMAIN or Creative Commons CC0
-------------------------------------------------------------------------------
-- Description:
-- This is a simple CDC block, transmitting the Wishbone accesses from
-- the "SLAVE" clock domain to the "MASTER" clock domain.
-- Please note, that the block requires timing constraints, limiting
-- 1) the bus skew between the address, data and WE lines for transmission
-- from SLAVE to MASTER side.
-- 2) the bus skew between the data, ACK, ERR, and RTY lines for
-- transmission from MASTER to SLAVE.
-------------------------------------------------------------------------------
-- Copyright (c) 2018
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2018-03-11 1.0 xl Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.wishbone_pkg.all;
X
entity wb_cdc is
X
X generic (
X width : integer := 32);
X
X port (
X -- Part connecting to the master (as a slave), working in the first clock domain
X slave_clk_i : in std_logic;
X slave_rst_n_i : in std_logic;
X slave_i : in t_wishbone_slave_in;
X slave_o : out t_wishbone_slave_out;
X -- Part connecting to slaves (as the master) working in the second clock domain
X master_clk_i : in std_logic;
X master_rst_n_i : in std_logic;
X master_i : in t_wishbone_master_in;
X master_o : out t_wishbone_master_out
X );
X
end entity wb_cdc;
X
X
architecture rtl of wb_cdc is
X
X signal req, req_m0, req_m1, req_m : std_logic := '0';
X signal resp, new_resp, resp_s0, resp_s1, resp_m : std_logic := '0';
X signal rst_sl_0, rst_sl_p, rst_ms_0, rst_ms_p : std_logic := '1';
X signal dat_m : std_logic_vector(width-1 downto 0) := (others => '0');
X signal ack_m, rty_m, err_m : std_logic := '0';
X
begin -- architecture rtl
X
X -- Synchronization of reset for slave side
X r1 : process (slave_clk_i, slave_rst_n_i) is
X begin -- process r1
X if slave_rst_n_i = '0' then -- asynchronous reset (active high)
X rst_sl_0 <= '1';
X rst_sl_p <= '1';
X elsif slave_clk_i'event and slave_clk_i = '1' then -- rising clock edge
X rst_sl_p <= rst_sl_0;
X rst_sl_0 <= '0';
X end if;
X end process r1;
X
X -- Synchronization of reset for master side
X r2 : process (master_clk_i, master_rst_n_i) is
X begin -- process r1
X if master_rst_n_i = '0' then -- asynchronous reset (active high)
X rst_ms_0 <= '1';
X rst_ms_p <= '1';
X elsif master_clk_i'event and master_clk_i = '1' then -- rising clock edge
X rst_ms_p <= rst_ms_0;
X rst_ms_p <= '0';
X end if;
X end process r2;
X
X -- How does it work
X -- If on the slave side we find that cyc&stb changed its state from 0 to 1,
X -- We trigger access, by toggling the request line.
X
X sync_s1 : process (slave_clk_i) is
X begin -- process sync_s1
X if slave_clk_i'event and slave_clk_i = '1' then -- rising clock edge
X if rst_ms_p = '1' then -- synchronous reset (active high)
X req <= '0';
X resp <= '0';
X new_resp <= '0';
X resp_s1 <= '0';
X resp_s0 <= '0';
X slave_o.ack <= '0';
X else
X -- defaults
X slave_o.ack <= '0';
X slave_o.err <= '0';
X slave_o.rty <= '0';
X -- Initiation of the cycle
X if (slave_i.cyc = '1') and (slave_i.stb = '1') and (resp = req) then
X req <= not req;
X end if;
X -- Termination of the cycle
X if (slave_i.cyc = '1') and (slave_i.stb = '1') and (new_resp = req) then
X slave_o.dat <= dat_m;
X slave_o.ack <= ack_m;
X slave_o.err <= err_m;
X slave_o.rty <= rty_m;
X end if;
X -- Propagation of signals from master
X resp <= new_resp;
X new_resp <= resp_s1;
X resp_s1 <= resp_s0;
X resp_s0 <= resp_m;
X end if;
X end if;
X end process sync_s1;
X
X
X -- purpose: synchronization at master side
X -- type : sequential
X -- inputs : master_clk_i, master_rst_n_i
X -- outputs:
X sync_m1 : process (master_clk_i) is
X begin -- process sync_m1
X if master_clk_i'event and master_clk_i = '1' then -- rising clock edge
X if rst_ms_p = '1' then -- synchronous reset (active high)
X req_m0 <= '0';
X req_m1 <= '0';
X req_m <= '0';
X dat_m <= (others => '0');
X ack_m <= '0';
X rty_m <= '0';
X err_m <= '0';
X else
X req_m0 <= req;
X req_m1 <= req_m0;
X req_m <= req_m1;
X if req_m /= resp_m then
X -- Copy address, data and WE
X master_o.adr <= slave_i.adr;
X master_o.dat <= slave_i.dat;
X master_o.we <= slave_i.we;
X -- Start the access
X master_o.cyc <= '1';
X master_o.stb <= '1';
X end if;
X -- Handle ACK
X if (master_i.ack = '1') or (master_i.err = '1') or (master_i.rty = '1') then
X master_o.cyc <= '0';
X master_o.stb <= '0';
X dat_m <= master_i.dat;
X err_m <= master_i.err;
X ack_m <= master_i.ack;
X rty_m <= master_i.rty;
X resp_m <= req_m;
X end if;
X end if;
X end if;
X end process sync_m1;
X
end architecture rtl;
SHAR_EOF
(set 20 18 11 23 11 21 00 'wb_cdc.vhd'
eval "${shar_touch}") && \
chmod 0644 'wb_cdc.vhd'
if test $? -ne 0
then ${echo} "restore of wb_cdc.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wb_cdc.vhd': 'MD5 check failed'
) << \SHAR_EOF
7d09018d6ae2665a714b56f384274e70 wb_cdc.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wb_cdc.vhd'` -ne 6058 && \
${echo} "restoration warning: size of 'wb_cdc.vhd' is not 6058"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0
allowing connection of master working in one "SLAVE" clock domain
with slaves located in the another "MASTER" clock domain.
Please note, that in synthesis this blok must be accompanied with
the appropriate constraints (please see sources).
The code is provided "AS IS" without warranty of any kind.
You use it on your own risk!
Regards,
Wojtek
#!/bin/sh
# This is a shell archive (produced by GNU sharutils 4.15.2).
# To extract the files from this archive, save it to some FILE, remove
# everything before the '#!/bin/sh' line above, then type 'sh FILE'.
#
lock_dir=_sh28034
# Made on 2018-11-23 11:34 CET by <***@wzdell>.
# Source directory was '/tmp/wb_cdc'.
#
# Existing files will *not* be overwritten, unless '-c' is specified.
#
# This shar contains:
# length mode name
# ------ ---------- ------------------------------------------
# 6058 -rw-r--r-- wb_cdc.vhd
#
MD5SUM=${MD5SUM-md5sum}
f=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
test -n "${f}" && md5check=true || md5check=false
${md5check} || \
echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
if test "X$1" = "X-c"
then keep_file=''
else keep_file=true
fi
echo=echo
save_IFS="${IFS}"
IFS="${IFS}:"
gettext_dir=
locale_dir=
set_echo=false
for dir in $PATH
do
if test -f $dir/gettext \
&& ($dir/gettext --version >/dev/null 2>&1)
then
case `$dir/gettext --version 2>&1 | sed 1q` in
*GNU*) gettext_dir=$dir
set_echo=true
break ;;
esac
fi
done
if ${set_echo}
then
set_echo=false
for dir in $PATH
do
if test -f $dir/shar \
&& ($dir/shar --print-text-domain-dir >/dev/null 2>&1)
then
locale_dir=`$dir/shar --print-text-domain-dir`
set_echo=true
break
fi
done
if ${set_echo}
then
TEXTDOMAINDIR=$locale_dir
export TEXTDOMAINDIR
TEXTDOMAIN=sharutils
export TEXTDOMAIN
echo="$gettext_dir/gettext -s"
fi
fi
IFS="$save_IFS"
if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null
then if (echo -n test; echo 1,2,3) | grep n >/dev/null
then shar_n= shar_c='
'
else shar_n=-n shar_c= ; fi
else shar_n= shar_c='\c' ; fi
f=shar-touch.$$
st1=200112312359.59
st2=123123592001.59
st2tr=123123592001.5 # old SysV 14-char limit
st3=1231235901
if touch -am -t ${st1} ${f} >/dev/null 2>&1 && \
test ! -f ${st1} && test -f ${f}; then
shar_touch='touch -am -t $1$2$3$4$5$6.$7 "$8"'
elif touch -am ${st2} ${f} >/dev/null 2>&1 && \
test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$1$2.$7 "$8"'
elif touch -am ${st3} ${f} >/dev/null 2>&1 && \
test ! -f ${st3} && test -f ${f}; then
shar_touch='touch -am $3$4$5$6$2 "$8"'
else
shar_touch=:
echo
${echo} 'WARNING: not restoring timestamps. Consider getting and
installing GNU '\''touch'\'', distributed in GNU coreutils...'
echo
fi
rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
#
if test ! -d ${lock_dir} ; then :
else ${echo} "lock directory ${lock_dir} exists"
exit 1
fi
if mkdir ${lock_dir}
then ${echo} "x - created lock directory ${lock_dir}."
else ${echo} "x - failed to create lock directory ${lock_dir}."
exit 1
fi
# ============= wb_cdc.vhd ==============
if test -n "${keep_file}" && test -f 'wb_cdc.vhd'
then
${echo} "x - SKIPPING wb_cdc.vhd (file already exists)"
else
${echo} "x - extracting wb_cdc.vhd (text)"
sed 's/^X//' << 'SHAR_EOF' > 'wb_cdc.vhd' &&
-------------------------------------------------------------------------------
-- Title : Wishbone CDC for classic single cycles
-- Project :
-------------------------------------------------------------------------------
-- File : wb_cdc.vhd
-- Author : Wojciech Zabolotny <***@gmail.com> or <***@ise.pw.edu.pl>
-- Company :
-- Created : 2018-03-11
-- Last update: 2018-11-23
-- Platform :
-- Standard : VHDL'93/02
-- License : PUBLIC DOMAIN or Creative Commons CC0
-------------------------------------------------------------------------------
-- Description:
-- This is a simple CDC block, transmitting the Wishbone accesses from
-- the "SLAVE" clock domain to the "MASTER" clock domain.
-- Please note, that the block requires timing constraints, limiting
-- 1) the bus skew between the address, data and WE lines for transmission
-- from SLAVE to MASTER side.
-- 2) the bus skew between the data, ACK, ERR, and RTY lines for
-- transmission from MASTER to SLAVE.
-------------------------------------------------------------------------------
-- Copyright (c) 2018
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2018-03-11 1.0 xl Created
-------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library work;
use work.wishbone_pkg.all;
X
entity wb_cdc is
X
X generic (
X width : integer := 32);
X
X port (
X -- Part connecting to the master (as a slave), working in the first clock domain
X slave_clk_i : in std_logic;
X slave_rst_n_i : in std_logic;
X slave_i : in t_wishbone_slave_in;
X slave_o : out t_wishbone_slave_out;
X -- Part connecting to slaves (as the master) working in the second clock domain
X master_clk_i : in std_logic;
X master_rst_n_i : in std_logic;
X master_i : in t_wishbone_master_in;
X master_o : out t_wishbone_master_out
X );
X
end entity wb_cdc;
X
X
architecture rtl of wb_cdc is
X
X signal req, req_m0, req_m1, req_m : std_logic := '0';
X signal resp, new_resp, resp_s0, resp_s1, resp_m : std_logic := '0';
X signal rst_sl_0, rst_sl_p, rst_ms_0, rst_ms_p : std_logic := '1';
X signal dat_m : std_logic_vector(width-1 downto 0) := (others => '0');
X signal ack_m, rty_m, err_m : std_logic := '0';
X
begin -- architecture rtl
X
X -- Synchronization of reset for slave side
X r1 : process (slave_clk_i, slave_rst_n_i) is
X begin -- process r1
X if slave_rst_n_i = '0' then -- asynchronous reset (active high)
X rst_sl_0 <= '1';
X rst_sl_p <= '1';
X elsif slave_clk_i'event and slave_clk_i = '1' then -- rising clock edge
X rst_sl_p <= rst_sl_0;
X rst_sl_0 <= '0';
X end if;
X end process r1;
X
X -- Synchronization of reset for master side
X r2 : process (master_clk_i, master_rst_n_i) is
X begin -- process r1
X if master_rst_n_i = '0' then -- asynchronous reset (active high)
X rst_ms_0 <= '1';
X rst_ms_p <= '1';
X elsif master_clk_i'event and master_clk_i = '1' then -- rising clock edge
X rst_ms_p <= rst_ms_0;
X rst_ms_p <= '0';
X end if;
X end process r2;
X
X -- How does it work
X -- If on the slave side we find that cyc&stb changed its state from 0 to 1,
X -- We trigger access, by toggling the request line.
X
X sync_s1 : process (slave_clk_i) is
X begin -- process sync_s1
X if slave_clk_i'event and slave_clk_i = '1' then -- rising clock edge
X if rst_ms_p = '1' then -- synchronous reset (active high)
X req <= '0';
X resp <= '0';
X new_resp <= '0';
X resp_s1 <= '0';
X resp_s0 <= '0';
X slave_o.ack <= '0';
X else
X -- defaults
X slave_o.ack <= '0';
X slave_o.err <= '0';
X slave_o.rty <= '0';
X -- Initiation of the cycle
X if (slave_i.cyc = '1') and (slave_i.stb = '1') and (resp = req) then
X req <= not req;
X end if;
X -- Termination of the cycle
X if (slave_i.cyc = '1') and (slave_i.stb = '1') and (new_resp = req) then
X slave_o.dat <= dat_m;
X slave_o.ack <= ack_m;
X slave_o.err <= err_m;
X slave_o.rty <= rty_m;
X end if;
X -- Propagation of signals from master
X resp <= new_resp;
X new_resp <= resp_s1;
X resp_s1 <= resp_s0;
X resp_s0 <= resp_m;
X end if;
X end if;
X end process sync_s1;
X
X
X -- purpose: synchronization at master side
X -- type : sequential
X -- inputs : master_clk_i, master_rst_n_i
X -- outputs:
X sync_m1 : process (master_clk_i) is
X begin -- process sync_m1
X if master_clk_i'event and master_clk_i = '1' then -- rising clock edge
X if rst_ms_p = '1' then -- synchronous reset (active high)
X req_m0 <= '0';
X req_m1 <= '0';
X req_m <= '0';
X dat_m <= (others => '0');
X ack_m <= '0';
X rty_m <= '0';
X err_m <= '0';
X else
X req_m0 <= req;
X req_m1 <= req_m0;
X req_m <= req_m1;
X if req_m /= resp_m then
X -- Copy address, data and WE
X master_o.adr <= slave_i.adr;
X master_o.dat <= slave_i.dat;
X master_o.we <= slave_i.we;
X -- Start the access
X master_o.cyc <= '1';
X master_o.stb <= '1';
X end if;
X -- Handle ACK
X if (master_i.ack = '1') or (master_i.err = '1') or (master_i.rty = '1') then
X master_o.cyc <= '0';
X master_o.stb <= '0';
X dat_m <= master_i.dat;
X err_m <= master_i.err;
X ack_m <= master_i.ack;
X rty_m <= master_i.rty;
X resp_m <= req_m;
X end if;
X end if;
X end if;
X end process sync_m1;
X
end architecture rtl;
SHAR_EOF
(set 20 18 11 23 11 21 00 'wb_cdc.vhd'
eval "${shar_touch}") && \
chmod 0644 'wb_cdc.vhd'
if test $? -ne 0
then ${echo} "restore of wb_cdc.vhd failed"
fi
if ${md5check}
then (
${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'wb_cdc.vhd': 'MD5 check failed'
) << \SHAR_EOF
7d09018d6ae2665a714b56f384274e70 wb_cdc.vhd
SHAR_EOF
else
test `LC_ALL=C wc -c < 'wb_cdc.vhd'` -ne 6058 && \
${echo} "restoration warning: size of 'wb_cdc.vhd' is not 6058"
fi
fi
if rm -fr ${lock_dir}
then ${echo} "x - removed lock directory ${lock_dir}."
else ${echo} "x - failed to remove lock directory ${lock_dir}."
exit 1
fi
exit 0